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

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

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