Merge remote-tracking branch 'origin/ys_selection'

This commit is contained in:
YuSanka 2019-04-05 11:25:29 +02:00
commit 0c662e298f
2 changed files with 190 additions and 52 deletions

View file

@ -82,13 +82,31 @@ ObjectList::ObjectList(wxWindow* parent) :
init_icons(); init_icons();
// describe control behavior // describe control behavior
Bind(wxEVT_DATAVIEW_SELECTION_CHANGED, [this](wxEvent& event) { Bind(wxEVT_DATAVIEW_SELECTION_CHANGED, [this](wxDataViewEvent& event) {
#ifndef __APPLE__ #ifndef __APPLE__
// On Windows and Linux, forces a kill focus emulation on the object manipulator fields because this event handler is called // 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 // 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() // manipulator cache with the following call to selection_changed()
wxGetApp().obj_manipul()->emulate_kill_focus(); wxGetApp().obj_manipul()->emulate_kill_focus();
#endif // __APPLE__ #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(); selection_changed();
#ifndef __WXMSW__ #ifndef __WXMSW__
set_tooltip_for_item(get_mouse_position_in_control()); set_tooltip_for_item(get_mouse_position_in_control());
@ -509,7 +527,7 @@ void ObjectList::key_event(wxKeyEvent& event)
) { ) {
remove(); remove();
} }
else if (wxGetKeyState(wxKeyCode('A')) && wxGetKeyState(WXK_SHIFT)) else if (wxGetKeyState(wxKeyCode('A')) && wxGetKeyState(WXK_CONTROL/*WXK_SHIFT*/))
select_item_all_children(); select_item_all_children();
else else
event.Skip(); event.Skip();
@ -1005,8 +1023,7 @@ wxMenuItem* ObjectList::append_menu_item_instance_to_object(wxMenu* menu)
void ObjectList::append_menu_items_osx(wxMenu* menu) void ObjectList::append_menu_items_osx(wxMenu* menu)
{ {
append_menu_item(menu, wxID_ANY, _(L("Delete item")), "", append_menu_item_delete(menu);
[this](wxCommandEvent&) { remove(); }, "", menu);
append_menu_item(menu, wxID_ANY, _(L("Rename")), "", append_menu_item(menu, wxID_ANY, _(L("Rename")), "",
[this](wxCommandEvent&) { rename_item(); }, "", menu); [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) void ObjectList::create_object_popupmenu(wxMenu *menu)
{ {
#ifdef __WXOSX__ #ifdef __WXOSX__
@ -1118,6 +1141,9 @@ void ObjectList::create_part_popupmenu(wxMenu *menu)
void ObjectList::create_instance_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); m_menu_item_split_instances = append_menu_item_instance_to_object(menu);
/* New behavior logic: /* New behavior logic:
@ -1560,7 +1586,7 @@ void ObjectList::split()
auto opt_keys = model_object->volumes[id]->config.keys(); auto opt_keys = model_object->volumes[id]->config.keys();
if ( !(opt_keys.size() == 1 && opt_keys[0] == "extruder") ) { if ( !(opt_keys.size() == 1 && opt_keys[0] == "extruder") ) {
select_item(m_objects_model->AddSettingsChild(vol_item)); 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(); auto opt_keys = model_object->volumes[id]->config.keys();
if (!opt_keys.empty() && !(opt_keys.size() == 1 && opt_keys[0] == "extruder")) { if (!opt_keys.empty() && !(opt_keys.size() == 1 && opt_keys[0] == "extruder")) {
select_item(m_objects_model->AddSettingsChild(vol_item)); select_item(m_objects_model->AddSettingsChild(vol_item));
Collapse(vol_item); /*Collapse*/Expand(vol_item);
} }
} }
Expand(item); Expand(item);
@ -1768,7 +1794,7 @@ void ObjectList::add_object_to_list(size_t obj_idx)
auto opt_keys = model_object->config.keys(); auto opt_keys = model_object->config.keys();
if (!opt_keys.empty() && !(opt_keys.size() == 1 && opt_keys[0] == "extruder")) { if (!opt_keys.empty() && !(opt_keys.size() == 1 && opt_keys[0] == "extruder")) {
select_item(m_objects_model->AddSettingsChild(item)); select_item(m_objects_model->AddSettingsChild(item));
Collapse(item); /*Collapse*/Expand(item);
} }
#ifndef __WXOSX__ #ifndef __WXOSX__
@ -1948,6 +1974,8 @@ void ObjectList::update_selections()
const Selection& selection = wxGetApp().plater()->canvas3D()->get_selection(); const Selection& selection = wxGetApp().plater()->canvas3D()->get_selection();
wxDataViewItemArray sels; wxDataViewItemArray sels;
m_selection_mode = smInstance;
// We doesn't update selection if SettingsItem for the current object/part is selected // We doesn't update selection if SettingsItem for the current object/part is selected
if (GetSelectedItemsCount() == 1 && m_objects_model->GetItemType(GetSelection()) == itSettings ) if (GetSelectedItemsCount() == 1 && m_objects_model->GetItemType(GetSelection()) == itSettings )
{ {
@ -1961,24 +1989,6 @@ void ObjectList::update_selections()
return; 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()) else if (selection.is_single_full_object() || selection.is_multiple_full_object())
{ {
const Selection::ObjectIdxsToInstanceIdxsMap& objects_content = selection.get_content(); const Selection::ObjectIdxsToInstanceIdxsMap& objects_content = selection.get_content();
@ -1993,8 +2003,10 @@ void ObjectList::update_selections()
bool root_is_selected = false; bool root_is_selected = false;
for (const auto& item:current_sels) 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; root_is_selected = true;
sels.Add(item);
break; break;
} }
if (root_is_selected) if (root_is_selected)
@ -2016,6 +2028,7 @@ void ObjectList::update_selections()
// (for example, SLA supports or SLA pad). // (for example, SLA supports or SLA pad).
sels.Add(m_objects_model->GetItemByVolumeId(gl_vol->object_idx(), gl_vol->volume_idx())); 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()) 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()) 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()) { for (auto idx : selection.get_volume_idxs()) {
const auto gl_vol = selection.get_volume(idx); 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)); sels.Add(m_objects_model->GetItemByVolumeId(glv_obj_idx, glv_vol_idx));
} }
} }
if (sels.size() == 0)
m_selection_mode = smUndef;
select_items(sels); 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) 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)) { const ItemType& type = m_objects_model->GetItemType(item);
selection.add_object(m_objects_model->GetIdByItem(item), as_single_selection); 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; 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 obj_idx = m_objects_model->GetIdByItem(m_objects_model->GetParent(item));
const int vol_idx = m_objects_model->GetVolumeIdByItem(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); 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 obj_idx = m_objects_model->GetIdByItem(m_objects_model->GetTopParent(item));
const int inst_idx = m_objects_model->GetInstanceIdByItem(item); const int inst_idx = m_objects_model->GetInstanceIdByItem(item);
selection.add_instance(obj_idx, inst_idx, as_single_selection); selection.add_instance(obj_idx, inst_idx, as_single_selection);
@ -2116,7 +2134,7 @@ void ObjectList::update_selections_on_canvas()
if (sel_cnt == 1) { if (sel_cnt == 1) {
wxDataViewItem item = GetSelection(); wxDataViewItem item = GetSelection();
if (m_objects_model->GetItemType(item) & (itSettings|itInstanceRoot)) 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 else
add_to_selection(item, selection, instance_idx, true); 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) { if (!GetSelection() || m_objects_model->GetItemType(GetSelection()) == itObject) {
for (int i = 0; i < m_objects->size(); i++) for (int i = 0; i < m_objects->size(); i++)
sels.Add(m_objects_model->GetItemById(i)); sels.Add(m_objects_model->GetItemById(i));
m_selection_mode = smInstance;
} }
else { else {
const auto item = GetSelection(); const auto item = GetSelection();
// Some volume(instance) is selected => select all volumes(instances) inside the current object // 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_objects_model->GetChildren(m_objects_model->GetParent(item), sels);
}
m_selection_mode = m_objects_model->GetItemType(item)&itVolume ? smVolume : smInstance;
} }
SetSelections(sels); SetSelections(sels);
selection_changed(); 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() 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; return;
m_prevent_list_events = true; m_prevent_list_events = true;
@ -2195,27 +2292,59 @@ void ObjectList::fix_multiselection_conflicts()
wxDataViewItemArray sels; wxDataViewItemArray sels;
GetSelections(sels); GetSelections(sels);
for (const auto item : sels) { if (m_selection_mode == smVolume)
if (!IsSelected(item)) // if this item is unselected now (from previous actions) {
continue; // 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) { sels.clear();
Unselect(item); wxDataViewItemArray children; // selected volumes from current parent
continue; m_objects_model->GetChildren(parent, children);
}
const wxDataViewItem& parent = m_objects_model->GetParent(item); for (const auto child : children)
if (parent != wxDataViewItem(0) && IsSelected(parent)) if (IsSelected(child) && m_objects_model->GetItemType(child)&itVolume)
Unselect(parent); sels.Add(child);
else
// 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; if (!IsSelected(item)) // if this item is unselected now (from previous actions)
m_objects_model->GetAllChildren(item, unsels); continue;
for (const auto unsel_item : unsels)
Unselect(unsel_item); 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; m_prevent_list_events = false;
} }
@ -2535,8 +2664,7 @@ void ObjectList::show_multi_selection_menu()
wxMenu* menu = new wxMenu(); wxMenu* menu = new wxMenu();
#ifdef __WXOSX__ #ifdef __WXOSX__
append_menu_item(menu, wxID_ANY, _(L("Delete items")), "", append_menu_item_delete(menu);
[this](wxCommandEvent&) { remove(); }, "", menu);
#endif //__WXOSX__ #endif //__WXOSX__
if (extruders_count() > 1) if (extruders_count() > 1)

View file

@ -60,6 +60,12 @@ struct ItemForDelete
class ObjectList : public wxDataViewCtrl class ObjectList : public wxDataViewCtrl
{ {
enum SELECTION_MODE
{
smUndef,
smVolume,
smInstance
} m_selection_mode {smUndef};
struct dragged_item_data struct dragged_item_data
{ {
@ -135,6 +141,7 @@ class ObjectList : public wxDataViewCtrl
bool m_part_settings_changed = false; bool m_part_settings_changed = false;
int m_selected_row = 0; int m_selected_row = 0;
wxDataViewItem m_last_selected_item {nullptr};
#if 0 #if 0
FreqSettingsBundle m_freq_settings_fff; FreqSettingsBundle m_freq_settings_fff;
@ -188,6 +195,7 @@ public:
void append_menu_item_fix_through_netfabb(wxMenu* menu); void append_menu_item_fix_through_netfabb(wxMenu* menu);
void append_menu_item_export_stl(wxMenu* menu) const ; void append_menu_item_export_stl(wxMenu* menu) const ;
void append_menu_item_change_extruder(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_object_popupmenu(wxMenu *menu);
void create_sla_object_popupmenu(wxMenu*menu); void create_sla_object_popupmenu(wxMenu*menu);
void create_part_popupmenu(wxMenu*menu); void create_part_popupmenu(wxMenu*menu);
@ -258,6 +266,8 @@ public:
void select_items(const wxDataViewItemArray& sels); void select_items(const wxDataViewItemArray& sels);
void select_all(); void select_all();
void select_item_all_children(); 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 // correct current selections to avoid of the possible conflicts
void fix_multiselection_conflicts(); void fix_multiselection_conflicts();