Selection improvements

+ "Delete" menu_item for Instances under OSX
This commit is contained in:
YuSanka 2019-04-02 16:33:52 +02:00
parent ac6a232795
commit 81809018bc
2 changed files with 129 additions and 39 deletions

View File

@ -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)

View File

@ -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();