PrusaSlicer-NonPlainar/src/slic3r/GUI/ObjectDataViewModel.cpp

1796 lines
55 KiB
C++
Raw Normal View History

#include "ObjectDataViewModel.hpp"
#include "wxExtensions.hpp"
#include "BitmapCache.hpp"
#include "GUI_App.hpp"
#include "GUI_ObjectList.hpp"
#include "I18N.hpp"
#include "libslic3r/Model.hpp"
#include <wx/bmpcbox.h>
#include <wx/dc.h>
namespace Slic3r {
namespace GUI {
wxDEFINE_EVENT(wxCUSTOMEVT_LAST_VOLUME_IS_DELETED, wxCommandEvent);
static wxBitmap get_extruder_color_icon(size_t extruder_idx, bool thin_icon = false)
{
// Create the bitmap with color bars.
std::vector<wxBitmap*> bmps = get_extruder_color_icons(thin_icon);
if (bmps.empty())
return wxNullBitmap;
return *bmps[extruder_idx >= bmps.size() ? 0 : extruder_idx];
}
BitmapCache* m_bitmap_cache = nullptr;
// *****************************************************************************
// ----------------------------------------------------------------------------
// ObjectDataViewModelNode
// ----------------------------------------------------------------------------
void ObjectDataViewModelNode::init_container()
{
#ifdef __WXGTK__
// it's necessary on GTK because of control have to know if this item will be container
// in another case you couldn't to add subitem for this item
// it will be produce "segmentation fault"
m_container = true;
#endif //__WXGTK__
}
#define LAYER_ROOT_ICON "edit_layers_all"
#define LAYER_ICON "edit_layers_some"
ObjectDataViewModelNode::ObjectDataViewModelNode(ObjectDataViewModelNode* parent, const ItemType type) :
m_parent(parent),
m_type(type),
m_extruder(wxEmptyString)
{
if (type == itSettings)
m_name = "Settings to modified";
else if (type == itInstanceRoot)
m_name = _(L("Instances"));
else if (type == itInstance)
{
m_idx = parent->GetChildCount();
m_name = wxString::Format(_(L("Instance %d")), m_idx + 1);
set_action_and_extruder_icons();
}
else if (type == itLayerRoot)
{
m_bmp = create_scaled_bitmap(LAYER_ROOT_ICON); // FIXME: pass window ptr
m_name = _(L("Layers"));
}
if (type & (itInstanceRoot | itLayerRoot))
init_container();
}
ObjectDataViewModelNode::ObjectDataViewModelNode(ObjectDataViewModelNode* parent,
const t_layer_height_range& layer_range,
const int idx /*= -1 */,
const wxString& extruder) :
m_parent(parent),
m_type(itLayer),
m_idx(idx),
m_layer_range(layer_range),
m_extruder(extruder)
{
const int children_cnt = parent->GetChildCount();
if (idx < 0)
m_idx = children_cnt;
else
{
// update indexes for another Laeyr Nodes
for (int i = m_idx; i < children_cnt; i++)
parent->GetNthChild(i)->SetIdx(i + 1);
}
const std::string label_range = (boost::format(" %.2f-%.2f ") % layer_range.first % layer_range.second).str();
m_name = _(L("Range")) + label_range + "(" + _(L("mm")) + ")";
m_bmp = create_scaled_bitmap(LAYER_ICON); // FIXME: pass window ptr
set_action_and_extruder_icons();
init_container();
}
#ifndef NDEBUG
bool ObjectDataViewModelNode::valid()
{
// Verify that the object was not deleted yet.
assert(m_idx >= -1);
return m_idx >= -1;
}
#endif /* NDEBUG */
void ObjectDataViewModelNode::set_action_and_extruder_icons()
{
m_action_icon_name = m_type & itObject ? "advanced_plus" :
m_type & (itVolume | itLayer) ? "cog" : /*m_type & itInstance*/ "set_separate_obj";
m_action_icon = create_scaled_bitmap(m_action_icon_name); // FIXME: pass window ptr
if (m_type & itInstance)
return; // don't set colored bitmap for Instance
// set extruder bitmap
int extruder_idx = atoi(m_extruder.c_str());
if (extruder_idx > 0) --extruder_idx;
m_extruder_bmp = get_extruder_color_icon(extruder_idx);
}
void ObjectDataViewModelNode::set_printable_icon(PrintIndicator printable)
{
m_printable = printable;
m_printable_icon = m_printable == piUndef ? m_empty_bmp :
create_scaled_bitmap(m_printable == piPrintable ? "eye_open.png" : "eye_closed.png");
}
void ObjectDataViewModelNode::update_settings_digest_bitmaps()
{
m_bmp = m_empty_bmp;
std::map<std::string, wxBitmap>& categories_icon = Slic3r::GUI::wxGetApp().obj_list()->CATEGORY_ICON;
std::string scaled_bitmap_name = m_name.ToUTF8().data();
scaled_bitmap_name += "-em" + std::to_string(Slic3r::GUI::wxGetApp().em_unit());
wxBitmap *bmp = m_bitmap_cache->find(scaled_bitmap_name);
if (bmp == nullptr) {
std::vector<wxBitmap> bmps;
for (auto& cat : m_opt_categories)
bmps.emplace_back( categories_icon.find(cat) == categories_icon.end() ?
wxNullBitmap : categories_icon.at(cat));
bmp = m_bitmap_cache->insert(scaled_bitmap_name, bmps);
}
m_bmp = *bmp;
}
bool ObjectDataViewModelNode::update_settings_digest(const std::vector<std::string>& categories)
{
if (m_type != itSettings || m_opt_categories == categories)
return false;
m_opt_categories = categories;
m_name = wxEmptyString;
for (auto& cat : m_opt_categories)
m_name += _(cat) + "; ";
if (!m_name.IsEmpty())
m_name.erase(m_name.Length()-2, 2); // Delete last "; "
update_settings_digest_bitmaps();
return true;
}
void ObjectDataViewModelNode::msw_rescale()
{
if (!m_action_icon_name.empty())
m_action_icon = create_scaled_bitmap(m_action_icon_name);
if (m_printable != piUndef)
m_printable_icon = create_scaled_bitmap(m_printable == piPrintable ? "eye_open.png" : "eye_closed.png");
if (!m_opt_categories.empty())
update_settings_digest_bitmaps();
}
bool ObjectDataViewModelNode::SetValue(const wxVariant& variant, unsigned col)
{
switch (col)
{
case colPrint:
m_printable_icon << variant;
return true;
case colName: {
DataViewBitmapText data;
data << variant;
m_bmp = data.GetBitmap();
m_name = data.GetText();
return true; }
case colExtruder: {
DataViewBitmapText data;
data << variant;
m_extruder_bmp = data.GetBitmap();
m_extruder = data.GetText() == "0" ? _(L("default")) : data.GetText();
return true; }
case colEditing:
m_action_icon << variant;
return true;
default:
printf("MyObjectTreeModel::SetValue: wrong column");
}
return false;
}
void ObjectDataViewModelNode::SetIdx(const int& idx)
{
m_idx = idx;
// update name if this node is instance
if (m_type == itInstance)
m_name = wxString::Format(_(L("Instance %d")), m_idx + 1);
}
// *****************************************************************************
// ----------------------------------------------------------------------------
// ObjectDataViewModel
// ----------------------------------------------------------------------------
static int get_root_idx(ObjectDataViewModelNode *parent_node, const ItemType root_type)
{
// because of istance_root and layers_root are at the end of the list, so
// start locking from the end
for (int root_idx = parent_node->GetChildCount() - 1; root_idx >= 0; root_idx--)
{
// if there is SettingsItem or VolumeItem, then RootItems don't exist in current ObjectItem
if (parent_node->GetNthChild(root_idx)->GetType() & (itSettings | itVolume))
break;
if (parent_node->GetNthChild(root_idx)->GetType() & root_type)
return root_idx;
}
return -1;
}
ObjectDataViewModel::ObjectDataViewModel()
{
m_bitmap_cache = new Slic3r::GUI::BitmapCache;
}
ObjectDataViewModel::~ObjectDataViewModel()
{
for (auto object : m_objects)
delete object;
delete m_bitmap_cache;
m_bitmap_cache = nullptr;
}
wxDataViewItem ObjectDataViewModel::Add(const wxString &name,
const int extruder,
const bool has_errors/* = false*/)
{
const wxString extruder_str = extruder == 0 ? _(L("default")) : wxString::Format("%d", extruder);
auto root = new ObjectDataViewModelNode(name, extruder_str);
// Add error icon if detected auto-repaire
if (has_errors)
root->m_bmp = *m_warning_bmp;
m_objects.push_back(root);
// notify control
wxDataViewItem child((void*)root);
wxDataViewItem parent((void*)NULL);
ItemAdded(parent, child);
return child;
}
wxDataViewItem ObjectDataViewModel::AddVolumeChild( const wxDataViewItem &parent_item,
const wxString &name,
const Slic3r::ModelVolumeType volume_type,
const bool has_errors/* = false*/,
const int extruder/* = 0*/,
const bool create_frst_child/* = true*/)
{
ObjectDataViewModelNode *root = (ObjectDataViewModelNode*)parent_item.GetID();
if (!root) return wxDataViewItem(0);
wxString extruder_str = extruder == 0 ? _(L("default")) : wxString::Format("%d", extruder);
// get insertion position according to the existed Layers and/or Instances Items
int insert_position = get_root_idx(root, itLayerRoot);
if (insert_position < 0)
insert_position = get_root_idx(root, itInstanceRoot);
const bool obj_errors = root->m_bmp.IsOk();
if (create_frst_child && root->m_volumes_cnt == 0)
{
const Slic3r::ModelVolumeType type = Slic3r::ModelVolumeType::MODEL_PART;
const auto node = new ObjectDataViewModelNode(root, root->m_name, GetVolumeIcon(type, obj_errors), extruder_str, 0);
node->m_volume_type = type;
insert_position < 0 ? root->Append(node) : root->Insert(node, insert_position);
// notify control
const wxDataViewItem child((void*)node);
ItemAdded(parent_item, child);
root->m_volumes_cnt++;
if (insert_position >= 0) insert_position++;
}
const auto node = new ObjectDataViewModelNode(root, name, GetVolumeIcon(volume_type, has_errors), extruder_str, root->m_volumes_cnt);
insert_position < 0 ? root->Append(node) : root->Insert(node, insert_position);
// if part with errors is added, but object wasn't marked, then mark it
if (!obj_errors && has_errors)
root->SetBitmap(*m_warning_bmp);
// notify control
const wxDataViewItem child((void*)node);
ItemAdded(parent_item, child);
root->m_volumes_cnt++;
node->m_volume_type = volume_type;
return child;
}
wxDataViewItem ObjectDataViewModel::AddSettingsChild(const wxDataViewItem &parent_item)
{
ObjectDataViewModelNode *root = (ObjectDataViewModelNode*)parent_item.GetID();
if (!root) return wxDataViewItem(0);
const auto node = new ObjectDataViewModelNode(root, itSettings);
root->Insert(node, 0);
// notify control
const wxDataViewItem child((void*)node);
ItemAdded(parent_item, child);
return child;
}
/* return values:
* true => root_node is created and added to the parent_root
* false => root node alredy exists
*/
static bool append_root_node(ObjectDataViewModelNode *parent_node,
ObjectDataViewModelNode **root_node,
const ItemType root_type)
{
const int inst_root_id = get_root_idx(parent_node, root_type);
*root_node = inst_root_id < 0 ?
new ObjectDataViewModelNode(parent_node, root_type) :
parent_node->GetNthChild(inst_root_id);
if (inst_root_id < 0) {
if ((root_type&itInstanceRoot) ||
( (root_type&itLayerRoot) && get_root_idx(parent_node, itInstanceRoot)<0) )
parent_node->Append(*root_node);
else if (root_type&itLayerRoot)
parent_node->Insert(*root_node, static_cast<unsigned int>(get_root_idx(parent_node, itInstanceRoot)));
return true;
}
return false;
}
wxDataViewItem ObjectDataViewModel::AddRoot(const wxDataViewItem &parent_item, ItemType root_type)
{
ObjectDataViewModelNode *parent_node = (ObjectDataViewModelNode*)parent_item.GetID();
if (!parent_node) return wxDataViewItem(0);
// get InstanceRoot node
ObjectDataViewModelNode *root_node { nullptr };
const bool appended = append_root_node(parent_node, &root_node, root_type);
if (!root_node) return wxDataViewItem(0);
const wxDataViewItem root_item((void*)root_node);
if (appended)
ItemAdded(parent_item, root_item);// notify control
return root_item;
}
wxDataViewItem ObjectDataViewModel::AddInstanceRoot(const wxDataViewItem &parent_item)
{
return AddRoot(parent_item, itInstanceRoot);
}
wxDataViewItem ObjectDataViewModel::AddInstanceChild(const wxDataViewItem &parent_item, size_t num)
{
std::vector<bool> print_indicator(num, true);
// if InstanceRoot item isn't created for this moment
if (!GetInstanceRootItem(parent_item).IsOk())
// use object's printable state to first instance
print_indicator[0] = IsPrintable(parent_item);
return wxDataViewItem((void*)AddInstanceChild(parent_item, print_indicator));
}
wxDataViewItem ObjectDataViewModel::AddInstanceChild(const wxDataViewItem& parent_item,
const std::vector<bool>& print_indicator)
{
const wxDataViewItem inst_root_item = AddInstanceRoot(parent_item);
if (!inst_root_item) return wxDataViewItem(0);
ObjectDataViewModelNode* inst_root_node = (ObjectDataViewModelNode*)inst_root_item.GetID();
// Add instance nodes
ObjectDataViewModelNode *instance_node = nullptr;
size_t counter = 0;
while (counter < print_indicator.size()) {
instance_node = new ObjectDataViewModelNode(inst_root_node, itInstance);
instance_node->set_printable_icon(print_indicator[counter] ? piPrintable : piUnprintable);
inst_root_node->Append(instance_node);
// notify control
const wxDataViewItem instance_item((void*)instance_node);
ItemAdded(inst_root_item, instance_item);
++counter;
}
// update object_node printable property
UpdateObjectPrintable(parent_item);
return wxDataViewItem((void*)instance_node);
}
void ObjectDataViewModel::UpdateObjectPrintable(wxDataViewItem parent_item)
{
const wxDataViewItem inst_root_item = GetInstanceRootItem(parent_item);
if (!inst_root_item)
return;
ObjectDataViewModelNode* inst_root_node = (ObjectDataViewModelNode*)inst_root_item.GetID();
const size_t child_cnt = inst_root_node->GetChildren().Count();
PrintIndicator obj_pi = piUnprintable;
for (size_t i=0; i < child_cnt; i++)
if (inst_root_node->GetNthChild(i)->IsPrintable() & piPrintable) {
obj_pi = piPrintable;
break;
}
// and set printable state for object_node to piUndef
ObjectDataViewModelNode* obj_node = (ObjectDataViewModelNode*)parent_item.GetID();
obj_node->set_printable_icon(obj_pi);
ItemChanged(parent_item);
}
// update printable property for all instances from object
void ObjectDataViewModel::UpdateInstancesPrintable(wxDataViewItem parent_item)
{
const wxDataViewItem inst_root_item = GetInstanceRootItem(parent_item);
if (!inst_root_item)
return;
ObjectDataViewModelNode* obj_node = (ObjectDataViewModelNode*)parent_item.GetID();
const PrintIndicator obj_pi = obj_node->IsPrintable();
ObjectDataViewModelNode* inst_root_node = (ObjectDataViewModelNode*)inst_root_item.GetID();
const size_t child_cnt = inst_root_node->GetChildren().Count();
for (size_t i=0; i < child_cnt; i++)
{
ObjectDataViewModelNode* inst_node = inst_root_node->GetNthChild(i);
// and set printable state for object_node to piUndef
inst_node->set_printable_icon(obj_pi);
ItemChanged(wxDataViewItem((void*)inst_node));
}
}
bool ObjectDataViewModel::IsPrintable(const wxDataViewItem& item) const
{
ObjectDataViewModelNode* node = (ObjectDataViewModelNode*)item.GetID();
if (!node)
return false;
return node->IsPrintable() == piPrintable;
}
wxDataViewItem ObjectDataViewModel::AddLayersRoot(const wxDataViewItem &parent_item)
{
return AddRoot(parent_item, itLayerRoot);
}
wxDataViewItem ObjectDataViewModel::AddLayersChild(const wxDataViewItem &parent_item,
const t_layer_height_range& layer_range,
const int extruder/* = 0*/,
const int index /* = -1*/)
{
ObjectDataViewModelNode *parent_node = (ObjectDataViewModelNode*)parent_item.GetID();
if (!parent_node) return wxDataViewItem(0);
wxString extruder_str = extruder == 0 ? _(L("default")) : wxString::Format("%d", extruder);
// get LayerRoot node
ObjectDataViewModelNode *layer_root_node;
wxDataViewItem layer_root_item;
if (parent_node->GetType() & itLayerRoot) {
layer_root_node = parent_node;
layer_root_item = parent_item;
}
else {
const int root_idx = get_root_idx(parent_node, itLayerRoot);
if (root_idx < 0) return wxDataViewItem(0);
layer_root_node = parent_node->GetNthChild(root_idx);
layer_root_item = wxDataViewItem((void*)layer_root_node);
}
// Add layer node
ObjectDataViewModelNode *layer_node = new ObjectDataViewModelNode(layer_root_node, layer_range, index, extruder_str);
if (index < 0)
layer_root_node->Append(layer_node);
else
layer_root_node->Insert(layer_node, index);
// notify control
const wxDataViewItem layer_item((void*)layer_node);
ItemAdded(layer_root_item, layer_item);
return layer_item;
}
wxDataViewItem ObjectDataViewModel::Delete(const wxDataViewItem &item)
{
auto ret_item = wxDataViewItem(0);
ObjectDataViewModelNode *node = (ObjectDataViewModelNode*)item.GetID();
if (!node) // happens if item.IsOk()==false
return ret_item;
auto node_parent = node->GetParent();
wxDataViewItem parent(node_parent);
// first remove the node from the parent's array of children;
// NOTE: MyObjectTreeModelNodePtrArray is only an array of _pointers_
// thus removing the node from it doesn't result in freeing it
if (node_parent) {
if (node->m_type & (itInstanceRoot|itLayerRoot))
{
// node can be deleted by the Delete, let's check its type while we safely can
bool is_instance_root = (node->m_type & itInstanceRoot);
for (int i = int(node->GetChildCount() - 1); i >= (is_instance_root ? 1 : 0); i--)
Delete(wxDataViewItem(node->GetNthChild(i)));
return parent;
}
auto id = node_parent->GetChildren().Index(node);
auto idx = node->GetIdx();
if (node->m_type & (itVolume|itLayer)) {
node_parent->m_volumes_cnt--;
DeleteSettings(item);
}
node_parent->GetChildren().Remove(node);
if (id > 0) {
if (size_t(id) == node_parent->GetChildCount()) id--;
ret_item = wxDataViewItem(node_parent->GetChildren().Item(id));
}
//update idx value for remaining child-nodes
auto children = node_parent->GetChildren();
for (size_t i = 0; i < node_parent->GetChildCount() && idx>=0; i++)
{
auto cur_idx = children[i]->GetIdx();
if (cur_idx > idx)
children[i]->SetIdx(cur_idx-1);
}
// if there is last instance item, delete both of it and instance root item
if (node_parent->GetChildCount() == 1 && node_parent->GetNthChild(0)->m_type == itInstance)
{
delete node;
ItemDeleted(parent, item);
ObjectDataViewModelNode *last_instance_node = node_parent->GetNthChild(0);
PrintIndicator last_instance_printable = last_instance_node->IsPrintable();
node_parent->GetChildren().Remove(last_instance_node);
delete last_instance_node;
ItemDeleted(parent, wxDataViewItem(last_instance_node));
ObjectDataViewModelNode *obj_node = node_parent->GetParent();
obj_node->set_printable_icon(last_instance_printable);
obj_node->GetChildren().Remove(node_parent);
delete node_parent;
ret_item = wxDataViewItem(obj_node);
#ifndef __WXGTK__
if (obj_node->GetChildCount() == 0)
obj_node->m_container = false;
#endif //__WXGTK__
ItemDeleted(ret_item, wxDataViewItem(node_parent));
return ret_item;
}
if (node->m_type & itInstance)
UpdateObjectPrintable(wxDataViewItem(node_parent->GetParent()));
// if there was last layer item, delete this one and layers root item
if (node_parent->GetChildCount() == 0 && node_parent->m_type == itLayerRoot)
{
ObjectDataViewModelNode *obj_node = node_parent->GetParent();
obj_node->GetChildren().Remove(node_parent);
delete node_parent;
ret_item = wxDataViewItem(obj_node);
#ifndef __WXGTK__
if (obj_node->GetChildCount() == 0)
obj_node->m_container = false;
#endif //__WXGTK__
ItemDeleted(ret_item, wxDataViewItem(node_parent));
return ret_item;
}
// if there is last volume item after deleting, delete this last volume too
if (node_parent->GetChildCount() <= 3) // 3??? #ys_FIXME
{
int vol_cnt = 0;
int vol_idx = 0;
for (size_t i = 0; i < node_parent->GetChildCount(); ++i) {
if (node_parent->GetNthChild(i)->GetType() == itVolume) {
vol_idx = i;
vol_cnt++;
}
if (vol_cnt > 1)
break;
}
if (vol_cnt == 1) {
delete node;
ItemDeleted(parent, item);
ObjectDataViewModelNode *last_child_node = node_parent->GetNthChild(vol_idx);
DeleteSettings(wxDataViewItem(last_child_node));
node_parent->GetChildren().Remove(last_child_node);
node_parent->m_volumes_cnt = 0;
delete last_child_node;
#ifndef __WXGTK__
if (node_parent->GetChildCount() == 0)
node_parent->m_container = false;
#endif //__WXGTK__
ItemDeleted(parent, wxDataViewItem(last_child_node));
wxCommandEvent event(wxCUSTOMEVT_LAST_VOLUME_IS_DELETED);
auto it = find(m_objects.begin(), m_objects.end(), node_parent);
event.SetInt(it == m_objects.end() ? -1 : it - m_objects.begin());
wxPostEvent(m_ctrl, event);
ret_item = parent;
return ret_item;
}
}
}
else
{
auto it = find(m_objects.begin(), m_objects.end(), node);
size_t id = it - m_objects.begin();
if (it != m_objects.end())
{
// Delete all sub-items
int i = m_objects[id]->GetChildCount() - 1;
while (i >= 0) {
Delete(wxDataViewItem(m_objects[id]->GetNthChild(i)));
i = m_objects[id]->GetChildCount() - 1;
}
m_objects.erase(it);
}
if (id > 0) {
if(id == m_objects.size()) id--;
ret_item = wxDataViewItem(m_objects[id]);
}
}
// free the node
delete node;
// set m_containet to FALSE if parent has no child
if (node_parent) {
#ifndef __WXGTK__
if (node_parent->GetChildCount() == 0)
node_parent->m_container = false;
#endif //__WXGTK__
ret_item = parent;
}
// notify control
ItemDeleted(parent, item);
return ret_item;
}
wxDataViewItem ObjectDataViewModel::DeleteLastInstance(const wxDataViewItem &parent_item, size_t num)
{
auto ret_item = wxDataViewItem(0);
ObjectDataViewModelNode *parent_node = (ObjectDataViewModelNode*)parent_item.GetID();
if (!parent_node) return ret_item;
const int inst_root_id = get_root_idx(parent_node, itInstanceRoot);
if (inst_root_id < 0) return ret_item;
wxDataViewItemArray items;
ObjectDataViewModelNode *inst_root_node = parent_node->GetNthChild(inst_root_id);
const wxDataViewItem inst_root_item((void*)inst_root_node);
const int inst_cnt = inst_root_node->GetChildCount();
const bool delete_inst_root_item = inst_cnt - num < 2 ? true : false;
PrintIndicator last_inst_printable = piUndef;
int stop = delete_inst_root_item ? 0 : inst_cnt - num;
for (int i = inst_cnt - 1; i >= stop;--i) {
ObjectDataViewModelNode *last_instance_node = inst_root_node->GetNthChild(i);
if (i==0) last_inst_printable = last_instance_node->IsPrintable();
inst_root_node->GetChildren().Remove(last_instance_node);
delete last_instance_node;
ItemDeleted(inst_root_item, wxDataViewItem(last_instance_node));
}
if (delete_inst_root_item) {
ret_item = parent_item;
parent_node->GetChildren().Remove(inst_root_node);
parent_node->set_printable_icon(last_inst_printable);
ItemDeleted(parent_item, inst_root_item);
ItemChanged(parent_item);
#ifndef __WXGTK__
if (parent_node->GetChildCount() == 0)
parent_node->m_container = false;
#endif //__WXGTK__
}
// update object_node printable property
UpdateObjectPrintable(parent_item);
return ret_item;
}
void ObjectDataViewModel::DeleteAll()
{
while (!m_objects.empty())
{
auto object = m_objects.back();
// object->RemoveAllChildren();
Delete(wxDataViewItem(object));
}
}
void ObjectDataViewModel::DeleteChildren(wxDataViewItem& parent)
{
ObjectDataViewModelNode *root = (ObjectDataViewModelNode*)parent.GetID();
if (!root) // happens if item.IsOk()==false
return;
// first remove the node from the parent's array of children;
// NOTE: MyObjectTreeModelNodePtrArray is only an array of _pointers_
// thus removing the node from it doesn't result in freeing it
auto& children = root->GetChildren();
for (int id = root->GetChildCount() - 1; id >= 0; --id)
{
auto node = children[id];
auto item = wxDataViewItem(node);
children.RemoveAt(id);
if (node->m_type == itVolume)
root->m_volumes_cnt--;
// free the node
delete node;
// notify control
ItemDeleted(parent, item);
}
// set m_containet to FALSE if parent has no child
#ifndef __WXGTK__
root->m_container = false;
#endif //__WXGTK__
}
void ObjectDataViewModel::DeleteVolumeChildren(wxDataViewItem& parent)
{
ObjectDataViewModelNode *root = (ObjectDataViewModelNode*)parent.GetID();
if (!root) // happens if item.IsOk()==false
return;
// first remove the node from the parent's array of children;
// NOTE: MyObjectTreeModelNodePtrArray is only an array of _pointers_
// thus removing the node from it doesn't result in freeing it
auto& children = root->GetChildren();
for (int id = root->GetChildCount() - 1; id >= 0; --id)
{
auto node = children[id];
if (node->m_type != itVolume)
continue;
auto item = wxDataViewItem(node);
DeleteSettings(item);
children.RemoveAt(id);
// free the node
delete node;
// notify control
ItemDeleted(parent, item);
}
root->m_volumes_cnt = 0;
// set m_containet to FALSE if parent has no child
#ifndef __WXGTK__
root->m_container = false;
#endif //__WXGTK__
}
void ObjectDataViewModel::DeleteSettings(const wxDataViewItem& parent)
{
ObjectDataViewModelNode *node = (ObjectDataViewModelNode*)parent.GetID();
if (!node) return;
// if volume has a "settings"item, than delete it before volume deleting
if (node->GetChildCount() > 0 && node->GetNthChild(0)->GetType() == itSettings) {
auto settings_node = node->GetNthChild(0);
auto settings_item = wxDataViewItem(settings_node);
node->GetChildren().RemoveAt(0);
delete settings_node;
ItemDeleted(parent, settings_item);
}
}
wxDataViewItem ObjectDataViewModel::GetItemById(int obj_idx)
{
if (size_t(obj_idx) >= m_objects.size())
{
printf("Error! Out of objects range.\n");
return wxDataViewItem(0);
}
return wxDataViewItem(m_objects[obj_idx]);
}
wxDataViewItem ObjectDataViewModel::GetItemByVolumeId(int obj_idx, int volume_idx)
{
if (size_t(obj_idx) >= m_objects.size()) {
printf("Error! Out of objects range.\n");
return wxDataViewItem(0);
}
auto parent = m_objects[obj_idx];
if (parent->GetChildCount() == 0 ||
(parent->GetChildCount() == 1 && parent->GetNthChild(0)->GetType() & itSettings )) {
if (volume_idx == 0)
return GetItemById(obj_idx);
printf("Error! Object has no one volume.\n");
return wxDataViewItem(0);
}
for (size_t i = 0; i < parent->GetChildCount(); i++)
if (parent->GetNthChild(i)->m_idx == volume_idx && parent->GetNthChild(i)->GetType() & itVolume)
return wxDataViewItem(parent->GetNthChild(i));
return wxDataViewItem(0);
}
wxDataViewItem ObjectDataViewModel::GetItemById(const int obj_idx, const int sub_obj_idx, const ItemType parent_type)
{
if (size_t(obj_idx) >= m_objects.size()) {
printf("Error! Out of objects range.\n");
return wxDataViewItem(0);
}
auto item = GetItemByType(wxDataViewItem(m_objects[obj_idx]), parent_type);
if (!item)
return wxDataViewItem(0);
auto parent = (ObjectDataViewModelNode*)item.GetID();
for (size_t i = 0; i < parent->GetChildCount(); i++)
if (parent->GetNthChild(i)->m_idx == sub_obj_idx)
return wxDataViewItem(parent->GetNthChild(i));
return wxDataViewItem(0);
}
wxDataViewItem ObjectDataViewModel::GetItemByInstanceId(int obj_idx, int inst_idx)
{
return GetItemById(obj_idx, inst_idx, itInstanceRoot);
}
wxDataViewItem ObjectDataViewModel::GetItemByLayerId(int obj_idx, int layer_idx)
{
return GetItemById(obj_idx, layer_idx, itLayerRoot);
}
wxDataViewItem ObjectDataViewModel::GetItemByLayerRange(const int obj_idx, const t_layer_height_range& layer_range)
{
if (size_t(obj_idx) >= m_objects.size()) {
printf("Error! Out of objects range.\n");
return wxDataViewItem(0);
}
auto item = GetItemByType(wxDataViewItem(m_objects[obj_idx]), itLayerRoot);
if (!item)
return wxDataViewItem(0);
auto parent = (ObjectDataViewModelNode*)item.GetID();
for (size_t i = 0; i < parent->GetChildCount(); i++)
if (parent->GetNthChild(i)->m_layer_range == layer_range)
return wxDataViewItem(parent->GetNthChild(i));
return wxDataViewItem(0);
}
int ObjectDataViewModel::GetItemIdByLayerRange(const int obj_idx, const t_layer_height_range& layer_range)
{
wxDataViewItem item = GetItemByLayerRange(obj_idx, layer_range);
if (!item)
return -1;
return GetLayerIdByItem(item);
}
int ObjectDataViewModel::GetIdByItem(const wxDataViewItem& item) const
{
if(!item.IsOk())
return -1;
ObjectDataViewModelNode *node = (ObjectDataViewModelNode*)item.GetID();
auto it = find(m_objects.begin(), m_objects.end(), node);
if (it == m_objects.end())
return -1;
return it - m_objects.begin();
}
int ObjectDataViewModel::GetIdByItemAndType(const wxDataViewItem& item, const ItemType type) const
{
wxASSERT(item.IsOk());
ObjectDataViewModelNode *node = (ObjectDataViewModelNode*)item.GetID();
if (!node || node->m_type != type)
return -1;
return node->GetIdx();
}
int ObjectDataViewModel::GetObjectIdByItem(const wxDataViewItem& item) const
{
return GetIdByItem(GetTopParent(item));
}
int ObjectDataViewModel::GetVolumeIdByItem(const wxDataViewItem& item) const
{
return GetIdByItemAndType(item, itVolume);
}
int ObjectDataViewModel::GetInstanceIdByItem(const wxDataViewItem& item) const
{
return GetIdByItemAndType(item, itInstance);
}
int ObjectDataViewModel::GetLayerIdByItem(const wxDataViewItem& item) const
{
return GetIdByItemAndType(item, itLayer);
}
t_layer_height_range ObjectDataViewModel::GetLayerRangeByItem(const wxDataViewItem& item) const
{
wxASSERT(item.IsOk());
ObjectDataViewModelNode *node = (ObjectDataViewModelNode*)item.GetID();
if (!node || node->m_type != itLayer)
return { 0.0f, 0.0f };
return node->GetLayerRange();
}
bool ObjectDataViewModel::UpdateColumValues(unsigned col)
{
switch (col)
{
case colPrint:
case colName:
case colEditing:
return true;
case colExtruder:
{
wxDataViewItemArray items;
GetAllChildren(wxDataViewItem(nullptr), items);
if (items.IsEmpty()) return false;
for (auto item : items)
UpdateExtruderBitmap(item);
return true;
}
default:
printf("MyObjectTreeModel::SetValue: wrong column");
}
return false;
}
void ObjectDataViewModel::UpdateExtruderBitmap(wxDataViewItem item)
{
wxString extruder = GetExtruder(item);
if (extruder.IsEmpty())
return;
// set extruder bitmap
int extruder_idx = atoi(extruder.c_str());
if (extruder_idx > 0) --extruder_idx;
const DataViewBitmapText extruder_val(extruder, get_extruder_color_icon(extruder_idx));
wxVariant value;
value << extruder_val;
SetValue(value, item, colExtruder);
}
void ObjectDataViewModel::GetItemInfo(const wxDataViewItem& item, ItemType& type, int& obj_idx, int& idx)
{
wxASSERT(item.IsOk());
type = itUndef;
ObjectDataViewModelNode *node = (ObjectDataViewModelNode*)item.GetID();
if (!node ||
node->GetIdx() <-1 ||
( node->GetIdx() == -1 &&
!(node->GetType() & (itObject | itSettings | itInstanceRoot | itLayerRoot/* | itLayer*/))
)
)
return;
idx = node->GetIdx();
type = node->GetType();
ObjectDataViewModelNode *parent_node = node->GetParent();
if (!parent_node) return;
// get top parent (Object) node
while (parent_node->m_type != itObject)
parent_node = parent_node->GetParent();
auto it = find(m_objects.begin(), m_objects.end(), parent_node);
if (it != m_objects.end())
obj_idx = it - m_objects.begin();
else
type = itUndef;
}
int ObjectDataViewModel::GetRowByItem(const wxDataViewItem& item) const
{
if (m_objects.empty())
return -1;
int row_num = 0;
for (size_t i = 0; i < m_objects.size(); i++)
{
row_num++;
if (item == wxDataViewItem(m_objects[i]))
return row_num;
for (size_t j = 0; j < m_objects[i]->GetChildCount(); j++)
{
row_num++;
ObjectDataViewModelNode* cur_node = m_objects[i]->GetNthChild(j);
if (item == wxDataViewItem(cur_node))
return row_num;
if (cur_node->m_type == itVolume && cur_node->GetChildCount() == 1)
row_num++;
if (cur_node->m_type == itInstanceRoot)
{
row_num++;
for (size_t t = 0; t < cur_node->GetChildCount(); t++)
{
row_num++;
if (item == wxDataViewItem(cur_node->GetNthChild(t)))
return row_num;
}
}
}
}
return -1;
}
bool ObjectDataViewModel::InvalidItem(const wxDataViewItem& item)
{
if (!item)
return true;
ObjectDataViewModelNode* node = (ObjectDataViewModelNode*)item.GetID();
if (!node || node->invalid())
return true;
return false;
}
wxString ObjectDataViewModel::GetName(const wxDataViewItem &item) const
{
ObjectDataViewModelNode *node = (ObjectDataViewModelNode*)item.GetID();
if (!node) // happens if item.IsOk()==false
return wxEmptyString;
return node->m_name;
}
wxBitmap& ObjectDataViewModel::GetBitmap(const wxDataViewItem &item) const
{
ObjectDataViewModelNode *node = (ObjectDataViewModelNode*)item.GetID();
return node->m_bmp;
}
wxString ObjectDataViewModel::GetExtruder(const wxDataViewItem& item) const
{
ObjectDataViewModelNode *node = (ObjectDataViewModelNode*)item.GetID();
if (!node) // happens if item.IsOk()==false
return wxEmptyString;
return node->m_extruder;
}
int ObjectDataViewModel::GetExtruderNumber(const wxDataViewItem& item) const
{
ObjectDataViewModelNode *node = (ObjectDataViewModelNode*)item.GetID();
if (!node) // happens if item.IsOk()==false
return 0;
return atoi(node->m_extruder.c_str());
}
void ObjectDataViewModel::GetValue(wxVariant &variant, const wxDataViewItem &item, unsigned int col) const
{
wxASSERT(item.IsOk());
ObjectDataViewModelNode *node = (ObjectDataViewModelNode*)item.GetID();
switch (col)
{
case colPrint:
variant << node->m_printable_icon;
break;
case colName:
variant << DataViewBitmapText(node->m_name, node->m_bmp);
break;
case colExtruder:
variant << DataViewBitmapText(node->m_extruder, node->m_extruder_bmp);
break;
case colEditing:
variant << node->m_action_icon;
break;
default:
;
}
}
bool ObjectDataViewModel::SetValue(const wxVariant &variant, const wxDataViewItem &item, unsigned int col)
{
wxASSERT(item.IsOk());
ObjectDataViewModelNode *node = (ObjectDataViewModelNode*)item.GetID();
return node->SetValue(variant, col);
}
bool ObjectDataViewModel::SetValue(const wxVariant &variant, const int item_idx, unsigned int col)
{
if (size_t(item_idx) >= m_objects.size())
return false;
return m_objects[item_idx]->SetValue(variant, col);
}
void ObjectDataViewModel::SetExtruder(const wxString& extruder, wxDataViewItem item)
{
DataViewBitmapText extruder_val;
extruder_val.SetText(extruder);
// set extruder bitmap
int extruder_idx = atoi(extruder.c_str());
if (extruder_idx > 0) --extruder_idx;
extruder_val.SetBitmap(get_extruder_color_icon(extruder_idx));
wxVariant value;
value << extruder_val;
SetValue(value, item, colExtruder);
}
void ObjectDataViewModel::AddAllChildren(const wxDataViewItem& parent)
{
ObjectDataViewModelNode* node = (ObjectDataViewModelNode*)parent.GetID();
if (!node || node->GetChildCount() == 0)
return;
wxDataViewItemArray array;
const size_t count = node->GetChildCount();
for (size_t pos = 0; pos < count; pos++) {
ObjectDataViewModelNode* child = node->GetChildren().Item(pos);
array.Add(wxDataViewItem((void*)child));
ItemAdded(parent, wxDataViewItem((void*)child));
}
for (const auto item : array)
AddAllChildren(item);
m_ctrl->Expand(parent);
};
wxDataViewItem ObjectDataViewModel::ReorganizeChildren( const int current_volume_id,
const int new_volume_id,
const wxDataViewItem &parent)
{
auto ret_item = wxDataViewItem(0);
if (current_volume_id == new_volume_id)
return ret_item;
wxASSERT(parent.IsOk());
ObjectDataViewModelNode *node_parent = (ObjectDataViewModelNode*)parent.GetID();
if (!node_parent) // happens if item.IsOk()==false
return ret_item;
const size_t shift = node_parent->GetChildren().Item(0)->m_type == itSettings ? 1 : 0;
ObjectDataViewModelNode *deleted_node = node_parent->GetNthChild(current_volume_id+shift);
node_parent->GetChildren().Remove(deleted_node);
ItemDeleted(parent, wxDataViewItem(deleted_node));
node_parent->Insert(deleted_node, new_volume_id+shift);
ItemAdded(parent, wxDataViewItem(deleted_node));
// If some item has a children, just to add a deleted item is not enough on Linux
// We should to add all its children separately
AddAllChildren(wxDataViewItem(deleted_node));
//update volume_id value for child-nodes
auto children = node_parent->GetChildren();
int id_frst = current_volume_id < new_volume_id ? current_volume_id : new_volume_id;
int id_last = current_volume_id > new_volume_id ? current_volume_id : new_volume_id;
for (int id = id_frst; id <= id_last; ++id)
children[id+shift]->SetIdx(id);
return wxDataViewItem(node_parent->GetNthChild(new_volume_id+shift));
}
wxDataViewItem ObjectDataViewModel::ReorganizeObjects( const int current_id, const int new_id)
{
if (current_id == new_id)
return wxDataViewItem(nullptr);
ObjectDataViewModelNode* deleted_node = m_objects[current_id];
m_objects.erase(m_objects.begin() + current_id);
ItemDeleted(wxDataViewItem(nullptr), wxDataViewItem(deleted_node));
m_objects.emplace(m_objects.begin() + new_id, deleted_node);
ItemAdded(wxDataViewItem(nullptr), wxDataViewItem(deleted_node));
// If some item has a children, just to add a deleted item is not enough on Linux
// We should to add all its children separately
AddAllChildren(wxDataViewItem(deleted_node));
return wxDataViewItem(deleted_node);
}
bool ObjectDataViewModel::IsEnabled(const wxDataViewItem &item, unsigned int col) const
{
wxASSERT(item.IsOk());
ObjectDataViewModelNode *node = (ObjectDataViewModelNode*)item.GetID();
// disable extruder selection for the non "itObject|itVolume" item
return !(col == colExtruder && node->m_extruder.IsEmpty());
}
wxDataViewItem ObjectDataViewModel::GetParent(const wxDataViewItem &item) const
{
// the invisible root node has no parent
if (!item.IsOk())
return wxDataViewItem(0);
ObjectDataViewModelNode *node = (ObjectDataViewModelNode*)item.GetID();
assert(node != nullptr && node->valid());
// objects nodes has no parent too
if (node->m_type == itObject)
return wxDataViewItem(0);
return wxDataViewItem((void*)node->GetParent());
}
wxDataViewItem ObjectDataViewModel::GetTopParent(const wxDataViewItem &item) const
{
// the invisible root node has no parent
if (!item.IsOk())
return wxDataViewItem(0);
ObjectDataViewModelNode *node = (ObjectDataViewModelNode*)item.GetID();
if (node->m_type == itObject)
return item;
ObjectDataViewModelNode *parent_node = node->GetParent();
while (parent_node->m_type != itObject)
parent_node = parent_node->GetParent();
return wxDataViewItem((void*)parent_node);
}
bool ObjectDataViewModel::IsContainer(const wxDataViewItem &item) const
{
// the invisible root node can have children
if (!item.IsOk())
return true;
ObjectDataViewModelNode *node = (ObjectDataViewModelNode*)item.GetID();
return node->IsContainer();
}
unsigned int ObjectDataViewModel::GetChildren(const wxDataViewItem &parent, wxDataViewItemArray &array) const
{
ObjectDataViewModelNode *node = (ObjectDataViewModelNode*)parent.GetID();
if (!node)
{
for (auto object : m_objects)
array.Add(wxDataViewItem((void*)object));
return m_objects.size();
}
if (node->GetChildCount() == 0)
{
return 0;
}
unsigned int count = node->GetChildren().GetCount();
for (unsigned int pos = 0; pos < count; pos++)
{
ObjectDataViewModelNode *child = node->GetChildren().Item(pos);
array.Add(wxDataViewItem((void*)child));
}
return count;
}
void ObjectDataViewModel::GetAllChildren(const wxDataViewItem &parent, wxDataViewItemArray &array) const
{
ObjectDataViewModelNode *node = (ObjectDataViewModelNode*)parent.GetID();
if (!node) {
for (auto object : m_objects)
array.Add(wxDataViewItem((void*)object));
}
else if (node->GetChildCount() == 0)
return;
else {
const size_t count = node->GetChildren().GetCount();
for (size_t pos = 0; pos < count; pos++) {
ObjectDataViewModelNode *child = node->GetChildren().Item(pos);
array.Add(wxDataViewItem((void*)child));
}
}
wxDataViewItemArray new_array = array;
for (const auto item : new_array)
{
wxDataViewItemArray children;
GetAllChildren(item, children);
WX_APPEND_ARRAY(array, children);
}
}
ItemType ObjectDataViewModel::GetItemType(const wxDataViewItem &item) const
{
if (!item.IsOk())
return itUndef;
ObjectDataViewModelNode *node = (ObjectDataViewModelNode*)item.GetID();
return node->m_type < 0 ? itUndef : node->m_type;
}
wxDataViewItem ObjectDataViewModel::GetItemByType(const wxDataViewItem &parent_item, ItemType type) const
{
if (!parent_item.IsOk())
return wxDataViewItem(0);
ObjectDataViewModelNode *node = (ObjectDataViewModelNode*)parent_item.GetID();
if (node->GetChildCount() == 0)
return wxDataViewItem(0);
for (size_t i = 0; i < node->GetChildCount(); i++) {
if (node->GetNthChild(i)->m_type == type)
return wxDataViewItem((void*)node->GetNthChild(i));
}
return wxDataViewItem(0);
}
wxDataViewItem ObjectDataViewModel::GetSettingsItem(const wxDataViewItem &item) const
{
return GetItemByType(item, itSettings);
}
wxDataViewItem ObjectDataViewModel::GetInstanceRootItem(const wxDataViewItem &item) const
{
return GetItemByType(item, itInstanceRoot);
}
wxDataViewItem ObjectDataViewModel::GetLayerRootItem(const wxDataViewItem &item) const
{
return GetItemByType(item, itLayerRoot);
}
bool ObjectDataViewModel::IsSettingsItem(const wxDataViewItem &item) const
{
if (!item.IsOk())
return false;
ObjectDataViewModelNode *node = (ObjectDataViewModelNode*)item.GetID();
return node->m_type == itSettings;
}
void ObjectDataViewModel::UpdateSettingsDigest(const wxDataViewItem &item,
const std::vector<std::string>& categories)
{
if (!item.IsOk()) return;
ObjectDataViewModelNode *node = (ObjectDataViewModelNode*)item.GetID();
if (!node->update_settings_digest(categories))
return;
ItemChanged(item);
}
void ObjectDataViewModel::SetVolumeType(const wxDataViewItem &item, const Slic3r::ModelVolumeType type)
{
if (!item.IsOk() || GetItemType(item) != itVolume)
return;
ObjectDataViewModelNode *node = (ObjectDataViewModelNode*)item.GetID();
node->SetBitmap(*m_volume_bmps[int(type)]);
ItemChanged(item);
}
wxDataViewItem ObjectDataViewModel::SetPrintableState(
PrintIndicator printable,
int obj_idx,
int subobj_idx /* = -1*/,
ItemType subobj_type/* = itInstance*/)
{
wxDataViewItem item = wxDataViewItem(0);
if (subobj_idx < 0)
item = GetItemById(obj_idx);
else
item = subobj_type&itInstance ? GetItemByInstanceId(obj_idx, subobj_idx) :
GetItemByVolumeId(obj_idx, subobj_idx);
ObjectDataViewModelNode* node = (ObjectDataViewModelNode*)item.GetID();
if (!node)
return wxDataViewItem(0);
node->set_printable_icon(printable);
ItemChanged(item);
if (subobj_idx >= 0)
UpdateObjectPrintable(GetItemById(obj_idx));
return item;
}
wxDataViewItem ObjectDataViewModel::SetObjectPrintableState(
PrintIndicator printable,
wxDataViewItem obj_item)
{
ObjectDataViewModelNode* node = (ObjectDataViewModelNode*)obj_item.GetID();
if (!node)
return wxDataViewItem(0);
node->set_printable_icon(printable);
ItemChanged(obj_item);
UpdateInstancesPrintable(obj_item);
return obj_item;
}
void ObjectDataViewModel::Rescale()
{
wxDataViewItemArray all_items;
GetAllChildren(wxDataViewItem(0), all_items);
for (wxDataViewItem item : all_items)
{
if (!item.IsOk())
continue;
ObjectDataViewModelNode *node = (ObjectDataViewModelNode*)item.GetID();
node->msw_rescale();
switch (node->m_type)
{
case itObject:
if (node->m_bmp.IsOk()) node->m_bmp = *m_warning_bmp;
break;
case itVolume:
node->m_bmp = GetVolumeIcon(node->m_volume_type, node->m_bmp.GetWidth() != node->m_bmp.GetHeight());
break;
case itLayerRoot:
node->m_bmp = create_scaled_bitmap(LAYER_ROOT_ICON);
case itLayer:
node->m_bmp = create_scaled_bitmap(LAYER_ICON);
break;
default: break;
}
ItemChanged(item);
}
}
wxBitmap ObjectDataViewModel::GetVolumeIcon(const Slic3r::ModelVolumeType vol_type, const bool is_marked/* = false*/)
{
if (!is_marked)
return *m_volume_bmps[static_cast<int>(vol_type)];
std::string scaled_bitmap_name = "warning" + std::to_string(static_cast<int>(vol_type));
scaled_bitmap_name += "-em" + std::to_string(Slic3r::GUI::wxGetApp().em_unit());
wxBitmap *bmp = m_bitmap_cache->find(scaled_bitmap_name);
if (bmp == nullptr) {
std::vector<wxBitmap> bmps;
bmps.emplace_back(*m_warning_bmp);
bmps.emplace_back(*m_volume_bmps[static_cast<int>(vol_type)]);
bmp = m_bitmap_cache->insert(scaled_bitmap_name, bmps);
}
return *bmp;
}
void ObjectDataViewModel::DeleteWarningIcon(const wxDataViewItem& item, const bool unmark_object/* = false*/)
{
if (!item.IsOk())
return;
ObjectDataViewModelNode *node = (ObjectDataViewModelNode*)item.GetID();
if (!node->GetBitmap().IsOk() || !(node->GetType() & (itVolume | itObject)))
return;
if (node->GetType() & itVolume) {
node->SetBitmap(*m_volume_bmps[static_cast<int>(node->volume_type())]);
return;
}
node->SetBitmap(wxNullBitmap);
if (unmark_object)
{
wxDataViewItemArray children;
GetChildren(item, children);
for (const wxDataViewItem& child : children)
DeleteWarningIcon(child);
}
}
/*
}
}
*/
//-----------------------------------------------------------------------------
// DataViewBitmapText
//-----------------------------------------------------------------------------
wxIMPLEMENT_DYNAMIC_CLASS(DataViewBitmapText, wxObject)
IMPLEMENT_VARIANT_OBJECT(DataViewBitmapText)
// ---------------------------------------------------------
// BitmapTextRenderer
// ---------------------------------------------------------
#if ENABLE_NONCUSTOM_DATA_VIEW_RENDERING
BitmapTextRenderer::BitmapTextRenderer(wxDataViewCellMode mode /*= wxDATAVIEW_CELL_EDITABLE*/,
int align /*= wxDVR_DEFAULT_ALIGNMENT*/):
wxDataViewRenderer(wxT("PrusaDataViewBitmapText"), mode, align)
{
SetMode(mode);
SetAlignment(align);
}
#endif // ENABLE_NONCUSTOM_DATA_VIEW_RENDERING
bool BitmapTextRenderer::SetValue(const wxVariant &value)
{
m_value << value;
return true;
}
bool BitmapTextRenderer::GetValue(wxVariant& WXUNUSED(value)) const
{
return false;
}
#if ENABLE_NONCUSTOM_DATA_VIEW_RENDERING && wxUSE_ACCESSIBILITY
wxString BitmapTextRenderer::GetAccessibleDescription() const
{
return m_value.GetText();
}
#endif // wxUSE_ACCESSIBILITY && ENABLE_NONCUSTOM_DATA_VIEW_RENDERING
bool BitmapTextRenderer::Render(wxRect rect, wxDC *dc, int state)
{
int xoffset = 0;
const wxBitmap& icon = m_value.GetBitmap();
if (icon.IsOk())
{
#ifdef __APPLE__
wxSize icon_sz = icon.GetScaledSize();
#else
wxSize icon_sz = icon.GetSize();
#endif
dc->DrawBitmap(icon, rect.x, rect.y + (rect.height - icon_sz.y) / 2);
xoffset = icon_sz.x + 4;
}
RenderText(m_value.GetText(), xoffset, rect, dc, state);
return true;
}
wxSize BitmapTextRenderer::GetSize() const
{
if (!m_value.GetText().empty())
{
wxSize size = GetTextExtent(m_value.GetText());
if (m_value.GetBitmap().IsOk())
size.x += m_value.GetBitmap().GetWidth() + 4;
return size;
}
return wxSize(80, 20);
}
wxWindow* BitmapTextRenderer::CreateEditorCtrl(wxWindow* parent, wxRect labelRect, const wxVariant& value)
{
wxDataViewCtrl* const dv_ctrl = GetOwner()->GetOwner();
ObjectDataViewModel* const model = dynamic_cast<ObjectDataViewModel*>(dv_ctrl->GetModel());
if ( !(model->GetItemType(dv_ctrl->GetSelection()) & (itVolume | itObject)) )
return nullptr;
DataViewBitmapText data;
data << value;
m_was_unusable_symbol = false;
wxPoint position = labelRect.GetPosition();
if (data.GetBitmap().IsOk()) {
const int bmp_width = data.GetBitmap().GetWidth();
position.x += bmp_width;
labelRect.SetWidth(labelRect.GetWidth() - bmp_width);
}
wxTextCtrl* text_editor = new wxTextCtrl(parent, wxID_ANY, data.GetText(),
position, labelRect.GetSize(), wxTE_PROCESS_ENTER);
text_editor->SetInsertionPointEnd();
text_editor->SelectAll();
return text_editor;
}
bool BitmapTextRenderer::GetValueFromEditorCtrl(wxWindow* ctrl, wxVariant& value)
{
wxTextCtrl* text_editor = wxDynamicCast(ctrl, wxTextCtrl);
if (!text_editor || text_editor->GetValue().IsEmpty())
return false;
std::string chosen_name = Slic3r::normalize_utf8_nfc(text_editor->GetValue().ToUTF8());
const char* unusable_symbols = "<>:/\\|?*\"";
for (size_t i = 0; i < std::strlen(unusable_symbols); i++) {
if (chosen_name.find_first_of(unusable_symbols[i]) != std::string::npos) {
m_was_unusable_symbol = true;
return false;
}
}
// The icon can't be edited so get its old value and reuse it.
wxVariant valueOld;
GetView()->GetModel()->GetValue(valueOld, m_item, colName);
DataViewBitmapText bmpText;
bmpText << valueOld;
// But replace the text with the value entered by user.
bmpText.SetText(text_editor->GetValue());
value << bmpText;
return true;
}
// ----------------------------------------------------------------------------
// BitmapChoiceRenderer
// ----------------------------------------------------------------------------
bool BitmapChoiceRenderer::SetValue(const wxVariant& value)
{
m_value << value;
return true;
}
bool BitmapChoiceRenderer::GetValue(wxVariant& value) const
{
value << m_value;
return true;
}
bool BitmapChoiceRenderer::Render(wxRect rect, wxDC* dc, int state)
{
int xoffset = 0;
const wxBitmap& icon = m_value.GetBitmap();
if (icon.IsOk())
{
dc->DrawBitmap(icon, rect.x, rect.y + (rect.height - icon.GetHeight()) / 2);
xoffset = icon.GetWidth() + 4;
if (rect.height==0)
rect.height= icon.GetHeight();
}
RenderText(m_value.GetText(), xoffset, rect, dc, state);
return true;
}
wxSize BitmapChoiceRenderer::GetSize() const
{
wxSize sz = GetTextExtent(m_value.GetText());
if (m_value.GetBitmap().IsOk())
sz.x += m_value.GetBitmap().GetWidth() + 4;
return sz;
}
wxWindow* BitmapChoiceRenderer::CreateEditorCtrl(wxWindow* parent, wxRect labelRect, const wxVariant& value)
{
wxDataViewCtrl* const dv_ctrl = GetOwner()->GetOwner();
ObjectDataViewModel* const model = dynamic_cast<ObjectDataViewModel*>(dv_ctrl->GetModel());
if (!(model->GetItemType(dv_ctrl->GetSelection()) & (itVolume | itLayer | itObject)))
return nullptr;
std::vector<wxBitmap*> icons = get_extruder_color_icons();
if (icons.empty())
return nullptr;
DataViewBitmapText data;
data << value;
auto c_editor = new wxBitmapComboBox(parent, wxID_ANY, wxEmptyString,
labelRect.GetTopLeft(), wxSize(labelRect.GetWidth(), -1),
0, nullptr , wxCB_READONLY);
int i=0;
for (wxBitmap* bmp : icons) {
if (i==0) {
c_editor->Append(_(L("default")), *bmp);
++i;
}
c_editor->Append(wxString::Format("%d", i), *bmp);
++i;
}
c_editor->SetSelection(atoi(data.GetText().c_str()));
// to avoid event propagation to other sidebar items
c_editor->Bind(wxEVT_COMBOBOX, [this](wxCommandEvent& evt) {
evt.StopPropagation();
// FinishEditing grabs new selection and triggers config update. We better call
// it explicitly, automatic update on KILL_FOCUS didn't work on Linux.
this->FinishEditing();
});
return c_editor;
}
bool BitmapChoiceRenderer::GetValueFromEditorCtrl(wxWindow* ctrl, wxVariant& value)
{
wxBitmapComboBox* c = (wxBitmapComboBox*)ctrl;
int selection = c->GetSelection();
if (selection < 0)
return false;
DataViewBitmapText bmpText;
bmpText.SetText(c->GetString(selection));
bmpText.SetBitmap(c->GetItemBitmap(selection));
value << bmpText;
return true;
}
} // namespace GUI
} // namespace Slic3r