diff --git a/src/Gui/View3DSettings.h b/src/Gui/View3DSettings.h index eddea34ea3e1..4c3798f07754 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 ba6f5f965ff3..c4d066b17bfc 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 row given the first column value + + + - Get the default value for the first column of the array + 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 02ef6e5465eb..706f62dddecf 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) +{ + int row; + if (!PyArg_ParseTuple(args, "i", &row)) { + return nullptr; + } + + 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) { - char* name; - if (!PyArg_ParseTuple(args, "s", &name)) { + int row; + int column; + if (!PyArg_ParseTuple(args, "ii", &row, &column)) { return nullptr; } - // QVariant value = getMaterial2DArrayPtr()->getPhysicalValue(QString::fromStdString(name)); - // return _pyObjectFromVariant(value); + 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 000000000000..b6d55f42edf5 --- /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 000000000000..e4650c59306b --- /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 ab2bc85745db..4f04e494a6fe 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 49152cd263fd..c27adbdf24db 100644 --- a/src/Mod/Material/App/Exceptions.h +++ b/src/Mod/Material/App/Exceptions.h @@ -110,6 +110,22 @@ class MaterialExists: public Base::Exception ~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 @@ class InvalidModel: public Base::Exception ~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 492730f2ec17..449c00e571c0 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 5d847d944cf6..f7b3d6b57453 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 5ccfa0346667..e68a8a777973 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 73a554ad6170..1da9c696f4bb 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 @@ class MaterialsExport MaterialLibrary: public LibraryBase, 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 @@ class MaterialsExport MaterialLibrary: public LibraryBase, 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 @@ class MaterialsExport MaterialExternalLibrary: public MaterialLibrary 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 a6b7a1f75fcd..bf2fab397831 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 61a6c9b9a892..1d1eb9d7bb9a 100644 --- a/src/Mod/Material/App/MaterialLoader.h +++ b/src/Mod/Material/App/MaterialLoader.h @@ -51,15 +51,15 @@ class MaterialEntry { 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 @@ class MaterialYamlEntry: public MaterialEntry 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 @@ class MaterialYamlEntry: public MaterialEntry 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 131f1b09b398..72c801dbd8fc 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 f13260883dd5..a4b9400227b9 100644 --- a/src/Mod/Material/App/MaterialManager.h +++ b/src/Mod/Material/App/MaterialManager.h @@ -48,60 +48,61 @@ class MaterialsExport MaterialManager: public Base::BaseClass 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 3067b139f98a..071ab12c072b 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 d14504b9e47f..99977e0d4f99 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(); +void Material2DArray::validateColumn(int column) const +{ + if (column < 0 || column >= columns()) { + throw InvalidIndex(); + } } -std::shared_ptr> Material2DArray::getRow(int row) const +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 +{ + if (level < 0 || level >= depth()) { + throw InvalidIndex(); + } +} + +void Material3DArray::validateColumn(int column) const +{ + if (column < 0 || column >= columns()) { + throw InvalidIndex(); + } +} + +void Material3DArray::validateRow(int level, int row) const { - return _value; + validateDepth(level); + + if (row < 0 || row >= rows(level)) { + throw InvalidIndex(); + } } -const std::shared_ptr>>>& +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 12b7f066a76b..89e0de8167c9 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 @@ class MaterialsExport MaterialValue: public Base::BaseClass Image = 11, File = 12, URL = 13, - MultiLineString = 14 + MultiLineString = 14, + FileList = 15, + ImageList = 16 }; MaterialValue(); explicit MaterialValue(const MaterialValue& other); @@ -99,7 +102,7 @@ class MaterialsExport MaterialValue: public Base::BaseClass } 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 @@ class MaterialsExport MaterialValue: public Base::BaseClass } void setInitialValue(ValueType inherited); + QString getYAMLStringImage() const; + QString getYAMLStringList() const; + QString getYAMLStringImageList() const; + QString getYAMLStringMultiLine() const; + ValueType _valueType; QVariant _value; }; @@ -128,58 +136,45 @@ class MaterialsExport Material2DArray: public MaterialValue bool isNull() const override; - void setDefault(MaterialValue value, bool markSet = true) - { - _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) + const QList>>& getArray() const { - _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 setColumns(int size) + { + _columns = size; } - void addRow(std::shared_ptr> row); - void insertRow(int index, std::shared_ptr> row); + 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 @@ class MaterialsExport Material3DArray: public MaterialValue bool isNull() const override; - void setDefault(MaterialValue value, bool markSet = true) - { - _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) + const QList< + std::pair>>>>>& + getArray() const { - _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 @@ class MaterialsExport Material3DArray: public MaterialValue { 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 142370292fed..b11d9db2362c 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 c1c0d7c1fce4..74a37a22cc74 100644 --- a/src/Mod/Material/App/Materials.h +++ b/src/Mod/Material/App/Materials.h @@ -321,6 +321,14 @@ class MaterialsExport Material: public Base::BaseClass { _dereferenced = true; } + bool isOldFormat() const + { + return _oldFormat; + } + void setOldFormat(bool isOld) + { + _oldFormat = isOld; + } /* * Normalize models by removing any inherited models @@ -387,12 +395,13 @@ class MaterialsExport Material: public Base::BaseClass 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 1b2374fa4ad5..63d06f2d0639 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 c0d1189642f3..e77b2c9da1d8 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 799be693fb79..23be5862534b 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 270eb6f9a62e..8e40b4428abd 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 97b82fe91f07..70a7ebb8e1a6 100644 --- a/src/Mod/Material/App/ModelUuids.h +++ b/src/Mod/Material/App/ModelUuids.h @@ -58,6 +58,7 @@ class MaterialsExport ModelUUIDs: public Base::BaseClass 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 @@ class MaterialsExport ModelUUIDs: public Base::BaseClass 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 29138e05c3bc..7448c032c798 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 94d3fb9071aa..e8d7af27daa7 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 79db6e584c97..4945e3febc8d 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 000000000000..b0351a87731e --- /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 000000000000..cbf4a71b2bed --- /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 194b5dfd36d6..359160ac1322 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 11af3e536678..0829a9565ef8 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 @@ class Array2D: public QDialog 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 3911c2f6d392..c90f671e9789 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 fb047809ebb9..37677a5f62cf 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 28903b31b9c7..00c9b6d68fb3 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 @@ class Array3D: public QDialog 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 7d2d6dd669a6..27bdc373ee2b 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 255cac8168b8..4ad6bffe93ad 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 2f07398a7977..75815b77aefc 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 @@ class ArrayDelegate: public QStyledItemDelegate 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 7c420a3495d2..c7f581316e45 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 303e94c6f60a..da5bf69fac7e 100644 --- a/src/Mod/Material/Gui/ArrayModel.h +++ b/src/Mod/Material/Gui/ArrayModel.h @@ -47,8 +47,8 @@ class AbstractArrayModel: public QAbstractTableModel 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 @@ class Array2DModel: public AbstractArrayModel 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 @@ class Array3DDepthModel: public AbstractArrayModel 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 000000000000..4776d737a502 --- /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 000000000000..31d32010199b --- /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 f464cfdcf3f3..8c250f8a7e66 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 000000000000..7111ab8335d1 --- /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 000000000000..d048b4da104b --- /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 000000000000..2c1fc90d4df5 --- /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 000000000000..6605020cf969 --- /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 000000000000..adcb1edfbfe3 --- /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 415b8886f822..cc1a59bad86c 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 af1d6ad8d891..8d781a376a8e 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 @@ class ListEdit: public QDialog 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 1f977fe13d22..edf56e2b686a 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 f451ac58d30b..f10726c59850 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 + } + if (type == "Image") { + return {64, 64}; } - else if (type == "2DArray" || type == "3DArray" || type == "MultiLineString" - || type == "List") { - return QSize(23, 23); + 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 0d389c711370..83c4f3a83ad0 100644 --- a/src/Mod/Material/Gui/MaterialDelegate.h +++ b/src/Mod/Material/Gui/MaterialDelegate.h @@ -44,7 +44,7 @@ class MaterialDelegate: public QStyledItemDelegate ~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 @@ class MaterialDelegate: public QStyledItemDelegate 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 df344b7ea8f4..1f82b7c39e00 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 9e173104cc73..9d4028a3b4f5 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 91b059da9e1a..a75b8801b4fb 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); +} + +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())); + + 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); + } + } } -// 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())) - -// QIcon MaterialsEditor::errorIcon(const QIcon &icon) const { -// auto pixmap = icon.pixmap(); -// } +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("DiffuseColor"))) { - diffuseColor = _material->getAppearanceValueString(QString::fromStdString("DiffuseColor")); + if (_material->hasAppearanceProperty(QString::fromStdString("AmbientColor"))) { + QString color = _material->getAppearanceValueString(QString::fromStdString("AmbientColor")); + _rendered->setAmbientColor(getColorHash(color, 255)); } - else if (_material->hasAppearanceProperty(QString::fromStdString("ViewColor"))) { - diffuseColor = _material->getAppearanceValueString(QString::fromStdString("ViewColor")); + else { + _rendered->resetAmbientColor(); } - else if (_material->hasAppearanceProperty(QString::fromStdString("Color"))) { - diffuseColor = _material->getAppearanceValueString(QString::fromStdString("Color")); + if (_material->hasAppearanceProperty(QString::fromStdString("DiffuseColor"))) { + QString color = _material->getAppearanceValueString(QString::fromStdString("DiffuseColor")); + _rendered->setDiffuseColor(getColorHash(color, 255)); + } + else { + _rendered->resetDiffuseColor(); } - 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 94bc86d48add..eef3d20cabba 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 @@ class MaterialsEditor: public QDialog 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 @@ class MaterialsEditor: public QDialog 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 @@ class MaterialsEditor: public QDialog void setMaterialDefaults(); void updatePreview() const; - QString getColorHash(const QString& colorString, int colorRange = 255) const; - - void addExpanded(QTreeView* tree, QStandardItem* parent, QStandardItem* child); - void addExpanded(QTreeView* tree, QStandardItemModel* parent, QStandardItem* child); + static QString getColorHash(const QString& colorString, int colorRange = 255); + + 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 @@ class MaterialsEditor: public QDialog 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 61b9543d2e6d..4a874939c5ed 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 787acf876c94..66b472e7cc48 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 000000000000..1dd3e62df743 Binary files /dev/null and b/src/Mod/Material/Gui/Resources/images/default_image.png differ diff --git a/src/Mod/Material/Gui/TextEdit.cpp b/src/Mod/Material/Gui/TextEdit.cpp index fab8df8f10df..93f46b77c3f8 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 f505d645d5b8..fafca3d65c24 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 c4762bd97a73..6cee49696515 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 348c69ecc3fa..a94675ff0ef9 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 000000000000..c2bca768a812 --- /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 ec4243add2f2..783dd913c6bb 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 7c398fc1944a..256342026fda 100644 --- a/src/Mod/Material/materialtests/TestMaterials.py +++ b/src/Mod/Material/materialtests/TestMaterials.py @@ -48,15 +48,13 @@ def testCalculiXSteel(self): 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 @@ def testCalculiXSteel(self): 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 @@ def testCalculiXSteel(self): 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 @@ def testMaterialsWithModel(self): 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 d4fd1434425f..69e1e5def63c 100644 --- a/src/Mod/Material/materialtests/TestModels.py +++ b/src/Mod/Material/materialtests/TestModels.py @@ -56,6 +56,7 @@ def testUUIDs(self): 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 @@ def testUUIDs(self): 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 9597aca1f73b..ab2c2096a391 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 TearDown() override {} - Materials::ModelManager* _modelManager; - Materials::MaterialManager* _materialManager; - std::shared_ptr _library; + + 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(); + + _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 bac0b1adee91..804cc227faec 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 34155822a2ef..d1f27335ad47 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 24a4f8d60ff1..de9447c34b6b 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