diff --git a/lib/Slic3r/GUI/MainFrame.pm b/lib/Slic3r/GUI/MainFrame.pm
index 7bd019070..e897a6353 100644
--- a/lib/Slic3r/GUI/MainFrame.pm
+++ b/lib/Slic3r/GUI/MainFrame.pm
@@ -26,6 +26,14 @@ our $appController;
 our $VALUE_CHANGE_EVENT    = Wx::NewEventType;
 # 2) To inform about a preset selection change or a "modified" status change.
 our $PRESETS_CHANGED_EVENT = Wx::NewEventType;
+# 3) To inform about a change of object selection
+our $OBJECT_SELECTION_CHANGED_EVENT = Wx::NewEventType;
+# 4) To inform about a change of object settings
+our $OBJECT_SETTINGS_CHANGED_EVENT = Wx::NewEventType;
+# 5) To inform about a remove of object 
+our $OBJECT_REMOVE_EVENT = Wx::NewEventType;
+# 6) To inform about a update of the scene 
+our $UPDATE_SCENE_EVENT = Wx::NewEventType;
 
 sub new {
     my ($class, %params) = @_;
@@ -114,6 +122,8 @@ sub new {
 
     $self->update_ui_from_settings;
 
+    Slic3r::GUI::update_mode();
+
     return $self;
 }
 
@@ -133,7 +143,12 @@ sub _init_tabpanel {
     });
     
     if (!$self->{no_plater}) {
-        $panel->AddPage($self->{plater} = Slic3r::GUI::Plater->new($panel), L("Plater"));
+        $panel->AddPage($self->{plater} = Slic3r::GUI::Plater->new($panel,
+            event_object_selection_changed   => $OBJECT_SELECTION_CHANGED_EVENT,
+            event_object_settings_changed    => $OBJECT_SETTINGS_CHANGED_EVENT,
+            event_remove_object              => $OBJECT_REMOVE_EVENT,
+            event_update_scene               => $UPDATE_SCENE_EVENT,
+            ), L("Plater"));
         if (!$self->{no_controller}) {
             $panel->AddPage($self->{controller} = Slic3r::GUI::Controller->new($panel), L("Controller"));
         }
@@ -192,6 +207,40 @@ sub _init_tabpanel {
             }
         }
     });
+
+    # The following event is emited by the C++ Tab implementation on object selection change.
+    EVT_COMMAND($self, -1, $OBJECT_SELECTION_CHANGED_EVENT, sub {
+        my ($self, $event) = @_;
+        my $obj_idx = $event->GetId;
+        my $child = $event->GetInt == 1 ? 1 : undef;
+
+        $self->{plater}->select_object($obj_idx < 0 ? undef: $obj_idx, $child);
+        $self->{plater}->item_changed_selection($obj_idx);
+    });
+
+    # The following event is emited by the C++ GUI implementation on object settings change.
+    EVT_COMMAND($self, -1, $OBJECT_SETTINGS_CHANGED_EVENT, sub {
+        my ($self, $event) = @_;
+
+        my $line = $event->GetString;
+        my ($obj_idx, $parts_changed, $part_settings_changed) = split('',$line);
+
+        $self->{plater}->changed_object_settings($obj_idx, $parts_changed, $part_settings_changed);
+    });
+
+    # The following event is emited by the C++ GUI implementation on object remove.
+    EVT_COMMAND($self, -1, $OBJECT_REMOVE_EVENT, sub {
+        my ($self, $event) = @_;
+        $self->{plater}->remove();
+    });
+
+    # The following event is emited by the C++ GUI implementation on extruder change for object.
+    EVT_COMMAND($self, -1, $UPDATE_SCENE_EVENT, sub {
+        my ($self, $event) = @_;
+        $self->{plater}->update();
+    });
+        
+
     Slic3r::GUI::create_preset_tabs($self->{no_controller}, $VALUE_CHANGE_EVENT, $PRESETS_CHANGED_EVENT);
     $self->{options_tabs} = {};
     for my $tab_name (qw(print filament sla_material printer)) {
diff --git a/lib/Slic3r/GUI/Plater.pm b/lib/Slic3r/GUI/Plater.pm
index f4a2f99ff..2c2cf086c 100644
--- a/lib/Slic3r/GUI/Plater.pm
+++ b/lib/Slic3r/GUI/Plater.pm
@@ -49,7 +49,7 @@ my $PreventListEvents = 0;
 our $appController;
 
 sub new {
-    my ($class, $parent) = @_;
+    my ($class, $parent, %params) = @_;
     my $self = $class->SUPER::new($parent, -1, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL);
     $self->{config} = Slic3r::Config::new_from_defaults_keys([qw(
         bed_shape complete_objects extruder_clearance_radius skirts skirt_distance brim_width variable_layer_height
@@ -57,6 +57,13 @@ sub new {
         nozzle_diameter single_extruder_multi_material wipe_tower wipe_tower_x wipe_tower_y wipe_tower_width
 	wipe_tower_rotation_angle extruder_colour filament_colour max_print_height printer_model
     )]);
+
+    # store input params
+    $self->{event_object_selection_changed} = $params{event_object_selection_changed};
+    $self->{event_object_settings_changed} = $params{event_object_settings_changed};
+    $self->{event_remove_object} = $params{event_remove_object};
+    $self->{event_update_scene} = $params{event_update_scene};
+
     # C++ Slic3r::Model with Perl extensions in Slic3r/Model.pm
     $self->{model} = Slic3r::Model->new;
     # C++ Slic3r::Print with Perl extensions in Slic3r/Print.pm
@@ -74,7 +81,7 @@ sub new {
     });
     
     # Initialize preview notebook
-    $self->{preview_notebook} = Wx::Notebook->new($self, -1, wxDefaultPosition, [335,335], wxNB_BOTTOM);
+    $self->{preview_notebook} = Wx::Notebook->new($self, -1, wxDefaultPosition, [-1,335], wxNB_BOTTOM);
     
     # Initialize handlers for canvases
     my $on_select_object = sub {
@@ -128,7 +135,9 @@ sub new {
         }
         $_->set_scaling_factor($scale) for @{ $model_object->instances };
         
-        $self->{list}->SetItem($obj_idx, 2, ($model_object->instances->[0]->scaling_factor * 100) . "%");
+        # Set object scale on c++ side
+        Slic3r::GUI::set_object_scale($obj_idx, $model_object->instances->[0]->scaling_factor * 100); 
+
 #        $object->transform_thumbnail($self->{model}, $obj_idx);
     
         #update print and start background processing
@@ -362,37 +371,12 @@ sub new {
 #    }
 
     ### Panel for right column
-    $self->{right_panel} = Wx::Panel->new($self, -1, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL);
-    
-    ### Scrolled Window for info boxes
-    my $scrolled_window_sizer = $self->{scrolled_window_sizer} = Wx::BoxSizer->new(wxVERTICAL);
-    $scrolled_window_sizer->SetMinSize([310, -1]);
-    my $scrolled_window_panel = $self->{scrolled_window_panel} = Wx::ScrolledWindow->new($self->{right_panel}, -1, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL);
-    $scrolled_window_panel->SetSizer($scrolled_window_sizer);
-    $scrolled_window_panel->SetScrollbars(1, 1, 1, 1);    
-
-    $self->{list} = Wx::ListView->new($scrolled_window_panel, -1, wxDefaultPosition, wxDefaultSize,
-        wxLC_SINGLE_SEL | wxLC_REPORT | wxBORDER_SUNKEN | wxTAB_TRAVERSAL | wxWANTS_CHARS );
-    $self->{list}->InsertColumn(0, L("Name"), wxLIST_FORMAT_LEFT, 145);
-    $self->{list}->InsertColumn(1, L("Copies"), wxLIST_FORMAT_CENTER, 45);
-    $self->{list}->InsertColumn(2, L("Scale"), wxLIST_FORMAT_CENTER, wxLIST_AUTOSIZE_USEHEADER);
-    EVT_LIST_ITEM_SELECTED($self, $self->{list}, \&list_item_selected);
-    EVT_LIST_ITEM_DESELECTED($self, $self->{list}, \&list_item_deselected);
-    EVT_LIST_ITEM_ACTIVATED($self, $self->{list}, \&list_item_activated);
-    EVT_KEY_DOWN($self->{list}, sub {
-        my ($list, $event) = @_;
-        if ($event->GetKeyCode == WXK_TAB) {
-            $list->Navigate($event->ShiftDown ? &Wx::wxNavigateBackward : &Wx::wxNavigateForward);
-        } elsif ($event->GetKeyCode == WXK_DELETE ||
-                ($event->GetKeyCode == WXK_BACK && &Wx::wxMAC) ) {
-            $self->remove;
-        } else {
-            $event->Skip;
-        }
-    });
+#    $self->{right_panel} = Wx::Panel->new($self, -1, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL);
+    $self->{right_panel} = Wx::ScrolledWindow->new($self, -1, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL);
+    $self->{right_panel}->SetScrollbars(0, 1, 1, 1);
     
     # right pane buttons
-    $self->{btn_export_gcode} = Wx::Button->new($self->{right_panel}, -1, L("Export G-code…"), wxDefaultPosition, [-1, 30], wxBU_LEFT);
+    $self->{btn_export_gcode} = Wx::Button->new($self->{right_panel}, -1, L("Export G-code…"), wxDefaultPosition, [-1, 30], wxNO_BORDER);#, wxBU_LEFT);
     $self->{btn_reslice} = Wx::Button->new($self->{right_panel}, -1, L("Slice now"), wxDefaultPosition, [-1, 30], wxBU_LEFT);
     $self->{btn_print} = Wx::Button->new($self->{right_panel}, -1, L("Print…"), wxDefaultPosition, [-1, 30], wxBU_LEFT);
     $self->{btn_send_gcode} = Wx::Button->new($self->{right_panel}, -1, L("Send to printer"), wxDefaultPosition, [-1, 30], wxBU_LEFT);
@@ -460,6 +444,7 @@ sub new {
 #    } else {
 #        EVT_BUTTON($self, $self->{btn_add}, sub { $self->add; });
 #        EVT_BUTTON($self, $self->{btn_remove}, sub { $self->remove() }); # explicitly pass no argument to remove
+#        EVT_BUTTON($self, $self->{btn_remove}, sub { Slic3r::GUI::remove_obj() }); # explicitly pass no argument to remove
 #        EVT_BUTTON($self, $self->{btn_reset}, sub { $self->reset; });
 #        EVT_BUTTON($self, $self->{btn_arrange}, sub { $self->arrange; });
 #        EVT_BUTTON($self, $self->{btn_increase}, sub { $self->increase; });
@@ -476,7 +461,7 @@ sub new {
     $_->SetDropTarget(Slic3r::GUI::Plater::DropTarget->new($self))
         for grep defined($_),
             $self, $self->{canvas3D}, $self->{preview3D}, $self->{list};
-#            $self, $self->{canvas}, $self->{canvas3D}, $self->{preview3D}, $self->{list};
+#            $self, $self->{canvas}, $self->{canvas3D}, $self->{preview3D};
     
     EVT_COMMAND($self, -1, $PROGRESS_BAR_EVENT, sub {
         my ($self, $event) = @_;
@@ -555,15 +540,32 @@ sub new {
             $presets->Layout;
         }
 
-        my $frequently_changed_parameters_sizer = $self->{frequently_changed_parameters_sizer} = Wx::BoxSizer->new(wxHORIZONTAL);
+        my $frequently_changed_parameters_sizer = $self->{frequently_changed_parameters_sizer} = Wx::BoxSizer->new(wxVERTICAL);
         Slic3r::GUI::add_frequently_changed_parameters($self->{right_panel}, $frequently_changed_parameters_sizer, $presets);
 
+        my $expert_mode_part_sizer = Wx::BoxSizer->new(wxVERTICAL);
+        Slic3r::GUI::add_expert_mode_part(  $self->{right_panel}, $expert_mode_part_sizer, 
+                                            $self->{model},
+                                            $self->{event_object_selection_changed},
+                                            $self->{event_object_settings_changed},
+                                            $self->{event_remove_object},
+                                            $self->{event_update_scene});
+#        if ($expert_mode_part_sizer->IsShown(2)==1) 
+#        { 
+#           $expert_mode_part_sizer->Layout;
+#            $expert_mode_part_sizer->Show(2, 0); # ? Why doesn't work
+#            $self->{right_panel}->Layout;
+#       }
+
         my $object_info_sizer;
         {
-            my $box = Wx::StaticBox->new($scrolled_window_panel, -1, L("Info"));
+#            my $box = Wx::StaticBox->new($scrolled_window_panel, -1, L("Info"));
+            my $box = Wx::StaticBox->new($self->{right_panel}, -1, L("Info"));
+            $box->SetFont($Slic3r::GUI::small_bold_font);
             $object_info_sizer = Wx::StaticBoxSizer->new($box, wxVERTICAL);
             $object_info_sizer->SetMinSize([300,-1]);
-            my $grid_sizer = Wx::FlexGridSizer->new(3, 4, 5, 5);
+            #!my $grid_sizer = Wx::FlexGridSizer->new(3, 4, 5, 5);
+            my $grid_sizer = Wx::FlexGridSizer->new(2, 4, 5, 5);
             $grid_sizer->SetFlexibleDirection(wxHORIZONTAL);
             $grid_sizer->AddGrowableCol(1, 1);
             $grid_sizer->AddGrowableCol(3, 1);
@@ -578,28 +580,45 @@ sub new {
             );
             while (my $field = shift @info) {
                 my $label = shift @info;
-                my $text = Wx::StaticText->new($scrolled_window_panel, -1, "$label:", wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT);
+#                my $text = Wx::StaticText->new($scrolled_window_panel, -1, "$label:", wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT);
+                my $text = Wx::StaticText->new($self->{right_panel}, -1, "$label:", wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT);
                 $text->SetFont($Slic3r::GUI::small_font);
-                $grid_sizer->Add($text, 0);
+                #!$grid_sizer->Add($text, 0);
                 
-                $self->{"object_info_$field"} = Wx::StaticText->new($scrolled_window_panel, -1, "", wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT);
+#                $self->{"object_info_$field"} = Wx::StaticText->new($scrolled_window_panel, -1, "", wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT);
+                $self->{"object_info_$field"} = Wx::StaticText->new($self->{right_panel}, -1, "", wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT);
                 $self->{"object_info_$field"}->SetFont($Slic3r::GUI::small_font);
                 if ($field eq 'manifold') {
-                    $self->{object_info_manifold_warning_icon} = Wx::StaticBitmap->new($scrolled_window_panel, -1, Wx::Bitmap->new(Slic3r::var("error.png"), wxBITMAP_TYPE_PNG));
-                    $self->{object_info_manifold_warning_icon}->Hide;
+#                    $self->{object_info_manifold_warning_icon} = Wx::StaticBitmap->new($scrolled_window_panel, -1, Wx::Bitmap->new(Slic3r::var("error.png"), wxBITMAP_TYPE_PNG));
+                    $self->{object_info_manifold_warning_icon} = Wx::StaticBitmap->new($self->{right_panel}, -1, Wx::Bitmap->new(Slic3r::var("error.png"), wxBITMAP_TYPE_PNG));
+                    #$self->{object_info_manifold_warning_icon}->Hide;
+                    $self->{"object_info_manifold_warning_icon_show"} = sub {
+                        if ($self->{object_info_manifold_warning_icon}->IsShown() != $_[0]) {
+                            Slic3r::GUI::set_show_manifold_warning_icon($_[0]);
+                            my $mode = wxTheApp->{app_config}->get("view_mode");
+                            return if ($mode eq "" || $mode eq "simple");
+                            $self->{object_info_manifold_warning_icon}->Show($_[0]); 
+                            $self->Layout
+                        }
+                    };
+                    $self->{"object_info_manifold_warning_icon_show"}->(0);
                     
                     my $h_sizer = Wx::BoxSizer->new(wxHORIZONTAL);
-                    $h_sizer->Add($self->{object_info_manifold_warning_icon}, 0);
-                    $h_sizer->Add($self->{"object_info_$field"}, 0);
-                    $grid_sizer->Add($h_sizer, 0, wxEXPAND);
+                    $h_sizer->Add($text, 0);
+                    $h_sizer->Add($self->{object_info_manifold_warning_icon}, 0, wxLEFT, 2);
+                    $h_sizer->Add($self->{"object_info_$field"}, 0, wxLEFT, 2);
+                    #!$grid_sizer->Add($h_sizer, 0, wxEXPAND);
+                    $object_info_sizer->Add($h_sizer, 0, wxEXPAND|wxTOP, 4);
                 } else {
+                    $grid_sizer->Add($text, 0);
                     $grid_sizer->Add($self->{"object_info_$field"}, 0);
                 }
             }
         }
 
         my $print_info_sizer = $self->{print_info_sizer} = Wx::StaticBoxSizer->new(
-                Wx::StaticBox->new($scrolled_window_panel, -1, L("Sliced Info")), wxVERTICAL);
+#                Wx::StaticBox->new($scrolled_window_panel, -1, L("Sliced Info")), wxVERTICAL);
+                Wx::StaticBox->new($self->{right_panel}, -1, L("Sliced Info")), wxVERTICAL);
         $print_info_sizer->SetMinSize([300,-1]);
         
         my $buttons_sizer = Wx::BoxSizer->new(wxHORIZONTAL);
@@ -609,22 +628,27 @@ sub new {
         $buttons_sizer->Add($self->{btn_reslice}, 0, wxALIGN_RIGHT, 0);
         $buttons_sizer->Add($self->{btn_print}, 0, wxALIGN_RIGHT, 0);
         $buttons_sizer->Add($self->{btn_send_gcode}, 0, wxALIGN_RIGHT, 0);
-        $buttons_sizer->Add($self->{btn_export_gcode}, 0, wxALIGN_RIGHT, 0);
         
-        $scrolled_window_sizer->Add($self->{list}, 1, wxEXPAND, 5);
-        $scrolled_window_sizer->Add($object_info_sizer, 0, wxEXPAND, 0);
-        $scrolled_window_sizer->Add($print_info_sizer, 0, wxEXPAND, 0);
+#        $scrolled_window_sizer->Add($self->{list}, 1, wxEXPAND, 5);
+#        $scrolled_window_sizer->Add($object_info_sizer, 0, wxEXPAND, 0);
+#        $scrolled_window_sizer->Add($print_info_sizer, 0, wxEXPAND, 0);
+        #$buttons_sizer->Add($self->{btn_export_gcode}, 0, wxALIGN_RIGHT, 0);
+
+        ### Sizer for info boxes
+        my $info_sizer = $self->{info_sizer} = Wx::BoxSizer->new(wxVERTICAL);
+        $info_sizer->SetMinSize([318, -1]);        
+        $info_sizer->Add($object_info_sizer, 0, wxEXPAND | wxBOTTOM, 5);
+        $info_sizer->Add($print_info_sizer, 0, wxEXPAND | wxBOTTOM, 5);
 
         my $right_sizer = Wx::BoxSizer->new(wxVERTICAL);
-        $right_sizer->SetMinSize([320,-1]);
-        $right_sizer->Add($presets, 0, wxEXPAND | wxTOP, 10) if defined $presets;
-        $right_sizer->Add($frequently_changed_parameters_sizer, 0, wxEXPAND | wxTOP, 0) if defined $frequently_changed_parameters_sizer;
-        $right_sizer->Add($buttons_sizer, 0, wxEXPAND | wxBOTTOM, 5);
-        $right_sizer->Add($scrolled_window_panel, 1, wxEXPAND | wxALL, 1);
-        # Show the box initially, let it be shown after the slicing is finished.
-        $self->print_info_box_show(0);
-
         $self->{right_panel}->SetSizer($right_sizer);
+        $right_sizer->SetMinSize([320, -1]);
+        $right_sizer->Add($presets, 0, wxEXPAND | wxTOP, 10) if defined $presets;
+        $right_sizer->Add($frequently_changed_parameters_sizer, 1, wxEXPAND | wxTOP, 0) if defined $frequently_changed_parameters_sizer;
+        $right_sizer->Add($expert_mode_part_sizer, 0, wxEXPAND | wxTOP, 10) if defined $expert_mode_part_sizer;
+        $right_sizer->Add($buttons_sizer, 0, wxEXPAND | wxBOTTOM | wxTOP, 10);
+        $right_sizer->Add($info_sizer, 0, wxEXPAND | wxLEFT, 20);
+        $right_sizer->Add($self->{btn_export_gcode}, 0, wxEXPAND | wxLEFT | wxTOP | wxBOTTOM, 20);
 
         my $hsizer = Wx::BoxSizer->new(wxHORIZONTAL);
         $hsizer->Add($self->{preview_notebook}, 1, wxEXPAND | wxTOP, 1);
@@ -637,6 +661,18 @@ sub new {
         
         $sizer->SetSizeHints($self);
         $self->SetSizer($sizer);
+
+        # Send sizers/buttons to C++
+        Slic3r::GUI::set_objects_from_perl( $self->{right_panel},
+                                $frequently_changed_parameters_sizer,
+                                $expert_mode_part_sizer,
+                                $info_sizer,
+                                $self->{btn_export_gcode},
+                                $self->{btn_export_stl},
+                                $self->{btn_reslice},
+                                $self->{btn_print},
+                                $self->{btn_send_gcode},
+                                $self->{object_info_manifold_warning_icon} );
     }
 
     # Last correct selected item for each preset
@@ -647,6 +683,7 @@ sub new {
     }
 
     $self->update_ui_from_settings();
+    $self->Layout;
     
     return $self;
 }
@@ -921,12 +958,10 @@ sub load_model_objects {
     foreach my $obj_idx (@obj_idx) {
         my $object = $self->{objects}[$obj_idx];
         my $model_object = $self->{model}->objects->[$obj_idx];
-        $self->{list}->InsertStringItem($obj_idx, $object->name);
-        $self->{list}->SetItemFont($obj_idx, Wx::Font->new(10, wxDEFAULT, wxNORMAL, wxNORMAL))
-            if $self->{list}->can('SetItemFont');  # legacy code for wxPerl < 0.9918 not supporting SetItemFont()
+
+        # Add object to list on c++ side
+        Slic3r::GUI::add_object_to_list($object->name, $model_object);
     
-        $self->{list}->SetItem($obj_idx, 1, $model_object->instances_count);
-        $self->{list}->SetItem($obj_idx, 2, ($model_object->instances->[0]->scaling_factor * 100) . "%");
 
 #        $self->reset_thumbnail($obj_idx);
     }
@@ -936,8 +971,6 @@ sub load_model_objects {
     # zoom to objects
     Slic3r::GUI::_3DScene::zoom_to_volumes($self->{canvas3D}) if $self->{canvas3D};
     
-    $self->{list}->Update;
-    $self->{list}->Select($obj_idx[-1], 1);
     $self->object_list_changed;
     
     $self->schedule_background_process;
@@ -972,7 +1005,8 @@ sub remove {
     splice @{$self->{objects}}, $obj_idx, 1;
     $self->{model}->delete_object($obj_idx);
     $self->{print}->delete_object($obj_idx);
-    $self->{list}->DeleteItem($obj_idx);
+    # Delete object from list on c++ side
+    Slic3r::GUI::delete_object_from_list();
     $self->object_list_changed;
     
     $self->select_object(undef);
@@ -992,7 +1026,8 @@ sub reset {
     @{$self->{objects}} = ();
     $self->{model}->clear_objects;
     $self->{print}->clear_objects;
-    $self->{list}->DeleteAllItems;
+    # Delete all objects from list on c++ side
+    Slic3r::GUI::delete_all_objects_from_list();
     $self->object_list_changed;
     
     $self->select_object(undef);
@@ -1014,7 +1049,8 @@ sub increase {
         );
         $self->{print}->objects->[$obj_idx]->add_copy($instance->offset);
     }
-    $self->{list}->SetItem($obj_idx, 1, $model_object->instances_count);
+    # Set conut of object on c++ side
+    Slic3r::GUI::set_object_count($obj_idx, $model_object->instances_count);
     
     # only autoarrange if user has autocentering enabled
     $self->stop_background_process;
@@ -1042,7 +1078,8 @@ sub decrease {
             $model_object->delete_last_instance;
             $self->{print}->objects->[$obj_idx]->delete_last_copy;
         }
-        $self->{list}->SetItem($obj_idx, 1, $model_object->instances_count);
+        # Set conut of object on c++ side
+        Slic3r::GUI::set_object_count($obj_idx, $model_object->instances_count);
     } elsif (defined $copies_asked) {
         # The "decrease" came from the "set number of copies" dialog.
         $self->remove;
@@ -1051,11 +1088,7 @@ sub decrease {
         $self->resume_background_process;
         return;
     }
-    
-    if ($self->{objects}[$obj_idx]) {
-        $self->{list}->Select($obj_idx, 0);
-        $self->{list}->Select($obj_idx, 1);
-    }
+
     $self->update;
     $self->schedule_background_process;
 }
@@ -1153,6 +1186,7 @@ sub rotate {
 #        $model_object->center_around_origin;
 #        $self->reset_thumbnail($obj_idx);
     }
+    Slic3r::GUI::update_rotation_value(deg2rad($angle), $axis == X ? "x" : ($axis == Y ? "y" : "z"));
     
     # update print and start background processing
     $self->{print}->add_model_object($model_object, $obj_idx);
@@ -1243,8 +1277,9 @@ sub changescale {
             $scale = $self->_get_number_from_user(L('Enter the scale % for the selected object:'), L('Scale'), L('Invalid scaling value entered'), $model_instance->scaling_factor*100, 1);
             return if ! defined($scale) || $scale eq '';
         }
-    
-        $self->{list}->SetItem($obj_idx, 2, "$scale%");
+
+        # Set object scale on c++ side
+        Slic3r::GUI::set_object_scale($obj_idx, $scale);
         $scale /= 100;  # turn percent into factor
         
         my $variation = $scale / $model_instance->scaling_factor;
@@ -1687,9 +1722,15 @@ sub on_export_completed {
 # Fill in the "Sliced info" box with the result of the G-code generator.
 sub print_info_box_show {
     my ($self, $show) = @_;
-    my $scrolled_window_panel = $self->{scrolled_window_panel}; 
-    my $scrolled_window_sizer = $self->{scrolled_window_sizer};
-    return if (!$show && ($scrolled_window_sizer->IsShown(2) == $show));
+#    my $scrolled_window_panel = $self->{scrolled_window_panel}; 
+#    my $scrolled_window_sizer = $self->{scrolled_window_sizer};
+#    return if (!$show && ($scrolled_window_sizer->IsShown(2) == $show));
+    my $panel = $self->{right_panel};
+    my $sizer = $self->{info_sizer};
+    return if (!$show && ($sizer->IsShown(2) == $show));
+
+    Slic3r::GUI::set_show_print_info($show);
+    return if (wxTheApp->{app_config}->get("view_mode") eq "simple");
 
     if ($show) {
         my $print_info_sizer = $self->{print_info_sizer};
@@ -1716,17 +1757,23 @@ sub print_info_box_show {
         while ( my $label = shift @info) {
             my $value = shift @info;
             next if $value eq "N/A";
-            my $text = Wx::StaticText->new($scrolled_window_panel, -1, "$label:", wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT);
+#            my $text = Wx::StaticText->new($scrolled_window_panel, -1, "$label:", wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT);
+            my $text = Wx::StaticText->new($panel, -1, "$label:", wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT);
             $text->SetFont($Slic3r::GUI::small_font);
             $grid_sizer->Add($text, 0);            
-            my $field = Wx::StaticText->new($scrolled_window_panel, -1, $value, wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT);
+#            my $field = Wx::StaticText->new($scrolled_window_panel, -1, $value, wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT);
+            my $field = Wx::StaticText->new($panel, -1, $value, wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT);
             $field->SetFont($Slic3r::GUI::small_font);
             $grid_sizer->Add($field, 0);
         }
     }
 
-    $scrolled_window_sizer->Show(2, $show);
-    $scrolled_window_panel->Layout;
+#    $scrolled_window_sizer->Show(2, $show);
+#    $scrolled_window_panel->Layout;
+    $sizer->Show(1, $show);
+
+#?    $self->Layout;
+#?    $panel->Refresh;
 }
 
 sub do_print {
@@ -2058,32 +2105,18 @@ sub on_config_change {
     $self->schedule_background_process;
 }
 
-sub list_item_deselected {
-    my ($self, $event) = @_;
-    return if $PreventListEvents;
-    $self->{_lecursor} = Wx::BusyCursor->new();
-    if ($self->{list}->GetFirstSelected == -1) {
-        $self->select_object(undef);
-#        $self->{canvas}->Refresh;
-        Slic3r::GUI::_3DScene::deselect_volumes($self->{canvas3D}) if $self->{canvas3D};
-        Slic3r::GUI::_3DScene::render($self->{canvas3D}) if $self->{canvas3D};
-    }
-    undef $self->{_lecursor};
-}
+sub item_changed_selection{
+    my ($self, $obj_idx) = @_;
 
-sub list_item_selected {
-    my ($self, $event) = @_;
-    return if $PreventListEvents;
-    $self->{_lecursor} = Wx::BusyCursor->new();
-    my $obj_idx = $event->GetIndex;
-    $self->select_object($obj_idx);
 #    $self->{canvas}->Refresh;
     if ($self->{canvas3D}) {
-        my $selections = $self->collect_selections;
-        Slic3r::GUI::_3DScene::update_volumes_selection($self->{canvas3D}, \@$selections);
+        Slic3r::GUI::_3DScene::deselect_volumes($self->{canvas3D});
+        if ($obj_idx >= 0){
+            my $selections = $self->collect_selections;
+            Slic3r::GUI::_3DScene::update_volumes_selection($self->{canvas3D}, \@$selections);
+        }
         Slic3r::GUI::_3DScene::render($self->{canvas3D});
     }
-    undef $self->{_lecursor};
 }
 
 sub collect_selections {
@@ -2095,6 +2128,7 @@ sub collect_selections {
     return $selections;
 }
 
+# doesn't used now
 sub list_item_activated {
     my ($self, $event, $obj_idx) = @_;
     
@@ -2195,6 +2229,31 @@ sub object_settings_dialog {
     }
 }
 
+sub changed_object_settings {
+    my ($self, $obj_idx, $parts_changed, $part_settings_changed) = @_;
+    
+    # update thumbnail since parts may have changed
+    if ($parts_changed) {
+        # recenter and re-align to Z = 0
+        my $model_object = $self->{model}->objects->[$obj_idx];
+        $model_object->center_around_origin;
+        $self->reset_thumbnail($obj_idx);
+    }
+    
+    # update print
+    if ($parts_changed || $part_settings_changed) {
+        $self->stop_background_process;
+        $self->{print}->reload_object($obj_idx);
+        $self->schedule_background_process;
+        $self->{canvas}->reload_scene if $self->{canvas};
+        my $selections = $self->collect_selections;
+        Slic3r::GUI::_3DScene::set_objects_selections($self->{canvas3D}, \@$selections);
+        Slic3r::GUI::_3DScene::reload_scene($self->{canvas3D}, 0);
+    } else {
+        $self->resume_background_process;
+    }
+}
+
 # Called to update various buttons depending on whether there are any objects or
 # whether background processing (export of a G-code, sending to Octoprint, forced background re-slicing) is active.
 sub object_list_changed {
@@ -2296,7 +2355,8 @@ sub selection_changed {
                 $self->{object_info_facets}->SetLabel(sprintf(L('%d (%d shells)'), $model_object->facets_count, $stats->{number_of_parts}));
                 if (my $errors = sum(@$stats{qw(degenerate_facets edges_fixed facets_removed facets_added facets_reversed backwards_edges)})) {
                     $self->{object_info_manifold}->SetLabel(sprintf(L("Auto-repaired (%d errors)"), $errors));
-                    $self->{object_info_manifold_warning_icon}->Show;
+                    #$self->{object_info_manifold_warning_icon}->Show;
+                    $self->{"object_info_manifold_warning_icon_show"}->(1);
                     
                     # we don't show normals_fixed because we never provide normals
 	                # to admesh, so it generates normals for all facets
@@ -2306,7 +2366,8 @@ sub selection_changed {
                     $self->{object_info_manifold_warning_icon}->SetToolTipString($message);
                 } else {
                     $self->{object_info_manifold}->SetLabel(L("Yes"));
-                    $self->{object_info_manifold_warning_icon}->Hide;
+                    #$self->{object_info_manifold_warning_icon}->Hide;
+                    $self->{"object_info_manifold_warning_icon_show"}->(0);
                     $self->{object_info_manifold}->SetToolTipString("");
                     $self->{object_info_manifold_warning_icon}->SetToolTipString("");
                 }
@@ -2315,7 +2376,8 @@ sub selection_changed {
             }
         } else {
             $self->{"object_info_$_"}->SetLabel("") for qw(size volume facets materials manifold);
-            $self->{object_info_manifold_warning_icon}->Hide;
+            #$self->{object_info_manifold_warning_icon}->Hide;
+            $self->{"object_info_manifold_warning_icon_show"}->(0);
             $self->{object_info_manifold}->SetToolTipString("");
             $self->{object_info_manifold_warning_icon}->SetToolTipString("");
         }
@@ -2328,26 +2390,21 @@ sub selection_changed {
 }
 
 sub select_object {
-    my ($self, $obj_idx) = @_;
+    my ($self, $obj_idx, $child) = @_;
 
     # remove current selection
     foreach my $o (0..$#{$self->{objects}}) {
-        $PreventListEvents = 1;
         $self->{objects}->[$o]->selected(0);
-        $self->{list}->Select($o, 0);
-        $PreventListEvents = 0;
     }
-    
+
     if (defined $obj_idx) {
         $self->{objects}->[$obj_idx]->selected(1);
-        # We use this flag to avoid circular event handling
-        # Select() happens to fire a wxEVT_LIST_ITEM_SELECTED on Windows, 
-        # whose event handler calls this method again and again and again
-        $PreventListEvents = 1;
-        $self->{list}->Select($obj_idx, 1);
-        $PreventListEvents = 0;
+        # Select current object in the list on c++ side, if item isn't child
+        if (!defined $child){
+            Slic3r::GUI::select_current_object($obj_idx);}
     } else {
-        # TODO: deselect all in list
+        # Unselect all objects in the list on c++ side
+        Slic3r::GUI::unselect_objects();
     }
     $self->selection_changed(1);
 }
diff --git a/resources/icons/add_object.png b/resources/icons/add_object.png
new file mode 100644
index 000000000..ffc958edc
Binary files /dev/null and b/resources/icons/add_object.png differ
diff --git a/resources/icons/colorchange_add_off.png b/resources/icons/colorchange_add_off.png
new file mode 100644
index 000000000..6ddeccbe0
Binary files /dev/null and b/resources/icons/colorchange_add_off.png differ
diff --git a/resources/icons/colorchange_add_on.png b/resources/icons/colorchange_add_on.png
new file mode 100644
index 000000000..cc800b81e
Binary files /dev/null and b/resources/icons/colorchange_add_on.png differ
diff --git a/resources/icons/colorchange_delete_off.png b/resources/icons/colorchange_delete_off.png
new file mode 100644
index 000000000..c16655271
Binary files /dev/null and b/resources/icons/colorchange_delete_off.png differ
diff --git a/resources/icons/colorchange_delete_on.png b/resources/icons/colorchange_delete_on.png
new file mode 100644
index 000000000..8f27ce9fe
Binary files /dev/null and b/resources/icons/colorchange_delete_on.png differ
diff --git a/resources/icons/disclosure_triangle_close.png b/resources/icons/disclosure_triangle_close.png
new file mode 100644
index 000000000..0660422c7
Binary files /dev/null and b/resources/icons/disclosure_triangle_close.png differ
diff --git a/resources/icons/disclosure_triangle_open.png b/resources/icons/disclosure_triangle_open.png
new file mode 100644
index 000000000..81112f2a2
Binary files /dev/null and b/resources/icons/disclosure_triangle_open.png differ
diff --git a/resources/icons/down_half_circle.png b/resources/icons/down_half_circle.png
new file mode 100644
index 000000000..84aba5c3c
Binary files /dev/null and b/resources/icons/down_half_circle.png differ
diff --git a/resources/icons/erase.png b/resources/icons/erase.png
new file mode 100644
index 000000000..4c4cfd755
Binary files /dev/null and b/resources/icons/erase.png differ
diff --git a/resources/icons/exclamation_mark_.png b/resources/icons/exclamation_mark_.png
new file mode 100644
index 000000000..5fe7c1355
Binary files /dev/null and b/resources/icons/exclamation_mark_.png differ
diff --git a/resources/icons/lambda.png b/resources/icons/lambda.png
new file mode 100644
index 000000000..3be73b142
Binary files /dev/null and b/resources/icons/lambda.png differ
diff --git a/resources/icons/lambda_.png b/resources/icons/lambda_.png
new file mode 100644
index 000000000..8e9d2b0ea
Binary files /dev/null and b/resources/icons/lambda_.png differ
diff --git a/resources/icons/left_half_circle.png b/resources/icons/left_half_circle.png
new file mode 100644
index 000000000..c1e8d3a9c
Binary files /dev/null and b/resources/icons/left_half_circle.png differ
diff --git a/resources/icons/object.png b/resources/icons/object.png
new file mode 100644
index 000000000..c85cbaf2f
Binary files /dev/null and b/resources/icons/object.png differ
diff --git a/resources/icons/one_layer_lock_off.png b/resources/icons/one_layer_lock_off.png
new file mode 100644
index 000000000..7dc8b0611
Binary files /dev/null and b/resources/icons/one_layer_lock_off.png differ
diff --git a/resources/icons/one_layer_lock_on.png b/resources/icons/one_layer_lock_on.png
new file mode 100644
index 000000000..41b7ff173
Binary files /dev/null and b/resources/icons/one_layer_lock_on.png differ
diff --git a/resources/icons/one_layer_unlock_off.png b/resources/icons/one_layer_unlock_off.png
new file mode 100644
index 000000000..c3931f8b9
Binary files /dev/null and b/resources/icons/one_layer_unlock_off.png differ
diff --git a/resources/icons/one_layer_unlock_on.png b/resources/icons/one_layer_unlock_on.png
new file mode 100644
index 000000000..99e0db5c2
Binary files /dev/null and b/resources/icons/one_layer_unlock_on.png differ
diff --git a/resources/icons/right_half_circle.png b/resources/icons/right_half_circle.png
new file mode 100644
index 000000000..9f182b0b4
Binary files /dev/null and b/resources/icons/right_half_circle.png differ
diff --git a/resources/icons/split.png b/resources/icons/split.png
new file mode 100644
index 000000000..c5680ab91
Binary files /dev/null and b/resources/icons/split.png differ
diff --git a/resources/icons/up_half_circle.png b/resources/icons/up_half_circle.png
new file mode 100644
index 000000000..9eea07fda
Binary files /dev/null and b/resources/icons/up_half_circle.png differ
diff --git a/xs/CMakeLists.txt b/xs/CMakeLists.txt
index fe33514a9..0d1f1bf13 100644
--- a/xs/CMakeLists.txt
+++ b/xs/CMakeLists.txt
@@ -211,6 +211,10 @@ add_library(libslic3r_gui STATIC
     ${LIBDIR}/slic3r/GUI/PresetHints.hpp
     ${LIBDIR}/slic3r/GUI/GUI.cpp
     ${LIBDIR}/slic3r/GUI/GUI.hpp
+    ${LIBDIR}/slic3r/GUI/GUI_ObjectParts.cpp
+    ${LIBDIR}/slic3r/GUI/GUI_ObjectParts.hpp
+    ${LIBDIR}/slic3r/GUI/LambdaObjectDialog.cpp
+    ${LIBDIR}/slic3r/GUI/LambdaObjectDialog.hpp
     ${LIBDIR}/slic3r/GUI/Tab.cpp
     ${LIBDIR}/slic3r/GUI/Tab.hpp
     ${LIBDIR}/slic3r/GUI/TabIface.cpp
diff --git a/xs/src/slic3r/GUI/3DScene.cpp b/xs/src/slic3r/GUI/3DScene.cpp
index d836866e2..1b9106d75 100644
--- a/xs/src/slic3r/GUI/3DScene.cpp
+++ b/xs/src/slic3r/GUI/3DScene.cpp
@@ -258,6 +258,11 @@ const Vec3d& GLVolume::get_origin() const
     return m_origin;
 }
 
+float GLVolume::get_angle_z()
+{
+    return m_angle_z;
+}
+
 void GLVolume::set_origin(const Vec3d& origin)
 {
     if (m_origin != origin)
diff --git a/xs/src/slic3r/GUI/3DScene.hpp b/xs/src/slic3r/GUI/3DScene.hpp
index 1fbd958a8..9aa023fae 100644
--- a/xs/src/slic3r/GUI/3DScene.hpp
+++ b/xs/src/slic3r/GUI/3DScene.hpp
@@ -323,6 +323,7 @@ public:
     // Sets render color in dependence of current state
     void set_render_color();
 
+    float get_angle_z();
     const Vec3d& get_origin() const;
     void set_origin(const Vec3d& origin);
     void set_angle_z(float angle_z);
diff --git a/xs/src/slic3r/GUI/Field.cpp b/xs/src/slic3r/GUI/Field.cpp
index 87f6693a8..b9753fe93 100644
--- a/xs/src/slic3r/GUI/Field.cpp
+++ b/xs/src/slic3r/GUI/Field.cpp
@@ -132,7 +132,11 @@ namespace Slic3r { namespace GUI {
 				break;
 			}
 			double val;
-			str.ToCDouble(&val);
+			if(!str.ToCDouble(&val))
+			{
+				show_error(m_parent, _(L("Input value contains incorrect symbol(s).\nUse, please, only digits")));
+				set_value(double_to_string(val), true);
+			}
 			if (m_opt.min > val || val > m_opt.max)
 			{
 				show_error(m_parent, _(L("Input value is out of range")));
@@ -330,9 +334,7 @@ void SpinCtrl::BUILD() {
 		break;
 	}
 
-	const int min_val = m_opt_id == "standby_temperature_delta" ? 
-						-500 : m_opt.min > 0 ? 
-						m_opt.min : 0;
+    const int min_val = m_opt.min == INT_MIN ? 0: m_opt.min;
 	const int max_val = m_opt.max < 2147483647 ? m_opt.max : 2147483647;
 
 	auto temp = new wxSpinCtrl(m_parent, wxID_ANY, text_value, wxDefaultPosition, size,
@@ -558,8 +560,11 @@ boost::any& Choice::get_value()
 // 	boost::any m_value;
 	wxString ret_str = static_cast<wxComboBox*>(window)->GetValue();	
 
-	if (m_opt_id == "support")
-		return m_value = boost::any(ret_str);//ret_str;
+	// options from right panel
+	std::vector <std::string> right_panel_options{ "support", "scale_unit" };
+	for (auto rp_option: right_panel_options)
+		if (m_opt_id == rp_option)
+			return m_value = boost::any(ret_str);
 
 	if (m_opt.type != coEnum)
 		/*m_value = */get_value_by_opt_type(ret_str);
@@ -705,6 +710,69 @@ void StaticText::BUILD()
 	temp->SetToolTip(get_tooltip_text(legend));
 }
 
+void SliderCtrl::BUILD()
+{
+	auto size = wxSize(wxDefaultSize);
+	if (m_opt.height >= 0) size.SetHeight(m_opt.height);
+	if (m_opt.width >= 0) size.SetWidth(m_opt.width);
+
+	auto temp = new wxBoxSizer(wxHORIZONTAL);
+
+	auto def_val = static_cast<ConfigOptionInt*>(m_opt.default_value)->value;
+	auto min = m_opt.min == INT_MIN ? 0 : m_opt.min;
+	auto max = m_opt.max == INT_MAX ? 100 : m_opt.max;
+
+	m_slider = new wxSlider(m_parent, wxID_ANY, def_val * m_scale,
+							min * m_scale, max * m_scale,
+							wxDefaultPosition, size);
+ 	wxSize field_size(40, -1);
+
+	m_textctrl = new wxTextCtrl(m_parent, wxID_ANY, wxString::Format("%d", m_slider->GetValue()/m_scale), 
+								wxDefaultPosition, field_size);
+
+	temp->Add(m_slider, 1, wxEXPAND | wxALIGN_CENTER_VERTICAL, 0);
+	temp->Add(m_textctrl, 0, wxALIGN_CENTER_VERTICAL, 0);
+
+	m_slider->Bind(wxEVT_SLIDER, ([this](wxCommandEvent e) {
+		if (!m_disable_change_event){
+			int val = boost::any_cast<int>(get_value());
+			m_textctrl->SetLabel(wxString::Format("%d", val));
+			on_change_field();
+		}
+	}), m_slider->GetId());
+
+	m_textctrl->Bind(wxEVT_TEXT, ([this](wxCommandEvent e) {
+		std::string value = e.GetString().utf8_str().data();
+		if (is_matched(value, "^-?\\d+(\\.\\d*)?$")){
+			m_disable_change_event = true;
+			m_slider->SetValue(stoi(value)*m_scale);
+			m_disable_change_event = false;
+			on_change_field();
+		}
+	}), m_textctrl->GetId());
+
+	m_sizer = dynamic_cast<wxSizer*>(temp);
+}
+
+void SliderCtrl::set_value(const boost::any& value, bool change_event)
+{
+	m_disable_change_event = !change_event;
+
+	m_slider->SetValue(boost::any_cast<int>(value)*m_scale);
+	int val = boost::any_cast<int>(get_value());
+	m_textctrl->SetLabel(wxString::Format("%d", val));
+
+	m_disable_change_event = false;
+}
+
+boost::any& SliderCtrl::get_value()
+{
+// 	int ret_val;
+// 	x_textctrl->GetValue().ToDouble(&val);
+	return m_value = int(m_slider->GetValue()/m_scale);
+}
+
+
 } // GUI
 } // Slic3r
 
diff --git a/xs/src/slic3r/GUI/Field.hpp b/xs/src/slic3r/GUI/Field.hpp
index 41eef0303..e305f1e53 100644
--- a/xs/src/slic3r/GUI/Field.hpp
+++ b/xs/src/slic3r/GUI/Field.hpp
@@ -196,6 +196,10 @@ public:
 		return false;
 	}
 
+	void	set_side_text_ptr(wxStaticText* side_text) {
+		m_side_text = side_text;
+    }
+
 protected:
 	MyButton*			m_Undo_btn = nullptr;
 	// Bitmap and Tooltip text for m_Undo_btn. The wxButton will be updated only if the new wxBitmap pointer differs from the currently rendered one.
@@ -210,6 +214,8 @@ protected:
 	// Color for Label. The wxColour will be updated only if the new wxColour pointer differs from the currently rendered one.
 	const wxColour*		m_label_color = nullptr;
 
+	wxStaticText*		m_side_text = nullptr;
+
 	// current value
 	boost::any			m_value;
 
@@ -221,7 +227,7 @@ protected:
 inline bool is_bad_field(const t_field& obj) { return obj->getSizer() == nullptr && obj->getWindow() == nullptr; }
 
 /// Covenience function to determine whether this field is a valid window field.
-inline bool is_window_field(const t_field& obj) { return !is_bad_field(obj) && obj->getWindow() != nullptr; }
+inline bool is_window_field(const t_field& obj) { return !is_bad_field(obj) && obj->getWindow() != nullptr && obj->getSizer() == nullptr; }
 
 /// Covenience function to determine whether this field is a valid sizer field.
 inline bool is_sizer_field(const t_field& obj) { return !is_bad_field(obj) && obj->getSizer() != nullptr; }
@@ -415,11 +421,44 @@ public:
 
 	boost::any&		get_value()override { return m_value; }
 
-	void			enable() override { dynamic_cast<wxColourPickerCtrl*>(window)->Enable(); };
-	void			disable() override{ dynamic_cast<wxColourPickerCtrl*>(window)->Disable(); };
+	void			enable() override { dynamic_cast<wxStaticText*>(window)->Enable(); };
+	void			disable() override{ dynamic_cast<wxStaticText*>(window)->Disable(); };
 	wxWindow*		getWindow() override { return window; }
 };
 
+class SliderCtrl : public Field {
+	using Field::Field;
+public:
+	SliderCtrl(const ConfigOptionDef& opt, const t_config_option_key& id) : Field(opt, id) {}
+	SliderCtrl(wxWindow* parent, const ConfigOptionDef& opt, const t_config_option_key& id) : Field(parent, opt, id) {}
+	~SliderCtrl() {}
+
+	wxSizer*		m_sizer{ nullptr };
+	wxTextCtrl*		m_textctrl{ nullptr };
+	wxSlider*		m_slider{ nullptr };
+
+	int				m_scale = 10;
+
+	void			BUILD()  override;
+
+	void			set_value(const int value, bool change_event = false);
+	void			set_value(const boost::any& value, bool change_event = false);
+	boost::any&		get_value() override;
+
+	void			enable() override {
+		m_slider->Enable();
+		m_textctrl->Enable();
+		m_textctrl->SetEditable(true);
+	}
+	void			disable() override{
+		m_slider->Disable();
+		m_textctrl->Disable();
+		m_textctrl->SetEditable(false);
+	}
+	wxSizer*		getSizer() override { return m_sizer; }
+	wxWindow*		getWindow() override { return dynamic_cast<wxWindow*>(m_slider); }
+};
+
 } // GUI
 } // Slic3r
 
diff --git a/xs/src/slic3r/GUI/GLCanvas3D.cpp b/xs/src/slic3r/GUI/GLCanvas3D.cpp
index 0bb1df25d..2b548896d 100644
--- a/xs/src/slic3r/GUI/GLCanvas3D.cpp
+++ b/xs/src/slic3r/GUI/GLCanvas3D.cpp
@@ -2950,7 +2950,13 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
 
         m_mouse.set_start_position_2D_as_invalid();
 #endif
-    } 
+    }
+    else if (evt.Leaving())
+    {
+        // to remove hover when mouse goes out of this canvas
+        m_mouse.position = Pointf((coordf_t)pos.x, (coordf_t)pos.y);
+        render();
+    }
     else if (evt.Leaving())
     {
         // to remove hover on objects when the mouse goes out of this canvas
@@ -3184,6 +3190,8 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
             }
             const Vec3d& size = bb.size();
             m_on_update_geometry_info_callback.call(size(0), size(1), size(2), m_gizmos.get_scale());
+            update_scale_values(size, m_gizmos.get_scale());
+            update_rotation_value(volumes[0]->get_angle_z(), "z");
         }
 
         if ((m_gizmos.get_current_type() != Gizmos::Rotate) && (volumes.size() > 1))
@@ -3284,6 +3292,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
             case Gizmos::Scale:
             {
                 m_on_gizmo_scale_uniformly_callback.call((double)m_gizmos.get_scale());
+                Slic3r::GUI::update_settings_value();
                 break;
             }
             case Gizmos::Rotate:
diff --git a/xs/src/slic3r/GUI/GUI.cpp b/xs/src/slic3r/GUI/GUI.cpp
index 8348db9c2..ed160b421 100644
--- a/xs/src/slic3r/GUI/GUI.cpp
+++ b/xs/src/slic3r/GUI/GUI.cpp
@@ -38,6 +38,8 @@
 #include <wx/msgdlg.h>
 #include <wx/settings.h>
 #include <wx/display.h>
+#include <wx/collpane.h>
+#include <wx/wupdlock.h>
 
 #include "wxExtensions.hpp"
 
@@ -53,12 +55,15 @@
 #include "PresetBundle.hpp"
 #include "UpdateDialogs.hpp"
 #include "FirmwareDialog.hpp"
+#include "GUI_ObjectParts.hpp"
 
 #include "../Utils/PresetUpdater.hpp"
 #include "../Config/Snapshot.hpp"
 
 #include "3DScene.hpp"
 #include "libslic3r/I18N.hpp"
+#include "Model.hpp"
+#include "LambdaObjectDialog.hpp"
 
 namespace Slic3r { namespace GUI {
 
@@ -123,10 +128,26 @@ wxLocale*	g_wxLocale;
 wxFont		g_small_font;
 wxFont		g_bold_font;
 
-std::shared_ptr<ConfigOptionsGroup>	m_optgroup;
-double m_brim_width = 0.0;
+std::vector <std::shared_ptr<ConfigOptionsGroup>> m_optgroups;
+double		m_brim_width = 0.0;
+size_t		m_label_width = 100;
 wxButton*	g_wiping_dialog_button = nullptr;
 
+//showed/hided controls according to the view mode
+wxWindow	*g_right_panel = nullptr;
+wxBoxSizer	*g_frequently_changed_parameters_sizer = nullptr;
+wxBoxSizer	*g_expert_mode_part_sizer = nullptr;
+wxBoxSizer	*g_scrolled_window_sizer = nullptr;
+wxBoxSizer	*g_object_list_sizer = nullptr;
+wxButton	*g_btn_export_gcode = nullptr;
+wxButton	*g_btn_export_stl = nullptr;
+wxButton	*g_btn_reslice = nullptr;
+wxButton	*g_btn_print = nullptr;
+wxButton	*g_btn_send_gcode = nullptr;
+wxStaticBitmap	*g_manifold_warning_icon = nullptr;
+bool		g_show_print_info = false;
+bool		g_show_manifold_warning_icon = false;
+
 static void init_label_colours()
 {
 	auto luma = get_colour_approx_luma(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
@@ -206,6 +227,39 @@ void set_3DScene(_3DScene *scene)
 	g_3DScene = scene;
 }
 
+void set_objects_from_perl(	wxWindow* parent, wxBoxSizer *frequently_changed_parameters_sizer,
+							wxBoxSizer *expert_mode_part_sizer, wxBoxSizer *scrolled_window_sizer,
+							wxButton *btn_export_gcode,
+							wxButton *btn_export_stl, wxButton *btn_reslice, 
+							wxButton *btn_print, wxButton *btn_send_gcode,
+							wxStaticBitmap *manifold_warning_icon)
+{
+	g_right_panel = parent;
+	g_frequently_changed_parameters_sizer = frequently_changed_parameters_sizer;
+	g_expert_mode_part_sizer = expert_mode_part_sizer;
+	g_scrolled_window_sizer = scrolled_window_sizer;
+	g_btn_export_gcode = btn_export_gcode;
+	g_btn_export_stl = btn_export_stl;
+	g_btn_reslice = btn_reslice;
+	g_btn_print = btn_print;
+	g_btn_send_gcode = btn_send_gcode;
+	g_manifold_warning_icon = manifold_warning_icon;
+}
+
+void set_show_print_info(bool show)
+{
+	g_show_print_info = show;
+}
+
+void set_show_manifold_warning_icon(bool show)
+{
+	g_show_manifold_warning_icon = show;
+}
+
+void set_objects_list_sizer(wxBoxSizer *objects_list_sizer){
+	g_object_list_sizer = objects_list_sizer;
+}
+
 std::vector<Tab *>& get_tabs_list()
 {
 	return g_tabs_list;
@@ -332,10 +386,21 @@ enum ConfigMenuIDs {
 	ConfigMenuTakeSnapshot,
 	ConfigMenuUpdate,
 	ConfigMenuPreferences,
+	ConfigMenuModeSimple,
+	ConfigMenuModeExpert,
 	ConfigMenuLanguage,
 	ConfigMenuFlashFirmware,
 	ConfigMenuCnt,
 };
+	
+ConfigMenuIDs get_view_mode()
+{
+	if (!g_AppConfig->has("view_mode"))
+		return ConfigMenuModeSimple;
+
+	const auto mode = g_AppConfig->get("view_mode");
+	return mode == "expert" ? ConfigMenuModeExpert : ConfigMenuModeSimple;
+}
 
 static wxString dots("…", wxConvUTF8);
 
@@ -353,8 +418,15 @@ void add_config_menu(wxMenuBar *menu, int event_preferences_changed, int event_l
 // 	local_menu->Append(config_id_base + ConfigMenuUpdate, 		_(L("Check for updates")), 					_(L("Check for configuration updates")));
    	local_menu->AppendSeparator();
    	local_menu->Append(config_id_base + ConfigMenuPreferences, 	_(L("Preferences"))+dots+"\tCtrl+,", 		_(L("Application preferences")));
-   	local_menu->Append(config_id_base + ConfigMenuLanguage, 	_(L("Change Application Language")));
+	local_menu->AppendSeparator();
+	auto mode_menu = new wxMenu();
+	mode_menu->AppendRadioItem(config_id_base + ConfigMenuModeSimple,	_(L("&Simple")),					_(L("Simple View Mode")));
+	mode_menu->AppendRadioItem(config_id_base + ConfigMenuModeExpert,	_(L("&Expert")),					_(L("Expert View Mode")));
+	mode_menu->Check(config_id_base + get_view_mode(), true);
+	local_menu->AppendSubMenu(mode_menu,						_(L("&Mode")), 								_(L("Slic3r View Mode")));
    	local_menu->AppendSeparator();
+	local_menu->Append(config_id_base + ConfigMenuLanguage,		_(L("Change Application Language")));
+	local_menu->AppendSeparator();
 	local_menu->Append(config_id_base + ConfigMenuFlashFirmware, _(L("Flash printer firmware")), _(L("Upload a firmware image into an Arduino based printer")));
 	// TODO: for when we're able to flash dictionaries
 	// local_menu->Append(config_id_base + FirmwareMenuDict,  _(L("Flash language file")),    _(L("Upload a language dictionary file into a Prusa printer")));
@@ -421,6 +493,13 @@ void add_config_menu(wxMenuBar *menu, int event_preferences_changed, int event_l
 			break;
 		}
 	});
+	mode_menu->Bind(wxEVT_MENU, [config_id_base](wxEvent& event) {
+		std::string mode =	event.GetId() - config_id_base == ConfigMenuModeExpert ?
+							"expert" : "simple";
+		g_AppConfig->set("view_mode", mode);
+		g_AppConfig->save();
+		update_mode();
+	});
 	menu->Append(local_menu, _(L("&Configuration")));
 }
 
@@ -429,6 +508,26 @@ void add_menus(wxMenuBar *menu, int event_preferences_changed, int event_languag
     add_config_menu(menu, event_preferences_changed, event_language_change);
 }
 
+void open_model(wxWindow *parent, wxArrayString& input_files){
+	t_file_wild_card vec_FILE_WILDCARDS = get_file_wild_card();
+	std::vector<std::string> file_types = { "known", "stl", "obj", "amf", "3mf", "prusa" };
+	wxString MODEL_WILDCARD;
+	for (auto file_type : file_types)
+		MODEL_WILDCARD += vec_FILE_WILDCARDS.at(file_type) + "|";
+
+	auto dlg_title = _(L("Choose one or more files (STL/OBJ/AMF/3MF/PRUSA):"));
+	auto dialog = new wxFileDialog(parent /*? parent : GetTopWindow(g_wxMainFrame)*/, dlg_title, 
+		g_AppConfig->get_last_dir(), "",
+		MODEL_WILDCARD, wxFD_OPEN | wxFD_MULTIPLE | wxFD_FILE_MUST_EXIST);
+	if (dialog->ShowModal() != wxID_OK) {
+		dialog->Destroy();
+		return ;
+	}
+	
+	dialog->GetPaths(input_files);
+	dialog->Destroy();
+}
+
 // This is called when closing the application, when loading a config file or when starting the config wizard
 // to notify the user whether he is aware that some preset changes will be lost.
 bool check_unsaved_changes()
@@ -757,6 +856,22 @@ unsigned get_colour_approx_luma(const wxColour &colour)
 	));
 }
 
+wxWindow* get_right_panel(){
+	return g_right_panel;
+}
+
+wxFrame* get_main_frame() {
+	return g_wxMainFrame;
+}
+
+wxNotebook * get_tab_panel() {
+	return g_wxTabPanel;
+}
+
+const size_t& label_width(){
+	return m_label_width;
+}
+
 void create_combochecklist(wxComboCtrl* comboCtrl, std::string text, std::string items, bool initial_value)
 {
     if (comboCtrl == nullptr)
@@ -825,14 +940,37 @@ wxString from_u8(const std::string &str)
 	return wxString::FromUTF8(str.c_str());
 }
 
+void add_expert_mode_part(	wxWindow* parent, wxBoxSizer* sizer, 
+							Model &model,
+							int event_object_selection_changed,
+							int event_object_settings_changed,
+							int event_remove_object, 
+							int event_update_scene)
+{
+	set_event_object_selection_changed(event_object_selection_changed);
+	set_event_object_settings_changed(event_object_settings_changed);
+	set_event_remove_object(event_remove_object);
+	set_event_update_scene(event_update_scene);
+	set_objects_from_model(model);
+	init_mesh_icons();
+
+// 	wxWindowUpdateLocker noUpdates(parent);
+
+// 	add_objects_list(parent, sizer);
+
+// 	add_collapsible_panes(parent, sizer);
+}
 
 void add_frequently_changed_parameters(wxWindow* parent, wxBoxSizer* sizer, wxFlexGridSizer* preset_sizer)
 {
 	DynamicPrintConfig*	config = &g_PresetBundle->prints.get_edited_preset().config;
-	m_optgroup = std::make_shared<ConfigOptionsGroup>(parent, "", config);
+	std::shared_ptr<ConfigOptionsGroup> optgroup = std::make_shared<ConfigOptionsGroup>(parent, "", config);
 	const wxArrayInt& ar = preset_sizer->GetColWidths();
-	m_optgroup->label_width = ar.IsEmpty() ? 100 : ar.front()-4; // doesn't work
-	m_optgroup->m_on_change = [config](t_config_option_key opt_key, boost::any value){
+	m_label_width = ar.IsEmpty() ? 100 : ar.front()-4;
+	optgroup->label_width = m_label_width;
+
+	//Frequently changed parameters
+	optgroup->m_on_change = [config](t_config_option_key opt_key, boost::any value){
 		TabPrint* tab_print = nullptr;
 		for (size_t i = 0; i < g_wxTabPanel->GetPageCount(); ++i) {
 			Tab *tab = dynamic_cast<Tab*>(g_wxTabPanel->GetPage(i));
@@ -847,7 +985,7 @@ void add_frequently_changed_parameters(wxWindow* parent, wxBoxSizer* sizer, wxFl
 			return;
 
 		if (opt_key == "fill_density"){
-			value = m_optgroup->get_config_value(*config, opt_key);
+			value = m_optgroups[ogFrequentlyChangingParameters]->get_config_value(*config, opt_key);
 			tab_print->set_value(opt_key, value);
 			tab_print->update();
 		}
@@ -870,14 +1008,14 @@ void add_frequently_changed_parameters(wxWindow* parent, wxBoxSizer* sizer, wxFl
 			}
 			else{ //(opt_key == "support")
 				const wxString& selection = boost::any_cast<wxString>(value);
-				
+
 				auto support_material = selection == _("None") ? false : true;
 				new_conf.set_key_value("support_material", new ConfigOptionBool(support_material));
 
 				if (selection == _("Everywhere"))
 					new_conf.set_key_value("support_material_buildplate_only", new ConfigOptionBool(false));
 				else if (selection == _("Support on build plate only"))
-					new_conf.set_key_value("support_material_buildplate_only", new ConfigOptionBool(true));				
+					new_conf.set_key_value("support_material_buildplate_only", new ConfigOptionBool(true));
 			}
 			tab_print->load_config(new_conf);
 		}
@@ -885,10 +1023,10 @@ void add_frequently_changed_parameters(wxWindow* parent, wxBoxSizer* sizer, wxFl
 		tab_print->update_dirty();
 	};
 
-	Option option = m_optgroup->get_option("fill_density");
+	Option option = optgroup->get_option("fill_density");
 	option.opt.sidetext = "";
 	option.opt.full_width = true;
-	m_optgroup->append_single_option_line(option);
+	optgroup->append_single_option_line(option);
 
 	ConfigOptionDef def;
 
@@ -907,7 +1045,7 @@ void add_frequently_changed_parameters(wxWindow* parent, wxBoxSizer* sizer, wxFl
 	def.default_value = new ConfigOptionStrings { selection };
 	option = Option(def, "support");
 	option.opt.full_width = true;
-	m_optgroup->append_single_option_line(option);
+	optgroup->append_single_option_line(option);
 
 	m_brim_width = config->opt_float("brim_width");
 	def.label = L("Brim");
@@ -916,7 +1054,7 @@ void add_frequently_changed_parameters(wxWindow* parent, wxBoxSizer* sizer, wxFl
 	def.gui_type = "";
 	def.default_value = new ConfigOptionBool{ m_brim_width > 0.0 ? true : false };
 	option = Option(def, "brim");
-	m_optgroup->append_single_option_line(option);
+	optgroup->append_single_option_line(option);
 
 
     Line line = { "", "" };
@@ -942,16 +1080,93 @@ void add_frequently_changed_parameters(wxWindow* parent, wxBoxSizer* sizer, wxFl
 			}));
 			return sizer;
 		};
-		m_optgroup->append_line(line);
+		optgroup->append_line(line);
 
+	sizer->Add(optgroup->sizer, 0, wxEXPAND | wxBOTTOM, 2);
 
+	m_optgroups.push_back(optgroup);// ogFrequentlyChangingParameters
 
-	sizer->Add(m_optgroup->sizer, 1, wxEXPAND | wxBOTTOM, 2);
+	// Object List
+	add_objects_list(parent, sizer);
+
+	// Frequently Object Settings
+	add_object_settings(parent, sizer);
 }
 
-ConfigOptionsGroup* get_optgroup()
+void show_frequently_changed_parameters(bool show)
 {
-	return m_optgroup.get();
+	g_frequently_changed_parameters_sizer->Show(show);
+	if (!show) return;
+
+	for (size_t i = 0; i < g_wxTabPanel->GetPageCount(); ++i) {
+		Tab *tab = dynamic_cast<Tab*>(g_wxTabPanel->GetPage(i));
+		if (!tab)
+			continue;
+		tab->update_wiping_button_visibility();
+		break;
+	}
+}
+
+void show_buttons(bool show)
+{
+	g_btn_export_stl->Show(show);
+	g_btn_reslice->Show(show);
+	for (size_t i = 0; i < g_wxTabPanel->GetPageCount(); ++i) {
+		TabPrinter *tab = dynamic_cast<TabPrinter*>(g_wxTabPanel->GetPage(i));
+		if (!tab)
+			continue;
+		g_btn_print->Show(show && !tab->m_config->opt_string("serial_port").empty());
+		g_btn_send_gcode->Show(show && !tab->m_config->opt_string("octoprint_host").empty());
+		break;
+	}
+}
+
+void show_info_sizer(bool show)
+{
+	g_scrolled_window_sizer->Show(static_cast<size_t>(0), show); 
+	g_scrolled_window_sizer->Show(1, show && g_show_print_info);
+	g_manifold_warning_icon->Show(show && g_show_manifold_warning_icon);
+}
+
+void update_mode()
+{
+	wxWindowUpdateLocker noUpdates(g_right_panel);
+
+	// TODO There is a not the best place of it!
+	//*** Update style of the "Export G-code" button****
+	if (g_btn_export_gcode->GetFont() != bold_font()){
+		g_btn_export_gcode->SetBackgroundColour(wxColour(252, 77, 1));
+		g_btn_export_gcode->SetFont(bold_font());
+	}
+	// ***********************************
+
+	ConfigMenuIDs mode = get_view_mode();
+
+// 	show_frequently_changed_parameters(mode >= ConfigMenuModeRegular);
+// 	g_expert_mode_part_sizer->Show(mode == ConfigMenuModeExpert);
+	g_object_list_sizer->Show(mode == ConfigMenuModeExpert);
+	show_info_sizer(mode == ConfigMenuModeExpert);
+	show_buttons(mode == ConfigMenuModeExpert);
+
+	// TODO There is a not the best place of it!
+	// *** Update showing of the collpane_settings
+// 	show_collpane_settings(mode == ConfigMenuModeExpert);
+	// *************************
+	g_right_panel->GetParent()->Layout();
+	g_right_panel->Layout();
+}
+
+bool is_expert_mode(){
+	return get_view_mode() == ConfigMenuModeExpert;
+}
+
+ConfigOptionsGroup* get_optgroup(size_t i)
+{
+	return m_optgroups[i].get();
+}
+
+std::vector <std::shared_ptr<ConfigOptionsGroup>>& get_optgroups() {
+	return m_optgroups;
 }
 
 wxButton* get_wiping_dialog_button()
diff --git a/xs/src/slic3r/GUI/GUI.hpp b/xs/src/slic3r/GUI/GUI.hpp
index 990711323..69e83eaab 100644
--- a/xs/src/slic3r/GUI/GUI.hpp
+++ b/xs/src/slic3r/GUI/GUI.hpp
@@ -5,6 +5,7 @@
 #include <vector>
 #include "PrintConfig.hpp"
 #include "../../libslic3r/Utils.hpp"
+#include "GUI_ObjectParts.hpp"
 
 #include <wx/intl.h>
 #include <wx/string.h>
@@ -12,7 +13,6 @@
 class wxApp;
 class wxWindow;
 class wxFrame;
-class wxFont;
 class wxMenuBar;
 class wxNotebook;
 class wxComboCtrl;
@@ -24,6 +24,8 @@ class wxBoxSizer;
 class wxFlexGridSizer;
 class wxButton;
 class wxFileDialog;
+class wxStaticBitmap;
+class wxFont;
 
 namespace Slic3r { 
 
@@ -67,15 +69,15 @@ typedef std::map<std::string, std::string> t_file_wild_card;
 inline t_file_wild_card& get_file_wild_card() {
 	static t_file_wild_card FILE_WILDCARDS;
 	if (FILE_WILDCARDS.empty()){
-		FILE_WILDCARDS["known"] = "Known files (*.stl, *.obj, *.amf, *.xml, *.prusa)|*.stl;*.STL;*.obj;*.OBJ;*.amf;*.AMF;*.xml;*.XML;*.prusa;*.PRUSA";
-		FILE_WILDCARDS["stl"] = "STL files (*.stl)|*.stl;*.STL";
-		FILE_WILDCARDS["obj"] = "OBJ files (*.obj)|*.obj;*.OBJ";
-        FILE_WILDCARDS["amf"] = "AMF files (*.amf)|*.zip.amf;*.amf;*.AMF;*.xml;*.XML";
-        FILE_WILDCARDS["3mf"] = "3MF files (*.3mf)|*.3mf;*.3MF;";
-        FILE_WILDCARDS["prusa"] = "Prusa Control files (*.prusa)|*.prusa;*.PRUSA";
-		FILE_WILDCARDS["ini"] = "INI files *.ini|*.ini;*.INI";
+		FILE_WILDCARDS["known"]	= "Known files (*.stl, *.obj, *.amf, *.xml, *.prusa)|*.stl;*.STL;*.obj;*.OBJ;*.amf;*.AMF;*.xml;*.XML;*.prusa;*.PRUSA";
+		FILE_WILDCARDS["stl"]	= "STL files (*.stl)|*.stl;*.STL";
+		FILE_WILDCARDS["obj"]	= "OBJ files (*.obj)|*.obj;*.OBJ";
+        FILE_WILDCARDS["amf"]	= "AMF files (*.amf)|*.zip.amf;*.amf;*.AMF;*.xml;*.XML";
+        FILE_WILDCARDS["3mf"]	= "3MF files (*.3mf)|*.3mf;*.3MF;";
+        FILE_WILDCARDS["prusa"]	= "Prusa Control files (*.prusa)|*.prusa;*.PRUSA";
+		FILE_WILDCARDS["ini"]	= "INI files *.ini|*.ini;*.INI";
 		FILE_WILDCARDS["gcode"] = "G-code files (*.gcode, *.gco, *.g, *.ngc)|*.gcode;*.GCODE;*.gco;*.GCO;*.g;*.G;*.ngc;*.NGC";
-		FILE_WILDCARDS["svg"] = "SVG files *.svg|*.svg;*.SVG";
+		FILE_WILDCARDS["svg"]	= "SVG files *.svg|*.svg;*.SVG";
 	}
 	return FILE_WILDCARDS;
 }
@@ -100,11 +102,26 @@ void set_app_config(AppConfig *app_config);
 void set_preset_bundle(PresetBundle *preset_bundle);
 void set_preset_updater(PresetUpdater *updater);
 void set_3DScene(_3DScene *scene);
+void set_objects_from_perl(	wxWindow* parent,
+							wxBoxSizer *frequently_changed_parameters_sizer,
+							wxBoxSizer *expert_mode_part_sizer,
+							wxBoxSizer *scrolled_window_sizer,
+							wxButton *btn_export_gcode,
+							wxButton *btn_export_stl,
+							wxButton *btn_reslice,
+							wxButton *btn_print,
+							wxButton *btn_send_gcode,
+							wxStaticBitmap *manifold_warning_icon);
+void set_show_print_info(bool show);
+void set_show_manifold_warning_icon(bool show);
+void set_objects_list_sizer(wxBoxSizer *objects_list_sizer);
 
-AppConfig*	get_app_config();
-wxApp*		get_app();
-PresetBundle* get_preset_bundle();
-wxNotebook* get_tab_panel();
+AppConfig*		get_app_config();
+wxApp*			get_app();
+PresetBundle*	get_preset_bundle();
+wxFrame*		get_main_frame();
+wxNotebook *	get_tab_panel();
+wxNotebook*		get_tab_panel();
 
 const wxColour& get_label_clr_modified();
 const wxColour& get_label_clr_sys();
@@ -116,6 +133,11 @@ void set_label_clr_sys(const wxColour& clr);
 const wxFont& small_font();
 const wxFont& bold_font();
 
+void open_model(wxWindow *parent, wxArrayString& input_files);
+
+wxWindow*			get_right_panel();
+const size_t&		label_width();
+
 Tab*         get_tab(const std::string& name);
 const std::vector<PresetTab>& get_preset_tabs();
 
@@ -161,6 +183,8 @@ void save_language();
 void get_installed_languages(wxArrayString & names, wxArrayLong & identifiers);
 // select language from the list of installed languages
 bool select_language(wxArrayString & names, wxArrayLong & identifiers);
+// update right panel of the Plater according to view mode
+void update_mode();
 
 std::vector<Tab *>& get_tabs_list();
 bool checked_tab(Tab* tab);
@@ -180,13 +204,22 @@ wxString	L_str(const std::string &str);
 // Return wxString from std::string in UTF8
 wxString	from_u8(const std::string &str);
 
-
+void add_expert_mode_part(	wxWindow* parent, wxBoxSizer* sizer, 
+							Model &model,
+							int event_object_selection_changed,
+							int event_object_settings_changed,
+							int event_remove_object, 
+							int event_update_scene);
 void add_frequently_changed_parameters(wxWindow* parent, wxBoxSizer* sizer, wxFlexGridSizer* preset_sizer);
+// Update view mode according to selected menu 
+void update_mode();
+bool is_expert_mode();
 
 // Callback to trigger a configuration update timer on the Plater.
 static PerlCallback g_on_request_update_callback;
  
-ConfigOptionsGroup* get_optgroup();
+ConfigOptionsGroup* get_optgroup(size_t i); 
+std::vector <std::shared_ptr<ConfigOptionsGroup>>& get_optgroups();
 wxButton*			get_wiping_dialog_button();
 
 void add_export_option(wxFileDialog* dlg, const std::string& format);
diff --git a/xs/src/slic3r/GUI/GUI_ObjectParts.cpp b/xs/src/slic3r/GUI/GUI_ObjectParts.cpp
new file mode 100644
index 000000000..e9d08ede5
--- /dev/null
+++ b/xs/src/slic3r/GUI/GUI_ObjectParts.cpp
@@ -0,0 +1,1639 @@
+#include "GUI.hpp"
+#include "OptionsGroup.hpp"
+#include "PresetBundle.hpp"
+#include "GUI_ObjectParts.hpp"
+#include "Model.hpp"
+#include "wxExtensions.hpp"
+#include "LambdaObjectDialog.hpp"
+#include "../../libslic3r/Utils.hpp"
+
+#include <wx/msgdlg.h>
+#include <boost/filesystem.hpp>
+#include <boost/algorithm/string.hpp>
+#include "Geometry.hpp"
+#include "slic3r/Utils/FixModelByWin10.hpp"
+
+namespace Slic3r
+{
+namespace GUI
+{
+wxSizer		*m_sizer_object_buttons = nullptr;
+wxSizer		*m_sizer_part_buttons = nullptr;
+wxSizer		*m_sizer_object_movers = nullptr;
+wxDataViewCtrl				*m_objects_ctrl = nullptr;
+PrusaObjectDataViewModel	*m_objects_model = nullptr;
+wxCollapsiblePane			*m_collpane_settings = nullptr;
+
+wxIcon		m_icon_modifiermesh;
+wxIcon		m_icon_solidmesh;
+wxIcon		m_icon_manifold_warning;
+wxBitmap	m_bmp_cog;
+wxBitmap	m_bmp_split;
+
+wxSlider*	m_mover_x = nullptr;
+wxSlider*	m_mover_y = nullptr;
+wxSlider*	m_mover_z = nullptr;
+wxButton*	m_btn_move_up = nullptr;
+wxButton*	m_btn_move_down = nullptr;
+Point3		m_move_options;
+Point3		m_last_coords;
+int			m_selected_object_id = -1;
+
+bool		g_prevent_list_events = false;		// We use this flag to avoid circular event handling Select() 
+												// happens to fire a wxEVT_LIST_ITEM_SELECTED on OSX, whose event handler 
+												// calls this method again and again and again
+bool        g_is_percent_scale = false;         // It indicates if scale unit is percentage
+int         g_rotation_x = 0;                   // Last value of the rotation around the X axis
+int         g_rotation_y = 0;                   // Last value of the rotation around the Y axis
+ModelObjectPtrs*			m_objects;
+std::shared_ptr<DynamicPrintConfig*> m_config;
+std::shared_ptr<DynamicPrintConfig> m_default_config;
+wxBoxSizer*					m_option_sizer = nullptr;
+
+// option groups for settings
+std::vector <std::shared_ptr<ConfigOptionsGroup>> m_og_settings;
+
+int			m_event_object_selection_changed = 0;
+int			m_event_object_settings_changed = 0;
+int			m_event_remove_object = 0;
+int			m_event_update_scene = 0;
+
+bool m_parts_changed = false;
+bool m_part_settings_changed = false;
+
+#ifdef __WXOSX__
+    wxString g_selected_extruder = "";
+#endif //__WXOSX__
+
+// typedef std::map<std::string, std::string> t_category_icon;
+typedef std::map<std::string, wxBitmap> t_category_icon;
+inline t_category_icon& get_category_icon() {
+	static t_category_icon CATEGORY_ICON;
+	if (CATEGORY_ICON.empty()){
+		CATEGORY_ICON[L("Layers and Perimeters")]	= wxBitmap(from_u8(Slic3r::var("layers.png")), wxBITMAP_TYPE_PNG);
+		CATEGORY_ICON[L("Infill")]					= wxBitmap(from_u8(Slic3r::var("infill.png")), wxBITMAP_TYPE_PNG);
+		CATEGORY_ICON[L("Support material")]		= wxBitmap(from_u8(Slic3r::var("building.png")), wxBITMAP_TYPE_PNG);
+		CATEGORY_ICON[L("Speed")]					= wxBitmap(from_u8(Slic3r::var("time.png")), wxBITMAP_TYPE_PNG);
+		CATEGORY_ICON[L("Extruders")]				= wxBitmap(from_u8(Slic3r::var("funnel.png")), wxBITMAP_TYPE_PNG);
+		CATEGORY_ICON[L("Extrusion Width")]			= wxBitmap(from_u8(Slic3r::var("funnel.png")), wxBITMAP_TYPE_PNG);
+// 		CATEGORY_ICON[L("Skirt and brim")]			= wxBitmap(from_u8(Slic3r::var("box.png")), wxBITMAP_TYPE_PNG);
+// 		CATEGORY_ICON[L("Speed > Acceleration")]	= wxBitmap(from_u8(Slic3r::var("time.png")), wxBITMAP_TYPE_PNG);
+		CATEGORY_ICON[L("Advanced")]				= wxBitmap(from_u8(Slic3r::var("wand.png")), wxBITMAP_TYPE_PNG);
+	}
+	return CATEGORY_ICON;
+}
+
+std::vector<std::string> get_options(const bool is_part)
+{
+	PrintRegionConfig reg_config;
+	auto options = reg_config.keys();
+	if (!is_part) {
+		PrintObjectConfig obj_config;
+		std::vector<std::string> obj_options = obj_config.keys();
+		options.insert(options.end(), obj_options.begin(), obj_options.end());
+	}
+	return options;
+}
+
+//				  category ->		vector 			 ( option	;  label )
+typedef std::map< std::string, std::vector< std::pair<std::string, std::string> > > settings_menu_hierarchy;
+void get_options_menu(settings_menu_hierarchy& settings_menu, bool is_part)
+{
+	auto options = get_options(is_part);
+
+    auto extruders_cnt = get_preset_bundle()->printers.get_edited_preset().config.option<ConfigOptionFloats>("nozzle_diameter")->values.size();
+
+	DynamicPrintConfig config;
+	for (auto& option : options)
+	{
+		auto const opt = config.def()->get(option);
+		auto category = opt->category;
+        if (category.empty() ||
+            (category == "Extruders" && extruders_cnt == 1)) continue;
+
+		std::pair<std::string, std::string> option_label(option, opt->label);
+		std::vector< std::pair<std::string, std::string> > new_category;
+		auto& cat_opt_label = settings_menu.find(category) == settings_menu.end() ? new_category : settings_menu.at(category);
+		cat_opt_label.push_back(option_label);
+		if (cat_opt_label.size() == 1)
+			settings_menu[category] = cat_opt_label;
+	}
+}
+
+void set_event_object_selection_changed(const int& event){
+	m_event_object_selection_changed = event;
+}
+void set_event_object_settings_changed(const int& event){
+	m_event_object_settings_changed = event;
+}
+void set_event_remove_object(const int& event){
+	m_event_remove_object = event;
+}
+void set_event_update_scene(const int& event){
+	m_event_update_scene = event;
+}
+
+void set_objects_from_model(Model &model) {
+	m_objects = &(model.objects);
+}
+
+void init_mesh_icons(){
+	m_icon_modifiermesh = wxIcon(Slic3r::GUI::from_u8(Slic3r::var("lambda.png")), wxBITMAP_TYPE_PNG);//(Slic3r::var("plugin.png")), wxBITMAP_TYPE_PNG);
+	m_icon_solidmesh = wxIcon(Slic3r::GUI::from_u8(Slic3r::var("object.png")), wxBITMAP_TYPE_PNG);//(Slic3r::var("package.png")), wxBITMAP_TYPE_PNG);
+
+	// init icon for manifold warning
+	m_icon_manifold_warning = wxIcon(Slic3r::GUI::from_u8(Slic3r::var("exclamation_mark_.png")), wxBITMAP_TYPE_PNG);//(Slic3r::var("error.png")), wxBITMAP_TYPE_PNG);
+
+	// init bitmap for "Split to sub-objects" context menu
+    m_bmp_split = wxBitmap(Slic3r::GUI::from_u8(Slic3r::var("split.png")), wxBITMAP_TYPE_PNG);
+
+	// init bitmap for "Add Settings" context menu
+	m_bmp_cog = wxBitmap(Slic3r::GUI::from_u8(Slic3r::var("cog.png")), wxBITMAP_TYPE_PNG);
+}
+
+bool is_parts_changed(){return m_parts_changed;}
+bool is_part_settings_changed(){ return m_part_settings_changed; }
+
+static wxString dots("…", wxConvUTF8);
+
+void set_tooltip_for_item(const wxPoint& pt)
+{
+    wxDataViewItem item;
+    wxDataViewColumn* col;
+    m_objects_ctrl->HitTest(pt, item, col);
+    if (!item) return;
+
+    if (col->GetTitle() == " ")
+        m_objects_ctrl->GetMainWindow()->SetToolTip(_(L("Right button click the icon to change the object settings")));
+    else if (col->GetTitle() == _("Name") &&
+        m_objects_model->GetIcon(item).GetRefData() == m_icon_manifold_warning.GetRefData()) {
+        int obj_idx = m_objects_model->GetIdByItem(item);
+        auto& stats = (*m_objects)[obj_idx]->volumes[0]->mesh.stl.stats;
+        int errors = stats.degenerate_facets + stats.edges_fixed + stats.facets_removed +
+            stats.facets_added + stats.facets_reversed + stats.backwards_edges;
+
+        wxString tooltip = wxString::Format(_(L("Auto-repaired (%d errors):\n")), errors);
+
+        std::map<std::string, int> error_msg;
+        error_msg[L("degenerate facets")] = stats.degenerate_facets;
+        error_msg[L("edges fixed")] = stats.edges_fixed;
+        error_msg[L("facets removed")] = stats.facets_removed;
+        error_msg[L("facets added")] = stats.facets_added;
+        error_msg[L("facets reversed")] = stats.facets_reversed;
+        error_msg[L("backwards edges")] = stats.backwards_edges;
+
+        for (auto error : error_msg)
+        {
+            if (error.second > 0)
+                tooltip += wxString::Format(_("\t%d %s\n"), error.second, error.first);
+        }
+// OR
+//             tooltip += wxString::Format(_(L("%d degenerate facets, %d edges fixed, %d facets removed, "
+//                                             "%d facets added, %d facets reversed, %d backwards edges")),
+//                                             stats.degenerate_facets, stats.edges_fixed, stats.facets_removed,
+//                                             stats.facets_added, stats.facets_reversed, stats.backwards_edges);
+
+        if (is_windows10())
+            tooltip += _(L("Right button click the icon to fix STL through Netfabb"));
+
+        m_objects_ctrl->GetMainWindow()->SetToolTip(tooltip);
+    }
+    else
+        m_objects_ctrl->GetMainWindow()->SetToolTip(""); // hide tooltip
+}
+
+wxPoint get_mouse_position_in_control() {
+    const wxPoint& pt = wxGetMousePosition();
+    wxWindow* win = m_objects_ctrl->GetMainWindow();
+    return wxPoint(pt.x - win->GetScreenPosition().x, 
+                   pt.y - win->GetScreenPosition().y);
+}
+
+bool is_mouse_position_in_control(wxPoint& pt) {
+    pt = get_mouse_position_in_control();
+    const wxSize& cz = m_objects_ctrl->GetSize();
+    if (pt.x > 0 && pt.x < cz.x &&
+        pt.y > 0 && pt.y < cz.y)
+        return true;
+    return false;
+}
+
+wxDataViewColumn* object_ctrl_create_extruder_column(int extruders_count)
+{
+    wxArrayString choices;
+    choices.Add("default");
+    for (int i = 1; i <= extruders_count; ++i)
+        choices.Add(wxString::Format("%d", i));
+    wxDataViewChoiceRenderer *c =
+        new wxDataViewChoiceRenderer(choices, wxDATAVIEW_CELL_EDITABLE, wxALIGN_CENTER_HORIZONTAL);
+    wxDataViewColumn* column = new wxDataViewColumn(_(L("Extruder")), c, 3, 60, wxALIGN_CENTER_HORIZONTAL, wxDATAVIEW_COL_RESIZABLE);
+    return column;
+}
+
+void create_objects_ctrl(wxWindow* win, wxBoxSizer*& objects_sz)
+{
+	m_objects_ctrl = new wxDataViewCtrl(win, wxID_ANY, wxDefaultPosition, wxDefaultSize);
+	m_objects_ctrl->SetInitialSize(wxSize(-1, 150)); // TODO - Set correct height according to the opened/closed objects
+
+	objects_sz = new wxBoxSizer(wxVERTICAL);
+	objects_sz->Add(m_objects_ctrl, 1, wxGROW | wxLEFT, 20);
+
+	m_objects_model = new PrusaObjectDataViewModel;
+	m_objects_ctrl->AssociateModel(m_objects_model);
+#if wxUSE_DRAG_AND_DROP && wxUSE_UNICODE
+	m_objects_ctrl->EnableDragSource(wxDF_UNICODETEXT);
+	m_objects_ctrl->EnableDropTarget(wxDF_UNICODETEXT);
+#endif // wxUSE_DRAG_AND_DROP && wxUSE_UNICODE
+
+	// column 0(Icon+Text) of the view control:
+	m_objects_ctrl->AppendIconTextColumn(_(L("Name")), 0, wxDATAVIEW_CELL_INERT, 120,
+		wxALIGN_LEFT, wxDATAVIEW_COL_RESIZABLE);
+
+	// column 1 of the view control:
+	m_objects_ctrl->AppendTextColumn(_(L("Copy")), 1, wxDATAVIEW_CELL_INERT, 45,
+		wxALIGN_CENTER_HORIZONTAL, wxDATAVIEW_COL_RESIZABLE);
+
+	// column 2 of the view control:
+	m_objects_ctrl->AppendTextColumn(_(L("Scale")), 2, wxDATAVIEW_CELL_INERT, 55,
+		wxALIGN_CENTER_HORIZONTAL, wxDATAVIEW_COL_RESIZABLE);
+
+	// column 3 of the view control:
+    m_objects_ctrl->AppendColumn(object_ctrl_create_extruder_column(4));
+
+	// column 4 of the view control:
+	m_objects_ctrl->AppendBitmapColumn(" ", 4, wxDATAVIEW_CELL_INERT, 25,
+		wxALIGN_CENTER_HORIZONTAL, wxDATAVIEW_COL_RESIZABLE);
+}
+
+// ****** from GUI.cpp
+wxBoxSizer* create_objects_list(wxWindow *win)
+{
+    wxBoxSizer* objects_sz;
+    // create control
+    create_objects_ctrl(win, objects_sz);
+
+    // describe control behavior 
+    m_objects_ctrl->Bind(wxEVT_DATAVIEW_SELECTION_CHANGED, [](wxEvent& event) {
+		object_ctrl_selection_changed();
+#ifndef __WXMSW__
+        set_tooltip_for_item(get_mouse_position_in_control());
+#endif //__WXMSW__        
+	});
+
+    m_objects_ctrl->Bind(wxEVT_DATAVIEW_ITEM_CONTEXT_MENU, [](wxDataViewEvent& event) {
+        object_ctrl_context_menu();
+		event.Skip();
+	});
+
+    m_objects_ctrl->Bind(wxEVT_CHAR, [](wxKeyEvent& event) { object_ctrl_key_event(event); }); // doesn't work on OSX
+
+#ifdef __WXMSW__
+    // Extruder value changed
+	m_objects_ctrl->Bind(wxEVT_CHOICE, [](wxCommandEvent& event) { update_extruder_in_config(event.GetString()); });
+
+    m_objects_ctrl->GetMainWindow()->Bind(wxEVT_MOTION, [](wxMouseEvent& event) {
+         set_tooltip_for_item(event.GetPosition());
+         event.Skip();
+    });
+#else
+    // equivalent to wxEVT_CHOICE on __WXMSW__
+    m_objects_ctrl->Bind(wxEVT_DATAVIEW_ITEM_VALUE_CHANGED, [](wxDataViewEvent& event) { object_ctrl_item_value_change(event); });
+#endif //__WXMSW__
+
+    m_objects_ctrl->Bind(wxEVT_DATAVIEW_ITEM_BEGIN_DRAG,    [](wxDataViewEvent& e) {on_begin_drag(e);});
+    m_objects_ctrl->Bind(wxEVT_DATAVIEW_ITEM_DROP_POSSIBLE, [](wxDataViewEvent& e) {on_drop_possible(e); });
+    m_objects_ctrl->Bind(wxEVT_DATAVIEW_ITEM_DROP,          [](wxDataViewEvent& e) {on_drop(e);});
+	return objects_sz;
+}
+
+wxBoxSizer* create_edit_object_buttons(wxWindow* win)
+{
+	auto sizer = new wxBoxSizer(wxVERTICAL);
+
+	auto btn_load_part = new wxButton(win, wxID_ANY, /*Load */"part" + dots, wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT | wxNO_BORDER/*wxBU_LEFT*/);
+	auto btn_load_modifier = new wxButton(win, wxID_ANY, /*Load */"modifier" + dots, wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT | wxNO_BORDER/*wxBU_LEFT*/);
+	auto btn_load_lambda_modifier = new wxButton(win, wxID_ANY, /*Load */"generic" + dots, wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT | wxNO_BORDER/*wxBU_LEFT*/);
+	auto btn_delete = new wxButton(win, wxID_ANY, "Delete"/*" part"*/, wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT | wxNO_BORDER/*wxBU_LEFT*/);
+	auto btn_split = new wxButton(win, wxID_ANY, "Split"/*" part"*/, wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT | wxNO_BORDER/*wxBU_LEFT*/);
+	m_btn_move_up = new wxButton(win, wxID_ANY, "", wxDefaultPosition, wxDefaultSize/*wxSize(30, -1)*/, wxBU_LEFT);
+	m_btn_move_down = new wxButton(win, wxID_ANY, "", wxDefaultPosition, wxDefaultSize/*wxSize(30, -1)*/, wxBU_LEFT);
+
+	//*** button's functions
+	btn_load_part->Bind(wxEVT_BUTTON, [win](wxEvent&) {
+		on_btn_load(win);
+	});
+
+	btn_load_modifier->Bind(wxEVT_BUTTON, [win](wxEvent&) {
+		on_btn_load(win, true);
+	});
+
+	btn_load_lambda_modifier->Bind(wxEVT_BUTTON, [win](wxEvent&) {
+		on_btn_load(win, true, true);
+	});
+
+	btn_delete		->Bind(wxEVT_BUTTON, [](wxEvent&) { on_btn_del(); });
+	btn_split		->Bind(wxEVT_BUTTON, [](wxEvent&) { on_btn_split(true); });
+	m_btn_move_up	->Bind(wxEVT_BUTTON, [](wxEvent&) { on_btn_move_up(); });
+	m_btn_move_down	->Bind(wxEVT_BUTTON, [](wxEvent&) { on_btn_move_down(); });
+	//***
+
+	m_btn_move_up->SetMinSize(wxSize(20, -1));
+	m_btn_move_down->SetMinSize(wxSize(20, -1));
+	btn_load_part->SetBitmap(wxBitmap(from_u8(Slic3r::var("brick_add.png")), wxBITMAP_TYPE_PNG));
+	btn_load_modifier->SetBitmap(wxBitmap(from_u8(Slic3r::var("brick_add.png")), wxBITMAP_TYPE_PNG));
+	btn_load_lambda_modifier->SetBitmap(wxBitmap(from_u8(Slic3r::var("brick_add.png")), wxBITMAP_TYPE_PNG));
+	btn_delete->SetBitmap(wxBitmap(from_u8(Slic3r::var("brick_delete.png")), wxBITMAP_TYPE_PNG));
+	btn_split->SetBitmap(wxBitmap(from_u8(Slic3r::var("shape_ungroup.png")), wxBITMAP_TYPE_PNG));
+	m_btn_move_up->SetBitmap(wxBitmap(from_u8(Slic3r::var("bullet_arrow_up.png")), wxBITMAP_TYPE_PNG));
+	m_btn_move_down->SetBitmap(wxBitmap(from_u8(Slic3r::var("bullet_arrow_down.png")), wxBITMAP_TYPE_PNG));
+
+	m_sizer_object_buttons = new wxGridSizer(1, 3, 0, 0);
+	m_sizer_object_buttons->Add(btn_load_part, 0, wxEXPAND);
+	m_sizer_object_buttons->Add(btn_load_modifier, 0, wxEXPAND);
+	m_sizer_object_buttons->Add(btn_load_lambda_modifier, 0, wxEXPAND);
+	m_sizer_object_buttons->Show(false);
+
+	m_sizer_part_buttons = new wxGridSizer(1, 3, 0, 0);
+	m_sizer_part_buttons->Add(btn_delete, 0, wxEXPAND);
+	m_sizer_part_buttons->Add(btn_split, 0, wxEXPAND);
+	{
+		auto up_down_sizer = new wxGridSizer(1, 2, 0, 0);
+		up_down_sizer->Add(m_btn_move_up, 1, wxEXPAND);
+		up_down_sizer->Add(m_btn_move_down, 1, wxEXPAND);
+		m_sizer_part_buttons->Add(up_down_sizer, 0, wxEXPAND);
+	}
+	m_sizer_part_buttons->Show(false);
+
+	btn_load_part->SetFont(Slic3r::GUI::small_font());
+	btn_load_modifier->SetFont(Slic3r::GUI::small_font());
+	btn_load_lambda_modifier->SetFont(Slic3r::GUI::small_font());
+	btn_delete->SetFont(Slic3r::GUI::small_font());
+	btn_split->SetFont(Slic3r::GUI::small_font());
+	m_btn_move_up->SetFont(Slic3r::GUI::small_font());
+	m_btn_move_down->SetFont(Slic3r::GUI::small_font());
+
+	sizer->Add(m_sizer_object_buttons, 0, wxEXPAND | wxLEFT, 20);
+	sizer->Add(m_sizer_part_buttons, 0, wxEXPAND | wxLEFT, 20);
+	return sizer;
+}
+
+void update_after_moving()
+{
+	auto item = m_objects_ctrl->GetSelection();
+	if (!item || m_selected_object_id<0)
+		return;
+
+	auto volume_id = m_objects_model->GetVolumeIdByItem(item);
+	if (volume_id < 0)
+		return;
+
+	Point3 m = m_move_options;
+	Point3 l = m_last_coords;
+
+	auto d = Pointf3(m.x - l.x, m.y - l.y, m.z - l.z);
+	auto volume = (*m_objects)[m_selected_object_id]->volumes[volume_id];
+	volume->mesh.translate(d.x,d.y,d.z);
+	m_last_coords = m;
+
+	m_parts_changed = true;
+	parts_changed(m_selected_object_id);
+}
+
+wxSizer* object_movers(wxWindow *win)
+{
+// 	DynamicPrintConfig* config = &get_preset_bundle()->/*full_config();//*/printers.get_edited_preset().config; // TODO get config from Model_volume
+	std::shared_ptr<ConfigOptionsGroup> optgroup = std::make_shared<ConfigOptionsGroup>(win, "Move"/*, config*/);
+	optgroup->label_width = 20;
+	optgroup->m_on_change = [](t_config_option_key opt_key, boost::any value){
+		int val = boost::any_cast<int>(value);
+		bool update = false;
+		if (opt_key == "x" && m_move_options.x != val){
+			update = true;
+			m_move_options.x = val;
+		}
+		else if (opt_key == "y" && m_move_options.y != val){
+			update = true;
+			m_move_options.y = val;
+		}
+		else if (opt_key == "z" && m_move_options.z != val){
+			update = true;
+			m_move_options.z = val;
+		}
+		if (update) update_after_moving();
+	};
+
+	ConfigOptionDef def;
+	def.label = L("X");
+	def.type = coInt;
+	def.gui_type = "slider";
+	def.default_value = new ConfigOptionInt(0);
+
+	Option option = Option(def, "x");
+	option.opt.full_width = true;
+	optgroup->append_single_option_line(option);
+	m_mover_x = dynamic_cast<wxSlider*>(optgroup->get_field("x")->getWindow());
+
+	def.label = L("Y");
+	option = Option(def, "y");
+	optgroup->append_single_option_line(option);
+	m_mover_y = dynamic_cast<wxSlider*>(optgroup->get_field("y")->getWindow());
+
+	def.label = L("Z");
+	option = Option(def, "z");
+	optgroup->append_single_option_line(option);
+	m_mover_z = dynamic_cast<wxSlider*>(optgroup->get_field("z")->getWindow());
+
+	get_optgroups().push_back(optgroup);  // ogObjectMovers
+
+	m_sizer_object_movers = optgroup->sizer;
+	m_sizer_object_movers->Show(false);
+
+	m_move_options = Point3(0, 0, 0);
+	m_last_coords = Point3(0, 0, 0);
+
+	return optgroup->sizer;
+}
+
+wxBoxSizer* content_settings(wxWindow *win)
+{
+	DynamicPrintConfig* config = &get_preset_bundle()->/*full_config();//*/printers.get_edited_preset().config; // TODO get config from Model_volume
+	std::shared_ptr<ConfigOptionsGroup> optgroup = std::make_shared<ConfigOptionsGroup>(win, "Extruders", config);
+	optgroup->label_width = label_width();
+
+	Option option = optgroup->get_option("extruder");
+	option.opt.default_value = new ConfigOptionInt(1);
+	optgroup->append_single_option_line(option);
+
+	get_optgroups().push_back(optgroup);  // ogObjectSettings
+
+	auto sizer = new wxBoxSizer(wxVERTICAL);
+	sizer->Add(create_edit_object_buttons(win), 0, wxEXPAND, 0); // *** Edit Object Buttons***
+
+	sizer->Add(optgroup->sizer, 1, wxEXPAND | wxLEFT, 20);
+
+	auto add_btn = new wxButton(win, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT | wxNO_BORDER);
+	if (wxMSW) add_btn->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
+	add_btn->SetBitmap(wxBitmap(from_u8(Slic3r::var("add.png")), wxBITMAP_TYPE_PNG));
+	sizer->Add(add_btn, 0, wxALIGN_LEFT | wxLEFT, 20);
+
+	sizer->Add(object_movers(win), 0, wxEXPAND | wxLEFT, 20);
+
+	return sizer;
+}
+
+void add_objects_list(wxWindow* parent, wxBoxSizer* sizer)
+{
+	const auto ol_sizer = create_objects_list(parent);
+	sizer->Add(ol_sizer, 1, wxEXPAND | wxTOP, 20);
+	set_objects_list_sizer(ol_sizer);
+}
+
+Line add_og_to_object_settings(const std::string& option_name, const std::string& sidetext, int def_value = 0)
+{
+	Line line = { _(option_name), "" };
+
+	ConfigOptionDef def;
+	def.type = coInt;
+	def.default_value = new ConfigOptionInt(def_value);
+	def.sidetext = sidetext;
+	def.width = 70;
+
+    if (option_name == "Rotation")
+        def.min = -360;
+
+	const std::string lower_name = boost::algorithm::to_lower_copy(option_name);
+
+	std::vector<std::string> axes{ "x", "y", "z" };
+	for (auto axis : axes) {
+		def.label = boost::algorithm::to_upper_copy(axis);
+		Option option = Option(def, lower_name + "_" + axis);
+		option.opt.full_width = true;
+		line.append_option(option);
+	}
+
+	if (option_name == "Scale")
+	{
+		def.label = L("Units");
+		def.type = coStrings;
+		def.gui_type = "select_open";
+		def.enum_labels.push_back(L("%"));
+		def.enum_labels.push_back(L("mm"));
+		def.default_value = new ConfigOptionStrings{ "%" };
+		def.sidetext = " ";
+
+		Option option = Option(def, lower_name + "_unit");
+		line.append_option(option);
+	}
+
+	return line;
+}
+
+void add_object_settings(wxWindow* parent, wxBoxSizer* sizer)
+{
+	auto optgroup = std::make_shared<ConfigOptionsGroup>(parent, _(L("Object Settings")));
+	optgroup->label_width = 100;
+	optgroup->set_grid_vgap(5);
+
+	optgroup->m_on_change = [](t_config_option_key opt_key, boost::any value){
+		if (opt_key == "scale_unit"){
+			const wxString& selection = boost::any_cast<wxString>(value);
+			std::vector<std::string> axes{ "x", "y", "z" };
+			for (auto axis : axes) {
+				std::string key = "scale_" + axis;
+				get_optgroup(ogFrequentlyObjectSettings)->set_side_text(key, selection);
+			}
+
+            g_is_percent_scale = selection == _("%");
+            update_scale_values();
+		}
+	};
+
+// 	def.label = L("Name");
+// 	def.type = coString;
+// 	def.tooltip = L("Object name");
+// 	def.full_width = true;
+// 	def.default_value = new ConfigOptionString{ "BlaBla_object.stl" };
+// 	optgroup->append_single_option_line(Option(def, "object_name"));
+
+	ConfigOptionDef def;
+
+	def.label = L("Name");
+// 	def.type = coString;
+    def.gui_type = "legend";
+	def.tooltip = L("Object name");
+	def.full_width = true;
+	def.default_value = new ConfigOptionString{ " " };
+	optgroup->append_single_option_line(Option(def, "object_name"));
+
+	optgroup->set_flag(ogSIDE_OPTIONS_VERTICAL);
+	optgroup->sidetext_width = 25;
+
+	optgroup->append_line(add_og_to_object_settings(L("Position"), L("mm")));
+	optgroup->append_line(add_og_to_object_settings(L("Rotation"), "°"));
+	optgroup->append_line(add_og_to_object_settings(L("Scale"), "%"));
+
+	optgroup->set_flag(ogDEFAULT);
+
+	def.label = L("Place on bed");
+	def.type = coBool;
+	def.tooltip = L("Automatic placing of models on printing bed in Y axis");
+	def.gui_type = "";
+	def.sidetext = "";
+	def.default_value = new ConfigOptionBool{ false };
+	optgroup->append_single_option_line(Option(def, "place_on_bed"));
+
+	m_option_sizer = new wxBoxSizer(wxVERTICAL);
+	optgroup->sizer->Add(m_option_sizer, 1, wxEXPAND | wxLEFT, 5);
+
+	sizer->Add(optgroup->sizer, 0, wxEXPAND | wxLEFT | wxTOP, 20);
+
+	optgroup->disable();
+
+	get_optgroups().push_back(optgroup);  // ogFrequentlyObjectSettings
+
+// 	add_current_settings();
+}
+
+
+// add Collapsible Pane to sizer
+wxCollapsiblePane* add_collapsible_pane(wxWindow* parent, wxBoxSizer* sizer_parent, const wxString& name, std::function<wxSizer *(wxWindow *)> content_function)
+{
+#ifdef __WXMSW__
+	auto *collpane = new PrusaCollapsiblePaneMSW(parent, wxID_ANY, name);
+#else
+	auto *collpane = new PrusaCollapsiblePane/*wxCollapsiblePane*/(parent, wxID_ANY, name);
+#endif // __WXMSW__
+	// add the pane with a zero proportion value to the sizer which contains it
+	sizer_parent->Add(collpane, 0, wxGROW | wxALL, 0);
+
+	wxWindow *win = collpane->GetPane();
+
+	wxSizer *sizer = content_function(win);
+
+	wxSizer *sizer_pane = new wxBoxSizer(wxVERTICAL);
+	sizer_pane->Add(sizer, 1, wxGROW | wxEXPAND | wxBOTTOM, 2);
+	win->SetSizer(sizer_pane);
+	// 	sizer_pane->SetSizeHints(win);
+	return collpane;
+}
+
+void add_collapsible_panes(wxWindow* parent, wxBoxSizer* sizer)
+{
+	// *** Objects List ***	
+	auto collpane = add_collapsible_pane(parent, sizer, "Objects List:", create_objects_list);
+	collpane->Bind(wxEVT_COLLAPSIBLEPANE_CHANGED, ([collpane](wxCommandEvent& e){
+		// 		wxWindowUpdateLocker noUpdates(g_right_panel);
+		if (collpane->IsCollapsed()) {
+			m_sizer_object_buttons->Show(false);
+			m_sizer_part_buttons->Show(false);
+			m_sizer_object_movers->Show(false);
+			if (!m_objects_ctrl->HasSelection())
+				m_collpane_settings->Show(false);
+		}
+	}));
+
+	// *** Object/Part Settings ***
+	m_collpane_settings = add_collapsible_pane(parent, sizer, "Object Settings", content_settings);
+}
+
+void show_collpane_settings(bool expert_mode)
+{
+	m_collpane_settings->Show(expert_mode && !m_objects_model->IsEmpty());
+}
+
+void add_object_to_list(const std::string &name, ModelObject* model_object)
+{
+	wxString item_name = name;
+	int scale = model_object->instances[0]->scaling_factor * 100;
+	auto item = m_objects_model->Add(item_name, model_object->instances.size(), scale);
+	m_objects_ctrl->Select(item);
+
+	// Add error icon if detected auto-repaire
+	auto stats = model_object->volumes[0]->mesh.stl.stats;
+	int errors =	stats.degenerate_facets + stats.edges_fixed + stats.facets_removed + 
+					stats.facets_added + stats.facets_reversed + stats.backwards_edges;
+	if (errors > 0)		{
+		const wxDataViewIconText data(item_name, m_icon_manifold_warning);
+		wxVariant variant;
+		variant << data;
+		m_objects_model->SetValue(variant, item, 0);
+	}
+
+    if (model_object->volumes.size() > 1) {
+        for (auto id = 0; id < model_object->volumes.size(); id++)
+            m_objects_model->AddChild(item, 
+                                      model_object->volumes[id]->name, 
+                                      m_icon_solidmesh, 
+                                      model_object->volumes[id]->config.option<ConfigOptionInt>("extruder")->value,
+                                      false);
+        m_objects_ctrl->Expand(item);
+    }
+
+#ifndef __WXOSX__ 
+	object_ctrl_selection_changed();
+#endif //__WXMSW__
+}
+
+void delete_object_from_list()
+{
+	auto item = m_objects_ctrl->GetSelection();
+	if (!item || m_objects_model->GetParent(item) != wxDataViewItem(0))
+		return;
+// 	m_objects_ctrl->Select(m_objects_model->Delete(item));
+	m_objects_model->Delete(item);
+
+// 	if (m_objects_model->IsEmpty())
+// 		m_collpane_settings->Show(false);
+}
+
+void delete_all_objects_from_list()
+{
+	m_objects_model->DeleteAll();
+// 	m_collpane_settings->Show(false);
+}
+
+void set_object_count(int idx, int count)
+{
+	m_objects_model->SetValue(wxString::Format("%d", count), idx, 1);
+	m_objects_ctrl->Refresh();
+}
+
+void set_object_scale(int idx, int scale)
+{
+	m_objects_model->SetValue(wxString::Format("%d%%", scale), idx, 2);
+	m_objects_ctrl->Refresh();
+}
+
+void unselect_objects()
+{
+    if (!m_objects_ctrl->GetSelection())
+        return;
+
+    g_prevent_list_events = true;
+    m_objects_ctrl->UnselectAll();
+    part_selection_changed();
+    g_prevent_list_events = false;
+}
+
+void select_current_object(int idx)
+{
+	g_prevent_list_events = true;
+	m_objects_ctrl->UnselectAll();
+	if (idx < 0) {
+		g_prevent_list_events = false;
+		return;
+	}
+	m_objects_ctrl->Select(m_objects_model->GetItemById(idx));
+	part_selection_changed();
+	g_prevent_list_events = false;
+}
+
+void remove()
+{
+	auto item = m_objects_ctrl->GetSelection();
+	if (!item)
+		return;
+	
+	if (m_objects_model->GetParent(item) == wxDataViewItem(0)) {
+		if (m_event_remove_object > 0) {
+			wxCommandEvent event(m_event_remove_object);
+			get_main_frame()->ProcessWindowEvent(event);
+		}
+// 		delete_object_from_list();
+	}
+	else
+		on_btn_del();
+}
+
+void object_ctrl_selection_changed()
+{
+	if (g_prevent_list_events) return;
+
+	part_selection_changed();
+
+	if (m_event_object_selection_changed > 0) {
+		wxCommandEvent event(m_event_object_selection_changed);
+		event.SetInt(int(m_objects_model->GetParent(m_objects_ctrl->GetSelection()) != wxDataViewItem(0)));
+		event.SetId(m_selected_object_id);
+		get_main_frame()->ProcessWindowEvent(event);
+	}
+
+#ifdef __WXOSX__
+    update_extruder_in_config(g_selected_extruder);
+#endif //__WXOSX__        
+}
+
+void object_ctrl_context_menu()
+{
+    wxDataViewItem item;
+    wxDataViewColumn* col;
+    m_objects_ctrl->HitTest(get_mouse_position_in_control(), item, col);
+    wxString title = col->GetTitle();
+    if (!item) return;
+
+    if (title == " ")
+        show_context_menu();
+// ys_FIXME
+//         else if (title == _("Name") && pt.x >15 &&
+//                     m_objects_model->GetIcon(item).GetRefData() == m_icon_manifold_warning.GetRefData())
+//         {
+//             if (is_windows10())
+//                 fix_through_netfabb();
+//         }
+#ifndef __WXMSW__
+    m_objects_ctrl->GetMainWindow()->SetToolTip(""); // hide tooltip
+#endif //__WXMSW__
+}
+
+void object_ctrl_key_event(wxKeyEvent& event)
+{
+    if (event.GetKeyCode() == WXK_TAB)
+        m_objects_ctrl->Navigate(event.ShiftDown() ? wxNavigationKeyEvent::IsBackward : wxNavigationKeyEvent::IsForward);
+    else if (event.GetKeyCode() == WXK_DELETE
+#ifdef __WXOSX__
+        || event.GetKeyCode() == WXK_BACK
+#endif //__WXOSX__
+        ){
+        printf("WXK_BACK\n");
+        remove();
+    }
+    else
+        event.Skip();
+}
+
+void object_ctrl_item_value_change(wxDataViewEvent& event)
+{
+    if (event.GetColumn() == 3)
+    {
+        wxVariant variant;
+        m_objects_model->GetValue(variant, event.GetItem(), 3);
+#ifdef __WXOSX__
+        g_selected_extruder = variant.GetString();
+#else // --> for Linux
+        update_extruder_in_config(variant.GetString());
+#endif //__WXOSX__  
+    }
+}
+
+//update_optgroup
+void update_settings_list()
+{
+#ifdef __WXGTK__
+    auto parent = get_optgroup(ogFrequentlyObjectSettings)->get_parent();
+#else
+    auto parent = get_optgroup(ogFrequentlyObjectSettings)->parent();
+#endif /* __WXGTK__ */
+    
+// There is a bug related to Ubuntu overlay scrollbars, see https://github.com/prusa3d/Slic3r/issues/898 and https://github.com/prusa3d/Slic3r/issues/952.
+// The issue apparently manifests when Show()ing a window with overlay scrollbars while the UI is frozen. For this reason,
+// we will Thaw the UI prematurely on Linux. This means destroing the no_updates object prematurely.
+#ifdef __linux__
+	std::unique_ptr<wxWindowUpdateLocker> no_updates(new wxWindowUpdateLocker(parent));
+#else
+	wxWindowUpdateLocker noUpdates(parent);
+#endif
+
+	m_option_sizer->Clear(true);
+
+	if (m_config) 
+	{
+        auto extra_column = [](wxWindow* parent, const Line& line)
+		{
+			auto opt_key = (line.get_options())[0].opt_id;  //we assume that we have one option per line
+
+			auto btn = new wxBitmapButton(parent, wxID_ANY, wxBitmap(Slic3r::GUI::from_u8(Slic3r::var("erase.png")), wxBITMAP_TYPE_PNG),
+				wxDefaultPosition, wxDefaultSize, wxBORDER_NONE);
+			btn->Bind(wxEVT_BUTTON, [opt_key](wxEvent &event){
+				(*m_config)->erase(opt_key);
+				wxTheApp->CallAfter([]() { update_settings_list(); });
+			});
+			return btn;
+		};
+
+		std::map<std::string, std::vector<std::string>> cat_options;
+		auto opt_keys = (*m_config)->keys();
+		if (opt_keys.size() == 1 && opt_keys[0] == "extruder")
+			return;
+
+        auto extruders_cnt = get_preset_bundle()->printers.get_edited_preset().config.option<ConfigOptionFloats>("nozzle_diameter")->values.size();
+
+		for (auto& opt_key : opt_keys) {
+			auto category = (*m_config)->def()->get(opt_key)->category;
+			if (category.empty() ||
+                (category == "Extruders" && extruders_cnt==1)) continue;
+
+			std::vector< std::string > new_category;
+
+			auto& cat_opt = cat_options.find(category) == cat_options.end() ? new_category : cat_options.at(category);
+			cat_opt.push_back(opt_key);
+			if (cat_opt.size() == 1)
+				cat_options[category] = cat_opt;
+		}
+
+
+		m_og_settings.resize(0);
+		for (auto& cat : cat_options) {
+			if (cat.second.size() == 1 && cat.second[0] == "extruder")
+				continue;
+
+			auto optgroup = std::make_shared<ConfigOptionsGroup>(parent, cat.first, *m_config, false, ogDEFAULT, extra_column);
+			optgroup->label_width = 100;
+			optgroup->sidetext_width = 70;
+
+			for (auto& opt : cat.second)
+			{
+				if (opt == "extruder")
+					continue;
+				Option option = optgroup->get_option(opt);
+				option.opt.width = 70;
+				optgroup->append_single_option_line(option);
+			}
+			optgroup->reload_config();
+			m_option_sizer->Add(optgroup->sizer, 0, wxEXPAND | wxALL, 0);
+			m_og_settings.push_back(optgroup);
+		}
+	}
+
+#ifdef __linux__
+	no_updates.reset(nullptr);
+#endif
+
+    get_right_panel()->Layout();
+	get_right_panel()->GetParent()->Layout();
+}
+
+void get_settings_choice(wxMenu *menu, int id, bool is_part)
+{
+	auto category_name = menu->GetLabel(id);
+
+	wxArrayString names;
+	wxArrayInt selections;
+
+	settings_menu_hierarchy settings_menu;
+	get_options_menu(settings_menu, is_part);
+	std::vector< std::pair<std::string, std::string> > *settings_list = nullptr;
+
+	auto opt_keys = (*m_config)->keys();
+
+	for (auto& cat : settings_menu)
+	{
+		if (_(cat.first) == category_name) {
+			int sel = 0;
+			for (auto& pair : cat.second) {
+				names.Add(_(pair.second));
+				if (find(opt_keys.begin(), opt_keys.end(), pair.first) != opt_keys.end())
+					selections.Add(sel);
+				sel++;
+			}
+			settings_list = &cat.second;
+			break;
+		}
+	} 
+
+	if (!settings_list)
+		return;
+
+	if (wxGetMultipleChoices(selections, _(L("Select showing settings")), category_name, names) ==0 )
+		return;
+
+	std::vector <std::string> selected_options;
+	for (auto sel : selections)
+		selected_options.push_back((*settings_list)[sel].first);
+
+	for (auto& setting:(*settings_list) )
+	{
+		auto& opt_key = setting.first;
+		if (find(opt_keys.begin(), opt_keys.end(), opt_key) != opt_keys.end() &&
+			find(selected_options.begin(), selected_options.end(), opt_key) == selected_options.end())
+			(*m_config)->erase(opt_key);
+		
+		if(find(opt_keys.begin(), opt_keys.end(), opt_key) == opt_keys.end() &&
+				find(selected_options.begin(), selected_options.end(), opt_key) != selected_options.end())
+			(*m_config)->set_key_value(opt_key, m_default_config.get()->option(opt_key)->clone());
+	}
+
+	update_settings_list();
+}
+
+bool cur_item_hase_children()
+{
+    wxDataViewItemArray children;
+    if (m_objects_model->GetChildren(m_objects_ctrl->GetSelection(), children) > 0)
+        return true;
+    return false;
+}
+
+wxMenuItem* menu_item_split(wxMenu* menu, int id) {
+    auto menu_item = new wxMenuItem(menu, id, _(L("Split to parts")));
+    menu_item->SetBitmap(m_bmp_split);
+    return menu_item;
+}
+
+wxMenuItem* menu_item_settings(wxMenu* menu, int id) {
+    auto  menu_item = new wxMenuItem(menu, id, _(L("Add settings")));
+    menu_item->SetBitmap(m_bmp_cog);
+
+    auto sub_menu = create_add_settings_popupmenu(false);
+    menu_item->SetSubMenu(sub_menu);
+    return menu_item;
+}
+
+wxMenu *create_add_part_popupmenu()
+{
+	wxMenu *menu = new wxMenu;
+	std::vector<std::string> menu_items = { L("Add part"), L("Add modifier"), L("Add generic") };
+
+	wxWindowID config_id_base = wxWindow::NewControlId(menu_items.size()+2);
+
+	int i = 0;
+	for (auto& item : menu_items) {
+		auto menu_item = new wxMenuItem(menu, config_id_base + i, _(item));
+		menu_item->SetBitmap(i == 0 ? m_icon_solidmesh : m_icon_modifiermesh);
+		menu->Append(menu_item);
+		i++;
+    }
+
+    menu->AppendSeparator();
+    auto menu_item = menu_item_split(menu, config_id_base + i);
+    menu->Append(menu_item);
+    menu_item->Enable(!cur_item_hase_children());
+
+    menu->AppendSeparator();
+    // Append settings popupmenu
+    menu->Append(menu_item_settings(menu, config_id_base + i + 1));
+
+	wxWindow* win = get_tab_panel()->GetPage(0);
+
+	menu->Bind(wxEVT_MENU, [config_id_base, win, menu](wxEvent &event){
+		switch (event.GetId() - config_id_base) {
+		case 0:
+			on_btn_load(win);
+			break;
+		case 1:
+			on_btn_load(win, true);
+			break;
+		case 2:
+			on_btn_load(win, true, true);
+			break;
+		case 3:
+			on_btn_split(false);
+			break;
+		default:{
+			get_settings_choice(menu, event.GetId(), false);
+			break;}
+		}
+	});
+
+	return menu;
+}
+
+wxMenu *create_part_settings_popupmenu()
+{
+    wxMenu *menu = new wxMenu;
+    wxWindowID config_id_base = wxWindow::NewControlId(2);
+
+    menu->Append(menu_item_split(menu, config_id_base));
+
+    menu->AppendSeparator();
+    // Append settings popupmenu
+    menu->Append(menu_item_settings(menu, config_id_base + 1));
+
+    menu->Bind(wxEVT_MENU, [config_id_base, menu](wxEvent &event){
+        switch (event.GetId() - config_id_base) {
+        case 0:
+            on_btn_split(true);
+            break;
+        default:{
+            get_settings_choice(menu, event.GetId(), true);
+            break; }
+        }
+    });
+
+    return menu;
+}
+
+wxMenu *create_add_settings_popupmenu(bool is_part)
+{
+	wxMenu *menu = new wxMenu;
+
+ 	auto categories = get_category_icon();
+
+	settings_menu_hierarchy settings_menu;
+	get_options_menu(settings_menu, is_part);
+
+	for (auto cat : settings_menu)
+	{
+		auto menu_item = new wxMenuItem(menu, wxID_ANY, _(cat.first));
+		menu_item->SetBitmap(categories.find(cat.first) == categories.end() ? 
+								wxNullBitmap : categories.at(cat.first));
+		menu->Append(menu_item);
+	}
+
+	menu->Bind(wxEVT_MENU, [menu](wxEvent &event) {
+		get_settings_choice(menu, event.GetId(), true);
+	});
+
+	return menu;
+}
+
+void show_context_menu()
+{
+    auto item = m_objects_ctrl->GetSelection();
+    if (item)
+    {
+        if (m_objects_model->GetParent(item) == wxDataViewItem(0))				{
+            auto menu = create_add_part_popupmenu();
+            get_tab_panel()->GetPage(0)->PopupMenu(menu);
+        }
+        else {
+            auto menu = create_part_settings_popupmenu();
+            get_tab_panel()->GetPage(0)->PopupMenu(menu);
+        }
+    }
+}
+
+// ******
+
+void load_part(	wxWindow* parent, ModelObject* model_object, 
+				wxArrayString& part_names, const bool is_modifier)
+{
+	wxArrayString input_files;
+	open_model(parent, input_files);
+	for (int i = 0; i < input_files.size(); ++i) {
+		std::string input_file = input_files.Item(i).ToStdString();
+
+		Model model;
+		try {
+			model = Model::read_from_file(input_file);
+		}
+		catch (std::exception &e) {
+			auto msg = _(L("Error! ")) + input_file + " : " + e.what() + ".";
+			show_error(parent, msg);
+			exit(1);
+		}
+
+		for ( auto object : model.objects) {
+			for (auto volume : object->volumes) {
+				auto new_volume = model_object->add_volume(*volume);
+				new_volume->modifier = is_modifier;
+				boost::filesystem::path(input_file).filename().string();
+				new_volume->name = boost::filesystem::path(input_file).filename().string();
+
+				part_names.Add(new_volume->name);
+
+				// apply the same translation we applied to the object
+				new_volume->mesh.translate( model_object->origin_translation.x,
+											model_object->origin_translation.y, 
+											model_object->origin_translation.y );
+				// set a default extruder value, since user can't add it manually
+				new_volume->config.set_key_value("extruder", new ConfigOptionInt(0));
+
+				m_parts_changed = true;
+			}
+		}
+	}
+}
+
+void load_lambda(	wxWindow* parent, ModelObject* model_object,
+					wxArrayString& part_names, const bool is_modifier)
+{
+	auto dlg = new LambdaObjectDialog(parent);
+	if (dlg->ShowModal() == wxID_CANCEL) {
+		return;
+	}
+
+	std::string name = "lambda-";
+	TriangleMesh mesh;
+
+	auto params = dlg->ObjectParameters();
+	switch (params.type)
+	{
+	case LambdaTypeBox:{
+		mesh = make_cube(params.dim[0], params.dim[1], params.dim[2]);
+		name += "Box";
+		break;}
+	case LambdaTypeCylinder:{
+		mesh = make_cylinder(params.cyl_r, params.cyl_h);
+		name += "Cylinder";
+		break;}
+	case LambdaTypeSphere:{
+		mesh = make_sphere(params.sph_rho);
+		name += "Sphere";
+		break;}
+	case LambdaTypeSlab:{
+		const auto& size = model_object->bounding_box().size();
+		mesh = make_cube(size.x*1.5, size.y*1.5, params.slab_h);
+		// box sets the base coordinate at 0, 0, move to center of plate and move it up to initial_z
+		mesh.translate(-size.x*1.5 / 2.0, -size.y*1.5 / 2.0, params.slab_z);
+		name += "Slab";
+		break; }
+	default:
+		break;
+	}
+	mesh.repair();
+
+	auto new_volume = model_object->add_volume(mesh);
+	new_volume->modifier = is_modifier;
+	new_volume->name = name;
+	// set a default extruder value, since user can't add it manually
+	new_volume->config.set_key_value("extruder", new ConfigOptionInt(0));
+
+	part_names.Add(name);
+
+	m_parts_changed = true;
+}
+
+void on_btn_load(wxWindow* parent, bool is_modifier /*= false*/, bool is_lambda/* = false*/)
+{
+	auto item = m_objects_ctrl->GetSelection();
+	if (!item)
+		return;
+	int obj_idx = -1;
+	if (m_objects_model->GetParent(item) == wxDataViewItem(0))
+		obj_idx = m_objects_model->GetIdByItem(item);
+	else
+		return;
+
+	if (obj_idx < 0) return;
+	wxArrayString part_names;
+	if (is_lambda)
+		load_lambda(parent, (*m_objects)[obj_idx], part_names, is_modifier);
+	else
+		load_part(parent, (*m_objects)[obj_idx], part_names, is_modifier);
+
+	parts_changed(obj_idx);
+
+	for (int i = 0; i < part_names.size(); ++i)
+		m_objects_ctrl->Select(	m_objects_model->AddChild(item, part_names.Item(i), 
+								is_modifier ? m_icon_modifiermesh : m_icon_solidmesh));
+// 	part_selection_changed();
+#ifdef __WXMSW__
+	object_ctrl_selection_changed();
+#endif //__WXMSW__
+}
+
+void on_btn_del()
+{
+	auto item = m_objects_ctrl->GetSelection();
+	if (!item) return;
+
+	auto volume_id = m_objects_model->GetVolumeIdByItem(item);
+	if (volume_id < 0)
+		return;
+	auto volume = (*m_objects)[m_selected_object_id]->volumes[volume_id];
+
+	// if user is deleting the last solid part, throw error
+	int solid_cnt = 0;
+	for (auto vol : (*m_objects)[m_selected_object_id]->volumes)
+		if (!vol->modifier)
+			++solid_cnt;
+	if (!volume->modifier && solid_cnt == 1) {
+		Slic3r::GUI::show_error(nullptr, _(L("You can't delete the last solid part from this object.")));
+		return;
+	}
+
+	(*m_objects)[m_selected_object_id]->delete_volume(volume_id);
+	m_parts_changed = true;
+
+	parts_changed(m_selected_object_id);
+
+	m_objects_ctrl->Select(m_objects_model->Delete(item));
+	part_selection_changed();
+// #ifdef __WXMSW__
+// 	object_ctrl_selection_changed();
+// #endif //__WXMSW__
+}
+
+void on_btn_split(const bool split_part)
+{
+	auto item = m_objects_ctrl->GetSelection();
+	if (!item || m_selected_object_id<0)
+		return;
+	auto volume_id = m_objects_model->GetVolumeIdByItem(item);
+    ModelVolume* volume;
+    if (volume_id < 0) {
+        if (split_part) return;
+        else
+            volume = (*m_objects)[m_selected_object_id]->volumes[0]; }
+    else
+	    volume = (*m_objects)[m_selected_object_id]->volumes[volume_id];
+ 	DynamicPrintConfig&	config = get_preset_bundle()->printers.get_edited_preset().config;
+    auto nozzle_dmrs_cnt = config.option<ConfigOptionFloats>("nozzle_diameter")->values.size();
+    auto split_rez = volume->split(nozzle_dmrs_cnt);
+    if (split_rez == 1) {
+        wxMessageBox(_(L("The selected object couldn't be split because it contains only one part.")));
+        return;
+    }
+
+    auto model_object = (*m_objects)[m_selected_object_id];
+
+    if (split_part) {
+        auto parent = m_objects_model->GetParent(item);
+        m_objects_model->DeleteChildren(parent);
+
+        for (auto id = 0; id < model_object->volumes.size(); id++)
+            m_objects_model->AddChild(parent, model_object->volumes[id]->name,
+                                      model_object->volumes[id]->modifier ? m_icon_modifiermesh : m_icon_solidmesh,
+                                      model_object->volumes[id]->config.option<ConfigOptionInt>("extruder")->value, 
+                                      false);
+
+        m_objects_ctrl->Expand(parent);
+    }
+    else {
+        for (auto id = 0; id < model_object->volumes.size(); id++)
+            m_objects_model->AddChild(item, model_object->volumes[id]->name, 
+                                      m_icon_solidmesh,
+                                      model_object->volumes[id]->config.option<ConfigOptionInt>("extruder")->value, 
+                                      false);
+        m_objects_ctrl->Expand(item);
+    }
+}
+
+void on_btn_move_up(){
+	auto item = m_objects_ctrl->GetSelection();
+	if (!item)
+		return;
+	auto volume_id = m_objects_model->GetVolumeIdByItem(item);
+	if (volume_id < 0)
+		return;
+	auto& volumes = (*m_objects)[m_selected_object_id]->volumes;
+	if (0 < volume_id && volume_id < volumes.size()) {
+		std::swap(volumes[volume_id - 1], volumes[volume_id]);
+		m_parts_changed = true;
+		m_objects_ctrl->Select(m_objects_model->MoveChildUp(item));
+		part_selection_changed();
+// #ifdef __WXMSW__
+// 		object_ctrl_selection_changed();
+// #endif //__WXMSW__
+	}
+}
+
+void on_btn_move_down(){
+	auto item = m_objects_ctrl->GetSelection();
+	if (!item)
+		return;
+	auto volume_id = m_objects_model->GetVolumeIdByItem(item);
+	if (volume_id < 0)
+		return;
+	auto& volumes = (*m_objects)[m_selected_object_id]->volumes;
+	if (0 <= volume_id && volume_id+1 < volumes.size()) {
+		std::swap(volumes[volume_id + 1], volumes[volume_id]);
+		m_parts_changed = true;
+		m_objects_ctrl->Select(m_objects_model->MoveChildDown(item));
+		part_selection_changed();
+// #ifdef __WXMSW__
+// 		object_ctrl_selection_changed();
+// #endif //__WXMSW__
+	}
+}
+
+void parts_changed(int obj_idx)
+{ 
+	if (m_event_object_settings_changed <= 0) return;
+
+	wxCommandEvent e(m_event_object_settings_changed);
+	auto event_str = wxString::Format("%d %d %d", obj_idx,
+		is_parts_changed() ? 1 : 0,
+		is_part_settings_changed() ? 1 : 0);
+	e.SetString(event_str);
+	get_main_frame()->ProcessWindowEvent(e);
+}
+	
+void update_settings_value()
+{
+	auto og = get_optgroup(ogFrequentlyObjectSettings);
+	if (m_selected_object_id < 0 || m_objects->size() <= m_selected_object_id) {
+		og->set_value("scale_x", 0);
+		og->set_value("scale_y", 0);
+		og->set_value("scale_z", 0);
+        og->disable();
+		return;
+	}
+    g_is_percent_scale = boost::any_cast<wxString>(og->get_value("scale_unit")) == _("%");
+    update_scale_values();
+    update_rotation_values();
+    og->enable();
+}
+
+void part_selection_changed()
+{
+	auto item = m_objects_ctrl->GetSelection();
+	int obj_idx = -1;
+	auto og = get_optgroup(ogFrequentlyObjectSettings);
+	if (item)
+	{
+		bool is_part = false;
+		if (m_objects_model->GetParent(item) == wxDataViewItem(0)) {
+			obj_idx = m_objects_model->GetIdByItem(item);
+			og->set_name(" " + _(L("Object Settings")) + " ");
+			m_config = std::make_shared<DynamicPrintConfig*>(&(*m_objects)[obj_idx]->config);
+		}
+		else {
+			auto parent = m_objects_model->GetParent(item);
+			// Take ID of the parent object to "inform" perl-side which object have to be selected on the scene
+			obj_idx = m_objects_model->GetIdByItem(parent);
+			og->set_name(" " + _(L("Part Settings")) + " ");
+			is_part = true;
+			auto volume_id = m_objects_model->GetVolumeIdByItem(item);
+			m_config = std::make_shared<DynamicPrintConfig*>(&(*m_objects)[obj_idx]->volumes[volume_id]->config);
+		}
+
+		auto config = m_config;
+        og->set_value("object_name", m_objects_model->GetName(item));
+		m_default_config = std::make_shared<DynamicPrintConfig>(*DynamicPrintConfig::new_from_defaults_keys(get_options(is_part)));
+	}
+    else {
+        wxString empty_str = wxEmptyString;
+        og->set_value("object_name", empty_str);
+        m_config = nullptr;
+    }
+
+	update_settings_list();
+
+	m_selected_object_id = obj_idx;
+
+	update_settings_value();
+
+/*	wxWindowUpdateLocker noUpdates(get_right_panel());
+
+	m_move_options = Point3(0, 0, 0);
+	m_last_coords = Point3(0, 0, 0);
+	// reset move sliders
+	std::vector<std::string> opt_keys = {"x", "y", "z"};
+	auto og = get_optgroup(ogObjectMovers);
+	for (auto opt_key: opt_keys)
+		og->set_value(opt_key, int(0));
+
+// 	if (!item || m_selected_object_id < 0){
+	if (m_selected_object_id < 0){
+		m_sizer_object_buttons->Show(false);
+		m_sizer_part_buttons->Show(false);
+		m_sizer_object_movers->Show(false);
+		m_collpane_settings->Show(false);
+		return;
+	}
+
+	m_collpane_settings->Show(true);
+
+	auto volume_id = m_objects_model->GetVolumeIdByItem(item);
+	if (volume_id < 0){
+		m_sizer_object_buttons->Show(true);
+		m_sizer_part_buttons->Show(false);
+		m_sizer_object_movers->Show(false);
+		m_collpane_settings->SetLabelText(_(L("Object Settings")) + ":");
+
+// 		elsif($itemData->{type} eq 'object') {
+// 			# select nothing in 3D preview
+// 
+// 			# attach object config to settings panel
+// 			$self->{optgroup_movers}->disable;
+// 			$self->{staticbox}->SetLabel('Object Settings');
+// 			@opt_keys = (map @{$_->get_keys}, Slic3r::Config::PrintObject->new, Slic3r::Config::PrintRegion->new);
+// 			$config = $self->{model_object}->config;
+// 		}
+
+		return;
+	}
+
+	m_collpane_settings->SetLabelText(_(L("Part Settings")) + ":");
+	
+	m_sizer_object_buttons->Show(false);
+	m_sizer_part_buttons->Show(true);
+	m_sizer_object_movers->Show(true);
+
+	auto bb_size = m_objects[m_selected_object_id]->bounding_box().size();
+	int scale = 10; //??
+
+	m_mover_x->SetMin(-bb_size.x * 4 * scale);
+	m_mover_x->SetMax(bb_size.x * 4 * scale);
+
+	m_mover_y->SetMin(-bb_size.y * 4 * scale);
+	m_mover_y->SetMax(bb_size.y * 4 * scale);
+
+	m_mover_z->SetMin(-bb_size.z * 4 * scale);
+	m_mover_z->SetMax(bb_size.z * 4 * scale);
+
+
+	
+//	my ($config, @opt_keys);
+	m_btn_move_up->Enable(volume_id > 0);
+	m_btn_move_down->Enable(volume_id + 1 < m_objects[m_selected_object_id]->volumes.size());
+
+	// attach volume config to settings panel
+	auto volume = m_objects[m_selected_object_id]->volumes[volume_id];
+
+	if (volume->modifier) 
+		og->enable();
+	else 
+		og->disable();
+
+//	auto config = volume->config;
+
+	// get default values
+// 	@opt_keys = @{Slic3r::Config::PrintRegion->new->get_keys};
+// 	} 
+/*	
+	# get default values
+	my $default_config = Slic3r::Config::new_from_defaults_keys(\@opt_keys);
+
+	# append default extruder
+	push @opt_keys, 'extruder';
+	$default_config->set('extruder', 0);
+	$config->set_ifndef('extruder', 0);
+	$self->{settings_panel}->set_default_config($default_config);
+	$self->{settings_panel}->set_config($config);
+	$self->{settings_panel}->set_opt_keys(\@opt_keys);
+	$self->{settings_panel}->set_fixed_options([qw(extruder)]);
+	$self->{settings_panel}->enable;
+	}
+	 */
+}
+
+void set_extruder_column_hidden(bool hide)
+{
+	m_objects_ctrl->GetColumn(3)->SetHidden(hide);
+}
+
+void update_extruder_in_config(const wxString& selection)
+{
+    if (!m_config || selection.empty())
+        return;
+
+    int extruder = selection.size() > 1 ? 0 : atoi(selection.c_str());
+    (*m_config)->set_key_value("extruder", new ConfigOptionInt(extruder));
+
+    if (m_event_update_scene > 0) {
+        wxCommandEvent e(m_event_update_scene);
+        get_main_frame()->ProcessWindowEvent(e);
+    }
+}
+
+void update_scale_values()
+{
+    update_scale_values((*m_objects)[m_selected_object_id]->instance_bounding_box(0).size(),
+                        (*m_objects)[m_selected_object_id]->instances[0]->scaling_factor);
+}
+
+void update_scale_values(const Pointf3& size, float scaling_factor)
+{
+    auto og = get_optgroup(ogFrequentlyObjectSettings);
+
+    if (g_is_percent_scale) {
+        auto scale = scaling_factor * 100;
+        og->set_value("scale_x", int(scale));
+        og->set_value("scale_y", int(scale));
+        og->set_value("scale_z", int(scale));
+    }
+    else {
+        og->set_value("scale_x", int(size.x + 0.5));
+        og->set_value("scale_y", int(size.y + 0.5));
+        og->set_value("scale_z", int(size.z + 0.5));
+    }
+}
+
+void update_rotation_values()
+{
+    auto og = get_optgroup(ogFrequentlyObjectSettings);
+
+    og->set_value("rotation_x", 0);
+    og->set_value("rotation_y", 0);
+
+    auto rotation_z = (*m_objects)[m_selected_object_id]->instances[0]->rotation;
+    auto deg = int(Geometry::rad2deg(rotation_z));
+//     if (deg > 180) deg -= 360;
+
+    og->set_value("rotation_z", deg);
+}
+
+void update_rotation_value(const double angle, const std::string& axis)
+{
+    auto og = get_optgroup(ogFrequentlyObjectSettings);
+    
+    int deg = int(Geometry::rad2deg(angle));
+//     if (deg>180) deg -= 360;
+
+    og->set_value("rotation_"+axis, deg);
+}
+
+void on_begin_drag(wxDataViewEvent &event)
+{
+    wxDataViewItem item(event.GetItem());
+
+    // only allow drags for item, not containers
+    if (m_objects_model->GetParent(item) == wxDataViewItem(0)) {
+        event.Veto();
+        return;
+    }
+
+    /* Under MSW or OSX, DnD moves an item to the place of another selected item
+     * But under GTK, DnD moves an item between another two items.
+     * And as a result - call EVT_CHANGE_SELECTION to unselect all items.
+     * To prevent such behavior use g_prevent_list_events
+    **/
+    g_prevent_list_events = true;//it's needed for GTK
+
+    wxTextDataObject *obj = new wxTextDataObject;
+    obj->SetText(wxString::Format("%d", m_objects_model->GetVolumeIdByItem(item)));
+    event.SetDataObject(obj);
+    event.SetDragFlags(/*wxDrag_AllowMove*/wxDrag_DefaultMove); // allows both copy and move;
+}
+
+void on_drop_possible(wxDataViewEvent &event)
+{
+    wxDataViewItem item(event.GetItem());
+
+    // only allow drags for item or background, not containers
+    if (item.IsOk() && m_objects_model->GetParent(item) == wxDataViewItem(0) ||
+        event.GetDataFormat() != wxDF_UNICODETEXT)
+        event.Veto();
+}
+
+void on_drop(wxDataViewEvent &event)
+{
+    wxDataViewItem item(event.GetItem());
+
+    // only allow drops for item, not containers
+    if (item.IsOk() && m_objects_model->GetParent(item) == wxDataViewItem(0) ||
+        event.GetDataFormat() != wxDF_UNICODETEXT) {
+        event.Veto();
+        return;
+    }    
+
+    wxTextDataObject obj;
+    obj.SetData(wxDF_UNICODETEXT, event.GetDataSize(), event.GetDataBuffer());
+
+    int from_volume_id = std::stoi(obj.GetText().ToStdString());
+    int to_volume_id = m_objects_model->GetVolumeIdByItem(item);
+
+#ifdef __WXGTK__
+    /* Under GTK, DnD moves an item between another two items.
+     * And event.GetItem() return item, which is under "insertion line"
+     * So, if we move item down we should to decrease the to_volume_id value
+    **/
+    if (to_volume_id > from_volume_id) to_volume_id--;
+#endif // __WXGTK__
+
+    m_objects_ctrl->Select(m_objects_model->ReorganizeChildren(from_volume_id, to_volume_id,
+                                                               m_objects_model->GetParent(item)));
+
+    auto& volumes = (*m_objects)[m_selected_object_id]->volumes;
+    auto delta = to_volume_id < from_volume_id ? -1 : 1;
+    int cnt = 0;
+    for (int id = from_volume_id; cnt < abs(from_volume_id - to_volume_id); id+=delta, cnt++)
+        std::swap(volumes[id], volumes[id +delta]);
+
+    g_prevent_list_events = false;
+}
+
+void update_objects_list_extruder_column(const int extruders_count)
+{
+    // delete old 3rd column
+    m_objects_ctrl->DeleteColumn(m_objects_ctrl->GetColumn(3));
+    // insert new created 3rd column
+    m_objects_ctrl->InsertColumn(3, object_ctrl_create_extruder_column(extruders_count));
+    // set show/hide for this column 
+    set_extruder_column_hidden(extruders_count <= 1);
+}
+
+} //namespace GUI
+} //namespace Slic3r 
\ No newline at end of file
diff --git a/xs/src/slic3r/GUI/GUI_ObjectParts.hpp b/xs/src/slic3r/GUI/GUI_ObjectParts.hpp
new file mode 100644
index 000000000..15be90bbf
--- /dev/null
+++ b/xs/src/slic3r/GUI/GUI_ObjectParts.hpp
@@ -0,0 +1,126 @@
+#ifndef slic3r_GUI_ObjectParts_hpp_
+#define slic3r_GUI_ObjectParts_hpp_
+
+class wxWindow;
+class wxSizer;
+class wxBoxSizer;
+class wxString;
+class wxArrayString;
+class wxMenu;
+class wxDataViewEvent;
+class wxKeyEvent;
+
+namespace Slic3r {
+class ModelObject;
+class Model;
+
+namespace GUI {
+
+enum ogGroup{
+	ogFrequentlyChangingParameters,
+	ogFrequentlyObjectSettings,
+	ogCurrentSettings
+// 	ogObjectSettings,
+// 	ogObjectMovers,
+// 	ogPartSettings
+};
+
+enum LambdaTypeIDs{
+	LambdaTypeBox,
+	LambdaTypeCylinder,
+	LambdaTypeSphere,
+	LambdaTypeSlab
+};
+
+struct OBJECT_PARAMETERS
+{
+	LambdaTypeIDs	type = LambdaTypeBox;
+	double			dim[3];// = { 1.0, 1.0, 1.0 };
+	int				cyl_r = 1;
+	int				cyl_h = 1;
+	double			sph_rho = 1.0;
+	double			slab_h = 1.0;
+	double			slab_z = 0.0;
+};
+
+void add_collapsible_panes(wxWindow* parent, wxBoxSizer* sizer);
+void add_objects_list(wxWindow* parent, wxBoxSizer* sizer);
+void add_object_settings(wxWindow* parent, wxBoxSizer* sizer);
+void show_collpane_settings(bool expert_mode);
+
+wxMenu *create_add_settings_popupmenu(bool is_part);
+wxMenu *create_add_part_popupmenu();
+wxMenu *create_part_settings_popupmenu();
+
+// Add object to the list
+//void add_object(const std::string &name);
+void add_object_to_list(const std::string &name, ModelObject* model_object);
+// Delete object from the list
+void delete_object_from_list();
+// Delete all objects from the list
+void delete_all_objects_from_list();
+// Set count of object on c++ side
+void set_object_count(int idx, int count);
+// Set object scale on c++ side
+void set_object_scale(int idx, int scale);
+// Unselect all objects in the list on c++ side
+void unselect_objects();
+// Select current object in the list on c++ side
+void select_current_object(int idx);
+// Remove objects/sub-object from the list
+void remove();
+
+void object_ctrl_selection_changed();
+void object_ctrl_context_menu();
+void object_ctrl_key_event(wxKeyEvent& event);
+void object_ctrl_item_value_change(wxDataViewEvent& event);
+void show_context_menu();
+
+void init_mesh_icons();
+void set_event_object_selection_changed(const int& event);
+void set_event_object_settings_changed(const int& event); 
+void set_event_remove_object(const int& event);
+void set_event_update_scene(const int& event);
+void set_objects_from_model(Model &model);
+
+bool is_parts_changed();
+bool is_part_settings_changed();
+
+void load_part(	wxWindow* parent, ModelObject* model_object, 
+				wxArrayString& part_names, const bool is_modifier); 
+
+void load_lambda(wxWindow* parent, ModelObject* model_object, 
+				wxArrayString& part_names, const bool is_modifier);
+
+void on_btn_load(wxWindow* parent, bool is_modifier = false, bool is_lambda = false);
+void on_btn_del();
+void on_btn_split(const bool split_part);
+void on_btn_move_up();
+void on_btn_move_down();
+
+void parts_changed(int obj_idx);
+void part_selection_changed();
+
+void update_settings_value();
+// show/hide "Extruder" column for Objects List
+void set_extruder_column_hidden(bool hide);
+// update extruder in current config
+void update_extruder_in_config(const wxString& selection);
+// update scale values after scale unit changing or "gizmos"
+void update_scale_values();
+void update_scale_values(const Pointf3& size, float scale);
+// update rotation values object selection changing
+void update_rotation_values();
+// update rotation value after "gizmos"
+void update_rotation_value(const double angle, const std::string& axis);
+
+void on_begin_drag(wxDataViewEvent &event);
+void on_drop_possible(wxDataViewEvent &event);
+void on_drop(wxDataViewEvent &event);
+
+// update extruder column for objects_ctrl according to extruders count
+void update_objects_list_extruder_column(const int extruders_count);
+
+} //namespace GUI
+} //namespace Slic3r 
+#endif  //slic3r_GUI_ObjectParts_hpp_
\ No newline at end of file
diff --git a/xs/src/slic3r/GUI/LambdaObjectDialog.cpp b/xs/src/slic3r/GUI/LambdaObjectDialog.cpp
new file mode 100644
index 000000000..7543821c0
--- /dev/null
+++ b/xs/src/slic3r/GUI/LambdaObjectDialog.cpp
@@ -0,0 +1,176 @@
+#include "LambdaObjectDialog.hpp"
+
+#include <wx/window.h>
+#include <wx/button.h>
+#include "OptionsGroup.hpp"
+
+namespace Slic3r
+{
+namespace GUI
+{
+static wxString dots("…", wxConvUTF8);
+
+LambdaObjectDialog::LambdaObjectDialog(wxWindow* parent)
+{
+	Create(parent, wxID_ANY, _(L("Lambda Object")),
+		wxDefaultPosition, wxDefaultSize,
+		wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER);
+
+	// instead of double dim[3] = { 1.0, 1.0, 1.0 };
+	object_parameters.dim[0] = 1.0;
+	object_parameters.dim[1] = 1.0;
+	object_parameters.dim[2] = 1.0;
+
+	sizer = new wxBoxSizer(wxVERTICAL);
+
+	// modificator options
+	m_modificator_options_book = new wxChoicebook(	this, wxID_ANY, wxDefaultPosition, 
+													wxDefaultSize, wxCHB_TOP);
+	sizer->Add(m_modificator_options_book, 1, wxEXPAND| wxALL, 10);
+
+	auto optgroup = init_modificator_options_page(_(L("Box")));
+		optgroup->m_on_change = [this](t_config_option_key opt_key, boost::any value){
+			int opt_id =	opt_key == "l" ? 0 :
+							opt_key == "w" ? 1 : 
+							opt_key == "h" ? 2 : -1;
+			if (opt_id < 0) return;
+			object_parameters.dim[opt_id] = boost::any_cast<double>(value);
+		};
+
+		ConfigOptionDef def;
+		def.width = 70;
+		def.type = coFloat;
+		def.default_value = new ConfigOptionFloat{ 1.0 };
+		def.label = L("L");
+		Option option(def, "l");
+		optgroup->append_single_option_line(option);
+		
+		def.label = L("W");
+		option = Option(def, "w");
+		optgroup->append_single_option_line(option);
+		
+		def.label = L("H");
+		option = Option(def, "h");
+		optgroup->append_single_option_line(option);
+
+	optgroup = init_modificator_options_page(_(L("Cylinder")));
+		optgroup->m_on_change = [this](t_config_option_key opt_key, boost::any value){
+			int val = boost::any_cast<int>(value);
+			if (opt_key == "cyl_r")
+				object_parameters.cyl_r = val;
+			else if (opt_key == "cyl_h")
+				object_parameters.cyl_h = val;
+			else return;
+		};
+
+		def.type = coInt;
+		def.default_value = new ConfigOptionInt{ 1 };
+		def.label = L("Radius");
+		option = Option(def, "cyl_r");
+		optgroup->append_single_option_line(option);
+
+		def.label = L("Height");
+		option = Option(def, "cyl_h");
+		optgroup->append_single_option_line(option);
+
+	optgroup = init_modificator_options_page(_(L("Sphere")));
+		optgroup->m_on_change = [this](t_config_option_key opt_key, boost::any value){
+			if (opt_key == "sph_rho")
+				object_parameters.sph_rho = boost::any_cast<double>(value);
+			else return;
+		};
+
+		def.type = coFloat;
+		def.default_value = new ConfigOptionFloat{ 1.0 };
+		def.label = L("Rho");
+		option = Option(def, "sph_rho");
+		optgroup->append_single_option_line(option);
+
+	optgroup = init_modificator_options_page(_(L("Slab")));
+		optgroup->m_on_change = [this](t_config_option_key opt_key, boost::any value){
+			double val = boost::any_cast<double>(value);
+			if (opt_key == "slab_z")
+				object_parameters.slab_z = val;
+			else if (opt_key == "slab_h")
+				object_parameters.slab_h = val;
+			else return;
+		};
+
+		def.label = L("H");
+		option = Option(def, "slab_h");
+		optgroup->append_single_option_line(option);
+
+		def.label = L("Initial Z");
+		option = Option(def, "slab_z");
+		optgroup->append_single_option_line(option);
+
+	Bind(wxEVT_CHOICEBOOK_PAGE_CHANGED, ([this](wxCommandEvent e)
+	{
+		auto page_idx = m_modificator_options_book->GetSelection();
+		if (page_idx < 0) return;
+		switch (page_idx)
+		{
+		case 0:
+			object_parameters.type = LambdaTypeBox;
+			break;
+		case 1:
+			object_parameters.type = LambdaTypeCylinder;
+			break;
+		case 2:
+			object_parameters.type = LambdaTypeSphere;
+			break;
+		case 3:
+			object_parameters.type = LambdaTypeSlab;
+			break;
+		default:
+			break;
+		}
+	}));
+
+
+	auto button_sizer = CreateStdDialogButtonSizer(wxOK | wxCANCEL);
+
+	wxButton* btn_OK = static_cast<wxButton*>(FindWindowById(wxID_OK, this));
+	btn_OK->Bind(wxEVT_BUTTON, [this](wxCommandEvent&) {
+		// validate user input
+		if (!CanClose())return;
+		EndModal(wxID_OK);
+		Destroy();
+	});
+
+	wxButton* btn_CANCEL = static_cast<wxButton*>(FindWindowById(wxID_CANCEL, this));
+	btn_CANCEL->Bind(wxEVT_BUTTON, [this](wxCommandEvent&) {
+		// validate user input
+		if (!CanClose())return;
+		EndModal(wxID_CANCEL);
+		Destroy();
+	});
+
+	sizer->Add(button_sizer, 0, wxALIGN_CENTER_HORIZONTAL | wxBOTTOM, 10);
+
+	SetSizer(sizer);
+	sizer->Fit(this);
+	sizer->SetSizeHints(this);
+}
+
+// Called from the constructor.
+// Create a panel for a rectangular / circular / custom bed shape.
+ConfigOptionsGroupShp LambdaObjectDialog::init_modificator_options_page(wxString title){
+
+	auto panel = new wxPanel(m_modificator_options_book);
+
+	ConfigOptionsGroupShp optgroup;
+	optgroup = std::make_shared<ConfigOptionsGroup>(panel, _(L("Add")) + " " +title + " " +dots);
+	optgroup->label_width = 100;
+
+	m_optgroups.push_back(optgroup);
+
+	panel->SetSizerAndFit(optgroup->sizer);
+	m_modificator_options_book->AddPage(panel, title);
+
+	return optgroup;
+}
+
+
+} //namespace GUI
+} //namespace Slic3r 
diff --git a/xs/src/slic3r/GUI/LambdaObjectDialog.hpp b/xs/src/slic3r/GUI/LambdaObjectDialog.hpp
new file mode 100644
index 000000000..a70c12449
--- /dev/null
+++ b/xs/src/slic3r/GUI/LambdaObjectDialog.hpp
@@ -0,0 +1,35 @@
+#ifndef slic3r_LambdaObjectDialog_hpp_
+#define slic3r_LambdaObjectDialog_hpp_
+
+#include "GUI.hpp"
+
+#include <wx/dialog.h>
+#include <wx/sizer.h>
+#include <wx/choicebk.h>
+
+namespace Slic3r
+{
+namespace GUI
+{
+using ConfigOptionsGroupShp = std::shared_ptr<ConfigOptionsGroup>;
+class LambdaObjectDialog : public wxDialog
+{
+	wxChoicebook*	m_modificator_options_book;
+	std::vector <ConfigOptionsGroupShp>	m_optgroups;
+public:
+	LambdaObjectDialog(wxWindow* parent);
+	~LambdaObjectDialog(){}
+
+	bool CanClose() { return true; }	// ???
+	OBJECT_PARAMETERS& ObjectParameters(){ return object_parameters; }
+
+	ConfigOptionsGroupShp init_modificator_options_page(wxString title);
+	
+	// Note whether the window was already closed, so a pending update is not executed.
+	bool m_already_closed = false;
+	OBJECT_PARAMETERS object_parameters;
+	wxBoxSizer* sizer = nullptr;
+};
+} //namespace GUI
+} //namespace Slic3r 
+#endif  //slic3r_LambdaObjectDialog_hpp_
diff --git a/xs/src/slic3r/GUI/OptionsGroup.cpp b/xs/src/slic3r/GUI/OptionsGroup.cpp
index a2d6559a9..453a2f3f7 100644
--- a/xs/src/slic3r/GUI/OptionsGroup.cpp
+++ b/xs/src/slic3r/GUI/OptionsGroup.cpp
@@ -30,6 +30,7 @@ const t_field& OptionsGroup::build_field(const t_config_option_key& id, const Co
                 opt.gui_type.compare("i_enum_closed") == 0) {
 		m_fields.emplace(id, STDMOVE(Choice::Create<Choice>(parent(), opt, id)));
     } else if (opt.gui_type.compare("slider") == 0) {
+		m_fields.emplace(id, STDMOVE(SliderCtrl::Create<SliderCtrl>(parent(), opt, id)));
     } else if (opt.gui_type.compare("i_spin") == 0) { // Spinctrl
     } else if (opt.gui_type.compare("legend") == 0) { // StaticText
 		m_fields.emplace(id, STDMOVE(StaticText::Create<StaticText>(parent(), opt, id)));
@@ -88,17 +89,23 @@ const t_field& OptionsGroup::build_field(const t_config_option_key& id, const Co
 		if (!this->m_disabled)
 			this->back_to_sys_value(opt_id);
 	};
-	if (!m_show_modified_btns) {
-		field->m_Undo_btn->Hide();
-		field->m_Undo_to_sys_btn->Hide();
-	}
-//	if (nonsys_btn_icon != nullptr)
-//		field->set_nonsys_btn_icon(*nonsys_btn_icon);
     
 	// assign function objects for callbacks, etc.
     return field;
 }
 
+void OptionsGroup::add_undo_buttuns_to_sizer(wxSizer* sizer, const t_field& field)
+{
+	if (!m_show_modified_btns) {
+		field->m_Undo_btn->Hide();
+		field->m_Undo_to_sys_btn->Hide();
+		return;
+	}
+
+	sizer->Add(field->m_Undo_to_sys_btn, 0, wxALIGN_CENTER_VERTICAL);
+	sizer->Add(field->m_Undo_btn, 0, wxALIGN_CENTER_VERTICAL);
+}
+
 void OptionsGroup::append_line(const Line& line, wxStaticText**	colored_Label/* = nullptr*/) {
 //!    if (line.sizer != nullptr || (line.widget != nullptr && line.full_width > 0)){
 	if ( (line.sizer != nullptr || line.widget != nullptr) && line.full_width){
@@ -133,8 +140,7 @@ void OptionsGroup::append_line(const Line& line, wxStaticText**	colored_Label/*
 		const auto& field = build_field(option);
 
 		auto btn_sizer = new wxBoxSizer(wxHORIZONTAL);
-		btn_sizer->Add(field->m_Undo_to_sys_btn);
-		btn_sizer->Add(field->m_Undo_btn);
+		add_undo_buttuns_to_sizer(btn_sizer, field);
 		tmp_sizer->Add(btn_sizer, 0, wxEXPAND | wxALL, 0);
 		if (is_window_field(field))
 			tmp_sizer->Add(field->getWindow(), 0, wxEXPAND | wxALL, wxOSX ? 0 : 5);
@@ -149,6 +155,18 @@ void OptionsGroup::append_line(const Line& line, wxStaticText**	colored_Label/*
         m_panel->Layout();
 #endif /* __WXGTK__ */
 
+	// if we have an extra column, build it
+	if (extra_column) {
+		if (extra_column) {
+			grid_sizer->Add(extra_column(parent(), line), 0, wxALIGN_CENTER_VERTICAL, 0);
+		}
+		else {
+			// if the callback provides no sizer for the extra cell, put a spacer
+			grid_sizer->AddSpacer(1);
+		}
+	}
+
+
     // Build a label if we have it
 	wxStaticText* label=nullptr;
     if (label_width != 0) {
@@ -163,7 +181,8 @@ void OptionsGroup::append_line(const Line& line, wxStaticText**	colored_Label/*
 							wxDefaultPosition, wxSize(label_width, -1), label_style);
         label->SetFont(label_font);
         label->Wrap(label_width); // avoid a Linux/GTK bug
-		grid_sizer->Add(label, 0, (staticbox ? 0 : wxALIGN_RIGHT | wxRIGHT) | wxALIGN_CENTER_VERTICAL, 5);
+		grid_sizer->Add(label, 0, (staticbox ? 0 : wxALIGN_RIGHT | wxRIGHT) | 
+						(m_flag == ogSIDE_OPTIONS_VERTICAL ? wxTOP : wxALIGN_CENTER_VERTICAL), 5);
 		if (line.label_tooltip.compare("") != 0)
 			label->SetToolTip(line.label_tooltip);
     }
@@ -177,28 +196,35 @@ void OptionsGroup::append_line(const Line& line, wxStaticText**	colored_Label/*
 		return;
 	}
 	
-	// if we have a single option with no sidetext just add it directly to the grid sizer
-	auto sizer = new wxBoxSizer(wxHORIZONTAL);
-	grid_sizer->Add(sizer, 0, wxEXPAND | (staticbox ? wxALL : wxBOTTOM|wxTOP|wxLEFT), staticbox ? 0 : 1);
+	// If we're here, we have more than one option or a single option with sidetext
+    // so we need a horizontal sizer to arrange these things
+	auto sizer = new wxBoxSizer(m_flag == ogSIDE_OPTIONS_VERTICAL ? wxVERTICAL : wxHORIZONTAL);
+	grid_sizer->Add(sizer, 0, wxEXPAND | (staticbox ? wxALL : wxBOTTOM | wxTOP | wxLEFT), staticbox ? 0 : 1);
+	// If we have a single option with no sidetext just add it directly to the grid sizer
 	if (option_set.size() == 1 && option_set.front().opt.sidetext.size() == 0 &&
 		option_set.front().side_widget == nullptr && line.get_extra_widgets().size() == 0) {
 		const auto& option = option_set.front();
 		const auto& field = build_field(option, label);
 
-		sizer->Add(field->m_Undo_to_sys_btn, 0, wxALIGN_CENTER_VERTICAL); 
-		sizer->Add(field->m_Undo_btn, 0, wxALIGN_CENTER_VERTICAL);
+		add_undo_buttuns_to_sizer(sizer, field);
 		if (is_window_field(field)) 
 			sizer->Add(field->getWindow(), option.opt.full_width ? 1 : 0, (option.opt.full_width ? wxEXPAND : 0) |
 							wxBOTTOM | wxTOP | wxALIGN_CENTER_VERTICAL, (wxOSX||!staticbox) ? 0 : 2);
 		if (is_sizer_field(field)) 
-			sizer->Add(field->getSizer(), 0, (option.opt.full_width ? wxEXPAND : 0) | wxALIGN_CENTER_VERTICAL, 0);
+			sizer->Add(field->getSizer(), 1, (option.opt.full_width ? wxEXPAND : 0) | wxALIGN_CENTER_VERTICAL, 0);
 		return;
 	}
 
-    // if we're here, we have more than one option or a single option with sidetext
-    // so we need a horizontal sizer to arrange these things
-	for (auto opt : option_set) {
+    for (auto opt : option_set) {
 		ConfigOptionDef option = opt.opt;
+		wxSizer* sizer_tmp;
+		if (m_flag == ogSIDE_OPTIONS_VERTICAL){
+			auto sz = new wxFlexGridSizer(1, 3, 2, 2);
+			sz->RemoveGrowableCol(2);
+			sizer_tmp = sz;
+		}
+    	else
+    		sizer_tmp = sizer;
 		// add label if any
 		if (option.label != "") {
 			wxString str_label = _(option.label);
@@ -208,34 +234,38 @@ void OptionsGroup::append_line(const Line& line, wxStaticText**	colored_Label/*
 // 								L_str(option.label);
 			label = new wxStaticText(parent(), wxID_ANY, str_label + ":", wxDefaultPosition, wxDefaultSize);
 			label->SetFont(label_font);
-			sizer->Add(label, 0, wxALIGN_CENTER_VERTICAL, 0);
+			sizer_tmp->Add(label, 0, wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL, 0);
 		}
 
 		// add field
 		const Option& opt_ref = opt;
 		auto& field = build_field(opt_ref, label);
-		sizer->Add(field->m_Undo_to_sys_btn, 0, wxALIGN_CENTER_VERTICAL);
-		sizer->Add(field->m_Undo_btn, 0, wxALIGN_CENTER_VERTICAL, 0);
+		add_undo_buttuns_to_sizer(sizer_tmp, field);
 		is_sizer_field(field) ? 
-			sizer->Add(field->getSizer(), 0, wxALIGN_CENTER_VERTICAL, 0) :
-			sizer->Add(field->getWindow(), 0, wxALIGN_CENTER_VERTICAL, 0);
+			sizer_tmp->Add(field->getSizer(), 0, wxALIGN_CENTER_VERTICAL, 0) :
+			sizer_tmp->Add(field->getWindow(), 0, wxALIGN_CENTER_VERTICAL, 0);
 		
 		// add sidetext if any
 		if (option.sidetext != "") {
-			auto sidetext = new wxStaticText(parent(), wxID_ANY, _(option.sidetext), wxDefaultPosition, wxDefaultSize);
+			auto sidetext = new wxStaticText(	parent(), wxID_ANY, _(option.sidetext), wxDefaultPosition, 
+												wxSize(sidetext_width, -1)/*wxDefaultSize*/, wxALIGN_LEFT);
 			sidetext->SetFont(sidetext_font);
-			sizer->Add(sidetext, 0, wxLEFT | wxALIGN_CENTER_VERTICAL, 4);
+			sizer_tmp->Add(sidetext, 0, wxLEFT | wxALIGN_CENTER_VERTICAL, m_flag == ogSIDE_OPTIONS_VERTICAL ? 0 : 4);
+			field->set_side_text_ptr(sidetext);
 		}
 
 		// add side widget if any
 		if (opt.side_widget != nullptr) {
-			sizer->Add(opt.side_widget(parent())/*!.target<wxWindow>()*/, 0, wxLEFT | wxALIGN_CENTER_VERTICAL, 1);	//! requires verification
+			sizer_tmp->Add(opt.side_widget(parent())/*!.target<wxWindow>()*/, 0, wxLEFT | wxALIGN_CENTER_VERTICAL, 1);	//! requires verification
 		}
 
-		if (opt.opt_id != option_set.back().opt_id) //! istead of (opt != option_set.back())
+		if (opt.opt_id != option_set.back().opt_id && m_flag != ogSIDE_OPTIONS_VERTICAL) //! istead of (opt != option_set.back())
 		{
-			sizer->AddSpacer(6);
+			sizer_tmp->AddSpacer(6);
 	    }
+
+		if (m_flag == ogSIDE_OPTIONS_VERTICAL)
+			sizer->Add(sizer_tmp, 0, wxALIGN_RIGHT|wxALL, 0);
 	}
 	// add extra sizers if any
 	for (auto extra_widget : line.get_extra_widgets()) {
@@ -259,7 +289,7 @@ void OptionsGroup::on_change_OG(const t_config_option_key& opt_id, const boost::
 Option ConfigOptionsGroup::get_option(const std::string& opt_key, int opt_index /*= -1*/)
 {
 	if (!m_config->has(opt_key)) {
-		std::cerr << "No " << opt_key << " in ConfigOptionsGroup config.";
+		std::cerr << "No " << opt_key << " in ConfigOptionsGroup config.\n";
 	}
 
 	std::string opt_id = opt_index == -1 ? opt_key : opt_key + "#" + std::to_string(opt_index);
diff --git a/xs/src/slic3r/GUI/OptionsGroup.hpp b/xs/src/slic3r/GUI/OptionsGroup.hpp
index 422e1afd9..4f263f5e3 100644
--- a/xs/src/slic3r/GUI/OptionsGroup.hpp
+++ b/xs/src/slic3r/GUI/OptionsGroup.hpp
@@ -26,9 +26,13 @@
 
 namespace Slic3r { namespace GUI {
 
+enum ogDrawFlag{
+	ogDEFAULT,
+	ogSIDE_OPTIONS_VERTICAL
+};
+
 /// Widget type describes a function object that returns a wxWindow (our widget) and accepts a wxWidget (parent window).
 using widget_t = std::function<wxSizer*(wxWindow*)>;//!std::function<wxWindow*(wxWindow*)>;
-using column_t = std::function<wxSizer*(const Line&)>;
 
 //auto default_label_clr = wxSystemSettings::GetColour(wxSYS_COLOUR_3DLIGHT); //GetSystemColour
 //auto modified_label_clr = *new wxColour(254, 189, 101);
@@ -71,10 +75,13 @@ private:
     std::vector<widget_t>	m_extra_widgets;//! {std::vector<widget_t>()};
 };
 
+using column_t = std::function<wxWindow*(wxWindow* parent, const Line&)>;//std::function<wxSizer*(const Line&)>;
+
 using t_optionfield_map = std::map<t_config_option_key, t_field>;
 using t_opt_map = std::map< std::string, std::pair<std::string, int> >;
 
 class OptionsGroup {
+	wxStaticBox*	stb;
 public:
     const bool		staticbox {true};
     const wxString	title {wxString("")};
@@ -88,8 +95,7 @@ public:
 
     wxFont			sidetext_font {wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT) };
     wxFont			label_font {wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT) };
-
-//	std::function<const wxBitmap&()>	nonsys_btn_icon{ nullptr };
+	int				sidetext_width{ -1 };
 
     /// Returns a copy of the pointer of the parent wxWindow.
     /// Accessor function is because users are not allowed to change the parent
@@ -101,6 +107,11 @@ public:
 		return m_parent;
 #endif /* __WXGTK__ */
     }
+#ifdef __WXGTK__
+    wxWindow* get_parent() const {
+        return m_parent;
+    }
+#endif /* __WXGTK__ */
 
 	void		append_line(const Line& line, wxStaticText** colored_Label = nullptr);
     Line		create_single_option_line(const Option& option) const;
@@ -124,23 +135,39 @@ public:
 							return out;
     }
 
+	bool			set_side_text(const t_config_option_key& opt_key, const wxString& side_text) {
+							if (m_fields.find(opt_key) == m_fields.end()) return false;
+							auto st = m_fields.at(opt_key)->m_side_text;
+							if (!st) return false;
+							st->SetLabel(side_text);
+							return true;
+    }
+
+	void			set_name(const wxString& new_name) {
+							stb->SetLabel(new_name);
+    }
+
 	inline void		enable() { for (auto& field : m_fields) field.second->enable(); }
     inline void		disable() { for (auto& field : m_fields) field.second->disable(); }
+	void			set_flag(ogDrawFlag flag) { m_flag = flag; }
+	void			set_grid_vgap(int gap) { m_grid_sizer->SetVGap(gap); }
 
 	void set_show_modified_btns_val(bool show) {
 		m_show_modified_btns = show;
     }
 
-    OptionsGroup(wxWindow* _parent, const wxString& title, bool is_tab_opt=false) : 
-		m_parent(_parent), title(title), m_show_modified_btns(is_tab_opt), staticbox(title!="") {
-		auto stb = new wxStaticBox(_parent, wxID_ANY, title);
+	OptionsGroup(	wxWindow* _parent, const wxString& title, bool is_tab_opt = false, 
+					ogDrawFlag flag = ogDEFAULT, column_t extra_clmn = nullptr) :
+					m_parent(_parent), title(title), m_show_modified_btns(is_tab_opt),
+					staticbox(title!=""), m_flag(flag), extra_column(extra_clmn){
+		stb = new wxStaticBox(_parent, wxID_ANY, title);
 		stb->SetFont(bold_font());
-		sizer = (staticbox ? new wxStaticBoxSizer(stb/*new wxStaticBox(_parent, wxID_ANY, title)*/, wxVERTICAL) : new wxBoxSizer(wxVERTICAL));
+        sizer = (staticbox ? new wxStaticBoxSizer(stb, wxVERTICAL) : new wxBoxSizer(wxVERTICAL));
         auto num_columns = 1U;
         if (label_width != 0) num_columns++;
         if (extra_column != nullptr) num_columns++;
-        m_grid_sizer = new wxFlexGridSizer(0, num_columns, 0,0);
-        static_cast<wxFlexGridSizer*>(m_grid_sizer)->SetFlexibleDirection(wxHORIZONTAL);
+        m_grid_sizer = new wxFlexGridSizer(0, num_columns, 1,0);
+        static_cast<wxFlexGridSizer*>(m_grid_sizer)->SetFlexibleDirection(wxBOTH/*wxHORIZONTAL*/);
         static_cast<wxFlexGridSizer*>(m_grid_sizer)->AddGrowableCol(label_width != 0);
 #ifdef __WXGTK__
         m_panel = new wxPanel( _parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
@@ -164,6 +191,8 @@ protected:
 	// "true" if option is created in preset tabs
 	bool					m_show_modified_btns{ false };
 
+	ogDrawFlag				m_flag{ ogDEFAULT };
+
 	// This panel is needed for correct showing of the ToolTips for Button, StaticText and CheckBox
 	// Tooltips on GTK doesn't work inside wxStaticBoxSizer unless you insert a panel 
 	// inside it before you insert the other controls.
@@ -177,6 +206,7 @@ protected:
 	const t_field&		build_field(const t_config_option_key& id, const ConfigOptionDef& opt, wxStaticText* label = nullptr);
 	const t_field&		build_field(const t_config_option_key& id, wxStaticText* label = nullptr);
 	const t_field&		build_field(const Option& opt, wxStaticText* label = nullptr);
+	void				add_undo_buttuns_to_sizer(wxSizer* sizer, const t_field& field);
 
     virtual void		on_kill_focus (){};
 	virtual void		on_change_OG(const t_config_option_key& opt_id, const boost::any& value);
@@ -186,8 +216,9 @@ protected:
 
 class ConfigOptionsGroup: public OptionsGroup {
 public:
-	ConfigOptionsGroup(wxWindow* parent, const wxString& title, DynamicPrintConfig* _config = nullptr, bool is_tab_opt = false) :
-		OptionsGroup(parent, title, is_tab_opt), m_config(_config) {}
+	ConfigOptionsGroup(	wxWindow* parent, const wxString& title, DynamicPrintConfig* _config = nullptr, 
+						bool is_tab_opt = false, ogDrawFlag flag = ogDEFAULT, column_t extra_clmn = nullptr) :
+		OptionsGroup(parent, title, is_tab_opt, flag, extra_clmn), m_config(_config) {}
 
     /// reference to libslic3r config, non-owning pointer (?).
     DynamicPrintConfig*		m_config {nullptr};
diff --git a/xs/src/slic3r/GUI/Tab.cpp b/xs/src/slic3r/GUI/Tab.cpp
index 07785e818..111b2b933 100644
--- a/xs/src/slic3r/GUI/Tab.cpp
+++ b/xs/src/slic3r/GUI/Tab.cpp
@@ -687,8 +687,8 @@ void Tab::on_value_change(const std::string& opt_key, const boost::any& value)
 	}
 	if (opt_key == "fill_density")
 	{
-		boost::any val = get_optgroup()->get_config_value(*m_config, opt_key);
-		get_optgroup()->set_value(opt_key, val);
+		boost::any val = get_optgroup(ogFrequentlyChangingParameters)->get_config_value(*m_config, opt_key);
+		get_optgroup(ogFrequentlyChangingParameters)->set_value(opt_key, val);
 	}
 	if (opt_key == "support_material" || opt_key == "support_material_buildplate_only")
 	{
@@ -697,12 +697,12 @@ void Tab::on_value_change(const std::string& opt_key, const boost::any& value)
 								m_config->opt_bool("support_material_buildplate_only") ?
 									_("Support on build plate only") :
 									_("Everywhere");
-		get_optgroup()->set_value("support", new_selection);
+		get_optgroup(ogFrequentlyChangingParameters)->set_value("support", new_selection);
 	}
 	if (opt_key == "brim_width")
 	{
 		bool val = m_config->opt_float("brim_width") > 0.0 ? true : false;
-		get_optgroup()->set_value("brim", val);
+		get_optgroup(ogFrequentlyChangingParameters)->set_value("brim", val);
 	}
 
     if (opt_key == "wipe_tower" || opt_key == "single_extruder_multi_material" || opt_key == "extruders_count" )
@@ -719,10 +719,8 @@ void Tab::update_wiping_button_visibility() {
     bool multiple_extruders = dynamic_cast<ConfigOptionFloats*>((m_preset_bundle->printers.get_edited_preset().config).option("nozzle_diameter"))->values.size() > 1;
     bool single_extruder_mm = dynamic_cast<ConfigOptionBool*>(  (m_preset_bundle->printers.get_edited_preset().config).option("single_extruder_multi_material"))->value;
 
-    if (wipe_tower_enabled && multiple_extruders && single_extruder_mm)
-        get_wiping_dialog_button()->Show();
-    else get_wiping_dialog_button()->Hide();
-
+	get_wiping_dialog_button()->Show(wipe_tower_enabled && multiple_extruders && single_extruder_mm);
+	
     (get_wiping_dialog_button()->GetParent())->Layout();
 }
 
@@ -789,18 +787,18 @@ void Tab::update_preset_description_line()
 
 void Tab::update_frequently_changed_parameters()
 {
-	boost::any value = get_optgroup()->get_config_value(*m_config, "fill_density");
-	get_optgroup()->set_value("fill_density", value);
+	boost::any value = get_optgroup(ogFrequentlyChangingParameters)->get_config_value(*m_config, "fill_density");
+	get_optgroup(ogFrequentlyChangingParameters)->set_value("fill_density", value);
 
 	wxString new_selection = !m_config->opt_bool("support_material") ?
 							_("None") :
 							m_config->opt_bool("support_material_buildplate_only") ?
 								_("Support on build plate only") :
 								_("Everywhere");
-	get_optgroup()->set_value("support", new_selection);
+	get_optgroup(ogFrequentlyChangingParameters)->set_value("support", new_selection);
 
 	bool val = m_config->opt_float("brim_width") > 0.0 ? true : false;
-	get_optgroup()->set_value("brim", val);
+	get_optgroup(ogFrequentlyChangingParameters)->set_value("brim", val);
 
 	update_wiping_button_visibility();
 }
@@ -1478,7 +1476,7 @@ void TabPrinter::build_fff()
 		Line line{ _(L("Bed shape")), "" };
 		line.widget = [this](wxWindow* parent){
 			auto btn = new wxButton(parent, wxID_ANY, _(L(" Set "))+dots, wxDefaultPosition, wxDefaultSize, wxBU_LEFT | wxBU_EXACTFIT);
-			//			btn->SetFont(Slic3r::GUI::small_font);
+			btn->SetFont(Slic3r::GUI::small_font());
 			btn->SetBitmap(wxBitmap(from_u8(Slic3r::var("printer_empty.png")), wxBITMAP_TYPE_PNG));
 
 			auto sizer = new wxBoxSizer(wxHORIZONTAL);
@@ -1546,7 +1544,7 @@ void TabPrinter::build_fff()
 			auto serial_test = [this](wxWindow* parent){
 				auto btn = m_serial_test_btn = new wxButton(parent, wxID_ANY,
 					_(L("Test")), wxDefaultPosition, wxDefaultSize, wxBU_LEFT | wxBU_EXACTFIT);
-//				btn->SetFont($Slic3r::GUI::small_font);
+				btn->SetFont(Slic3r::GUI::small_font());
 				btn->SetBitmap(wxBitmap(from_u8(Slic3r::var("wrench.png")), wxBITMAP_TYPE_PNG));
 				auto sizer = new wxBoxSizer(wxHORIZONTAL);
 				sizer->Add(btn);
@@ -1832,6 +1830,7 @@ void TabPrinter::extruders_count_changed(size_t extruders_count){
 	build_extruder_pages();
 	reload_config();
 	on_value_change("extruders_count", extruders_count);
+    update_objects_list_extruder_column(extruders_count);
 }
 
 void TabPrinter::append_option_line(ConfigOptionsGroupShp optgroup, const std::string opt_key)
@@ -2174,7 +2173,7 @@ void Tab::load_current_preset()
 		// checking out if this Tab exists till this moment
 		if (!checked_tab(this))
 			return;
-        update_tab_ui();
+		update_tab_ui();
 
         // update show/hide tabs
         if (m_name == "printer"){
diff --git a/xs/src/slic3r/GUI/Tab.hpp b/xs/src/slic3r/GUI/Tab.hpp
index 353277d64..a1214465e 100644
--- a/xs/src/slic3r/GUI/Tab.hpp
+++ b/xs/src/slic3r/GUI/Tab.hpp
@@ -267,11 +267,11 @@ public:
 
 	void			on_value_change(const std::string& opt_key, const boost::any& value);
 
+    void            update_wiping_button_visibility();
 protected:
 	void			on_presets_changed();
 	void			update_preset_description_line();
 	void			update_frequently_changed_parameters();
-    void            update_wiping_button_visibility();
 	void			update_tab_presets(wxComboCtrl* ui, bool show_incompatible);
 	void			fill_icon_descriptions();
 	void			set_tooltips_text();
diff --git a/xs/src/slic3r/GUI/wxExtensions.cpp b/xs/src/slic3r/GUI/wxExtensions.cpp
index 5949efb37..7fcad9e65 100644
--- a/xs/src/slic3r/GUI/wxExtensions.cpp
+++ b/xs/src/slic3r/GUI/wxExtensions.cpp
@@ -1,5 +1,13 @@
 #include "wxExtensions.hpp"
 
+#include "GUI.hpp"
+#include "../../libslic3r/Utils.hpp"
+
+#include <wx/sizer.h>
+#include <wx/statline.h>
+#include <wx/dcclient.h>
+#include <wx/numformatter.h>
+
 const unsigned int wxCheckListBoxComboPopup::DefaultWidth = 200;
 const unsigned int wxCheckListBoxComboPopup::DefaultHeight = 200;
 const unsigned int wxCheckListBoxComboPopup::DefaultItemHeight = 18;
@@ -182,3 +190,1216 @@ void wxDataViewTreeCtrlComboPopup::OnDataViewTreeCtrlSelection(wxCommandEvent& e
 	auto selected = GetItemText(GetSelection());
 	cmb->SetText(selected);
 }
+
+// ----------------------------------------------------------------------------
+// ***  PrusaCollapsiblePane  ***    
+// ----------------------------------------------------------------------------
+void PrusaCollapsiblePane::OnStateChange(const wxSize& sz)
+{
+#ifdef __WXOSX__
+	wxCollapsiblePane::OnStateChange(sz);
+#else
+	SetSize(sz);
+
+	if (this->HasFlag(wxCP_NO_TLW_RESIZE))
+	{
+		// the user asked to explicitly handle the resizing itself...
+		return;
+	}
+
+	auto top = GetParent(); //right_panel
+	if (!top)
+		return;
+
+	wxSizer *sizer = top->GetSizer();
+	if (!sizer)
+		return;
+
+	const wxSize newBestSize = sizer->ComputeFittingClientSize(top);
+	top->SetMinClientSize(newBestSize);
+
+	wxWindowUpdateLocker noUpdates_p(top->GetParent());
+	// we shouldn't attempt to resize a maximized window, whatever happens
+	// 	if (!top->IsMaximized())
+	// 		top->SetClientSize(newBestSize);
+	top->GetParent()->Layout();
+	top->Refresh();
+#endif //__WXOSX__
+}
+
+// ----------------------------------------------------------------------------
+// ***  PrusaCollapsiblePaneMSW  ***    used only #ifdef __WXMSW__
+// ----------------------------------------------------------------------------
+#ifdef __WXMSW__
+bool PrusaCollapsiblePaneMSW::Create(wxWindow *parent, wxWindowID id, const wxString& label, 
+	const wxPoint& pos, const wxSize& size, long style, const wxValidator& val, const wxString& name)
+{
+	if (!wxControl::Create(parent, id, pos, size, style, val, name))
+		return false;
+	m_pStaticLine = NULL;
+	m_strLabel = label;
+
+	// sizer containing the expand button and possibly a static line
+	m_sz = new wxBoxSizer(wxHORIZONTAL);
+
+	m_bmp_close.LoadFile(Slic3r::GUI::from_u8(Slic3r::var("disclosure_triangle_close.png")), wxBITMAP_TYPE_PNG);
+	m_bmp_open.LoadFile(Slic3r::GUI::from_u8(Slic3r::var("disclosure_triangle_open.png")), wxBITMAP_TYPE_PNG);
+
+	m_pDisclosureTriangleButton = new wxButton(this, wxID_ANY, m_strLabel, wxPoint(0, 0),
+		wxDefaultSize, wxBU_EXACTFIT | wxNO_BORDER);
+	UpdateBtnBmp();
+	m_pDisclosureTriangleButton->Bind(wxEVT_BUTTON, [this](wxCommandEvent& event)
+	{
+		if (event.GetEventObject() != m_pDisclosureTriangleButton)
+		{
+			event.Skip();
+			return;
+		}
+
+		Collapse(!IsCollapsed());
+
+		// this change was generated by the user - send the event
+		wxCollapsiblePaneEvent ev(this, GetId(), IsCollapsed());
+		GetEventHandler()->ProcessEvent(ev);
+	});
+
+	m_sz->Add(m_pDisclosureTriangleButton, 0, wxLEFT | wxTOP | wxBOTTOM, GetBorder());
+
+	// do not set sz as our sizers since we handle the pane window without using sizers
+	m_pPane = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxDefaultSize,
+		wxTAB_TRAVERSAL | wxNO_BORDER, wxT("wxCollapsiblePanePane"));
+
+	wxColour& clr = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW);
+	m_pDisclosureTriangleButton->SetBackgroundColour(clr);
+	this->SetBackgroundColour(clr);
+	m_pPane->SetBackgroundColour(clr);
+
+	// start as collapsed:
+	m_pPane->Hide();
+
+	return true;
+}
+
+void PrusaCollapsiblePaneMSW::UpdateBtnBmp()
+{
+	if (IsCollapsed())
+		m_pDisclosureTriangleButton->SetBitmap(m_bmp_close);
+	else{
+		m_pDisclosureTriangleButton->SetBitmap(m_bmp_open);
+		// To updating button bitmap it's needed to lost focus on this button, so
+		// we set focus to mainframe 
+		//GetParent()->GetParent()->GetParent()->SetFocus();
+		//or to pane
+		GetPane()->SetFocus();
+	}
+	Layout();
+}
+
+void PrusaCollapsiblePaneMSW::SetLabel(const wxString &label)
+{
+	m_strLabel = label;
+	m_pDisclosureTriangleButton->SetLabel(m_strLabel);
+	Layout();
+}
+
+bool PrusaCollapsiblePaneMSW::Layout()
+{
+	if (!m_pDisclosureTriangleButton || !m_pPane || !m_sz)
+		return false;     // we need to complete the creation first!
+
+	wxSize oursz(GetSize());
+
+	// move & resize the button and the static line
+	m_sz->SetDimension(0, 0, oursz.GetWidth(), m_sz->GetMinSize().GetHeight());
+	m_sz->Layout();
+
+	if (IsExpanded())
+	{
+		// move & resize the container window
+		int yoffset = m_sz->GetSize().GetHeight() + GetBorder();
+		m_pPane->SetSize(0, yoffset,
+			oursz.x, oursz.y - yoffset);
+
+		// this is very important to make the pane window layout show correctly
+		m_pPane->Layout();
+	}
+
+	return true;
+}
+
+void PrusaCollapsiblePaneMSW::Collapse(bool collapse)
+{
+	// optimization
+	if (IsCollapsed() == collapse)
+		return;
+
+	InvalidateBestSize();
+
+	// update our state
+	m_pPane->Show(!collapse);
+
+	// update button bitmap
+	UpdateBtnBmp();
+
+	OnStateChange(GetBestSize());
+}
+#endif //__WXMSW__
+
+// *****************************************************************************
+// ----------------------------------------------------------------------------
+// PrusaObjectDataViewModelNode
+// ----------------------------------------------------------------------------
+
+void PrusaObjectDataViewModelNode::set_object_action_icon() {
+	m_action_icon = wxBitmap(Slic3r::GUI::from_u8(Slic3r::var("add_object.png")), wxBITMAP_TYPE_PNG);
+}
+void  PrusaObjectDataViewModelNode::set_part_action_icon() {
+	m_action_icon = wxBitmap(Slic3r::GUI::from_u8(Slic3r::var("cog.png")), wxBITMAP_TYPE_PNG);
+}
+
+// *****************************************************************************
+// ----------------------------------------------------------------------------
+// PrusaObjectDataViewModel
+// ----------------------------------------------------------------------------
+
+wxDataViewItem PrusaObjectDataViewModel::Add(wxString &name)
+{
+	auto root = new PrusaObjectDataViewModelNode(name);
+	m_objects.push_back(root);
+	// notify control
+	wxDataViewItem child((void*)root);
+	wxDataViewItem parent((void*)NULL);
+	ItemAdded(parent, child);
+	return child;
+}
+
+wxDataViewItem PrusaObjectDataViewModel::Add(wxString &name, int instances_count, int scale)
+{
+	auto root = new PrusaObjectDataViewModelNode(name, instances_count, scale);
+	m_objects.push_back(root);
+	// notify control
+	wxDataViewItem child((void*)root);
+	wxDataViewItem parent((void*)NULL);
+	ItemAdded(parent, child);
+	return child;
+}
+
+wxDataViewItem PrusaObjectDataViewModel::AddChild(	const wxDataViewItem &parent_item,
+													const wxString &name,
+													const wxIcon& icon,
+                                                    const int extruder/* = 0*/,
+                                                    const bool create_frst_child/* = true*/)
+{
+	PrusaObjectDataViewModelNode *root = (PrusaObjectDataViewModelNode*)parent_item.GetID();
+	if (!root) return wxDataViewItem(0);
+
+    wxString extruder_str = extruder == 0 ? "default" : wxString::Format("%d", extruder);
+
+    if (root->GetChildren().Count() == 0 && create_frst_child)
+	{
+		auto icon_solid_mesh = wxIcon(Slic3r::GUI::from_u8(Slic3r::var("object.png")), wxBITMAP_TYPE_PNG);//(Slic3r::var("package.png")), wxBITMAP_TYPE_PNG);
+		auto node = new PrusaObjectDataViewModelNode(root, root->m_name, icon_solid_mesh, extruder_str, 0);
+		root->Append(node);
+		// notify control
+		wxDataViewItem child((void*)node);
+		ItemAdded(parent_item, child);
+	}
+
+	auto volume_id = root->GetChildCount();
+	auto node = new PrusaObjectDataViewModelNode(root, name, icon, extruder_str, volume_id);
+	root->Append(node);
+	// notify control
+	wxDataViewItem child((void*)node);
+	ItemAdded(parent_item, child);
+	return child;
+}
+
+wxDataViewItem PrusaObjectDataViewModel::Delete(const wxDataViewItem &item)
+{
+	auto ret_item = wxDataViewItem(0);
+	PrusaObjectDataViewModelNode *node = (PrusaObjectDataViewModelNode*)item.GetID();
+	if (!node)      // happens if item.IsOk()==false
+		return ret_item;
+
+	auto node_parent = node->GetParent();
+	wxDataViewItem parent(node_parent);
+
+	// first remove the node from the parent's array of children;
+	// NOTE: MyObjectTreeModelNodePtrArray is only an array of _pointers_
+	//       thus removing the node from it doesn't result in freeing it
+	if (node_parent){
+		auto id = node_parent->GetChildren().Index(node);
+		auto v_id = node->GetVolumeId();
+		node_parent->GetChildren().Remove(node);
+		if (id > 0){ 
+			if(id == node_parent->GetChildCount()) id--;
+			ret_item = wxDataViewItem(node_parent->GetChildren().Item(id));
+		}
+
+		//update volume_id value for remaining child-nodes
+		auto children = node_parent->GetChildren();
+		for (size_t i = 0; i < node_parent->GetChildCount(); i++)
+		{
+			auto volume_id = children[i]->GetVolumeId();
+			if (volume_id > v_id)
+				children[i]->SetVolumeId(volume_id-1);
+		}
+	}
+	else
+	{
+		auto it = find(m_objects.begin(), m_objects.end(), node);
+		auto id = it - m_objects.begin();
+		if (it != m_objects.end())
+			m_objects.erase(it);
+		if (id > 0){ 
+			if(id == m_objects.size()) id--;
+			ret_item = wxDataViewItem(m_objects[id]);
+		}
+	}
+	// free the node
+	delete node;
+
+	// set m_containet to FALSE if parent has no child
+	if (node_parent && node_parent->GetChildCount() == 0){
+#ifndef __WXGTK__
+		node_parent->m_container = false;
+#endif //__WXGTK__
+		ret_item = parent;
+	}
+
+	// notify control
+	ItemDeleted(parent, item);
+	return ret_item;
+}
+
+void PrusaObjectDataViewModel::DeleteAll()
+{
+	while (!m_objects.empty())
+	{
+		auto object = m_objects.back();
+// 		object->RemoveAllChildren();
+		Delete(wxDataViewItem(object));	
+	}
+}
+
+void PrusaObjectDataViewModel::DeleteChildren(wxDataViewItem& parent)
+{
+    PrusaObjectDataViewModelNode *root = (PrusaObjectDataViewModelNode*)parent.GetID();
+    if (!root)      // happens if item.IsOk()==false
+        return;
+
+    // first remove the node from the parent's array of children;
+    // NOTE: MyObjectTreeModelNodePtrArray is only an array of _pointers_
+    //       thus removing the node from it doesn't result in freeing it
+    auto& children = root->GetChildren();
+    for (int id = root->GetChildCount() - 1; id >= 0; --id)
+    {
+        auto node = children[id];
+        auto item = wxDataViewItem(node);
+        children.RemoveAt(id);
+
+        // free the node
+        delete node;
+
+        // notify control
+        ItemDeleted(parent, item);
+    }
+
+    // set m_containet to FALSE if parent has no child
+#ifndef __WXGTK__
+        root->m_container = false;
+#endif //__WXGTK__
+}
+
+wxDataViewItem PrusaObjectDataViewModel::GetItemById(int obj_idx)
+{
+	if (obj_idx >= m_objects.size())
+	{
+		printf("Error! Out of objects range.\n");
+		return wxDataViewItem(0);
+	}
+	return wxDataViewItem(m_objects[obj_idx]);
+}
+
+
+int PrusaObjectDataViewModel::GetIdByItem(wxDataViewItem& item)
+{
+	wxASSERT(item.IsOk());
+
+	PrusaObjectDataViewModelNode *node = (PrusaObjectDataViewModelNode*)item.GetID();
+	auto it = find(m_objects.begin(), m_objects.end(), node);
+	if (it == m_objects.end())
+		return -1;
+
+	return it - m_objects.begin();
+}
+
+int PrusaObjectDataViewModel::GetVolumeIdByItem(wxDataViewItem& item)
+{
+	wxASSERT(item.IsOk());
+
+	PrusaObjectDataViewModelNode *node = (PrusaObjectDataViewModelNode*)item.GetID();
+	if (!node)      // happens if item.IsOk()==false
+		return -1;
+	return node->GetVolumeId();
+}
+
+wxString PrusaObjectDataViewModel::GetName(const wxDataViewItem &item) const
+{
+	PrusaObjectDataViewModelNode *node = (PrusaObjectDataViewModelNode*)item.GetID();
+	if (!node)      // happens if item.IsOk()==false
+		return wxEmptyString;
+
+	return node->m_name;
+}
+
+wxString PrusaObjectDataViewModel::GetCopy(const wxDataViewItem &item) const
+{
+	PrusaObjectDataViewModelNode *node = (PrusaObjectDataViewModelNode*)item.GetID();
+	if (!node)      // happens if item.IsOk()==false
+		return wxEmptyString;
+
+	return node->m_copy;
+}
+
+wxString PrusaObjectDataViewModel::GetScale(const wxDataViewItem &item) const
+{
+	PrusaObjectDataViewModelNode *node = (PrusaObjectDataViewModelNode*)item.GetID();
+	if (!node)      // happens if item.IsOk()==false
+		return wxEmptyString;
+
+	return node->m_scale;
+}
+
+wxIcon& PrusaObjectDataViewModel::GetIcon(const wxDataViewItem &item) const
+{
+    PrusaObjectDataViewModelNode *node = (PrusaObjectDataViewModelNode*)item.GetID();
+    return node->m_icon;
+}
+
+void PrusaObjectDataViewModel::GetValue(wxVariant &variant, const wxDataViewItem &item, unsigned int col) const
+{
+	wxASSERT(item.IsOk());
+
+	PrusaObjectDataViewModelNode *node = (PrusaObjectDataViewModelNode*)item.GetID();
+	switch (col)
+	{
+	case 0:{
+		const wxDataViewIconText data(node->m_name, node->m_icon);
+		variant << data;
+		break;}
+	case 1:
+		variant = node->m_copy;
+		break;
+	case 2:
+		variant = node->m_scale;
+		break;
+	case 3:
+		variant = node->m_extruder;
+		break;
+	case 4:
+		variant << node->m_action_icon;
+		break;
+	default:
+		;
+	}
+}
+
+bool PrusaObjectDataViewModel::SetValue(const wxVariant &variant, const wxDataViewItem &item, unsigned int col)
+{
+	wxASSERT(item.IsOk());
+
+	PrusaObjectDataViewModelNode *node = (PrusaObjectDataViewModelNode*)item.GetID();
+	return node->SetValue(variant, col);
+}
+
+bool PrusaObjectDataViewModel::SetValue(const wxVariant &variant, const int item_idx, unsigned int col)
+{
+	if (item_idx < 0 || item_idx >= m_objects.size())
+		return false;
+
+	return m_objects[item_idx]->SetValue(variant, col);
+}
+
+wxDataViewItem PrusaObjectDataViewModel::MoveChildUp(const wxDataViewItem &item)
+{
+	auto ret_item = wxDataViewItem(0);
+	wxASSERT(item.IsOk());
+	PrusaObjectDataViewModelNode *node = (PrusaObjectDataViewModelNode*)item.GetID();
+	if (!node)      // happens if item.IsOk()==false
+		return ret_item;
+
+	auto node_parent = node->GetParent();
+	if (!node_parent) // If isn't part, but object
+		return ret_item;
+
+	auto volume_id = node->GetVolumeId();
+	if (0 < volume_id && volume_id < node_parent->GetChildCount()){
+		node_parent->SwapChildrens(volume_id - 1, volume_id);
+		ret_item = wxDataViewItem(node_parent->GetNthChild(volume_id - 1));
+		ItemChanged(item);
+		ItemChanged(ret_item);
+	}
+	else
+		ret_item = wxDataViewItem(node_parent->GetNthChild(0));
+	return ret_item;
+}
+
+wxDataViewItem PrusaObjectDataViewModel::MoveChildDown(const wxDataViewItem &item)
+{
+	auto ret_item = wxDataViewItem(0);
+	wxASSERT(item.IsOk());
+	PrusaObjectDataViewModelNode *node = (PrusaObjectDataViewModelNode*)item.GetID();
+	if (!node)      // happens if item.IsOk()==false
+		return ret_item;
+
+	auto node_parent = node->GetParent();
+	if (!node_parent) // If isn't part, but object
+		return ret_item;
+
+	auto volume_id = node->GetVolumeId();
+	if (0 <= volume_id && volume_id+1 < node_parent->GetChildCount()){
+		node_parent->SwapChildrens(volume_id + 1, volume_id);
+		ret_item = wxDataViewItem(node_parent->GetNthChild(volume_id + 1));
+		ItemChanged(item);
+		ItemChanged(ret_item);
+	}
+	else
+		ret_item = wxDataViewItem(node_parent->GetNthChild(node_parent->GetChildCount()-1));
+	return ret_item;
+}
+
+wxDataViewItem PrusaObjectDataViewModel::ReorganizeChildren(int current_volume_id, int new_volume_id, const wxDataViewItem &parent)
+{
+    auto ret_item = wxDataViewItem(0);
+    if (current_volume_id == new_volume_id)
+        return ret_item;
+    wxASSERT(parent.IsOk());
+    PrusaObjectDataViewModelNode *node_parent = (PrusaObjectDataViewModelNode*)parent.GetID();
+    if (!node_parent)      // happens if item.IsOk()==false
+        return ret_item;
+
+    PrusaObjectDataViewModelNode *deleted_node = node_parent->GetNthChild(current_volume_id);
+    node_parent->GetChildren().Remove(deleted_node);
+    ItemDeleted(parent, wxDataViewItem(deleted_node));
+    node_parent->Insert(deleted_node, new_volume_id);
+    ItemAdded(parent, wxDataViewItem(deleted_node));
+
+    //update volume_id value for child-nodes
+    auto children = node_parent->GetChildren();
+    int id_frst = current_volume_id < new_volume_id ? current_volume_id : new_volume_id;
+    int id_last = current_volume_id > new_volume_id ? current_volume_id : new_volume_id;
+    for (int id = id_frst; id <= id_last; ++id)
+        children[id]->SetVolumeId(id);
+
+    return wxDataViewItem(node_parent->GetNthChild(new_volume_id));
+}
+
+// bool MyObjectTreeModel::IsEnabled(const wxDataViewItem &item, unsigned int col) const
+// {
+// 
+// }
+
+wxDataViewItem PrusaObjectDataViewModel::GetParent(const wxDataViewItem &item) const
+{
+	// the invisible root node has no parent
+	if (!item.IsOk())
+		return wxDataViewItem(0);
+
+	PrusaObjectDataViewModelNode *node = (PrusaObjectDataViewModelNode*)item.GetID();
+
+	// objects nodes has no parent too
+	if (find(m_objects.begin(), m_objects.end(),node) != m_objects.end())
+		return wxDataViewItem(0);
+
+	return wxDataViewItem((void*)node->GetParent());
+}
+
+bool PrusaObjectDataViewModel::IsContainer(const wxDataViewItem &item) const
+{
+	// the invisible root node can have children
+	if (!item.IsOk())
+		return true;
+
+	PrusaObjectDataViewModelNode *node = (PrusaObjectDataViewModelNode*)item.GetID();
+	return node->IsContainer();
+}
+
+unsigned int PrusaObjectDataViewModel::GetChildren(const wxDataViewItem &parent, wxDataViewItemArray &array) const
+{
+	PrusaObjectDataViewModelNode *node = (PrusaObjectDataViewModelNode*)parent.GetID();
+	if (!node)
+	{
+		for (auto object : m_objects)
+			array.Add(wxDataViewItem((void*)object));
+		return m_objects.size();
+	}
+
+	if (node->GetChildCount() == 0)
+	{
+		return 0;
+	}
+
+	unsigned int count = node->GetChildren().GetCount();
+	for (unsigned int pos = 0; pos < count; pos++)
+	{
+		PrusaObjectDataViewModelNode *child = node->GetChildren().Item(pos);
+		array.Add(wxDataViewItem((void*)child));
+	}
+
+	return count;
+}
+
+// ************************************** EXPERIMENTS ***************************************
+PrusaDoubleSlider::PrusaDoubleSlider(   wxWindow *parent,
+                                        wxWindowID id,
+                                        int lowerValue, 
+                                        int higherValue, 
+                                        int minValue, 
+                                        int maxValue,
+                                        const wxPoint& pos,
+                                        const wxSize& size,
+                                        long style,
+                                        const wxValidator& val,
+                                        const wxString& name) : 
+    wxControl(parent, id, pos, size, wxWANTS_CHARS | wxBORDER_NONE),
+    m_lower_value(lowerValue), m_higher_value (higherValue), 
+    m_min_value(minValue), m_max_value(maxValue),
+    m_style(style == wxSL_HORIZONTAL || style == wxSL_VERTICAL ? style: wxSL_HORIZONTAL)
+{
+#ifndef __WXOSX__ // SetDoubleBuffered exists on Win and Linux/GTK, but is missing on OSX
+    SetDoubleBuffered(true);
+#endif //__WXOSX__
+
+    m_bmp_thumb_higher = wxBitmap(style == wxSL_HORIZONTAL ? Slic3r::GUI::from_u8(Slic3r::var("right_half_circle.png")) :
+                                                             Slic3r::GUI::from_u8(Slic3r::var("up_half_circle.png")), wxBITMAP_TYPE_PNG);
+    m_bmp_thumb_lower  = wxBitmap(style == wxSL_HORIZONTAL ? Slic3r::GUI::from_u8(Slic3r::var("left_half_circle.png")) :
+                                                             Slic3r::GUI::from_u8(Slic3r::var("down_half_circle.png")), wxBITMAP_TYPE_PNG);
+    m_thumb_size = m_bmp_thumb_lower.GetSize();
+
+    m_bmp_add_tick_on  = wxBitmap(Slic3r::GUI::from_u8(Slic3r::var("colorchange_add_on.png")), wxBITMAP_TYPE_PNG);
+    m_bmp_add_tick_off = wxBitmap(Slic3r::GUI::from_u8(Slic3r::var("colorchange_add_off.png")), wxBITMAP_TYPE_PNG);
+    m_bmp_del_tick_on  = wxBitmap(Slic3r::GUI::from_u8(Slic3r::var("colorchange_delete_on.png")), wxBITMAP_TYPE_PNG);
+    m_bmp_del_tick_off = wxBitmap(Slic3r::GUI::from_u8(Slic3r::var("colorchange_delete_off.png")), wxBITMAP_TYPE_PNG);
+    m_tick_icon_dim = m_bmp_add_tick_on.GetSize().x;
+
+    m_bmp_one_layer_lock_on    = wxBitmap(Slic3r::GUI::from_u8(Slic3r::var("one_layer_lock_on.png")), wxBITMAP_TYPE_PNG);
+    m_bmp_one_layer_lock_off   = wxBitmap(Slic3r::GUI::from_u8(Slic3r::var("one_layer_lock_off.png")), wxBITMAP_TYPE_PNG);
+    m_bmp_one_layer_unlock_on  = wxBitmap(Slic3r::GUI::from_u8(Slic3r::var("one_layer_unlock_on.png")), wxBITMAP_TYPE_PNG);
+    m_bmp_one_layer_unlock_off = wxBitmap(Slic3r::GUI::from_u8(Slic3r::var("one_layer_unlock_off.png")), wxBITMAP_TYPE_PNG);
+    m_lock_icon_dim = m_bmp_one_layer_lock_on.GetSize().x;
+
+    m_selection = ssUndef;
+
+    // slider events
+    Bind(wxEVT_PAINT,       &PrusaDoubleSlider::OnPaint,    this);
+    Bind(wxEVT_LEFT_DOWN,   &PrusaDoubleSlider::OnLeftDown, this);
+    Bind(wxEVT_MOTION,      &PrusaDoubleSlider::OnMotion,   this);
+    Bind(wxEVT_LEFT_UP,     &PrusaDoubleSlider::OnLeftUp,   this);
+    Bind(wxEVT_MOUSEWHEEL,  &PrusaDoubleSlider::OnWheel,    this);
+    Bind(wxEVT_ENTER_WINDOW,&PrusaDoubleSlider::OnEnterWin, this);
+    Bind(wxEVT_LEAVE_WINDOW,&PrusaDoubleSlider::OnLeaveWin, this);
+    Bind(wxEVT_KEY_DOWN,    &PrusaDoubleSlider::OnKeyDown,  this);
+    Bind(wxEVT_KEY_UP,      &PrusaDoubleSlider::OnKeyUp,    this);
+    Bind(wxEVT_RIGHT_DOWN,  &PrusaDoubleSlider::OnRightDown,this);
+    Bind(wxEVT_RIGHT_UP,    &PrusaDoubleSlider::OnRightUp,  this);
+
+    // control's view variables
+    SLIDER_MARGIN     = 4 + (style == wxSL_HORIZONTAL ? m_bmp_thumb_higher.GetWidth() : m_bmp_thumb_higher.GetHeight());
+
+    DARK_ORANGE_PEN   = wxPen(wxColour(253, 84, 2));
+    ORANGE_PEN        = wxPen(wxColour(253, 126, 66));
+    LIGHT_ORANGE_PEN  = wxPen(wxColour(254, 177, 139));
+
+    DARK_GREY_PEN     = wxPen(wxColour(128, 128, 128));
+    GREY_PEN          = wxPen(wxColour(164, 164, 164));
+    LIGHT_GREY_PEN    = wxPen(wxColour(204, 204, 204));
+
+    line_pens = { &DARK_GREY_PEN, &GREY_PEN, &LIGHT_GREY_PEN };
+    segm_pens = { &DARK_ORANGE_PEN, &ORANGE_PEN, &LIGHT_ORANGE_PEN };
+}
+
+int PrusaDoubleSlider::GetActiveValue() const
+{
+    return m_selection == ssLower ?
+    m_lower_value : m_selection == ssHigher ?
+                m_higher_value : -1;
+}
+
+wxSize PrusaDoubleSlider::DoGetBestSize() const
+{
+    const wxSize size = wxControl::DoGetBestSize();
+    if (size.x > 1 && size.y > 1)
+        return size;
+    const int new_size = is_horizontal() ? 80 : 120;
+    return wxSize(new_size, new_size);
+}
+
+void PrusaDoubleSlider::SetLowerValue(const int lower_val)
+{
+    m_lower_value = lower_val;
+    Refresh();
+    Update();
+}
+
+void PrusaDoubleSlider::SetHigherValue(const int higher_val)
+{
+    m_higher_value = higher_val;
+    Refresh();
+    Update();
+}
+
+void PrusaDoubleSlider::SetMaxValue(const int max_value)
+{
+    m_max_value = max_value;
+    Refresh();
+    Update();
+}
+
+void PrusaDoubleSlider::draw_scroll_line(wxDC& dc, const int lower_pos, const int higher_pos)
+{
+    int width;
+    int height;
+    get_size(&width, &height);
+
+    wxCoord line_beg_x = is_horizontal() ? SLIDER_MARGIN : width*0.5 - 1;
+    wxCoord line_beg_y = is_horizontal() ? height*0.5 - 1 : SLIDER_MARGIN;
+    wxCoord line_end_x = is_horizontal() ? width - SLIDER_MARGIN + 1 : width*0.5 - 1;
+    wxCoord line_end_y = is_horizontal() ? height*0.5 - 1 : height - SLIDER_MARGIN + 1;
+
+    wxCoord segm_beg_x = is_horizontal() ? lower_pos : width*0.5 - 1;
+    wxCoord segm_beg_y = is_horizontal() ? height*0.5 - 1 : lower_pos-1;
+    wxCoord segm_end_x = is_horizontal() ? higher_pos : width*0.5 - 1;
+    wxCoord segm_end_y = is_horizontal() ? height*0.5 - 1 : higher_pos-1;
+
+    for (int id = 0; id < line_pens.size(); id++)
+    {
+        dc.SetPen(*line_pens[id]);
+        dc.DrawLine(line_beg_x, line_beg_y, line_end_x, line_end_y);
+        dc.SetPen(*segm_pens[id]);
+        dc.DrawLine(segm_beg_x, segm_beg_y, segm_end_x, segm_end_y);
+        if (is_horizontal())
+            line_beg_y = line_end_y = segm_beg_y = segm_end_y += 1;
+        else
+            line_beg_x = line_end_x = segm_beg_x = segm_end_x += 1;
+    }
+}
+
+double PrusaDoubleSlider::get_scroll_step()
+{
+    const wxSize sz = get_size();
+    const int& slider_len = m_style == wxSL_HORIZONTAL ? sz.x : sz.y;
+    return double(slider_len - SLIDER_MARGIN * 2) / (m_max_value - m_min_value);
+}
+
+// get position on the slider line from entered value
+wxCoord PrusaDoubleSlider::get_position_from_value(const int value)
+{
+    const double step = get_scroll_step();
+    const int val = is_horizontal() ? value : m_max_value - value;
+    return wxCoord(SLIDER_MARGIN + int(val*step + 0.5));
+}
+
+wxSize PrusaDoubleSlider::get_size()
+{
+    int w, h;
+    get_size(&w, &h);
+    return wxSize(w, h);
+}
+
+void PrusaDoubleSlider::get_size(int *w, int *h)
+{
+    GetSize(w, h);
+    is_horizontal() ? *w -= m_lock_icon_dim : *h -= m_lock_icon_dim;
+}
+
+void PrusaDoubleSlider::get_lower_and_higher_position(int& lower_pos, int& higher_pos)
+{
+    const double step = get_scroll_step();
+    if (is_horizontal()) {
+        lower_pos = SLIDER_MARGIN + int(m_lower_value*step + 0.5);
+        higher_pos = SLIDER_MARGIN + int(m_higher_value*step + 0.5);
+    }
+    else {
+        lower_pos = SLIDER_MARGIN + int((m_max_value - m_lower_value)*step + 0.5);
+        higher_pos = SLIDER_MARGIN + int((m_max_value - m_higher_value)*step + 0.5);
+    }
+}
+
+void PrusaDoubleSlider::draw_focus_rect()
+{
+    if (!m_is_focused) 
+        return;
+    const wxSize sz = GetSize();
+    wxPaintDC dc(this);
+    const wxPen pen = wxPen(wxColour(128, 128, 10), 1, wxPENSTYLE_DOT);
+    dc.SetPen(pen);
+    dc.SetBrush(wxBrush(wxColour(0, 0, 0), wxBRUSHSTYLE_TRANSPARENT));
+    dc.DrawRectangle(1, 1, sz.x - 2, sz.y - 2);
+}
+
+void PrusaDoubleSlider::render()
+{
+    SetBackgroundColour(GetParent()->GetBackgroundColour());
+    draw_focus_rect();
+
+    wxPaintDC dc(this);
+    wxFont font = dc.GetFont();
+    const wxFont smaller_font = font.Smaller();
+    dc.SetFont(smaller_font);
+
+    const wxCoord lower_pos = get_position_from_value(m_lower_value);
+    const wxCoord higher_pos = get_position_from_value(m_higher_value);
+
+    // draw line
+    draw_scroll_line(dc, lower_pos, higher_pos);
+
+//     //lower slider:
+//     draw_thumb(dc, lower_pos, ssLower);
+//     //higher slider:
+//     draw_thumb(dc, higher_pos, ssHigher);
+
+    // draw both sliders
+    draw_thumbs(dc, lower_pos, higher_pos);
+
+    //draw color print ticks
+    draw_ticks(dc);
+
+    //draw color print ticks
+    draw_one_layer_icon(dc);
+}
+
+void PrusaDoubleSlider::draw_action_icon(wxDC& dc, const wxPoint pt_beg, const wxPoint pt_end)
+{
+    const int tick = m_selection == ssLower ? m_lower_value : m_higher_value;
+    wxBitmap* icon = m_is_action_icon_focesed ? &m_bmp_add_tick_off : &m_bmp_add_tick_on;
+    if (m_ticks.find(tick) != m_ticks.end())
+        icon = m_is_action_icon_focesed ? &m_bmp_del_tick_off : &m_bmp_del_tick_on;
+
+    wxCoord x_draw, y_draw;
+    is_horizontal() ? x_draw = pt_beg.x - 0.5*m_tick_icon_dim : y_draw = pt_beg.y - 0.5*m_tick_icon_dim;
+    if (m_selection == ssLower)
+        is_horizontal() ? y_draw = pt_end.y + 3 : x_draw = pt_beg.x - m_tick_icon_dim-2;
+    else
+        is_horizontal() ? y_draw = pt_beg.y - m_tick_icon_dim-2 : x_draw = pt_end.x + 3;
+
+    dc.DrawBitmap(*icon, x_draw, y_draw);
+
+    //update rect of the tick action icon
+    m_rect_tick_action = wxRect(x_draw, y_draw, m_tick_icon_dim, m_tick_icon_dim);
+}
+
+void PrusaDoubleSlider::draw_info_line_with_icon(wxDC& dc, const wxPoint& pos, const SelectedSlider selection)
+{
+    if (m_selection == selection) {
+        //draw info line
+        dc.SetPen(DARK_ORANGE_PEN);
+        const wxPoint pt_beg = is_horizontal() ? wxPoint(pos.x, pos.y - m_thumb_size.y) : wxPoint(pos.x - m_thumb_size.x, pos.y - 1);
+        const wxPoint pt_end = is_horizontal() ? wxPoint(pos.x, pos.y + m_thumb_size.y) : wxPoint(pos.x + m_thumb_size.x, pos.y - 1);
+        dc.DrawLine(pt_beg, pt_end);
+
+        //draw action icon
+        draw_action_icon(dc, pt_beg, pt_end);
+    }
+}
+
+wxString PrusaDoubleSlider::get_label(const SelectedSlider& selection) const
+{
+    const int value = selection == ssLower ? m_lower_value : m_higher_value;
+
+    if (m_label_koef == 1.0 && m_values.empty())
+        return wxString::Format("%d", value);
+
+    const wxString str = m_values.empty() ? 
+                         wxNumberFormatter::ToString(m_label_koef*value, 2, wxNumberFormatter::Style_None) :
+                         wxNumberFormatter::ToString(m_values[value], 2, wxNumberFormatter::Style_None);
+    return wxString::Format("%s\n(%d)", str, value);
+}
+
+void PrusaDoubleSlider::draw_thumb_text(wxDC& dc, const wxPoint& pos, const SelectedSlider& selection) const
+{
+    if (m_is_one_layer && selection != m_selection || !selection) 
+        return;
+    wxCoord text_width, text_height;
+    const wxString label = get_label(selection);
+    dc.GetMultiLineTextExtent(label, &text_width, &text_height);
+    wxPoint text_pos;
+    if (selection ==ssLower)
+        text_pos = is_horizontal() ? wxPoint(pos.x + 1, pos.y + m_thumb_size.x) :
+                           wxPoint(pos.x + m_thumb_size.x+1, pos.y - 0.5*text_height - 1);
+    else
+        text_pos = is_horizontal() ? wxPoint(pos.x - text_width - 1, pos.y - m_thumb_size.x - text_height) :
+                    wxPoint(pos.x - text_width - 1 - m_thumb_size.x, pos.y - 0.5*text_height + 1);
+    dc.DrawText(label, text_pos);
+}
+
+void PrusaDoubleSlider::draw_thumb_item(wxDC& dc, const wxPoint& pos, const SelectedSlider& selection)
+{
+    wxCoord x_draw, y_draw;
+    if (selection == ssLower) {
+        if (is_horizontal()) {
+            x_draw = pos.x - m_thumb_size.x;
+            y_draw = pos.y - int(0.5*m_thumb_size.y);
+        }
+        else {
+            x_draw = pos.x - int(0.5*m_thumb_size.x);
+            y_draw = pos.y;
+        }
+    }
+    else{
+        if (is_horizontal()) {
+            x_draw = pos.x;
+            y_draw = pos.y - int(0.5*m_thumb_size.y);
+        }
+        else {
+            x_draw = pos.x - int(0.5*m_thumb_size.x);
+            y_draw = pos.y - m_thumb_size.y;
+        }
+    }
+    dc.DrawBitmap(selection == ssLower ? m_bmp_thumb_lower : m_bmp_thumb_higher, x_draw, y_draw);
+
+    // Update thumb rect
+    update_thumb_rect(x_draw, y_draw, selection);
+}
+
+void PrusaDoubleSlider::draw_thumb(wxDC& dc, const wxCoord& pos_coord, const SelectedSlider& selection)
+{
+    //calculate thumb position on slider line
+    int width, height;
+    get_size(&width, &height);
+    const wxPoint pos = is_horizontal() ? wxPoint(pos_coord, height*0.5) : wxPoint(0.5*width, pos_coord);
+
+    // Draw thumb
+    draw_thumb_item(dc, pos, selection);
+
+    // Draw info_line
+    draw_info_line_with_icon(dc, pos, selection);
+
+    // Draw thumb text
+    draw_thumb_text(dc, pos, selection);
+}
+
+void PrusaDoubleSlider::draw_thumbs(wxDC& dc, const wxCoord& lower_pos, const wxCoord& higher_pos)
+{
+    //calculate thumb position on slider line
+    int width, height;
+    get_size(&width, &height);
+    const wxPoint pos_l = is_horizontal() ? wxPoint(lower_pos, height*0.5) : wxPoint(0.5*width, lower_pos);
+    const wxPoint pos_h = is_horizontal() ? wxPoint(higher_pos, height*0.5) : wxPoint(0.5*width, higher_pos);
+
+    // Draw lower thumb
+    draw_thumb_item(dc, pos_l, ssLower);
+    // Draw lower info_line
+    draw_info_line_with_icon(dc, pos_l, ssLower);
+
+    // Draw higher thumb
+    draw_thumb_item(dc, pos_h, ssHigher);
+    // Draw higher info_line
+    draw_info_line_with_icon(dc, pos_h, ssHigher);
+    // Draw higher thumb text
+    draw_thumb_text(dc, pos_h, ssHigher);
+
+    // Draw lower thumb text
+    draw_thumb_text(dc, pos_l, ssLower);
+}
+
+void PrusaDoubleSlider::draw_ticks(wxDC& dc)
+{
+    dc.SetPen(DARK_GREY_PEN);
+    int height, width;
+    get_size(&width, &height);
+    const wxCoord mid = is_horizontal() ? 0.5*height : 0.5*width;
+    for (auto tick : m_ticks)
+    {
+        const wxCoord pos = get_position_from_value(tick);
+
+        is_horizontal() ?   dc.DrawLine(pos, mid-14, pos, mid-9) :
+                            dc.DrawLine(mid - 14, pos - 1, mid - 9, pos - 1);
+        is_horizontal() ?   dc.DrawLine(pos, mid+14, pos, mid+9) :
+                            dc.DrawLine(mid + 14, pos - 1, mid + 9, pos - 1);
+    }
+}
+
+void PrusaDoubleSlider::draw_one_layer_icon(wxDC& dc)
+{
+    wxBitmap* icon = m_is_one_layer ?
+                     m_is_one_layer_icon_focesed ? &m_bmp_one_layer_lock_off : &m_bmp_one_layer_lock_on :
+                     m_is_one_layer_icon_focesed ? &m_bmp_one_layer_unlock_off : &m_bmp_one_layer_unlock_on;
+
+    int width, height;
+    get_size(&width, &height);
+
+    wxCoord x_draw, y_draw;
+    is_horizontal() ? x_draw = width-2 : x_draw = 0.5*width - 0.5*m_lock_icon_dim;
+    is_horizontal() ? y_draw = 0.5*height - 0.5*m_lock_icon_dim : y_draw = height-2;
+
+    dc.DrawBitmap(*icon, x_draw, y_draw);
+
+    //update rect of the lock/unlock icon
+    m_rect_one_layer_icon = wxRect(x_draw, y_draw, m_lock_icon_dim, m_lock_icon_dim);
+}
+
+void PrusaDoubleSlider::update_thumb_rect(const wxCoord& begin_x, const wxCoord& begin_y, const SelectedSlider& selection)
+{
+    const wxRect& rect = wxRect(begin_x, begin_y, m_thumb_size.x, m_thumb_size.y);
+    if (selection == ssLower)
+        m_rect_lower_thumb = rect;
+    else
+        m_rect_higher_thumb = rect;
+}
+
+int PrusaDoubleSlider::get_value_from_position(const wxCoord x, const wxCoord y)
+{
+    const int height = get_size().y;
+    const double step = get_scroll_step();
+    
+    if (is_horizontal()) 
+        return int(double(x - SLIDER_MARGIN) / step + 0.5);
+    else 
+        return int(m_min_value + double(height - SLIDER_MARGIN - y) / step + 0.5);
+}
+
+void PrusaDoubleSlider::detect_selected_slider(const wxPoint& pt, const bool is_mouse_wheel /*= false*/)
+{
+    if (is_mouse_wheel)
+    {
+        if (is_horizontal()) {
+            m_selection = pt.x <= m_rect_lower_thumb.GetRight() ? ssLower :
+                          pt.x >= m_rect_higher_thumb.GetLeft() ? ssHigher : ssUndef;
+        }
+        else {
+            m_selection = pt.y >= m_rect_lower_thumb.GetTop() ? ssLower :
+                          pt.y <= m_rect_higher_thumb.GetBottom() ? ssHigher : ssUndef;            
+        }
+        return;
+    }
+
+    m_selection = is_point_in_rect(pt, m_rect_lower_thumb) ? ssLower :
+                  is_point_in_rect(pt, m_rect_higher_thumb) ? ssHigher : ssUndef;
+}
+
+bool PrusaDoubleSlider::is_point_in_rect(const wxPoint& pt, const wxRect& rect)
+{
+    if (rect.GetLeft() <= pt.x && pt.x <= rect.GetRight() && 
+        rect.GetTop()  <= pt.y && pt.y <= rect.GetBottom())
+        return true;
+    return false;
+}
+
+void PrusaDoubleSlider::OnLeftDown(wxMouseEvent& event)
+{
+    this->CaptureMouse();
+    wxClientDC dc(this);
+    wxPoint pos = event.GetLogicalPosition(dc);
+    if (is_point_in_rect(pos, m_rect_tick_action)) {
+        action_tick(taOnIcon);
+        return;
+    }
+
+    m_is_left_down = true;
+    if (is_point_in_rect(pos, m_rect_one_layer_icon)){
+        m_is_one_layer = !m_is_one_layer;
+        m_selection == ssLower ? correct_lower_value() : correct_higher_value();
+        if (!m_selection) m_selection = ssHigher;
+    }
+    else
+        detect_selected_slider(pos);
+
+    Refresh();
+    Update();
+    event.Skip();
+}
+
+void PrusaDoubleSlider::correct_lower_value()
+{
+    if (m_lower_value < m_min_value)
+        m_lower_value = m_min_value;
+    else if (m_lower_value > m_max_value)
+        m_lower_value = m_max_value;
+    
+    if (m_lower_value >= m_higher_value && m_lower_value <= m_max_value || m_is_one_layer)
+        m_higher_value = m_lower_value;
+}
+
+void PrusaDoubleSlider::correct_higher_value()
+{
+    if (m_higher_value > m_max_value)
+        m_higher_value = m_max_value;
+    else if (m_higher_value < m_min_value)
+        m_higher_value = m_min_value;
+    
+    if (m_higher_value <= m_lower_value && m_higher_value >= m_min_value || m_is_one_layer)
+        m_lower_value = m_higher_value;
+}
+
+void PrusaDoubleSlider::OnMotion(wxMouseEvent& event)
+{
+    const wxClientDC dc(this);
+    const wxPoint pos = event.GetLogicalPosition(dc);
+    m_is_one_layer_icon_focesed = is_point_in_rect(pos, m_rect_one_layer_icon);
+    if (!m_is_left_down && !m_is_one_layer){
+        m_is_action_icon_focesed = is_point_in_rect(pos, m_rect_tick_action);
+    }
+    else if (m_is_left_down || m_is_right_down){
+        if (m_selection == ssLower) {
+            m_lower_value = get_value_from_position(pos.x, pos.y);
+            correct_lower_value();
+        }
+        else if (m_selection == ssHigher) {
+            m_higher_value = get_value_from_position(pos.x, pos.y);
+            correct_higher_value();
+        }
+    }
+    Refresh();
+    Update();
+    event.Skip();
+}
+
+void PrusaDoubleSlider::OnLeftUp(wxMouseEvent& event)
+{
+    this->ReleaseMouse();
+    m_is_left_down = false;
+    Refresh();
+    Update();
+    event.Skip();
+
+    wxCommandEvent e(wxEVT_SCROLL_CHANGED);
+    e.SetEventObject(this);
+    ProcessWindowEvent(e);
+}
+
+void PrusaDoubleSlider::enter_window(wxMouseEvent& event, const bool enter)
+{
+    m_is_focused = enter;
+    Refresh();
+    Update();
+    event.Skip();
+}
+
+// "condition" have to be true for:
+//    -  value increase (if wxSL_VERTICAL)
+//    -  value decrease (if wxSL_HORIZONTAL) 
+void PrusaDoubleSlider::move_current_thumb(const bool condition)
+{
+    m_is_one_layer = wxGetKeyState(WXK_CONTROL);
+    int delta = condition ? -1 : 1;
+    if (is_horizontal())
+        delta *= -1;
+
+    if (m_selection == ssLower) {
+        m_lower_value -= delta;
+        correct_lower_value();
+    }
+    else if (m_selection == ssHigher) {
+        m_higher_value -= delta;
+        correct_higher_value();
+    }
+    Refresh();
+    Update();
+
+    wxCommandEvent e(wxEVT_SCROLL_CHANGED);
+    e.SetEventObject(this);
+    ProcessWindowEvent(e);
+}
+
+void PrusaDoubleSlider::action_tick(const TicksAction action)
+{
+    if (m_selection == ssUndef)
+        return;
+
+    const int tick = m_selection == ssLower ? m_lower_value : m_higher_value;
+
+    if (action == taOnIcon && !m_ticks.insert(tick).second)
+        m_ticks.erase(tick);
+    else {
+        const auto it = m_ticks.find(tick);
+        if (it == m_ticks.end() && action == taAdd)
+            m_ticks.insert(tick);
+        else if (it != m_ticks.end() && action == taDel)
+            m_ticks.erase(tick);
+        else
+            return;
+    }
+
+    Refresh();
+    Update();
+}
+
+void PrusaDoubleSlider::OnWheel(wxMouseEvent& event)
+{
+    wxClientDC dc(this);
+    wxPoint pos = event.GetLogicalPosition(dc);
+    detect_selected_slider(pos, true);
+
+    if (m_selection == ssUndef)
+        return;
+
+    move_current_thumb(event.GetWheelRotation() > 0);
+}
+
+void PrusaDoubleSlider::OnKeyDown(wxKeyEvent &event)
+{
+    const int key = event.GetKeyCode();
+    if (key == '+' || key == WXK_NUMPAD_ADD)
+        action_tick(taAdd);
+    else if (key == '-' || key == 390 || key == WXK_DELETE || key == WXK_BACK)
+        action_tick(taDel);
+    else if (is_horizontal())
+    {
+        if (key == WXK_LEFT || key == WXK_RIGHT)
+            move_current_thumb(key == WXK_LEFT); 
+        else if (key == WXK_UP || key == WXK_DOWN){
+            m_selection = key == WXK_UP ? ssHigher : ssLower;
+            Refresh();
+        }
+    }
+    else {
+        if (key == WXK_LEFT || key == WXK_RIGHT) {
+            m_selection = key == WXK_LEFT ? ssHigher : ssLower;
+            Refresh();
+        }
+        else if (key == WXK_UP || key == WXK_DOWN)
+            move_current_thumb(key == WXK_UP);
+    }
+}
+
+void PrusaDoubleSlider::OnKeyUp(wxKeyEvent &event)
+{
+    if (event.GetKeyCode() == WXK_CONTROL)
+        m_is_one_layer = false;
+    Refresh();
+    Update();
+    event.Skip();
+}
+
+void PrusaDoubleSlider::OnRightDown(wxMouseEvent& event)
+{
+    this->CaptureMouse();
+    const wxClientDC dc(this);
+    detect_selected_slider(event.GetLogicalPosition(dc));
+    if (!m_selection)
+        return;
+
+    if (m_selection == ssLower)
+        m_higher_value = m_lower_value;
+    else
+        m_lower_value = m_higher_value;
+
+    m_is_right_down = m_is_one_layer = true;
+
+    Refresh();
+    Update();
+    event.Skip();
+}
+
+void PrusaDoubleSlider::OnRightUp(wxMouseEvent& event)
+{
+    this->ReleaseMouse();
+    m_is_right_down = m_is_one_layer = false;
+
+    Refresh();
+    Update();
+    event.Skip();
+}
+
+// *****************************************************************************
diff --git a/xs/src/slic3r/GUI/wxExtensions.hpp b/xs/src/slic3r/GUI/wxExtensions.hpp
index 3667c7905..064ce1038 100644
--- a/xs/src/slic3r/GUI/wxExtensions.hpp
+++ b/xs/src/slic3r/GUI/wxExtensions.hpp
@@ -4,6 +4,14 @@
 #include <wx/checklst.h>
 #include <wx/combo.h>
 #include <wx/dataview.h>
+#include <wx/dc.h>
+#include <wx/collpane.h>
+#include <wx/wupdlock.h>
+#include <wx/button.h>
+#include <wx/slider.h>
+
+#include <vector>
+#include <set>
 
 class wxCheckListBoxComboPopup : public wxCheckListBox, public wxComboPopup
 {
@@ -65,4 +73,568 @@ public:
 	void				SetItemsCnt(int cnt) { m_cnt_open_items = cnt; }
 };
 
+
+
+// ***  PrusaCollapsiblePane  *** 
+// ----------------------------------------------------------------------------
+class PrusaCollapsiblePane : public wxCollapsiblePane
+{
+public:
+	PrusaCollapsiblePane() {}
+	PrusaCollapsiblePane(wxWindow *parent,
+		wxWindowID winid,
+		const wxString& label,
+		const wxPoint& pos = wxDefaultPosition,
+		const wxSize& size = wxDefaultSize,
+		long style = wxCP_DEFAULT_STYLE,
+		const wxValidator& val = wxDefaultValidator,
+		const wxString& name = wxCollapsiblePaneNameStr)
+	{
+		Create(parent, winid, label, pos, size, style, val, name);
+	}
+	~PrusaCollapsiblePane() {}
+
+	void OnStateChange(const wxSize& sz); //override/hide of OnStateChange from wxCollapsiblePane
+	virtual bool Show(bool show = true) override {
+		wxCollapsiblePane::Show(show);
+		OnStateChange(GetBestSize());
+		return true;
+	}
+};
+
+
+// ***  PrusaCollapsiblePaneMSW  ***  used only #ifdef __WXMSW__
+// ----------------------------------------------------------------------------
+#ifdef __WXMSW__
+class PrusaCollapsiblePaneMSW : public PrusaCollapsiblePane//wxCollapsiblePane
+{
+	wxButton*	m_pDisclosureTriangleButton = nullptr;
+	wxBitmap	m_bmp_close;
+	wxBitmap	m_bmp_open;
+public:
+	PrusaCollapsiblePaneMSW() {}
+	PrusaCollapsiblePaneMSW(	wxWindow *parent,
+							wxWindowID winid,
+							const wxString& label,
+							const wxPoint& pos = wxDefaultPosition,
+							const wxSize& size = wxDefaultSize,
+							long style = wxCP_DEFAULT_STYLE,
+							const wxValidator& val = wxDefaultValidator,
+							const wxString& name = wxCollapsiblePaneNameStr)
+	{
+		Create(parent, winid, label, pos, size, style, val, name);
+	}
+
+	~PrusaCollapsiblePaneMSW() {}
+
+	bool Create(wxWindow *parent,
+				wxWindowID id,
+				const wxString& label,
+				const wxPoint& pos,
+				const wxSize& size,
+				long style,
+				const wxValidator& val,
+				const wxString& name);
+
+	void UpdateBtnBmp();
+	void SetLabel(const wxString &label) override;
+	bool Layout() override;
+	void Collapse(bool collapse) override;
+};
+#endif //__WXMSW__
+
+// *****************************************************************************
+// ----------------------------------------------------------------------------
+// PrusaObjectDataViewModelNode: a node inside PrusaObjectDataViewModel
+// ----------------------------------------------------------------------------
+
+class PrusaObjectDataViewModelNode;
+WX_DEFINE_ARRAY_PTR(PrusaObjectDataViewModelNode*, MyObjectTreeModelNodePtrArray);
+
+class PrusaObjectDataViewModelNode
+{
+	PrusaObjectDataViewModelNode*	m_parent;
+	MyObjectTreeModelNodePtrArray   m_children;
+    wxIcon                          m_empty_icon; 
+public:
+	PrusaObjectDataViewModelNode(const wxString &name, int instances_count=1, int scale=100) {
+		m_parent	= NULL;
+		m_name		= name;
+		m_copy		= wxString::Format("%d", instances_count);
+		m_scale		= wxString::Format("%d%%", scale);
+		m_type		= "object";
+		m_volume_id	= -1;
+#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_object_action_icon();
+	}
+
+	PrusaObjectDataViewModelNode(	PrusaObjectDataViewModelNode* parent,
+									const wxString& sub_obj_name, 
+									const wxIcon& icon, 
+                                    const wxString& extruder, 
+									const int volume_id=-1) {
+		m_parent	= parent;
+		m_name		= sub_obj_name;
+		m_copy		= wxEmptyString;
+		m_scale		= wxEmptyString;
+		m_icon		= icon;
+		m_type		= "volume";
+		m_volume_id = volume_id;
+        m_extruder  = extruder;
+		set_part_action_icon();
+	}
+
+	~PrusaObjectDataViewModelNode()
+	{
+		// free all our children nodes
+		size_t count = m_children.GetCount();
+		for (size_t i = 0; i < count; i++)
+		{
+			PrusaObjectDataViewModelNode *child = m_children[i];
+			delete child;
+		}
+	}
+	
+	wxString				m_name;
+	wxIcon&					m_icon = m_empty_icon;
+	wxString				m_copy;
+	wxString				m_scale;
+	std::string				m_type;
+	int						m_volume_id;
+	bool					m_container = false;
+	wxString				m_extruder = "default";
+	wxBitmap				m_action_icon;
+
+	bool IsContainer() const
+	{
+		return m_container;
+	}
+
+	PrusaObjectDataViewModelNode* GetParent()
+	{
+		return m_parent;
+	}
+	MyObjectTreeModelNodePtrArray& GetChildren()
+	{
+		return m_children;
+	}
+	PrusaObjectDataViewModelNode* GetNthChild(unsigned int n)
+	{
+		return m_children.Item(n);
+	}
+	void Insert(PrusaObjectDataViewModelNode* child, unsigned int n)
+	{
+		m_children.Insert(child, n);
+	}
+	void Append(PrusaObjectDataViewModelNode* child)
+	{
+		if (!m_container)
+			m_container = true;
+		m_children.Add(child);
+	}
+	void RemoveAllChildren()
+	{
+		if (GetChildCount() == 0)
+			return;
+		for (size_t id = GetChildCount() - 1; id >= 0; --id)
+		{
+			if (m_children.Item(id)->GetChildCount() > 0)
+				m_children[id]->RemoveAllChildren();
+			auto node = m_children[id];
+			m_children.RemoveAt(id);
+			delete node;
+		}
+	}
+
+	size_t GetChildCount() const
+	{
+		return m_children.GetCount();
+	}
+
+	bool SetValue(const wxVariant &variant, unsigned int col)
+	{
+		switch (col)
+		{
+		case 0:{
+			wxDataViewIconText data;
+			data << variant;
+			m_icon = data.GetIcon();
+			m_name = data.GetText();
+			return true;}
+		case 1:
+			m_copy = variant.GetString();
+			return true;
+		case 2:
+			m_scale = variant.GetString();
+			return true;
+		case 3:
+			m_extruder = variant.GetString();
+			return true;
+		case 4:
+			m_action_icon << variant;
+			return true;
+		default:
+			printf("MyObjectTreeModel::SetValue: wrong column");
+		}
+		return false;
+	}
+	void SetIcon(const wxIcon &icon)
+	{
+		m_icon = icon;
+	}
+	
+	void SetType(const std::string& type){
+		m_type = type;
+	}	
+	const std::string& GetType(){
+		return m_type;
+	}
+
+	void SetVolumeId(const int& volume_id){
+		m_volume_id = volume_id;
+	}
+	const int& GetVolumeId(){
+		return m_volume_id;
+	}
+
+	// use this function only for childrens
+	void AssignAllVal(PrusaObjectDataViewModelNode& from_node)
+	{
+		// ! Don't overwrite other values because of equality of this values for all children --
+		m_name = from_node.m_name;
+		m_icon = from_node.m_icon;
+		m_volume_id = from_node.m_volume_id;
+		m_extruder = from_node.m_extruder;
+	}
+
+	bool SwapChildrens(int frst_id, int scnd_id) {
+		if (GetChildCount() < 2 || 
+			frst_id < 0 || frst_id >= GetChildCount() || 
+			scnd_id < 0 || scnd_id >= GetChildCount())
+			return false;
+
+		PrusaObjectDataViewModelNode new_scnd = *GetNthChild(frst_id);
+		PrusaObjectDataViewModelNode new_frst = *GetNthChild(scnd_id);
+
+		new_scnd.m_volume_id = m_children.Item(scnd_id)->m_volume_id;
+		new_frst.m_volume_id = m_children.Item(frst_id)->m_volume_id;
+
+		m_children.Item(frst_id)->AssignAllVal(new_frst);
+		m_children.Item(scnd_id)->AssignAllVal(new_scnd);
+		return true;
+	}
+
+	// Set action icons for node
+	void set_object_action_icon();
+	void set_part_action_icon();
+};
+
+// ----------------------------------------------------------------------------
+// PrusaObjectDataViewModel
+// ----------------------------------------------------------------------------
+
+class PrusaObjectDataViewModel :public wxDataViewModel
+{
+	std::vector<PrusaObjectDataViewModelNode*> m_objects;
+public:
+	PrusaObjectDataViewModel(){}
+	~PrusaObjectDataViewModel()
+	{
+		for (auto object : m_objects)
+			delete object;		
+	}
+
+	wxDataViewItem Add(wxString &name);
+	wxDataViewItem Add(wxString &name, int instances_count, int scale);
+	wxDataViewItem AddChild(const wxDataViewItem &parent_item, 
+							const wxString &name, 
+                            const wxIcon& icon,
+                            const int = 0,
+                            const bool create_frst_child = true);
+	wxDataViewItem Delete(const wxDataViewItem &item);
+	void DeleteAll();
+    void DeleteChildren(wxDataViewItem& parent);
+	wxDataViewItem GetItemById(int obj_idx);
+	int GetIdByItem(wxDataViewItem& item);
+	int GetVolumeIdByItem(wxDataViewItem& item);
+	bool IsEmpty() { return m_objects.empty(); }
+
+	// helper method for wxLog
+
+	wxString GetName(const wxDataViewItem &item) const;
+	wxString GetCopy(const wxDataViewItem &item) const;
+	wxString GetScale(const wxDataViewItem &item) const;
+	wxIcon&  GetIcon(const wxDataViewItem &item) const;
+
+	// helper methods to change the model
+
+	virtual unsigned int GetColumnCount() const override { return 3;}
+	virtual wxString GetColumnType(unsigned int col) const override{ return wxT("string"); }
+
+	virtual void GetValue(wxVariant &variant,
+		const wxDataViewItem &item, unsigned int col) const override;
+	virtual bool SetValue(const wxVariant &variant,
+		const wxDataViewItem &item, unsigned int col) override;
+	bool SetValue(const wxVariant &variant, const int item_idx, unsigned int col);
+
+	wxDataViewItem MoveChildUp(const wxDataViewItem &item);
+	wxDataViewItem MoveChildDown(const wxDataViewItem &item);
+    // For parent move child from cur_volume_id place to new_volume_id 
+    // Remaining items will moved up/down accordingly
+    wxDataViewItem ReorganizeChildren(int cur_volume_id, 
+                                      int new_volume_id,
+                                      const wxDataViewItem &parent);
+
+// 	virtual bool IsEnabled(const wxDataViewItem &item,
+// 		unsigned int col) const override;
+
+	virtual wxDataViewItem GetParent(const wxDataViewItem &item) const override;
+	virtual bool IsContainer(const wxDataViewItem &item) const override;
+	virtual unsigned int GetChildren(const wxDataViewItem &parent,
+		wxDataViewItemArray &array) const override;
+
+	// Is the container just a header or an item with all columns
+	// In our case it is an item with all columns 
+	virtual bool HasContainerColumns(const wxDataViewItem& WXUNUSED(item)) const override {	return true; }
+};
+
+
+
+// ----------------------------------------------------------------------------
+// MyCustomRenderer
+// ----------------------------------------------------------------------------
+
+class MyCustomRenderer : public wxDataViewCustomRenderer
+{
+public:
+	// This renderer can be either activatable or editable, for demonstration
+	// purposes. In real programs, you should select whether the user should be
+	// able to activate or edit the cell and it doesn't make sense to switch
+	// between the two -- but this is just an example, so it doesn't stop us.
+	explicit MyCustomRenderer(wxDataViewCellMode mode)
+		: wxDataViewCustomRenderer("string", mode, wxALIGN_CENTER)
+	{ }
+
+	virtual bool Render(wxRect rect, wxDC *dc, int state) override/*wxOVERRIDE*/
+	{
+		dc->SetBrush(*wxLIGHT_GREY_BRUSH);
+		dc->SetPen(*wxTRANSPARENT_PEN);
+
+		rect.Deflate(2);
+		dc->DrawRoundedRectangle(rect, 5);
+
+		RenderText(m_value,
+			0, // no offset
+			wxRect(dc->GetTextExtent(m_value)).CentreIn(rect),
+			dc,
+			state);
+		return true;
+	}
+
+		virtual bool ActivateCell(const wxRect& WXUNUSED(cell),
+		wxDataViewModel *WXUNUSED(model),
+		const wxDataViewItem &WXUNUSED(item),
+		unsigned int WXUNUSED(col),
+		const wxMouseEvent *mouseEvent) override/*wxOVERRIDE*/
+	{
+		wxString position;
+		if (mouseEvent)
+			position = wxString::Format("via mouse at %d, %d", mouseEvent->m_x, mouseEvent->m_y);
+		else
+			position = "from keyboard";
+//		wxLogMessage("MyCustomRenderer ActivateCell() %s", position);
+		return false;
+	}
+
+		virtual wxSize GetSize() const override/*wxOVERRIDE*/
+	{
+		return wxSize(60, 20);
+	}
+
+		virtual bool SetValue(const wxVariant &value) override/*wxOVERRIDE*/
+	{
+		m_value = value.GetString();
+		return true;
+	}
+
+		virtual bool GetValue(wxVariant &WXUNUSED(value)) const override/*wxOVERRIDE*/{ return true; }
+
+		virtual bool HasEditorCtrl() const override/*wxOVERRIDE*/{ return true; }
+
+		virtual wxWindow*
+		CreateEditorCtrl(wxWindow* parent,
+		wxRect labelRect,
+		const wxVariant& value) override/*wxOVERRIDE*/
+	{
+		wxTextCtrl* text = new wxTextCtrl(parent, wxID_ANY, value,
+		labelRect.GetPosition(),
+		labelRect.GetSize(),
+		wxTE_PROCESS_ENTER);
+		text->SetInsertionPointEnd();
+
+		return text;
+	}
+
+		virtual bool
+			GetValueFromEditorCtrl(wxWindow* ctrl, wxVariant& value) override/*wxOVERRIDE*/
+	{
+		wxTextCtrl* text = wxDynamicCast(ctrl, wxTextCtrl);
+		if (!text)
+			return false;
+
+		value = text->GetValue();
+
+		return true;
+	}
+
+private:
+	wxString m_value;
+};
+// ******************************* EXPERIMENTS **********************************************
+enum SelectedSlider {
+    ssUndef,
+    ssLower,
+    ssHigher
+};
+enum TicksAction{
+    taOnIcon,
+    taAdd,
+    taDel
+};
+class PrusaDoubleSlider : public wxControl
+{
+public:
+    PrusaDoubleSlider(
+        wxWindow *parent,
+        wxWindowID id,
+        int lowerValue, 
+        int higherValue, 
+        int minValue, 
+        int maxValue,
+        const wxPoint& pos = wxDefaultPosition,
+        const wxSize& size = wxDefaultSize,
+        long style = wxSL_HORIZONTAL,
+        const wxValidator& val = wxDefaultValidator,
+        const wxString& name = wxEmptyString);
+
+    int GetLowerValue() const {
+        return m_lower_value;
+    }
+    int GetHigherValue() const {
+        return m_higher_value;
+    }
+    int GetActiveValue() const;
+    wxSize DoGetBestSize() const override;
+    void SetLowerValue(const int lower_val);
+    void SetHigherValue(const int higher_val);
+    void SetMaxValue(const int max_value);
+    void SetKoefForLabels(const double koef) {
+        m_label_koef = koef;
+    }
+    void SetSliderValues(const std::vector<double>& values) {
+        m_values = values;
+    }
+
+    void OnPaint(wxPaintEvent& ){ render();}
+    void OnLeftDown(wxMouseEvent& event);
+    void OnMotion(wxMouseEvent& event);
+    void OnLeftUp(wxMouseEvent& event);
+    void OnEnterWin(wxMouseEvent& event){ enter_window(event, true); }
+    void OnLeaveWin(wxMouseEvent& event){ enter_window(event, false); }
+    void OnWheel(wxMouseEvent& event);
+    void OnKeyDown(wxKeyEvent &event);
+    void OnKeyUp(wxKeyEvent &event);
+    void OnRightDown(wxMouseEvent& event);
+    void OnRightUp(wxMouseEvent& event);
+
+protected:
+ 
+    void    render();
+    void    draw_focus_rect();
+    void    draw_action_icon(wxDC& dc, const wxPoint pt_beg, const wxPoint pt_end);
+    void    draw_scroll_line(wxDC& dc, const int lower_pos, const int higher_pos);
+    void    draw_thumb(wxDC& dc, const wxCoord& pos_coord, const SelectedSlider& selection);
+    void    draw_thumbs(wxDC& dc, const wxCoord& lower_pos, const wxCoord& higher_pos);
+    void    draw_ticks(wxDC& dc);
+    void    draw_one_layer_icon(wxDC& dc);
+    void    draw_thumb_item(wxDC& dc, const wxPoint& pos, const SelectedSlider& selection);
+    void    draw_info_line_with_icon(wxDC& dc, const wxPoint& pos, SelectedSlider selection);
+    void    draw_thumb_text(wxDC& dc, const wxPoint& pos, const SelectedSlider& selection) const;
+
+    void    update_thumb_rect(const wxCoord& begin_x, const wxCoord& begin_y, const SelectedSlider& selection);
+    void    detect_selected_slider(const wxPoint& pt, const bool is_mouse_wheel = false);
+    void    correct_lower_value();
+    void    correct_higher_value();
+    void    move_current_thumb(const bool condition);
+    void    action_tick(const TicksAction action);
+    void    enter_window(wxMouseEvent& event, const bool enter);
+
+    bool    is_point_in_rect(const wxPoint& pt, const wxRect& rect);
+    bool    is_horizontal() const { return m_style == wxSL_HORIZONTAL; }
+
+    double      get_scroll_step();
+    wxString    get_label(const SelectedSlider& selection) const;
+    void        get_lower_and_higher_position(int& lower_pos, int& higher_pos);
+    int         get_value_from_position(const wxCoord x, const wxCoord y);
+    wxCoord     get_position_from_value(const int value);
+    wxSize      get_size();
+    void        get_size(int *w, int *h);
+
+private:
+    int         m_min_value;
+    int         m_max_value;
+    int         m_lower_value;
+    int         m_higher_value;
+    wxBitmap    m_bmp_thumb_higher;
+    wxBitmap    m_bmp_thumb_lower;
+    wxBitmap    m_bmp_add_tick_on;
+    wxBitmap    m_bmp_add_tick_off;
+    wxBitmap    m_bmp_del_tick_on;
+    wxBitmap    m_bmp_del_tick_off;
+    wxBitmap    m_bmp_one_layer_lock_on;
+    wxBitmap    m_bmp_one_layer_lock_off;
+    wxBitmap    m_bmp_one_layer_unlock_on;
+    wxBitmap    m_bmp_one_layer_unlock_off;
+    SelectedSlider  m_selection;
+    bool        m_is_left_down = false;
+    bool        m_is_right_down = false;
+    bool        m_is_one_layer = false;
+    bool        m_is_focused = false;
+    bool        m_is_action_icon_focesed = false;
+    bool        m_is_one_layer_icon_focesed = false;
+
+    wxRect      m_rect_lower_thumb;
+    wxRect      m_rect_higher_thumb;
+    wxRect      m_rect_tick_action;
+    wxRect      m_rect_one_layer_icon;
+    wxSize      m_thumb_size;
+    int         m_tick_icon_dim;
+    int         m_lock_icon_dim = 16;
+    long        m_style;
+    float       m_label_koef = 1.0;
+
+// control's view variables
+    wxCoord SLIDER_MARGIN; // margin around slider
+
+    wxPen   DARK_ORANGE_PEN;
+    wxPen   ORANGE_PEN;
+    wxPen   LIGHT_ORANGE_PEN;
+
+    wxPen   DARK_GREY_PEN;
+    wxPen   GREY_PEN;
+    wxPen   LIGHT_GREY_PEN;
+
+    std::vector<wxPen*> line_pens;
+    std::vector<wxPen*> segm_pens;
+    std::set<int>       m_ticks;
+    std::vector<double> m_values;
+};
+// ******************************************************************************************
+
+
 #endif // slic3r_GUI_wxExtensions_hpp_
diff --git a/xs/xsp/GUI.xsp b/xs/xsp/GUI.xsp
index c6eead1ad..b9183af1d 100644
--- a/xs/xsp/GUI.xsp
+++ b/xs/xsp/GUI.xsp
@@ -87,6 +87,80 @@ void add_frequently_changed_parameters(SV *ui_parent, SV *ui_sizer, SV *ui_p_siz
                                                            (wxBoxSizer*)wxPli_sv_2_object(aTHX_ ui_sizer, "Wx::BoxSizer"),
                                                            (wxFlexGridSizer*)wxPli_sv_2_object(aTHX_ ui_p_sizer, "Wx::FlexGridSizer")); %};
 
+void add_expert_mode_part(  SV *ui_parent, SV *ui_sizer, 
+                            Model *model,
+                            int event_object_selection_changed,
+                            int event_object_settings_changed,
+                            int event_remove_object, 
+                            int event_update_scene)
+    %code%{ Slic3r::GUI::add_expert_mode_part(  (wxWindow*)wxPli_sv_2_object(aTHX_ ui_parent, "Wx::Window"),
+                                                (wxBoxSizer*)wxPli_sv_2_object(aTHX_ ui_sizer, "Wx::BoxSizer"), 
+                                                *model,  
+                                                event_object_selection_changed,
+                                                event_object_settings_changed,
+                                                event_remove_object, 
+                                                event_update_scene); %};
+
+void set_objects_from_perl( SV *ui_parent, 
+                            SV *frequently_changed_parameters_sizer,
+                            SV *expert_mode_part_sizer,
+                            SV *scrolled_window_sizer,
+                            SV *btn_export_gcode,
+                            SV *btn_export_stl,
+                            SV *btn_reslice,
+                            SV *btn_print,
+                            SV *btn_send_gcode,
+                            SV *manifold_warning_icon)
+    %code%{ Slic3r::GUI::set_objects_from_perl(
+                            (wxWindow *)wxPli_sv_2_object(aTHX_ ui_parent, "Wx::Window"),
+                            (wxBoxSizer *)wxPli_sv_2_object(aTHX_ frequently_changed_parameters_sizer, "Wx::BoxSizer"),
+                            (wxBoxSizer *)wxPli_sv_2_object(aTHX_ expert_mode_part_sizer, "Wx::BoxSizer"),
+                            (wxBoxSizer *)wxPli_sv_2_object(aTHX_ scrolled_window_sizer, "Wx::BoxSizer"),
+                            (wxButton *)wxPli_sv_2_object(aTHX_ btn_export_gcode, "Wx::Button"),
+                            (wxButton *)wxPli_sv_2_object(aTHX_ btn_export_stl, "Wx::Button"),
+                            (wxButton *)wxPli_sv_2_object(aTHX_ btn_reslice, "Wx::Button"),
+                            (wxButton *)wxPli_sv_2_object(aTHX_ btn_print, "Wx::Button"),
+                            (wxButton *)wxPli_sv_2_object(aTHX_ btn_send_gcode, "Wx::Button"),
+                            (wxStaticBitmap *)wxPli_sv_2_object(aTHX_ manifold_warning_icon, "Wx::StaticBitmap")); %};
+
+void set_show_print_info(bool show)
+    %code%{ Slic3r::GUI::set_show_print_info(show); %};
+
+void set_show_manifold_warning_icon(bool show)
+    %code%{ Slic3r::GUI::set_show_manifold_warning_icon(show); %};
+
+void update_mode()
+    %code%{ Slic3r::GUI::update_mode(); %};
+
+void add_object_to_list(const char *name, SV *object_model)
+    %code%{ Slic3r::GUI::add_object_to_list(
+                    name, 
+                    (ModelObject *)wxPli_sv_2_object(aTHX_ object_model, "Slic3r::Model::Object") ); %};
+
+void delete_object_from_list()
+    %code%{ Slic3r::GUI::delete_object_from_list(); %};
+
+void delete_all_objects_from_list()
+    %code%{ Slic3r::GUI::delete_all_objects_from_list(); %};
+
+void set_object_count(int idx, int count)
+    %code%{ Slic3r::GUI::set_object_count(idx, count); %};
+
+void set_object_scale(int idx, int scale)
+    %code%{ Slic3r::GUI::set_object_scale(idx, scale); %};
+
+void unselect_objects()
+    %code%{ Slic3r::GUI::unselect_objects(); %};
+
+void select_current_object(int idx)
+    %code%{ Slic3r::GUI::select_current_object(idx); %};
+
+void remove_obj()
+    %code%{ Slic3r::GUI::remove(); %};
+
+void update_rotation_value(double angle, const char *axis)
+    %code%{ Slic3r::GUI::update_rotation_value(angle, axis); %};
+
 std::string fold_utf8_to_ascii(const char *src)
     %code%{ RETVAL = Slic3r::fold_utf8_to_ascii(src); %};