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