mirror of
				https://github.com/SoftFever/OrcaSlicer.git
				synced 2025-10-30 04:02:52 -06:00 
			
		
		
		
	Merge remote-tracking branch 'origin/ys_selection'
This commit is contained in:
		
						commit
						0c662e298f
					
				
					 2 changed files with 190 additions and 52 deletions
				
			
		|  | @ -82,13 +82,31 @@ ObjectList::ObjectList(wxWindow* parent) : | |||
|     init_icons(); | ||||
| 
 | ||||
|     // describe control behavior 
 | ||||
|     Bind(wxEVT_DATAVIEW_SELECTION_CHANGED, [this](wxEvent& event) { | ||||
|     Bind(wxEVT_DATAVIEW_SELECTION_CHANGED, [this](wxDataViewEvent& event) { | ||||
| #ifndef __APPLE__ | ||||
|         // On Windows and Linux, forces a kill focus emulation on the object manipulator fields because this event handler is called
 | ||||
|         // before the kill focus event handler on the object manipulator when changing selection in the list, invalidating the object
 | ||||
|         // manipulator cache with the following call to selection_changed()
 | ||||
|         wxGetApp().obj_manipul()->emulate_kill_focus(); | ||||
| #endif // __APPLE__
 | ||||
| 
 | ||||
|         /* For multiple selection with pressed SHIFT, 
 | ||||
|          * event.GetItem() returns value of a first item in selection list  | ||||
|          * instead of real last clicked item. | ||||
|          * So, let check last selected item in such strange way | ||||
|          */ | ||||
|         if (wxGetKeyState(WXK_SHIFT)) | ||||
|         { | ||||
|             wxDataViewItemArray sels; | ||||
|             GetSelections(sels); | ||||
|             if (sels.front() == m_last_selected_item) | ||||
|                 m_last_selected_item = sels.back(); | ||||
|             else | ||||
|                 m_last_selected_item = event.GetItem(); | ||||
|         } | ||||
|         else | ||||
|             m_last_selected_item = event.GetItem(); | ||||
| 
 | ||||
|         selection_changed(); | ||||
| #ifndef __WXMSW__ | ||||
|         set_tooltip_for_item(get_mouse_position_in_control()); | ||||
|  | @ -509,7 +527,7 @@ void ObjectList::key_event(wxKeyEvent& event) | |||
|         ) { | ||||
|         remove(); | ||||
|     } | ||||
|     else if (wxGetKeyState(wxKeyCode('A')) && wxGetKeyState(WXK_SHIFT)) | ||||
|     else if (wxGetKeyState(wxKeyCode('A')) && wxGetKeyState(WXK_CONTROL/*WXK_SHIFT*/)) | ||||
|         select_item_all_children(); | ||||
|     else | ||||
|         event.Skip(); | ||||
|  | @ -1005,8 +1023,7 @@ wxMenuItem* ObjectList::append_menu_item_instance_to_object(wxMenu* menu) | |||
| 
 | ||||
| void ObjectList::append_menu_items_osx(wxMenu* menu) | ||||
| { | ||||
|     append_menu_item(menu, wxID_ANY, _(L("Delete item")), "", | ||||
|         [this](wxCommandEvent&) { remove(); }, "", menu); | ||||
|     append_menu_item_delete(menu); | ||||
|      | ||||
|     append_menu_item(menu, wxID_ANY, _(L("Rename")), "", | ||||
|         [this](wxCommandEvent&) { rename_item(); }, "", menu); | ||||
|  | @ -1061,6 +1078,12 @@ void ObjectList::append_menu_item_change_extruder(wxMenu* menu) const | |||
|     } | ||||
| } | ||||
| 
 | ||||
| void ObjectList::append_menu_item_delete(wxMenu* menu) | ||||
| { | ||||
|     append_menu_item(menu, wxID_ANY, _(L("Delete")), "", | ||||
|         [this](wxCommandEvent&) { remove(); }, "", menu); | ||||
| } | ||||
| 
 | ||||
| void ObjectList::create_object_popupmenu(wxMenu *menu) | ||||
| { | ||||
| #ifdef __WXOSX__   | ||||
|  | @ -1118,6 +1141,9 @@ void ObjectList::create_part_popupmenu(wxMenu *menu) | |||
| 
 | ||||
| void ObjectList::create_instance_popupmenu(wxMenu*menu) | ||||
| { | ||||
| #ifdef __WXOSX__   | ||||
|     append_menu_item_delete(menu); | ||||
| #endif // __WXOSX__
 | ||||
|     m_menu_item_split_instances = append_menu_item_instance_to_object(menu); | ||||
| 
 | ||||
|     /* New behavior logic:
 | ||||
|  | @ -1560,7 +1586,7 @@ void ObjectList::split() | |||
|         auto opt_keys = model_object->volumes[id]->config.keys(); | ||||
|         if ( !(opt_keys.size() == 1 && opt_keys[0] == "extruder") ) { | ||||
|             select_item(m_objects_model->AddSettingsChild(vol_item)); | ||||
|             Collapse(vol_item); | ||||
|             /*Collapse*/Expand(vol_item); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|  | @ -1754,7 +1780,7 @@ void ObjectList::add_object_to_list(size_t obj_idx) | |||
|             auto opt_keys = model_object->volumes[id]->config.keys(); | ||||
|             if (!opt_keys.empty() && !(opt_keys.size() == 1 && opt_keys[0] == "extruder")) { | ||||
|                 select_item(m_objects_model->AddSettingsChild(vol_item)); | ||||
|                 Collapse(vol_item); | ||||
|                 /*Collapse*/Expand(vol_item); | ||||
|             } | ||||
|         } | ||||
|         Expand(item); | ||||
|  | @ -1768,7 +1794,7 @@ void ObjectList::add_object_to_list(size_t obj_idx) | |||
|     auto opt_keys = model_object->config.keys(); | ||||
|     if (!opt_keys.empty() && !(opt_keys.size() == 1 && opt_keys[0] == "extruder")) { | ||||
|         select_item(m_objects_model->AddSettingsChild(item)); | ||||
|         Collapse(item); | ||||
|         /*Collapse*/Expand(item); | ||||
|     } | ||||
| 
 | ||||
| #ifndef __WXOSX__  | ||||
|  | @ -1948,6 +1974,8 @@ void ObjectList::update_selections() | |||
|     const Selection& selection = wxGetApp().plater()->canvas3D()->get_selection(); | ||||
|     wxDataViewItemArray sels; | ||||
| 
 | ||||
|     m_selection_mode = smInstance; | ||||
| 
 | ||||
|     // We doesn't update selection if SettingsItem for the current object/part is selected
 | ||||
|     if (GetSelectedItemsCount() == 1 && m_objects_model->GetItemType(GetSelection()) == itSettings ) | ||||
|     { | ||||
|  | @ -1961,24 +1989,6 @@ void ObjectList::update_selections() | |||
|                 return; | ||||
|         } | ||||
|     } | ||||
| //     if (selection.is_single_full_object() && selection.get_instance_idx() != -1)
 | ||||
| //     {
 | ||||
| //         sels.Add(m_objects_model->GetItemById(selection.get_object_idx()));
 | ||||
| //     }
 | ||||
| //     else if (selection.is_single_volume() || selection.is_modifier() ||
 | ||||
| //         selection.is_multiple_volume() || selection.is_multiple_full_object())
 | ||||
| //     {
 | ||||
| //         for (auto idx : selection.get_volume_idxs()) {
 | ||||
| //             const auto gl_vol = selection.get_volume(idx);
 | ||||
| //             if (selection.is_multiple_full_object())
 | ||||
| //                 sels.Add(m_objects_model->GetItemById(gl_vol->object_idx()));
 | ||||
| //             else if (gl_vol->volume_idx() >= 0)
 | ||||
| //                 // Only add GLVolumes with non-negative volume_ids. GLVolumes with negative volume ids
 | ||||
| //                 // are not associated with ModelVolumes, but they are temporarily generated by the backend
 | ||||
| //                 // (for example, SLA supports or SLA pad).
 | ||||
| //                 sels.Add(m_objects_model->GetItemByVolumeId(gl_vol->object_idx(), gl_vol->volume_idx()));
 | ||||
| //         }
 | ||||
| //     }
 | ||||
|     else if (selection.is_single_full_object() || selection.is_multiple_full_object()) | ||||
|     { | ||||
|         const Selection::ObjectIdxsToInstanceIdxsMap& objects_content = selection.get_content(); | ||||
|  | @ -1993,8 +2003,10 @@ void ObjectList::update_selections() | |||
| 
 | ||||
|                 bool root_is_selected = false; | ||||
|                 for (const auto& item:current_sels) | ||||
|                     if (item == m_objects_model->GetParent(frst_inst_item)) { | ||||
|                     if (item == m_objects_model->GetParent(frst_inst_item) ||  | ||||
|                         item == m_objects_model->GetTopParent(frst_inst_item)) { | ||||
|                         root_is_selected = true; | ||||
|                         sels.Add(item); | ||||
|                         break; | ||||
|                     } | ||||
|                 if (root_is_selected) | ||||
|  | @ -2016,6 +2028,7 @@ void ObjectList::update_selections() | |||
|                 // (for example, SLA supports or SLA pad).
 | ||||
|                 sels.Add(m_objects_model->GetItemByVolumeId(gl_vol->object_idx(), gl_vol->volume_idx())); | ||||
|         } | ||||
|         m_selection_mode = smVolume; | ||||
|     } | ||||
|     else if (selection.is_single_full_instance() || selection.is_multiple_full_instance()) | ||||
|     { | ||||
|  | @ -2025,7 +2038,7 @@ void ObjectList::update_selections() | |||
|     } | ||||
|     else if (selection.is_mixed()) | ||||
|     { | ||||
|         auto& objects_content_list = selection.get_content(); | ||||
|         const Selection::ObjectIdxsToInstanceIdxsMap& objects_content_list = selection.get_content(); | ||||
| 
 | ||||
|         for (auto idx : selection.get_volume_idxs()) { | ||||
|             const auto gl_vol = selection.get_volume(idx); | ||||
|  | @ -2058,6 +2071,9 @@ void ObjectList::update_selections() | |||
|                 sels.Add(m_objects_model->GetItemByVolumeId(glv_obj_idx, glv_vol_idx)); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     if (sels.size() == 0) | ||||
|         m_selection_mode = smUndef; | ||||
|      | ||||
|     select_items(sels); | ||||
| 
 | ||||
|  | @ -2093,17 +2109,19 @@ void ObjectList::update_selections_on_canvas() | |||
| 
 | ||||
|     auto add_to_selection = [this](const wxDataViewItem& item, Selection& selection, int instance_idx, bool as_single_selection) | ||||
|     { | ||||
|         if (m_objects_model->GetParent(item) == wxDataViewItem(0)) { | ||||
|             selection.add_object(m_objects_model->GetIdByItem(item), as_single_selection); | ||||
|         const ItemType& type = m_objects_model->GetItemType(item); | ||||
|         if ( type == itInstanceRoot || m_objects_model->GetParent(item) == wxDataViewItem(0) ) { | ||||
|             wxDataViewItem obj_item = type == itInstanceRoot ? m_objects_model->GetParent(item) : item; | ||||
|             selection.add_object(m_objects_model->GetIdByItem(obj_item), as_single_selection); | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         if (m_objects_model->GetItemType(item) == itVolume) { | ||||
|         if (type == itVolume) { | ||||
|             const int obj_idx = m_objects_model->GetIdByItem(m_objects_model->GetParent(item)); | ||||
|             const int vol_idx = m_objects_model->GetVolumeIdByItem(item); | ||||
|             selection.add_volume(obj_idx, vol_idx, std::max(instance_idx, 0), as_single_selection); | ||||
|         } | ||||
|         else if (m_objects_model->GetItemType(item) == itInstance) { | ||||
|         else if (type == itInstance) { | ||||
|             const int obj_idx = m_objects_model->GetIdByItem(m_objects_model->GetTopParent(item)); | ||||
|             const int inst_idx = m_objects_model->GetInstanceIdByItem(item); | ||||
|             selection.add_instance(obj_idx, inst_idx, as_single_selection); | ||||
|  | @ -2116,7 +2134,7 @@ void ObjectList::update_selections_on_canvas() | |||
|     if (sel_cnt == 1) { | ||||
|         wxDataViewItem item = GetSelection(); | ||||
|         if (m_objects_model->GetItemType(item) & (itSettings|itInstanceRoot)) | ||||
|             add_to_selection(m_objects_model->GetParent(item), selection, -1, true); | ||||
|             add_to_selection(m_objects_model->GetParent(item), selection, instance_idx, true); | ||||
|         else | ||||
|             add_to_selection(item, selection, instance_idx, true); | ||||
| 
 | ||||
|  | @ -2172,22 +2190,101 @@ void ObjectList::select_item_all_children() | |||
|     if (!GetSelection() || m_objects_model->GetItemType(GetSelection()) == itObject) { | ||||
|         for (int i = 0; i < m_objects->size(); i++) | ||||
|             sels.Add(m_objects_model->GetItemById(i)); | ||||
|         m_selection_mode = smInstance; | ||||
|     } | ||||
|     else { | ||||
|         const auto item = GetSelection(); | ||||
|         // Some volume(instance) is selected    =>  select all volumes(instances) inside the current object
 | ||||
|         if (m_objects_model->GetItemType(item) & (itVolume | itInstance)) { | ||||
|         if (m_objects_model->GetItemType(item) & (itVolume | itInstance)) | ||||
|             m_objects_model->GetChildren(m_objects_model->GetParent(item), sels); | ||||
|         } | ||||
| 
 | ||||
|         m_selection_mode = m_objects_model->GetItemType(item)&itVolume ? smVolume : smInstance; | ||||
|     } | ||||
| 
 | ||||
|     SetSelections(sels); | ||||
|     selection_changed(); | ||||
| } | ||||
| 
 | ||||
| // update selection mode for non-multiple selection
 | ||||
| void ObjectList::update_selection_mode() | ||||
| { | ||||
|     // All items are unselected 
 | ||||
|     if (!GetSelection()) | ||||
|     { | ||||
|         m_last_selected_item = wxDataViewItem(0); | ||||
|         m_selection_mode = smUndef; | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     const ItemType type = m_objects_model->GetItemType(GetSelection()); | ||||
|     m_selection_mode =  type&itSettings ? smUndef   : | ||||
|                         type&itVolume   ? smVolume  : smInstance; | ||||
| } | ||||
| 
 | ||||
| // check last selected item. If is it possible to select it
 | ||||
| bool ObjectList::check_last_selection(wxString& msg_str) | ||||
| { | ||||
|     if (!m_last_selected_item) | ||||
|         return true; | ||||
|          | ||||
|     const bool is_shift_pressed = wxGetKeyState(WXK_SHIFT); | ||||
| 
 | ||||
|     /* We can't mix Parts and Objects/Instances.
 | ||||
|      * So, show information about it | ||||
|      */ | ||||
|     const ItemType type = m_objects_model->GetItemType(m_last_selected_item); | ||||
| 
 | ||||
|     // check a case of a selection of the Parts from different Objects
 | ||||
|     bool impossible_multipart_selection = false; | ||||
|     if (type & itVolume && m_selection_mode == smVolume) | ||||
|     { | ||||
|         wxDataViewItemArray sels; | ||||
|         GetSelections(sels); | ||||
|         for (const auto& sel: sels) | ||||
|             if (sel != m_last_selected_item &&  | ||||
|                 m_objects_model->GetParent(sel) != m_objects_model->GetParent(m_last_selected_item)) | ||||
|             { | ||||
|                 impossible_multipart_selection = true; | ||||
|                 break; | ||||
|             } | ||||
|     } | ||||
| 
 | ||||
|     if (impossible_multipart_selection || | ||||
|         type & itSettings || | ||||
|         type & itVolume && m_selection_mode == smInstance || | ||||
|         !(type & itVolume) && m_selection_mode == smVolume) | ||||
|     { | ||||
|         // Inform user why selection isn't complited
 | ||||
|         const wxString item_type = m_selection_mode == smInstance ? _(L("Object or Instance")) : _(L("Part")); | ||||
| 
 | ||||
|         msg_str = wxString::Format( _(L("Unsupported selection")) + "\n\n" +  | ||||
|                                     _(L("You started your selection with %s Item.")) + "\n" + | ||||
|                                     _(L("In this mode you can select only other %s Items%s")),  | ||||
|                                     item_type, item_type, | ||||
|                                     m_selection_mode == smInstance ? "." :  | ||||
|                                                         " " + _(L("of a current Object"))); | ||||
| 
 | ||||
|         // Unselect last selected item, if selection is without SHIFT
 | ||||
|         if (!is_shift_pressed) { | ||||
|             Unselect(m_last_selected_item); | ||||
|             show_info(this, msg_str, _(L("Info"))); | ||||
|         } | ||||
|          | ||||
|         return is_shift_pressed; | ||||
|     } | ||||
| 
 | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| void ObjectList::fix_multiselection_conflicts() | ||||
| { | ||||
|     if (GetSelectedItemsCount() <= 1) | ||||
|     if (GetSelectedItemsCount() <= 1) { | ||||
|         update_selection_mode(); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     wxString msg_string; | ||||
|     if (!check_last_selection(msg_string)) | ||||
|         return; | ||||
| 
 | ||||
|     m_prevent_list_events = true; | ||||
|  | @ -2195,27 +2292,59 @@ void ObjectList::fix_multiselection_conflicts() | |||
|     wxDataViewItemArray sels; | ||||
|     GetSelections(sels); | ||||
| 
 | ||||
|     for (const auto item : sels) { | ||||
|         if (!IsSelected(item)) // if this item is unselected now (from previous actions)
 | ||||
|             continue; | ||||
|     if (m_selection_mode == smVolume) | ||||
|     { | ||||
|         // identify correct parent of the initial selected item
 | ||||
|         const wxDataViewItem& parent = m_objects_model->GetParent(m_last_selected_item == sels.front() ? sels.back() : sels.front()); | ||||
| 
 | ||||
|         if (m_objects_model->GetItemType(item) & itSettings) { | ||||
|             Unselect(item); | ||||
|             continue; | ||||
|         } | ||||
|         sels.clear(); | ||||
|         wxDataViewItemArray children; // selected volumes from current parent
 | ||||
|         m_objects_model->GetChildren(parent, children); | ||||
| 
 | ||||
|         const wxDataViewItem& parent = m_objects_model->GetParent(item); | ||||
|         if (parent != wxDataViewItem(0) && IsSelected(parent)) | ||||
|             Unselect(parent); | ||||
|         else | ||||
|         for (const auto child : children) | ||||
|             if (IsSelected(child) && m_objects_model->GetItemType(child)&itVolume) | ||||
|                 sels.Add(child); | ||||
| 
 | ||||
|         // If some part is selected, unselect all items except of selected parts of the current object
 | ||||
|         UnselectAll(); | ||||
|         SetSelections(sels); | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         for (const auto item : sels) | ||||
|         { | ||||
|             wxDataViewItemArray unsels; | ||||
|             m_objects_model->GetAllChildren(item, unsels); | ||||
|             for (const auto unsel_item : unsels) | ||||
|                 Unselect(unsel_item); | ||||
|             if (!IsSelected(item)) // if this item is unselected now (from previous actions)
 | ||||
|                 continue; | ||||
| 
 | ||||
|             if (m_objects_model->GetItemType(item) & itSettings) { | ||||
|                 Unselect(item); | ||||
|                 continue; | ||||
|             } | ||||
| 
 | ||||
|             const wxDataViewItem& parent = m_objects_model->GetParent(item); | ||||
|             if (parent != wxDataViewItem(0) && IsSelected(parent)) | ||||
|                 Unselect(parent); | ||||
|             else | ||||
|             { | ||||
|                 wxDataViewItemArray unsels; | ||||
|                 m_objects_model->GetAllChildren(item, unsels); | ||||
|                 for (const auto unsel_item : unsels) | ||||
|                     Unselect(unsel_item); | ||||
|             } | ||||
| 
 | ||||
|             if (m_objects_model->GetItemType(item) & itVolume) | ||||
|                 Unselect(item); | ||||
| 
 | ||||
|             m_selection_mode = smInstance; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     if (!msg_string.IsEmpty()) | ||||
|         show_info(this, msg_string, _(L("Info"))); | ||||
| 
 | ||||
|     if (!IsSelected(m_last_selected_item)) | ||||
|         m_last_selected_item = wxDataViewItem(0); | ||||
| 
 | ||||
|     m_prevent_list_events = false; | ||||
| } | ||||
| 
 | ||||
|  | @ -2535,8 +2664,7 @@ void ObjectList::show_multi_selection_menu() | |||
|     wxMenu* menu = new wxMenu(); | ||||
| 
 | ||||
| #ifdef __WXOSX__ | ||||
|     append_menu_item(menu, wxID_ANY, _(L("Delete items")), "", | ||||
|         [this](wxCommandEvent&) { remove(); }, "", menu); | ||||
|     append_menu_item_delete(menu); | ||||
| #endif //__WXOSX__
 | ||||
| 
 | ||||
|     if (extruders_count() > 1) | ||||
|  |  | |||
|  | @ -60,6 +60,12 @@ struct ItemForDelete | |||
| 
 | ||||
| class ObjectList : public wxDataViewCtrl | ||||
| { | ||||
|     enum SELECTION_MODE | ||||
|     { | ||||
|         smUndef, | ||||
|         smVolume, | ||||
|         smInstance | ||||
|     } m_selection_mode {smUndef}; | ||||
| 
 | ||||
|     struct dragged_item_data | ||||
|     { | ||||
|  | @ -135,6 +141,7 @@ class ObjectList : public wxDataViewCtrl | |||
|     bool        m_part_settings_changed = false; | ||||
| 
 | ||||
|     int         m_selected_row = 0; | ||||
|     wxDataViewItem m_last_selected_item {nullptr}; | ||||
| 
 | ||||
| #if 0 | ||||
|     FreqSettingsBundle m_freq_settings_fff; | ||||
|  | @ -188,6 +195,7 @@ public: | |||
|     void                append_menu_item_fix_through_netfabb(wxMenu* menu); | ||||
|     void                append_menu_item_export_stl(wxMenu* menu) const ; | ||||
|     void                append_menu_item_change_extruder(wxMenu* menu) const; | ||||
|     void                append_menu_item_delete(wxMenu* menu); | ||||
|     void                create_object_popupmenu(wxMenu *menu); | ||||
|     void                create_sla_object_popupmenu(wxMenu*menu); | ||||
|     void                create_part_popupmenu(wxMenu*menu); | ||||
|  | @ -258,6 +266,8 @@ public: | |||
|     void select_items(const wxDataViewItemArray& sels); | ||||
|     void select_all(); | ||||
|     void select_item_all_children(); | ||||
|     void update_selection_mode(); | ||||
|     bool check_last_selection(wxString& msg_str); | ||||
|     // correct current selections to avoid of the possible conflicts
 | ||||
|     void fix_multiselection_conflicts(); | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 YuSanka
						YuSanka