From 3dd6a678042bed5a8a22627bfd4d24032d6f5f36 Mon Sep 17 00:00:00 2001 From: David Carter Date: Sun, 3 Dec 2023 13:22:43 -0500 Subject: [PATCH] Material: Material editor enhancements Continues the work of the material subsystem improvements. This merge covers the continued development of the material editor. The primary improvements are the addition of new data types, a new appearance preview UI, and changes in the array data types. New data types were added to support more advanced workflows, such as the Render Workbench.The Image datatype allows the material to embed the image in the card instead of pointing to an image in an external file. Multi-buyte strings span multiple lines as the name implies. It preserves formatting accross those lines. Also several list types are now supported, with the primary difference being the editors. List is a list of strings, FileList is a list of file path names, and ImageList is a list of embedded images. For the appearance preview, the UI now uses the same Coin library as is used in the documents, meaning the preview will look exactly the same as the material will be shown in the documents. The array data types are now more complete. The default value wasn't being used as originially envisioned and was tehrefore removed. For 3D arrays, the Python API was implemented. There were a lot of code clean ups. This involved removing logging statements used for debugging during development, reduction of lint warnings, and code refactoring. The editor can automatically convert from previous format files to the current format. This has been extended to material files generated by the Render WB. Old format files are displayed in the editor with a warning icon. Selecting one will require saving the file in the new format before it can be used. --- src/Gui/View3DSettings.h | 18 +- src/Mod/Material/App/Array2DPy.xml | 15 +- src/Mod/Material/App/Array2DPyImpl.cpp | 71 +- src/Mod/Material/App/Array3DPy.xml | 52 ++ src/Mod/Material/App/Array3DPyImpl.cpp | 152 ++++ src/Mod/Material/App/CMakeLists.txt | 3 + src/Mod/Material/App/Exceptions.h | 64 +- src/Mod/Material/App/MaterialConfigLoader.cpp | 803 ++++++++++++++++-- src/Mod/Material/App/MaterialConfigLoader.h | 107 ++- src/Mod/Material/App/MaterialLibrary.cpp | 77 +- src/Mod/Material/App/MaterialLibrary.h | 11 +- src/Mod/Material/App/MaterialLoader.cpp | 203 +++-- src/Mod/Material/App/MaterialLoader.h | 41 +- src/Mod/Material/App/MaterialManager.cpp | 58 +- src/Mod/Material/App/MaterialManager.h | 39 +- src/Mod/Material/App/MaterialPyImpl.cpp | 46 +- src/Mod/Material/App/MaterialValue.cpp | 301 ++++--- src/Mod/Material/App/MaterialValue.h | 136 ++- src/Mod/Material/App/Materials.cpp | 70 +- src/Mod/Material/App/Materials.h | 11 +- src/Mod/Material/App/ModelLibrary.cpp | 24 +- src/Mod/Material/App/ModelLibrary.h | 2 +- src/Mod/Material/App/ModelManager.cpp | 11 - src/Mod/Material/App/ModelUuids.cpp | 39 +- src/Mod/Material/App/ModelUuids.h | 20 +- src/Mod/Material/App/UUIDsPy.xml | 108 +++ src/Mod/Material/App/UUIDsPyImpl.cpp | 90 ++ src/Mod/Material/CMakeLists.txt | 2 +- src/Mod/Material/Gui/AppearancePreview.cpp | 225 +++++ src/Mod/Material/Gui/AppearancePreview.h | 77 ++ src/Mod/Material/Gui/Array2D.cpp | 56 +- src/Mod/Material/Gui/Array2D.h | 4 +- src/Mod/Material/Gui/Array2D.ui | 25 - src/Mod/Material/Gui/Array3D.cpp | 68 +- src/Mod/Material/Gui/Array3D.h | 4 +- src/Mod/Material/Gui/Array3D.ui | 31 - src/Mod/Material/Gui/ArrayDelegate.cpp | 38 +- src/Mod/Material/Gui/ArrayDelegate.h | 8 +- src/Mod/Material/Gui/ArrayModel.cpp | 109 +-- src/Mod/Material/Gui/ArrayModel.h | 15 +- src/Mod/Material/Gui/BaseDelegate.cpp | 421 +++++++++ src/Mod/Material/Gui/BaseDelegate.h | 95 +++ src/Mod/Material/Gui/CMakeLists.txt | 20 +- src/Mod/Material/Gui/ImageEdit.cpp | 163 ++++ src/Mod/Material/Gui/ImageEdit.h | 91 ++ src/Mod/Material/Gui/ImageEdit.ui | 230 +++++ src/Mod/Material/Gui/ListDelegate.cpp | 111 +++ src/Mod/Material/Gui/ListDelegate.h | 59 ++ src/Mod/Material/Gui/ListEdit.cpp | 60 +- src/Mod/Material/Gui/ListEdit.h | 5 +- src/Mod/Material/Gui/ListModel.cpp | 26 +- src/Mod/Material/Gui/MaterialDelegate.cpp | 164 ++-- src/Mod/Material/Gui/MaterialDelegate.h | 3 +- src/Mod/Material/Gui/MaterialSave.cpp | 47 +- src/Mod/Material/Gui/MaterialSave.h | 3 +- src/Mod/Material/Gui/MaterialsEditor.cpp | 315 ++++--- src/Mod/Material/Gui/MaterialsEditor.h | 36 +- src/Mod/Material/Gui/ModelSelect.cpp | 20 +- src/Mod/Material/Gui/Resources/Material.qrc | 1 + .../Gui/Resources/images/default_image.png | Bin 0 -> 9907 bytes src/Mod/Material/Gui/TextEdit.cpp | 4 +- src/Mod/Material/Gui/TextEdit.h | 2 +- .../Materials/Test/Test Material.FCMat | 5 +- .../Models/Architectural/Architectural.yml | 10 - .../Architectural/ArchitecturalRendering.yml | 39 + .../Resources/Models/Test/Test Model.yml | 17 +- .../Material/materialtests/TestMaterials.py | 223 ++++- src/Mod/Material/materialtests/TestModels.py | 20 + .../Mod/Material/App/TestMaterialCards.cpp | 93 +- .../Material/App/TestMaterialProperties.cpp | 10 - .../Mod/Material/App/TestMaterialValue.cpp | 26 +- tests/src/Mod/Material/App/TestMaterials.cpp | 29 + 72 files changed, 4248 insertions(+), 1334 deletions(-) create mode 100644 src/Mod/Material/App/Array3DPy.xml create mode 100644 src/Mod/Material/App/Array3DPyImpl.cpp create mode 100644 src/Mod/Material/Gui/AppearancePreview.cpp create mode 100644 src/Mod/Material/Gui/AppearancePreview.h create mode 100644 src/Mod/Material/Gui/BaseDelegate.cpp create mode 100644 src/Mod/Material/Gui/BaseDelegate.h create mode 100644 src/Mod/Material/Gui/ImageEdit.cpp create mode 100644 src/Mod/Material/Gui/ImageEdit.h create mode 100644 src/Mod/Material/Gui/ImageEdit.ui create mode 100644 src/Mod/Material/Gui/ListDelegate.cpp create mode 100644 src/Mod/Material/Gui/ListDelegate.h create mode 100644 src/Mod/Material/Gui/Resources/images/default_image.png create mode 100644 src/Mod/Material/Resources/Models/Architectural/ArchitecturalRendering.yml diff --git a/src/Gui/View3DSettings.h b/src/Gui/View3DSettings.h index eddea34ea3..4c3798f077 100644 --- a/src/Gui/View3DSettings.h +++ b/src/Gui/View3DSettings.h @@ -26,18 +26,19 @@ #include #include -namespace Gui { +namespace Gui +{ class View3DInventorViewer; -class View3DSettings : public ParameterGrp::ObserverType +class GuiExport View3DSettings: public ParameterGrp::ObserverType { public: - View3DSettings(ParameterGrp::handle hGrp, View3DInventorViewer *); - View3DSettings(ParameterGrp::handle hGrp, const std::vector&); + View3DSettings(ParameterGrp::handle hGrp, View3DInventorViewer*); + View3DSettings(ParameterGrp::handle hGrp, const std::vector&); ~View3DSettings() override; /// Observer message from the ParameterGrp - void OnChange(ParameterGrp::SubjectType &rCaller,ParameterGrp::MessageType Reason) override; + void OnChange(ParameterGrp::SubjectType& rCaller, ParameterGrp::MessageType Reason) override; void applySettings(); int stopAnimatingIfDeactivated() const; @@ -56,17 +57,18 @@ class NaviCubeSettings { Q_DECLARE_TR_FUNCTIONS(NaviCubeSettings) public: - NaviCubeSettings(ParameterGrp::handle hGrp, View3DInventorViewer *); + NaviCubeSettings(ParameterGrp::handle hGrp, View3DInventorViewer*); ~NaviCubeSettings(); void applySettings(); + private: void parameterChanged(ParameterGrp::MessageType pName); ParameterGrp::handle hGrp; - View3DInventorViewer * _viewer; + View3DInventorViewer* _viewer; boost::signals2::connection connectParameterChanged; }; -} // namespace Gui +} // namespace Gui #endif // GUI_VIEW3DSETTINGS_H diff --git a/src/Mod/Material/App/Array2DPy.xml b/src/Mod/Material/App/Array2DPy.xml index ba6f5f965f..c4d066b17b 100644 --- a/src/Mod/Material/App/Array2DPy.xml +++ b/src/Mod/Material/App/Array2DPy.xml @@ -15,6 +15,12 @@ 2D Array of material properties. + + + The 2 dimensional array. + + + The number of rows in the array. @@ -27,9 +33,14 @@ - + - Get the default value for the first column of the array + Get the row given the first column value + + + + + Get the value at the given row and column diff --git a/src/Mod/Material/App/Array2DPyImpl.cpp b/src/Mod/Material/App/Array2DPyImpl.cpp index 02ef6e5465..706f62ddde 100644 --- a/src/Mod/Material/App/Array2DPyImpl.cpp +++ b/src/Mod/Material/App/Array2DPyImpl.cpp @@ -21,7 +21,16 @@ #include "PreCompiled.h" +#include +#include + +#include +#include +#include +#include + #include "Array2DPy.h" +#include "Exceptions.h" #include "Model.h" #include "ModelLibrary.h" #include "ModelPropertyPy.h" @@ -52,6 +61,25 @@ int Array2DPy::PyInit(PyObject* /*args*/, PyObject* /*kwd*/) return 0; } +Py::List Array2DPy::getArray() const +{ + Py::List list; + auto array = getMaterial2DArrayPtr()->getArray(); + + for (auto& row : array) { + Py::List* rowList = new Py::List(); + for (auto& column : *row) { + auto quantity = + new Base::QuantityPy(new Base::Quantity(column.value())); + rowList->append(Py::Object(quantity)); + } + + list.append(*rowList); + } + + return list; +} + Py::Int Array2DPy::getRows() const { return Py::Int(getMaterial2DArrayPtr()->rows()); @@ -62,15 +90,48 @@ Py::Int Array2DPy::getColumns() const return Py::Int(getMaterial2DArrayPtr()->columns()); } -PyObject* Array2DPy::getDefaultValue(PyObject* args) +PyObject* Array2DPy::getRow(PyObject* args) { - char* name; - if (!PyArg_ParseTuple(args, "s", &name)) { + int row; + if (!PyArg_ParseTuple(args, "i", &row)) { return nullptr; } - // QVariant value = getMaterial2DArrayPtr()->getPhysicalValue(QString::fromStdString(name)); - // return _pyObjectFromVariant(value); + try { + Py::List list; + + auto arrayRow = getMaterial2DArrayPtr()->getRow(row); + for (auto& column : *arrayRow) { + auto quantity = + new Base::QuantityPy(new Base::Quantity(column.value())); + list.append(Py::Object(quantity)); + } + + return Py::new_reference_to(list); + } + catch (const InvalidIndex&) { + } + + PyErr_SetString(PyExc_IndexError, "Invalid array index"); + return nullptr; +} + +PyObject* Array2DPy::getValue(PyObject* args) +{ + int row; + int column; + if (!PyArg_ParseTuple(args, "ii", &row, &column)) { + return nullptr; + } + + try { + auto value = getMaterial2DArrayPtr()->getValue(row, column); + return new Base::QuantityPy(new Base::Quantity(value.value())); + } + catch (const InvalidIndex&) { + } + + PyErr_SetString(PyExc_IndexError, "Invalid array index"); return nullptr; } diff --git a/src/Mod/Material/App/Array3DPy.xml b/src/Mod/Material/App/Array3DPy.xml new file mode 100644 index 0000000000..b6d55f42ed --- /dev/null +++ b/src/Mod/Material/App/Array3DPy.xml @@ -0,0 +1,52 @@ + + + + + + 3D Array of material properties. + + + + The 3 dimensional array. + + + + + + The number of columns in the array. + + + + + + The depth of the array (3rd dimension). + + + + + + Get the number of rows in the array at the specified depth. + + + + + Get the value at the given row and column + + + + + Get the column value at the given depth + + + + diff --git a/src/Mod/Material/App/Array3DPyImpl.cpp b/src/Mod/Material/App/Array3DPyImpl.cpp new file mode 100644 index 0000000000..e4650c5930 --- /dev/null +++ b/src/Mod/Material/App/Array3DPyImpl.cpp @@ -0,0 +1,152 @@ +/*************************************************************************** + * 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 + +#include +#include +#include +#include + +#include "Array3DPy.h" +#include "Exceptions.h" +#include "Model.h" +#include "ModelLibrary.h" +#include "ModelPropertyPy.h" +#include "ModelUuids.h" + +#include "Array3DPy.cpp" + +using namespace Materials; + +// returns a string which represents the object e.g. when printed in python +std::string Array3DPy::representation() const +{ + std::stringstream str; + str << ""; + + return str.str(); +} + +PyObject* Array3DPy::PyMake(struct _typeobject*, PyObject*, PyObject*) // Python wrapper +{ + // never create such objects with the constructor + return new Array3DPy(new Material3DArray()); +} + +// constructor method +int Array3DPy::PyInit(PyObject* /*args*/, PyObject* /*kwd*/) +{ + return 0; +} + +Py::List Array3DPy::getArray() const +{ + Py::List list; + auto array = getMaterial3DArrayPtr()->getArray(); + + for (auto& depth : array) { + Py::List* depthList = new Py::List(); + for (auto& row : *std::get<1>(depth)) { + Py::List* rowList = new Py::List(); + for (auto& column : *row) { + auto quantity = new Base::QuantityPy(new Base::Quantity(column)); + rowList->append(Py::Object(quantity)); + } + + depthList->append(*rowList); + } + list.append(*depthList); + } + + return list; +} + +Py::Int Array3DPy::getColumns() const +{ + return Py::Int(getMaterial3DArrayPtr()->columns()); +} + +Py::Int Array3DPy::getDepth() const +{ + return Py::Int(getMaterial3DArrayPtr()->depth()); +} + +PyObject* Array3DPy::getRows(PyObject* args) +{ + int depth = getMaterial3DArrayPtr()->currentDepth(); + if (!PyArg_ParseTuple(args, "|i", &depth)) { + return nullptr; + } + + return PyLong_FromLong(getMaterial3DArrayPtr()->rows(depth)); +} + +PyObject* Array3DPy::getValue(PyObject* args) +{ + int depth; + int row; + int column; + if (!PyArg_ParseTuple(args, "iii", &depth, &row, &column)) { + return nullptr; + } + + try { + auto value = getMaterial3DArrayPtr()->getValue(depth, row, column); + return new Base::QuantityPy(new Base::Quantity(value)); + } + catch (const InvalidIndex&) { + } + + PyErr_SetString(PyExc_IndexError, "Invalid array index"); + return nullptr; +} + +PyObject* Array3DPy::getDepthValue(PyObject* args) +{ + int depth; + if (!PyArg_ParseTuple(args, "i", &depth)) { + return nullptr; + } + + try { + auto value = getMaterial3DArrayPtr()->getDepthValue(depth); + return new Base::QuantityPy(new Base::Quantity(value)); + } + catch (const InvalidIndex&) { + } + + PyErr_SetString(PyExc_IndexError, "Invalid array index"); + return nullptr; +} + +PyObject* Array3DPy::getCustomAttributes(const char* /*attr*/) const +{ + return nullptr; +} + +int Array3DPy::setCustomAttributes(const char* /*attr*/, PyObject* /*obj*/) +{ + return 0; +} diff --git a/src/Mod/Material/App/CMakeLists.txt b/src/Mod/Material/App/CMakeLists.txt index ab2bc85745..4f04e494a6 100644 --- a/src/Mod/Material/App/CMakeLists.txt +++ b/src/Mod/Material/App/CMakeLists.txt @@ -34,6 +34,7 @@ list(APPEND Material_LIBS ) generate_from_xml(Array2DPy) +generate_from_xml(Array3DPy) generate_from_xml(MaterialManagerPy) generate_from_xml(MaterialPy) generate_from_xml(ModelManagerPy) @@ -45,6 +46,8 @@ SET(Python_SRCS Exceptions.h Array2DPy.xml Array2DPyImpl.cpp + Array3DPy.xml + Array3DPyImpl.cpp MaterialManagerPy.xml MaterialManagerPyImpl.cpp MaterialPy.xml diff --git a/src/Mod/Material/App/Exceptions.h b/src/Mod/Material/App/Exceptions.h index 49152cd263..c27adbdf24 100644 --- a/src/Mod/Material/App/Exceptions.h +++ b/src/Mod/Material/App/Exceptions.h @@ -110,6 +110,22 @@ public: ~MaterialExists() noexcept override = default; }; +class MaterialReadError: public Base::Exception +{ +public: + MaterialReadError() + {} + explicit MaterialReadError(const char* msg) + { + this->setMessage(msg); + } + explicit MaterialReadError(const QString& msg) + { + this->setMessage(msg.toStdString().c_str()); + } + ~MaterialReadError() noexcept override = default; +}; + class PropertyNotFound: public Base::Exception { public: @@ -158,54 +174,6 @@ public: ~InvalidModel() noexcept override = default; }; -class InvalidRow: public Base::Exception -{ -public: - InvalidRow() - {} - explicit InvalidRow(char* msg) - { - this->setMessage(msg); - } - explicit InvalidRow(const QString& msg) - { - this->setMessage(msg.toStdString().c_str()); - } - ~InvalidRow() noexcept override = default; -}; - -class InvalidColumn: public Base::Exception -{ -public: - InvalidColumn() - {} - explicit InvalidColumn(char* msg) - { - this->setMessage(msg); - } - explicit InvalidColumn(const QString& msg) - { - this->setMessage(msg.toStdString().c_str()); - } - ~InvalidColumn() noexcept override = default; -}; - -class InvalidDepth: public Base::Exception -{ -public: - InvalidDepth() - {} - explicit InvalidDepth(char* msg) - { - this->setMessage(msg); - } - explicit InvalidDepth(const QString& msg) - { - this->setMessage(msg.toStdString().c_str()); - } - ~InvalidDepth() noexcept override = default; -}; - class InvalidIndex: public Base::Exception { public: diff --git a/src/Mod/Material/App/MaterialConfigLoader.cpp b/src/Mod/Material/App/MaterialConfigLoader.cpp index 492730f2ec..449c00e571 100644 --- a/src/Mod/Material/App/MaterialConfigLoader.cpp +++ b/src/Mod/Material/App/MaterialConfigLoader.cpp @@ -26,6 +26,11 @@ #include #endif +#include + +#include +#include +#include #include #include @@ -33,6 +38,7 @@ #include +#include "Exceptions.h" #include "MaterialConfigLoader.h" #include "MaterialLoader.h" #include "Model.h" @@ -41,27 +47,117 @@ using namespace Materials; -MaterialConfigLoader::MaterialConfigLoader() -{} - bool MaterialConfigLoader::isConfigStyle(const QString& path) { - std::ifstream infile(path.toStdString()); + QSettings fcmat(path, QSettings::IniFormat); - // Check the first 2 lines for a ";" - for (int i = 0; i < 2; i++) { - std::string line; - if (!std::getline(infile, line)) { - return false; - } - if (line.at(0) != ';') { - return false; - } + // No [sections] means not .ini + if (fcmat.childGroups().empty()) { + return false; } + // Sometimes arrays can create a false positive + QFile infile(path); + if (infile.open(QIODevice::ReadOnly)) { + QTextStream in(&infile); + + if (!in.atEnd()) { + auto line = in.readLine(); + if (line.trimmed().startsWith(QLatin1Char('-')) + || line.trimmed().startsWith(QLatin1Char('#'))) { + // Definitely a YAML file + return false; + } + } + } + infile.close(); + + // No false positive return true; } +bool MaterialConfigLoader::readFile(const QString& path, QMap& map) +{ + // This function is necessary as the built in routines don't always return the full value string + QFile infile(path); + if (infile.open(QIODevice::ReadOnly)) { + QTextStream in(&infile); + in.setCodec("UTF-8"); + + QString line; + QString prefix; + while (!in.atEnd()) { + line = in.readLine(); + if (line.trimmed().startsWith(QLatin1Char(';'))) { + continue; + } + + if (line.startsWith(QLatin1Char('['))) { + // read prefix + auto end = line.indexOf(QLatin1Char(']')); + if (end > 1) { + prefix = line.mid(1, end - 1) + QString::fromStdString("/"); + + // Render WB uses both Render and Rendering + if (prefix == QString::fromStdString("Rendering/")) { + prefix = QString::fromStdString("Render/"); + } + } + } + else { + auto separator = line.indexOf(QLatin1Char('=')); + if (separator > 2) { + auto left = line.mid(0, separator - 1); + auto right = line.mid(separator + 2); + map[prefix + left] = right; + } + } + } + infile.close(); + return true; + } + + return false; +} + +void MaterialConfigLoader::splitTexture(const QString& value, QString* texture, QString* remain) +{ + // Split Texture(...);(...) into its two pieces + if (value.contains(QLatin1Char(';'))) { + auto separator = value.indexOf(QLatin1Char(';')); + auto left = value.mid(0, separator); + auto right = value.mid(separator + 1); + if (isTexture(left)) { + *texture = left; + *remain = right; + } + else { + *texture = right; + *remain = left; + } + } + else { + if (isTexture(value)) { + *texture = value; + } + else { + *remain = value; + } + } +} + +void MaterialConfigLoader::splitTextureObject(const QString& value, + QString* texture, + QString* remain, + QString* object) +{ + splitTexture(value, texture, remain); + if (*remain == QString::fromStdString("Object")) { + *remain = QString(); // Empty string + *object = QString::fromStdString("true"); + } +} + QString MaterialConfigLoader::getAuthorAndLicense(const QString& path) { std::ifstream infile(path.toStdString()); @@ -77,7 +173,7 @@ QString MaterialConfigLoader::getAuthorAndLicense(const QString& path) if (!std::getline(infile, line)) { return noAuthor; } - std::size_t found = line.find(";"); + std::size_t found = line.find(';'); if (found != std::string::npos) { return QString::fromStdString(trim_copy(line.substr(found + 1))); } @@ -85,8 +181,8 @@ QString MaterialConfigLoader::getAuthorAndLicense(const QString& path) return noAuthor; } -void MaterialConfigLoader::addVectorRendering(const QSettings& fcmat, - std::shared_ptr finalModel) +void MaterialConfigLoader::addVectorRendering(const QMap& fcmat, + const std::shared_ptr& finalModel) { QString sectionFillPattern = value(fcmat, "VectorRendering/SectionFillPattern", ""); QString sectionLinewidth = value(fcmat, "VectorRendering/SectionLinewidth", ""); @@ -95,23 +191,30 @@ void MaterialConfigLoader::addVectorRendering(const QSettings& fcmat, QString viewFillPattern = value(fcmat, "VectorRendering/ViewFillPattern", ""); QString viewLinewidth = value(fcmat, "VectorRendering/ViewLinewidth", ""); + // Defined by the Render WB + QString aSection = value(fcmat, "Architectural/SectionColor", ""); + + if (!aSection.isEmpty()) { + sectionColor = aSection; + } + if (sectionFillPattern.length() + sectionLinewidth.length() + sectionColor.length() + viewColor.length() + viewFillPattern.length() + viewLinewidth.length() > 0) { finalModel->addAppearance(ModelUUIDs::ModelUUID_Rendering_Vector); - } - // Now add the data - setAppearanceValue(finalModel, "SectionFillPattern", sectionFillPattern); - setAppearanceValue(finalModel, "SectionLinewidth", sectionLinewidth); - setAppearanceValue(finalModel, "SectionColor", sectionColor); - setAppearanceValue(finalModel, "ViewColor", viewColor); - setAppearanceValue(finalModel, "ViewFillPattern", viewFillPattern); - setAppearanceValue(finalModel, "ViewLinewidth", viewLinewidth); + // Now add the data + setAppearanceValue(finalModel, "SectionFillPattern", sectionFillPattern); + setAppearanceValue(finalModel, "SectionLinewidth", sectionLinewidth); + setAppearanceValue(finalModel, "SectionColor", sectionColor); + setAppearanceValue(finalModel, "ViewColor", viewColor); + setAppearanceValue(finalModel, "ViewFillPattern", viewFillPattern); + setAppearanceValue(finalModel, "ViewLinewidth", viewLinewidth); + } } -void MaterialConfigLoader::addRendering(const QSettings& fcmat, - std::shared_ptr finalModel) +void MaterialConfigLoader::addRendering(const QMap& fcmat, + const std::shared_ptr& finalModel) { QString ambientColor = value(fcmat, "Rendering/AmbientColor", ""); QString diffuseColor = value(fcmat, "Rendering/DiffuseColor", ""); @@ -124,6 +227,17 @@ void MaterialConfigLoader::addRendering(const QSettings& fcmat, QString fragmentShader = value(fcmat, "Rendering/FragmentShader", ""); QString vertexShader = value(fcmat, "Rendering/VertexShader", ""); + // Defined by the Render WB + QString aDiffuse = value(fcmat, "Architectural/DiffuseColor", ""); + QString aTransparency = value(fcmat, "Architectural/Transparency", ""); + + if (!aDiffuse.isEmpty()) { + diffuseColor = aDiffuse; + } + if (!aTransparency.isEmpty()) { + transparency = aTransparency; + } + // Check which model we need bool useTexture = false; bool useAdvanced = false; @@ -163,7 +277,565 @@ void MaterialConfigLoader::addRendering(const QSettings& fcmat, setAppearanceValue(finalModel, "VertexShader", vertexShader); } -void MaterialConfigLoader::addCosts(const QSettings& fcmat, std::shared_ptr finalModel) +QString MaterialConfigLoader::multiLineKey(QMap& fcmat, const QString& prefix) +{ + // fcmat.beginGroup(QString::fromStdString("Render")); + QString multiLineString; + auto keys = fcmat.keys(); + for (const auto& key : keys) { + if (key.startsWith(prefix) || key.startsWith(QString::fromStdString("Render/") + prefix)) { + QString string = value(fcmat, key.toStdString(), ""); + if (multiLineString.isEmpty()) { + multiLineString += string; + } + else { + multiLineString += QString::fromStdString("\n") + string; + } + } + } + // fcmat.endGroup(); + + return multiLineString; +} + +void MaterialConfigLoader::addRenderAppleseed(QMap& fcmat, + const std::shared_ptr& finalModel) +{ + QString prefix = QString::fromStdString("Render.Appleseed"); + QString string = multiLineKey(fcmat, prefix); + + if (!string.isEmpty()) { + finalModel->addAppearance(ModelUUIDs::ModelUUID_Render_Appleseed); + + // Now add the data + setAppearanceValue(finalModel, "Render.Appleseed", string); + } +} + +void MaterialConfigLoader::addRenderCarpaint(QMap& fcmat, + const std::shared_ptr& finalModel) +{ + QString renderBaseColorValue = value(fcmat, "Render/Render.Carpaint.BaseColor", ""); + QString renderBump = value(fcmat, "Render/Render.Carpaint.Bump", ""); + QString renderDisplacement = value(fcmat, "Render/Render.Carpaint.Displacement", ""); + QString renderNormal = value(fcmat, "Render/Render.Carpaint.Normal", ""); + + // Split out the textures + QString renderBaseColor; + QString renderBaseColorTexture; + QString renderBaseColorObject; + splitTextureObject(renderBaseColorValue, + &renderBaseColorTexture, + &renderBaseColor, + &renderBaseColorObject); + + if (!renderBaseColorValue.isEmpty() || !renderBump.isEmpty() || !renderDisplacement.isEmpty() + || !renderNormal.isEmpty()) { + finalModel->addAppearance(ModelUUIDs::ModelUUID_Render_Carpaint); + + // Now add the data + setAppearanceValue(finalModel, "Render.Carpaint.BaseColor", renderBaseColor); + setAppearanceValue(finalModel, "Render.Carpaint.BaseColor.Texture", renderBaseColorTexture); + setAppearanceValue(finalModel, "Render.Carpaint.BaseColor.Object", renderBaseColorObject); + setAppearanceValue(finalModel, "Render.Carpaint.Bump", renderBump); + setAppearanceValue(finalModel, "Render.Carpaint.Displacement", renderDisplacement); + setAppearanceValue(finalModel, "Render.Carpaint.Normal", renderNormal); + } +} + +void MaterialConfigLoader::addRenderCycles(QMap& fcmat, + const std::shared_ptr& finalModel) +{ + QString prefix = QString::fromStdString("Render.Cycles"); + QString string = multiLineKey(fcmat, prefix); + if (!string.isEmpty()) { + finalModel->addAppearance(ModelUUIDs::ModelUUID_Render_Cycles); + + // Now add the data + setAppearanceValue(finalModel, "Render.Cycles", string); + } +} + +void MaterialConfigLoader::addRenderDiffuse(QMap& fcmat, + const std::shared_ptr& finalModel) +{ + QString renderBump = value(fcmat, "Render/Render.Diffuse.Bump", ""); + QString renderColorValue = value(fcmat, "Render/Render.Diffuse.Color", ""); + QString renderDisplacement = value(fcmat, "Render/Render.Diffuse.Displacement", ""); + QString renderNormal = value(fcmat, "Render/Render.Diffuse.Normal", ""); + + // Split out the textures + QString renderColor; + QString renderColorTexture; + QString renderColorObject; + splitTextureObject(renderColorValue, &renderColorTexture, &renderColor, &renderColorObject); + + if (!renderBump.isEmpty() || !renderColorValue.isEmpty() || !renderDisplacement.isEmpty() + || !renderNormal.isEmpty()) { + finalModel->addAppearance(ModelUUIDs::ModelUUID_Render_Diffuse); + + // Now add the data + setAppearanceValue(finalModel, "Render.Diffuse.Bump", renderBump); + setAppearanceValue(finalModel, "Render.Diffuse.Color", renderColor); + setAppearanceValue(finalModel, "Render.Diffuse.Color.Texture", renderColorTexture); + setAppearanceValue(finalModel, "Render.Diffuse.Color.Object", renderColorObject); + setAppearanceValue(finalModel, "Render.Diffuse.Displacement", renderDisplacement); + setAppearanceValue(finalModel, "Render.Diffuse.Normal", renderNormal); + } +} + +void MaterialConfigLoader::addRenderDisney(QMap& fcmat, + const std::shared_ptr& finalModel) +{ + QString renderAnisotropicValue = value(fcmat, "Render/Render.Disney.Anisotropic", ""); + QString renderBaseColorValue = value(fcmat, "Render/Render.Disney.BaseColor", ""); + QString renderBump = value(fcmat, "Render/Render.Disney.Bump", ""); + QString renderClearCoatValue = value(fcmat, "Render/Render.Disney.ClearCoat", ""); + QString renderClearCoatGlossValue = value(fcmat, "Render/Render.Disney.ClearCoatGloss", ""); + QString renderDisplacement = value(fcmat, "Render/Render.Disney.Displacement", ""); + QString renderMetallicValue = value(fcmat, "Render/Render.Disney.Metallic", ""); + QString renderNormal = value(fcmat, "Render/Render.Disney.Normal", ""); + QString renderRoughnessValue = value(fcmat, "Render/Render.Disney.Roughness", ""); + QString renderSheenValue = value(fcmat, "Render/Render.Disney.Sheen", ""); + QString renderSheenTintValue = value(fcmat, "Render/Render.Disney.SheenTint", ""); + QString renderSpecularValue = value(fcmat, "Render/Render.Disney.Specular", ""); + QString renderSpecularTintValue = value(fcmat, "Render/Render.Disney.SpecularTint", ""); + QString renderSubsurfaceValue = value(fcmat, "Render/Render.Disney.Subsurface", ""); + + // Split out the textures + QString renderAnisotropic; + QString renderAnisotropicTexture; + splitTexture(renderAnisotropicValue, &renderAnisotropicTexture, &renderAnisotropic); + QString renderBaseColor; + QString renderBaseColorTexture; + QString renderBaseColorObject; + splitTextureObject(renderBaseColorValue, + &renderBaseColorTexture, + &renderBaseColor, + &renderBaseColorObject); + QString renderClearCoat; + QString renderClearCoatTexture; + QString renderClearCoatObject; + splitTextureObject(renderClearCoatValue, + &renderClearCoatTexture, + &renderClearCoat, + &renderClearCoatObject); + QString renderClearCoatGloss; + QString renderClearCoatGlossTexture; + QString renderClearCoatGlossObject; + splitTextureObject(renderClearCoatGlossValue, + &renderClearCoatGlossTexture, + &renderClearCoatGloss, + &renderClearCoatGlossObject); + QString renderMetallic; + QString renderMetallicTexture; + splitTexture(renderMetallicValue, &renderMetallicTexture, &renderMetallic); + QString renderRoughness; + QString renderRoughnessTexture; + splitTexture(renderRoughnessValue, &renderRoughnessTexture, &renderRoughness); + QString renderSheen; + QString renderSheenTexture; + splitTexture(renderSheenValue, &renderSheenTexture, &renderSheen); + QString renderSheenTint; + QString renderSheenTintTexture; + splitTexture(renderSheenTintValue, &renderSheenTintTexture, &renderSheenTint); + QString renderSpecular; + QString renderSpecularTexture; + QString renderSpecularObject; + splitTextureObject(renderSpecularValue, + &renderSpecularTexture, + &renderSpecular, + &renderSpecularObject); + QString renderSpecularTint; + QString renderSpecularTintTexture; + QString renderSpecularTintObject; + splitTextureObject(renderSpecularTintValue, + &renderSpecularTintTexture, + &renderSpecularTint, + &renderSpecularTintObject); + QString renderSubsurface; + QString renderSubsurfaceTexture; + splitTexture(renderSubsurfaceValue, &renderSubsurfaceTexture, &renderSubsurface); + + if (!renderAnisotropicValue.isEmpty() || !renderBaseColorValue.isEmpty() + || !renderBump.isEmpty() || !renderClearCoatValue.isEmpty() + || !renderClearCoatGlossValue.isEmpty() || !renderDisplacement.isEmpty() + || !renderMetallicValue.isEmpty() || !renderNormal.isEmpty() + || !renderRoughnessValue.isEmpty() || !renderSheenValue.isEmpty() + || !renderSheenTintValue.isEmpty() || !renderSpecularValue.isEmpty() + || !renderSpecularTintValue.isEmpty() || !renderSubsurfaceValue.isEmpty()) { + finalModel->addAppearance(ModelUUIDs::ModelUUID_Render_Disney); + + // Now add the data + setAppearanceValue(finalModel, "Render.Disney.Anisotropic", renderAnisotropic); + setAppearanceValue(finalModel, + "Render.Disney.Anisotropic.Texture", + renderAnisotropicTexture); + setAppearanceValue(finalModel, "Render.Disney.BaseColor", renderBaseColor); + setAppearanceValue(finalModel, "Render.Disney.BaseColor.Texture", renderBaseColorTexture); + setAppearanceValue(finalModel, "Render.Disney.Bump", renderBump); + setAppearanceValue(finalModel, "Render.Disney.ClearCoat", renderClearCoat); + setAppearanceValue(finalModel, "Render.Disney.ClearCoat.Texture", renderClearCoatTexture); + setAppearanceValue(finalModel, "Render.Disney.ClearCoatGloss", renderClearCoatGloss); + setAppearanceValue(finalModel, + "Render.Disney.ClearCoatGloss.Texture", + renderClearCoatGlossTexture); + setAppearanceValue(finalModel, "Render.Disney.Displacement", renderDisplacement); + setAppearanceValue(finalModel, "Render.Disney.Metallic", renderMetallic); + setAppearanceValue(finalModel, "Render.Disney.Metallic.Texture", renderMetallicTexture); + setAppearanceValue(finalModel, "Render.Disney.Normal", renderNormal); + setAppearanceValue(finalModel, "Render.Disney.Roughness", renderRoughness); + setAppearanceValue(finalModel, "Render.Disney.Roughness.Texture", renderRoughnessTexture); + setAppearanceValue(finalModel, "Render.Disney.Sheen", renderSheen); + setAppearanceValue(finalModel, "Render.Disney.Sheen.Texture", renderSheenTexture); + setAppearanceValue(finalModel, "Render.Disney.SheenTint", renderSheenTint); + setAppearanceValue(finalModel, "Render.Disney.SheenTint.Texture", renderSheenTintTexture); + setAppearanceValue(finalModel, "Render.Disney.Specular", renderSpecular); + setAppearanceValue(finalModel, "Render.Disney.Specular.Texture", renderSpecularTexture); + setAppearanceValue(finalModel, "Render.Disney.SpecularTint", renderSpecularTint); + setAppearanceValue(finalModel, + "Render.Disney.SpecularTint.Texture", + renderSpecularTintTexture); + setAppearanceValue(finalModel, "Render.Disney.Subsurface", renderSubsurface); + setAppearanceValue(finalModel, "Render.Disney.Subsurface.Texture", renderSubsurfaceTexture); + } +} + +void MaterialConfigLoader::addRenderEmission(QMap& fcmat, + const std::shared_ptr& finalModel) +{ + QString renderBump = value(fcmat, "Render/Render.Emission.Bump", ""); + QString renderColorValue = value(fcmat, "Render/Render.Emission.Color", ""); + QString renderNormal = value(fcmat, "Render/Render.Emission.Normal", ""); + QString renderPowerValue = value(fcmat, "Render/Render.Emission.Power", ""); + + // Split out the textures + QString renderColor; + QString renderColorTexture; + QString renderColorObject; + splitTextureObject(renderColorValue, &renderColorTexture, &renderColor, &renderColorObject); + QString renderPower; + QString renderPowerTexture; + splitTexture(renderPowerValue, &renderPowerTexture, &renderPower); + + if (!renderColorValue.isEmpty() || !renderBump.isEmpty() || !renderPowerValue.isEmpty() + || !renderNormal.isEmpty()) { + finalModel->addAppearance(ModelUUIDs::ModelUUID_Render_Emission); + + // Now add the data + setAppearanceValue(finalModel, "Render.Emission.Bump", renderBump); + setAppearanceValue(finalModel, "Render.Emission.Color", renderColor); + setAppearanceValue(finalModel, "Render.Emission.Color.Texture", renderColorTexture); + setAppearanceValue(finalModel, "Render.Emission.Color.Object", renderColorObject); + setAppearanceValue(finalModel, "Render.Emission.Normal", renderNormal); + setAppearanceValue(finalModel, "Render.Emission.Power", renderPower); + setAppearanceValue(finalModel, "Render.Emission.Power.Texture", renderPowerTexture); + } +} + +void MaterialConfigLoader::addRenderGlass(QMap& fcmat, + const std::shared_ptr& finalModel) +{ + QString renderBump = value(fcmat, "Render/Render.Glass.Bump", ""); + QString renderColorValue = value(fcmat, "Render/Render.Glass.Color", ""); + QString renderIORValue = value(fcmat, "Render/Render.Glass.IOR", ""); + QString renderDisplacement = value(fcmat, "Render/Render.Glass.Displacement", ""); + QString renderNormal = value(fcmat, "Render/Render.Glass.Normal", ""); + + // Split out the textures + QString renderColor; + QString renderColorTexture; + QString renderColorObject; + splitTextureObject(renderColorValue, &renderColorTexture, &renderColor, &renderColorObject); + QString renderIOR; + QString renderIORTexture; + splitTexture(renderIORValue, &renderIORTexture, &renderIOR); + + if (!renderBump.isEmpty() || !renderColorValue.isEmpty() || !renderIORValue.isEmpty() + || !renderDisplacement.isEmpty() || !renderNormal.isEmpty()) { + finalModel->addAppearance(ModelUUIDs::ModelUUID_Render_Glass); + + setAppearanceValue(finalModel, "Render.Glass.Bump", renderBump); + setAppearanceValue(finalModel, "Render.Glass.Color", renderColor); + setAppearanceValue(finalModel, "Render.Glass.Color.Texture", renderColorTexture); + setAppearanceValue(finalModel, "Render.Glass.Color.Object", renderColorObject); + setAppearanceValue(finalModel, "Render.Glass.IOR", renderIOR); + setAppearanceValue(finalModel, "Render.Glass.IOR.Texture", renderIORTexture); + setAppearanceValue(finalModel, "Render.Glass.Displacement", renderDisplacement); + setAppearanceValue(finalModel, "Render.Glass.Normal", renderNormal); + } +} + +void MaterialConfigLoader::addRenderLuxcore(QMap& fcmat, + const std::shared_ptr& finalModel) +{ + QString prefix = QString::fromStdString("Render.Luxcore"); + QString string = multiLineKey(fcmat, prefix); + + if (!string.isEmpty()) { + finalModel->addAppearance(ModelUUIDs::ModelUUID_Render_Luxcore); + + // Now add the data + setAppearanceValue(finalModel, "Render.Luxcore", string); + } +} + +void MaterialConfigLoader::addRenderLuxrender(QMap& fcmat, + const std::shared_ptr& finalModel) +{ + QString prefix = QString::fromStdString("Render.Luxrender"); + QString string = multiLineKey(fcmat, prefix); + + if (!string.isEmpty()) { + finalModel->addAppearance(ModelUUIDs::ModelUUID_Render_Luxrender); + + // Now add the data + setAppearanceValue(finalModel, "Render.Luxrender", string); + } +} + +void MaterialConfigLoader::addRenderMixed(QMap& fcmat, + const std::shared_ptr& finalModel) +{ + QString renderBump = value(fcmat, "Render/Render.Mixed.Bump", ""); + QString renderDiffuseColorValue = value(fcmat, "Render/Render.Mixed.Diffuse.Color", ""); + QString renderDisplacement = value(fcmat, "Render/Render.Mixed.Displacement", ""); + QString renderGlassColorValue = value(fcmat, "Render/Render.Mixed.Glass.Color", ""); + QString renderGlassIORValue = value(fcmat, "Render/Render.Mixed.Glass.IOR", ""); + QString renderNormal = value(fcmat, "Render/Render.Mixed.Normal", ""); + QString renderTransparencyValue = value(fcmat, "Render/Render.Mixed.Transparency", ""); + + // Split out the textures + QString renderDiffuseColor; + QString renderDiffuseColorTexture; + QString renderDiffuseColorObject; + splitTextureObject(renderDiffuseColorValue, + &renderDiffuseColorTexture, + &renderDiffuseColor, + &renderDiffuseColorObject); + QString renderGlassColor; + QString renderGlassColorTexture; + QString renderGlassColorObject; + splitTextureObject(renderGlassColorValue, + &renderGlassColorTexture, + &renderGlassColor, + &renderGlassColorObject); + QString renderGlassIOR; + QString renderGlassIORTexture; + splitTexture(renderGlassIORValue, &renderGlassIORTexture, &renderGlassIOR); + QString renderTransparency; + QString renderTransparencyTexture; + splitTexture(renderTransparencyValue, &renderTransparencyTexture, &renderTransparency); + + if (!renderBump.isEmpty() || !renderDiffuseColorValue.isEmpty() || !renderDisplacement.isEmpty() + || !renderGlassColorValue.isEmpty() || !renderGlassIORValue.isEmpty() + || !renderNormal.isEmpty() || !renderTransparencyValue.isEmpty()) { + finalModel->addAppearance(ModelUUIDs::ModelUUID_Render_Mixed); + + // Now add the data + setAppearanceValue(finalModel, "Render.Mixed.Bump", renderBump); + setAppearanceValue(finalModel, "Render.Mixed.Diffuse.Color", renderDiffuseColor); + setAppearanceValue(finalModel, + "Render.Mixed.Diffuse.Color.Texture", + renderDiffuseColorTexture); + setAppearanceValue(finalModel, + "Render.Mixed.Diffuse.Color.Object", + renderDiffuseColorObject); + setAppearanceValue(finalModel, "Render.Mixed.Displacement", renderDisplacement); + setAppearanceValue(finalModel, "Render.Mixed.Glass.Color", renderGlassColor); + setAppearanceValue(finalModel, "Render.Mixed.Glass.Color.Texture", renderGlassColorTexture); + setAppearanceValue(finalModel, "Render.Mixed.Glass.Color.Object", renderGlassColorObject); + setAppearanceValue(finalModel, "Render.Mixed.Glass.IOR", renderGlassIOR); + setAppearanceValue(finalModel, "Render.Mixed.Glass.IOR.Texture", renderGlassIORTexture); + setAppearanceValue(finalModel, "Render.Mixed.Normal", renderNormal); + setAppearanceValue(finalModel, "Render.Mixed.Transparency", renderTransparency); + setAppearanceValue(finalModel, + "Render.Mixed.Transparency.Texture", + renderTransparencyTexture); + } +} + +void MaterialConfigLoader::addRenderOspray(QMap& fcmat, + const std::shared_ptr& finalModel) +{ + QString prefix = QString::fromStdString("Render.Ospray"); + QString string = multiLineKey(fcmat, prefix); + + if (!string.isEmpty()) { + finalModel->addAppearance(ModelUUIDs::ModelUUID_Render_Ospray); + + // Now add the data + setAppearanceValue(finalModel, "Render.Ospray", string); + } +} + +void MaterialConfigLoader::addRenderPbrt(QMap& fcmat, + const std::shared_ptr& finalModel) +{ + QString prefix = QString::fromStdString("Render.Pbrt"); + QString string = multiLineKey(fcmat, prefix); + + if (!string.isEmpty()) { + finalModel->addAppearance(ModelUUIDs::ModelUUID_Render_Pbrt); + + // Now add the data + setAppearanceValue(finalModel, "Render.Pbrt", string); + } +} + +void MaterialConfigLoader::addRenderPovray(QMap& fcmat, + const std::shared_ptr& finalModel) +{ + QString prefix = QString::fromStdString("Render.Povray"); + QString string = multiLineKey(fcmat, prefix); + + if (!string.isEmpty()) { + finalModel->addAppearance(ModelUUIDs::ModelUUID_Render_Povray); + + // Now add the data + setAppearanceValue(finalModel, "Render.Povray", string); + } +} + +void MaterialConfigLoader::addRenderSubstancePBR(QMap& fcmat, + const std::shared_ptr& finalModel) +{ + QString renderBaseColorValue = value(fcmat, "Render/Render.Substance_PBR.BaseColor", ""); + QString renderBump = value(fcmat, "Render/Render.Substance_PBR.Bump", ""); + QString renderMetallicValue = value(fcmat, "Render/Render.Substance_PBR.Metallic", ""); + QString renderNormal = value(fcmat, "Render/Render.Substance_PBR.Normal", ""); + QString renderRoughnessValue = value(fcmat, "Render/Render.Substance_PBR.Roughness", ""); + QString renderSpecularValue = value(fcmat, "Render/Render.Substance_PBR.Specular", ""); + + // Split out the textures + QString renderBaseColor; + QString renderBaseColorTexture; + QString renderBaseColorObject; + splitTextureObject(renderBaseColorValue, + &renderBaseColorTexture, + &renderBaseColor, + &renderBaseColorObject); + QString renderMetallic; + QString renderMetallicTexture; + splitTexture(renderMetallicValue, &renderMetallicTexture, &renderMetallic); + QString renderRoughness; + QString renderRoughnessTexture; + splitTexture(renderRoughnessValue, &renderRoughnessTexture, &renderRoughness); + QString renderSpecular; + QString renderSpecularTexture; + splitTexture(renderSpecularValue, &renderSpecularTexture, &renderSpecular); + + if (!renderBaseColorValue.isEmpty() || !renderBump.isEmpty() || !renderMetallicValue.isEmpty() + || !renderNormal.isEmpty() || !renderRoughnessValue.isEmpty() + || !renderSpecularValue.isEmpty()) { + finalModel->addAppearance(ModelUUIDs::ModelUUID_Render_SubstancePBR); + + // Now add the data + setAppearanceValue(finalModel, "Render.Substance_PBR.BaseColor", renderBaseColor); + setAppearanceValue(finalModel, + "Render.Substance_PBR.BaseColor.Texture", + renderBaseColorTexture); + setAppearanceValue(finalModel, + "Render.Substance_PBR.BaseColor.Object", + renderBaseColorObject); + setAppearanceValue(finalModel, "Render.Substance_PBR.Bump", renderBump); + setAppearanceValue(finalModel, "Render.Substance_PBR.Metallic", renderMetallic); + setAppearanceValue(finalModel, + "Render.Substance_PBR.Metallic.Texture", + renderMetallicTexture); + setAppearanceValue(finalModel, "Render.Substance_PBR.Normal", renderNormal); + setAppearanceValue(finalModel, "Render.Substance_PBR.Roughness", renderRoughness); + setAppearanceValue(finalModel, + "Render.Substance_PBR.Roughness.Texture", + renderRoughnessTexture); + setAppearanceValue(finalModel, "Render.Substance_PBR.Specular", renderSpecular); + setAppearanceValue(finalModel, + "Render.Substance_PBR.Specular.Texture", + renderSpecularTexture); + } +} + +void MaterialConfigLoader::addRenderTexture(QMap& fcmat, + const std::shared_ptr& finalModel) +{ + QString renderName; + auto renderImage = std::make_shared>(); + QString renderScale; + QString renderRotation; + QString renderTranslationU; + QString renderTranslationV; + + auto keys = fcmat.keys(); + for (const auto& key : keys) { + if (key.startsWith(QString::fromStdString("Render/Render.Textures."))) { + QStringList list1 = key.split(QLatin1Char('.')); + if (renderName.isEmpty()) { + renderName = list1[2]; + } + if (list1[3] == QString::fromStdString("Images")) { + renderImage->push_back(value(fcmat, key.toStdString(), "")); + } + else if (list1[3] == QString::fromStdString("Scale")) { + renderScale = value(fcmat, key.toStdString(), ""); + } + else if (list1[3] == QString::fromStdString("Rotation")) { + renderRotation = value(fcmat, key.toStdString(), ""); + } + else if (list1[3] == QString::fromStdString("TranslationU")) { + renderTranslationU = value(fcmat, key.toStdString(), ""); + } + else if (list1[3] == QString::fromStdString(" TranslationV")) { + renderTranslationV = value(fcmat, key.toStdString(), ""); + } + } + } + + if (!renderName.isEmpty()) { + finalModel->addAppearance(ModelUUIDs::ModelUUID_Render_Texture); + + // Now add the data + setAppearanceValue(finalModel, "Render.Textures.Name", renderName); + setAppearanceValue(finalModel, "Render.Textures.Images", renderImage); + setAppearanceValue(finalModel, "Render.Textures.Scale", renderScale); + setAppearanceValue(finalModel, "Render.Textures.Rotation", renderRotation); + setAppearanceValue(finalModel, "Render.Textures.TranslationU", renderTranslationU); + setAppearanceValue(finalModel, "Render.Textures.TranslationV", renderTranslationV); + } +} + +void MaterialConfigLoader::addRenderWB(QMap& fcmat, + const std::shared_ptr& finalModel) +{ + QString useObjectColor = value(fcmat, "General/UseObjectColor", ""); + QString renderType = value(fcmat, "Render/Render.Type", ""); + + if (!renderType.isEmpty()) { + finalModel->addAppearance(ModelUUIDs::ModelUUID_RenderWB); + + // Now add the data + setAppearanceValue(finalModel, "UseObjectColor", useObjectColor); + setAppearanceValue(finalModel, "Render.Type", renderType); + } + + addRenderAppleseed(fcmat, finalModel); + addRenderCarpaint(fcmat, finalModel); + addRenderCycles(fcmat, finalModel); + addRenderDiffuse(fcmat, finalModel); + addRenderDisney(fcmat, finalModel); + addRenderEmission(fcmat, finalModel); + addRenderGlass(fcmat, finalModel); + addRenderLuxcore(fcmat, finalModel); + addRenderLuxrender(fcmat, finalModel); + addRenderMixed(fcmat, finalModel); + addRenderOspray(fcmat, finalModel); + addRenderPbrt(fcmat, finalModel); + addRenderPovray(fcmat, finalModel); + addRenderSubstancePBR(fcmat, finalModel); + addRenderTexture(fcmat, finalModel); +} + +void MaterialConfigLoader::addCosts(const QMap& fcmat, + const std::shared_ptr& finalModel) { QString productURL = value(fcmat, "Cost/ProductURL", ""); QString specificPrice = value(fcmat, "Cost/SpecificPrice", ""); @@ -171,16 +843,16 @@ void MaterialConfigLoader::addCosts(const QSettings& fcmat, std::shared_ptr 0) { finalModel->addPhysical(ModelUUIDs::ModelUUID_Costs_Default); - } - // Now add the data - setPhysicalValue(finalModel, "ProductURL", productURL); - setPhysicalValue(finalModel, "SpecificPrice", specificPrice); - setPhysicalValue(finalModel, "Vendor", vendor); + // Now add the data + setPhysicalValue(finalModel, "ProductURL", productURL); + setPhysicalValue(finalModel, "SpecificPrice", specificPrice); + setPhysicalValue(finalModel, "Vendor", vendor); + } } -void MaterialConfigLoader::addArchitectural(const QSettings& fcmat, - std::shared_ptr finalModel) +void MaterialConfigLoader::addArchitectural(const QMap& fcmat, + const std::shared_ptr& finalModel) { QString color = value(fcmat, "Architectural/Color", ""); QString environmentalEfficiencyClass = @@ -192,26 +864,30 @@ void MaterialConfigLoader::addArchitectural(const QSettings& fcmat, QString soundTransmissionClass = value(fcmat, "Architectural/SoundTransmissionClass", ""); QString unitsPerQuantity = value(fcmat, "Architectural/UnitsPerQuantity", ""); - if (color.length() + environmentalEfficiencyClass.length() + executionInstructions.length() - + finish.length() + fireResistanceClass.length() + model.length() - + soundTransmissionClass.length() + unitsPerQuantity.length() + if (environmentalEfficiencyClass.length() + executionInstructions.length() + + fireResistanceClass.length() + model.length() + soundTransmissionClass.length() + + unitsPerQuantity.length() > 0) { finalModel->addPhysical(ModelUUIDs::ModelUUID_Architectural_Default); } + if (color.length() + finish.length() > 0) { + finalModel->addAppearance(ModelUUIDs::ModelUUID_Rendering_Architectural); + } // Now add the data - setPhysicalValue(finalModel, "Color", color); setPhysicalValue(finalModel, "EnvironmentalEfficiencyClass", environmentalEfficiencyClass); setPhysicalValue(finalModel, "ExecutionInstructions", executionInstructions); - setPhysicalValue(finalModel, "Finish", finish); setPhysicalValue(finalModel, "FireResistanceClass", fireResistanceClass); setPhysicalValue(finalModel, "Model", model); setPhysicalValue(finalModel, "SoundTransmissionClass", soundTransmissionClass); setPhysicalValue(finalModel, "UnitsPerQuantity", unitsPerQuantity); + + setAppearanceValue(finalModel, "Color", color); + setAppearanceValue(finalModel, "Finish", finish); } -void MaterialConfigLoader::addElectromagnetic(const QSettings& fcmat, - std::shared_ptr finalModel) +void MaterialConfigLoader::addElectromagnetic(const QMap& fcmat, + const std::shared_ptr& finalModel) { QString relativePermittivity = value(fcmat, "Electromagnetic/RelativePermittivity", ""); QString electricalConductivity = value(fcmat, "Electromagnetic/ElectricalConductivity", ""); @@ -221,15 +897,16 @@ void MaterialConfigLoader::addElectromagnetic(const QSettings& fcmat, + relativePermeability.length() > 0) { finalModel->addPhysical(ModelUUIDs::ModelUUID_Electromagnetic_Default); - } - // Now add the data - setPhysicalValue(finalModel, "RelativePermittivity", relativePermittivity); - setPhysicalValue(finalModel, "ElectricalConductivity", electricalConductivity); - setPhysicalValue(finalModel, "RelativePermeability", relativePermeability); + // Now add the data + setPhysicalValue(finalModel, "RelativePermittivity", relativePermittivity); + setPhysicalValue(finalModel, "ElectricalConductivity", electricalConductivity); + setPhysicalValue(finalModel, "RelativePermeability", relativePermeability); + } } -void MaterialConfigLoader::addThermal(const QSettings& fcmat, std::shared_ptr finalModel) +void MaterialConfigLoader::addThermal(const QMap& fcmat, + const std::shared_ptr& finalModel) { QString specificHeat = value(fcmat, "Thermal/SpecificHeat", ""); QString thermalConductivity = value(fcmat, "Thermal/ThermalConductivity", ""); @@ -238,15 +915,16 @@ void MaterialConfigLoader::addThermal(const QSettings& fcmat, std::shared_ptr 0) { finalModel->addPhysical(ModelUUIDs::ModelUUID_Thermal_Default); - } - // Now add the data - setPhysicalValue(finalModel, "SpecificHeat", specificHeat); - setPhysicalValue(finalModel, "ThermalConductivity", thermalConductivity); - setPhysicalValue(finalModel, "ThermalExpansionCoefficient", thermalExpansionCoefficient); + // Now add the data + setPhysicalValue(finalModel, "SpecificHeat", specificHeat); + setPhysicalValue(finalModel, "ThermalConductivity", thermalConductivity); + setPhysicalValue(finalModel, "ThermalExpansionCoefficient", thermalExpansionCoefficient); + } } -void MaterialConfigLoader::addFluid(const QSettings& fcmat, std::shared_ptr finalModel) +void MaterialConfigLoader::addFluid(const QMap& fcmat, + const std::shared_ptr& finalModel) { QString density = value(fcmat, "Fluidic/Density", ""); QString dynamicViscosity = value(fcmat, "Fluidic/DynamicViscosity", ""); @@ -277,8 +955,8 @@ void MaterialConfigLoader::addFluid(const QSettings& fcmat, std::shared_ptr finalModel) +void MaterialConfigLoader::addMechanical(const QMap& fcmat, + const std::shared_ptr& finalModel) { QString density = value(fcmat, "Mechanical/Density", ""); QString bulkModulus = value(fcmat, "Mechanical/BulkModulus", ""); @@ -340,12 +1018,16 @@ void MaterialConfigLoader::addMechanical(const QSettings& fcmat, } std::shared_ptr -MaterialConfigLoader::getMaterialFromPath(std::shared_ptr library, +MaterialConfigLoader::getMaterialFromPath(const std::shared_ptr& library, const QString& path) { QString author = getAuthorAndLicense(path); // Place them both in the author field - QSettings fcmat(path, QSettings::IniFormat); + QMap fcmat; + if (!readFile(path, fcmat)) { + Base::Console().Log("Error reading '%s'\n", path.toStdString().c_str()); + throw MaterialReadError(); + } // General section // QString name = value(fcmat, "Name", ""); - always get the name from the filename @@ -359,13 +1041,15 @@ MaterialConfigLoader::getMaterialFromPath(std::shared_ptr libra QString sourceURL = value(fcmat, "SourceURL", ""); std::shared_ptr finalModel = std::make_shared(library, path, uuid, name); + finalModel->setOldFormat(true); + finalModel->setAuthor(author); finalModel->setDescription(description); finalModel->setReference(sourceReference); finalModel->setURL(sourceURL); QString father = value(fcmat, "Father", ""); - if (father.length() > 0) { + if (!father.isEmpty()) { finalModel->addPhysical(ModelUUIDs::ModelUUID_Legacy_Father); // Now add the data @@ -396,6 +1080,7 @@ MaterialConfigLoader::getMaterialFromPath(std::shared_ptr libra addCosts(fcmat, finalModel); addRendering(fcmat, finalModel); addVectorRendering(fcmat, finalModel); + addRenderWB(fcmat, finalModel); return finalModel; -} +} \ No newline at end of file diff --git a/src/Mod/Material/App/MaterialConfigLoader.h b/src/Mod/Material/App/MaterialConfigLoader.h index 5d847d944c..f7b3d6b574 100644 --- a/src/Mod/Material/App/MaterialConfigLoader.h +++ b/src/Mod/Material/App/MaterialConfigLoader.h @@ -25,8 +25,11 @@ #include #include +#include +#include #include #include +#include #include "Materials.h" @@ -36,48 +39,114 @@ namespace Materials class MaterialConfigLoader { public: - MaterialConfigLoader(); + MaterialConfigLoader() = default; virtual ~MaterialConfigLoader() = default; static bool isConfigStyle(const QString& path); - static std::shared_ptr getMaterialFromPath(std::shared_ptr library, - const QString& path); + static std::shared_ptr + getMaterialFromPath(const std::shared_ptr& library, const QString& path); private: - static QString - value(const QSettings& fcmat, const std::string& name, const std::string& defaultValue) + static QString value(const QMap& fcmat, + const std::string& name, + const std::string& defaultValue) { - return fcmat.value(QString::fromStdString(name), QString::fromStdString(defaultValue)) - .toString(); + try { + return fcmat[QString::fromStdString(name)]; + } + catch (const std::out_of_range&) { + } + + return QString::fromStdString(defaultValue); } - static void setPhysicalValue(std::shared_ptr finalModel, + static void setPhysicalValue(const std::shared_ptr& finalModel, const std::string& name, const QString& value) { - if (value.length() > 0) { + if (!value.isEmpty()) { finalModel->setPhysicalValue(QString::fromStdString(name), value); } } - static void setAppearanceValue(std::shared_ptr finalModel, + static void setAppearanceValue(const std::shared_ptr& finalModel, const std::string& name, const QString& value) { - if (value.length() > 0) { + if (!value.isEmpty()) { + finalModel->setAppearanceValue(QString::fromStdString(name), value); + } + } + static void setAppearanceValue(const std::shared_ptr& finalModel, + const std::string& name, + const std::shared_ptr>& value) + { + if (!value->isEmpty()) { finalModel->setAppearanceValue(QString::fromStdString(name), value); } } + static bool isTexture(const QString& value) + { + return value.contains(QString::fromStdString("Texture"), Qt::CaseInsensitive); + } + + static bool readFile(const QString& path, QMap& map); + static void splitTexture(const QString& value, QString* texture, QString* remain); + static void + splitTextureObject(const QString& value, QString* texture, QString* remain, QString* object); + static QString getAuthorAndLicense(const QString& path); - static void addMechanical(const QSettings& fcmat, std::shared_ptr finalModel); - static void addFluid(const QSettings& fcmat, std::shared_ptr finalModel); - static void addThermal(const QSettings& fcmat, std::shared_ptr finalModel); - static void addElectromagnetic(const QSettings& fcmat, std::shared_ptr finalModel); - static void addArchitectural(const QSettings& fcmat, std::shared_ptr finalModel); - static void addCosts(const QSettings& fcmat, std::shared_ptr finalModel); - static void addRendering(const QSettings& fcmat, std::shared_ptr finalModel); - static void addVectorRendering(const QSettings& fcmat, std::shared_ptr finalModel); + static void addMechanical(const QMap& fcmat, + const std::shared_ptr& finalModel); + static void addFluid(const QMap& fcmat, + const std::shared_ptr& finalModel); + static void addThermal(const QMap& fcmat, + const std::shared_ptr& finalModel); + static void addElectromagnetic(const QMap& fcmat, + const std::shared_ptr& finalModel); + static void addArchitectural(const QMap& fcmat, + const std::shared_ptr& finalModel); + static void addCosts(const QMap& fcmat, + const std::shared_ptr& finalModel); + static void addRendering(const QMap& fcmat, + const std::shared_ptr& finalModel); + static void addVectorRendering(const QMap& fcmat, + const std::shared_ptr& finalModel); + + static QString multiLineKey(QMap& fcmat, const QString& prefix); + static void addRenderAppleseed(QMap& fcmat, + const std::shared_ptr& finalModel); + static void addRenderCarpaint(QMap& fcmat, + const std::shared_ptr& finalModel); + static void addRenderCycles(QMap& fcmat, + const std::shared_ptr& finalModel); + static void addRenderDiffuse(QMap& fcmat, + const std::shared_ptr& finalModel); + static void addRenderDisney(QMap& fcmat, + const std::shared_ptr& finalModel); + static void addRenderEmission(QMap& fcmat, + const std::shared_ptr& finalModel); + static void addRenderGlass(QMap& fcmat, + const std::shared_ptr& finalModel); + static void addRenderLuxcore(QMap& fcmat, + const std::shared_ptr& finalModel); + static void addRenderLuxrender(QMap& fcmat, + const std::shared_ptr& finalModel); + static void addRenderMixed(QMap& fcmat, + const std::shared_ptr& finalModel); + static void addRenderOspray(QMap& fcmat, + const std::shared_ptr& finalModel); + static void addRenderPbrt(QMap& fcmat, + const std::shared_ptr& finalModel); + static void addRenderPovray(QMap& fcmat, + const std::shared_ptr& finalModel); + static void addRenderSubstancePBR(QMap& fcmat, + const std::shared_ptr& finalModel); + static void addRenderTexture(QMap& fcmat, + const std::shared_ptr& finalModel); + static void addRenderWB(QMap& fcmat, + const std::shared_ptr& finalModel); }; } // namespace Materials diff --git a/src/Mod/Material/App/MaterialLibrary.cpp b/src/Mod/Material/App/MaterialLibrary.cpp index 5ccfa03466..e68a8a7779 100644 --- a/src/Mod/Material/App/MaterialLibrary.cpp +++ b/src/Mod/Material/App/MaterialLibrary.cpp @@ -54,7 +54,6 @@ MaterialLibrary::MaterialLibrary(const QString& libraryName, void MaterialLibrary::createFolder(const QString& path) { QString filePath = getLocalPath(path); - // Base::Console().Log("\tfilePath = '%s'\n", filePath.toStdString().c_str()); QDir fileDir(filePath); if (!fileDir.exists()) { @@ -68,8 +67,6 @@ void MaterialLibrary::createFolder(const QString& path) // This accepts the filesystem path as returned from getLocalPath void MaterialLibrary::deleteDir(MaterialManager& manager, const QString& path) { - // Base::Console().Log("Removing directory '%s'\n", path.toStdString().c_str()); - // Remove the children first QDirIterator it(path, QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot); @@ -109,12 +106,9 @@ void MaterialLibrary::deleteDir(MaterialManager& manager, const QString& path) // This accepts the filesystem path as returned from getLocalPath void MaterialLibrary::deleteFile(MaterialManager& manager, const QString& path) { - // Base::Console().Log("Removing file '%s'\n", path.toStdString().c_str()); - if (QFile::remove(path)) { // Remove from the map QString rPath = getRelativePath(path); - // Base::Console().Log("\trpath '%s'\n", rPath.toStdString().c_str()); try { auto material = getMaterialByPath(rPath); manager.remove(material->getUUID()); @@ -132,15 +126,11 @@ void MaterialLibrary::deleteFile(MaterialManager& manager, const QString& path) void MaterialLibrary::deleteRecursive(const QString& path) { - std::string pstring = path.toStdString(); - Base::Console().Log("\tdeleteRecursive '%s'\n", pstring.c_str()); - if (isRoot(path)) { return; } QString filePath = getLocalPath(path); - // Base::Console().Log("\tfilePath = '%s'\n", filePath.toStdString().c_str()); MaterialManager manager; QFileInfo info(filePath); @@ -159,16 +149,13 @@ void MaterialLibrary::updatePaths(const QString& oldPath, const QString& newPath QString np = getRelativePath(newPath); std::unique_ptr>> pathMap = std::make_unique>>(); - for (auto itp = _materialPathMap->begin(); itp != _materialPathMap->end(); itp++) { - QString path = itp->first; + for (auto& itp : *_materialPathMap) { + QString path = itp.first; if (path.startsWith(op)) { path = np + path.remove(0, op.size()); } - Base::Console().Error("Path '%s' -> '%s'\n", - itp->first.toStdString().c_str(), - path.toStdString().c_str()); - itp->second->setDirectory(path); - (*pathMap)[path] = itp->second; + itp.second->setDirectory(path); + (*pathMap)[path] = itp.second; } _materialPathMap = std::move(pathMap); @@ -177,9 +164,7 @@ void MaterialLibrary::updatePaths(const QString& oldPath, const QString& newPath void MaterialLibrary::renameFolder(const QString& oldPath, const QString& newPath) { QString filePath = getLocalPath(oldPath); - // Base::Console().Log("\tfilePath = '%s'\n", filePath.toStdString().c_str()); QString newFilePath = getLocalPath(newPath); - // Base::Console().Log("\tnew filePath = '%s'\n", newFilePath.toStdString().c_str()); QDir fileDir(filePath); if (fileDir.exists()) { @@ -192,25 +177,15 @@ void MaterialLibrary::renameFolder(const QString& oldPath, const QString& newPat updatePaths(oldPath, newPath); } -std::shared_ptr MaterialLibrary::saveMaterial(std::shared_ptr material, +std::shared_ptr MaterialLibrary::saveMaterial(const std::shared_ptr& material, const QString& path, bool overwrite, bool saveAsCopy, bool saveInherited) { QString filePath = getLocalPath(path); - // Base::Console().Log("\tfilePath = '%s'\n", filePath.toStdString().c_str()); QFile file(filePath); - // Update UUID if required - // if name changed true - // if (material->getName() != file.fileName()) { - // material->newUuid(); - // } - // if overwrite false having warned the user - // if old format true, but already set - - QFileInfo info(file); QDir fileDir(info.path()); if (!fileDir.exists()) { @@ -252,7 +227,7 @@ bool MaterialLibrary::fileExists(const QString& path) const return info.exists(); } -std::shared_ptr MaterialLibrary::addMaterial(std::shared_ptr material, +std::shared_ptr MaterialLibrary::addMaterial(const std::shared_ptr& material, const QString& path) { QString filePath = getRelativePath(path); @@ -267,11 +242,6 @@ std::shared_ptr MaterialLibrary::addMaterial(std::shared_ptr std::shared_ptr MaterialLibrary::getMaterialByPath(const QString& path) const { - // Base::Console().Log("MaterialLibrary::getMaterialByPath(%s)\n", path.toStdString().c_str()); - // for (auto itp = _materialPathMap->begin(); itp != _materialPathMap->end(); itp++) { - // Base::Console().Log("\tpath = '%s'\n", itp->first.toStdString().c_str()); - // } - QString filePath = getRelativePath(path); try { auto material = _materialPathMap->at(filePath); @@ -282,7 +252,7 @@ std::shared_ptr MaterialLibrary::getMaterialByPath(const QString& path } } -const QString MaterialLibrary::getUUIDFromPath(const QString& path) const +QString MaterialLibrary::getUUIDFromPath(const QString& path) const { QString filePath = getRelativePath(path); try { @@ -300,34 +270,32 @@ MaterialLibrary::getMaterialTree() const std::shared_ptr>> materialTree = std::make_shared>>(); - for (auto it = _materialPathMap->begin(); it != _materialPathMap->end(); it++) { - auto filename = it->first; - auto material = it->second; + for (auto& it : *_materialPathMap) { + auto filename = it.first; + auto material = it.second; - // Base::Console().Log("Relative path '%s'\n\t", filename.toStdString().c_str()); QStringList list = filename.split(QString::fromStdString("/")); // Start at the root std::shared_ptr>> node = materialTree; - for (auto itp = list.begin(); itp != list.end(); itp++) { - // Base::Console().Log("\t%s", itp->toStdString().c_str()); - if (itp->endsWith(QString::fromStdString(".FCMat"))) { + for (auto& itp : list) { + if (itp.endsWith(QString::fromStdString(".FCMat"))) { std::shared_ptr child = std::make_shared(); child->setData(material); - (*node)[*itp] = child; + (*node)[itp] = child; } else { // Add the folder only if it's not already there - if (node->count(*itp) == 0) { + if (node->count(itp) == 0) { auto mapPtr = std::make_shared>>(); std::shared_ptr child = std::make_shared(); child->setFolder(mapPtr); - (*node)[*itp] = child; + (*node)[itp] = child; node = mapPtr; } else { - node = (*node)[*itp]->getFolder(); + node = (*node)[itp]->getFolder(); } } } @@ -341,18 +309,18 @@ MaterialLibrary::getMaterialTree() const // Start at the root auto node = materialTree; - for (auto itp = list.begin(); itp != list.end(); itp++) { + for (auto& itp : list) { // Add the folder only if it's not already there - if (node->count(*itp) == 0) { + if (node->count(itp) == 0) { std::shared_ptr>> mapPtr = std::make_shared>>(); std::shared_ptr child = std::make_shared(); child->setFolder(mapPtr); - (*node)[*itp] = child; + (*node)[itp] = child; node = mapPtr; } else { - node = (*node)[*itp]->getFolder(); + node = (*node)[itp]->getFolder(); } } } @@ -368,8 +336,3 @@ MaterialExternalLibrary::MaterialExternalLibrary(const QString& libraryName, bool readOnly) : MaterialLibrary(libraryName, dir, icon, readOnly) {} - -MaterialExternalLibrary::~MaterialExternalLibrary() -{ - // delete directory; -} diff --git a/src/Mod/Material/App/MaterialLibrary.h b/src/Mod/Material/App/MaterialLibrary.h index 73a554ad61..1da9c696f4 100644 --- a/src/Mod/Material/App/MaterialLibrary.h +++ b/src/Mod/Material/App/MaterialLibrary.h @@ -29,8 +29,8 @@ #include #include - #include + #include "Materials.h" #include "Model.h" #include "ModelLibrary.h" @@ -69,13 +69,14 @@ public: void renameFolder(const QString& oldPath, const QString& newPath); void deleteRecursive(const QString& path); - std::shared_ptr saveMaterial(std::shared_ptr material, + std::shared_ptr saveMaterial(const std::shared_ptr& material, const QString& path, bool overwrite, bool saveAsCopy, bool saveInherited); bool fileExists(const QString& path) const; - std::shared_ptr addMaterial(std::shared_ptr material, const QString& path); + std::shared_ptr addMaterial(const std::shared_ptr& material, + const QString& path); std::shared_ptr>> getMaterialTree() const; bool isReadOnly() const @@ -94,7 +95,7 @@ protected: void deleteFile(MaterialManager& manager, const QString& path); void updatePaths(const QString& oldPath, const QString& newPath); - const QString getUUIDFromPath(const QString& path) const; + QString getUUIDFromPath(const QString& path) const; bool _readOnly; std::unique_ptr>> _materialPathMap; @@ -110,7 +111,7 @@ public: const QString& dir, const QString& icon, bool readOnly = true); - ~MaterialExternalLibrary() override; + ~MaterialExternalLibrary() = default; }; } // namespace Materials diff --git a/src/Mod/Material/App/MaterialLoader.cpp b/src/Mod/Material/App/MaterialLoader.cpp index a6b7a1f75f..bf2fab3978 100644 --- a/src/Mod/Material/App/MaterialLoader.cpp +++ b/src/Mod/Material/App/MaterialLoader.cpp @@ -26,6 +26,7 @@ #include #include +#include #include #include @@ -62,9 +63,6 @@ MaterialYamlEntry::MaterialYamlEntry(const std::shared_ptr& lib , _model(modelData) {} -// MaterialYamlEntry::~MaterialYamlEntry() -// {} - QString MaterialYamlEntry::yamlValue(const YAML::Node& node, const std::string& key, const std::string& defaultValue) @@ -75,38 +73,50 @@ QString MaterialYamlEntry::yamlValue(const YAML::Node& node, return QString::fromStdString(defaultValue); } -std::shared_ptr> MaterialYamlEntry::readList(const YAML::Node& node) +std::shared_ptr> MaterialYamlEntry::readList(const YAML::Node& node, + bool isImageList) { auto list = std::make_shared>(); for (auto it = node.begin(); it != node.end(); it++) { - QVariant nodeName = QString::fromStdString(it->as()); - list->append(nodeName); + QVariant nodeValue; + if (isImageList) { + nodeValue = QString::fromStdString(it->as()) + .remove(QRegExp(QString::fromStdString("[\r\n]"))); + } + else { + nodeValue = QString::fromStdString(it->as()); + } + list->append(nodeValue); } return list; } -std::shared_ptr MaterialYamlEntry::read2DArray(const YAML::Node& node) +std::shared_ptr> MaterialYamlEntry::readImageList(const YAML::Node& node) { - // Base::Console().Log("Read 2D Array\n"); + return readList(node, true); +} +std::shared_ptr MaterialYamlEntry::read2DArray(const YAML::Node& node, int columns) +{ auto array2d = std::make_shared(); + array2d->setColumns(columns); - if (node.size() == 2) { - // Get the default - Base::Quantity defaultValue( - Base::Quantity::parse(QString::fromStdString(node[0].as()))); - array2d->setDefault(QVariant::fromValue(defaultValue)); + if (node.size() == 1 || node.size() == 2) { + // There used to be a default value. Ignore it. + auto yamlArray = node[0]; + if (node.size() == 2) { + yamlArray = node[1]; + } - auto yamlArray = node[1]; for (std::size_t i = 0; i < yamlArray.size(); i++) { auto yamlRow = yamlArray[i]; - auto row = std::make_shared>(); + auto row = std::make_shared>(); for (std::size_t j = 0; j < yamlRow.size(); j++) { - Base::Quantity q = + Base::Quantity qq = Base::Quantity::parse(QString::fromStdString(yamlRow[j].as())); - row->push_back(QVariant::fromValue(q)); + row->push_back(QVariant::fromValue(qq)); } array2d->addRow(row); } @@ -115,28 +125,21 @@ std::shared_ptr MaterialYamlEntry::read2DArray(const YAML::Node return array2d; } -std::shared_ptr MaterialYamlEntry::read3DArray(const YAML::Node& node) +std::shared_ptr MaterialYamlEntry::read3DArray(const YAML::Node& node, int columns) { - Base::Console().Log("Read 3D Array\n"); - auto array3d = std::make_shared(); + array3d->setColumns(columns - 1); // First column is third dimension - if (node.size() == 2) { - // Get the default - Base::Quantity defaultValue( - Base::Quantity::parse(QString::fromStdString(node[0].as()))); - array3d->setDefault(QVariant::fromValue(defaultValue)); - - auto yamlArray = node[1]; + if (node.size() == 1 || node.size() == 2) { + // There used to be a default value. Ignore it. + auto yamlArray = node[0]; + if (node.size() == 2) { + yamlArray = node[1]; + } for (std::size_t depth = 0; depth < yamlArray.size(); depth++) { auto yamlDepth = yamlArray[depth]; - MaterialLoader::showYaml(yamlDepth); for (auto it = yamlDepth.begin(); it != yamlDepth.end(); it++) { - MaterialLoader::showYaml(it->first); - MaterialLoader::showYaml(it->second); - - Base::Console().Log("Depth %d '%s'\n", depth, it->first.as().c_str()); auto depthValue = Base::Quantity::parse(QString::fromStdString(it->first.as())); @@ -146,7 +149,7 @@ std::shared_ptr MaterialYamlEntry::read3DArray(const YAML::Node for (std::size_t i = 0; i < yamlTable.size(); i++) { auto yamlRow = yamlTable[i]; - auto row = std::make_shared>(); + auto row = std::make_shared>(); for (std::size_t j = 0; j < yamlRow.size(); j++) { row->push_back(Base::Quantity::parse( QString::fromStdString(yamlRow[j].as()))); @@ -187,7 +190,7 @@ void MaterialYamlEntry::addToTree( if (yamlModel["Inherits"]) { auto inherits = yamlModel["Inherits"]; for (auto it = inherits.begin(); it != inherits.end(); it++) { - std::string nodeName = it->second["UUID"].as(); + auto nodeName = it->second["UUID"].as(); finalModel->setParentUUID( QString::fromStdString(nodeName)); // Should only be one. Need to check @@ -198,42 +201,52 @@ void MaterialYamlEntry::addToTree( if (yamlModel["Models"]) { auto models = yamlModel["Models"]; for (auto it = models.begin(); it != models.end(); it++) { - std::string modelName = (it->first).as(); + auto modelName = (it->first).as(); // Add the model uuid auto modelNode = models[modelName]; - std::string modelUUID = modelNode["UUID"].as(); + auto modelUUID = modelNode["UUID"].as(); finalModel->addPhysical(QString::fromStdString(modelUUID)); // Add the property values auto properties = yamlModel["Models"][modelName]; for (auto itp = properties.begin(); itp != properties.end(); itp++) { - std::string propertyName = (itp->first).as(); + auto propertyName = (itp->first).as(); if (finalModel->hasPhysicalProperty(QString::fromStdString(propertyName))) { auto prop = finalModel->getPhysicalProperty(QString::fromStdString(propertyName)); auto type = prop->getType(); try { - if (type == MaterialValue::List) { + if (type == MaterialValue::List || type == MaterialValue::FileList) { auto list = readList(itp->second); finalModel->setPhysicalValue(QString::fromStdString(propertyName), list); } + else if (type == MaterialValue::ImageList) { + auto list = readImageList(itp->second); + finalModel->setPhysicalValue(QString::fromStdString(propertyName), + list); + } else if (type == MaterialValue::Array2D) { - auto array2d = read2DArray(itp->second); + auto array2d = read2DArray(itp->second, prop->columns()); finalModel->setPhysicalValue(QString::fromStdString(propertyName), array2d); } else if (type == MaterialValue::Array3D) { - auto array3d = read3DArray(itp->second); + auto array3d = read3DArray(itp->second, prop->columns()); finalModel->setPhysicalValue(QString::fromStdString(propertyName), array3d); } else { - std::string propertyValue = (itp->second).as(); + QString propertyValue = + QString::fromStdString((itp->second).as()); + if (type == MaterialValue::Image) { + propertyValue = + propertyValue.remove(QRegExp(QString::fromStdString("[\r\n]"))); + } finalModel->setPhysicalValue(QString::fromStdString(propertyName), - QString::fromStdString(propertyValue)); + propertyValue); } } catch (const YAML::BadConversion& e) { @@ -255,40 +268,52 @@ void MaterialYamlEntry::addToTree( if (yamlModel["AppearanceModels"]) { auto models = yamlModel["AppearanceModels"]; for (auto it = models.begin(); it != models.end(); it++) { - std::string modelName = (it->first).as(); + auto modelName = (it->first).as(); // Add the model uuid auto modelNode = models[modelName]; - std::string modelUUID = modelNode["UUID"].as(); + auto modelUUID = modelNode["UUID"].as(); finalModel->addAppearance(QString::fromStdString(modelUUID)); // Add the property values auto properties = yamlModel["AppearanceModels"][modelName]; for (auto itp = properties.begin(); itp != properties.end(); itp++) { - std::string propertyName = (itp->first).as(); + auto propertyName = (itp->first).as(); if (finalModel->hasAppearanceProperty(QString::fromStdString(propertyName))) { auto prop = finalModel->getAppearanceProperty(QString::fromStdString(propertyName)); auto type = prop->getType(); try { - if (type == MaterialValue::List) { + if (type == MaterialValue::List || type == MaterialValue::FileList) { auto list = readList(itp->second); finalModel->setAppearanceValue(QString::fromStdString(propertyName), list); } + else if (type == MaterialValue::ImageList) { + auto list = readImageList(itp->second); + finalModel->setAppearanceValue(QString::fromStdString(propertyName), + list); + } else if (type == MaterialValue::Array2D) { - auto array2d = read2DArray(itp->second); + auto array2d = read2DArray(itp->second, prop->columns()); finalModel->setAppearanceValue(QString::fromStdString(propertyName), array2d); } else if (type == MaterialValue::Array3D) { - Base::Console().Log("Read 3D Array\n"); + auto array3d = read3DArray(itp->second, prop->columns()); + finalModel->setAppearanceValue(QString::fromStdString(propertyName), + array3d); } else { - std::string propertyValue = (itp->second).as(); + QString propertyValue = + QString::fromStdString((itp->second).as()); + if (type == MaterialValue::Image) { + propertyValue = + propertyValue.remove(QRegExp(QString::fromStdString("[\r\n]"))); + } finalModel->setAppearanceValue(QString::fromStdString(propertyName), - QString::fromStdString(propertyValue)); + propertyValue); } } catch (const YAML::BadConversion& e) { @@ -307,39 +332,39 @@ void MaterialYamlEntry::addToTree( } QString path = QDir(directory).absolutePath(); - // Base::Console().Log("\tPath '%s'\n", path.toStdString().c_str()); (*materialMap)[uuid] = library->addMaterial(finalModel, path); } +//=== + std::unique_ptr>> MaterialLoader::_materialEntryMap = nullptr; MaterialLoader::MaterialLoader( - std::shared_ptr>> materialMap, - std::shared_ptr>> libraryList) + const std::shared_ptr>>& materialMap, + const std::shared_ptr>>& libraryList) : _materialMap(materialMap) , _libraryList(libraryList) { loadLibraries(); } -void MaterialLoader::addLibrary(std::shared_ptr model) +void MaterialLoader::addLibrary(const std::shared_ptr& model) { _libraryList->push_back(model); } std::shared_ptr -MaterialLoader::getMaterialFromYAML(std::shared_ptr library, +MaterialLoader::getMaterialFromYAML(const std::shared_ptr& library, YAML::Node& yamlroot, - const QString& path) const + const QString& path) { std::shared_ptr model = nullptr; try { - const std::string uuid = yamlroot["General"]["UUID"].as(); + auto uuid = yamlroot["General"]["UUID"].as(); // Always get the name from the filename - // QString name = QString::fromStdString(yamlroot["General"]["Name"].as()); QFileInfo filepath(path); QString name = filepath.fileName().remove(QString::fromStdString(".FCMat"), Qt::CaseInsensitive); @@ -349,7 +374,6 @@ MaterialLoader::getMaterialFromYAML(std::shared_ptr library, path, QString::fromStdString(uuid), yamlroot); - // showYaml(yamlroot); } catch (YAML::Exception const& e) { Base::Console().Error("YAML parsing error: '%s'\n", path.toStdString().c_str()); @@ -362,7 +386,7 @@ MaterialLoader::getMaterialFromYAML(std::shared_ptr library, } std::shared_ptr -MaterialLoader::getMaterialFromPath(std::shared_ptr library, +MaterialLoader::getMaterialFromPath(const std::shared_ptr& library, const QString& path) const { std::shared_ptr model = nullptr; @@ -371,7 +395,6 @@ MaterialLoader::getMaterialFromPath(std::shared_ptr library, std::string pathName = path.toStdString(); if (MaterialConfigLoader::isConfigStyle(path)) { - // Base::Console().Log("Old format .FCMat file: '%s'\n", pathName.c_str()); auto material = MaterialConfigLoader::getMaterialFromPath(library, path); if (material) { (*_materialMap)[material->getUUID()] = library->addMaterial(material, path); @@ -409,17 +432,14 @@ void MaterialLoader::showYaml(const YAML::Node& yaml) void MaterialLoader::dereference( - std::shared_ptr>> materialMap, - std::shared_ptr material) + const std::shared_ptr>>& materialMap, + const std::shared_ptr& material) { // Avoid recursion if (material->getDereferenced()) { return; } - // Base::Console().Log("Dereferencing material '%s'.\n", - // material->getName().toStdString().c_str()); - auto parentUUID = material->getParentUUID(); if (parentUUID.size() > 0) { std::shared_ptr parent; @@ -439,25 +459,25 @@ void MaterialLoader::dereference( // Add physical models auto modelVector = parent->getPhysicalModels(); - for (auto model = modelVector->begin(); model != modelVector->end(); model++) { - if (!material->hasPhysicalModel(*model)) { - material->addPhysical(*model); + for (auto& model : *modelVector) { + if (!material->hasPhysicalModel(model)) { + material->addPhysical(model); } } // Add appearance models modelVector = parent->getAppearanceModels(); - for (auto model = modelVector->begin(); model != modelVector->end(); model++) { - if (!material->hasAppearanceModel(*model)) { - material->addAppearance(*model); + for (auto& model : *modelVector) { + if (!material->hasAppearanceModel(model)) { + material->addAppearance(model); } } // Add values auto properties = parent->getPhysicalProperties(); - for (auto itp = properties.begin(); itp != properties.end(); itp++) { - auto name = itp->first; - auto property = itp->second; + for (auto& itp : properties) { + auto name = itp.first; + auto property = itp.second; if (material->getPhysicalProperty(name)->isNull()) { material->getPhysicalProperty(name)->setValue(property->getValue()); @@ -465,9 +485,9 @@ void MaterialLoader::dereference( } properties = parent->getAppearanceProperties(); - for (auto itp = properties.begin(); itp != properties.end(); itp++) { - auto name = itp->first; - auto property = itp->second; + for (auto& itp : properties) { + auto name = itp.first; + auto property = itp.second; if (material->getAppearanceProperty(name)->isNull()) { material->getAppearanceProperty(name)->setValue(property->getValue()); @@ -478,12 +498,12 @@ void MaterialLoader::dereference( material->markDereferenced(); } -void MaterialLoader::dereference(std::shared_ptr material) +void MaterialLoader::dereference(const std::shared_ptr& material) { dereference(_materialMap, material); } -void MaterialLoader::loadLibrary(std::shared_ptr library) +void MaterialLoader::loadLibrary(const std::shared_ptr& library) { if (_materialEntryMap == nullptr) { _materialEntryMap = std::make_unique>>(); @@ -495,16 +515,21 @@ void MaterialLoader::loadLibrary(std::shared_ptr library) QFileInfo file(pathname); if (file.isFile()) { if (file.suffix().toStdString() == "FCMat") { - auto model = getMaterialFromPath(library, file.canonicalFilePath()); - if (model) { - (*_materialEntryMap)[model->getUUID()] = model; + try { + auto model = getMaterialFromPath(library, file.canonicalFilePath()); + if (model) { + (*_materialEntryMap)[model->getUUID()] = model; + } + } + catch (const MaterialReadError&) { + // Ignore the file. Error messages should have already been logged } } } } - for (auto it = _materialEntryMap->begin(); it != _materialEntryMap->end(); it++) { - it->second->addToTree(_materialMap); + for (auto& it : *_materialEntryMap) { + it.second->addToTree(_materialMap); } } @@ -512,13 +537,13 @@ void MaterialLoader::loadLibraries() { auto _libraryList = getMaterialLibraries(); if (_libraryList) { - for (auto it = _libraryList->begin(); it != _libraryList->end(); it++) { - loadLibrary(*it); + for (auto& it : *_libraryList) { + loadLibrary(it); } } - for (auto it = _materialMap->begin(); it != _materialMap->end(); it++) { - dereference(it->second); + for (auto& it : *_materialMap) { + dereference(it.second); } } diff --git a/src/Mod/Material/App/MaterialLoader.h b/src/Mod/Material/App/MaterialLoader.h index 61a6c9b9a8..1d1eb9d7bb 100644 --- a/src/Mod/Material/App/MaterialLoader.h +++ b/src/Mod/Material/App/MaterialLoader.h @@ -51,15 +51,15 @@ public: { return _library; } - const QString getName() const + QString getName() const { return _name; } - const QString getDirectory() const + QString getDirectory() const { return _directory; } - const QString getUUID() const + QString getUUID() const { return _uuid; } @@ -96,11 +96,13 @@ public: private: MaterialYamlEntry(); - QString + static QString yamlValue(const YAML::Node& node, const std::string& key, const std::string& defaultValue); - std::shared_ptr> readList(const YAML::Node& node); - std::shared_ptr read2DArray(const YAML::Node& node); - std::shared_ptr read3DArray(const YAML::Node& node); + static std::shared_ptr> readList(const YAML::Node& node, + bool isImageList = false); + static std::shared_ptr> readImageList(const YAML::Node& node); + static std::shared_ptr read2DArray(const YAML::Node& node, int columns); + static std::shared_ptr read3DArray(const YAML::Node& node, int columns); YAML::Node _model; }; @@ -108,29 +110,30 @@ private: class MaterialLoader { public: - MaterialLoader(std::shared_ptr>> materialMap, - std::shared_ptr>> libraryList); + MaterialLoader(const std::shared_ptr>>& materialMap, + const std::shared_ptr>>& libraryList); ~MaterialLoader() = default; std::shared_ptr>> getMaterialLibraries(); static std::shared_ptr> getMaterialFolders(const MaterialLibrary& library); static void showYaml(const YAML::Node& yaml); static void - dereference(std::shared_ptr>> materialMap, - std::shared_ptr material); - std::shared_ptr getMaterialFromYAML(std::shared_ptr library, - YAML::Node& yamlroot, - const QString& path) const; + dereference(const std::shared_ptr>>& materialMap, + const std::shared_ptr& material); + static std::shared_ptr + getMaterialFromYAML(const std::shared_ptr& library, + YAML::Node& yamlroot, + const QString& path); private: MaterialLoader(); void addToTree(std::shared_ptr model); - void dereference(std::shared_ptr material); - std::shared_ptr getMaterialFromPath(std::shared_ptr library, - const QString& path) const; - void addLibrary(std::shared_ptr model); - void loadLibrary(std::shared_ptr library); + void dereference(const std::shared_ptr& material); + std::shared_ptr + getMaterialFromPath(const std::shared_ptr& library, const QString& path) const; + void addLibrary(const std::shared_ptr& model); + void loadLibrary(const std::shared_ptr& library); void loadLibraries(); static std::unique_ptr>> _materialEntryMap; diff --git a/src/Mod/Material/App/MaterialManager.cpp b/src/Mod/Material/App/MaterialManager.cpp index 131f1b09b3..72c801dbd8 100644 --- a/src/Mod/Material/App/MaterialManager.cpp +++ b/src/Mod/Material/App/MaterialManager.cpp @@ -58,11 +58,9 @@ void MaterialManager::initLibraries() if (_materialMap == nullptr) { // Load the models first - ModelManager* manager = new ModelManager(); + auto manager = std::make_unique(); Q_UNUSED(manager) - delete manager; - _materialMap = std::make_shared>>(); if (_libraryList == nullptr) { @@ -74,18 +72,18 @@ void MaterialManager::initLibraries() } } -void MaterialManager::saveMaterial(std::shared_ptr library, - std::shared_ptr material, +void MaterialManager::saveMaterial(const std::shared_ptr& library, + const std::shared_ptr& material, const QString& path, bool overwrite, bool saveAsCopy, - bool saveInherited) + bool saveInherited) const { auto newMaterial = library->saveMaterial(material, path, overwrite, saveAsCopy, saveInherited); (*_materialMap)[newMaterial->getUUID()] = newMaterial; } -bool MaterialManager::isMaterial(const fs::path& p) +bool MaterialManager::isMaterial(const fs::path& p) const { if (!fs::is_regular_file(p)) { return false; @@ -97,7 +95,7 @@ bool MaterialManager::isMaterial(const fs::path& p) return false; } -bool MaterialManager::isMaterial(const QFileInfo& file) +bool MaterialManager::isMaterial(const QFileInfo& file) const { if (!file.isFile()) { return false; @@ -124,21 +122,10 @@ std::shared_ptr MaterialManager::getMaterialByPath(const QString& path QString cleanPath = QDir::cleanPath(path); for (auto& library : *_libraryList) { - // Base::Console().Log("MaterialManager::getMaterialByPath() Checking library '%s'->'%s'\n", - // library->getName().toStdString().c_str(), - // library->getDirectory().toStdString().c_str()); - - if (cleanPath.startsWith(library->getDirectory())) { - // Base::Console().Log("MaterialManager::getMaterialByPath() Library '%s'\n", - // library->getDirectory().toStdString().c_str()); - // Base::Console().Log("MaterialManager::getMaterialByPath() Path '%s'\n", - // cleanPath.toStdString().c_str()); return library->getMaterialByPath(cleanPath); } } - Base::Console().Log("MaterialManager::getMaterialByPath() Library not found for path '%s'\n", - cleanPath.toStdString().c_str()); throw MaterialNotFound(); } @@ -154,7 +141,7 @@ bool MaterialManager::exists(const QString& uuid) const { try { auto material = getMaterial(uuid); - if (material.get() != nullptr) { + if (material) { return true; } } @@ -164,7 +151,8 @@ bool MaterialManager::exists(const QString& uuid) const return false; } -std::shared_ptr MaterialManager::getParent(std::shared_ptr material) +std::shared_ptr +MaterialManager::getParent(const std::shared_ptr& material) const { if (material->getParentUUID().isEmpty()) { throw MaterialNotFound(); @@ -173,11 +161,12 @@ std::shared_ptr MaterialManager::getParent(std::shared_ptr m return getMaterial(material->getParentUUID()); } -bool MaterialManager::exists(std::shared_ptr library, const QString& uuid) const +bool MaterialManager::exists(const std::shared_ptr& library, + const QString& uuid) const { try { auto material = getMaterial(uuid); - if (material.get() != nullptr) { + if (material) { return (*material->getLibrary() == *library); } } @@ -198,7 +187,8 @@ std::shared_ptr MaterialManager::getLibrary(const QString& name throw LibraryNotFound(); } -std::shared_ptr>> MaterialManager::getMaterialLibraries() +std::shared_ptr>> +MaterialManager::getMaterialLibraries() const { if (_libraryList == nullptr) { if (_materialMap == nullptr) { @@ -213,20 +203,20 @@ std::shared_ptr>> MaterialManager::ge } std::shared_ptr> -MaterialManager::getMaterialFolders(std::shared_ptr library) const +MaterialManager::getMaterialFolders(const std::shared_ptr& library) const { return MaterialLoader::getMaterialFolders(*library); } std::shared_ptr>> -MaterialManager::materialsWithModel(QString uuid) +MaterialManager::materialsWithModel(const QString& uuid) const { std::shared_ptr>> dict = std::make_shared>>(); - for (auto it = _materialMap->begin(); it != _materialMap->end(); it++) { - QString key = it->first; - auto material = it->second; + for (auto& it : *_materialMap) { + QString key = it.first; + auto material = it.second; if (material->hasModel(uuid)) { (*dict)[key] = material; @@ -237,14 +227,14 @@ MaterialManager::materialsWithModel(QString uuid) } std::shared_ptr>> -MaterialManager::materialsWithModelComplete(QString uuid) +MaterialManager::materialsWithModelComplete(const QString& uuid) const { std::shared_ptr>> dict = std::make_shared>>(); - for (auto it = _materialMap->begin(); it != _materialMap->end(); it++) { - QString key = it->first; - auto material = it->second; + for (auto& it : *_materialMap) { + QString key = it.first; + auto material = it.second; if (material->isModelComplete(uuid)) { (*dict)[key] = material; @@ -254,7 +244,7 @@ MaterialManager::materialsWithModelComplete(QString uuid) return dict; } -void MaterialManager::dereference(std::shared_ptr material) +void MaterialManager::dereference(std::shared_ptr material) const { MaterialLoader::dereference(_materialMap, material); } diff --git a/src/Mod/Material/App/MaterialManager.h b/src/Mod/Material/App/MaterialManager.h index f13260883d..a4b9400227 100644 --- a/src/Mod/Material/App/MaterialManager.h +++ b/src/Mod/Material/App/MaterialManager.h @@ -48,60 +48,61 @@ public: MaterialManager(); ~MaterialManager() override = default; - std::shared_ptr>> getMaterials() + std::shared_ptr>> getMaterials() const { return _materialMap; } std::shared_ptr getMaterial(const QString& uuid) const; std::shared_ptr getMaterialByPath(const QString& path) const; std::shared_ptr getMaterialByPath(const QString& path, const QString& library) const; - std::shared_ptr getParent(std::shared_ptr material); + std::shared_ptr getParent(const std::shared_ptr& material) const; std::shared_ptr getLibrary(const QString& name) const; bool exists(const QString& uuid) const; - bool exists(std::shared_ptr library, const QString& uuid) const; + bool exists(const std::shared_ptr& library, const QString& uuid) const; // Library management - static std::shared_ptr>> getMaterialLibraries(); + std::shared_ptr>> getMaterialLibraries() const; std::shared_ptr>> - getMaterialTree(std::shared_ptr library) const + getMaterialTree(const std::shared_ptr& library) const { return library->getMaterialTree(); } std::shared_ptr> - getMaterialFolders(std::shared_ptr library) const; - void createFolder(std::shared_ptr library, const QString& path) + getMaterialFolders(const std::shared_ptr& library) const; + void createFolder(const std::shared_ptr& library, const QString& path) const { library->createFolder(path); } - void renameFolder(std::shared_ptr library, + void renameFolder(const std::shared_ptr& library, const QString& oldPath, - const QString& newPath) + const QString& newPath) const { library->renameFolder(oldPath, newPath); } - void deleteRecursive(std::shared_ptr library, const QString& path) + void deleteRecursive(const std::shared_ptr& library, const QString& path) const { library->deleteRecursive(path); } - void remove(const QString& uuid) + void remove(const QString& uuid) const { _materialMap->erase(uuid); } - void saveMaterial(std::shared_ptr library, - std::shared_ptr material, + void saveMaterial(const std::shared_ptr& library, + const std::shared_ptr& material, const QString& path, bool overwrite, bool saveAsCopy, - bool saveInherited); + bool saveInherited) const; - static bool isMaterial(const fs::path& p); - static bool isMaterial(const QFileInfo& file); + bool isMaterial(const fs::path& p) const; + bool isMaterial(const QFileInfo& file) const; - std::shared_ptr>> materialsWithModel(QString uuid); std::shared_ptr>> - materialsWithModelComplete(QString uuid); - void dereference(std::shared_ptr material); + materialsWithModel(const QString& uuid) const; + std::shared_ptr>> + materialsWithModelComplete(const QString& uuid) const; + void dereference(std::shared_ptr material) const; private: static std::shared_ptr>> _libraryList; diff --git a/src/Mod/Material/App/MaterialPyImpl.cpp b/src/Mod/Material/App/MaterialPyImpl.cpp index 3067b139f9..071ab12c07 100644 --- a/src/Mod/Material/App/MaterialPyImpl.cpp +++ b/src/Mod/Material/App/MaterialPyImpl.cpp @@ -23,21 +23,28 @@ #include -#include #include #include +#include #include #include "Materials.h" +#include "Array2DPy.h" +#include "Array3DPy.h" #include "Exceptions.h" #include "MaterialLibrary.h" #include "MaterialPy.h" +#include "MaterialValue.h" #include "MaterialPy.cpp" using namespace Materials; +// Forward declaration +static PyObject* _pyObjectFromVariant(const QVariant& value); +static Py::List getList(const QVariant& value); + // returns a string which represents the object e.g. when printed in python std::string MaterialPy::representation() const { @@ -351,6 +358,18 @@ Py::Dict MaterialPy::getAppearanceProperties() const return dict; } +static Py::List getList(const QVariant& value) +{ + auto listValue = value.value>(); + Py::List list; + + for (auto& it : listValue) { + list.append(Py::Object(_pyObjectFromVariant(it))); + } + + return list; +} + static PyObject* _pyObjectFromVariant(const QVariant& value) { if (value.isNull()) { @@ -378,6 +397,9 @@ static PyObject* _pyObjectFromVariant(const QVariant& value) if (value.userType() == QMetaType::QString) { return PyUnicode_FromString(value.toString().toStdString().c_str()); } + if (value.userType() == qMetaTypeId>()) { + return Py::new_reference_to(getList(value)); + } throw UnknownValueType(); } @@ -389,7 +411,27 @@ PyObject* MaterialPy::getPhysicalValue(PyObject* args) return nullptr; } - QVariant value = getMaterialPtr()->getPhysicalValue(QString::fromStdString(name)); + if (!getMaterialPtr()->hasPhysicalProperty(QString::fromStdString(name))) { + Py_RETURN_NONE; + } + + auto property = getMaterialPtr()->getPhysicalProperty(QString::fromStdString(name)); + if (!property) { + Py_RETURN_NONE; + } + + if (property->getType() == MaterialValue::Array2D) { + auto value = + std::static_pointer_cast(property->getMaterialValue()); + return new Array2DPy(new Material2DArray(*value)); + } + else if (property->getType() == MaterialValue::Array3D) { + auto value = + std::static_pointer_cast(property->getMaterialValue()); + return new Array3DPy(new Material3DArray(*value)); + } + + QVariant value = property->getValue(); return _pyObjectFromVariant(value); } diff --git a/src/Mod/Material/App/MaterialValue.cpp b/src/Mod/Material/App/MaterialValue.cpp index d14504b9e4..99977e0d4f 100644 --- a/src/Mod/Material/App/MaterialValue.cpp +++ b/src/Mod/Material/App/MaterialValue.cpp @@ -151,7 +151,7 @@ void MaterialValue::setInitialValue(ValueType inherited) qu.setInvalid(); _value = QVariant::fromValue(qu); } - else if (_valueType == List) { + else if (_valueType == List || _valueType == FileList || _valueType == ImageList) { auto list = QList(); _value = QVariant::fromValue(list); } @@ -191,19 +191,79 @@ bool MaterialValue::isNull() const return !_value.value().isValid(); } - if (_valueType == List) { + if (_valueType == List || _valueType == FileList || _valueType == ImageList) { return _value.value>().isEmpty(); } return false; } -const QString MaterialValue::getYAMLString() const +QString MaterialValue::getYAMLStringImage() const +{ + QString yaml; + yaml = QString::fromStdString(" |-2"); + QString base64 = getValue().toString(); + while (!base64.isEmpty()) { + yaml += QString::fromStdString("\n ") + base64.left(74); + base64.remove(0, 74); + } + return yaml; +} + +QString MaterialValue::getYAMLStringList() const +{ + QString yaml; + for (auto& it : getList()) { + yaml += QString::fromStdString("\n - \"") + escapeString(it.toString()) + + QString::fromStdString("\""); + } + return yaml; +} + +QString MaterialValue::getYAMLStringImageList() const +{ + QString yaml; + for (auto& it : getList()) { + yaml += QString::fromStdString("\n - |-2"); + QString base64 = it.toString(); + while (!base64.isEmpty()) { + yaml += QString::fromStdString("\n ") + base64.left(72); + base64.remove(0, 72); + } + } + return yaml; +} + +QString MaterialValue::getYAMLStringMultiLine() const +{ + QString yaml; + yaml = QString::fromStdString(" >2"); + auto list = + getValue().toString().split(QRegExp(QString::fromStdString("[\r\n]")), Qt::SkipEmptyParts); + for (auto& it : list) { + yaml += QString::fromStdString("\n ") + it; + } + return yaml; +} + +QString MaterialValue::getYAMLString() const { QString yaml; if (!isNull()) { + if (getType() == MaterialValue::Image) { + return getYAMLStringImage(); + } + if (getType() == MaterialValue::List || getType() == MaterialValue::FileList) { + return getYAMLStringList(); + } + if (getType() == MaterialValue::ImageList) { + return getYAMLStringImageList(); + } + if (getType() == MaterialValue::MultiLineString) { + return getYAMLStringMultiLine(); + } if (getType() == MaterialValue::Quantity) { - Base::Quantity quantity = getValue().value(); + auto quantity = getValue().value(); yaml += quantity.getUserString(); } else if (getType() == MaterialValue::Float) { @@ -214,8 +274,9 @@ const QString MaterialValue::getYAMLString() const } else if (getType() == MaterialValue::MultiLineString) { yaml = QString::fromLatin1(">2"); - auto list = getValue().toString().split(QRegularExpression(QString::fromLatin1("[\r\n]")), - Qt::SkipEmptyParts); + auto list = + getValue().toString().split(QRegularExpression(QString::fromLatin1("[\r\n]")), + Qt::SkipEmptyParts); for (auto& it : list) { yaml += QString::fromLatin1("\n ") + it; } @@ -242,7 +303,7 @@ TYPESYSTEM_SOURCE(Materials::Material2DArray, Materials::MaterialValue) Material2DArray::Material2DArray() : MaterialValue(Array2D, Array2D) - , _defaultSet(false) + , _columns(0) { // Initialize separatelt to prevent recursion // setType(Array2D); @@ -250,7 +311,7 @@ Material2DArray::Material2DArray() Material2DArray::Material2DArray(const Material2DArray& other) : MaterialValue(other) - , _defaultSet(other._defaultSet) + , _columns(other._columns) { deepCopy(other); } @@ -262,7 +323,7 @@ Material2DArray& Material2DArray::operator=(const Material2DArray& other) } MaterialValue::operator=(other); - _defaultSet = other._defaultSet; + _columns = other._columns; deepCopy(other); @@ -273,12 +334,12 @@ void Material2DArray::deepCopy(const Material2DArray& other) { // Deep copy for (auto& row : other._rows) { - std::vector v; + QList vv; for (auto& col : *row) { QVariant newVariant(col); - v.push_back(newVariant); + vv.push_back(newVariant); } - addRow(std::make_shared>(v)); + addRow(std::make_shared>(vv)); } } @@ -287,85 +348,90 @@ bool Material2DArray::isNull() const return rows() <= 0; } -const QVariant Material2DArray::getDefault() const +void Material2DArray::validateRow(int row) const { - if (_defaultSet) { - return _value; + if (row < 0 || row >= rows()) { + throw InvalidIndex(); } - - return QVariant(); } -std::shared_ptr> Material2DArray::getRow(int row) const +void Material2DArray::validateColumn(int column) const { + if (column < 0 || column >= columns()) { + throw InvalidIndex(); + } +} + +std::shared_ptr> Material2DArray::getRow(int row) const +{ + validateRow(row); + try { return _rows.at(row); } catch (std::out_of_range const&) { - throw InvalidRow(); + throw InvalidIndex(); } } -std::shared_ptr> Material2DArray::getRow(int row) +std::shared_ptr> Material2DArray::getRow(int row) { + validateRow(row); + try { return _rows.at(row); } catch (std::out_of_range const&) { - throw InvalidRow(); + throw InvalidIndex(); } } -void Material2DArray::addRow(std::shared_ptr> row) +void Material2DArray::addRow(const std::shared_ptr>& row) { _rows.push_back(row); } -void Material2DArray::insertRow(int index, std::shared_ptr> row) +void Material2DArray::insertRow(int index, const std::shared_ptr>& row) { _rows.insert(_rows.begin() + index, row); } void Material2DArray::deleteRow(int row) { - if (static_cast(row) >= _rows.size() || row < 0) { - throw InvalidRow(); + if (row >= static_cast(_rows.size()) || row < 0) { + throw InvalidIndex(); } _rows.erase(_rows.begin() + row); } void Material2DArray::setValue(int row, int column, const QVariant& value) { - if (row >= rows()) { - throw InvalidIndex(); - } + validateRow(row); + validateColumn(column); auto val = getRow(row); try { - val->at(column) = value; + val->replace(column, value); } catch (const std::out_of_range&) { throw InvalidIndex(); } } -const QVariant Material2DArray::getValue(int row, int column) const +QVariant Material2DArray::getValue(int row, int column) const { + validateColumn(column); + + auto val = getRow(row); try { - auto val = getRow(row); - try { - return val->at(column); - } - catch (std::out_of_range const&) { - throw InvalidIndex(); - } + return val->at(column); } - catch (const InvalidRow&) { + catch (std::out_of_range const&) { throw InvalidIndex(); } } -void Material2DArray::dumpRow(std::shared_ptr> row) const +void Material2DArray::dumpRow(const std::shared_ptr>& row) { Base::Console().Log("row: "); for (auto& column : *row) { @@ -381,7 +447,7 @@ void Material2DArray::dump() const } } -const QString Material2DArray::getYAMLString() const +QString Material2DArray::getYAMLString() const { if (isNull()) { return QString(); @@ -391,14 +457,8 @@ const QString Material2DArray::getYAMLString() const QString pad; pad.fill(QChar::fromLatin1(' '), 9); - // Save the default value - QString yaml = QString::fromStdString("\n - \""); - Base::Quantity quantity = getDefault().value(); - yaml += quantity.getUserString(); - yaml += QString::fromStdString("\"\n"); - - // Next the array contents - yaml += QString::fromStdString(" - ["); + // Save the array contents + QString yaml = QString::fromStdString("\n - ["); bool firstRow = true; for (auto& row : _rows) { if (!firstRow) { @@ -420,7 +480,7 @@ const QString Material2DArray::getYAMLString() const first = false; } yaml += QString::fromStdString("\""); - Base::Quantity quantity = column.value(); + auto quantity = column.value(); yaml += quantity.getUserString(); yaml += QString::fromStdString("\""); } @@ -437,8 +497,8 @@ TYPESYSTEM_SOURCE(Materials::Material3DArray, Materials::MaterialValue) Material3DArray::Material3DArray() : MaterialValue(Array3D, Array3D) - , _defaultSet(false) , _currentDepth(0) + , _columns(0) { // Initialize separatelt to prevent recursion // setType(Array3D); @@ -449,99 +509,121 @@ bool Material3DArray::isNull() const return depth() <= 0; } -const QVariant Material3DArray::getDefault() const +void Material3DArray::validateDepth(int level) const { - return _value; + if (level < 0 || level >= depth()) { + throw InvalidIndex(); + } } -const std::shared_ptr>>>& +void Material3DArray::validateColumn(int column) const +{ + if (column < 0 || column >= columns()) { + throw InvalidIndex(); + } +} + +void Material3DArray::validateRow(int level, int row) const +{ + validateDepth(level); + + if (row < 0 || row >= rows(level)) { + throw InvalidIndex(); + } +} + +const std::shared_ptr>>>& Material3DArray::getTable(const Base::Quantity& depth) const { - for (auto it = _rowMap.begin(); it != _rowMap.end(); it++) { - if (std::get<0>(*it) == depth) { - return std::get<1>(*it); + for (auto& it : _rowMap) { + if (std::get<0>(it) == depth) { + return std::get<1>(it); } } - throw InvalidDepth(); + throw InvalidIndex(); } -const std::shared_ptr>>>& +const std::shared_ptr>>>& Material3DArray::getTable(int depthIndex) const { try { return std::get<1>(_rowMap.at(depthIndex)); } catch (std::out_of_range const&) { - throw InvalidDepth(); + throw InvalidIndex(); } } -const std::shared_ptr> Material3DArray::getRow(int depth, int row) const +std::shared_ptr> Material3DArray::getRow(int depth, int row) const { + validateRow(depth, row); + try { return getTable(depth)->at(row); } catch (std::out_of_range const&) { - throw InvalidRow(); + throw InvalidIndex(); } } -std::shared_ptr> Material3DArray::getRow(int row) const +std::shared_ptr> Material3DArray::getRow(int row) const { // Check if we can convert otherwise throw error return getRow(_currentDepth, row); } -std::shared_ptr> Material3DArray::getRow(int depth, int row) +std::shared_ptr> Material3DArray::getRow(int depth, int row) { + validateRow(depth, row); + try { return getTable(depth)->at(row); } catch (std::out_of_range const&) { - throw InvalidRow(); + throw InvalidIndex(); } } -std::shared_ptr> Material3DArray::getRow(int row) +std::shared_ptr> Material3DArray::getRow(int row) { return getRow(_currentDepth, row); } -void Material3DArray::addRow(int depth, std::shared_ptr> row) +void Material3DArray::addRow(int depth, const std::shared_ptr>& row) { try { getTable(depth)->push_back(row); } catch (std::out_of_range const&) { - throw InvalidRow(); + throw InvalidIndex(); } } -void Material3DArray::addRow(std::shared_ptr> row) +void Material3DArray::addRow(const std::shared_ptr>& row) { addRow(_currentDepth, row); } -int Material3DArray::addDepth(int depth, Base::Quantity value) +int Material3DArray::addDepth(int depth, const Base::Quantity& value) { if (depth == this->depth()) { // Append to the end return addDepth(value); } - else if (depth > this->depth()) { - throw InvalidDepth(); + if (depth > this->depth()) { + throw InvalidIndex(); } - auto rowVector = std::make_shared>>>(); + auto rowVector = std::make_shared>>>(); auto entry = std::make_pair(value, rowVector); _rowMap.insert(_rowMap.begin() + depth, entry); return depth; } -int Material3DArray::addDepth(Base::Quantity value) +int Material3DArray::addDepth(const Base::Quantity& value) { - auto rowVector = std::make_shared>>>(); + auto rowVector = std::make_shared>>>(); auto entry = std::make_pair(value, rowVector); _rowMap.push_back(entry); @@ -550,26 +632,24 @@ int Material3DArray::addDepth(Base::Quantity value) void Material3DArray::deleteDepth(int depth) { - deleteRows(depth); // This may throw an InvalidDepth + deleteRows(depth); // This may throw an InvalidIndex _rowMap.erase(_rowMap.begin() + depth); } void Material3DArray::insertRow(int depth, int row, - std::shared_ptr> rowData) + const std::shared_ptr>& rowData) { try { auto table = getTable(depth); - // auto it = table->begin(); - // std::advance(it, row); table->insert(table->begin() + row, rowData); } catch (std::out_of_range const&) { - throw InvalidRow(); + throw InvalidIndex(); } } -void Material3DArray::insertRow(int row, std::shared_ptr> rowData) +void Material3DArray::insertRow(int row, const std::shared_ptr>& rowData) { insertRow(_currentDepth, row, rowData); } @@ -577,8 +657,8 @@ void Material3DArray::insertRow(int row, std::shared_ptr(row) >= table->size() || row < 0) { - throw InvalidRow(); + if (row >= static_cast(table->size()) || row < 0) { + throw InvalidIndex(); } table->erase(table->begin() + row); } @@ -604,30 +684,22 @@ int Material3DArray::rows(int depth) const if (depth < 0 || (depth == 0 && this->depth() == 0)) { return 0; } + validateDepth(depth); return getTable(depth)->size(); } -int Material3DArray::columns(int depth) const -{ - if (depth < 0 || (depth == 0 && this->depth() == 0)) { - return 0; - } - if (rows() == 0) { - return 0; - } - - return getTable(depth)->at(0)->size(); -} - void Material3DArray::setValue(int depth, int row, int column, const Base::Quantity& value) { + validateRow(depth, row); + validateColumn(column); + auto val = getRow(depth, row); try { - val->at(column) = value; + val->replace(column, value); } catch (std::out_of_range const&) { - throw InvalidColumn(); + throw InvalidIndex(); } } @@ -640,10 +712,10 @@ void Material3DArray::setDepthValue(int depth, const Base::Quantity& value) { try { auto oldRows = getTable(depth); - _rowMap.at(depth) = std::pair(value, oldRows); + _rowMap.replace(depth, std::pair(value, oldRows)); } catch (std::out_of_range const&) { - throw InvalidRow(); + throw InvalidIndex(); } } @@ -653,29 +725,34 @@ void Material3DArray::setDepthValue(const Base::Quantity& value) } -const Base::Quantity Material3DArray::getValue(int depth, int row, int column) const +Base::Quantity Material3DArray::getValue(int depth, int row, int column) const { + // getRow validates depth and row. Do that first auto val = getRow(depth, row); + validateColumn(column); + try { return val->at(column); } catch (std::out_of_range const&) { - throw InvalidColumn(); + throw InvalidIndex(); } } -const Base::Quantity Material3DArray::getValue(int row, int column) const +Base::Quantity Material3DArray::getValue(int row, int column) const { return getValue(_currentDepth, row, column); } -const Base::Quantity Material3DArray::getDepthValue(int depth) const +Base::Quantity Material3DArray::getDepthValue(int depth) const { + validateDepth(depth); + try { return std::get<0>(_rowMap.at(depth)); } catch (std::out_of_range const&) { - throw InvalidRow(); + throw InvalidIndex(); } } @@ -686,10 +763,12 @@ int Material3DArray::currentDepth() const void Material3DArray::setCurrentDepth(int depth) { - if (depth < 0 || _rowMap.size() == 0) { + validateDepth(depth); + + if (depth < 0 || _rowMap.empty()) { _currentDepth = 0; } - else if (static_cast(depth) >= _rowMap.size()) { + else if (depth >= static_cast(_rowMap.size())) { _currentDepth = _rowMap.size() - 1; } else { @@ -697,7 +776,7 @@ void Material3DArray::setCurrentDepth(int depth) } } -const QString Material3DArray::getYAMLString() const +QString Material3DArray::getYAMLString() const { if (isNull()) { return QString(); @@ -707,14 +786,8 @@ const QString Material3DArray::getYAMLString() const QString pad; pad.fill(QChar::fromLatin1(' '), 9); - // Save the default value - QString yaml = QString::fromStdString("\n - \""); - Base::Quantity quantity = getDefault().value(); - yaml += quantity.getUserString(); - yaml += QString::fromStdString("\"\n"); - - // Next the array contents - yaml += QString::fromStdString(" - ["); + // Save the array contents + QString yaml = QString::fromStdString("\n - ["); for (int depth = 0; depth < this->depth(); depth++) { if (depth > 0) { // Each row is on its own line, padded for correct indentation diff --git a/src/Mod/Material/App/MaterialValue.h b/src/Mod/Material/App/MaterialValue.h index 12b7f066a7..89e0de8167 100644 --- a/src/Mod/Material/App/MaterialValue.h +++ b/src/Mod/Material/App/MaterialValue.h @@ -24,6 +24,7 @@ #include +#include #include #include @@ -55,7 +56,9 @@ public: Image = 11, File = 12, URL = 13, - MultiLineString = 14 + MultiLineString = 14, + FileList = 15, + ImageList = 16 }; MaterialValue(); explicit MaterialValue(const MaterialValue& other); @@ -99,7 +102,7 @@ public: } void setList(const QList& value); - virtual const QString getYAMLString() const; + virtual QString getYAMLString() const; static QString escapeString(const QString& source); protected: @@ -111,6 +114,11 @@ protected: } void setInitialValue(ValueType inherited); + QString getYAMLStringImage() const; + QString getYAMLStringList() const; + QString getYAMLStringImageList() const; + QString getYAMLStringMultiLine() const; + ValueType _valueType; QVariant _value; }; @@ -128,58 +136,45 @@ public: bool isNull() const override; - void setDefault(MaterialValue value, bool markSet = true) + const QList>>& getArray() const { - _value = value.getValue(); - _defaultSet = markSet; - } - void setDefault(const QVariant& value, bool markSet = true) - { - _value = value; - _defaultSet = markSet; - } - void setDefault(const Base::Quantity& value, bool markSet = true) - { - _value = QVariant::fromValue(value); - _defaultSet = markSet; - } - const QVariant getDefault() const; - bool defaultSet() const - { - return _defaultSet; + return _rows; } - std::shared_ptr> getRow(int row) const; - std::shared_ptr> getRow(int row); + void validateRow(int row) const; + void validateColumn(int column) const; + + std::shared_ptr> getRow(int row) const; + std::shared_ptr> getRow(int row); int rows() const { return _rows.size(); } int columns() const { - if (rows() == 0) { - return 0; - } - - return _rows.at(0)->size(); + return _columns; } - void addRow(std::shared_ptr> row); - void insertRow(int index, std::shared_ptr> row); + void setColumns(int size) + { + _columns = size; + } + void addRow(const std::shared_ptr>& row); + void insertRow(int index, const std::shared_ptr>& row); void deleteRow(int row); void setValue(int row, int column, const QVariant& value); - const QVariant getValue(int row, int column) const; + QVariant getValue(int row, int column) const; - const QString getYAMLString() const override; + QString getYAMLString() const override; protected: void deepCopy(const Material2DArray& other); - std::vector>> _rows; - bool _defaultSet; + QList>> _rows; + int _columns; private: - void dumpRow(std::shared_ptr> row) const; + static void dumpRow(const std::shared_ptr>& row); void dump() const; }; @@ -193,42 +188,32 @@ public: bool isNull() const override; - void setDefault(MaterialValue value, bool markSet = true) + const QList< + std::pair>>>>>& + getArray() const { - _value = value.getValue(); - _defaultSet = markSet; - } - void setDefault(const QVariant& value, bool markSet = true) - { - _value = value; - _defaultSet = markSet; - } - void setDefault(const Base::Quantity& value, bool markSet = true) - { - _value = QVariant::fromValue(value); - _defaultSet = markSet; - } - const QVariant getDefault() const; - bool defaultSet() const - { - return _defaultSet; + return _rowMap; } - const std::shared_ptr>>>& + void validateDepth(int level) const; + void validateColumn(int column) const; + void validateRow(int level, int row) const; + + const std::shared_ptr>>>& getTable(const Base::Quantity& depth) const; - const std::shared_ptr>>>& + const std::shared_ptr>>>& getTable(int depthIndex) const; - const std::shared_ptr> getRow(int depth, int row) const; - std::shared_ptr> getRow(int row) const; - std::shared_ptr> getRow(int depth, int row); - std::shared_ptr> getRow(int row); - void addRow(int depth, std::shared_ptr> row); - void addRow(std::shared_ptr> row); - int addDepth(int depth, Base::Quantity value); - int addDepth(Base::Quantity value); + std::shared_ptr> getRow(int depth, int row) const; + std::shared_ptr> getRow(int row) const; + std::shared_ptr> getRow(int depth, int row); + std::shared_ptr> getRow(int row); + void addRow(int depth, const std::shared_ptr>& row); + void addRow(const std::shared_ptr>& row); + int addDepth(int depth, const Base::Quantity& value); + int addDepth(const Base::Quantity& value); void deleteDepth(int depth); - void insertRow(int depth, int row, std::shared_ptr> rowData); - void insertRow(int row, std::shared_ptr> rowData); + void insertRow(int depth, int row, const std::shared_ptr>& rowData); + void insertRow(int row, const std::shared_ptr>& rowData); void deleteRow(int depth, int row); void deleteRow(int row); void deleteRows(int depth); @@ -242,40 +227,39 @@ public: { return rows(_currentDepth); } - int columns(int depth) const; int columns() const { - return columns(_currentDepth); + return _columns; + } + void setColumns(int size) + { + _columns = size; } void setValue(int depth, int row, int column, const Base::Quantity& value); void setValue(int row, int column, const Base::Quantity& value); void setDepthValue(int depth, const Base::Quantity& value); void setDepthValue(const Base::Quantity& value); - const Base::Quantity getValue(int depth, int row, int column) const; - const Base::Quantity getValue(int row, int column) const; - const Base::Quantity getDepthValue(int depth) const; + Base::Quantity getValue(int depth, int row, int column) const; + Base::Quantity getValue(int row, int column) const; + Base::Quantity getDepthValue(int depth) const; int currentDepth() const; void setCurrentDepth(int depth); - const QString getYAMLString() const override; + QString getYAMLString() const override; protected: - std::vector< - std::pair>>>>> + QList>>>>> _rowMap; - bool _defaultSet; int _currentDepth; + int _columns; }; } // namespace Materials Q_DECLARE_METATYPE(Materials::MaterialValue) -// Q_DECLARE_METATYPE(Materials::Material2DArray) Q_DECLARE_METATYPE(std::shared_ptr) -// Q_DECLARE_METATYPE(Materials::Material3DArray) Q_DECLARE_METATYPE(std::shared_ptr) #endif // MATERIAL_MATERIALVALUE_H diff --git a/src/Mod/Material/App/Materials.cpp b/src/Mod/Material/App/Materials.cpp index 142370292f..b11d9db236 100644 --- a/src/Mod/Material/App/Materials.cpp +++ b/src/Mod/Material/App/Materials.cpp @@ -59,13 +59,6 @@ MaterialProperty::MaterialProperty(const ModelProperty& other) MaterialProperty prop(it); addColumn(prop); } - - if (_valuePtr->getType() == MaterialValue::Array2D) { - std::static_pointer_cast(_valuePtr)->setDefault(getColumnNull(0), false); - } - else if (_valuePtr->getType() == MaterialValue::Array3D) { - std::static_pointer_cast(_valuePtr)->setDefault(getColumnNull(0), false); - } } void MaterialProperty::copyValuePtr(const std::shared_ptr& value) @@ -185,20 +178,29 @@ void MaterialProperty::setType(const QString& type) else if (type == QString::fromStdString("List")) { _valuePtr = std::make_shared(MaterialValue::List); } + else if (type == QString::fromStdString("FileList")) { + _valuePtr = std::make_shared(MaterialValue::FileList); + } + else if (type == QString::fromStdString("ImageList")) { + _valuePtr = std::make_shared(MaterialValue::ImageList); + } else if (type == QString::fromStdString("MultiLineString")) { _valuePtr = std::make_shared(MaterialValue::MultiLineString); } else if (type == QString::fromStdString("2DArray")) { - _valuePtr = std::make_shared(); + auto arrayPtr = std::make_shared(); + arrayPtr->setColumns(columns()); + _valuePtr = arrayPtr; } else if (type == QString::fromStdString("3DArray")) { - _valuePtr = std::make_shared(); + auto arrayPtr = std::make_shared(); + // First column is third dimension + arrayPtr->setColumns(columns() - 1); + _valuePtr = arrayPtr; } else { // Error. Throw something _valuePtr = std::make_shared(MaterialValue::None); - // std::string stringType = type.toStdString(); - useful for debugging since we can't see - // std::string name = getName().toStdString(); throw UnknownValueType(); } } @@ -209,7 +211,7 @@ MaterialProperty& MaterialProperty::getColumn(int column) return _columns.at(column); } catch (std::out_of_range const&) { - throw InvalidColumn(); + throw InvalidIndex(); } } @@ -219,7 +221,7 @@ const MaterialProperty& MaterialProperty::getColumn(int column) const return _columns.at(column); } catch (std::out_of_range const&) { - throw InvalidColumn(); + throw InvalidIndex(); } } @@ -229,7 +231,7 @@ MaterialValue::ValueType MaterialProperty::getColumnType(int column) const return _columns.at(column).getType(); } catch (std::out_of_range const&) { - throw InvalidColumn(); + throw InvalidIndex(); } } @@ -239,7 +241,7 @@ QString MaterialProperty::getColumnUnits(int column) const return _columns.at(column).getUnits(); } catch (std::out_of_range const&) { - throw InvalidColumn(); + throw InvalidIndex(); } } @@ -288,7 +290,6 @@ void MaterialProperty::setValue(const QString& value) // This value can't be directly assigned } else if (_valuePtr->getType() == MaterialValue::Quantity) { - // Base::Console().Log("\tParse quantity '%s'\n", value.toStdString().c_str()); try { setQuantity(Base::Quantity::parse(value)); } @@ -312,19 +313,16 @@ void MaterialProperty::setValue(const std::shared_ptr& value) void MaterialProperty::setString(const QString& value) { - // _valueType = MaterialValue::String; _valuePtr->setValue(QVariant(value)); } void MaterialProperty::setBoolean(bool value) { - // _valueType = MaterialValue::Boolean; _valuePtr->setValue(QVariant(value)); } void MaterialProperty::setBoolean(int value) { - // _valueType = MaterialValue::Boolean; _valuePtr->setValue(QVariant(value != 0)); } @@ -425,6 +423,7 @@ TYPESYSTEM_SOURCE(Materials::Material, Base::BaseClass) Material::Material() : _dereferenced(false) + , _oldFormat(false) , _editState(ModelEdit_None) {} @@ -436,6 +435,7 @@ Material::Material(const std::shared_ptr& library, , _uuid(uuid) , _name(name) , _dereferenced(false) + , _oldFormat(false) , _editState(ModelEdit_None) { setDirectory(directory); @@ -453,6 +453,7 @@ Material::Material(const Material& other) , _url(other._url) , _reference(other._reference) , _dereferenced(other._dereferenced) + , _oldFormat(other._oldFormat) , _editState(other._editState) { for (auto& it : other._tags) { @@ -666,6 +667,7 @@ void Material::removePhysical(const QString& uuid) setEditStateAlter(); } catch (ModelNotFound const&) { + Base::Console().Log("Physical model not found '%s'\n", uuid.toStdString().c_str()); } } @@ -701,6 +703,7 @@ void Material::addAppearance(const QString& uuid) } } catch (ModelNotFound const&) { + Base::Console().Log("Appearance model not found '%s'\n", uuid.toStdString().c_str()); } } @@ -747,11 +750,15 @@ void Material::removeAppearance(const QString& uuid) void Material::setPropertyEditState(const QString& name) { - if (hasPhysicalProperty(name)) { - setPhysicalEditState(name); + try { + if (hasPhysicalProperty(name)) { + setPhysicalEditState(name); + } + else if (hasAppearanceProperty(name)) { + setAppearanceEditState(name); + } } - else if (hasAppearanceProperty(name)) { - setAppearanceEditState(name); + catch (const PropertyNotFound&) { } } @@ -767,11 +774,15 @@ void Material::setPhysicalEditState(const QString& name) void Material::setAppearanceEditState(const QString& name) { - if (getAppearanceProperty(name)->isNull()) { - setEditStateExtend(); + try { + if (getAppearanceProperty(name)->isNull()) { + setEditStateExtend(); + } + else { + setEditStateAlter(); + } } - else { - setEditStateAlter(); + catch (const PropertyNotFound&) { } } @@ -834,7 +845,7 @@ void Material::setAppearanceValue(const QString& name, const std::shared_ptr>& value) { - setPhysicalEditState(name); + setAppearanceEditState(name); _appearance[name]->setList(*value); } @@ -1321,6 +1332,8 @@ void Material::save(QTextStream& stream, bool overwrite, bool saveAsCopy, bool s } saveModels(stream, saveInherited); saveAppearanceModels(stream, saveInherited); + + setOldFormat(false); } Material& Material::operator=(const Material& other) @@ -1340,6 +1353,7 @@ Material& Material::operator=(const Material& other) _url = other._url; _reference = other._reference; _dereferenced = other._dereferenced; + _oldFormat = other._oldFormat; _editState = other._editState; _tags.clear(); diff --git a/src/Mod/Material/App/Materials.h b/src/Mod/Material/App/Materials.h index c1c0d7c1fc..74a37a22cc 100644 --- a/src/Mod/Material/App/Materials.h +++ b/src/Mod/Material/App/Materials.h @@ -321,6 +321,14 @@ public: { _dereferenced = true; } + bool isOldFormat() const + { + return _oldFormat; + } + void setOldFormat(bool isOld) + { + _oldFormat = isOld; + } /* * Normalize models by removing any inherited models @@ -387,12 +395,13 @@ private: std::map> _physical; std::map> _appearance; bool _dereferenced; + bool _oldFormat; ModelEdit _editState; }; inline QTextStream& operator<<(QTextStream& output, const MaterialProperty& property) { - output << MaterialValue::escapeString(property.getName()) << ": " << property.getYAMLString(); + output << MaterialValue::escapeString(property.getName()) << ":" << property.getYAMLString(); return output; } diff --git a/src/Mod/Material/App/ModelLibrary.cpp b/src/Mod/Material/App/ModelLibrary.cpp index 1b2374fa4a..63d06f2d06 100644 --- a/src/Mod/Material/App/ModelLibrary.cpp +++ b/src/Mod/Material/App/ModelLibrary.cpp @@ -43,9 +43,6 @@ LibraryBase::LibraryBase(const QString& libraryName, const QString& dir, const Q , _iconPath(icon) {} -LibraryBase::LibraryBase() -{} - bool LibraryBase::operator==(const LibraryBase& library) const { return (_name == library._name) && (_directory == library._directory); @@ -146,39 +143,36 @@ ModelLibrary::getModelTree(ModelFilter filter) const std::shared_ptr>> modelTree = std::make_shared>>(); - for (auto it = _modelPathMap->begin(); it != _modelPathMap->end(); it++) { - auto filename = it->first; - auto model = it->second; + for (auto& it : *_modelPathMap) { + auto filename = it.first; + auto model = it.second; if (ModelManager::passFilter(filter, model->getType())) { - // Base::Console().Log("Relative path '%s'\n\t", filename.toStdString().c_str()); QStringList list = filename.split(QString::fromStdString("/")); // Start at the root std::shared_ptr>> node = modelTree; - for (auto itp = list.begin(); itp != list.end(); itp++) { - // Base::Console().Log("\t%s", itp->toStdString().c_str()); - if (ModelManager::isModel(*itp)) { + for (auto& itp : list) { + if (ModelManager::isModel(itp)) { std::shared_ptr child = std::make_shared(); child->setData(model); - (*node)[*itp] = child; + (*node)[itp] = child; } else { // Add the folder only if it's not already there - if (node->count(*itp) == 0) { + if (node->count(itp) == 0) { auto mapPtr = std::make_shared>>(); std::shared_ptr child = std::make_shared(); child->setFolder(mapPtr); - (*node)[*itp] = child; + (*node)[itp] = child; node = mapPtr; } else { - node = (*node)[*itp]->getFolder(); + node = (*node)[itp]->getFolder(); } } } - // Base::Console().Log("\n"); } } diff --git a/src/Mod/Material/App/ModelLibrary.h b/src/Mod/Material/App/ModelLibrary.h index c0d1189642..e77b2c9da1 100644 --- a/src/Mod/Material/App/ModelLibrary.h +++ b/src/Mod/Material/App/ModelLibrary.h @@ -44,7 +44,7 @@ class MaterialsExport LibraryBase: public Base::BaseClass TYPESYSTEM_HEADER_WITH_OVERRIDE(); public: - LibraryBase(); + LibraryBase() = default; LibraryBase(const QString& libraryName, const QString& dir, const QString& icon); ~LibraryBase() override = default; diff --git a/src/Mod/Material/App/ModelManager.cpp b/src/Mod/Material/App/ModelManager.cpp index 799be693fb..23be586253 100644 --- a/src/Mod/Material/App/ModelManager.cpp +++ b/src/Mod/Material/App/ModelManager.cpp @@ -100,21 +100,10 @@ std::shared_ptr ModelManager::getModelByPath(const QString& path) const QString cleanPath = QDir::cleanPath(path); for (auto& library : *_libraryList) { - // Base::Console().Log("ModelManager::getModelByPath() Checking library '%s'->'%s'\n", - // library->getName().toStdString().c_str(), - // library->getDirectory().toStdString().c_str()); - - if (cleanPath.startsWith(library->getDirectory())) { - // Base::Console().Log("ModelManager::getModelByPath() Library '%s'\n", - // library->getDirectory().toStdString().c_str()); - // Base::Console().Log("ModelManager::getModelByPath() Path '%s'\n", - // cleanPath.toStdString().c_str()); return library->getModelByPath(cleanPath); } } - Base::Console().Log("ModelManager::getModelByPath() Library not found for path '%s'\n", - cleanPath.toStdString().c_str()); throw MaterialNotFound(); } diff --git a/src/Mod/Material/App/ModelUuids.cpp b/src/Mod/Material/App/ModelUuids.cpp index 270eb6f9a6..8e40b4428a 100644 --- a/src/Mod/Material/App/ModelUuids.cpp +++ b/src/Mod/Material/App/ModelUuids.cpp @@ -56,6 +56,8 @@ const QString ModelUUIDs::ModelUUID_Electromagnetic_Default = const QString ModelUUIDs::ModelUUID_Architectural_Default = QString::fromStdString("32439c3b-262f-4b7b-99a8-f7f44e5894c8"); +const QString ModelUUIDs::ModelUUID_Rendering_Architectural = + QString::fromStdString("27e48ac9-54e1-4a1f-aa49-d5d690242705"); const QString ModelUUIDs::ModelUUID_Costs_Default = QString::fromStdString("881df808-8726-4c2e-be38-688bb6cce466"); @@ -69,5 +71,38 @@ const QString ModelUUIDs::ModelUUID_Rendering_Advanced = const QString ModelUUIDs::ModelUUID_Rendering_Vector = QString::fromStdString("fdf5a80e-de50-4157-b2e5-b6e5f88b680e"); -const QString ModelUUIDs::ModelUUID_Test_Material = - QString::fromStdString("c6c64159-19c1-40b5-859c-10561f20f979"); +const QString ModelUUIDs::ModelUUID_Render_Appleseed = + QString::fromStdString("b0a10f70-13bf-4598-ab63-bcfbbcd813e3"); +const QString ModelUUIDs::ModelUUID_Render_Carpaint = + QString::fromStdString("4d2cc163-0707-40e2-a9f7-14288c4b97bd"); +const QString ModelUUIDs::ModelUUID_Render_Cycles = + QString::fromStdString("a6da1b66-929c-48bf-ae80-3b0495c7b50b"); +const QString ModelUUIDs::ModelUUID_Render_Diffuse = + QString::fromStdString("c19b2d30-c55b-48aa-a938-df9e2f7779cf"); +const QString ModelUUIDs::ModelUUID_Render_Disney = + QString::fromStdString("f8723572-4470-4c39-a749-6d3b71358a5b"); +const QString ModelUUIDs::ModelUUID_Render_Emission = + QString::fromStdString("9f6cb588-c89d-4a74-9d0f-2786a8568cec"); +const QString ModelUUIDs::ModelUUID_Render_Glass = + QString::fromStdString("d76a56f5-7250-4efb-bb89-8ea0a9ccaa6b"); +const QString ModelUUIDs::ModelUUID_Render_Luxcore = + QString::fromStdString("6b992304-33e0-490b-a391-e9d0af79bb69"); +const QString ModelUUIDs::ModelUUID_Render_Luxrender = + QString::fromStdString("67ac6a63-e173-4e05-898b-af743f1f9563"); +const QString ModelUUIDs::ModelUUID_Render_Mixed = + QString::fromStdString("84bab333-984f-47fe-a512-d17c7cb2daa9"); +const QString ModelUUIDs::ModelUUID_Render_Ospray = + QString::fromStdString("a4792c23-0be9-47c2-b16d-47b2d2d5efd6"); +const QString ModelUUIDs::ModelUUID_Render_Pbrt = + QString::fromStdString("35b34b82-4325-4d27-97bd-d10bb2c56586"); +const QString ModelUUIDs::ModelUUID_Render_Povray = + QString::fromStdString("6ec8b415-4c7b-4206-a80b-2ea64101f34b"); +const QString ModelUUIDs::ModelUUID_Render_SubstancePBR = + QString::fromStdString("f212b643-db96-452e-8428-376a4534e5ab"); +const QString ModelUUIDs::ModelUUID_Render_Texture = // ??? + QString::fromStdString("fc9b6135-95cd-4ba8-ad9a-0972caeebad2"); +const QString ModelUUIDs::ModelUUID_RenderWB = + QString::fromStdString("344008be-a837-43af-90bc-f795f277b309"); + +const QString ModelUUIDs::ModelUUID_Test_Model = + QString::fromStdString("34d0583d-f999-49ba-99e6-aa40bd5c3a6b"); diff --git a/src/Mod/Material/App/ModelUuids.h b/src/Mod/Material/App/ModelUuids.h index 97b82fe91f..70a7ebb8e1 100644 --- a/src/Mod/Material/App/ModelUuids.h +++ b/src/Mod/Material/App/ModelUuids.h @@ -58,6 +58,7 @@ public: static const QString ModelUUID_Electromagnetic_Default; static const QString ModelUUID_Architectural_Default; + static const QString ModelUUID_Rendering_Architectural; static const QString ModelUUID_Costs_Default; @@ -66,7 +67,24 @@ public: static const QString ModelUUID_Rendering_Advanced; static const QString ModelUUID_Rendering_Vector; - static const QString ModelUUID_Test_Material; + static const QString ModelUUID_Render_Appleseed; + static const QString ModelUUID_Render_Carpaint; + static const QString ModelUUID_Render_Cycles; + static const QString ModelUUID_Render_Diffuse; + static const QString ModelUUID_Render_Disney; + static const QString ModelUUID_Render_Emission; + static const QString ModelUUID_Render_Glass; + static const QString ModelUUID_Render_Luxcore; + static const QString ModelUUID_Render_Luxrender; + static const QString ModelUUID_Render_Mixed; + static const QString ModelUUID_Render_Ospray; + static const QString ModelUUID_Render_Pbrt; + static const QString ModelUUID_Render_Povray; + static const QString ModelUUID_Render_SubstancePBR; + static const QString ModelUUID_Render_Texture; + static const QString ModelUUID_RenderWB; + + static const QString ModelUUID_Test_Model; }; } // namespace Materials diff --git a/src/Mod/Material/App/UUIDsPy.xml b/src/Mod/Material/App/UUIDsPy.xml index 29138e05c3..7448c032c7 100644 --- a/src/Mod/Material/App/UUIDsPy.xml +++ b/src/Mod/Material/App/UUIDsPy.xml @@ -82,6 +82,12 @@ + + + UUID for model System:Architectural/ArchitecturalRendering + + + UUID for model System:Costs/Costs @@ -112,5 +118,107 @@ + + + UUID for model System:Rendering/RenderAppleseed + + + + + + UUID for model System:Rendering/RenderCarpaint + + + + + + UUID for model System:Rendering/RenderCycles + + + + + + UUID for model System:Rendering/RenderDiffuse + + + + + + UUID for model System:Rendering/RenderDisney + + + + + + UUID for model System:Rendering/RenderEmission + + + + + + UUID for model System:Rendering/RenderGlass + + + + + + UUID for model System:Rendering/RenderLuxcore + + + + + + UUID for model System:Rendering/RenderLuxrender + + + + + + UUID for model System:Rendering/RenderMixed + + + + + + UUID for model System:Rendering/RenderOspray + + + + + + UUID for model System:Rendering/RenderPbrt + + + + + + UUID for model System:Rendering/RenderPovray + + + + + + UUID for model System:Rendering/RenderSubstancePBR + + + + + + UUID for model System:Rendering/RenderTexture + + + + + + UUID for model System:Rendering/RenderWB + + + + + + UUID for model System:Test/Test Model + + + diff --git a/src/Mod/Material/App/UUIDsPyImpl.cpp b/src/Mod/Material/App/UUIDsPyImpl.cpp index 94d3fb9071..e8d7af27da 100644 --- a/src/Mod/Material/App/UUIDsPyImpl.cpp +++ b/src/Mod/Material/App/UUIDsPyImpl.cpp @@ -102,6 +102,11 @@ Py::String UUIDsPy::getArchitectural() const return Py::String(ModelUUIDs::ModelUUID_Architectural_Default.toStdString()); } +Py::String UUIDsPy::getArchitecturalRendering() const +{ + return Py::String(ModelUUIDs::ModelUUID_Rendering_Architectural.toStdString()); +} + Py::String UUIDsPy::getCosts() const { return Py::String(ModelUUIDs::ModelUUID_Costs_Default.toStdString()); @@ -128,6 +133,91 @@ Py::String UUIDsPy::getVectorRendering() const return Py::String(ModelUUIDs::ModelUUID_Rendering_Vector.toStdString()); } +Py::String UUIDsPy::getRenderAppleseed() const +{ + return Py::String(ModelUUIDs::ModelUUID_Render_Appleseed.toStdString()); +} + +Py::String UUIDsPy::getRenderCarpaint() const +{ + return Py::String(ModelUUIDs::ModelUUID_Render_Carpaint.toStdString()); +} + +Py::String UUIDsPy::getRenderCycles() const +{ + return Py::String(ModelUUIDs::ModelUUID_Render_Cycles.toStdString()); +} + +Py::String UUIDsPy::getRenderDiffuse() const +{ + return Py::String(ModelUUIDs::ModelUUID_Render_Diffuse.toStdString()); +} + +Py::String UUIDsPy::getRenderDisney() const +{ + return Py::String(ModelUUIDs::ModelUUID_Render_Disney.toStdString()); +} + +Py::String UUIDsPy::getRenderEmission() const +{ + return Py::String(ModelUUIDs::ModelUUID_Render_Emission.toStdString()); +} + +Py::String UUIDsPy::getRenderLuxcore() const +{ + return Py::String(ModelUUIDs::ModelUUID_Render_Luxcore.toStdString()); +} + +Py::String UUIDsPy::getRenderLuxrender() const +{ + return Py::String(ModelUUIDs::ModelUUID_Render_Luxrender.toStdString()); +} + +Py::String UUIDsPy::getRenderGlass() const +{ + return Py::String(ModelUUIDs::ModelUUID_Render_Glass.toStdString()); +} + +Py::String UUIDsPy::getRenderMixed() const +{ + return Py::String(ModelUUIDs::ModelUUID_Render_Mixed.toStdString()); +} + +Py::String UUIDsPy::getRenderOspray() const +{ + return Py::String(ModelUUIDs::ModelUUID_Render_Ospray.toStdString()); +} + +Py::String UUIDsPy::getRenderPbrt() const +{ + return Py::String(ModelUUIDs::ModelUUID_Render_Pbrt.toStdString()); +} + +Py::String UUIDsPy::getRenderPovray() const +{ + return Py::String(ModelUUIDs::ModelUUID_Render_Povray.toStdString()); +} + +Py::String UUIDsPy::getRenderSubstancePBR() const +{ + return Py::String(ModelUUIDs::ModelUUID_Render_SubstancePBR.toStdString()); +} + +Py::String UUIDsPy::getRenderTexture() const +{ + return Py::String(ModelUUIDs::ModelUUID_Render_Texture.toStdString()); +} + +Py::String UUIDsPy::getRenderWB() const +{ + return Py::String(ModelUUIDs::ModelUUID_RenderWB.toStdString()); +} + +Py::String UUIDsPy::getTestModel() const +{ + return Py::String(ModelUUIDs::ModelUUID_Test_Model.toStdString()); +} + PyObject* UUIDsPy::getCustomAttributes(const char* /*attr*/) const { return nullptr; diff --git a/src/Mod/Material/CMakeLists.txt b/src/Mod/Material/CMakeLists.txt index 79db6e584c..4945e3febc 100644 --- a/src/Mod/Material/CMakeLists.txt +++ b/src/Mod/Material/CMakeLists.txt @@ -30,7 +30,6 @@ SET(Material_Icon_Files ) # collect all the material cards: -# FILE( GLOB MaterialLib_Files ./StandardMaterial/*.FCMat ./StandardMaterial/*.txt ) SET(MaterialLib_Files Resources/Materials/Standard/Aggregate/Concrete-EN-C35_45.FCMat Resources/Materials/Standard/Aggregate/Concrete-Generic.FCMat @@ -192,6 +191,7 @@ SET(MaterialTestLib_Files SET(MaterialModel_Files Resources/Models/Architectural/Architectural.yml + Resources/Models/Architectural/ArchitecturalRendering.yml Resources/Models/Costs/Costs.yml Resources/Models/Electromagnetic/Electromagnetic.yml Resources/Models/Fluid/Fluid.yml diff --git a/src/Mod/Material/Gui/AppearancePreview.cpp b/src/Mod/Material/Gui/AppearancePreview.cpp new file mode 100644 index 0000000000..b0351a8773 --- /dev/null +++ b/src/Mod/Material/Gui/AppearancePreview.cpp @@ -0,0 +1,225 @@ +/*************************************************************************** + * 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" +#ifndef _PreComp_ +#endif + +#include +#include +#include +#include + +#include +#include + +#include "AppearancePreview.h" + +using namespace MatGui; + +/* TRANSLATOR MatGui::AppearancePreview */ + +AppearanceSettings::AppearanceSettings(const ParameterGrp::handle& hGrp, + Gui::View3DInventorViewer* view) + : Gui::View3DSettings(hGrp, view) +{} + +AppearanceSettings::AppearanceSettings(const ParameterGrp::handle& hGrp, + const std::vector& view) + : Gui::View3DSettings(hGrp, view) +{} + +void AppearanceSettings::OnChange(ParameterGrp::SubjectType& rCaller, + ParameterGrp::MessageType Reason) +{ + // Exclude settings that either we're not interested in, or that + // may interfere with functionality + if (strcmp(Reason, "CornerCoordSystem") == 0) { + return; + } + if (strcmp(Reason, "CornerCoordSystemSize") == 0) { + return; + } + if (strcmp(Reason, "ShowAxisCross") == 0) { + return; + } + if (strcmp(Reason, "UseNavigationAnimations") == 0) { + return; + } + if (strcmp(Reason, "ShowFPS") == 0) { + return; + } + if (strcmp(Reason, "ShowNaviCube") == 0) { + return; + } + if (strcmp(Reason, "UseVBO") == 0) { + return; + } + if (strcmp(Reason, "RenderCache") == 0) { + return; + } + if (strcmp(Reason, "Orthographic") == 0) { + return; + } + if (strcmp(Reason, "NavigationStyle") == 0) { + return; + } + if (strcmp(Reason, "OrbitStyle") == 0) { + return; + } + if (strcmp(Reason, "Sensitivity") == 0) { + return; + } + if (strcmp(Reason, "ResetCursorPosition") == 0) { + return; + } + if (strcmp(Reason, "DimensionsVisible") == 0) { + return; + } + if (strcmp(Reason, "Dimensions3dVisible") == 0) { + return; + } + if (strcmp(Reason, "DimensionsDeltaVisible") == 0) { + return; + } + if (strcmp(Reason, "PickRadius") == 0) { + return; + } + if (strcmp(Reason, "TransparentObjectRenderType") == 0) { + return; + } + + View3DSettings::OnChange(rCaller, Reason); +} + +//=== + +AppearancePreview::AppearancePreview(QWidget* parent) + : Gui::View3DInventorViewer(parent) +{ + setRedirectToSceneGraph(true); + setViewing(true); + setPopupMenuEnabled(false); + + applySettings(); + // setBackground(); + setEnabledNaviCube(false); + + auto root = dynamic_cast(getSceneGraph()); + _material = new SoMaterial(); + _material->ref(); + root->addChild(_material); + root->addChild(new SoSphere()); + + setCameraType(SoOrthographicCamera::getClassTypeId()); + setViewDirection(SbVec3f(1, 1, -5)); + viewAll(); +} + +AppearancePreview::~AppearancePreview() +{ + _material->unref(); + _material = nullptr; +} + +void AppearancePreview::applySettings() +{ + viewSettings = std::make_unique( + App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/View"), + this); + viewSettings->applySettings(); +} + +void AppearancePreview::setAmbientColor(const QColor& color) +{ + _material->ambientColor.setValue( + SbColor(color.red() / 255.0, color.green() / 255.0, color.blue() / 255.0)); + _material->ambientColor.setDefault(false); +} + +void AppearancePreview::setDiffuseColor(const QColor& color) +{ + _material->diffuseColor.setValue( + SbColor(color.red() / 255.0, color.green() / 255.0, color.blue() / 255.0)); + _material->diffuseColor.setDefault(false); +} + +void AppearancePreview::setSpecularColor(const QColor& color) +{ + _material->specularColor.setValue( + SbColor(color.red() / 255.0, color.green() / 255.0, color.blue() / 255.0)); + _material->specularColor.setDefault(false); +} + +void AppearancePreview::setEmissiveColor(const QColor& color) +{ + _material->emissiveColor.setValue( + SbColor(color.red() / 255.0, color.green() / 255.0, color.blue() / 255.0)); + _material->emissiveColor.setDefault(false); +} + +void AppearancePreview::setShininess(double value) +{ + _material->shininess.setValue(value); + _material->shininess.setDefault(false); +} + +void AppearancePreview::setTransparency(double value) +{ + _material->transparency.setValue(value); + _material->transparency.setDefault(false); +} + +void AppearancePreview::resetAmbientColor() +{ + _material->ambientColor.deleteValues(0); + _material->ambientColor.setDefault(true); +} + +void AppearancePreview::resetDiffuseColor() +{ + _material->diffuseColor.deleteValues(0); + _material->diffuseColor.setDefault(true); +} + +void AppearancePreview::resetSpecularColor() +{ + _material->specularColor.deleteValues(0); + _material->specularColor.setDefault(true); +} + +void AppearancePreview::resetEmissiveColor() +{ + _material->emissiveColor.deleteValues(0); + _material->emissiveColor.setDefault(true); +} + +void AppearancePreview::resetShininess() +{ + _material->shininess.deleteValues(0); + _material->shininess.setDefault(true); +} + +void AppearancePreview::resetTransparency() +{ + _material->transparency.deleteValues(0); + _material->transparency.setDefault(true); +} diff --git a/src/Mod/Material/Gui/AppearancePreview.h b/src/Mod/Material/Gui/AppearancePreview.h new file mode 100644 index 0000000000..cbf4a71b2b --- /dev/null +++ b/src/Mod/Material/Gui/AppearancePreview.h @@ -0,0 +1,77 @@ +/*************************************************************************** + * 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 * + * . * + * * + **************************************************************************/ + +#ifndef MATGUI_APPEARANCEPREVIEW_H +#define MATGUI_APPEARANCEPREVIEW_H + +#include +#include +#include + +class SoMaterial; + +namespace MatGui +{ + +class AppearanceSettings: public Gui::View3DSettings +{ +public: + AppearanceSettings(const ParameterGrp::handle& hGrp, Gui::View3DInventorViewer*); + AppearanceSettings(const ParameterGrp::handle& hGrp, + const std::vector&); + ~AppearanceSettings() = default; + + /// Observer message from the ParameterGrp + void OnChange(ParameterGrp::SubjectType& rCaller, ParameterGrp::MessageType Reason) override; +}; + +class AppearancePreview: public Gui::View3DInventorViewer +{ + Q_OBJECT + +public: + explicit AppearancePreview(QWidget* parent = nullptr); + ~AppearancePreview() override; + + void setAmbientColor(const QColor& color); + void setDiffuseColor(const QColor& color); + void setSpecularColor(const QColor& color); + void setEmissiveColor(const QColor& color); + void setShininess(double value); + void setTransparency(double value); + + void resetAmbientColor(); + void resetDiffuseColor(); + void resetSpecularColor(); + void resetEmissiveColor(); + void resetShininess(); + void resetTransparency(); + +private: + SoMaterial* _material; + std::unique_ptr viewSettings; + + void applySettings(); +}; + +} // namespace MatGui + +#endif // MATGUI_APPEARANCEPREVIEW_H diff --git a/src/Mod/Material/Gui/Array2D.cpp b/src/Mod/Material/Gui/Array2D.cpp index 194b5dfd36..359160ac13 100644 --- a/src/Mod/Material/Gui/Array2D.cpp +++ b/src/Mod/Material/Gui/Array2D.cpp @@ -42,7 +42,7 @@ using namespace MatGui; /* TRANSLATOR MatGui::Array2D */ Array2D::Array2D(const QString& propertyName, - std::shared_ptr material, + const std::shared_ptr& material, QWidget* parent) : QDialog(parent) , ui(new Ui_Array2D) @@ -61,22 +61,13 @@ Array2D::Array2D(const QString& propertyName, _property = nullptr; } if (_property) { - Base::Console().Log("Value type %d\n", - static_cast(_property->getMaterialValue()->getType())); _value = std::static_pointer_cast(_property->getMaterialValue()); } else { - Base::Console().Log("No value loaded\n"); _value = nullptr; } - if (_value) { - Base::Console().Log("Value type %d\n", static_cast(_value->getType())); - // auto value = _property->getMaterialValue()->getValue(); - // Base::Console().Log("\tQVariant type %d\n", value.userType()); - } - setupDefault(); setupArray(); ui->tableView->setContextMenuPolicy(Qt::CustomContextMenu); @@ -91,36 +82,6 @@ Array2D::Array2D(const QString& propertyName, connect(ui->standardButtons, &QDialogButtonBox::rejected, this, &Array2D::reject); } -void Array2D::setupDefault() -{ - if (_property == nullptr) { - return; - } - - try { - const Materials::MaterialProperty& column1 = _property->getColumn(0); - QString label(tr("Default ") + column1.getName()); - ui->labelDefault->setText(label); - if (column1.getPropertyType() == QString::fromStdString("Quantity")) { - ui->editDefault->setMinimum(std::numeric_limits::min()); - ui->editDefault->setMaximum(std::numeric_limits::max()); - ui->editDefault->setUnitText(_property->getColumnUnits(0)); - if (!_value->defaultSet()) { - _value->setDefault(_property->getColumnNull(0).value()); - } - ui->editDefault->setValue(_value->getDefault().value()); - - connect(ui->editDefault, - qOverload(&Gui::QuantitySpinBox::valueChanged), - this, - &Array2D::defaultValueChanged); - } - } - catch (const Materials::PropertyNotFound&) { - return; - } -} - void Array2D::setHeaders(QStandardItemModel* model) { QStringList headers; @@ -178,18 +139,9 @@ void Array2D::onDataChanged(const QModelIndex& topLeft, _material->setEditStateAlter(); } -void Array2D::defaultValueChanged(const Base::Quantity& value) -{ - _value->setDefault(QVariant::fromValue(value)); - _material->setEditStateAlter(); -} - void Array2D::onContextMenu(const QPoint& pos) { - Base::Console().Log("Array2D::onContextMenu(%d,%d)\n", pos.x(), pos.y()); QModelIndex index = ui->tableView->indexAt(pos); - Base::Console().Log("\tindex at (%d,%d)\n", index.row(), index.column()); - QMenu contextMenu(tr("Context menu"), this); @@ -200,7 +152,7 @@ void Array2D::onContextMenu(const QPoint& pos) bool Array2D::newRow(const QModelIndex& index) { - Array2DModel* model = static_cast(ui->tableView->model()); + auto model = static_cast(ui->tableView->model()); return model->newRow(index); } @@ -208,10 +160,8 @@ void Array2D::onDelete(bool checked) { Q_UNUSED(checked) - Base::Console().Log("Array2D::onDelete()\n"); QItemSelectionModel* selectionModel = ui->tableView->selectionModel(); if (!selectionModel->hasSelection() || newRow(selectionModel->currentIndex())) { - Base::Console().Log("\tNothing selected\n"); return; } @@ -248,7 +198,7 @@ int Array2D::confirmDelete() void Array2D::deleteSelected() { - Array2DModel* model = static_cast(ui->tableView->model()); + auto model = static_cast(ui->tableView->model()); QItemSelectionModel* selectionModel = ui->tableView->selectionModel(); auto index = selectionModel->currentIndex(); model->deleteRow(index); diff --git a/src/Mod/Material/Gui/Array2D.h b/src/Mod/Material/Gui/Array2D.h index 11af3e5366..0829a9565e 100644 --- a/src/Mod/Material/Gui/Array2D.h +++ b/src/Mod/Material/Gui/Array2D.h @@ -47,14 +47,13 @@ class Array2D: public QDialog public: Array2D(const QString& propertyName, - std::shared_ptr material, + const std::shared_ptr& material, QWidget* parent = nullptr); ~Array2D() override = default; void onDataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight, const QVector& roles = QVector()); - void defaultValueChanged(const Base::Quantity& value); void onDelete(bool checked); void onContextMenu(const QPoint& pos); @@ -69,7 +68,6 @@ private: QAction _deleteAction; - void setupDefault(); void setHeaders(QStandardItemModel* model); void setColumnWidths(QTableView* table); void setColumnDelegates(QTableView* table); diff --git a/src/Mod/Material/Gui/Array2D.ui b/src/Mod/Material/Gui/Array2D.ui index 3911c2f6d3..c90f671e97 100644 --- a/src/Mod/Material/Gui/Array2D.ui +++ b/src/Mod/Material/Gui/Array2D.ui @@ -14,24 +14,6 @@ 2D Array - - - - - - Default Value - - - - - - - - - - - - @@ -47,13 +29,6 @@ - - - Gui::QuantitySpinBox - QWidget -
Gui/QuantitySpinBox.h
-
-
diff --git a/src/Mod/Material/Gui/Array3D.cpp b/src/Mod/Material/Gui/Array3D.cpp index fb047809eb..37677a5f62 100644 --- a/src/Mod/Material/Gui/Array3D.cpp +++ b/src/Mod/Material/Gui/Array3D.cpp @@ -40,7 +40,7 @@ using namespace MatGui; Array3D::Array3D(const QString& propertyName, - std::shared_ptr material, + const std::shared_ptr& material, QWidget* parent) : QDialog(parent) , ui(new Ui_Array3D) @@ -63,11 +63,9 @@ Array3D::Array3D(const QString& propertyName, std::static_pointer_cast(_property->getMaterialValue()); } else { - Base::Console().Log("No value loaded\n"); _value = nullptr; } - setupDefault(); setupDepthArray(); setupArray(); @@ -87,12 +85,6 @@ Array3D::Array3D(const QString& propertyName, connect(&_delete2DAction, &QAction::triggered, this, &Array3D::on2DDelete); ui->table2D->addAction(&_delete2DAction); - Base::Console().Log("Material '%s'\n", material->getName().toStdString().c_str()); - Base::Console().Log("\tproperty '%s'\n", propertyName.toStdString().c_str()); - - // connect(ui->splitter, &QSplitter::event, - // this, &Array3D::onSplitter); - connect(ui->standardButtons->button(QDialogButtonBox::Ok), &QPushButton::clicked, this, @@ -114,42 +106,6 @@ bool Array3D::onSplitter(QEvent* e) return false; } -void Array3D::setupDefault() -{ - if (_property == nullptr) { - return; - } - - try { - auto& column1 = _property->getColumn(0); - QString label = tr("Default ") + column1.getName(); - ui->labelDefault->setText(label); - if (column1.getPropertyType() == QString::fromStdString("Quantity")) { - ui->editDefault->setMinimum(std::numeric_limits::min()); - ui->editDefault->setMaximum(std::numeric_limits::max()); - ui->editDefault->setUnitText(_property->getColumnUnits(0)); - if (!_value->defaultSet()) { - _value->setDefault(_property->getColumnNull(0).value()); - } - ui->editDefault->setValue(_value->getDefault().value()); - - connect(ui->editDefault, - qOverload(&Gui::QuantitySpinBox::valueChanged), - this, - &Array3D::defaultValueChanged); - } - } - catch (const Materials::PropertyNotFound&) { - return; - } -} - -void Array3D::defaultValueChanged(const Base::Quantity& value) -{ - _value->setDefault(QVariant::fromValue(value)); - _material->setEditStateAlter(); -} - void Array3D::setDepthColumnDelegate(QTableView* table) { auto& column = _property->getColumn(0); @@ -275,11 +231,6 @@ void Array3D::update2DArray() void Array3D::onDepthContextMenu(const QPoint& pos) { - Base::Console().Log("Array3D::onDepthContextMenu(%d,%d)\n", pos.x(), pos.y()); - QModelIndex index = ui->table3D->indexAt(pos); - Base::Console().Log("\tindex at (%d,%d)\n", index.row(), index.column()); - - QMenu contextMenu(tr("Context menu"), this); contextMenu.addAction(&_deleteDepthAction); @@ -289,7 +240,7 @@ void Array3D::onDepthContextMenu(const QPoint& pos) bool Array3D::newDepthRow(const QModelIndex& index) { - Array3DDepthModel* model = static_cast(ui->table3D->model()); + auto model = static_cast(ui->table3D->model()); return model->newRow(index); } @@ -297,10 +248,8 @@ void Array3D::onDepthDelete(bool checked) { Q_UNUSED(checked) - Base::Console().Log("Array3D::onDepthDelete()\n"); QItemSelectionModel* selectionModel = ui->table3D->selectionModel(); if (!selectionModel->hasSelection() || newDepthRow(selectionModel->currentIndex())) { - Base::Console().Log("\tNothing selected\n"); return; } @@ -338,7 +287,7 @@ int Array3D::confirmDepthDelete() void Array3D::deleteDepthSelected() { - Array3DDepthModel* model = static_cast(ui->table3D->model()); + auto model = static_cast(ui->table3D->model()); QItemSelectionModel* selectionModel = ui->table3D->selectionModel(); auto index = selectionModel->currentIndex(); model->deleteRow(index); @@ -353,11 +302,6 @@ void Array3D::deleteDepthSelected() void Array3D::on2DContextMenu(const QPoint& pos) { - Base::Console().Log("Array3D::onDepthContextMenu(%d,%d)\n", pos.x(), pos.y()); - QModelIndex index = ui->table2D->indexAt(pos); - Base::Console().Log("\tindex at (%d,%d)\n", index.row(), index.column()); - - QMenu contextMenu(tr("Context menu"), this); contextMenu.addAction(&_delete2DAction); @@ -368,7 +312,7 @@ void Array3D::on2DContextMenu(const QPoint& pos) bool Array3D::new2DRow(const QModelIndex& index) { - Array3DModel* model = static_cast(ui->table2D->model()); + auto model = static_cast(ui->table2D->model()); return model->newRow(index); } @@ -376,10 +320,8 @@ void Array3D::on2DDelete(bool checked) { Q_UNUSED(checked) - Base::Console().Log("Array3D::on2DDelete()\n"); QItemSelectionModel* selectionModel = ui->table2D->selectionModel(); if (!selectionModel->hasSelection() || new2DRow(selectionModel->currentIndex())) { - Base::Console().Log("\tNothing selected\n"); return; } @@ -416,7 +358,7 @@ int Array3D::confirm2dDelete() void Array3D::delete2DSelected() { - Array3DModel* model = static_cast(ui->table2D->model()); + auto model = static_cast(ui->table2D->model()); QItemSelectionModel* selectionModel = ui->table2D->selectionModel(); auto index = selectionModel->currentIndex(); model->deleteRow(index); diff --git a/src/Mod/Material/Gui/Array3D.h b/src/Mod/Material/Gui/Array3D.h index 28903b31b9..00c9b6d68f 100644 --- a/src/Mod/Material/Gui/Array3D.h +++ b/src/Mod/Material/Gui/Array3D.h @@ -40,11 +40,10 @@ class Array3D: public QDialog public: Array3D(const QString& propertyName, - std::shared_ptr material, + const std::shared_ptr& material, QWidget* parent = nullptr); ~Array3D() override = default; - void defaultValueChanged(const Base::Quantity& value); void onRowsInserted(const QModelIndex& parent, int first, int last); void onRowsRemoved(const QModelIndex& parent, int first, int last); void onDataChanged(const QModelIndex& topLeft, @@ -75,7 +74,6 @@ private: bool newDepthRow(const QModelIndex& index); bool new2DRow(const QModelIndex& index); - void setupDefault(); void setDepthColumnWidth(QTableView* table); void setDepthColumnDelegate(QTableView* table); void setupDepthArray(); diff --git a/src/Mod/Material/Gui/Array3D.ui b/src/Mod/Material/Gui/Array3D.ui index 7d2d6dd669..27bdc373ee 100644 --- a/src/Mod/Material/Gui/Array3D.ui +++ b/src/Mod/Material/Gui/Array3D.ui @@ -14,30 +14,6 @@ 3D Array - - - - - - - 0 - 0 - - - - Default Value - - - - - - - - - - - - @@ -59,13 +35,6 @@ - - - Gui::QuantitySpinBox - QWidget -
Gui/QuantitySpinBox.h
-
-
diff --git a/src/Mod/Material/Gui/ArrayDelegate.cpp b/src/Mod/Material/Gui/ArrayDelegate.cpp index 255cac8168..4ad6bffe93 100644 --- a/src/Mod/Material/Gui/ArrayDelegate.cpp +++ b/src/Mod/Material/Gui/ArrayDelegate.cpp @@ -57,7 +57,7 @@ using namespace MatGui; ArrayDelegate::ArrayDelegate(Materials::MaterialValue::ValueType type, - QString units, + const QString& units, QObject* parent) : QStyledItemDelegate(parent) , _type(type) @@ -70,8 +70,7 @@ void ArrayDelegate::paint(QPainter* painter, { if (_type == Materials::MaterialValue::Quantity) { - const AbstractArrayModel* tableModel = - reinterpret_cast(index.model()); + auto* tableModel = dynamic_cast(index.model()); painter->save(); if (tableModel->newRow(index)) { @@ -79,7 +78,7 @@ void ArrayDelegate::paint(QPainter* painter, } else { QVariant item = tableModel->data(index); - Base::Quantity quantity = item.value(); + auto quantity = item.value(); QString text = quantity.getUserString(); painter->drawText(option.rect, 0, text); } @@ -93,15 +92,11 @@ void ArrayDelegate::paint(QPainter* painter, void ArrayDelegate::setEditorData(QWidget* editor, const QModelIndex& index) const { - Base::Console().Log("ArrayDelegate::setEditorData()\n"); - if (_type == Materials::MaterialValue::Quantity) { - QAbstractItemModel* tableModel = const_cast(index.model()); + auto tableModel = dynamic_cast(index.model()); auto item = tableModel->data(index); - // Gui::InputField* input = static_cast(editor); - // input->setText(item.toString()); - Gui::QuantitySpinBox* input = static_cast(editor); + auto input = static_cast(editor); input->setValue(item.value()); } else { @@ -110,12 +105,12 @@ void ArrayDelegate::setEditorData(QWidget* editor, const QModelIndex& index) con } QWidget* ArrayDelegate::createEditor(QWidget* parent, - const QStyleOptionViewItem&, + const QStyleOptionViewItem& styleOption, const QModelIndex& index) const { - Base::Console().Log("ArrayDelegate::createEditor()\n"); + Q_UNUSED(styleOption) - const QAbstractTableModel* tableModel = static_cast(index.model()); + auto tableModel = dynamic_cast(index.model()); auto item = tableModel->data(index); QWidget* editor = createWidget(parent, item); @@ -139,7 +134,7 @@ QWidget* ArrayDelegate::createWidget(QWidget* parent, const QVariant& item) cons widget = spinner; } else if (_type == Materials::MaterialValue::Float) { - Gui::DoubleSpinBox* spinner = new Gui::DoubleSpinBox(parent); + auto spinner = new Gui::DoubleSpinBox(parent); // the magnetic permeability is the parameter for which many decimals matter // the most however, even for this, 6 digits are sufficient @@ -154,7 +149,7 @@ QWidget* ArrayDelegate::createWidget(QWidget* parent, const QVariant& item) cons widget = spinner; } else if (_type == Materials::MaterialValue::Boolean) { - Gui::PrefComboBox* combo = new Gui::PrefComboBox(parent); + auto combo = new Gui::PrefComboBox(parent); combo->insertItem(0, QString::fromStdString("")); combo->insertItem(1, tr("False")); combo->insertItem(2, tr("True")); @@ -162,7 +157,7 @@ QWidget* ArrayDelegate::createWidget(QWidget* parent, const QVariant& item) cons widget = combo; } else if (_type == Materials::MaterialValue::Quantity) { - Gui::QuantitySpinBox* input = new Gui::QuantitySpinBox(); + auto input = new Gui::QuantitySpinBox(); input->setMinimum(std::numeric_limits::min()); input->setMaximum(std::numeric_limits::max()); input->setUnitText(_units); @@ -170,6 +165,15 @@ QWidget* ArrayDelegate::createWidget(QWidget* parent, const QVariant& item) cons widget = input; } + else if (_type == Materials::MaterialValue::FileList) { + auto chooser = new Gui::FileChooser(); + auto propertyValue = item.toString(); + if (!propertyValue.isEmpty()) { + chooser->setFileName(propertyValue); + } + + widget = chooser; + } else { // Default editor widget = new QLineEdit(parent); @@ -179,5 +183,3 @@ QWidget* ArrayDelegate::createWidget(QWidget* parent, const QVariant& item) cons return widget; } - -#include "moc_ArrayDelegate.cpp" diff --git a/src/Mod/Material/Gui/ArrayDelegate.h b/src/Mod/Material/Gui/ArrayDelegate.h index 2f07398a79..75815b77ae 100644 --- a/src/Mod/Material/Gui/ArrayDelegate.h +++ b/src/Mod/Material/Gui/ArrayDelegate.h @@ -41,7 +41,7 @@ class ArrayDelegate: public QStyledItemDelegate Q_OBJECT public: ArrayDelegate(Materials::MaterialValue::ValueType type = Materials::MaterialValue::None, - QString units = QString(), + const QString& units = QString(), QObject* parent = nullptr); virtual ~ArrayDelegate() = default; @@ -49,14 +49,10 @@ public: const QStyleOptionViewItem& option, const QModelIndex& index) const override; QWidget* createEditor(QWidget* parent, - const QStyleOptionViewItem&, + const QStyleOptionViewItem& styleOption, const QModelIndex& index) const override; void setEditorData(QWidget* editor, const QModelIndex& index) const override; - // Q_SIGNALS: - /** Emits this signal when a property has changed */ - // void propertyChange(const QString &property, const QString value); - private: Materials::MaterialValue::ValueType _type; QString _units; diff --git a/src/Mod/Material/Gui/ArrayModel.cpp b/src/Mod/Material/Gui/ArrayModel.cpp index 7c420a3495..c7f581316e 100644 --- a/src/Mod/Material/Gui/ArrayModel.cpp +++ b/src/Mod/Material/Gui/ArrayModel.cpp @@ -23,6 +23,7 @@ #ifndef _PreComp_ #endif +#include #include #include @@ -46,8 +47,8 @@ AbstractArrayModel::AbstractArrayModel(QObject* parent) //=== -Array2DModel::Array2DModel(std::shared_ptr property, - std::shared_ptr value, +Array2DModel::Array2DModel(const std::shared_ptr& property, + const std::shared_ptr& value, QObject* parent) : AbstractArrayModel(parent) , _property(property) @@ -93,17 +94,17 @@ QVariant Array2DModel::data(const QModelIndex& index, int role) const try { auto column = _property->getColumnType(index.column()); if (column == Materials::MaterialValue::Quantity) { - Base::Quantity q = Base::Quantity(0, _property->getColumnUnits(index.column())); - return QVariant::fromValue(q); + Base::Quantity qq = Base::Quantity(0, _property->getColumnUnits(index.column())); + return QVariant::fromValue(qq); } } - catch (const Materials::InvalidColumn&) { + catch (const Materials::InvalidIndex&) { } return QString(); } - return QVariant(); + return {}; } QVariant Array2DModel::headerData(int section, Qt::Orientation orientation, int role) const @@ -111,14 +112,14 @@ QVariant Array2DModel::headerData(int section, Qt::Orientation orientation, int if (role == Qt::DisplayRole) { if (orientation == Qt::Horizontal) { const Materials::MaterialProperty& column = _property->getColumn(section); - return QVariant(column.getName()); + return column.getName(); } else if (orientation == Qt::Vertical) { // Vertical header if (section == (rowCount() - 1)) { - return QVariant(QString::fromStdString("*")); + return QString::fromStdString("*"); } - return QVariant(section + 1); + return {section + 1}; } } @@ -151,7 +152,7 @@ bool Array2DModel::insertRows(int row, int count, const QModelIndex& parent) int columns = columnCount(); for (int i = 0; i < count; i++) { - auto rowPtr = std::make_shared>(); + auto rowPtr = std::make_shared>(); for (int j = 0; j < columns; j++) { rowPtr->push_back(_property->getColumnNull(j)); } @@ -197,8 +198,8 @@ bool Array2DModel::removeColumns(int column, int count, const QModelIndex& paren //=== -Array3DDepthModel::Array3DDepthModel(std::shared_ptr property, - std::shared_ptr value, +Array3DDepthModel::Array3DDepthModel(const std::shared_ptr& property, + const std::shared_ptr& value, QObject* parent) : AbstractArrayModel(parent) , _property(property) @@ -229,27 +230,21 @@ QVariant Array3DDepthModel::data(const QModelIndex& index, int role) const { if (role == Qt::DisplayRole) { try { - Base::Quantity q = _value->getDepthValue(index.row()); - return QVariant::fromValue(q); - } - catch (const Materials::InvalidDepth&) { - } - catch (const Materials::InvalidRow&) { - } - catch (const Materials::InvalidColumn&) { + Base::Quantity qq = _value->getDepthValue(index.row()); + return QVariant::fromValue(qq); } catch (const Materials::InvalidIndex&) { } try { - Base::Quantity q = Base::Quantity(0, _property->getColumnUnits(0)); - return QVariant::fromValue(q); + Base::Quantity qq = Base::Quantity(0, _property->getColumnUnits(0)); + return QVariant::fromValue(qq); } - catch (const Materials::InvalidColumn&) { + catch (const Materials::InvalidIndex&) { } } - return QVariant(); + return {}; } QVariant Array3DDepthModel::headerData(int section, Qt::Orientation orientation, int role) const @@ -257,14 +252,14 @@ QVariant Array3DDepthModel::headerData(int section, Qt::Orientation orientation, if (role == Qt::DisplayRole) { if (orientation == Qt::Horizontal) { const Materials::MaterialProperty& column = _property->getColumn(section); - return QVariant(column.getName()); + return column.getName(); } - else if (orientation == Qt::Vertical) { + if (orientation == Qt::Vertical) { // Vertical header if (section == (rowCount() - 1)) { - return QVariant(QString::fromStdString("*")); + return QString::fromStdString("*"); } - return QVariant(section + 1); + return {section + 1}; } } @@ -338,8 +333,8 @@ bool Array3DDepthModel::removeColumns(int column, int count, const QModelIndex& //=== -Array3DModel::Array3DModel(std::shared_ptr property, - std::shared_ptr value, +Array3DModel::Array3DModel(const std::shared_ptr& property, + const std::shared_ptr& value, QObject* parent) : AbstractArrayModel(parent) , _property(property) @@ -355,10 +350,7 @@ int Array3DModel::rowCount(const QModelIndex& parent) const try { return _value->rows() + 1; // Will always have 1 empty row } - catch (const Materials::InvalidDepth&) { - return 1; - } - catch (const Materials::InvalidRow&) { + catch (const Materials::InvalidIndex&) { return 1; } } @@ -375,10 +367,7 @@ bool Array3DModel::newRow(const QModelIndex& index) const try { return (index.row() == _value->rows()); } - catch (const Materials::InvalidDepth&) { - return true; - } - catch (const Materials::InvalidRow&) { + catch (const Materials::InvalidIndex&) { return true; } } @@ -392,16 +381,9 @@ void Array3DModel::deleteRow(const QModelIndex& index) QVariant Array3DModel::data(const QModelIndex& index, int role) const { if (role == Qt::DisplayRole) { - // Base::Console().Log("Row %d, column %d\n", index.row(), index.column()); try { - Base::Quantity q = _value->getValue(index.row(), index.column()); - return QVariant::fromValue(q); - } - catch (const Materials::InvalidDepth&) { - } - catch (const Materials::InvalidRow&) { - } - catch (const Materials::InvalidColumn&) { + Base::Quantity qq = _value->getValue(index.row(), index.column()); + return QVariant::fromValue(qq); } catch (const Materials::InvalidIndex&) { } @@ -410,14 +392,14 @@ QVariant Array3DModel::data(const QModelIndex& index, int role) const } try { - Base::Quantity q = Base::Quantity(0, _property->getColumnUnits(index.column() + 1)); - return QVariant::fromValue(q); + Base::Quantity qq = Base::Quantity(0, _property->getColumnUnits(index.column() + 1)); + return QVariant::fromValue(qq); } - catch (const Materials::InvalidColumn&) { + catch (const Materials::InvalidIndex&) { } } - return QVariant(); + return {}; } QVariant Array3DModel::headerData(int section, Qt::Orientation orientation, int role) const @@ -425,14 +407,14 @@ QVariant Array3DModel::headerData(int section, Qt::Orientation orientation, int if (role == Qt::DisplayRole) { if (orientation == Qt::Horizontal) { const Materials::MaterialProperty& column = _property->getColumn(section + 1); - return QVariant(column.getName()); + return column.getName(); } - else if (orientation == Qt::Vertical) { + if (orientation == Qt::Vertical) { // Vertical header if (section == (rowCount() - 1)) { - return QVariant(QString::fromStdString("*")); + return QString::fromStdString("*"); } - return QVariant(section + 1); + return {section + 1}; } } @@ -443,11 +425,6 @@ bool Array3DModel::setData(const QModelIndex& index, const QVariant& value, int { Q_UNUSED(role); - Base::Console().Log("Array3DModel::setData at (%d, %d, %d)\n", - _value->currentDepth(), - index.row(), - index.column()); - if (_value->depth() == 0) { // Create the first row // _value->addDepth(Base::Quantity(0, _property->getColumnUnits(0))); @@ -460,14 +437,8 @@ bool Array3DModel::setData(const QModelIndex& index, const QVariant& value, int try { _value->setValue(index.row(), index.column(), value.value()); } - catch (const Materials::InvalidDepth&) { - Base::Console().Error("Array3DModel::setData - InvalidDepth"); - } - catch (const Materials::InvalidRow&) { - Base::Console().Error("Array3DModel::setData - invalidRow"); - } - catch (const Materials::InvalidColumn&) { - Base::Console().Error("Array3DModel::setData - InvalidColumn"); + catch (const Materials::InvalidIndex&) { + Base::Console().Error("Array3DModel::setData - InvalidIndex"); } Q_EMIT dataChanged(index, index); @@ -487,7 +458,7 @@ bool Array3DModel::insertRows(int row, int count, const QModelIndex& parent) int columns = columnCount(); for (int i = 0; i < count; i++) { - auto rowPtr = std::make_shared>(); + auto rowPtr = std::make_shared>(); for (int j = 0; j < columns; j++) { rowPtr->push_back(_property->getColumnNull(j).value()); } diff --git a/src/Mod/Material/Gui/ArrayModel.h b/src/Mod/Material/Gui/ArrayModel.h index 303e94c6f6..da5bf69fac 100644 --- a/src/Mod/Material/Gui/ArrayModel.h +++ b/src/Mod/Material/Gui/ArrayModel.h @@ -47,8 +47,8 @@ public: class Array2DModel: public AbstractArrayModel { public: - explicit Array2DModel(std::shared_ptr property = nullptr, - std::shared_ptr value = nullptr, + explicit Array2DModel(const std::shared_ptr& property = nullptr, + const std::shared_ptr& value = nullptr, QObject* parent = nullptr); ~Array2DModel() override = default; @@ -77,9 +77,10 @@ private: class Array3DDepthModel: public AbstractArrayModel { public: - explicit Array3DDepthModel(std::shared_ptr property = nullptr, - std::shared_ptr value = nullptr, - QObject* parent = nullptr); + explicit Array3DDepthModel( + const std::shared_ptr& property = nullptr, + const std::shared_ptr& value = nullptr, + QObject* parent = nullptr); ~Array3DDepthModel() override = default; // Overridden virtual functions @@ -111,8 +112,8 @@ private: class Array3DModel: public AbstractArrayModel { public: - explicit Array3DModel(std::shared_ptr property = nullptr, - std::shared_ptr value = nullptr, + explicit Array3DModel(const std::shared_ptr& property = nullptr, + const std::shared_ptr& value = nullptr, QObject* parent = nullptr); ~Array3DModel() override = default; diff --git a/src/Mod/Material/Gui/BaseDelegate.cpp b/src/Mod/Material/Gui/BaseDelegate.cpp new file mode 100644 index 0000000000..4776d737a5 --- /dev/null +++ b/src/Mod/Material/Gui/BaseDelegate.cpp @@ -0,0 +1,421 @@ +/*************************************************************************** + * 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" +#ifndef _PreComp_ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#endif + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +// #include + +#include +#include + +#include "BaseDelegate.h" +#include "ListModel.h" +#include "MaterialSave.h" + + +using namespace MatGui; + +BaseDelegate::BaseDelegate(Materials::MaterialValue::ValueType type, + const QString& units, + QObject* parent) + : QStyledItemDelegate(parent) + , _type(type) + , _units(units) +{} + +bool BaseDelegate::newRow(const QAbstractItemModel* model, const QModelIndex& index) const +{ + // The model always includes an empty row to allow for additions + return (index.row() == (model->rowCount() - 1)); +} + +QString BaseDelegate::getStringValue(const QModelIndex& index) const +{ + auto model = index.model(); + QVariant item = model->data(index); + auto propertyValue = item.value(); + + return propertyValue; +} + +QRgb BaseDelegate::parseColor(const QString& color) const +{ + QString trimmed = color; + trimmed.replace(QRegularExpression(QString::fromStdString("\\(([^<]*)\\)")), + QString::fromStdString("\\1")); + QStringList parts = trimmed.split(QString::fromStdString(",")); + if (parts.length() < 3) { + return qRgba(0, 0, 0, 255); + } + int red = parts.at(0).toDouble() * 255; + int green = parts.at(1).toDouble() * 255; + int blue = parts.at(2).toDouble() * 255; + int alpha = 255; + if (parts.length() > 3) { + alpha = parts.at(3).toDouble() * 255; + } + + return qRgba(red, green, blue, alpha); +} + +void BaseDelegate::paintQuantity(QPainter* painter, + const QStyleOptionViewItem& option, + const QModelIndex& index) const +{ + auto model = index.model(); + painter->save(); + + if (newRow(model, index)) { + painter->drawText(option.rect, 0, QString()); + } + else { + QVariant item = model->data(index); + auto quantity = item.value(); + QString text = quantity.getUserString(); + painter->drawText(option.rect, 0, text); + } + + painter->restore(); +} + +void BaseDelegate::paintImage(QPainter* painter, + const QStyleOptionViewItem& option, + const QModelIndex& index) const +{ + auto propertyValue = getStringValue(index); + + painter->save(); + + QImage img; + if (!propertyValue.isEmpty()) { + Base::Console().Log("Loading image\n"); + QByteArray by = QByteArray::fromBase64(propertyValue.toUtf8()); + img = QImage::fromData(by, "PNG").scaled(64, 64, Qt::KeepAspectRatio); + } + QRect target(option.rect); + if (target.width() > target.height()) { + target.setWidth(target.height()); + } + else { + target.setHeight(target.width()); + } + painter->drawImage(target, img, img.rect()); + + painter->restore(); +} + +void BaseDelegate::paintColor(QPainter* painter, + const QStyleOptionViewItem& option, + const QModelIndex& index) const +{ + auto propertyValue = getStringValue(index); + painter->save(); + + QColor color; + color.setRgba(qRgba(0, 0, 0, 255)); // Black border + int left = option.rect.left() + 2; + int width = option.rect.width() - 4; + if (option.rect.width() > 75) { + left += (option.rect.width() - 75) / 2; + width = 71; + } + painter->fillRect(left, option.rect.top() + 2, width, option.rect.height() - 4, QBrush(color)); + + color.setRgba(parseColor(propertyValue)); + left = option.rect.left() + 5; + width = option.rect.width() - 10; + if (option.rect.width() > 75) { + left += (option.rect.width() - 75) / 2; + width = 65; + } + painter->fillRect(left, option.rect.top() + 5, width, option.rect.height() - 10, QBrush(color)); + + painter->restore(); +} + +void BaseDelegate::paintList(QPainter* painter, + const QStyleOptionViewItem& option, + const QModelIndex& index) const +{ + painter->save(); + + QImage list(QString::fromStdString(":/icons/list.svg")); + QRect target(option.rect); + if (target.width() > target.height()) { + target.setWidth(target.height()); + } + else { + target.setHeight(target.width()); + } + painter->drawImage(target, list, list.rect()); + + painter->restore(); +} + +void BaseDelegate::paintMultiLineString(QPainter* painter, + const QStyleOptionViewItem& option, + const QModelIndex& index) const +{ + painter->save(); + + QImage table(QString::fromStdString(":/icons/multiline.svg")); + QRect target(option.rect); + if (target.width() > target.height()) { + target.setWidth(target.height()); + } + else { + target.setHeight(target.width()); + } + painter->drawImage(target, table, table.rect()); + + painter->restore(); +} + +void BaseDelegate::paintArray(QPainter* painter, + const QStyleOptionViewItem& option, + const QModelIndex& index) const +{ + painter->save(); + + QImage table(QString::fromStdString(":/icons/table.svg")); + QRect target(option.rect); + if (target.width() > target.height()) { + target.setWidth(target.height()); + } + else { + target.setHeight(target.width()); + } + painter->drawImage(target, table, table.rect()); + + painter->restore(); + return; +} + +void BaseDelegate::paint(QPainter* painter, + const QStyleOptionViewItem& option, + const QModelIndex& index) const +{ + + if (_type == Materials::MaterialValue::Quantity) { + paintQuantity(painter, option, index); + return; + } + if (_type == Materials::MaterialValue::Image) { + paintImage(painter, option, index); + return; + } + if (_type == Materials::MaterialValue::Color) { + paintColor(painter, option, index); + return; + } + if (_type == Materials::MaterialValue::List || _type == Materials::MaterialValue::FileList + || _type == Materials::MaterialValue::ImageList) { + paintList(painter, option, index); + return; + } + if (_type == Materials::MaterialValue::MultiLineString) { + paintMultiLineString(painter, option, index); + return; + } + if (_type == Materials::MaterialValue::Array2D || _type == Materials::MaterialValue::Array3D) { + paintArray(painter, option, index); + return; + } + + QStyledItemDelegate::paint(painter, option, index); +} + +QSize BaseDelegate::sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const +{ + Q_UNUSED(option) + Q_UNUSED(index) + + if (_type == Materials::MaterialValue::Color) { + return {75, 23}; // Standard QPushButton size + } + if (_type == Materials::MaterialValue::Image || _type == Materials::MaterialValue::ImageList) { + return {64, 64}; + } + if (_type == Materials::MaterialValue::Array2D || _type == Materials::MaterialValue::Array3D + || _type == Materials::MaterialValue::MultiLineString + || _type == Materials::MaterialValue::List || _type == Materials::MaterialValue::FileList + || _type == Materials::MaterialValue::ImageList) { + return {23, 23}; + } + + return QStyledItemDelegate::sizeHint(option, index); +} + +void BaseDelegate::setEditorData(QWidget* editor, const QModelIndex& index) const +{ + auto model = index.model(); + auto item = model->data(index); + + if (_type == Materials::MaterialValue::List) { + auto input = dynamic_cast(editor); + item = input->text(); + return; + } + if (_type == Materials::MaterialValue::FileList || _type == Materials::MaterialValue::File) { + auto chooser = dynamic_cast(editor); + chooser->setFileName(item.toString()); + return; + } + if (_type == Materials::MaterialValue::Quantity) { + auto input = dynamic_cast(editor); + input->setQuantityString(item.toString()); + return; + } + + QStyledItemDelegate::setEditorData(editor, index); +} + +void BaseDelegate::setModelData(QWidget* editor, + QAbstractItemModel* model, + const QModelIndex& index) const +{ + if (_type == Materials::MaterialValue::FileList) { + auto chooser = dynamic_cast(editor); + model->setData(index, chooser->fileName()); + } + else { + QStyledItemDelegate::setModelData(editor, model, index); + } +} + +QWidget* BaseDelegate::createEditor(QWidget* parent, + const QStyleOptionViewItem& styleOption, + const QModelIndex& index) const +{ + Q_UNUSED(styleOption) + + auto model = index.model(); + + // If this is a new row then it has to be added before the editor is created. Otherwise + // Adding the row while the editor is active can change where the editor is placed. + if (newRow(model, index)) { + const_cast(model)->insertRows(index.row(), 1); + } + auto item = model->data(index); + + QWidget* editor = createWidget(parent, item, index); + + return editor; +} + +QWidget* +BaseDelegate::createWidget(QWidget* parent, const QVariant& item, const QModelIndex& index) const +{ + QWidget* widget = nullptr; + + if (_type == Materials::MaterialValue::String || _type == Materials::MaterialValue::URL + || _type == Materials::MaterialValue::List) { + auto lineEdit = new Gui::PrefLineEdit(parent); + lineEdit->setText(item.toString()); + widget = lineEdit; + } + else if (_type == Materials::MaterialValue::Integer) { + auto spinner = new Gui::UIntSpinBox(parent); + spinner->setMinimum(0); + spinner->setMaximum(UINT_MAX); + spinner->setValue(item.toUInt()); + widget = spinner; + } + else if (_type == Materials::MaterialValue::Float) { + auto spinner = new Gui::DoubleSpinBox(parent); + + // the magnetic permeability is the parameter for which many decimals matter + // the most however, even for this, 6 digits are sufficient + spinner->setDecimals(6); + + // for almost all Float parameters of materials a step of 1 would be too large + spinner->setSingleStep(0.1); + + spinner->setMinimum(std::numeric_limits::min()); + spinner->setMaximum(std::numeric_limits::max()); + spinner->setValue(item.toDouble()); + widget = spinner; + } + else if (_type == Materials::MaterialValue::Boolean) { + auto combo = new Gui::PrefComboBox(parent); + combo->insertItem(0, QString::fromStdString("")); + combo->insertItem(1, tr("False")); + combo->insertItem(2, tr("True")); + combo->setCurrentText(item.toString()); + widget = combo; + } + else if (_type == Materials::MaterialValue::Quantity) { + auto input = new Gui::QuantitySpinBox(parent); + input->setMinimum(std::numeric_limits::min()); + input->setMaximum(std::numeric_limits::max()); + input->setUnitText(_units); + input->setValue(item.value()); + + widget = input; + } + else if (_type == Materials::MaterialValue::FileList) { + auto chooser = new Gui::FileChooser(parent); + auto propertyValue = item.toString(); + + connect(chooser, + &Gui::FileChooser::fileNameChanged, + [this, chooser, index](const QString&) { + setModelData(chooser, const_cast(index.model()), index); + }); + + connect(chooser, + &Gui::FileChooser::fileNameSelected, + [this, chooser, index](const QString&) { + setModelData(chooser, const_cast(index.model()), index); + }); + widget = chooser; + } + else { + // Default editor + widget = new QLineEdit(parent); + } + + return widget; +} + +#include "moc_BaseDelegate.cpp" diff --git a/src/Mod/Material/Gui/BaseDelegate.h b/src/Mod/Material/Gui/BaseDelegate.h new file mode 100644 index 0000000000..31d3201019 --- /dev/null +++ b/src/Mod/Material/Gui/BaseDelegate.h @@ -0,0 +1,95 @@ +/*************************************************************************** + * 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 * + * . * + * * + **************************************************************************/ + +#ifndef MATGUI_BASEDELEGATE_H +#define MATGUI_BASEDELEGATE_H + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +namespace MatGui +{ + +class BaseDelegate: public QStyledItemDelegate +{ + Q_OBJECT +public: + BaseDelegate(Materials::MaterialValue::ValueType type = Materials::MaterialValue::None, + const QString& units = QString(), + QObject* parent = nullptr); + virtual ~BaseDelegate() = default; + + QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const; + void paint(QPainter* painter, + const QStyleOptionViewItem& option, + const QModelIndex& index) const override; + QWidget* createEditor(QWidget* parent, + const QStyleOptionViewItem& styleOption, + const QModelIndex& index) const override; + void setEditorData(QWidget* editor, const QModelIndex& index) const override; + void setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const; + + // Q_SIGNALS: + /** Emits this signal when a property has changed */ + // void propertyChange(const QModelIndex& index, const QString value); + +protected: + Materials::MaterialValue::ValueType _type; + QString _units; + + + QString getStringValue(const QModelIndex& index) const; + QRgb parseColor(const QString& color) const; + + void paintQuantity(QPainter* painter, + const QStyleOptionViewItem& option, + const QModelIndex& index) const; + void paintImage(QPainter* painter, + const QStyleOptionViewItem& option, + const QModelIndex& index) const; + void paintColor(QPainter* painter, + const QStyleOptionViewItem& option, + const QModelIndex& index) const; + void paintList(QPainter* painter, + const QStyleOptionViewItem& option, + const QModelIndex& index) const; + void paintMultiLineString(QPainter* painter, + const QStyleOptionViewItem& option, + const QModelIndex& index) const; + void paintArray(QPainter* painter, + const QStyleOptionViewItem& option, + const QModelIndex& index) const; + + bool newRow(const QAbstractItemModel* model, const QModelIndex& index) const; + QWidget* createWidget(QWidget* parent, const QVariant& item, const QModelIndex& index) const; +}; + +} // namespace MatGui + +#endif // MATGUI_BASEDELEGATE_H diff --git a/src/Mod/Material/Gui/CMakeLists.txt b/src/Mod/Material/Gui/CMakeLists.txt index f464cfdcf3..8c250f8a7e 100644 --- a/src/Mod/Material/Gui/CMakeLists.txt +++ b/src/Mod/Material/Gui/CMakeLists.txt @@ -40,6 +40,7 @@ set(MatGui_UIC_SRCS Array2D.ui Array3D.ui DlgSettingsMaterial.ui + ImageEdit.ui ListEdit.ui MaterialSave.ui MaterialsEditor.ui @@ -50,6 +51,8 @@ set(MatGui_UIC_SRCS SET(MatGui_SRCS ${MatGui_QRC_SRCS} ${MatGui_UIC_HDRS} + AppearancePreview.h + AppearancePreview.cpp AppMatGui.cpp Array2D.cpp Array2D.h @@ -61,15 +64,22 @@ SET(MatGui_SRCS ArrayDelegate.h ArrayModel.cpp ArrayModel.h + BaseDelegate.cpp + BaseDelegate.h Command.cpp DlgSettingsMaterial.cpp DlgSettingsMaterial.h DlgSettingsMaterial.ui - ListModel.cpp - ListModel.h + ImageEdit.cpp + ImageEdit.h + ImageEdit.ui + ListDelegate.cpp + ListDelegate.h ListEdit.cpp ListEdit.h ListEdit.ui + ListModel.cpp + ListModel.h MaterialDelegate.cpp MaterialDelegate.h MaterialSave.cpp @@ -107,6 +117,10 @@ SET(MatGuiIcon_SVG Resources/icons/table.svg ) +SET(MatGuiImages + Resources/images/default_image.png +) + add_library(MatGui SHARED ${MatGui_SRCS} ${MatGuiIcon_SVG}) target_link_libraries(MatGui ${MatGui_LIBS}) @@ -114,6 +128,8 @@ SET_BIN_DIR(MatGui MatGui /Mod/Material) SET_PYTHON_PREFIX_SUFFIX(MatGui) fc_copy_sources(MatGui "${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_DATADIR}/Mod/Material" ${MatGuiIcon_SVG}) +fc_copy_sources(MatGui "${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_DATADIR}/Mod/Material" ${MatGuiImages}) INSTALL(TARGETS MatGui DESTINATION ${CMAKE_INSTALL_LIBDIR}) INSTALL(FILES ${MatGuiIcon_SVG} DESTINATION "${CMAKE_INSTALL_DATADIR}/Mod/Material/Resources/icons") +INSTALL(FILES ${MatGuiImages} DESTINATION "${CMAKE_INSTALL_DATADIR}/Mod/Material/Resources/images") diff --git a/src/Mod/Material/Gui/ImageEdit.cpp b/src/Mod/Material/Gui/ImageEdit.cpp new file mode 100644 index 0000000000..7111ab8335 --- /dev/null +++ b/src/Mod/Material/Gui/ImageEdit.cpp @@ -0,0 +1,163 @@ +/*************************************************************************** + * 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" +#ifndef _PreComp_ +#include +#endif + +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include "ArrayDelegate.h" +#include "ArrayModel.h" +#include "ImageEdit.h" +#include "ListModel.h" +#include "ui_ImageEdit.h" + + +using namespace MatGui; + +/* TRANSLATOR MatGui::ImageEdit */ + +ImageLabel::ImageLabel(QWidget* parent) + : QLabel(parent) +{} + +void ImageLabel::setPixmap(const QPixmap& pixmap) +{ + _pixmap = pixmap; + QLabel::setPixmap(pixmap); +} + +void ImageLabel::resizeEvent(QResizeEvent* event) +{ + QPixmap px = _pixmap.scaled(event->size(), Qt::KeepAspectRatio); + QLabel::setPixmap(px); + QLabel::resizeEvent(event); +} + +//=== + +ImageEdit::ImageEdit(const QString& propertyName, + const std::shared_ptr& material, + QWidget* parent) + : QDialog(parent) + , ui(new Ui_ImageEdit) + , _material(material) + , _pixmap(QString::fromStdString(":/images/default_image.png")) +{ + ui->setupUi(this); + + if (material->hasPhysicalProperty(propertyName)) { + _property = material->getPhysicalProperty(propertyName); + } + else if (material->hasAppearanceProperty(propertyName)) { + _property = material->getAppearanceProperty(propertyName); + } + else { + Base::Console().Log("Property '%s' not found\n", propertyName.toStdString().c_str()); + _property = nullptr; + } + if (_property) { + QString value = _property->getString(); + if (!value.isEmpty()) { + QByteArray by = QByteArray::fromBase64(value.toUtf8()); + QImage img = QImage::fromData(by, "PNG"); + _pixmap = QPixmap::fromImage(img); + } + } + else { + Base::Console().Log("No value loaded\n"); + } + showPixmap(); + + connect(ui->buttonFileSelect, &QPushButton::clicked, this, &ImageEdit::onFileSelect); + + connect(ui->standardButtons, &QDialogButtonBox::accepted, this, &ImageEdit::accept); + connect(ui->standardButtons, &QDialogButtonBox::rejected, this, &ImageEdit::reject); +} + +void ImageEdit::showPixmap() +{ + ui->labelThumb->setPixmap(_pixmap); + ui->labelThumb->setFixedSize(64, 64); + ui->labelImage->setPixmap(_pixmap); + QString text; + ui->editWidth->setText(text.setNum(_pixmap.width())); + ui->editHeight->setText(text.setNum(_pixmap.height())); +} + +void ImageEdit::onFileSelect(bool checked) +{ + Q_UNUSED(checked) + + QFileDialog::Options dlgOpt; + if (Gui::DialogOptions::dontUseNativeFileDialog()) { + dlgOpt = QFileDialog::DontUseNativeDialog; + } + + QString directory = Gui::FileDialog::getWorkingDirectory(); + QString fn = Gui::FileDialog::getOpenFileName( + this, + tr("Select an image"), + directory, + tr("Image files (*.jpg *.jpeg *.png *.bmp);;All files (*)"), + nullptr, + dlgOpt); + + if (!fn.isEmpty()) { + fn = QDir::fromNativeSeparators(fn); + Gui::FileDialog::setWorkingDirectory(fn); + + _pixmap = QPixmap(fn); + showPixmap(); + } +} + + +void ImageEdit::accept() +{ + if (_property) { + QBuffer buffer; + buffer.open(QIODevice::WriteOnly); + _pixmap.save(&buffer, "PNG"); + QByteArray base64 = buffer.data().toBase64(); + QString encoded = QString::fromUtf8(base64); + _property->setValue(encoded); + } + QDialog::accept(); +} + +void ImageEdit::reject() +{ + QDialog::reject(); +} + +#include "moc_ImageEdit.cpp" diff --git a/src/Mod/Material/Gui/ImageEdit.h b/src/Mod/Material/Gui/ImageEdit.h new file mode 100644 index 0000000000..d048b4da10 --- /dev/null +++ b/src/Mod/Material/Gui/ImageEdit.h @@ -0,0 +1,91 @@ +/*************************************************************************** + * 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 * + * . * + * * + **************************************************************************/ + +#ifndef MATGUI_IMAGEEDIT_H +#define MATGUI_IMAGEEDIT_H + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "ListModel.h" + +namespace MatGui +{ + +class Ui_ImageEdit; + +class ImageLabel: public QLabel +{ + Q_OBJECT + +public: + explicit ImageLabel(QWidget* parent = 0); + ~ImageLabel() = default; + + void setPixmap(const QPixmap& pixmap); + +protected: + void resizeEvent(QResizeEvent* event); + +private: + QPixmap _pixmap; +}; + +class ImageEdit: public QDialog +{ + Q_OBJECT + +public: + ImageEdit(const QString& propertyName, + const std::shared_ptr& material, + QWidget* parent = nullptr); + ~ImageEdit() override = default; + + void onFileSelect(bool checked); + + void accept() override; + void reject() override; + +private: + std::unique_ptr ui; + std::shared_ptr _material; + std::shared_ptr _property; + + QPixmap _pixmap; + + void showPixmap(); +}; + +} // namespace MatGui + +#endif // MATGUI_IMAGEEDIT_H diff --git a/src/Mod/Material/Gui/ImageEdit.ui b/src/Mod/Material/Gui/ImageEdit.ui new file mode 100644 index 0000000000..2c1fc90d4d --- /dev/null +++ b/src/Mod/Material/Gui/ImageEdit.ui @@ -0,0 +1,230 @@ + + + MatGui::ImageEdit + + + + 0 + 0 + 498 + 626 + + + + Image + + + + + + QLayout::SetMinimumSize + + + + + QLayout::SetFixedSize + + + + + Thumbnail + + + + + + + + 0 + 0 + + + + + 64 + 64 + + + + QFrame::Box + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + 0 + 0 + + + + File... + + + + + + + + + Height + + + + + + + Width + + + + + + + false + + + true + + + + + + + false + + + true + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + + + + 0 + 0 + + + + + 480 + 480 + + + + QFrame::Box + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + MatGui::ImageLabel + QLabel +
Mod/Material/Gui/ImageEdit.h
+
+
+ + + + standardButtons + accepted() + MatGui::ImageEdit + accept() + + + 248 + 254 + + + 157 + 274 + + + + + standardButtons + rejected() + MatGui::ImageEdit + reject() + + + 316 + 260 + + + 286 + 274 + + + + +
diff --git a/src/Mod/Material/Gui/ListDelegate.cpp b/src/Mod/Material/Gui/ListDelegate.cpp new file mode 100644 index 0000000000..6605020cf9 --- /dev/null +++ b/src/Mod/Material/Gui/ListDelegate.cpp @@ -0,0 +1,111 @@ +/*************************************************************************** + * 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" +#ifndef _PreComp_ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#endif + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +// #include + +#include +#include + +#include "ListDelegate.h" +#include "ListModel.h" +#include "MaterialSave.h" + + +using namespace MatGui; + +ListDelegate::ListDelegate(Materials::MaterialValue::ValueType type, + const QString& units, + QObject* parent) + : BaseDelegate(type, units, parent) +{} + +void ListDelegate::paint(QPainter* painter, + const QStyleOptionViewItem& option, + const QModelIndex& index) const +{ + + if (_type == Materials::MaterialValue::Quantity) { + paintQuantity(painter, option, index); + return; + } + + if (_type == Materials::MaterialValue::Image || _type == Materials::MaterialValue::ImageList) { + paintImage(painter, option, index); + return; + } + + QStyledItemDelegate::paint(painter, option, index); +} + +// bool ListDelegate::editorEvent(QEvent* event, +// QAbstractItemModel* model, +// const QStyleOptionViewItem& option, +// const QModelIndex& index) +// { +// if (event->type() == QEvent::MouseButtonDblClick) { +// auto treeModel = index.model(); + +// auto item = treeModel->data(index); + +// int row = index.row(); + +// QString propertyName = group->child(row, 0)->text(); +// QString propertyType = QString::fromStdString("String"); +// if (group->child(row, 2)) { +// propertyType = group->child(row, 2)->text(); +// } + +// std::string type = propertyType.toStdString(); +// if (_type == Materials::MaterialValue::Image || _type == +// Materials::MaterialValue::ImageList) { +// showImageModal(propertyName, item); +// // Mark as handled +// return true; +// } +// } +// return QStyledItemDelegate::editorEvent(event, model, option, index); +// } + +#include "moc_ListDelegate.cpp" diff --git a/src/Mod/Material/Gui/ListDelegate.h b/src/Mod/Material/Gui/ListDelegate.h new file mode 100644 index 0000000000..adcb1edfbf --- /dev/null +++ b/src/Mod/Material/Gui/ListDelegate.h @@ -0,0 +1,59 @@ +/*************************************************************************** + * 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 * + * . * + * * + **************************************************************************/ + +#ifndef MATGUI_LISTDELEGATE_H +#define MATGUI_LISTDELEGATE_H + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "BaseDelegate.h" + +namespace MatGui +{ + +class ListDelegate: public BaseDelegate +{ + Q_OBJECT +public: + ListDelegate(Materials::MaterialValue::ValueType type = Materials::MaterialValue::None, + const QString& units = QString(), + QObject* parent = nullptr); + virtual ~ListDelegate() = default; + + void paint(QPainter* painter, + const QStyleOptionViewItem& option, + const QModelIndex& index) const override; + +private: +}; + +} // namespace MatGui + +#endif // MATGUI_LISTDELEGATE_H diff --git a/src/Mod/Material/Gui/ListEdit.cpp b/src/Mod/Material/Gui/ListEdit.cpp index 415b8886f8..cc1a59bad8 100644 --- a/src/Mod/Material/Gui/ListEdit.cpp +++ b/src/Mod/Material/Gui/ListEdit.cpp @@ -31,8 +31,8 @@ #include #include -#include "ArrayDelegate.h" #include "ArrayModel.h" +#include "ListDelegate.h" #include "ListEdit.h" #include "ListModel.h" #include "ui_ListEdit.h" @@ -43,7 +43,7 @@ using namespace MatGui; /* TRANSLATOR MatGui::ListEdit */ ListEdit::ListEdit(const QString& propertyName, - std::shared_ptr material, + const std::shared_ptr& material, QWidget* parent) : QDialog(parent) , ui(new Ui_ListEdit) @@ -62,40 +62,28 @@ ListEdit::ListEdit(const QString& propertyName, _property = nullptr; } if (_property) { - Base::Console().Log("Value type %d\n", - static_cast(_property->getMaterialValue()->getType())); _value = _property->getList(); } else { Base::Console().Log("No value loaded\n"); } - // if (_value) { - // Base::Console().Log("Value type %d\n", static_cast(_value->getType())); - // } setupListView(); - - // ui->listView->setContextMenuPolicy(Qt::CustomContextMenu); - // connect(ui->listView, &QWidget::customContextMenuRequested, this, &ListEdit::onContextMenu); - - // _deleteAction.setText(tr("Delete row")); - // _deleteAction.setShortcut(Qt::Key_Delete); - // connect(&_deleteAction, &QAction::triggered, this, &ListEdit::onDelete); - // ui->listView->addAction(&_deleteAction); + setDelegates(ui->listView); connect(ui->standardButtons, &QDialogButtonBox::accepted, this, &ListEdit::accept); connect(ui->standardButtons, &QDialogButtonBox::rejected, this, &ListEdit::reject); + + QItemSelectionModel* selectionModel = ui->listView->selectionModel(); + connect(selectionModel, + &QItemSelectionModel::selectionChanged, + this, + &ListEdit::onSelectionChanged); } -void ListEdit::setColumnDelegates(QListView* list) +void ListEdit::setDelegates(QListView* list) { - int length = _property->columns(); - for (int i = 0; i < length; i++) { - const Materials::MaterialProperty& column = _property->getColumn(i); - list->setItemDelegateForColumn( - i, - new ArrayDelegate(column.getType(), column.getUnits(), this)); - } + list->setItemDelegate(new ListDelegate(_property->getType(), _property->getUnits(), this)); } void ListEdit::setupListView() @@ -107,11 +95,9 @@ void ListEdit::setupListView() auto list = ui->listView; auto model = new ListModel(_property, _value, this); list->setModel(model); - // table->setEditTriggers(QAbstractItemView::AllEditTriggers); + list->setEditTriggers(QAbstractItemView::AllEditTriggers); list->setSelectionMode(QAbstractItemView::SingleSelection); - // setColumnWidths(list); - // setColumnDelegates(list); connect(model, &QAbstractItemModel::dataChanged, this, &ListEdit::onDataChanged); } @@ -128,7 +114,7 @@ void ListEdit::onDataChanged(const QModelIndex& topLeft, bool ListEdit::newRow(const QModelIndex& index) { - ListModel* model = static_cast(ui->listView->model()); + auto model = dynamic_cast(ui->listView->model()); return model->newRow(index); } @@ -136,10 +122,8 @@ void ListEdit::onDelete(bool checked) { Q_UNUSED(checked) - Base::Console().Log("ListEdit::onDelete()\n"); QItemSelectionModel* selectionModel = ui->listView->selectionModel(); if (!selectionModel->hasSelection() || newRow(selectionModel->currentIndex())) { - Base::Console().Log("\tNothing selected\n"); return; } @@ -176,7 +160,7 @@ int ListEdit::confirmDelete() void ListEdit::deleteSelected() { - ListModel* model = static_cast(ui->listView->model()); + auto model = dynamic_cast(ui->listView->model()); QItemSelectionModel* selectionModel = ui->listView->selectionModel(); auto index = selectionModel->currentIndex(); model->deleteRow(index); @@ -193,4 +177,20 @@ void ListEdit::reject() QDialog::reject(); } +void ListEdit::onSelectionChanged(const QItemSelection& selected, const QItemSelection& deselected) +{ + Q_UNUSED(selected) + Q_UNUSED(deselected) + + // auto indexList = selected.indexes(); + // if (indexList.size() > 0) { + // auto index = indexList[0]; + // auto listModel = dynamic_cast(index.model()); + // if (listModel->newRow(index)) { + // Base::Console().Log("*** New Row ***\n"); + // const_cast(listModel)->insertRows(index.row(), 1); + // } + // } +} + #include "moc_ListEdit.cpp" diff --git a/src/Mod/Material/Gui/ListEdit.h b/src/Mod/Material/Gui/ListEdit.h index af1d6ad8d8..8d781a376a 100644 --- a/src/Mod/Material/Gui/ListEdit.h +++ b/src/Mod/Material/Gui/ListEdit.h @@ -47,7 +47,7 @@ class ListEdit: public QDialog public: ListEdit(const QString& propertyName, - std::shared_ptr material, + const std::shared_ptr& material, QWidget* parent = nullptr); ~ListEdit() override = default; @@ -69,12 +69,13 @@ private: QAction _deleteAction; - void setColumnDelegates(QListView* list); + void setDelegates(QListView* list); void setupListView(); bool newRow(const QModelIndex& index); int confirmDelete(); void deleteSelected(); + void onSelectionChanged(const QItemSelection& selected, const QItemSelection& deselected); }; } // namespace MatGui diff --git a/src/Mod/Material/Gui/ListModel.cpp b/src/Mod/Material/Gui/ListModel.cpp index 1f977fe13d..edf56e2b68 100644 --- a/src/Mod/Material/Gui/ListModel.cpp +++ b/src/Mod/Material/Gui/ListModel.cpp @@ -83,20 +83,6 @@ QVariant ListModel::data(const QModelIndex& index, int role) const QVariant ListModel::headerData(int section, Qt::Orientation orientation, int role) const { - // if (role == Qt::DisplayRole) { - // if (orientation == Qt::Horizontal) { - // const Materials::MaterialProperty& column = _property->getColumn(section); - // return QVariant(column.getName()); - // } - // else if (orientation == Qt::Vertical) { - // // Vertical header - // if (section == (rowCount() - 1)) { - // return QVariant(QString::fromStdString("*")); - // } - // return QVariant(section + 1); - // } - // } - return QAbstractListModel::headerData(section, orientation, role); } @@ -125,18 +111,22 @@ bool ListModel::insertRows(int row, int count, const QModelIndex& parent) beginInsertRows(parent, row, row + count - 1); QVariant newRow = QString(); - _valuePtr->insert(row, newRow); + while (count--) { + _valuePtr->insert(row, newRow); + } endInsertRows(); - return false; + return true; } bool ListModel::removeRows(int row, int count, const QModelIndex& parent) { beginRemoveRows(parent, row, row + count - 1); - _valuePtr->removeAt(row); + while (count--) { + _valuePtr->removeAt(row); + } - return false; + return true; } diff --git a/src/Mod/Material/Gui/MaterialDelegate.cpp b/src/Mod/Material/Gui/MaterialDelegate.cpp index f451ac58d3..f10726c598 100644 --- a/src/Mod/Material/Gui/MaterialDelegate.cpp +++ b/src/Mod/Material/Gui/MaterialDelegate.cpp @@ -49,6 +49,7 @@ #include "Array2D.h" #include "Array3D.h" +#include "ImageEdit.h" #include "ListEdit.h" #include "MaterialDelegate.h" #include "MaterialSave.h" @@ -68,8 +69,7 @@ bool MaterialDelegate::editorEvent(QEvent* event, { if (index.column() == 1) { if (event->type() == QEvent::MouseButtonDblClick) { - const QStandardItemModel* treeModel = - static_cast(index.model()); + auto treeModel = dynamic_cast(index.model()); // Check we're not the material model root. This is also used to access the entry // columns @@ -89,35 +89,35 @@ bool MaterialDelegate::editorEvent(QEvent* event, std::string type = propertyType.toStdString(); if (type == "Color") { - Base::Console().Log("Edit color\n"); showColorModal(item, propertyName); // Mark as handled return true; } - else if (type == "MultiLineString") { - Base::Console().Log("Edit List\n"); + if (type == "MultiLineString") { showMultiLineString(propertyName, item); // Mark as handled return true; } - else if (type == "List") { - Base::Console().Log("Edit List\n"); + if (type == "List" || type == "FileList" || type == "ImageList") { showListModal(propertyName, item); // Mark as handled return true; } - else if (type == "2DArray") { - Base::Console().Log("Edit 2DArray\n"); + if (type == "2DArray") { showArray2DModal(propertyName, item); // Mark as handled return true; } - else if (type == "3DArray") { - Base::Console().Log("Edit 3DArray\n"); + if (type == "3DArray") { showArray3DModal(propertyName, item); // Mark as handled return true; } + if (type == "Image") { + showImageModal(propertyName, item); + // Mark as handled + return true; + } } } return QStyledItemDelegate::editorEvent(event, model, option, index); @@ -127,7 +127,7 @@ void MaterialDelegate::showColorModal(QStandardItem* item, QString propertyName) { QColor currentColor; // = d->col; currentColor.setRgba(parseColor(item->text())); - QColorDialog* dlg = new QColorDialog(currentColor); + auto dlg = new QColorDialog(currentColor); dlg->setAttribute(Qt::WA_DeleteOnClose); if (Gui::DialogOptions::dontUseNativeColorDialog()) { @@ -140,10 +140,8 @@ void MaterialDelegate::showColorModal(QStandardItem* item, QString propertyName) connect(dlg, &QColorDialog::finished, this, [&](int result) { if (result == QDialog::Accepted) { - Base::Console().Log("Accepted\n"); QColor color = dlg->selectedColor(); if (color.isValid()) { - Base::Console().Log("isValid\n"); QString colorText = QString(QString::fromStdString("(%1,%2,%3,%4)")) .arg(color.red() / 255.0) .arg(color.green() / 255.0) @@ -159,6 +157,24 @@ void MaterialDelegate::showColorModal(QStandardItem* item, QString propertyName) dlg->exec(); } +void MaterialDelegate::showImageModal(const QString& propertyName, QStandardItem* item) +{ + auto material = item->data().value>(); + auto dlg = new ImageEdit(propertyName, material); + + dlg->setAttribute(Qt::WA_DeleteOnClose); + + dlg->adjustSize(); + + connect(dlg, &QDialog::finished, this, [&](int result) { + if (result == QDialog::Accepted) { + Base::Console().Log("Accepted\n"); + } + }); + + dlg->exec(); +} + void MaterialDelegate::showListModal(const QString& propertyName, QStandardItem* item) { auto material = item->data().value>(); @@ -180,7 +196,7 @@ void MaterialDelegate::showListModal(const QString& propertyName, QStandardItem* void MaterialDelegate::showMultiLineString(const QString& propertyName, QStandardItem* item) { auto material = item->data().value>(); - TextEdit* dlg = new TextEdit(propertyName, material); + auto dlg = new TextEdit(propertyName, material); dlg->setAttribute(Qt::WA_DeleteOnClose); @@ -199,7 +215,7 @@ void MaterialDelegate::showMultiLineString(const QString& propertyName, QStandar void MaterialDelegate::showArray2DModal(const QString& propertyName, QStandardItem* item) { auto material = item->data().value>(); - Array2D* dlg = new Array2D(propertyName, material); + auto dlg = new Array2D(propertyName, material); dlg->setAttribute(Qt::WA_DeleteOnClose); @@ -217,7 +233,7 @@ void MaterialDelegate::showArray2DModal(const QString& propertyName, QStandardIt void MaterialDelegate::showArray3DModal(const QString& propertyName, QStandardItem* item) { auto material = item->data().value>(); - Array3D* dlg = new Array3D(propertyName, material); + auto dlg = new Array3D(propertyName, material); dlg->setAttribute(Qt::WA_DeleteOnClose); @@ -236,13 +252,12 @@ void MaterialDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const { - // Base::Console().Log("MaterialsEditor::paint()\n"); if (index.column() != 1) { QStyledItemDelegate::paint(painter, option, index); return; } - const QStandardItemModel* treeModel = static_cast(index.model()); + auto treeModel = dynamic_cast(index.model()); // Check we're not the material model root. This is also used to access the entry columns auto item = treeModel->itemFromIndex(index); @@ -267,11 +282,25 @@ void MaterialDelegate::paint(QPainter* painter, std::string type = propertyType.toStdString(); if (type == "Color") { painter->save(); + ; QColor color; + color.setRgba(qRgba(0, 0, 0, 255)); // Black border + int left = option.rect.left() + 2; + int width = option.rect.width() - 4; + if (option.rect.width() > 75) { + left += (option.rect.width() - 75) / 2; + width = 71; + } + painter->fillRect(left, + option.rect.top() + 2, + width, + option.rect.height() - 4, + QBrush(color)); + color.setRgba(parseColor(propertyValue)); - int left = option.rect.left() + 5; - int width = option.rect.width() - 10; + left = option.rect.left() + 5; + width = option.rect.width() - 10; if (option.rect.width() > 75) { left += (option.rect.width() - 75) / 2; width = 65; @@ -285,10 +314,15 @@ void MaterialDelegate::paint(QPainter* painter, painter->restore(); return; } - else if (type == "MultiLineString") { + if (type == "Image") { painter->save(); - QImage table(QString::fromStdString(":/icons/multiline.svg")); + QImage img; + if (!propertyValue.isEmpty()) { + Base::Console().Log("Loading image\n"); + QByteArray by = QByteArray::fromBase64(propertyValue.toUtf8()); + img = QImage::fromData(by, "PNG").scaled(64, 64, Qt::KeepAspectRatio); + } QRect target(option.rect); if (target.width() > target.height()) { target.setWidth(target.height()); @@ -296,12 +330,12 @@ void MaterialDelegate::paint(QPainter* painter, else { target.setHeight(target.width()); } - painter->drawImage(target, table, table.rect()); + painter->drawImage(target, img, img.rect()); painter->restore(); return; } - else if (type == "List") { + if (type == "List" || type == "FileList" || type == "ImageList") { painter->save(); QImage table(QString::fromStdString(":/icons/list.svg")); @@ -317,8 +351,24 @@ void MaterialDelegate::paint(QPainter* painter, painter->restore(); return; } - else if (type == "2DArray" || type == "3DArray") { - // painter->save(); + if (type == "MultiLineString") { + painter->save(); + + QImage table(QString::fromStdString(":/icons/multiline.svg")); + QRect target(option.rect); + if (target.width() > target.height()) { + target.setWidth(target.height()); + } + else { + target.setHeight(target.width()); + } + painter->drawImage(target, table, table.rect()); + + painter->restore(); + return; + } + if (type == "2DArray" || type == "3DArray") { + painter->save(); QImage table(QString::fromStdString(":/icons/table.svg")); QRect target(option.rect); @@ -330,7 +380,7 @@ void MaterialDelegate::paint(QPainter* painter, } painter->drawImage(target, table, table.rect()); - // painter->restore(); + painter->restore(); return; } @@ -343,7 +393,7 @@ QSize MaterialDelegate::sizeHint(const QStyleOptionViewItem& option, const QMode return QStyledItemDelegate::sizeHint(option, index); } - const QStandardItemModel* treeModel = static_cast(index.model()); + auto treeModel = dynamic_cast(index.model()); // Check we're not the material model root. This is also used to access the entry columns auto item = treeModel->itemFromIndex(index); @@ -361,11 +411,14 @@ QSize MaterialDelegate::sizeHint(const QStyleOptionViewItem& option, const QMode std::string type = propertyType.toStdString(); if (type == "Color") { - return QSize(75, 23); // Standard QPushButton size + return {75, 23}; // Standard QPushButton size } - else if (type == "2DArray" || type == "3DArray" || type == "MultiLineString" - || type == "List") { - return QSize(23, 23); + if (type == "Image") { + return {64, 64}; + } + if (type == "2DArray" || type == "3DArray" || type == "MultiLineString" || type == "List" + || type == "FileList" || type == "ImageList") { + return {23, 23}; } return QStyledItemDelegate::sizeHint(option, index); @@ -373,9 +426,8 @@ QSize MaterialDelegate::sizeHint(const QStyleOptionViewItem& option, const QMode void MaterialDelegate::setEditorData(QWidget* editor, const QModelIndex& index) const { - Base::Console().Log("MaterialsEditor::setEditorData()\n"); QVariant propertyType = editor->property("Type"); - const QStandardItemModel* model = static_cast(index.model()); + auto model = dynamic_cast(index.model()); QStandardItem* item = model->itemFromIndex(index); auto group = item->parent(); if (!group) { @@ -387,18 +439,16 @@ void MaterialDelegate::setEditorData(QWidget* editor, const QModelIndex& index) std::string type = propertyType.toString().toStdString(); if (type == "File") { - Gui::FileChooser* chooser = static_cast(editor); + auto chooser = dynamic_cast(editor); item->setText(chooser->fileName()); } else if (type == "Quantity") { - Gui::InputField* input = static_cast(editor); + auto input = dynamic_cast(editor); item->setText(input->getQuantityString()); } else { QStyledItemDelegate::setEditorData(editor, index); } - - // Q_EMIT const_cast(this)->propertyChange(propertyName, item->text()); } void MaterialDelegate::setModelData(QWidget* editor, @@ -407,7 +457,7 @@ void MaterialDelegate::setModelData(QWidget* editor, { QStyledItemDelegate::setModelData(editor, model, index); - QStandardItem* item = static_cast(model)->itemFromIndex(index); + auto item = dynamic_cast(model)->itemFromIndex(index); auto group = item->parent(); if (!group) { return; @@ -419,15 +469,16 @@ void MaterialDelegate::setModelData(QWidget* editor, } QWidget* MaterialDelegate::createEditor(QWidget* parent, - const QStyleOptionViewItem&, + const QStyleOptionViewItem& styleOption, const QModelIndex& index) const { - Base::Console().Log("MaterialsEditor::createEditor()\n"); + Q_UNUSED(styleOption) + if (index.column() != 1) { return nullptr; } - const QStandardItemModel* treeModel = static_cast(index.model()); + auto treeModel = dynamic_cast(index.model()); // Check we're not the material model root. This is also used to access the entry columns auto item = treeModel->itemFromIndex(index); @@ -471,18 +522,18 @@ QWidget* MaterialDelegate::createWidget(QWidget* parent, QWidget* widget = nullptr; std::string type = propertyType.toStdString(); - if (type == "String" || type == "URL" || type == "List") { + if (type == "String" || type == "URL") { widget = new Gui::PrefLineEdit(parent); } - else if ((type == "Integer") || (type == "Int")) { - Gui::IntSpinBox* spinner = new Gui::IntSpinBox(parent); + else if (type == "Integer") { + auto spinner = new Gui::IntSpinBox(parent); spinner->setMinimum(0); spinner->setMaximum(INT_MAX); spinner->setValue(propertyValue.toInt()); widget = spinner; } else if (type == "Float") { - Gui::DoubleSpinBox* spinner = new Gui::DoubleSpinBox(parent); + auto spinner = new Gui::DoubleSpinBox(parent); // the magnetic permeability is the parameter for which many decimals matter // the most however, even for this, 6 digits are sufficient @@ -497,7 +548,7 @@ QWidget* MaterialDelegate::createWidget(QWidget* parent, widget = spinner; } else if (type == "Boolean") { - Gui::PrefComboBox* combo = new Gui::PrefComboBox(parent); + auto combo = new Gui::PrefComboBox(parent); combo->insertItem(0, QString::fromStdString("")); combo->insertItem(1, tr("False")); combo->insertItem(2, tr("True")); @@ -505,7 +556,7 @@ QWidget* MaterialDelegate::createWidget(QWidget* parent, widget = combo; } else if (type == "Quantity") { - Gui::InputField* input = new Gui::InputField(); + auto input = new Gui::InputField(parent); input->setMinimum(std::numeric_limits::min()); input->setMaximum(std::numeric_limits::max()); input->setUnitText(propertyUnits); // TODO: Ensure this exists @@ -515,8 +566,8 @@ QWidget* MaterialDelegate::createWidget(QWidget* parent, widget = input; } else if (type == "File") { - Gui::FileChooser* chooser = new Gui::FileChooser(); - if (propertyValue.length() > 0) { + auto chooser = new Gui::FileChooser(parent); + if (!propertyValue.isEmpty()) { chooser->setFileName(propertyValue); } @@ -528,7 +579,7 @@ QWidget* MaterialDelegate::createWidget(QWidget* parent, } widget->setProperty("Type", propertyType); - widget->setParent(parent); + // widget->setParent(parent); return widget; } @@ -539,13 +590,16 @@ QRgb MaterialDelegate::parseColor(const QString& color) const trimmed.replace(QRegularExpression(QString::fromStdString("\\(([^<]*)\\)")), QString::fromStdString("\\1")); QStringList parts = trimmed.split(QString::fromStdString(",")); - if (parts.length() < 4) { - return qRgba(0, 0, 0, 1); + if (parts.length() < 3) { + return qRgba(0, 0, 0, 255); } int red = parts.at(0).toDouble() * 255; int green = parts.at(1).toDouble() * 255; int blue = parts.at(2).toDouble() * 255; - int alpha = parts.at(3).toDouble() * 255; + int alpha = 255; + if (parts.length() > 3) { + alpha = parts.at(3).toDouble() * 255; + } return qRgba(red, green, blue, alpha); } diff --git a/src/Mod/Material/Gui/MaterialDelegate.h b/src/Mod/Material/Gui/MaterialDelegate.h index 0d389c7113..83c4f3a83a 100644 --- a/src/Mod/Material/Gui/MaterialDelegate.h +++ b/src/Mod/Material/Gui/MaterialDelegate.h @@ -44,7 +44,7 @@ public: ~MaterialDelegate() override = default; QWidget* createEditor(QWidget* parent, - const QStyleOptionViewItem&, + const QStyleOptionViewItem& styleOption, const QModelIndex& index) const override; QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const override; void paint(QPainter* painter, @@ -73,6 +73,7 @@ private: const QString& propertyUnits) const; QRgb parseColor(const QString& color) const; void showColorModal(QStandardItem* item, QString propertyName); + void showImageModal(const QString& propertyName, QStandardItem* item); void showListModal(const QString& propertyName, QStandardItem* item); void showMultiLineString(const QString& propertyName, QStandardItem* item); void showArray2DModal(const QString& propertyName, QStandardItem* item); diff --git a/src/Mod/Material/Gui/MaterialSave.cpp b/src/Mod/Material/Gui/MaterialSave.cpp index df344b7ea8..1f82b7c39e 100644 --- a/src/Mod/Material/Gui/MaterialSave.cpp +++ b/src/Mod/Material/Gui/MaterialSave.cpp @@ -37,14 +37,14 @@ using namespace MatGui; /* TRANSLATOR MatGui::MaterialsEditor */ -MaterialSave::MaterialSave(std::shared_ptr material, QWidget* parent) +MaterialSave::MaterialSave(const std::shared_ptr& material, QWidget* parent) : QDialog(parent) , ui(new Ui_MaterialSave) , _material(material) , _saveInherited(true) , _selectedPath(QString::fromStdString("/")) , _selectedFull(QString::fromStdString("/")) - , _selectedUUID(QString()) + , _selectedUUID() , _deleteAction(this) { ui->setupUi(this); @@ -121,7 +121,6 @@ void MaterialSave::onOk(bool checked) Q_UNUSED(checked) QString name = _filename.remove(QString::fromStdString(".FCMat"), Qt::CaseInsensitive); - Base::Console().Log("name '%s'\n", _filename.toStdString().c_str()); if (name != _material->getName()) { _material->setName(name); _material->setEditStateAlter(); // ? Does a name change count? @@ -131,10 +130,6 @@ void MaterialSave::onOk(bool checked) auto library = variant.value>(); QFileInfo filepath(_selectedPath + QString::fromStdString("/") + name + QString::fromStdString(".FCMat")); - Base::Console().Log("saveMaterial(library(%s), material(%s), path(%s))\n", - library->getName().toStdString().c_str(), - _material->getName().toStdString().c_str(), - filepath.filePath().toStdString().c_str()); if (library->fileExists(filepath.filePath())) { // confirm overwrite @@ -165,7 +160,7 @@ void MaterialSave::onOk(bool checked) if (res == QMessageBox::Cancel) { return; } - else if (res == QMessageBox::Save) { + if (res == QMessageBox::Save) { // QMessageBox::Save saves as normal, a duplicate saveAsCopy = true; } @@ -329,8 +324,6 @@ void MaterialSave::addMaterials( if (nodePtr->getType() == Materials::MaterialTreeNode::DataNode) { std::shared_ptr material = nodePtr->getData(); QString uuid = material->getUUID(); - Base::Console().Log("Material path '%s'\n", - material->getDirectory().toStdString().c_str()); auto card = new QStandardItem(icon, mat.first); card->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsDragEnabled @@ -340,7 +333,6 @@ void MaterialSave::addMaterials( addExpanded(tree, &parent, card); } else { - Base::Console().Log("Material folder path '%s'\n", mat.first.toStdString().c_str()); auto node = new QStandardItem(folderIcon, mat.first); node->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | Qt::ItemIsEditable); @@ -399,23 +391,19 @@ void MaterialSave::onSelectModel(const QItemSelection& selected, const QItemSele Q_UNUSED(deselected); _filename = QString(ui->editFilename->text()); // No filename by default - QStandardItemModel* model = static_cast(ui->treeMaterials->model()); + auto model = static_cast(ui->treeMaterials->model()); QModelIndexList indexes = selected.indexes(); if (indexes.count() == 0) { - Base::Console().Log("Nothing selected\n"); _selectedPath = QString::fromStdString("/") + _libraryName; _selectedFull = _selectedPath; _selectedUUID = QString(); - Base::Console().Log("\tSelected path '%s'\n", _selectedPath.toStdString().c_str()); return; } for (auto it = indexes.begin(); it != indexes.end(); it++) { QStandardItem* item = model->itemFromIndex(*it); - Base::Console().Log("%s\n", item->text().toStdString().c_str()); if (item) { auto _selected = item->data(Qt::UserRole); if (_selected.isValid()) { - Base::Console().Log("\tuuid %s\n", _selected.toString().toStdString().c_str()); _selectedPath = getPath(item->parent()); _selectedFull = getPath(item); _selectedUUID = _selected.toString(); @@ -431,9 +419,6 @@ void MaterialSave::onSelectModel(const QItemSelection& selected, const QItemSele if (_filename.length() > 0) { ui->editFilename->setText(_filename); } - Base::Console().Log("\tSelected path '%s', filename = '%s'\n", - _selectedPath.toStdString().c_str(), - _filename.toStdString().c_str()); } void MaterialSave::currentTextChanged(const QString& value) @@ -496,7 +481,6 @@ void MaterialSave::onNewFolder(bool checked) // Folders have no associated data if (item->data(Qt::UserRole).isNull()) { - Base::Console().Log("Add new folder to '%s'\n", item->text().toStdString().c_str()); QIcon folderIcon(QString::fromStdString(":/icons/folder.svg")); QString folderName = tr("New Folder"); @@ -508,9 +492,6 @@ void MaterialSave::onNewFolder(bool checked) | Qt::ItemIsDropEnabled | Qt::ItemIsEditable); addExpanded(tree, item, node); - Base::Console().Log("New folder index valid: %s\n", - node->index().isValid() ? "true" : "false"); - QItemSelectionModel* selectionModel = ui->treeMaterials->selectionModel(); selectionModel->select(node->index(), QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Current); @@ -521,39 +502,27 @@ void MaterialSave::onNewFolder(bool checked) void MaterialSave::onItemChanged(QStandardItem* item) { - Base::Console().Log("MaterialSave::onItemChanged('%s')\n", item->text().toStdString().c_str()); QString oldPath = _selectedPath; _selectedPath = getPath(item); _selectedFull = _selectedPath; - Base::Console().Log("\tSelected path '%s'\n", _selectedPath.toStdString().c_str()); + renameFolder(oldPath, _selectedPath); } void MaterialSave::onFilename(const QString& text) { - Base::Console().Log("MaterialSave::onFilename('%s')\n", text.toStdString().c_str()); - _filename = text; } QString MaterialSave::pathFromIndex(const QModelIndex& index) const { - auto model = static_cast(index.model()); + auto model = dynamic_cast(index.model()); auto item = model->itemFromIndex(index); return getPath(item); } void MaterialSave::onContextMenu(const QPoint& pos) { - Base::Console().Log("MaterialSave::onContextMenu(%d,%d)\n", pos.x(), pos.y()); - QModelIndex index = ui->treeMaterials->indexAt(pos); - QString path = pathFromIndex(index); - Base::Console().Log("\tindex at (%d,%d)->'%s'\n", - index.row(), - index.column(), - path.toStdString().c_str()); - - QMenu contextMenu(tr("Context menu"), this); // QAction action1(tr("Delete"), this); @@ -568,14 +537,11 @@ void MaterialSave::onDelete(bool checked) { Q_UNUSED(checked) - Base::Console().Log("MaterialSave::onDelete()\n"); QItemSelectionModel* selectionModel = ui->treeMaterials->selectionModel(); if (!selectionModel->hasSelection()) { - Base::Console().Log("\tNothing selected\n"); return; } - Base::Console().Log("\tSelected path '%s'\n", _selectedFull.toStdString().c_str()); int res = confirmDelete(this); if (res == QMessageBox::Cancel) { return; @@ -632,7 +598,6 @@ bool MaterialSave::selectedHasChildren() void MaterialSave::deleteSelected() { - Base::Console().Log("\tDelete selected path '%s'\n", _selectedFull.toStdString().c_str()); auto library = currentLibrary(); if (!library->isRoot(_selectedFull)) { diff --git a/src/Mod/Material/Gui/MaterialSave.h b/src/Mod/Material/Gui/MaterialSave.h index 9e173104cc..9d4028a3b4 100644 --- a/src/Mod/Material/Gui/MaterialSave.h +++ b/src/Mod/Material/Gui/MaterialSave.h @@ -42,7 +42,8 @@ class MaterialSave: public QDialog Q_OBJECT public: - explicit MaterialSave(std::shared_ptr material, QWidget* parent = nullptr); + explicit MaterialSave(const std::shared_ptr& material, + QWidget* parent = nullptr); ~MaterialSave() override; void setLibraries(); diff --git a/src/Mod/Material/Gui/MaterialsEditor.cpp b/src/Mod/Material/Gui/MaterialsEditor.cpp index 91b059da9e..a75b8801b4 100644 --- a/src/Mod/Material/Gui/MaterialsEditor.cpp +++ b/src/Mod/Material/Gui/MaterialsEditor.cpp @@ -65,9 +65,13 @@ MaterialsEditor::MaterialsEditor(QWidget* parent) , ui(new Ui_MaterialsEditor) , _material(std::make_shared()) , _edited(false) + , _rendered(nullptr) + , _recentMax(0) { ui->setupUi(this); + _warningIcon = QIcon(QString::fromStdString(":/icons/Warning.svg")); + getFavorites(); getRecents(); @@ -331,9 +335,6 @@ void MaterialsEditor::onDescription() void MaterialsEditor::propertyChange(const QString& property, const QString value) { - Base::Console().Log("MaterialsEditor::propertyChange(%s) = '%s'\n", - property.toStdString().c_str(), - value.toStdString().c_str()); if (_material->hasPhysicalProperty(property)) { _material->setPhysicalValue(property, value); } @@ -348,7 +349,6 @@ void MaterialsEditor::onURL(bool checked) { Q_UNUSED(checked) - Base::Console().Log("URL\n"); QString url = ui->editSourceURL->text(); if (url.length() > 0) { QDesktopServices::openUrl(QUrl(url, QUrl::TolerantMode)); @@ -363,7 +363,6 @@ void MaterialsEditor::onPhysicalAdd(bool checked) dialog.setModal(true); if (dialog.exec() == QDialog::Accepted) { QString selected = dialog.selectedModel(); - Base::Console().Log("Selected model '%s'\n", selected.toStdString().c_str()); _material->addPhysical(selected); updateMaterial(); } @@ -378,9 +377,9 @@ void MaterialsEditor::onPhysicalRemove(bool checked) QItemSelectionModel* selectionModel = ui->treePhysicalProperties->selectionModel(); if (selectionModel->hasSelection()) { - const QModelIndex index = selectionModel->currentIndex().siblingAtColumn(0); + auto index = selectionModel->currentIndex().siblingAtColumn(0); - const QStandardItemModel* treeModel = static_cast(index.model()); + auto treeModel = dynamic_cast(index.model()); // Check we're the material model root. auto item = treeModel->itemFromIndex(index); @@ -403,7 +402,6 @@ void MaterialsEditor::onAppearanceAdd(bool checked) dialog.setModal(true); if (dialog.exec() == QDialog::Accepted) { QString selected = dialog.selectedModel(); - Base::Console().Log("Selected model '%s'\n", selected.toStdString().c_str()); _material->addAppearance(selected); updateMaterial(); } @@ -418,9 +416,9 @@ void MaterialsEditor::onAppearanceRemove(bool checked) QItemSelectionModel* selectionModel = ui->treeAppearance->selectionModel(); if (selectionModel->hasSelection()) { - const QModelIndex index = selectionModel->currentIndex().siblingAtColumn(0); + auto index = selectionModel->currentIndex().siblingAtColumn(0); - const QStandardItemModel* treeModel = static_cast(index.model()); + auto treeModel = dynamic_cast(index.model()); // Check we're the material model root. auto item = treeModel->itemFromIndex(index); @@ -439,7 +437,6 @@ void MaterialsEditor::onFavourite(bool checked) { Q_UNUSED(checked) - Base::Console().Log("Favorite\n"); auto selected = _material->getUUID(); if (isFavorite(selected)) { removeFavorite(selected); @@ -477,12 +474,9 @@ void MaterialsEditor::onNewMaterial(bool checked) { Q_UNUSED(checked) - Base::Console().Log("New Material\n"); - // Ensure data is saved (or discarded) before changing materials if (_material->getEditState() != Materials::Material::ModelEdit_None) { // Prompt the user to save or discard changes - Base::Console().Log("*** Material edited!!!\n"); int res = confirmSave(this); if (res == QMessageBox::Cancel) { return; @@ -498,15 +492,12 @@ void MaterialsEditor::onInheritNewMaterial(bool checked) { Q_UNUSED(checked) - Base::Console().Log("Inherit New Material\n"); - // Save the current UUID to use as out parent auto parent = _material->getUUID(); // Ensure data is saved (or discarded) before changing materials if (_material->getEditState() != Materials::Material::ModelEdit_None) { // Prompt the user to save or discard changes - Base::Console().Log("*** Material edited!!!\n"); int res = confirmSave(this); if (res == QMessageBox::Cancel) { return; @@ -553,11 +544,29 @@ void MaterialsEditor::saveMaterial() void MaterialsEditor::accept() { + if (_material->isOldFormat()) { + Base::Console().Log("*** Old Format File ***\n"); + oldFormatError(); + + return; + } addRecent(_material->getUUID()); saveWindow(); QDialog::accept(); } +void MaterialsEditor::oldFormatError() +{ + QMessageBox box(this); + box.setIcon(QMessageBox::Warning); + box.setWindowTitle(tr("Old Format Material")); + + box.setText(tr("This file is in the old material card format.")); + box.setInformativeText(QObject::tr("You must save the material before using it.")); + box.adjustSize(); // Silence warnings from Qt on Windows + box.exec(); +} + void MaterialsEditor::reject() { saveWindow(); @@ -571,59 +580,80 @@ void MaterialsEditor::saveWindow() param->SetInt("EditorWidth", width()); param->SetInt("EditorHeight", height()); - // int count = param->GetInt("Favorites", 0); - // for (int i = 0; i < count; i++) { - // QString key = QString::fromLatin1("FAV%1").arg(i); - // QString uuid = QString::fromStdString(param->GetASCII(key.toStdString().c_str(), "")); - // _favorites.push_back(uuid); - // } + saveMaterialTree(param); } -// def storeSize(self): -// "stores the widget size" -// #store widths -// p = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Material") -// p.SetInt("MaterialEditorWidth", self.widget.width()) -// p.SetInt("MaterialEditorHeight", self.widget.height()) -// root = self.widget.treeView.model().invisibleRootItem() -// for gg in range(root.rowCount()): -// group = root.child(gg) -// p.SetBool("TreeExpand"+group.text(), self.widget.treeView.isExpanded(group.index())) +void MaterialsEditor::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())); -// QIcon MaterialsEditor::errorIcon(const QIcon &icon) const { -// auto pixmap = icon.pixmap(); -// } + 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); + } + } +} + +void MaterialsEditor::saveMaterialTree(const Base::Reference& param) +{ + auto treeParam = param->GetGroup("MaterialTree"); + treeParam->Clear(); + + auto tree = ui->treeMaterials; + auto model = static_cast(tree->model()); + + auto root = model->invisibleRootItem(); + for (int i = 0; i < root->rowCount(); i++) { + auto child = root->child(i); + // treeParam->SetBool(child->text().toStdString().c_str(), + // tree->isExpanded(child->index())); + + saveMaterialTreeChildren(treeParam, tree, model, child); + } +} void MaterialsEditor::addMaterials( QStandardItem& parent, 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()); auto tree = ui->treeMaterials; for (auto& mat : *modelTree) { std::shared_ptr 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); + QIcon matIcon = icon; + if (material->isOldFormat()) { + matIcon = _warningIcon; + } + auto card = new QStandardItem(matIcon, mat.first); card->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled); card->setData(QVariant(uuid), Qt::UserRole); + if (material->isOldFormat()) { + card->setToolTip(tr("This card uses the old format and must be saved before use")); + } addExpanded(tree, &parent, card); } else { auto node = new QStandardItem(folderIcon, mat.first); - addExpanded(tree, &parent, node); + addExpanded(tree, &parent, node, childParam); node->setFlags(Qt::ItemIsEnabled | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled); auto treeMap = nodePtr->getFolder(); - addMaterials(*node, treeMap, folderIcon, icon); + addMaterials(*node, treeMap, folderIcon, icon, childParam); } } } @@ -634,12 +664,36 @@ void MaterialsEditor::addExpanded(QTreeView* tree, QStandardItem* parent, QStand tree->setExpanded(child->index(), true); } +void MaterialsEditor::addExpanded(QTreeView* tree, + 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); + tree->setExpanded(child->index(), expand); +} + void MaterialsEditor::addExpanded(QTreeView* tree, QStandardItemModel* parent, QStandardItem* child) { parent->appendRow(child); tree->setExpanded(child->index(), true); } +void MaterialsEditor::addExpanded(QTreeView* tree, + QStandardItemModel* 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); + tree->setExpanded(child->index(), expand); +} + void MaterialsEditor::createPhysicalTree() { auto tree = ui->treePhysicalProperties; @@ -657,30 +711,18 @@ void MaterialsEditor::createPhysicalTree() tree->setColumnHidden(2, true); tree->setHeaderHidden(false); - tree->setUniformRowHeights(true); - MaterialDelegate* delegate = new MaterialDelegate(this); + tree->setUniformRowHeights(false); + auto delegate = new MaterialDelegate(this); tree->setItemDelegateForColumn(1, delegate); connect(delegate, &MaterialDelegate::propertyChange, this, &MaterialsEditor::propertyChange); - - // QItemSelectionModel* selectionModel = ui->treePhysicalProperties->selectionModel(); - // connect(selectionModel, - // &QItemSelectionModel::selectionChanged, - // this, } void MaterialsEditor::createPreviews() { - _rendered = new QSvgWidget(QString::fromStdString(":/icons/preview-rendered.svg")); - _rendered->setMaximumWidth(64); - _rendered->setMinimumHeight(64); + _rendered = new AppearancePreview(); ui->layoutAppearance->addWidget(_rendered); - _vectored = new QSvgWidget(QString::fromStdString(":/icons/preview-vector.svg")); - _vectored->setMaximumWidth(64); - _vectored->setMinimumHeight(64); - ui->layoutAppearance->addWidget(_vectored); - updatePreview(); } @@ -702,7 +744,7 @@ void MaterialsEditor::createAppearanceTree() tree->setHeaderHidden(false); tree->setUniformRowHeights(false); - MaterialDelegate* delegate = new MaterialDelegate(this); + auto delegate = new MaterialDelegate(this); tree->setItemDelegateForColumn(1, delegate); connect(delegate, &MaterialDelegate::propertyChange, this, &MaterialsEditor::propertyChange); @@ -750,38 +792,38 @@ void MaterialsEditor::addFavorites(QStandardItem* parent) void MaterialsEditor::fillMaterialTree() { + auto param = App::GetApplication().GetParameterGroupByPath( + "User parameter:BaseApp/Preferences/Mod/Material/Editor/MaterialTree"); + auto tree = ui->treeMaterials; auto model = static_cast(tree->model()); auto lib = new QStandardItem(tr("Favorites")); lib->setFlags(Qt::ItemIsEnabled | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled); - addExpanded(tree, model, lib); + addExpanded(tree, model, lib, param); addFavorites(lib); lib = new QStandardItem(tr("Recent")); lib->setFlags(Qt::ItemIsEnabled | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled); - addExpanded(tree, model, lib); + addExpanded(tree, model, lib, param); addRecents(lib); - auto libraries = Materials::MaterialManager::getMaterialLibraries(); + auto libraries = getMaterialManager().getMaterialLibraries(); for (const auto& library : *libraries) { lib = new QStandardItem(library->getName()); lib->setFlags(Qt::ItemIsEnabled | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled); - addExpanded(tree, model, lib); + addExpanded(tree, model, lib, param); QIcon icon(library->getIconPath()); QIcon folderIcon(QString::fromStdString(":/icons/folder.svg")); - auto modelTree = _materialManager.getMaterialTree(library); - addMaterials(*lib, modelTree, folderIcon, icon); + auto modelTree = getMaterialManager().getMaterialTree(library); + addMaterials(*lib, modelTree, folderIcon, icon, param); } } void MaterialsEditor::createMaterialTree() { - // Materials::ModelManager &modelManager = getModelManager(); - // Q_UNUSED(modelManager) - auto tree = ui->treeMaterials; auto model = new QStandardItemModel(); tree->setModel(model); @@ -801,69 +843,55 @@ void MaterialsEditor::refreshMaterialTree() void MaterialsEditor::updatePreview() const { - QString diffuseColor; - QString highlightColor; - QString sectionColor; - + if (_material->hasAppearanceProperty(QString::fromStdString("AmbientColor"))) { + QString color = _material->getAppearanceValueString(QString::fromStdString("AmbientColor")); + _rendered->setAmbientColor(getColorHash(color, 255)); + } + else { + _rendered->resetAmbientColor(); + } if (_material->hasAppearanceProperty(QString::fromStdString("DiffuseColor"))) { - diffuseColor = _material->getAppearanceValueString(QString::fromStdString("DiffuseColor")); + QString color = _material->getAppearanceValueString(QString::fromStdString("DiffuseColor")); + _rendered->setDiffuseColor(getColorHash(color, 255)); } - else if (_material->hasAppearanceProperty(QString::fromStdString("ViewColor"))) { - diffuseColor = _material->getAppearanceValueString(QString::fromStdString("ViewColor")); + else { + _rendered->resetDiffuseColor(); } - else if (_material->hasAppearanceProperty(QString::fromStdString("Color"))) { - diffuseColor = _material->getAppearanceValueString(QString::fromStdString("Color")); - } - if (_material->hasAppearanceProperty(QString::fromStdString("SpecularColor"))) { - highlightColor = + QString color = _material->getAppearanceValueString(QString::fromStdString("SpecularColor")); + _rendered->setSpecularColor(getColorHash(color, 255)); } - - if (_material->hasAppearanceProperty(QString::fromStdString("SectionColor"))) { - sectionColor = _material->getAppearanceValueString(QString::fromStdString("SectionColor")); + else { + _rendered->resetSpecularColor(); } - - if ((diffuseColor.length() + highlightColor.length()) > 0) { - auto file = QFile(QString::fromStdString(":/icons/preview-rendered.svg")); - if (file.open(QIODevice::ReadOnly | QIODevice::Text)) { - QString svg = QTextStream(&file).readAll(); - file.close(); - if (diffuseColor.length() > 0) { - svg = - svg.replace(QString::fromStdString("#d3d7cf"), getColorHash(diffuseColor, 255)); - svg = - svg.replace(QString::fromStdString("#555753"), getColorHash(diffuseColor, 125)); - } - if (highlightColor.length() > 0) { - svg = svg.replace(QString::fromStdString("#fffffe"), - getColorHash(highlightColor, 255)); - } - _rendered->load(svg.toUtf8()); - } + if (_material->hasAppearanceProperty(QString::fromStdString("EmissiveColor"))) { + QString color = + _material->getAppearanceValueString(QString::fromStdString("EmissiveColor")); + _rendered->setEmissiveColor(getColorHash(color, 255)); } - - if ((diffuseColor.length() + sectionColor.length()) > 0) { - auto file = QFile(QString::fromStdString(":/icons/preview-vector.svg")); - if (file.open(QIODevice::ReadOnly | QIODevice::Text)) { - QString svg = QTextStream(&file).readAll(); - file.close(); - if (diffuseColor.length() > 0) { - svg = - svg.replace(QString::fromStdString("#d3d7cf"), getColorHash(diffuseColor, 255)); - svg = - svg.replace(QString::fromStdString("#555753"), getColorHash(diffuseColor, 125)); - } - if (sectionColor.length() > 0) { - svg = - svg.replace(QString::fromStdString("#ffffff"), getColorHash(sectionColor, 255)); - } - _vectored->load(svg.toUtf8()); - } + else { + _rendered->resetEmissiveColor(); + } + if (_material->hasAppearanceProperty(QString::fromStdString("Shininess"))) { + double value = + _material->getAppearanceValue(QString::fromStdString("Shininess")).toDouble(); + _rendered->setShininess(value); + } + else { + _rendered->resetShininess(); + } + if (_material->hasAppearanceProperty(QString::fromStdString("Transparency"))) { + double value = + _material->getAppearanceValue(QString::fromStdString("Transparency")).toDouble(); + _rendered->setTransparency(value); + } + else { + _rendered->resetTransparency(); } } -QString MaterialsEditor::getColorHash(const QString& colorString, int colorRange) const +QString MaterialsEditor::getColorHash(const QString& colorString, int colorRange) { /* returns a '#000000' string from a '(0.1,0.2,0.3)' string. Optionally the string @@ -897,7 +925,7 @@ QString MaterialsEditor::getColorHash(const QString& colorString, int colorRange void MaterialsEditor::updateMaterialAppearance() { QTreeView* tree = ui->treeAppearance; - QStandardItemModel* treeModel = static_cast(tree->model()); + auto treeModel = static_cast(tree->model()); treeModel->clear(); QStringList headers; @@ -956,7 +984,7 @@ void MaterialsEditor::updateMaterialAppearance() void MaterialsEditor::updateMaterialProperties() { QTreeView* tree = ui->treePhysicalProperties; - QStandardItemModel* treeModel = static_cast(tree->model()); + auto treeModel = dynamic_cast(tree->model()); treeModel->clear(); QStringList headers; @@ -1017,7 +1045,7 @@ void MaterialsEditor::updateMaterialProperties() } } -QString MaterialsEditor::libraryPath(std::shared_ptr material) const +QString MaterialsEditor::libraryPath(const std::shared_ptr& material) { QString path; auto library = material->getLibrary(); @@ -1071,12 +1099,11 @@ void MaterialsEditor::onSelectMaterial(const QItemSelection& selected, // Get the UUID before changing the underlying data model QString uuid; - QStandardItemModel* model = static_cast(ui->treeMaterials->model()); + auto model = static_cast(ui->treeMaterials->model()); QModelIndexList indexes = selected.indexes(); for (auto it = indexes.begin(); it != indexes.end(); it++) { QStandardItem* item = model->itemFromIndex(*it); - Base::Console().Log("%s\n", item->text().toStdString().c_str()); if (item) { uuid = item->data(Qt::UserRole).toString(); break; @@ -1084,14 +1111,12 @@ void MaterialsEditor::onSelectMaterial(const QItemSelection& selected, } if (uuid.isEmpty() || uuid == _material->getUUID()) { - Base::Console().Log("*** Unchanged material '%s'\n", uuid.toStdString().c_str()); return; } // Ensure data is saved (or discarded) before changing materials if (_material->getEditState() != Materials::Material::ModelEdit_None) { // Prompt the user to save or discard changes - Base::Console().Log("*** Material edited!!!\n"); int res = confirmSave(this); if (res == QMessageBox::Cancel) { return; @@ -1115,21 +1140,11 @@ void MaterialsEditor::onDoubleClick(const QModelIndex& index) { Q_UNUSED(index) - Base::Console().Log("MaterialsEditor::onDoubleClick()\n"); accept(); } void MaterialsEditor::onContextMenu(const QPoint& pos) { - Base::Console().Log("MaterialsEditor::onContextMenu(%d,%d)\n", pos.x(), pos.y()); - // QModelIndex index = ui->treeMaterials->indexAt(pos); - // QString path = pathFromIndex(index); - // Base::Console().Log("\tindex at (%d,%d)->'%s'\n", - // index.row(), - // index.column(), - // path.toStdString().c_str()); - - QMenu contextMenu(tr("Context menu"), this); QAction action1(tr("Inherit from"), this); @@ -1148,37 +1163,11 @@ void MaterialsEditor::onContextMenu(const QPoint& pos) void MaterialsEditor::onInherit(bool checked) { Q_UNUSED(checked) - - Base::Console().Log("MaterialsEditor::onInherit()\n"); - // QItemSelectionModel* selectionModel = ui->treeMaterials->selectionModel(); - // if (!selectionModel->hasSelection()) { - // Base::Console().Log("\tNothing selected\n"); - // return; - // } - - // Base::Console().Log("\tSelected path '%s'\n", _selectedFull.toStdString().c_str()); - // int res = confirmDelete(this); - // if (res == QMessageBox::Cancel) { - // return; - // } } void MaterialsEditor::onInheritNew(bool checked) { Q_UNUSED(checked) - - Base::Console().Log("MaterialsEditor::onInherit()\n"); - // QItemSelectionModel* selectionModel = ui->treeMaterials->selectionModel(); - // if (!selectionModel->hasSelection()) { - // Base::Console().Log("\tNothing selected\n"); - // return; - // } - - // Base::Console().Log("\tSelected path '%s'\n", _selectedFull.toStdString().c_str()); - // int res = confirmDelete(this); - // if (res == QMessageBox::Cancel) { - // return; - // } } int MaterialsEditor::confirmSave(QWidget* parent) diff --git a/src/Mod/Material/Gui/MaterialsEditor.h b/src/Mod/Material/Gui/MaterialsEditor.h index 94bc86d48a..eef3d20cab 100644 --- a/src/Mod/Material/Gui/MaterialsEditor.h +++ b/src/Mod/Material/Gui/MaterialsEditor.h @@ -26,16 +26,22 @@ #include #include +#include #include #include #include #include #include +#include +#include + #include #include #include +#include "AppearancePreview.h" + namespace MatGui { @@ -80,7 +86,7 @@ public: return _modelManager; } - QString libraryPath(std::shared_ptr material) const; + static QString libraryPath(const std::shared_ptr& material); void updateMaterialAppearance(); void updateMaterialProperties(); @@ -99,14 +105,21 @@ private: Materials::MaterialManager _materialManager; Materials::ModelManager _modelManager; std::shared_ptr _material; - QSvgWidget* _rendered; - QSvgWidget* _vectored; + AppearancePreview* _rendered; bool _edited; std::list _favorites; std::list _recents; int _recentMax; + QIcon _warningIcon; void saveWindow(); + void saveMaterialTreeChildren(const Base::Reference& param, + QTreeView* tree, + QStandardItemModel* model, + QStandardItem* item); + void saveMaterialTree(const Base::Reference& param); + + void oldFormatError(); void getFavorites(); void saveFavorites(); @@ -124,10 +137,18 @@ private: void setMaterialDefaults(); void updatePreview() const; - QString getColorHash(const QString& colorString, int colorRange = 255) const; + static QString getColorHash(const QString& colorString, int colorRange = 255); - void addExpanded(QTreeView* tree, QStandardItem* parent, QStandardItem* child); - void addExpanded(QTreeView* tree, QStandardItemModel* parent, QStandardItem* child); + static void addExpanded(QTreeView* tree, QStandardItem* parent, QStandardItem* child); + static void addExpanded(QTreeView* tree, + QStandardItem* parent, + QStandardItem* child, + const Base::Reference& param); + static void addExpanded(QTreeView* tree, QStandardItemModel* parent, QStandardItem* child); + static void addExpanded(QTreeView* tree, + QStandardItemModel* parent, + QStandardItem* child, + const Base::Reference& param); void addRecents(QStandardItem* parent); void addFavorites(QStandardItem* parent); void createPreviews(); @@ -141,7 +162,8 @@ private: const std::shared_ptr>> modelTree, const QIcon& folderIcon, - const QIcon& icon); + const QIcon& icon, + const Base::Reference& param); }; } // namespace MatGui diff --git a/src/Mod/Material/Gui/ModelSelect.cpp b/src/Mod/Material/Gui/ModelSelect.cpp index 61b9543d2e..4a874939c5 100644 --- a/src/Mod/Material/Gui/ModelSelect.cpp +++ b/src/Mod/Material/Gui/ModelSelect.cpp @@ -389,18 +389,18 @@ void ModelSelect::createModelProperties() void ModelSelect::updateModelProperties(std::shared_ptr model) { QTableView* table = ui->tableProperties; - QStandardItemModel* tableModel = static_cast(table->model()); + auto tableModel = dynamic_cast(table->model()); tableModel->clear(); setHeaders(tableModel); setColumnWidths(table); - for (auto itp = model->begin(); itp != model->end(); itp++) { + for (auto& itp : *model) { QList items; - QString key = itp->first; + QString key = itp.first; const Materials::ModelProperty modelProperty = - static_cast(itp->second); + static_cast(itp.second); auto inherited = new QStandardItem(QString::fromStdString(modelProperty.isInherited() ? "*" : "")); @@ -454,7 +454,7 @@ void ModelSelect::clearMaterialModel() ui->tabWidget->setTabText(1, tr("Properties")); QTableView* table = ui->tableProperties; - QStandardItemModel* tableModel = static_cast(table->model()); + auto tableModel = dynamic_cast(table->model()); tableModel->clear(); setHeaders(tableModel); @@ -465,23 +465,19 @@ void ModelSelect::onSelectModel(const QItemSelection& selected, const QItemSelec { Q_UNUSED(deselected); - Base::Console().Log("ModelSelect::onSelectModel()\n"); - QStandardItemModel* model = static_cast(ui->treeModels->model()); + auto model = dynamic_cast(ui->treeModels->model()); QModelIndexList indexes = selected.indexes(); for (auto it = indexes.begin(); it != indexes.end(); it++) { QStandardItem* item = model->itemFromIndex(*it); - Base::Console().Log("%s\n", item->text().toStdString().c_str()); if (item) { try { _selected = item->data(Qt::UserRole).toString(); - Base::Console().Log("\t%s\n", _selected.toStdString().c_str()); updateMaterialModel(_selected); ui->standardButtons->button(QDialogButtonBox::Ok)->setEnabled(true); ui->buttonFavorite->setEnabled(true); } catch (const std::exception& e) { _selected = QString::fromStdString(""); - Base::Console().Log("Error %s\n", e.what()); clearMaterialModel(); ui->standardButtons->button(QDialogButtonBox::Ok)->setEnabled(false); ui->buttonFavorite->setEnabled(false); @@ -494,7 +490,6 @@ void ModelSelect::onDoubleClick(const QModelIndex& index) { Q_UNUSED(index) - Base::Console().Log("ModelSelect::onDoubleClick()\n"); accept(); } @@ -502,7 +497,6 @@ void ModelSelect::onURL(bool checked) { Q_UNUSED(checked) - Base::Console().Log("URL\n"); QString url = ui->editURL->text(); if (url.length() > 0) { QDesktopServices::openUrl(QUrl(url, QUrl::TolerantMode)); @@ -513,7 +507,6 @@ void ModelSelect::onDOI(bool checked) { Q_UNUSED(checked) - Base::Console().Log("DOI\n"); QString url = QString::fromStdString("https://doi.org/") + ui->editDOI->text(); if (url.length() > 0) { QDesktopServices::openUrl(QUrl(url, QUrl::TolerantMode)); @@ -524,7 +517,6 @@ void ModelSelect::onFavourite(bool checked) { Q_UNUSED(checked) - Base::Console().Log("Favorite\n"); if (isFavorite(_selected)) { removeFavorite(_selected); } diff --git a/src/Mod/Material/Gui/Resources/Material.qrc b/src/Mod/Material/Gui/Resources/Material.qrc index 787acf876c..66b472e7cc 100644 --- a/src/Mod/Material/Gui/Resources/Material.qrc +++ b/src/Mod/Material/Gui/Resources/Material.qrc @@ -8,5 +8,6 @@ icons/preview-rendered.svg icons/preview-vector.svg icons/table.svg + images/default_image.png diff --git a/src/Mod/Material/Gui/Resources/images/default_image.png b/src/Mod/Material/Gui/Resources/images/default_image.png new file mode 100644 index 0000000000000000000000000000000000000000..1dd3e62df74368d9316833b8f370dbb0c9dc1903 GIT binary patch literal 9907 zcmd^l2Uk;T*KOzu0v=H#P1GDjqy$8z69p9zrHIm`ihzLh8hVZhDhelxf>aAdX^|!! zqJZ=!CDK7kln6nZl#tw&bKdv6_Z{CE_Xm7m#)dJHy|ef8tY@vc=A2LN8|rKGatm=I z5C~pfopV9cL-Fc5^=CvH zZHzOoNQwS1Y&fjtR}}L=>Dlr9A2gk%O6F|6zavk||1K#T`-kg?4{?n-cVdbQ_zM0w zw9fK%?rX-kBjR+lWXZjs6Xjym1@(n77R}twtHo%RH%SgRjdcqREq`Mp95}a|CGxkY ziEp!gc(8%7gy8k{ASBs*j7%5Ny4Z3v!r*s(xzTs`NcWvi%cL%Actu_lzq_6i`0)kL z9*nn@|HdPqMmwC-g@+;ju}YfKCP8Kkb|$B;es%tu_{t?7z1Px2$-~Qp!aGnQ5pMS; zLxxk)4HjA#@#(;-M@ht>!RKTv8GrW3GF%L$;3$

JniINZ^1y!Ymeis^<`%~`{(nE<9fLc8Cc1TBDkW7fp?2YYGdl%!^3q> zD%;zL8=6 zl3%ao9Ki_-AAiiT$DGv;zq=?R^32g;Du3r{J5^N2QS;-KG%|Wag?fT|bE&1OUG-5; zZtfH!0+m~M8S-rx^VlKBJPr|=M+AZmj(?r_-+b=xp!{=O{%4+(c+;P2s<_F>%+4N` z{%hhVGsbDNijRbd8M;qyUq2JUf?(lf9_$AYv3i%?Sow^P?R6Q*dp?h_lZIxRPp~2IAHEn>e7E)US9t2 z;g@d1?^9L$T*j)gT6ryL>cJ;YoT%Mes46KbdHC=ljYiAJ$T+ATYM;kd`qktmN^YFf=D z)aKOZ`TzLh)gqq2?pS)W<*}A}*yP8%_D!*F{W;ezd1UIRs?^Yy+OC(mKXM+uVrs36<8HJcDVFrUFK~QRdgSj?MUWVS$^=~L417tOReaE>e;ELxUP*cYbv(z%zDPhWq3`@XZrOT$}zZ;Wso?TPZQqjaPA#ln=r z`)W64led0RG3|*@6B5uCC2wHlJ<^2``L+Z!e>--2bG1H-H^w`4YHG@~z!IBCsdgn5 zD2@fbo?VGbR`U7^;f^zlFurnSbLG20uO4$G=-TyvS8@Ly7>LfjM&B=G=AMS7^ zJbQKl^Q4ZxO28?P1XF8ZguKX!^73-+gV^6&pQ_zz=jP`A6e}uB(KO97^Ri8wnVDIh z?TGPPT3=s3+5<cwz_(?B%DEqDuUF5s@*4LQoT8s%ccH+K3_H-w1pz3n6b#B(cy4+6d`cv zz1#H;# zO*mb<)}NgoX5q6VdY9m1Jl^ZgcAMd`lcAd{#NQQ1eU0-;7y93ImW>5b9_*8HNvwzB zC)Ck5n|VuNVWV~|I;Ds1#|nNRr-xfFE8l~Ga*2h=$=RiAgucR*^0T(rX-4Gc=ElUt zpb~<~sR09vJYJnC%6=N2R*Fy?02sKtj!sS_8AqSl_WQHaOUqrD@HcuzNVK&j<#}6C zQPHqRow}TxzP`TbK!tI(zD?MM!%6bRGPmLVSffqmW2r1-h4$JL3KoDQqb1J9@r2pP zodT?Sv`q?OoAXSBaulm2IxTco#~xByWo2b`wb~+f#=0h`(f85~C_mi3 zbt;2SH6tn0e27K`YcgdcdlGd!#9qdpB5rJK;F`kM2Av9PU*Iv`@HT9xq0PvH$5WpG zskT>o4Y)X|&;mqN{b?&*P-lScGB&kp?_Q6<98m9~0H+svUTd#6zjqtHkqT!ozY6z+ z3g_B&V7JEOw6uf0A{Os&3zpB`Vj^kH%cRq8L6rP5PR`!mUW(UmxO5z(dEcb*l{(rC znhhna=)R(#F&1Y3g21v9bzJ1`YwPvHi^1>_pY|BmKCf64u9vMKA|{HWAm7& zx`n8F*hY*E?a1Qtd;fV0>bbdjv{7=zR5KvPCT+PZJ0s)vXyt15hwr`FHbLJr14g`> z=K6CzD!*qfHr1_vjj7w7_n>%j@P%;S`o)kue*Cz!^hl|zDb$L!^;p*B`)H(*;fbmeRh?lk9NPzn;T%yu2 zU`EA2V`ExZBGp%kr?s<_KK;btU^wlky-ejPE+v!fRR19(^X1M|Rjvzwn8RmS3J8SL z+;tNOK>VK6fU%9yfbp82pM;}>h{7J#zfnkn9ARD1k5^v=B&!UF&;t$)=q=ApKo0Uh zZ17#%d~2V#eL7A>8;=9a8CZ+}7=|%c!GD?S z@71OrDtw)qx?Xb2i`hUzmRewnpB1{)1h8Dk`9C+Ql-M3kp zqTxLrG+rBeT8VYn>Y=^d>OUIqVRAE1OHx)gmd2N2YK?VRnr;C~SK2|b z($&?q{e4NH!%qNfRfa$j4KV=A`NaG+HehC}@YSZ1UBErH7qO;vW&Y17USU=gREoCf zf{o5e=uGsrvbwu*yF`@U)oSDqL%SpDn3z0si$&Di4OU~9|2(YqQ9Ejvp!e2%*{|=t z8=JCh_|d}yd*;TCSG;3qfW`f$G#WPZ)O3K<&i1Pb2*LGA-?wlt zt1#-IGL7g3u|KlOgMiL{qkobWC__yrj`sk{9qy9DY+pTsI?} zzMPK3Ct znRdiW+5OUHi{D@0j8!XdRW_jq!d)iCK*TIO&9tmYwr|>3H02TR94=A zZown=97xah*yBx79o^4%`epP%i&B@TkKzzox1rI8*7GVxGQ+#LP(_UmnPx&Z8N*PP zQ-a>~_3PIpn;}RE4ngeO|lBG+Lq1qA$JCh`kC5#Hvf6p zk6zRW1<;YAtgxiXvfGyabl={+>=wg7H~`m0SM<#Q><_B?-v%oFkt;#ke5udapuaje zsOLPA<3g5xs?ZFty0^FYg}8&E!)|5RLYMczU4j=XoEjhOo4g|+pGi2k zzeaovY~|F|L%Uy`mEX4Vn=r@)(#&^2?$FY^)6n=@HD7j5#bIhgHkKAY3>G_qcA*+3L|2 zvkIOsg)*7}k~7z#qn;aO#=a&^X)Es12!118yEf#CFWoP>AJym#q$ff8tGX&Hv+1DS;30H1VrcDA;*2H1h8 zYR8HQD)+6si_HV_RbcbPfiOiK+0Z(o=^_GML0-O#-b!}_PG<}r^_7_ zaraXQ8&G_VXV3R0v2c;z(YL@)l--6(h!aqUbRkZ(ak^knuAv+_J)ZrbBVulKgxGY94}(Prt^- zGHcU{vyZ|RCj;;J2GJCtPcqkN6EcIJ@ivN%^Q=9-JrRUmg=gdBj10FQf z`V?55u8xip-iCljX)k;!v{d6~p&rjegtX+DCBNy0&&f;h;?%!K5e|5Awh z+XVnUo~jzK0PMuvDbRdl~0c{-}qvc-q z+4`xFDLwhu%b=4=h>MHz@ItQr+FYghczc6rF9U{>l9JMqtXOud=ZL)g&lI0dWd?2e z$>Ya+_Ur)_61@36I~a9{NGv>PdnkzSEYk-2zfRcSj?aHtWW=6HllcEMJ-{9L4}%2U zkpD77{_$MwGf-kD9~e=`YTOk6JZqT&t&scu2{M(y@ z5s3&S4Y9uiGX&fZ;K{NwGBPL>3WLFbI{^f46e<_cE1FN#C9S%$Qbkcw5m*@tWe?^9 zg+zdy(gmMEV9%bQwI5i3(NYL7&@n%=Lf{Lq2D2ckXJ*`>+k>#KsHouJ;DF`}h5r3Z z;S?+m+$Oi7p&>Fd66)H2u8&z%tEJ{)w4Y6|w15KO3xJn|+_z8s=+QKQVxR%=LRtsf zX=-YYrkU~{my&`aS_hnPf*f#i@_^0`N)k%k3w#jZOrtO+z{R!s;dCHEVeZNc*Xj%N zO$pXGu^}*9wx{2|eT!>>S#0$(nAbuPfg(1p55754?vSks;b}I3Q!3Tpxkn0STLx-x)B0DW%(=6gC*!|PoF-`%*Z%L z|Gt}|sdw?>ep$=F)qYdb=1EoGZ*l<(BVWJXpz_7KvbOIOnt<2=<@Tct$Rxc3Z_8z4 zX$GeZ?ob%a%_vJ=Ln91otB0_*I9bn6=BFr*hxmZF_4_ges*+CIC|y{Iu9{79y$~yc zO=Qv6)ddM)aH*?ME1J(HWj3apd_C8$uP5#OI5P6PhYHU2raFa)PH<;IIoI6~GHy(y84Kvw*z9t9JJY zgFb+^G?gtxj+j*X!p2uV86^xf)n%Zk zmy8K#+74k#!9?h(fNM9VOa7a!k-oq3M&kpm)aP_yTs6j?JA`7B5x*!TG*BkPx6n^E zp}D%&a7&_4uXA$dUij>|s|gFpf62S|vf?!plYz=1e)W~^mG8ZE+iSz19OYY`EUsQ% z`C=c(v7ZDz6O@`owpGb3qv>L(7&4e#E@_?sb4;@*LDp(+_e7V*mbBcpxVW{4FI-?2j`7X=;WI*%#`o~NVATXmYs|{jmEp=Bf!os ziHW-aXh9pO*XHKo5%#?cC@VyV7?)R2z_g<4wLuf2t9}$kjb(_1t{AOj!1cO9 z`9RaDTW>^j@`)VKfOq~%S>?!+eXstz=I`7TS%1;Dz%agg^(wfBfb_3ky#hN3<^^_I zG)7}Dx2TH=*cCWLoTw_3A$oMro12-f1NA=@@_XwR{`?%%Y1ssdyXAF0V$!DRpA`K* ziV85qn@&znj*eLw8STl6XwUBQ&LeU9q>8)I#oa(GtK5rKKvc#}zvS3$tJKO8+wYv6 zYC?7{E-q%O8fHS&z7lqCiWSA-6AL192nZ6%RQSAxC|n&YN=MTAWhPbqe2rAxQV8^I32;_!gOQDL#TU{~lJ zGFFv+dT|Ig?OtG0Y$$xTGo|M_m@$p}Oe5o}>6;YT1@P!52aaLM9PWY2*rn-_5leyw z>n@Q~cyf?^4b}G&Qv=`XezAxL)&*REGc*l(zE2mZXR%o~#Xd@;Y5@FLy_px@y+2 zb^!1Wu$w1Q9ssCJ71U7z+zDs_W7URn3Yc|bnj_>0wUSamoB+u`M?3!r;+?GQ<2Wto zyW95Aaio>6(KP*5yo3WV#ed1i#*&7kmy^zgEdg$Q0GXOUsqg`A`~CZO(2iYTn$n@a zG|+;xy`})ACFBy*(llVQiS!AjMa8DinR-kI5^E;Re&C)7Fd27feT#U|iBvEdU@zva zT@Dz|2{vIBuotA@*#4$oGkA4wb+MkGi<662$QJ}`DEK~r1Hj)5pmou=x1i+%*v|rH z*%BjQRq6n>{KB%VDt)ort0cBNde5YFFJ4SiaMB0MKi{XhtBV18pV`tOmzH`BFst?T zKeL5m#p|Q_30fGJL^~H3mx-T%1dp7b&UU4XCDz0C){Vc#-!?asb}lKeQAkus@sW3S z_0Z;9VFN-+N>5J@Ol%lh5s-k&*?9#pJuFCaXf*Y)p6uIY0-jG)h5Z6}k}g)?VBAa_ z@lNMEU|LK;p|3v%I0?i5do$yrp5F4((&ye@a#uPAY=h>vaNn<@4PFiT$0omcZ_FfM z*1p(-c;6*vSslo1Vy~Zv0Eq*jDqP@B2X7oqwF<~bpn$@?k+9s))r0-@^*bS@1(k}d zC?!Dn)BoDK>4&YQy%hn%*oQ(Qe{c#Jf>{jxC;;r>PbzjHA+$d@c#i6)1VYapu&V%$ zI?14QF)YKkS9=Ujfc*pVS0i-uq)Xqi5Vg(J@B3ve)Bwf6*I%uKOzt58aQs`h8JuwG zdjr)3lh-b$V2=U9qytL<%jpQeB-e;{n+$Mha11`;lFdy_O--bBav~7yc;;^bq8a0$ zsFXJEp7t1{G1XM-Qz_{Dvnqs*&|jkoDJdcwhh>$XDYNr7z3SChoxd-UwjRe=kGn4* zaa2NrwAk!5^=UL@xnr~{fRI4wQ=f@9c89OSNMP3hUQkKL)z#G{BqR zSpk5z^++ZjE}&yR=~SWQy{>&6zS*1pk-(7*!Jq=i zQ|WR8PYjeuS4)dI@I5f_z`%i-k3cX%Sb#tygBflBd&N3Bw}#)(1M6InU}xdfHv~cs z>gGD^ks6@JVZKn2?rmo}QrI~8+CcSuqzEIC0UtP!U!)Ha&#(cBb*ngP1RpkJf#3O(m+VIJ!1(bo|y+&XCeg$&wel<&TU-NfhnY&cC&a<%f`8@{6|sS zZG(4QyUqzuKqK2ChJ)MY03H(5ASmTqARnM7eui}hO`ZTR7-f9?^z3X_W+u}x#*b^n zKYu<5KK-x&0E05o?=&cAaG!fVMIM7C?Yjeh3C2@NXt(VP7SVFI0czNhbu`#qa}h$@nAPd(mqY9vWcW1`LifD>xdKhwKmHGB6v>hR literal 0 HcmV?d00001 diff --git a/src/Mod/Material/Gui/TextEdit.cpp b/src/Mod/Material/Gui/TextEdit.cpp index fab8df8f10..93f46b77c3 100644 --- a/src/Mod/Material/Gui/TextEdit.cpp +++ b/src/Mod/Material/Gui/TextEdit.cpp @@ -40,7 +40,7 @@ using namespace MatGui; /* TRANSLATOR MatGui::TextEdit */ TextEdit::TextEdit(const QString& propertyName, - std::shared_ptr material, + const std::shared_ptr& material, QWidget* parent) : QDialog(parent) , ui(new Ui_TextEdit) @@ -59,8 +59,6 @@ TextEdit::TextEdit(const QString& propertyName, _property = nullptr; } if (_property) { - Base::Console().Log("Value type %d\n", - static_cast(_property->getMaterialValue()->getType())); _value = _property->getString(); } else { diff --git a/src/Mod/Material/Gui/TextEdit.h b/src/Mod/Material/Gui/TextEdit.h index f505d645d5..fafca3d65c 100644 --- a/src/Mod/Material/Gui/TextEdit.h +++ b/src/Mod/Material/Gui/TextEdit.h @@ -47,7 +47,7 @@ class TextEdit: public QDialog public: TextEdit(const QString& propertyName, - std::shared_ptr material, + const std::shared_ptr& material, QWidget* parent = nullptr); ~TextEdit() override = default; diff --git a/src/Mod/Material/Resources/Materials/Test/Test Material.FCMat b/src/Mod/Material/Resources/Materials/Test/Test Material.FCMat index c4762bd97a..6cee496965 100644 --- a/src/Mod/Material/Resources/Materials/Test/Test Material.FCMat +++ b/src/Mod/Material/Resources/Materials/Test/Test Material.FCMat @@ -10,20 +10,17 @@ Inherits: DefaultAppearance: UUID: "5dbb7be6-8b63-479b-ab4c-87be02ead973" Models: - TestModel: + Test Model: UUID: "34d0583d-f999-49ba-99e6-aa40bd5c3a6b" TestArray2D: - - "20.00 C" - [["10.00 C", "10.00 kg/m^3"], ["20.00 C", "20.00 kg/m^3"], ["30.00 C", "30.00 kg/m^3"]] TestArray2D3Column: - - "20.00 C" - [["10.00 C", "11.00 kg/m^3", "12.00 Pa"], ["20.00 C", "21.00 kg/m^3", "22.00 Pa"], ["30.00 C", "31.00 kg/m^3", "32.00 Pa"]] TestArray3D: - - "20.00 C" - ["10.00 C": [["11.00 Pa", "12.00 Pa"], ["21.00 Pa", "22.00 Pa"]], "20.00 C": [], diff --git a/src/Mod/Material/Resources/Models/Architectural/Architectural.yml b/src/Mod/Material/Resources/Models/Architectural/Architectural.yml index 348c69ecc3..a94675ff0e 100644 --- a/src/Mod/Material/Resources/Models/Architectural/Architectural.yml +++ b/src/Mod/Material/Resources/Models/Architectural/Architectural.yml @@ -27,11 +27,6 @@ Model: URL: '' Description: "default architectural model" DOI: "" - Color: - Type: 'String' - Units: '' - URL: '' - Description: " " EnvironmentalEfficiencyClass: Type: 'String' Units: '' @@ -42,11 +37,6 @@ Model: Units: '' URL: '' Description: " " - Finish: - Type: 'String' - Units: '' - URL: '' - Description: " " FireResistanceClass: Type: 'String' Units: '' diff --git a/src/Mod/Material/Resources/Models/Architectural/ArchitecturalRendering.yml b/src/Mod/Material/Resources/Models/Architectural/ArchitecturalRendering.yml new file mode 100644 index 0000000000..c2bca768a8 --- /dev/null +++ b/src/Mod/Material/Resources/Models/Architectural/ArchitecturalRendering.yml @@ -0,0 +1,39 @@ +--- +# *************************************************************************** +# * * +# * Copyright (c) 2023 David Carter * +# * * +# * This program is free software; you can redistribute it and/or modify * +# * it under the terms of the GNU Lesser General Public License (LGPL) * +# * as published by the Free Software Foundation; either version 2 of * +# * the License, or (at your option) any later version. * +# * for detail see the LICENCE text file. * +# * * +# * This program 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 Library General Public License for more details. * +# * * +# * You should have received a copy of the GNU Library General Public * +# * License along with this program; if not, write to the Free Software * +# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * +# * USA * +# * * +# *************************************************************************** + +AppearanceModel: + Name: "ArchitecturalRendering" + UUID: '27e48ac9-54e1-4a1f-aa49-d5d690242705' + URL: '' + Description: "default architectural model" + DOI: "" + Color: + Type: 'Color' + Units: '' + URL: '' + Description: " " + Finish: + Type: 'String' + Units: '' + URL: '' + Description: " " diff --git a/src/Mod/Material/Resources/Models/Test/Test Model.yml b/src/Mod/Material/Resources/Models/Test/Test Model.yml index ec4243add2..783dd913c6 100644 --- a/src/Mod/Material/Resources/Models/Test/Test Model.yml +++ b/src/Mod/Material/Resources/Models/Test/Test Model.yml @@ -22,7 +22,7 @@ # *************************************************************************** Model: - Name: 'TestModel' + Name: 'Test Model' UUID: '34d0583d-f999-49ba-99e6-aa40bd5c3a6b' URL: '' Description: 'Demonstrate the different model types' @@ -42,6 +42,16 @@ Model: Units: '' URL: '' Description: "A List" + TestFileList: + Type: 'FileList' + Units: '' + URL: '' + Description: "A List of file paths" + TestImageList: + Type: 'ImageList' + Units: '' + URL: '' + Description: "A List of embedded images" TestInteger: Type: 'Integer' Units: '' @@ -67,6 +77,11 @@ Model: Units: '' URL: '' Description: "A File" + TestImage: + Type: 'Image' + Units: '' + URL: '' + Description: "An Image" TestQuantity: Type: 'Quantity' Units: 'kg/m^3' diff --git a/src/Mod/Material/materialtests/TestMaterials.py b/src/Mod/Material/materialtests/TestMaterials.py index 7c398fc194..256342026f 100644 --- a/src/Mod/Material/materialtests/TestMaterials.py +++ b/src/Mod/Material/materialtests/TestMaterials.py @@ -48,15 +48,13 @@ class MaterialTestCases(unittest.TestCase): self.assertTrue(steel.hasPhysicalModel(self.uuids.IsotropicLinearElastic)) self.assertTrue(steel.hasPhysicalModel(self.uuids.Thermal)) self.assertFalse(steel.hasPhysicalModel(self.uuids.LinearElastic)) # Not in the model - # inherited from Steel.FCMat - self.assertTrue(steel.hasAppearanceModel(self.uuids.BasicRendering)) + self.assertTrue(steel.hasAppearanceModel(self.uuids.BasicRendering)) # inherited from Steel.FCMat self.assertTrue(steel.isPhysicalModelComplete(self.uuids.Density)) self.assertFalse(steel.isPhysicalModelComplete(self.uuids.IsotropicLinearElastic)) self.assertTrue(steel.isPhysicalModelComplete(self.uuids.Thermal)) self.assertFalse(steel.isPhysicalModelComplete(self.uuids.LinearElastic)) # Not in the model - # inherited from Steel.FCMat - self.assertTrue(steel.isAppearanceModelComplete(self.uuids.BasicRendering)) + self.assertTrue(steel.isAppearanceModelComplete(self.uuids.BasicRendering)) # inherited from Steel.FCMat self.assertTrue(steel.hasPhysicalProperty("Density")) self.assertTrue(steel.hasPhysicalProperty("BulkModulus")) @@ -159,19 +157,16 @@ class MaterialTestCases(unittest.TestCase): self.assertEqual(properties["Density"], parseQuantity("7900.00 kg/m^3").UserString) # self.assertEqual(properties["BulkModulus"], "") - self.assertAlmostEqual(parseQuantity(properties["PoissonRatio"]).Value, - parseQuantity("0.3").Value) + self.assertAlmostEqual(parseQuantity(properties["PoissonRatio"]).Value, parseQuantity("0.3").Value) self.assertEqual(properties["YoungsModulus"], parseQuantity("210.00 GPa").UserString) # self.assertEqual(properties["ShearModulus"], "") self.assertEqual(properties["SpecificHeat"], parseQuantity("590.00 J/kg/K").UserString) self.assertEqual(properties["ThermalConductivity"], parseQuantity("43.00 W/m/K").UserString) - self.assertEqual(properties["ThermalExpansionCoefficient"], - parseQuantity("12.00 µm/m/K").UserString) + self.assertEqual(properties["ThermalExpansionCoefficient"], parseQuantity("12.00 µm/m/K").UserString) self.assertEqual(properties["AmbientColor"], "(0.0020, 0.0020, 0.0020, 1.0)") self.assertEqual(properties["DiffuseColor"], "(0.0000, 0.0000, 0.0000, 1.0)") self.assertEqual(properties["EmissiveColor"], "(0.0000, 0.0000, 0.0000, 1.0)") - self.assertAlmostEqual(parseQuantity(properties["Shininess"]).Value, - parseQuantity("0.06").Value) + self.assertAlmostEqual(parseQuantity(properties["Shininess"]).Value, parseQuantity("0.06").Value) self.assertEqual(properties["SpecularColor"], "(0.9800, 0.9800, 0.9800, 1.0)") self.assertAlmostEqual(parseQuantity(properties["Transparency"]).Value, parseQuantity("0").Value) @@ -204,15 +199,12 @@ class MaterialTestCases(unittest.TestCase): self.assertAlmostEqual(steel.getAppearanceValue("Transparency"), 0.0) def testMaterialsWithModel(self): - # IsotropicLinearElastic - materials = self.MaterialManager.materialsWithModel('f6f9e48c-b116-4e82-ad7f-3659a9219c50') - materialsComplete = self.MaterialManager.materialsWithModelComplete( - 'f6f9e48c-b116-4e82-ad7f-3659a9219c50') + materials = self.MaterialManager.materialsWithModel('f6f9e48c-b116-4e82-ad7f-3659a9219c50') # IsotropicLinearElastic + materialsComplete = self.MaterialManager.materialsWithModelComplete('f6f9e48c-b116-4e82-ad7f-3659a9219c50') # IsotropicLinearElastic self.assertTrue(len(materialsComplete) <= len(materials)) # Not all will be complete - # LinearElastic - materialsLinearElastic = self.MaterialManager.materialsWithModel( - '7b561d1d-fb9b-44f6-9da9-56a4f74d7536') + + materialsLinearElastic = self.MaterialManager.materialsWithModel('7b561d1d-fb9b-44f6-9da9-56a4f74d7536') # LinearElastic # All LinearElastic models should be in IsotropicLinearElastic since it is inherited self.assertTrue(len(materialsLinearElastic) <= len(materials)) @@ -220,22 +212,203 @@ class MaterialTestCases(unittest.TestCase): self.assertIn(mat, materials) def testMaterialByPath(self): - steel = self.MaterialManager.getMaterialByPath( - 'Standard/Metal/Steel/CalculiX-Steel.FCMat', 'System') + steel = self.MaterialManager.getMaterialByPath('Standard/Metal/Steel/CalculiX-Steel.FCMat', 'System') self.assertIsNotNone(steel) self.assertEqual(steel.Name, "CalculiX-Steel") self.assertEqual(steel.UUID, "92589471-a6cb-4bbc-b748-d425a17dea7d") - # Same with leading '/' - steel2 = self.MaterialManager.getMaterialByPath( - '/Standard/Metal/Steel/CalculiX-Steel.FCMat', 'System') + steel2 = self.MaterialManager.getMaterialByPath('/Standard/Metal/Steel/CalculiX-Steel.FCMat', 'System') self.assertIsNotNone(steel2) self.assertEqual(steel2.Name, "CalculiX-Steel") self.assertEqual(steel2.UUID, "92589471-a6cb-4bbc-b748-d425a17dea7d") - # Same with leading '/System' - steel3 = self.MaterialManager.getMaterialByPath( - '/System/Standard/Metal/Steel/CalculiX-Steel.FCMat', 'System') + steel3 = self.MaterialManager.getMaterialByPath('/System/Standard/Metal/Steel/CalculiX-Steel.FCMat', 'System') self.assertIsNotNone(steel3) self.assertEqual(steel3.Name, "CalculiX-Steel") self.assertEqual(steel3.UUID, "92589471-a6cb-4bbc-b748-d425a17dea7d") + + def testLists(self): + mat = self.MaterialManager.getMaterial("c6c64159-19c1-40b5-859c-10561f20f979") + self.assertIsNotNone(mat) + self.assertEqual(mat.Name, "Test Material") + self.assertEqual(mat.UUID, "c6c64159-19c1-40b5-859c-10561f20f979") + + self.assertTrue(mat.hasPhysicalModel(self.uuids.TestModel)) + self.assertFalse(mat.isPhysicalModelComplete(self.uuids.TestModel)) + + self.assertTrue(mat.hasPhysicalProperty("TestList")) + + list = mat.getPhysicalValue("TestList") + self.assertEqual(len(list), 6) + self.assertEqual(list[0], "Now is the time for all good men to come to the aid of the party") + self.assertEqual(list[1], "The quick brown fox jumps over the lazy dogs back") + self.assertEqual(list[2], "Lore Ipsum") + self.assertEqual(list[3], "Single quote '") + self.assertEqual(list[4], "Double quote \"") + self.assertEqual(list[5], "Backslash \\") + + properties = mat.Properties + self.assertIn("TestList", properties) + self.assertTrue(len(properties["TestList"]) == 0) + + def test2DArray(self): + mat = self.MaterialManager.getMaterial("c6c64159-19c1-40b5-859c-10561f20f979") + self.assertIsNotNone(mat) + self.assertEqual(mat.Name, "Test Material") + self.assertEqual(mat.UUID, "c6c64159-19c1-40b5-859c-10561f20f979") + + self.assertTrue(mat.hasPhysicalModel(self.uuids.TestModel)) + self.assertTrue(mat.isPhysicalModelComplete(self.uuids.TestModel)) + + self.assertTrue(mat.hasPhysicalProperty("TestArray2D")) + + array = mat.getPhysicalValue("TestArray2D") + self.assertIsNotNone(array) + self.assertEqual(array.Rows, 3) + self.assertEqual(array.Columns, 2) + + arrayData = array.Array + self.assertIsNotNone(arrayData) + self.assertEqual(len(arrayData), 3) + self.assertEqual(len(arrayData[0]), 2) + self.assertEqual(len(arrayData[1]), 2) + self.assertEqual(len(arrayData[2]), 2) + + self.assertEqual(arrayData[0][0].UserString, parseQuantity("10.00 C").UserString) + self.assertEqual(arrayData[0][1].UserString, parseQuantity("10.00 kg/m^3").UserString) + self.assertEqual(arrayData[1][0].UserString, parseQuantity("20.00 C").UserString) + self.assertEqual(arrayData[1][1].UserString, parseQuantity("20.00 kg/m^3").UserString) + self.assertEqual(arrayData[2][0].UserString, parseQuantity("30.00 C").UserString) + self.assertEqual(arrayData[2][1].UserString, parseQuantity("30.00 kg/m^3").UserString) + + self.assertAlmostEqual(arrayData[0][0].Value, 10.0) + self.assertAlmostEqual(arrayData[0][1].Value, 1e-8) + self.assertAlmostEqual(arrayData[1][0].Value, 20.0) + self.assertAlmostEqual(arrayData[1][1].Value, 2e-8) + self.assertAlmostEqual(arrayData[2][0].Value, 30.0) + self.assertAlmostEqual(arrayData[2][1].Value, 3e-8) + + self.assertAlmostEqual(arrayData[-1][0].Value, 30.0) # Last in list + with self.assertRaises(IndexError): + self.assertAlmostEqual(arrayData[3][0].Value, 10.0) + self.assertAlmostEqual(arrayData[0][-1].Value, 1e-8) + with self.assertRaises(IndexError): + self.assertAlmostEqual(arrayData[0][2].Value, 10.0) + + self.assertEqual(array.getValue(0,0).UserString, parseQuantity("10.00 C").UserString) + self.assertEqual(array.getValue(0,1).UserString, parseQuantity("10.00 kg/m^3").UserString) + self.assertEqual(array.getValue(1,0).UserString, parseQuantity("20.00 C").UserString) + self.assertEqual(array.getValue(1,1).UserString, parseQuantity("20.00 kg/m^3").UserString) + self.assertEqual(array.getValue(2,0).UserString, parseQuantity("30.00 C").UserString) + self.assertEqual(array.getValue(2,1).UserString, parseQuantity("30.00 kg/m^3").UserString) + + self.assertAlmostEqual(array.getValue(0,0).Value, 10.0) + self.assertAlmostEqual(array.getValue(0,1).Value, 1e-8) + self.assertAlmostEqual(array.getValue(1,0).Value, 20.0) + self.assertAlmostEqual(array.getValue(1,1).Value, 2e-8) + self.assertAlmostEqual(array.getValue(2,0).Value, 30.0) + self.assertAlmostEqual(array.getValue(2,1).Value, 3e-8) + + with self.assertRaises(IndexError): + self.assertAlmostEqual(array.getValue(-1,0).Value, 10.0) + with self.assertRaises(IndexError): + self.assertAlmostEqual(array.getValue(3,0).Value, 10.0) + with self.assertRaises(IndexError): + self.assertAlmostEqual(array.getValue(0,-1).Value, 10.0) + with self.assertRaises(IndexError): + self.assertAlmostEqual(array.getValue(0,2).Value, 10.0) + + for rowIndex in range(0, array.Rows): + row = array.getRow(rowIndex) + self.assertIsNotNone(row) + self.assertEqual(len(row), 2) + + with self.assertRaises(IndexError): + row = array.getRow(-1) + with self.assertRaises(IndexError): + row = array.getRow(3) + + def test2DArray(self): + mat = self.MaterialManager.getMaterial("c6c64159-19c1-40b5-859c-10561f20f979") + self.assertIsNotNone(mat) + self.assertEqual(mat.Name, "Test Material") + self.assertEqual(mat.UUID, "c6c64159-19c1-40b5-859c-10561f20f979") + + self.assertTrue(mat.hasPhysicalModel(self.uuids.TestModel)) + self.assertFalse(mat.isPhysicalModelComplete(self.uuids.TestModel)) + + self.assertTrue(mat.hasPhysicalProperty("TestArray3D")) + + array = mat.getPhysicalValue("TestArray3D") + self.assertIsNotNone(array) + self.assertEqual(array.Depth, 3) + self.assertEqual(array.Columns, 2) + self.assertEqual(array.getRows(), 2) + self.assertEqual(array.getRows(0), 2) + self.assertEqual(array.getRows(1), 0) + self.assertEqual(array.getRows(2), 3) + + arrayData = array.Array + self.assertIsNotNone(arrayData) + self.assertEqual(len(arrayData), 3) + self.assertEqual(len(arrayData[0]), 2) + self.assertEqual(len(arrayData[1]), 0) + self.assertEqual(len(arrayData[2]), 3) + + self.assertEqual(arrayData[0][0][0].UserString, parseQuantity("11.00 Pa").UserString) + self.assertEqual(arrayData[0][0][1].UserString, parseQuantity("12.00 Pa").UserString) + self.assertEqual(arrayData[0][1][0].UserString, parseQuantity("21.00 Pa").UserString) + self.assertEqual(arrayData[0][1][1].UserString, parseQuantity("22.00 Pa").UserString) + self.assertEqual(arrayData[2][0][0].UserString, parseQuantity("10.00 Pa").UserString) + self.assertEqual(arrayData[2][0][1].UserString, parseQuantity("11.00 Pa").UserString) + self.assertEqual(arrayData[2][1][0].UserString, parseQuantity("20.00 Pa").UserString) + self.assertEqual(arrayData[2][1][1].UserString, parseQuantity("21.00 Pa").UserString) + self.assertEqual(arrayData[2][2][0].UserString, parseQuantity("30.00 Pa").UserString) + self.assertEqual(arrayData[2][2][1].UserString, parseQuantity("31.00 Pa").UserString) + + self.assertEqual(array.getDepthValue(0).UserString, parseQuantity("10.00 C").UserString) + self.assertEqual(array.getDepthValue(1).UserString, parseQuantity("20.00 C").UserString) + self.assertEqual(array.getDepthValue(2).UserString, parseQuantity("30.00 C").UserString) + + self.assertEqual(arrayData[0][0][-1].UserString, parseQuantity("12.00 Pa").UserString) + with self.assertRaises(IndexError): + self.assertEqual(arrayData[0][0][2].UserString, parseQuantity("11.00 Pa").UserString) + self.assertEqual(arrayData[0][-1][0].UserString, parseQuantity("21.00 Pa").UserString) + with self.assertRaises(IndexError): + self.assertEqual(arrayData[0][2][0].UserString, parseQuantity("11.00 Pa").UserString) + with self.assertRaises(IndexError): + self.assertEqual(arrayData[1][0][0].UserString, parseQuantity("11.00 Pa").UserString) + self.assertEqual(arrayData[-1][0][0].UserString, parseQuantity("10.00 Pa").UserString) + with self.assertRaises(IndexError): + self.assertEqual(arrayData[3][0][0].UserString, parseQuantity("11.00 Pa").UserString) + + with self.assertRaises(IndexError): + self.assertEqual(array.getDepthValue(-1).UserString, parseQuantity("10.00 C").UserString) + with self.assertRaises(IndexError): + self.assertEqual(array.getDepthValue(3).UserString, parseQuantity("10.00 C").UserString) + + self.assertEqual(array.getValue(0,0,0).UserString, parseQuantity("11.00 Pa").UserString) + self.assertEqual(array.getValue(0,0,1).UserString, parseQuantity("12.00 Pa").UserString) + self.assertEqual(array.getValue(0,1,0).UserString, parseQuantity("21.00 Pa").UserString) + self.assertEqual(array.getValue(0,1,1).UserString, parseQuantity("22.00 Pa").UserString) + self.assertEqual(array.getValue(2,0,0).UserString, parseQuantity("10.00 Pa").UserString) + self.assertEqual(array.getValue(2,0,1).UserString, parseQuantity("11.00 Pa").UserString) + self.assertEqual(array.getValue(2,1,0).UserString, parseQuantity("20.00 Pa").UserString) + self.assertEqual(array.getValue(2,1,1).UserString, parseQuantity("21.00 Pa").UserString) + self.assertEqual(array.getValue(2,2,0).UserString, parseQuantity("30.00 Pa").UserString) + self.assertEqual(array.getValue(2,2,1).UserString, parseQuantity("31.00 Pa").UserString) + + with self.assertRaises(IndexError): + self.assertEqual(array.getValue(0,0,-1).UserString, parseQuantity("11.00 Pa").UserString) + with self.assertRaises(IndexError): + self.assertEqual(array.getValue(0,0,2).UserString, parseQuantity("11.00 Pa").UserString) + with self.assertRaises(IndexError): + self.assertEqual(array.getValue(0,-1,0).UserString, parseQuantity("11.00 Pa").UserString) + with self.assertRaises(IndexError): + self.assertEqual(array.getValue(0,2,0).UserString, parseQuantity("11.00 Pa").UserString) + with self.assertRaises(IndexError): + self.assertEqual(array.getValue(1,0,0).UserString, parseQuantity("11.00 Pa").UserString) + with self.assertRaises(IndexError): + self.assertEqual(array.getValue(-1,0,0).UserString, parseQuantity("11.00 Pa").UserString) + with self.assertRaises(IndexError): + self.assertEqual(array.getValue(3,0,0).UserString, parseQuantity("11.00 Pa").UserString) diff --git a/src/Mod/Material/materialtests/TestModels.py b/src/Mod/Material/materialtests/TestModels.py index d4fd143442..69e1e5def6 100644 --- a/src/Mod/Material/materialtests/TestModels.py +++ b/src/Mod/Material/materialtests/TestModels.py @@ -56,6 +56,7 @@ class ModelTestCases(unittest.TestCase): self.assertTrue(self.uuids.Electromagnetic, "b2eb5f48-74b3-4193-9fbb-948674f427f3") self.assertTrue(self.uuids.Architectural, "32439c3b-262f-4b7b-99a8-f7f44e5894c8") + self.assertTrue(self.uuids.ArchitecturalRendering, "27e48ac9-54e1-4a1f-aa49-d5d690242705") self.assertTrue(self.uuids.Costs, "881df808-8726-4c2e-be38-688bb6cce466") @@ -64,6 +65,25 @@ class ModelTestCases(unittest.TestCase): self.assertTrue(self.uuids.AdvancedRendering, "c880f092-cdae-43d6-a24b-55e884aacbbf") self.assertTrue(self.uuids.VectorRendering, "fdf5a80e-de50-4157-b2e5-b6e5f88b680e") + self.assertTrue(self.uuids.RenderAppleseed, "b0a10f70-13bf-4598-ab63-bcfbbcd813e3") + self.assertTrue(self.uuids.RenderCarpaint, "4d2cc163-0707-40e2-a9f7-14288c4b97bd") + self.assertTrue(self.uuids.RenderCycles, "a6da1b66-929c-48bf-ae80-3b0495c7b50b") + self.assertTrue(self.uuids.RenderDiffuse, "c19b2d30-c55b-48aa-a938-df9e2f7779cf") + self.assertTrue(self.uuids.RenderDisney, "f8723572-4470-4c39-a749-6d3b71358a5b") + self.assertTrue(self.uuids.RenderEmission, "9f6cb588-c89d-4a74-9d0f-2786a8568cec") + self.assertTrue(self.uuids.RenderGlass, "d76a56f5-7250-4efb-bb89-8ea0a9ccaa6b") + self.assertTrue(self.uuids.RenderLuxcore, "6b992304-33e0-490b-a391-e9d0af79bb69") + self.assertTrue(self.uuids.RenderLuxrender, "67ac6a63-e173-4e05-898b-af743f1f9563") + self.assertTrue(self.uuids.RenderMixed, "84bab333-984f-47fe-a512-d17c7cb2daa9") + self.assertTrue(self.uuids.RenderOspray, "a4792c23-0be9-47c2-b16d-47b2d2d5efd6") + self.assertTrue(self.uuids.RenderPbrt, "35b34b82-4325-4d27-97bd-d10bb2c56586") + self.assertTrue(self.uuids.RenderPovray, "6ec8b415-4c7b-4206-a80b-2ea64101f34b") + self.assertTrue(self.uuids.RenderSubstancePBR, "f212b643-db96-452e-8428-376a4534e5ab") + self.assertTrue(self.uuids.RenderTexture, "fc9b6135-95cd-4ba8-ad9a-0972caeebad2") + self.assertTrue(self.uuids.RenderWB, "344008be-a837-43af-90bc-f795f277b309") + + self.assertTrue(self.uuids.TestModel, "34d0583d-f999-49ba-99e6-aa40bd5c3a6b") + def testModelLoad(self): density = self.ModelManager.getModel(self.uuids.Density) self.assertIsNotNone(density) diff --git a/tests/src/Mod/Material/App/TestMaterialCards.cpp b/tests/src/Mod/Material/App/TestMaterialCards.cpp index 9597aca1f7..ab2c2096a3 100644 --- a/tests/src/Mod/Material/App/TestMaterialCards.cpp +++ b/tests/src/Mod/Material/App/TestMaterialCards.cpp @@ -35,6 +35,7 @@ #include #include +#include #include #include #include @@ -42,34 +43,37 @@ // clang-format off class TestMaterialCards : public ::testing::Test { - protected: - static void SetUpTestSuite() { - if (App::Application::GetARGC() == 0) { - constexpr int argc = 1; - std::array argv {"FreeCAD"}; - App::Application::Config()["ExeName"] = "FreeCAD"; - App::Application::init(argc, argv.data()); +protected: + static void SetUpTestSuite() { + if (App::Application::GetARGC() == 0) { + constexpr int argc = 1; + std::array argv {"FreeCAD"}; + App::Application::Config()["ExeName"] = "FreeCAD"; + App::Application::init(argc, argv.data()); + } } - } - void SetUp() override { - // Create a temporary library - QString libPath = QDir::tempPath() + QString::fromStdString("/TestMaterialCards"); - QDir libDir(libPath); - libDir.removeRecursively(); // Clear old run data - libDir.mkdir(libPath); - _library = std::make_shared(QString::fromStdString("Testing"), - libPath, - QString::fromStdString(":/icons/preferences-general.svg"), - false); - _modelManager = new Materials::ModelManager(); - _materialManager = new Materials::MaterialManager(); - } + void SetUp() override { + // Create a temporary library + QString libPath = QDir::tempPath() + QString::fromStdString("/TestMaterialCards"); + QDir libDir(libPath); + libDir.removeRecursively(); // Clear old run data + libDir.mkdir(libPath); + _library = std::make_shared(QString::fromStdString("Testing"), + libPath, + QString::fromStdString(":/icons/preferences-general.svg"), + false); + _modelManager = new Materials::ModelManager(); + _materialManager = new Materials::MaterialManager(); - // void TearDown() override {} - Materials::ModelManager* _modelManager; - Materials::MaterialManager* _materialManager; - std::shared_ptr _library; + _testMaterialUUID = QString::fromStdString("c6c64159-19c1-40b5-859c-10561f20f979"); + } + + // void TearDown() override {} + Materials::ModelManager* _modelManager; + Materials::MaterialManager* _materialManager; + std::shared_ptr _library; + QString _testMaterialUUID; }; TEST_F(TestMaterialCards, TestCopy) @@ -78,11 +82,11 @@ TEST_F(TestMaterialCards, TestCopy) EXPECT_TRUE(_library); // FAIL() << "Test library " << _library->getDirectoryPath().toStdString() << "\n"; - auto testMaterial = _materialManager->getMaterial(Materials::ModelUUIDs::ModelUUID_Test_Material); + auto testMaterial = _materialManager->getMaterial(_testMaterialUUID); auto newMaterial = std::make_shared(*testMaterial); - EXPECT_EQ(testMaterial->getUUID(), Materials::ModelUUIDs::ModelUUID_Test_Material); - EXPECT_EQ(newMaterial->getUUID(), Materials::ModelUUIDs::ModelUUID_Test_Material); + EXPECT_EQ(testMaterial->getUUID(), _testMaterialUUID); + EXPECT_EQ(newMaterial->getUUID(), _testMaterialUUID); // Save the material _materialManager->saveMaterial(_library, @@ -91,7 +95,7 @@ TEST_F(TestMaterialCards, TestCopy) false, // overwrite true, // saveAsCopy false); // saveInherited - EXPECT_EQ(newMaterial->getUUID(), Materials::ModelUUIDs::ModelUUID_Test_Material); + EXPECT_EQ(newMaterial->getUUID(), _testMaterialUUID); EXPECT_EQ(newMaterial->getName(), QString::fromStdString("Test Material2")); // Save it when it already exists throwing an error @@ -102,7 +106,7 @@ TEST_F(TestMaterialCards, TestCopy) true, // saveAsCopy false) // saveInherited , Materials::MaterialExists); - EXPECT_EQ(newMaterial->getUUID(), Materials::ModelUUIDs::ModelUUID_Test_Material); + EXPECT_EQ(newMaterial->getUUID(), _testMaterialUUID); EXPECT_EQ(newMaterial->getName(), QString::fromStdString("Test Material2")); // Overwrite the existing file @@ -112,7 +116,7 @@ TEST_F(TestMaterialCards, TestCopy) true, // overwrite true, // saveAsCopy false);// saveInherited - EXPECT_EQ(newMaterial->getUUID(), Materials::ModelUUIDs::ModelUUID_Test_Material); + EXPECT_EQ(newMaterial->getUUID(), _testMaterialUUID); EXPECT_EQ(newMaterial->getName(), QString::fromStdString("Test Material2")); // Save to a new file, inheritance mode @@ -122,7 +126,7 @@ TEST_F(TestMaterialCards, TestCopy) false, // overwrite true, // saveAsCopy true);// saveInherited - EXPECT_EQ(newMaterial->getUUID(), Materials::ModelUUIDs::ModelUUID_Test_Material); + EXPECT_EQ(newMaterial->getUUID(), _testMaterialUUID); EXPECT_EQ(newMaterial->getName(), QString::fromStdString("Test Material3")); // Save to a new file, inheritance mode. no copy @@ -132,7 +136,7 @@ TEST_F(TestMaterialCards, TestCopy) false, // overwrite false, // saveAsCopy true);// saveInherited - EXPECT_NE(newMaterial->getUUID(), Materials::ModelUUIDs::ModelUUID_Test_Material); + EXPECT_NE(newMaterial->getUUID(), _testMaterialUUID); EXPECT_EQ(newMaterial->getName(), QString::fromStdString("Test Material4")); QString uuid1 = newMaterial->getUUID(); @@ -175,4 +179,27 @@ TEST_F(TestMaterialCards, TestCopy) EXPECT_EQ(newMaterial->getName(), QString::fromStdString("Test Material6")); } +TEST_F(TestMaterialCards, TestColumns) +{ + EXPECT_NE(_modelManager, nullptr); + EXPECT_TRUE(_library); + + auto testMaterial = _materialManager->getMaterial(_testMaterialUUID); + + EXPECT_TRUE(testMaterial->hasPhysicalProperty(QString::fromStdString("TestArray2D"))); + auto array2d = testMaterial->getPhysicalProperty(QString::fromStdString("TestArray2D"))->getMaterialValue(); + EXPECT_TRUE(array2d); + EXPECT_EQ(static_cast(*array2d).columns(), 2); + + EXPECT_TRUE(testMaterial->hasPhysicalProperty(QString::fromStdString("TestArray2D3Column"))); + auto array2d3Column = testMaterial->getPhysicalProperty(QString::fromStdString("TestArray2D3Column"))->getMaterialValue(); + EXPECT_TRUE(array2d3Column); + EXPECT_EQ(static_cast(*array2d3Column).columns(), 3); + + EXPECT_TRUE(testMaterial->hasPhysicalProperty(QString::fromStdString("TestArray3D"))); + auto array3d = testMaterial->getPhysicalProperty(QString::fromStdString("TestArray3D"))->getMaterialValue(); + EXPECT_TRUE(array3d); + EXPECT_EQ(static_cast(*array3d).columns(), 2); +} + // clang-format on diff --git a/tests/src/Mod/Material/App/TestMaterialProperties.cpp b/tests/src/Mod/Material/App/TestMaterialProperties.cpp index bac0b1adee..804cc227fa 100644 --- a/tests/src/Mod/Material/App/TestMaterialProperties.cpp +++ b/tests/src/Mod/Material/App/TestMaterialProperties.cpp @@ -140,13 +140,8 @@ void check2DArray(Materials::MaterialProperty& prop) EXPECT_EQ(prop.getType(), Materials::MaterialValue::Array2D); EXPECT_TRUE(prop.isNull()); auto array = std::static_pointer_cast(prop.getMaterialValue()); - EXPECT_FALSE(array->defaultSet()); EXPECT_EQ(array->rows(), 0); auto variant = prop.getValue(); // Throw an error? - // Getting a default value is not yet defined or implemented - // EXPECT_TRUE(variant.canConvert()); - // EXPECT_TRUE(variant.isNull()); - // EXPECT_FALSE(variant.value().isValid()); -- the variant is null EXPECT_FALSE(variant.canConvert()); EXPECT_TRUE(variant.toString().isNull()); EXPECT_TRUE(variant.toString().isEmpty()); @@ -183,13 +178,8 @@ void check3DArray(Materials::MaterialProperty& prop) EXPECT_EQ(prop.getType(), Materials::MaterialValue::Array3D); EXPECT_TRUE(prop.isNull()); auto array = std::static_pointer_cast(prop.getMaterialValue()); - EXPECT_FALSE(array->defaultSet()); EXPECT_EQ(array->depth(), 0); auto variant = prop.getValue(); // Throw an error? - // Getting a default value is not yet defined or implemented - // EXPECT_TRUE(variant.canConvert()); - // EXPECT_TRUE(variant.isNull()); - // EXPECT_FALSE(variant.value().isValid()); -- the variant is null EXPECT_FALSE(variant.canConvert()); EXPECT_TRUE(variant.toString().isNull()); EXPECT_TRUE(variant.toString().isEmpty()); diff --git a/tests/src/Mod/Material/App/TestMaterialValue.cpp b/tests/src/Mod/Material/App/TestMaterialValue.cpp index 34155822a2..d1f27335ad 100644 --- a/tests/src/Mod/Material/App/TestMaterialValue.cpp +++ b/tests/src/Mod/Material/App/TestMaterialValue.cpp @@ -190,13 +190,6 @@ TEST_F(TestMaterialValue, TestArray2DType) auto mat2 = Materials::Material2DArray(); EXPECT_EQ(mat2.getType(), Materials::MaterialValue::Array2D); EXPECT_TRUE(mat2.isNull()); - auto variant = mat2.getDefault(); - EXPECT_TRUE(variant.isNull()); - EXPECT_FALSE(variant.canConvert()); - EXPECT_TRUE(variant.toString().isNull()); - EXPECT_TRUE(variant.toString().isEmpty()); - EXPECT_EQ(variant.toString().size(), 0); - EXPECT_EQ(mat2.rows(), 0); } @@ -205,19 +198,14 @@ TEST_F(TestMaterialValue, TestArray3DType) EXPECT_THROW(auto mat1 = Materials::MaterialValue(Materials::MaterialValue::Array3D), Materials::InvalidMaterialType); auto mat2 = Materials::Material3DArray(); + mat2.setColumns(2); EXPECT_EQ(mat2.getType(), Materials::MaterialValue::Array3D); EXPECT_TRUE(mat2.isNull()); - auto variant = mat2.getDefault(); - EXPECT_TRUE(variant.isNull()); - EXPECT_FALSE(variant.canConvert()); - EXPECT_TRUE(variant.toString().isNull()); - EXPECT_TRUE(variant.toString().isEmpty()); - EXPECT_EQ(variant.toString().size(), 0); EXPECT_EQ(mat2.depth(), 0); EXPECT_EQ(mat2.rows(), 0); EXPECT_EQ(mat2.rows(0), 0); - EXPECT_THROW(mat2.rows(1), Materials::InvalidDepth); + EXPECT_THROW(mat2.rows(1), Materials::InvalidIndex); Base::Quantity quantity; quantity.setInvalid(); @@ -225,19 +213,19 @@ TEST_F(TestMaterialValue, TestArray3DType) EXPECT_EQ(mat2.addDepth(0, quantity), 0); EXPECT_EQ(mat2.depth(), 1); EXPECT_EQ(mat2.rows(0), 0); - EXPECT_THROW(mat2.rows(1), Materials::InvalidDepth); + EXPECT_THROW(mat2.rows(1), Materials::InvalidIndex); EXPECT_EQ(mat2.addDepth(quantity), 1); EXPECT_EQ(mat2.depth(), 2); EXPECT_EQ(mat2.rows(1), 0); - EXPECT_THROW(mat2.addDepth(99, quantity), Materials::InvalidDepth); + EXPECT_THROW(mat2.addDepth(99, quantity), Materials::InvalidIndex); EXPECT_EQ(mat2.addDepth(2, quantity), 2); EXPECT_EQ(mat2.depth(), 3); EXPECT_EQ(mat2.rows(2), 0); // Add rows - auto row = std::make_shared>(); + auto row = std::make_shared>(); row->push_back(quantity); row->push_back(quantity); @@ -296,7 +284,7 @@ TEST_F(TestMaterialValue, TestArray3DType) EXPECT_EQ(mat2.getDepthValue(2), Base::Quantity::parse(QString::fromStdString("32 C"))); // Rows are currently empty - EXPECT_THROW(mat2.getValue(2, 0), Materials::InvalidRow); + EXPECT_THROW(mat2.getValue(2, 0), Materials::InvalidIndex); EXPECT_NO_THROW(mat2.getValue(0, 0)); EXPECT_FALSE(mat2.getValue(0, 0).isValid()); EXPECT_FALSE(mat2.getValue(0, 1).isValid()); @@ -306,7 +294,7 @@ TEST_F(TestMaterialValue, TestArray3DType) EXPECT_TRUE(mat2.getValue(0, 0).isValid()); mat2.setValue(0, 1, Base::Quantity::parse(QString::fromStdString("9.8 m/s/s"))); EXPECT_TRUE(mat2.getValue(0, 1).isValid()); - EXPECT_THROW(mat2.setValue(0, 2, Base::Quantity::parse(QString::fromStdString("32 C"))), Materials::InvalidColumn); + EXPECT_THROW(mat2.setValue(0, 2, Base::Quantity::parse(QString::fromStdString("32 C"))), Materials::InvalidIndex); } diff --git a/tests/src/Mod/Material/App/TestMaterials.cpp b/tests/src/Mod/Material/App/TestMaterials.cpp index 24a4f8d60f..de9447c34b 100644 --- a/tests/src/Mod/Material/App/TestMaterials.cpp +++ b/tests/src/Mod/Material/App/TestMaterials.cpp @@ -340,4 +340,33 @@ TEST_F(TestMaterial, TestCalculiXSteel) } +TEST_F(TestMaterial, TestColumns) +{ + // Start with an empty material + Materials::Material testMaterial; + auto models = testMaterial.getPhysicalModels(); + EXPECT_NE(&models, nullptr); + EXPECT_EQ(models->size(), 0); + + // Add a model + testMaterial.addPhysical(Materials::ModelUUIDs::ModelUUID_Test_Model); + models = testMaterial.getPhysicalModels(); + EXPECT_EQ(models->size(), 1); + + EXPECT_TRUE(testMaterial.hasPhysicalProperty(QString::fromStdString("TestArray2D"))); + auto array2d = testMaterial.getPhysicalProperty(QString::fromStdString("TestArray2D"))->getMaterialValue(); + EXPECT_TRUE(array2d); + EXPECT_EQ(static_cast(*array2d).columns(), 2); + + EXPECT_TRUE(testMaterial.hasPhysicalProperty(QString::fromStdString("TestArray2D3Column"))); + auto array2d3Column = testMaterial.getPhysicalProperty(QString::fromStdString("TestArray2D3Column"))->getMaterialValue(); + EXPECT_TRUE(array2d3Column); + EXPECT_EQ(static_cast(*array2d3Column).columns(), 3); + + EXPECT_TRUE(testMaterial.hasPhysicalProperty(QString::fromStdString("TestArray3D"))); + auto array3d = testMaterial.getPhysicalProperty(QString::fromStdString("TestArray3D"))->getMaterialValue(); + EXPECT_TRUE(array3d); + EXPECT_EQ(static_cast(*array3d).columns(), 2); +} + // clang-format on