diff --git a/src/Mod/Material/App/AppMaterial.cpp b/src/Mod/Material/App/AppMaterial.cpp
index ea5b7bf1e1..6b4b137c9c 100644
--- a/src/Mod/Material/App/AppMaterial.cpp
+++ b/src/Mod/Material/App/AppMaterial.cpp
@@ -27,9 +27,7 @@
#include
#include
-// #include "Model.h"
-#include "MaterialFilter.h"
-
+#include "MaterialFilterPy.h"
#include "MaterialManagerPy.h"
#include "MaterialPy.h"
#include "ModelManagerPy.h"
@@ -68,6 +66,7 @@ PyMOD_INIT_FUNC(Materials)
Base::Console().Log("Loading Material module... done\n");
Base::Interpreter().addType(&Materials::MaterialManagerPy::Type, module, "MaterialManager");
+ Base::Interpreter().addType(&Materials::MaterialFilterPy::Type, module, "MaterialFilter");
Base::Interpreter().addType(&Materials::MaterialPy::Type, module, "Material");
Base::Interpreter().addType(&Materials::ModelManagerPy::Type, module, "ModelManager");
Base::Interpreter().addType(&Materials::ModelPropertyPy::Type, module, "ModelProperty");
diff --git a/src/Mod/Material/App/MaterialFilter.cpp b/src/Mod/Material/App/MaterialFilter.cpp
index 2a0450d02b..c0448b8c60 100644
--- a/src/Mod/Material/App/MaterialFilter.cpp
+++ b/src/Mod/Material/App/MaterialFilter.cpp
@@ -33,12 +33,31 @@
using namespace Materials;
+MaterialFilterOptions::MaterialFilterOptions()
+ : _includeFavorites(true)
+ , _includeRecent(true)
+ , _includeFolders(true)
+ , _includeLibraries(true)
+ , _includeLegacy(false)
+{}
+
+MaterialFilterTreeWidgetOptions::MaterialFilterTreeWidgetOptions()
+{
+ auto param = App::GetApplication().GetParameterGroupByPath(
+ "User parameter:BaseApp/Preferences/Mod/Material/TreeWidget");
+ _includeFavorites = param->GetBool("ShowFavorites", true);
+ _includeRecent = param->GetBool("ShowRecent", true);
+ _includeFolders = param->GetBool("ShowEmptyFolders", false);
+ _includeLibraries = param->GetBool("ShowEmptyLibraries", true);
+ _includeLegacy = param->GetBool("ShowLegacy", false);
+}
+
+//===
+
TYPESYSTEM_SOURCE(Materials::MaterialFilter, Base::BaseClass)
MaterialFilter::MaterialFilter()
- : _includeFolders(true)
- , _includeLegacy(true)
- , _required()
+ : _required()
, _requiredComplete()
{}
diff --git a/src/Mod/Material/App/MaterialFilter.h b/src/Mod/Material/App/MaterialFilter.h
index 99ab1d7f3d..44285a2d94 100644
--- a/src/Mod/Material/App/MaterialFilter.h
+++ b/src/Mod/Material/App/MaterialFilter.h
@@ -24,6 +24,7 @@
#include
+#include
#include
#include
@@ -36,6 +37,102 @@ namespace Materials
class Material;
+/*
+ * This class is used to set options for a material tree search
+ *
+ */
+class MaterialsExport MaterialFilterOptions
+{
+
+public:
+ MaterialFilterOptions();
+ virtual ~MaterialFilterOptions() = default;
+
+ /* Indicates if we should show favourite materials
+ *
+ * Default is to show favourite materials
+ */
+ bool includeFavorites() const
+ {
+ return _includeFavorites;
+ }
+ void setIncludeFavorites(bool value)
+ {
+ _includeFavorites = value;
+ }
+
+ /* Indicates if we should show recent materials
+ *
+ * Default is to show recent materials
+ */
+ bool includeRecent() const
+ {
+ return _includeRecent;
+ }
+ void setIncludeRecent(bool value)
+ {
+ _includeRecent = value;
+ }
+
+ /* Indicates if we should include empty folders
+ *
+ * Default is not to include empty folders
+ */
+ bool includeEmptyFolders() const
+ {
+ return _includeFolders;
+ }
+ void setIncludeEmptyFolders(bool value)
+ {
+ _includeFolders = value;
+ }
+
+ /* Indicates if we should include empty libraries
+ *
+ * Default is to include empty libraries
+ */
+ bool includeEmptyLibraries() const
+ {
+ return _includeLibraries;
+ }
+ void setIncludeEmptyLibraries(bool value)
+ {
+ _includeLibraries = value;
+ }
+
+ /* Indicates if we should include materials in the older format
+ *
+ * Default is not to include legacy format materials
+ */
+ bool includeLegacy() const
+ {
+ return _includeLegacy;
+ }
+ void setIncludeLegacy(bool legacy)
+ {
+ _includeLegacy = legacy;
+ }
+
+protected:
+ bool _includeFavorites;
+ bool _includeRecent;
+ bool _includeFolders;
+ bool _includeLibraries;
+ bool _includeLegacy;
+};
+
+/*
+ * The same class initialized with preferences for the MaterialTreeWidget
+ *
+ */
+class MaterialsExport MaterialFilterTreeWidgetOptions: public MaterialFilterOptions
+{
+
+public:
+ MaterialFilterTreeWidgetOptions();
+ ~MaterialFilterTreeWidgetOptions() override = default;
+};
+
/*
* This class is used to filter materials during a material tree search
*
@@ -48,30 +145,17 @@ public:
MaterialFilter();
virtual ~MaterialFilter() = default;
- /* Indicates if we should include empty folders
- *
- * Default is to include empty folders
+ /*
+ * Filter name when used in a list of filters. The name should be
+ * unique within the list.
*/
- bool includeEmptyFolders() const
+ QString name() const
{
- return _includeFolders;
+ return _name;
}
- void setIncludeEmptyFolders(bool value)
+ void setName(const QString& name)
{
- _includeFolders = value;
- }
-
- /* Indicates if we should include materials in the older format
- *
- * Default is to include legacy format materials
- */
- bool includeLegacy() const
- {
- return _includeLegacy;
- }
- void setIncludeLegacy(bool legacy)
- {
- _includeLegacy = legacy;
+ _name = name;
}
/* Sets of model UUIDs that should be included. Optionally, we can
@@ -101,12 +185,13 @@ public:
}
private:
- bool _includeFolders;
- bool _includeLegacy;
+ QString _name;
QSet _required;
QSet _requiredComplete;
};
} // namespace Materials
+Q_DECLARE_METATYPE(Materials::MaterialFilter)
+
#endif // MATERIAL_MATERIALFILTER_H
diff --git a/src/Mod/Material/App/MaterialFilterPy.xml b/src/Mod/Material/App/MaterialFilterPy.xml
index 3dbbe10074..ac7825ff31 100644
--- a/src/Mod/Material/App/MaterialFilterPy.xml
+++ b/src/Mod/Material/App/MaterialFilterPy.xml
@@ -15,17 +15,11 @@
Material filters.
-
+
- Include empty folders in the material list.
+ Name of the filter used to select a filter in a list
-
-
-
-
- Include legacy materials in the material list.
-
-
+
diff --git a/src/Mod/Material/App/MaterialFilterPyImpl.cpp b/src/Mod/Material/App/MaterialFilterPyImpl.cpp
index bc8e635c20..2b467e5587 100644
--- a/src/Mod/Material/App/MaterialFilterPyImpl.cpp
+++ b/src/Mod/Material/App/MaterialFilterPyImpl.cpp
@@ -61,24 +61,15 @@ int MaterialFilterPy::PyInit(PyObject* /*args*/, PyObject* /*kwd*/)
return 0;
}
-Py::Boolean MaterialFilterPy::getIncludeEmptyFolders() const
+Py::String MaterialFilterPy::getName() const
{
- return {getMaterialFilterPtr()->includeEmptyFolders()};
+ auto filterName = getMaterialFilterPtr()->name();
+ return {filterName.toStdString()};
}
-void MaterialFilterPy::setIncludeEmptyFolders(const Py::Boolean value)
+void MaterialFilterPy::setName(const Py::String value)
{
- getMaterialFilterPtr()->setIncludeEmptyFolders(value.isTrue());
-}
-
-Py::Boolean MaterialFilterPy::getIncludeLegacy() const
-{
- return {getMaterialFilterPtr()->includeLegacy()};
-}
-
-void MaterialFilterPy::setIncludeLegacy(const Py::Boolean value)
-{
- getMaterialFilterPtr()->setIncludeLegacy(value.isTrue());
+ getMaterialFilterPtr()->setName(QString::fromStdString(value));
}
Py::List MaterialFilterPy::getRequiredModels() const
diff --git a/src/Mod/Material/App/MaterialLibrary.cpp b/src/Mod/Material/App/MaterialLibrary.cpp
index 28ffdd27eb..221dcbcc0e 100644
--- a/src/Mod/Material/App/MaterialLibrary.cpp
+++ b/src/Mod/Material/App/MaterialLibrary.cpp
@@ -266,7 +266,8 @@ QString MaterialLibrary::getUUIDFromPath(const QString& path) const
}
bool MaterialLibrary::materialInTree(const std::shared_ptr& material,
- const std::shared_ptr& filter) const
+ const std::shared_ptr& filter,
+ const Materials::MaterialFilterOptions& options) const
{
if (!filter) {
// If there's no filter we always include
@@ -274,7 +275,7 @@ bool MaterialLibrary::materialInTree(const std::shared_ptr& material,
}
// filter out old format files
- if (material->isOldFormat() && !filter->includeLegacy()) {
+ if (material->isOldFormat() && !options.includeLegacy()) {
return false;
}
@@ -283,7 +284,8 @@ bool MaterialLibrary::materialInTree(const std::shared_ptr& material,
}
std::shared_ptr>>
-MaterialLibrary::getMaterialTree(const std::shared_ptr& filter) const
+MaterialLibrary::getMaterialTree(const std::shared_ptr& filter,
+ const Materials::MaterialFilterOptions& options) const
{
std::shared_ptr>> materialTree =
std::make_shared>>();
@@ -292,7 +294,7 @@ MaterialLibrary::getMaterialTree(const std::shared_ptrincludeEmptyFolders()) {
+ if (!filter || options.includeEmptyFolders()) {
auto folderList = MaterialLoader::getMaterialFolders(*this);
for (auto& folder : *folderList) {
QStringList list = folder.split(QString::fromStdString("/"));
diff --git a/src/Mod/Material/App/MaterialLibrary.h b/src/Mod/Material/App/MaterialLibrary.h
index ec0175743a..bb40951258 100644
--- a/src/Mod/Material/App/MaterialLibrary.h
+++ b/src/Mod/Material/App/MaterialLibrary.h
@@ -41,6 +41,7 @@ namespace Materials
class Material;
class MaterialManager;
class MaterialFilter;
+class MaterialFilterOptions;
class MaterialsExport MaterialLibrary: public LibraryBase,
public std::enable_shared_from_this
@@ -79,7 +80,8 @@ public:
std::shared_ptr addMaterial(const std::shared_ptr& material,
const QString& path);
std::shared_ptr>>
- getMaterialTree(const std::shared_ptr& filter) const;
+ getMaterialTree(const std::shared_ptr& filter,
+ const Materials::MaterialFilterOptions& options) const;
bool isReadOnly() const
{
@@ -99,7 +101,8 @@ protected:
void updatePaths(const QString& oldPath, const QString& newPath);
QString getUUIDFromPath(const QString& path) const;
bool materialInTree(const std::shared_ptr& material,
- const std::shared_ptr& filter) const;
+ const std::shared_ptr& filter,
+ const Materials::MaterialFilterOptions& options) const;
bool _readOnly;
std::unique_ptr>> _materialPathMap;
diff --git a/src/Mod/Material/App/MaterialManager.cpp b/src/Mod/Material/App/MaterialManager.cpp
index 6e03f2720c..afb0c9024b 100644
--- a/src/Mod/Material/App/MaterialManager.cpp
+++ b/src/Mod/Material/App/MaterialManager.cpp
@@ -24,6 +24,7 @@
#include
#endif
+#include
#include
#include
diff --git a/src/Mod/Material/App/MaterialManager.h b/src/Mod/Material/App/MaterialManager.h
index ed6926e657..e8c1c5b13f 100644
--- a/src/Mod/Material/App/MaterialManager.h
+++ b/src/Mod/Material/App/MaterialManager.h
@@ -24,8 +24,6 @@
#include
-#include
-
#include
#include
@@ -34,9 +32,12 @@
#include "Materials.h"
#include "MaterialLibrary.h"
+#include "MaterialFilter.h"
namespace fs = boost::filesystem;
+class QMutex;
+
namespace App
{
class Material;
@@ -45,8 +46,6 @@ class Material;
namespace Materials
{
-class MaterialFilter;
-
class MaterialsExport MaterialManager: public Base::BaseClass
{
TYPESYSTEM_HEADER_WITH_OVERRIDE();
@@ -77,13 +76,22 @@ public:
getMaterialTree(const std::shared_ptr& library,
const std::shared_ptr& filter) const
{
- return library->getMaterialTree(filter);
+ MaterialFilterOptions options;
+ return library->getMaterialTree(filter, options);
+ }
+ std::shared_ptr>>
+ getMaterialTree(const std::shared_ptr& library,
+ const std::shared_ptr& filter,
+ const MaterialFilterOptions& options) const
+ {
+ return library->getMaterialTree(filter, options);
}
std::shared_ptr>>
getMaterialTree(const std::shared_ptr& library) const
{
std::shared_ptr filter;
- return library->getMaterialTree(filter);
+ MaterialFilterOptions options;
+ return library->getMaterialTree(filter, options);
}
std::shared_ptr>
getMaterialFolders(const std::shared_ptr& library) const;
diff --git a/src/Mod/Material/App/MaterialManagerPyImpl.cpp b/src/Mod/Material/App/MaterialManagerPyImpl.cpp
index e6dd15e7ab..e5af5059e4 100644
--- a/src/Mod/Material/App/MaterialManagerPyImpl.cpp
+++ b/src/Mod/Material/App/MaterialManagerPyImpl.cpp
@@ -71,7 +71,7 @@ PyObject* MaterialManagerPy::getMaterial(PyObject* args)
PyObject* MaterialManagerPy::getMaterialByPath(PyObject* args)
{
- char* path;
+ char* path {};
const char* lib = "";
if (!PyArg_ParseTuple(args, "et|s", "utf-8", &path, &lib)) {
return nullptr;
diff --git a/src/Mod/Material/Gui/AppMatGui.cpp b/src/Mod/Material/Gui/AppMatGui.cpp
index 0c5f673cf1..db053bcb5f 100644
--- a/src/Mod/Material/Gui/AppMatGui.cpp
+++ b/src/Mod/Material/Gui/AppMatGui.cpp
@@ -34,6 +34,8 @@
#include "DlgSettingsMaterial.h"
#include "Workbench.h"
#include "WorkbenchManipulator.h"
+#include "MaterialTreeWidget.h"
+#include "MaterialTreeWidgetPy.h"
// use a different name to CreateCommand()
void CreateMaterialCommands();
@@ -78,7 +80,7 @@ PyMOD_INIT_FUNC(MatGui)
// load needed modules
try {
- Base::Interpreter().runString("import Material");
+ Base::Interpreter().runString("import Materials");
}
catch (const Base::Exception& e) {
PyErr_SetString(PyExc_ImportError, e.what());
@@ -107,5 +109,18 @@ PyMOD_INIT_FUNC(MatGui)
// add resources and reloads the translators
loadMaterialResource();
+ Base::Interpreter().addType(&MatGui::MaterialTreeWidgetPy::Type,
+ matGuiModule,
+ "MaterialTreeWidget");
+
+
+ // Initialize types
+
+ MatGui::MaterialTreeWidget::init();
+
+ // Add custom widgets
+ new Gui::WidgetProducer;
+
+
PyMOD_Return(matGuiModule);
}
diff --git a/src/Mod/Material/Gui/CMakeLists.txt b/src/Mod/Material/Gui/CMakeLists.txt
index 3e9dee2510..6c754a369c 100644
--- a/src/Mod/Material/Gui/CMakeLists.txt
+++ b/src/Mod/Material/Gui/CMakeLists.txt
@@ -36,6 +36,14 @@ qt_find_and_add_translation(QM_SRCS "Resources/translations/*_*.ts"
qt_create_resource_file(${Material_TR_QRC} ${QM_SRCS})
qt_add_resources(MatGui_QRC_SRCS Resources/Material.qrc ${Material_TR_QRC})
+generate_from_xml(MaterialTreeWidgetPy)
+
+SET(Python_SRCS
+ MaterialTreeWidgetPy.xml
+ MaterialTreeWidgetPyImpl.cpp
+)
+SOURCE_GROUP("Python" FILES ${Python_SRCS})
+
set(MatGui_UIC_SRCS
Array2D.ui
Array3D.ui
@@ -51,6 +59,7 @@ set(MatGui_UIC_SRCS
)
SET(MatGui_SRCS
+ ${Python_SRCS}
${MatGui_QRC_SRCS}
${MatGui_UIC_HDRS}
AppearancePreview.h
diff --git a/src/Mod/Material/Gui/DlgDisplayProperties.ui b/src/Mod/Material/Gui/DlgDisplayProperties.ui
index cc054d201e..fd80c1d23d 100644
--- a/src/Mod/Material/Gui/DlgDisplayProperties.ui
+++ b/src/Mod/Material/Gui/DlgDisplayProperties.ui
@@ -402,18 +402,6 @@
-
-
-
- 0
- 0
-
-
-
-
- 40
- 32767
-
-
...
diff --git a/src/Mod/Material/Gui/DlgDisplayPropertiesImp.cpp b/src/Mod/Material/Gui/DlgDisplayPropertiesImp.cpp
index 08d7dc37dd..eb68612826 100644
--- a/src/Mod/Material/Gui/DlgDisplayPropertiesImp.cpp
+++ b/src/Mod/Material/Gui/DlgDisplayPropertiesImp.cpp
@@ -163,11 +163,7 @@ DlgDisplayPropertiesImp::DlgDisplayPropertiesImp(bool floating, QWidget* parent,
// Create a filter to only include current format materials
// that contain the basic render model.
- auto filter = std::make_shared();
- filter->setIncludeEmptyFolders(false);
- filter->setIncludeLegacy(false);
- filter->addRequiredComplete(Materials::ModelUUIDs::ModelUUID_Rendering_Basic);
- d->ui.widgetMaterial->setFilter(filter);
+ setupFilters();
std::vector views = getSelection();
setDisplayModes(views);
@@ -209,6 +205,32 @@ DlgDisplayPropertiesImp::~DlgDisplayPropertiesImp()
Gui::Selection().Detach(this);
}
+void DlgDisplayPropertiesImp::setupFilters()
+{
+ // Create a filter to only include current format materials
+ // that contain the basic render model.
+ auto filterList = std::make_shared>>();
+
+ auto filter = std::make_shared();
+ filter->setName(tr("Basic Appearance"));
+ filter->addRequiredComplete(Materials::ModelUUIDs::ModelUUID_Rendering_Basic);
+ filterList->push_back(filter);
+
+ filter = std::make_shared();
+ filter->setName(tr("Texture Appearance"));
+ filter->addRequiredComplete(Materials::ModelUUIDs::ModelUUID_Rendering_Texture);
+ filterList->push_back(filter);
+
+ filter = std::make_shared();
+ filter->setName(tr("All Materials"));
+ filterList->push_back(filter);
+
+ d->ui.widgetMaterial->setIncludeEmptyFolders(false);
+ d->ui.widgetMaterial->setIncludeLegacy(false);
+
+ d->ui.widgetMaterial->setFilter(filterList);
+}
+
void DlgDisplayPropertiesImp::setupConnections()
{
#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
@@ -337,6 +359,7 @@ void DlgDisplayPropertiesImp::slotChangedObject(const Gui::ViewProvider& obj,
else if (prop.isDerivedFrom()) {
//auto& value = static_cast(prop).getValue();
if (prop_name == "ShapeAppearance") {
+ // Base::Console().Log("slotChangeObject(ShapeAppearance)\n");
// bool blocked = d->ui.buttonColor->blockSignals(true);
// auto color = value.diffuseColor;
// d->ui.buttonColor->setColor(QColor((int)(255.0f * color.r),
@@ -565,17 +588,21 @@ void DlgDisplayPropertiesImp::setDisplayModes(const std::vector& views)
{
- bool material = false;
- //App::Material::MaterialType matType = App::Material::DEFAULT;
- for (auto view : views) {
- if (auto* prop =
- dynamic_cast(view->getPropertyByName("ShapeMaterial"))) {
- material = true;
- // matType = prop->getValue().getType();
- break;
- }
- }
- d->ui.buttonUserDefinedMaterial->setEnabled(material);
+ Q_UNUSED(views);
+ // bool material = false;
+ // App::Material mat = App::Material(App::Material::DEFAULT);
+ // for (auto view : views) {
+ // if (auto* prop =
+ // dynamic_cast(view->getPropertyByName("ShapeMaterial"))) {
+ // mat = prop->getValue();
+ // material = mat.uuid.empty();
+ // if (!material) {
+ // d->ui.widgetMaterial->setMaterial(QString::fromStdString(mat.uuid));
+ // }
+ // break;
+ // }
+ // }
+ // d->ui.buttonUserDefinedMaterial->setEnabled(material);
}
void DlgDisplayPropertiesImp::setColorPlot(const std::vector& views)
@@ -595,9 +622,21 @@ void DlgDisplayPropertiesImp::setColorPlot(const std::vector
void DlgDisplayPropertiesImp::setShapeAppearance(const std::vector& views)
{
- Q_UNUSED(views)
-
- // Private::setElementAppearance(views, "ShapeColor", d->ui.buttonColor);
+ bool material = false;
+ App::Material mat = App::Material(App::Material::DEFAULT);
+ for (auto view : views) {
+ if (auto* prop =
+ dynamic_cast(view->getPropertyByName("ShapeAppearance"))) {
+ mat = prop->getValues()[0];
+ material = mat.uuid.empty();
+ if (!material) {
+ d->ui.widgetMaterial->setMaterial(QString::fromStdString(mat.uuid));
+ }
+ break;
+ }
+ }
+ // d->ui.buttonUserDefinedMaterial->setEnabled(material);
+ d->ui.buttonUserDefinedMaterial->setEnabled(true);
}
void DlgDisplayPropertiesImp::setLineColor(const std::vector& views)
@@ -668,6 +707,7 @@ void DlgDisplayPropertiesImp::onMaterialSelected(
material->getAppearanceProperty(QString::fromLatin1("Shininess"))->getFloat();
mat.transparency =
material->getAppearanceProperty(QString::fromLatin1("Transparency"))->getFloat();
+ mat.uuid = material->getUUID().toStdString();
prop->setValue(mat);
}
}
diff --git a/src/Mod/Material/Gui/DlgDisplayPropertiesImp.h b/src/Mod/Material/Gui/DlgDisplayPropertiesImp.h
index 3914256b58..d16b2aea88 100644
--- a/src/Mod/Material/Gui/DlgDisplayPropertiesImp.h
+++ b/src/Mod/Material/Gui/DlgDisplayPropertiesImp.h
@@ -84,6 +84,7 @@ protected:
private:
void setupConnections();
+ void setupFilters();
void slotChangedObject(const Gui::ViewProvider&, const App::Property& Prop);
void setDisplayModes(const std::vector&);
void setMaterial(const std::vector&);
diff --git a/src/Mod/Material/Gui/DlgSettingsMaterial.cpp b/src/Mod/Material/Gui/DlgSettingsMaterial.cpp
index 5c0436ae68..882687c857 100644
--- a/src/Mod/Material/Gui/DlgSettingsMaterial.cpp
+++ b/src/Mod/Material/Gui/DlgSettingsMaterial.cpp
@@ -43,6 +43,11 @@ void DlgSettingsMaterial::saveSettings()
ui->fc_custom_mat_dir->onSave();
ui->cb_delete_duplicates->onSave();
ui->cb_sort_by_resources->onSave();
+ ui->cb_show_favorites->onSave();
+ ui->cb_show_recent->onSave();
+ ui->cb_show_empty_libraries->onSave();
+ ui->cb_show_empty_folders->onSave();
+ ui->cb_show_legacy->onSave();
// Temporary for testing
ui->cb_legacy_editor->onSave();
@@ -57,6 +62,11 @@ void DlgSettingsMaterial::loadSettings()
ui->fc_custom_mat_dir->onRestore();
ui->cb_delete_duplicates->onRestore();
ui->cb_sort_by_resources->onRestore();
+ ui->cb_show_favorites->onRestore();
+ ui->cb_show_recent->onRestore();
+ ui->cb_show_empty_libraries->onRestore();
+ ui->cb_show_empty_folders->onRestore();
+ ui->cb_show_legacy->onRestore();
// Temporary for testing
ui->cb_legacy_editor->onRestore();
diff --git a/src/Mod/Material/Gui/DlgSettingsMaterial.ui b/src/Mod/Material/Gui/DlgSettingsMaterial.ui
index fa3afcd8d8..9a96f2fd6d 100644
--- a/src/Mod/Material/Gui/DlgSettingsMaterial.ui
+++ b/src/Mod/Material/Gui/DlgSettingsMaterial.ui
@@ -7,7 +7,7 @@
0
0
434
- 341
+ 553
@@ -231,6 +231,89 @@ If unchecked, they will be sorted by their name.
+ -
+
+
+ Material Selector
+
+
+
-
+
+
+ Show favorites
+
+
+ true
+
+
+ ShowFavorites
+
+
+ Mod/Material/TreeWidget
+
+
+
+ -
+
+
+ Show recent
+
+
+ true
+
+
+ ShowRecent
+
+
+ Mod/Material/TreeWidget
+
+
+
+ -
+
+
+ Show empty libraries
+
+
+ true
+
+
+ ShowEmptyLibraries
+
+
+ Mod/Material/TreeWidget
+
+
+
+ -
+
+
+ Show empty folders
+
+
+ ShowEmptyFolders
+
+
+ Mod/Material/TreeWidget
+
+
+
+ -
+
+
+ Show legacy files
+
+
+ ShowLegacy
+
+
+ Mod/Material/TreeWidget
+
+
+
+
+
+
-
diff --git a/src/Mod/Material/Gui/MaterialTreeWidget.cpp b/src/Mod/Material/Gui/MaterialTreeWidget.cpp
index b8b82cbd82..aa49c94733 100644
--- a/src/Mod/Material/Gui/MaterialTreeWidget.cpp
+++ b/src/Mod/Material/Gui/MaterialTreeWidget.cpp
@@ -38,12 +38,14 @@
#include
#include
+#include
#include
#include "MaterialTreeWidget.h"
#include "MaterialsEditor.h"
#include "ui_MaterialsEditor.h"
+Q_DECLARE_METATYPE(Materials::MaterialFilterPy*)
using Base::Console;
using namespace MatGui;
@@ -51,7 +53,9 @@ using namespace MatGui;
/** Constructs a Material tree widget.
*/
-MaterialTreeWidget::MaterialTreeWidget(std::shared_ptr filter,
+TYPESYSTEM_SOURCE(MatGui::MaterialTreeWidget, Base::BaseClass)
+
+MaterialTreeWidget::MaterialTreeWidget(const std::shared_ptr& filter,
QWidget* parent)
: QWidget(parent)
, m_expanded(false)
@@ -60,10 +64,21 @@ MaterialTreeWidget::MaterialTreeWidget(std::shared_ptr>>& filterList,
+ QWidget* parent)
+ : QWidget(parent)
+ , m_expanded(false)
+ , _filter(std::make_shared())
+ , _filterList(filterList)
+{
+ setup();
+}
+
MaterialTreeWidget::MaterialTreeWidget(QWidget* parent)
: QWidget(parent)
, m_expanded(false)
- , _filter(nullptr)
+ , _filter(std::make_shared())
{
setup();
}
@@ -80,7 +95,12 @@ void MaterialTreeWidget::setup()
/**
* Destroys the widget and detaches it from its parameter group.
*/
-MaterialTreeWidget::~MaterialTreeWidget() = default;
+MaterialTreeWidget::~MaterialTreeWidget()
+{
+ addRecent(m_uuid);
+ saveWidgetSettings();
+ saveMaterialTree();
+}
void MaterialTreeWidget::createLayout()
{
@@ -88,9 +108,9 @@ void MaterialTreeWidget::createLayout()
m_expand = new QPushButton(this);
m_expand->setIcon(style()->standardIcon(QStyle::SP_TitleBarUnshadeButton));
m_materialTree = new QTreeView(this);
+ m_filterCombo = new QComboBox(this);
m_editor = new QPushButton(tr("Launch editor"), this);
- // m_materialTree->setSelectionModel(QAbstractItemView::SingleSelection);
m_materialTree->setSelectionMode(QAbstractItemView::SingleSelection);
m_materialTree->setSelectionBehavior(QAbstractItemView::SelectItems);
@@ -102,6 +122,7 @@ void MaterialTreeWidget::createLayout()
treeLayout->addWidget(m_materialTree);
auto buttonLayout = new QHBoxLayout();
+ buttonLayout->addWidget(m_filterCombo);
buttonLayout->addItem(new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Preferred));
buttonLayout->addWidget(m_editor);
@@ -112,18 +133,34 @@ void MaterialTreeWidget::createLayout()
layout->addItem(buttonLayout);
setLayout(layout);
- // Start in an unexpanded state. Store the state?
- openWidgetState(false);
+ // Set the filter if using a filter list
+ if (hasMultipleFilters()) {
+ _filter = _filterList->front();
+ }
+
+ fillFilterCombo();
+
+ // Start in the previous expanded state
+ auto param = App::GetApplication().GetParameterGroupByPath(
+ "User parameter:BaseApp/Preferences/Mod/Material/TreeWidget");
+ auto expanded = param->GetBool("WidgetExpanded", false);
+ setExpanded(expanded);
connect(m_expand, &QPushButton::clicked, this, &MaterialTreeWidget::expandClicked);
connect(m_editor, &QPushButton::clicked, this, &MaterialTreeWidget::editorClicked);
+ connect(m_filterCombo,
+ &QComboBox::currentTextChanged,
+ this,
+ &MaterialTreeWidget::onFilter);
}
-void MaterialTreeWidget::openWidgetState(bool open)
+void MaterialTreeWidget::setExpanded(bool open)
{
m_materialTree->setVisible(open);
m_editor->setVisible(open);
+ setFilterVisible(open);
+
m_expanded = open;
if (open) {
@@ -134,12 +171,33 @@ void MaterialTreeWidget::openWidgetState(bool open)
}
}
+void MaterialTreeWidget::setFilterVisible(bool open)
+{
+ if (open && hasMultipleFilters()) {
+ m_filterCombo->setVisible(true);
+ }
+ else {
+ m_filterCombo->setVisible(false);
+ }
+}
+
+void MaterialTreeWidget::fillFilterCombo()
+{
+ m_filterCombo->clear();
+ if (hasMultipleFilters()) {
+ for (auto const& filter : *_filterList) {
+ m_filterCombo->addItem(filter->name());
+ }
+ }
+}
+
+
void MaterialTreeWidget::expandClicked(bool checked)
{
Q_UNUSED(checked)
// Toggle the open state
- openWidgetState(!m_expanded);
+ setExpanded(!m_expanded);
}
void MaterialTreeWidget::editorClicked(bool checked)
@@ -160,7 +218,7 @@ void MaterialTreeWidget::editorClicked(bool checked)
// Gui::Application::Instance->commandManager().runCommandByName("Materials_Edit");
// Toggle the open state
- // openWidgetState(!m_expanded);
+ // setExpanded(!m_expanded);
}
void MaterialTreeWidget::updateMaterial(const QString& uuid)
@@ -212,8 +270,14 @@ QModelIndex MaterialTreeWidget::findInTree(const QString& uuid)
auto root = model->invisibleRootItem();
QModelIndex index;
- if (findInTree(*root, &index, uuid)) {
- return index;
+ // Find the original item, not the reference in favourites or recents
+ for (int i = 0; i < root->rowCount(); i++) {
+ auto child = root->child(i);
+ if (child->text() != tr("Favorites") && child->text() != tr("Recent")) {
+ if (findInTree(*child, &index, uuid)) {
+ return index;
+ }
+ }
}
return {};
@@ -231,6 +295,7 @@ void MaterialTreeWidget::setMaterial(const QString& uuid)
if (index.isValid()) {
QItemSelectionModel* selectionModel = m_materialTree->selectionModel();
selectionModel->select(index, QItemSelectionModel::SelectCurrent);
+ m_materialTree->scrollTo(index);
}
}
@@ -239,14 +304,61 @@ QString MaterialTreeWidget::getMaterialUUID() const
return m_uuid;
}
-void MaterialTreeWidget::setFilter(std::shared_ptr filter)
+void MaterialTreeWidget::setFilter(const std::shared_ptr& filter)
{
- _filter.reset();
+ if (_filter) {
+ _filter.reset();
+ }
+ if (_filterList) {
+ _filterList.reset();
+ }
+
_filter = filter;
+ fillFilterCombo();
+ setFilterVisible(m_expanded);
+
updateMaterialTree();
}
+void MaterialTreeWidget::setFilter(
+ const std::shared_ptr>>& filterList)
+{
+ _filter.reset();
+ if (_filterList) {
+ _filterList.reset();
+ }
+
+ _filterList = filterList;
+ if (hasMultipleFilters()) {
+ _filter = _filterList->front();
+ }
+
+ fillFilterCombo();
+ setFilterVisible(m_expanded);
+
+ updateMaterialTree();
+}
+
+void MaterialTreeWidget::setActiveFilter(const QString& name)
+{
+ if (_filterList) {
+ for (auto const& filter : *_filterList) {
+ if (filter->name() == name) {
+ _filter.reset();
+
+ _filter = filter;
+
+ // Save the library/folder expansion state
+ saveMaterialTree();
+
+ updateMaterialTree();
+ return;
+ }
+ }
+ }
+}
+
void MaterialTreeWidget::updateMaterialTree()
{
_favorites.clear();
@@ -293,6 +405,70 @@ void MaterialTreeWidget::getRecents()
}
}
+void MaterialTreeWidget::saveRecents()
+{
+ auto param = App::GetApplication().GetParameterGroupByPath(
+ "User parameter:BaseApp/Preferences/Mod/Material/Recent");
+
+ // Clear out the existing favorites
+ int count = param->GetInt("Recent", 0);
+ for (int i = 0; static_cast(i) < count; i++) {
+ QString key = QString::fromLatin1("MRU%1").arg(i);
+ param->RemoveASCII(key.toStdString().c_str());
+ }
+
+ // Add the current values
+ int size = _recents.size();
+ if (size > _recentMax) {
+ size = _recentMax;
+ }
+ param->SetInt("Recent", size);
+ int j = 0;
+ for (auto& recent : _recents) {
+ QString key = QString::fromLatin1("MRU%1").arg(j);
+ param->SetASCII(key.toStdString().c_str(), recent.toStdString());
+
+ j++;
+ if (j >= size) {
+ break;
+ }
+ }
+}
+
+void MaterialTreeWidget::addRecent(const QString& uuid)
+{
+ // Ensure it is a material. New, unsaved materials will not be
+ try {
+ auto material = _materialManager.getMaterial(uuid);
+ Q_UNUSED(material)
+ }
+ catch (const Materials::MaterialNotFound&) {
+ return;
+ }
+
+ // Ensure no duplicates
+ if (isRecent(uuid)) {
+ _recents.remove(uuid);
+ }
+
+ _recents.push_front(uuid);
+ while (_recents.size() > static_cast(_recentMax)) {
+ _recents.pop_back();
+ }
+
+ saveRecents();
+}
+
+bool MaterialTreeWidget::isRecent(const QString& uuid) const
+{
+ for (auto& it : _recents) {
+ if (it == uuid) {
+ return true;
+ }
+ }
+ return false;
+}
+
void MaterialTreeWidget::createMaterialTree()
{
auto model = new QStandardItemModel(this);
@@ -312,36 +488,44 @@ void MaterialTreeWidget::createMaterialTree()
void MaterialTreeWidget::fillMaterialTree()
{
+ auto param = App::GetApplication().GetParameterGroupByPath(
+ "User parameter:BaseApp/Preferences/Mod/Material/TreeWidget/MaterialTree");
+
auto model = dynamic_cast(m_materialTree->model());
- auto lib = new QStandardItem(tr("Favorites"));
- lib->setFlags(Qt::ItemIsEnabled);
- addExpanded(model, lib);
- addFavorites(lib);
+ if (_filterOptions.includeFavorites()) {
+ auto lib = new QStandardItem(tr("Favorites"));
+ lib->setFlags(Qt::ItemIsEnabled);
+ addExpanded(model, lib, param);
+ addFavorites(lib);
+ }
- lib = new QStandardItem(tr("Recent"));
- lib->setFlags(Qt::ItemIsEnabled);
- addExpanded(model, lib);
- addRecents(lib);
-
- // // Create a filter to only include current format materials
- // // that contain the basic render model.
- // Materials::MaterialFilter filter;
- // filter.setIncludeEmptyFolders(false);
- // filter.setIncludeLegacy(false);
- // filter.addRequired(Materials::ModelUUIDs::ModelUUID_Rendering_Basic);
+ if (_filterOptions.includeRecent()) {
+ auto lib = new QStandardItem(tr("Recent"));
+ lib->setFlags(Qt::ItemIsEnabled);
+ addExpanded(model, lib, param);
+ addRecents(lib);
+ }
auto libraries = _materialManager.getMaterialLibraries();
for (const auto& library : *libraries) {
- lib = new QStandardItem(library->getName());
- lib->setFlags(Qt::ItemIsEnabled);
- addExpanded(model, lib);
+ auto modelTree = _materialManager.getMaterialTree(library, _filter, _filterOptions);
- QIcon icon(library->getIconPath());
- QIcon folderIcon(QString::fromStdString(":/icons/folder.svg"));
+ bool showLibraries = _filterOptions.includeEmptyLibraries();
+ if (!_filterOptions.includeEmptyLibraries() && modelTree->size() > 0) {
+ showLibraries = true;
+ }
- auto modelTree = _materialManager.getMaterialTree(library, _filter);
- addMaterials(*lib, modelTree, folderIcon, icon);
+ if (showLibraries) {
+ auto lib = new QStandardItem(library->getName());
+ lib->setFlags(Qt::ItemIsEnabled);
+ addExpanded(model, lib, param);
+
+ QIcon icon(library->getIconPath());
+ QIcon folderIcon(QString::fromStdString(":/icons/folder.svg"));
+
+ addMaterials(*lib, modelTree, folderIcon, icon, param);
+ }
}
}
@@ -351,12 +535,34 @@ void MaterialTreeWidget::addExpanded(QStandardItem* parent, QStandardItem* child
m_materialTree->setExpanded(child->index(), true);
}
+void MaterialTreeWidget::addExpanded(QStandardItem* parent,
+ QStandardItem* child,
+ const Base::Reference& param)
+{
+ parent->appendRow(child);
+
+ // Restore to any previous expansion state
+ auto expand = param->GetBool(child->text().toStdString().c_str(), true);
+ m_materialTree->setExpanded(child->index(), expand);
+}
+
void MaterialTreeWidget::addExpanded(QStandardItemModel* model, QStandardItem* child)
{
model->appendRow(child);
m_materialTree->setExpanded(child->index(), true);
}
+void MaterialTreeWidget::addExpanded(QStandardItemModel* model,
+ QStandardItem* child,
+ const Base::Reference& param)
+{
+ model->appendRow(child);
+
+ // Restore to any previous expansion state
+ auto expand = param->GetBool(child->text().toStdString().c_str(), true);
+ m_materialTree->setExpanded(child->index(), expand);
+}
+
void MaterialTreeWidget::addRecents(QStandardItem* parent)
{
for (auto& uuid : _recents) {
@@ -397,17 +603,16 @@ void MaterialTreeWidget::addMaterials(
const std::shared_ptr>>&
modelTree,
const QIcon& folderIcon,
- const QIcon& icon)
+ const QIcon& icon,
+ const Base::Reference& param)
{
+ auto childParam = param->GetGroup(parent.text().toStdString().c_str());
for (auto& mat : *modelTree) {
auto nodePtr = mat.second;
if (nodePtr->getType() == Materials::MaterialTreeNode::DataNode) {
auto material = nodePtr->getData();
QString uuid = material->getUUID();
- // Base::Console().Log("Material path '%s'\n",
- // material->getDirectory().toStdString().c_str());
- // auto card = new QStandardItem(icon, material->getName());
auto card = new QStandardItem(icon, mat.first);
card->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
card->setData(QVariant(uuid), Qt::UserRole);
@@ -416,10 +621,10 @@ void MaterialTreeWidget::addMaterials(
}
else {
auto node = new QStandardItem(folderIcon, mat.first);
- addExpanded(&parent, node);
+ addExpanded(&parent, node, childParam);
node->setFlags(Qt::ItemIsEnabled);
auto treeMap = nodePtr->getFolder();
- addMaterials(*node, treeMap, folderIcon, icon);
+ addMaterials(*node, treeMap, folderIcon, icon, childParam);
}
}
}
@@ -446,6 +651,7 @@ void MaterialTreeWidget::onSelectMaterial(const QItemSelection& selected,
std::string _uuid = uuid.toStdString();
Q_EMIT materialSelected(getMaterialManager().getMaterial(uuid));
+ Q_EMIT onMaterial(uuid);
}
void MaterialTreeWidget::onDoubleClick(const QModelIndex& index)
@@ -458,3 +664,48 @@ void MaterialTreeWidget::onDoubleClick(const QModelIndex& index)
updateMaterial(uuid);
}
}
+
+void MaterialTreeWidget::onFilter(const QString& text)
+{
+ setActiveFilter(text);
+}
+
+void MaterialTreeWidget::saveWidgetSettings()
+{
+ auto param = App::GetApplication().GetParameterGroupByPath(
+ "User parameter:BaseApp/Preferences/Mod/Material/TreeWidget");
+ param->SetBool("WidgetExpanded", m_expanded);
+}
+
+void MaterialTreeWidget::saveMaterialTree()
+{
+ auto param = App::GetApplication().GetParameterGroupByPath(
+ "User parameter:BaseApp/Preferences/Mod/Material/TreeWidget/MaterialTree");
+ param->Clear();
+
+ auto tree = m_materialTree;
+ auto model = dynamic_cast(tree->model());
+
+ auto root = model->invisibleRootItem();
+ for (int i = 0; i < root->rowCount(); i++) {
+ auto child = root->child(i);
+ saveMaterialTreeChildren(param, tree, model, child);
+ }
+}
+
+void MaterialTreeWidget::saveMaterialTreeChildren(const Base::Reference& param,
+ QTreeView* tree,
+ QStandardItemModel* model,
+ QStandardItem* item)
+{
+ if (item->hasChildren()) {
+ param->SetBool(item->text().toStdString().c_str(), tree->isExpanded(item->index()));
+
+ auto treeParam = param->GetGroup(item->text().toStdString().c_str());
+ for (int i = 0; i < item->rowCount(); i++) {
+ auto child = item->child(i);
+
+ saveMaterialTreeChildren(treeParam, tree, model, child);
+ }
+ }
+}
diff --git a/src/Mod/Material/Gui/MaterialTreeWidget.h b/src/Mod/Material/Gui/MaterialTreeWidget.h
index cfcd508d56..af7a1be11b 100644
--- a/src/Mod/Material/Gui/MaterialTreeWidget.h
+++ b/src/Mod/Material/Gui/MaterialTreeWidget.h
@@ -41,6 +41,7 @@
#include
+#include
#include
#include
@@ -48,6 +49,7 @@ namespace MatGui
{
class CommandManager;
class WidgetFactoryInst;
+class MaterialTreeWidgetPy;
/** The Material Tree widget class
* This widget is intended for use wherever materials are used. It is a light weight
@@ -65,36 +67,21 @@ class WidgetFactoryInst;
*
* \author David Carter
*/
-class MatGuiExport MaterialTreeWidget: public QWidget
+class MatGuiExport MaterialTreeWidget: public QWidget, public Base::BaseClass
{
Q_OBJECT
+ TYPESYSTEM_HEADER_WITH_OVERRIDE();
+
public:
- explicit MaterialTreeWidget(std::shared_ptr filter,
+ explicit MaterialTreeWidget(const std::shared_ptr& filter,
QWidget* parent = nullptr);
+ explicit MaterialTreeWidget(
+ const std::shared_ptr>>& filterList,
+ QWidget* parent = nullptr);
explicit MaterialTreeWidget(QWidget* parent = nullptr);
~MaterialTreeWidget() override;
- // void setEntryName( const QByteArray& name );
- // QByteArray entryName() const;
- // /** Does the same as setEntryName().
- // * This function is added for convenience because the ui compiler
- // * will use this function if the attribute stdset isn't set to 0 in a .ui file.
- // */
- // void setPrefEntry(const QByteArray& name);
-
- // void setParamGrpPath( const QByteArray& path );
- // QByteArray paramGrpPath() const;
- // /** Does the same as setParamGrpPath().
- // * This function is added for convenience because the ui compiler
- // * will use this function if the attribute stdset isn't set to 0 in a .ui file.
- // */
- // void setPrefPath(const QByteArray& name);
-
- // void OnChange(Base::Subject &rCaller, const char * sReason) override;
- // void onSave();
- // void onRestore();
-
/** Set the material by specifying its UUID
*/
void setMaterial(const QString& uuid);
@@ -103,17 +90,84 @@ public:
QString getMaterialUUID() const;
/** Set the material filter
*/
- void setFilter(std::shared_ptr filter);
+ void setFilter(const std::shared_ptr& filter);
+ void setFilter(
+ const std::shared_ptr>>& filterList);
+ void setActiveFilter(const QString &name);
+
+ void setExpanded(bool open);
+ bool getExpanded()
+ {
+ return m_expanded;
+ }
+
+ /* Indicates if we should show favourite materials
+ */
+ bool includeFavorites() const
+ {
+ return _filterOptions.includeFavorites();
+ }
+ void setIncludeFavorites(bool value)
+ {
+ _filterOptions.setIncludeFavorites(value);
+ }
+
+ /* Indicates if we should show recent materials
+ */
+ bool includeRecent() const
+ {
+ return _filterOptions.includeRecent();
+ }
+ void setIncludeRecent(bool value)
+ {
+ _filterOptions.setIncludeRecent(value);
+ }
+
+ /* Indicates if we should include empty folders
+ */
+ bool includeEmptyFolders() const
+ {
+ return _filterOptions.includeEmptyFolders();
+ }
+ void setIncludeEmptyFolders(bool value)
+ {
+ _filterOptions.setIncludeEmptyFolders(value);
+ }
+
+ /* Indicates if we should include empty libraries
+ */
+ bool includeEmptyLibraries() const
+ {
+ return _filterOptions.includeEmptyLibraries();
+ }
+ void setIncludeEmptyLibraries(bool value)
+ {
+ Base::Console().Log("setIncludeEmptyLibraries(%s)\n", (value ? "true" : "false"));
+ _filterOptions.setIncludeEmptyLibraries(value);
+ }
+
+ /* Indicates if we should include materials in the older format
+ */
+ bool includeLegacy() const
+ {
+ return _filterOptions.includeLegacy();
+ }
+ void setIncludeLegacy(bool legacy)
+ {
+ _filterOptions.setIncludeLegacy(legacy);
+ }
Q_SIGNALS:
/** Emits this signal when a material has been selected */
void materialSelected(const std::shared_ptr& material);
+ void onMaterial(const QString& uuid);
private Q_SLOTS:
void expandClicked(bool checked);
void editorClicked(bool checked);
void onSelectMaterial(const QItemSelection& selected, const QItemSelection& deselected);
void onDoubleClick(const QModelIndex& index);
+ void onFilter(const QString& text);
private:
void setup();
@@ -122,6 +176,7 @@ private:
QPushButton* m_expand;
QTreeView* m_materialTree;
QPushButton* m_editor;
+ QComboBox* m_filterCombo;
bool m_expanded;
QString m_materialDisplay;
@@ -130,7 +185,10 @@ private:
std::list _favorites;
std::list _recents;
std::shared_ptr _filter;
+ Materials::MaterialFilterTreeWidgetOptions _filterOptions;
+ std::shared_ptr>> _filterList;
int _recentMax;
+ MaterialTreeWidgetPy* pyTreeWidget {nullptr};
Materials::MaterialManager _materialManager;
@@ -146,7 +204,17 @@ protected:
}
void getFavorites();
+
void getRecents();
+ void saveRecents();
+ void addRecent(const QString& uuid);
+ bool isRecent(const QString& uuid) const;
+ void saveWidgetSettings();
+ void saveMaterialTreeChildren(const Base::Reference& param,
+ QTreeView* tree,
+ QStandardItemModel* model,
+ QStandardItem* item);
+ void saveMaterialTree();
/** Create the widgets UI objects
*/
@@ -159,7 +227,13 @@ protected:
void fillMaterialTree();
void updateMaterialTree();
void addExpanded(QStandardItem* parent, QStandardItem* child);
+ void addExpanded(QStandardItem* parent,
+ QStandardItem* child,
+ const Base::Reference& param);
void addExpanded(QStandardItemModel* model, QStandardItem* child);
+ void addExpanded(QStandardItemModel* model,
+ QStandardItem* child,
+ const Base::Reference& param);
void addRecents(QStandardItem* parent);
void addFavorites(QStandardItem* parent);
void addMaterials(
@@ -167,9 +241,13 @@ protected:
const std::shared_ptr>>&
modelTree,
const QIcon& folderIcon,
- const QIcon& icon);
-
- void openWidgetState(bool open);
+ const QIcon& icon,
+ const Base::Reference& param);
+ void setFilterVisible(bool open);
+ void fillFilterCombo();
+ bool hasMultipleFilters() const {
+ return (_filterList && _filterList->size() > 1);
+ }
};
} // namespace MatGui
diff --git a/src/Mod/Material/Gui/MaterialTreeWidgetPy.xml b/src/Mod/Material/Gui/MaterialTreeWidgetPy.xml
new file mode 100644
index 0000000000..182aa1eb0e
--- /dev/null
+++ b/src/Mod/Material/Gui/MaterialTreeWidgetPy.xml
@@ -0,0 +1,71 @@
+
+
+
+
+
+ Material tree widget.
+
+
+
+ Material UUID.
+
+
+
+
+
+ Expand material tree.
+
+
+
+
+
+ Include favorites in the material list.
+
+
+
+
+
+ Include recently used materials in the material list.
+
+
+
+
+
+ Include empty folders in the material list.
+
+
+
+
+
+ Include empty libraries in the material list.
+
+
+
+
+
+ Include legacy materials in the material list.
+
+
+
+
+
+ Set the material filter or list of filters.
+
+
+
+
+ Set the current material filter.
+
+
+
+
diff --git a/src/Mod/Material/Gui/MaterialTreeWidgetPyImpl.cpp b/src/Mod/Material/Gui/MaterialTreeWidgetPyImpl.cpp
new file mode 100644
index 0000000000..c107880518
--- /dev/null
+++ b/src/Mod/Material/Gui/MaterialTreeWidgetPyImpl.cpp
@@ -0,0 +1,238 @@
+/***************************************************************************
+ * Copyright (c) 2023 David Carter *
+ * *
+ * This file is part of FreeCAD. *
+ * *
+ * FreeCAD is free software: you can redistribute it and/or modify it *
+ * under the terms of the GNU Lesser General Public License as *
+ * published by the Free Software Foundation, either version 2.1 of the *
+ * License, or (at your option) any later version. *
+ * *
+ * FreeCAD is distributed in the hope that it will be useful, but *
+ * WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
+ * Lesser General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU Lesser General Public *
+ * License along with FreeCAD. If not, see *
+ * . *
+ * *
+ **************************************************************************/
+
+#include "PreCompiled.h"
+
+#include
+
+#include "MaterialTreeWidget.h"
+#include "MaterialTreeWidgetPy.h"
+
+#include "MaterialTreeWidgetPy.cpp"
+
+using namespace MatGui;
+
+// returns a string which represents the object e.g. when printed in python
+std::string MaterialTreeWidgetPy::representation() const
+{
+ std::ostringstream str;
+ str << "";
+ return str.str();
+}
+
+PyObject* MaterialTreeWidgetPy::PyMake(struct _typeobject*, PyObject*, PyObject*) // Python wrapper
+{
+ // never create such objects with the constructor
+ return new MaterialTreeWidgetPy(new MaterialTreeWidget());
+}
+
+// constructor method
+int MaterialTreeWidgetPy::PyInit(PyObject* args, PyObject* /*kwd*/)
+{
+ PyObject* obj {};
+ if (PyArg_ParseTuple(args, "")) {
+ return 0;
+ }
+
+ PyErr_Clear();
+ if (PyArg_ParseTuple(args, "O!", &(MatGui::MaterialTreeWidgetPy::Type), &obj)) {
+ auto widget = static_cast(obj)->getMaterialTreeWidgetPtr();
+ _pcTwinPointer = widget;
+ return 0;
+ }
+
+ // PyErr_Clear();
+ // if (PyArg_ParseTuple(args, "O!", &(QWidget::Type), &obj)) {
+ // auto widget = static_cast(obj);
+ // _pcTwinPointer = widget;
+ // return 0;
+ // }
+
+ PyErr_Clear();
+ if (PyArg_ParseTuple(args, "O", &obj)) {
+ if (QLatin1String(obj->ob_type->tp_name) == QLatin1String("PySide2.QtWidgets.QWidget")) {
+ Gui::PythonWrapper wrap;
+ wrap.loadWidgetsModule();
+ auto qObject = wrap.toQObject(Py::Object(obj));
+ auto widget = static_cast(qObject);
+ _pcTwinPointer = widget;
+ return 0;
+ }
+ else {
+ PyErr_Format(PyExc_TypeError,
+ "empty parameter list, or MaterialTreeWidget expected not '%s'",
+ obj->ob_type->tp_name);
+ return -1;
+ }
+ }
+
+ PyErr_SetString(PyExc_TypeError, "empty parameter list, or MaterialTreeWidget expected");
+ // PyErr_Format(PyExc_TypeError,
+ // "empty parameter list, or MaterialTreeWidget expected not '%s'",
+ // obj->ob_type->tp_name);
+ return -1;
+}
+
+Py::String MaterialTreeWidgetPy::getUUID() const
+{
+ return Py::String(getMaterialTreeWidgetPtr()->getMaterialUUID().toStdString());
+}
+
+void MaterialTreeWidgetPy::setUUID(const Py::String value)
+{
+ getMaterialTreeWidgetPtr()->setMaterial(QString::fromStdString(value));
+}
+
+Py::Boolean MaterialTreeWidgetPy::getexpanded() const
+{
+ return {getMaterialTreeWidgetPtr()->getExpanded()};
+}
+
+void MaterialTreeWidgetPy::setexpanded(const Py::Boolean value)
+{
+ getMaterialTreeWidgetPtr()->setExpanded(value.isTrue());
+}
+
+Py::Boolean MaterialTreeWidgetPy::getIncludeFavorites() const
+{
+ return {getMaterialTreeWidgetPtr()->includeFavorites()};
+}
+
+void MaterialTreeWidgetPy::setIncludeFavorites(const Py::Boolean value)
+{
+ getMaterialTreeWidgetPtr()->setIncludeFavorites(value.isTrue());
+}
+
+Py::Boolean MaterialTreeWidgetPy::getIncludeRecent() const
+{
+ return {getMaterialTreeWidgetPtr()->includeRecent()};
+}
+
+void MaterialTreeWidgetPy::setIncludeRecent(const Py::Boolean value)
+{
+ getMaterialTreeWidgetPtr()->setIncludeRecent(value.isTrue());
+}
+
+Py::Boolean MaterialTreeWidgetPy::getIncludeEmptyFolders() const
+{
+ return {getMaterialTreeWidgetPtr()->includeEmptyFolders()};
+}
+
+void MaterialTreeWidgetPy::setIncludeEmptyFolders(const Py::Boolean value)
+{
+ getMaterialTreeWidgetPtr()->setIncludeEmptyFolders(value.isTrue());
+}
+
+Py::Boolean MaterialTreeWidgetPy::getIncludeEmptyLibraries() const
+{
+ return {getMaterialTreeWidgetPtr()->includeEmptyLibraries()};
+}
+
+void MaterialTreeWidgetPy::setIncludeEmptyLibraries(const Py::Boolean value)
+{
+ getMaterialTreeWidgetPtr()->setIncludeEmptyLibraries(value.isTrue());
+}
+
+Py::Boolean MaterialTreeWidgetPy::getIncludeLegacy() const
+{
+ return {getMaterialTreeWidgetPtr()->includeLegacy()};
+}
+
+void MaterialTreeWidgetPy::setIncludeLegacy(const Py::Boolean value)
+{
+ getMaterialTreeWidgetPtr()->setIncludeLegacy(value.isTrue());
+}
+
+PyObject* MaterialTreeWidgetPy::setFilter(PyObject* args)
+{
+ PyObject* obj;
+ if (!PyArg_ParseTuple(args, "O", &obj)) {
+ return nullptr;
+ }
+ if (PyObject_TypeCheck(obj, &(Materials::MaterialFilterPy::Type))) {
+ auto filter = static_cast(obj)->getMaterialFilterPtr();
+ Base::Console().Log("Filter '%s'\n", filter->name().toStdString().c_str());
+ auto filterPtr = std::make_shared(*filter);
+ getMaterialTreeWidgetPtr()->setFilter(filterPtr);
+ }
+ else if (PyList_Check(obj)) {
+ // The argument is a list of filters
+ Base::Console().Log("Filter List\n");
+ Py_ssize_t n = PyList_Size(obj);
+ Base::Console().Log("n = %d\n", n);
+ if (n < 0) {
+ Py_Return;
+ }
+ PyObject* item;
+ auto filterList = std::make_shared>>();
+ for (int i = 0; i < n; i++) {
+ item = PyList_GetItem(obj, i);
+ if (PyObject_TypeCheck(item, &(Materials::MaterialFilterPy::Type))) {
+ auto filter =
+ static_cast(item)->getMaterialFilterPtr();
+ Base::Console().Log("\tFilter '%s'\n",
+ filter->name().toStdString().c_str()); auto filterPtr =
+ std::make_shared(*filter);
+ filterList->push_back(filterPtr);
+ // getMaterialTreeWidgetPtr()->setFilter(
+ //
+ // *static_cast(obj)->getMaterialFilterPtr());
+ }
+ else {
+ PyErr_Format(PyExc_TypeError,
+ "List entry must be of type 'MaterialFilter' not '%s'",
+ obj->ob_type->tp_name);
+ return nullptr;
+ }
+ }
+ getMaterialTreeWidgetPtr()->setFilter(filterList);
+ }
+ else {
+ PyErr_Format(PyExc_TypeError,
+ "Type must be 'MaterialFilter' or list of 'MaterialFilter' not '%s'",
+ obj->ob_type->tp_name);
+ return nullptr;
+ }
+
+ Py_Return;
+}
+
+PyObject* MaterialTreeWidgetPy::selectFilter(PyObject* args)
+{
+ char* name;
+ if (!PyArg_ParseTuple(args, "s", &name)) {
+ return nullptr;
+ }
+
+ Base::Console().Log("selectFilter(%s)\n", name);
+
+ Py_Return;
+}
+
+PyObject* MaterialTreeWidgetPy::getCustomAttributes(const char* /*attr*/) const
+{
+ return nullptr;
+}
+
+int MaterialTreeWidgetPy::setCustomAttributes(const char* /*attr*/, PyObject* /*obj*/)
+{
+ return 0;
+}