Selection improvements
+ "Delete" menu_item for Instances under OSX
This commit is contained in:
parent
ac6a232795
commit
81809018bc
@ -82,13 +82,14 @@ 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__
|
||||
m_last_selected_item = event.GetItem();
|
||||
selection_changed();
|
||||
#ifndef __WXMSW__
|
||||
set_tooltip_for_item(get_mouse_position_in_control());
|
||||
@ -1006,8 +1007,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);
|
||||
@ -1062,6 +1062,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 +1124,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);
|
||||
|
||||
wxGetApp().plater()->Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) {
|
||||
@ -1552,7 +1561,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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1746,7 +1755,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);
|
||||
@ -1760,7 +1769,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__
|
||||
@ -1940,6 +1949,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 )
|
||||
{
|
||||
@ -1953,24 +1964,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();
|
||||
@ -1985,8 +1978,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)
|
||||
@ -2008,6 +2003,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())
|
||||
{
|
||||
@ -2017,7 +2013,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);
|
||||
@ -2050,6 +2046,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);
|
||||
|
||||
@ -2085,29 +2084,34 @@ 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);
|
||||
}
|
||||
};
|
||||
|
||||
// stores current instance idx before to clear the selection
|
||||
int instance_idx = selection.get_instance_idx();
|
||||
|
||||
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, -1, true);
|
||||
add_to_selection(item, selection, instance_idx, true);
|
||||
|
||||
wxGetApp().plater()->canvas3D()->update_gizmos_on_off_state();
|
||||
return;
|
||||
@ -2116,8 +2120,6 @@ void ObjectList::update_selections_on_canvas()
|
||||
wxDataViewItemArray sels;
|
||||
GetSelections(sels);
|
||||
|
||||
// stores current instance idx before to clear the selection
|
||||
int instance_idx = selection.get_instance_idx();
|
||||
selection.clear();
|
||||
for (auto item: sels)
|
||||
add_to_selection(item, selection, instance_idx, false);
|
||||
@ -2163,22 +2165,79 @@ 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()
|
||||
{
|
||||
m_last_selected_item = wxDataViewItem(0);
|
||||
|
||||
// All items are unselected
|
||||
if (!GetSelection())
|
||||
{
|
||||
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()
|
||||
{
|
||||
if (!m_last_selected_item)
|
||||
return true;
|
||||
|
||||
/* We can't mix Parts and Objects/Instances.
|
||||
* So, unselect last selected item and show information about it
|
||||
*/
|
||||
const ItemType type = m_objects_model->GetItemType(m_last_selected_item);
|
||||
if (type & itSettings ||
|
||||
type & itVolume && m_selection_mode == smInstance ||
|
||||
!(type & itVolume) && m_selection_mode == smVolume)
|
||||
{
|
||||
Unselect(m_last_selected_item);
|
||||
|
||||
// Inform user why selection isn't complited
|
||||
const wxString item_type = m_selection_mode == smInstance ? _(L("Object or Instance")) : _(L("Part"));
|
||||
|
||||
const wxString msg_str = wxString::Format(_(L("You started your selection with %s Item.")) + "\n" +
|
||||
_(L("In this mode you can select only another %s Items%s")), item_type, item_type,
|
||||
m_selection_mode == smInstance ? "." : " " + _(L("of a current Object")));
|
||||
|
||||
wxMessageDialog dialog(this, _(L("Unsupported selection")) + "\n\n" + msg_str,
|
||||
_(L("Info")), wxICON_INFORMATION);
|
||||
dialog.ShowModal();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ObjectList::fix_multiselection_conflicts()
|
||||
{
|
||||
if (GetSelectedItemsCount() <= 1)
|
||||
if (GetSelectedItemsCount() <= 1) {
|
||||
update_selection_mode();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!check_last_selection())
|
||||
return;
|
||||
|
||||
m_prevent_list_events = true;
|
||||
@ -2186,6 +2245,8 @@ void ObjectList::fix_multiselection_conflicts()
|
||||
wxDataViewItemArray sels;
|
||||
GetSelections(sels);
|
||||
|
||||
m_selection_mode = smInstance;
|
||||
|
||||
for (const auto item : sels) {
|
||||
if (!IsSelected(item)) // if this item is unselected now (from previous actions)
|
||||
continue;
|
||||
@ -2205,6 +2266,26 @@ void ObjectList::fix_multiselection_conflicts()
|
||||
for (const auto unsel_item : unsels)
|
||||
Unselect(unsel_item);
|
||||
}
|
||||
|
||||
if (m_objects_model->GetItemType(item) == itVolume)
|
||||
{
|
||||
// If some part is selected, unselect all items except of selected parts of the current object
|
||||
sels.clear();
|
||||
|
||||
wxDataViewItemArray children; // selected volumes from current parent
|
||||
m_objects_model->GetChildren(parent, children);
|
||||
for (const auto child : children)
|
||||
{
|
||||
if (IsSelected(child) && m_objects_model->GetItemType(child)&itVolume)
|
||||
sels.Add(child);
|
||||
}
|
||||
|
||||
UnselectAll();
|
||||
SetSelections(sels);
|
||||
|
||||
m_selection_mode = smVolume;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
m_prevent_list_events = false;
|
||||
@ -2489,8 +2570,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();
|
||||
#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();
|
||||
// correct current selections to avoid of the possible conflicts
|
||||
void fix_multiselection_conflicts();
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user