From db549e86095eace3df2befe2ccca2248a58426b0 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Fri, 4 May 2018 18:32:20 +0200 Subject: [PATCH] First experiments with ObjectsTreeList --- lib/Slic3r/GUI/Plater.pm | 4 +- xs/src/slic3r/GUI/GUI.cpp | 136 ++++++++- xs/src/slic3r/GUI/wxExtensions.cpp | 443 +++++++++++++++++++++++++++++ xs/src/slic3r/GUI/wxExtensions.hpp | 411 ++++++++++++++++++++++++++ 4 files changed, 992 insertions(+), 2 deletions(-) diff --git a/lib/Slic3r/GUI/Plater.pm b/lib/Slic3r/GUI/Plater.pm index 603d97a2ff..83a14f21a6 100644 --- a/lib/Slic3r/GUI/Plater.pm +++ b/lib/Slic3r/GUI/Plater.pm @@ -72,7 +72,7 @@ sub new { }); # Initialize preview notebook - $self->{preview_notebook} = Wx::Notebook->new($self, -1, wxDefaultPosition, [335,335], wxNB_BOTTOM); + $self->{preview_notebook} = Wx::Notebook->new($self, -1, wxDefaultPosition, [-1,335], wxNB_BOTTOM); # Initialize handlers for canvases my $on_select_object = sub { @@ -485,6 +485,7 @@ sub new { $buttons_sizer->Add($self->{btn_export_gcode}, 0, wxALIGN_RIGHT, 0); my $right_sizer = Wx::BoxSizer->new(wxVERTICAL); + $right_sizer->SetMinSize([-1, 600]); $right_sizer->Add($presets, 0, wxEXPAND | wxTOP, 10) if defined $presets; $right_sizer->Add($frequently_changed_parameters_sizer, 0, wxEXPAND | wxTOP, 0) if defined $frequently_changed_parameters_sizer; $right_sizer->Add($buttons_sizer, 0, wxEXPAND | wxBOTTOM, 5); @@ -522,6 +523,7 @@ sub new { } $self->update_ui_from_settings(); + $self->Layout; return $self; } diff --git a/xs/src/slic3r/GUI/GUI.cpp b/xs/src/slic3r/GUI/GUI.cpp index 2542c04c6e..0be77b6bac 100644 --- a/xs/src/slic3r/GUI/GUI.cpp +++ b/xs/src/slic3r/GUI/GUI.cpp @@ -812,6 +812,7 @@ void add_frequently_changed_parameters(wxWindow* parent, wxBoxSizer* sizer, wxFl // Experiments with new UI wxCollapsiblePane *collpane = new wxCollapsiblePane(parent, wxID_ANY, "Print settings:"); collpane->Bind(wxEVT_COLLAPSIBLEPANE_CHANGED, ([parent, collpane](wxCommandEvent e){ + wxWindowUpdateLocker noUpdates_cp(collpane); wxWindowUpdateLocker noUpdates(parent); parent->Layout(); collpane->Refresh(); @@ -942,9 +943,142 @@ void add_frequently_changed_parameters(wxWindow* parent, wxBoxSizer* sizer, wxFl }; m_optgroup->append_line(line); + auto common_sizer = new wxBoxSizer(wxVERTICAL); + common_sizer->Add(m_optgroup->sizer); + +// auto listctrl = new wxDataViewListCtrl(win, wxID_ANY, wxDefaultPosition, wxSize(-1, 100)); +// listctrl->AppendToggleColumn("Toggle"); +// listctrl->AppendTextColumn("Text"); +// wxVector data; +// data.push_back(wxVariant(true)); +// data.push_back(wxVariant("row 1")); +// listctrl->AppendItem(data); +// data.clear(); +// data.push_back(wxVariant(false)); +// data.push_back(wxVariant("row 3")); +// listctrl->AppendItem(data); +// data.clear(); +// data.push_back(wxVariant(false)); +// data.push_back(wxVariant("row 2")); +// listctrl->AppendItem(data); +// common_sizer->Add(listctrl, 0, wxEXPAND | wxALL, 1); + + // ********************************************************************************************** + auto objects_ctrl = new wxDataViewCtrl(win, wxID_ANY, wxDefaultPosition, wxDefaultSize); + wxSizer *objects_sz = new wxBoxSizer(wxVERTICAL); + objects_ctrl->SetMinSize(wxSize(-1, 200)); + objects_sz->Add(objects_ctrl, 1, wxGROW | wxALL, 5); + + auto objects_model = new MyObjectTreeModel; + objects_ctrl->AssociateModel(objects_model); +#if wxUSE_DRAG_AND_DROP && wxUSE_UNICODE + objects_ctrl->EnableDragSource(wxDF_UNICODETEXT); + objects_ctrl->EnableDropTarget(wxDF_UNICODETEXT); +#endif // wxUSE_DRAG_AND_DROP && wxUSE_UNICODE + + // column 0 of the view control: + + wxDataViewTextRenderer *tr = new wxDataViewTextRenderer("string", wxDATAVIEW_CELL_INERT); + wxDataViewColumn *column00 = new wxDataViewColumn("Name", tr, 0, 150, wxALIGN_LEFT, + wxDATAVIEW_COL_SORTABLE | wxDATAVIEW_COL_RESIZABLE); + objects_ctrl->AppendColumn(column00); + + // column 1 of the view control: + + tr = new wxDataViewTextRenderer("string", wxDATAVIEW_CELL_INERT); + wxDataViewColumn *column01 = new wxDataViewColumn("Copy", tr, 1, 95, wxALIGN_CENTER_HORIZONTAL, + wxDATAVIEW_COL_SORTABLE | wxDATAVIEW_COL_RESIZABLE); + objects_ctrl->AppendColumn(column01); + + // column 2 of the view control: + + tr = new wxDataViewTextRenderer("string", wxDATAVIEW_CELL_INERT); + wxDataViewColumn *column02 = new wxDataViewColumn("Scale", tr, 2, 95, wxALIGN_CENTER_HORIZONTAL, + wxDATAVIEW_COL_SORTABLE | wxDATAVIEW_COL_RESIZABLE); + objects_ctrl->AppendColumn(column02); + + common_sizer->Add(objects_sz, 0, wxEXPAND | wxALL, 1); + + // ********************************************************************************************** +/* auto view_ctrl = new wxDataViewCtrl(win, wxID_ANY, wxDefaultPosition, wxDefaultSize); + wxSizer *PanelSz = new wxBoxSizer(wxVERTICAL); + view_ctrl->SetMinSize(wxSize(-1, 200)); + PanelSz->Add(view_ctrl, 1, wxGROW | wxALL, 5); + PanelSz->Add( new wxStaticText(win, wxID_ANY, "Most of the cells above are editable!"), 0, wxGROW | wxALL, 5); + + auto m_music_model = new MyMusicTreeModel; + view_ctrl->AssociateModel(m_music_model); + +#if wxUSE_DRAG_AND_DROP && wxUSE_UNICODE + view_ctrl->EnableDragSource(wxDF_UNICODETEXT); + view_ctrl->EnableDropTarget(wxDF_UNICODETEXT); +#endif // wxUSE_DRAG_AND_DROP && wxUSE_UNICODE + + // column 0 of the view control: + + tr = new wxDataViewTextRenderer("string", wxDATAVIEW_CELL_INERT); + wxDataViewColumn *column0 = + new wxDataViewColumn("title", tr, 0, 150, wxALIGN_LEFT, + wxDATAVIEW_COL_SORTABLE | wxDATAVIEW_COL_RESIZABLE); + view_ctrl->AppendColumn(column0); +#if 0 + // Call this and sorting is enabled + // immediately upon start up. + column0->SetAsSortKey(); +#endif + + // column 1 of the view control: + + tr = new wxDataViewTextRenderer("string", wxDATAVIEW_CELL_EDITABLE); + wxDataViewColumn *column1 = + new wxDataViewColumn("artist", tr, 1, 150, wxALIGN_LEFT, + wxDATAVIEW_COL_SORTABLE | wxDATAVIEW_COL_REORDERABLE | + wxDATAVIEW_COL_RESIZABLE); + column1->SetMinWidth(100); // this column can't be resized to be smaller + view_ctrl->AppendColumn(column1); + + // column 2 of the view control: + + wxDataViewSpinRenderer *sr = + new wxDataViewSpinRenderer(0, 2010, wxDATAVIEW_CELL_EDITABLE, + wxALIGN_RIGHT | wxALIGN_CENTRE_VERTICAL); + wxDataViewColumn *column2 = + new wxDataViewColumn("year", sr, 2, 60, wxALIGN_LEFT, + wxDATAVIEW_COL_SORTABLE | wxDATAVIEW_COL_REORDERABLE); + view_ctrl->AppendColumn(column2); + + // column 3 of the view control: + + wxArrayString choices; + choices.Add("good"); + choices.Add("bad"); + choices.Add("lousy"); + wxDataViewChoiceRenderer *c = + new wxDataViewChoiceRenderer(choices, wxDATAVIEW_CELL_EDITABLE, + wxALIGN_RIGHT | wxALIGN_CENTRE_VERTICAL); + wxDataViewColumn *column3 = + new wxDataViewColumn("rating", c, 3, 100, wxALIGN_LEFT, + wxDATAVIEW_COL_REORDERABLE | wxDATAVIEW_COL_RESIZABLE); + view_ctrl->AppendColumn(column3); + + // column 4 of the view control: + + view_ctrl->AppendProgressColumn("popularity", 4, wxDATAVIEW_CELL_INERT, 80); + + // column 5 of the view control: + + MyCustomRenderer *cr = new MyCustomRenderer(wxDATAVIEW_CELL_ACTIVATABLE); + wxDataViewColumn *column5 = + new wxDataViewColumn("custom", cr, 5, -1, wxALIGN_LEFT, + wxDATAVIEW_COL_RESIZABLE); + view_ctrl->AppendColumn(column5); + + // ********************************************************************************************** + common_sizer->Add(PanelSz, 0, wxEXPAND | wxALL, 1); +*/ wxSizer *paneSz = new wxBoxSizer(wxVERTICAL); - paneSz->Add(m_optgroup->sizer, 1, wxGROW | wxEXPAND | wxBOTTOM, 2); + paneSz->Add(common_sizer/*m_optgroup->sizer*/, 1, wxGROW | wxEXPAND | wxBOTTOM, 2); win->SetSizer(paneSz); paneSz->SetSizeHints(win); } diff --git a/xs/src/slic3r/GUI/wxExtensions.cpp b/xs/src/slic3r/GUI/wxExtensions.cpp index 8bc282474e..9d691b1aa4 100644 --- a/xs/src/slic3r/GUI/wxExtensions.cpp +++ b/xs/src/slic3r/GUI/wxExtensions.cpp @@ -165,3 +165,446 @@ void wxDataViewTreeCtrlComboPopup::OnDataViewTreeCtrlSelection(wxCommandEvent& e auto selected = GetItemText(GetSelection()); cmb->SetText(selected); } + +// ***************************************************************************** +// ---------------------------------------------------------------------------- +// MyObjectTreeModel +// ---------------------------------------------------------------------------- + +MyObjectTreeModel::MyObjectTreeModel() +{ + auto root1 = new MyObjectTreeModelNode("Object1"); + m_objects.emplace(root1); + + auto root2 = new MyObjectTreeModelNode("Object2"); + m_objects.emplace(root2); + root2->Append(new MyObjectTreeModelNode(root2, "SubObject1")); + root2->Append(new MyObjectTreeModelNode(root2, "SubObject2")); + root2->Append(new MyObjectTreeModelNode(root2, "SubObject3")); + + auto root3 = new MyObjectTreeModelNode("Object3"); + m_objects.emplace(root3); + auto root4 = new MyObjectTreeModelNode("Object4"); + m_objects.emplace(root4); + root4->Append(new MyObjectTreeModelNode(root2, "SubObject1")); + root4->Append(new MyObjectTreeModelNode(root2, "SubObject2")); + root4->Append(new MyObjectTreeModelNode(root2, "SubObject3")); +} + +wxString MyObjectTreeModel::GetName(const wxDataViewItem &item) const +{ + MyObjectTreeModelNode *node = (MyObjectTreeModelNode*)item.GetID(); + if (!node) // happens if item.IsOk()==false + return wxEmptyString; + + return node->m_name; +} + +wxString MyObjectTreeModel::GetCopyCnt(const wxDataViewItem &item) const +{ + MyObjectTreeModelNode *node = (MyObjectTreeModelNode*)item.GetID(); + if (!node) // happens if item.IsOk()==false + return wxEmptyString; + + return node->m_copy; +} + +wxString MyObjectTreeModel::GetScale(const wxDataViewItem &item) const +{ + MyObjectTreeModelNode *node = (MyObjectTreeModelNode*)item.GetID(); + if (!node) // happens if item.IsOk()==false + return wxEmptyString; + + return node->m_scale; +} + +// void MyObjectTreeModel::Delete(const wxDataViewItem &item) +// { +// +// } + +void MyObjectTreeModel::GetValue(wxVariant &variant, const wxDataViewItem &item, unsigned int col) const +{ + wxASSERT(item.IsOk()); + + MyObjectTreeModelNode *node = (MyObjectTreeModelNode*)item.GetID(); + switch (col) + { + case 0: + variant = node->m_name; + break; + case 1: + variant = node->m_copy; + break; + case 2: + variant = node->m_scale; + break; + default: + ;// wxLogError("MyMusicTreeModel::GetValue: wrong column %d", col); + } +} + +bool MyObjectTreeModel::SetValue(const wxVariant &variant, const wxDataViewItem &item, unsigned int col) +{ + wxASSERT(item.IsOk()); + + MyObjectTreeModelNode *node = (MyObjectTreeModelNode*)item.GetID(); + switch (col) + { + case 0: + node->m_name = variant.GetString(); + return true; + case 1: + node->m_copy = variant.GetString(); + return true; + case 2: + node->m_scale = variant.GetString(); + return true; + + default:; + // wxLogError("MyObjectTreeModel::SetValue: wrong column"); + } + return false; +} + +// bool MyObjectTreeModel::IsEnabled(const wxDataViewItem &item, unsigned int col) const +// { +// +// } + +wxDataViewItem MyObjectTreeModel::GetParent(const wxDataViewItem &item) const +{ + // the invisible root node has no parent + if (!item.IsOk()) + return wxDataViewItem(0); + + MyObjectTreeModelNode *node = (MyObjectTreeModelNode*)item.GetID(); + + // objects nodes also has no parent + if (m_objects.find(node) != m_objects.end()) + return wxDataViewItem(0); + + return wxDataViewItem((void*)node->GetParent()); +} + +bool MyObjectTreeModel::IsContainer(const wxDataViewItem &item) const +{ + // the invisble root node can have children + if (!item.IsOk()) + return true; + + MyObjectTreeModelNode *node = (MyObjectTreeModelNode*)item.GetID(); + return node->IsContainer(); +} + +unsigned int MyObjectTreeModel::GetChildren(const wxDataViewItem &parent, wxDataViewItemArray &array) const +{ + MyObjectTreeModelNode *node = (MyObjectTreeModelNode*)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++) + { + MyObjectTreeModelNode *child = node->GetChildren().Item(pos); + array.Add(wxDataViewItem((void*)child)); + } + + return count; +} + +// ***************************************************************************** +// ---------------------------------------------------------------------------- +// MyMusicTreeModel +// ---------------------------------------------------------------------------- + +MyMusicTreeModel::MyMusicTreeModel() +{ + m_root = new MyMusicTreeModelNode(NULL, "");// , "My Music"); + + // setup pop music + m_pop = new MyMusicTreeModelNode(m_root, "Pop music"); + m_pop->Append( + new MyMusicTreeModelNode(m_pop, "You are not alone", "Michael Jackson", 1995)); + m_pop->Append( + new MyMusicTreeModelNode(m_pop, "Take a bow", "Madonna", 1994)); + m_root->Append(m_pop); + + // setup classical music + m_classical = new MyMusicTreeModelNode(m_root, "Classical music"); + m_ninth = new MyMusicTreeModelNode(m_classical, "Ninth symphony", + "Ludwig van Beethoven", 1824); + m_classical->Append(m_ninth); + m_classical->Append(new MyMusicTreeModelNode(m_classical, "German Requiem", + "Johannes Brahms", 1868)); + m_root->Append(m_classical); + + m_classicalMusicIsKnownToControl = false; +} + +wxString MyMusicTreeModel::GetTitle(const wxDataViewItem &item) const +{ + MyMusicTreeModelNode *node = (MyMusicTreeModelNode*)item.GetID(); + if (!node) // happens if item.IsOk()==false + return wxEmptyString; + + return node->m_title; +} + +wxString MyMusicTreeModel::GetArtist(const wxDataViewItem &item) const +{ + MyMusicTreeModelNode *node = (MyMusicTreeModelNode*)item.GetID(); + if (!node) // happens if item.IsOk()==false + return wxEmptyString; + + return node->m_artist; +} + +int MyMusicTreeModel::GetYear(const wxDataViewItem &item) const +{ + MyMusicTreeModelNode *node = (MyMusicTreeModelNode*)item.GetID(); + if (!node) // happens if item.IsOk()==false + return 2000; + + return node->m_year; +} + +void MyMusicTreeModel::AddToClassical(const wxString &title, const wxString &artist, + unsigned int year) +{ + if (!m_classical) + { + wxASSERT(m_root); + + // it was removed: restore it + m_classical = new MyMusicTreeModelNode(m_root, "Classical music"); + m_root->Append(m_classical); + + // notify control + wxDataViewItem child((void*)m_classical); + wxDataViewItem parent((void*)m_root); + ItemAdded(parent, child); + } + + // add to the classical music node a new node: + MyMusicTreeModelNode *child_node = + new MyMusicTreeModelNode(m_classical, title, artist, year); + m_classical->Append(child_node); + + // FIXME: what's m_classicalMusicIsKnownToControl for? + if (m_classicalMusicIsKnownToControl) + { + // notify control + wxDataViewItem child((void*)child_node); + wxDataViewItem parent((void*)m_classical); + ItemAdded(parent, child); + } +} + +void MyMusicTreeModel::Delete(const wxDataViewItem &item) +{ + MyMusicTreeModelNode *node = (MyMusicTreeModelNode*)item.GetID(); + if (!node) // happens if item.IsOk()==false + return; + + wxDataViewItem parent(node->GetParent()); + if (!parent.IsOk()) + { + wxASSERT(node == m_root); + + // don't make the control completely empty: + //wxLogError("Cannot remove the root item!"); + return; + } + + // is the node one of those we keep stored in special pointers? + if (node == m_pop) + m_pop = NULL; + else if (node == m_classical) + m_classical = NULL; + else if (node == m_ninth) + m_ninth = NULL; + + // first remove the node from the parent's array of children; + // NOTE: MyMusicTreeModelNodePtrArray is only an array of _pointers_ + // thus removing the node from it doesn't result in freeing it + node->GetParent()->GetChildren().Remove(node); + + // free the node + delete node; + + // notify control + ItemDeleted(parent, item); +} + +int MyMusicTreeModel::Compare(const wxDataViewItem &item1, const wxDataViewItem &item2, + unsigned int column, bool ascending) const +{ + wxASSERT(item1.IsOk() && item2.IsOk()); + // should never happen + + if (IsContainer(item1) && IsContainer(item2)) + { + wxVariant value1, value2; + GetValue(value1, item1, 0); + GetValue(value2, item2, 0); + + wxString str1 = value1.GetString(); + wxString str2 = value2.GetString(); + int res = str1.Cmp(str2); + if (res) return res; + + // items must be different + wxUIntPtr litem1 = (wxUIntPtr)item1.GetID(); + wxUIntPtr litem2 = (wxUIntPtr)item2.GetID(); + + return litem1 - litem2; + } + + return wxDataViewModel::Compare(item1, item2, column, ascending); +} + +void MyMusicTreeModel::GetValue(wxVariant &variant, + const wxDataViewItem &item, unsigned int col) const +{ + wxASSERT(item.IsOk()); + + MyMusicTreeModelNode *node = (MyMusicTreeModelNode*)item.GetID(); + switch (col) + { + case 0: + variant = node->m_title; + break; + case 1: + variant = node->m_artist; + break; + case 2: + variant = (long)node->m_year; + break; + case 3: + variant = node->m_quality; + break; + case 4: + variant = 80L; // all music is very 80% popular + break; + case 5: + if (GetYear(item) < 1900) + variant = "old"; + else + variant = "new"; + break; + + default: + ;// wxLogError("MyMusicTreeModel::GetValue: wrong column %d", col); + } +} + +bool MyMusicTreeModel::SetValue(const wxVariant &variant, + const wxDataViewItem &item, unsigned int col) +{ + wxASSERT(item.IsOk()); + + MyMusicTreeModelNode *node = (MyMusicTreeModelNode*)item.GetID(); + switch (col) + { + case 0: + node->m_title = variant.GetString(); + return true; + case 1: + node->m_artist = variant.GetString(); + return true; + case 2: + node->m_year = variant.GetLong(); + return true; + case 3: + node->m_quality = variant.GetString(); + return true; + + default:; +// wxLogError("MyMusicTreeModel::SetValue: wrong column"); + } + return false; +} + +bool MyMusicTreeModel::IsEnabled(const wxDataViewItem &item, + unsigned int col) const +{ + wxASSERT(item.IsOk()); + + MyMusicTreeModelNode *node = (MyMusicTreeModelNode*)item.GetID(); + + // disable Beethoven's ratings, his pieces can only be good + return !(col == 3 && node->m_artist.EndsWith("Beethoven")); +} + +wxDataViewItem MyMusicTreeModel::GetParent(const wxDataViewItem &item) const +{ + // the invisible root node has no parent + if (!item.IsOk()) + return wxDataViewItem(0); + + MyMusicTreeModelNode *node = (MyMusicTreeModelNode*)item.GetID(); + + // "MyMusic" also has no parent + if (node == m_root) + return wxDataViewItem(0); + + return wxDataViewItem((void*)node->GetParent()); +} + +bool MyMusicTreeModel::IsContainer(const wxDataViewItem &item) const +{ + // the invisble root node can have children + // (in our model always "MyMusic") + if (!item.IsOk()) + return true; + + MyMusicTreeModelNode *node = (MyMusicTreeModelNode*)item.GetID(); + return node->IsContainer(); +} + +unsigned int MyMusicTreeModel::GetChildren(const wxDataViewItem &parent, + wxDataViewItemArray &array) const +{ + MyMusicTreeModelNode *node = (MyMusicTreeModelNode*)parent.GetID(); + if (!node) + { + array.Add(wxDataViewItem((void*)m_root)); + return 1; + } + + if (node == m_classical) + { + MyMusicTreeModel *model = (MyMusicTreeModel*)(const MyMusicTreeModel*) this; + model->m_classicalMusicIsKnownToControl = true; + } + + if (node->GetChildCount() == 0) + { + return 0; + } + + unsigned int count = node->GetChildren().GetCount(); + for (unsigned int pos = 0; pos < count; pos++) + { + MyMusicTreeModelNode *child = node->GetChildren().Item(pos); + array.Add(wxDataViewItem((void*)child)); + } + + return count; +} + + +// ***************************************************************************** + + + diff --git a/xs/src/slic3r/GUI/wxExtensions.hpp b/xs/src/slic3r/GUI/wxExtensions.hpp index ed8bb9276a..0ed27ab74f 100644 --- a/xs/src/slic3r/GUI/wxExtensions.hpp +++ b/xs/src/slic3r/GUI/wxExtensions.hpp @@ -4,6 +4,9 @@ #include #include #include +#include +#include +#include class wxCheckListBoxComboPopup : public wxCheckListBox, public wxComboPopup { @@ -50,4 +53,412 @@ public: void SetItemsCnt(int cnt) { m_cnt_open_items = cnt; } }; +// ***************************************************************************** +// ---------------------------------------------------------------------------- +// MyObjectTreeModelNode: a node inside MyObjectTreeModel +// ---------------------------------------------------------------------------- + +class MyObjectTreeModelNode; +WX_DEFINE_ARRAY_PTR(MyObjectTreeModelNode*, MyObjectTreeModelNodePtrArray); + +class MyObjectTreeModelNode +{ + MyObjectTreeModelNode* m_parent; + MyObjectTreeModelNodePtrArray m_children; +public: + MyObjectTreeModelNode( const wxString &name) { + m_parent = NULL; + m_name = name; + m_copy = "1"; + m_scale = "100%"; + } + + MyObjectTreeModelNode( MyObjectTreeModelNode* parent, + const wxString& sub_obj) { + m_parent = parent; + m_name = sub_obj; + m_copy = wxEmptyString; + m_scale = wxEmptyString; + } + + ~MyObjectTreeModelNode() + { + // free all our children nodes + size_t count = m_children.GetCount(); + for (size_t i = 0; i < count; i++) + { + MyObjectTreeModelNode *child = m_children[i]; + delete child; + } + } + + wxString m_name; + wxString m_copy; + wxString m_scale; + bool m_container = false; + + bool IsContainer() const + { + return m_container; + } + + MyObjectTreeModelNode* GetParent() + { + return m_parent; + } + MyObjectTreeModelNodePtrArray& GetChildren() + { + return m_children; + } + MyObjectTreeModelNode* GetNthChild(unsigned int n) + { + return m_children.Item(n); + } + void Insert(MyObjectTreeModelNode* child, unsigned int n) + { + m_children.Insert(child, n); + } + void Append(MyObjectTreeModelNode* child) + { + if (!m_container) + m_container = true; + m_children.Add(child); + } + unsigned int GetChildCount() const + { + return m_children.GetCount(); + } +}; + +// ---------------------------------------------------------------------------- +// MyObjectTreeModel +// ---------------------------------------------------------------------------- + +class MyObjectTreeModel :public wxDataViewModel +{ + std::set m_objects; +public: + MyObjectTreeModel(); + ~MyObjectTreeModel() + { + for (auto object : m_objects) + delete object; + } + + // helper method for wxLog + + wxString GetName(const wxDataViewItem &item) const; + wxString GetCopyCnt(const wxDataViewItem &item) const; + wxString GetScale(const wxDataViewItem &item) const; + + // helper methods to change the model + +// void AddToClassical(const wxString &title, const wxString &artist, +// unsigned int year); +// void Delete(const wxDataViewItem &item); + + 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; + +// virtual bool IsEnabled(const wxDataViewItem &item, +// unsigned int col) const override; + + virtual wxDataViewItem GetParent(const wxDataViewItem &item) const override; + virtual bool IsContainer(const wxDataViewItem &item) const override; + virtual unsigned int GetChildren(const wxDataViewItem &parent, + wxDataViewItemArray &array) const override; +}; + + + + +// ***************************************************************************** +// ---------------------------------------------------------------------------- +// MyMusicTreeModelNode: a node inside MyMusicTreeModel +// ---------------------------------------------------------------------------- + +class MyMusicTreeModelNode; +WX_DEFINE_ARRAY_PTR(MyMusicTreeModelNode*, MyMusicTreeModelNodePtrArray); + +class MyMusicTreeModelNode +{ +public: + MyMusicTreeModelNode(MyMusicTreeModelNode* parent, + const wxString &title, const wxString &artist, + unsigned int year) + { + m_parent = parent; + + m_title = title; + m_artist = artist; + m_year = year; + m_quality = "good"; + + m_container = false; + } + + MyMusicTreeModelNode(MyMusicTreeModelNode* parent, + const wxString &branch) + { + m_parent = parent; + + m_title = branch; + m_year = -1; + + m_container = true; + } + + ~MyMusicTreeModelNode() + { + // free all our children nodes + size_t count = m_children.GetCount(); + for (size_t i = 0; i < count; i++) + { + MyMusicTreeModelNode *child = m_children[i]; + delete child; + } + } + + bool IsContainer() const + { + return m_container; + } + + MyMusicTreeModelNode* GetParent() + { + return m_parent; + } + MyMusicTreeModelNodePtrArray& GetChildren() + { + return m_children; + } + MyMusicTreeModelNode* GetNthChild(unsigned int n) + { + return m_children.Item(n); + } + void Insert(MyMusicTreeModelNode* child, unsigned int n) + { + m_children.Insert(child, n); + } + void Append(MyMusicTreeModelNode* child) + { + m_children.Add(child); + } + unsigned int GetChildCount() const + { + return m_children.GetCount(); + } + +public: // public to avoid getters/setters + wxString m_title; + wxString m_artist; + int m_year; + wxString m_quality; + + // TODO/FIXME: + // the GTK version of wxDVC (in particular wxDataViewCtrlInternal::ItemAdded) + // needs to know in advance if a node is or _will be_ a container. + // Thus implementing: + // bool IsContainer() const + // { return m_children.GetCount()>0; } + // doesn't work with wxGTK when MyMusicTreeModel::AddToClassical is called + // AND the classical node was removed (a new node temporary without children + // would be added to the control) + bool m_container; + +private: + MyMusicTreeModelNode *m_parent; + MyMusicTreeModelNodePtrArray m_children; +}; + + +// ---------------------------------------------------------------------------- +// MyMusicTreeModel +// ---------------------------------------------------------------------------- + +/* +Implement this data model +Title Artist Year Judgement +-------------------------------------------------------------------------- +1: My Music: +2: Pop music +3: You are not alone Michael Jackson 1995 good +4: Take a bow Madonna 1994 good +5: Classical music +6: Ninth Symphony Ludwig v. Beethoven 1824 good +7: German Requiem Johannes Brahms 1868 good +*/ + +class MyMusicTreeModel : public wxDataViewModel +{ +public: + MyMusicTreeModel(); + ~MyMusicTreeModel() + { + if (m_root) + delete m_root; + + } + + // helper method for wxLog + + wxString GetTitle(const wxDataViewItem &item) const; + wxString GetArtist(const wxDataViewItem &item) const; + int GetYear(const wxDataViewItem &item) const; + + // helper methods to change the model + + void AddToClassical(const wxString &title, const wxString &artist, + unsigned int year); + void Delete(const wxDataViewItem &item); + + wxDataViewItem GetNinthItem() const + { + return wxDataViewItem(m_ninth); + } + + // override sorting to always sort branches ascendingly + + int Compare(const wxDataViewItem &item1, const wxDataViewItem &item2, + unsigned int column, bool ascending) const override/*wxOVERRIDE*/; + + // implementation of base class virtuals to define model + + virtual unsigned int GetColumnCount() const override/*wxOVERRIDE*/ + { + return 6; + } + + virtual wxString GetColumnType(unsigned int col) const override/*wxOVERRIDE*/ + { + if (col == 2) + return wxT("long"); + + return wxT("string"); + } + + virtual void GetValue(wxVariant &variant, + const wxDataViewItem &item, unsigned int col) const override/*wxOVERRIDE*/; + virtual bool SetValue(const wxVariant &variant, + const wxDataViewItem &item, unsigned int col) override/*wxOVERRIDE*/; + + virtual bool IsEnabled(const wxDataViewItem &item, + unsigned int col) const override/*wxOVERRIDE*/; + + virtual wxDataViewItem GetParent(const wxDataViewItem &item) const override/*wxOVERRIDE*/; + virtual bool IsContainer(const wxDataViewItem &item) const override/*wxOVERRIDE*/; + virtual unsigned int GetChildren(const wxDataViewItem &parent, + wxDataViewItemArray &array) const override/*wxOVERRIDE*/; + +private: + MyMusicTreeModelNode* m_root; + + // pointers to some "special" nodes of the tree: + MyMusicTreeModelNode* m_pop; + MyMusicTreeModelNode* m_classical; + MyMusicTreeModelNode* m_ninth; + + // ?? + bool m_classicalMusicIsKnownToControl; +}; + +// ---------------------------------------------------------------------------- +// MyCustomRenderer +// ---------------------------------------------------------------------------- + +class MyCustomRenderer : public wxDataViewCustomRenderer +{ +public: + // This renderer can be either activatable or editable, for demonstration + // purposes. In real programs, you should select whether the user should be + // able to activate or edit the cell and it doesn't make sense to switch + // between the two -- but this is just an example, so it doesn't stop us. + explicit MyCustomRenderer(wxDataViewCellMode mode) + : wxDataViewCustomRenderer("string", mode, wxALIGN_CENTER) + { } + + virtual bool Render(wxRect rect, wxDC *dc, int state) override/*wxOVERRIDE*/ + { + dc->SetBrush(*wxLIGHT_GREY_BRUSH); + dc->SetPen(*wxTRANSPARENT_PEN); + + rect.Deflate(2); + dc->DrawRoundedRectangle(rect, 5); + + RenderText(m_value, + 0, // no offset + wxRect(dc->GetTextExtent(m_value)).CentreIn(rect), + dc, + state); + return true; + } + + virtual bool ActivateCell(const wxRect& WXUNUSED(cell), + wxDataViewModel *WXUNUSED(model), + const wxDataViewItem &WXUNUSED(item), + unsigned int WXUNUSED(col), + const wxMouseEvent *mouseEvent) override/*wxOVERRIDE*/ + { + wxString position; + if (mouseEvent) + position = wxString::Format("via mouse at %d, %d", mouseEvent->m_x, mouseEvent->m_y); + else + position = "from keyboard"; +// wxLogMessage("MyCustomRenderer ActivateCell() %s", position); + return false; + } + + virtual wxSize GetSize() const override/*wxOVERRIDE*/ + { + return wxSize(60, 20); + } + + virtual bool SetValue(const wxVariant &value) override/*wxOVERRIDE*/ + { + m_value = value.GetString(); + return true; + } + + virtual bool GetValue(wxVariant &WXUNUSED(value)) const override/*wxOVERRIDE*/{ return true; } + + virtual bool HasEditorCtrl() const override/*wxOVERRIDE*/{ return true; } + + virtual wxWindow* + CreateEditorCtrl(wxWindow* parent, + wxRect labelRect, + const wxVariant& value) override/*wxOVERRIDE*/ + { + wxTextCtrl* text = new wxTextCtrl(parent, wxID_ANY, value, + labelRect.GetPosition(), + labelRect.GetSize(), + wxTE_PROCESS_ENTER); + text->SetInsertionPointEnd(); + + return text; + } + + virtual bool + GetValueFromEditorCtrl(wxWindow* ctrl, wxVariant& value) override/*wxOVERRIDE*/ + { + wxTextCtrl* text = wxDynamicCast(ctrl, wxTextCtrl); + if (!text) + return false; + + value = text->GetValue(); + + return true; + } + +private: + wxString m_value; +}; +// ***************************************************************************** + + + #endif // slic3r_GUI_wxExtensions_hpp_