#ifndef slic3r_GUI_ObjectDataViewModel_hpp_ #define slic3r_GUI_ObjectDataViewModel_hpp_ #include #include namespace Slic3r { enum class ModelVolumeType : int; namespace GUI { typedef double coordf_t; typedef std::pair t_layer_height_range; // ---------------------------------------------------------------------------- // DataViewBitmapText: helper class used by BitmapTextRenderer // ---------------------------------------------------------------------------- class DataViewBitmapText : public wxObject { public: DataViewBitmapText( const wxString &text = wxEmptyString, const wxBitmap& bmp = wxNullBitmap) : m_text(text), m_bmp(bmp) { } DataViewBitmapText(const DataViewBitmapText &other) : wxObject(), m_text(other.m_text), m_bmp(other.m_bmp) { } void SetText(const wxString &text) { m_text = text; } wxString GetText() const { return m_text; } void SetBitmap(const wxBitmap &bmp) { m_bmp = bmp; } const wxBitmap &GetBitmap() const { return m_bmp; } bool IsSameAs(const DataViewBitmapText& other) const { return m_text == other.m_text && m_bmp.IsSameAs(other.m_bmp); } bool operator==(const DataViewBitmapText& other) const { return IsSameAs(other); } bool operator!=(const DataViewBitmapText& other) const { return !IsSameAs(other); } private: wxString m_text; wxBitmap m_bmp; wxDECLARE_DYNAMIC_CLASS(DataViewBitmapText); }; DECLARE_VARIANT_OBJECT(DataViewBitmapText) // ---------------------------------------------------------------------------- // BitmapTextRenderer // ---------------------------------------------------------------------------- #if ENABLE_NONCUSTOM_DATA_VIEW_RENDERING class BitmapTextRenderer : public wxDataViewRenderer #else class BitmapTextRenderer : public wxDataViewCustomRenderer #endif //ENABLE_NONCUSTOM_DATA_VIEW_RENDERING { public: BitmapTextRenderer(wxWindow* parent, wxDataViewCellMode mode = #ifdef __WXOSX__ wxDATAVIEW_CELL_INERT #else wxDATAVIEW_CELL_EDITABLE #endif , int align = wxDVR_DEFAULT_ALIGNMENT #if ENABLE_NONCUSTOM_DATA_VIEW_RENDERING ); #else ) : wxDataViewCustomRenderer(wxT("DataViewBitmapText"), mode, align), m_parent(parent) {} #endif //ENABLE_NONCUSTOM_DATA_VIEW_RENDERING bool SetValue(const wxVariant& value); bool GetValue(wxVariant& value) const; #if ENABLE_NONCUSTOM_DATA_VIEW_RENDERING && wxUSE_ACCESSIBILITY virtual wxString GetAccessibleDescription() const override; #endif // wxUSE_ACCESSIBILITY && ENABLE_NONCUSTOM_DATA_VIEW_RENDERING virtual bool Render(wxRect cell, wxDC* dc, int state) override; virtual wxSize GetSize() const override; bool HasEditorCtrl() const override { #ifdef __WXOSX__ return false; #else return true; #endif } wxWindow* CreateEditorCtrl(wxWindow* parent, wxRect labelRect, const wxVariant& value) override; bool GetValueFromEditorCtrl(wxWindow* ctrl, wxVariant& value) override; bool WasCanceled() const { return m_was_unusable_symbol; } private: DataViewBitmapText m_value; bool m_was_unusable_symbol{ false }; wxWindow* m_parent{ nullptr }; }; // ---------------------------------------------------------------------------- // BitmapChoiceRenderer // ---------------------------------------------------------------------------- class BitmapChoiceRenderer : public wxDataViewCustomRenderer { public: BitmapChoiceRenderer(wxDataViewCellMode mode = #ifdef __WXOSX__ wxDATAVIEW_CELL_INERT #else wxDATAVIEW_CELL_EDITABLE #endif , int align = wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL ) : wxDataViewCustomRenderer(wxT("DataViewBitmapText"), mode, align) {} bool SetValue(const wxVariant& value); bool GetValue(wxVariant& value) const; virtual bool Render(wxRect cell, wxDC* dc, int state) override; virtual wxSize GetSize() const override; bool HasEditorCtrl() const override { return true; } wxWindow* CreateEditorCtrl(wxWindow* parent, wxRect labelRect, const wxVariant& value) override; bool GetValueFromEditorCtrl(wxWindow* ctrl, wxVariant& value) override; private: DataViewBitmapText m_value; }; // ---------------------------------------------------------------------------- // ObjectDataViewModelNode: a node inside ObjectDataViewModel // ---------------------------------------------------------------------------- enum ItemType { itUndef = 0, itObject = 1, itVolume = 2, itInstanceRoot = 4, itInstance = 8, itSettings = 16, itLayerRoot = 32, itLayer = 64, }; enum ColumnNumber { colName = 0, // item name colPrint , // printable property colExtruder , // extruder selection colEditing , // item editing }; enum PrintIndicator { piUndef = 0, // no print indicator piPrintable , // printable piUnprintable , // unprintable }; class ObjectDataViewModelNode; WX_DEFINE_ARRAY_PTR(ObjectDataViewModelNode*, MyObjectTreeModelNodePtrArray); class ObjectDataViewModelNode { ObjectDataViewModelNode* m_parent; MyObjectTreeModelNodePtrArray m_children; wxBitmap m_empty_bmp; size_t m_volumes_cnt = 0; std::vector< std::string > m_opt_categories; t_layer_height_range m_layer_range = { 0.0f, 0.0f }; wxString m_name; wxBitmap& m_bmp = m_empty_bmp; ItemType m_type; int m_idx = -1; bool m_container = false; wxString m_extruder = "default"; wxBitmap m_extruder_bmp; wxBitmap m_action_icon; PrintIndicator m_printable {piUndef}; wxBitmap m_printable_icon; std::string m_action_icon_name = ""; ModelVolumeType m_volume_type; public: ObjectDataViewModelNode(const wxString& name, const wxString& extruder): m_parent(NULL), m_name(name), m_type(itObject), m_extruder(extruder) { set_action_and_extruder_icons(); init_container(); } ObjectDataViewModelNode(ObjectDataViewModelNode* parent, const wxString& sub_obj_name, const wxBitmap& bmp, const wxString& extruder, const int idx = -1 ) : m_parent (parent), m_name (sub_obj_name), m_type (itVolume), m_idx (idx), m_extruder (extruder) { m_bmp = bmp; set_action_and_extruder_icons(); init_container(); } ObjectDataViewModelNode(ObjectDataViewModelNode* parent, const t_layer_height_range& layer_range, const int idx = -1, const wxString& extruder = wxEmptyString ); ObjectDataViewModelNode(ObjectDataViewModelNode* parent, const ItemType type); ~ObjectDataViewModelNode() { // free all our children nodes size_t count = m_children.GetCount(); for (size_t i = 0; i < count; i++) { ObjectDataViewModelNode *child = m_children[i]; delete child; } #ifndef NDEBUG // Indicate that the object was deleted. m_idx = -2; #endif /* NDEBUG */ } void init_container(); bool IsContainer() const { return m_container; } ObjectDataViewModelNode* GetParent() { assert(m_parent == nullptr || m_parent->valid()); return m_parent; } MyObjectTreeModelNodePtrArray& GetChildren() { return m_children; } ObjectDataViewModelNode* GetNthChild(unsigned int n) { return m_children.Item(n); } void Insert(ObjectDataViewModelNode* child, unsigned int n) { if (!m_container) m_container = true; m_children.Insert(child, n); } void Append(ObjectDataViewModelNode* child) { if (!m_container) m_container = true; m_children.Add(child); } void RemoveAllChildren() { if (GetChildCount() == 0) return; for (int id = int(GetChildCount()) - 1; id >= 0; --id) { if (m_children.Item(id)->GetChildCount() > 0) m_children[id]->RemoveAllChildren(); auto node = m_children[id]; m_children.RemoveAt(id); delete node; } } size_t GetChildCount() const { return m_children.GetCount(); } bool SetValue(const wxVariant &variant, unsigned int col); void SetBitmap(const wxBitmap &icon) { m_bmp = icon; } const wxBitmap& GetBitmap() const { return m_bmp; } const wxString& GetName() const { return m_name; } ItemType GetType() const { return m_type; } void SetIdx(const int& idx); int GetIdx() const { return m_idx; } t_layer_height_range GetLayerRange() const { return m_layer_range; } PrintIndicator IsPrintable() const { return m_printable; } // use this function only for childrens void AssignAllVal(ObjectDataViewModelNode& from_node) { // ! Don't overwrite other values because of equality of this values for all children -- m_name = from_node.m_name; m_bmp = from_node.m_bmp; m_idx = from_node.m_idx; m_extruder = from_node.m_extruder; m_type = from_node.m_type; } bool SwapChildrens(int frst_id, int scnd_id) { if (GetChildCount() < 2 || frst_id < 0 || (size_t)frst_id >= GetChildCount() || scnd_id < 0 || (size_t)scnd_id >= GetChildCount()) return false; ObjectDataViewModelNode new_scnd = *GetNthChild(frst_id); ObjectDataViewModelNode new_frst = *GetNthChild(scnd_id); new_scnd.m_idx = m_children.Item(scnd_id)->m_idx; new_frst.m_idx = m_children.Item(frst_id)->m_idx; m_children.Item(frst_id)->AssignAllVal(new_frst); m_children.Item(scnd_id)->AssignAllVal(new_scnd); return true; } // Set action icons for node void set_action_and_extruder_icons(); // Set printable icon for node void set_printable_icon(PrintIndicator printable); void update_settings_digest_bitmaps(); bool update_settings_digest(const std::vector& categories); int volume_type() const { return int(m_volume_type); } void msw_rescale(); #ifndef NDEBUG bool valid(); #endif /* NDEBUG */ bool invalid() const { return m_idx < -1; } private: friend class ObjectDataViewModel; }; // ---------------------------------------------------------------------------- // ObjectDataViewModel // ---------------------------------------------------------------------------- // custom message the model sends to associated control to notify a last volume deleted from the object: wxDECLARE_EVENT(wxCUSTOMEVT_LAST_VOLUME_IS_DELETED, wxCommandEvent); class ObjectDataViewModel :public wxDataViewModel { std::vector m_objects; std::vector m_volume_bmps; wxBitmap* m_warning_bmp { nullptr }; wxDataViewCtrl* m_ctrl { nullptr }; public: ObjectDataViewModel(); ~ObjectDataViewModel(); wxDataViewItem Add( const wxString &name, const int extruder, const bool has_errors = false); wxDataViewItem 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); wxDataViewItem AddSettingsChild(const wxDataViewItem &parent_item); wxDataViewItem AddInstanceChild(const wxDataViewItem &parent_item, size_t num); wxDataViewItem AddInstanceChild(const wxDataViewItem &parent_item, const std::vector& print_indicator); wxDataViewItem AddLayersRoot(const wxDataViewItem &parent_item); wxDataViewItem AddLayersChild( const wxDataViewItem &parent_item, const t_layer_height_range& layer_range, const int extruder = 0, const int index = -1); wxDataViewItem Delete(const wxDataViewItem &item); wxDataViewItem DeleteLastInstance(const wxDataViewItem &parent_item, size_t num); void DeleteAll(); void DeleteChildren(wxDataViewItem& parent); void DeleteVolumeChildren(wxDataViewItem& parent); void DeleteSettings(const wxDataViewItem& parent); wxDataViewItem GetItemById(int obj_idx); wxDataViewItem GetItemById(const int obj_idx, const int sub_obj_idx, const ItemType parent_type); wxDataViewItem GetItemByVolumeId(int obj_idx, int volume_idx); wxDataViewItem GetItemByInstanceId(int obj_idx, int inst_idx); wxDataViewItem GetItemByLayerId(int obj_idx, int layer_idx); wxDataViewItem GetItemByLayerRange(const int obj_idx, const t_layer_height_range& layer_range); int GetItemIdByLayerRange(const int obj_idx, const t_layer_height_range& layer_range); int GetIdByItem(const wxDataViewItem& item) const; int GetIdByItemAndType(const wxDataViewItem& item, const ItemType type) const; int GetObjectIdByItem(const wxDataViewItem& item) const; int GetVolumeIdByItem(const wxDataViewItem& item) const; int GetInstanceIdByItem(const wxDataViewItem& item) const; int GetLayerIdByItem(const wxDataViewItem& item) const; void GetItemInfo(const wxDataViewItem& item, ItemType& type, int& obj_idx, int& idx); int GetRowByItem(const wxDataViewItem& item) const; bool IsEmpty() { return m_objects.empty(); } bool InvalidItem(const wxDataViewItem& item); // helper method for wxLog wxString GetName(const wxDataViewItem &item) const; wxBitmap& GetBitmap(const wxDataViewItem &item) const; wxString GetExtruder(const wxDataViewItem &item) const; int GetExtruderNumber(const wxDataViewItem &item) const; // helper methods to change the model virtual unsigned int GetColumnCount() const override { return 3;} virtual wxString GetColumnType(unsigned int col) const override{ return wxT("string"); } virtual void GetValue( wxVariant &variant, const wxDataViewItem &item, unsigned int col) const override; virtual bool SetValue( const wxVariant &variant, const wxDataViewItem &item, unsigned int col) override; bool SetValue( const wxVariant &variant, const int item_idx, unsigned int col); void SetExtruder(const wxString& extruder, wxDataViewItem item); // For parent move child from cur_volume_id place to new_volume_id // Remaining items will moved up/down accordingly wxDataViewItem ReorganizeChildren( const int cur_volume_id, const int new_volume_id, const wxDataViewItem &parent); wxDataViewItem ReorganizeObjects( int current_id, int new_id); virtual bool IsEnabled(const wxDataViewItem &item, unsigned int col) const override; virtual wxDataViewItem GetParent(const wxDataViewItem &item) const override; // get object item wxDataViewItem GetTopParent(const wxDataViewItem &item) const; virtual bool IsContainer(const wxDataViewItem &item) const override; virtual unsigned int GetChildren(const wxDataViewItem &parent, wxDataViewItemArray &array) const override; void GetAllChildren(const wxDataViewItem &parent,wxDataViewItemArray &array) const; // Is the container just a header or an item with all columns // In our case it is an item with all columns virtual bool HasContainerColumns(const wxDataViewItem& WXUNUSED(item)) const override { return true; } ItemType GetItemType(const wxDataViewItem &item) const ; wxDataViewItem GetItemByType( const wxDataViewItem &parent_item, ItemType type) const; wxDataViewItem GetSettingsItem(const wxDataViewItem &item) const; wxDataViewItem GetInstanceRootItem(const wxDataViewItem &item) const; wxDataViewItem GetLayerRootItem(const wxDataViewItem &item) const; bool IsSettingsItem(const wxDataViewItem &item) const; void UpdateSettingsDigest( const wxDataViewItem &item, const std::vector& categories); bool IsPrintable(const wxDataViewItem &item) const; void UpdateObjectPrintable(wxDataViewItem parent_item); void UpdateInstancesPrintable(wxDataViewItem parent_item); void SetVolumeBitmaps(const std::vector& volume_bmps) { m_volume_bmps = volume_bmps; } void SetWarningBitmap(wxBitmap* bitmap) { m_warning_bmp = bitmap; } void SetVolumeType(const wxDataViewItem &item, const Slic3r::ModelVolumeType type); wxDataViewItem SetPrintableState( PrintIndicator printable, int obj_idx, int subobj_idx = -1, ItemType subobj_type = itInstance); wxDataViewItem SetObjectPrintableState(PrintIndicator printable, wxDataViewItem obj_item); void SetAssociatedControl(wxDataViewCtrl* ctrl) { m_ctrl = ctrl; } // Rescale bitmaps for existing Items void Rescale(); wxBitmap GetVolumeIcon(const Slic3r::ModelVolumeType vol_type, const bool is_marked = false); void DeleteWarningIcon(const wxDataViewItem& item, const bool unmark_object = false); t_layer_height_range GetLayerRangeByItem(const wxDataViewItem& item) const; bool UpdateColumValues(unsigned col); void UpdateExtruderBitmap(wxDataViewItem item); private: wxDataViewItem AddRoot(const wxDataViewItem& parent_item, const ItemType root_type); wxDataViewItem AddInstanceRoot(const wxDataViewItem& parent_item); void AddAllChildren(const wxDataViewItem& parent); }; } } #endif // slic3r_GUI_ObjectDataViewModel_hpp_