1 #include "ObjectDataViewModel.hpp"
2 #include "wxExtensions.hpp"
3 #include "BitmapCache.hpp"
4 #include "GUI_App.hpp"
5 #include "GUI_ObjectList.hpp"
6 #include "I18N.hpp"
7 
8 #include "libslic3r/Model.hpp"
9 
10 #include <wx/bmpcbox.h>
11 #include <wx/dc.h>
12 
13 
14 namespace Slic3r {
15 
16 namespace GUI {
17 
18 wxDEFINE_EVENT(wxCUSTOMEVT_LAST_VOLUME_IS_DELETED, wxCommandEvent);
19 
get_extruder_color_icon(size_t extruder_idx,bool thin_icon=false)20 static wxBitmap get_extruder_color_icon(size_t extruder_idx, bool thin_icon = false)
21 {
22     // Create the bitmap with color bars.
23     std::vector<wxBitmap*> bmps = get_extruder_color_icons(thin_icon);
24     if (bmps.empty())
25         return wxNullBitmap;
26 
27     return *bmps[extruder_idx >= bmps.size() ? 0 : extruder_idx];
28 }
29 
30 BitmapCache* m_bitmap_cache = nullptr;
31 
32 // *****************************************************************************
33 // ----------------------------------------------------------------------------
34 // ObjectDataViewModelNode
35 // ----------------------------------------------------------------------------
36 
init_container()37 void ObjectDataViewModelNode::init_container()
38 {
39 #ifdef __WXGTK__
40     // it's necessary on GTK because of control have to know if this item will be container
41     // in another case you couldn't to add subitem for this item
42     // it will be produce "segmentation fault"
43     m_container = true;
44 #endif  //__WXGTK__
45 }
46 
47 #define LAYER_ROOT_ICON "edit_layers_all"
48 #define LAYER_ICON      "edit_layers_some"
49 
ObjectDataViewModelNode(ObjectDataViewModelNode * parent,const ItemType type)50 ObjectDataViewModelNode::ObjectDataViewModelNode(ObjectDataViewModelNode* parent, const ItemType type) :
51     m_parent(parent),
52     m_type(type),
53     m_extruder(wxEmptyString)
54 {
55     if (type == itSettings)
56         m_name = "Settings to modified";
57     else if (type == itInstanceRoot)
58         m_name = _(L("Instances"));
59     else if (type == itInstance)
60     {
61         m_idx = parent->GetChildCount();
62         m_name = wxString::Format(_(L("Instance %d")), m_idx + 1);
63 
64         set_action_and_extruder_icons();
65     }
66     else if (type == itLayerRoot)
67     {
68         m_bmp = create_scaled_bitmap(LAYER_ROOT_ICON);    // FIXME: pass window ptr
69         m_name = _(L("Layers"));
70     }
71 
72     if (type & (itInstanceRoot | itLayerRoot))
73         init_container();
74 }
75 
ObjectDataViewModelNode(ObjectDataViewModelNode * parent,const t_layer_height_range & layer_range,const int idx,const wxString & extruder)76 ObjectDataViewModelNode::ObjectDataViewModelNode(ObjectDataViewModelNode* parent,
77                                                  const t_layer_height_range& layer_range,
78                                                  const int idx /*= -1 */,
79                                                  const wxString& extruder) :
80     m_parent(parent),
81     m_type(itLayer),
82     m_idx(idx),
83     m_layer_range(layer_range),
84     m_extruder(extruder)
85 {
86     const int children_cnt = parent->GetChildCount();
87     if (idx < 0)
88         m_idx = children_cnt;
89     else
90     {
91         // update indexes for another Laeyr Nodes
92         for (int i = m_idx; i < children_cnt; i++)
93             parent->GetNthChild(i)->SetIdx(i + 1);
94     }
95     const std::string label_range = (boost::format(" %.2f-%.2f ") % layer_range.first % layer_range.second).str();
96     m_name = _(L("Range")) + label_range + "(" + _(L("mm")) + ")";
97     m_bmp = create_scaled_bitmap(LAYER_ICON);    // FIXME: pass window ptr
98 
99     set_action_and_extruder_icons();
100     init_container();
101 }
102 
103 #ifndef NDEBUG
valid()104 bool ObjectDataViewModelNode::valid()
105 {
106 	// Verify that the object was not deleted yet.
107 	assert(m_idx >= -1);
108 	return m_idx >= -1;
109 }
110 #endif /* NDEBUG */
111 
set_action_and_extruder_icons()112 void ObjectDataViewModelNode::set_action_and_extruder_icons()
113 {
114     m_action_icon_name = m_type & itObject              ? "advanced_plus" :
115                          m_type & (itVolume | itLayer)  ? "cog" : /*m_type & itInstance*/ "set_separate_obj";
116     m_action_icon = create_scaled_bitmap(m_action_icon_name);    // FIXME: pass window ptr
117 
118     // set extruder bitmap
119     set_extruder_icon();
120 }
121 
set_extruder_icon()122 void ObjectDataViewModelNode::set_extruder_icon()
123 {
124     if (m_type & itInstance)
125         return; // don't set colored bitmap for Instance
126 
127     int extruder_idx = atoi(m_extruder.c_str());
128     if (extruder_idx > 0) --extruder_idx;
129     m_extruder_bmp = get_extruder_color_icon(extruder_idx);
130 }
131 
set_printable_icon(PrintIndicator printable)132 void ObjectDataViewModelNode::set_printable_icon(PrintIndicator printable)
133 {
134     m_printable = printable;
135     m_printable_icon = m_printable == piUndef ? m_empty_bmp :
136                        create_scaled_bitmap(m_printable == piPrintable ? "eye_open.png" : "eye_closed.png");
137 }
138 
update_settings_digest_bitmaps()139 void ObjectDataViewModelNode::update_settings_digest_bitmaps()
140 {
141     m_bmp = m_empty_bmp;
142 
143     std::map<std::string, wxBitmap>& categories_icon = Slic3r::GUI::wxGetApp().obj_list()->CATEGORY_ICON;
144 
145     std::string scaled_bitmap_name = m_name.ToUTF8().data();
146     scaled_bitmap_name += "-em" + std::to_string(wxGetApp().em_unit()) + (wxGetApp().dark_mode() ? "-dm" : "");
147 
148     wxBitmap *bmp = m_bitmap_cache->find(scaled_bitmap_name);
149     if (bmp == nullptr) {
150         std::vector<wxBitmap> bmps;
151         for (auto& cat : m_opt_categories)
152             bmps.emplace_back(  categories_icon.find(cat) == categories_icon.end() ?
153                                 wxNullBitmap : categories_icon.at(cat));
154         bmp = m_bitmap_cache->insert(scaled_bitmap_name, bmps);
155     }
156 
157     m_bmp = *bmp;
158 }
159 
update_settings_digest(const std::vector<std::string> & categories)160 bool ObjectDataViewModelNode::update_settings_digest(const std::vector<std::string>& categories)
161 {
162     if (m_type != itSettings || m_opt_categories == categories)
163         return false;
164 
165     m_opt_categories = categories;
166     m_name = wxEmptyString;
167 
168     for (auto& cat : m_opt_categories)
169         m_name += _(cat) + "; ";
170     if (!m_name.IsEmpty())
171         m_name.erase(m_name.Length()-2, 2); // Delete last "; "
172 
173     update_settings_digest_bitmaps();
174 
175     return true;
176 }
177 
msw_rescale()178 void ObjectDataViewModelNode::msw_rescale()
179 {
180     if (!m_action_icon_name.empty())
181         m_action_icon = create_scaled_bitmap(m_action_icon_name);
182 
183     if (m_printable != piUndef)
184         m_printable_icon = create_scaled_bitmap(m_printable == piPrintable ? "eye_open.png" : "eye_closed.png");
185 
186     if (!m_opt_categories.empty())
187         update_settings_digest_bitmaps();
188 
189     set_extruder_icon();
190 }
191 
SetValue(const wxVariant & variant,unsigned col)192 bool ObjectDataViewModelNode::SetValue(const wxVariant& variant, unsigned col)
193 {
194     switch (col)
195     {
196     case colPrint:
197         m_printable_icon << variant;
198         return true;
199     case colName: {
200         DataViewBitmapText data;
201         data << variant;
202         m_bmp = data.GetBitmap();
203         m_name = data.GetText();
204         return true; }
205     case colExtruder: {
206         DataViewBitmapText data;
207         data << variant;
208         m_extruder_bmp = data.GetBitmap();
209         m_extruder = data.GetText() == "0" ? _(L("default")) : data.GetText();
210         return true; }
211     case colEditing:
212         m_action_icon << variant;
213         return true;
214     default:
215         printf("MyObjectTreeModel::SetValue: wrong column");
216     }
217     return false;
218 }
219 
SetIdx(const int & idx)220 void ObjectDataViewModelNode::SetIdx(const int& idx)
221 {
222     m_idx = idx;
223     // update name if this node is instance
224     if (m_type == itInstance)
225         m_name = wxString::Format(_(L("Instance %d")), m_idx + 1);
226 }
227 
228 // *****************************************************************************
229 // ----------------------------------------------------------------------------
230 // ObjectDataViewModel
231 // ----------------------------------------------------------------------------
232 
get_root_idx(ObjectDataViewModelNode * parent_node,const ItemType root_type)233 static int get_root_idx(ObjectDataViewModelNode *parent_node, const ItemType root_type)
234 {
235     // because of istance_root and layers_root are at the end of the list, so
236     // start locking from the end
237     for (int root_idx = parent_node->GetChildCount() - 1; root_idx >= 0; root_idx--)
238     {
239         // if there is SettingsItem or VolumeItem, then RootItems don't exist in current ObjectItem
240         if (parent_node->GetNthChild(root_idx)->GetType() & (itSettings | itVolume))
241             break;
242         if (parent_node->GetNthChild(root_idx)->GetType() & root_type)
243             return root_idx;
244     }
245 
246     return -1;
247 }
248 
ObjectDataViewModel()249 ObjectDataViewModel::ObjectDataViewModel()
250 {
251     m_bitmap_cache = new Slic3r::GUI::BitmapCache;
252 }
253 
~ObjectDataViewModel()254 ObjectDataViewModel::~ObjectDataViewModel()
255 {
256     for (auto object : m_objects)
257 			delete object;
258     delete m_bitmap_cache;
259     m_bitmap_cache = nullptr;
260 }
261 
Add(const wxString & name,const int extruder,const bool has_errors)262 wxDataViewItem ObjectDataViewModel::Add(const wxString &name,
263                                         const int extruder,
264                                         const bool has_errors/* = false*/)
265 {
266     const wxString extruder_str = extruder == 0 ? _(L("default")) : wxString::Format("%d", extruder);
267 	auto root = new ObjectDataViewModelNode(name, extruder_str);
268     // Add error icon if detected auto-repaire
269     if (has_errors)
270         root->m_bmp = *m_warning_bmp;
271 
272     m_objects.push_back(root);
273 	// notify control
274 	wxDataViewItem child((void*)root);
275 	wxDataViewItem parent((void*)NULL);
276 
277 	ItemAdded(parent, child);
278 	return child;
279 }
280 
AddVolumeChild(const wxDataViewItem & parent_item,const wxString & name,const Slic3r::ModelVolumeType volume_type,const bool has_errors,const int extruder,const bool create_frst_child)281 wxDataViewItem ObjectDataViewModel::AddVolumeChild( const wxDataViewItem &parent_item,
282                                                     const wxString &name,
283                                                     const Slic3r::ModelVolumeType volume_type,
284                                                     const bool has_errors/* = false*/,
285                                                     const int extruder/* = 0*/,
286                                                     const bool create_frst_child/* = true*/)
287 {
288 	ObjectDataViewModelNode *root = static_cast<ObjectDataViewModelNode*>(parent_item.GetID());
289 	if (!root) return wxDataViewItem(0);
290 
291     wxString extruder_str = extruder == 0 ? _(L("default")) : wxString::Format("%d", extruder);
292 
293     // get insertion position according to the existed Layers and/or Instances Items
294     int insert_position = get_root_idx(root, itLayerRoot);
295     if (insert_position < 0)
296         insert_position = get_root_idx(root, itInstanceRoot);
297 
298     const bool obj_errors = root->m_bmp.IsOk();
299 
300     if (create_frst_child && root->m_volumes_cnt == 0)
301     {
302         const Slic3r::ModelVolumeType type = Slic3r::ModelVolumeType::MODEL_PART;
303         const auto node = new ObjectDataViewModelNode(root, root->m_name, GetVolumeIcon(type, obj_errors), extruder_str, 0);
304         node->m_volume_type = type;
305 
306         insert_position < 0 ? root->Append(node) : root->Insert(node, insert_position);
307 		// notify control
308 		const wxDataViewItem child((void*)node);
309 		ItemAdded(parent_item, child);
310 
311         root->m_volumes_cnt++;
312         if (insert_position >= 0) insert_position++;
313 	}
314 
315     const auto node = new ObjectDataViewModelNode(root, name, GetVolumeIcon(volume_type, has_errors), extruder_str, root->m_volumes_cnt);
316     insert_position < 0 ? root->Append(node) : root->Insert(node, insert_position);
317 
318     // if part with errors is added, but object wasn't marked, then mark it
319     if (!obj_errors && has_errors)
320         root->SetBitmap(*m_warning_bmp);
321 
322 	// notify control
323     const wxDataViewItem child((void*)node);
324     ItemAdded(parent_item, child);
325     root->m_volumes_cnt++;
326 
327     node->m_volume_type = volume_type;
328 
329 	return child;
330 }
331 
AddSettingsChild(const wxDataViewItem & parent_item)332 wxDataViewItem ObjectDataViewModel::AddSettingsChild(const wxDataViewItem &parent_item)
333 {
334     ObjectDataViewModelNode *root = static_cast<ObjectDataViewModelNode*>(parent_item.GetID());
335     if (!root) return wxDataViewItem(0);
336 
337     const auto node = new ObjectDataViewModelNode(root, itSettings);
338     root->Insert(node, 0);
339     // notify control
340     const wxDataViewItem child((void*)node);
341     ItemAdded(parent_item, child);
342     return child;
343 }
344 
345 /* return values:
346  * true     => root_node is created and added to the parent_root
347  * false    => root node alredy exists
348 */
append_root_node(ObjectDataViewModelNode * parent_node,ObjectDataViewModelNode ** root_node,const ItemType root_type)349 static bool append_root_node(ObjectDataViewModelNode *parent_node,
350                              ObjectDataViewModelNode **root_node,
351                              const ItemType root_type)
352 {
353     const int inst_root_id = get_root_idx(parent_node, root_type);
354 
355     *root_node = inst_root_id < 0 ?
356                 new ObjectDataViewModelNode(parent_node, root_type) :
357                 parent_node->GetNthChild(inst_root_id);
358 
359     if (inst_root_id < 0) {
360         if ((root_type&itInstanceRoot) ||
361             ( (root_type&itLayerRoot) && get_root_idx(parent_node, itInstanceRoot)<0) )
362             parent_node->Append(*root_node);
363         else if (root_type&itLayerRoot)
364             parent_node->Insert(*root_node, static_cast<unsigned int>(get_root_idx(parent_node, itInstanceRoot)));
365         return true;
366     }
367 
368     return false;
369 }
370 
AddRoot(const wxDataViewItem & parent_item,ItemType root_type)371 wxDataViewItem ObjectDataViewModel::AddRoot(const wxDataViewItem &parent_item, ItemType root_type)
372 {
373     ObjectDataViewModelNode *parent_node = static_cast<ObjectDataViewModelNode*>(parent_item.GetID());
374     if (!parent_node) return wxDataViewItem(0);
375 
376     // get InstanceRoot node
377     ObjectDataViewModelNode *root_node { nullptr };
378     const bool appended = append_root_node(parent_node, &root_node, root_type);
379     if (!root_node) return wxDataViewItem(0);
380 
381     const wxDataViewItem root_item((void*)root_node);
382 
383     if (appended)
384         ItemAdded(parent_item, root_item);// notify control
385     return root_item;
386 }
387 
AddInstanceRoot(const wxDataViewItem & parent_item)388 wxDataViewItem ObjectDataViewModel::AddInstanceRoot(const wxDataViewItem &parent_item)
389 {
390     return AddRoot(parent_item, itInstanceRoot);
391 }
392 
AddInstanceChild(const wxDataViewItem & parent_item,size_t num)393 wxDataViewItem ObjectDataViewModel::AddInstanceChild(const wxDataViewItem &parent_item, size_t num)
394 {
395     std::vector<bool> print_indicator(num, true);
396 
397     // if InstanceRoot item isn't created for this moment
398     if (!GetInstanceRootItem(parent_item).IsOk())
399         // use object's printable state to first instance
400         print_indicator[0] = IsPrintable(parent_item);
401 
402     return wxDataViewItem((void*)AddInstanceChild(parent_item, print_indicator));
403 }
404 
AddInstanceChild(const wxDataViewItem & parent_item,const std::vector<bool> & print_indicator)405 wxDataViewItem ObjectDataViewModel::AddInstanceChild(const wxDataViewItem& parent_item,
406                                                      const std::vector<bool>& print_indicator)
407 {
408     const wxDataViewItem inst_root_item = AddInstanceRoot(parent_item);
409     if (!inst_root_item) return wxDataViewItem(0);
410 
411     ObjectDataViewModelNode* inst_root_node = static_cast<ObjectDataViewModelNode*>(inst_root_item.GetID());
412 
413     // Add instance nodes
414     ObjectDataViewModelNode *instance_node = nullptr;
415     size_t counter = 0;
416     while (counter < print_indicator.size()) {
417         instance_node = new ObjectDataViewModelNode(inst_root_node, itInstance);
418 
419         instance_node->set_printable_icon(print_indicator[counter] ? piPrintable : piUnprintable);
420 
421         inst_root_node->Append(instance_node);
422         // notify control
423         const wxDataViewItem instance_item((void*)instance_node);
424         ItemAdded(inst_root_item, instance_item);
425         ++counter;
426     }
427 
428     // update object_node printable property
429     UpdateObjectPrintable(parent_item);
430 
431     return wxDataViewItem((void*)instance_node);
432 }
433 
UpdateObjectPrintable(wxDataViewItem parent_item)434 void ObjectDataViewModel::UpdateObjectPrintable(wxDataViewItem parent_item)
435 {
436     const wxDataViewItem inst_root_item = GetInstanceRootItem(parent_item);
437     if (!inst_root_item)
438         return;
439 
440     ObjectDataViewModelNode* inst_root_node = static_cast<ObjectDataViewModelNode*>(inst_root_item.GetID());
441 
442     const size_t child_cnt = inst_root_node->GetChildren().Count();
443     PrintIndicator obj_pi = piUnprintable;
444     for (size_t i=0; i < child_cnt; i++)
445         if (inst_root_node->GetNthChild(i)->IsPrintable() & piPrintable) {
446             obj_pi = piPrintable;
447             break;
448         }
449     // and set printable state for object_node to piUndef
450     ObjectDataViewModelNode* obj_node = static_cast<ObjectDataViewModelNode*>(parent_item.GetID());
451     obj_node->set_printable_icon(obj_pi);
452     ItemChanged(parent_item);
453 }
454 
455 // update printable property for all instances from object
UpdateInstancesPrintable(wxDataViewItem parent_item)456 void ObjectDataViewModel::UpdateInstancesPrintable(wxDataViewItem parent_item)
457 {
458     const wxDataViewItem inst_root_item = GetInstanceRootItem(parent_item);
459     if (!inst_root_item)
460         return;
461 
462     ObjectDataViewModelNode* obj_node = static_cast<ObjectDataViewModelNode*>(parent_item.GetID());
463     const PrintIndicator obj_pi = obj_node->IsPrintable();
464 
465     ObjectDataViewModelNode* inst_root_node = static_cast<ObjectDataViewModelNode*>(inst_root_item.GetID());
466     const size_t child_cnt = inst_root_node->GetChildren().Count();
467 
468     for (size_t i=0; i < child_cnt; i++)
469     {
470         ObjectDataViewModelNode* inst_node = inst_root_node->GetNthChild(i);
471         // and set printable state for object_node to piUndef
472         inst_node->set_printable_icon(obj_pi);
473         ItemChanged(wxDataViewItem((void*)inst_node));
474     }
475 }
476 
IsPrintable(const wxDataViewItem & item) const477 bool ObjectDataViewModel::IsPrintable(const wxDataViewItem& item) const
478 {
479     ObjectDataViewModelNode* node = static_cast<ObjectDataViewModelNode*>(item.GetID());
480     if (!node)
481         return false;
482 
483     return node->IsPrintable() == piPrintable;
484 }
485 
AddLayersRoot(const wxDataViewItem & parent_item)486 wxDataViewItem ObjectDataViewModel::AddLayersRoot(const wxDataViewItem &parent_item)
487 {
488     return AddRoot(parent_item, itLayerRoot);
489 }
490 
AddLayersChild(const wxDataViewItem & parent_item,const t_layer_height_range & layer_range,const int extruder,const int index)491 wxDataViewItem ObjectDataViewModel::AddLayersChild(const wxDataViewItem &parent_item,
492                                                    const t_layer_height_range& layer_range,
493                                                    const int extruder/* = 0*/,
494                                                    const int index /* = -1*/)
495 {
496     ObjectDataViewModelNode *parent_node = static_cast<ObjectDataViewModelNode*>(parent_item.GetID());
497     if (!parent_node) return wxDataViewItem(0);
498 
499     wxString extruder_str = extruder == 0 ? _(L("default")) : wxString::Format("%d", extruder);
500 
501     // get LayerRoot node
502     ObjectDataViewModelNode *layer_root_node;
503     wxDataViewItem layer_root_item;
504 
505     if (parent_node->GetType() & itLayerRoot) {
506         layer_root_node = parent_node;
507         layer_root_item = parent_item;
508     }
509     else {
510         const int root_idx = get_root_idx(parent_node, itLayerRoot);
511         if (root_idx < 0) return wxDataViewItem(0);
512         layer_root_node = parent_node->GetNthChild(root_idx);
513         layer_root_item = wxDataViewItem((void*)layer_root_node);
514     }
515 
516     // Add layer node
517     ObjectDataViewModelNode *layer_node = new ObjectDataViewModelNode(layer_root_node, layer_range, index, extruder_str);
518     if (index < 0)
519         layer_root_node->Append(layer_node);
520     else
521         layer_root_node->Insert(layer_node, index);
522 
523     // notify control
524     const wxDataViewItem layer_item((void*)layer_node);
525     ItemAdded(layer_root_item, layer_item);
526 
527     return layer_item;
528 }
529 
Delete(const wxDataViewItem & item)530 wxDataViewItem ObjectDataViewModel::Delete(const wxDataViewItem &item)
531 {
532 	auto ret_item = wxDataViewItem(0);
533 	ObjectDataViewModelNode *node = static_cast<ObjectDataViewModelNode*>(item.GetID());
534 	if (!node)      // happens if item.IsOk()==false
535 		return ret_item;
536 
537 	auto node_parent = node->GetParent();
538 	wxDataViewItem parent(node_parent);
539 
540 	// first remove the node from the parent's array of children;
541 	// NOTE: MyObjectTreeModelNodePtrArray is only an array of _pointers_
542 	//       thus removing the node from it doesn't result in freeing it
543 	if (node_parent) {
544         if (node->m_type & (itInstanceRoot|itLayerRoot))
545         {
546             // node can be deleted by the Delete, let's check its type while we safely can
547             bool is_instance_root = (node->m_type & itInstanceRoot);
548 
549             for (int i = int(node->GetChildCount() - 1); i >= (is_instance_root ? 1 : 0); i--)
550                 Delete(wxDataViewItem(node->GetNthChild(i)));
551 
552             return parent;
553         }
554 
555 		auto id = node_parent->GetChildren().Index(node);
556         auto idx = node->GetIdx();
557 
558 
559         if (node->m_type & (itVolume|itLayer)) {
560             node_parent->m_volumes_cnt--;
561             DeleteSettings(item);
562         }
563 		node_parent->GetChildren().Remove(node);
564 
565 		if (id > 0) {
566             if (size_t(id) == node_parent->GetChildCount()) id--;
567 			ret_item = wxDataViewItem(node_parent->GetChildren().Item(id));
568 		}
569 
570 		//update idx value for remaining child-nodes
571 		auto children = node_parent->GetChildren();
572         for (size_t i = 0; i < node_parent->GetChildCount() && idx>=0; i++)
573 		{
574             auto cur_idx = children[i]->GetIdx();
575 			if (cur_idx > idx)
576 				children[i]->SetIdx(cur_idx-1);
577 		}
578 
579         // if there is last instance item, delete both of it and instance root item
580         if (node_parent->GetChildCount() == 1 && node_parent->GetNthChild(0)->m_type == itInstance)
581         {
582             delete node;
583             ItemDeleted(parent, item);
584 
585             ObjectDataViewModelNode *last_instance_node = node_parent->GetNthChild(0);
586             PrintIndicator last_instance_printable = last_instance_node->IsPrintable();
587             node_parent->GetChildren().Remove(last_instance_node);
588             delete last_instance_node;
589             ItemDeleted(parent, wxDataViewItem(last_instance_node));
590 
591             ObjectDataViewModelNode *obj_node = node_parent->GetParent();
592             obj_node->set_printable_icon(last_instance_printable);
593             obj_node->GetChildren().Remove(node_parent);
594             delete node_parent;
595             ret_item = wxDataViewItem(obj_node);
596 
597 #ifndef __WXGTK__
598             if (obj_node->GetChildCount() == 0)
599                 obj_node->m_container = false;
600 #endif //__WXGTK__
601             ItemDeleted(ret_item, wxDataViewItem(node_parent));
602             return ret_item;
603         }
604 
605         if (node->m_type & itInstance)
606             UpdateObjectPrintable(wxDataViewItem(node_parent->GetParent()));
607 
608         // if there was last layer item, delete this one and layers root item
609         if (node_parent->GetChildCount() == 0 && node_parent->m_type == itLayerRoot)
610         {
611             ObjectDataViewModelNode *obj_node = node_parent->GetParent();
612             obj_node->GetChildren().Remove(node_parent);
613             delete node_parent;
614             ret_item = wxDataViewItem(obj_node);
615 
616 #ifndef __WXGTK__
617             if (obj_node->GetChildCount() == 0)
618                 obj_node->m_container = false;
619 #endif //__WXGTK__
620             ItemDeleted(ret_item, wxDataViewItem(node_parent));
621             return ret_item;
622         }
623 
624         // if there is last volume item after deleting, delete this last volume too
625         if (node_parent->GetChildCount() <= 3) // 3??? #ys_FIXME
626         {
627             int vol_cnt = 0;
628             int vol_idx = 0;
629             for (size_t i = 0; i < node_parent->GetChildCount(); ++i) {
630                 if (node_parent->GetNthChild(i)->GetType() == itVolume) {
631                     vol_idx = i;
632                     vol_cnt++;
633                 }
634                 if (vol_cnt > 1)
635                     break;
636             }
637 
638             if (vol_cnt == 1) {
639                 delete node;
640                 ItemDeleted(parent, item);
641 
642                 ObjectDataViewModelNode *last_child_node = node_parent->GetNthChild(vol_idx);
643                 DeleteSettings(wxDataViewItem(last_child_node));
644                 node_parent->GetChildren().Remove(last_child_node);
645                 node_parent->m_volumes_cnt = 0;
646                 delete last_child_node;
647 
648 #ifndef __WXGTK__
649                 if (node_parent->GetChildCount() == 0)
650                     node_parent->m_container = false;
651 #endif //__WXGTK__
652                 ItemDeleted(parent, wxDataViewItem(last_child_node));
653 
654                 wxCommandEvent event(wxCUSTOMEVT_LAST_VOLUME_IS_DELETED);
655                 auto it = find(m_objects.begin(), m_objects.end(), node_parent);
656                 event.SetInt(it == m_objects.end() ? -1 : it - m_objects.begin());
657                 wxPostEvent(m_ctrl, event);
658 
659                 ret_item = parent;
660 
661                 return ret_item;
662             }
663         }
664 	}
665 	else
666 	{
667 		auto it = find(m_objects.begin(), m_objects.end(), node);
668         size_t id = it - m_objects.begin();
669 		if (it != m_objects.end())
670 		{
671             // Delete all sub-items
672             int i = m_objects[id]->GetChildCount() - 1;
673             while (i >= 0) {
674                 Delete(wxDataViewItem(m_objects[id]->GetNthChild(i)));
675                 i = m_objects[id]->GetChildCount() - 1;
676             }
677 			m_objects.erase(it);
678         }
679 		if (id > 0) {
680 			if(id == m_objects.size()) id--;
681 			ret_item = wxDataViewItem(m_objects[id]);
682 		}
683 	}
684 	// free the node
685 	delete node;
686 
687 	// set m_containet to FALSE if parent has no child
688 	if (node_parent) {
689 #ifndef __WXGTK__
690         if (node_parent->GetChildCount() == 0)
691             node_parent->m_container = false;
692 #endif //__WXGTK__
693 		ret_item = parent;
694 	}
695 
696 	// notify control
697 	ItemDeleted(parent, item);
698 	return ret_item;
699 }
700 
DeleteLastInstance(const wxDataViewItem & parent_item,size_t num)701 wxDataViewItem ObjectDataViewModel::DeleteLastInstance(const wxDataViewItem &parent_item, size_t num)
702 {
703     auto ret_item = wxDataViewItem(0);
704     ObjectDataViewModelNode *parent_node = static_cast<ObjectDataViewModelNode*>(parent_item.GetID());
705     if (!parent_node) return ret_item;
706 
707     const int inst_root_id = get_root_idx(parent_node, itInstanceRoot);
708     if (inst_root_id < 0) return ret_item;
709 
710     wxDataViewItemArray items;
711     ObjectDataViewModelNode *inst_root_node = parent_node->GetNthChild(inst_root_id);
712     const wxDataViewItem inst_root_item((void*)inst_root_node);
713 
714     const int inst_cnt = inst_root_node->GetChildCount();
715     const bool delete_inst_root_item = inst_cnt - num < 2 ? true : false;
716 
717     PrintIndicator last_inst_printable = piUndef;
718 
719     int stop = delete_inst_root_item ? 0 : inst_cnt - num;
720     for (int i = inst_cnt - 1; i >= stop;--i) {
721         ObjectDataViewModelNode *last_instance_node = inst_root_node->GetNthChild(i);
722         if (i==0) last_inst_printable = last_instance_node->IsPrintable();
723         inst_root_node->GetChildren().Remove(last_instance_node);
724         delete last_instance_node;
725         ItemDeleted(inst_root_item, wxDataViewItem(last_instance_node));
726     }
727 
728     if (delete_inst_root_item) {
729         ret_item = parent_item;
730         parent_node->GetChildren().Remove(inst_root_node);
731         parent_node->set_printable_icon(last_inst_printable);
732         ItemDeleted(parent_item, inst_root_item);
733         ItemChanged(parent_item);
734 #ifndef __WXGTK__
735         if (parent_node->GetChildCount() == 0)
736             parent_node->m_container = false;
737 #endif //__WXGTK__
738     }
739 
740     // update object_node printable property
741     UpdateObjectPrintable(parent_item);
742 
743     return ret_item;
744 }
745 
DeleteAll()746 void ObjectDataViewModel::DeleteAll()
747 {
748 	while (!m_objects.empty())
749 	{
750 		auto object = m_objects.back();
751 // 		object->RemoveAllChildren();
752 		Delete(wxDataViewItem(object));
753 	}
754 }
755 
DeleteChildren(wxDataViewItem & parent)756 void ObjectDataViewModel::DeleteChildren(wxDataViewItem& parent)
757 {
758     ObjectDataViewModelNode *root = static_cast<ObjectDataViewModelNode*>(parent.GetID());
759     if (!root)      // happens if item.IsOk()==false
760         return;
761 
762     // first remove the node from the parent's array of children;
763     // NOTE: MyObjectTreeModelNodePtrArray is only an array of _pointers_
764     //       thus removing the node from it doesn't result in freeing it
765     auto& children = root->GetChildren();
766     for (int id = root->GetChildCount() - 1; id >= 0; --id)
767     {
768         auto node = children[id];
769         auto item = wxDataViewItem(node);
770         children.RemoveAt(id);
771 
772         if (node->m_type == itVolume)
773             root->m_volumes_cnt--;
774 
775         // free the node
776         delete node;
777 
778         // notify control
779         ItemDeleted(parent, item);
780     }
781 
782     // set m_containet to FALSE if parent has no child
783 #ifndef __WXGTK__
784         root->m_container = false;
785 #endif //__WXGTK__
786 }
787 
DeleteVolumeChildren(wxDataViewItem & parent)788 void ObjectDataViewModel::DeleteVolumeChildren(wxDataViewItem& parent)
789 {
790     ObjectDataViewModelNode *root = static_cast<ObjectDataViewModelNode*>(parent.GetID());
791     if (!root)      // happens if item.IsOk()==false
792         return;
793 
794     // first remove the node from the parent's array of children;
795     // NOTE: MyObjectTreeModelNodePtrArray is only an array of _pointers_
796     //       thus removing the node from it doesn't result in freeing it
797     auto& children = root->GetChildren();
798     for (int id = root->GetChildCount() - 1; id >= 0; --id)
799     {
800         auto node = children[id];
801         if (node->m_type != itVolume)
802             continue;
803 
804         auto item = wxDataViewItem(node);
805         DeleteSettings(item);
806         children.RemoveAt(id);
807 
808         // free the node
809         delete node;
810 
811         // notify control
812         ItemDeleted(parent, item);
813     }
814     root->m_volumes_cnt = 0;
815 
816     // set m_containet to FALSE if parent has no child
817 #ifndef __WXGTK__
818     root->m_container = false;
819 #endif //__WXGTK__
820 }
821 
DeleteSettings(const wxDataViewItem & parent)822 void ObjectDataViewModel::DeleteSettings(const wxDataViewItem& parent)
823 {
824     ObjectDataViewModelNode *node = static_cast<ObjectDataViewModelNode*>(parent.GetID());
825     if (!node) return;
826 
827     // if volume has a "settings"item, than delete it before volume deleting
828     if (node->GetChildCount() > 0 && node->GetNthChild(0)->GetType() == itSettings) {
829         auto settings_node = node->GetNthChild(0);
830         auto settings_item = wxDataViewItem(settings_node);
831         node->GetChildren().RemoveAt(0);
832         delete settings_node;
833         ItemDeleted(parent, settings_item);
834     }
835 }
836 
GetItemById(int obj_idx)837 wxDataViewItem ObjectDataViewModel::GetItemById(int obj_idx)
838 {
839     if (size_t(obj_idx) >= m_objects.size())
840 	{
841 		printf("Error! Out of objects range.\n");
842 		return wxDataViewItem(0);
843 	}
844 	return wxDataViewItem(m_objects[obj_idx]);
845 }
846 
847 
GetItemByVolumeId(int obj_idx,int volume_idx)848 wxDataViewItem ObjectDataViewModel::GetItemByVolumeId(int obj_idx, int volume_idx)
849 {
850     if (size_t(obj_idx) >= m_objects.size()) {
851 		printf("Error! Out of objects range.\n");
852 		return wxDataViewItem(0);
853 	}
854 
855     auto parent = m_objects[obj_idx];
856     if (parent->GetChildCount() == 0 ||
857         (parent->GetChildCount() == 1 && parent->GetNthChild(0)->GetType() & itSettings )) {
858         if (volume_idx == 0)
859             return GetItemById(obj_idx);
860 
861         printf("Error! Object has no one volume.\n");
862         return wxDataViewItem(0);
863     }
864 
865     for (size_t i = 0; i < parent->GetChildCount(); i++)
866         if (parent->GetNthChild(i)->m_idx == volume_idx && parent->GetNthChild(i)->GetType() & itVolume)
867             return wxDataViewItem(parent->GetNthChild(i));
868 
869     return wxDataViewItem(0);
870 }
871 
GetItemById(const int obj_idx,const int sub_obj_idx,const ItemType parent_type)872 wxDataViewItem ObjectDataViewModel::GetItemById(const int obj_idx, const int sub_obj_idx, const ItemType parent_type)
873 {
874     if (size_t(obj_idx) >= m_objects.size()) {
875         printf("Error! Out of objects range.\n");
876         return wxDataViewItem(0);
877     }
878 
879     auto item = GetItemByType(wxDataViewItem(m_objects[obj_idx]), parent_type);
880     if (!item)
881         return wxDataViewItem(0);
882 
883     auto parent = static_cast<ObjectDataViewModelNode*>(item.GetID());
884     for (size_t i = 0; i < parent->GetChildCount(); i++)
885         if (parent->GetNthChild(i)->m_idx == sub_obj_idx)
886             return wxDataViewItem(parent->GetNthChild(i));
887 
888     return wxDataViewItem(0);
889 }
890 
GetItemByInstanceId(int obj_idx,int inst_idx)891 wxDataViewItem ObjectDataViewModel::GetItemByInstanceId(int obj_idx, int inst_idx)
892 {
893     return GetItemById(obj_idx, inst_idx, itInstanceRoot);
894 }
895 
GetItemByLayerId(int obj_idx,int layer_idx)896 wxDataViewItem ObjectDataViewModel::GetItemByLayerId(int obj_idx, int layer_idx)
897 {
898     return GetItemById(obj_idx, layer_idx, itLayerRoot);
899 }
900 
GetItemByLayerRange(const int obj_idx,const t_layer_height_range & layer_range)901 wxDataViewItem ObjectDataViewModel::GetItemByLayerRange(const int obj_idx, const t_layer_height_range& layer_range)
902 {
903     if (size_t(obj_idx) >= m_objects.size()) {
904         printf("Error! Out of objects range.\n");
905         return wxDataViewItem(0);
906     }
907 
908     auto item = GetItemByType(wxDataViewItem(m_objects[obj_idx]), itLayerRoot);
909     if (!item)
910         return wxDataViewItem(0);
911 
912     auto parent = static_cast<ObjectDataViewModelNode*>(item.GetID());
913     for (size_t i = 0; i < parent->GetChildCount(); i++)
914         if (parent->GetNthChild(i)->m_layer_range == layer_range)
915             return wxDataViewItem(parent->GetNthChild(i));
916 
917     return wxDataViewItem(0);
918 }
919 
GetItemIdByLayerRange(const int obj_idx,const t_layer_height_range & layer_range)920 int  ObjectDataViewModel::GetItemIdByLayerRange(const int obj_idx, const t_layer_height_range& layer_range)
921 {
922     wxDataViewItem item = GetItemByLayerRange(obj_idx, layer_range);
923     if (!item)
924         return -1;
925 
926     return GetLayerIdByItem(item);
927 }
928 
GetIdByItem(const wxDataViewItem & item) const929 int ObjectDataViewModel::GetIdByItem(const wxDataViewItem& item) const
930 {
931 	if(!item.IsOk())
932         return -1;
933 
934 	ObjectDataViewModelNode *node = static_cast<ObjectDataViewModelNode*>(item.GetID());
935 	auto it = find(m_objects.begin(), m_objects.end(), node);
936 	if (it == m_objects.end())
937 		return -1;
938 
939 	return it - m_objects.begin();
940 }
941 
GetIdByItemAndType(const wxDataViewItem & item,const ItemType type) const942 int ObjectDataViewModel::GetIdByItemAndType(const wxDataViewItem& item, const ItemType type) const
943 {
944 	wxASSERT(item.IsOk());
945 
946 	ObjectDataViewModelNode *node = static_cast<ObjectDataViewModelNode*>(item.GetID());
947 	if (!node || node->m_type != type)
948 		return -1;
949 	return node->GetIdx();
950 }
951 
GetObjectIdByItem(const wxDataViewItem & item) const952 int ObjectDataViewModel::GetObjectIdByItem(const wxDataViewItem& item) const
953 {
954     return GetIdByItem(GetTopParent(item));
955 }
956 
GetVolumeIdByItem(const wxDataViewItem & item) const957 int ObjectDataViewModel::GetVolumeIdByItem(const wxDataViewItem& item) const
958 {
959     return GetIdByItemAndType(item, itVolume);
960 }
961 
GetInstanceIdByItem(const wxDataViewItem & item) const962 int ObjectDataViewModel::GetInstanceIdByItem(const wxDataViewItem& item) const
963 {
964     return GetIdByItemAndType(item, itInstance);
965 }
966 
GetLayerIdByItem(const wxDataViewItem & item) const967 int ObjectDataViewModel::GetLayerIdByItem(const wxDataViewItem& item) const
968 {
969     return GetIdByItemAndType(item, itLayer);
970 }
971 
GetLayerRangeByItem(const wxDataViewItem & item) const972 t_layer_height_range ObjectDataViewModel::GetLayerRangeByItem(const wxDataViewItem& item) const
973 {
974     wxASSERT(item.IsOk());
975 
976     ObjectDataViewModelNode *node = static_cast<ObjectDataViewModelNode*>(item.GetID());
977     if (!node || node->m_type != itLayer)
978         return { 0.0f, 0.0f };
979     return node->GetLayerRange();
980 }
981 
UpdateColumValues(unsigned col)982 bool ObjectDataViewModel::UpdateColumValues(unsigned col)
983 {
984     switch (col)
985     {
986     case colPrint:
987     case colName:
988     case colEditing:
989         return true;
990     case colExtruder:
991     {
992         wxDataViewItemArray items;
993         GetAllChildren(wxDataViewItem(nullptr), items);
994 
995         if (items.IsEmpty()) return false;
996 
997         for (auto item : items)
998             UpdateExtruderBitmap(item);
999 
1000         return true;
1001     }
1002     default:
1003         printf("MyObjectTreeModel::SetValue: wrong column");
1004     }
1005     return false;
1006 }
1007 
1008 
UpdateExtruderBitmap(wxDataViewItem item)1009 void ObjectDataViewModel::UpdateExtruderBitmap(wxDataViewItem item)
1010 {
1011     wxString extruder = GetExtruder(item);
1012     if (extruder.IsEmpty())
1013         return;
1014 
1015     // set extruder bitmap
1016     int extruder_idx = atoi(extruder.c_str());
1017     if (extruder_idx > 0) --extruder_idx;
1018 
1019     const DataViewBitmapText extruder_val(extruder, get_extruder_color_icon(extruder_idx));
1020 
1021     wxVariant value;
1022     value << extruder_val;
1023 
1024     SetValue(value, item, colExtruder);
1025 }
1026 
GetItemInfo(const wxDataViewItem & item,ItemType & type,int & obj_idx,int & idx)1027 void ObjectDataViewModel::GetItemInfo(const wxDataViewItem& item, ItemType& type, int& obj_idx, int& idx)
1028 {
1029     wxASSERT(item.IsOk());
1030     type = itUndef;
1031 
1032     ObjectDataViewModelNode *node = static_cast<ObjectDataViewModelNode*>(item.GetID());
1033     if (!node ||
1034         node->GetIdx() <-1 ||
1035         ( node->GetIdx() == -1 &&
1036          !(node->GetType() & (itObject | itSettings | itInstanceRoot | itLayerRoot/* | itLayer*/))
1037         )
1038        )
1039         return;
1040 
1041     idx = node->GetIdx();
1042     type = node->GetType();
1043 
1044     ObjectDataViewModelNode *parent_node = node->GetParent();
1045     if (!parent_node) return;
1046 
1047     // get top parent (Object) node
1048     while (parent_node->m_type != itObject)
1049         parent_node = parent_node->GetParent();
1050 
1051     auto it = find(m_objects.begin(), m_objects.end(), parent_node);
1052     if (it != m_objects.end())
1053         obj_idx = it - m_objects.begin();
1054     else
1055         type = itUndef;
1056 }
1057 
GetRowByItem(const wxDataViewItem & item) const1058 int ObjectDataViewModel::GetRowByItem(const wxDataViewItem& item) const
1059 {
1060     if (m_objects.empty())
1061         return -1;
1062 
1063     int row_num = 0;
1064 
1065     for (size_t i = 0; i < m_objects.size(); i++)
1066     {
1067         row_num++;
1068         if (item == wxDataViewItem(m_objects[i]))
1069             return row_num;
1070 
1071         for (size_t j = 0; j < m_objects[i]->GetChildCount(); j++)
1072         {
1073             row_num++;
1074             ObjectDataViewModelNode* cur_node = m_objects[i]->GetNthChild(j);
1075             if (item == wxDataViewItem(cur_node))
1076                 return row_num;
1077 
1078             if (cur_node->m_type == itVolume && cur_node->GetChildCount() == 1)
1079                 row_num++;
1080             if (cur_node->m_type == itInstanceRoot)
1081             {
1082                 row_num++;
1083                 for (size_t t = 0; t < cur_node->GetChildCount(); t++)
1084                 {
1085                     row_num++;
1086                     if (item == wxDataViewItem(cur_node->GetNthChild(t)))
1087                         return row_num;
1088                 }
1089             }
1090         }
1091     }
1092 
1093     return -1;
1094 }
1095 
InvalidItem(const wxDataViewItem & item)1096 bool ObjectDataViewModel::InvalidItem(const wxDataViewItem& item)
1097 {
1098     if (!item)
1099         return true;
1100 
1101     ObjectDataViewModelNode* node = static_cast<ObjectDataViewModelNode*>(item.GetID());
1102     if (!node || node->invalid())
1103         return true;
1104 
1105     return false;
1106 }
1107 
GetName(const wxDataViewItem & item) const1108 wxString ObjectDataViewModel::GetName(const wxDataViewItem &item) const
1109 {
1110 	ObjectDataViewModelNode *node = static_cast<ObjectDataViewModelNode*>(item.GetID());
1111 	if (!node)      // happens if item.IsOk()==false
1112 		return wxEmptyString;
1113 
1114 	return node->m_name;
1115 }
1116 
GetBitmap(const wxDataViewItem & item) const1117 wxBitmap& ObjectDataViewModel::GetBitmap(const wxDataViewItem &item) const
1118 {
1119     ObjectDataViewModelNode *node = static_cast<ObjectDataViewModelNode*>(item.GetID());
1120     return node->m_bmp;
1121 }
1122 
GetExtruder(const wxDataViewItem & item) const1123 wxString ObjectDataViewModel::GetExtruder(const wxDataViewItem& item) const
1124 {
1125 	ObjectDataViewModelNode *node = static_cast<ObjectDataViewModelNode*>(item.GetID());
1126 	if (!node)      // happens if item.IsOk()==false
1127 		return wxEmptyString;
1128 
1129 	return node->m_extruder;
1130 }
1131 
GetExtruderNumber(const wxDataViewItem & item) const1132 int ObjectDataViewModel::GetExtruderNumber(const wxDataViewItem& item) const
1133 {
1134 	ObjectDataViewModelNode *node = static_cast<ObjectDataViewModelNode*>(item.GetID());
1135 	if (!node)      // happens if item.IsOk()==false
1136 		return 0;
1137 
1138 	return atoi(node->m_extruder.c_str());
1139 }
1140 
GetValue(wxVariant & variant,const wxDataViewItem & item,unsigned int col) const1141 void ObjectDataViewModel::GetValue(wxVariant &variant, const wxDataViewItem &item, unsigned int col) const
1142 {
1143 	wxASSERT(item.IsOk());
1144 
1145 	ObjectDataViewModelNode *node = static_cast<ObjectDataViewModelNode*>(item.GetID());
1146 	switch (col)
1147 	{
1148 	case colPrint:
1149 		variant << node->m_printable_icon;
1150 		break;
1151 	case colName:
1152         variant << DataViewBitmapText(node->m_name, node->m_bmp);
1153 		break;
1154 	case colExtruder:
1155 		variant << DataViewBitmapText(node->m_extruder, node->m_extruder_bmp);
1156 		break;
1157 	case colEditing:
1158 		variant << node->m_action_icon;
1159 		break;
1160 	default:
1161 		;
1162 	}
1163 }
1164 
SetValue(const wxVariant & variant,const wxDataViewItem & item,unsigned int col)1165 bool ObjectDataViewModel::SetValue(const wxVariant &variant, const wxDataViewItem &item, unsigned int col)
1166 {
1167 	wxASSERT(item.IsOk());
1168 
1169 	ObjectDataViewModelNode *node = static_cast<ObjectDataViewModelNode*>(item.GetID());
1170 	return node->SetValue(variant, col);
1171 }
1172 
SetValue(const wxVariant & variant,const int item_idx,unsigned int col)1173 bool ObjectDataViewModel::SetValue(const wxVariant &variant, const int item_idx, unsigned int col)
1174 {
1175     if (size_t(item_idx) >= m_objects.size())
1176 		return false;
1177 
1178 	return m_objects[item_idx]->SetValue(variant, col);
1179 }
1180 
SetExtruder(const wxString & extruder,wxDataViewItem item)1181 void ObjectDataViewModel::SetExtruder(const wxString& extruder, wxDataViewItem item)
1182 {
1183     DataViewBitmapText extruder_val;
1184     extruder_val.SetText(extruder);
1185 
1186     // set extruder bitmap
1187     int extruder_idx = atoi(extruder.c_str());
1188     if (extruder_idx > 0) --extruder_idx;
1189     extruder_val.SetBitmap(get_extruder_color_icon(extruder_idx));
1190 
1191     wxVariant value;
1192     value << extruder_val;
1193 
1194     SetValue(value, item, colExtruder);
1195 }
1196 
AddAllChildren(const wxDataViewItem & parent)1197 void ObjectDataViewModel::AddAllChildren(const wxDataViewItem& parent)
1198 {
1199     ObjectDataViewModelNode* node = static_cast<ObjectDataViewModelNode*>(parent.GetID());
1200     if (!node || node->GetChildCount() == 0)
1201         return;
1202 
1203     wxDataViewItemArray array;
1204     const size_t count = node->GetChildCount();
1205     for (size_t pos = 0; pos < count; pos++) {
1206         ObjectDataViewModelNode* child = node->GetChildren().Item(pos);
1207         array.Add(wxDataViewItem((void*)child));
1208         ItemAdded(parent, wxDataViewItem((void*)child));
1209     }
1210 
1211     for (const auto item : array)
1212         AddAllChildren(item);
1213 
1214     m_ctrl->Expand(parent);
1215 };
1216 
ReorganizeChildren(const int current_volume_id,const int new_volume_id,const wxDataViewItem & parent)1217 wxDataViewItem ObjectDataViewModel::ReorganizeChildren( const int current_volume_id,
1218                                                         const int new_volume_id,
1219                                                         const wxDataViewItem &parent)
1220 {
1221     auto ret_item = wxDataViewItem(0);
1222     if (current_volume_id == new_volume_id)
1223         return ret_item;
1224     wxASSERT(parent.IsOk());
1225     ObjectDataViewModelNode *node_parent = static_cast<ObjectDataViewModelNode*>(parent.GetID());
1226     if (!node_parent)      // happens if item.IsOk()==false
1227         return ret_item;
1228 
1229     const size_t shift = node_parent->GetChildren().Item(0)->m_type == itSettings ? 1 : 0;
1230 
1231     ObjectDataViewModelNode *deleted_node = node_parent->GetNthChild(current_volume_id+shift);
1232     node_parent->GetChildren().Remove(deleted_node);
1233     ItemDeleted(parent, wxDataViewItem(deleted_node));
1234     node_parent->Insert(deleted_node, new_volume_id+shift);
1235     ItemAdded(parent, wxDataViewItem(deleted_node));
1236 
1237     // If some item has a children, just to add a deleted item is not enough on Linux
1238     // We should to add all its children separately
1239     AddAllChildren(wxDataViewItem(deleted_node));
1240 
1241     //update volume_id value for child-nodes
1242     auto children = node_parent->GetChildren();
1243     int id_frst = current_volume_id < new_volume_id ? current_volume_id : new_volume_id;
1244     int id_last = current_volume_id > new_volume_id ? current_volume_id : new_volume_id;
1245     for (int id = id_frst; id <= id_last; ++id)
1246         children[id+shift]->SetIdx(id);
1247 
1248     return wxDataViewItem(node_parent->GetNthChild(new_volume_id+shift));
1249 }
1250 
ReorganizeObjects(const int current_id,const int new_id)1251 wxDataViewItem ObjectDataViewModel::ReorganizeObjects(  const int current_id, const int new_id)
1252 {
1253     if (current_id == new_id)
1254         return wxDataViewItem(nullptr);
1255 
1256     ObjectDataViewModelNode* deleted_node = m_objects[current_id];
1257     m_objects.erase(m_objects.begin() + current_id);
1258     ItemDeleted(wxDataViewItem(nullptr), wxDataViewItem(deleted_node));
1259 
1260     m_objects.emplace(m_objects.begin() + new_id, deleted_node);
1261     ItemAdded(wxDataViewItem(nullptr), wxDataViewItem(deleted_node));
1262 
1263     // If some item has a children, just to add a deleted item is not enough on Linux
1264     // We should to add all its children separately
1265     AddAllChildren(wxDataViewItem(deleted_node));
1266 
1267     return wxDataViewItem(deleted_node);
1268 }
1269 
IsEnabled(const wxDataViewItem & item,unsigned int col) const1270 bool ObjectDataViewModel::IsEnabled(const wxDataViewItem &item, unsigned int col) const
1271 {
1272     wxASSERT(item.IsOk());
1273     ObjectDataViewModelNode *node = static_cast<ObjectDataViewModelNode*>(item.GetID());
1274 
1275     // disable extruder selection for the non "itObject|itVolume" item
1276     return !(col == colExtruder && node->m_extruder.IsEmpty());
1277 }
1278 
GetParent(const wxDataViewItem & item) const1279 wxDataViewItem ObjectDataViewModel::GetParent(const wxDataViewItem &item) const
1280 {
1281 	// the invisible root node has no parent
1282 	if (!item.IsOk())
1283 		return wxDataViewItem(0);
1284 
1285 	ObjectDataViewModelNode *node = static_cast<ObjectDataViewModelNode*>(item.GetID());
1286 	assert(node != nullptr && node->valid());
1287 
1288 	// objects nodes has no parent too
1289     if (node->m_type == itObject)
1290 		return wxDataViewItem(0);
1291 
1292 	return wxDataViewItem((void*)node->GetParent());
1293 }
1294 
GetTopParent(const wxDataViewItem & item) const1295 wxDataViewItem ObjectDataViewModel::GetTopParent(const wxDataViewItem &item) const
1296 {
1297 	// the invisible root node has no parent
1298 	if (!item.IsOk())
1299 		return wxDataViewItem(0);
1300 
1301 	ObjectDataViewModelNode *node = static_cast<ObjectDataViewModelNode*>(item.GetID());
1302     if (node->m_type == itObject)
1303         return item;
1304 
1305     ObjectDataViewModelNode *parent_node = node->GetParent();
1306     while (parent_node->m_type != itObject)
1307         parent_node = parent_node->GetParent();
1308 
1309     return wxDataViewItem((void*)parent_node);
1310 }
1311 
IsContainer(const wxDataViewItem & item) const1312 bool ObjectDataViewModel::IsContainer(const wxDataViewItem &item) const
1313 {
1314 	// the invisible root node can have children
1315 	if (!item.IsOk())
1316 		return true;
1317 
1318 	ObjectDataViewModelNode *node = static_cast<ObjectDataViewModelNode*>(item.GetID());
1319 	return node->IsContainer();
1320 }
1321 
GetChildren(const wxDataViewItem & parent,wxDataViewItemArray & array) const1322 unsigned int ObjectDataViewModel::GetChildren(const wxDataViewItem &parent, wxDataViewItemArray &array) const
1323 {
1324 	ObjectDataViewModelNode *node = static_cast<ObjectDataViewModelNode*>(parent.GetID());
1325 	if (!node)
1326 	{
1327 		for (auto object : m_objects)
1328 			array.Add(wxDataViewItem((void*)object));
1329 		return m_objects.size();
1330 	}
1331 
1332 	if (node->GetChildCount() == 0)
1333 	{
1334 		return 0;
1335 	}
1336 
1337 	unsigned int count = node->GetChildren().GetCount();
1338 	for (unsigned int pos = 0; pos < count; pos++)
1339 	{
1340 		ObjectDataViewModelNode *child = node->GetChildren().Item(pos);
1341 		array.Add(wxDataViewItem((void*)child));
1342 	}
1343 
1344 	return count;
1345 }
1346 
GetAllChildren(const wxDataViewItem & parent,wxDataViewItemArray & array) const1347 void ObjectDataViewModel::GetAllChildren(const wxDataViewItem &parent, wxDataViewItemArray &array) const
1348 {
1349 	ObjectDataViewModelNode *node = static_cast<ObjectDataViewModelNode*>(parent.GetID());
1350 	if (!node) {
1351 		for (auto object : m_objects)
1352 			array.Add(wxDataViewItem((void*)object));
1353 	}
1354 	else if (node->GetChildCount() == 0)
1355 		return;
1356     else {
1357         const size_t count = node->GetChildren().GetCount();
1358         for (size_t pos = 0; pos < count; pos++) {
1359             ObjectDataViewModelNode *child = node->GetChildren().Item(pos);
1360             array.Add(wxDataViewItem((void*)child));
1361         }
1362     }
1363 
1364     wxDataViewItemArray new_array = array;
1365     for (const auto item : new_array)
1366     {
1367         wxDataViewItemArray children;
1368         GetAllChildren(item, children);
1369         WX_APPEND_ARRAY(array, children);
1370     }
1371 }
1372 
GetItemType(const wxDataViewItem & item) const1373 ItemType ObjectDataViewModel::GetItemType(const wxDataViewItem &item) const
1374 {
1375     if (!item.IsOk())
1376         return itUndef;
1377     ObjectDataViewModelNode *node = static_cast<ObjectDataViewModelNode*>(item.GetID());
1378     return node->m_type < 0 ? itUndef : node->m_type;
1379 }
1380 
GetItemByType(const wxDataViewItem & parent_item,ItemType type) const1381 wxDataViewItem ObjectDataViewModel::GetItemByType(const wxDataViewItem &parent_item, ItemType type) const
1382 {
1383     if (!parent_item.IsOk())
1384         return wxDataViewItem(0);
1385 
1386     ObjectDataViewModelNode *node = static_cast<ObjectDataViewModelNode*>(parent_item.GetID());
1387     if (node->GetChildCount() == 0)
1388         return wxDataViewItem(0);
1389 
1390     for (size_t i = 0; i < node->GetChildCount(); i++) {
1391         if (node->GetNthChild(i)->m_type == type)
1392             return wxDataViewItem((void*)node->GetNthChild(i));
1393     }
1394 
1395     return wxDataViewItem(0);
1396 }
1397 
GetSettingsItem(const wxDataViewItem & item) const1398 wxDataViewItem ObjectDataViewModel::GetSettingsItem(const wxDataViewItem &item) const
1399 {
1400     return GetItemByType(item, itSettings);
1401 }
1402 
GetInstanceRootItem(const wxDataViewItem & item) const1403 wxDataViewItem ObjectDataViewModel::GetInstanceRootItem(const wxDataViewItem &item) const
1404 {
1405     return GetItemByType(item, itInstanceRoot);
1406 }
1407 
GetLayerRootItem(const wxDataViewItem & item) const1408 wxDataViewItem ObjectDataViewModel::GetLayerRootItem(const wxDataViewItem &item) const
1409 {
1410     return GetItemByType(item, itLayerRoot);
1411 }
1412 
IsSettingsItem(const wxDataViewItem & item) const1413 bool ObjectDataViewModel::IsSettingsItem(const wxDataViewItem &item) const
1414 {
1415     if (!item.IsOk())
1416         return false;
1417     ObjectDataViewModelNode *node = static_cast<ObjectDataViewModelNode*>(item.GetID());
1418     return node->m_type == itSettings;
1419 }
1420 
UpdateSettingsDigest(const wxDataViewItem & item,const std::vector<std::string> & categories)1421 void ObjectDataViewModel::UpdateSettingsDigest(const wxDataViewItem &item,
1422                                                     const std::vector<std::string>& categories)
1423 {
1424     if (!item.IsOk()) return;
1425     ObjectDataViewModelNode *node = static_cast<ObjectDataViewModelNode*>(item.GetID());
1426     if (!node->update_settings_digest(categories))
1427         return;
1428     ItemChanged(item);
1429 }
1430 
SetVolumeType(const wxDataViewItem & item,const Slic3r::ModelVolumeType type)1431 void ObjectDataViewModel::SetVolumeType(const wxDataViewItem &item, const Slic3r::ModelVolumeType type)
1432 {
1433     if (!item.IsOk() || GetItemType(item) != itVolume)
1434         return;
1435 
1436     ObjectDataViewModelNode *node = static_cast<ObjectDataViewModelNode*>(item.GetID());
1437     node->SetBitmap(*m_volume_bmps[int(type)]);
1438     ItemChanged(item);
1439 }
1440 
SetPrintableState(PrintIndicator printable,int obj_idx,int subobj_idx,ItemType subobj_type)1441 wxDataViewItem ObjectDataViewModel::SetPrintableState(
1442     PrintIndicator  printable,
1443     int             obj_idx,
1444     int             subobj_idx /* = -1*/,
1445     ItemType        subobj_type/* = itInstance*/)
1446 {
1447     wxDataViewItem item = wxDataViewItem(0);
1448     if (subobj_idx < 0)
1449         item = GetItemById(obj_idx);
1450     else
1451         item =  subobj_type&itInstance ? GetItemByInstanceId(obj_idx, subobj_idx) :
1452                 GetItemByVolumeId(obj_idx, subobj_idx);
1453 
1454     ObjectDataViewModelNode* node = static_cast<ObjectDataViewModelNode*>(item.GetID());
1455     if (!node)
1456         return wxDataViewItem(0);
1457     node->set_printable_icon(printable);
1458     ItemChanged(item);
1459 
1460     if (subobj_idx >= 0)
1461         UpdateObjectPrintable(GetItemById(obj_idx));
1462 
1463     return item;
1464 }
1465 
SetObjectPrintableState(PrintIndicator printable,wxDataViewItem obj_item)1466 wxDataViewItem ObjectDataViewModel::SetObjectPrintableState(
1467     PrintIndicator  printable,
1468     wxDataViewItem  obj_item)
1469 {
1470     ObjectDataViewModelNode* node = static_cast<ObjectDataViewModelNode*>(obj_item.GetID());
1471     if (!node)
1472         return wxDataViewItem(0);
1473     node->set_printable_icon(printable);
1474     ItemChanged(obj_item);
1475 
1476     UpdateInstancesPrintable(obj_item);
1477 
1478     return obj_item;
1479 }
1480 
Rescale()1481 void ObjectDataViewModel::Rescale()
1482 {
1483     wxDataViewItemArray all_items;
1484     GetAllChildren(wxDataViewItem(0), all_items);
1485 
1486     for (wxDataViewItem item : all_items)
1487     {
1488         if (!item.IsOk())
1489             continue;
1490 
1491         ObjectDataViewModelNode *node = static_cast<ObjectDataViewModelNode*>(item.GetID());
1492         node->msw_rescale();
1493 
1494         switch (node->m_type)
1495         {
1496         case itObject:
1497             if (node->m_bmp.IsOk()) node->m_bmp = *m_warning_bmp;
1498             break;
1499         case itVolume:
1500             node->m_bmp = GetVolumeIcon(node->m_volume_type, node->m_bmp.GetWidth() != node->m_bmp.GetHeight());
1501             break;
1502         case itLayerRoot:
1503             node->m_bmp = create_scaled_bitmap(LAYER_ROOT_ICON);
1504         case itLayer:
1505             node->m_bmp = create_scaled_bitmap(LAYER_ICON);
1506             break;
1507         default: break;
1508         }
1509 
1510         ItemChanged(item);
1511     }
1512 }
1513 
GetVolumeIcon(const Slic3r::ModelVolumeType vol_type,const bool is_marked)1514 wxBitmap ObjectDataViewModel::GetVolumeIcon(const Slic3r::ModelVolumeType vol_type, const bool is_marked/* = false*/)
1515 {
1516     if (!is_marked)
1517         return *m_volume_bmps[static_cast<int>(vol_type)];
1518 
1519     std::string scaled_bitmap_name = "warning" + std::to_string(static_cast<int>(vol_type));
1520     scaled_bitmap_name += "-em" + std::to_string(Slic3r::GUI::wxGetApp().em_unit());
1521 
1522     wxBitmap *bmp = m_bitmap_cache->find(scaled_bitmap_name);
1523     if (bmp == nullptr) {
1524         std::vector<wxBitmap> bmps;
1525 
1526         bmps.emplace_back(*m_warning_bmp);
1527         bmps.emplace_back(*m_volume_bmps[static_cast<int>(vol_type)]);
1528 
1529         bmp = m_bitmap_cache->insert(scaled_bitmap_name, bmps);
1530     }
1531 
1532     return *bmp;
1533 }
1534 
DeleteWarningIcon(const wxDataViewItem & item,const bool unmark_object)1535 void ObjectDataViewModel::DeleteWarningIcon(const wxDataViewItem& item, const bool unmark_object/* = false*/)
1536 {
1537     if (!item.IsOk())
1538         return;
1539 
1540     ObjectDataViewModelNode *node = static_cast<ObjectDataViewModelNode*>(item.GetID());
1541 
1542     if (!node->GetBitmap().IsOk() || !(node->GetType() & (itVolume | itObject)))
1543         return;
1544 
1545     if (node->GetType() & itVolume) {
1546         node->SetBitmap(*m_volume_bmps[static_cast<int>(node->volume_type())]);
1547         return;
1548     }
1549 
1550     node->SetBitmap(wxNullBitmap);
1551     if (unmark_object)
1552     {
1553         wxDataViewItemArray children;
1554         GetChildren(item, children);
1555         for (const wxDataViewItem& child : children)
1556             DeleteWarningIcon(child);
1557     }
1558 }
1559 
1560 } // namespace GUI
1561 } // namespace Slic3r
1562 
1563 
1564