From 94f26da61489694a53c24341c313fdb702a1a57f Mon Sep 17 00:00:00 2001 From: "chunmao.guo" Date: Fri, 18 Aug 2023 18:46:51 +0800 Subject: [PATCH] ENH: [STUDIO-3980] drag object accross plate in ObjectList Change-Id: Iee3193a8e0eaea67670a55e023fe64adca7a8695 --- src/slic3r/GUI/GUI_ObjectList.cpp | 93 +++++++++++++++++++++----- src/slic3r/GUI/GUI_ObjectList.hpp | 8 +++ src/slic3r/GUI/GUI_ObjectSettings.cpp | 3 +- src/slic3r/GUI/ObjectDataViewModel.cpp | 6 +- 4 files changed, 92 insertions(+), 18 deletions(-) diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index b14509403..277897072 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #include "slic3r/Utils/FixModelByWin10.hpp" #include "libslic3r/Format/bbs_3mf.hpp" @@ -96,6 +97,8 @@ ObjectList::ObjectList(wxWindow* parent) : GenericGetHeader()->SetFont(Label::sysFont(13)); static auto render = new wxRenderer; wxRendererNative::Set(render); + + ShowScrollbars(wxSHOW_SB_NEVER, wxSHOW_SB_DEFAULT); #endif // create control @@ -1480,6 +1483,30 @@ void ObjectList::key_event(wxKeyEvent& event) } #endif /* __WXOSX__ */ +bool ObjectList::dragged_item_data::set_cur_plate(int plate) +{ + if (m_last_plate == plate) + return m_last_plate_time + wxTimeSpan::Seconds(1) < wxDateTime::Now(); + m_last_plate = plate; + m_last_plate_time = wxDateTime::Now(); + return false; +} + +struct ObjectList_TextDataObject : wxTextDataObject +{ + ObjectList *list; + ObjectList_TextDataObject(ObjectList *list) : list(list) {} + virtual ~ObjectList_TextDataObject() { list->cancel_drag(); } +}; + +void GUI::ObjectList::cancel_drag() +{ + if (is_dragging()) { + m_dragged_data.clear(); + part_selection_changed(); + } +} + void ObjectList::OnBeginDrag(wxDataViewEvent &event) { const bool mult_sel = multiple_selection(); @@ -1495,28 +1522,18 @@ void ObjectList::OnBeginDrag(wxDataViewEvent &event) return; } + int from_plate = -1; if (type & itObject) { int curr_obj_id = m_objects_model->GetIdByItem(event.GetItem()); PartPlateList& partplate_list = wxGetApp().plater()->get_partplate_list(); - int from_plate = partplate_list.find_instance(curr_obj_id, 0); + from_plate = partplate_list.find_instance(curr_obj_id, 0); if (from_plate == -1) { event.Veto(); return; } - auto curr_plate_seq = partplate_list.get_plate(from_plate)->get_print_seq(); - if (curr_plate_seq == PrintSequence::ByDefault) { - auto curr_preset_config = wxGetApp().preset_bundle->prints.get_edited_preset().config; - if (curr_preset_config.has("print_sequence")) - curr_plate_seq = curr_preset_config.option>("print_sequence")->value; - } - - if (curr_plate_seq != PrintSequence::ByObject) { - //drag forbidden under bylayer mode - event.Veto(); - return; - } m_dragged_data.init(m_objects_model->GetIdByItem(item), type); + m_dragged_data.set_cur_plate(from_plate); } else if (type & itVolume){ m_dragged_data.init(m_objects_model->GetObjectIdByItem(item), m_objects_model->GetVolumeIdByItem(item), type); @@ -1561,11 +1578,22 @@ void ObjectList::OnBeginDrag(wxDataViewEvent &event) /* Under GTK, DnD requires to the wxTextDataObject been initialized with some valid value, * so set some nonempty string */ - wxTextDataObject* obj = new wxTextDataObject; + wxTextDataObject *obj = new ObjectList_TextDataObject(this); obj->SetText("Some text");//it's needed for GTK event.SetDataObject(obj); event.SetDragFlags(wxDrag_DefaultMove); // allows both copy and move; + + this->part_selection_changed(); + + if (from_plate >= 0 && (GetScrollPos(wxVERTICAL) > 0 || GetScrollPos(wxVERTICAL) + 1 < GetScrollRange(wxVERTICAL))) { + PartPlateList &partplate_list = wxGetApp().plater()->get_partplate_list(); + for (int plate_id = 0; plate_id < partplate_list.get_plate_count(); ++plate_id) + if (plate_id != from_plate) + Collapse(m_objects_model->GetItemByPlateId(plate_id)); + wxIdleEvent evt; + SendIdleEvents(evt); + } } bool ObjectList::can_drop(const wxDataViewItem& item, int& src_obj_id, int& src_plate, int& dest_obj_id, int& dest_plate) const @@ -1584,7 +1612,7 @@ bool ObjectList::can_drop(const wxDataViewItem& item, int& src_obj_id, int& src_ if (from_plate == -1) return false; int to_plate = partplate_list.find_instance(to_obj_id, 0); - if ((to_plate == -1) || (from_plate != to_plate)) + if (to_plate == -1) return false; src_obj_id = from_obj_id; @@ -1642,9 +1670,35 @@ void ObjectList::OnDropPossible(wxDataViewEvent &event) int src_obj_id, src_plate, dest_obj_id, dest_plate; if (!can_drop(item, src_obj_id, src_plate, dest_obj_id, dest_plate)) { + if (m_objects_model->GetItemType(item) == itPlate) { + ObjectDataViewModelNode *node = static_cast(item.GetID()); + if (m_dragged_data.set_cur_plate(node->GetPlateIdx()) && !IsExpanded(item)) { + Expand(item); + wxIdleEvent evt; + SendIdleEvents(evt); + } + } event.Veto(); m_prevent_list_events = false; } +#ifdef __WXMSW__ + auto m = GetMainWindow(); + wxPoint mouse_pos = wxGetMousePosition(); + m->ScreenToClient(&mouse_pos.x, &mouse_pos.y); + int offset = mouse_pos.y; + int height = m->GetSize().y; + GetScrollPixelsPerUnit(&mouse_pos.x, &mouse_pos.y); + auto u = mouse_pos.y; + if (offset < u) { + offset = std::min(4 * (u - offset) / u, GetScrollPos(wxVERTICAL) - 0); + } else if (offset + u > height) { + offset = std::max(4 * (height - u - offset) / u, GetScrollPos(wxVERTICAL) + 1 - GetScrollRange(wxVERTICAL)); + } else { + offset = 0; + } + if (offset != 0) + Scroll(0, GetScrollPos(wxVERTICAL) - offset); +#endif } void ObjectList::OnDrop(wxDataViewEvent &event) @@ -1656,6 +1710,7 @@ void ObjectList::OnDrop(wxDataViewEvent &event) { event.Veto(); m_dragged_data.clear(); + part_selection_changed(); return; } @@ -1688,6 +1743,13 @@ void ObjectList::OnDrop(wxDataViewEvent &event) select_item(m_objects_model->ReorganizeObjects(src_obj_id, dest_obj_id)); + if (dest_plate != src_plate) { + // TODO: move object + auto start_origin = partplate_list.get_plate(src_plate)->get_origin(); + auto dest_origin = partplate_list.get_plate(dest_plate)->get_origin(); + (*m_objects)[dest_obj_id]->translate(dest_origin - start_origin); + partplate_list.reload_all_objects(false, dest_plate); + } partplate_list.reload_all_objects(false, src_plate); changed_object(src_obj_id); } @@ -1707,6 +1769,7 @@ void ObjectList::OnDrop(wxDataViewEvent &event) } m_dragged_data.clear(); + part_selection_changed(); wxGetApp().plater()->set_current_canvas_as_dirty(); } diff --git a/src/slic3r/GUI/GUI_ObjectList.hpp b/src/slic3r/GUI/GUI_ObjectList.hpp index 428917701..ee63c29a8 100644 --- a/src/slic3r/GUI/GUI_ObjectList.hpp +++ b/src/slic3r/GUI/GUI_ObjectList.hpp @@ -144,9 +144,12 @@ private: m_type = type; } + bool set_cur_plate(int plate); + void clear() { m_obj_idx = -1; m_vol_idx = -1; + m_last_plate = -1; m_inst_idxs.clear(); m_type = itUndef; } @@ -159,8 +162,10 @@ private: private: int m_obj_idx = -1; int m_vol_idx = -1; + int m_last_plate = -1; std::set m_inst_idxs{}; ItemType m_type = itUndef; + wxDateTime m_last_plate_time; } m_dragged_data; @@ -454,6 +459,9 @@ public: void object_config_options_changed(const ObjectVolumeID& ov_id); void printable_state_changed(const std::vector& ov_ids); + bool is_dragging() const { return m_dragged_data.type() != itUndef; } + void cancel_drag(); + private: #ifdef __WXOSX__ // void OnChar(wxKeyEvent& event); diff --git a/src/slic3r/GUI/GUI_ObjectSettings.cpp b/src/slic3r/GUI/GUI_ObjectSettings.cpp index 90ea93094..790429f93 100644 --- a/src/slic3r/GUI/GUI_ObjectSettings.cpp +++ b/src/slic3r/GUI/GUI_ObjectSettings.cpp @@ -197,7 +197,8 @@ bool ObjectSettings::update_settings_list() auto objects_model = wxGetApp().obj_list()->GetModel(); wxDataViewItemArray items; - objects_ctrl->GetSelections(items); + if (!objects_ctrl->is_dragging()) + objects_ctrl->GetSelections(items); std::map object_configs; bool is_object_settings = false; diff --git a/src/slic3r/GUI/ObjectDataViewModel.cpp b/src/slic3r/GUI/ObjectDataViewModel.cpp index 6352c9253..ee6aa67c0 100644 --- a/src/slic3r/GUI/ObjectDataViewModel.cpp +++ b/src/slic3r/GUI/ObjectDataViewModel.cpp @@ -1811,8 +1811,10 @@ wxDataViewItem ObjectDataViewModel::ReorganizeObjects( const int current_id, co m_objects.erase(m_objects.begin() + current_id); plate_node->GetChildren().Remove(deleted_node); - ItemDeleted(wxDataViewItem(deleted_node->m_parent), wxDataViewItem(deleted_node)); + ItemDeleted(wxDataViewItem(plate_node), wxDataViewItem(deleted_node)); + bool change_plate = plate_node != new_node->m_parent; + plate_node = deleted_node->m_parent = new_node->m_parent; m_objects.emplace(m_objects.begin() + new_id, deleted_node); int plate_child_index = plate_node->GetChildIndex(new_node); if (current_id < new_id) @@ -1821,7 +1823,7 @@ wxDataViewItem ObjectDataViewModel::ReorganizeObjects( const int current_id, co //should not happen plate_node->Insert(deleted_node, plate_child_index); } - ItemAdded(wxDataViewItem(deleted_node->m_parent), wxDataViewItem(deleted_node)); + ItemAdded(wxDataViewItem(plate_node), wxDataViewItem(deleted_node)); //ItemChanged(wxDataViewItem(nullptr));