Merge pull request #10690 from davesrocketshop/material_merge
Material: Material handling enhancements
This commit is contained in:
@@ -47,6 +47,13 @@ runs:
|
||||
testCommand: ${{ inputs.builddir }}/tests/Tests_run --gtest_output=json:${{ inputs.reportdir }}core_gtest_results.json
|
||||
testLogFile: ${{ inputs.reportdir }}core_gtest_test_log.txt
|
||||
testName: Core
|
||||
- name: C++ Material tests
|
||||
id: material
|
||||
uses: ./.github/workflows/actions/runCPPTests/runSingleTest
|
||||
with:
|
||||
testCommand: ${{ inputs.builddir }}/tests/Material_tests_run --gtest_output=json:${{ inputs.reportdir }}material_gtest_results.json
|
||||
testLogFile: ${{ inputs.reportdir }}material_gtest_test_log.txt
|
||||
testName: Material
|
||||
- name: C++ Mesh tests
|
||||
id: mesh
|
||||
uses: ./.github/workflows/actions/runCPPTests/runSingleTest
|
||||
|
||||
@@ -51,6 +51,7 @@ CheckInterModuleDependencies()
|
||||
FreeCADLibpackChecks()
|
||||
SetupDoxygen()
|
||||
SetupLibFmt()
|
||||
SetupYamlCpp()
|
||||
if(NOT FREECAD_LIBPACK_USE OR FREECAD_LIBPACK_CHECKFILE_CLBUNDLER)
|
||||
SetupPython()
|
||||
SetupPCL()
|
||||
|
||||
4
cMake/FreeCAD_Helpers/SetupLibYaml.cmake
Normal file
4
cMake/FreeCAD_Helpers/SetupLibYaml.cmake
Normal file
@@ -0,0 +1,4 @@
|
||||
macro(SetupYamlCpp)
|
||||
# -------------------------------- YamlCpp --------------------------------
|
||||
find_package(yaml-cpp REQUIRED)
|
||||
endmacro(SetupYamlCpp)
|
||||
@@ -25,8 +25,8 @@
|
||||
#include <Base/Console.h>
|
||||
#include <Base/PyObjectBase.h>
|
||||
#include <Gui/Application.h>
|
||||
#include <Gui/Language/Translator.h>
|
||||
#include <Gui/WidgetFactory.h>
|
||||
#include <Gui/Language/Translator.h>
|
||||
|
||||
#include "DlgSettingsFemCcxImp.h"
|
||||
#include "DlgSettingsFemElmerImp.h"
|
||||
@@ -34,18 +34,25 @@
|
||||
#include "DlgSettingsFemGeneralImp.h"
|
||||
#include "DlgSettingsFemGmshImp.h"
|
||||
#include "DlgSettingsFemInOutVtkImp.h"
|
||||
#include "DlgSettingsFemMaterialImp.h"
|
||||
#include "DlgSettingsFemMystranImp.h"
|
||||
#include "DlgSettingsFemZ88Imp.h"
|
||||
#include "PropertyFemMeshItem.h"
|
||||
#include "ViewProviderAnalysis.h"
|
||||
#include "ViewProviderFemMesh.h"
|
||||
#include "ViewProviderFemMeshShape.h"
|
||||
#include "ViewProviderFemMeshShapeNetgen.h"
|
||||
#include "ViewProviderSetElements.h"
|
||||
#include "ViewProviderSetFaces.h"
|
||||
#include "ViewProviderSetGeometry.h"
|
||||
#include "ViewProviderSetNodes.h"
|
||||
#include "ViewProviderSolver.h"
|
||||
#include "ViewProviderFemConstraint.h"
|
||||
#include "ViewProviderFemConstraintBearing.h"
|
||||
#include "ViewProviderFemConstraintContact.h"
|
||||
#include "ViewProviderFemConstraintDisplacement.h"
|
||||
#include "ViewProviderFemConstraintFixed.h"
|
||||
#include "ViewProviderFemConstraintFluidBoundary.h"
|
||||
#include "ViewProviderFemConstraintForce.h"
|
||||
#include "ViewProviderFemConstraintFluidBoundary.h"
|
||||
#include "ViewProviderFemConstraintGear.h"
|
||||
#include "ViewProviderFemConstraintHeatflux.h"
|
||||
#include "ViewProviderFemConstraintInitialTemperature.h"
|
||||
@@ -56,15 +63,7 @@
|
||||
#include "ViewProviderFemConstraintSpring.h"
|
||||
#include "ViewProviderFemConstraintTemperature.h"
|
||||
#include "ViewProviderFemConstraintTransform.h"
|
||||
#include "ViewProviderFemMesh.h"
|
||||
#include "ViewProviderFemMeshShape.h"
|
||||
#include "ViewProviderFemMeshShapeNetgen.h"
|
||||
#include "ViewProviderResult.h"
|
||||
#include "ViewProviderSetElements.h"
|
||||
#include "ViewProviderSetFaces.h"
|
||||
#include "ViewProviderSetGeometry.h"
|
||||
#include "ViewProviderSetNodes.h"
|
||||
#include "ViewProviderSolver.h"
|
||||
#include "Workbench.h"
|
||||
|
||||
#ifdef FC_USE_VTK
|
||||
@@ -178,7 +177,6 @@ PyMOD_INIT_FUNC(FemGui)
|
||||
new Gui::PrefPageProducer<FemGui::DlgSettingsFemElmerImp>(QT_TRANSLATE_NOOP("QObject", "FEM"));
|
||||
new Gui::PrefPageProducer<FemGui::DlgSettingsFemMystranImp>(QT_TRANSLATE_NOOP("QObject", "FEM"));
|
||||
new Gui::PrefPageProducer<FemGui::DlgSettingsFemZ88Imp>(QT_TRANSLATE_NOOP("QObject", "FEM"));
|
||||
new Gui::PrefPageProducer<FemGui::DlgSettingsFemMaterialImp>(QT_TRANSLATE_NOOP("QObject", "FEM"));
|
||||
|
||||
// register preferences pages on Import-Export
|
||||
new Gui::PrefPageProducer<FemGui::DlgSettingsFemExportAbaqusImp>(QT_TRANSLATE_NOOP("QObject", "Import-Export"));
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
|
||||
# Many warnings caused by vtk
|
||||
if(CMAKE_COMPILER_IS_CLANGXX)
|
||||
add_compile_options(-Wno-pedantic) # needed for vtk headers
|
||||
if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 4.0)
|
||||
|
||||
if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 4.0)
|
||||
add_compile_options(-Wno-inconsistent-missing-override)
|
||||
endif()
|
||||
elseif(CMAKE_COMPILER_IS_GNUCXX)
|
||||
@@ -15,12 +15,10 @@ else(MSVC)
|
||||
add_definitions(-DHAVE_LIMITS_H -DHAVE_CONFIG_H)
|
||||
endif(MSVC)
|
||||
|
||||
|
||||
if(BUILD_FEM_NETGEN)
|
||||
add_definitions(-DFCWithNetgen)
|
||||
endif(BUILD_FEM_NETGEN)
|
||||
|
||||
|
||||
include_directories(
|
||||
${CMAKE_BINARY_DIR}
|
||||
${CMAKE_SOURCE_DIR}/src
|
||||
@@ -37,18 +35,15 @@ include_directories(
|
||||
link_directories(${OCC_LIBRARY_DIR})
|
||||
link_directories(${SMESH_LIB_PATH})
|
||||
|
||||
|
||||
set(FemGui_LIBS
|
||||
Fem
|
||||
FreeCADGui
|
||||
PartGui
|
||||
)
|
||||
|
||||
|
||||
generate_from_xml(ViewProviderFemMeshPy)
|
||||
generate_from_xml(ViewProviderFemPostPipelinePy)
|
||||
|
||||
|
||||
SET(Python_SRCS
|
||||
ViewProviderFemMeshPy.xml
|
||||
ViewProviderFemMeshPyImp.cpp
|
||||
@@ -57,7 +52,6 @@ SET(Python_SRCS
|
||||
)
|
||||
SOURCE_GROUP("Python" FILES ${Python_SRCS})
|
||||
|
||||
|
||||
set(FemGui_UIC_SRCS
|
||||
DlgSettingsFemCcx.ui
|
||||
DlgSettingsFemElmer.ui
|
||||
@@ -65,7 +59,6 @@ set(FemGui_UIC_SRCS
|
||||
DlgSettingsFemGeneral.ui
|
||||
DlgSettingsFemGmsh.ui
|
||||
DlgSettingsFemInOutVtk.ui
|
||||
DlgSettingsFemMaterial.ui
|
||||
DlgSettingsFemMystran.ui
|
||||
DlgSettingsFemZ88.ui
|
||||
TaskCreateNodeSet.ui
|
||||
@@ -88,6 +81,7 @@ set(FemGui_UIC_SRCS
|
||||
TaskAnalysisInfo.ui
|
||||
TaskDriver.ui
|
||||
)
|
||||
|
||||
if(BUILD_FEM_VTK)
|
||||
set(FemGui_UIC_SRCS
|
||||
${FemGui_UIC_SRCS}
|
||||
@@ -126,9 +120,6 @@ SET(FemGui_DLG_SRCS
|
||||
DlgSettingsFemInOutVtk.ui
|
||||
DlgSettingsFemInOutVtkImp.cpp
|
||||
DlgSettingsFemInOutVtkImp.h
|
||||
DlgSettingsFemMaterial.ui
|
||||
DlgSettingsFemMaterialImp.cpp
|
||||
DlgSettingsFemMaterialImp.h
|
||||
DlgSettingsFemMystran.ui
|
||||
DlgSettingsFemMystranImp.cpp
|
||||
DlgSettingsFemMystranImp.h
|
||||
@@ -186,14 +177,13 @@ SET(FemGui_DLG_SRCS
|
||||
)
|
||||
SOURCE_GROUP("Constraint-Dialogs" FILES ${FemGui_DLG_SRCS})
|
||||
|
||||
set (Fem_TR_QRC ${CMAKE_CURRENT_BINARY_DIR}/Resources/Fem_translation.qrc)
|
||||
set(Fem_TR_QRC ${CMAKE_CURRENT_BINARY_DIR}/Resources/Fem_translation.qrc)
|
||||
qt_find_and_add_translation(QM_SRCS "Resources/translations/*_*.ts"
|
||||
${CMAKE_CURRENT_BINARY_DIR}/Resources/translations)
|
||||
qt_create_resource_file(${Fem_TR_QRC} ${QM_SRCS})
|
||||
qt_add_resources(FemResource_SRCS Resources/Fem.qrc ${Fem_TR_QRC})
|
||||
SOURCE_GROUP("Resources" FILES ${FemResource_SRCS})
|
||||
|
||||
|
||||
SET(FemGui_SRCS_ViewProvider
|
||||
ViewProviderFemMesh.cpp
|
||||
ViewProviderFemMesh.h
|
||||
@@ -254,7 +244,6 @@ SET(FemGui_SRCS_ViewProvider
|
||||
)
|
||||
SOURCE_GROUP("ViewProvider" FILES ${FemGui_SRCS_ViewProvider})
|
||||
|
||||
|
||||
SET(FemGui_SRCS_TaskBoxes
|
||||
TaskObjectName.ui
|
||||
TaskObjectName.cpp
|
||||
@@ -272,6 +261,7 @@ SET(FemGui_SRCS_TaskBoxes
|
||||
TaskTetParameter.cpp
|
||||
TaskTetParameter.h
|
||||
)
|
||||
|
||||
if(BUILD_FEM_VTK)
|
||||
SET(FemGui_SRCS_TaskBoxes
|
||||
${FemGui_SRCS_TaskBoxes}
|
||||
@@ -291,8 +281,8 @@ if(BUILD_FEM_VTK)
|
||||
TaskPostWarpVector.ui
|
||||
)
|
||||
endif(BUILD_FEM_VTK)
|
||||
SOURCE_GROUP("Task_Boxes" FILES ${FemGui_SRCS_TaskBoxes})
|
||||
|
||||
SOURCE_GROUP("Task_Boxes" FILES ${FemGui_SRCS_TaskBoxes})
|
||||
|
||||
SET(FemGui_SRCS_TaskDlg
|
||||
TaskDlgCreateNodeSet.h
|
||||
@@ -304,7 +294,6 @@ SET(FemGui_SRCS_TaskDlg
|
||||
)
|
||||
SOURCE_GROUP("Task_Dialogs" FILES ${FemGui_SRCS_TaskDlg})
|
||||
|
||||
|
||||
SET(FemGui_SRCS_Module
|
||||
AppFemGui.cpp
|
||||
AppFemGuiPy.cpp
|
||||
@@ -325,7 +314,6 @@ SET(FemGui_SRCS_Module
|
||||
)
|
||||
SOURCE_GROUP("Module" FILES ${FemGui_SRCS_Module})
|
||||
|
||||
|
||||
if(BUILD_FEM_VTK)
|
||||
SET(FemGui_SRCS_Post
|
||||
ViewProviderFemPostObject.h
|
||||
@@ -336,11 +324,10 @@ if(BUILD_FEM_VTK)
|
||||
ViewProviderFemPostFunction.cpp
|
||||
ViewProviderFemPostFilter.h
|
||||
ViewProviderFemPostFilter.cpp
|
||||
)
|
||||
)
|
||||
SOURCE_GROUP("PostObjects" FILES ${FemGui_SRCS_Post})
|
||||
endif(BUILD_FEM_VTK)
|
||||
|
||||
|
||||
SET(FemGui_SRCS
|
||||
${Python_SRCS}
|
||||
${FemGui_DLG_SRCS}
|
||||
@@ -365,13 +352,10 @@ SET(FemGuiIcon_SVG
|
||||
add_library(FemGui SHARED ${FemGui_SRCS} ${FemGuiIcon_SVG})
|
||||
target_link_libraries(FemGui ${FemGui_LIBS} ${VTK_LIBRARIES})
|
||||
|
||||
|
||||
fc_copy_sources(FemGui "${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_DATADIR}/Mod/Fem" ${FemGuiIcon_SVG})
|
||||
|
||||
|
||||
INSTALL(FILES ${FemGuiIcon_SVG} DESTINATION "${CMAKE_INSTALL_DATADIR}/Mod/Fem/Resources/icons")
|
||||
|
||||
|
||||
# Python modules ui files, they are copied as they are, thus the need not to be added to Fem.qrc
|
||||
# see https://forum.freecad.org/viewtopic.php?f=10&t=25833
|
||||
SET(FemGuiPythonUI_SRCS
|
||||
@@ -409,10 +393,7 @@ fc_copy_sources(FemPythonUi "${CMAKE_BINARY_DIR}/Mod/Fem" ${FemGuiPythonUI_SRCS}
|
||||
|
||||
INSTALL(FILES ${FemGuiPythonUI_SRCS} DESTINATION Mod/Fem/Resources/ui)
|
||||
|
||||
|
||||
|
||||
SET_BIN_DIR(FemGui FemGui /Mod/Fem)
|
||||
SET_PYTHON_PREFIX_SUFFIX(FemGui)
|
||||
|
||||
|
||||
INSTALL(TARGETS FemGui DESTINATION ${CMAKE_INSTALL_LIBDIR})
|
||||
|
||||
@@ -1,75 +0,0 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2018 FreeCAD Developers *
|
||||
* Author: Bernd Hahnebach <bernd@bimstatik.ch> *
|
||||
* Based on src/Mod/Fem/Gui/DlgSettingsFemElmerImp.cpp *
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library 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 library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#include "PreCompiled.h"
|
||||
|
||||
#include "DlgSettingsFemMaterialImp.h"
|
||||
#include "ui_DlgSettingsFemMaterial.h"
|
||||
|
||||
|
||||
using namespace FemGui;
|
||||
|
||||
DlgSettingsFemMaterialImp::DlgSettingsFemMaterialImp(QWidget* parent)
|
||||
: PreferencePage(parent)
|
||||
, ui(new Ui_DlgSettingsFemMaterialImp)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
}
|
||||
|
||||
DlgSettingsFemMaterialImp::~DlgSettingsFemMaterialImp() = default;
|
||||
|
||||
void DlgSettingsFemMaterialImp::saveSettings()
|
||||
{
|
||||
ui->cb_use_built_in_materials->onSave();
|
||||
ui->cb_use_mat_from_config_dir->onSave();
|
||||
ui->cb_use_mat_from_custom_dir->onSave();
|
||||
ui->fc_custom_mat_dir->onSave();
|
||||
ui->cb_delete_duplicates->onSave();
|
||||
ui->cb_sort_by_resources->onSave();
|
||||
}
|
||||
|
||||
void DlgSettingsFemMaterialImp::loadSettings()
|
||||
{
|
||||
ui->cb_use_built_in_materials->onRestore();
|
||||
ui->cb_use_mat_from_config_dir->onRestore();
|
||||
ui->cb_use_mat_from_custom_dir->onRestore();
|
||||
ui->fc_custom_mat_dir->onRestore();
|
||||
ui->cb_delete_duplicates->onRestore();
|
||||
ui->cb_sort_by_resources->onRestore();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the strings of the subwidgets using the current language.
|
||||
*/
|
||||
void DlgSettingsFemMaterialImp::changeEvent(QEvent* e)
|
||||
{
|
||||
if (e->type() == QEvent::LanguageChange) {
|
||||
ui->retranslateUi(this);
|
||||
}
|
||||
else {
|
||||
QWidget::changeEvent(e);
|
||||
}
|
||||
}
|
||||
|
||||
#include "moc_DlgSettingsFemMaterialImp.cpp"
|
||||
@@ -1,55 +0,0 @@
|
||||
/**************************************************************************
|
||||
* Copyright (c) 2018 FreeCAD Developers *
|
||||
* Author: Bernd Hahnebach <bernd@bimstatik.ch> *
|
||||
* Based on src/Mod/Fem/Gui/DlgSettingsFemElmer.h *
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library 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 library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef FEMGUI_DLGSETTINGSFEMMATERIALIMP_H
|
||||
#define FEMGUI_DLGSETTINGSFEMMATERIALIMP_H
|
||||
|
||||
#include <Gui/PropertyPage.h>
|
||||
#include <memory>
|
||||
|
||||
|
||||
namespace FemGui
|
||||
{
|
||||
class Ui_DlgSettingsFemMaterialImp;
|
||||
|
||||
class DlgSettingsFemMaterialImp: public Gui::Dialog::PreferencePage
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit DlgSettingsFemMaterialImp(QWidget* parent = nullptr);
|
||||
~DlgSettingsFemMaterialImp() override;
|
||||
|
||||
protected:
|
||||
void saveSettings() override;
|
||||
void loadSettings() override;
|
||||
void changeEvent(QEvent* e) override;
|
||||
|
||||
private:
|
||||
std::unique_ptr<Ui_DlgSettingsFemMaterialImp> ui;
|
||||
};
|
||||
|
||||
} // namespace FemGui
|
||||
|
||||
#endif // FEMGUI_DLGSETTINGSFEMMATERIALIMP_H
|
||||
73
src/Mod/Material/App/AppMaterial.cpp
Normal file
73
src/Mod/Material/App/AppMaterial.cpp
Normal file
@@ -0,0 +1,73 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
|
||||
* *
|
||||
* 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 *
|
||||
* <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
**************************************************************************/
|
||||
|
||||
#include "PreCompiled.h"
|
||||
#ifndef _PreComp_
|
||||
#endif
|
||||
|
||||
#include <Base/Console.h>
|
||||
#include <Base/Interpreter.h>
|
||||
#include <Base/PyObjectBase.h>
|
||||
|
||||
// #include "Model.h"
|
||||
#include "MaterialManagerPy.h"
|
||||
#include "MaterialPy.h"
|
||||
#include "ModelManagerPy.h"
|
||||
#include "ModelPropertyPy.h"
|
||||
#include "ModelPy.h"
|
||||
|
||||
namespace Materials
|
||||
{
|
||||
class Module: public Py::ExtensionModule<Module>
|
||||
{
|
||||
public:
|
||||
Module()
|
||||
: Py::ExtensionModule<Module>("Material")
|
||||
{
|
||||
initialize("This module is the Material module."); // register with Python
|
||||
}
|
||||
|
||||
~Module() override = default;
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
PyObject* initModule()
|
||||
{
|
||||
return Base::Interpreter().addModule(new Module);
|
||||
}
|
||||
|
||||
} // namespace Materials
|
||||
|
||||
PyMOD_INIT_FUNC(Material)
|
||||
{
|
||||
PyObject* module = Materials::initModule();
|
||||
|
||||
Base::Console().Log("Loading Material module... done\n");
|
||||
|
||||
Base::Interpreter().addType(&Materials::MaterialManagerPy ::Type, module, "MaterialManager");
|
||||
Base::Interpreter().addType(&Materials::MaterialPy ::Type, module, "Material");
|
||||
Base::Interpreter().addType(&Materials::ModelManagerPy ::Type, module, "ModelManager");
|
||||
Base::Interpreter().addType(&Materials::ModelPropertyPy ::Type, module, "ModelProperty");
|
||||
Base::Interpreter().addType(&Materials::ModelPy ::Type, module, "Model");
|
||||
|
||||
PyMOD_Return(module);
|
||||
}
|
||||
99
src/Mod/Material/App/CMakeLists.txt
Normal file
99
src/Mod/Material/App/CMakeLists.txt
Normal file
@@ -0,0 +1,99 @@
|
||||
if(MSVC)
|
||||
add_definitions(-DFCAppMaterial -DHAVE_ACOSH -DHAVE_ASINH -DHAVE_ATANH)
|
||||
else(MSVC)
|
||||
add_definitions(-DHAVE_LIMITS_H -DHAVE_CONFIG_H)
|
||||
endif(MSVC)
|
||||
|
||||
add_definitions(-DYAML_CPP_STATIC_DEFINE)
|
||||
|
||||
include_directories(
|
||||
${CMAKE_BINARY_DIR}
|
||||
${CMAKE_BINARY_DIR}/src
|
||||
${CMAKE_SOURCE_DIR}/src
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${Boost_INCLUDE_DIRS}
|
||||
${PYTHON_INCLUDE_DIRS}
|
||||
${XercesC_INCLUDE_DIRS}
|
||||
${ZLIB_INCLUDE_DIR}
|
||||
${YAML_CPP_INCLUDE_DIR}
|
||||
)
|
||||
link_directories(${YAML_CPP_LIBRARY_DIR})
|
||||
|
||||
set(Material_LIBS
|
||||
${Boost_LIBRARIES}
|
||||
FreeCADApp
|
||||
)
|
||||
|
||||
include_directories(
|
||||
${QtConcurrent_INCLUDE_DIRS}
|
||||
)
|
||||
list(APPEND Material_LIBS
|
||||
${QtConcurrent_LIBRARIES}
|
||||
${YAML_CPP_LIBRARIES}
|
||||
)
|
||||
|
||||
generate_from_xml(MaterialManagerPy)
|
||||
generate_from_xml(MaterialPy)
|
||||
generate_from_xml(ModelManagerPy)
|
||||
generate_from_xml(ModelPropertyPy)
|
||||
generate_from_xml(ModelPy)
|
||||
|
||||
SET(Python_SRCS
|
||||
Exceptions.h
|
||||
MaterialManagerPy.xml
|
||||
MaterialManagerPyImpl.cpp
|
||||
MaterialPy.xml
|
||||
MaterialPyImpl.cpp
|
||||
ModelManagerPy.xml
|
||||
ModelManagerPyImpl.cpp
|
||||
ModelPropertyPy.xml
|
||||
ModelPropertyPyImpl.cpp
|
||||
ModelPy.xml
|
||||
ModelPyImpl.cpp
|
||||
)
|
||||
SOURCE_GROUP("Python" FILES ${Python_SRCS})
|
||||
|
||||
SET(Material_SRCS
|
||||
${Python_SRCS}
|
||||
AppMaterial.cpp
|
||||
FolderTree.h
|
||||
MaterialConfigLoader.cpp
|
||||
MaterialConfigLoader.h
|
||||
MaterialLibrary.cpp
|
||||
MaterialLibrary.h
|
||||
MaterialLoader.cpp
|
||||
MaterialLoader.h
|
||||
MaterialManager.cpp
|
||||
MaterialManager.h
|
||||
Materials.cpp
|
||||
Materials.h
|
||||
MaterialValue.cpp
|
||||
MaterialValue.h
|
||||
Model.cpp
|
||||
Model.h
|
||||
ModelLibrary.cpp
|
||||
ModelLibrary.h
|
||||
ModelLoader.cpp
|
||||
ModelLoader.h
|
||||
ModelManager.cpp
|
||||
ModelManager.h
|
||||
ModelUuids.h
|
||||
PreCompiled.cpp
|
||||
PreCompiled.h
|
||||
trim.h
|
||||
)
|
||||
|
||||
if(FREECAD_USE_PCH)
|
||||
add_definitions(-D_PreComp_)
|
||||
GET_MSVC_PRECOMPILED_SOURCE("PreCompiled.cpp" PCH_SRCS ${Material_SRCS})
|
||||
ADD_MSVC_PRECOMPILED_HEADER(Material PreCompiled.h PreCompiled.cpp PCH_SRCS)
|
||||
endif(FREECAD_USE_PCH)
|
||||
|
||||
add_library(Material SHARED ${Material_SRCS})
|
||||
target_link_libraries(Material ${Material_LIBS})
|
||||
|
||||
SET_BIN_DIR(Material Material /Mod/Material)
|
||||
SET_PYTHON_PREFIX_SUFFIX(Material)
|
||||
|
||||
INSTALL(TARGETS Material DESTINATION ${CMAKE_INSTALL_LIBDIR})
|
||||
153
src/Mod/Material/App/Exceptions.h
Normal file
153
src/Mod/Material/App/Exceptions.h
Normal file
@@ -0,0 +1,153 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
|
||||
* *
|
||||
* 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 *
|
||||
* <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef MATERIAL_EXCEPTIONS_H
|
||||
#define MATERIAL_EXCEPTIONS_H
|
||||
|
||||
#include <Base/BaseClass.h>
|
||||
#include <Base/Exception.h>
|
||||
|
||||
namespace Materials
|
||||
{
|
||||
|
||||
class Uninitialized: public Base::Exception
|
||||
{
|
||||
public:
|
||||
Uninitialized()
|
||||
{}
|
||||
explicit Uninitialized(const char* msg)
|
||||
{
|
||||
this->setMessage(msg);
|
||||
}
|
||||
~Uninitialized() noexcept override = default;
|
||||
};
|
||||
|
||||
class ModelNotFound: public Base::Exception
|
||||
{
|
||||
public:
|
||||
ModelNotFound()
|
||||
{}
|
||||
explicit ModelNotFound(const char* msg)
|
||||
{
|
||||
this->setMessage(msg);
|
||||
}
|
||||
~ModelNotFound() noexcept override = default;
|
||||
};
|
||||
|
||||
class MaterialNotFound: public Base::Exception
|
||||
{
|
||||
public:
|
||||
MaterialNotFound()
|
||||
{}
|
||||
explicit MaterialNotFound(const char* msg)
|
||||
{
|
||||
this->setMessage(msg);
|
||||
}
|
||||
~MaterialNotFound() noexcept override = default;
|
||||
};
|
||||
|
||||
class PropertyNotFound: public Base::Exception
|
||||
{
|
||||
public:
|
||||
PropertyNotFound()
|
||||
{}
|
||||
explicit PropertyNotFound(const char* msg)
|
||||
{
|
||||
this->setMessage(msg);
|
||||
}
|
||||
~PropertyNotFound() noexcept override = default;
|
||||
};
|
||||
|
||||
class LibraryNotFound: public Base::Exception
|
||||
{
|
||||
public:
|
||||
LibraryNotFound()
|
||||
{}
|
||||
explicit LibraryNotFound(const char* msg)
|
||||
{
|
||||
this->setMessage(msg);
|
||||
}
|
||||
~LibraryNotFound() noexcept override = default;
|
||||
};
|
||||
|
||||
class InvalidModel: public Base::Exception
|
||||
{
|
||||
public:
|
||||
InvalidModel()
|
||||
{}
|
||||
explicit InvalidModel(const char* msg)
|
||||
{
|
||||
this->setMessage(msg);
|
||||
}
|
||||
~InvalidModel() noexcept override = default;
|
||||
};
|
||||
|
||||
class InvalidRow: public Base::Exception
|
||||
{
|
||||
public:
|
||||
InvalidRow()
|
||||
{}
|
||||
explicit InvalidRow(char* msg)
|
||||
{
|
||||
this->setMessage(msg);
|
||||
}
|
||||
~InvalidRow() noexcept override = default;
|
||||
};
|
||||
|
||||
class InvalidColumn: public Base::Exception
|
||||
{
|
||||
public:
|
||||
InvalidColumn()
|
||||
{}
|
||||
explicit InvalidColumn(char* msg)
|
||||
{
|
||||
this->setMessage(msg);
|
||||
}
|
||||
~InvalidColumn() noexcept override = default;
|
||||
};
|
||||
|
||||
class InvalidIndex: public Base::Exception
|
||||
{
|
||||
public:
|
||||
InvalidIndex()
|
||||
{}
|
||||
explicit InvalidIndex(char* msg)
|
||||
{
|
||||
this->setMessage(msg);
|
||||
}
|
||||
~InvalidIndex() noexcept override = default;
|
||||
};
|
||||
|
||||
class UnknownValueType: public Base::Exception
|
||||
{
|
||||
public:
|
||||
UnknownValueType()
|
||||
{}
|
||||
explicit UnknownValueType(char* msg)
|
||||
{
|
||||
this->setMessage(msg);
|
||||
}
|
||||
~UnknownValueType() noexcept override = default;
|
||||
};
|
||||
|
||||
} // namespace Materials
|
||||
|
||||
#endif // MATERIAL_EXCEPTIONS_H
|
||||
86
src/Mod/Material/App/FolderTree.h
Normal file
86
src/Mod/Material/App/FolderTree.h
Normal file
@@ -0,0 +1,86 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
|
||||
* *
|
||||
* 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 *
|
||||
* <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef MATERIAL_FOLDERTREE_H
|
||||
#define MATERIAL_FOLDERTREE_H
|
||||
|
||||
#include <QString>
|
||||
#include <map>
|
||||
|
||||
namespace Materials
|
||||
{
|
||||
|
||||
template<class T>
|
||||
class FolderTreeNode
|
||||
{
|
||||
public:
|
||||
enum NodeType
|
||||
{
|
||||
DataNode,
|
||||
FolderNode
|
||||
};
|
||||
|
||||
FolderTreeNode()
|
||||
{}
|
||||
virtual ~FolderTreeNode() = default;
|
||||
|
||||
NodeType getType() const
|
||||
{
|
||||
return _type;
|
||||
}
|
||||
void setType(NodeType type)
|
||||
{
|
||||
_type = type;
|
||||
}
|
||||
|
||||
const std::shared_ptr<std::map<QString, FolderTreeNode<T>*>> getFolder() const
|
||||
{
|
||||
return _folder;
|
||||
}
|
||||
std::shared_ptr<std::map<QString, FolderTreeNode<T>*>> getFolder()
|
||||
{
|
||||
return _folder;
|
||||
}
|
||||
const T* getData() const
|
||||
{
|
||||
return _data;
|
||||
}
|
||||
|
||||
void setFolder(std::shared_ptr<std::map<QString, FolderTreeNode<T>*>> folder)
|
||||
{
|
||||
setType(FolderNode);
|
||||
_folder = folder;
|
||||
}
|
||||
void setData(const T* data)
|
||||
{
|
||||
setType(DataNode);
|
||||
_data = data;
|
||||
}
|
||||
|
||||
private:
|
||||
NodeType _type;
|
||||
std::shared_ptr<std::map<QString, FolderTreeNode<T>*>> _folder;
|
||||
const T* _data;
|
||||
};
|
||||
|
||||
} // namespace Materials
|
||||
|
||||
#endif // MATERIAL_FOLDERTREE_H
|
||||
395
src/Mod/Material/App/MaterialConfigLoader.cpp
Normal file
395
src/Mod/Material/App/MaterialConfigLoader.cpp
Normal file
@@ -0,0 +1,395 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
|
||||
* *
|
||||
* 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 *
|
||||
* <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
**************************************************************************/
|
||||
|
||||
#include "PreCompiled.h"
|
||||
#ifndef _PreComp_
|
||||
#include <QDirIterator>
|
||||
#include <QFileInfo>
|
||||
#include <QString>
|
||||
#endif
|
||||
|
||||
#include <QUuid>
|
||||
|
||||
#include <App/Application.h>
|
||||
#include <Base/Interpreter.h>
|
||||
#include <fstream>
|
||||
|
||||
|
||||
#include "MaterialConfigLoader.h"
|
||||
#include "MaterialLoader.h"
|
||||
#include "Model.h"
|
||||
#include "ModelUuids.h"
|
||||
|
||||
|
||||
using namespace Materials;
|
||||
|
||||
MaterialConfigLoader::MaterialConfigLoader()
|
||||
{}
|
||||
|
||||
bool MaterialConfigLoader::isConfigStyle(const QString& path)
|
||||
{
|
||||
std::ifstream infile(path.toStdString());
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
QString MaterialConfigLoader::getAuthorAndLicense(const QString& path)
|
||||
{
|
||||
std::ifstream infile(path.toStdString());
|
||||
QString noAuthor;
|
||||
|
||||
// Skip the first line
|
||||
std::string line;
|
||||
if (!std::getline(infile, line)) {
|
||||
return noAuthor;
|
||||
}
|
||||
|
||||
// The second line has it in a comment
|
||||
if (!std::getline(infile, line)) {
|
||||
return noAuthor;
|
||||
}
|
||||
std::size_t found = line.find(";");
|
||||
if (found != std::string::npos) {
|
||||
return QString::fromStdString(trim_copy(line.substr(found + 1)));
|
||||
}
|
||||
|
||||
return noAuthor;
|
||||
}
|
||||
|
||||
void MaterialConfigLoader::addVectorRendering(const QSettings& fcmat, Material* finalModel)
|
||||
{
|
||||
QString sectionFillPattern = value(fcmat, "VectorRendering/SectionFillPattern", "");
|
||||
QString sectionLinewidth = value(fcmat, "VectorRendering/SectionLinewidth", "");
|
||||
QString sectionColor = value(fcmat, "VectorRendering/SectionColor", "");
|
||||
QString viewColor = value(fcmat, "VectorRendering/ViewColor", "");
|
||||
QString viewFillPattern = value(fcmat, "VectorRendering/ViewFillPattern", "");
|
||||
QString viewLinewidth = value(fcmat, "VectorRendering/ViewLinewidth", "");
|
||||
|
||||
if (sectionFillPattern.length() + sectionLinewidth.length() + sectionColor.length()
|
||||
+ viewColor.length() + viewFillPattern.length() + viewLinewidth.length()
|
||||
> 0) {
|
||||
finalModel->addAppearance(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);
|
||||
}
|
||||
|
||||
void MaterialConfigLoader::addRendering(const QSettings& fcmat, Material* finalModel)
|
||||
{
|
||||
QString ambientColor = value(fcmat, "Rendering/AmbientColor", "");
|
||||
QString diffuseColor = value(fcmat, "Rendering/DiffuseColor", "");
|
||||
QString emissiveColor = value(fcmat, "Rendering/EmissiveColor", "");
|
||||
QString shininess = value(fcmat, "Rendering/Shininess", "");
|
||||
QString specularColor = value(fcmat, "Rendering/SpecularColor", "");
|
||||
QString transparency = value(fcmat, "Rendering/Transparency", "");
|
||||
QString texturePath = value(fcmat, "Rendering/TexturePath", "");
|
||||
QString textureScaling = value(fcmat, "Rendering/TextureScaling", "");
|
||||
QString fragmentShader = value(fcmat, "Rendering/FragmentShader", "");
|
||||
QString vertexShader = value(fcmat, "Rendering/VertexShader", "");
|
||||
|
||||
// Check which model we need
|
||||
bool useTexture = false;
|
||||
bool useAdvanced = false;
|
||||
bool useBasic = false;
|
||||
if (texturePath.length() + textureScaling.length() > 0) {
|
||||
useTexture = true;
|
||||
}
|
||||
if (fragmentShader.length() + vertexShader.length() > 0) {
|
||||
useAdvanced = true;
|
||||
}
|
||||
if (ambientColor.length() + diffuseColor.length() + emissiveColor.length() + shininess.length()
|
||||
+ specularColor.length() + transparency.length()
|
||||
> 0) {
|
||||
useBasic = true;
|
||||
}
|
||||
|
||||
if (useAdvanced) {
|
||||
finalModel->addAppearance(ModelUUID_Rendering_Advanced);
|
||||
}
|
||||
else if (useTexture) {
|
||||
finalModel->addAppearance(ModelUUID_Rendering_Texture);
|
||||
}
|
||||
else if (useBasic) {
|
||||
finalModel->addAppearance(ModelUUID_Rendering_Basic);
|
||||
}
|
||||
|
||||
// Now add the data
|
||||
setAppearanceValue(finalModel, "AmbientColor", ambientColor);
|
||||
setAppearanceValue(finalModel, "DiffuseColor", diffuseColor);
|
||||
setAppearanceValue(finalModel, "EmissiveColor", emissiveColor);
|
||||
setAppearanceValue(finalModel, "Shininess", shininess);
|
||||
setAppearanceValue(finalModel, "SpecularColor", specularColor);
|
||||
setAppearanceValue(finalModel, "Transparency", transparency);
|
||||
setAppearanceValue(finalModel, "TexturePath", texturePath);
|
||||
setAppearanceValue(finalModel, "TextureScaling", textureScaling);
|
||||
setAppearanceValue(finalModel, "FragmentShader", fragmentShader);
|
||||
setAppearanceValue(finalModel, "VertexShader", vertexShader);
|
||||
}
|
||||
|
||||
void MaterialConfigLoader::addCosts(const QSettings& fcmat, Material* finalModel)
|
||||
{
|
||||
QString productURL = value(fcmat, "Cost/ProductURL", "");
|
||||
QString specificPrice = value(fcmat, "Cost/SpecificPrice", "");
|
||||
QString vendor = value(fcmat, "Cost/Vendor", "");
|
||||
|
||||
if (productURL.length() + specificPrice.length() + vendor.length() > 0) {
|
||||
finalModel->addPhysical(ModelUUID_Costs_Default);
|
||||
}
|
||||
|
||||
// Now add the data
|
||||
setPhysicalValue(finalModel, "ProductURL", productURL);
|
||||
setPhysicalValue(finalModel, "SpecificPrice", specificPrice);
|
||||
setPhysicalValue(finalModel, "Vendor", vendor);
|
||||
}
|
||||
|
||||
void MaterialConfigLoader::addArchitectural(const QSettings& fcmat, Material* finalModel)
|
||||
{
|
||||
QString color = value(fcmat, "Architectural/Color", "");
|
||||
QString environmentalEfficiencyClass =
|
||||
value(fcmat, "Architectural/EnvironmentalEfficiencyClass", "");
|
||||
QString executionInstructions = value(fcmat, "Architectural/ExecutionInstructions", "");
|
||||
QString finish = value(fcmat, "Architectural/Finish", "");
|
||||
QString fireResistanceClass = value(fcmat, "Architectural/FireResistanceClass", "");
|
||||
QString model = value(fcmat, "Architectural/Model", "");
|
||||
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()
|
||||
> 0) {
|
||||
finalModel->addPhysical(ModelUUID_Architectural_Default);
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
void MaterialConfigLoader::addElectromagnetic(const QSettings& fcmat, Material* finalModel)
|
||||
{
|
||||
QString relativePermittivity = value(fcmat, "Electromagnetic/RelativePermittivity", "");
|
||||
QString electricalConductivity = value(fcmat, "Electromagnetic/ElectricalConductivity", "");
|
||||
QString relativePermeability = value(fcmat, "Electromagnetic/RelativePermeability", "");
|
||||
|
||||
if (relativePermittivity.length() + electricalConductivity.length()
|
||||
+ relativePermeability.length()
|
||||
> 0) {
|
||||
finalModel->addPhysical(ModelUUID_Electromagnetic_Default);
|
||||
}
|
||||
|
||||
// Now add the data
|
||||
setPhysicalValue(finalModel, "RelativePermittivity", relativePermittivity);
|
||||
setPhysicalValue(finalModel, "ElectricalConductivity", electricalConductivity);
|
||||
setPhysicalValue(finalModel, "RelativePermeability", relativePermeability);
|
||||
}
|
||||
|
||||
void MaterialConfigLoader::addThermal(const QSettings& fcmat, Material* finalModel)
|
||||
{
|
||||
QString specificHeat = value(fcmat, "Thermal/SpecificHeat", "");
|
||||
QString thermalConductivity = value(fcmat, "Thermal/ThermalConductivity", "");
|
||||
QString thermalExpansionCoefficient = value(fcmat, "Thermal/ThermalExpansionCoefficient", "");
|
||||
|
||||
if (specificHeat.length() + thermalConductivity.length() + thermalExpansionCoefficient.length()
|
||||
> 0) {
|
||||
finalModel->addPhysical(ModelUUID_Thermal_Default);
|
||||
}
|
||||
|
||||
// Now add the data
|
||||
setPhysicalValue(finalModel, "SpecificHeat", specificHeat);
|
||||
setPhysicalValue(finalModel, "ThermalConductivity", thermalConductivity);
|
||||
setPhysicalValue(finalModel, "ThermalExpansionCoefficient", thermalExpansionCoefficient);
|
||||
}
|
||||
|
||||
void MaterialConfigLoader::addFluid(const QSettings& fcmat, Material* finalModel)
|
||||
{
|
||||
QString density = value(fcmat, "Fluidic/Density", "");
|
||||
QString dynamicViscosity = value(fcmat, "Fluidic/DynamicViscosity", "");
|
||||
QString kinematicViscosity = value(fcmat, "Fluidic/KinematicViscosity", "");
|
||||
QString prandtlNumber = value(fcmat, "Fluidic/PrandtlNumber", "");
|
||||
|
||||
// Check which model we need
|
||||
bool useDensity = false;
|
||||
bool useFluid = false;
|
||||
if (density.length() > 0) {
|
||||
useDensity = true;
|
||||
}
|
||||
if (dynamicViscosity.length() + kinematicViscosity.length() + prandtlNumber.length() > 0) {
|
||||
useFluid = true;
|
||||
}
|
||||
|
||||
if (useFluid) {
|
||||
finalModel->addPhysical(ModelUUID_Fluid_Default);
|
||||
}
|
||||
else if (useDensity) {
|
||||
finalModel->addPhysical(ModelUUID_Mechanical_Density);
|
||||
}
|
||||
|
||||
// Now add the data
|
||||
setPhysicalValue(finalModel, "Density", density);
|
||||
setPhysicalValue(finalModel, "DynamicViscosity", dynamicViscosity);
|
||||
setPhysicalValue(finalModel, "KinematicViscosity", kinematicViscosity);
|
||||
setPhysicalValue(finalModel, "PrandtlNumber", prandtlNumber);
|
||||
}
|
||||
|
||||
void MaterialConfigLoader::addMechanical(const QSettings& fcmat, Material* finalModel)
|
||||
{
|
||||
QString density = value(fcmat, "Mechanical/Density", "");
|
||||
QString bulkModulus = value(fcmat, "Mechanical/BulkModulus", "");
|
||||
QString poissonRatio = value(fcmat, "Mechanical/PoissonRatio", "");
|
||||
QString shearModulus = value(fcmat, "Mechanical/ShearModulus", "");
|
||||
QString youngsModulus = value(fcmat, "Mechanical/YoungsModulus", "");
|
||||
QString angleOfFriction = value(fcmat, "Mechanical/AngleOfFriction", "");
|
||||
QString compressiveStrength = value(fcmat, "Mechanical/CompressiveStrength", "");
|
||||
QString fractureToughness = value(fcmat, "Mechanical/FractureToughness", "");
|
||||
QString ultimateStrain = value(fcmat, "Mechanical/UltimateStrain", "");
|
||||
QString ultimateTensileStrength = value(fcmat, "Mechanical/UltimateTensileStrength", "");
|
||||
QString yieldStrength = value(fcmat, "Mechanical/YieldStrength", "");
|
||||
QString stiffness = value(fcmat, "Mechanical/Stiffness", "");
|
||||
|
||||
// Check which model we need
|
||||
bool useDensity = false;
|
||||
bool useIso = false;
|
||||
bool useLinearElastic = false;
|
||||
if (density.length() > 0) {
|
||||
useDensity = true;
|
||||
}
|
||||
if (bulkModulus.length() + poissonRatio.length() + shearModulus.length()
|
||||
+ youngsModulus.length()
|
||||
> 0) {
|
||||
useIso = true;
|
||||
}
|
||||
if (angleOfFriction.length() + compressiveStrength.length() + fractureToughness.length()
|
||||
+ ultimateStrain.length() + ultimateTensileStrength.length() + yieldStrength.length()
|
||||
+ stiffness.length()
|
||||
> 0) {
|
||||
useLinearElastic = true;
|
||||
}
|
||||
|
||||
if (useLinearElastic) {
|
||||
finalModel->addPhysical(ModelUUID_Mechanical_LinearElastic);
|
||||
}
|
||||
else {
|
||||
if (useIso) {
|
||||
finalModel->addPhysical(ModelUUID_Mechanical_IsotropicLinearElastic);
|
||||
}
|
||||
if (useDensity) {
|
||||
finalModel->addPhysical(ModelUUID_Mechanical_Density);
|
||||
}
|
||||
}
|
||||
|
||||
// Now add the data
|
||||
setPhysicalValue(finalModel, "Density", density);
|
||||
setPhysicalValue(finalModel, "BulkModulus", bulkModulus);
|
||||
setPhysicalValue(finalModel, "PoissonRatio", poissonRatio);
|
||||
setPhysicalValue(finalModel, "ShearModulus", shearModulus);
|
||||
setPhysicalValue(finalModel, "YoungsModulus", youngsModulus);
|
||||
setPhysicalValue(finalModel, "AngleOfFriction", angleOfFriction);
|
||||
setPhysicalValue(finalModel, "CompressiveStrength", compressiveStrength);
|
||||
setPhysicalValue(finalModel, "FractureToughness", fractureToughness);
|
||||
setPhysicalValue(finalModel, "UltimateStrain", ultimateStrain);
|
||||
setPhysicalValue(finalModel, "UltimateTensileStrength", ultimateTensileStrength);
|
||||
setPhysicalValue(finalModel, "YieldStrength", yieldStrength);
|
||||
setPhysicalValue(finalModel, "Stiffness", stiffness);
|
||||
}
|
||||
|
||||
Material* MaterialConfigLoader::getMaterialFromPath(const MaterialLibrary& library,
|
||||
const QString& path)
|
||||
{
|
||||
QString authorAndLicense = getAuthorAndLicense(path);
|
||||
|
||||
QSettings fcmat(path, QSettings::IniFormat);
|
||||
|
||||
// General section
|
||||
// QString name = value(fcmat, "Name", ""); - always get the name from the filename
|
||||
QFileInfo filepath(path);
|
||||
QString name =
|
||||
filepath.fileName().remove(QString::fromStdString(".FCMat"), Qt::CaseInsensitive);
|
||||
QString uuid = QUuid::createUuid().toString(QUuid::WithoutBraces);
|
||||
|
||||
QString description = value(fcmat, "Description", "");
|
||||
QString sourceReference = value(fcmat, "ReferenceSource", "");
|
||||
QString sourceURL = value(fcmat, "SourceURL", "");
|
||||
|
||||
Material* finalModel = new Material(library, path, uuid, name);
|
||||
finalModel->setAuthorAndLicense(authorAndLicense);
|
||||
finalModel->setDescription(description);
|
||||
finalModel->setReference(sourceReference);
|
||||
finalModel->setURL(sourceURL);
|
||||
|
||||
QString father = value(fcmat, "Father", "");
|
||||
if (father.length() > 0) {
|
||||
finalModel->addPhysical(ModelUUID_Legacy_Father);
|
||||
|
||||
// Now add the data
|
||||
setPhysicalValue(finalModel, "Father", father);
|
||||
}
|
||||
|
||||
QString kindOfMaterial = value(fcmat, "KindOfMaterial", "");
|
||||
QString materialNumber = value(fcmat, "MaterialNumber", "");
|
||||
QString norm = value(fcmat, "Norm", "");
|
||||
QString standardCode = value(fcmat, "StandardCode", "");
|
||||
if (kindOfMaterial.length() + materialNumber.length() + norm.length() + standardCode.length()
|
||||
> 0) {
|
||||
finalModel->addPhysical(ModelUUID_Legacy_MaterialStandard);
|
||||
|
||||
// Now add the data
|
||||
setPhysicalValue(finalModel, "KindOfMaterial", kindOfMaterial);
|
||||
setPhysicalValue(finalModel, "MaterialNumber", materialNumber);
|
||||
setPhysicalValue(finalModel, "StandardCode", norm); // Norm is the same as StandardCode
|
||||
setPhysicalValue(finalModel, "StandardCode", standardCode);
|
||||
}
|
||||
|
||||
// Add the remaining sections
|
||||
addMechanical(fcmat, finalModel);
|
||||
addFluid(fcmat, finalModel);
|
||||
addThermal(fcmat, finalModel);
|
||||
addElectromagnetic(fcmat, finalModel);
|
||||
addArchitectural(fcmat, finalModel);
|
||||
addCosts(fcmat, finalModel);
|
||||
addRendering(fcmat, finalModel);
|
||||
addVectorRendering(fcmat, finalModel);
|
||||
|
||||
return finalModel;
|
||||
}
|
||||
80
src/Mod/Material/App/MaterialConfigLoader.h
Normal file
80
src/Mod/Material/App/MaterialConfigLoader.h
Normal file
@@ -0,0 +1,80 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
|
||||
* *
|
||||
* 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 *
|
||||
* <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef MATERIAL_MATERIALCONFIGLOADER_H
|
||||
#define MATERIAL_MATERIALCONFIGLOADER_H
|
||||
|
||||
#include <QDir>
|
||||
#include <QSettings>
|
||||
#include <QString>
|
||||
|
||||
#include "Materials.h"
|
||||
|
||||
namespace Materials
|
||||
{
|
||||
|
||||
class MaterialConfigLoader
|
||||
{
|
||||
public:
|
||||
MaterialConfigLoader();
|
||||
virtual ~MaterialConfigLoader() = default;
|
||||
|
||||
|
||||
static bool isConfigStyle(const QString& path);
|
||||
static Material* getMaterialFromPath(const MaterialLibrary& library, const QString& path);
|
||||
|
||||
private:
|
||||
static QString
|
||||
value(const QSettings& fcmat, const std::string& name, const std::string& defaultValue)
|
||||
{
|
||||
return fcmat.value(QString::fromStdString(name), QString::fromStdString(defaultValue))
|
||||
.toString();
|
||||
}
|
||||
|
||||
static void
|
||||
setPhysicalValue(Material* finalModel, const std::string& name, const QString& value)
|
||||
{
|
||||
if (value.length() > 0) {
|
||||
finalModel->setPhysicalValue(QString::fromStdString(name), value);
|
||||
}
|
||||
}
|
||||
static void
|
||||
setAppearanceValue(Material* finalModel, const std::string& name, const QString& value)
|
||||
{
|
||||
if (value.length() > 0) {
|
||||
finalModel->setAppearanceValue(QString::fromStdString(name), value);
|
||||
}
|
||||
}
|
||||
|
||||
static QString getAuthorAndLicense(const QString& path);
|
||||
static void addMechanical(const QSettings& fcmat, Material* finalModel);
|
||||
static void addFluid(const QSettings& fcmat, Material* finalModel);
|
||||
static void addThermal(const QSettings& fcmat, Material* finalModel);
|
||||
static void addElectromagnetic(const QSettings& fcmat, Material* finalModel);
|
||||
static void addArchitectural(const QSettings& fcmat, Material* finalModel);
|
||||
static void addCosts(const QSettings& fcmat, Material* finalModel);
|
||||
static void addRendering(const QSettings& fcmat, Material* finalModel);
|
||||
static void addVectorRendering(const QSettings& fcmat, Material* finalModel);
|
||||
};
|
||||
|
||||
} // namespace Materials
|
||||
|
||||
#endif // MATERIAL_MATERIALCONFIGLOADER_H
|
||||
160
src/Mod/Material/App/MaterialLibrary.cpp
Normal file
160
src/Mod/Material/App/MaterialLibrary.cpp
Normal file
@@ -0,0 +1,160 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
|
||||
* *
|
||||
* 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 *
|
||||
* <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
**************************************************************************/
|
||||
|
||||
#include "PreCompiled.h"
|
||||
#ifndef _PreComp_
|
||||
#endif
|
||||
|
||||
#include <App/Application.h>
|
||||
|
||||
#include "MaterialLibrary.h"
|
||||
#include "Materials.h"
|
||||
#include "ModelManager.h"
|
||||
|
||||
|
||||
using namespace Materials;
|
||||
|
||||
/* TRANSLATOR Material::Materials */
|
||||
|
||||
std::unique_ptr<std::map<QString, Material*>> MaterialLibrary::_materialPathMap =
|
||||
std::make_unique<std::map<QString, Material*>>();
|
||||
|
||||
TYPESYSTEM_SOURCE(Materials::MaterialLibrary, LibraryBase)
|
||||
|
||||
MaterialLibrary::MaterialLibrary()
|
||||
{}
|
||||
|
||||
MaterialLibrary::MaterialLibrary(const QString& libraryName,
|
||||
const QString& dir,
|
||||
const QString& icon,
|
||||
bool readOnly)
|
||||
: LibraryBase(libraryName, dir, icon)
|
||||
, _readOnly(readOnly)
|
||||
{}
|
||||
|
||||
void MaterialLibrary::createPath(const QString& path)
|
||||
{
|
||||
Q_UNUSED(path)
|
||||
}
|
||||
|
||||
Material* MaterialLibrary::saveMaterial(Material& material, const QString& path, bool saveAsCopy)
|
||||
{
|
||||
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()) {
|
||||
if (!fileDir.mkpath(info.path())) {
|
||||
Base::Console().Error("Unable to create directory path '%s'\n",
|
||||
info.path().toStdString().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
if (file.open(QIODevice::WriteOnly | QIODevice::Text)) {
|
||||
QTextStream stream(&file);
|
||||
stream.setCodec("UTF-8");
|
||||
stream.setGenerateByteOrderMark(true);
|
||||
|
||||
// Write the contents
|
||||
material.setLibrary(*this);
|
||||
material.setDirectory(getRelativePath(path));
|
||||
material.save(stream, saveAsCopy);
|
||||
}
|
||||
|
||||
return addMaterial(material, path);
|
||||
}
|
||||
|
||||
Material* MaterialLibrary::addMaterial(const Material& material, const QString& path)
|
||||
{
|
||||
QString filePath = getRelativePath(path);
|
||||
Material* newMaterial = new Material(material);
|
||||
newMaterial->setLibrary(*this);
|
||||
newMaterial->setDirectory(filePath);
|
||||
|
||||
try {
|
||||
// If there's already a material at that path we'll replace it
|
||||
Material* old = _materialPathMap->at(filePath);
|
||||
delete old;
|
||||
}
|
||||
catch (const std::out_of_range&) {
|
||||
}
|
||||
|
||||
(*_materialPathMap)[filePath] = newMaterial;
|
||||
|
||||
return newMaterial;
|
||||
}
|
||||
|
||||
const Material& 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 {
|
||||
Material* material = _materialPathMap->at(filePath);
|
||||
return *material;
|
||||
}
|
||||
catch (std::out_of_range& e) {
|
||||
throw MaterialNotFound();
|
||||
}
|
||||
}
|
||||
|
||||
const QString MaterialLibrary::getUUIDFromPath(const QString& path) const
|
||||
{
|
||||
QString filePath = getRelativePath(path);
|
||||
try {
|
||||
Material* material = _materialPathMap->at(filePath);
|
||||
return material->getUUID();
|
||||
}
|
||||
catch (std::out_of_range& e) {
|
||||
throw MaterialNotFound();
|
||||
}
|
||||
}
|
||||
|
||||
TYPESYSTEM_SOURCE(Materials::MaterialExternalLibrary, MaterialLibrary::MaterialLibrary)
|
||||
|
||||
MaterialExternalLibrary::MaterialExternalLibrary()
|
||||
{}
|
||||
|
||||
MaterialExternalLibrary::MaterialExternalLibrary(const QString& libraryName,
|
||||
const QString& dir,
|
||||
const QString& icon,
|
||||
bool readOnly)
|
||||
: MaterialLibrary(libraryName, dir, icon, readOnly)
|
||||
{}
|
||||
|
||||
MaterialExternalLibrary::~MaterialExternalLibrary()
|
||||
{
|
||||
// delete directory;
|
||||
}
|
||||
96
src/Mod/Material/App/MaterialLibrary.h
Normal file
96
src/Mod/Material/App/MaterialLibrary.h
Normal file
@@ -0,0 +1,96 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
|
||||
* *
|
||||
* 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 *
|
||||
* <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef MATERIAL_MATERIALLIBRARY_H
|
||||
#define MATERIAL_MATERIALLIBRARY_H
|
||||
|
||||
#include <Mod/Material/MaterialGlobal.h>
|
||||
|
||||
#include <Base/BaseClass.h>
|
||||
#include <QDir>
|
||||
#include <QString>
|
||||
#include <QVariant>
|
||||
|
||||
#include "Model.h"
|
||||
#include "ModelLibrary.h"
|
||||
|
||||
namespace Materials
|
||||
{
|
||||
|
||||
class Material;
|
||||
|
||||
class MaterialsExport MaterialLibrary: public LibraryBase
|
||||
{
|
||||
TYPESYSTEM_HEADER();
|
||||
|
||||
public:
|
||||
MaterialLibrary();
|
||||
explicit MaterialLibrary(const QString& libraryName,
|
||||
const QString& dir,
|
||||
const QString& icon,
|
||||
bool readOnly = true);
|
||||
~MaterialLibrary() override = default;
|
||||
|
||||
bool operator==(const MaterialLibrary& library) const
|
||||
{
|
||||
return LibraryBase::operator==(library);
|
||||
}
|
||||
bool operator!=(const MaterialLibrary& library) const
|
||||
{
|
||||
return !operator==(library);
|
||||
}
|
||||
const Material& getMaterialByPath(const QString& path) const;
|
||||
|
||||
void createPath(const QString& path);
|
||||
Material* saveMaterial(Material& material, const QString& path, bool saveAsCopy);
|
||||
Material* addMaterial(const Material& material, const QString& path);
|
||||
|
||||
bool isReadOnly() const
|
||||
{
|
||||
return _readOnly;
|
||||
}
|
||||
|
||||
protected:
|
||||
const QString getUUIDFromPath(const QString& path) const;
|
||||
|
||||
bool _readOnly;
|
||||
static std::unique_ptr<std::map<QString, Material*>> _materialPathMap;
|
||||
};
|
||||
|
||||
class MaterialsExport MaterialExternalLibrary: public MaterialLibrary
|
||||
{
|
||||
TYPESYSTEM_HEADER();
|
||||
|
||||
public:
|
||||
MaterialExternalLibrary();
|
||||
explicit MaterialExternalLibrary(const QString& libraryName,
|
||||
const QString& dir,
|
||||
const QString& icon,
|
||||
bool readOnly = true);
|
||||
~MaterialExternalLibrary() override;
|
||||
};
|
||||
|
||||
} // namespace Materials
|
||||
|
||||
Q_DECLARE_METATYPE(Materials::MaterialLibrary)
|
||||
Q_DECLARE_METATYPE(Materials::MaterialExternalLibrary)
|
||||
|
||||
#endif // MATERIAL_MATERIALLIBRARY_H
|
||||
445
src/Mod/Material/App/MaterialLoader.cpp
Normal file
445
src/Mod/Material/App/MaterialLoader.cpp
Normal file
@@ -0,0 +1,445 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
|
||||
* *
|
||||
* 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 *
|
||||
* <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
**************************************************************************/
|
||||
|
||||
#include "PreCompiled.h"
|
||||
#ifndef _PreComp_
|
||||
#include <QString>
|
||||
#endif
|
||||
|
||||
#include <App/Application.h>
|
||||
#include <Base/Interpreter.h>
|
||||
|
||||
#include <QDirIterator>
|
||||
#include <QFileInfo>
|
||||
|
||||
#include "MaterialConfigLoader.h"
|
||||
#include "MaterialLoader.h"
|
||||
#include "Model.h"
|
||||
#include "ModelManager.h"
|
||||
|
||||
|
||||
using namespace Materials;
|
||||
|
||||
MaterialEntry::MaterialEntry()
|
||||
{}
|
||||
|
||||
MaterialEntry::MaterialEntry(const MaterialLibrary& library,
|
||||
const QString& modelName,
|
||||
const QString& dir,
|
||||
const QString& modelUuid)
|
||||
: _library(library)
|
||||
, _name(modelName)
|
||||
, _directory(dir)
|
||||
, _uuid(modelUuid)
|
||||
{}
|
||||
|
||||
MaterialYamlEntry::MaterialYamlEntry(const MaterialLibrary& library,
|
||||
const QString& modelName,
|
||||
const QString& dir,
|
||||
const QString& modelUuid,
|
||||
const YAML::Node& modelData)
|
||||
: MaterialEntry(library, modelName, dir, modelUuid)
|
||||
, _model(modelData)
|
||||
{}
|
||||
|
||||
// MaterialYamlEntry::~MaterialYamlEntry()
|
||||
// {}
|
||||
|
||||
QString MaterialYamlEntry::yamlValue(const YAML::Node& node,
|
||||
const std::string& key,
|
||||
const std::string& defaultValue)
|
||||
{
|
||||
if (node[key]) {
|
||||
return QString::fromStdString(node[key].as<std::string>());
|
||||
}
|
||||
return QString::fromStdString(defaultValue);
|
||||
}
|
||||
|
||||
void MaterialYamlEntry::addToTree(std::shared_ptr<std::map<QString, Material*>> materialMap)
|
||||
{
|
||||
std::set<QString> exclude;
|
||||
exclude.insert(QString::fromStdString("General"));
|
||||
exclude.insert(QString::fromStdString("Inherits"));
|
||||
|
||||
auto yamlModel = getModel();
|
||||
auto library = getLibrary();
|
||||
auto name = getName();
|
||||
auto directory = getDirectory();
|
||||
QString uuid = getUUID();
|
||||
|
||||
QString authorAndLicense = yamlValue(yamlModel["General"], "AuthorAndLicense", "");
|
||||
QString description = yamlValue(yamlModel["General"], "Description", "");
|
||||
|
||||
Material* finalModel = new Material(library, directory, uuid, name);
|
||||
finalModel->setAuthorAndLicense(authorAndLicense);
|
||||
finalModel->setDescription(description);
|
||||
|
||||
// Add inheritance list
|
||||
if (yamlModel["Inherits"]) {
|
||||
auto inherits = yamlModel["Inherits"];
|
||||
for (auto it = inherits.begin(); it != inherits.end(); it++) {
|
||||
std::string nodeName = it->second["UUID"].as<std::string>();
|
||||
|
||||
finalModel->setParentUUID(
|
||||
QString::fromStdString(nodeName)); // Should only be one. Need to check
|
||||
}
|
||||
}
|
||||
|
||||
// Add material models
|
||||
if (yamlModel["Models"]) {
|
||||
auto models = yamlModel["Models"];
|
||||
for (auto it = models.begin(); it != models.end(); it++) {
|
||||
std::string modelName = (it->first).as<std::string>();
|
||||
|
||||
// Add the model uuid
|
||||
auto modelNode = models[modelName];
|
||||
std::string modelUUID = modelNode["UUID"].as<std::string>();
|
||||
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<std::string>();
|
||||
std::string propertyValue = (itp->second).as<std::string>();
|
||||
|
||||
if (finalModel->hasPhysicalProperty(QString::fromStdString(propertyName))) {
|
||||
finalModel->setPhysicalValue(QString::fromStdString(propertyName),
|
||||
QString::fromStdString(propertyValue));
|
||||
}
|
||||
else if (propertyName != "UUID") {
|
||||
Base::Console().Log("\tProperty '%s' is not described by any model. Ignored\n",
|
||||
propertyName.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add appearance models
|
||||
if (yamlModel["AppearanceModels"]) {
|
||||
auto models = yamlModel["AppearanceModels"];
|
||||
for (auto it = models.begin(); it != models.end(); it++) {
|
||||
std::string modelName = (it->first).as<std::string>();
|
||||
|
||||
// Add the model uuid
|
||||
auto modelNode = models[modelName];
|
||||
std::string modelUUID = modelNode["UUID"].as<std::string>();
|
||||
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<std::string>();
|
||||
std::string propertyValue = (itp->second).as<std::string>();
|
||||
|
||||
if (finalModel->hasAppearanceProperty(QString::fromStdString(propertyName))) {
|
||||
finalModel->setAppearanceValue(QString::fromStdString(propertyName),
|
||||
QString::fromStdString(propertyValue));
|
||||
}
|
||||
else if (propertyName != "UUID") {
|
||||
Base::Console().Log("\tProperty '%s' is not described by any model. Ignored\n",
|
||||
propertyName.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QString path = QDir(directory).absolutePath();
|
||||
// Base::Console().Log("\tPath '%s'\n", path.toStdString().c_str());
|
||||
(*materialMap)[uuid] = library.addMaterial(*finalModel, path);
|
||||
}
|
||||
|
||||
std::unique_ptr<std::map<QString, MaterialEntry*>> MaterialLoader::_materialEntryMap = nullptr;
|
||||
|
||||
MaterialLoader::MaterialLoader(std::shared_ptr<std::map<QString, Material*>> materialMap,
|
||||
std::shared_ptr<std::list<MaterialLibrary*>> libraryList)
|
||||
: _materialMap(materialMap)
|
||||
, _libraryList(libraryList)
|
||||
{
|
||||
loadLibraries();
|
||||
}
|
||||
|
||||
/*
|
||||
* Destroys the object and frees any allocated resources
|
||||
*/
|
||||
MaterialLoader::~MaterialLoader()
|
||||
{}
|
||||
|
||||
void MaterialLoader::addLibrary(MaterialLibrary* model)
|
||||
{
|
||||
_libraryList->push_back(model);
|
||||
}
|
||||
|
||||
MaterialEntry* MaterialLoader::getMaterialFromPath(MaterialLibrary& library,
|
||||
const QString& path) const
|
||||
{
|
||||
MaterialEntry* model = nullptr;
|
||||
|
||||
// Used for debugging
|
||||
std::string uuid;
|
||||
std::string pathName = path.toStdString();
|
||||
|
||||
if (MaterialConfigLoader::isConfigStyle(path)) {
|
||||
Base::Console().Log("Old format .FCMat file: '%s'\n", pathName.c_str());
|
||||
Material* material = MaterialConfigLoader::getMaterialFromPath(library, path);
|
||||
if (material) {
|
||||
(*_materialMap)[material->getUUID()] = library.addMaterial(*material, path);
|
||||
}
|
||||
|
||||
// Return the nullptr as there are no intermediate steps to take, such
|
||||
// as checking inheritance
|
||||
return model;
|
||||
}
|
||||
|
||||
YAML::Node yamlroot;
|
||||
try {
|
||||
yamlroot = YAML::LoadFile(pathName);
|
||||
|
||||
const std::string uuid = yamlroot["General"]["UUID"].as<std::string>();
|
||||
// Always get the name from the filename
|
||||
// QString name = QString::fromStdString(yamlroot["General"]["Name"].as<std::string>());
|
||||
QFileInfo filepath(path);
|
||||
QString name =
|
||||
filepath.fileName().remove(QString::fromStdString(".FCMat"), Qt::CaseInsensitive);
|
||||
|
||||
model = new MaterialYamlEntry(library, name, path, QString::fromStdString(uuid), yamlroot);
|
||||
// showYaml(yamlroot);
|
||||
}
|
||||
catch (YAML::Exception const& e) {
|
||||
Base::Console().Error("YAML parsing error: '%s'\n", pathName.c_str());
|
||||
Base::Console().Error("\t'%s'\n", e.what());
|
||||
showYaml(yamlroot);
|
||||
}
|
||||
|
||||
|
||||
return model;
|
||||
}
|
||||
|
||||
void MaterialLoader::showYaml(const YAML::Node& yaml)
|
||||
{
|
||||
std::stringstream out;
|
||||
|
||||
out << yaml;
|
||||
std::string logData = out.str();
|
||||
Base::Console().Log("%s\n", logData.c_str());
|
||||
}
|
||||
|
||||
|
||||
void MaterialLoader::dereference(Material* 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) {
|
||||
Material* parent;
|
||||
try {
|
||||
parent = (*_materialMap)[parentUUID];
|
||||
}
|
||||
catch (std::out_of_range& e) {
|
||||
Base::Console().Log(
|
||||
"Unable to apply inheritance for material '%s', parent '%s' not found.\n",
|
||||
material->getName().toStdString().c_str(),
|
||||
parentUUID.toStdString().c_str());
|
||||
}
|
||||
|
||||
// Ensure the parent has been dereferenced
|
||||
dereference(parent);
|
||||
|
||||
// Add physical models
|
||||
auto modelVector = parent->getPhysicalModels();
|
||||
for (auto model = modelVector->begin(); model != modelVector->end(); model++) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
// Add values
|
||||
auto properties = parent->getPhysicalProperties();
|
||||
for (auto itp = properties.begin(); itp != properties.end(); itp++) {
|
||||
auto name = itp->first;
|
||||
auto property = static_cast<const MaterialProperty>(itp->second);
|
||||
|
||||
if (material->getPhysicalProperty(name).isNull()) {
|
||||
material->getPhysicalProperty(name).setValue(property.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
properties = parent->getAppearanceProperties();
|
||||
for (auto itp = properties.begin(); itp != properties.end(); itp++) {
|
||||
auto name = itp->first;
|
||||
auto property = static_cast<const MaterialProperty>(itp->second);
|
||||
|
||||
if (material->getAppearanceProperty(name).isNull()) {
|
||||
material->getAppearanceProperty(name).setValue(property.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
material->markDereferenced();
|
||||
}
|
||||
|
||||
void MaterialLoader::loadLibrary(MaterialLibrary& library)
|
||||
{
|
||||
if (_materialEntryMap == nullptr) {
|
||||
_materialEntryMap = std::make_unique<std::map<QString, MaterialEntry*>>();
|
||||
}
|
||||
|
||||
QDirIterator it(library.getDirectory(), QDirIterator::Subdirectories);
|
||||
while (it.hasNext()) {
|
||||
auto pathname = it.next();
|
||||
QFileInfo file(pathname);
|
||||
if (file.isFile()) {
|
||||
if (file.suffix().toStdString() == "FCMat") {
|
||||
QString libraryName = file.baseName();
|
||||
|
||||
auto model = getMaterialFromPath(library, file.canonicalFilePath());
|
||||
if (model) {
|
||||
(*_materialEntryMap)[model->getUUID()] = model;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (auto it = _materialEntryMap->begin(); it != _materialEntryMap->end(); it++) {
|
||||
it->second->addToTree(_materialMap);
|
||||
}
|
||||
}
|
||||
|
||||
void MaterialLoader::loadLibraries()
|
||||
{
|
||||
auto _libraryList = getMaterialLibraries();
|
||||
if (_libraryList) {
|
||||
for (auto it = _libraryList->begin(); it != _libraryList->end(); it++) {
|
||||
loadLibrary(**it);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto it = _materialMap->begin(); it != _materialMap->end(); it++) {
|
||||
dereference(it->second);
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<std::list<MaterialLibrary*>> MaterialLoader::getMaterialLibraries()
|
||||
{
|
||||
auto param = App::GetApplication().GetParameterGroupByPath(
|
||||
"User parameter:BaseApp/Preferences/Mod/Material/Resources");
|
||||
bool useBuiltInMaterials = param->GetBool("UseBuiltInMaterials", true);
|
||||
bool useMatFromModules = param->GetBool("UseMaterialsFromWorkbenches", true);
|
||||
bool useMatFromConfigDir = param->GetBool("UseMaterialsFromConfigDir", true);
|
||||
bool useMatFromCustomDir = param->GetBool("UseMaterialsFromCustomDir", true);
|
||||
|
||||
if (useBuiltInMaterials) {
|
||||
QString resourceDir = QString::fromStdString(App::Application::getResourceDir()
|
||||
+ "/Mod/Material/Resources/Materials");
|
||||
auto libData = new MaterialLibrary(QString::fromStdString("System"),
|
||||
resourceDir,
|
||||
QString::fromStdString(":/icons/freecad.svg"),
|
||||
true);
|
||||
_libraryList->push_back(libData);
|
||||
}
|
||||
|
||||
if (useMatFromModules) {
|
||||
auto moduleParam = App::GetApplication().GetParameterGroupByPath(
|
||||
"User parameter:BaseApp/Preferences/Mod/Material/Resources/Modules");
|
||||
for (auto& group : moduleParam->GetGroups()) {
|
||||
// auto module = moduleParam->GetGroup(group->GetGroupName());
|
||||
auto moduleName = QString::fromStdString(group->GetGroupName());
|
||||
auto materialDir = QString::fromStdString(group->GetASCII("ModuleDir", ""));
|
||||
auto materialIcon = QString::fromStdString(group->GetASCII("ModuleIcon", ""));
|
||||
auto materialReadOnly = group->GetBool("ModuleReadOnly", true);
|
||||
|
||||
if (materialDir.length() > 0) {
|
||||
QDir dir(materialDir);
|
||||
if (dir.exists()) {
|
||||
auto libData = new MaterialLibrary(moduleName,
|
||||
materialDir,
|
||||
materialIcon,
|
||||
materialReadOnly);
|
||||
_libraryList->push_back(libData);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (useMatFromConfigDir) {
|
||||
QString resourceDir =
|
||||
QString::fromStdString(App::Application::getUserAppDataDir() + "/Material");
|
||||
if (!resourceDir.isEmpty()) {
|
||||
QDir materialDir(resourceDir);
|
||||
if (materialDir.exists()) {
|
||||
auto libData =
|
||||
new MaterialLibrary(QString::fromStdString("User"),
|
||||
resourceDir,
|
||||
QString::fromStdString(":/icons/preferences-general.svg"),
|
||||
false);
|
||||
_libraryList->push_back(libData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (useMatFromCustomDir) {
|
||||
QString resourceDir = QString::fromStdString(param->GetASCII("CustomMaterialsDir", ""));
|
||||
if (!resourceDir.isEmpty()) {
|
||||
QDir materialDir(resourceDir);
|
||||
if (materialDir.exists()) {
|
||||
auto libData = new MaterialLibrary(QString::fromStdString("Custom"),
|
||||
resourceDir,
|
||||
QString::fromStdString(":/icons/user.svg"),
|
||||
false);
|
||||
_libraryList->push_back(libData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return _libraryList;
|
||||
}
|
||||
|
||||
std::shared_ptr<std::list<QString>>
|
||||
MaterialLoader::getMaterialFolders(const MaterialLibrary& library)
|
||||
{
|
||||
std::shared_ptr<std::list<QString>> pathList = std::make_shared<std::list<QString>>();
|
||||
QDirIterator it(library.getDirectory(), QDirIterator::Subdirectories);
|
||||
while (it.hasNext()) {
|
||||
auto pathname = it.next();
|
||||
QFileInfo file(pathname);
|
||||
if (file.isDir()) {
|
||||
QString path = QDir(library.getDirectory()).relativeFilePath(file.absoluteFilePath());
|
||||
if (!path.startsWith(QString::fromStdString("."))) {
|
||||
pathList->push_back(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return pathList;
|
||||
}
|
||||
128
src/Mod/Material/App/MaterialLoader.h
Normal file
128
src/Mod/Material/App/MaterialLoader.h
Normal file
@@ -0,0 +1,128 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
|
||||
* *
|
||||
* 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 *
|
||||
* <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef MATERIAL_MATERIALLOADER_H
|
||||
#define MATERIAL_MATERIALLOADER_H
|
||||
|
||||
#include <QDir>
|
||||
#include <QString>
|
||||
#include <yaml-cpp/yaml.h>
|
||||
|
||||
#include "Materials.h"
|
||||
#include "trim.h"
|
||||
|
||||
namespace Materials
|
||||
{
|
||||
|
||||
class MaterialEntry
|
||||
{
|
||||
public:
|
||||
MaterialEntry();
|
||||
explicit MaterialEntry(const MaterialLibrary& library,
|
||||
const QString& modelName,
|
||||
const QString& dir,
|
||||
const QString& modelUuid);
|
||||
virtual ~MaterialEntry() = default;
|
||||
|
||||
virtual void addToTree(std::shared_ptr<std::map<QString, Material*>> materialMap) = 0;
|
||||
|
||||
const MaterialLibrary& getLibrary() const
|
||||
{
|
||||
return _library;
|
||||
}
|
||||
const QString getName() const
|
||||
{
|
||||
return _name;
|
||||
}
|
||||
const QString getDirectory() const
|
||||
{
|
||||
return _directory;
|
||||
}
|
||||
const QString getUUID() const
|
||||
{
|
||||
return _uuid;
|
||||
}
|
||||
|
||||
protected:
|
||||
MaterialLibrary _library;
|
||||
QString _name;
|
||||
QString _directory;
|
||||
QString _uuid;
|
||||
};
|
||||
|
||||
class MaterialYamlEntry: public MaterialEntry
|
||||
{
|
||||
public:
|
||||
explicit MaterialYamlEntry(const MaterialLibrary& library,
|
||||
const QString& modelName,
|
||||
const QString& dir,
|
||||
const QString& modelUuid,
|
||||
const YAML::Node& modelData);
|
||||
~MaterialYamlEntry() override = default;
|
||||
|
||||
void addToTree(std::shared_ptr<std::map<QString, Material*>> materialMap) override;
|
||||
|
||||
const YAML::Node& getModel() const
|
||||
{
|
||||
return _model;
|
||||
}
|
||||
YAML::Node* getModelPtr()
|
||||
{
|
||||
return &_model;
|
||||
}
|
||||
|
||||
private:
|
||||
MaterialYamlEntry();
|
||||
|
||||
QString
|
||||
yamlValue(const YAML::Node& node, const std::string& key, const std::string& defaultValue);
|
||||
|
||||
YAML::Node _model;
|
||||
};
|
||||
|
||||
class MaterialLoader
|
||||
{
|
||||
public:
|
||||
explicit MaterialLoader(std::shared_ptr<std::map<QString, Material*>> materialMap,
|
||||
std::shared_ptr<std::list<MaterialLibrary*>> libraryList);
|
||||
virtual ~MaterialLoader();
|
||||
|
||||
std::shared_ptr<std::list<MaterialLibrary*>> getMaterialLibraries();
|
||||
static std::shared_ptr<std::list<QString>> getMaterialFolders(const MaterialLibrary& library);
|
||||
static void showYaml(const YAML::Node& yaml);
|
||||
|
||||
private:
|
||||
MaterialLoader();
|
||||
|
||||
void addToTree(MaterialEntry* model);
|
||||
void dereference(Material* material);
|
||||
MaterialEntry* getMaterialFromPath(MaterialLibrary& library, const QString& path) const;
|
||||
void addLibrary(MaterialLibrary* model);
|
||||
void loadLibrary(MaterialLibrary& library);
|
||||
void loadLibraries();
|
||||
static std::unique_ptr<std::map<QString, MaterialEntry*>> _materialEntryMap;
|
||||
std::shared_ptr<std::map<QString, Material*>> _materialMap;
|
||||
std::shared_ptr<std::list<MaterialLibrary*>> _libraryList;
|
||||
};
|
||||
|
||||
} // namespace Materials
|
||||
|
||||
#endif // MATERIAL_MATERIALLOADER_H
|
||||
276
src/Mod/Material/App/MaterialManager.cpp
Normal file
276
src/Mod/Material/App/MaterialManager.cpp
Normal file
@@ -0,0 +1,276 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
|
||||
* *
|
||||
* 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 *
|
||||
* <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
**************************************************************************/
|
||||
|
||||
#include "PreCompiled.h"
|
||||
#ifndef _PreComp_
|
||||
#endif
|
||||
|
||||
#include <QMutexLocker>
|
||||
|
||||
#include <App/Application.h>
|
||||
|
||||
#include "Exceptions.h"
|
||||
#include "MaterialLoader.h"
|
||||
#include "MaterialManager.h"
|
||||
#include "ModelManager.h"
|
||||
|
||||
|
||||
using namespace Materials;
|
||||
|
||||
/* TRANSLATOR Material::Materials */
|
||||
|
||||
std::shared_ptr<std::list<MaterialLibrary*>> MaterialManager::_libraryList = nullptr;
|
||||
std::shared_ptr<std::map<QString, Material*>> MaterialManager::_materialMap = nullptr;
|
||||
QMutex MaterialManager::_mutex;
|
||||
|
||||
TYPESYSTEM_SOURCE(Materials::MaterialManager, Base::BaseClass)
|
||||
|
||||
MaterialManager::MaterialManager()
|
||||
{
|
||||
// TODO: Add a mutex or similar
|
||||
initLibraries();
|
||||
}
|
||||
|
||||
void MaterialManager::initLibraries()
|
||||
{
|
||||
QMutexLocker locker(&_mutex);
|
||||
|
||||
if (_materialMap == nullptr) {
|
||||
// Load the models first
|
||||
ModelManager* manager = new ModelManager();
|
||||
Q_UNUSED(manager)
|
||||
|
||||
delete manager;
|
||||
|
||||
_materialMap = std::make_shared<std::map<QString, Material*>>();
|
||||
|
||||
if (_libraryList == nullptr) {
|
||||
_libraryList = std::make_shared<std::list<MaterialLibrary*>>();
|
||||
}
|
||||
|
||||
// Load the libraries
|
||||
MaterialLoader loader(_materialMap, _libraryList);
|
||||
}
|
||||
}
|
||||
|
||||
void MaterialManager::saveMaterial(MaterialLibrary* library,
|
||||
Material& material,
|
||||
const QString& path,
|
||||
bool saveAsCopy)
|
||||
{
|
||||
Material* newMaterial = library->saveMaterial(material, path, saveAsCopy);
|
||||
|
||||
try {
|
||||
Material* old = _materialMap->at(newMaterial->getUUID());
|
||||
if (old) {
|
||||
delete old;
|
||||
}
|
||||
}
|
||||
catch (const std::out_of_range&) {
|
||||
}
|
||||
|
||||
(*_materialMap)[material.getUUID()] = newMaterial;
|
||||
}
|
||||
|
||||
bool MaterialManager::isMaterial(const fs::path& p)
|
||||
{
|
||||
if (!fs::is_regular_file(p)) {
|
||||
return false;
|
||||
}
|
||||
// check file extension
|
||||
if (p.extension() == ".FCMat") {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const Material& MaterialManager::getMaterial(const QString& uuid) const
|
||||
{
|
||||
try {
|
||||
return *(_materialMap->at(uuid));
|
||||
}
|
||||
catch (std::out_of_range& e) {
|
||||
throw MaterialNotFound();
|
||||
}
|
||||
}
|
||||
|
||||
const Material& MaterialManager::getMaterialByPath(const QString& path) const
|
||||
{
|
||||
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();
|
||||
}
|
||||
|
||||
const Material& MaterialManager::getMaterialByPath(const QString& path, const QString& lib) const
|
||||
{
|
||||
auto library = getLibrary(lib); // May throw LibraryNotFound
|
||||
return library->getMaterialByPath(path); // May throw MaterialNotFound
|
||||
}
|
||||
|
||||
MaterialLibrary* MaterialManager::getLibrary(const QString& name) const
|
||||
{
|
||||
for (auto library : *_libraryList) {
|
||||
if (library->getName() == name) {
|
||||
return library;
|
||||
}
|
||||
}
|
||||
|
||||
throw LibraryNotFound();
|
||||
}
|
||||
|
||||
std::shared_ptr<std::list<MaterialLibrary*>> MaterialManager::getMaterialLibraries()
|
||||
{
|
||||
if (_libraryList == nullptr) {
|
||||
if (_materialMap == nullptr) {
|
||||
_materialMap = std::make_shared<std::map<QString, Material*>>();
|
||||
}
|
||||
_libraryList = std::make_shared<std::list<MaterialLibrary*>>();
|
||||
|
||||
// Load the libraries
|
||||
MaterialLoader loader(_materialMap, _libraryList);
|
||||
}
|
||||
return _libraryList;
|
||||
}
|
||||
|
||||
std::shared_ptr<std::map<QString, MaterialTreeNode*>>
|
||||
MaterialManager::getMaterialTree(const MaterialLibrary& library) const
|
||||
{
|
||||
std::shared_ptr<std::map<QString, MaterialTreeNode*>> materialTree =
|
||||
std::make_shared<std::map<QString, MaterialTreeNode*>>();
|
||||
|
||||
for (auto it = _materialMap->begin(); it != _materialMap->end(); it++) {
|
||||
auto filename = it->first;
|
||||
auto material = it->second;
|
||||
|
||||
if (material->getLibrary() == library) {
|
||||
fs::path path = material->getDirectory().toStdString();
|
||||
|
||||
// Start at the root
|
||||
auto node = materialTree;
|
||||
for (auto itp = path.begin(); itp != path.end(); itp++) {
|
||||
if (QString::fromStdString(itp->string())
|
||||
.endsWith(QString::fromStdString(".FCMat"))) {
|
||||
MaterialTreeNode* child = new MaterialTreeNode();
|
||||
child->setData(material);
|
||||
(*node)[QString::fromStdString(itp->string())] = child;
|
||||
}
|
||||
else {
|
||||
// Add the folder only if it's not already there
|
||||
QString folderName = QString::fromStdString(itp->string());
|
||||
std::shared_ptr<std::map<QString, MaterialTreeNode*>> mapPtr;
|
||||
if (node->count(folderName) == 0) {
|
||||
mapPtr = std::make_shared<std::map<QString, MaterialTreeNode*>>();
|
||||
MaterialTreeNode* child = new MaterialTreeNode();
|
||||
child->setFolder(mapPtr);
|
||||
(*node)[folderName] = child;
|
||||
node = mapPtr;
|
||||
}
|
||||
else {
|
||||
node = (*node)[folderName]->getFolder();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto folderList = getMaterialFolders(library);
|
||||
for (auto folder : *folderList) {
|
||||
fs::path path = folder.toStdString();
|
||||
|
||||
// Start at the root
|
||||
auto node = materialTree;
|
||||
for (auto itp = path.begin(); itp != path.end(); itp++) {
|
||||
// Add the folder only if it's not already there
|
||||
QString folderName = QString::fromStdString(itp->string());
|
||||
if (node->count(folderName) == 0) {
|
||||
std::shared_ptr<std::map<QString, MaterialTreeNode*>> mapPtr =
|
||||
std::make_shared<std::map<QString, MaterialTreeNode*>>();
|
||||
MaterialTreeNode* child = new MaterialTreeNode();
|
||||
child->setFolder(mapPtr);
|
||||
(*node)[folderName] = child;
|
||||
node = mapPtr;
|
||||
}
|
||||
else {
|
||||
node = (*node)[folderName]->getFolder();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return materialTree;
|
||||
}
|
||||
|
||||
std::shared_ptr<std::list<QString>>
|
||||
MaterialManager::getMaterialFolders(const MaterialLibrary& library) const
|
||||
{
|
||||
return MaterialLoader::getMaterialFolders(library);
|
||||
}
|
||||
|
||||
std::shared_ptr<std::map<QString, Material*>> MaterialManager::materialsWithModel(QString uuid)
|
||||
{
|
||||
std::shared_ptr<std::map<QString, Material*>> dict =
|
||||
std::make_shared<std::map<QString, Material*>>();
|
||||
|
||||
for (auto it = _materialMap->begin(); it != _materialMap->end(); it++) {
|
||||
QString key = it->first;
|
||||
Material* material = it->second;
|
||||
|
||||
if (material->hasModel(uuid)) {
|
||||
(*dict)[key] = material;
|
||||
}
|
||||
}
|
||||
|
||||
return dict;
|
||||
}
|
||||
|
||||
std::shared_ptr<std::map<QString, Material*>>
|
||||
MaterialManager::materialsWithModelComplete(QString uuid)
|
||||
{
|
||||
std::shared_ptr<std::map<QString, Material*>> dict =
|
||||
std::make_shared<std::map<QString, Material*>>();
|
||||
|
||||
for (auto it = _materialMap->begin(); it != _materialMap->end(); it++) {
|
||||
QString key = it->first;
|
||||
Material* material = it->second;
|
||||
|
||||
if (material->isModelComplete(uuid)) {
|
||||
(*dict)[key] = material;
|
||||
}
|
||||
}
|
||||
|
||||
return dict;
|
||||
}
|
||||
87
src/Mod/Material/App/MaterialManager.h
Normal file
87
src/Mod/Material/App/MaterialManager.h
Normal file
@@ -0,0 +1,87 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
|
||||
* *
|
||||
* 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 *
|
||||
* <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef MATERIAL_MATERIALMANAGER_H
|
||||
#define MATERIAL_MATERIALMANAGER_H
|
||||
|
||||
#include <Mod/Material/MaterialGlobal.h>
|
||||
|
||||
#include <QMutex>
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
#include "FolderTree.h"
|
||||
#include "Materials.h"
|
||||
|
||||
namespace fs = boost::filesystem;
|
||||
|
||||
namespace Materials
|
||||
{
|
||||
|
||||
typedef FolderTreeNode<Material> MaterialTreeNode;
|
||||
|
||||
class MaterialsExport MaterialManager: public Base::BaseClass
|
||||
{
|
||||
TYPESYSTEM_HEADER();
|
||||
|
||||
public:
|
||||
MaterialManager();
|
||||
~MaterialManager() override = default;
|
||||
|
||||
std::shared_ptr<std::map<QString, Material*>> getMaterials()
|
||||
{
|
||||
return _materialMap;
|
||||
}
|
||||
const Material& getMaterial(const QString& uuid) const;
|
||||
const Material& getMaterialByPath(const QString& path) const;
|
||||
const Material& getMaterialByPath(const QString& path, const QString& library) const;
|
||||
MaterialLibrary* getLibrary(const QString& name) const;
|
||||
|
||||
// Library management
|
||||
static std::shared_ptr<std::list<MaterialLibrary*>> getMaterialLibraries();
|
||||
std::shared_ptr<std::map<QString, MaterialTreeNode*>>
|
||||
getMaterialTree(const MaterialLibrary& library) const;
|
||||
std::shared_ptr<std::list<QString>> getMaterialFolders(const MaterialLibrary& library) const;
|
||||
void createPath(MaterialLibrary* library, const QString& path)
|
||||
{
|
||||
library->createPath(path);
|
||||
}
|
||||
void saveMaterial(MaterialLibrary* library,
|
||||
Material& material,
|
||||
const QString& path,
|
||||
bool saveAsCopy = true);
|
||||
|
||||
static bool isMaterial(const fs::path& p);
|
||||
|
||||
std::shared_ptr<std::map<QString, Material*>> materialsWithModel(QString uuid);
|
||||
std::shared_ptr<std::map<QString, Material*>> materialsWithModelComplete(QString uuid);
|
||||
|
||||
private:
|
||||
static std::shared_ptr<std::list<MaterialLibrary*>> _libraryList;
|
||||
static std::shared_ptr<std::map<QString, Material*>> _materialMap;
|
||||
static QMutex _mutex;
|
||||
|
||||
static void initLibraries();
|
||||
};
|
||||
|
||||
} // namespace Materials
|
||||
|
||||
#endif // MATERIAL_MATERIALMANAGER_H
|
||||
51
src/Mod/Material/App/MaterialManagerPy.xml
Normal file
51
src/Mod/Material/App/MaterialManagerPy.xml
Normal file
@@ -0,0 +1,51 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<GenerateMaterial xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="generateMetaMaterial_Module.xsd">
|
||||
<PythonExport
|
||||
Father="BaseClassPy"
|
||||
Name="MaterialManagerPy"
|
||||
Twin="MaterialManager"
|
||||
TwinPointer="MaterialManager"
|
||||
Include="Mod/Material/App/MaterialManager.h"
|
||||
Namespace="Materials"
|
||||
FatherInclude="Base/BaseClassPy.h"
|
||||
FatherNamespace="Base"
|
||||
Constructor="true"
|
||||
Delete="true">
|
||||
<Documentation>
|
||||
<Author Licence="LGPL" Name="DavidCarter" EMail="dcarter@davidcarter.ca" />
|
||||
<UserDocu>Material descriptions.</UserDocu>
|
||||
</Documentation>
|
||||
<Methode Name="getMaterial">
|
||||
<Documentation>
|
||||
<UserDocu>Get a material object by specifying its UUID</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="getMaterialByPath">
|
||||
<Documentation>
|
||||
<UserDocu>Get a material object by specifying its path and library name</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Attribute Name="MaterialLibraries" ReadOnly="true">
|
||||
<Documentation>
|
||||
<UserDocu>List of Material libraries.</UserDocu>
|
||||
</Documentation>
|
||||
<Parameter Name="MaterialLibraries" Type="List"/>
|
||||
</Attribute>
|
||||
<Attribute Name="Materials" ReadOnly="true">
|
||||
<Documentation>
|
||||
<UserDocu>List of Materials.</UserDocu>
|
||||
</Documentation>
|
||||
<Parameter Name="Materials" Type="Dict"/>
|
||||
</Attribute>
|
||||
<Methode Name="materialsWithModel">
|
||||
<Documentation>
|
||||
<UserDocu>Get a list of materials implementing the specified model</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="materialsWithModelComplete">
|
||||
<Documentation>
|
||||
<UserDocu>Get a list of materials implementing the specified model, with values for all properties</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
</PythonExport>
|
||||
</GenerateMaterial>
|
||||
200
src/Mod/Material/App/MaterialManagerPyImpl.cpp
Normal file
200
src/Mod/Material/App/MaterialManagerPyImpl.cpp
Normal file
@@ -0,0 +1,200 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
|
||||
* *
|
||||
* 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 *
|
||||
* <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
**************************************************************************/
|
||||
|
||||
#include "PreCompiled.h"
|
||||
|
||||
#ifndef _PreComp_
|
||||
#include <boost/uuid/uuid_io.hpp>
|
||||
#endif
|
||||
|
||||
#include "Exceptions.h"
|
||||
#include "MaterialManager.h"
|
||||
#include "MaterialManagerPy.h"
|
||||
#include "MaterialPy.h"
|
||||
#include "Materials.h"
|
||||
|
||||
#include "MaterialManagerPy.cpp"
|
||||
|
||||
using namespace Materials;
|
||||
|
||||
// returns a string which represents the object e.g. when printed in python
|
||||
std::string MaterialManagerPy::representation() const
|
||||
{
|
||||
std::stringstream str;
|
||||
str << "<MaterialManager object at " << getMaterialManagerPtr() << ">";
|
||||
|
||||
return str.str();
|
||||
}
|
||||
|
||||
PyObject* MaterialManagerPy::PyMake(struct _typeobject*, PyObject*, PyObject*) // Python wrapper
|
||||
{
|
||||
// never create such objects with the constructor
|
||||
return new MaterialManagerPy(new MaterialManager());
|
||||
}
|
||||
|
||||
// constructor method
|
||||
int MaterialManagerPy::PyInit(PyObject* /*args*/, PyObject* /*kwd*/)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
PyObject* MaterialManagerPy::getMaterial(PyObject* args)
|
||||
{
|
||||
char* uuid;
|
||||
if (!PyArg_ParseTuple(args, "s", &uuid)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
try {
|
||||
const Material& material =
|
||||
getMaterialManagerPtr()->getMaterial(QString::fromStdString(uuid));
|
||||
return new MaterialPy(new Material(material));
|
||||
}
|
||||
catch (const MaterialNotFound&) {
|
||||
PyErr_SetString(PyExc_LookupError, "Material not found");
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
PyObject* MaterialManagerPy::getMaterialByPath(PyObject* args)
|
||||
{
|
||||
char* path;
|
||||
char* lib = "";
|
||||
if (!PyArg_ParseTuple(args, "s|s", &path, &lib)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
QString libPath(QString::fromStdString(lib));
|
||||
if (!libPath.isEmpty()) {
|
||||
try {
|
||||
const Material& material =
|
||||
getMaterialManagerPtr()->getMaterialByPath(QString::fromStdString(path), libPath);
|
||||
return new MaterialPy(new Material(material));
|
||||
}
|
||||
catch (const MaterialNotFound&) {
|
||||
PyErr_SetString(PyExc_LookupError, "Material not found");
|
||||
return nullptr;
|
||||
}
|
||||
catch (const LibraryNotFound&) {
|
||||
PyErr_SetString(PyExc_LookupError, "Library not found");
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
const Material& material =
|
||||
getMaterialManagerPtr()->getMaterialByPath(QString::fromStdString(path));
|
||||
return new MaterialPy(new Material(material));
|
||||
}
|
||||
catch (const MaterialNotFound&) {
|
||||
PyErr_SetString(PyExc_LookupError, "Material not found");
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
Py::List MaterialManagerPy::getMaterialLibraries() const
|
||||
{
|
||||
auto libraries = getMaterialManagerPtr()->getMaterialLibraries();
|
||||
Py::List list;
|
||||
|
||||
for (auto it = libraries->begin(); it != libraries->end(); it++) {
|
||||
MaterialLibrary* lib = *it;
|
||||
Py::Tuple libTuple(3);
|
||||
libTuple.setItem(0, Py::String(lib->getName().toStdString()));
|
||||
libTuple.setItem(1, Py::String(lib->getDirectoryPath().toStdString()));
|
||||
libTuple.setItem(2, Py::String(lib->getIconPath().toStdString()));
|
||||
|
||||
list.append(libTuple);
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
Py::Dict MaterialManagerPy::getMaterials() const
|
||||
{
|
||||
Py::Dict dict;
|
||||
|
||||
auto materials = getMaterialManagerPtr()->getMaterials();
|
||||
|
||||
for (auto it = materials->begin(); it != materials->end(); it++) {
|
||||
QString key = it->first;
|
||||
Material* material = it->second;
|
||||
|
||||
PyObject* materialPy = new MaterialPy(new Material(*material));
|
||||
dict.setItem(Py::String(key.toStdString()), Py::Object(materialPy, true));
|
||||
}
|
||||
|
||||
// return Py::new_reference_to(dict);
|
||||
return dict;
|
||||
}
|
||||
|
||||
PyObject* MaterialManagerPy::getCustomAttributes(const char* /*attr*/) const
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int MaterialManagerPy::setCustomAttributes(const char* /*attr*/, PyObject* /*obj*/)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
PyObject* MaterialManagerPy::materialsWithModel(PyObject* args)
|
||||
{
|
||||
char* uuid;
|
||||
if (!PyArg_ParseTuple(args, "s", &uuid)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto materials = getMaterialManagerPtr()->materialsWithModel(QString::fromStdString(uuid));
|
||||
PyObject* dict = PyDict_New();
|
||||
|
||||
for (auto it = materials->begin(); it != materials->end(); it++) {
|
||||
QString key = it->first;
|
||||
Material* material = it->second;
|
||||
|
||||
PyObject* materialPy = new MaterialPy(new Material(*material));
|
||||
PyDict_SetItem(dict, PyUnicode_FromString(key.toStdString().c_str()), materialPy);
|
||||
}
|
||||
|
||||
return dict;
|
||||
}
|
||||
|
||||
PyObject* MaterialManagerPy::materialsWithModelComplete(PyObject* args)
|
||||
{
|
||||
char* uuid;
|
||||
if (!PyArg_ParseTuple(args, "s", &uuid)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto materials =
|
||||
getMaterialManagerPtr()->materialsWithModelComplete(QString::fromStdString(uuid));
|
||||
PyObject* dict = PyDict_New();
|
||||
|
||||
for (auto it = materials->begin(); it != materials->end(); it++) {
|
||||
QString key = it->first;
|
||||
Material* material = it->second;
|
||||
|
||||
PyObject* materialPy = new MaterialPy(new Material(*material));
|
||||
PyDict_SetItem(dict, PyUnicode_FromString(key.toStdString().c_str()), materialPy);
|
||||
}
|
||||
|
||||
return dict;
|
||||
}
|
||||
161
src/Mod/Material/App/MaterialPy.xml
Normal file
161
src/Mod/Material/App/MaterialPy.xml
Normal file
@@ -0,0 +1,161 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<GenerateModel xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="generateMetaModel_Module.xsd">
|
||||
<PythonExport
|
||||
Father="BaseClassPy"
|
||||
Name="MaterialPy"
|
||||
Twin="Material"
|
||||
TwinPointer="Material"
|
||||
Include="Mod/Material/App/Materials.h"
|
||||
Namespace="Materials"
|
||||
FatherInclude="Base/BaseClassPy.h"
|
||||
FatherNamespace="Base"
|
||||
Constructor="true"
|
||||
Delete="true">
|
||||
<Documentation>
|
||||
<Author Licence="LGPL" Name="DavidCarter" EMail="dcarter@davidcarter.ca" />
|
||||
<UserDocu>Material descriptions.</UserDocu>
|
||||
</Documentation>
|
||||
<Attribute Name="LibraryName" ReadOnly="true">
|
||||
<Documentation>
|
||||
<UserDocu>Model library name.</UserDocu>
|
||||
</Documentation>
|
||||
<Parameter Name="LibraryName" Type="String"/>
|
||||
</Attribute>
|
||||
<Attribute Name="LibraryRoot" ReadOnly="true">
|
||||
<Documentation>
|
||||
<UserDocu>Model library path.</UserDocu>
|
||||
</Documentation>
|
||||
<Parameter Name="LibraryRoot" Type="String"/>
|
||||
</Attribute>
|
||||
<Attribute Name="LibraryIcon" ReadOnly="true">
|
||||
<Documentation>
|
||||
<UserDocu>Model icon path.</UserDocu>
|
||||
</Documentation>
|
||||
<Parameter Name="LibraryIcon" Type="String"/>
|
||||
</Attribute>
|
||||
<Attribute Name="Name" ReadOnly="true">
|
||||
<Documentation>
|
||||
<UserDocu>Model name.</UserDocu>
|
||||
</Documentation>
|
||||
<Parameter Name="Name" Type="String"/>
|
||||
</Attribute>
|
||||
<Attribute Name="Directory" ReadOnly="true">
|
||||
<Documentation>
|
||||
<UserDocu>Model directory relative to the library root.</UserDocu>
|
||||
</Documentation>
|
||||
<Parameter Name="Directory" Type="String"/>
|
||||
</Attribute>
|
||||
<Attribute Name="UUID" ReadOnly="true">
|
||||
<Documentation>
|
||||
<UserDocu>Unique model identifier.</UserDocu>
|
||||
</Documentation>
|
||||
<Parameter Name="UUID" Type="String"/>
|
||||
</Attribute>
|
||||
<Attribute Name="Description" ReadOnly="true">
|
||||
<Documentation>
|
||||
<UserDocu>Description of the material.</UserDocu>
|
||||
</Documentation>
|
||||
<Parameter Name="Description" Type="String"/>
|
||||
</Attribute>
|
||||
<Attribute Name="URL" ReadOnly="true">
|
||||
<Documentation>
|
||||
<UserDocu>URL to a material reference.</UserDocu>
|
||||
</Documentation>
|
||||
<Parameter Name="URL" Type="String"/>
|
||||
</Attribute>
|
||||
<Attribute Name="Reference" ReadOnly="true">
|
||||
<Documentation>
|
||||
<UserDocu>Reference for material data.</UserDocu>
|
||||
</Documentation>
|
||||
<Parameter Name="Reference" Type="String"/>
|
||||
</Attribute>
|
||||
<Attribute Name="Parent" ReadOnly="true">
|
||||
<Documentation>
|
||||
<UserDocu>Parent material UUID.</UserDocu>
|
||||
</Documentation>
|
||||
<Parameter Name="Parent" Type="String"/>
|
||||
</Attribute>
|
||||
<Attribute Name="AuthorAndLicense" ReadOnly="true">
|
||||
<Documentation>
|
||||
<UserDocu>Author and license information.</UserDocu>
|
||||
</Documentation>
|
||||
<Parameter Name="AuthorAndLicense" Type="String"/>
|
||||
</Attribute>
|
||||
<Attribute Name="PhysicalModels" ReadOnly="true">
|
||||
<Documentation>
|
||||
<UserDocu>List of implemented models.</UserDocu>
|
||||
</Documentation>
|
||||
<Parameter Name="PhysicalModels" Type="List"/>
|
||||
</Attribute>
|
||||
<Attribute Name="AppearanceModels" ReadOnly="true">
|
||||
<Documentation>
|
||||
<UserDocu>List of implemented models.</UserDocu>
|
||||
</Documentation>
|
||||
<Parameter Name="AppearanceModels" Type="List"/>
|
||||
</Attribute>
|
||||
<Attribute Name="Tags" ReadOnly="true">
|
||||
<Documentation>
|
||||
<UserDocu>List of searchable tags.</UserDocu>
|
||||
</Documentation>
|
||||
<Parameter Name="Tags" Type="List"/>
|
||||
</Attribute>
|
||||
<Methode Name="hasPhysicalModel" ReadOnly="true">
|
||||
<Documentation>
|
||||
<UserDocu>Check if the material implements the physical model with the given UUID</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="hasAppearanceModel" ReadOnly="true">
|
||||
<Documentation>
|
||||
<UserDocu>Check if the material implements the appearance model with the given UUID</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="isPhysicalModelComplete" ReadOnly="true">
|
||||
<Documentation>
|
||||
<UserDocu>Check if the material implements the physical model with the given UUID, and has values defined for each property</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="isAppearanceModelComplete" ReadOnly="true">
|
||||
<Documentation>
|
||||
<UserDocu>Check if the material implements the appearance model with the given UUID, and has values defined for each property</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="hasPhysicalProperty" ReadOnly="true">
|
||||
<Documentation>
|
||||
<UserDocu>Check if the material implements the physical property with the given name</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="hasAppearanceProperty" ReadOnly="true">
|
||||
<Documentation>
|
||||
<UserDocu>Check if the material implements the appearance property with the given name</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Attribute Name="Properties" ReadOnly="true">
|
||||
<Documentation>
|
||||
<UserDocu>deprecated -- Dictionary of all material properties.</UserDocu>
|
||||
</Documentation>
|
||||
<Parameter Name="Properties" Type="Dict"/>
|
||||
</Attribute>
|
||||
<Attribute Name="PhysicalProperties" ReadOnly="true">
|
||||
<Documentation>
|
||||
<UserDocu>deprecated -- Dictionary of material physical properties.</UserDocu>
|
||||
</Documentation>
|
||||
<Parameter Name="PhysicalProperties" Type="Dict"/>
|
||||
</Attribute>
|
||||
<Attribute Name="AppearanceProperties" ReadOnly="true">
|
||||
<Documentation>
|
||||
<UserDocu>deprecated -- Dictionary of material appearance properties.</UserDocu>
|
||||
</Documentation>
|
||||
<Parameter Name="AppearanceProperties" Type="Dict"/>
|
||||
</Attribute>
|
||||
<Methode Name="getPhysicalValue" ReadOnly="true">
|
||||
<Documentation>
|
||||
<UserDocu>Get the value associated with the property</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="getAppearanceValue" ReadOnly="true">
|
||||
<Documentation>
|
||||
<UserDocu>Get the value associated with the property</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
</PythonExport>
|
||||
</GenerateModel>
|
||||
394
src/Mod/Material/App/MaterialPyImpl.cpp
Normal file
394
src/Mod/Material/App/MaterialPyImpl.cpp
Normal file
@@ -0,0 +1,394 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
|
||||
* *
|
||||
* 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 *
|
||||
* <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
**************************************************************************/
|
||||
|
||||
#include "PreCompiled.h"
|
||||
|
||||
#ifndef _PreComp_
|
||||
#include <boost/uuid/uuid_io.hpp>
|
||||
#endif
|
||||
|
||||
#include <QMetaType>
|
||||
|
||||
#include <Base/Quantity.h>
|
||||
#include <Base/QuantityPy.h>
|
||||
#include <Gui/MetaTypes.h>
|
||||
|
||||
#include "Exceptions.h"
|
||||
#include "MaterialPy.h"
|
||||
#include "Materials.h"
|
||||
|
||||
#include "MaterialPy.cpp"
|
||||
|
||||
using namespace Materials;
|
||||
|
||||
// returns a string which represents the object e.g. when printed in python
|
||||
std::string MaterialPy::representation() const
|
||||
{
|
||||
MaterialPy::PointerType ptr = getMaterialPtr();
|
||||
std::stringstream str;
|
||||
str << "Property [Name=(";
|
||||
str << ptr->getName().toStdString();
|
||||
str << "), UUID=(";
|
||||
str << ptr->getUUID().toStdString();
|
||||
str << "), Library Name=(";
|
||||
str << ptr->getLibrary().getName().toStdString();
|
||||
str << "), Library Root=(";
|
||||
str << ptr->getLibrary().getDirectoryPath().toStdString();
|
||||
str << "), Library Icon=(";
|
||||
str << ptr->getLibrary().getIconPath().toStdString();
|
||||
str << "), Directory=(";
|
||||
str << ptr->getDirectory().toStdString();
|
||||
// str << "), URL=(";
|
||||
// str << ptr->getURL();
|
||||
// str << "), DOI=(";
|
||||
// str << ptr->getDOI();
|
||||
// str << "), Description=(";
|
||||
// str << ptr->getDescription();
|
||||
// str << "), Inherits=[";
|
||||
// const std::vector<std::string> &inherited = getMaterialPtr()->getInheritance();
|
||||
// for (auto it = inherited.begin(); it != inherited.end(); it++)
|
||||
// {
|
||||
// std::string uuid = *it;
|
||||
// if (it != inherited.begin())
|
||||
// str << "), UUID=(";
|
||||
// else
|
||||
// str << "UUID=(";
|
||||
// str << uuid << ")";
|
||||
// }
|
||||
// str << "]]";
|
||||
str << ")]";
|
||||
|
||||
return str.str();
|
||||
}
|
||||
|
||||
PyObject* MaterialPy::PyMake(struct _typeobject*, PyObject*, PyObject*) // Python wrapper
|
||||
{
|
||||
// never create such objects with the constructor
|
||||
return new MaterialPy(new Material());
|
||||
}
|
||||
|
||||
// constructor method
|
||||
int MaterialPy::PyInit(PyObject* /*args*/, PyObject* /*kwd*/)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
Py::String MaterialPy::getLibraryName() const
|
||||
{
|
||||
return Py::String(getMaterialPtr()->getLibrary().getName().toStdString());
|
||||
}
|
||||
|
||||
Py::String MaterialPy::getLibraryRoot() const
|
||||
{
|
||||
return Py::String(getMaterialPtr()->getLibrary().getDirectoryPath().toStdString());
|
||||
}
|
||||
|
||||
Py::String MaterialPy::getLibraryIcon() const
|
||||
{
|
||||
return Py::String(getMaterialPtr()->getLibrary().getIconPath().toStdString());
|
||||
}
|
||||
|
||||
Py::String MaterialPy::getName() const
|
||||
{
|
||||
return Py::String(getMaterialPtr()->getName().toStdString());
|
||||
}
|
||||
|
||||
Py::String MaterialPy::getDirectory() const
|
||||
{
|
||||
return Py::String(getMaterialPtr()->getDirectory().toStdString());
|
||||
}
|
||||
|
||||
Py::String MaterialPy::getUUID() const
|
||||
{
|
||||
return Py::String(getMaterialPtr()->getUUID().toStdString());
|
||||
}
|
||||
|
||||
Py::String MaterialPy::getDescription() const
|
||||
{
|
||||
return Py::String(getMaterialPtr()->getDescription().toStdString());
|
||||
}
|
||||
|
||||
Py::String MaterialPy::getURL() const
|
||||
{
|
||||
return Py::String(getMaterialPtr()->getURL().toStdString());
|
||||
}
|
||||
|
||||
Py::String MaterialPy::getReference() const
|
||||
{
|
||||
return Py::String(getMaterialPtr()->getReference().toStdString());
|
||||
}
|
||||
|
||||
Py::String MaterialPy::getParent() const
|
||||
{
|
||||
return Py::String(getMaterialPtr()->getParentUUID().toStdString());
|
||||
}
|
||||
|
||||
Py::String MaterialPy::getAuthorAndLicense() const
|
||||
{
|
||||
return Py::String(getMaterialPtr()->getAuthorAndLicense().toStdString());
|
||||
}
|
||||
|
||||
Py::List MaterialPy::getPhysicalModels() const
|
||||
{
|
||||
const std::vector<QString>* models = getMaterialPtr()->getPhysicalModels();
|
||||
Py::List list;
|
||||
|
||||
for (auto it = models->begin(); it != models->end(); it++) {
|
||||
QString uuid = *it;
|
||||
|
||||
list.append(Py::String(uuid.toStdString()));
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
Py::List MaterialPy::getAppearanceModels() const
|
||||
{
|
||||
const std::vector<QString>* models = getMaterialPtr()->getAppearanceModels();
|
||||
Py::List list;
|
||||
|
||||
for (auto it = models->begin(); it != models->end(); it++) {
|
||||
QString uuid = *it;
|
||||
|
||||
list.append(Py::String(uuid.toStdString()));
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
Py::List MaterialPy::getTags() const
|
||||
{
|
||||
const std::list<QString>& tags = getMaterialPtr()->getTags();
|
||||
Py::List list;
|
||||
|
||||
for (auto it = tags.begin(); it != tags.end(); it++) {
|
||||
QString uuid = *it;
|
||||
|
||||
list.append(Py::String(uuid.toStdString()));
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
PyObject* MaterialPy::getCustomAttributes(const char* /*attr*/) const
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int MaterialPy::setCustomAttributes(const char* /*attr*/, PyObject* /*obj*/)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
PyObject* MaterialPy::hasPhysicalModel(PyObject* args)
|
||||
{
|
||||
char* uuid;
|
||||
if (!PyArg_ParseTuple(args, "s", &uuid)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool hasProperty = getMaterialPtr()->hasPhysicalModel(QString::fromStdString(uuid));
|
||||
return hasProperty ? Py_True : Py_False;
|
||||
}
|
||||
|
||||
PyObject* MaterialPy::hasAppearanceModel(PyObject* args)
|
||||
{
|
||||
char* uuid;
|
||||
if (!PyArg_ParseTuple(args, "s", &uuid)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool hasProperty = getMaterialPtr()->hasAppearanceModel(QString::fromStdString(uuid));
|
||||
return hasProperty ? Py_True : Py_False;
|
||||
}
|
||||
|
||||
PyObject* MaterialPy::isPhysicalModelComplete(PyObject* args)
|
||||
{
|
||||
char* name;
|
||||
if (!PyArg_ParseTuple(args, "s", &name)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool isComplete = getMaterialPtr()->isPhysicalModelComplete(QString::fromStdString(name));
|
||||
return isComplete ? Py_True : Py_False;
|
||||
}
|
||||
|
||||
PyObject* MaterialPy::isAppearanceModelComplete(PyObject* args)
|
||||
{
|
||||
char* name;
|
||||
if (!PyArg_ParseTuple(args, "s", &name)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool isComplete = getMaterialPtr()->isAppearanceModelComplete(QString::fromStdString(name));
|
||||
return isComplete ? Py_True : Py_False;
|
||||
}
|
||||
|
||||
PyObject* MaterialPy::hasPhysicalProperty(PyObject* args)
|
||||
{
|
||||
char* name;
|
||||
if (!PyArg_ParseTuple(args, "s", &name)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool hasProperty = getMaterialPtr()->hasPhysicalProperty(QString::fromStdString(name));
|
||||
return hasProperty ? Py_True : Py_False;
|
||||
}
|
||||
|
||||
PyObject* MaterialPy::hasAppearanceProperty(PyObject* args)
|
||||
{
|
||||
char* name;
|
||||
if (!PyArg_ParseTuple(args, "s", &name)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool hasProperty = getMaterialPtr()->hasAppearanceProperty(QString::fromStdString(name));
|
||||
return hasProperty ? Py_True : Py_False;
|
||||
}
|
||||
|
||||
Py::Dict MaterialPy::getProperties() const
|
||||
{
|
||||
Py::Dict dict;
|
||||
|
||||
// Maintain backwards compatibility
|
||||
dict.setItem(Py::String("CardName"), Py::String(getMaterialPtr()->getName().toStdString()));
|
||||
dict.setItem(Py::String("AuthorAndLicense"),
|
||||
Py::String(getMaterialPtr()->getAuthorAndLicense().toStdString()));
|
||||
dict.setItem(Py::String("Name"), Py::String(getMaterialPtr()->getName().toStdString()));
|
||||
dict.setItem(Py::String("Description"),
|
||||
Py::String(getMaterialPtr()->getDescription().toStdString()));
|
||||
dict.setItem(Py::String("ReferenceSource"),
|
||||
Py::String(getMaterialPtr()->getReference().toStdString()));
|
||||
dict.setItem(Py::String("SourceURL"), Py::String(getMaterialPtr()->getURL().toStdString()));
|
||||
|
||||
auto properties = getMaterialPtr()->getPhysicalProperties();
|
||||
for (auto it = properties.begin(); it != properties.end(); it++) {
|
||||
QString key = it->first;
|
||||
MaterialProperty& materialProperty = it->second;
|
||||
|
||||
if (!materialProperty.isNull()) {
|
||||
auto value = materialProperty.getString();
|
||||
dict.setItem(Py::String(key.toStdString()), Py::String(value.toStdString()));
|
||||
}
|
||||
}
|
||||
|
||||
properties = getMaterialPtr()->getAppearanceProperties();
|
||||
for (auto it = properties.begin(); it != properties.end(); it++) {
|
||||
QString key = it->first;
|
||||
MaterialProperty& materialProperty = it->second;
|
||||
|
||||
if (!materialProperty.isNull()) {
|
||||
auto value = materialProperty.getString();
|
||||
dict.setItem(Py::String(key.toStdString()), Py::String(value.toStdString()));
|
||||
}
|
||||
}
|
||||
|
||||
return dict;
|
||||
}
|
||||
|
||||
Py::Dict MaterialPy::getPhysicalProperties() const
|
||||
{
|
||||
Py::Dict dict;
|
||||
|
||||
auto properties = getMaterialPtr()->getPhysicalProperties();
|
||||
for (auto it = properties.begin(); it != properties.end(); it++) {
|
||||
QString key = it->first;
|
||||
MaterialProperty& materialProperty = it->second;
|
||||
|
||||
if (!materialProperty.isNull()) {
|
||||
auto value = materialProperty.getString();
|
||||
dict.setItem(Py::String(key.toStdString()), Py::String(value.toStdString()));
|
||||
}
|
||||
}
|
||||
|
||||
return dict;
|
||||
}
|
||||
|
||||
Py::Dict MaterialPy::getAppearanceProperties() const
|
||||
{
|
||||
Py::Dict dict;
|
||||
|
||||
auto properties = getMaterialPtr()->getAppearanceProperties();
|
||||
for (auto it = properties.begin(); it != properties.end(); it++) {
|
||||
QString key = it->first;
|
||||
MaterialProperty& materialProperty = it->second;
|
||||
|
||||
if (!materialProperty.isNull()) {
|
||||
auto value = materialProperty.getString();
|
||||
dict.setItem(Py::String(key.toStdString()), Py::String(value.toStdString()));
|
||||
}
|
||||
}
|
||||
|
||||
return dict;
|
||||
}
|
||||
|
||||
static PyObject* _pyObjectFromVariant(const QVariant& value)
|
||||
{
|
||||
if (value.isNull()) {
|
||||
return new PyObject();
|
||||
}
|
||||
|
||||
if (value.userType() == QMetaType::type("Base::Quantity")) {
|
||||
return new Base::QuantityPy(new Base::Quantity(value.value<Base::Quantity>()));
|
||||
}
|
||||
else if (value.userType() == QMetaType::Double) {
|
||||
return PyFloat_FromDouble(value.toDouble());
|
||||
}
|
||||
else if (value.userType() == QMetaType::Float) {
|
||||
return PyFloat_FromDouble(value.toFloat());
|
||||
}
|
||||
else if (value.userType() == QMetaType::Int) {
|
||||
return PyLong_FromLong(value.toInt());
|
||||
}
|
||||
else if (value.userType() == QMetaType::Long) {
|
||||
return PyLong_FromLong(value.toInt());
|
||||
}
|
||||
else if (value.userType() == QMetaType::Bool) {
|
||||
return value.toBool() ? Py_True : Py_False;
|
||||
}
|
||||
else if (value.userType() == QMetaType::QString) {
|
||||
return PyUnicode_FromString(value.toString().toStdString().c_str());
|
||||
}
|
||||
|
||||
throw UnknownValueType();
|
||||
}
|
||||
|
||||
PyObject* MaterialPy::getPhysicalValue(PyObject* args)
|
||||
{
|
||||
char* name;
|
||||
if (!PyArg_ParseTuple(args, "s", &name)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
QVariant value = getMaterialPtr()->getPhysicalValue(QString::fromStdString(name));
|
||||
return _pyObjectFromVariant(value);
|
||||
}
|
||||
|
||||
PyObject* MaterialPy::getAppearanceValue(PyObject* args)
|
||||
{
|
||||
char* name;
|
||||
if (!PyArg_ParseTuple(args, "s", &name)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
QVariant value = getMaterialPtr()->getAppearanceValue(QString::fromStdString(name));
|
||||
return _pyObjectFromVariant(value);
|
||||
}
|
||||
242
src/Mod/Material/App/MaterialValue.cpp
Normal file
242
src/Mod/Material/App/MaterialValue.cpp
Normal file
@@ -0,0 +1,242 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
|
||||
* *
|
||||
* 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 *
|
||||
* <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
**************************************************************************/
|
||||
|
||||
#include "PreCompiled.h"
|
||||
#ifndef _PreComp_
|
||||
#endif
|
||||
|
||||
#include <App/Application.h>
|
||||
|
||||
#include "Exceptions.h"
|
||||
#include "MaterialValue.h"
|
||||
|
||||
|
||||
using namespace Materials;
|
||||
|
||||
/* TRANSLATOR Material::MaterialValue */
|
||||
|
||||
MaterialValue::MaterialValue()
|
||||
: _valueType(None)
|
||||
{}
|
||||
|
||||
MaterialValue::MaterialValue(ValueType type)
|
||||
: _valueType(type)
|
||||
{}
|
||||
|
||||
//===
|
||||
|
||||
Material2DArray::Material2DArray()
|
||||
: MaterialValue(Array2D)
|
||||
, _defaultSet(false)
|
||||
{}
|
||||
|
||||
MaterialValue Material2DArray::getDefault() const
|
||||
{
|
||||
MaterialValue ret(_valueType);
|
||||
ret.setValue(_value);
|
||||
return ret;
|
||||
}
|
||||
|
||||
const std::vector<QVariant>* Material2DArray::getRow(int row) const
|
||||
{
|
||||
try {
|
||||
return _rows.at(row);
|
||||
}
|
||||
catch (std::out_of_range const&) {
|
||||
throw InvalidRow();
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<QVariant>* Material2DArray::getRow(int row)
|
||||
{
|
||||
try {
|
||||
return _rows.at(row);
|
||||
}
|
||||
catch (std::out_of_range const&) {
|
||||
throw InvalidRow();
|
||||
}
|
||||
}
|
||||
|
||||
void Material2DArray::addRow(std::vector<QVariant>* row)
|
||||
{
|
||||
_rows.push_back(row);
|
||||
}
|
||||
|
||||
void Material2DArray::insertRow(int index, std::vector<QVariant>* row)
|
||||
{
|
||||
_rows.insert(_rows.begin() + index, row);
|
||||
}
|
||||
|
||||
void Material2DArray::deleteRow(int row)
|
||||
{
|
||||
if (static_cast<std::size_t>(row) >= _rows.size() || row < 0) {
|
||||
throw InvalidRow();
|
||||
}
|
||||
_rows.erase(_rows.begin() + row);
|
||||
}
|
||||
|
||||
void Material2DArray::setValue(int row, int column, const QVariant& value)
|
||||
{
|
||||
if (row >= rows()) {
|
||||
throw InvalidIndex();
|
||||
}
|
||||
|
||||
std::vector<QVariant>* val = getRow(row);
|
||||
try {
|
||||
val->at(column) = value;
|
||||
}
|
||||
catch (const std::out_of_range&) {
|
||||
throw InvalidIndex();
|
||||
}
|
||||
}
|
||||
|
||||
const QVariant Material2DArray::getValue(int row, int column) const
|
||||
{
|
||||
try {
|
||||
auto val = getRow(row);
|
||||
try {
|
||||
return val->at(column);
|
||||
}
|
||||
catch (std::out_of_range const&) {
|
||||
throw InvalidIndex();
|
||||
}
|
||||
}
|
||||
catch (const InvalidRow&) {
|
||||
throw InvalidIndex();
|
||||
}
|
||||
}
|
||||
|
||||
void Material2DArray::dumpRow(const std::vector<QVariant>& row) const
|
||||
{
|
||||
Base::Console().Log("row: ");
|
||||
for (auto column : row) {
|
||||
Base::Console().Log("'%s' ", column.toString().toStdString().c_str());
|
||||
}
|
||||
Base::Console().Log("\n");
|
||||
}
|
||||
|
||||
void Material2DArray::dump() const
|
||||
{
|
||||
for (auto row : _rows) {
|
||||
dumpRow(*row);
|
||||
}
|
||||
}
|
||||
|
||||
//===
|
||||
|
||||
Material3DArray::Material3DArray()
|
||||
: MaterialValue(Array3D)
|
||||
, _defaultSet(false)
|
||||
{}
|
||||
|
||||
MaterialValue Material3DArray::getDefault() const
|
||||
{
|
||||
MaterialValue ret(_valueType);
|
||||
ret.setValue(_value);
|
||||
return ret;
|
||||
}
|
||||
|
||||
const std::vector<std::vector<QVariant>*>& Material3DArray::getTable(const QVariant& depth) const
|
||||
{
|
||||
try {
|
||||
return _rowMap.at(depth);
|
||||
}
|
||||
catch (std::out_of_range const&) {
|
||||
throw InvalidRow();
|
||||
}
|
||||
}
|
||||
|
||||
const std::vector<QVariant>& Material3DArray::getRow(const QVariant& depth, int row) const
|
||||
{
|
||||
try {
|
||||
return *(_rowMap.at(depth).at(row));
|
||||
}
|
||||
catch (std::out_of_range const&) {
|
||||
throw InvalidRow();
|
||||
}
|
||||
}
|
||||
|
||||
const std::vector<QVariant>& Material3DArray::getRow(int row) const
|
||||
{
|
||||
return getRow(getDefault().getValue().toString(), row);
|
||||
}
|
||||
|
||||
std::vector<QVariant>& Material3DArray::getRow(const QVariant& depth, int row)
|
||||
{
|
||||
try {
|
||||
return *(_rowMap.at(depth).at(row));
|
||||
}
|
||||
catch (std::out_of_range const&) {
|
||||
throw InvalidRow();
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<QVariant>& Material3DArray::getRow(int row)
|
||||
{
|
||||
return getRow(getDefault().getValue().toString(), row);
|
||||
}
|
||||
|
||||
void Material3DArray::addRow(const QVariant& depth, std::vector<QVariant>* row)
|
||||
{
|
||||
_rowMap[depth].push_back(row);
|
||||
}
|
||||
|
||||
void Material3DArray::deleteRow(const QVariant& depth, int row)
|
||||
{
|
||||
Q_UNUSED(depth)
|
||||
Q_UNUSED(row)
|
||||
}
|
||||
|
||||
void Material3DArray::deleteRows(int depth)
|
||||
{
|
||||
Q_UNUSED(depth)
|
||||
}
|
||||
|
||||
void Material3DArray::setValue(const QVariant& depth, int row, int column, const QVariant& value)
|
||||
{
|
||||
Q_UNUSED(depth)
|
||||
Q_UNUSED(row)
|
||||
Q_UNUSED(column)
|
||||
Q_UNUSED(value)
|
||||
}
|
||||
|
||||
void Material3DArray::setValue(int row, int column, const QVariant& value)
|
||||
{
|
||||
Q_UNUSED(row)
|
||||
Q_UNUSED(column)
|
||||
Q_UNUSED(value)
|
||||
}
|
||||
|
||||
const QVariant Material3DArray::getValue(const QVariant& depth, int row, int column)
|
||||
{
|
||||
auto val = getRow(depth, row);
|
||||
try {
|
||||
return val.at(column);
|
||||
}
|
||||
catch (std::out_of_range const&) {
|
||||
throw InvalidColumn();
|
||||
}
|
||||
}
|
||||
|
||||
const QVariant Material3DArray::getValue(int row, int column)
|
||||
{
|
||||
return getValue(getDefault().getValue().toString(), row, column);
|
||||
}
|
||||
188
src/Mod/Material/App/MaterialValue.h
Normal file
188
src/Mod/Material/App/MaterialValue.h
Normal file
@@ -0,0 +1,188 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
|
||||
* *
|
||||
* 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 *
|
||||
* <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef MATERIAL_MATERIALVALUE_H
|
||||
#define MATERIAL_MATERIALVALUE_H
|
||||
|
||||
#include <Mod/Material/MaterialGlobal.h>
|
||||
|
||||
#include <QVariant>
|
||||
|
||||
namespace Materials
|
||||
{
|
||||
|
||||
class MaterialsExport MaterialValue
|
||||
{
|
||||
public:
|
||||
enum ValueType
|
||||
{
|
||||
None = 0,
|
||||
String = 1,
|
||||
Boolean = 2,
|
||||
Integer = 3,
|
||||
Float = 4,
|
||||
Quantity = 5,
|
||||
Distribution = 6,
|
||||
List = 7,
|
||||
Array2D = 8,
|
||||
Array3D = 9,
|
||||
Color = 10,
|
||||
Image = 11,
|
||||
File = 12,
|
||||
URL = 13
|
||||
};
|
||||
MaterialValue();
|
||||
explicit MaterialValue(ValueType type);
|
||||
virtual ~MaterialValue() = default;
|
||||
|
||||
ValueType getType() const
|
||||
{
|
||||
return _valueType;
|
||||
}
|
||||
|
||||
const QVariant getValue() const
|
||||
{
|
||||
return _value;
|
||||
}
|
||||
bool isNull() const
|
||||
{
|
||||
return _value.isNull();
|
||||
}
|
||||
virtual const QVariant getValueAt(const QVariant& value) const
|
||||
{
|
||||
Q_UNUSED(value);
|
||||
return _value;
|
||||
}
|
||||
void setValue(const QVariant& value)
|
||||
{
|
||||
_value = value;
|
||||
}
|
||||
|
||||
protected:
|
||||
ValueType _valueType;
|
||||
QVariant _value;
|
||||
|
||||
void setType(ValueType type)
|
||||
{
|
||||
_valueType = type;
|
||||
}
|
||||
};
|
||||
|
||||
class MaterialsExport Material2DArray: public MaterialValue
|
||||
{
|
||||
public:
|
||||
Material2DArray();
|
||||
~Material2DArray() override = default;
|
||||
|
||||
void setDefault(MaterialValue value)
|
||||
{
|
||||
_value = value.getValue();
|
||||
_defaultSet = true;
|
||||
}
|
||||
void setDefault(const QVariant& value)
|
||||
{
|
||||
_value = value;
|
||||
_defaultSet = true;
|
||||
}
|
||||
MaterialValue getDefault() const;
|
||||
bool defaultSet() const
|
||||
{
|
||||
return _defaultSet;
|
||||
}
|
||||
|
||||
const std::vector<QVariant>* getRow(int row) const;
|
||||
std::vector<QVariant>* getRow(int row);
|
||||
int rows() const
|
||||
{
|
||||
return _rows.size();
|
||||
}
|
||||
void addRow(std::vector<QVariant>* row);
|
||||
void insertRow(int index, std::vector<QVariant>* row);
|
||||
void deleteRow(int row);
|
||||
|
||||
void setValue(int row, int column, const QVariant& value);
|
||||
const QVariant getValue(int row, int column) const;
|
||||
|
||||
protected:
|
||||
std::vector<std::vector<QVariant>*> _rows;
|
||||
bool _defaultSet;
|
||||
|
||||
private:
|
||||
void dumpRow(const std::vector<QVariant>& row) const;
|
||||
void dump() const;
|
||||
};
|
||||
|
||||
class MaterialsExport Material3DArray: public MaterialValue
|
||||
{
|
||||
public:
|
||||
Material3DArray();
|
||||
~Material3DArray() override = default;
|
||||
|
||||
void setDefault(MaterialValue value)
|
||||
{
|
||||
_value = value.getValue();
|
||||
_defaultSet = true;
|
||||
}
|
||||
void setDefault(const QVariant& value)
|
||||
{
|
||||
_value = value;
|
||||
_defaultSet = true;
|
||||
}
|
||||
MaterialValue getDefault() const;
|
||||
bool defaultSet() const
|
||||
{
|
||||
return _defaultSet;
|
||||
}
|
||||
|
||||
const std::vector<std::vector<QVariant>*>& getTable(const QVariant& depth) const;
|
||||
const std::vector<QVariant>& getRow(const QVariant& depth, int row) const;
|
||||
const std::vector<QVariant>& getRow(int row) const;
|
||||
std::vector<QVariant>& getRow(const QVariant& depth, int row);
|
||||
std::vector<QVariant>& getRow(int row);
|
||||
void addRow(const QVariant& depth, std::vector<QVariant>* row);
|
||||
void deleteRow(const QVariant& depth, int row);
|
||||
void deleteRows(int depth);
|
||||
int depth() const
|
||||
{
|
||||
return _rowMap.size();
|
||||
}
|
||||
int rows(const QVariant& depth) const
|
||||
{
|
||||
return getTable(depth).size();
|
||||
}
|
||||
|
||||
void setValue(const QVariant& depth, int row, int column, const QVariant& value);
|
||||
void setValue(int row, int column, const QVariant& value);
|
||||
const QVariant getValue(const QVariant& depth, int row, int column);
|
||||
const QVariant getValue(int row, int column);
|
||||
|
||||
protected:
|
||||
std::map<QVariant, std::vector<std::vector<QVariant>*>> _rowMap;
|
||||
bool _defaultSet;
|
||||
};
|
||||
|
||||
} // namespace Materials
|
||||
|
||||
Q_DECLARE_METATYPE(Materials::MaterialValue)
|
||||
Q_DECLARE_METATYPE(Materials::Material2DArray)
|
||||
Q_DECLARE_METATYPE(Materials::Material3DArray)
|
||||
|
||||
#endif // MATERIAL_MATERIALVALUE_H
|
||||
924
src/Mod/Material/App/Materials.cpp
Normal file
924
src/Mod/Material/App/Materials.cpp
Normal file
@@ -0,0 +1,924 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
|
||||
* *
|
||||
* 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 *
|
||||
* <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
**************************************************************************/
|
||||
|
||||
#include "PreCompiled.h"
|
||||
#ifndef _PreComp_
|
||||
#endif
|
||||
|
||||
#include <QMetaType>
|
||||
#include <QUuid>
|
||||
|
||||
#include <App/Application.h>
|
||||
#include <Gui/MetaTypes.h>
|
||||
|
||||
#include "MaterialManager.h"
|
||||
#include "Materials.h"
|
||||
#include "ModelManager.h"
|
||||
|
||||
|
||||
using namespace Materials;
|
||||
|
||||
/* TRANSLATOR Material::Materials */
|
||||
|
||||
TYPESYSTEM_SOURCE(Materials::MaterialProperty, Materials::ModelProperty)
|
||||
|
||||
MaterialProperty::MaterialProperty()
|
||||
{
|
||||
_valuePtr = std::make_shared<MaterialValue>(MaterialValue::None);
|
||||
}
|
||||
|
||||
MaterialProperty::MaterialProperty(const ModelProperty& property)
|
||||
: ModelProperty(property)
|
||||
, _valuePtr(nullptr)
|
||||
{
|
||||
setType(getPropertyType());
|
||||
auto columns = property.getColumns();
|
||||
for (std::vector<ModelProperty>::const_iterator it = columns.begin(); it != columns.end();
|
||||
it++) {
|
||||
MaterialProperty prop(*it);
|
||||
addColumn(prop);
|
||||
}
|
||||
|
||||
if (_valuePtr->getType() == MaterialValue::Array2D) {
|
||||
std::static_pointer_cast<Material2DArray>(_valuePtr)->setDefault(getColumnNull(0));
|
||||
}
|
||||
else if (_valuePtr->getType() == MaterialValue::Array3D) {
|
||||
std::static_pointer_cast<Material3DArray>(_valuePtr)->setDefault(getColumnNull(0));
|
||||
}
|
||||
}
|
||||
|
||||
MaterialProperty::MaterialProperty(const MaterialProperty& other)
|
||||
: ModelProperty(other)
|
||||
{
|
||||
_modelUUID = other._modelUUID;
|
||||
if (other._valuePtr != nullptr) {
|
||||
_valuePtr = std::make_shared<MaterialValue>(*(other._valuePtr));
|
||||
}
|
||||
else {
|
||||
_valuePtr = nullptr;
|
||||
}
|
||||
|
||||
for (auto it = other._columns.begin(); it != other._columns.end(); it++) {
|
||||
_columns.push_back(*it);
|
||||
}
|
||||
}
|
||||
|
||||
// MaterialProperty::~MaterialProperty()
|
||||
// {}
|
||||
|
||||
void MaterialProperty::setModelUUID(const QString& uuid)
|
||||
{
|
||||
_modelUUID = uuid;
|
||||
}
|
||||
|
||||
const QVariant MaterialProperty::getValue() const
|
||||
{
|
||||
return _valuePtr->getValue();
|
||||
}
|
||||
|
||||
std::shared_ptr<MaterialValue> MaterialProperty::getMaterialValue()
|
||||
{
|
||||
return _valuePtr;
|
||||
}
|
||||
|
||||
const std::shared_ptr<MaterialValue> MaterialProperty::getMaterialValue() const
|
||||
{
|
||||
return _valuePtr;
|
||||
}
|
||||
|
||||
const QString MaterialProperty::getString() const
|
||||
{
|
||||
if (getType() == MaterialValue::Quantity) {
|
||||
Base::Quantity quantity = getValue().value<Base::Quantity>();
|
||||
return quantity.getUserString();
|
||||
}
|
||||
return getValue().toString();
|
||||
}
|
||||
|
||||
void MaterialProperty::setPropertyType(const QString& type)
|
||||
{
|
||||
ModelProperty::setPropertyType(type);
|
||||
setType(type);
|
||||
}
|
||||
|
||||
void MaterialProperty::setType(const QString& type)
|
||||
{
|
||||
if (type == QString::fromStdString("String")) {
|
||||
_valuePtr = std::make_shared<MaterialValue>(MaterialValue::String);
|
||||
}
|
||||
else if (type == QString::fromStdString("Boolean")) {
|
||||
_valuePtr = std::make_shared<MaterialValue>(MaterialValue::Boolean);
|
||||
}
|
||||
else if (type == QString::fromStdString("Integer")) {
|
||||
_valuePtr = std::make_shared<MaterialValue>(MaterialValue::Integer);
|
||||
}
|
||||
else if (type == QString::fromStdString("Float")) {
|
||||
_valuePtr = std::make_shared<MaterialValue>(MaterialValue::Float);
|
||||
}
|
||||
else if (type == QString::fromStdString("URL")) {
|
||||
_valuePtr = std::make_shared<MaterialValue>(MaterialValue::URL);
|
||||
}
|
||||
else if (type == QString::fromStdString("Quantity")) {
|
||||
_valuePtr = std::make_shared<MaterialValue>(MaterialValue::Quantity);
|
||||
}
|
||||
else if (type == QString::fromStdString("Color")) {
|
||||
_valuePtr = std::make_shared<MaterialValue>(MaterialValue::Color);
|
||||
}
|
||||
else if (type == QString::fromStdString("File")) {
|
||||
_valuePtr = std::make_shared<MaterialValue>(MaterialValue::File);
|
||||
}
|
||||
else if (type == QString::fromStdString("Image")) {
|
||||
_valuePtr = std::make_shared<MaterialValue>(MaterialValue::Image);
|
||||
}
|
||||
else if (type == QString::fromStdString("List")) {
|
||||
_valuePtr = std::make_shared<MaterialValue>(MaterialValue::List);
|
||||
}
|
||||
else if (type == QString::fromStdString("2DArray")) {
|
||||
_valuePtr = std::make_shared<Material2DArray>();
|
||||
}
|
||||
else if (type == QString::fromStdString("3DArray")) {
|
||||
_valuePtr = std::make_shared<Material3DArray>();
|
||||
}
|
||||
else {
|
||||
// Error. Throw something
|
||||
_valuePtr = std::make_shared<MaterialValue>(MaterialValue::None);
|
||||
std::string stringType = type.toStdString();
|
||||
std::string name = getName().toStdString();
|
||||
throw UnknownValueType();
|
||||
}
|
||||
}
|
||||
|
||||
MaterialProperty& MaterialProperty::getColumn(int column)
|
||||
{
|
||||
try {
|
||||
return _columns.at(column);
|
||||
}
|
||||
catch (std::out_of_range const&) {
|
||||
throw InvalidColumn();
|
||||
}
|
||||
}
|
||||
|
||||
const MaterialProperty& MaterialProperty::getColumn(int column) const
|
||||
{
|
||||
try {
|
||||
return _columns.at(column);
|
||||
}
|
||||
catch (std::out_of_range const&) {
|
||||
throw InvalidColumn();
|
||||
}
|
||||
}
|
||||
|
||||
MaterialValue::ValueType MaterialProperty::getColumnType(int column) const
|
||||
{
|
||||
try {
|
||||
return _columns.at(column).getType();
|
||||
}
|
||||
catch (std::out_of_range const&) {
|
||||
throw InvalidColumn();
|
||||
}
|
||||
}
|
||||
|
||||
QString MaterialProperty::getColumnUnits(int column) const
|
||||
{
|
||||
try {
|
||||
return _columns.at(column).getUnits();
|
||||
}
|
||||
catch (std::out_of_range const&) {
|
||||
throw InvalidColumn();
|
||||
}
|
||||
}
|
||||
|
||||
QVariant MaterialProperty::getColumnNull(int column) const
|
||||
{
|
||||
MaterialValue::ValueType valueType = getColumnType(column);
|
||||
|
||||
switch (valueType) {
|
||||
case MaterialValue::Quantity: {
|
||||
Base::Quantity q = Base::Quantity(0, getColumnUnits(column));
|
||||
return QVariant::fromValue(q);
|
||||
}
|
||||
|
||||
case MaterialValue::Float:
|
||||
case MaterialValue::Integer:
|
||||
return QVariant(0);
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return QVariant(QString());
|
||||
}
|
||||
|
||||
void MaterialProperty::setValue(const QVariant& value)
|
||||
{
|
||||
// _valueType = MaterialValue::String;
|
||||
_valuePtr->setValue(value);
|
||||
}
|
||||
|
||||
void MaterialProperty::setValue(const QString& value)
|
||||
{
|
||||
if (_valuePtr->getType() == MaterialValue::Boolean) {
|
||||
setBoolean(value);
|
||||
}
|
||||
else if (_valuePtr->getType() == MaterialValue::Integer) {
|
||||
setInt(value);
|
||||
}
|
||||
else if (_valuePtr->getType() == MaterialValue::Float) {
|
||||
setFloat(value);
|
||||
}
|
||||
else if (_valuePtr->getType() == MaterialValue::URL) {
|
||||
setURL(value);
|
||||
}
|
||||
else if (_valuePtr->getType() == MaterialValue::Quantity) {
|
||||
// Base::Console().Log("\tParse quantity '%s'\n", value.toStdString().c_str());
|
||||
try {
|
||||
setQuantity(Base::Quantity::parse(value));
|
||||
}
|
||||
catch (const Base::ParserError& e) {
|
||||
Base::Console().Log("Error '%s'\n", e.what());
|
||||
// Save as a string
|
||||
setString(value);
|
||||
}
|
||||
}
|
||||
else {
|
||||
setString(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));
|
||||
}
|
||||
|
||||
void MaterialProperty::setBoolean(const QString& value)
|
||||
{
|
||||
// _valueType = MaterialValue::Boolean;
|
||||
bool boolean;
|
||||
std::string val = value.toStdString();
|
||||
if ((val == "true") || (val == "True")) {
|
||||
boolean = true;
|
||||
}
|
||||
else if ((val == "false") || (val == "False")) {
|
||||
boolean = false;
|
||||
}
|
||||
else {
|
||||
boolean = (std::stoi(val) != 0);
|
||||
}
|
||||
|
||||
setBoolean(boolean);
|
||||
}
|
||||
|
||||
void MaterialProperty::setInt(int value)
|
||||
{
|
||||
_valuePtr->setValue(QVariant(value));
|
||||
}
|
||||
|
||||
void MaterialProperty::setInt(const QString& value)
|
||||
{
|
||||
_valuePtr->setValue(value.toInt());
|
||||
}
|
||||
|
||||
void MaterialProperty::setFloat(double value)
|
||||
{
|
||||
_valuePtr->setValue(QVariant(value));
|
||||
}
|
||||
|
||||
void MaterialProperty::setFloat(const QString& value)
|
||||
{
|
||||
_valuePtr->setValue(QVariant(value.toFloat()));
|
||||
}
|
||||
|
||||
void MaterialProperty::setQuantity(const Base::Quantity& value)
|
||||
{
|
||||
_valuePtr->setValue(QVariant(QVariant::fromValue(value)));
|
||||
}
|
||||
|
||||
void MaterialProperty::setQuantity(double value, const QString& units)
|
||||
{
|
||||
setQuantity(Base::Quantity(value, units));
|
||||
}
|
||||
|
||||
void MaterialProperty::setQuantity(const QString& value)
|
||||
{
|
||||
setQuantity(Base::Quantity::parse(value));
|
||||
}
|
||||
|
||||
void MaterialProperty::setURL(const QString& value)
|
||||
{
|
||||
_valuePtr->setValue(QVariant(value));
|
||||
}
|
||||
|
||||
MaterialProperty& MaterialProperty::operator=(const MaterialProperty& other)
|
||||
{
|
||||
if (this == &other) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
ModelProperty::operator=(other);
|
||||
_modelUUID = other._modelUUID;
|
||||
|
||||
if (other._valuePtr != nullptr) {
|
||||
_valuePtr = std::make_shared<MaterialValue>(*(other._valuePtr));
|
||||
}
|
||||
else {
|
||||
_valuePtr = nullptr;
|
||||
}
|
||||
|
||||
_columns.clear();
|
||||
for (auto it = other._columns.begin(); it != other._columns.end(); it++) {
|
||||
_columns.push_back(*it);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
TYPESYSTEM_SOURCE(Materials::Material, Base::BaseClass)
|
||||
|
||||
Material::Material()
|
||||
: _dereferenced(false)
|
||||
{}
|
||||
|
||||
Material::Material(const MaterialLibrary& library,
|
||||
const QString& directory,
|
||||
const QString& uuid,
|
||||
const QString& name)
|
||||
: _library(library)
|
||||
, _uuid(uuid)
|
||||
, _name(name)
|
||||
, _dereferenced(false)
|
||||
, _editState(ModelEdit_None)
|
||||
{
|
||||
setDirectory(directory);
|
||||
}
|
||||
|
||||
Material::Material(const Material& other)
|
||||
: _library(other._library)
|
||||
, _directory(other._directory)
|
||||
, _uuid(other._uuid)
|
||||
, _name(other._name)
|
||||
, _authorAndLicense(other._authorAndLicense)
|
||||
, _parentUuid(other._parentUuid)
|
||||
, _description(other._description)
|
||||
, _url(other._url)
|
||||
, _reference(other._reference)
|
||||
, _dereferenced(other._dereferenced)
|
||||
, _editState(other._editState)
|
||||
{
|
||||
for (auto it = other._tags.begin(); it != other._tags.end(); it++) {
|
||||
_tags.push_back(*it);
|
||||
}
|
||||
for (auto it = other._physicalUuids.begin(); it != other._physicalUuids.end(); it++) {
|
||||
_physicalUuids.push_back(*it);
|
||||
}
|
||||
for (auto it = other._appearanceUuids.begin(); it != other._appearanceUuids.end(); it++) {
|
||||
_appearanceUuids.push_back(*it);
|
||||
}
|
||||
for (auto it = other._allUuids.begin(); it != other._allUuids.end(); it++) {
|
||||
_allUuids.push_back(*it);
|
||||
}
|
||||
for (auto it = other._physical.begin(); it != other._physical.end(); it++) {
|
||||
_physical[it->first] = MaterialProperty(it->second);
|
||||
}
|
||||
for (auto it = other._appearance.begin(); it != other._appearance.end(); it++) {
|
||||
_appearance[it->first] = MaterialProperty(it->second);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Destroys the object and frees any allocated resources
|
||||
*/
|
||||
Material::~Material()
|
||||
{
|
||||
// no need to delete child widgets, Qt does it all for us
|
||||
}
|
||||
|
||||
void Material::addModel(const QString& uuid)
|
||||
{
|
||||
for (QString modelUUID : _allUuids) {
|
||||
if (modelUUID == uuid) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
_allUuids.push_back(uuid);
|
||||
|
||||
ModelManager manager;
|
||||
|
||||
try {
|
||||
const Model& model = manager.getModel(uuid);
|
||||
auto inheritance = model.getInheritance();
|
||||
for (auto inherits = inheritance.begin(); inherits != inheritance.end(); inherits++) {
|
||||
addModel(*inherits);
|
||||
}
|
||||
}
|
||||
catch (ModelNotFound const&) {
|
||||
}
|
||||
}
|
||||
|
||||
void Material::setEditState(ModelEdit newState)
|
||||
{
|
||||
if (newState == ModelEdit_Extend) {
|
||||
if (_editState != ModelEdit_Alter) {
|
||||
_editState = newState;
|
||||
}
|
||||
}
|
||||
else if (newState == ModelEdit_Alter) {
|
||||
_editState = newState;
|
||||
}
|
||||
}
|
||||
|
||||
void Material::addPhysical(const QString& uuid)
|
||||
{
|
||||
if (hasPhysicalModel(uuid)) {
|
||||
return;
|
||||
}
|
||||
|
||||
ModelManager manager;
|
||||
|
||||
try {
|
||||
const Model& model = manager.getModel(uuid);
|
||||
|
||||
_physicalUuids.push_back(uuid);
|
||||
addModel(uuid);
|
||||
setEditStateExtend();
|
||||
|
||||
for (auto it = model.begin(); it != model.end(); it++) {
|
||||
QString propertyName = it->first;
|
||||
ModelProperty property = static_cast<ModelProperty>(it->second);
|
||||
|
||||
try {
|
||||
_physical[propertyName] = MaterialProperty(property);
|
||||
}
|
||||
catch (const UnknownValueType&) {
|
||||
Base::Console().Error("Property '%s' has unknown type '%s'. Ignoring\n",
|
||||
property.getName().toStdString().c_str(),
|
||||
property.getPropertyType().toStdString().c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (ModelNotFound const&) {
|
||||
}
|
||||
}
|
||||
|
||||
void Material::addAppearance(const QString& uuid)
|
||||
{
|
||||
if (hasAppearanceModel(uuid)) {
|
||||
return;
|
||||
}
|
||||
|
||||
ModelManager manager;
|
||||
|
||||
try {
|
||||
const Model& model = manager.getModel(uuid);
|
||||
|
||||
_appearanceUuids.push_back(uuid);
|
||||
addModel(uuid);
|
||||
setEditStateExtend();
|
||||
|
||||
for (auto it = model.begin(); it != model.end(); it++) {
|
||||
QString propertyName = it->first;
|
||||
ModelProperty property = static_cast<ModelProperty>(it->second);
|
||||
|
||||
_appearance[propertyName] = MaterialProperty(property);
|
||||
}
|
||||
}
|
||||
catch (ModelNotFound const&) {
|
||||
}
|
||||
}
|
||||
|
||||
void Material::setPhysicalEditState(const QString& name)
|
||||
{
|
||||
if (getPhysicalProperty(name).isNull()) {
|
||||
setEditStateExtend();
|
||||
}
|
||||
else {
|
||||
setEditStateAlter();
|
||||
}
|
||||
}
|
||||
|
||||
void Material::setAppearanceEditState(const QString& name)
|
||||
{
|
||||
if (getAppearanceProperty(name).isNull()) {
|
||||
setEditStateExtend();
|
||||
}
|
||||
else {
|
||||
setEditStateAlter();
|
||||
}
|
||||
}
|
||||
|
||||
void Material::setPhysicalValue(const QString& name, const QString& value)
|
||||
{
|
||||
setPhysicalEditState(name);
|
||||
|
||||
_physical[name].setValue(value); // may not be a string type
|
||||
}
|
||||
|
||||
void Material::setPhysicalValue(const QString& name, int value)
|
||||
{
|
||||
setPhysicalEditState(name);
|
||||
|
||||
_physical[name].setInt(value);
|
||||
}
|
||||
|
||||
void Material::setPhysicalValue(const QString& name, double value)
|
||||
{
|
||||
setPhysicalEditState(name);
|
||||
|
||||
_physical[name].setFloat(value);
|
||||
}
|
||||
|
||||
void Material::setPhysicalValue(const QString& name, const Base::Quantity value)
|
||||
{
|
||||
setPhysicalEditState(name);
|
||||
|
||||
_physical[name].setQuantity(value);
|
||||
}
|
||||
|
||||
void Material::setAppearanceValue(const QString& name, const QString& value)
|
||||
{
|
||||
setAppearanceEditState(name);
|
||||
|
||||
_appearance[name].setValue(value); // may not be a string type
|
||||
}
|
||||
|
||||
MaterialProperty& Material::getPhysicalProperty(const QString& name)
|
||||
{
|
||||
try {
|
||||
return _physical.at(name);
|
||||
}
|
||||
catch (std::out_of_range const&) {
|
||||
throw PropertyNotFound();
|
||||
}
|
||||
}
|
||||
|
||||
const MaterialProperty& Material::getPhysicalProperty(const QString& name) const
|
||||
{
|
||||
try {
|
||||
return _physical.at(name);
|
||||
}
|
||||
catch (std::out_of_range const&) {
|
||||
throw PropertyNotFound();
|
||||
}
|
||||
}
|
||||
|
||||
MaterialProperty& Material::getAppearanceProperty(const QString& name)
|
||||
{
|
||||
try {
|
||||
return _appearance.at(name);
|
||||
}
|
||||
catch (std::out_of_range const&) {
|
||||
throw PropertyNotFound();
|
||||
}
|
||||
}
|
||||
|
||||
const MaterialProperty& Material::getAppearanceProperty(const QString& name) const
|
||||
{
|
||||
try {
|
||||
return _appearance.at(name);
|
||||
}
|
||||
catch (std::out_of_range const&) {
|
||||
throw PropertyNotFound();
|
||||
}
|
||||
}
|
||||
|
||||
const QVariant Material::getValue(const std::map<QString, MaterialProperty>& propertyList,
|
||||
const QString& name) const
|
||||
{
|
||||
try {
|
||||
return propertyList.at(name).getValue();
|
||||
}
|
||||
catch (std::out_of_range const&) {
|
||||
throw PropertyNotFound();
|
||||
}
|
||||
}
|
||||
|
||||
const QString Material::getValueString(const std::map<QString, MaterialProperty>& propertyList,
|
||||
const QString& name) const
|
||||
{
|
||||
try {
|
||||
if (propertyList.at(name).getType() == MaterialValue::Quantity) {
|
||||
auto value = propertyList.at(name).getValue();
|
||||
if (value.isNull()) {
|
||||
return QString();
|
||||
}
|
||||
return value.value<Base::Quantity>().getUserString();
|
||||
}
|
||||
return propertyList.at(name).getValue().toString();
|
||||
}
|
||||
catch (std::out_of_range const&) {
|
||||
throw PropertyNotFound();
|
||||
}
|
||||
}
|
||||
|
||||
const QVariant Material::getPhysicalValue(const QString& name) const
|
||||
{
|
||||
return getValue(_physical, name);
|
||||
}
|
||||
|
||||
const QString Material::getPhysicalValueString(const QString& name) const
|
||||
{
|
||||
return getValueString(_physical, name);
|
||||
}
|
||||
|
||||
const QVariant Material::getAppearanceValue(const QString& name) const
|
||||
{
|
||||
return getValue(_appearance, name);
|
||||
}
|
||||
|
||||
const QString Material::getAppearanceValueString(const QString& name) const
|
||||
{
|
||||
return getValueString(_appearance, name);
|
||||
}
|
||||
|
||||
bool Material::hasPhysicalProperty(const QString& name) const
|
||||
{
|
||||
try {
|
||||
static_cast<void>(_physical.at(name));
|
||||
}
|
||||
catch (std::out_of_range const&) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Material::hasAppearanceProperty(const QString& name) const
|
||||
{
|
||||
try {
|
||||
static_cast<void>(_appearance.at(name));
|
||||
}
|
||||
catch (std::out_of_range const&) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Material::hasModel(const QString& uuid) const
|
||||
{
|
||||
for (QString modelUUID : _allUuids) {
|
||||
if (modelUUID == uuid) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Material::hasPhysicalModel(const QString& uuid) const
|
||||
{
|
||||
if (!hasModel(uuid)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ModelManager manager;
|
||||
|
||||
try {
|
||||
const Model& model = manager.getModel(uuid);
|
||||
if (model.getType() == Model::ModelType_Physical) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch (ModelNotFound const&) {
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Material::hasAppearanceModel(const QString& uuid) const
|
||||
{
|
||||
if (!hasModel(uuid)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ModelManager manager;
|
||||
|
||||
try {
|
||||
const Model& model = manager.getModel(uuid);
|
||||
if (model.getType() == Model::ModelType_Appearance) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch (ModelNotFound const&) {
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Material::isPhysicalModelComplete(const QString& uuid) const
|
||||
{
|
||||
if (!hasPhysicalModel(uuid)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ModelManager manager;
|
||||
|
||||
try {
|
||||
const Model& model = manager.getModel(uuid);
|
||||
for (auto it = model.begin(); it != model.end(); it++) {
|
||||
QString propertyName = it->first;
|
||||
const MaterialProperty& property = getPhysicalProperty(propertyName);
|
||||
|
||||
if (property.isNull()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (ModelNotFound const&) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Material::isAppearanceModelComplete(const QString& uuid) const
|
||||
{
|
||||
if (!hasAppearanceModel(uuid)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ModelManager manager;
|
||||
|
||||
try {
|
||||
const Model& model = manager.getModel(uuid);
|
||||
for (auto it = model.begin(); it != model.end(); it++) {
|
||||
QString propertyName = it->first;
|
||||
const MaterialProperty& property = getAppearanceProperty(propertyName);
|
||||
|
||||
if (property.isNull()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (ModelNotFound const&) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Material::saveGeneral(QTextStream& stream) const
|
||||
{
|
||||
stream << "General:\n";
|
||||
stream << " UUID: \"" << _uuid << "\"\n";
|
||||
stream << " Name: \"" << _name << "\"\n";
|
||||
if (!_authorAndLicense.isEmpty()) {
|
||||
stream << " AuthorAndLicense: \"" << _authorAndLicense << "\"\n";
|
||||
}
|
||||
if (!_description.isEmpty()) {
|
||||
stream << " Description: \"" << _description << "\"\n";
|
||||
}
|
||||
if (!_url.isEmpty()) {
|
||||
stream << " SourceURL: \"" << _url << "\"\n";
|
||||
}
|
||||
if (!_reference.isEmpty()) {
|
||||
stream << " ReferenceSource: \"" << _reference << "\"\n";
|
||||
}
|
||||
}
|
||||
|
||||
void Material::saveInherits(QTextStream& stream) const
|
||||
{
|
||||
if (!_parentUuid.isEmpty()) {
|
||||
MaterialManager manager;
|
||||
|
||||
stream << "Inherits:\n";
|
||||
stream << " " << manager.getMaterial(_parentUuid).getName() << ":\n";
|
||||
stream << " UUID: \"" << _parentUuid << "\"\n";
|
||||
}
|
||||
}
|
||||
|
||||
void Material::saveModels(QTextStream& stream) const
|
||||
{
|
||||
if (!_physical.empty()) {
|
||||
ModelManager modelManager;
|
||||
|
||||
stream << "Models:\n";
|
||||
for (auto itm = _physicalUuids.begin(); itm != _physicalUuids.end(); itm++) {
|
||||
auto model = modelManager.getModel(*itm);
|
||||
stream << " " << model.getName() << ":\n";
|
||||
stream << " UUID: \"" << model.getUUID() << "\"\n";
|
||||
for (auto itp = model.begin(); itp != model.end(); itp++) {
|
||||
QString propertyName = itp->first;
|
||||
const MaterialProperty& property = getPhysicalProperty(propertyName);
|
||||
|
||||
if (!property.isNull()) {
|
||||
stream << " " << propertyName << ": \""
|
||||
<< getPhysicalValueString(propertyName) << "\"\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Material::saveAppearanceModels(QTextStream& stream) const
|
||||
{
|
||||
if (!_appearance.empty()) {
|
||||
ModelManager modelManager;
|
||||
|
||||
stream << "AppearanceModels:\n";
|
||||
for (auto itm = _appearanceUuids.begin(); itm != _appearanceUuids.end(); itm++) {
|
||||
auto model = modelManager.getModel(*itm);
|
||||
stream << " " << model.getName() << ":\n";
|
||||
stream << " UUID: \"" << model.getUUID() << "\"\n";
|
||||
for (auto itp = model.begin(); itp != model.end(); itp++) {
|
||||
QString propertyName = itp->first;
|
||||
const MaterialProperty& property = getAppearanceProperty(propertyName);
|
||||
|
||||
if (!property.isNull()) {
|
||||
stream << " " << propertyName << ": \""
|
||||
<< getAppearanceValueString(propertyName) << "\"\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Material::newUuid()
|
||||
{
|
||||
_uuid = QUuid::createUuid().toString(QUuid::WithoutBraces);
|
||||
}
|
||||
|
||||
void Material::save(QTextStream& stream, bool saveAsCopy)
|
||||
{
|
||||
Q_UNUSED(saveAsCopy)
|
||||
|
||||
stream << "# File created by FreeCAD\n";
|
||||
saveGeneral(stream);
|
||||
saveInherits(stream);
|
||||
saveModels(stream);
|
||||
saveAppearanceModels(stream);
|
||||
}
|
||||
|
||||
Material& Material::operator=(const Material& other)
|
||||
{
|
||||
if (this == &other) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
_library = other._library;
|
||||
_directory = other._directory;
|
||||
_uuid = other._uuid;
|
||||
_name = other._name;
|
||||
_authorAndLicense = other._authorAndLicense;
|
||||
_parentUuid = other._parentUuid;
|
||||
_description = other._description;
|
||||
_url = other._url;
|
||||
_reference = other._reference;
|
||||
_dereferenced = other._dereferenced;
|
||||
|
||||
_tags.clear();
|
||||
for (auto it = other._tags.begin(); it != other._tags.end(); it++) {
|
||||
_tags.push_back(*it);
|
||||
}
|
||||
_physicalUuids.clear();
|
||||
for (auto it = other._physicalUuids.begin(); it != other._physicalUuids.end(); it++) {
|
||||
_physicalUuids.push_back(*it);
|
||||
}
|
||||
_appearanceUuids.clear();
|
||||
for (auto it = other._appearanceUuids.begin(); it != other._appearanceUuids.end(); it++) {
|
||||
_appearanceUuids.push_back(*it);
|
||||
}
|
||||
_allUuids.clear();
|
||||
for (auto it = other._allUuids.begin(); it != other._allUuids.end(); it++) {
|
||||
_allUuids.push_back(*it);
|
||||
}
|
||||
_physical.clear();
|
||||
for (auto it = other._physical.begin(); it != other._physical.end(); it++) {
|
||||
_physical[it->first] = MaterialProperty(it->second);
|
||||
}
|
||||
_appearance.clear();
|
||||
for (auto it = other._appearance.begin(); it != other._appearance.end(); it++) {
|
||||
_appearance[it->first] = MaterialProperty(it->second);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
337
src/Mod/Material/App/Materials.h
Normal file
337
src/Mod/Material/App/Materials.h
Normal file
@@ -0,0 +1,337 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
|
||||
* *
|
||||
* 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 *
|
||||
* <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef MATERIAL_MATERIALS_H
|
||||
#define MATERIAL_MATERIALS_H
|
||||
|
||||
#include <Mod/Material/MaterialGlobal.h>
|
||||
|
||||
#include <Base/BaseClass.h>
|
||||
#include <QDir>
|
||||
#include <QString>
|
||||
#include <QTextStream>
|
||||
|
||||
#include <App/Application.h>
|
||||
|
||||
#include "MaterialLibrary.h"
|
||||
#include "Model.h"
|
||||
|
||||
namespace fs = boost::filesystem;
|
||||
|
||||
namespace Materials
|
||||
{
|
||||
|
||||
class MaterialsExport MaterialProperty: public ModelProperty
|
||||
{
|
||||
TYPESYSTEM_HEADER_WITH_OVERRIDE();
|
||||
|
||||
public:
|
||||
MaterialProperty();
|
||||
explicit MaterialProperty(const ModelProperty& property);
|
||||
explicit MaterialProperty(const MaterialProperty& property);
|
||||
~MaterialProperty() override = default;
|
||||
|
||||
MaterialValue::ValueType getType() const
|
||||
{
|
||||
return _valuePtr->getType();
|
||||
}
|
||||
|
||||
const QString getModelUUID() const;
|
||||
const QVariant getValue() const;
|
||||
bool isNull() const
|
||||
{
|
||||
return _valuePtr->isNull();
|
||||
}
|
||||
std::shared_ptr<MaterialValue> getMaterialValue();
|
||||
const std::shared_ptr<MaterialValue> getMaterialValue() const;
|
||||
const QString getString() const;
|
||||
bool getBoolean() const;
|
||||
int getInt() const;
|
||||
double getFloat() const;
|
||||
const Base::Quantity& getQuantity() const;
|
||||
const QString getURL() const;
|
||||
|
||||
MaterialProperty& getColumn(int column);
|
||||
const MaterialProperty& getColumn(int column) const;
|
||||
MaterialValue::ValueType getColumnType(int column) const;
|
||||
QString getColumnUnits(int column) const;
|
||||
QVariant getColumnNull(int column) const;
|
||||
|
||||
void setModelUUID(const QString& uuid);
|
||||
void setPropertyType(const QString& type) override;
|
||||
void setValue(const QVariant& value);
|
||||
void setValue(const QString& value);
|
||||
void setString(const QString& value);
|
||||
void setBoolean(bool value);
|
||||
void setBoolean(int value);
|
||||
void setBoolean(const QString& value);
|
||||
void setInt(int value);
|
||||
void setInt(const QString& value);
|
||||
void setFloat(double value);
|
||||
void setFloat(const QString& value);
|
||||
void setQuantity(const Base::Quantity& value);
|
||||
void setQuantity(double value, const QString& units);
|
||||
void setQuantity(const QString& value);
|
||||
void setURL(const QString& value);
|
||||
|
||||
MaterialProperty& operator=(const MaterialProperty& other);
|
||||
|
||||
protected:
|
||||
void setType(const QString& type);
|
||||
// void setType(MaterialValue::ValueType type) { _valueType = type; }
|
||||
|
||||
void addColumn(MaterialProperty& column)
|
||||
{
|
||||
_columns.push_back(column);
|
||||
}
|
||||
|
||||
private:
|
||||
QString _modelUUID;
|
||||
std::shared_ptr<MaterialValue> _valuePtr;
|
||||
std::vector<MaterialProperty> _columns;
|
||||
};
|
||||
|
||||
class MaterialsExport Material: public Base::BaseClass
|
||||
{
|
||||
TYPESYSTEM_HEADER();
|
||||
|
||||
public:
|
||||
enum ModelEdit
|
||||
{
|
||||
ModelEdit_None, // No change
|
||||
ModelEdit_Alter, // Existing values are changed
|
||||
ModelEdit_Extend // New values added
|
||||
};
|
||||
|
||||
Material();
|
||||
explicit Material(const MaterialLibrary& library,
|
||||
const QString& directory,
|
||||
const QString& uuid,
|
||||
const QString& name);
|
||||
explicit Material(const Material& other);
|
||||
virtual ~Material();
|
||||
|
||||
const MaterialLibrary& getLibrary() const
|
||||
{
|
||||
return _library;
|
||||
}
|
||||
const QString getDirectory() const
|
||||
{
|
||||
return _directory;
|
||||
}
|
||||
const QString getUUID() const
|
||||
{
|
||||
return _uuid;
|
||||
}
|
||||
const QString getName() const
|
||||
{
|
||||
return _name;
|
||||
}
|
||||
const QString getAuthorAndLicense() const
|
||||
{
|
||||
return _authorAndLicense;
|
||||
}
|
||||
const QString getParentUUID() const
|
||||
{
|
||||
return _parentUuid;
|
||||
}
|
||||
const QString getDescription() const
|
||||
{
|
||||
return _description;
|
||||
}
|
||||
const QString getURL() const
|
||||
{
|
||||
return _url;
|
||||
}
|
||||
const QString getReference() const
|
||||
{
|
||||
return _reference;
|
||||
}
|
||||
ModelEdit getEditState() const
|
||||
{
|
||||
return _editState;
|
||||
}
|
||||
const std::list<QString>& getTags() const
|
||||
{
|
||||
return _tags;
|
||||
}
|
||||
const std::vector<QString>* getPhysicalModels() const
|
||||
{
|
||||
return &_physicalUuids;
|
||||
}
|
||||
const std::vector<QString>* getAppearanceModels() const
|
||||
{
|
||||
return &_appearanceUuids;
|
||||
}
|
||||
|
||||
void setLibrary(const MaterialLibrary& library)
|
||||
{
|
||||
_library = library;
|
||||
}
|
||||
void setDirectory(const QString& directory)
|
||||
{
|
||||
Base::Console().Log("Materials::setDirectory(%s)\n", directory.toStdString().c_str());
|
||||
_directory = directory;
|
||||
}
|
||||
void setUUID(const QString& uuid)
|
||||
{
|
||||
_uuid = uuid;
|
||||
}
|
||||
void setName(const QString& name)
|
||||
{
|
||||
_name = name;
|
||||
}
|
||||
void setAuthorAndLicense(const QString& authorAndLicense)
|
||||
{
|
||||
_authorAndLicense = authorAndLicense;
|
||||
}
|
||||
void setParentUUID(const QString& uuid)
|
||||
{
|
||||
_parentUuid = uuid;
|
||||
}
|
||||
void setDescription(const QString& description)
|
||||
{
|
||||
_description = description;
|
||||
}
|
||||
void setURL(const QString& url)
|
||||
{
|
||||
_url = url;
|
||||
}
|
||||
void setReference(const QString& reference)
|
||||
{
|
||||
_reference = reference;
|
||||
}
|
||||
void setEditState(ModelEdit newState);
|
||||
void setEditStateAlter()
|
||||
{
|
||||
setEditState(ModelEdit_Alter);
|
||||
}
|
||||
void setEditStateExtend()
|
||||
{
|
||||
setEditState(ModelEdit_Extend);
|
||||
}
|
||||
void setPhysicalEditState(const QString& name);
|
||||
void setAppearanceEditState(const QString& name);
|
||||
void resetEditState()
|
||||
{
|
||||
_editState = ModelEdit_None;
|
||||
}
|
||||
void addTag(const QString& tag)
|
||||
{
|
||||
Q_UNUSED(tag);
|
||||
}
|
||||
void removeTag(const QString& tag)
|
||||
{
|
||||
Q_UNUSED(tag);
|
||||
}
|
||||
void addPhysical(const QString& uuid);
|
||||
void addAppearance(const QString& uuid);
|
||||
void newUuid();
|
||||
|
||||
void setPhysicalValue(const QString& name, const QString& value);
|
||||
void setPhysicalValue(const QString& name, int value);
|
||||
void setPhysicalValue(const QString& name, double value);
|
||||
void setPhysicalValue(const QString& name, const Base::Quantity value);
|
||||
|
||||
void setAppearanceValue(const QString& name, const QString& value);
|
||||
|
||||
MaterialProperty& getPhysicalProperty(const QString& name);
|
||||
const MaterialProperty& getPhysicalProperty(const QString& name) const;
|
||||
MaterialProperty& getAppearanceProperty(const QString& name);
|
||||
const MaterialProperty& getAppearanceProperty(const QString& name) const;
|
||||
const QVariant getPhysicalValue(const QString& name) const;
|
||||
const QString getPhysicalValueString(const QString& name) const;
|
||||
const QVariant getAppearanceValue(const QString& name) const;
|
||||
const QString getAppearanceValueString(const QString& name) const;
|
||||
bool hasPhysicalProperty(const QString& name) const;
|
||||
bool hasAppearanceProperty(const QString& name) const;
|
||||
|
||||
// Test if the model is defined, and if values are provided for all properties
|
||||
bool hasModel(const QString& uuid) const;
|
||||
bool hasPhysicalModel(const QString& uuid) const;
|
||||
bool hasAppearanceModel(const QString& uuid) const;
|
||||
bool isModelComplete(const QString& uuid) const
|
||||
{
|
||||
return isPhysicalModelComplete(uuid) || isAppearanceModelComplete(uuid);
|
||||
}
|
||||
bool isPhysicalModelComplete(const QString& uuid) const;
|
||||
bool isAppearanceModelComplete(const QString& uuid) const;
|
||||
|
||||
const std::map<QString, MaterialProperty>& getPhysicalProperties() const
|
||||
{
|
||||
return _physical;
|
||||
}
|
||||
const std::map<QString, MaterialProperty>& getAppearanceProperties() const
|
||||
{
|
||||
return _appearance;
|
||||
}
|
||||
|
||||
bool getDereferenced() const
|
||||
{
|
||||
return _dereferenced;
|
||||
}
|
||||
void markDereferenced()
|
||||
{
|
||||
_dereferenced = true;
|
||||
}
|
||||
|
||||
void save(QTextStream& stream, bool saveAsCopy);
|
||||
|
||||
Material& operator=(const Material& other);
|
||||
|
||||
protected:
|
||||
void addModel(const QString& uuid);
|
||||
|
||||
const QVariant getValue(const std::map<QString, MaterialProperty>& propertyList,
|
||||
const QString& name) const;
|
||||
const QString getValueString(const std::map<QString, MaterialProperty>& propertyList,
|
||||
const QString& name) const;
|
||||
|
||||
void saveGeneral(QTextStream& stream) const;
|
||||
void saveInherits(QTextStream& stream) const;
|
||||
void saveModels(QTextStream& stream) const;
|
||||
void saveAppearanceModels(QTextStream& stream) const;
|
||||
|
||||
private:
|
||||
MaterialLibrary _library;
|
||||
QString _directory;
|
||||
QString _uuid;
|
||||
QString _name;
|
||||
QString _authorAndLicense;
|
||||
QString _parentUuid;
|
||||
QString _description;
|
||||
QString _url;
|
||||
QString _reference;
|
||||
std::list<QString> _tags;
|
||||
std::vector<QString> _physicalUuids;
|
||||
std::vector<QString> _appearanceUuids;
|
||||
std::vector<QString> _allUuids; // Includes inherited models
|
||||
std::map<QString, MaterialProperty> _physical;
|
||||
std::map<QString, MaterialProperty> _appearance;
|
||||
bool _dereferenced;
|
||||
ModelEdit _editState;
|
||||
};
|
||||
|
||||
} // namespace Materials
|
||||
|
||||
Q_DECLARE_METATYPE(Materials::Material*)
|
||||
|
||||
#endif // MATERIAL_MATERIALS_H
|
||||
115
src/Mod/Material/App/Model.cpp
Normal file
115
src/Mod/Material/App/Model.cpp
Normal file
@@ -0,0 +1,115 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
|
||||
* *
|
||||
* 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 *
|
||||
* <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
**************************************************************************/
|
||||
|
||||
#include "PreCompiled.h"
|
||||
#ifndef _PreComp_
|
||||
#endif
|
||||
|
||||
#include "Exceptions.h"
|
||||
#include "Model.h"
|
||||
#include "ModelLibrary.h"
|
||||
#include <string>
|
||||
|
||||
|
||||
using namespace Materials;
|
||||
|
||||
TYPESYSTEM_SOURCE(Materials::ModelProperty, Base::BaseClass)
|
||||
|
||||
ModelProperty::ModelProperty()
|
||||
{}
|
||||
|
||||
ModelProperty::ModelProperty(const QString& name,
|
||||
const QString& type,
|
||||
const QString& units,
|
||||
const QString& url,
|
||||
const QString& description)
|
||||
: _name(name)
|
||||
, _propertyType(type)
|
||||
, _units(units)
|
||||
, _url(url)
|
||||
, _description(description)
|
||||
{}
|
||||
|
||||
ModelProperty::ModelProperty(const ModelProperty& other)
|
||||
: _name(other._name)
|
||||
, _propertyType(other._propertyType)
|
||||
, _units(other._units)
|
||||
, _url(other._url)
|
||||
, _description(other._description)
|
||||
, _inheritance(other._inheritance)
|
||||
{
|
||||
for (auto it = other._columns.begin(); it != other._columns.end(); it++) {
|
||||
_columns.push_back(*it);
|
||||
}
|
||||
}
|
||||
|
||||
ModelProperty& ModelProperty::operator=(const ModelProperty& other)
|
||||
{
|
||||
if (this == &other) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
_name = other._name;
|
||||
_propertyType = other._propertyType;
|
||||
_units = other._units;
|
||||
_url = other._url;
|
||||
_description = other._description;
|
||||
_inheritance = other._inheritance;
|
||||
_columns.clear();
|
||||
for (auto it = other._columns.begin(); it != other._columns.end(); it++) {
|
||||
_columns.push_back(*it);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
TYPESYSTEM_SOURCE(Materials::Model, Base::BaseClass)
|
||||
|
||||
Model::Model()
|
||||
{}
|
||||
|
||||
Model::Model(const ModelLibrary& library,
|
||||
ModelType type,
|
||||
const QString& name,
|
||||
const QString& directory,
|
||||
const QString& uuid,
|
||||
const QString& description,
|
||||
const QString& url,
|
||||
const QString& doi)
|
||||
: _library(library)
|
||||
, _type(type)
|
||||
, _name(name)
|
||||
, _directory(directory)
|
||||
, _uuid(uuid)
|
||||
, _description(description)
|
||||
, _url(url)
|
||||
, _doi(doi)
|
||||
{}
|
||||
|
||||
ModelProperty& Model::operator[](const QString& key)
|
||||
{
|
||||
try {
|
||||
return _properties.at(key);
|
||||
}
|
||||
catch (std::out_of_range const&) {
|
||||
throw PropertyNotFound();
|
||||
}
|
||||
}
|
||||
298
src/Mod/Material/App/Model.h
Normal file
298
src/Mod/Material/App/Model.h
Normal file
@@ -0,0 +1,298 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
|
||||
* *
|
||||
* 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 *
|
||||
* <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef MATERIAL_MODEL_H
|
||||
#define MATERIAL_MODEL_H
|
||||
|
||||
#include <Mod/Material/MaterialGlobal.h>
|
||||
|
||||
#include <Base/BaseClass.h>
|
||||
#include <Base/Quantity.h>
|
||||
#include <QDir>
|
||||
#include <QString>
|
||||
|
||||
#include "MaterialValue.h"
|
||||
#include "ModelLibrary.h"
|
||||
|
||||
namespace Materials
|
||||
{
|
||||
|
||||
class MaterialsExport ModelProperty: public Base::BaseClass
|
||||
{
|
||||
TYPESYSTEM_HEADER();
|
||||
|
||||
public:
|
||||
ModelProperty();
|
||||
explicit ModelProperty(const QString& name,
|
||||
const QString& type,
|
||||
const QString& units,
|
||||
const QString& url,
|
||||
const QString& description);
|
||||
explicit ModelProperty(const ModelProperty& other);
|
||||
~ModelProperty() override = default;
|
||||
|
||||
const QString getName() const
|
||||
{
|
||||
return _name;
|
||||
}
|
||||
const QString getPropertyType() const
|
||||
{
|
||||
return _propertyType;
|
||||
}
|
||||
const QString getUnits() const
|
||||
{
|
||||
return _units;
|
||||
}
|
||||
const QString getURL() const
|
||||
{
|
||||
return _url;
|
||||
}
|
||||
const QString getDescription() const
|
||||
{
|
||||
return _description;
|
||||
}
|
||||
const QString getInheritance() const
|
||||
{
|
||||
return _inheritance;
|
||||
}
|
||||
bool isInherited() const
|
||||
{
|
||||
return (_inheritance.length() > 0);
|
||||
}
|
||||
|
||||
void setName(const QString& name)
|
||||
{
|
||||
_name = name;
|
||||
}
|
||||
virtual void setPropertyType(const QString& type)
|
||||
{
|
||||
_propertyType = type;
|
||||
}
|
||||
void setUnits(const QString& units)
|
||||
{
|
||||
_units = units;
|
||||
}
|
||||
void setURL(const QString& url)
|
||||
{
|
||||
_url = url;
|
||||
}
|
||||
void setDescription(const QString& description)
|
||||
{
|
||||
_description = description;
|
||||
}
|
||||
void setInheritance(const QString& uuid)
|
||||
{
|
||||
_inheritance = uuid;
|
||||
}
|
||||
|
||||
void addColumn(ModelProperty& column)
|
||||
{
|
||||
_columns.push_back(column);
|
||||
}
|
||||
const std::vector<ModelProperty>& getColumns() const
|
||||
{
|
||||
return _columns;
|
||||
}
|
||||
int columns() const
|
||||
{
|
||||
return _columns.size();
|
||||
}
|
||||
|
||||
ModelProperty& operator=(const ModelProperty& other);
|
||||
|
||||
private:
|
||||
QString _name;
|
||||
QString _propertyType;
|
||||
QString _units;
|
||||
QString _url;
|
||||
QString _description;
|
||||
QString _inheritance;
|
||||
std::vector<ModelProperty> _columns;
|
||||
};
|
||||
|
||||
class MaterialsExport Model: public Base::BaseClass
|
||||
{
|
||||
TYPESYSTEM_HEADER();
|
||||
|
||||
public:
|
||||
enum ModelType
|
||||
{
|
||||
ModelType_Physical,
|
||||
ModelType_Appearance
|
||||
};
|
||||
|
||||
Model();
|
||||
explicit Model(const ModelLibrary& library,
|
||||
ModelType type,
|
||||
const QString& name,
|
||||
const QString& directory,
|
||||
const QString& uuid,
|
||||
const QString& description,
|
||||
const QString& url,
|
||||
const QString& doi);
|
||||
~Model() override = default;
|
||||
|
||||
const ModelLibrary& getLibrary() const
|
||||
{
|
||||
return _library;
|
||||
}
|
||||
const QString getBase() const
|
||||
{
|
||||
return (_type == ModelType_Physical) ? QString::fromStdString("Model")
|
||||
: QString::fromStdString("AppearanceModel");
|
||||
}
|
||||
const QString getName() const
|
||||
{
|
||||
return _name;
|
||||
}
|
||||
ModelType getType() const
|
||||
{
|
||||
return _type;
|
||||
}
|
||||
const QString getDirectory() const
|
||||
{
|
||||
return _directory;
|
||||
}
|
||||
const QString getDirectoryPath() const
|
||||
{
|
||||
return QDir(_directory).absolutePath();
|
||||
}
|
||||
const QString getRelativePath() const
|
||||
{
|
||||
return QDir(_directory).relativeFilePath(QDir(_directory).absolutePath());
|
||||
}
|
||||
const QString getUUID() const
|
||||
{
|
||||
return _uuid;
|
||||
}
|
||||
const QString getDescription() const
|
||||
{
|
||||
return _description;
|
||||
}
|
||||
const QString getURL() const
|
||||
{
|
||||
return _url;
|
||||
}
|
||||
const QString getDOI() const
|
||||
{
|
||||
return _doi;
|
||||
}
|
||||
|
||||
void setLibrary(const ModelLibrary& library)
|
||||
{
|
||||
_library = library;
|
||||
}
|
||||
void setType(ModelType type)
|
||||
{
|
||||
_type = type;
|
||||
}
|
||||
void setName(const QString& name)
|
||||
{
|
||||
_name = name;
|
||||
}
|
||||
void setDirectory(const QString& directory)
|
||||
{
|
||||
_directory = directory;
|
||||
}
|
||||
void setUUID(const QString& uuid)
|
||||
{
|
||||
_uuid = uuid;
|
||||
}
|
||||
void setDescription(const QString& description)
|
||||
{
|
||||
_description = description;
|
||||
}
|
||||
void setURL(const QString& url)
|
||||
{
|
||||
_url = url;
|
||||
}
|
||||
void setDOI(const QString& doi)
|
||||
{
|
||||
_doi = doi;
|
||||
}
|
||||
|
||||
void addInheritance(const QString& uuid)
|
||||
{
|
||||
_inheritedUuids.push_back(uuid);
|
||||
}
|
||||
const std::vector<QString>& getInheritance() const
|
||||
{
|
||||
return _inheritedUuids;
|
||||
}
|
||||
|
||||
bool operator==(const Model& m) const
|
||||
{
|
||||
return _uuid == m._uuid;
|
||||
}
|
||||
bool operator!=(const Model& m) const
|
||||
{
|
||||
return !operator==(m);
|
||||
}
|
||||
|
||||
ModelProperty& operator[](const QString& key);
|
||||
void addProperty(ModelProperty& property)
|
||||
{
|
||||
_properties[property.getName()] = property;
|
||||
}
|
||||
|
||||
using iterator = typename std::map<QString, ModelProperty>::iterator;
|
||||
using const_iterator = typename std::map<QString, ModelProperty>::const_iterator;
|
||||
iterator begin()
|
||||
{
|
||||
return _properties.begin();
|
||||
}
|
||||
const_iterator begin() const noexcept
|
||||
{
|
||||
return _properties.begin();
|
||||
}
|
||||
iterator end() noexcept
|
||||
{
|
||||
return _properties.end();
|
||||
}
|
||||
const_iterator end() const noexcept
|
||||
{
|
||||
return _properties.end();
|
||||
}
|
||||
const_iterator cbegin() const noexcept
|
||||
{
|
||||
return _properties.cbegin();
|
||||
}
|
||||
const_iterator cend() const noexcept
|
||||
{
|
||||
return _properties.cend();
|
||||
}
|
||||
|
||||
private:
|
||||
ModelLibrary _library;
|
||||
ModelType _type;
|
||||
QString _name;
|
||||
QString _directory;
|
||||
QString _uuid;
|
||||
QString _description;
|
||||
QString _url;
|
||||
QString _doi;
|
||||
std::vector<QString> _inheritedUuids;
|
||||
std::map<QString, ModelProperty> _properties;
|
||||
};
|
||||
|
||||
} // namespace Materials
|
||||
|
||||
#endif // MATERIAL_MODEL_H
|
||||
113
src/Mod/Material/App/ModelLibrary.cpp
Normal file
113
src/Mod/Material/App/ModelLibrary.cpp
Normal file
@@ -0,0 +1,113 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
|
||||
* *
|
||||
* 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 *
|
||||
* <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
**************************************************************************/
|
||||
|
||||
#include "PreCompiled.h"
|
||||
#ifndef _PreComp_
|
||||
#endif
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <App/Application.h>
|
||||
|
||||
#include "Exceptions.h"
|
||||
#include "Model.h"
|
||||
#include "ModelLibrary.h"
|
||||
|
||||
|
||||
using namespace Materials;
|
||||
|
||||
TYPESYSTEM_SOURCE(Materials::LibraryBase, Base::BaseClass)
|
||||
|
||||
LibraryBase::LibraryBase(const QString& libraryName, const QString& dir, const QString& icon)
|
||||
: _name(libraryName)
|
||||
, _directory(QDir::cleanPath(dir))
|
||||
, _iconPath(icon)
|
||||
{}
|
||||
|
||||
LibraryBase::LibraryBase()
|
||||
{}
|
||||
|
||||
bool LibraryBase::operator==(const LibraryBase& library) const
|
||||
{
|
||||
return (_name == library._name) && (_directory == library._directory);
|
||||
}
|
||||
|
||||
QString LibraryBase::getLocalPath(const QString& path) const
|
||||
{
|
||||
QString filePath = getDirectoryPath();
|
||||
QString cleanPath = QDir::cleanPath(path);
|
||||
QString prefix = QString::fromStdString("/") + getName();
|
||||
if (cleanPath.startsWith(prefix)) {
|
||||
// Remove the library name from the path
|
||||
filePath += cleanPath.right(cleanPath.length() - prefix.length());
|
||||
}
|
||||
else {
|
||||
filePath += cleanPath;
|
||||
}
|
||||
|
||||
return filePath;
|
||||
}
|
||||
|
||||
QString LibraryBase::getRelativePath(const QString& path) const
|
||||
{
|
||||
QString filePath;
|
||||
QString cleanPath = QDir::cleanPath(path);
|
||||
QString prefix = QString::fromStdString("/") + getName();
|
||||
if (cleanPath.startsWith(prefix)) {
|
||||
// Remove the library name from the path
|
||||
filePath = cleanPath.right(cleanPath.length() - prefix.length());
|
||||
}
|
||||
else {
|
||||
filePath = cleanPath;
|
||||
}
|
||||
|
||||
prefix = getDirectoryPath();
|
||||
if (filePath.startsWith(prefix)) {
|
||||
// Remove the library root from the path
|
||||
filePath = filePath.right(filePath.length() - prefix.length());
|
||||
}
|
||||
|
||||
// Remove any leading '/'
|
||||
if (filePath.startsWith(QString::fromStdString("/"))) {
|
||||
filePath.remove(0, 1);
|
||||
}
|
||||
|
||||
return filePath;
|
||||
}
|
||||
|
||||
TYPESYSTEM_SOURCE(Materials::ModelLibrary, LibraryBase)
|
||||
|
||||
ModelLibrary::ModelLibrary(const QString& libraryName, const QString& dir, const QString& icon)
|
||||
: LibraryBase(libraryName, dir, icon)
|
||||
{}
|
||||
|
||||
ModelLibrary::ModelLibrary()
|
||||
{}
|
||||
|
||||
Model* ModelLibrary::addModel(const Model& model, const QString& path)
|
||||
{
|
||||
QString filePath = getRelativePath(path);
|
||||
Model* newModel = new Model(model);
|
||||
newModel->setLibrary(*this);
|
||||
newModel->setDirectory(filePath);
|
||||
|
||||
return newModel;
|
||||
}
|
||||
101
src/Mod/Material/App/ModelLibrary.h
Normal file
101
src/Mod/Material/App/ModelLibrary.h
Normal file
@@ -0,0 +1,101 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
|
||||
* *
|
||||
* 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 *
|
||||
* <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef MATERIAL_MODELLIBRARY_H
|
||||
#define MATERIAL_MODELLIBRARY_H
|
||||
|
||||
#include <Mod/Material/MaterialGlobal.h>
|
||||
|
||||
#include <Base/BaseClass.h>
|
||||
#include <Base/Quantity.h>
|
||||
#include <QDir>
|
||||
#include <QString>
|
||||
|
||||
#include "MaterialValue.h"
|
||||
|
||||
namespace Materials
|
||||
{
|
||||
|
||||
class Model;
|
||||
|
||||
class MaterialsExport LibraryBase: public Base::BaseClass
|
||||
{
|
||||
TYPESYSTEM_HEADER();
|
||||
|
||||
public:
|
||||
LibraryBase();
|
||||
explicit LibraryBase(const QString& libraryName, const QString& dir, const QString& icon);
|
||||
~LibraryBase() override = default;
|
||||
|
||||
const QString getName() const
|
||||
{
|
||||
return _name;
|
||||
}
|
||||
const QString getDirectory() const
|
||||
{
|
||||
return _directory;
|
||||
}
|
||||
const QString getDirectoryPath() const
|
||||
{
|
||||
return QDir(_directory).absolutePath();
|
||||
}
|
||||
const QString getIconPath() const
|
||||
{
|
||||
return _iconPath;
|
||||
}
|
||||
bool operator==(const LibraryBase& library) const;
|
||||
bool operator!=(const LibraryBase& library) const
|
||||
{
|
||||
return !operator==(library);
|
||||
}
|
||||
QString getLocalPath(const QString& path) const;
|
||||
QString getRelativePath(const QString& path) const;
|
||||
|
||||
private:
|
||||
QString _name;
|
||||
QString _directory;
|
||||
QString _iconPath;
|
||||
};
|
||||
|
||||
class MaterialsExport ModelLibrary: public LibraryBase
|
||||
{
|
||||
TYPESYSTEM_HEADER();
|
||||
|
||||
public:
|
||||
ModelLibrary();
|
||||
explicit ModelLibrary(const QString& libraryName, const QString& dir, const QString& icon);
|
||||
~ModelLibrary() override = default;
|
||||
|
||||
bool operator==(const ModelLibrary& library) const
|
||||
{
|
||||
return LibraryBase::operator==(library);
|
||||
}
|
||||
bool operator!=(const ModelLibrary& library) const
|
||||
{
|
||||
return !operator==(library);
|
||||
}
|
||||
|
||||
Model* addModel(const Model& model, const QString& path);
|
||||
};
|
||||
|
||||
} // namespace Materials
|
||||
|
||||
#endif // MATERIAL_MODELLIBRARY_H
|
||||
417
src/Mod/Material/App/ModelLoader.cpp
Normal file
417
src/Mod/Material/App/ModelLoader.cpp
Normal file
@@ -0,0 +1,417 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
|
||||
* *
|
||||
* 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 *
|
||||
* <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
**************************************************************************/
|
||||
|
||||
#include "PreCompiled.h"
|
||||
#ifndef _PreComp_
|
||||
#include <QString>
|
||||
#endif
|
||||
|
||||
#include <App/Application.h>
|
||||
#include <Base/Interpreter.h>
|
||||
|
||||
#include <QDirIterator>
|
||||
#include <QFileInfo>
|
||||
|
||||
#include "Model.h"
|
||||
#include "ModelLoader.h"
|
||||
#include "ModelManager.h"
|
||||
|
||||
|
||||
using namespace Materials;
|
||||
|
||||
ModelEntry::ModelEntry(const ModelLibrary& library,
|
||||
const QString& baseName,
|
||||
const QString& modelName,
|
||||
const QString& dir,
|
||||
const QString& modelUuid,
|
||||
const YAML::Node& modelData)
|
||||
: _library(library)
|
||||
, _base(baseName)
|
||||
, _name(modelName)
|
||||
, _directory(dir)
|
||||
, _uuid(modelUuid)
|
||||
, _model(modelData)
|
||||
, _dereferenced(false)
|
||||
{}
|
||||
|
||||
std::unique_ptr<std::map<QString, ModelEntry*>> ModelLoader::_modelEntryMap = nullptr;
|
||||
|
||||
ModelLoader::ModelLoader(std::shared_ptr<std::map<QString, Model*>> modelMap,
|
||||
std::shared_ptr<std::list<ModelLibrary*>> libraryList)
|
||||
: _modelMap(modelMap)
|
||||
, _libraryList(libraryList)
|
||||
{
|
||||
loadLibraries();
|
||||
}
|
||||
|
||||
void ModelLoader::addLibrary(ModelLibrary* model)
|
||||
{
|
||||
_libraryList->push_back(model);
|
||||
}
|
||||
|
||||
const QString ModelLoader::getUUIDFromPath(const QString& path)
|
||||
{
|
||||
QFile file(path);
|
||||
if (!file.exists()) {
|
||||
throw ModelNotFound();
|
||||
}
|
||||
|
||||
try {
|
||||
YAML::Node yamlroot = YAML::LoadFile(path.toStdString());
|
||||
std::string base = "Model";
|
||||
if (yamlroot["AppearanceModel"]) {
|
||||
base = "AppearanceModel";
|
||||
}
|
||||
|
||||
const QString uuid = QString::fromStdString(yamlroot[base]["UUID"].as<std::string>());
|
||||
return uuid;
|
||||
}
|
||||
catch (YAML::Exception& ex) {
|
||||
throw ModelNotFound();
|
||||
}
|
||||
}
|
||||
|
||||
ModelEntry* ModelLoader::getModelFromPath(const ModelLibrary& library, const QString& path) const
|
||||
{
|
||||
QFile file(path);
|
||||
if (!file.exists()) {
|
||||
throw ModelNotFound();
|
||||
}
|
||||
|
||||
YAML::Node yamlroot;
|
||||
std::string base = "Model";
|
||||
std::string uuid;
|
||||
std::string name;
|
||||
try {
|
||||
yamlroot = YAML::LoadFile(path.toStdString());
|
||||
if (yamlroot["AppearanceModel"]) {
|
||||
base = "AppearanceModel";
|
||||
}
|
||||
|
||||
uuid = yamlroot[base]["UUID"].as<std::string>();
|
||||
name = yamlroot[base]["Name"].as<std::string>();
|
||||
}
|
||||
catch (YAML::Exception const&) {
|
||||
throw InvalidModel();
|
||||
}
|
||||
|
||||
ModelEntry* model = new ModelEntry(library,
|
||||
QString::fromStdString(base),
|
||||
QString::fromStdString(name),
|
||||
path,
|
||||
QString::fromStdString(uuid),
|
||||
yamlroot);
|
||||
|
||||
return model;
|
||||
}
|
||||
|
||||
void ModelLoader::showYaml(const YAML::Node& yaml) const
|
||||
{
|
||||
std::stringstream out;
|
||||
|
||||
out << yaml;
|
||||
std::string logData = out.str();
|
||||
Base::Console().Log("%s\n", logData.c_str());
|
||||
}
|
||||
|
||||
void ModelLoader::dereference(const QString& uuid,
|
||||
ModelEntry* parent,
|
||||
const ModelEntry* child,
|
||||
std::map<std::pair<QString, QString>, QString>* inheritances)
|
||||
{
|
||||
auto parentPtr = parent->getModelPtr();
|
||||
auto parentBase = parent->getBase().toStdString();
|
||||
auto childYaml = child->getModel();
|
||||
auto childBase = child->getBase().toStdString();
|
||||
|
||||
std::set<QString> exclude;
|
||||
exclude.insert(QString::fromStdString("Name"));
|
||||
exclude.insert(QString::fromStdString("UUID"));
|
||||
exclude.insert(QString::fromStdString("URL"));
|
||||
exclude.insert(QString::fromStdString("Description"));
|
||||
exclude.insert(QString::fromStdString("DOI"));
|
||||
exclude.insert(QString::fromStdString("Inherits"));
|
||||
|
||||
auto parentProperties = (*parentPtr)[parentBase];
|
||||
auto childProperties = childYaml[childBase];
|
||||
for (auto it = childProperties.begin(); it != childProperties.end(); it++) {
|
||||
std::string name = it->first.as<std::string>();
|
||||
if (exclude.count(QString::fromStdString(name)) == 0) {
|
||||
// showYaml(it->second);
|
||||
if (!parentProperties[name]) {
|
||||
parentProperties[name] = it->second;
|
||||
// parentProperties[name]["Inherits"] = childYaml[childBase]["UUID"];
|
||||
(*inheritances)[std::pair<QString, QString>(uuid, QString::fromStdString(name))] =
|
||||
yamlValue(childYaml[childBase], "UUID", "");
|
||||
}
|
||||
}
|
||||
}
|
||||
// showYaml(*parentPtr);
|
||||
}
|
||||
|
||||
|
||||
void ModelLoader::dereference(ModelEntry* model,
|
||||
std::map<std::pair<QString, QString>, QString>* inheritances)
|
||||
{
|
||||
// Avoid recursion
|
||||
if (model->getDereferenced()) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto yamlModel = model->getModel();
|
||||
auto base = model->getBase().toStdString();
|
||||
if (yamlModel[base]["Inherits"]) {
|
||||
auto inherits = yamlModel[base]["Inherits"];
|
||||
for (auto it = inherits.begin(); it != inherits.end(); it++) {
|
||||
QString nodeName = QString::fromStdString((*it)["UUID"].as<std::string>());
|
||||
|
||||
// This requires that all models have already been loaded undereferenced
|
||||
try {
|
||||
const ModelEntry* child = (*_modelEntryMap)[nodeName];
|
||||
dereference(model->getUUID(), model, child, inheritances);
|
||||
}
|
||||
catch (const std::out_of_range& oor) {
|
||||
Base::Console().Log("Unable to find '%s' in model map\n",
|
||||
nodeName.toStdString().c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
model->markDereferenced();
|
||||
}
|
||||
|
||||
QString ModelLoader::yamlValue(const YAML::Node& node,
|
||||
const std::string& key,
|
||||
const std::string& defaultValue)
|
||||
{
|
||||
if (node[key]) {
|
||||
return QString::fromStdString(node[key].as<std::string>());
|
||||
}
|
||||
return QString::fromStdString(defaultValue);
|
||||
}
|
||||
|
||||
void ModelLoader::addToTree(ModelEntry* model,
|
||||
std::map<std::pair<QString, QString>, QString>* inheritances)
|
||||
{
|
||||
std::set<QString> exclude;
|
||||
exclude.insert(QString::fromStdString("Name"));
|
||||
exclude.insert(QString::fromStdString("UUID"));
|
||||
exclude.insert(QString::fromStdString("URL"));
|
||||
exclude.insert(QString::fromStdString("Description"));
|
||||
exclude.insert(QString::fromStdString("DOI"));
|
||||
exclude.insert(QString::fromStdString("Inherits"));
|
||||
|
||||
auto yamlModel = model->getModel();
|
||||
auto library = model->getLibrary();
|
||||
auto base = model->getBase().toStdString();
|
||||
auto name = model->getName();
|
||||
auto directory = model->getDirectory();
|
||||
auto uuid = model->getUUID();
|
||||
|
||||
QString version = yamlValue(yamlModel["General"], "Version", "");
|
||||
|
||||
QString description = yamlValue(yamlModel[base], "Description", "");
|
||||
QString url = yamlValue(yamlModel[base], "URL", "");
|
||||
QString doi = yamlValue(yamlModel[base], "DOI", "");
|
||||
|
||||
Model::ModelType type =
|
||||
(base == "Model") ? Model::ModelType_Physical : Model::ModelType_Appearance;
|
||||
|
||||
Model* finalModel = new Model(library, type, name, directory, uuid, description, url, doi);
|
||||
|
||||
// Add inheritance list
|
||||
if (yamlModel[base]["Inherits"]) {
|
||||
auto inherits = yamlModel[base]["Inherits"];
|
||||
for (auto it = inherits.begin(); it != inherits.end(); it++) {
|
||||
QString nodeName = QString::fromStdString((*it)["UUID"].as<std::string>());
|
||||
|
||||
finalModel->addInheritance(nodeName);
|
||||
}
|
||||
}
|
||||
|
||||
// Add property list
|
||||
auto yamlProperties = yamlModel[base];
|
||||
for (auto it = yamlProperties.begin(); it != yamlProperties.end(); it++) {
|
||||
std::string propName = it->first.as<std::string>();
|
||||
if (exclude.count(QString::fromStdString(propName)) == 0) {
|
||||
// showYaml(it->second);
|
||||
auto yamlProp = yamlProperties[propName];
|
||||
auto propType = yamlValue(yamlProp, "Type", "");
|
||||
auto propUnits = yamlValue(yamlProp, "Units", "");
|
||||
auto propURL = yamlValue(yamlProp, "URL", "");
|
||||
auto propDescription = yamlValue(yamlProp, "Description", "");
|
||||
// auto inherits = yamlValue(yamlProp, "Inherits", "");
|
||||
|
||||
ModelProperty property(QString::fromStdString(propName),
|
||||
propType,
|
||||
propUnits,
|
||||
propURL,
|
||||
propDescription);
|
||||
|
||||
if (propType == QString::fromStdString("2DArray")
|
||||
|| propType == QString::fromStdString("3DArray")) {
|
||||
Base::Console().Log("Reading columns\n");
|
||||
// Read the columns
|
||||
auto cols = yamlProp["Columns"];
|
||||
for (auto col : cols) {
|
||||
std::string colName = col.first.as<std::string>();
|
||||
Base::Console().Log("\tColumns '%s'\n", colName.c_str());
|
||||
|
||||
auto colProp = cols[colName];
|
||||
auto colPropType = yamlValue(colProp, "Type", "");
|
||||
auto colPropUnits = yamlValue(colProp, "Units", "");
|
||||
auto colPropURL = yamlValue(colProp, "URL", "");
|
||||
auto colPropDescription = yamlValue(colProp, "Description", "");
|
||||
ModelProperty colProperty(QString::fromStdString(colName),
|
||||
colPropType,
|
||||
colPropUnits,
|
||||
colPropURL,
|
||||
colPropDescription);
|
||||
|
||||
property.addColumn(colProperty);
|
||||
}
|
||||
}
|
||||
|
||||
auto key = std::pair<QString, QString>(uuid, QString::fromStdString(propName));
|
||||
if (inheritances->count(key) > 0) {
|
||||
property.setInheritance((*inheritances)[key]);
|
||||
}
|
||||
|
||||
finalModel->addProperty(property);
|
||||
}
|
||||
}
|
||||
|
||||
(*_modelMap)[uuid] = library.addModel(*finalModel, directory);
|
||||
}
|
||||
|
||||
void ModelLoader::loadLibrary(const ModelLibrary& library)
|
||||
{
|
||||
if (_modelEntryMap == nullptr) {
|
||||
_modelEntryMap = std::make_unique<std::map<QString, ModelEntry*>>();
|
||||
}
|
||||
|
||||
QDirIterator it(library.getDirectory(), QDirIterator::Subdirectories);
|
||||
while (it.hasNext()) {
|
||||
auto pathname = it.next();
|
||||
QFileInfo file(pathname);
|
||||
if (file.isFile()) {
|
||||
if (file.suffix().toStdString() == "yml") {
|
||||
QString libraryName = file.baseName();
|
||||
|
||||
try {
|
||||
auto model = getModelFromPath(library, file.canonicalFilePath());
|
||||
(*_modelEntryMap)[model->getUUID()] = model;
|
||||
// showYaml(model->getModel());
|
||||
}
|
||||
catch (InvalidModel const&) {
|
||||
Base::Console().Log("Invalid model '%s'\n", pathname.toStdString().c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::map<std::pair<QString, QString>, QString>* inheritances =
|
||||
new std::map<std::pair<QString, QString>, QString>();
|
||||
for (auto it = _modelEntryMap->begin(); it != _modelEntryMap->end(); it++) {
|
||||
dereference(it->second, inheritances);
|
||||
}
|
||||
|
||||
for (auto it = _modelEntryMap->begin(); it != _modelEntryMap->end(); it++) {
|
||||
addToTree(it->second, inheritances);
|
||||
}
|
||||
// delete inheritances;
|
||||
}
|
||||
|
||||
void ModelLoader::loadLibraries()
|
||||
{
|
||||
getModelLibraries();
|
||||
if (_libraryList) {
|
||||
for (auto it = _libraryList->begin(); it != _libraryList->end(); it++) {
|
||||
loadLibrary(**it);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ModelLoader::getModelLibraries()
|
||||
{
|
||||
auto param = App::GetApplication().GetParameterGroupByPath(
|
||||
"User parameter:BaseApp/Preferences/Mod/Material/Resources");
|
||||
bool useBuiltInMaterials = param->GetBool("UseBuiltInMaterials", true);
|
||||
bool useMatFromModules = param->GetBool("UseMaterialsFromWorkbenches", true);
|
||||
bool useMatFromConfigDir = param->GetBool("UseMaterialsFromConfigDir", true);
|
||||
bool useMatFromCustomDir = param->GetBool("UseMaterialsFromCustomDir", true);
|
||||
|
||||
if (useBuiltInMaterials) {
|
||||
QString resourceDir = QString::fromStdString(App::Application::getResourceDir()
|
||||
+ "/Mod/Material/Resources/Models");
|
||||
auto libData = new ModelLibrary(QString::fromStdString("System"),
|
||||
resourceDir,
|
||||
QString::fromStdString(":/icons/freecad.svg"));
|
||||
_libraryList->push_back(libData);
|
||||
}
|
||||
|
||||
if (useMatFromModules) {
|
||||
auto moduleParam = App::GetApplication().GetParameterGroupByPath(
|
||||
"User parameter:BaseApp/Preferences/Mod/Material/Resources/Modules");
|
||||
for (auto& group : moduleParam->GetGroups()) {
|
||||
// auto module = moduleParam->GetGroup(group->GetGroupName());
|
||||
auto moduleName = QString::fromStdString(group->GetGroupName());
|
||||
auto modelDir = QString::fromStdString(group->GetASCII("ModuleModelDir", ""));
|
||||
auto modelIcon = QString::fromStdString(group->GetASCII("ModuleIcon", ""));
|
||||
|
||||
if (modelDir.length() > 0) {
|
||||
QDir dir(modelDir);
|
||||
if (dir.exists()) {
|
||||
auto libData = new ModelLibrary(moduleName, modelDir, modelIcon);
|
||||
_libraryList->push_back(libData);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (useMatFromConfigDir) {
|
||||
QString resourceDir =
|
||||
QString::fromStdString(App::Application::getUserAppDataDir() + "/Models");
|
||||
if (!resourceDir.isEmpty()) {
|
||||
QDir materialDir(resourceDir);
|
||||
if (materialDir.exists()) {
|
||||
auto libData =
|
||||
new ModelLibrary(QString::fromStdString("User"),
|
||||
resourceDir,
|
||||
QString::fromStdString(":/icons/preferences-general.svg"));
|
||||
_libraryList->push_back(libData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (useMatFromCustomDir) {
|
||||
QString resourceDir = QString::fromStdString(param->GetASCII("CustomMaterialsDir", ""));
|
||||
if (!resourceDir.isEmpty()) {
|
||||
QDir materialDir(resourceDir);
|
||||
if (materialDir.exists()) {
|
||||
auto libData = new ModelLibrary(QString::fromStdString("Custom"),
|
||||
resourceDir,
|
||||
QString::fromStdString(":/icons/user.svg"));
|
||||
_libraryList->push_back(libData);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
129
src/Mod/Material/App/ModelLoader.h
Normal file
129
src/Mod/Material/App/ModelLoader.h
Normal file
@@ -0,0 +1,129 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
|
||||
* *
|
||||
* 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 *
|
||||
* <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef MATERIAL_MODELLOADER_H
|
||||
#define MATERIAL_MODELLOADER_H
|
||||
|
||||
#include <QDir>
|
||||
#include <QString>
|
||||
#include <yaml-cpp/yaml.h>
|
||||
|
||||
#include "Model.h"
|
||||
|
||||
namespace Materials
|
||||
{
|
||||
|
||||
class ModelEntry
|
||||
{
|
||||
public:
|
||||
explicit ModelEntry(const ModelLibrary& library,
|
||||
const QString& baseName,
|
||||
const QString& modelName,
|
||||
const QString& dir,
|
||||
const QString& modelUuid,
|
||||
const YAML::Node& modelData);
|
||||
virtual ~ModelEntry() = default;
|
||||
|
||||
const ModelLibrary& getLibrary() const
|
||||
{
|
||||
return _library;
|
||||
}
|
||||
const QString getBase() const
|
||||
{
|
||||
return _base;
|
||||
}
|
||||
const QString getName() const
|
||||
{
|
||||
return _name;
|
||||
}
|
||||
const QString getDirectory() const
|
||||
{
|
||||
return _directory;
|
||||
}
|
||||
const QString getUUID() const
|
||||
{
|
||||
return _uuid;
|
||||
}
|
||||
const YAML::Node& getModel() const
|
||||
{
|
||||
return _model;
|
||||
}
|
||||
YAML::Node* getModelPtr()
|
||||
{
|
||||
return &_model;
|
||||
}
|
||||
bool getDereferenced() const
|
||||
{
|
||||
return _dereferenced;
|
||||
}
|
||||
|
||||
void markDereferenced()
|
||||
{
|
||||
_dereferenced = true;
|
||||
}
|
||||
|
||||
private:
|
||||
ModelEntry();
|
||||
|
||||
ModelLibrary _library;
|
||||
QString _base;
|
||||
QString _name;
|
||||
QString _directory;
|
||||
QString _uuid;
|
||||
YAML::Node _model;
|
||||
bool _dereferenced;
|
||||
};
|
||||
|
||||
class ModelLoader
|
||||
{
|
||||
public:
|
||||
explicit ModelLoader(std::shared_ptr<std::map<QString, Model*>> modelMap,
|
||||
std::shared_ptr<std::list<ModelLibrary*>> libraryList);
|
||||
virtual ~ModelLoader() = default;
|
||||
|
||||
static const QString getUUIDFromPath(const QString& path);
|
||||
|
||||
private:
|
||||
ModelLoader();
|
||||
|
||||
void getModelLibraries();
|
||||
QString
|
||||
yamlValue(const YAML::Node& node, const std::string& key, const std::string& defaultValue);
|
||||
void addToTree(ModelEntry* model, std::map<std::pair<QString, QString>, QString>* inheritances);
|
||||
void showYaml(const YAML::Node& yaml) const;
|
||||
void dereference(const QString& uuid,
|
||||
ModelEntry* parent,
|
||||
const ModelEntry* child,
|
||||
std::map<std::pair<QString, QString>, QString>* inheritances);
|
||||
void dereference(ModelEntry* model,
|
||||
std::map<std::pair<QString, QString>, QString>* inheritances);
|
||||
ModelEntry* getModelFromPath(const ModelLibrary& library, const QString& path) const;
|
||||
void addLibrary(ModelLibrary* model);
|
||||
void loadLibrary(const ModelLibrary& library);
|
||||
void loadLibraries();
|
||||
static std::unique_ptr<std::map<QString, ModelEntry*>> _modelEntryMap;
|
||||
std::shared_ptr<std::map<QString, Model*>> _modelMap;
|
||||
std::shared_ptr<std::list<ModelLibrary*>> _libraryList;
|
||||
};
|
||||
|
||||
} // namespace Materials
|
||||
|
||||
#endif // MATERIAL_MODELLOADER_H
|
||||
172
src/Mod/Material/App/ModelManager.cpp
Normal file
172
src/Mod/Material/App/ModelManager.cpp
Normal file
@@ -0,0 +1,172 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
|
||||
* *
|
||||
* 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 *
|
||||
* <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
**************************************************************************/
|
||||
|
||||
#include "PreCompiled.h"
|
||||
#ifndef _PreComp_
|
||||
#endif
|
||||
|
||||
#include <QMutexLocker>
|
||||
|
||||
#include <Base/Console.h>
|
||||
|
||||
#include "Model.h"
|
||||
#include "ModelLoader.h"
|
||||
#include "ModelManager.h"
|
||||
|
||||
|
||||
using namespace Materials;
|
||||
|
||||
std::shared_ptr<std::list<ModelLibrary*>> ModelManager::_libraryList = nullptr;
|
||||
std::shared_ptr<std::map<QString, Model*>> ModelManager::_modelMap = nullptr;
|
||||
QMutex ModelManager::_mutex;
|
||||
|
||||
TYPESYSTEM_SOURCE(Materials::ModelManager, Base::BaseClass)
|
||||
|
||||
ModelManager::ModelManager()
|
||||
{
|
||||
initLibraries();
|
||||
}
|
||||
|
||||
void ModelManager::initLibraries()
|
||||
{
|
||||
QMutexLocker locker(&_mutex);
|
||||
|
||||
if (_modelMap == nullptr) {
|
||||
_modelMap = std::make_shared<std::map<QString, Model*>>();
|
||||
if (_libraryList == nullptr) {
|
||||
_libraryList = std::make_shared<std::list<ModelLibrary*>>();
|
||||
}
|
||||
|
||||
// Load the libraries
|
||||
ModelLoader loader(_modelMap, _libraryList);
|
||||
}
|
||||
}
|
||||
|
||||
bool ModelManager::isModel(const fs::path& p)
|
||||
{
|
||||
// if (!fs::is_regular_file(p))
|
||||
// return false;
|
||||
// check file extension
|
||||
if (p.extension() == ".yml") {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ModelManager::refresh()
|
||||
{
|
||||
_modelMap->clear();
|
||||
_libraryList->clear();
|
||||
|
||||
// Load the libraries
|
||||
ModelLoader loader(_modelMap, _libraryList);
|
||||
}
|
||||
|
||||
const Model& ModelManager::getModel(const QString& uuid) const
|
||||
{
|
||||
try {
|
||||
if (_modelMap == nullptr) {
|
||||
throw Uninitialized();
|
||||
}
|
||||
|
||||
return *(_modelMap->at(uuid));
|
||||
}
|
||||
catch (std::out_of_range const&) {
|
||||
throw ModelNotFound();
|
||||
}
|
||||
}
|
||||
|
||||
const Model& ModelManager::getModelByPath(const QString& path) const
|
||||
{
|
||||
const QString& uuid = ModelLoader::getUUIDFromPath(path);
|
||||
const Model& model = getModel(uuid);
|
||||
|
||||
return model;
|
||||
}
|
||||
|
||||
const Model& ModelManager::getModelByPath(const QString& path, const QString& libraryPath) const
|
||||
{
|
||||
QDir modelDir(QDir::cleanPath(libraryPath + QString::fromStdString("/") + path));
|
||||
QString absPath = modelDir.absolutePath();
|
||||
return getModelByPath(absPath);
|
||||
}
|
||||
|
||||
bool ModelManager::passFilter(ModelFilter filter, Model::ModelType modelType) const
|
||||
{
|
||||
switch (filter) {
|
||||
case ModelFilter_None:
|
||||
return true;
|
||||
|
||||
case ModelFilter_Physical:
|
||||
return (modelType == Model::ModelType_Physical);
|
||||
|
||||
case ModelFilter_Appearance:
|
||||
return (modelType == Model::ModelType_Appearance);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
std::shared_ptr<std::map<QString, ModelTreeNode*>>
|
||||
ModelManager::getModelTree(const ModelLibrary& library, ModelFilter filter) const
|
||||
{
|
||||
std::shared_ptr<std::map<QString, ModelTreeNode*>> modelTree =
|
||||
std::make_shared<std::map<QString, ModelTreeNode*>>();
|
||||
|
||||
for (auto it = _modelMap->begin(); it != _modelMap->end(); it++) {
|
||||
auto filename = it->first;
|
||||
auto model = it->second;
|
||||
|
||||
if (model->getLibrary() == library && passFilter(filter, model->getType())) {
|
||||
fs::path path = model->getDirectory().toStdString();
|
||||
Base::Console().Log("Relative path '%s'\n\t", path.string().c_str());
|
||||
|
||||
// Start at the root
|
||||
std::shared_ptr<std::map<QString, ModelTreeNode*>> node = modelTree;
|
||||
for (auto itp = path.begin(); itp != path.end(); itp++) {
|
||||
if (isModel(itp->string())) {
|
||||
ModelTreeNode* child = new ModelTreeNode();
|
||||
child->setData(model);
|
||||
(*node)[QString::fromStdString(itp->string())] = child;
|
||||
}
|
||||
else {
|
||||
// Add the folder only if it's not already there
|
||||
QString folderName = QString::fromStdString(itp->string());
|
||||
std::shared_ptr<std::map<QString, ModelTreeNode*>> mapPtr;
|
||||
if (node->count(QString::fromStdString(itp->string())) == 0) {
|
||||
mapPtr = std::make_shared<std::map<QString, ModelTreeNode*>>();
|
||||
ModelTreeNode* child = new ModelTreeNode();
|
||||
child->setFolder(mapPtr);
|
||||
(*node)[QString::fromStdString(itp->string())] = child;
|
||||
node = mapPtr;
|
||||
}
|
||||
else {
|
||||
node = (*node)[QString::fromStdString(itp->string())]->getFolder();
|
||||
}
|
||||
}
|
||||
Base::Console().Log("'%s' ", itp->string().c_str());
|
||||
}
|
||||
Base::Console().Log("\n");
|
||||
}
|
||||
}
|
||||
|
||||
return modelTree;
|
||||
}
|
||||
86
src/Mod/Material/App/ModelManager.h
Normal file
86
src/Mod/Material/App/ModelManager.h
Normal file
@@ -0,0 +1,86 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
|
||||
* *
|
||||
* 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 *
|
||||
* <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef MATERIAL_MODELMANAGER_H
|
||||
#define MATERIAL_MODELMANAGER_H
|
||||
|
||||
#include <Mod/Material/MaterialGlobal.h>
|
||||
|
||||
#include <QMutex>
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
#include "Exceptions.h"
|
||||
#include "FolderTree.h"
|
||||
#include "Model.h"
|
||||
|
||||
namespace fs = boost::filesystem;
|
||||
|
||||
namespace Materials
|
||||
{
|
||||
|
||||
typedef FolderTreeNode<Model> ModelTreeNode;
|
||||
|
||||
class MaterialsExport ModelManager: public Base::BaseClass
|
||||
{
|
||||
TYPESYSTEM_HEADER();
|
||||
|
||||
public:
|
||||
enum ModelFilter
|
||||
{
|
||||
ModelFilter_None,
|
||||
ModelFilter_Physical,
|
||||
ModelFilter_Appearance
|
||||
};
|
||||
|
||||
ModelManager();
|
||||
~ModelManager() override = default;
|
||||
|
||||
void refresh();
|
||||
|
||||
std::shared_ptr<std::list<ModelLibrary*>> getModelLibraries()
|
||||
{
|
||||
return _libraryList;
|
||||
}
|
||||
std::shared_ptr<std::map<QString, Model*>> getModels()
|
||||
{
|
||||
return _modelMap;
|
||||
}
|
||||
std::shared_ptr<std::map<QString, ModelTreeNode*>>
|
||||
getModelTree(const ModelLibrary& library, ModelFilter filter = ModelFilter_None) const;
|
||||
const Model& getModel(const QString& uuid) const;
|
||||
const Model& getModelByPath(const QString& path) const;
|
||||
const Model& getModelByPath(const QString& path, const QString& libraryPath) const;
|
||||
|
||||
static bool isModel(const fs::path& p);
|
||||
bool passFilter(ModelFilter filter, Model::ModelType modelType) const;
|
||||
|
||||
private:
|
||||
static void initLibraries();
|
||||
|
||||
static std::shared_ptr<std::list<ModelLibrary*>> _libraryList;
|
||||
static std::shared_ptr<std::map<QString, Model*>> _modelMap;
|
||||
static QMutex _mutex;
|
||||
};
|
||||
|
||||
} // namespace Materials
|
||||
|
||||
#endif // MATERIAL_MODELMANAGER_H
|
||||
41
src/Mod/Material/App/ModelManagerPy.xml
Normal file
41
src/Mod/Material/App/ModelManagerPy.xml
Normal file
@@ -0,0 +1,41 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<GenerateModel xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="generateMetaModel_Module.xsd">
|
||||
<PythonExport
|
||||
Father="BaseClassPy"
|
||||
Name="ModelManagerPy"
|
||||
Twin="ModelManager"
|
||||
TwinPointer="ModelManager"
|
||||
Include="Mod/Material/App/ModelManager.h"
|
||||
Namespace="Materials"
|
||||
FatherInclude="Base/BaseClassPy.h"
|
||||
FatherNamespace="Base"
|
||||
Constructor="true"
|
||||
Delete="true">
|
||||
<Documentation>
|
||||
<Author Licence="LGPL" Name="DavidCarter" EMail="dcarter@davidcarter.ca" />
|
||||
<UserDocu>Material model descriptions.</UserDocu>
|
||||
</Documentation>
|
||||
<Methode Name="getModel">
|
||||
<Documentation>
|
||||
<UserDocu>Get a model object by specifying its UUID</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Methode Name="getModelByPath">
|
||||
<Documentation>
|
||||
<UserDocu>Get a model object by specifying its path</UserDocu>
|
||||
</Documentation>
|
||||
</Methode>
|
||||
<Attribute Name="ModelLibraries" ReadOnly="true">
|
||||
<Documentation>
|
||||
<UserDocu>List of model libraries.</UserDocu>
|
||||
</Documentation>
|
||||
<Parameter Name="ModelLibraries" Type="List"/>
|
||||
</Attribute>
|
||||
<Attribute Name="Models" ReadOnly="true">
|
||||
<Documentation>
|
||||
<UserDocu>List of model libraries.</UserDocu>
|
||||
</Documentation>
|
||||
<Parameter Name="Models" Type="Dict"/>
|
||||
</Attribute>
|
||||
</PythonExport>
|
||||
</GenerateModel>
|
||||
162
src/Mod/Material/App/ModelManagerPyImpl.cpp
Normal file
162
src/Mod/Material/App/ModelManagerPyImpl.cpp
Normal file
@@ -0,0 +1,162 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
|
||||
* *
|
||||
* 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 *
|
||||
* <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
**************************************************************************/
|
||||
|
||||
#include "PreCompiled.h"
|
||||
|
||||
#ifndef _PreComp_
|
||||
#include <boost/uuid/uuid_io.hpp>
|
||||
#endif
|
||||
|
||||
#include "ModelManager.h"
|
||||
#include "ModelManagerPy.h"
|
||||
#include "ModelPy.h"
|
||||
|
||||
#include "ModelManagerPy.cpp"
|
||||
|
||||
using namespace Materials;
|
||||
|
||||
// returns a string which represents the object e.g. when printed in python
|
||||
std::string ModelManagerPy::representation() const
|
||||
{
|
||||
std::stringstream str;
|
||||
str << "<ModelManager object at " << getModelManagerPtr() << ">";
|
||||
|
||||
return str.str();
|
||||
}
|
||||
|
||||
PyObject* ModelManagerPy::PyMake(struct _typeobject*, PyObject*, PyObject*) // Python wrapper
|
||||
{
|
||||
// never create such objects with the constructor
|
||||
return new ModelManagerPy(new ModelManager());
|
||||
}
|
||||
|
||||
// constructor method
|
||||
int ModelManagerPy::PyInit(PyObject* /*args*/, PyObject* /*kwd*/)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
PyObject* ModelManagerPy::getModel(PyObject* args)
|
||||
{
|
||||
char* uuid;
|
||||
if (!PyArg_ParseTuple(args, "s", &uuid)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
try {
|
||||
const Model model = getModelManagerPtr()->getModel(QString::fromStdString(uuid));
|
||||
return new ModelPy(new Model(model));
|
||||
}
|
||||
catch (ModelNotFound const&) {
|
||||
QString error = QString::fromStdString("Model not found:\n");
|
||||
auto _modelMap = getModelManagerPtr()->getModels();
|
||||
error += QString::fromStdString("ModelMap:\n");
|
||||
for (auto itp = _modelMap->begin(); itp != _modelMap->end(); itp++) {
|
||||
error += QString::fromStdString("\t_modelMap[") + itp->first
|
||||
+ QString::fromStdString("] = '") + itp->second->getName()
|
||||
+ QString::fromStdString("'\n");
|
||||
}
|
||||
error += QString::fromStdString("\tuuid = '") + QString::fromStdString(uuid)
|
||||
+ QString::fromStdString("'\n");
|
||||
PyErr_SetString(PyExc_LookupError, error.toStdString().c_str());
|
||||
return nullptr;
|
||||
}
|
||||
catch (Uninitialized const&) {
|
||||
PyErr_SetString(PyExc_LookupError, "Uninitialized model list");
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
PyObject* ModelManagerPy::getModelByPath(PyObject* args)
|
||||
{
|
||||
char* path;
|
||||
char* lib = "";
|
||||
if (!PyArg_ParseTuple(args, "s|s", &path, &lib)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::string libPath(lib);
|
||||
if (libPath.length() > 0) {
|
||||
try {
|
||||
const Model& model =
|
||||
getModelManagerPtr()->getModelByPath(QString::fromStdString(path),
|
||||
QString::fromStdString(libPath));
|
||||
return new ModelPy(new Model(model));
|
||||
}
|
||||
catch (ModelNotFound const&) {
|
||||
PyErr_SetString(PyExc_LookupError, "Model not found");
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
const Model& model = getModelManagerPtr()->getModelByPath(QString::fromStdString(path));
|
||||
return new ModelPy(new Model(model));
|
||||
}
|
||||
catch (ModelNotFound const&) {
|
||||
PyErr_SetString(PyExc_LookupError, "Model not found");
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
Py::List ModelManagerPy::getModelLibraries() const
|
||||
{
|
||||
std::shared_ptr<std::list<ModelLibrary*>> libraries = getModelManagerPtr()->getModelLibraries();
|
||||
Py::List list;
|
||||
|
||||
for (auto it = libraries->begin(); it != libraries->end(); it++) {
|
||||
ModelLibrary* lib = *it;
|
||||
Py::Tuple libTuple(3);
|
||||
libTuple.setItem(0, Py::String(lib->getName().toStdString()));
|
||||
libTuple.setItem(1, Py::String(lib->getDirectoryPath().toStdString()));
|
||||
libTuple.setItem(2, Py::String(lib->getIconPath().toStdString()));
|
||||
|
||||
list.append(libTuple);
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
Py::Dict ModelManagerPy::getModels() const
|
||||
{
|
||||
auto models = getModelManagerPtr()->getModels();
|
||||
Py::Dict dict;
|
||||
|
||||
for (auto it = models->begin(); it != models->end(); it++) {
|
||||
QString key = it->first;
|
||||
Model* model = it->second;
|
||||
|
||||
PyObject* modelPy = new ModelPy(new Model(*model));
|
||||
dict.setItem(Py::String(key.toStdString()), Py::Object(modelPy, true));
|
||||
}
|
||||
|
||||
return dict;
|
||||
}
|
||||
|
||||
PyObject* ModelManagerPy::getCustomAttributes(const char* /*attr*/) const
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int ModelManagerPy::setCustomAttributes(const char* /*attr*/, PyObject* /*obj*/)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
54
src/Mod/Material/App/ModelPropertyPy.xml
Normal file
54
src/Mod/Material/App/ModelPropertyPy.xml
Normal file
@@ -0,0 +1,54 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<GenerateModel xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="generateMetaModel_Module.xsd">
|
||||
<PythonExport
|
||||
Father="BaseClassPy"
|
||||
Name="ModelPropertyPy"
|
||||
Twin="ModelProperty"
|
||||
TwinPointer="ModelProperty"
|
||||
Include="Mod/Material/App/Model.h"
|
||||
Namespace="Materials"
|
||||
FatherInclude="Base/BaseClassPy.h"
|
||||
FatherNamespace="Base"
|
||||
Constructor="true"
|
||||
Delete="true">
|
||||
<Documentation>
|
||||
<Author Licence="LGPL" Name="DavidCarter" EMail="dcarter@davidcarter.ca" />
|
||||
<UserDocu>Material property descriptions.</UserDocu>
|
||||
</Documentation>
|
||||
<!-- <Methode Name="mirror">
|
||||
<Documentation>
|
||||
<UserDocu>Performs the symmetrical transformation of this geometric object</UserDocu>
|
||||
</Documentation>
|
||||
</Methode> -->
|
||||
<Attribute Name="Name" ReadOnly="true">
|
||||
<Documentation>
|
||||
<UserDocu>Property name.</UserDocu>
|
||||
</Documentation>
|
||||
<Parameter Name="Name" Type="String"/>
|
||||
</Attribute>
|
||||
<Attribute Name="Type" ReadOnly="true">
|
||||
<Documentation>
|
||||
<UserDocu>Property type.</UserDocu>
|
||||
</Documentation>
|
||||
<Parameter Name="Type" Type="String"/>
|
||||
</Attribute>
|
||||
<Attribute Name="Units" ReadOnly="true">
|
||||
<Documentation>
|
||||
<UserDocu>Property units category.</UserDocu>
|
||||
</Documentation>
|
||||
<Parameter Name="Units" Type="String"/>
|
||||
</Attribute>
|
||||
<Attribute Name="URL" ReadOnly="true">
|
||||
<Documentation>
|
||||
<UserDocu>URL to a detailed description of the property.</UserDocu>
|
||||
</Documentation>
|
||||
<Parameter Name="URL" Type="String"/>
|
||||
</Attribute>
|
||||
<Attribute Name="Description" ReadOnly="true">
|
||||
<Documentation>
|
||||
<UserDocu>Property description.</UserDocu>
|
||||
</Documentation>
|
||||
<Parameter Name="Description" Type="String"/>
|
||||
</Attribute>
|
||||
</PythonExport>
|
||||
</GenerateModel>
|
||||
100
src/Mod/Material/App/ModelPropertyPyImpl.cpp
Normal file
100
src/Mod/Material/App/ModelPropertyPyImpl.cpp
Normal file
@@ -0,0 +1,100 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
|
||||
* *
|
||||
* 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 *
|
||||
* <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
**************************************************************************/
|
||||
|
||||
#include "PreCompiled.h"
|
||||
|
||||
#ifndef _PreComp_
|
||||
#include <boost/uuid/uuid_io.hpp>
|
||||
#endif
|
||||
|
||||
#include "Model.h"
|
||||
#include "ModelPropertyPy.h"
|
||||
|
||||
#include "ModelPropertyPy.cpp"
|
||||
|
||||
using namespace Materials;
|
||||
|
||||
// returns a string which represents the object e.g. when printed in python
|
||||
std::string ModelPropertyPy::representation() const
|
||||
{
|
||||
ModelPropertyPy::PointerType ptr = getModelPropertyPtr();
|
||||
std::stringstream str;
|
||||
str << "Property [Name=(";
|
||||
str << ptr->getName().toStdString();
|
||||
str << "), Type=(";
|
||||
str << ptr->getPropertyType().toStdString();
|
||||
str << "), Units=(";
|
||||
str << ptr->getUnits().toStdString();
|
||||
str << "), URL=(";
|
||||
str << ptr->getURL().toStdString();
|
||||
str << "), Description=(";
|
||||
str << ptr->getDescription().toStdString();
|
||||
str << ")]";
|
||||
|
||||
return str.str();
|
||||
}
|
||||
|
||||
PyObject* ModelPropertyPy::PyMake(struct _typeobject*, PyObject*, PyObject*) // Python wrapper
|
||||
{
|
||||
// never create such objects with the constructor
|
||||
return new ModelPropertyPy(new ModelProperty());
|
||||
}
|
||||
|
||||
// constructor method
|
||||
int ModelPropertyPy::PyInit(PyObject* /*args*/, PyObject* /*kwd*/)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
Py::String ModelPropertyPy::getName() const
|
||||
{
|
||||
return Py::String(getModelPropertyPtr()->getName().toStdString());
|
||||
}
|
||||
|
||||
Py::String ModelPropertyPy::getType() const
|
||||
{
|
||||
return Py::String(getModelPropertyPtr()->getPropertyType().toStdString());
|
||||
}
|
||||
|
||||
Py::String ModelPropertyPy::getUnits() const
|
||||
{
|
||||
return Py::String(getModelPropertyPtr()->getUnits().toStdString());
|
||||
}
|
||||
|
||||
Py::String ModelPropertyPy::getURL() const
|
||||
{
|
||||
return Py::String(getModelPropertyPtr()->getURL().toStdString());
|
||||
}
|
||||
|
||||
Py::String ModelPropertyPy::getDescription() const
|
||||
{
|
||||
return Py::String(getModelPropertyPtr()->getDescription().toStdString());
|
||||
}
|
||||
|
||||
PyObject* ModelPropertyPy::getCustomAttributes(const char* /*attr*/) const
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int ModelPropertyPy::setCustomAttributes(const char* /*attr*/, PyObject* /*obj*/)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
85
src/Mod/Material/App/ModelPy.xml
Normal file
85
src/Mod/Material/App/ModelPy.xml
Normal file
@@ -0,0 +1,85 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<GenerateModel xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="generateMetaModel_Module.xsd">
|
||||
<PythonExport
|
||||
Father="BaseClassPy"
|
||||
Name="ModelPy"
|
||||
Twin="Model"
|
||||
TwinPointer="Model"
|
||||
Include="Mod/Material/App/Model.h"
|
||||
Namespace="Materials"
|
||||
FatherInclude="Base/BaseClassPy.h"
|
||||
FatherNamespace="Base"
|
||||
Constructor="true"
|
||||
Delete="true">
|
||||
<Documentation>
|
||||
<Author Licence="LGPL" Name="DavidCarter" EMail="dcarter@davidcarter.ca" />
|
||||
<UserDocu>Material model descriptions.</UserDocu>
|
||||
</Documentation>
|
||||
<Attribute Name="LibraryName" ReadOnly="true">
|
||||
<Documentation>
|
||||
<UserDocu>Model library name.</UserDocu>
|
||||
</Documentation>
|
||||
<Parameter Name="LibraryName" Type="String"/>
|
||||
</Attribute>
|
||||
<Attribute Name="LibraryRoot" ReadOnly="true">
|
||||
<Documentation>
|
||||
<UserDocu>Model library path.</UserDocu>
|
||||
</Documentation>
|
||||
<Parameter Name="LibraryRoot" Type="String"/>
|
||||
</Attribute>
|
||||
<Attribute Name="LibraryIcon" ReadOnly="true">
|
||||
<Documentation>
|
||||
<UserDocu>Model icon path.</UserDocu>
|
||||
</Documentation>
|
||||
<Parameter Name="LibraryIcon" Type="String"/>
|
||||
</Attribute>
|
||||
<Attribute Name="Name" ReadOnly="true">
|
||||
<Documentation>
|
||||
<UserDocu>Model name.</UserDocu>
|
||||
</Documentation>
|
||||
<Parameter Name="Name" Type="String"/>
|
||||
</Attribute>
|
||||
<Attribute Name="Directory" ReadOnly="true">
|
||||
<Documentation>
|
||||
<UserDocu>Model directory.</UserDocu>
|
||||
</Documentation>
|
||||
<Parameter Name="Directory" Type="String"/>
|
||||
</Attribute>
|
||||
<Attribute Name="UUID" ReadOnly="true">
|
||||
<Documentation>
|
||||
<UserDocu>Unique model identifier.</UserDocu>
|
||||
</Documentation>
|
||||
<Parameter Name="UUID" Type="String"/>
|
||||
</Attribute>
|
||||
<Attribute Name="Description" ReadOnly="true">
|
||||
<Documentation>
|
||||
<UserDocu>Description of the model.</UserDocu>
|
||||
</Documentation>
|
||||
<Parameter Name="Description" Type="String"/>
|
||||
</Attribute>
|
||||
<Attribute Name="URL" ReadOnly="true">
|
||||
<Documentation>
|
||||
<UserDocu>URL to a detailed description of the model.</UserDocu>
|
||||
</Documentation>
|
||||
<Parameter Name="URL" Type="String"/>
|
||||
</Attribute>
|
||||
<Attribute Name="DOI" ReadOnly="true">
|
||||
<Documentation>
|
||||
<UserDocu>Digital Object Identifier (see https://doi.org/)</UserDocu>
|
||||
</Documentation>
|
||||
<Parameter Name="DOI" Type="String"/>
|
||||
</Attribute>
|
||||
<Attribute Name="Inherited" ReadOnly="true">
|
||||
<Documentation>
|
||||
<UserDocu>List of inherited models identified by UUID.</UserDocu>
|
||||
</Documentation>
|
||||
<Parameter Name="Inherited" Type="List"/>
|
||||
</Attribute>
|
||||
<Attribute Name="Properties" ReadOnly="true">
|
||||
<Documentation>
|
||||
<UserDocu>Dictionary of model properties.</UserDocu>
|
||||
</Documentation>
|
||||
<Parameter Name="Properties" Type="Dict"/>
|
||||
</Attribute>
|
||||
</PythonExport>
|
||||
</GenerateModel>
|
||||
171
src/Mod/Material/App/ModelPyImpl.cpp
Normal file
171
src/Mod/Material/App/ModelPyImpl.cpp
Normal file
@@ -0,0 +1,171 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
|
||||
* *
|
||||
* 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 *
|
||||
* <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
**************************************************************************/
|
||||
|
||||
#include "PreCompiled.h"
|
||||
|
||||
#ifndef _PreComp_
|
||||
#include <boost/uuid/uuid_io.hpp>
|
||||
#endif
|
||||
|
||||
#include "Model.h"
|
||||
#include "ModelPropertyPy.h"
|
||||
#include "ModelPy.h"
|
||||
|
||||
#include "ModelPy.cpp"
|
||||
|
||||
using namespace Materials;
|
||||
|
||||
// returns a string which represents the object e.g. when printed in python
|
||||
std::string ModelPy::representation() const
|
||||
{
|
||||
ModelPy::PointerType ptr = getModelPtr();
|
||||
std::stringstream str;
|
||||
str << "Property [Name=(";
|
||||
str << ptr->getName().toStdString();
|
||||
str << "), UUID=(";
|
||||
str << ptr->getUUID().toStdString();
|
||||
str << "), Library Name=(";
|
||||
str << ptr->getLibrary().getName().toStdString();
|
||||
str << "), Library Root=(";
|
||||
str << ptr->getLibrary().getDirectoryPath().toStdString();
|
||||
str << "), Library Icon=(";
|
||||
str << ptr->getLibrary().getIconPath().toStdString();
|
||||
str << "), Directory=(";
|
||||
str << ptr->getDirectory().toStdString();
|
||||
str << "), URL=(";
|
||||
str << ptr->getURL().toStdString();
|
||||
str << "), DOI=(";
|
||||
str << ptr->getDOI().toStdString();
|
||||
str << "), Description=(";
|
||||
str << ptr->getDescription().toStdString();
|
||||
str << "), Inherits=[";
|
||||
const std::vector<QString>& inherited = getModelPtr()->getInheritance();
|
||||
for (auto it = inherited.begin(); it != inherited.end(); it++) {
|
||||
QString uuid = *it;
|
||||
if (it != inherited.begin()) {
|
||||
str << "), UUID=(";
|
||||
}
|
||||
else {
|
||||
str << "UUID=(";
|
||||
}
|
||||
str << uuid.toStdString() << ")";
|
||||
}
|
||||
str << "]]";
|
||||
|
||||
return str.str();
|
||||
}
|
||||
|
||||
PyObject* ModelPy::PyMake(struct _typeobject*, PyObject*, PyObject*) // Python wrapper
|
||||
{
|
||||
// never create such objects with the constructor
|
||||
return new ModelPy(new Model());
|
||||
}
|
||||
|
||||
// constructor method
|
||||
int ModelPy::PyInit(PyObject* /*args*/, PyObject* /*kwd*/)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
Py::String ModelPy::getLibraryName() const
|
||||
{
|
||||
return Py::String(getModelPtr()->getLibrary().getName().toStdString());
|
||||
}
|
||||
|
||||
Py::String ModelPy::getLibraryRoot() const
|
||||
{
|
||||
return Py::String(getModelPtr()->getLibrary().getDirectoryPath().toStdString());
|
||||
}
|
||||
|
||||
Py::String ModelPy::getLibraryIcon() const
|
||||
{
|
||||
return Py::String(getModelPtr()->getLibrary().getIconPath().toStdString());
|
||||
}
|
||||
|
||||
Py::String ModelPy::getName() const
|
||||
{
|
||||
return Py::String(getModelPtr()->getName().toStdString());
|
||||
}
|
||||
|
||||
Py::String ModelPy::getDirectory() const
|
||||
{
|
||||
return Py::String(getModelPtr()->getDirectoryPath().toStdString());
|
||||
}
|
||||
|
||||
Py::String ModelPy::getUUID() const
|
||||
{
|
||||
return Py::String(getModelPtr()->getUUID().toStdString());
|
||||
}
|
||||
|
||||
Py::String ModelPy::getDescription() const
|
||||
{
|
||||
return Py::String(getModelPtr()->getDescription().toStdString());
|
||||
}
|
||||
|
||||
Py::String ModelPy::getURL() const
|
||||
{
|
||||
return Py::String(getModelPtr()->getURL().toStdString());
|
||||
}
|
||||
|
||||
Py::String ModelPy::getDOI() const
|
||||
{
|
||||
return Py::String(getModelPtr()->getDOI().toStdString());
|
||||
}
|
||||
|
||||
Py::List ModelPy::getInherited() const
|
||||
{
|
||||
const std::vector<QString>& inherited = getModelPtr()->getInheritance();
|
||||
Py::List list;
|
||||
|
||||
for (auto it = inherited.begin(); it != inherited.end(); it++) {
|
||||
QString uuid = *it;
|
||||
|
||||
list.append(Py::String(uuid.toStdString()));
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
Py::Dict ModelPy::getProperties() const
|
||||
{
|
||||
// std::map<std::string, Model*> *models = getModelPtr()->getModels();
|
||||
Py::Dict dict;
|
||||
|
||||
for (auto it = getModelPtr()->begin(); it != getModelPtr()->end(); it++) {
|
||||
QString key = it->first;
|
||||
ModelProperty& modelProperty = it->second;
|
||||
|
||||
PyObject* modelPropertyPy = new ModelPropertyPy(new ModelProperty(modelProperty));
|
||||
dict.setItem(Py::String(key.toStdString()), Py::Object(modelPropertyPy, true));
|
||||
}
|
||||
|
||||
return dict;
|
||||
}
|
||||
|
||||
PyObject* ModelPy::getCustomAttributes(const char* /*attr*/) const
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int ModelPy::setCustomAttributes(const char* /*attr*/, PyObject* /*obj*/)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
72
src/Mod/Material/App/ModelUuids.h
Normal file
72
src/Mod/Material/App/ModelUuids.h
Normal file
@@ -0,0 +1,72 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
|
||||
* *
|
||||
* 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 *
|
||||
* <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef MATERIAL_MODELUUIDS_H
|
||||
#define MATERIAL_MODELUUIDS_H
|
||||
|
||||
namespace Materials
|
||||
{
|
||||
|
||||
// UUIDs for predefined material models
|
||||
|
||||
static const QString ModelUUID_Legacy_Father =
|
||||
QString::fromStdString("9cdda8b6-b606-4778-8f13-3934d8668e67");
|
||||
static const QString ModelUUID_Legacy_MaterialStandard =
|
||||
QString::fromStdString("1e2c0088-904a-4537-925f-64064c07d700");
|
||||
|
||||
static const QString ModelUUID_Mechanical_Density =
|
||||
QString::fromStdString("454661e5-265b-4320-8e6f-fcf6223ac3af");
|
||||
static const QString ModelUUID_Mechanical_IsotropicLinearElastic =
|
||||
QString::fromStdString("f6f9e48c-b116-4e82-ad7f-3659a9219c50");
|
||||
static const QString ModelUUID_Mechanical_LinearElastic =
|
||||
QString::fromStdString("7b561d1d-fb9b-44f6-9da9-56a4f74d7536");
|
||||
static const QString ModelUUID_Mechanical_OgdenYld2004p18 =
|
||||
QString::fromStdString("3ef9e427-cc25-43f7-817f-79ff0d49625f");
|
||||
static const QString ModelUUID_Mechanical_OrthotropicLinearElastic =
|
||||
QString::fromStdString("b19ccc6b-a431-418e-91c2-0ac8c649d146");
|
||||
|
||||
static const QString ModelUUID_Fluid_Default =
|
||||
QString::fromStdString("1ae66d8c-1ba1-4211-ad12-b9917573b202");
|
||||
|
||||
static const QString ModelUUID_Thermal_Default =
|
||||
QString::fromStdString("9959d007-a970-4ea7-bae4-3eb1b8b883c7");
|
||||
|
||||
static const QString ModelUUID_Electromagnetic_Default =
|
||||
QString::fromStdString("b2eb5f48-74b3-4193-9fbb-948674f427f3");
|
||||
|
||||
static const QString ModelUUID_Architectural_Default =
|
||||
QString::fromStdString("32439c3b-262f-4b7b-99a8-f7f44e5894c8");
|
||||
|
||||
static const QString ModelUUID_Costs_Default =
|
||||
QString::fromStdString("881df808-8726-4c2e-be38-688bb6cce466");
|
||||
|
||||
static const QString ModelUUID_Rendering_Basic =
|
||||
QString::fromStdString("f006c7e4-35b7-43d5-bbf9-c5d572309e6e");
|
||||
static const QString ModelUUID_Rendering_Texture =
|
||||
QString::fromStdString("bbdcc65b-67ca-489c-bd5c-a36e33d1c160");
|
||||
static const QString ModelUUID_Rendering_Advanced =
|
||||
QString::fromStdString("c880f092-cdae-43d6-a24b-55e884aacbbf");
|
||||
static const QString ModelUUID_Rendering_Vector =
|
||||
QString::fromStdString("fdf5a80e-de50-4157-b2e5-b6e5f88b680e");
|
||||
|
||||
} // namespace Materials
|
||||
|
||||
#endif // MATERIAL_MODELUUIDS_H
|
||||
22
src/Mod/Material/App/PreCompiled.cpp
Normal file
22
src/Mod/Material/App/PreCompiled.cpp
Normal file
@@ -0,0 +1,22 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
|
||||
* *
|
||||
* 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 *
|
||||
* <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
**************************************************************************/
|
||||
|
||||
#include "PreCompiled.h"
|
||||
64
src/Mod/Material/App/PreCompiled.h
Normal file
64
src/Mod/Material/App/PreCompiled.h
Normal file
@@ -0,0 +1,64 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
|
||||
* *
|
||||
* 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 *
|
||||
* <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef MATERIAL_PRECOMPILED_H
|
||||
#define MATERIAL_PRECOMPILED_H
|
||||
|
||||
#include <FCConfig.h>
|
||||
|
||||
// point at which warnings of overly long specifiers disabled (needed for VC6)
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable : 4251)
|
||||
#pragma warning(disable : 4503)
|
||||
#pragma warning(disable : 4786) // specifier longer then 255 chars
|
||||
#pragma warning(disable : 4273)
|
||||
#endif
|
||||
|
||||
#ifdef FC_OS_WIN32
|
||||
#ifndef NOMINMAX
|
||||
#define NOMINMAX
|
||||
#endif
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#ifdef _PreComp_
|
||||
|
||||
// standard
|
||||
#include <cfloat>
|
||||
#include <cmath>
|
||||
|
||||
// STL
|
||||
#include <algorithm>
|
||||
#include <map>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
// Qt
|
||||
#include <QtGlobal>
|
||||
|
||||
// Boost
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
#include <boost/regex.hpp>
|
||||
|
||||
#endif //_PreComp_
|
||||
|
||||
#endif // MATERIAL_PRECOMPILED_H
|
||||
80
src/Mod/Material/App/trim.h
Normal file
80
src/Mod/Material/App/trim.h
Normal file
@@ -0,0 +1,80 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
|
||||
* *
|
||||
* 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 *
|
||||
* <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef MATERIAL_TRIM_H
|
||||
#define MATERIAL_TRIM_H
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace Materials
|
||||
{
|
||||
|
||||
// trim from start (in place)
|
||||
static inline void ltrim(std::string& s)
|
||||
{
|
||||
s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](unsigned char ch) {
|
||||
return !std::isspace(ch);
|
||||
}));
|
||||
}
|
||||
|
||||
// trim from end (in place)
|
||||
static inline void rtrim(std::string& s)
|
||||
{
|
||||
s.erase(std::find_if(s.rbegin(),
|
||||
s.rend(),
|
||||
[](unsigned char ch) {
|
||||
return !std::isspace(ch);
|
||||
})
|
||||
.base(),
|
||||
s.end());
|
||||
}
|
||||
|
||||
// trim from both ends (in place)
|
||||
static inline void trim(std::string& s)
|
||||
{
|
||||
rtrim(s);
|
||||
ltrim(s);
|
||||
}
|
||||
|
||||
// trim from start (copying)
|
||||
static inline std::string ltrim_copy(std::string s)
|
||||
{
|
||||
ltrim(s);
|
||||
return s;
|
||||
}
|
||||
|
||||
// trim from end (copying)
|
||||
static inline std::string rtrim_copy(std::string s)
|
||||
{
|
||||
rtrim(s);
|
||||
return s;
|
||||
}
|
||||
|
||||
// trim from both ends (copying)
|
||||
static inline std::string trim_copy(std::string s)
|
||||
{
|
||||
trim(s);
|
||||
return s;
|
||||
}
|
||||
|
||||
} // namespace Materials
|
||||
|
||||
#endif // MATERIAL_TRIM_H
|
||||
@@ -1,174 +1,221 @@
|
||||
IF (BUILD_GUI)
|
||||
PYSIDE_WRAP_RC(Material_QRC_SRCS Resources/Material.qrc)
|
||||
ENDIF (BUILD_GUI)
|
||||
add_subdirectory(App)
|
||||
|
||||
SET(Material_SRCS
|
||||
if(BUILD_GUI)
|
||||
add_subdirectory(Gui)
|
||||
endif(BUILD_GUI)
|
||||
|
||||
IF(BUILD_GUI)
|
||||
PYSIDE_WRAP_RC(Material_QRC_SRCS Resources/Material.qrc)
|
||||
ENDIF(BUILD_GUI)
|
||||
|
||||
SET(MaterialScripts_Files
|
||||
Init.py
|
||||
InitGui.py
|
||||
Material.py
|
||||
importFCMat.py
|
||||
MaterialEditor.py
|
||||
materials-editor.ui
|
||||
TestMaterialsApp.py
|
||||
Resources/ui/materials-editor.ui
|
||||
Templatematerial.yml
|
||||
)
|
||||
SOURCE_GROUP("Module" FILES ${Material_SRCS})
|
||||
|
||||
SET (MaterialTools_Files
|
||||
# SOURCE_GROUP("MaterialScripts" FILES ${MaterialScripts_Files})
|
||||
SET(MaterialTools_Files
|
||||
materialtools/__init__.py
|
||||
materialtools/cardutils.py
|
||||
materialtools/MaterialModels.py
|
||||
)
|
||||
SET (Material_Icon_Files
|
||||
SET(Material_Icon_Files
|
||||
Resources/icons/preview-rendered.svg
|
||||
Resources/icons/preview-vector.svg
|
||||
)
|
||||
|
||||
# collect all the material cards:
|
||||
#FILE( GLOB MaterialLib_Files ./StandardMaterial/*.FCMat ./StandardMaterial/*.txt )
|
||||
|
||||
SET (MaterialLib_Files
|
||||
StandardMaterial/None.FCMat
|
||||
StandardMaterial/ABS-Generic.FCMat
|
||||
StandardMaterial/Acrylic-Glass-Generic.FCMat
|
||||
StandardMaterial/AlMg3F24.FCMat
|
||||
StandardMaterial/AlMgSi1F31.FCMat
|
||||
StandardMaterial/Aluminum-6061-T6.FCMat
|
||||
StandardMaterial/Aluminum-Generic.FCMat
|
||||
StandardMaterial/AlZn4-5Mg1F35.FCMat
|
||||
StandardMaterial/CalculiX-Steel.FCMat
|
||||
StandardMaterial/Concrete-Generic.FCMat
|
||||
StandardMaterial/Copper-Generic.FCMat
|
||||
StandardMaterial/Glass-E-GlassFibre.FCMat
|
||||
StandardMaterial/Glass-Generic.FCMat
|
||||
StandardMaterial/Glass-S2-GlassFibre.FCMat
|
||||
StandardMaterial/Graphite.FCMat
|
||||
StandardMaterial/Iron-Generic.FCMat
|
||||
StandardMaterial/Invar-Generic.FCMat
|
||||
StandardMaterial/PA6-Generic.FCMat
|
||||
StandardMaterial/PET-Generic.FCMat
|
||||
StandardMaterial/PLA-Generic.FCMat
|
||||
StandardMaterial/PP-Generic.FCMat
|
||||
StandardMaterial/PTFE-Generic.FCMat
|
||||
StandardMaterial/PVC-Generic.FCMat
|
||||
StandardMaterial/Reinforcement-FIB-B500.FCMat
|
||||
StandardMaterial/Steel-15CrNi6.FCMat
|
||||
StandardMaterial/Steel-17CrNiMo6.FCMat
|
||||
StandardMaterial/Steel-1C22.FCMat
|
||||
StandardMaterial/Steel-1C35.FCMat
|
||||
StandardMaterial/Steel-1C45.FCMat
|
||||
StandardMaterial/Steel-1C60.FCMat
|
||||
StandardMaterial/Steel-20NiCrMo2.FCMat
|
||||
StandardMaterial/Steel-28Mn6.FCMat
|
||||
StandardMaterial/Steel-2C10.FCMat
|
||||
StandardMaterial/Steel-30CrNiMo8.FCMat
|
||||
StandardMaterial/Steel-34CrNiMo6.FCMat
|
||||
StandardMaterial/Steel-36CrNiMo4.FCMat
|
||||
StandardMaterial/Steel-36NiCrMo16.FCMat
|
||||
StandardMaterial/Steel-3C15.FCMat
|
||||
StandardMaterial/Steel-3C22.FCMat
|
||||
StandardMaterial/Steel-3C35.FCMat
|
||||
StandardMaterial/Steel-3V45.FCMat
|
||||
StandardMaterial/Steel-C10.FCMat
|
||||
StandardMaterial/Steel-C15.FCMat
|
||||
StandardMaterial/Steel-C22E.FCMat
|
||||
StandardMaterial/Steel-C25E.FCMat
|
||||
StandardMaterial/Steel-C30E.FCMat
|
||||
StandardMaterial/Steel-C40E.FCMat
|
||||
StandardMaterial/Steel-C50E.FCMat
|
||||
StandardMaterial/Steel-C55E.FCMat
|
||||
StandardMaterial/Steel-C60E.FCMat
|
||||
StandardMaterial/Steel-E295-GC.FCMat
|
||||
StandardMaterial/Steel-E295.FCMat
|
||||
StandardMaterial/Steel-E335-GC.FCMat
|
||||
StandardMaterial/Steel-E335.FCMat
|
||||
StandardMaterial/Steel-E360-GC.FCMat
|
||||
StandardMaterial/Steel-E360.FCMat
|
||||
StandardMaterial/Steel-EN-GJL-100.FCMat
|
||||
StandardMaterial/Steel-EN-GJL-150.FCMat
|
||||
StandardMaterial/Steel-EN-GJL-200.FCMat
|
||||
StandardMaterial/Steel-EN-GJL-250.FCMat
|
||||
StandardMaterial/Steel-EN-GJL-300.FCMat
|
||||
StandardMaterial/Steel-EN-GJL-350.FCMat
|
||||
StandardMaterial/Steel-EN-GJMB-350-10.FCMat
|
||||
StandardMaterial/Steel-EN-GJMB-550-4.FCMat
|
||||
StandardMaterial/Steel-EN-GJMB-650-2.FCMat
|
||||
StandardMaterial/Steel-EN-GJMW-350-4.FCMat
|
||||
StandardMaterial/Steel-EN-GJMW-360-12.FCMat
|
||||
StandardMaterial/Steel-EN-GJMW-400-5.FCMat
|
||||
StandardMaterial/Steel-EN-GJMW-450-7.FCMat
|
||||
StandardMaterial/Steel-EN-GJS-400-15.FCMat
|
||||
StandardMaterial/Steel-EN-GJS-500-7.FCMat
|
||||
StandardMaterial/Steel-EN-GJS-600-3.FCMat
|
||||
StandardMaterial/Steel-EN-GJS-700-2.FCMat
|
||||
StandardMaterial/Steel-EN-GJS-800-1.FCMat
|
||||
StandardMaterial/Steel-G16Mn5.FCMat
|
||||
StandardMaterial/Steel-G200.FCMat
|
||||
StandardMaterial/Steel-G20Mn5.FCMat
|
||||
StandardMaterial/Steel-G230.FCMat
|
||||
StandardMaterial/Steel-G260.FCMat
|
||||
StandardMaterial/Steel-G300.FCMat
|
||||
StandardMaterial/Steel-G30Mn5.FCMat
|
||||
StandardMaterial/Steel-Generic.FCMat
|
||||
StandardMaterial/Steel-S185.FCMat
|
||||
StandardMaterial/Steel-S235JO.FCMat
|
||||
StandardMaterial/Steel-S235JR.FCMat
|
||||
StandardMaterial/Steel-S235JRG1.FCMat
|
||||
StandardMaterial/Steel-S260NC.FCMat
|
||||
StandardMaterial/Steel-S275JO.FCMat
|
||||
StandardMaterial/Steel-S275JR.FCMat
|
||||
StandardMaterial/Steel-S275N.FCMat
|
||||
StandardMaterial/Steel-S335JO.FCMat
|
||||
StandardMaterial/Steel-S335JR.FCMat
|
||||
StandardMaterial/Steel-S335N.FCMat
|
||||
StandardMaterial/Steel-S340MC.FCMat
|
||||
StandardMaterial/Steel-S355J2G3.FCMat
|
||||
StandardMaterial/Steel-S380MC.FCMat
|
||||
StandardMaterial/Steel-S420MC.FCMat
|
||||
StandardMaterial/Steel-S420N.FCMat
|
||||
StandardMaterial/Steel-S460MC.FCMat
|
||||
StandardMaterial/Steel-S460N.FCMat
|
||||
StandardMaterial/Steel-S500MC.FCMat
|
||||
StandardMaterial/Steel-S550MC.FCMat
|
||||
StandardMaterial/Steel-S690MC.FCMat
|
||||
StandardMaterial/Steel-St-37-2K.FCMat
|
||||
StandardMaterial/Steel-St-E-255.FCMat
|
||||
StandardMaterial/Steel-St-E-315.FCMat
|
||||
StandardMaterial/Steel-St-E-380.FCMat
|
||||
StandardMaterial/Steel-St-E-460.FCMat
|
||||
StandardMaterial/Steel-St-E-500.FCMat
|
||||
StandardMaterial/Steel-X2CrNiMoN17-13-3.FCMat
|
||||
StandardMaterial/Steel-X2CrNiN24-4.FCMat
|
||||
StandardMaterial/Steel-X39CrMo17-1.FCMat
|
||||
StandardMaterial/Steel-X3CrNiMo13-14.FCMat
|
||||
StandardMaterial/Steel-X5CrNi18-10.FCMat
|
||||
StandardMaterial/Steel-X5CrNiMo17-12-2.FCMat
|
||||
StandardMaterial/Steel-X6CrNiTi18-10.FCMat
|
||||
StandardMaterial/TEMPLATE.FCMat
|
||||
StandardMaterial/Ti-6Al-4V.FCMat
|
||||
StandardMaterial/Wood-Generic.FCMat
|
||||
StandardMaterial/Readme.txt
|
||||
)
|
||||
SOURCE_GROUP("MatLib" FILES ${MaterialLib_Files})
|
||||
|
||||
SET (FluidMaterial_Files
|
||||
FluidMaterial/None.FCMat
|
||||
FluidMaterial/Air.FCMat
|
||||
FluidMaterial/Argon.FCMat
|
||||
FluidMaterial/Carbon_dioxide.FCMat
|
||||
FluidMaterial/Nitrogen.FCMat
|
||||
FluidMaterial/Water.FCMat
|
||||
FluidMaterial/Readme.md
|
||||
)
|
||||
SOURCE_GROUP("MatLib" FILES ${FluidMaterial_Files})
|
||||
|
||||
ADD_CUSTOM_TARGET(Material ALL
|
||||
SOURCES ${Material_SRCS} ${Material_QRC_SRCS}
|
||||
# FILE( GLOB MaterialLib_Files ./StandardMaterial/*.FCMat ./StandardMaterial/*.txt )
|
||||
SET(MaterialLib_Files
|
||||
Resources/Materials/StandardMaterial/Aggregate/Concrete-EN-C35_45.FCMat
|
||||
Resources/Materials/StandardMaterial/Aggregate/Concrete-Generic.FCMat
|
||||
Resources/Materials/StandardMaterial/Aggregate/Reinforcement-FIB-B500.FCMat
|
||||
Resources/Materials/StandardMaterial/Carbon/Graphite.FCMat
|
||||
Resources/Materials/StandardMaterial/Glass/Glass-E-GlassFibre.FCMat
|
||||
Resources/Materials/StandardMaterial/Glass/Glass-Generic.FCMat
|
||||
Resources/Materials/StandardMaterial/Glass/Glass-S2-GlassFibre.FCMat
|
||||
Resources/Materials/StandardMaterial/Metal/Alloys/Invar-Generic.FCMat
|
||||
Resources/Materials/StandardMaterial/Metal/Aluminum/AlMg3F24.FCMat
|
||||
Resources/Materials/StandardMaterial/Metal/Aluminum/AlMgSi1F31.FCMat
|
||||
Resources/Materials/StandardMaterial/Metal/Aluminum/Aluminum-6061-T6.FCMat
|
||||
Resources/Materials/StandardMaterial/Metal/Aluminum/Aluminum-Generic.FCMat
|
||||
Resources/Materials/StandardMaterial/Metal/Aluminum/AlZn4-5Mg1F35.FCMat
|
||||
Resources/Materials/StandardMaterial/Metal/Copper/Copper-Generic.FCMat
|
||||
Resources/Materials/StandardMaterial/Metal/Iron/Iron-Generic.FCMat
|
||||
Resources/Materials/StandardMaterial/Metal/Steel/CalculiX-Steel.FCMat
|
||||
Resources/Materials/StandardMaterial/Metal/Steel/Steel-15CrNi6.FCMat
|
||||
Resources/Materials/StandardMaterial/Metal/Steel/Steel-17CrNiMo6.FCMat
|
||||
Resources/Materials/StandardMaterial/Metal/Steel/Steel-1C22.FCMat
|
||||
Resources/Materials/StandardMaterial/Metal/Steel/Steel-1C35.FCMat
|
||||
Resources/Materials/StandardMaterial/Metal/Steel/Steel-1C45.FCMat
|
||||
Resources/Materials/StandardMaterial/Metal/Steel/Steel-1C60.FCMat
|
||||
Resources/Materials/StandardMaterial/Metal/Steel/Steel-20NiCrMo2.FCMat
|
||||
Resources/Materials/StandardMaterial/Metal/Steel/Steel-28Mn6.FCMat
|
||||
Resources/Materials/StandardMaterial/Metal/Steel/Steel-2C10.FCMat
|
||||
Resources/Materials/StandardMaterial/Metal/Steel/Steel-30CrNiMo8.FCMat
|
||||
Resources/Materials/StandardMaterial/Metal/Steel/Steel-34CrNiMo6.FCMat
|
||||
Resources/Materials/StandardMaterial/Metal/Steel/Steel-36CrNiMo4.FCMat
|
||||
Resources/Materials/StandardMaterial/Metal/Steel/Steel-36NiCrMo16.FCMat
|
||||
Resources/Materials/StandardMaterial/Metal/Steel/Steel-3C15.FCMat
|
||||
Resources/Materials/StandardMaterial/Metal/Steel/Steel-3C22.FCMat
|
||||
Resources/Materials/StandardMaterial/Metal/Steel/Steel-3C35.FCMat
|
||||
Resources/Materials/StandardMaterial/Metal/Steel/Steel-3V45.FCMat
|
||||
Resources/Materials/StandardMaterial/Metal/Steel/Steel-C10.FCMat
|
||||
Resources/Materials/StandardMaterial/Metal/Steel/Steel-C15.FCMat
|
||||
Resources/Materials/StandardMaterial/Metal/Steel/Steel-C22E.FCMat
|
||||
Resources/Materials/StandardMaterial/Metal/Steel/Steel-C25E.FCMat
|
||||
Resources/Materials/StandardMaterial/Metal/Steel/Steel-C30E.FCMat
|
||||
Resources/Materials/StandardMaterial/Metal/Steel/Steel-C40E.FCMat
|
||||
Resources/Materials/StandardMaterial/Metal/Steel/Steel-C50E.FCMat
|
||||
Resources/Materials/StandardMaterial/Metal/Steel/Steel-C55E.FCMat
|
||||
Resources/Materials/StandardMaterial/Metal/Steel/Steel-C60E.FCMat
|
||||
Resources/Materials/StandardMaterial/Metal/Steel/Steel-E295-GC.FCMat
|
||||
Resources/Materials/StandardMaterial/Metal/Steel/Steel-E295.FCMat
|
||||
Resources/Materials/StandardMaterial/Metal/Steel/Steel-E335-GC.FCMat
|
||||
Resources/Materials/StandardMaterial/Metal/Steel/Steel-E335.FCMat
|
||||
Resources/Materials/StandardMaterial/Metal/Steel/Steel-E360-GC.FCMat
|
||||
Resources/Materials/StandardMaterial/Metal/Steel/Steel-E360.FCMat
|
||||
Resources/Materials/StandardMaterial/Metal/Steel/Steel-EN-GJL-100.FCMat
|
||||
Resources/Materials/StandardMaterial/Metal/Steel/Steel-EN-GJL-150.FCMat
|
||||
Resources/Materials/StandardMaterial/Metal/Steel/Steel-EN-GJL-200.FCMat
|
||||
Resources/Materials/StandardMaterial/Metal/Steel/Steel-EN-GJL-250.FCMat
|
||||
Resources/Materials/StandardMaterial/Metal/Steel/Steel-EN-GJL-300.FCMat
|
||||
Resources/Materials/StandardMaterial/Metal/Steel/Steel-EN-GJL-350.FCMat
|
||||
Resources/Materials/StandardMaterial/Metal/Steel/Steel-EN-GJMB-350-10.FCMat
|
||||
Resources/Materials/StandardMaterial/Metal/Steel/Steel-EN-GJMB-550-4.FCMat
|
||||
Resources/Materials/StandardMaterial/Metal/Steel/Steel-EN-GJMB-650-2.FCMat
|
||||
Resources/Materials/StandardMaterial/Metal/Steel/Steel-EN-GJMW-350-4.FCMat
|
||||
Resources/Materials/StandardMaterial/Metal/Steel/Steel-EN-GJMW-360-12.FCMat
|
||||
Resources/Materials/StandardMaterial/Metal/Steel/Steel-EN-GJMW-400-5.FCMat
|
||||
Resources/Materials/StandardMaterial/Metal/Steel/Steel-EN-GJMW-450-7.FCMat
|
||||
Resources/Materials/StandardMaterial/Metal/Steel/Steel-EN-GJS-400-15.FCMat
|
||||
Resources/Materials/StandardMaterial/Metal/Steel/Steel-EN-GJS-500-7.FCMat
|
||||
Resources/Materials/StandardMaterial/Metal/Steel/Steel-EN-GJS-600-3.FCMat
|
||||
Resources/Materials/StandardMaterial/Metal/Steel/Steel-EN-GJS-700-2.FCMat
|
||||
Resources/Materials/StandardMaterial/Metal/Steel/Steel-EN-GJS-800-1.FCMat
|
||||
Resources/Materials/StandardMaterial/Metal/Steel/Steel-G16Mn5.FCMat
|
||||
Resources/Materials/StandardMaterial/Metal/Steel/Steel-G200.FCMat
|
||||
Resources/Materials/StandardMaterial/Metal/Steel/Steel-G20Mn5.FCMat
|
||||
Resources/Materials/StandardMaterial/Metal/Steel/Steel-G230.FCMat
|
||||
Resources/Materials/StandardMaterial/Metal/Steel/Steel-G260.FCMat
|
||||
Resources/Materials/StandardMaterial/Metal/Steel/Steel-G300.FCMat
|
||||
Resources/Materials/StandardMaterial/Metal/Steel/Steel-G30Mn5.FCMat
|
||||
Resources/Materials/StandardMaterial/Metal/Steel/Steel-Generic.FCMat
|
||||
Resources/Materials/StandardMaterial/Metal/Steel/Steel-S185.FCMat
|
||||
Resources/Materials/StandardMaterial/Metal/Steel/Steel-S235JO.FCMat
|
||||
Resources/Materials/StandardMaterial/Metal/Steel/Steel-S235JR.FCMat
|
||||
Resources/Materials/StandardMaterial/Metal/Steel/Steel-S235JRG1.FCMat
|
||||
Resources/Materials/StandardMaterial/Metal/Steel/Steel-S260NC.FCMat
|
||||
Resources/Materials/StandardMaterial/Metal/Steel/Steel-S275JO.FCMat
|
||||
Resources/Materials/StandardMaterial/Metal/Steel/Steel-S275JR.FCMat
|
||||
Resources/Materials/StandardMaterial/Metal/Steel/Steel-S275N.FCMat
|
||||
Resources/Materials/StandardMaterial/Metal/Steel/Steel-S335JO.FCMat
|
||||
Resources/Materials/StandardMaterial/Metal/Steel/Steel-S335JR.FCMat
|
||||
Resources/Materials/StandardMaterial/Metal/Steel/Steel-S335N.FCMat
|
||||
Resources/Materials/StandardMaterial/Metal/Steel/Steel-S340MC.FCMat
|
||||
Resources/Materials/StandardMaterial/Metal/Steel/Steel-S355J2G3.FCMat
|
||||
Resources/Materials/StandardMaterial/Metal/Steel/Steel-S380MC.FCMat
|
||||
Resources/Materials/StandardMaterial/Metal/Steel/Steel-S420MC.FCMat
|
||||
Resources/Materials/StandardMaterial/Metal/Steel/Steel-S420N.FCMat
|
||||
Resources/Materials/StandardMaterial/Metal/Steel/Steel-S460MC.FCMat
|
||||
Resources/Materials/StandardMaterial/Metal/Steel/Steel-S460N.FCMat
|
||||
Resources/Materials/StandardMaterial/Metal/Steel/Steel-S500MC.FCMat
|
||||
Resources/Materials/StandardMaterial/Metal/Steel/Steel-S550MC.FCMat
|
||||
Resources/Materials/StandardMaterial/Metal/Steel/Steel-S690MC.FCMat
|
||||
Resources/Materials/StandardMaterial/Metal/Steel/Steel-St-37-2K.FCMat
|
||||
Resources/Materials/StandardMaterial/Metal/Steel/Steel-St-E-255.FCMat
|
||||
Resources/Materials/StandardMaterial/Metal/Steel/Steel-St-E-315.FCMat
|
||||
Resources/Materials/StandardMaterial/Metal/Steel/Steel-St-E-380.FCMat
|
||||
Resources/Materials/StandardMaterial/Metal/Steel/Steel-St-E-460.FCMat
|
||||
Resources/Materials/StandardMaterial/Metal/Steel/Steel-St-E-500.FCMat
|
||||
Resources/Materials/StandardMaterial/Metal/Steel/Steel-X2CrNiMoN17-13-3.FCMat
|
||||
Resources/Materials/StandardMaterial/Metal/Steel/Steel-X2CrNiN24-4.FCMat
|
||||
Resources/Materials/StandardMaterial/Metal/Steel/Steel-X39CrMo17-1.FCMat
|
||||
Resources/Materials/StandardMaterial/Metal/Steel/Steel-X3CrNiMo13-14.FCMat
|
||||
Resources/Materials/StandardMaterial/Metal/Steel/Steel-X5CrNi18-10.FCMat
|
||||
Resources/Materials/StandardMaterial/Metal/Steel/Steel-X5CrNiMo17-12-2.FCMat
|
||||
Resources/Materials/StandardMaterial/Metal/Steel/Steel-X6CrNiTi18-10.FCMat
|
||||
Resources/Materials/StandardMaterial/Metal/Titanium/Ti-6Al-4V.FCMat
|
||||
Resources/Materials/StandardMaterial/Thermoplast/ABS-Generic.FCMat
|
||||
Resources/Materials/StandardMaterial/Thermoplast/Acrylic-Glass-Generic.FCMat
|
||||
Resources/Materials/StandardMaterial/Thermoplast/PA6-Generic.FCMat
|
||||
Resources/Materials/StandardMaterial/Thermoplast/PET-Generic.FCMat
|
||||
Resources/Materials/StandardMaterial/Thermoplast/PLA-Generic.FCMat
|
||||
Resources/Materials/StandardMaterial/Thermoplast/PP-Generic.FCMat
|
||||
Resources/Materials/StandardMaterial/Thermoplast/PTFE-Generic.FCMat
|
||||
Resources/Materials/StandardMaterial/Thermoplast/PVC-Generic.FCMat
|
||||
Resources/Materials/StandardMaterial/Wood/Wood-Generic.FCMat
|
||||
)
|
||||
|
||||
fc_target_copy_resource(Material
|
||||
SET(FluidMaterial_Files
|
||||
Resources/Materials/FluidMaterial/None.FCMat
|
||||
Resources/Materials/FluidMaterial/Air.FCMat
|
||||
Resources/Materials/FluidMaterial/Argon.FCMat
|
||||
Resources/Materials/FluidMaterial/Carbon_dioxide.FCMat
|
||||
Resources/Materials/FluidMaterial/Nitrogen.FCMat
|
||||
Resources/Materials/FluidMaterial/Water.FCMat
|
||||
)
|
||||
|
||||
SET(AppearanceLib_Files
|
||||
Resources/Materials/Appearance/Aluminum.FCMat
|
||||
Resources/Materials/Appearance/Brass.FCMat
|
||||
Resources/Materials/Appearance/Bronze.FCMat
|
||||
Resources/Materials/Appearance/Chrome.FCMat
|
||||
Resources/Materials/Appearance/Copper.FCMat
|
||||
Resources/Materials/Appearance/DefaultAppearance.FCMat
|
||||
Resources/Materials/Appearance/Emerald.FCMat
|
||||
Resources/Materials/Appearance/Gold.FCMat
|
||||
Resources/Materials/Appearance/Jade.FCMat
|
||||
Resources/Materials/Appearance/Metalized.FCMat
|
||||
Resources/Materials/Appearance/NeonGNC.FCMat
|
||||
Resources/Materials/Appearance/NeonPHC.FCMat
|
||||
Resources/Materials/Appearance/Obsidian.FCMat
|
||||
Resources/Materials/Appearance/Pewter.FCMat
|
||||
Resources/Materials/Appearance/Plaster.FCMat
|
||||
Resources/Materials/Appearance/Plastic.FCMat
|
||||
Resources/Materials/Appearance/Ruby.FCMat
|
||||
Resources/Materials/Appearance/Satin.FCMat
|
||||
Resources/Materials/Appearance/ShinyPlastic.FCMat
|
||||
Resources/Materials/Appearance/Silver.FCMat
|
||||
Resources/Materials/Appearance/Steel.FCMat
|
||||
Resources/Materials/Appearance/Stone.FCMat
|
||||
)
|
||||
|
||||
SET(MaterialModel_Files
|
||||
Resources/Models/Architectural/Architectural.yml
|
||||
Resources/Models/Costs/Costs.yml
|
||||
Resources/Models/Electromagnetic/Electromagnetic.yml
|
||||
Resources/Models/Fluid/Fluid.yml
|
||||
Resources/Models/Legacy/Father.yml
|
||||
Resources/Models/Legacy/MaterialStandard.yml
|
||||
Resources/Models/Mechanical/Density.yml
|
||||
Resources/Models/Mechanical/HypotheticalExample.yml
|
||||
Resources/Models/Mechanical/IsotropicLinearElastic.yml
|
||||
Resources/Models/Mechanical/LinearElastic.yml
|
||||
Resources/Models/Mechanical/OgdenYld2004p18.yml
|
||||
Resources/Models/Mechanical/OrthotropicLinearElastic.yml
|
||||
Resources/Models/Rendering/AdvancedRendering.yml
|
||||
Resources/Models/Rendering/BasicRendering.yml
|
||||
Resources/Models/Rendering/TextureRendering.yml
|
||||
Resources/Models/Rendering/VectorRendering.yml
|
||||
Resources/Models/Thermal/Thermal.yml
|
||||
)
|
||||
|
||||
ADD_CUSTOM_TARGET(MaterialScripts ALL
|
||||
SOURCES ${MaterialScripts_Files} ${Material_QRC_SRCS}
|
||||
)
|
||||
|
||||
fc_target_copy_resource(MaterialScripts
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_BINARY_DIR}/Mod/Material
|
||||
${Material_SRCS})
|
||||
${MaterialScripts_Files})
|
||||
|
||||
INSTALL(FILES ${MaterialScripts_Files} DESTINATION Mod/Material)
|
||||
|
||||
ADD_CUSTOM_TARGET(MaterialToolsLib ALL
|
||||
SOURCES ${MaterialTools_Files}
|
||||
@@ -191,42 +238,47 @@ fc_target_copy_resource(MaterialIconsLib
|
||||
INSTALL(FILES ${MaterialTools_Files} DESTINATION Mod/Material/materialtools)
|
||||
INSTALL(FILES ${Material_Icon_Files} DESTINATION Mod/Material/Resources/icons)
|
||||
|
||||
IF (BUILD_GUI)
|
||||
fc_target_copy_resource(Material
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
${CMAKE_BINARY_DIR}/Mod/Material
|
||||
Material_rc.py)
|
||||
ENDIF (BUILD_GUI)
|
||||
|
||||
ADD_CUSTOM_TARGET(MaterialLib ALL
|
||||
SOURCES ${MaterialLib_Files}
|
||||
)
|
||||
ADD_CUSTOM_TARGET(FluidMaterialLib ALL
|
||||
SOURCES ${FluidMaterial_Files}
|
||||
)
|
||||
ADD_CUSTOM_TARGET(AppearanceLib ALL
|
||||
SOURCES ${AppearanceLib_Files}
|
||||
)
|
||||
ADD_CUSTOM_TARGET(MaterialModelLib ALL
|
||||
SOURCES ${MaterialModel_Files}
|
||||
)
|
||||
|
||||
# When a target copies files to different output directories then apparently it always builds the project
|
||||
# which is very annoying. So, the trick is to split this into two targets to avoid this behaviour.
|
||||
fc_target_copy_resource(MaterialLib
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_DATADIR}/Mod/Material
|
||||
${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_DATADIR}/Mod/Material/
|
||||
${MaterialLib_Files})
|
||||
fc_target_copy_resource(FluidMaterialLib
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_DATADIR}/Mod/Material
|
||||
${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_DATADIR}/Mod/Material/
|
||||
${FluidMaterial_Files})
|
||||
fc_target_copy_resource(AppearanceLib
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_DATADIR}/Mod/Material/
|
||||
${AppearanceLib_Files})
|
||||
fc_target_copy_resource(MaterialModelLib
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_DATADIR}/Mod/Material/
|
||||
${MaterialModel_Files})
|
||||
|
||||
INSTALL(
|
||||
FILES ${Material_SRCS} ${Material_QRC_SRCS}
|
||||
DESTINATION Mod/Material
|
||||
)
|
||||
|
||||
INSTALL(
|
||||
DIRECTORY
|
||||
StandardMaterial
|
||||
DIRECTORY
|
||||
FluidMaterial
|
||||
DESTINATION
|
||||
${CMAKE_INSTALL_DATADIR}/Mod/Material
|
||||
FILES_MATCHING PATTERN "*.FCMat*"
|
||||
)
|
||||
foreach(file ${MaterialLib_Files} ${FluidMaterial_Files} ${AppearanceLib_Files} ${MaterialModel_Files})
|
||||
cmake_path(REMOVE_FILENAME file OUTPUT_VARIABLE filepath)
|
||||
INSTALL(
|
||||
FILES ${file}
|
||||
DESTINATION ${CMAKE_INSTALL_DATADIR}/Mod/Material/${filepath}
|
||||
)
|
||||
endforeach()
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
[General]
|
||||
Name = Air
|
||||
Description = Dry air properties at 20 Degrees Celsius and 1 atm
|
||||
MolarMass = 28.965
|
||||
Father = Gas
|
||||
|
||||
[Fluidic]
|
||||
Density = 1.204 kg/m^3
|
||||
DynamicViscosity = 1.80e-5 kg/m/s
|
||||
KinematicViscosity = 1.511e-5 m^2/s
|
||||
; PrandtlNumber is a nondimension number for CFD simulation
|
||||
PrandtlNumber = 0.7
|
||||
|
||||
[Thermal]
|
||||
SpecificHeat = 1.01 kJ/kg/K
|
||||
ThermalConductivity = 0.02587 W/m/K
|
||||
; thermal expansion coefficient of ideal gas is 1/temperature
|
||||
ThermalExpansionCoefficient = 3.43e-3 1/K
|
||||
|
||||
[Electromagnetic]
|
||||
RelativePermittivity = 1.00059
|
||||
; at 18°C and 50Hz
|
||||
ElectricalConductivity = 1e-12 S/m
|
||||
RelativePermeability = 1.0
|
||||
@@ -1,24 +0,0 @@
|
||||
[General]
|
||||
Name = Argon
|
||||
Description = Argon properties at 20 Degrees Celsius and 1 atm
|
||||
MolarMass = 39.95
|
||||
Father = Gas
|
||||
|
||||
[Fluidic]
|
||||
Density = 1.641 kg/m^3
|
||||
DynamicViscosity = 22.3e-6 kg/m/s
|
||||
; Kinematic Viscosity = Dynamic Viscosity / Density
|
||||
KinematicViscosity = 13.59-6 m^2/s
|
||||
; PrandtlNumber is a nondimension number for CFD simulation
|
||||
PrandtlNumber = 0.7
|
||||
|
||||
[Thermal]
|
||||
SpecificHeat = 0.520 kJ/kg/K
|
||||
ThermalConductivity = 0.018 W/m/K
|
||||
; thermal expansion coefficient of ideal gas is 1/temperature
|
||||
ThermalExpansionCoefficient = 3.43e-3 1/K
|
||||
|
||||
[Electromagnetic]
|
||||
RelativePermittivity = 1.000513
|
||||
ElectricalConductivity = 1e-15 S/m
|
||||
RelativePermeability = 1.0
|
||||
@@ -1,24 +0,0 @@
|
||||
[General]
|
||||
Name = Carbon dioxide
|
||||
Description = Carbon dioxide properties at 20 Degrees Celsius and 1 atm
|
||||
MolarMass = 44.009
|
||||
Father = Gas
|
||||
|
||||
[Fluidic]
|
||||
Density = 1.8393 kg/m^3
|
||||
DynamicViscosity = 14.7e-6 kg/m/s
|
||||
; Kinematic Viscosity = Dynamic Viscosity / Density
|
||||
KinematicViscosity = 8.09e-6 m^2/s
|
||||
; PrandtlNumber is a nondimension number for CFD simulation
|
||||
PrandtlNumber = 0.7651
|
||||
|
||||
[Thermal]
|
||||
SpecificHeat = 0.8460 kJ/kg/K
|
||||
ThermalConductivity = 0.016242 W/m/K
|
||||
; thermal expansion coefficient of ideal gas is 1/temperature
|
||||
ThermalExpansionCoefficient = 3.43e-3 1/K
|
||||
|
||||
[Electromagnetic]
|
||||
RelativePermittivity = 1.0009217
|
||||
ElectricalConductivity = 1e-12 S/m
|
||||
RelativePermeability = 1.0
|
||||
@@ -1,24 +0,0 @@
|
||||
[General]
|
||||
Name = Nitrogen
|
||||
Description = Nitrogen properties at 20 Degrees Celsius and 1 atm
|
||||
MolarMass = 14.007
|
||||
Father = Gas
|
||||
|
||||
[Fluidic]
|
||||
Density = 1.2506 kg/m^3
|
||||
DynamicViscosity = 17.58e-6 kg/m/s
|
||||
; Kinematic Viscosity = Dynamic Viscosity / Density
|
||||
KinematicViscosity = 14.06e-6 m^2/s
|
||||
; PrandtlNumber is a nondimension number for CFD simulation
|
||||
PrandtlNumber = 0.7
|
||||
|
||||
[Thermal]
|
||||
SpecificHeat = 1.04 kJ/kg/K
|
||||
ThermalConductivity = 25.83e-3 W/m/K
|
||||
; thermal expansion coefficient of ideal gas is 1/temperature
|
||||
ThermalExpansionCoefficient = 3.43e-3 1/K
|
||||
|
||||
[Electromagnetic]
|
||||
RelativePermittivity = 1.00058
|
||||
ElectricalConductivity = 1e-12 S/m
|
||||
RelativePermeability = 1.0
|
||||
@@ -1,15 +0,0 @@
|
||||
; None means nothing, as the starting point of making a new fluid material
|
||||
|
||||
[General]
|
||||
Name = None
|
||||
Description = "None"
|
||||
|
||||
[Fluidic]
|
||||
Density = 0 kg/m^3
|
||||
DynamicViscosity = 0 kg/m/s
|
||||
KinematicViscosity = 0 m^2/s
|
||||
|
||||
[Thermal]
|
||||
SpecificHeat = 0 J/kg/K
|
||||
ThermalConductivity = 0 W/m/K
|
||||
ThermalExpansionCoefficient = 0 1/K
|
||||
@@ -1,31 +0,0 @@
|
||||
# FreeCAD fluid material library
|
||||
|
||||
It's intended to gather the most common fluid properties, water, air, which are useful for other modules and workbenches.
|
||||
|
||||
## User defined material
|
||||
|
||||
To prevent the database from becoming inefficiently large it is only limited to commonly used variables at 20 degrees Celsius at 1 atm.
|
||||
|
||||
Users can defined new material, either in Fem material card editor, or directly generate textual material file, * .FCMat, see example in this folder.
|
||||
|
||||
To enable new material, go to FreeCAD menu "Edit->Preference..." Cfd preference page (select on the left panel) and switch to materiai tab on the right.
|
||||
|
||||
Browse to your material folder, and save/apply this preference, new material will be Material with same name as FreeCAD material has higher priority, so user defined `Water` material will not appear in Fem material task panel's dropbox list, just give it a different name!
|
||||
|
||||
### Edit material value
|
||||
|
||||
Please verify the fluid material properties before use. It aims to serve as a quick reference and does not aim to be an extended look up table.
|
||||
|
||||
|
||||
## Add new material to Material module
|
||||
|
||||
1. follow examples in material folders to create new material file
|
||||
2. stick to the meta data definition in `src/Mod/Material/Templatematerial.yml` for property name
|
||||
3. add the file name into the `src/Mod/Material/CMakeLists.txt` , so the new files can be installed to the properly place during compiling and installation.
|
||||
|
||||
## Changelog
|
||||
|
||||
CfdOF module authored 5 material types, values are taken from FM White (2011) Fluid Mechanics.
|
||||
|
||||
Currently, 3 (Water, Air, None) are merged into Fem module and maintained by Cfd module author, Qingfeng Xia
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
; see meta data definition in the file: src/Mod/Material/Templatematerial.yml
|
||||
[General]
|
||||
Name = Water
|
||||
Description = Standard distilled water properties at 20 Degrees Celsius and 1 atm
|
||||
MolarMass = 18
|
||||
Father = Gas
|
||||
ReferenceSource = ''
|
||||
|
||||
[Fluidic]
|
||||
Density = 998 kg/m^3
|
||||
DynamicViscosity = 1.003e-3 kg/m/s
|
||||
KinematicViscosity = 1.005e-6 m^2/s
|
||||
; PrandtlNumber is a nondimension number for CFD simulation
|
||||
PrandtlNumber = 7.56
|
||||
|
||||
[Thermal]
|
||||
SpecificHeat = 4182 J/kg/K
|
||||
ThermalConductivity = 0.591 W/m/K
|
||||
; https://en.wikipedia.org/wiki/Water
|
||||
ThermalExpansionCoefficient = 2.07e-4 m/m/K
|
||||
|
||||
[Electromagnetic]
|
||||
RelativePermittivity = 80.0
|
||||
; at 20°C and 50Hz
|
||||
ElectricalConductivity = 5.5e-6 S/m
|
||||
RelativePermeability = 0.999992
|
||||
106
src/Mod/Material/Gui/AppMatGui.cpp
Normal file
106
src/Mod/Material/Gui/AppMatGui.cpp
Normal file
@@ -0,0 +1,106 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
|
||||
* *
|
||||
* 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 *
|
||||
* <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
**************************************************************************/
|
||||
|
||||
|
||||
#include "PreCompiled.h"
|
||||
#ifndef _PreComp_
|
||||
#endif
|
||||
|
||||
#include <Base/Console.h>
|
||||
#include <Base/Interpreter.h>
|
||||
#include <Base/PyObjectBase.h>
|
||||
#include <Gui/Application.h>
|
||||
#include <Gui/Language/Translator.h>
|
||||
#include <Gui/WidgetFactory.h>
|
||||
|
||||
#include "DlgSettingsMaterial.h"
|
||||
#include "Workbench.h"
|
||||
|
||||
// use a different name to CreateCommand()
|
||||
void CreateMaterialCommands();
|
||||
|
||||
void loadMaterialResource()
|
||||
{
|
||||
// add resources and reloads the translators
|
||||
Q_INIT_RESOURCE(Material);
|
||||
Q_INIT_RESOURCE(Material_translation);
|
||||
Gui::Translator::instance()->refresh();
|
||||
}
|
||||
|
||||
namespace MatGui
|
||||
{
|
||||
class Module: public Py::ExtensionModule<Module>
|
||||
{
|
||||
public:
|
||||
Module()
|
||||
: Py::ExtensionModule<Module>("MatGui")
|
||||
{
|
||||
initialize("This module is the MatGui module."); // register with Python
|
||||
}
|
||||
|
||||
~Module() override
|
||||
{}
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
PyObject* initModule()
|
||||
{
|
||||
return Base::Interpreter().addModule(new Module);
|
||||
}
|
||||
|
||||
} // namespace MatGui
|
||||
|
||||
PyMOD_INIT_FUNC(MatGui)
|
||||
{
|
||||
if (!Gui::Application::Instance) {
|
||||
PyErr_SetString(PyExc_ImportError, "Cannot load Gui module in console application.");
|
||||
PyMOD_Return(nullptr);
|
||||
}
|
||||
|
||||
// load needed modules
|
||||
try {
|
||||
Base::Interpreter().runString("import Material");
|
||||
}
|
||||
catch (const Base::Exception& e) {
|
||||
PyErr_SetString(PyExc_ImportError, e.what());
|
||||
PyMOD_Return(nullptr);
|
||||
}
|
||||
|
||||
PyObject* matGuiModule = MatGui::initModule();
|
||||
|
||||
Base::Console().Log("Loading GUI of Material module... done\n");
|
||||
|
||||
MatGui::Workbench ::init();
|
||||
|
||||
// instantiating the commands
|
||||
CreateMaterialCommands();
|
||||
|
||||
// register preferences pages on Material, the order here will be the order of the tabs in pref
|
||||
// widget
|
||||
new Gui::PrefPageProducer<MatGui::DlgSettingsMaterial>(
|
||||
QT_TRANSLATE_NOOP("QObject", "Material"));
|
||||
|
||||
// add resources and reloads the translators
|
||||
loadMaterialResource();
|
||||
|
||||
PyMOD_Return(matGuiModule);
|
||||
}
|
||||
158
src/Mod/Material/Gui/Array2D.cpp
Normal file
158
src/Mod/Material/Gui/Array2D.cpp
Normal file
@@ -0,0 +1,158 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
|
||||
* *
|
||||
* 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 *
|
||||
* <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
**************************************************************************/
|
||||
|
||||
#include "PreCompiled.h"
|
||||
#ifndef _PreComp_
|
||||
#include <QMessageBox>
|
||||
#endif
|
||||
|
||||
#include <Gui/MainWindow.h>
|
||||
|
||||
#include <Mod/Material/App/Exceptions.h>
|
||||
#include <Mod/Material/App/Materials.h>
|
||||
|
||||
#include "Array2D.h"
|
||||
#include "ArrayDelegate.h"
|
||||
#include "ArrayModel.h"
|
||||
#include "ui_Array2D.h"
|
||||
|
||||
|
||||
using namespace MatGui;
|
||||
|
||||
/* TRANSLATOR MatGui::Array2D */
|
||||
|
||||
Array2D::Array2D(const QString& propertyName, Materials::Material* material, QWidget* parent)
|
||||
: QDialog(parent)
|
||||
, ui(new Ui_Array2D)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
if (material->hasPhysicalProperty(propertyName)) {
|
||||
_property = &(material->getPhysicalProperty(propertyName));
|
||||
}
|
||||
else if (material->hasAppearanceProperty(propertyName)) {
|
||||
_property = &(material->getAppearanceProperty(propertyName));
|
||||
}
|
||||
else {
|
||||
_property = nullptr;
|
||||
}
|
||||
if (_property) {
|
||||
_value =
|
||||
std::static_pointer_cast<Materials::Material2DArray>(_property->getMaterialValue());
|
||||
}
|
||||
else {
|
||||
_value = nullptr;
|
||||
}
|
||||
|
||||
setupDefault();
|
||||
setupArray();
|
||||
|
||||
connect(ui->standardButtons, &QDialogButtonBox::accepted, this, &Array2D::accept);
|
||||
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 = QString::fromStdString("Default ") + column1.getName();
|
||||
ui->labelDefault->setText(label);
|
||||
if (column1.getPropertyType() == QString::fromStdString("Quantity")) {
|
||||
ui->editDefault->setMinimum(std::numeric_limits<double>::min());
|
||||
ui->editDefault->setMaximum(std::numeric_limits<double>::max());
|
||||
ui->editDefault->setUnitText(_property->getColumnUnits(0));
|
||||
ui->editDefault->setValue(_value->getDefault().getValue().value<Base::Quantity>());
|
||||
|
||||
connect(ui->editDefault,
|
||||
qOverload<const Base::Quantity&>(&Gui::QuantitySpinBox::valueChanged),
|
||||
this,
|
||||
&Array2D::defaultValueChanged);
|
||||
}
|
||||
}
|
||||
catch (const Materials::PropertyNotFound&) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void Array2D::setHeaders(QStandardItemModel* model)
|
||||
{
|
||||
QStringList headers;
|
||||
auto columns = _property->getColumns();
|
||||
for (auto column = columns.begin(); column != columns.end(); column++) {
|
||||
headers.append(column->getName());
|
||||
}
|
||||
model->setHorizontalHeaderLabels(headers);
|
||||
}
|
||||
|
||||
void Array2D::setColumnWidths(QTableView* table)
|
||||
{
|
||||
int length = _property->columns();
|
||||
for (int i = 0; i < length; i++) {
|
||||
table->setColumnWidth(i, 100);
|
||||
}
|
||||
}
|
||||
|
||||
void Array2D::setColumnDelegates(QTableView* table)
|
||||
{
|
||||
int length = _property->columns();
|
||||
for (int i = 0; i < length; i++) {
|
||||
const Materials::MaterialProperty& column = _property->getColumn(i);
|
||||
table->setItemDelegateForColumn(
|
||||
i,
|
||||
new ArrayDelegate(column.getType(), column.getUnits(), this));
|
||||
}
|
||||
}
|
||||
|
||||
void Array2D::setupArray()
|
||||
{
|
||||
if (_property == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto table = ui->tableView;
|
||||
auto model = new Array2DModel(_property, _value, this);
|
||||
table->setModel(model);
|
||||
table->setEditTriggers(QAbstractItemView::AllEditTriggers);
|
||||
|
||||
setColumnWidths(table);
|
||||
setColumnDelegates(table);
|
||||
}
|
||||
|
||||
void Array2D::defaultValueChanged(const Base::Quantity& value)
|
||||
{
|
||||
_value->setDefault(QVariant::fromValue(value));
|
||||
}
|
||||
|
||||
void Array2D::accept()
|
||||
{
|
||||
QDialog::accept();
|
||||
}
|
||||
|
||||
void Array2D::reject()
|
||||
{
|
||||
QDialog::reject();
|
||||
}
|
||||
|
||||
#include "moc_Array2D.cpp"
|
||||
67
src/Mod/Material/Gui/Array2D.h
Normal file
67
src/Mod/Material/Gui/Array2D.h
Normal file
@@ -0,0 +1,67 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
|
||||
* *
|
||||
* 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 *
|
||||
* <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef MATGUI_ARRAY2D_H
|
||||
#define MATGUI_ARRAY2D_H
|
||||
|
||||
#include <QAbstractTableModel>
|
||||
#include <QDialog>
|
||||
#include <QStandardItem>
|
||||
#include <QTableView>
|
||||
|
||||
#include "ArrayModel.h"
|
||||
#include <Mod/Material/App/Model.h>
|
||||
|
||||
namespace MatGui
|
||||
{
|
||||
|
||||
class Ui_Array2D;
|
||||
|
||||
class Array2D: public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit Array2D(const QString& propertyName,
|
||||
Materials::Material* material,
|
||||
QWidget* parent = nullptr);
|
||||
~Array2D() override = default;
|
||||
|
||||
void defaultValueChanged(const Base::Quantity& value);
|
||||
|
||||
void accept() override;
|
||||
void reject() override;
|
||||
|
||||
private:
|
||||
std::unique_ptr<Ui_Array2D> ui;
|
||||
const Materials::MaterialProperty* _property;
|
||||
std::shared_ptr<Materials::Material2DArray> _value;
|
||||
|
||||
void setupDefault();
|
||||
void setHeaders(QStandardItemModel* model);
|
||||
void setColumnWidths(QTableView* table);
|
||||
void setColumnDelegates(QTableView* table);
|
||||
void setupArray();
|
||||
};
|
||||
|
||||
} // namespace MatGui
|
||||
|
||||
#endif // MATGUI_ARRAY2D_H
|
||||
92
src/Mod/Material/Gui/Array2D.ui
Normal file
92
src/Mod/Material/Gui/Array2D.ui
Normal file
@@ -0,0 +1,92 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>MatGui::Array2D</class>
|
||||
<widget class="QDialog" name="MatGui::Array2D">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>578</width>
|
||||
<height>557</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>2D Array</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="labelDefault">
|
||||
<property name="text">
|
||||
<string>Default Value</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Gui::QuantitySpinBox" name="editDefault" native="true">
|
||||
<property name="unit" stdset="0">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QTableView" name="tableView"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="standardButtons">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>Gui::QuantitySpinBox</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>Gui/QuantitySpinBox.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>standardButtons</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>MatGui::Array2D</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>248</x>
|
||||
<y>254</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>standardButtons</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>MatGui::Array2D</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>316</x>
|
||||
<y>260</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
||||
198
src/Mod/Material/Gui/Array3D.cpp
Normal file
198
src/Mod/Material/Gui/Array3D.cpp
Normal file
@@ -0,0 +1,198 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
|
||||
* *
|
||||
* 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 *
|
||||
* <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
**************************************************************************/
|
||||
|
||||
#include "PreCompiled.h"
|
||||
#ifndef _PreComp_
|
||||
#include <QMessageBox>
|
||||
#include <QPushButton>
|
||||
#endif
|
||||
|
||||
#include <Gui/MainWindow.h>
|
||||
|
||||
#include <Mod/Material/App/Exceptions.h>
|
||||
#include <Mod/Material/App/Materials.h>
|
||||
|
||||
#include "Array3D.h"
|
||||
#include "ArrayDelegate.h"
|
||||
#include "ArrayModel.h"
|
||||
#include "ui_Array3D.h"
|
||||
|
||||
|
||||
using namespace MatGui;
|
||||
|
||||
Array3D::Array3D(const QString& propertyName, Materials::Material* material, QWidget* parent)
|
||||
: QDialog(parent)
|
||||
, ui(new Ui_Array3D)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
if (material->hasPhysicalProperty(propertyName)) {
|
||||
_property = &(material->getPhysicalProperty(propertyName));
|
||||
}
|
||||
else if (material->hasAppearanceProperty(propertyName)) {
|
||||
_property = &(material->getAppearanceProperty(propertyName));
|
||||
}
|
||||
else {
|
||||
_property = nullptr;
|
||||
}
|
||||
if (_property) {
|
||||
_value =
|
||||
std::static_pointer_cast<Materials::Material3DArray>(_property->getMaterialValue());
|
||||
}
|
||||
else {
|
||||
_value = nullptr;
|
||||
}
|
||||
|
||||
setupDefault();
|
||||
setupDepthArray();
|
||||
setupArray();
|
||||
|
||||
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,
|
||||
&Array3D::onOk);
|
||||
connect(ui->standardButtons->button(QDialogButtonBox::Cancel),
|
||||
&QPushButton::clicked,
|
||||
this,
|
||||
&Array3D::onCancel);
|
||||
}
|
||||
|
||||
bool Array3D::onSplitter(QEvent* e)
|
||||
{
|
||||
Q_UNUSED(e)
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void Array3D::setupDefault()
|
||||
{
|
||||
if (_property == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
auto& column1 = _property->getColumn(0);
|
||||
QString label = QString::fromStdString("Default ") + column1.getName();
|
||||
ui->labelDefault->setText(label);
|
||||
if (column1.getPropertyType() == QString::fromStdString("Quantity")) {
|
||||
ui->editDefault->setMinimum(std::numeric_limits<double>::min());
|
||||
ui->editDefault->setMaximum(std::numeric_limits<double>::max());
|
||||
ui->editDefault->setUnitText(_property->getColumnUnits(0));
|
||||
ui->editDefault->setValue(_value->getDefault().getValue().value<Base::Quantity>());
|
||||
|
||||
connect(ui->editDefault,
|
||||
qOverload<const Base::Quantity&>(&Gui::QuantitySpinBox::valueChanged),
|
||||
this,
|
||||
&Array3D::defaultValueChanged);
|
||||
}
|
||||
}
|
||||
catch (const Materials::PropertyNotFound&) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void Array3D::defaultValueChanged(const Base::Quantity& value)
|
||||
{
|
||||
_value->setDefault(QVariant::fromValue(value));
|
||||
}
|
||||
|
||||
void Array3D::setDepthColumnDelegate(QTableView* table)
|
||||
{
|
||||
auto& column = _property->getColumn(0);
|
||||
table->setItemDelegateForColumn(0,
|
||||
new ArrayDelegate(column.getType(), column.getUnits(), this));
|
||||
}
|
||||
|
||||
void Array3D::setDepthColumnWidth(QTableView* table)
|
||||
{
|
||||
table->setColumnWidth(0, 100);
|
||||
}
|
||||
|
||||
void Array3D::setupDepthArray()
|
||||
{
|
||||
if (_property == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto table = ui->table3D;
|
||||
auto model = new Array3DDepthModel(_property, _value, this);
|
||||
table->setModel(model);
|
||||
table->setEditTriggers(QAbstractItemView::AllEditTriggers);
|
||||
|
||||
setDepthColumnWidth(table);
|
||||
setDepthColumnDelegate(table);
|
||||
}
|
||||
|
||||
void Array3D::setColumnWidths(QTableView* table)
|
||||
{
|
||||
int length = _property->columns();
|
||||
for (int i = 0; i < length; i++) {
|
||||
table->setColumnWidth(i, 100);
|
||||
}
|
||||
}
|
||||
|
||||
void Array3D::setColumnDelegates(QTableView* table)
|
||||
{
|
||||
int length = _property->columns();
|
||||
for (int i = 0; i < length; i++) {
|
||||
auto& column = _property->getColumn(i);
|
||||
table->setItemDelegateForColumn(
|
||||
i,
|
||||
new ArrayDelegate(column.getType(), column.getUnits(), this));
|
||||
}
|
||||
}
|
||||
|
||||
void Array3D::setupArray()
|
||||
{
|
||||
if (_property == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto table = ui->table2D;
|
||||
auto model = new Array3DModel(_property, _value, this);
|
||||
table->setModel(model);
|
||||
table->setEditTriggers(QAbstractItemView::AllEditTriggers);
|
||||
|
||||
setColumnWidths(table);
|
||||
setColumnDelegates(table);
|
||||
}
|
||||
|
||||
void Array3D::onOk(bool checked)
|
||||
{
|
||||
Q_UNUSED(checked)
|
||||
|
||||
QDialog::accept();
|
||||
}
|
||||
|
||||
void Array3D::onCancel(bool checked)
|
||||
{
|
||||
Q_UNUSED(checked)
|
||||
|
||||
QDialog::reject();
|
||||
}
|
||||
|
||||
#include "moc_Array3D.cpp"
|
||||
66
src/Mod/Material/Gui/Array3D.h
Normal file
66
src/Mod/Material/Gui/Array3D.h
Normal file
@@ -0,0 +1,66 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
|
||||
* *
|
||||
* 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 *
|
||||
* <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef MATGUI_ARRAY3D_H
|
||||
#define MATGUI_ARRAY3D_H
|
||||
|
||||
#include <QDialog>
|
||||
#include <QStandardItem>
|
||||
#include <QTableView>
|
||||
|
||||
namespace MatGui
|
||||
{
|
||||
|
||||
class Ui_Array3D;
|
||||
|
||||
class Array3D: public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit Array3D(const QString& propertyName,
|
||||
Materials::Material* material,
|
||||
QWidget* parent = nullptr);
|
||||
~Array3D() override = default;
|
||||
|
||||
void defaultValueChanged(const Base::Quantity& value);
|
||||
bool onSplitter(QEvent* e);
|
||||
|
||||
void onOk(bool checked);
|
||||
void onCancel(bool checked);
|
||||
|
||||
private:
|
||||
std::unique_ptr<Ui_Array3D> ui;
|
||||
const Materials::MaterialProperty* _property;
|
||||
std::shared_ptr<Materials::Material3DArray> _value;
|
||||
|
||||
void setupDefault();
|
||||
void setDepthColumnWidth(QTableView* table);
|
||||
void setDepthColumnDelegate(QTableView* table);
|
||||
void setupDepthArray();
|
||||
void setColumnWidths(QTableView* table);
|
||||
void setColumnDelegates(QTableView* table);
|
||||
void setupArray();
|
||||
};
|
||||
|
||||
} // namespace MatGui
|
||||
|
||||
#endif // MATGUI_ARRAY3D_H
|
||||
104
src/Mod/Material/Gui/Array3D.ui
Normal file
104
src/Mod/Material/Gui/Array3D.ui
Normal file
@@ -0,0 +1,104 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>MatGui::Array3D</class>
|
||||
<widget class="QDialog" name="MatGui::Array3D">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>915</width>
|
||||
<height>709</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>3D Array</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="labelDefault">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Default Value</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Gui::QuantitySpinBox" name="editDefault" native="true">
|
||||
<property name="unit" stdset="0">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSplitter" name="splitter">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<widget class="QTableView" name="table3D"/>
|
||||
<widget class="QTableView" name="table2D"/>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="standardButtons">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>Gui::QuantitySpinBox</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>Gui/QuantitySpinBox.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>standardButtons</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>MatGui::Array3D</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>248</x>
|
||||
<y>254</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>standardButtons</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>MatGui::Array3D</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>316</x>
|
||||
<y>260</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
||||
183
src/Mod/Material/Gui/ArrayDelegate.cpp
Normal file
183
src/Mod/Material/Gui/ArrayDelegate.cpp
Normal file
@@ -0,0 +1,183 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
|
||||
* *
|
||||
* 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 *
|
||||
* <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
**************************************************************************/
|
||||
|
||||
#include "PreCompiled.h"
|
||||
#ifndef _PreComp_
|
||||
#include <QColorDialog>
|
||||
#include <QDesktopServices>
|
||||
#include <QIODevice>
|
||||
#include <QItemSelectionModel>
|
||||
#include <QPainter>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QTextStream>
|
||||
#include <QVariant>
|
||||
#endif
|
||||
|
||||
#include <limits>
|
||||
|
||||
#include <App/Application.h>
|
||||
#include <Base/Interpreter.h>
|
||||
#include <Base/Quantity.h>
|
||||
#include <Gui/Application.h>
|
||||
#include <Gui/Command.h>
|
||||
#include <Gui/InputField.h>
|
||||
#include <Gui/PrefWidgets.h>
|
||||
#include <Gui/SpinBox.h>
|
||||
#include <Gui/WaitCursor.h>
|
||||
// #include <Gui/FileDialog.h>
|
||||
|
||||
#include <Mod/Material/App/Exceptions.h>
|
||||
#include <Mod/Material/App/ModelManager.h>
|
||||
|
||||
#include "Array2D.h"
|
||||
#include "Array3D.h"
|
||||
#include "ArrayDelegate.h"
|
||||
#include "MaterialSave.h"
|
||||
|
||||
|
||||
using namespace MatGui;
|
||||
|
||||
ArrayDelegate::ArrayDelegate(Materials::MaterialValue::ValueType type,
|
||||
QString units,
|
||||
QObject* parent)
|
||||
: QStyledItemDelegate(parent)
|
||||
, _type(type)
|
||||
, _units(units)
|
||||
{}
|
||||
|
||||
void ArrayDelegate::paint(QPainter* painter,
|
||||
const QStyleOptionViewItem& option,
|
||||
const QModelIndex& index) const
|
||||
{
|
||||
|
||||
if (_type == Materials::MaterialValue::Quantity) {
|
||||
const AbstractArrayModel* tableModel =
|
||||
reinterpret_cast<const AbstractArrayModel*>(index.model());
|
||||
painter->save();
|
||||
|
||||
if (tableModel->newRow(index)) {
|
||||
painter->drawText(option.rect, 0, QString());
|
||||
}
|
||||
else {
|
||||
QVariant item = tableModel->data(index);
|
||||
Base::Quantity quantity = item.value<Base::Quantity>();
|
||||
QString text = quantity.getUserString();
|
||||
painter->drawText(option.rect, 0, text);
|
||||
}
|
||||
|
||||
painter->restore();
|
||||
}
|
||||
else {
|
||||
QStyledItemDelegate::paint(painter, option, index);
|
||||
}
|
||||
}
|
||||
|
||||
void ArrayDelegate::setEditorData(QWidget* editor, const QModelIndex& index) const
|
||||
{
|
||||
Base::Console().Log("ArrayDelegate::setEditorData()\n");
|
||||
|
||||
if (_type == Materials::MaterialValue::Quantity) {
|
||||
QAbstractItemModel* tableModel = const_cast<QAbstractItemModel*>(index.model());
|
||||
auto item = tableModel->data(index);
|
||||
|
||||
// Gui::InputField* input = static_cast<Gui::InputField*>(editor);
|
||||
// input->setText(item.toString());
|
||||
Gui::QuantitySpinBox* input = static_cast<Gui::QuantitySpinBox*>(editor);
|
||||
input->setValue(item.value<Base::Quantity>());
|
||||
}
|
||||
else {
|
||||
QStyledItemDelegate::setEditorData(editor, index);
|
||||
}
|
||||
}
|
||||
|
||||
QWidget* ArrayDelegate::createEditor(QWidget* parent,
|
||||
const QStyleOptionViewItem&,
|
||||
const QModelIndex& index) const
|
||||
{
|
||||
Base::Console().Log("ArrayDelegate::createEditor()\n");
|
||||
|
||||
const QAbstractTableModel* tableModel = static_cast<const QAbstractTableModel*>(index.model());
|
||||
auto item = tableModel->data(index);
|
||||
|
||||
QWidget* editor = createWidget(parent, item);
|
||||
|
||||
return editor;
|
||||
}
|
||||
|
||||
QWidget* ArrayDelegate::createWidget(QWidget* parent, const QVariant& item) const
|
||||
{
|
||||
QWidget* widget = nullptr;
|
||||
|
||||
if (_type == Materials::MaterialValue::String || _type == Materials::MaterialValue::URL
|
||||
|| _type == Materials::MaterialValue::List) {
|
||||
widget = new Gui::PrefLineEdit(parent);
|
||||
}
|
||||
else if (_type == Materials::MaterialValue::Integer) {
|
||||
Gui::UIntSpinBox* spinner = new Gui::UIntSpinBox(parent);
|
||||
spinner->setMinimum(0);
|
||||
spinner->setMaximum(UINT_MAX);
|
||||
spinner->setValue(item.toUInt());
|
||||
widget = spinner;
|
||||
}
|
||||
else if (_type == Materials::MaterialValue::Float) {
|
||||
Gui::DoubleSpinBox* 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<double>::min());
|
||||
spinner->setMaximum(std::numeric_limits<double>::max());
|
||||
spinner->setValue(item.toDouble());
|
||||
widget = spinner;
|
||||
}
|
||||
else if (_type == Materials::MaterialValue::Boolean) {
|
||||
Gui::PrefComboBox* combo = new Gui::PrefComboBox(parent);
|
||||
combo->insertItem(0, QString::fromStdString(""));
|
||||
combo->insertItem(1, QString::fromStdString("False"));
|
||||
combo->insertItem(2, QString::fromStdString("True"));
|
||||
combo->setCurrentText(item.toString());
|
||||
widget = combo;
|
||||
}
|
||||
else if (_type == Materials::MaterialValue::Quantity) {
|
||||
Gui::QuantitySpinBox* input = new Gui::QuantitySpinBox();
|
||||
input->setMinimum(std::numeric_limits<double>::min());
|
||||
input->setMaximum(std::numeric_limits<double>::max());
|
||||
input->setUnitText(_units);
|
||||
input->setValue(item.value<Base::Quantity>());
|
||||
|
||||
widget = input;
|
||||
}
|
||||
else {
|
||||
// Default editor
|
||||
widget = new QLineEdit(parent);
|
||||
}
|
||||
|
||||
widget->setParent(parent);
|
||||
|
||||
return widget;
|
||||
}
|
||||
|
||||
#include "moc_ArrayDelegate.cpp"
|
||||
74
src/Mod/Material/Gui/ArrayDelegate.h
Normal file
74
src/Mod/Material/Gui/ArrayDelegate.h
Normal file
@@ -0,0 +1,74 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
|
||||
* *
|
||||
* 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 *
|
||||
* <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef MATGUI_ArrayDelegate_H
|
||||
#define MATGUI_ArrayDelegate_H
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
#include <QDialog>
|
||||
#include <QDir>
|
||||
#include <QStandardItem>
|
||||
#include <QStyledItemDelegate>
|
||||
#include <QSvgWidget>
|
||||
#include <QTreeView>
|
||||
|
||||
#include <Mod/Material/App/MaterialManager.h>
|
||||
#include <Mod/Material/App/Materials.h>
|
||||
#include <Mod/Material/App/ModelManager.h>
|
||||
|
||||
namespace fs = boost::filesystem;
|
||||
|
||||
namespace MatGui
|
||||
{
|
||||
|
||||
class ArrayDelegate: public QStyledItemDelegate
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ArrayDelegate(
|
||||
Materials::MaterialValue::ValueType type = Materials::MaterialValue::None,
|
||||
QString units = QString(),
|
||||
QObject* parent = nullptr);
|
||||
virtual ~ArrayDelegate() = default;
|
||||
|
||||
void paint(QPainter* painter,
|
||||
const QStyleOptionViewItem& option,
|
||||
const QModelIndex& index) const override;
|
||||
QWidget* createEditor(QWidget* parent,
|
||||
const QStyleOptionViewItem&,
|
||||
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;
|
||||
|
||||
QWidget* createWidget(QWidget* parent, const QVariant& item) const;
|
||||
};
|
||||
|
||||
} // namespace MatGui
|
||||
|
||||
#endif // MATGUI_ArrayDelegate_H
|
||||
465
src/Mod/Material/Gui/ArrayModel.cpp
Normal file
465
src/Mod/Material/Gui/ArrayModel.cpp
Normal file
@@ -0,0 +1,465 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
|
||||
* *
|
||||
* 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 *
|
||||
* <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
**************************************************************************/
|
||||
|
||||
#include "PreCompiled.h"
|
||||
#ifndef _PreComp_
|
||||
#include <QMessageBox>
|
||||
#endif
|
||||
|
||||
#include <QMetaType>
|
||||
|
||||
#include <Gui/MainWindow.h>
|
||||
#include <Gui/MetaTypes.h>
|
||||
|
||||
#include <Mod/Material/App/Exceptions.h>
|
||||
#include <Mod/Material/App/Materials.h>
|
||||
|
||||
#include "ArrayModel.h"
|
||||
|
||||
|
||||
using namespace MatGui;
|
||||
|
||||
/* TRANSLATOR MatGui::ArrayModel */
|
||||
|
||||
AbstractArrayModel::AbstractArrayModel(QObject* parent)
|
||||
: QAbstractTableModel(parent)
|
||||
{}
|
||||
|
||||
//===
|
||||
|
||||
|
||||
Array2DModel::Array2DModel(const Materials::MaterialProperty* property,
|
||||
std::shared_ptr<Materials::Material2DArray> value,
|
||||
QObject* parent)
|
||||
: AbstractArrayModel(parent)
|
||||
, _property(property)
|
||||
, _value(value)
|
||||
{}
|
||||
|
||||
int Array2DModel::rowCount(const QModelIndex& parent) const
|
||||
{
|
||||
if (parent.isValid()) {
|
||||
return 0; // No children
|
||||
}
|
||||
|
||||
return _value->rows() + 1; // Will always have 1 empty row
|
||||
}
|
||||
|
||||
bool Array2DModel::newRow(const QModelIndex& index) const
|
||||
{
|
||||
return (index.row() == _value->rows());
|
||||
}
|
||||
|
||||
int Array2DModel::columnCount(const QModelIndex& parent) const
|
||||
{
|
||||
Q_UNUSED(parent);
|
||||
|
||||
return _property->columns();
|
||||
}
|
||||
|
||||
QVariant Array2DModel::data(const QModelIndex& index, int role) const
|
||||
{
|
||||
if (role == Qt::DisplayRole) {
|
||||
try {
|
||||
return _value->getValue(index.row(), index.column());
|
||||
}
|
||||
catch (const Materials::InvalidIndex&) {
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
catch (const Materials::InvalidColumn&) {
|
||||
}
|
||||
|
||||
return QString();
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
QVariant Array2DModel::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 QAbstractTableModel::headerData(section, orientation, role);
|
||||
}
|
||||
|
||||
bool Array2DModel::setData(const QModelIndex& index, const QVariant& value, int role)
|
||||
{
|
||||
Q_UNUSED(role);
|
||||
|
||||
if (index.row() == _value->rows()) {
|
||||
insertRows(index.row(), 1);
|
||||
}
|
||||
_value->setValue(index.row(), index.column(), value);
|
||||
|
||||
Q_EMIT dataChanged(index, index);
|
||||
return true;
|
||||
}
|
||||
|
||||
Qt::ItemFlags Array2DModel::flags(const QModelIndex& index) const
|
||||
{
|
||||
return (QAbstractTableModel::flags(index) | Qt::ItemIsEditable);
|
||||
}
|
||||
|
||||
|
||||
// Resizing functions
|
||||
bool Array2DModel::insertRows(int row, int count, const QModelIndex& parent)
|
||||
{
|
||||
beginInsertRows(parent, row, row + count - 1);
|
||||
|
||||
int columns = columnCount();
|
||||
for (int i = 0; i < count; i++) {
|
||||
std::vector<QVariant>* rowPtr = new std::vector<QVariant>();
|
||||
for (int j = 0; j < columns; j++) {
|
||||
rowPtr->push_back(_property->getColumnNull(j));
|
||||
}
|
||||
|
||||
_value->insertRow(row, rowPtr);
|
||||
}
|
||||
|
||||
endInsertRows();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Array2DModel::removeRows(int row, int count, const QModelIndex& parent)
|
||||
{
|
||||
beginRemoveRows(parent, row, row + count - 1);
|
||||
|
||||
endRemoveRows();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Array2DModel::insertColumns(int column, int count, const QModelIndex& parent)
|
||||
{
|
||||
Q_UNUSED(column);
|
||||
Q_UNUSED(count);
|
||||
Q_UNUSED(parent);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Array2DModel::removeColumns(int column, int count, const QModelIndex& parent)
|
||||
{
|
||||
Q_UNUSED(column);
|
||||
Q_UNUSED(count);
|
||||
Q_UNUSED(parent);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//===
|
||||
|
||||
Array3DDepthModel::Array3DDepthModel(const Materials::MaterialProperty* property,
|
||||
std::shared_ptr<Materials::Material3DArray> value,
|
||||
QObject* parent)
|
||||
: AbstractArrayModel(parent)
|
||||
, _property(property)
|
||||
, _value(value)
|
||||
{}
|
||||
|
||||
int Array3DDepthModel::rowCount(const QModelIndex& parent) const
|
||||
{
|
||||
if (parent.isValid()) {
|
||||
return 0; // No children
|
||||
}
|
||||
|
||||
return _value->depth() + 1; // Will always have 1 empty row
|
||||
}
|
||||
|
||||
bool Array3DDepthModel::newRow(const QModelIndex& index) const
|
||||
{
|
||||
return (index.row() == _value->depth());
|
||||
}
|
||||
|
||||
QVariant Array3DDepthModel::data(const QModelIndex& index, int role) const
|
||||
{
|
||||
if (role == Qt::DisplayRole) {
|
||||
try {
|
||||
return _value->getValue(index.row(), index.column());
|
||||
}
|
||||
catch (const Materials::InvalidIndex&) {
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
catch (const Materials::InvalidColumn&) {
|
||||
}
|
||||
|
||||
return QString();
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
QVariant Array3DDepthModel::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 QAbstractTableModel::headerData(section, orientation, role);
|
||||
}
|
||||
|
||||
bool Array3DDepthModel::setData(const QModelIndex& index, const QVariant& value, int role)
|
||||
{
|
||||
Q_UNUSED(role);
|
||||
|
||||
if (index.row() == _value->depth()) {
|
||||
insertRows(index.row(), 1);
|
||||
}
|
||||
_value->setValue(index.row(), index.column(), value);
|
||||
|
||||
Q_EMIT dataChanged(index, index);
|
||||
return true;
|
||||
}
|
||||
|
||||
Qt::ItemFlags Array3DDepthModel::flags(const QModelIndex& index) const
|
||||
{
|
||||
return (QAbstractTableModel::flags(index) | Qt::ItemIsEditable);
|
||||
}
|
||||
|
||||
|
||||
// Resizing functions
|
||||
bool Array3DDepthModel::insertRows(int row, int count, const QModelIndex& parent)
|
||||
{
|
||||
beginInsertRows(parent, row, row + count - 1);
|
||||
|
||||
int columns = columnCount();
|
||||
for (int i = 0; i < count; i++) {
|
||||
std::vector<QVariant>* rowPtr = new std::vector<QVariant>();
|
||||
for (int j = 0; j < columns; j++) {
|
||||
rowPtr->push_back(_property->getColumnNull(j));
|
||||
}
|
||||
|
||||
// _value->insertRow(row, rowPtr);
|
||||
}
|
||||
|
||||
endInsertRows();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Array3DDepthModel::removeRows(int row, int count, const QModelIndex& parent)
|
||||
{
|
||||
beginRemoveRows(parent, row, row + count - 1);
|
||||
|
||||
endRemoveRows();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Array3DDepthModel::insertColumns(int column, int count, const QModelIndex& parent)
|
||||
{
|
||||
Q_UNUSED(column);
|
||||
Q_UNUSED(count);
|
||||
Q_UNUSED(parent);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Array3DDepthModel::removeColumns(int column, int count, const QModelIndex& parent)
|
||||
{
|
||||
Q_UNUSED(column);
|
||||
Q_UNUSED(count);
|
||||
Q_UNUSED(parent);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//===
|
||||
|
||||
Array3DModel::Array3DModel(const Materials::MaterialProperty* property,
|
||||
std::shared_ptr<Materials::Material3DArray> value,
|
||||
QObject* parent)
|
||||
: AbstractArrayModel(parent)
|
||||
, _property(property)
|
||||
, _value(value)
|
||||
{}
|
||||
|
||||
int Array3DModel::rowCount(const QModelIndex& parent) const
|
||||
{
|
||||
if (parent.isValid()) {
|
||||
return 0; // No children
|
||||
}
|
||||
|
||||
return _value->depth() + 1; // Will always have 1 empty row
|
||||
}
|
||||
|
||||
int Array3DModel::columnCount(const QModelIndex& parent) const
|
||||
{
|
||||
Q_UNUSED(parent);
|
||||
|
||||
return _property->columns() - 1;
|
||||
}
|
||||
|
||||
bool Array3DModel::newRow(const QModelIndex& index) const
|
||||
{
|
||||
return (index.row() == _value->depth());
|
||||
}
|
||||
|
||||
QVariant Array3DModel::data(const QModelIndex& index, int role) const
|
||||
{
|
||||
if (role == Qt::DisplayRole) {
|
||||
Base::Console().Error("Row %d, column %d\n", index.row(), index.column());
|
||||
try {
|
||||
return _value->getValue(index.row(), index.column() + 1);
|
||||
}
|
||||
catch (const Materials::InvalidIndex&) {
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
Base::Console().Error("The error message is: %s\n", e.what());
|
||||
}
|
||||
|
||||
try {
|
||||
auto column = _property->getColumnType(index.column() + 1);
|
||||
if (column == Materials::MaterialValue::Quantity) {
|
||||
Base::Quantity q = Base::Quantity(0, _property->getColumnUnits(index.column() - 1));
|
||||
return QVariant::fromValue(q);
|
||||
}
|
||||
}
|
||||
catch (const Materials::InvalidColumn&) {
|
||||
}
|
||||
|
||||
return QString();
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
QVariant Array3DModel::headerData(int section, Qt::Orientation orientation, int role) const
|
||||
{
|
||||
if (role == Qt::DisplayRole) {
|
||||
if (orientation == Qt::Horizontal) {
|
||||
const Materials::MaterialProperty& column = _property->getColumn(section + 1);
|
||||
return QVariant(column.getName());
|
||||
}
|
||||
else if (orientation == Qt::Vertical) {
|
||||
// Vertical header
|
||||
if (section == (rowCount() - 1)) {
|
||||
return QVariant(QString::fromStdString("*"));
|
||||
}
|
||||
return QVariant(section + 1);
|
||||
}
|
||||
}
|
||||
|
||||
return QAbstractTableModel::headerData(section, orientation, role);
|
||||
}
|
||||
|
||||
bool Array3DModel::setData(const QModelIndex& index, const QVariant& value, int role)
|
||||
{
|
||||
Q_UNUSED(role);
|
||||
|
||||
if (index.row() == _value->depth()) {
|
||||
insertRows(index.row(), 1);
|
||||
}
|
||||
_value->setValue(index.row(), index.column(), value);
|
||||
|
||||
Q_EMIT dataChanged(index, index);
|
||||
return true;
|
||||
}
|
||||
|
||||
Qt::ItemFlags Array3DModel::flags(const QModelIndex& index) const
|
||||
{
|
||||
return (QAbstractTableModel::flags(index) | Qt::ItemIsEditable);
|
||||
}
|
||||
|
||||
|
||||
// Resizing functions
|
||||
bool Array3DModel::insertRows(int row, int count, const QModelIndex& parent)
|
||||
{
|
||||
beginInsertRows(parent, row, row + count - 1);
|
||||
|
||||
int columns = columnCount();
|
||||
for (int i = 0; i < count; i++) {
|
||||
std::vector<QVariant>* rowPtr = new std::vector<QVariant>();
|
||||
for (int j = 0; j < columns; j++) {
|
||||
rowPtr->push_back(_property->getColumnNull(j));
|
||||
}
|
||||
|
||||
// _value->insertRow(row, rowPtr);
|
||||
}
|
||||
|
||||
endInsertRows();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Array3DModel::removeRows(int row, int count, const QModelIndex& parent)
|
||||
{
|
||||
beginRemoveRows(parent, row, row + count - 1);
|
||||
|
||||
endRemoveRows();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Array3DModel::insertColumns(int column, int count, const QModelIndex& parent)
|
||||
{
|
||||
Q_UNUSED(column);
|
||||
Q_UNUSED(count);
|
||||
Q_UNUSED(parent);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Array3DModel::removeColumns(int column, int count, const QModelIndex& parent)
|
||||
{
|
||||
Q_UNUSED(column);
|
||||
Q_UNUSED(count);
|
||||
Q_UNUSED(parent);
|
||||
|
||||
return false;
|
||||
}
|
||||
138
src/Mod/Material/Gui/ArrayModel.h
Normal file
138
src/Mod/Material/Gui/ArrayModel.h
Normal file
@@ -0,0 +1,138 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
|
||||
* *
|
||||
* 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 *
|
||||
* <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef MATGUI_ARRAYMODEL_H
|
||||
#define MATGUI_ARRAYMODEL_H
|
||||
|
||||
#include <QAbstractTableModel>
|
||||
#include <QDialog>
|
||||
#include <QStandardItem>
|
||||
#include <QTableView>
|
||||
|
||||
#include <Mod/Material/App/Materials.h>
|
||||
#include <Mod/Material/App/Model.h>
|
||||
|
||||
namespace MatGui
|
||||
{
|
||||
|
||||
class AbstractArrayModel: public QAbstractTableModel
|
||||
{
|
||||
public:
|
||||
explicit AbstractArrayModel(QObject* parent = nullptr);
|
||||
~AbstractArrayModel() override = default;
|
||||
|
||||
virtual bool newRow(const QModelIndex& index) const = 0;
|
||||
};
|
||||
|
||||
class Array2DModel: public AbstractArrayModel
|
||||
{
|
||||
public:
|
||||
explicit Array2DModel(const Materials::MaterialProperty* property = nullptr,
|
||||
std::shared_ptr<Materials::Material2DArray> value = nullptr,
|
||||
QObject* parent = nullptr);
|
||||
~Array2DModel() override = default;
|
||||
|
||||
// Overridden virtual functions
|
||||
int rowCount(const QModelIndex& parent = QModelIndex()) const override;
|
||||
bool newRow(const QModelIndex& index) const override;
|
||||
int columnCount(const QModelIndex& parent = QModelIndex()) const override;
|
||||
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
|
||||
QVariant
|
||||
headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
|
||||
bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole) override;
|
||||
Qt::ItemFlags flags(const QModelIndex& index) const override;
|
||||
|
||||
// Resizing functions
|
||||
bool insertRows(int row, int count, const QModelIndex& parent = QModelIndex()) override;
|
||||
bool removeRows(int row, int count, const QModelIndex& parent = QModelIndex()) override;
|
||||
bool insertColumns(int column, int count, const QModelIndex& parent = QModelIndex()) override;
|
||||
bool removeColumns(int column, int count, const QModelIndex& parent = QModelIndex()) override;
|
||||
|
||||
private:
|
||||
const Materials::MaterialProperty* _property;
|
||||
std::shared_ptr<Materials::Material2DArray> _value;
|
||||
};
|
||||
|
||||
class Array3DDepthModel: public AbstractArrayModel
|
||||
{
|
||||
public:
|
||||
explicit Array3DDepthModel(const Materials::MaterialProperty* property = nullptr,
|
||||
std::shared_ptr<Materials::Material3DArray> value = nullptr,
|
||||
QObject* parent = nullptr);
|
||||
~Array3DDepthModel() override = default;
|
||||
|
||||
// Overridden virtual functions
|
||||
int rowCount(const QModelIndex& parent = QModelIndex()) const override;
|
||||
bool newRow(const QModelIndex& index) const override;
|
||||
int columnCount(const QModelIndex& parent = QModelIndex()) const override
|
||||
{
|
||||
Q_UNUSED(parent)
|
||||
return 1;
|
||||
}
|
||||
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
|
||||
QVariant
|
||||
headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
|
||||
bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole) override;
|
||||
Qt::ItemFlags flags(const QModelIndex& index) const override;
|
||||
|
||||
// Resizing functions
|
||||
bool insertRows(int row, int count, const QModelIndex& parent = QModelIndex()) override;
|
||||
bool removeRows(int row, int count, const QModelIndex& parent = QModelIndex()) override;
|
||||
bool insertColumns(int column, int count, const QModelIndex& parent = QModelIndex()) override;
|
||||
bool removeColumns(int column, int count, const QModelIndex& parent = QModelIndex()) override;
|
||||
|
||||
private:
|
||||
const Materials::MaterialProperty* _property;
|
||||
std::shared_ptr<Materials::Material3DArray> _value;
|
||||
};
|
||||
|
||||
class Array3DModel: public AbstractArrayModel
|
||||
{
|
||||
public:
|
||||
explicit Array3DModel(const Materials::MaterialProperty* property = nullptr,
|
||||
std::shared_ptr<Materials::Material3DArray> value = nullptr,
|
||||
QObject* parent = nullptr);
|
||||
~Array3DModel() override = default;
|
||||
|
||||
// Overridden virtual functions
|
||||
int rowCount(const QModelIndex& parent = QModelIndex()) const override;
|
||||
bool newRow(const QModelIndex& index) const override;
|
||||
int columnCount(const QModelIndex& parent = QModelIndex()) const override;
|
||||
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
|
||||
QVariant
|
||||
headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
|
||||
bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole) override;
|
||||
Qt::ItemFlags flags(const QModelIndex& index) const override;
|
||||
|
||||
// Resizing functions
|
||||
bool insertRows(int row, int count, const QModelIndex& parent = QModelIndex()) override;
|
||||
bool removeRows(int row, int count, const QModelIndex& parent = QModelIndex()) override;
|
||||
bool insertColumns(int column, int count, const QModelIndex& parent = QModelIndex()) override;
|
||||
bool removeColumns(int column, int count, const QModelIndex& parent = QModelIndex()) override;
|
||||
|
||||
private:
|
||||
const Materials::MaterialProperty* _property;
|
||||
std::shared_ptr<Materials::Material3DArray> _value;
|
||||
};
|
||||
|
||||
} // namespace MatGui
|
||||
|
||||
#endif // MATGUI_ARRAYMODEL_H
|
||||
107
src/Mod/Material/Gui/CMakeLists.txt
Normal file
107
src/Mod/Material/Gui/CMakeLists.txt
Normal file
@@ -0,0 +1,107 @@
|
||||
if(MSVC)
|
||||
add_definitions(-DHAVE_ACOSH -DHAVE_ATANH -DHAVE_ASINH)
|
||||
else(MSVC)
|
||||
add_definitions(-DHAVE_LIMITS_H -DHAVE_CONFIG_H)
|
||||
endif(MSVC)
|
||||
|
||||
include_directories(
|
||||
${CMAKE_BINARY_DIR}
|
||||
${CMAKE_SOURCE_DIR}/src
|
||||
${CMAKE_BINARY_DIR}/src
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
${Boost_INCLUDE_DIRS}
|
||||
${COIN3D_INCLUDE_DIRS}
|
||||
${OCC_INCLUDE_DIR}
|
||||
${PYTHON_INCLUDE_DIRS}
|
||||
${XercesC_INCLUDE_DIRS}
|
||||
${ZLIB_INCLUDE_DIR}
|
||||
)
|
||||
link_directories(${OCC_LIBRARY_DIR})
|
||||
|
||||
set(MatGui_LIBS
|
||||
Material
|
||||
FreeCADGui
|
||||
)
|
||||
|
||||
include_directories(
|
||||
${QtConcurrent_INCLUDE_DIRS}
|
||||
)
|
||||
list(APPEND MatGui_LIBS
|
||||
${QtConcurrent_LIBRARIES}
|
||||
)
|
||||
|
||||
set(Material_TR_QRC ${CMAKE_CURRENT_BINARY_DIR}/Resources/Material_translation.qrc)
|
||||
qt_find_and_add_translation(QM_SRCS "Resources/translations/*_*.ts"
|
||||
${CMAKE_CURRENT_BINARY_DIR}/Resources/translations)
|
||||
qt_create_resource_file(${Material_TR_QRC} ${QM_SRCS})
|
||||
qt_add_resources(MatGui_QRC_SRCS Resources/Material.qrc ${Material_TR_QRC})
|
||||
|
||||
set(MatGui_UIC_SRCS
|
||||
Array2D.ui
|
||||
Array3D.ui
|
||||
DlgSettingsMaterial.ui
|
||||
MaterialSave.ui
|
||||
MaterialsEditor.ui
|
||||
ModelSelect.ui
|
||||
)
|
||||
|
||||
SET(MatGui_SRCS
|
||||
${MatGui_QRC_SRCS}
|
||||
${MatGui_UIC_HDRS}
|
||||
AppMatGui.cpp
|
||||
Array2D.cpp
|
||||
Array2D.h
|
||||
Array2D.ui
|
||||
Array3D.cpp
|
||||
Array3D.h
|
||||
Array3D.ui
|
||||
ArrayDelegate.cpp
|
||||
ArrayDelegate.h
|
||||
ArrayModel.cpp
|
||||
ArrayModel.h
|
||||
Command.cpp
|
||||
DlgSettingsMaterial.cpp
|
||||
DlgSettingsMaterial.h
|
||||
DlgSettingsMaterial.ui
|
||||
MaterialDelegate.cpp
|
||||
MaterialDelegate.h
|
||||
MaterialSave.cpp
|
||||
MaterialSave.h
|
||||
MaterialSave.ui
|
||||
MaterialsEditor.cpp
|
||||
MaterialsEditor.h
|
||||
MaterialsEditor.ui
|
||||
ModelSelect.cpp
|
||||
ModelSelect.h
|
||||
ModelSelect.ui
|
||||
PreCompiled.cpp
|
||||
PreCompiled.h
|
||||
Workbench.cpp
|
||||
Workbench.h
|
||||
)
|
||||
|
||||
if(FREECAD_USE_PCH)
|
||||
add_definitions(-D_PreComp_)
|
||||
GET_MSVC_PRECOMPILED_SOURCE("PreCompiled.cpp" PCH_SRCS ${MatGui_SRCS})
|
||||
ADD_MSVC_PRECOMPILED_HEADER(MatGui PreCompiled.h PreCompiled.cpp PCH_SRCS)
|
||||
endif(FREECAD_USE_PCH)
|
||||
|
||||
SET(MatGuiIcon_SVG
|
||||
Resources/icons/Materials_Edit.svg
|
||||
Resources/icons/MaterialWorkbench.svg
|
||||
Resources/icons/preferences-material.svg
|
||||
Resources/icons/preview-rendered.svg
|
||||
Resources/icons/preview-vector.svg
|
||||
Resources/icons/table.svg
|
||||
)
|
||||
|
||||
add_library(MatGui SHARED ${MatGui_SRCS} ${MatGuiIcon_SVG})
|
||||
target_link_libraries(MatGui ${MatGui_LIBS})
|
||||
|
||||
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})
|
||||
|
||||
INSTALL(TARGETS MatGui DESTINATION ${CMAKE_INSTALL_LIBDIR})
|
||||
INSTALL(FILES ${MatGuiIcon_SVG} DESTINATION "${CMAKE_INSTALL_DATADIR}/Mod/Material/Resources/icons")
|
||||
81
src/Mod/Material/Gui/Command.cpp
Normal file
81
src/Mod/Material/Gui/Command.cpp
Normal file
@@ -0,0 +1,81 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
|
||||
* *
|
||||
* 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 *
|
||||
* <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
**************************************************************************/
|
||||
|
||||
#include "PreCompiled.h"
|
||||
#ifndef _PreComp_
|
||||
#include <QPointer>
|
||||
#endif
|
||||
|
||||
#include <Gui/Command.h>
|
||||
#include <Gui/MainWindow.h>
|
||||
|
||||
#include "MaterialSave.h"
|
||||
#include "MaterialsEditor.h"
|
||||
#include "ModelSelect.h"
|
||||
|
||||
|
||||
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
//===========================================================================
|
||||
// Material_Edit
|
||||
//===========================================================================
|
||||
DEF_STD_CMD_A(CmdMaterialsEdit)
|
||||
|
||||
CmdMaterialsEdit::CmdMaterialsEdit()
|
||||
: Command("Materials_Edit")
|
||||
{
|
||||
sAppModule = "Material";
|
||||
sGroup = QT_TR_NOOP("Material");
|
||||
sMenuText = QT_TR_NOOP("Edit...");
|
||||
sToolTipText = QT_TR_NOOP("Edit material properties");
|
||||
sWhatsThis = "Materials_Edit";
|
||||
sStatusTip = sToolTipText;
|
||||
sPixmap = "Materials_Edit";
|
||||
}
|
||||
|
||||
void CmdMaterialsEdit::activated(int iMsg)
|
||||
{
|
||||
Q_UNUSED(iMsg);
|
||||
|
||||
Base::Console().Log("Materials_Edit\n");
|
||||
|
||||
static QPointer<QDialog> dlg = nullptr;
|
||||
if (!dlg) {
|
||||
dlg = new MatGui::MaterialsEditor(Gui::getMainWindow());
|
||||
}
|
||||
dlg->setAttribute(Qt::WA_DeleteOnClose);
|
||||
dlg->show();
|
||||
}
|
||||
|
||||
bool CmdMaterialsEdit::isActive()
|
||||
{
|
||||
// return (hasActiveDocument() && !Gui::Control().activeDialog());
|
||||
return true;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------
|
||||
|
||||
void CreateMaterialCommands()
|
||||
{
|
||||
Gui::CommandManager& rcCmdMgr = Gui::Application::Instance->commandManager();
|
||||
|
||||
rcCmdMgr.addCommand(new CmdMaterialsEdit());
|
||||
}
|
||||
78
src/Mod/Material/Gui/DlgSettingsMaterial.cpp
Normal file
78
src/Mod/Material/Gui/DlgSettingsMaterial.cpp
Normal file
@@ -0,0 +1,78 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
|
||||
* *
|
||||
* 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 *
|
||||
* <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
**************************************************************************/
|
||||
|
||||
#include "PreCompiled.h"
|
||||
|
||||
#include "DlgSettingsMaterial.h"
|
||||
#include "ui_DlgSettingsMaterial.h"
|
||||
|
||||
|
||||
using namespace MatGui;
|
||||
|
||||
DlgSettingsMaterial::DlgSettingsMaterial(QWidget* parent)
|
||||
: PreferencePage(parent)
|
||||
, ui(new Ui_DlgSettingsMaterial)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
}
|
||||
|
||||
void DlgSettingsMaterial::saveSettings()
|
||||
{
|
||||
ui->cb_use_built_in_materials->onSave();
|
||||
ui->cb_use_mat_from_workbenches->onSave();
|
||||
ui->cb_use_mat_from_config_dir->onSave();
|
||||
ui->cb_use_mat_from_custom_dir->onSave();
|
||||
ui->fc_custom_mat_dir->onSave();
|
||||
ui->cb_delete_duplicates->onSave();
|
||||
ui->cb_sort_by_resources->onSave();
|
||||
|
||||
// Temporary for testing
|
||||
ui->cb_legacy_editor->onSave();
|
||||
}
|
||||
|
||||
void DlgSettingsMaterial::loadSettings()
|
||||
{
|
||||
ui->cb_use_built_in_materials->onRestore();
|
||||
ui->cb_use_mat_from_workbenches->onRestore();
|
||||
ui->cb_use_mat_from_config_dir->onRestore();
|
||||
ui->cb_use_mat_from_custom_dir->onRestore();
|
||||
ui->fc_custom_mat_dir->onRestore();
|
||||
ui->cb_delete_duplicates->onRestore();
|
||||
ui->cb_sort_by_resources->onRestore();
|
||||
|
||||
// Temporary for testing
|
||||
ui->cb_legacy_editor->onRestore();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the strings of the subwidgets using the current language.
|
||||
*/
|
||||
void DlgSettingsMaterial::changeEvent(QEvent* e)
|
||||
{
|
||||
if (e->type() == QEvent::LanguageChange) {
|
||||
ui->retranslateUi(this);
|
||||
}
|
||||
else {
|
||||
QWidget::changeEvent(e);
|
||||
}
|
||||
}
|
||||
|
||||
#include "moc_DlgSettingsMaterial.cpp"
|
||||
52
src/Mod/Material/Gui/DlgSettingsMaterial.h
Normal file
52
src/Mod/Material/Gui/DlgSettingsMaterial.h
Normal file
@@ -0,0 +1,52 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
|
||||
* *
|
||||
* 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 *
|
||||
* <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef MATGUI_DLGSETTINGSMATERIAL_H
|
||||
#define MATGUI_DLGSETTINGSMATERIAL_H
|
||||
|
||||
#include <Gui/PropertyPage.h>
|
||||
#include <memory>
|
||||
|
||||
|
||||
namespace MatGui
|
||||
{
|
||||
class Ui_DlgSettingsMaterial;
|
||||
|
||||
class DlgSettingsMaterial: public Gui::Dialog::PreferencePage
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit DlgSettingsMaterial(QWidget* parent = nullptr);
|
||||
~DlgSettingsMaterial() override = default;
|
||||
|
||||
protected:
|
||||
void saveSettings() override;
|
||||
void loadSettings() override;
|
||||
void changeEvent(QEvent* e) override;
|
||||
|
||||
private:
|
||||
std::unique_ptr<Ui_DlgSettingsMaterial> ui;
|
||||
};
|
||||
|
||||
} // namespace MatGui
|
||||
|
||||
#endif // MATGUI_DLGSETTINGSMATERIAL_H
|
||||
@@ -1,17 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>FemGui::DlgSettingsFemMaterialImp</class>
|
||||
<widget class="QWidget" name="FemGui::DlgSettingsFemMaterialImp">
|
||||
<class>MatGui::DlgSettingsMaterial</class>
|
||||
<widget class="QWidget" name="MatGui::DlgSettingsMaterial">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>434</width>
|
||||
<height>229</height>
|
||||
<height>341</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Material</string>
|
||||
<string>General</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="spacing">
|
||||
@@ -44,6 +44,25 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Gui::PrefCheckBox" name="cb_use_mat_from_workbenches">
|
||||
<property name="toolTip">
|
||||
<string>Use materials added by external workbenches.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Use materials from external workbenches</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="prefEntry" stdset="0">
|
||||
<cstring>UseMaterialsFromWorkbenches</cstring>
|
||||
</property>
|
||||
<property name="prefPath" stdset="0">
|
||||
<cstring>Mod/Material/Resources</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Gui::PrefCheckBox" name="cb_use_mat_from_config_dir">
|
||||
<property name="toolTip">
|
||||
@@ -124,9 +143,6 @@ will be listed as available.</string>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="mode">
|
||||
<enum>Gui::FileChooser::Directory</enum>
|
||||
</property>
|
||||
<property name="prefEntry" stdset="0">
|
||||
<cstring>CustomMaterialsDir</cstring>
|
||||
</property>
|
||||
@@ -190,6 +206,31 @@ If unchecked, they will be sorted by their name.</string>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="gb_materials_testing">
|
||||
<property name="title">
|
||||
<string>Testing</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||
<item>
|
||||
<widget class="Gui::PrefCheckBox" name="cb_legacy_editor">
|
||||
<property name="text">
|
||||
<string>Use legacy editor</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="prefEntry" stdset="0">
|
||||
<cstring>LegacyEditor</cstring>
|
||||
</property>
|
||||
<property name="prefPath" stdset="0">
|
||||
<cstring>Mod/Material/Cards</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
@@ -226,9 +267,7 @@ If unchecked, they will be sorted by their name.</string>
|
||||
<header>Gui/PrefWidgets.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources>
|
||||
<include location="Resources/Fem.qrc"/>
|
||||
</resources>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>cb_use_mat_from_custom_dir</sender>
|
||||
465
src/Mod/Material/Gui/MaterialDelegate.cpp
Normal file
465
src/Mod/Material/Gui/MaterialDelegate.cpp
Normal file
@@ -0,0 +1,465 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
|
||||
* *
|
||||
* 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 *
|
||||
* <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
**************************************************************************/
|
||||
|
||||
#include "PreCompiled.h"
|
||||
#ifndef _PreComp_
|
||||
#include <QColorDialog>
|
||||
#include <QDesktopServices>
|
||||
#include <QIODevice>
|
||||
#include <QItemSelectionModel>
|
||||
#include <QPainter>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QTextStream>
|
||||
#include <QVariant>
|
||||
#endif
|
||||
|
||||
#include <limits>
|
||||
|
||||
#include <App/Application.h>
|
||||
#include <Base/Interpreter.h>
|
||||
#include <Base/Quantity.h>
|
||||
#include <Gui/Application.h>
|
||||
#include <Gui/Command.h>
|
||||
#include <Gui/InputField.h>
|
||||
#include <Gui/PrefWidgets.h>
|
||||
#include <Gui/SpinBox.h>
|
||||
#include <Gui/WaitCursor.h>
|
||||
|
||||
#include <Mod/Material/App/Exceptions.h>
|
||||
#include <Mod/Material/App/ModelManager.h>
|
||||
|
||||
#include "Array2D.h"
|
||||
#include "Array3D.h"
|
||||
#include "MaterialDelegate.h"
|
||||
#include "MaterialSave.h"
|
||||
|
||||
|
||||
using namespace MatGui;
|
||||
|
||||
MaterialDelegate::MaterialDelegate(QObject* parent)
|
||||
: QStyledItemDelegate(parent)
|
||||
{}
|
||||
|
||||
bool MaterialDelegate::editorEvent(QEvent* event,
|
||||
QAbstractItemModel* model,
|
||||
const QStyleOptionViewItem& option,
|
||||
const QModelIndex& index)
|
||||
{
|
||||
if (index.column() == 1) {
|
||||
if (event->type() == QEvent::MouseButtonDblClick) {
|
||||
const QStandardItemModel* treeModel =
|
||||
static_cast<const QStandardItemModel*>(index.model());
|
||||
|
||||
// Check we're not the material model root. This is also used to access the entry
|
||||
// columns
|
||||
auto item = treeModel->itemFromIndex(index);
|
||||
auto group = item->parent();
|
||||
if (!group) {
|
||||
return QStyledItemDelegate::editorEvent(event, model, option, 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 == "Color") {
|
||||
Base::Console().Log("Edit color\n");
|
||||
showColorModal(item);
|
||||
// Mark as handled
|
||||
return true;
|
||||
}
|
||||
else if (type == "2DArray") {
|
||||
Base::Console().Log("Edit 2DArray\n");
|
||||
showArray2DModal(propertyName, item);
|
||||
// Mark as handled
|
||||
return true;
|
||||
}
|
||||
else if (type == "3DArray") {
|
||||
Base::Console().Log("Edit 3DArray\n");
|
||||
showArray3DModal(propertyName, item);
|
||||
// Mark as handled
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return QStyledItemDelegate::editorEvent(event, model, option, index);
|
||||
}
|
||||
|
||||
void MaterialDelegate::showColorModal(QStandardItem* item)
|
||||
{
|
||||
QColor currentColor; // = d->col;
|
||||
currentColor.setRgba(parseColor(item->text()));
|
||||
QColorDialog* dlg = new QColorDialog(currentColor);
|
||||
|
||||
dlg->setAttribute(Qt::WA_DeleteOnClose);
|
||||
if (Gui::DialogOptions::dontUseNativeColorDialog()) {
|
||||
dlg->setOptions(QColorDialog::DontUseNativeDialog);
|
||||
}
|
||||
dlg->setOption(QColorDialog::ColorDialogOption::ShowAlphaChannel, false);
|
||||
|
||||
dlg->setCurrentColor(currentColor);
|
||||
dlg->adjustSize();
|
||||
|
||||
connect(dlg, &QColorDialog::finished, this, [&](int result) {
|
||||
if (result == QDialog::Accepted) {
|
||||
QColor color = dlg->selectedColor();
|
||||
if (color.isValid()) {
|
||||
QString colorText = QString(QString::fromStdString("(%1,%2,%3,%4)"))
|
||||
.arg(color.red() / 255.0)
|
||||
.arg(color.green() / 255.0)
|
||||
.arg(color.blue() / 255.0)
|
||||
.arg(color.alpha() / 255.0);
|
||||
item->setText(colorText);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
dlg->exec();
|
||||
}
|
||||
|
||||
void MaterialDelegate::showArray2DModal(const QString& propertyName, QStandardItem* item)
|
||||
{
|
||||
Materials::Material* material = item->data().value<Materials::Material*>();
|
||||
Array2D* dlg = new Array2D(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::showArray3DModal(const QString& propertyName, QStandardItem* item)
|
||||
{
|
||||
Materials::Material* material = item->data().value<Materials::Material*>();
|
||||
Array3D* dlg = new Array3D(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::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<const QStandardItemModel*>(index.model());
|
||||
|
||||
// Check we're not the material model root. This is also used to access the entry columns
|
||||
auto item = treeModel->itemFromIndex(index);
|
||||
auto group = item->parent();
|
||||
if (!group) {
|
||||
QStyledItemDelegate::paint(painter, option, index);
|
||||
return;
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
QString propertyValue = QString::fromStdString("");
|
||||
if (group->child(row, 1)) {
|
||||
propertyValue = group->child(row, 1)->text();
|
||||
}
|
||||
|
||||
std::string type = propertyType.toStdString();
|
||||
if (type == "Color") {
|
||||
painter->save();
|
||||
|
||||
QColor color;
|
||||
color.setRgba(parseColor(propertyValue));
|
||||
int left = option.rect.left() + 5;
|
||||
int 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();
|
||||
return;
|
||||
}
|
||||
else if (type == "2DArray" || type == "3DArray") {
|
||||
// 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;
|
||||
}
|
||||
|
||||
QStyledItemDelegate::paint(painter, option, index);
|
||||
}
|
||||
|
||||
QSize MaterialDelegate::sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const
|
||||
{
|
||||
if (index.column() != 1) {
|
||||
return QStyledItemDelegate::sizeHint(option, index);
|
||||
}
|
||||
|
||||
const QStandardItemModel* treeModel = static_cast<const QStandardItemModel*>(index.model());
|
||||
|
||||
// Check we're not the material model root. This is also used to access the entry columns
|
||||
auto item = treeModel->itemFromIndex(index);
|
||||
auto group = item->parent();
|
||||
if (!group) {
|
||||
return QStyledItemDelegate::sizeHint(option, index);
|
||||
}
|
||||
|
||||
int row = index.row();
|
||||
|
||||
QString propertyType = QString::fromStdString("String");
|
||||
if (group->child(row, 2)) {
|
||||
propertyType = group->child(row, 2)->text();
|
||||
}
|
||||
|
||||
std::string type = propertyType.toStdString();
|
||||
if (type == "Color") {
|
||||
return QSize(75, 23); // Standard QPushButton size
|
||||
}
|
||||
else if (type == "2DArray" || type == "3DArray") {
|
||||
return QSize(23, 23);
|
||||
}
|
||||
|
||||
return QStyledItemDelegate::sizeHint(option, index);
|
||||
}
|
||||
|
||||
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<const QStandardItemModel*>(index.model());
|
||||
QStandardItem* item = model->itemFromIndex(index);
|
||||
auto group = item->parent();
|
||||
if (!group) {
|
||||
return;
|
||||
}
|
||||
|
||||
int row = index.row();
|
||||
QString propertyName = group->child(row, 0)->text();
|
||||
|
||||
std::string type = propertyType.toString().toStdString();
|
||||
if (type == "File") {
|
||||
Gui::FileChooser* chooser = static_cast<Gui::FileChooser*>(editor);
|
||||
item->setText(chooser->fileName());
|
||||
}
|
||||
else if (type == "Quantity") {
|
||||
Gui::InputField* input = static_cast<Gui::InputField*>(editor);
|
||||
item->setText(input->getQuantityString());
|
||||
}
|
||||
else {
|
||||
QStyledItemDelegate::setEditorData(editor, index);
|
||||
}
|
||||
|
||||
// Q_EMIT const_cast<MaterialDelegate *>(this)->propertyChange(propertyName, item->text());
|
||||
}
|
||||
|
||||
void MaterialDelegate::setModelData(QWidget* editor,
|
||||
QAbstractItemModel* model,
|
||||
const QModelIndex& index) const
|
||||
{
|
||||
QStyledItemDelegate::setModelData(editor, model, index);
|
||||
|
||||
QStandardItem* item = static_cast<const QStandardItemModel*>(model)->itemFromIndex(index);
|
||||
auto group = item->parent();
|
||||
if (!group) {
|
||||
return;
|
||||
}
|
||||
|
||||
int row = index.row();
|
||||
QString propertyName = group->child(row, 0)->text();
|
||||
Q_EMIT const_cast<MaterialDelegate*>(this)->propertyChange(propertyName, item->text());
|
||||
}
|
||||
|
||||
QWidget* MaterialDelegate::createEditor(QWidget* parent,
|
||||
const QStyleOptionViewItem&,
|
||||
const QModelIndex& index) const
|
||||
{
|
||||
Base::Console().Log("MaterialsEditor::createEditor()\n");
|
||||
if (index.column() != 1) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const QStandardItemModel* treeModel = static_cast<const QStandardItemModel*>(index.model());
|
||||
|
||||
// Check we're not the material model root. This is also used to access the entry columns
|
||||
auto item = treeModel->itemFromIndex(index);
|
||||
auto group = item->parent();
|
||||
if (!group) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
QString propertyValue = QString::fromStdString("");
|
||||
if (group->child(row, 1)) {
|
||||
propertyValue = group->child(row, 1)->text();
|
||||
}
|
||||
|
||||
QString propertyUnits = QString::fromStdString("");
|
||||
if (group->child(row, 1)) {
|
||||
propertyUnits = group->child(row, 3)->text();
|
||||
}
|
||||
|
||||
QWidget* editor =
|
||||
createWidget(parent, propertyName, propertyType, propertyValue, propertyUnits);
|
||||
|
||||
return editor;
|
||||
}
|
||||
|
||||
QWidget* MaterialDelegate::createWidget(QWidget* parent,
|
||||
const QString& propertyName,
|
||||
const QString& propertyType,
|
||||
const QString& propertyValue,
|
||||
const QString& propertyUnits) const
|
||||
{
|
||||
Q_UNUSED(propertyName);
|
||||
|
||||
QWidget* widget = nullptr;
|
||||
|
||||
std::string type = propertyType.toStdString();
|
||||
if (type == "String" || type == "URL" || type == "Vector") {
|
||||
widget = new Gui::PrefLineEdit(parent);
|
||||
}
|
||||
else if ((type == "Integer") || (type == "Int")) {
|
||||
Gui::UIntSpinBox* spinner = new Gui::UIntSpinBox(parent);
|
||||
spinner->setMinimum(0);
|
||||
spinner->setMaximum(UINT_MAX);
|
||||
spinner->setValue(propertyValue.toUInt());
|
||||
widget = spinner;
|
||||
}
|
||||
else if (type == "Float") {
|
||||
Gui::DoubleSpinBox* 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<double>::min());
|
||||
spinner->setMaximum(std::numeric_limits<double>::max());
|
||||
spinner->setValue(propertyValue.toDouble());
|
||||
widget = spinner;
|
||||
}
|
||||
else if (type == "Boolean") {
|
||||
Gui::PrefComboBox* combo = new Gui::PrefComboBox(parent);
|
||||
combo->insertItem(0, QString::fromStdString(""));
|
||||
combo->insertItem(1, QString::fromStdString("False"));
|
||||
combo->insertItem(2, QString::fromStdString("True"));
|
||||
combo->setCurrentText(propertyValue);
|
||||
widget = combo;
|
||||
}
|
||||
else if (type == "Quantity") {
|
||||
Gui::InputField* input = new Gui::InputField();
|
||||
input->setMinimum(std::numeric_limits<double>::min());
|
||||
input->setMaximum(std::numeric_limits<double>::max());
|
||||
input->setUnitText(propertyUnits); // TODO: Ensure this exists
|
||||
input->setPrecision(6);
|
||||
input->setQuantityString(propertyValue);
|
||||
|
||||
widget = input;
|
||||
}
|
||||
else if (type == "File") {
|
||||
Gui::FileChooser* chooser = new Gui::FileChooser();
|
||||
if (propertyValue.length() > 0) {
|
||||
chooser->setFileName(propertyValue);
|
||||
}
|
||||
|
||||
widget = chooser;
|
||||
}
|
||||
else {
|
||||
// Default editor
|
||||
widget = new QLineEdit(parent);
|
||||
}
|
||||
|
||||
widget->setProperty("Type", propertyType);
|
||||
widget->setParent(parent);
|
||||
|
||||
return widget;
|
||||
}
|
||||
|
||||
QRgb MaterialDelegate::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() < 4) {
|
||||
return qRgba(0, 0, 0, 1);
|
||||
}
|
||||
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;
|
||||
|
||||
return qRgba(red, green, blue, alpha);
|
||||
}
|
||||
|
||||
#include "moc_MaterialDelegate.cpp"
|
||||
86
src/Mod/Material/Gui/MaterialDelegate.h
Normal file
86
src/Mod/Material/Gui/MaterialDelegate.h
Normal file
@@ -0,0 +1,86 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
|
||||
* *
|
||||
* 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 *
|
||||
* <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef MATGUI_MATERIALDELEGATE_H
|
||||
#define MATGUI_MATERIALDELEGATE_H
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
#include <QDialog>
|
||||
#include <QDir>
|
||||
#include <QStandardItem>
|
||||
#include <QStyledItemDelegate>
|
||||
#include <QSvgWidget>
|
||||
#include <QTreeView>
|
||||
|
||||
#include <Mod/Material/App/MaterialManager.h>
|
||||
#include <Mod/Material/App/Materials.h>
|
||||
#include <Mod/Material/App/ModelManager.h>
|
||||
|
||||
namespace fs = boost::filesystem;
|
||||
|
||||
namespace MatGui
|
||||
{
|
||||
|
||||
class MaterialDelegate: public QStyledItemDelegate
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit MaterialDelegate(QObject* parent = nullptr);
|
||||
~MaterialDelegate() override = default;
|
||||
|
||||
QWidget* createEditor(QWidget* parent,
|
||||
const QStyleOptionViewItem&,
|
||||
const QModelIndex& index) const override;
|
||||
QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const override;
|
||||
void paint(QPainter* painter,
|
||||
const QStyleOptionViewItem& option,
|
||||
const QModelIndex& index) const override;
|
||||
void setEditorData(QWidget* editor, const QModelIndex& index) const override;
|
||||
void setModelData(QWidget* editor,
|
||||
QAbstractItemModel* model,
|
||||
const QModelIndex& index) const override;
|
||||
|
||||
protected:
|
||||
bool editorEvent(QEvent* event,
|
||||
QAbstractItemModel* model,
|
||||
const QStyleOptionViewItem& option,
|
||||
const QModelIndex& index) override;
|
||||
|
||||
Q_SIGNALS:
|
||||
/** Emits this signal when a property has changed */
|
||||
void propertyChange(const QString& property, const QString value);
|
||||
|
||||
private:
|
||||
QWidget* createWidget(QWidget* parent,
|
||||
const QString& propertyName,
|
||||
const QString& propertyType,
|
||||
const QString& propertyValue,
|
||||
const QString& propertyUnits) const;
|
||||
QRgb parseColor(const QString& color) const;
|
||||
void showColorModal(QStandardItem* item);
|
||||
void showArray2DModal(const QString& propertyName, QStandardItem* item);
|
||||
void showArray3DModal(const QString& propertyName, QStandardItem* item);
|
||||
};
|
||||
|
||||
} // namespace MatGui
|
||||
|
||||
#endif // MATGUI_MATERIALDELEGATE_H
|
||||
313
src/Mod/Material/Gui/MaterialSave.cpp
Normal file
313
src/Mod/Material/Gui/MaterialSave.cpp
Normal file
@@ -0,0 +1,313 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
|
||||
* *
|
||||
* 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 *
|
||||
* <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
**************************************************************************/
|
||||
|
||||
#include "PreCompiled.h"
|
||||
#ifndef _PreComp_
|
||||
#include <QMessageBox>
|
||||
#include <QTreeView>
|
||||
#endif
|
||||
|
||||
#include <Gui/MainWindow.h>
|
||||
|
||||
#include <Mod/Material/App/MaterialLibrary.h>
|
||||
|
||||
#include "MaterialSave.h"
|
||||
#include "ui_MaterialSave.h"
|
||||
|
||||
using namespace MatGui;
|
||||
|
||||
/* TRANSLATOR MatGui::MaterialsEditor */
|
||||
|
||||
MaterialSave::MaterialSave(Materials::Material* material, QWidget* parent)
|
||||
: QDialog(parent)
|
||||
, ui(new Ui_MaterialSave)
|
||||
, _material(material)
|
||||
, _selectedPath(QString::fromStdString("/"))
|
||||
, _selectedUUID(QString())
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
setLibraries();
|
||||
createModelTree();
|
||||
showSelectedTree();
|
||||
|
||||
if (_material->getName().length() > 0) {
|
||||
ui->editFilename->setText(_material->getName() + QString::fromStdString(".FCMat"));
|
||||
}
|
||||
else {
|
||||
ui->editFilename->setText(QString::fromStdString("NewMaterial.FCMat"));
|
||||
}
|
||||
_filename = QString(ui->editFilename->text()); // No filename by default
|
||||
|
||||
connect(ui->standardButtons->button(QDialogButtonBox::Ok),
|
||||
&QPushButton::clicked,
|
||||
this,
|
||||
&MaterialSave::onOk);
|
||||
connect(ui->standardButtons->button(QDialogButtonBox::Cancel),
|
||||
&QPushButton::clicked,
|
||||
this,
|
||||
&MaterialSave::onCancel);
|
||||
|
||||
connect(ui->comboLibrary,
|
||||
&QComboBox::currentTextChanged,
|
||||
this,
|
||||
&MaterialSave::currentTextChanged);
|
||||
connect(ui->buttonNewFolder, &QPushButton::clicked, this, &MaterialSave::onNewFolder);
|
||||
connect(ui->editFilename, &QLineEdit::textEdited, this, &MaterialSave::onFilename);
|
||||
|
||||
QItemSelectionModel* selectionModel = ui->treeMaterials->selectionModel();
|
||||
connect(selectionModel,
|
||||
&QItemSelectionModel::selectionChanged,
|
||||
this,
|
||||
&MaterialSave::onSelectModel);
|
||||
}
|
||||
|
||||
/*
|
||||
* Destroys the object and frees any allocated resources
|
||||
*/
|
||||
MaterialSave::~MaterialSave()
|
||||
{
|
||||
// no need to delete child widgets, Qt does it all for us
|
||||
}
|
||||
|
||||
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?
|
||||
}
|
||||
|
||||
auto variant = ui->comboLibrary->currentData();
|
||||
auto library = variant.value<Materials::MaterialLibrary>();
|
||||
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());
|
||||
_manager.saveMaterial(&library, *_material, filepath.filePath());
|
||||
|
||||
accept();
|
||||
}
|
||||
|
||||
void MaterialSave::onCancel(bool checked)
|
||||
{
|
||||
Q_UNUSED(checked)
|
||||
|
||||
reject();
|
||||
}
|
||||
|
||||
void MaterialSave::accept()
|
||||
{
|
||||
QDialog::accept();
|
||||
}
|
||||
|
||||
void MaterialSave::reject()
|
||||
{
|
||||
QDialog::reject();
|
||||
}
|
||||
|
||||
void MaterialSave::setLibraries()
|
||||
{
|
||||
auto libraries = _manager.getMaterialLibraries();
|
||||
for (auto library : *libraries) {
|
||||
if (!library->isReadOnly()) {
|
||||
QVariant libraryVariant;
|
||||
libraryVariant.setValue(*library);
|
||||
ui->comboLibrary->addItem(library->getName(), libraryVariant);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MaterialSave::createModelTree()
|
||||
{
|
||||
auto tree = ui->treeMaterials;
|
||||
auto model = new QStandardItemModel();
|
||||
tree->setModel(model);
|
||||
tree->setHeaderHidden(true);
|
||||
}
|
||||
|
||||
void MaterialSave::addExpanded(QTreeView* tree, QStandardItem* parent, QStandardItem* child)
|
||||
{
|
||||
parent->appendRow(child);
|
||||
tree->setExpanded(child->index(), true);
|
||||
}
|
||||
|
||||
void MaterialSave::addExpanded(QTreeView* tree, QStandardItemModel* parent, QStandardItem* child)
|
||||
{
|
||||
parent->appendRow(child);
|
||||
tree->setExpanded(child->index(), true);
|
||||
}
|
||||
|
||||
void MaterialSave::addMaterials(
|
||||
QStandardItem& parent,
|
||||
const std::shared_ptr<std::map<QString, Materials::MaterialTreeNode*>> modelTree,
|
||||
const QIcon& folderIcon,
|
||||
const QIcon& icon)
|
||||
{
|
||||
auto tree = ui->treeMaterials;
|
||||
for (auto& mat : *modelTree) {
|
||||
Materials::MaterialTreeNode* nodePtr = mat.second;
|
||||
if (nodePtr->getType() == Materials::MaterialTreeNode::DataNode) {
|
||||
const Materials::Material* material = nodePtr->getData();
|
||||
QString uuid = material->getUUID();
|
||||
Base::Console().Log("Material path '%s'\n",
|
||||
material->getDirectory().toStdString().c_str());
|
||||
|
||||
// auto card = new QStandardItem(icon, material->getName());
|
||||
auto card = new QStandardItem(icon, mat.first);
|
||||
// card->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsDragEnabled
|
||||
// | Qt::ItemIsDropEnabled);
|
||||
card->setData(QVariant(uuid), Qt::UserRole);
|
||||
|
||||
addExpanded(tree, &parent, card);
|
||||
}
|
||||
else {
|
||||
auto node = new QStandardItem(folderIcon, mat.first);
|
||||
addExpanded(tree, &parent, node);
|
||||
// node->setFlags(Qt::ItemIsEnabled | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled);
|
||||
auto treeMap = nodePtr->getFolder();
|
||||
addMaterials(*node, treeMap, folderIcon, icon);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MaterialSave::showSelectedTree()
|
||||
{
|
||||
auto tree = ui->treeMaterials;
|
||||
auto model = static_cast<QStandardItemModel*>(tree->model());
|
||||
model->clear();
|
||||
|
||||
if (ui->comboLibrary->count() > 0) {
|
||||
auto variant = ui->comboLibrary->currentData();
|
||||
auto library = variant.value<Materials::MaterialLibrary>();
|
||||
QIcon icon(library.getIconPath());
|
||||
QIcon folderIcon(QString::fromStdString(":/icons/folder.svg"));
|
||||
_libraryName = library.getName();
|
||||
_selectedPath = QString::fromStdString("/") + _libraryName;
|
||||
|
||||
auto lib = new QStandardItem(library.getName());
|
||||
lib->setFlags(Qt::ItemIsEnabled | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled);
|
||||
addExpanded(tree, model, lib);
|
||||
|
||||
auto modelTree = _manager.getMaterialTree(library);
|
||||
addMaterials(*lib, modelTree, folderIcon, icon);
|
||||
}
|
||||
else {
|
||||
QMessageBox::warning(Gui::getMainWindow(),
|
||||
QObject::tr("No writeable library"),
|
||||
QObject::tr("No writeable library"));
|
||||
}
|
||||
}
|
||||
|
||||
QString MaterialSave::getPath(const QStandardItem* item) const
|
||||
{
|
||||
QString path = QString::fromStdString("/");
|
||||
if (item) {
|
||||
path = path + item->text();
|
||||
if (item->parent()) {
|
||||
return getPath(item->parent()) + path;
|
||||
}
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
void MaterialSave::onSelectModel(const QItemSelection& selected, const QItemSelection& deselected)
|
||||
{
|
||||
// Q_UNUSED(selected);
|
||||
Q_UNUSED(deselected);
|
||||
|
||||
_filename = QString(ui->editFilename->text()); // No filename by default
|
||||
QStandardItemModel* model = static_cast<QStandardItemModel*>(ui->treeMaterials->model());
|
||||
QModelIndexList indexes = selected.indexes();
|
||||
if (indexes.count() == 0) {
|
||||
Base::Console().Log("Nothing selected\n");
|
||||
_selectedPath = QString::fromStdString("/") + _libraryName;
|
||||
_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());
|
||||
_selectedUUID = _selected.toString();
|
||||
_filename = item->text();
|
||||
}
|
||||
else {
|
||||
_selectedPath = getPath(item);
|
||||
_selectedUUID = QString();
|
||||
}
|
||||
}
|
||||
}
|
||||
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)
|
||||
{
|
||||
Q_UNUSED(value)
|
||||
|
||||
showSelectedTree();
|
||||
}
|
||||
|
||||
void MaterialSave::onNewFolder(bool checked)
|
||||
{
|
||||
Q_UNUSED(checked)
|
||||
|
||||
auto tree = ui->treeMaterials;
|
||||
auto model = static_cast<QStandardItemModel*>(tree->model());
|
||||
auto current = tree->currentIndex();
|
||||
if (!current.isValid()) {
|
||||
current = model->index(0, 0);
|
||||
}
|
||||
auto item = model->itemFromIndex(current);
|
||||
if (item->hasChildren()) {
|
||||
Base::Console().Log("Add new folder to '%s'\n", item->text().toStdString().c_str());
|
||||
QIcon folderIcon(QString::fromStdString(":/icons/folder.svg"));
|
||||
|
||||
auto node = new QStandardItem(folderIcon, QString::fromStdString("New Folder"));
|
||||
addExpanded(tree, item, node);
|
||||
// node->setFlags(Qt::ItemIsEnabled | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled);
|
||||
}
|
||||
}
|
||||
|
||||
void MaterialSave::onFilename(const QString& text)
|
||||
{
|
||||
Base::Console().Log("MaterialSave::onFilename('%s')\n", text.toStdString().c_str());
|
||||
|
||||
_filename = text;
|
||||
}
|
||||
|
||||
#include "moc_MaterialSave.cpp"
|
||||
81
src/Mod/Material/Gui/MaterialSave.h
Normal file
81
src/Mod/Material/Gui/MaterialSave.h
Normal file
@@ -0,0 +1,81 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
|
||||
* *
|
||||
* 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 *
|
||||
* <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef MATGUI_MATERIALSAVE_H
|
||||
#define MATGUI_MATERIALSAVE_H
|
||||
|
||||
// #include <boost/filesystem.hpp>
|
||||
|
||||
#include <QDialog>
|
||||
#include <QItemSelection>
|
||||
#include <QStandardItem>
|
||||
#include <QTreeView>
|
||||
|
||||
#include <Mod/Material/App/MaterialManager.h>
|
||||
|
||||
namespace MatGui
|
||||
{
|
||||
|
||||
class Ui_MaterialSave;
|
||||
|
||||
class MaterialSave: public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit MaterialSave(Materials::Material* material, QWidget* parent = nullptr);
|
||||
~MaterialSave() override;
|
||||
|
||||
void setLibraries();
|
||||
void createModelTree();
|
||||
void addExpanded(QTreeView* tree, QStandardItem* parent, QStandardItem* child);
|
||||
void addExpanded(QTreeView* tree, QStandardItemModel* parent, QStandardItem* child);
|
||||
void
|
||||
addMaterials(QStandardItem& parent,
|
||||
const std::shared_ptr<std::map<QString, Materials::MaterialTreeNode*>> modelTree,
|
||||
const QIcon& folderIcon,
|
||||
const QIcon& icon);
|
||||
void showSelectedTree();
|
||||
|
||||
void onSelectModel(const QItemSelection& selected, const QItemSelection& deselected);
|
||||
void currentTextChanged(const QString& value);
|
||||
void onNewFolder(bool checked);
|
||||
void onFilename(const QString& text);
|
||||
void onOk(bool checked);
|
||||
void onCancel(bool checked);
|
||||
void accept() override;
|
||||
void reject() override;
|
||||
|
||||
private:
|
||||
std::unique_ptr<Ui_MaterialSave> ui;
|
||||
Materials::MaterialManager _manager;
|
||||
Materials::Material* _material;
|
||||
QString _selectedPath;
|
||||
QString _selectedUUID;
|
||||
QString _libraryName;
|
||||
QString _filename;
|
||||
|
||||
QString getPath(const QStandardItem* item) const;
|
||||
};
|
||||
|
||||
} // namespace MatGui
|
||||
|
||||
#endif // MATGUI_MATERIALSAVE_H
|
||||
133
src/Mod/Material/Gui/MaterialSave.ui
Normal file
133
src/Mod/Material/Gui/MaterialSave.ui
Normal file
@@ -0,0 +1,133 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>MatGui::MaterialSave</class>
|
||||
<widget class="QDialog" name="MatGui::MaterialSave">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>654</width>
|
||||
<height>708</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Save Material</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Library:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="comboLibrary">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QTreeView" name="treeMaterials"/>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="buttonNewFolder">
|
||||
<property name="text">
|
||||
<string>New Folder</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Filename:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="editFilename">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="standardButtons">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>standardButtons</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>MatGui::MaterialSave</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>248</x>
|
||||
<y>254</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>standardButtons</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>MatGui::MaterialSave</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>316</x>
|
||||
<y>260</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
||||
0
src/Mod/Material/Gui/MaterialTreeView.h
Normal file
0
src/Mod/Material/Gui/MaterialTreeView.h
Normal file
904
src/Mod/Material/Gui/MaterialsEditor.cpp
Normal file
904
src/Mod/Material/Gui/MaterialsEditor.cpp
Normal file
@@ -0,0 +1,904 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
|
||||
* *
|
||||
* 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 *
|
||||
* <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
**************************************************************************/
|
||||
|
||||
#include "PreCompiled.h"
|
||||
#ifndef _PreComp_
|
||||
#include <QColorDialog>
|
||||
#include <QDesktopServices>
|
||||
#include <QIODevice>
|
||||
#include <QItemSelectionModel>
|
||||
#include <QMessageBox>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QTextStream>
|
||||
#include <QVariant>
|
||||
#endif
|
||||
|
||||
#include <limits>
|
||||
|
||||
#include <App/Application.h>
|
||||
#include <Base/Interpreter.h>
|
||||
#include <Base/Quantity.h>
|
||||
#include <Gui/Application.h>
|
||||
#include <Gui/Command.h>
|
||||
#include <Gui/InputField.h>
|
||||
#include <Gui/PrefWidgets.h>
|
||||
#include <Gui/SpinBox.h>
|
||||
#include <Gui/WaitCursor.h>
|
||||
|
||||
#include <Mod/Material/App/Exceptions.h>
|
||||
#include <Mod/Material/App/ModelManager.h>
|
||||
|
||||
#include "MaterialDelegate.h"
|
||||
#include "MaterialSave.h"
|
||||
#include "MaterialsEditor.h"
|
||||
#include "ModelSelect.h"
|
||||
#include "ui_MaterialsEditor.h"
|
||||
|
||||
|
||||
using namespace MatGui;
|
||||
|
||||
/* TRANSLATOR MatGui::MaterialsEditor */
|
||||
|
||||
MaterialsEditor::MaterialsEditor(QWidget* parent)
|
||||
: QDialog(parent)
|
||||
, ui(new Ui_MaterialsEditor)
|
||||
, _edited(false)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
getFavorites();
|
||||
getRecents();
|
||||
|
||||
createMaterialTree();
|
||||
createPhysicalTree();
|
||||
createAppearanceTree();
|
||||
createPreviews();
|
||||
|
||||
ui->buttonURL->setIcon(QIcon(QString::fromStdString(":/icons/internet-web-browser.svg")));
|
||||
|
||||
connect(ui->standardButtons->button(QDialogButtonBox::Ok),
|
||||
&QPushButton::clicked,
|
||||
this,
|
||||
&MaterialsEditor::onOk);
|
||||
connect(ui->standardButtons->button(QDialogButtonBox::Cancel),
|
||||
&QPushButton::clicked,
|
||||
this,
|
||||
&MaterialsEditor::onCancel);
|
||||
connect(ui->standardButtons->button(QDialogButtonBox::Save),
|
||||
&QPushButton::clicked,
|
||||
this,
|
||||
&MaterialsEditor::onSave);
|
||||
|
||||
connect(ui->buttonURL, &QPushButton::clicked, this, &MaterialsEditor::onURL);
|
||||
connect(ui->buttonPhysicalAdd, &QPushButton::clicked, this, &MaterialsEditor::onPhysicalAdd);
|
||||
connect(ui->buttonAppearanceAdd,
|
||||
&QPushButton::clicked,
|
||||
this,
|
||||
&MaterialsEditor::onAppearanceAdd);
|
||||
connect(ui->buttonFavorite, &QPushButton::clicked, this, &MaterialsEditor::onFavourite);
|
||||
|
||||
QItemSelectionModel* selectionModel = ui->treeMaterials->selectionModel();
|
||||
connect(selectionModel,
|
||||
&QItemSelectionModel::selectionChanged,
|
||||
this,
|
||||
&MaterialsEditor::onSelectMaterial);
|
||||
}
|
||||
|
||||
void MaterialsEditor::getFavorites()
|
||||
{
|
||||
_favorites.clear();
|
||||
|
||||
auto param = App::GetApplication().GetParameterGroupByPath(
|
||||
"User parameter:BaseApp/Preferences/Mod/Material/Favorites");
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
void MaterialsEditor::saveFavorites()
|
||||
{
|
||||
auto param = App::GetApplication().GetParameterGroupByPath(
|
||||
"User parameter:BaseApp/Preferences/Mod/Material/Favorites");
|
||||
|
||||
// Clear out the existing favorites
|
||||
int count = param->GetInt("Favorites", 0);
|
||||
for (int i = 0; i < count; i++) {
|
||||
QString key = QString::fromLatin1("FAV%1").arg(i);
|
||||
param->RemoveASCII(key.toStdString().c_str());
|
||||
}
|
||||
|
||||
// Add the current values
|
||||
param->SetInt("Favorites", _favorites.size());
|
||||
int j = 0;
|
||||
for (auto favorite : _favorites) {
|
||||
QString key = QString::fromLatin1("FAV%1").arg(j);
|
||||
param->SetASCII(key.toStdString().c_str(), favorite.toStdString());
|
||||
|
||||
j++;
|
||||
}
|
||||
}
|
||||
|
||||
void MaterialsEditor::addFavorite(const QString& uuid)
|
||||
{
|
||||
// Ensure it is a material. New, unsaved materials will not be
|
||||
try {
|
||||
const Materials::Material& material = _materialManager.getMaterial(uuid);
|
||||
Q_UNUSED(material)
|
||||
}
|
||||
catch (const Materials::MaterialNotFound&) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isFavorite(uuid)) {
|
||||
_favorites.push_back(uuid);
|
||||
saveFavorites();
|
||||
refreshMaterialTree();
|
||||
}
|
||||
}
|
||||
|
||||
void MaterialsEditor::removeFavorite(const QString& uuid)
|
||||
{
|
||||
if (isFavorite(uuid)) {
|
||||
_favorites.remove(uuid);
|
||||
saveFavorites();
|
||||
refreshMaterialTree();
|
||||
}
|
||||
}
|
||||
|
||||
bool MaterialsEditor::isFavorite(const QString& uuid) const
|
||||
{
|
||||
for (auto it : _favorites) {
|
||||
if (it == uuid) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void MaterialsEditor::getRecents()
|
||||
{
|
||||
_recents.clear();
|
||||
|
||||
auto param = App::GetApplication().GetParameterGroupByPath(
|
||||
"User parameter:BaseApp/Preferences/Mod/Material/Recent");
|
||||
_recentMax = param->GetInt("RecentMax", 5);
|
||||
int count = param->GetInt("Recent", 0);
|
||||
for (int i = 0; i < count; i++) {
|
||||
QString key = QString::fromLatin1("MRU%1").arg(i);
|
||||
QString uuid = QString::fromStdString(param->GetASCII(key.toStdString().c_str(), ""));
|
||||
_recents.push_back(uuid);
|
||||
}
|
||||
}
|
||||
|
||||
void MaterialsEditor::saveRecents()
|
||||
{
|
||||
auto param = App::GetApplication().GetParameterGroupByPath(
|
||||
"User parameter:BaseApp/Preferences/Mod/Material/Recent");
|
||||
|
||||
// Clear out the existing favorites
|
||||
int count = param->GetInt("Recent", 0);
|
||||
for (int i = 0; i < count; i++) {
|
||||
QString key = QString::fromLatin1("MRU%1").arg(i);
|
||||
param->RemoveASCII(key.toStdString().c_str());
|
||||
}
|
||||
|
||||
// Add the current values
|
||||
int size = _recents.size();
|
||||
if (size > _recentMax) {
|
||||
size = _recentMax;
|
||||
}
|
||||
param->SetInt("Recent", size);
|
||||
int j = 0;
|
||||
for (auto recent : _recents) {
|
||||
QString key = QString::fromLatin1("MRU%1").arg(j);
|
||||
param->SetASCII(key.toStdString().c_str(), recent.toStdString());
|
||||
|
||||
j++;
|
||||
if (j >= size) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MaterialsEditor::addRecent(const QString& uuid)
|
||||
{
|
||||
// Ensure it is a material. New, unsaved materials will not be
|
||||
try {
|
||||
const Materials::Material& material = _materialManager.getMaterial(uuid);
|
||||
Q_UNUSED(material)
|
||||
}
|
||||
catch (const Materials::MaterialNotFound&) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Ensure no duplicates
|
||||
if (isRecent(uuid)) {
|
||||
_recents.remove(uuid);
|
||||
}
|
||||
|
||||
_recents.push_front(uuid);
|
||||
while (_recents.size() > static_cast<std::size_t>(_recentMax)) {
|
||||
_recents.pop_back();
|
||||
}
|
||||
|
||||
saveRecents();
|
||||
}
|
||||
|
||||
bool MaterialsEditor::isRecent(const QString& uuid) const
|
||||
{
|
||||
for (auto it : _recents) {
|
||||
if (it == uuid) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
else if (_material.hasAppearanceProperty(property)) {
|
||||
_material.setAppearanceValue(property, value);
|
||||
updatePreview();
|
||||
}
|
||||
_edited = true;
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
void MaterialsEditor::onPhysicalAdd(bool checked)
|
||||
{
|
||||
Q_UNUSED(checked)
|
||||
|
||||
ModelSelect dialog(this, Materials::ModelManager::ModelFilter_Physical);
|
||||
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();
|
||||
}
|
||||
else {
|
||||
Base::Console().Log("No model selected\n");
|
||||
}
|
||||
}
|
||||
|
||||
void MaterialsEditor::onAppearanceAdd(bool checked)
|
||||
{
|
||||
Q_UNUSED(checked)
|
||||
|
||||
ModelSelect dialog(this, Materials::ModelManager::ModelFilter_Appearance);
|
||||
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();
|
||||
}
|
||||
else {
|
||||
Base::Console().Log("No model selected\n");
|
||||
}
|
||||
}
|
||||
|
||||
void MaterialsEditor::onFavourite(bool checked)
|
||||
{
|
||||
Q_UNUSED(checked)
|
||||
|
||||
Base::Console().Log("Favorite\n");
|
||||
auto selected = _material.getUUID();
|
||||
if (isFavorite(selected)) {
|
||||
removeFavorite(selected);
|
||||
}
|
||||
else {
|
||||
addFavorite(selected);
|
||||
}
|
||||
}
|
||||
|
||||
void MaterialsEditor::onOk(bool checked)
|
||||
{
|
||||
Q_UNUSED(checked)
|
||||
|
||||
accept();
|
||||
}
|
||||
|
||||
void MaterialsEditor::onCancel(bool checked)
|
||||
{
|
||||
Q_UNUSED(checked)
|
||||
|
||||
reject();
|
||||
}
|
||||
|
||||
void MaterialsEditor::onSave(bool checked)
|
||||
{
|
||||
Q_UNUSED(checked)
|
||||
|
||||
saveMaterial();
|
||||
}
|
||||
|
||||
void MaterialsEditor::saveMaterial()
|
||||
{
|
||||
MaterialSave dialog(&_material, this);
|
||||
dialog.setModal(true);
|
||||
if (dialog.exec() == QDialog::Accepted) {
|
||||
_material.resetEditState();
|
||||
refreshMaterialTree();
|
||||
}
|
||||
}
|
||||
|
||||
void MaterialsEditor::accept()
|
||||
{
|
||||
addRecent(_material.getUUID());
|
||||
QDialog::accept();
|
||||
}
|
||||
|
||||
void MaterialsEditor::reject()
|
||||
{
|
||||
QDialog::reject();
|
||||
}
|
||||
|
||||
// QIcon MaterialsEditor::errorIcon(const QIcon &icon) const {
|
||||
// auto pixmap = icon.pixmap();
|
||||
// }
|
||||
|
||||
void MaterialsEditor::addMaterials(
|
||||
QStandardItem& parent,
|
||||
const std::shared_ptr<std::map<QString, Materials::MaterialTreeNode*>> modelTree,
|
||||
const QIcon& folderIcon,
|
||||
const QIcon& icon)
|
||||
{
|
||||
auto tree = ui->treeMaterials;
|
||||
for (auto& mat : *modelTree) {
|
||||
Materials::MaterialTreeNode* nodePtr = mat.second;
|
||||
if (nodePtr->getType() == Materials::MaterialTreeNode::DataNode) {
|
||||
const Materials::Material* material = nodePtr->getData();
|
||||
QString uuid = material->getUUID();
|
||||
// Base::Console().Log("Material path '%s'\n",
|
||||
// material->getDirectory().toStdString().c_str());
|
||||
|
||||
// auto card = new QStandardItem(icon, material->getName());
|
||||
auto card = new QStandardItem(icon, mat.first);
|
||||
card->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsDragEnabled
|
||||
| Qt::ItemIsDropEnabled);
|
||||
card->setData(QVariant(uuid), Qt::UserRole);
|
||||
|
||||
addExpanded(tree, &parent, card);
|
||||
}
|
||||
else {
|
||||
auto node = new QStandardItem(folderIcon, mat.first);
|
||||
addExpanded(tree, &parent, node);
|
||||
node->setFlags(Qt::ItemIsEnabled | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled);
|
||||
auto treeMap = nodePtr->getFolder();
|
||||
addMaterials(*node, treeMap, folderIcon, icon);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MaterialsEditor::addExpanded(QTreeView* tree, QStandardItem* parent, QStandardItem* child)
|
||||
{
|
||||
parent->appendRow(child);
|
||||
tree->setExpanded(child->index(), true);
|
||||
}
|
||||
|
||||
void MaterialsEditor::addExpanded(QTreeView* tree, QStandardItemModel* parent, QStandardItem* child)
|
||||
{
|
||||
parent->appendRow(child);
|
||||
tree->setExpanded(child->index(), true);
|
||||
}
|
||||
|
||||
void MaterialsEditor::createPhysicalTree()
|
||||
{
|
||||
auto tree = ui->treePhysicalProperties;
|
||||
auto model = new QStandardItemModel();
|
||||
tree->setModel(model);
|
||||
|
||||
QStringList headers;
|
||||
headers.append(QString::fromStdString("Property"));
|
||||
headers.append(QString::fromStdString("Value"));
|
||||
headers.append(QString::fromStdString("Type"));
|
||||
model->setHorizontalHeaderLabels(headers);
|
||||
|
||||
tree->setColumnWidth(0, 250);
|
||||
tree->setColumnWidth(1, 250);
|
||||
tree->setColumnHidden(2, true);
|
||||
|
||||
tree->setHeaderHidden(false);
|
||||
tree->setUniformRowHeights(true);
|
||||
MaterialDelegate* delegate = new MaterialDelegate(this);
|
||||
tree->setItemDelegateForColumn(1, delegate);
|
||||
|
||||
connect(delegate, &MaterialDelegate::propertyChange, this, &MaterialsEditor::propertyChange);
|
||||
}
|
||||
|
||||
void MaterialsEditor::createPreviews()
|
||||
{
|
||||
_rendered = new QSvgWidget(QString::fromStdString(":/icons/preview-rendered.svg"));
|
||||
_rendered->setMaximumWidth(64);
|
||||
_rendered->setMinimumHeight(64);
|
||||
ui->layoutAppearance->addWidget(_rendered);
|
||||
|
||||
_vectored = new QSvgWidget(QString::fromStdString(":/icons/preview-vector.svg"));
|
||||
_vectored->setMaximumWidth(64);
|
||||
_vectored->setMinimumHeight(64);
|
||||
ui->layoutAppearance->addWidget(_vectored);
|
||||
|
||||
updatePreview();
|
||||
}
|
||||
|
||||
void MaterialsEditor::createAppearanceTree()
|
||||
{
|
||||
auto tree = ui->treeAppearance;
|
||||
auto model = new QStandardItemModel();
|
||||
tree->setModel(model);
|
||||
|
||||
QStringList headers;
|
||||
headers.append(QString::fromStdString("Property"));
|
||||
headers.append(QString::fromStdString("Value"));
|
||||
headers.append(QString::fromStdString("Type"));
|
||||
model->setHorizontalHeaderLabels(headers);
|
||||
|
||||
tree->setColumnWidth(0, 250);
|
||||
tree->setColumnWidth(1, 250);
|
||||
tree->setColumnHidden(2, true);
|
||||
|
||||
tree->setHeaderHidden(false);
|
||||
tree->setUniformRowHeights(false);
|
||||
MaterialDelegate* delegate = new MaterialDelegate(this);
|
||||
tree->setItemDelegateForColumn(1, delegate);
|
||||
|
||||
connect(delegate, &MaterialDelegate::propertyChange, this, &MaterialsEditor::propertyChange);
|
||||
}
|
||||
|
||||
void MaterialsEditor::addRecents(QStandardItem* parent)
|
||||
{
|
||||
auto tree = ui->treeMaterials;
|
||||
for (auto& uuid : _recents) {
|
||||
try {
|
||||
const Materials::Material& material = getMaterialManager().getMaterial(uuid);
|
||||
|
||||
QIcon icon = QIcon(material.getLibrary().getIconPath());
|
||||
auto card = new QStandardItem(icon, material.getName());
|
||||
card->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsDragEnabled
|
||||
| Qt::ItemIsDropEnabled);
|
||||
card->setData(QVariant(uuid), Qt::UserRole);
|
||||
|
||||
addExpanded(tree, parent, card);
|
||||
}
|
||||
catch (const Materials::MaterialNotFound&) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MaterialsEditor::addFavorites(QStandardItem* parent)
|
||||
{
|
||||
auto tree = ui->treeMaterials;
|
||||
for (auto& uuid : _favorites) {
|
||||
try {
|
||||
const Materials::Material& material = getMaterialManager().getMaterial(uuid);
|
||||
|
||||
QIcon icon = QIcon(material.getLibrary().getIconPath());
|
||||
auto card = new QStandardItem(icon, material.getName());
|
||||
card->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsDragEnabled
|
||||
| Qt::ItemIsDropEnabled);
|
||||
card->setData(QVariant(uuid), Qt::UserRole);
|
||||
|
||||
addExpanded(tree, parent, card);
|
||||
}
|
||||
catch (const Materials::MaterialNotFound&) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MaterialsEditor::fillMaterialTree()
|
||||
{
|
||||
auto tree = ui->treeMaterials;
|
||||
auto model = static_cast<QStandardItemModel*>(tree->model());
|
||||
|
||||
auto lib = new QStandardItem(QString::fromStdString("Favorites"));
|
||||
lib->setFlags(Qt::ItemIsEnabled | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled);
|
||||
addExpanded(tree, model, lib);
|
||||
addFavorites(lib);
|
||||
|
||||
lib = new QStandardItem(QString::fromStdString("Recent"));
|
||||
lib->setFlags(Qt::ItemIsEnabled | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled);
|
||||
addExpanded(tree, model, lib);
|
||||
addRecents(lib);
|
||||
|
||||
auto libraries = Materials::MaterialManager::getMaterialLibraries();
|
||||
for (const auto& library : *libraries) {
|
||||
lib = new QStandardItem(library->getName());
|
||||
lib->setFlags(Qt::ItemIsEnabled | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled);
|
||||
addExpanded(tree, model, lib);
|
||||
|
||||
QIcon icon(library->getIconPath());
|
||||
QIcon folderIcon(QString::fromStdString(":/icons/folder.svg"));
|
||||
|
||||
auto modelTree = _materialManager.getMaterialTree(*library);
|
||||
addMaterials(*lib, modelTree, folderIcon, icon);
|
||||
}
|
||||
}
|
||||
|
||||
void MaterialsEditor::createMaterialTree()
|
||||
{
|
||||
// Materials::ModelManager &modelManager = getModelManager();
|
||||
// Q_UNUSED(modelManager)
|
||||
|
||||
auto tree = ui->treeMaterials;
|
||||
auto model = new QStandardItemModel();
|
||||
tree->setModel(model);
|
||||
|
||||
tree->setHeaderHidden(true);
|
||||
fillMaterialTree();
|
||||
}
|
||||
|
||||
void MaterialsEditor::refreshMaterialTree()
|
||||
{
|
||||
auto tree = ui->treeMaterials;
|
||||
auto model = static_cast<QStandardItemModel*>(tree->model());
|
||||
model->clear();
|
||||
|
||||
fillMaterialTree();
|
||||
}
|
||||
|
||||
void MaterialsEditor::updatePreview() const
|
||||
{
|
||||
QString diffuseColor;
|
||||
QString highlightColor;
|
||||
QString sectionColor;
|
||||
|
||||
if (_material.hasAppearanceProperty(QString::fromStdString("DiffuseColor"))) {
|
||||
diffuseColor = _material.getAppearanceValueString(QString::fromStdString("DiffuseColor"));
|
||||
}
|
||||
else if (_material.hasAppearanceProperty(QString::fromStdString("ViewColor"))) {
|
||||
diffuseColor = _material.getAppearanceValueString(QString::fromStdString("ViewColor"));
|
||||
}
|
||||
else if (_material.hasAppearanceProperty(QString::fromStdString("Color"))) {
|
||||
diffuseColor = _material.getAppearanceValueString(QString::fromStdString("Color"));
|
||||
}
|
||||
|
||||
if (_material.hasAppearanceProperty(QString::fromStdString("SpecularColor"))) {
|
||||
highlightColor =
|
||||
_material.getAppearanceValueString(QString::fromStdString("SpecularColor"));
|
||||
}
|
||||
|
||||
if (_material.hasAppearanceProperty(QString::fromStdString("SectionColor"))) {
|
||||
sectionColor = _material.getAppearanceValueString(QString::fromStdString("SectionColor"));
|
||||
}
|
||||
|
||||
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 ((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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QString MaterialsEditor::getColorHash(const QString& colorString, int colorRange) const
|
||||
{
|
||||
/*
|
||||
returns a '#000000' string from a '(0.1,0.2,0.3)' string. Optionally the string
|
||||
has a fourth value for alpha (transparency)
|
||||
*/
|
||||
std::stringstream stream(colorString.toStdString());
|
||||
|
||||
char c;
|
||||
stream >> c; // read "("
|
||||
double red;
|
||||
stream >> red;
|
||||
stream >> c; // ","
|
||||
double green;
|
||||
stream >> green;
|
||||
stream >> c; // ","
|
||||
double blue;
|
||||
stream >> blue;
|
||||
stream >> c; // ","
|
||||
double alpha = 1.0;
|
||||
if (c == ',') {
|
||||
stream >> alpha;
|
||||
}
|
||||
|
||||
QColor color(static_cast<int>(red * colorRange),
|
||||
static_cast<int>(green * colorRange),
|
||||
static_cast<int>(blue * colorRange),
|
||||
static_cast<int>(alpha * colorRange));
|
||||
return color.name();
|
||||
}
|
||||
|
||||
void MaterialsEditor::updateMaterialAppearance()
|
||||
{
|
||||
QTreeView* tree = ui->treeAppearance;
|
||||
QStandardItemModel* treeModel = static_cast<QStandardItemModel*>(tree->model());
|
||||
treeModel->clear();
|
||||
|
||||
QStringList headers;
|
||||
headers.append(QString::fromStdString("Property"));
|
||||
headers.append(QString::fromStdString("Value"));
|
||||
headers.append(QString::fromStdString("Type"));
|
||||
treeModel->setHorizontalHeaderLabels(headers);
|
||||
|
||||
tree->setColumnWidth(0, 250);
|
||||
tree->setColumnWidth(1, 250);
|
||||
tree->setColumnHidden(2, true);
|
||||
|
||||
const std::vector<QString>* models = _material.getAppearanceModels();
|
||||
if (models) {
|
||||
for (auto it = models->begin(); it != models->end(); it++) {
|
||||
QString uuid = *it;
|
||||
try {
|
||||
const Materials::Model& model = getModelManager().getModel(uuid);
|
||||
QString name = model.getName();
|
||||
|
||||
auto modelRoot = new QStandardItem(name);
|
||||
modelRoot->setFlags(Qt::ItemIsEnabled | Qt::ItemIsDragEnabled
|
||||
| Qt::ItemIsDropEnabled);
|
||||
addExpanded(tree, treeModel, modelRoot);
|
||||
for (auto itp = model.begin(); itp != model.end(); itp++) {
|
||||
QList<QStandardItem*> items;
|
||||
|
||||
QString key = itp->first;
|
||||
auto propertyItem = new QStandardItem(key);
|
||||
propertyItem->setToolTip(itp->second.getDescription());
|
||||
items.append(propertyItem);
|
||||
|
||||
auto valueItem = new QStandardItem(_material.getAppearanceValueString(key));
|
||||
valueItem->setToolTip(itp->second.getDescription());
|
||||
QVariant variant;
|
||||
variant.setValue(&_material);
|
||||
valueItem->setData(variant);
|
||||
items.append(valueItem);
|
||||
|
||||
auto typeItem = new QStandardItem(itp->second.getPropertyType());
|
||||
items.append(typeItem);
|
||||
|
||||
auto unitsItem = new QStandardItem(itp->second.getUnits());
|
||||
items.append(unitsItem);
|
||||
|
||||
modelRoot->appendRow(items);
|
||||
tree->setExpanded(modelRoot->index(), true);
|
||||
}
|
||||
}
|
||||
catch (Materials::ModelNotFound const&) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MaterialsEditor::updateMaterialProperties()
|
||||
{
|
||||
QTreeView* tree = ui->treePhysicalProperties;
|
||||
QStandardItemModel* treeModel = static_cast<QStandardItemModel*>(tree->model());
|
||||
treeModel->clear();
|
||||
|
||||
QStringList headers;
|
||||
headers.append(QString::fromStdString("Property"));
|
||||
headers.append(QString::fromStdString("Value"));
|
||||
headers.append(QString::fromStdString("Type"));
|
||||
headers.append(QString::fromStdString("Units"));
|
||||
treeModel->setHorizontalHeaderLabels(headers);
|
||||
|
||||
tree->setColumnWidth(0, 250);
|
||||
tree->setColumnWidth(1, 250);
|
||||
tree->setColumnHidden(2, true);
|
||||
tree->setColumnHidden(3, true);
|
||||
|
||||
const std::vector<QString>* models = _material.getPhysicalModels();
|
||||
if (models) {
|
||||
for (auto it = models->begin(); it != models->end(); it++) {
|
||||
QString uuid = *it;
|
||||
try {
|
||||
const Materials::Model& model = getModelManager().getModel(uuid);
|
||||
QString name = model.getName();
|
||||
|
||||
auto modelRoot = new QStandardItem(name);
|
||||
modelRoot->setFlags(Qt::ItemIsEnabled | Qt::ItemIsDragEnabled
|
||||
| Qt::ItemIsDropEnabled);
|
||||
addExpanded(tree, treeModel, modelRoot);
|
||||
for (auto itp = model.begin(); itp != model.end(); itp++) {
|
||||
QList<QStandardItem*> items;
|
||||
|
||||
QString key = itp->first;
|
||||
Materials::ModelProperty modelProperty =
|
||||
static_cast<Materials::ModelProperty>(itp->second);
|
||||
auto propertyItem = new QStandardItem(key);
|
||||
propertyItem->setToolTip(modelProperty.getDescription());
|
||||
items.append(propertyItem);
|
||||
|
||||
auto valueItem = new QStandardItem(_material.getPhysicalValueString(key));
|
||||
valueItem->setToolTip(modelProperty.getDescription());
|
||||
QVariant variant;
|
||||
variant.setValue(&_material);
|
||||
valueItem->setData(variant);
|
||||
items.append(valueItem);
|
||||
|
||||
auto typeItem = new QStandardItem(modelProperty.getPropertyType());
|
||||
items.append(typeItem);
|
||||
|
||||
auto unitsItem = new QStandardItem(modelProperty.getUnits());
|
||||
items.append(unitsItem);
|
||||
|
||||
// addExpanded(tree, modelRoot, propertyItem);
|
||||
modelRoot->appendRow(items);
|
||||
tree->setExpanded(modelRoot->index(), true);
|
||||
}
|
||||
}
|
||||
catch (Materials::ModelNotFound const&) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MaterialsEditor::updateMaterial()
|
||||
{
|
||||
// Update the general information
|
||||
ui->editName->setText(_material.getName());
|
||||
ui->editAuthorLicense->setText(_material.getAuthorAndLicense());
|
||||
// ui->editParent->setText(_material.getName());
|
||||
ui->editSourceURL->setText(_material.getURL());
|
||||
ui->editSourceReference->setText(_material.getReference());
|
||||
// ui->editTags->setText(_material.getName());
|
||||
ui->editDescription->setText(_material.getDescription());
|
||||
|
||||
updateMaterialProperties();
|
||||
updateMaterialAppearance();
|
||||
|
||||
updatePreview();
|
||||
}
|
||||
|
||||
void MaterialsEditor::onSelectMaterial(const QItemSelection& selected,
|
||||
const QItemSelection& deselected)
|
||||
{
|
||||
Q_UNUSED(deselected);
|
||||
|
||||
// Get the UUID before changing the underlying data model
|
||||
QString uuid;
|
||||
QStandardItemModel* model = static_cast<QStandardItemModel*>(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;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
// Get the selected material
|
||||
try {
|
||||
_material = getMaterialManager().getMaterial(uuid);
|
||||
}
|
||||
catch (Materials::ModelNotFound const&) {
|
||||
Base::Console().Log("*** Unable to load material '%s'\n", uuid.toStdString().c_str());
|
||||
Materials::Material empty;
|
||||
_material = empty;
|
||||
}
|
||||
|
||||
updateMaterial();
|
||||
_material.resetEditState();
|
||||
}
|
||||
|
||||
int MaterialsEditor::confirmSave(QWidget* parent)
|
||||
{
|
||||
QMessageBox box(parent ? parent : this);
|
||||
box.setIcon(QMessageBox::Question);
|
||||
box.setWindowTitle(QObject::tr("Unsaved Material"));
|
||||
box.setText(QObject::tr("Do you want to save your changes to the material before closing?"));
|
||||
|
||||
box.setInformativeText(QObject::tr("If you don't save, your changes will be lost."));
|
||||
box.setStandardButtons(QMessageBox::Discard | QMessageBox::Cancel | QMessageBox::Save);
|
||||
box.setDefaultButton(QMessageBox::Save);
|
||||
box.setEscapeButton(QMessageBox::Cancel);
|
||||
|
||||
// add shortcuts
|
||||
QAbstractButton* saveBtn = box.button(QMessageBox::Save);
|
||||
if (saveBtn->shortcut().isEmpty()) {
|
||||
QString text = saveBtn->text();
|
||||
text.prepend(QLatin1Char('&'));
|
||||
saveBtn->setShortcut(QKeySequence::mnemonic(text));
|
||||
}
|
||||
|
||||
QAbstractButton* discardBtn = box.button(QMessageBox::Discard);
|
||||
if (discardBtn->shortcut().isEmpty()) {
|
||||
QString text = discardBtn->text();
|
||||
text.prepend(QLatin1Char('&'));
|
||||
discardBtn->setShortcut(QKeySequence::mnemonic(text));
|
||||
}
|
||||
|
||||
int res = QMessageBox::Cancel;
|
||||
box.adjustSize(); // Silence warnings from Qt on Windows
|
||||
switch (box.exec()) {
|
||||
case QMessageBox::Save:
|
||||
saveMaterial();
|
||||
res = QMessageBox::Save;
|
||||
break;
|
||||
case QMessageBox::Discard:
|
||||
res = QMessageBox::Discard;
|
||||
break;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
#include "moc_MaterialsEditor.cpp"
|
||||
131
src/Mod/Material/Gui/MaterialsEditor.h
Normal file
131
src/Mod/Material/Gui/MaterialsEditor.h
Normal file
@@ -0,0 +1,131 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
|
||||
* *
|
||||
* 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 *
|
||||
* <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef MATGUI_MATERIALSEDITOR_H
|
||||
#define MATGUI_MATERIALSEDITOR_H
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
#include <QDialog>
|
||||
#include <QDir>
|
||||
#include <QStandardItem>
|
||||
#include <QStyledItemDelegate>
|
||||
#include <QSvgWidget>
|
||||
#include <QTreeView>
|
||||
|
||||
#include <Mod/Material/App/MaterialManager.h>
|
||||
#include <Mod/Material/App/Materials.h>
|
||||
#include <Mod/Material/App/ModelManager.h>
|
||||
|
||||
namespace fs = boost::filesystem;
|
||||
|
||||
namespace MatGui
|
||||
{
|
||||
|
||||
class Ui_MaterialsEditor;
|
||||
|
||||
class MaterialsEditor: public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit MaterialsEditor(QWidget* parent = nullptr);
|
||||
~MaterialsEditor() override = default;
|
||||
|
||||
void propertyChange(const QString& property, const QString value);
|
||||
void onFavourite(bool checked);
|
||||
void onURL(bool checked);
|
||||
void onPhysicalAdd(bool checked);
|
||||
void onAppearanceAdd(bool checked);
|
||||
void onOk(bool checked);
|
||||
void onCancel(bool checked);
|
||||
void onSave(bool checked);
|
||||
void accept() override;
|
||||
void reject() override;
|
||||
|
||||
Materials::MaterialManager& getMaterialManager()
|
||||
{
|
||||
return _materialManager;
|
||||
}
|
||||
Materials::ModelManager& getModelManager()
|
||||
{
|
||||
return _modelManager;
|
||||
}
|
||||
|
||||
void updateMaterialAppearance();
|
||||
void updateMaterialProperties();
|
||||
void updateMaterial();
|
||||
void onSelectMaterial(const QItemSelection& selected, const QItemSelection& deselected);
|
||||
|
||||
protected:
|
||||
int confirmSave(QWidget* parent);
|
||||
void saveMaterial();
|
||||
|
||||
private:
|
||||
std::unique_ptr<Ui_MaterialsEditor> ui;
|
||||
Materials::MaterialManager _materialManager;
|
||||
Materials::ModelManager _modelManager;
|
||||
Materials::Material _material;
|
||||
QSvgWidget* _rendered;
|
||||
QSvgWidget* _vectored;
|
||||
bool _edited;
|
||||
std::list<QString> _favorites;
|
||||
std::list<QString> _recents;
|
||||
int _recentMax;
|
||||
|
||||
void getFavorites();
|
||||
void saveFavorites();
|
||||
void addFavorite(const QString& uuid);
|
||||
void removeFavorite(const QString& uuid);
|
||||
bool isFavorite(const QString& uuid) const;
|
||||
|
||||
void getRecents();
|
||||
void saveRecents();
|
||||
void addRecent(const QString& uuid);
|
||||
bool isRecent(const QString& uuid) const;
|
||||
|
||||
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);
|
||||
void addRecents(QStandardItem* parent);
|
||||
void addFavorites(QStandardItem* parent);
|
||||
void createPreviews();
|
||||
void createAppearanceTree();
|
||||
void createPhysicalTree();
|
||||
void createMaterialTree();
|
||||
void fillMaterialTree();
|
||||
void refreshMaterialTree();
|
||||
void
|
||||
addMaterials(QStandardItem& parent,
|
||||
const std::shared_ptr<std::map<QString, Materials::MaterialTreeNode*>> modelTree,
|
||||
const QIcon& folderIcon,
|
||||
const QIcon& icon);
|
||||
bool isMaterial(const fs::path& p) const
|
||||
{
|
||||
return Materials::MaterialManager::isMaterial(p);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace MatGui
|
||||
|
||||
#endif // MATGUI_MATERIALSEDITOR_H
|
||||
288
src/Mod/Material/Gui/MaterialsEditor.ui
Normal file
288
src/Mod/Material/Gui/MaterialsEditor.ui
Normal file
@@ -0,0 +1,288 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>MatGui::MaterialsEditor</class>
|
||||
<widget class="QDialog" name="MatGui::MaterialsEditor">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>835</width>
|
||||
<height>542</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Materials</string>
|
||||
</property>
|
||||
<property name="sizeGripEnabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QSplitter" name="splitter">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<widget class="QTreeView" name="treeMaterials">
|
||||
<property name="selectionBehavior">
|
||||
<enum>QAbstractItemView::SelectItems</enum>
|
||||
</property>
|
||||
<property name="headerHidden">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QTabWidget" name="tabWidget">
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="tabGeneral">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<attribute name="title">
|
||||
<string>General</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<property name="sizeConstraint">
|
||||
<enum>QLayout::SetMinAndMaxSize</enum>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>7</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>7</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>7</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>7</number>
|
||||
</property>
|
||||
<item row="0" column="2">
|
||||
<widget class="QLineEdit" name="editName"/>
|
||||
</item>
|
||||
<item row="7" column="0">
|
||||
<widget class="QLabel" name="labelDescription">
|
||||
<property name="text">
|
||||
<string>Description</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QLineEdit" name="editAuthorLicense"/>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="labelName">
|
||||
<property name="text">
|
||||
<string>Name</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="labelSourceReference">
|
||||
<property name="text">
|
||||
<string>Source Reference</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="labelParent">
|
||||
<property name="text">
|
||||
<string>Parent</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="2">
|
||||
<widget class="QTextEdit" name="editDescription"/>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="labelAuthorLicense">
|
||||
<property name="text">
|
||||
<string>Author and License</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="2">
|
||||
<widget class="QLineEdit" name="editParent"/>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Tags</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="labelSourceURL">
|
||||
<property name="text">
|
||||
<string>Source URL</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="2">
|
||||
<widget class="QLineEdit" name="editTags"/>
|
||||
</item>
|
||||
<item row="4" column="2">
|
||||
<widget class="QLineEdit" name="editSourceReference"/>
|
||||
</item>
|
||||
<item row="3" column="2">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QLineEdit" name="editSourceURL"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="buttonURL">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>22</width>
|
||||
<height>22</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="buttonFavorite">
|
||||
<property name="text">
|
||||
<string>*</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tabProperties">
|
||||
<attribute name="title">
|
||||
<string>Properties</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_43">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_23">
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="buttonPhysicalAdd">
|
||||
<property name="text">
|
||||
<string>+</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="buttonPhysicalRemove">
|
||||
<property name="text">
|
||||
<string>-</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QTreeView" name="treePhysicalProperties"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tabAppearance">
|
||||
<attribute name="title">
|
||||
<string>Appearance</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_42">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="layoutAppearance"/>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="buttonAppearanceAdd">
|
||||
<property name="text">
|
||||
<string>+</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="buttonAppearanceRemove">
|
||||
<property name="text">
|
||||
<string>-</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QTreeView" name="treeAppearance"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="standardButtons">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok|QDialogButtonBox::Save</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
542
src/Mod/Material/Gui/ModelSelect.cpp
Normal file
542
src/Mod/Material/Gui/ModelSelect.cpp
Normal file
@@ -0,0 +1,542 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
|
||||
* *
|
||||
* 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 *
|
||||
* <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
**************************************************************************/
|
||||
|
||||
#include "PreCompiled.h"
|
||||
#ifndef _PreComp_
|
||||
#include <QDesktopServices>
|
||||
#include <QItemSelectionModel>
|
||||
#include <QPushButton>
|
||||
#include <QString>
|
||||
#endif
|
||||
|
||||
#include <App/Application.h>
|
||||
#include <Base/Interpreter.h>
|
||||
#include <Gui/Application.h>
|
||||
#include <Gui/Command.h>
|
||||
#include <Gui/WaitCursor.h>
|
||||
|
||||
#include <Mod/Material/App/ModelManager.h>
|
||||
|
||||
#include "ModelSelect.h"
|
||||
#include "ui_ModelSelect.h"
|
||||
|
||||
|
||||
using namespace MatGui;
|
||||
|
||||
/* TRANSLATOR MatGui::ModelSelect */
|
||||
|
||||
ModelSelect::ModelSelect(QWidget* parent, Materials::ModelManager::ModelFilter filter)
|
||||
: QDialog(parent)
|
||||
, _filter(filter)
|
||||
, ui(new Ui_ModelSelect)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
getFavorites();
|
||||
getRecents();
|
||||
|
||||
createModelTree();
|
||||
createModelProperties();
|
||||
|
||||
ui->buttonURL->setIcon(QIcon(QString::fromStdString(":/icons/internet-web-browser.svg")));
|
||||
ui->buttonDOI->setIcon(QIcon(QString::fromStdString(":/icons/internet-web-browser.svg")));
|
||||
|
||||
connect(ui->standardButtons, &QDialogButtonBox::accepted, this, &ModelSelect::accept);
|
||||
connect(ui->standardButtons, &QDialogButtonBox::rejected, this, &ModelSelect::reject);
|
||||
|
||||
QItemSelectionModel* selectionModel = ui->treeModels->selectionModel();
|
||||
connect(selectionModel,
|
||||
&QItemSelectionModel::selectionChanged,
|
||||
this,
|
||||
&ModelSelect::onSelectModel);
|
||||
|
||||
connect(ui->buttonURL, &QPushButton::clicked, this, &ModelSelect::onURL);
|
||||
connect(ui->buttonDOI, &QPushButton::clicked, this, &ModelSelect::onDOI);
|
||||
connect(ui->buttonFavorite, &QPushButton::clicked, this, &ModelSelect::onFavourite);
|
||||
|
||||
ui->standardButtons->button(QDialogButtonBox::Ok)->setEnabled(false);
|
||||
ui->buttonFavorite->setEnabled(false);
|
||||
}
|
||||
|
||||
void ModelSelect::getFavorites()
|
||||
{
|
||||
_favorites.clear();
|
||||
|
||||
auto param = App::GetApplication().GetParameterGroupByPath(
|
||||
"User parameter:BaseApp/Preferences/Mod/Material/Models/Favorites");
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
void ModelSelect::saveFavorites()
|
||||
{
|
||||
auto param = App::GetApplication().GetParameterGroupByPath(
|
||||
"User parameter:BaseApp/Preferences/Mod/Material/Models/Favorites");
|
||||
|
||||
// Clear out the existing favorites
|
||||
int count = param->GetInt("Favorites", 0);
|
||||
for (int i = 0; i < count; i++) {
|
||||
QString key = QString::fromLatin1("FAV%1").arg(i);
|
||||
param->RemoveASCII(key.toStdString().c_str());
|
||||
}
|
||||
|
||||
// Add the current values
|
||||
param->SetInt("Favorites", _favorites.size());
|
||||
int j = 0;
|
||||
for (auto favorite : _favorites) {
|
||||
QString key = QString::fromLatin1("FAV%1").arg(j);
|
||||
param->SetASCII(key.toStdString().c_str(), favorite.toStdString());
|
||||
|
||||
j++;
|
||||
}
|
||||
}
|
||||
|
||||
void ModelSelect::addFavorite(const QString& uuid)
|
||||
{
|
||||
if (!isFavorite(uuid)) {
|
||||
_favorites.push_back(uuid);
|
||||
saveFavorites();
|
||||
refreshModelTree();
|
||||
}
|
||||
}
|
||||
|
||||
void ModelSelect::removeFavorite(const QString& uuid)
|
||||
{
|
||||
if (isFavorite(uuid)) {
|
||||
_favorites.remove(uuid);
|
||||
saveFavorites();
|
||||
refreshModelTree();
|
||||
}
|
||||
}
|
||||
|
||||
bool ModelSelect::isFavorite(const QString& uuid) const
|
||||
{
|
||||
for (auto it : _favorites) {
|
||||
if (it == uuid) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void ModelSelect::getRecents()
|
||||
{
|
||||
_recents.clear();
|
||||
|
||||
auto param = App::GetApplication().GetParameterGroupByPath(
|
||||
"User parameter:BaseApp/Preferences/Mod/Material/Models/Recent");
|
||||
_recentMax = param->GetInt("RecentMax", 5);
|
||||
int count = param->GetInt("Recent", 0);
|
||||
for (int i = 0; i < count; i++) {
|
||||
QString key = QString::fromLatin1("MRU%1").arg(i);
|
||||
QString uuid = QString::fromStdString(param->GetASCII(key.toStdString().c_str(), ""));
|
||||
_recents.push_back(uuid);
|
||||
}
|
||||
}
|
||||
|
||||
void ModelSelect::saveRecents()
|
||||
{
|
||||
auto param = App::GetApplication().GetParameterGroupByPath(
|
||||
"User parameter:BaseApp/Preferences/Mod/Material/Models/Recent");
|
||||
|
||||
// Clear out the existing favorites
|
||||
int count = param->GetInt("Recent", 0);
|
||||
for (int i = 0; i < count; i++) {
|
||||
QString key = QString::fromLatin1("MRU%1").arg(i);
|
||||
param->RemoveASCII(key.toStdString().c_str());
|
||||
}
|
||||
|
||||
// Add the current values
|
||||
int size = _recents.size();
|
||||
if (size > _recentMax) {
|
||||
size = _recentMax;
|
||||
}
|
||||
param->SetInt("Recent", size);
|
||||
int j = 0;
|
||||
for (auto recent : _recents) {
|
||||
QString key = QString::fromLatin1("MRU%1").arg(j);
|
||||
param->SetASCII(key.toStdString().c_str(), recent.toStdString());
|
||||
|
||||
j++;
|
||||
if (j >= size) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ModelSelect::addRecent(const QString& uuid)
|
||||
{
|
||||
// Ensure no duplicates
|
||||
if (isRecent(uuid)) {
|
||||
_recents.remove(uuid);
|
||||
}
|
||||
|
||||
_recents.push_front(uuid);
|
||||
while (_recents.size() > static_cast<std::size_t>(_recentMax)) {
|
||||
_recents.pop_back();
|
||||
}
|
||||
|
||||
saveRecents();
|
||||
}
|
||||
|
||||
bool ModelSelect::isRecent(const QString& uuid) const
|
||||
{
|
||||
for (auto it : _recents) {
|
||||
if (it == uuid) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Destroys the object and frees any allocated resources
|
||||
*/
|
||||
ModelSelect::~ModelSelect()
|
||||
{
|
||||
// no need to delete child widgets, Qt does it all for us
|
||||
}
|
||||
|
||||
void ModelSelect::addExpanded(QTreeView* tree, QStandardItem* parent, QStandardItem* child)
|
||||
{
|
||||
parent->appendRow(child);
|
||||
tree->setExpanded(child->index(), true);
|
||||
}
|
||||
|
||||
void ModelSelect::addExpanded(QTreeView* tree, QStandardItemModel* parent, QStandardItem* child)
|
||||
{
|
||||
parent->appendRow(child);
|
||||
tree->setExpanded(child->index(), true);
|
||||
}
|
||||
|
||||
void ModelSelect::addModels(
|
||||
QStandardItem& parent,
|
||||
const std::shared_ptr<std::map<QString, Materials::ModelTreeNode*>> modelTree,
|
||||
const QIcon& icon)
|
||||
{
|
||||
auto tree = ui->treeModels;
|
||||
for (auto& mod : *modelTree) {
|
||||
Materials::ModelTreeNode* nodePtr = mod.second;
|
||||
if (nodePtr->getType() == Materials::ModelTreeNode::DataNode) {
|
||||
const Materials::Model* model = nodePtr->getData();
|
||||
QString uuid = model->getUUID();
|
||||
|
||||
auto card = new QStandardItem(icon, model->getName());
|
||||
card->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsDragEnabled
|
||||
| Qt::ItemIsDropEnabled);
|
||||
card->setData(QVariant(uuid), Qt::UserRole);
|
||||
|
||||
addExpanded(tree, &parent, card);
|
||||
}
|
||||
else {
|
||||
auto node = new QStandardItem(mod.first);
|
||||
addExpanded(tree, &parent, node);
|
||||
node->setFlags(Qt::ItemIsEnabled | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled);
|
||||
auto treeMap = nodePtr->getFolder();
|
||||
addModels(*node, treeMap, icon);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ModelSelect::addRecents(QStandardItem* parent)
|
||||
{
|
||||
auto tree = ui->treeModels;
|
||||
for (auto& uuid : _recents) {
|
||||
try {
|
||||
const Materials::Model& model = getModelManager().getModel(uuid);
|
||||
|
||||
if (getModelManager().passFilter(_filter, model.getType())) {
|
||||
QIcon icon = QIcon(model.getLibrary().getIconPath());
|
||||
auto card = new QStandardItem(icon, model.getName());
|
||||
card->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsDragEnabled
|
||||
| Qt::ItemIsDropEnabled);
|
||||
card->setData(QVariant(uuid), Qt::UserRole);
|
||||
|
||||
addExpanded(tree, parent, card);
|
||||
}
|
||||
}
|
||||
catch (const Materials::ModelNotFound&) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ModelSelect::addFavorites(QStandardItem* parent)
|
||||
{
|
||||
auto tree = ui->treeModels;
|
||||
for (auto& uuid : _favorites) {
|
||||
try {
|
||||
const Materials::Model& model = getModelManager().getModel(uuid);
|
||||
|
||||
if (getModelManager().passFilter(_filter, model.getType())) {
|
||||
QIcon icon = QIcon(model.getLibrary().getIconPath());
|
||||
auto card = new QStandardItem(icon, model.getName());
|
||||
card->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsDragEnabled
|
||||
| Qt::ItemIsDropEnabled);
|
||||
card->setData(QVariant(uuid), Qt::UserRole);
|
||||
|
||||
addExpanded(tree, parent, card);
|
||||
}
|
||||
}
|
||||
catch (const Materials::ModelNotFound&) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ModelSelect::createModelTree()
|
||||
{
|
||||
// Materials::ModelManager modelManager;
|
||||
|
||||
auto tree = ui->treeModels;
|
||||
auto model = new QStandardItemModel();
|
||||
tree->setModel(model);
|
||||
tree->setHeaderHidden(true);
|
||||
|
||||
fillTree();
|
||||
}
|
||||
|
||||
void ModelSelect::refreshModelTree()
|
||||
{
|
||||
auto tree = ui->treeModels;
|
||||
auto model = static_cast<QStandardItemModel*>(tree->model());
|
||||
model->clear();
|
||||
|
||||
fillTree();
|
||||
}
|
||||
|
||||
void ModelSelect::fillTree()
|
||||
{
|
||||
// Materials::ModelManager modelManager;
|
||||
|
||||
auto tree = ui->treeModels;
|
||||
auto model = static_cast<QStandardItemModel*>(tree->model());
|
||||
|
||||
auto lib = new QStandardItem(QString::fromStdString("Favorites"));
|
||||
lib->setFlags(Qt::ItemIsEnabled | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled);
|
||||
addExpanded(tree, model, lib);
|
||||
addFavorites(lib);
|
||||
|
||||
lib = new QStandardItem(QString::fromStdString("Recent"));
|
||||
lib->setFlags(Qt::ItemIsEnabled | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled);
|
||||
addExpanded(tree, model, lib);
|
||||
addRecents(lib);
|
||||
|
||||
auto libraries = getModelManager().getModelLibraries();
|
||||
for (auto library : *libraries) {
|
||||
lib = new QStandardItem(library->getName());
|
||||
lib->setFlags(Qt::ItemIsEnabled | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled);
|
||||
addExpanded(tree, model, lib);
|
||||
|
||||
auto modelTree = getModelManager().getModelTree(*library, _filter);
|
||||
addModels(*lib, modelTree, QIcon(library->getIconPath()));
|
||||
}
|
||||
}
|
||||
|
||||
void ModelSelect::setHeaders(QStandardItemModel* model)
|
||||
{
|
||||
QStringList headers;
|
||||
headers.append(QString::fromStdString("Inherited"));
|
||||
headers.append(QString::fromStdString("Property"));
|
||||
headers.append(QString::fromStdString("Units"));
|
||||
headers.append(QString::fromStdString("Description"));
|
||||
headers.append(QString::fromStdString("URL"));
|
||||
|
||||
model->setHorizontalHeaderLabels(headers);
|
||||
}
|
||||
|
||||
void ModelSelect::setColumnWidths(QTableView* table)
|
||||
{
|
||||
table->setColumnWidth(0, 75);
|
||||
table->setColumnWidth(1, 200);
|
||||
table->setColumnWidth(2, 200);
|
||||
table->setColumnWidth(3, 200);
|
||||
table->setColumnWidth(4, 200);
|
||||
}
|
||||
|
||||
void ModelSelect::createModelProperties()
|
||||
{
|
||||
auto table = ui->tableProperties;
|
||||
auto model = new QStandardItemModel();
|
||||
table->setModel(model);
|
||||
table->setEditTriggers(QAbstractItemView::NoEditTriggers);
|
||||
|
||||
setHeaders(model);
|
||||
setColumnWidths(table);
|
||||
|
||||
// table->setHeaderHidden(false);
|
||||
// table->setUniformRowHeights(true);
|
||||
// table->setItemDelegate(new MaterialDelegate(this));
|
||||
}
|
||||
|
||||
void ModelSelect::updateModelProperties(const Materials::Model& model)
|
||||
{
|
||||
QTableView* table = ui->tableProperties;
|
||||
QStandardItemModel* tableModel = static_cast<QStandardItemModel*>(table->model());
|
||||
tableModel->clear();
|
||||
|
||||
setHeaders(tableModel);
|
||||
setColumnWidths(table);
|
||||
|
||||
for (auto itp = model.begin(); itp != model.end(); itp++) {
|
||||
QList<QStandardItem*> items;
|
||||
|
||||
QString key = itp->first;
|
||||
const Materials::ModelProperty modelProperty =
|
||||
static_cast<const Materials::ModelProperty>(itp->second);
|
||||
|
||||
auto inherited =
|
||||
new QStandardItem(QString::fromStdString(modelProperty.isInherited() ? "*" : ""));
|
||||
// inherited->setToolTip(QString::fromStdString(modelProperty.getDescription()));
|
||||
items.append(inherited);
|
||||
|
||||
auto propertyItem = new QStandardItem(key);
|
||||
items.append(propertyItem);
|
||||
|
||||
auto unitsItem = new QStandardItem(modelProperty.getUnits());
|
||||
items.append(unitsItem);
|
||||
|
||||
auto descriptionItem = new QStandardItem(modelProperty.getDescription());
|
||||
items.append(descriptionItem);
|
||||
|
||||
auto urlItem = new QStandardItem(modelProperty.getURL());
|
||||
items.append(urlItem);
|
||||
|
||||
// addExpanded(tree, modelRoot, propertyItem);
|
||||
tableModel->appendRow(items);
|
||||
}
|
||||
}
|
||||
|
||||
void ModelSelect::updateMaterialModel(const QString& uuid)
|
||||
{
|
||||
Materials::Model model = getModelManager().getModel(uuid);
|
||||
|
||||
// Update the general information
|
||||
ui->editName->setText(model.getName());
|
||||
ui->editURL->setText(model.getURL());
|
||||
ui->editDOI->setText(model.getDOI());
|
||||
ui->editDescription->setText(model.getDescription());
|
||||
|
||||
if (model.getType() == Materials::Model::ModelType_Physical) {
|
||||
ui->tabWidget->setTabText(1, QString::fromStdString("Properties"));
|
||||
}
|
||||
else {
|
||||
ui->tabWidget->setTabText(1, QString::fromStdString("Appearance"));
|
||||
}
|
||||
updateModelProperties(model);
|
||||
}
|
||||
|
||||
void ModelSelect::clearMaterialModel()
|
||||
{
|
||||
// Update the general information
|
||||
ui->editName->setText(QString::fromStdString(""));
|
||||
ui->editURL->setText(QString::fromStdString(""));
|
||||
ui->editDOI->setText(QString::fromStdString(""));
|
||||
ui->editDescription->setText(QString::fromStdString(""));
|
||||
|
||||
ui->tabWidget->setTabText(1, QString::fromStdString("Properties"));
|
||||
|
||||
QTableView* table = ui->tableProperties;
|
||||
QStandardItemModel* tableModel = static_cast<QStandardItemModel*>(table->model());
|
||||
tableModel->clear();
|
||||
|
||||
setHeaders(tableModel);
|
||||
setColumnWidths(table);
|
||||
}
|
||||
|
||||
void ModelSelect::onSelectModel(const QItemSelection& selected, const QItemSelection& deselected)
|
||||
{
|
||||
Q_UNUSED(deselected);
|
||||
|
||||
QStandardItemModel* model = static_cast<QStandardItemModel*>(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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
void ModelSelect::onFavourite(bool checked)
|
||||
{
|
||||
Q_UNUSED(checked)
|
||||
|
||||
Base::Console().Log("Favorite\n");
|
||||
if (isFavorite(_selected)) {
|
||||
removeFavorite(_selected);
|
||||
}
|
||||
else {
|
||||
addFavorite(_selected);
|
||||
}
|
||||
}
|
||||
|
||||
void ModelSelect::accept()
|
||||
{
|
||||
addRecent(_selected);
|
||||
QDialog::accept();
|
||||
}
|
||||
|
||||
void ModelSelect::reject()
|
||||
{
|
||||
QDialog::reject();
|
||||
}
|
||||
|
||||
#include "moc_ModelSelect.cpp"
|
||||
108
src/Mod/Material/Gui/ModelSelect.h
Normal file
108
src/Mod/Material/Gui/ModelSelect.h
Normal file
@@ -0,0 +1,108 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
|
||||
* *
|
||||
* 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 *
|
||||
* <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef MATGUI_MODELSELECT_H
|
||||
#define MATGUI_MODELSELECT_H
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
#include <QDialog>
|
||||
#include <QDir>
|
||||
#include <QStandardItem>
|
||||
#include <QTableView>
|
||||
#include <QTreeView>
|
||||
|
||||
#include <Mod/Material/App/Materials.h>
|
||||
|
||||
namespace fs = boost::filesystem;
|
||||
|
||||
namespace MatGui
|
||||
{
|
||||
|
||||
class Ui_ModelSelect;
|
||||
|
||||
class ModelSelect: public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ModelSelect(
|
||||
QWidget* parent = nullptr,
|
||||
Materials::ModelManager::ModelFilter filter = Materials::ModelManager::ModelFilter_None);
|
||||
~ModelSelect() override;
|
||||
|
||||
void onURL(bool checked);
|
||||
void onDOI(bool checked);
|
||||
void onFavourite(bool checked);
|
||||
void onSelectModel(const QItemSelection& selected, const QItemSelection& deselected);
|
||||
const QString& selectedModel() const
|
||||
{
|
||||
return _selected;
|
||||
}
|
||||
void accept() override;
|
||||
void reject() override;
|
||||
|
||||
private:
|
||||
void getFavorites();
|
||||
void saveFavorites();
|
||||
void addFavorite(const QString& uuid);
|
||||
void removeFavorite(const QString& uuid);
|
||||
bool isFavorite(const QString& uuid) const;
|
||||
|
||||
void getRecents();
|
||||
void saveRecents();
|
||||
void addRecent(const QString& uuid);
|
||||
bool isRecent(const QString& uuid) const;
|
||||
|
||||
void addExpanded(QTreeView* tree, QStandardItem* parent, QStandardItem* child);
|
||||
void addExpanded(QTreeView* tree, QStandardItemModel* parent, QStandardItem* child);
|
||||
void addRecents(QStandardItem* parent);
|
||||
void addFavorites(QStandardItem* parent);
|
||||
void addModels(QStandardItem& parent,
|
||||
const std::shared_ptr<std::map<QString, Materials::ModelTreeNode*>> modelTree,
|
||||
const QIcon& icon);
|
||||
void updateMaterialModel(const QString& uuid);
|
||||
void clearMaterialModel();
|
||||
void createModelTree();
|
||||
void refreshModelTree();
|
||||
void fillTree();
|
||||
|
||||
void setHeaders(QStandardItemModel* model);
|
||||
void setColumnWidths(QTableView* table);
|
||||
void updateModelProperties(const Materials::Model& model);
|
||||
void createModelProperties();
|
||||
Materials::ModelManager& getModelManager()
|
||||
{
|
||||
return _modelManager;
|
||||
}
|
||||
|
||||
Materials::ModelManager::ModelFilter _filter;
|
||||
std::unique_ptr<Ui_ModelSelect> ui;
|
||||
Materials::ModelManager _modelManager;
|
||||
QString _selected;
|
||||
std::list<QString> _favorites;
|
||||
std::list<QString> _recents;
|
||||
int _recentMax;
|
||||
};
|
||||
|
||||
} // namespace MatGui
|
||||
|
||||
#endif // MATGUI_MODELSELECT_H
|
||||
197
src/Mod/Material/Gui/ModelSelect.ui
Normal file
197
src/Mod/Material/Gui/ModelSelect.ui
Normal file
@@ -0,0 +1,197 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>MatGui::ModelSelect</class>
|
||||
<widget class="QDialog" name="MatGui::ModelSelect">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>705</width>
|
||||
<height>489</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Material Models</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QSplitter" name="splitter">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<widget class="QTreeView" name="treeModels"/>
|
||||
<widget class="QTabWidget" name="tabWidget">
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="tabGeneral">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>365</width>
|
||||
<height>409</height>
|
||||
</size>
|
||||
</property>
|
||||
<attribute name="title">
|
||||
<string>General</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="labelURL">
|
||||
<property name="text">
|
||||
<string>URL</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Description</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="labelDOI">
|
||||
<property name="text">
|
||||
<string>DOI</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QTextEdit" name="editDescription">
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="editName">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="labelName">
|
||||
<property name="text">
|
||||
<string>Name</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<item>
|
||||
<widget class="QLineEdit" name="editDOI">
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="buttonDOI">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>22</width>
|
||||
<height>22</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QLineEdit" name="editURL">
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="buttonURL">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>22</width>
|
||||
<height>22</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="buttonFavorite">
|
||||
<property name="toolTip">
|
||||
<string>Add to favorites</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>*</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tabProperties">
|
||||
<attribute name="title">
|
||||
<string>Properties</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item>
|
||||
<widget class="QTableView" name="tableProperties"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="standardButtons">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
22
src/Mod/Material/Gui/PreCompiled.cpp
Normal file
22
src/Mod/Material/Gui/PreCompiled.cpp
Normal file
@@ -0,0 +1,22 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
|
||||
* *
|
||||
* 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 *
|
||||
* <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
**************************************************************************/
|
||||
|
||||
#include "PreCompiled.h"
|
||||
74
src/Mod/Material/Gui/PreCompiled.h
Normal file
74
src/Mod/Material/Gui/PreCompiled.h
Normal file
@@ -0,0 +1,74 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
|
||||
* *
|
||||
* 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 *
|
||||
* <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef MATGUI_PRECOMPILED_H
|
||||
#define MATGUI_PRECOMPILED_H
|
||||
|
||||
#include <FCConfig.h>
|
||||
|
||||
// point at which warnings of overly long specifiers disabled (needed for VC6)
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable : 4251)
|
||||
#pragma warning(disable : 4503)
|
||||
#pragma warning(disable : 4786) // specifier longer then 255 chars
|
||||
#pragma warning(disable : 4273)
|
||||
#endif
|
||||
|
||||
#ifdef FC_OS_WIN32
|
||||
#ifndef NOMINMAX
|
||||
#define NOMINMAX
|
||||
#endif
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#ifdef _PreComp_
|
||||
|
||||
// standard
|
||||
#include <cfloat>
|
||||
#include <cmath>
|
||||
|
||||
// STL
|
||||
#include <algorithm>
|
||||
#include <map>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
// OpenCasCade
|
||||
// #include <Mod/Part/App/OpenCascadeAll.h>
|
||||
|
||||
// Boost
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
#include <boost/regex.hpp>
|
||||
|
||||
// Qt Toolkit
|
||||
#ifndef __QtAll__
|
||||
#include <Gui/QtAll.h>
|
||||
#endif
|
||||
|
||||
// // Inventor includes OpenGL
|
||||
// #ifndef __InventorAll__
|
||||
// # include <Gui/InventorAll.h>
|
||||
// #endif
|
||||
|
||||
#endif //_PreComp_
|
||||
|
||||
#endif // MATGUI_PRECOMPILED_H
|
||||
10
src/Mod/Material/Gui/Resources/Material.qrc
Normal file
10
src/Mod/Material/Gui/Resources/Material.qrc
Normal file
@@ -0,0 +1,10 @@
|
||||
<RCC>
|
||||
<qresource>
|
||||
<file>icons/MaterialWorkbench.svg</file>
|
||||
<file>icons/Materials_Edit.svg</file>
|
||||
<file>icons/preferences-material.svg</file>
|
||||
<file>icons/preview-rendered.svg</file>
|
||||
<file>icons/preview-vector.svg</file>
|
||||
<file>icons/table.svg</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
128
src/Mod/Material/Gui/Resources/icons/MaterialWorkbench.svg
Normal file
128
src/Mod/Material/Gui/Resources/icons/MaterialWorkbench.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 16 KiB |
128
src/Mod/Material/Gui/Resources/icons/Materials_Edit.svg
Normal file
128
src/Mod/Material/Gui/Resources/icons/Materials_Edit.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 16 KiB |
128
src/Mod/Material/Gui/Resources/icons/preferences-material.svg
Normal file
128
src/Mod/Material/Gui/Resources/icons/preferences-material.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 16 KiB |
65
src/Mod/Material/Gui/Resources/icons/preview-rendered.svg
Normal file
65
src/Mod/Material/Gui/Resources/icons/preview-rendered.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 6.2 KiB |
157
src/Mod/Material/Gui/Resources/icons/preview-vector.svg
Normal file
157
src/Mod/Material/Gui/Resources/icons/preview-vector.svg
Normal file
@@ -0,0 +1,157 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="64"
|
||||
height="64"
|
||||
id="svg2"
|
||||
version="1.1"
|
||||
inkscape:version="0.48.5 r10040"
|
||||
sodipodi:docname="preview-vector.svg">
|
||||
<defs
|
||||
id="defs4">
|
||||
<inkscape:perspective
|
||||
sodipodi:type="inkscape:persp3d"
|
||||
inkscape:vp_x="-206.25075 : 119.68854 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_z="183.50001 : 140.32143 : 1"
|
||||
inkscape:persp3d-origin="48 : 32 : 1"
|
||||
id="perspective3792" />
|
||||
<linearGradient
|
||||
id="linearGradient3755">
|
||||
<stop
|
||||
style="stop-color:#424242;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop3757" />
|
||||
<stop
|
||||
style="stop-color:#9f9f9f;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop3759" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3755"
|
||||
id="linearGradient3761"
|
||||
x1="75.724594"
|
||||
y1="85.023956"
|
||||
x2="41.895164"
|
||||
y2="13.334851"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="8.7571168"
|
||||
inkscape:cx="39.859065"
|
||||
inkscape:cy="30.925664"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="g3794"
|
||||
showgrid="true"
|
||||
showborder="true"
|
||||
inkscape:window-width="800"
|
||||
inkscape:window-height="836"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="27"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:snap-bbox="false"
|
||||
inkscape:snap-nodes="true"
|
||||
inkscape:snap-global="true">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid3002"
|
||||
empspacing="2"
|
||||
visible="true"
|
||||
enabled="true"
|
||||
snapvisiblegridlinesonly="true" />
|
||||
</sodipodi:namedview>
|
||||
<metadata
|
||||
id="metadata7">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title />
|
||||
<dc:creator>
|
||||
<cc:Agent>
|
||||
<dc:title>$committer</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:creator>
|
||||
<dc:title>preview-vector</dc:title>
|
||||
<dc:date>2013-11-19</dc:date>
|
||||
<dc:relation>http://www.freecad.org/wiki/index.php?title=Artwork</dc:relation>
|
||||
<dc:publisher>
|
||||
<cc:Agent>
|
||||
<dc:title>FreeCAD</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:publisher>
|
||||
<dc:identifier>FreeCAD/src/Mod/Material/Resources/icons/preview-vector.svg</dc:identifier>
|
||||
<dc:rights>
|
||||
<cc:Agent>
|
||||
<dc:title>FreeCAD LGPL2+</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:rights>
|
||||
<cc:license>https://www.gnu.org/copyleft/lesser.html</cc:license>
|
||||
<dc:contributor>
|
||||
<cc:Agent>
|
||||
<dc:title>[agryson] Alexander Gryson</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:contributor>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(0,-988.36218)">
|
||||
<g
|
||||
id="g3794"
|
||||
style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:3.29399991;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate">
|
||||
<path
|
||||
style="fill:#d3d7cf;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
|
||||
d="m 29.814326,991.36218 -8.814326,4 -1,7.00002 26,1 14.994091,-8.6577 z"
|
||||
id="path3816"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cccccc" />
|
||||
<path
|
||||
d="M 38.484871,1007.8171 40,1046.3622 l 21,-22.4044 0,-29.25647 z"
|
||||
style="fill:#b7b7b7;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
|
||||
id="path3818"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccccc" />
|
||||
<path
|
||||
style="fill:#555753;stroke:#555753;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="M 59.035745,9.6627807 59.108006,34.818961 40.91531,54.264958 42.698526,19.372964 z"
|
||||
id="path3022"
|
||||
inkscape:connector-curvature="0"
|
||||
transform="translate(0,988.36218)"
|
||||
sodipodi:nodetypes="ccccc" />
|
||||
<path
|
||||
d="m 21,995.36218 31,5.00002 -12,46 -30,-8 z"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:4;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
|
||||
id="path3820"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccccc" />
|
||||
<path
|
||||
d="m 21,995.36218 31,5.00002 -12,46 -30,-8 z"
|
||||
style="color:#000000;fill:none;stroke:#888a85;stroke-width:2;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
id="path3820-3"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccccc" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 5.7 KiB |
77
src/Mod/Material/Gui/Resources/icons/table.svg
Normal file
77
src/Mod/Material/Gui/Resources/icons/table.svg
Normal file
@@ -0,0 +1,77 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
width="64"
|
||||
height="64"
|
||||
viewBox="0 0 16.933333 16.933333"
|
||||
version="1.1"
|
||||
id="svg5"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<defs
|
||||
id="defs2">
|
||||
<linearGradient
|
||||
id="linearGradient992">
|
||||
<stop
|
||||
style="stop-color:#ff0000;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop990" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<g
|
||||
id="layer1">
|
||||
<rect
|
||||
style="fill:none;stroke:#000000;stroke-width:0.52916667;stroke-opacity:1;stroke-dasharray:none"
|
||||
id="rect434"
|
||||
width="14.684375"
|
||||
height="14.122135"
|
||||
x="1.1244792"
|
||||
y="1.3559896" />
|
||||
<path
|
||||
style="fill:none;stroke:#000000;stroke-width:0.529167;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M 1.1244792,4.9609349 15.643489,5.0270807"
|
||||
id="path1407" />
|
||||
<path
|
||||
style="fill:none;stroke:#000000;stroke-width:0.529167;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M 1.9182291,7.3752603 H 5.523177 v 0"
|
||||
id="path2181" />
|
||||
<path
|
||||
style="fill:none;stroke:#000000;stroke-width:0.529167;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 6.8295573,7.3421875 h 3.6049477 v 0"
|
||||
id="path2181-4" />
|
||||
<path
|
||||
style="fill:none;stroke:#000000;stroke-width:0.529167;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 11.426692,7.4083334 h 3.604948 v 0"
|
||||
id="path2181-5" />
|
||||
<path
|
||||
style="fill:none;stroke:#000000;stroke-width:0.529167;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 1.9099611,12.567709 h 3.604948 v 0"
|
||||
id="path2181-2" />
|
||||
<path
|
||||
style="fill:none;stroke:#000000;stroke-width:0.529167;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 6.8212891,12.534636 h 3.6049479 v 0"
|
||||
id="path2181-4-0" />
|
||||
<path
|
||||
style="fill:none;stroke:#000000;stroke-width:0.529167;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 11.418424,12.600782 h 3.604948 v 0"
|
||||
id="path2181-5-5" />
|
||||
<path
|
||||
style="fill:none;stroke:#000000;stroke-width:0.529167;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 1.9264977,10.021094 h 3.6049479 v 0"
|
||||
id="path2181-46" />
|
||||
<path
|
||||
style="fill:none;stroke:#000000;stroke-width:0.529167;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 6.8378259,10.021094 h 3.6049471 v 0"
|
||||
id="path2181-4-3" />
|
||||
<path
|
||||
style="fill:none;stroke:#000000;stroke-width:0.529167;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 11.43496,10.054167 h 3.604948 v 0"
|
||||
id="path2181-5-7" />
|
||||
<path
|
||||
style="fill:#0000ff;stroke:#000000;stroke-width:0.25;stroke-dasharray:none;stroke-opacity:1;fill-opacity:1"
|
||||
d="M 29.5,17.805701 C 20.7,17.760754 11.657813,17.715771 9.40625,17.705739 L 5.3125,17.6875 v -5.75 -5.75 H 32 58.6875 v 5.875 5.875 L 52.09375,17.91246 C 48.467188,17.89869 38.3,17.850648 29.5,17.805701 Z"
|
||||
id="path2364"
|
||||
transform="scale(0.26458333)" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.0 KiB |
85
src/Mod/Material/Gui/Resources/translations/Material.ts
Normal file
85
src/Mod/Material/Gui/Resources/translations/Material.ts
Normal file
@@ -0,0 +1,85 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE TS>
|
||||
<TS version="2.1">
|
||||
<context>
|
||||
<name>MaterialEditor</name>
|
||||
<message>
|
||||
<location filename="../../materials-editor.ui" line="14"/>
|
||||
<source>Material Editor</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../materials-editor.ui" line="22"/>
|
||||
<source>Material card</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../materials-editor.ui" line="40"/>
|
||||
<source>Opens the Product URL of this material in an external browser</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../materials-editor.ui" line="56"/>
|
||||
<source>Existing material cards</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../materials-editor.ui" line="67"/>
|
||||
<source>Opens an existing material card</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../materials-editor.ui" line="70"/>
|
||||
<source>Open...</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../materials-editor.ui" line="77"/>
|
||||
<source>Saves this material as a card</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../materials-editor.ui" line="80"/>
|
||||
<source>Save as...</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../materials-editor.ui" line="96"/>
|
||||
<source>Material parameter</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../materials-editor.ui" line="115"/>
|
||||
<source>Add / remove parameter</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../materials-editor.ui" line="126"/>
|
||||
<source>Add property</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../materials-editor.ui" line="133"/>
|
||||
<source>Delete property</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>Material</name>
|
||||
<message>
|
||||
<location filename="../../MaterialEditor.py" line="275"/>
|
||||
<source>Product URL</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../MaterialEditor.py" line="337"/>
|
||||
<source>UserDefined</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../MaterialEditor.py" line="583"/>
|
||||
<source>Name</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
||||
34
src/Mod/Material/Gui/Workbench.cpp
Normal file
34
src/Mod/Material/Gui/Workbench.cpp
Normal file
@@ -0,0 +1,34 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
|
||||
* *
|
||||
* 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 *
|
||||
* <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
**************************************************************************/
|
||||
|
||||
|
||||
#include "PreCompiled.h"
|
||||
|
||||
#include "Workbench.h"
|
||||
|
||||
using namespace MatGui;
|
||||
|
||||
/// @namespace MatGui @class Workbench
|
||||
TYPESYSTEM_SOURCE(MatGui::Workbench, Gui::StdWorkbench)
|
||||
|
||||
Workbench::Workbench() = default;
|
||||
|
||||
Workbench::~Workbench() = default;
|
||||
47
src/Mod/Material/Gui/Workbench.h
Normal file
47
src/Mod/Material/Gui/Workbench.h
Normal file
@@ -0,0 +1,47 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
|
||||
* *
|
||||
* 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 *
|
||||
* <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
**************************************************************************/
|
||||
|
||||
|
||||
#ifndef MATGUI_WORKBENCH_H
|
||||
#define MATGUI_WORKBENCH_H
|
||||
|
||||
#include <Gui/Workbench.h>
|
||||
#include <Mod/Material/MaterialGlobal.h>
|
||||
|
||||
namespace MatGui
|
||||
{
|
||||
|
||||
/**
|
||||
* @author David Carter
|
||||
*/
|
||||
class MatGuiExport Workbench: public Gui::StdWorkbench
|
||||
{
|
||||
TYPESYSTEM_HEADER_WITH_OVERRIDE();
|
||||
|
||||
public:
|
||||
Workbench();
|
||||
~Workbench() override;
|
||||
};
|
||||
|
||||
} // namespace MatGui
|
||||
|
||||
|
||||
#endif // MATGUI_WORKBENCH_H
|
||||
@@ -23,3 +23,5 @@ import FreeCAD
|
||||
|
||||
# import for the FreeCAD Material card
|
||||
FreeCAD.addImportType("FreeCAD Material Card (*.FCMat)", "importFCMat")
|
||||
|
||||
FreeCAD.__unit_test__ += [ "TestMaterialsApp" ]
|
||||
|
||||
@@ -18,4 +18,30 @@
|
||||
#* USA *
|
||||
#* *
|
||||
#***************************************************************************
|
||||
"""Initialization of the Material Workbench graphical interface."""
|
||||
|
||||
import FreeCAD as App
|
||||
import FreeCADGui as Gui
|
||||
import os
|
||||
|
||||
|
||||
class MaterialWorkbench(Gui.Workbench):
|
||||
"""Part workbench object."""
|
||||
|
||||
def __init__(self):
|
||||
self.__class__.Icon = os.path.join(App.getResourceDir(),
|
||||
"Mod", "Material",
|
||||
"Resources", "icons",
|
||||
"MaterialWorkbench.svg")
|
||||
self.__class__.MenuText = "Material"
|
||||
self.__class__.ToolTip = "Material workbench"
|
||||
|
||||
def Initialize(self):
|
||||
# load the module
|
||||
import MatGui
|
||||
|
||||
def GetClassName(self):
|
||||
return "MatGui::Workbench"
|
||||
|
||||
|
||||
Gui.addWorkbench(MaterialWorkbench())
|
||||
|
||||
@@ -1,135 +0,0 @@
|
||||
# ***************************************************************************
|
||||
# * Copyright (c) 2013-2015 Juergen Riegel <FreeCAD@juergen-riegel.net> *
|
||||
# * *
|
||||
# * 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 *
|
||||
# * *
|
||||
# ***************************************************************************
|
||||
|
||||
import sys
|
||||
import FreeCAD
|
||||
|
||||
|
||||
# The usage description if you use this tool from the command line ("__main__")
|
||||
CommandlineUsage = """Material - Tool to work with FreeCAD Material definition cards
|
||||
|
||||
Usage:
|
||||
Material [Options] card-file-name
|
||||
|
||||
Options:
|
||||
-c, --output-csv=filename write a comma separated grid with the material data
|
||||
|
||||
Exit:
|
||||
0 No Error or Warning found
|
||||
1 Argument error, wrong or too few Arguments given
|
||||
|
||||
Tool to work with FreeCAD Material definition cards
|
||||
|
||||
Examples:
|
||||
|
||||
Material "StandardMaterial/Steel.FCMat"
|
||||
|
||||
Author:
|
||||
(c) 2013 Juergen Riegel
|
||||
mail@juergen-riegel.net
|
||||
Licence: LGPL
|
||||
|
||||
Version:
|
||||
0.1
|
||||
"""
|
||||
|
||||
|
||||
# see comments in module importFCMat, there is an independent parser implementation
|
||||
# for reading and writing FCMat files
|
||||
# inside FreeCAD mostly the one from importFCMat.py is used
|
||||
|
||||
|
||||
def importFCMat(fileName):
|
||||
"Read a FCMat file into a dictionary"
|
||||
try:
|
||||
import ConfigParser as configparser
|
||||
except ImportError:
|
||||
import configparser
|
||||
|
||||
FreeCAD.Console.PrintError(
|
||||
'This mat card reader is probably deprecated and not widely used in FreeCAD. '
|
||||
'See comment in Material.py module.\n'
|
||||
)
|
||||
Config = configparser.RawConfigParser()
|
||||
Config.optionxform = str
|
||||
Config.read(fileName, encoding='utf-8') # respect unicode filenames
|
||||
dict1 = {}
|
||||
for section in Config.sections():
|
||||
options = Config.options(section)
|
||||
for option in options:
|
||||
dict1[option] = Config.get(section, option)
|
||||
|
||||
return dict1
|
||||
|
||||
|
||||
def exportFCMat(fileName, matDict):
|
||||
"Write a material dictionary to a FCMat file"
|
||||
try:
|
||||
import ConfigParser as configparser
|
||||
except ImportError:
|
||||
import configparser
|
||||
import string
|
||||
Config = configparser.RawConfigParser()
|
||||
|
||||
FreeCAD.Console.PrintError(
|
||||
'This mat card writer is probably deprecated and not widely used in FreeCAD. '
|
||||
'See comment in Material.py module.\n'
|
||||
)
|
||||
# create groups
|
||||
for x in matDict.keys():
|
||||
grp, key = string.split(x, sep='_')
|
||||
if not Config.has_section(grp):
|
||||
Config.add_section(grp)
|
||||
|
||||
# fill groups
|
||||
for x in matDict.keys():
|
||||
grp, key = string.split(x, sep='_')
|
||||
Config.set(grp, key, matDict[x])
|
||||
|
||||
Preamble = "# This is a FreeCAD material-card file\n\n"
|
||||
# Writing our configuration file to 'example.cfg'
|
||||
with open(fileName, 'wb') as configfile:
|
||||
configfile.write(Preamble)
|
||||
Config.write(configfile)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import getopt
|
||||
try:
|
||||
opts, args = getopt.getopt(sys.argv[1:], "c:", ["output-csv="])
|
||||
except getopt.GetoptError:
|
||||
# print help information and exit:
|
||||
sys.stderr.write(CommandlineUsage)
|
||||
sys.exit(1)
|
||||
|
||||
# checking on the options
|
||||
for o, a in opts:
|
||||
if o in ("-c", "--output-csv"):
|
||||
print("writing file: " + a + "\n")
|
||||
OutPath = a
|
||||
|
||||
# running through the files
|
||||
FileName = args[0]
|
||||
|
||||
kv_map = importFCMat(FileName)
|
||||
for k in kv_map.keys():
|
||||
print(repr(k) + " : " + repr(kv_map[k]))
|
||||
sys.exit(0) # no error
|
||||
@@ -25,12 +25,15 @@ __author__ = "Yorik van Havre, Bernd Hahnebach"
|
||||
__url__ = "http://www.freecad.org"
|
||||
|
||||
import os
|
||||
from pathlib import PurePath
|
||||
import sys
|
||||
from PySide import QtCore, QtGui, QtSvg
|
||||
|
||||
import FreeCAD
|
||||
import FreeCADGui
|
||||
# import Material_rc
|
||||
from materialtools.cardutils import get_material_preferred_directory, get_material_preferred_save_directory
|
||||
|
||||
|
||||
# is this still needed after the move to card utils???
|
||||
unicode = str
|
||||
@@ -52,17 +55,21 @@ class MaterialEditor:
|
||||
self.customprops = []
|
||||
self.internalprops = []
|
||||
self.groups = []
|
||||
self.directory = FreeCAD.getResourceDir() + "Mod/Material"
|
||||
self.directory = get_material_preferred_directory()
|
||||
self.save_directory = get_material_preferred_save_directory()
|
||||
if self.directory is None:
|
||||
self.directory = FreeCAD.getResourceDir() + "Mod/Material"
|
||||
self.materials = {}
|
||||
self.cards = {}
|
||||
self.icons = {}
|
||||
self.initialIndex = -1
|
||||
self.edited = False
|
||||
self.card_path = card_path
|
||||
filePath = os.path.dirname(__file__) + os.sep
|
||||
self.iconPath = (filePath + "Resources" + os.sep + "icons" + os.sep)
|
||||
|
||||
# load the UI file from the same directory as this script
|
||||
self.widget = FreeCADGui.PySideUic.loadUi(filePath + "materials-editor.ui")
|
||||
self.widget = FreeCADGui.PySideUic.loadUi(filePath + "Resources" + os.sep + "ui" + os.sep + "materials-editor.ui")
|
||||
# remove unused Help button
|
||||
self.widget.setWindowFlags(self.widget.windowFlags()
|
||||
& ~QtCore.Qt.WindowContextHelpButtonHint)
|
||||
@@ -104,7 +111,7 @@ class MaterialEditor:
|
||||
# currently closes the dialog
|
||||
|
||||
standardButtons.rejected.connect(self.reject)
|
||||
standardButtons.accepted.connect(self.accept)
|
||||
standardButtons.button(QtGui.QDialogButtonBox.Ok).clicked.connect(self.verify)
|
||||
buttonOpen.clicked.connect(self.openfile)
|
||||
buttonSave.clicked.connect(self.savefile)
|
||||
buttonURL.clicked.connect(self.openProductURL)
|
||||
@@ -117,6 +124,7 @@ class MaterialEditor:
|
||||
treeView.setModel(model)
|
||||
treeView.setUniformRowHeights(True)
|
||||
treeView.setItemDelegate(MaterialsDelegate())
|
||||
model.itemChanged.connect(self.modelChange)
|
||||
|
||||
# init model
|
||||
self.implementModel()
|
||||
@@ -181,6 +189,7 @@ class MaterialEditor:
|
||||
# top.sortChildren(0)
|
||||
|
||||
# treeView.expandAll()
|
||||
self.edited = False
|
||||
|
||||
def updateMatParamsInTree(self, data):
|
||||
|
||||
@@ -220,10 +229,20 @@ class MaterialEditor:
|
||||
it = QtGui.QStandardItem(i)
|
||||
userGroup.appendRow([item, it])
|
||||
self.customprops.append(k)
|
||||
self.edited = False
|
||||
|
||||
def chooseMaterial(self, index):
|
||||
if index < 0:
|
||||
return
|
||||
|
||||
if self.verifyMaterial():
|
||||
"""
|
||||
Save any unchanged data
|
||||
"""
|
||||
self.edited = False
|
||||
else:
|
||||
return
|
||||
|
||||
self.card_path = self.widget.ComboMaterial.itemData(index)
|
||||
FreeCAD.Console.PrintMessage(
|
||||
"choose_material in material editor:\n"
|
||||
@@ -239,6 +258,21 @@ class MaterialEditor:
|
||||
else:
|
||||
FreeCAD.Console.PrintError("Material card not found: {}\n".format(self.card_path))
|
||||
|
||||
def verifyMaterial(self):
|
||||
if self.edited:
|
||||
reply = QtGui.QMessageBox.question(self.widget, #FreeCADGui.getMainWindow(),
|
||||
translate("Material","The document has been modified."),
|
||||
translate("Material","Do you want to save your changes?"),
|
||||
QtGui.QMessageBox.Save | QtGui.QMessageBox.Discard | QtGui.QMessageBox.Cancel,
|
||||
QtGui.QMessageBox.Save)
|
||||
|
||||
if reply == QtGui.QMessageBox.Cancel:
|
||||
return False
|
||||
if reply == QtGui.QMessageBox.Save:
|
||||
self.savefile()
|
||||
|
||||
return True
|
||||
|
||||
def updateCardsInCombo(self):
|
||||
|
||||
"""updates the contents of the materials combo with existing material cards"""
|
||||
@@ -280,6 +314,32 @@ class MaterialEditor:
|
||||
if url:
|
||||
QtGui.QDesktopServices.openUrl(QtCore.QUrl(url, QtCore.QUrl.TolerantMode))
|
||||
|
||||
def modelChange(self, item):
|
||||
"""
|
||||
Called when an item in the tree is modified. This will set edited to True, but this
|
||||
will be reset in the event of mass updates, such as loading a card
|
||||
"""
|
||||
self.edited = True
|
||||
|
||||
def verify(self, button):
|
||||
"""
|
||||
Verify that the user wants to save any changed data before exiting
|
||||
"""
|
||||
|
||||
if self.edited:
|
||||
reply = QtGui.QMessageBox.question(self.widget, #FreeCADGui.getMainWindow(),
|
||||
translate("Material","The document has been modified."),
|
||||
translate("Material","Do you want to save your changes?"),
|
||||
QtGui.QMessageBox.Save | QtGui.QMessageBox.Discard | QtGui.QMessageBox.Cancel,
|
||||
QtGui.QMessageBox.Save)
|
||||
|
||||
if reply == QtGui.QMessageBox.Cancel:
|
||||
return
|
||||
if reply == QtGui.QMessageBox.Save:
|
||||
self.savefile()
|
||||
|
||||
self.accept()
|
||||
|
||||
def accept(self):
|
||||
""
|
||||
|
||||
@@ -340,6 +400,7 @@ class MaterialEditor:
|
||||
it = QtGui.QStandardItem(value)
|
||||
top.appendRow([item, it])
|
||||
self.customprops.append(key)
|
||||
self.edited = True
|
||||
|
||||
def deleteCustomProperty(self, key=None):
|
||||
|
||||
@@ -376,6 +437,8 @@ class MaterialEditor:
|
||||
it.setText("")
|
||||
buttonDeleteProperty.setProperty("text", "Delete value")
|
||||
|
||||
self.edited = True
|
||||
|
||||
buttonDeleteProperty.setEnabled(False)
|
||||
|
||||
def onClickTree(self, index):
|
||||
@@ -505,12 +568,20 @@ class MaterialEditor:
|
||||
return color.name()
|
||||
|
||||
def openfile(self):
|
||||
if self.verifyMaterial():
|
||||
"""
|
||||
Save any unchanged data
|
||||
"""
|
||||
self.edited = False
|
||||
else:
|
||||
return
|
||||
|
||||
"Opens a FCMat file"
|
||||
if self.category == "Solid":
|
||||
directory = self.directory + os.sep + "StandardMaterial"
|
||||
else:
|
||||
directory = self.directory + os.sep + "FluidMaterial"
|
||||
if self.card_path is None:
|
||||
if self.card_path is None or len(self.card_path) == 0:
|
||||
self.card_path = directory
|
||||
filetuple = QtGui.QFileDialog.getOpenFileName(
|
||||
QtGui.QApplication.activeWindow(),
|
||||
@@ -529,8 +600,11 @@ class MaterialEditor:
|
||||
# D:/FreeCAD-build/data/Mod\Material\FluidMaterial\Air.FCMat
|
||||
# To keep it simple, we take a path from the ComboMaterial and change only the
|
||||
# material card filename
|
||||
if self.initialIndex > -1:
|
||||
path = self.widget.ComboMaterial.itemData(self.initialIndex)
|
||||
#
|
||||
# Using the initialIndex variable won't work before a card os selected for the
|
||||
# first time, so use index 1. Index 0 is a blank entry
|
||||
if self.widget.ComboMaterial.count() > 1:
|
||||
path = self.widget.ComboMaterial.itemData(1)
|
||||
# at first check if we have a uniform usage
|
||||
# (if a character is not present, rsplit delivers the initial string)
|
||||
testBackslash = path.rsplit('\\', 1)[0]
|
||||
@@ -590,19 +664,27 @@ class MaterialEditor:
|
||||
filetuple = QtGui.QFileDialog.getSaveFileName(
|
||||
QtGui.QApplication.activeWindow(),
|
||||
"Save FreeCAD Material file",
|
||||
self.directory + "/" + name + ".FCMat",
|
||||
self.save_directory + "/" + name + ".FCMat",
|
||||
"*.FCMat"
|
||||
)
|
||||
# a tuple of two empty strings returns True, so use the filename directly
|
||||
filename = filetuple[0]
|
||||
if filename:
|
||||
self.directory = os.path.dirname(filename)
|
||||
# should not be resource dir but user result dir instead
|
||||
# Update the directories to the current save value
|
||||
self.save_directory = os.path.dirname(filename)
|
||||
self.directory = self.save_directory
|
||||
self.card_path = filename
|
||||
|
||||
d = self.getDict()
|
||||
# self.outputDict(d)
|
||||
if d:
|
||||
# Set the card name to match the filename
|
||||
path = PurePath(filename)
|
||||
d["CardName"] = path.stem
|
||||
|
||||
from importFCMat import write
|
||||
write(filename, d)
|
||||
self.edited = False
|
||||
self.updateCardsInCombo()
|
||||
|
||||
def show(self):
|
||||
@@ -854,8 +936,13 @@ def translate(context, text):
|
||||
def openEditor(obj=None, prop=None):
|
||||
"""openEditor([obj,prop]): opens the editor, optionally with
|
||||
an object name and material property name to edit"""
|
||||
editor = MaterialEditor(obj, prop)
|
||||
editor.exec_()
|
||||
param = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Material/Cards")
|
||||
legacy = param.GetBool("LegacyEditor", True)
|
||||
if legacy:
|
||||
editor = MaterialEditor(obj, prop)
|
||||
editor.exec_()
|
||||
else:
|
||||
FreeCADGui.runCommand('Materials_Edit',0)
|
||||
|
||||
|
||||
def editMaterial(material=None, card_path=None, category="Solid"):
|
||||
|
||||
45
src/Mod/Material/MaterialGlobal.h
Normal file
45
src/Mod/Material/MaterialGlobal.h
Normal file
@@ -0,0 +1,45 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2023 David Carter <dcarter@david.carter.ca> *
|
||||
* *
|
||||
* 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 *
|
||||
* <https://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
**************************************************************************/
|
||||
|
||||
#include <FCGlobal.h>
|
||||
|
||||
#ifndef MATERIAL_GLOBAL_H
|
||||
#define MATERIAL_GLOBAL_H
|
||||
|
||||
// Material
|
||||
#ifndef MaterialsExport
|
||||
#ifdef Material_EXPORTS
|
||||
#define MaterialsExport FREECAD_DECL_EXPORT
|
||||
#else
|
||||
#define MaterialsExport FREECAD_DECL_IMPORT
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// MatGui
|
||||
#ifndef MatGuiExport
|
||||
#ifdef MatGui_EXPORTS
|
||||
#define MatGuiExport FREECAD_DECL_EXPORT
|
||||
#else
|
||||
#define MatGuiExport FREECAD_DECL_IMPORT
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif // MATERIAL_GLOBAL_H
|
||||
@@ -2,5 +2,6 @@
|
||||
<qresource>
|
||||
<file>icons/preview-rendered.svg</file>
|
||||
<file>icons/preview-vector.svg</file>
|
||||
<file>ui/materials-editor.ui</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
# File created by ConvertFCMat.py
|
||||
General:
|
||||
UUID: "d1f317f0-5ffa-4798-8ab3-af2ff0b5182c"
|
||||
AuthorAndLicense: "(c) 2023 David Carter"
|
||||
Name: "Aluminum"
|
||||
Description: "Defines the Aluminum appearance properties"
|
||||
AppearanceModels:
|
||||
BasicRendering:
|
||||
UUID: 'f006c7e4-35b7-43d5-bbf9-c5d572309e6e'
|
||||
AmbientColor: "(0.3000, 0.3000, 0.3000, 1.0)"
|
||||
DiffuseColor: "(0.3000, 0.3000, 0.3000, 1.0)"
|
||||
EmissiveColor: "(0.0000, 0.0000, 0.0000, 1.0)"
|
||||
Shininess: "0.0900"
|
||||
SpecularColor: "(0.3000, 0.3000, 0.3000, 1.0)"
|
||||
Transparency: "0.0"
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user