mirror of
				https://github.com/SoftFever/OrcaSlicer.git
				synced 2025-11-02 20:51:23 -07:00 
			
		
		
		
	Implemented splitting of object instances by :
- drag & drop outside of any object - set as a separated Object (context menu)
This commit is contained in:
		
							parent
							
								
									a85db038be
								
							
						
					
					
						commit
						94b5f9c567
					
				
					 4 changed files with 96 additions and 27 deletions
				
			
		| 
						 | 
				
			
			@ -97,7 +97,7 @@ void ObjectList::create_objects_ctrl()
 | 
			
		|||
    // temporary workaround for the correct behavior of the Scrolled sidebar panel:
 | 
			
		||||
    // 1. set a height of the list to some big value 
 | 
			
		||||
    // 2. change it to the normal min value (200) after first whole App updating/layouting
 | 
			
		||||
    SetMinSize(wxSize(-1, 1500));   // #ys_FIXME 
 | 
			
		||||
    SetMinSize(wxSize(-1, 3000));   // #ys_FIXME 
 | 
			
		||||
 | 
			
		||||
    m_sizer = new wxBoxSizer(wxVERTICAL);
 | 
			
		||||
    m_sizer->Add(this, 1, wxGROW | wxLEFT, 20);
 | 
			
		||||
| 
						 | 
				
			
			@ -445,13 +445,21 @@ void ObjectList::OnBeginDrag(wxDataViewEvent &event)
 | 
			
		|||
 | 
			
		||||
    // only allow drags for item, not containers
 | 
			
		||||
    if (multiple_selection() || GetSelection()!=item || 
 | 
			
		||||
        m_objects_model->GetParent(item) == wxDataViewItem(0) ||
 | 
			
		||||
        m_objects_model->GetItemType(item) != itVolume ) {
 | 
			
		||||
        m_objects_model->GetParent(item) == wxDataViewItem(0)) {
 | 
			
		||||
        event.Veto();
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
   
 | 
			
		||||
    const ItemType& type = m_objects_model->GetItemType(item);
 | 
			
		||||
    if (!(type & (itVolume | itInstance))) {
 | 
			
		||||
        event.Veto();
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    m_dragged_data.init(m_objects_model->GetObjectIdByItem(item), m_objects_model->GetVolumeIdByItem(item));
 | 
			
		||||
    m_dragged_data.init(m_objects_model->GetObjectIdByItem(item), 
 | 
			
		||||
                        type&itVolume ? m_objects_model->GetVolumeIdByItem(item) :
 | 
			
		||||
                                        m_objects_model->GetInstanceIdByItem(item), 
 | 
			
		||||
                        type);
 | 
			
		||||
 | 
			
		||||
    /* 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.
 | 
			
		||||
| 
						 | 
				
			
			@ -470,31 +478,41 @@ void ObjectList::OnBeginDrag(wxDataViewEvent &event)
 | 
			
		|||
    event.SetDragFlags(wxDrag_DefaultMove); // allows both copy and move;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool ObjectList::can_drop(const wxDataViewItem& item) const 
 | 
			
		||||
{
 | 
			
		||||
    return  m_dragged_data.type() == itInstance && !item.IsOk()     ||
 | 
			
		||||
            m_dragged_data.type() == itVolume && item.IsOk() &&
 | 
			
		||||
            m_objects_model->GetItemType(item) == itVolume &&
 | 
			
		||||
            m_dragged_data.obj_idx() == m_objects_model->GetObjectIdByItem(item);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ObjectList::OnDropPossible(wxDataViewEvent &event)
 | 
			
		||||
{
 | 
			
		||||
    wxDataViewItem item(event.GetItem());
 | 
			
		||||
    const wxDataViewItem& item = event.GetItem();
 | 
			
		||||
 | 
			
		||||
    // only allow drags for item or background, not containers
 | 
			
		||||
    if (!item.IsOk() ||
 | 
			
		||||
        m_objects_model->GetParent(item) == wxDataViewItem(0) || 
 | 
			
		||||
        m_objects_model->GetItemType(item) != itVolume ||
 | 
			
		||||
        m_dragged_data.obj_idx() != m_objects_model->GetObjectIdByItem(item))
 | 
			
		||||
    if (!can_drop(item))
 | 
			
		||||
        event.Veto();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ObjectList::OnDrop(wxDataViewEvent &event)
 | 
			
		||||
{
 | 
			
		||||
    wxDataViewItem item(event.GetItem());
 | 
			
		||||
    const wxDataViewItem& item = event.GetItem();
 | 
			
		||||
 | 
			
		||||
    if (!item.IsOk() || m_objects_model->GetParent(item) == wxDataViewItem(0) ||
 | 
			
		||||
                        m_objects_model->GetItemType(item) != itVolume ||
 | 
			
		||||
                        m_dragged_data.obj_idx() != m_objects_model->GetObjectIdByItem(item)) {
 | 
			
		||||
    if (!can_drop(item))
 | 
			
		||||
    {
 | 
			
		||||
        event.Veto();
 | 
			
		||||
        m_dragged_data.clear();
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const int from_volume_id = m_dragged_data.vol_idx();
 | 
			
		||||
    if (m_dragged_data.type() == itInstance)
 | 
			
		||||
    {
 | 
			
		||||
        instance_to_separated_object(m_dragged_data.obj_idx(), m_dragged_data.sub_obj_idx());
 | 
			
		||||
        m_dragged_data.clear();
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const int from_volume_id = m_dragged_data.sub_obj_idx();
 | 
			
		||||
    int to_volume_id = m_objects_model->GetVolumeIdByItem(item);
 | 
			
		||||
 | 
			
		||||
// It looks like a fixed in current version of the wxWidgets
 | 
			
		||||
| 
						 | 
				
			
			@ -506,7 +524,7 @@ void ObjectList::OnDrop(wxDataViewEvent &event)
 | 
			
		|||
//     if (to_volume_id > from_volume_id) to_volume_id--;
 | 
			
		||||
// #endif // __WXGTK__
 | 
			
		||||
 | 
			
		||||
    auto& volumes = (*m_objects)[/*m_selected_object_id*/m_dragged_data.obj_idx()]->volumes;
 | 
			
		||||
    auto& volumes = (*m_objects)[m_dragged_data.obj_idx()]->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++)
 | 
			
		||||
| 
						 | 
				
			
			@ -516,7 +534,7 @@ void ObjectList::OnDrop(wxDataViewEvent &event)
 | 
			
		|||
                                                    m_objects_model->GetParent(item)));
 | 
			
		||||
 | 
			
		||||
    m_parts_changed = true;
 | 
			
		||||
    parts_changed(/*m_selected_object_id*/m_dragged_data.obj_idx());
 | 
			
		||||
    parts_changed(m_dragged_data.obj_idx());
 | 
			
		||||
 | 
			
		||||
    m_dragged_data.clear();
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1729,6 +1747,25 @@ void ObjectList::update_settings_items()
 | 
			
		|||
    UnselectAll();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ObjectList::instance_to_separated_object(const int obj_idx, const int inst_idx)
 | 
			
		||||
{
 | 
			
		||||
    // create new object from selected instance  
 | 
			
		||||
    ModelObject* model_object = (*m_objects)[obj_idx]->get_model()->add_object(*(*m_objects)[obj_idx]);
 | 
			
		||||
    for (int i = model_object->instances.size() - 1; i >= 0; i--)
 | 
			
		||||
    {
 | 
			
		||||
        if (i == inst_idx)
 | 
			
		||||
            continue;
 | 
			
		||||
        model_object->delete_instance(i);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Add new object to the object_list
 | 
			
		||||
    add_object_to_list(m_objects->size() - 1);
 | 
			
		||||
 | 
			
		||||
    // delete selected instance from the object
 | 
			
		||||
    del_subobject_from_object(obj_idx, inst_idx, itInstance);
 | 
			
		||||
    delete_instance_from_list(obj_idx, inst_idx);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ObjectList::ItemValueChanged(wxDataViewEvent &event)
 | 
			
		||||
{
 | 
			
		||||
    if (event.GetColumn() == 0)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -56,22 +56,27 @@ class ObjectList : public wxDataViewCtrl
 | 
			
		|||
 | 
			
		||||
    struct dragged_item_data
 | 
			
		||||
    {
 | 
			
		||||
        void init(const int obj_idx, const int vol_idx) {
 | 
			
		||||
        void init(const int obj_idx, const int subobj_idx, const ItemType type) {
 | 
			
		||||
            m_obj_idx = obj_idx;
 | 
			
		||||
            m_vol_idx = vol_idx;            
 | 
			
		||||
            m_subobj_idx = subobj_idx;
 | 
			
		||||
            m_type = type;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        void clear() {
 | 
			
		||||
            m_obj_idx = -1;
 | 
			
		||||
            m_vol_idx = -1;            
 | 
			
		||||
            m_subobj_idx = -1;
 | 
			
		||||
            m_type = itUndef;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        int obj_idx() const  { return m_obj_idx; }
 | 
			
		||||
        int vol_idx() const  { return m_vol_idx; }
 | 
			
		||||
        int sub_obj_idx() const  { return m_subobj_idx; }
 | 
			
		||||
        ItemType type() const { return m_type; }
 | 
			
		||||
 | 
			
		||||
    private:
 | 
			
		||||
        int m_obj_idx = -1;
 | 
			
		||||
        int m_vol_idx = -1;
 | 
			
		||||
        int m_subobj_idx = -1;
 | 
			
		||||
        ItemType m_type = itUndef;
 | 
			
		||||
 | 
			
		||||
    } m_dragged_data;
 | 
			
		||||
 | 
			
		||||
    wxBoxSizer          *m_sizer {nullptr};
 | 
			
		||||
| 
						 | 
				
			
			@ -222,6 +227,8 @@ public:
 | 
			
		|||
    bool has_multi_part_objects();
 | 
			
		||||
    void update_settings_items();
 | 
			
		||||
 | 
			
		||||
    void instance_to_separated_object(const int obj_idx, const int inst_idx);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    void OnChar(wxKeyEvent& event);
 | 
			
		||||
    void OnContextMenu(wxDataViewEvent &event);
 | 
			
		||||
| 
						 | 
				
			
			@ -229,6 +236,7 @@ private:
 | 
			
		|||
    void OnBeginDrag(wxDataViewEvent &event);
 | 
			
		||||
    void OnDropPossible(wxDataViewEvent &event);
 | 
			
		||||
    void OnDrop(wxDataViewEvent &event);
 | 
			
		||||
    bool can_drop(const wxDataViewItem& item) const ;
 | 
			
		||||
 | 
			
		||||
    void ItemValueChanged(wxDataViewEvent &event);
 | 
			
		||||
    void OnEditingDone(wxDataViewEvent &event);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1063,6 +1063,7 @@ private:
 | 
			
		|||
    bool can_delete_object() const;
 | 
			
		||||
    bool can_increase_instances() const;
 | 
			
		||||
    bool can_decrease_instances() const;
 | 
			
		||||
    bool can_set_instance_to_object() const;
 | 
			
		||||
    bool can_split_to_objects() const;
 | 
			
		||||
    bool can_split_to_volumes() const;
 | 
			
		||||
    bool can_split() const;
 | 
			
		||||
| 
						 | 
				
			
			@ -2359,11 +2360,17 @@ bool Plater::priv::init_common_menu(wxMenu* menu, const bool is_part/* = false*/
 | 
			
		|||
            [this](wxCommandEvent&) { q->decrease_instances(); }, "delete.png");
 | 
			
		||||
        wxMenuItem* item_set_number_of_copies = append_menu_item(menu, wxID_ANY, _(L("Set number of copies")) + dots, _(L("Change the number of copies of the selected object")),
 | 
			
		||||
            [this](wxCommandEvent&) { q->set_number_of_copies(); }, "textfield.png");
 | 
			
		||||
 | 
			
		||||
        menu->AppendSeparator();
 | 
			
		||||
        wxMenuItem* item_instance_to_object = append_menu_item(menu, wxID_ANY, _(L("Set as a Separated Object")) + dots, _(L("Set an Instance as a Separate Object")),
 | 
			
		||||
            [this](wxCommandEvent&) { q->instance_to_separated_object(); }, "");
 | 
			
		||||
 | 
			
		||||
        if (q != nullptr)
 | 
			
		||||
        {
 | 
			
		||||
            q->Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable(can_increase_instances()); }, item_increase->GetId());
 | 
			
		||||
            q->Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable(can_decrease_instances()); }, item_decrease->GetId());
 | 
			
		||||
            q->Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable(can_increase_instances()); }, item_set_number_of_copies->GetId());
 | 
			
		||||
            q->Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable(can_set_instance_to_object()); }, item_instance_to_object->GetId());
 | 
			
		||||
        }
 | 
			
		||||
        menu->AppendSeparator();
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -2426,9 +2433,9 @@ bool Plater::priv::complit_init_object_menu()
 | 
			
		|||
    // ui updates needs to be binded to the parent panel
 | 
			
		||||
    if (q != nullptr)
 | 
			
		||||
    {
 | 
			
		||||
        q->Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable(can_split/*_to_objects() || can_split_to_volumes*/()); }, item_split->GetId());
 | 
			
		||||
        q->Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable(can_split/*_to_objects*/()); }, item_split_objects->GetId());
 | 
			
		||||
        q->Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable(can_split/*_to_volumes*/()); }, item_split_volumes->GetId());
 | 
			
		||||
        q->Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable(can_split()); }, item_split->GetId());
 | 
			
		||||
        q->Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable(can_split()); }, item_split_objects->GetId());
 | 
			
		||||
        q->Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable(can_split()); }, item_split_volumes->GetId());
 | 
			
		||||
    }
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -2447,7 +2454,7 @@ bool Plater::priv::complit_init_sla_object_menu()
 | 
			
		|||
    // ui updates needs to be binded to the parent panel
 | 
			
		||||
    if (q != nullptr)
 | 
			
		||||
    {
 | 
			
		||||
        q->Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable(can_split/*_to_objects*/()); }, item_split->GetId());
 | 
			
		||||
        q->Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable(can_split()); }, item_split->GetId());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return true;
 | 
			
		||||
| 
						 | 
				
			
			@ -2466,7 +2473,7 @@ bool Plater::priv::complit_init_part_menu()
 | 
			
		|||
    // ui updates needs to be binded to the parent panel
 | 
			
		||||
    if (q != nullptr)
 | 
			
		||||
    {
 | 
			
		||||
        q->Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable(can_split/*_to_volumes*/()); },  item_split->GetId());
 | 
			
		||||
        q->Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable(can_split()); },  item_split->GetId());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return true;
 | 
			
		||||
| 
						 | 
				
			
			@ -2534,6 +2541,12 @@ bool Plater::priv::can_increase_instances() const
 | 
			
		|||
    return (0 <= obj_idx) && (obj_idx < (int)model.objects.size());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool Plater::priv::can_set_instance_to_object() const
 | 
			
		||||
{
 | 
			
		||||
    const int obj_idx = get_selected_object_idx();
 | 
			
		||||
    return (0 <= obj_idx) && (obj_idx < (int)model.objects.size()) && (model.objects[obj_idx]->instances.size() > 1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool Plater::priv::can_decrease_instances() const
 | 
			
		||||
{
 | 
			
		||||
    int obj_idx = get_selected_object_idx();
 | 
			
		||||
| 
						 | 
				
			
			@ -2760,6 +2773,16 @@ void Plater::set_number_of_copies(/*size_t num*/)
 | 
			
		|||
        decrease_instances(-diff);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Plater::instance_to_separated_object()
 | 
			
		||||
{
 | 
			
		||||
    const int obj_idx = p->get_selected_object_idx();
 | 
			
		||||
    const int inst_idx = p->get_selection().get_instance_idx();
 | 
			
		||||
    if (obj_idx == -1 || inst_idx == -1)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    sidebar().obj_list()->instance_to_separated_object(obj_idx, inst_idx);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool Plater::is_selection_empty() const
 | 
			
		||||
{
 | 
			
		||||
    return p->get_selection().is_empty();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -136,6 +136,7 @@ public:
 | 
			
		|||
    void increase_instances(size_t num = 1);
 | 
			
		||||
    void decrease_instances(size_t num = 1);
 | 
			
		||||
    void set_number_of_copies(/*size_t num*/);
 | 
			
		||||
    void instance_to_separated_object();
 | 
			
		||||
    bool is_selection_empty() const;
 | 
			
		||||
 | 
			
		||||
    void cut(size_t obj_idx, size_t instance_idx, coordf_t z, bool keep_upper = true, bool keep_lower = true, bool rotate_lower = false);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue