diff --git a/src/App/GeoFeature.cpp b/src/App/GeoFeature.cpp index 1c96e9e299..2bcf5bf6ad 100644 --- a/src/App/GeoFeature.cpp +++ b/src/App/GeoFeature.cpp @@ -173,3 +173,12 @@ DocumentObject *GeoFeature::resolveElement(DocumentObject *obj, const char *subn return sobj; } +App::Material GeoFeature::getMaterialAppearance() const +{ + return App::Material(App::Material::DEFAULT); +} + +void GeoFeature::setMaterialAppearance(const App::Material& material) +{ + Q_UNUSED(material) +} diff --git a/src/App/GeoFeature.h b/src/App/GeoFeature.h index e43ba869e1..fb3d244b4e 100644 --- a/src/App/GeoFeature.h +++ b/src/App/GeoFeature.h @@ -27,6 +27,7 @@ #include "DocumentObject.h" #include "PropertyGeo.h" #include "MappedElement.h" +#include "Material.h" namespace App { @@ -120,6 +121,25 @@ public: * @return Base::Placement The transformation from the global reference coordinate system */ Base::Placement globalPlacement() const; + /** + * @brief Virtual function to get an App::Material object describing the appearance + * + * The appearance properties are described by the underlying features material. This can not + * be accessed directly from within the Gui module. This virtual function will return a + * App::Material object describing the appearance properties of the material. + * + * @return App::Material the appearance properties of the object material + */ + virtual App::Material getMaterialAppearance() const; + + /** + * @brief Virtual function to set the appearance with an App::Material object + * + * The appearance properties are described by the underlying features material. This cannot + * be accessed directly from within the Gui module. This virtual function will set the + * appearance from an App::Material object. + */ + virtual void setMaterialAppearance(const App::Material& material); protected: std::pair _getElementName(const char* name, diff --git a/src/App/Material.cpp b/src/App/Material.cpp index c3b80e9153..3a34d208d2 100644 --- a/src/App/Material.cpp +++ b/src/App/Material.cpp @@ -24,7 +24,7 @@ #include "PreCompiled.h" #ifndef _PreComp_ -# include +#include #endif #include "Material.h" @@ -36,113 +36,123 @@ using namespace App; // Material //=========================================================================== Material::Material() - : shininess{0.9000f} - , transparency{} + : shininess {0.9000f} + , transparency {} { setType(STEEL); setType(USER_DEFINED); } +Material::Material(const Material& other) + : ambientColor(other.ambientColor) + , diffuseColor(other.diffuseColor) + , specularColor(other.specularColor) + , emissiveColor(other.emissiveColor) + , shininess(other.shininess) + , transparency(other.transparency) + , uuid(other.uuid) + , _matType(other._matType) +{ +} + Material::Material(const char* MatName) - : shininess{0.9000f} - , transparency{} + : shininess {0.9000f} + , transparency {} { set(MatName); } Material::Material(const MaterialType MatType) - : shininess{0.9000f} - , transparency{} + : shininess {0.9000f} + , transparency {} { setType(MatType); } +Material& Material::operator=(const Material& other) +{ + if (this == &other) { + return *this; + } + + _matType = other._matType; + ambientColor = other.ambientColor; + diffuseColor = other.diffuseColor; + specularColor = other.specularColor; + emissiveColor = other.emissiveColor; + shininess = other.shininess; + transparency = other.transparency; + uuid = other.uuid; + + return *this; +} + void Material::set(const char* MatName) { - if (strcmp("Brass",MatName) == 0 ) { + if (strcmp("Brass", MatName) == 0) { setType(BRASS); } - else if (strcmp("Bronze",MatName) == 0 ) { + else if (strcmp("Bronze", MatName) == 0) { setType(BRONZE); } - else if (strcmp("Copper",MatName) == 0 ) { + else if (strcmp("Copper", MatName) == 0) { setType(COPPER); } - else if (strcmp("Gold",MatName) == 0 ) { -// ambientColor.set(0.3f,0.1f,0.1f); -// diffuseColor.set(0.8f,0.7f,0.2f); -// specularColor.set(0.4f,0.3f,0.1f); -// shininess = .4f; -// transparency = .0f; -//// ambientColor.set(0.3f,0.1f,0.1f); -//// diffuseColor.set(0.22f,0.15f,0.00f); -//// specularColor.set(0.71f,0.70f,0.56f); -//// shininess = .16f; -//// transparency = .0f; -//// ambientColor.set(0.24725f, 0.1995f, 0.0745f); -//// diffuseColor.set(0.75164f, 0.60648f, 0.22648f); -//// specularColor.set(0.628281f, 0.555802f, 0.366065f); -//// shininess = .16f; -//// transparency = .0f; + else if (strcmp("Gold", MatName) == 0) { setType(GOLD); } - else if (strcmp("Pewter",MatName) == 0 ) { + else if (strcmp("Pewter", MatName) == 0) { setType(PEWTER); } - else if (strcmp("Plaster",MatName) == 0 ) { + else if (strcmp("Plaster", MatName) == 0) { setType(PLASTER); } - else if (strcmp("Plastic",MatName) == 0 ) { + else if (strcmp("Plastic", MatName) == 0) { setType(PLASTIC); } - else if (strcmp("Silver",MatName) == 0 ) { + else if (strcmp("Silver", MatName) == 0) { setType(SILVER); } - else if (strcmp("Steel",MatName) == 0 ) { + else if (strcmp("Steel", MatName) == 0) { setType(STEEL); } - else if (strcmp("Stone",MatName) == 0 ) { -// ambientColor.set(0.0f,0.0f,0.0f); -// diffuseColor.set(0.0f,0.0f,0.0f); -// specularColor.set(0.4f,0.3f,0.1f); -// shininess = .4f; -// transparency = .0f; + else if (strcmp("Stone", MatName) == 0) { setType(STONE); } - else if (strcmp("Shiny plastic",MatName) == 0 ) { + else if (strcmp("Shiny plastic", MatName) == 0) { setType(SHINY_PLASTIC); } - else if (strcmp("Satin",MatName) == 0 ) { + else if (strcmp("Satin", MatName) == 0) { setType(SATIN); } - else if (strcmp("Metalized",MatName) == 0 ) { + else if (strcmp("Metalized", MatName) == 0) { setType(METALIZED); } - else if (strcmp("Neon GNC",MatName) == 0 ) { + else if (strcmp("Neon GNC", MatName) == 0) { setType(NEON_GNC); } - else if (strcmp("Chrome",MatName) == 0 ) { + else if (strcmp("Chrome", MatName) == 0) { setType(CHROME); } - else if (strcmp("Aluminium",MatName) == 0 ) { + else if (strcmp("Aluminium", MatName) == 0) { setType(ALUMINIUM); } - else if (strcmp("Obsidian",MatName) == 0 ) { + else if (strcmp("Obsidian", MatName) == 0) { setType(OBSIDIAN); } - else if (strcmp("Neon PHC",MatName) == 0 ) { + else if (strcmp("Neon PHC", MatName) == 0) { setType(NEON_PHC); } - else if (strcmp("Jade",MatName) == 0 ) { + else if (strcmp("Jade", MatName) == 0) { setType(JADE); } - else if (strcmp("Ruby",MatName) == 0 ) { + else if (strcmp("Ruby", MatName) == 0) { setType(RUBY); } - else if (strcmp("Emerald",MatName) == 0 ) { + else if (strcmp("Emerald", MatName) == 0) { setType(EMERALD); } - else if (strcmp("Default",MatName) == 0 ) { + else if (strcmp("Default", MatName) == 0) { setType(DEFAULT); } else { @@ -153,185 +163,184 @@ void Material::set(const char* MatName) void Material::setType(const MaterialType MatType) { _matType = MatType; - switch (MatType) - { - case BRASS: - ambientColor .set(0.3294f,0.2235f,0.0275f); - diffuseColor .set(0.7804f,0.5686f,0.1137f); - specularColor.set(0.9922f,0.9412f,0.8078f); - emissiveColor.set(0.0000f,0.0000f,0.0000f); - shininess = 0.2179f; - transparency = 0.0000f; - break; - case BRONZE: - ambientColor .set(0.2125f,0.1275f,0.0540f); - diffuseColor .set(0.7140f,0.4284f,0.1814f); - specularColor.set(0.3935f,0.2719f,0.1667f); - emissiveColor.set(0.0000f,0.0000f,0.0000f); - shininess = 0.2000f; - transparency = 0.0000f; - break; - case COPPER: - ambientColor .set(0.3300f,0.2600f,0.2300f); - diffuseColor .set(0.5000f,0.1100f,0.0000f); - specularColor.set(0.9500f,0.7300f,0.0000f); - emissiveColor.set(0.0000f,0.0000f,0.0000f); - shininess = 0.9300f; - transparency = 0.0000f; - break; - case GOLD: - ambientColor .set(0.3000f,0.2306f,0.0953f); - diffuseColor .set(0.4000f,0.2760f,0.0000f); - specularColor.set(0.9000f,0.8820f,0.7020f); - emissiveColor.set(0.0000f,0.0000f,0.0000f); - shininess = 0.0625f; - transparency = 0.0000f; - break; - case PEWTER: - ambientColor .set(0.1059f,0.0588f,0.1137f); - diffuseColor .set(0.4275f,0.4706f,0.5412f); - specularColor.set(0.3333f,0.3333f,0.5216f); - emissiveColor.set(0.0000f,0.0000f,0.0000f); - shininess = 0.0769f; - transparency = 0.0000f; - break; - case PLASTER: - ambientColor .set(0.0500f,0.0500f,0.0500f); - diffuseColor .set(0.1167f,0.1167f,0.1167f); - specularColor.set(0.0305f,0.0305f,0.0305f); - emissiveColor.set(0.0000f,0.0000f,0.0000f); - shininess = 0.0078f; - transparency = 0.0000f; - break; - case PLASTIC: - ambientColor .set(0.1000f,0.1000f,0.1000f); - diffuseColor .set(0.0000f,0.0000f,0.0000f); - specularColor.set(0.0600f,0.0600f,0.0600f); - emissiveColor.set(0.0000f,0.0000f,0.0000f); - shininess = 0.0078f; - transparency = 0.0000f; - break; - case SILVER: - ambientColor .set(0.1922f,0.1922f,0.1922f); - diffuseColor .set(0.5075f,0.5075f,0.5075f); - specularColor.set(0.5083f,0.5083f,0.5083f); - emissiveColor.set(0.0000f,0.0000f,0.0000f); - shininess = 0.2000f; - transparency = 0.0000f; - break; - case STEEL: - ambientColor .set(0.0020f,0.0020f,0.0020f); - diffuseColor .set(0.0000f,0.0000f,0.0000f); - specularColor.set(0.9800f,0.9800f,0.9800f); - emissiveColor.set(0.0000f,0.0000f,0.0000f); - shininess = 0.0600f; - transparency = 0.0000f; - break; - case STONE: - ambientColor .set(0.1900f,0.1520f,0.1178f); - diffuseColor .set(0.7500f,0.6000f,0.4650f); - specularColor.set(0.0784f,0.0800f,0.0480f); - emissiveColor.set(0.0000f,0.0000f,0.0000f); - shininess = 0.1700f; - transparency = 0.0000f; - break; - case SHINY_PLASTIC: - ambientColor .set(0.0880f,0.0880f,0.0880f); - diffuseColor .set(0.0000f,0.0000f,0.0000f); - specularColor.set(1.0000f,1.0000f,1.0000f); - emissiveColor.set(0.0000f,0.0000f,0.0000f); - shininess = 1.0000f; - transparency = 0.0000f; - break; - case SATIN: - ambientColor .set(0.0660f,0.0660f,0.0660f); - diffuseColor .set(0.0000f,0.0000f,0.0000f); - specularColor.set(0.4400f,0.4400f,0.4400f); - emissiveColor.set(0.0000f,0.0000f,0.0000f); - shininess = 0.0938f; - transparency = 0.0000f; - break; - case METALIZED: - ambientColor .set(0.1800f,0.1800f,0.1800f); - diffuseColor .set(0.0000f,0.0000f,0.0000f); - specularColor.set(0.4500f,0.4500f,0.4500f); - emissiveColor.set(0.0000f,0.0000f,0.0000f); - shininess = 0.1300f; - transparency = 0.0000f; - break; - case NEON_GNC: - ambientColor .set(0.2000f,0.2000f,0.2000f); - diffuseColor .set(0.0000f,0.0000f,0.0000f); - specularColor.set(0.6200f,0.6200f,0.6200f); - emissiveColor.set(1.0000f,1.0000f,0.0000f); - shininess = 0.0500f; - transparency = 0.0000f; - break; - case CHROME: - ambientColor .set(0.3500f,0.3500f,0.3500f); - diffuseColor .set(0.9176f,0.9176f,0.9176f); - specularColor.set(0.9746f,0.9746f,0.9746f); - emissiveColor.set(0.0000f,0.0000f,0.0000f); - shininess = 0.1000f; - transparency = 0.0000f; - break; - case ALUMINIUM: - ambientColor .set(0.3000f,0.3000f,0.3000f); - diffuseColor .set(0.3000f,0.3000f,0.3000f); - specularColor.set(0.7000f,0.7000f,0.8000f); - emissiveColor.set(0.0000f,0.0000f,0.0000f); - shininess = 0.0900f; - transparency = 0.0000f; - break; - case OBSIDIAN: - ambientColor .set(0.0538f,0.0500f,0.0662f); - diffuseColor .set(0.1828f,0.1700f,0.2253f); - specularColor.set(0.3327f,0.3286f,0.3464f); - emissiveColor.set(0.0000f,0.0000f,0.0000f); - shininess = 0.3000f; - transparency = 0.0000f; - break; - case NEON_PHC: - ambientColor .set(1.0000f,1.0000f,1.0000f); - diffuseColor .set(1.0000f,1.0000f,1.0000f); - specularColor.set(0.6200f,0.6200f,0.6200f); - emissiveColor.set(0.0000f,0.9000f,0.4140f); - shininess = 0.0500f; - transparency = 0.0000f; - break; - case JADE: - ambientColor .set(0.1350f,0.2225f,0.1575f); - diffuseColor .set(0.5400f,0.8900f,0.6300f); - specularColor.set(0.3162f,0.3162f,0.3162f); - emissiveColor.set(0.0000f,0.0000f,0.0000f); - shininess = 0.1000f; - transparency = 0.0000f; - break; - case RUBY: - ambientColor .set(0.1745f,0.0118f,0.0118f); - diffuseColor .set(0.6142f,0.0414f,0.0414f); - specularColor.set(0.7278f,0.6279f,0.6267f); - emissiveColor.set(0.0000f,0.0000f,0.0000f); - shininess = 0.6000f; - transparency = 0.0000f; - break; - case EMERALD: - ambientColor .set(0.0215f,0.1745f,0.0215f); - diffuseColor .set(0.0757f,0.6142f,0.0757f); - specularColor.set(0.6330f,0.7278f,0.6330f); - emissiveColor.set(0.0000f,0.0000f,0.0000f); - shininess = 0.6000f; - transparency = 0.0000f; - break; - case USER_DEFINED: - break; - default: - ambientColor.set(0.3333f, 0.3333f, 0.3333f); - diffuseColor .set(0.8000f,0.8000f,0.9000f); - specularColor.set(0.5333f, 0.5333f, 0.5333f); - emissiveColor.set(0.0000f,0.0000f,0.0000f); - shininess = 0.9000f; - transparency = 0.0000f; - break; + switch (MatType) { + case BRASS: + ambientColor.set(0.3294f, 0.2235f, 0.0275f); + diffuseColor.set(0.7804f, 0.5686f, 0.1137f); + specularColor.set(0.9922f, 0.9412f, 0.8078f); + emissiveColor.set(0.0000f, 0.0000f, 0.0000f); + shininess = 0.2179f; + transparency = 0.0000f; + break; + case BRONZE: + ambientColor.set(0.2125f, 0.1275f, 0.0540f); + diffuseColor.set(0.7140f, 0.4284f, 0.1814f); + specularColor.set(0.3935f, 0.2719f, 0.1667f); + emissiveColor.set(0.0000f, 0.0000f, 0.0000f); + shininess = 0.2000f; + transparency = 0.0000f; + break; + case COPPER: + ambientColor.set(0.3300f, 0.2600f, 0.2300f); + diffuseColor.set(0.5000f, 0.1100f, 0.0000f); + specularColor.set(0.9500f, 0.7300f, 0.0000f); + emissiveColor.set(0.0000f, 0.0000f, 0.0000f); + shininess = 0.9300f; + transparency = 0.0000f; + break; + case GOLD: + ambientColor.set(0.3000f, 0.2306f, 0.0953f); + diffuseColor.set(0.4000f, 0.2760f, 0.0000f); + specularColor.set(0.9000f, 0.8820f, 0.7020f); + emissiveColor.set(0.0000f, 0.0000f, 0.0000f); + shininess = 0.0625f; + transparency = 0.0000f; + break; + case PEWTER: + ambientColor.set(0.1059f, 0.0588f, 0.1137f); + diffuseColor.set(0.4275f, 0.4706f, 0.5412f); + specularColor.set(0.3333f, 0.3333f, 0.5216f); + emissiveColor.set(0.0000f, 0.0000f, 0.0000f); + shininess = 0.0769f; + transparency = 0.0000f; + break; + case PLASTER: + ambientColor.set(0.0500f, 0.0500f, 0.0500f); + diffuseColor.set(0.1167f, 0.1167f, 0.1167f); + specularColor.set(0.0305f, 0.0305f, 0.0305f); + emissiveColor.set(0.0000f, 0.0000f, 0.0000f); + shininess = 0.0078f; + transparency = 0.0000f; + break; + case PLASTIC: + ambientColor.set(0.1000f, 0.1000f, 0.1000f); + diffuseColor.set(0.0000f, 0.0000f, 0.0000f); + specularColor.set(0.0600f, 0.0600f, 0.0600f); + emissiveColor.set(0.0000f, 0.0000f, 0.0000f); + shininess = 0.0078f; + transparency = 0.0000f; + break; + case SILVER: + ambientColor.set(0.1922f, 0.1922f, 0.1922f); + diffuseColor.set(0.5075f, 0.5075f, 0.5075f); + specularColor.set(0.5083f, 0.5083f, 0.5083f); + emissiveColor.set(0.0000f, 0.0000f, 0.0000f); + shininess = 0.2000f; + transparency = 0.0000f; + break; + case STEEL: + ambientColor.set(0.0020f, 0.0020f, 0.0020f); + diffuseColor.set(0.0000f, 0.0000f, 0.0000f); + specularColor.set(0.9800f, 0.9800f, 0.9800f); + emissiveColor.set(0.0000f, 0.0000f, 0.0000f); + shininess = 0.0600f; + transparency = 0.0000f; + break; + case STONE: + ambientColor.set(0.1900f, 0.1520f, 0.1178f); + diffuseColor.set(0.7500f, 0.6000f, 0.4650f); + specularColor.set(0.0784f, 0.0800f, 0.0480f); + emissiveColor.set(0.0000f, 0.0000f, 0.0000f); + shininess = 0.1700f; + transparency = 0.0000f; + break; + case SHINY_PLASTIC: + ambientColor.set(0.0880f, 0.0880f, 0.0880f); + diffuseColor.set(0.0000f, 0.0000f, 0.0000f); + specularColor.set(1.0000f, 1.0000f, 1.0000f); + emissiveColor.set(0.0000f, 0.0000f, 0.0000f); + shininess = 1.0000f; + transparency = 0.0000f; + break; + case SATIN: + ambientColor.set(0.0660f, 0.0660f, 0.0660f); + diffuseColor.set(0.0000f, 0.0000f, 0.0000f); + specularColor.set(0.4400f, 0.4400f, 0.4400f); + emissiveColor.set(0.0000f, 0.0000f, 0.0000f); + shininess = 0.0938f; + transparency = 0.0000f; + break; + case METALIZED: + ambientColor.set(0.1800f, 0.1800f, 0.1800f); + diffuseColor.set(0.0000f, 0.0000f, 0.0000f); + specularColor.set(0.4500f, 0.4500f, 0.4500f); + emissiveColor.set(0.0000f, 0.0000f, 0.0000f); + shininess = 0.1300f; + transparency = 0.0000f; + break; + case NEON_GNC: + ambientColor.set(0.2000f, 0.2000f, 0.2000f); + diffuseColor.set(0.0000f, 0.0000f, 0.0000f); + specularColor.set(0.6200f, 0.6200f, 0.6200f); + emissiveColor.set(1.0000f, 1.0000f, 0.0000f); + shininess = 0.0500f; + transparency = 0.0000f; + break; + case CHROME: + ambientColor.set(0.3500f, 0.3500f, 0.3500f); + diffuseColor.set(0.9176f, 0.9176f, 0.9176f); + specularColor.set(0.9746f, 0.9746f, 0.9746f); + emissiveColor.set(0.0000f, 0.0000f, 0.0000f); + shininess = 0.1000f; + transparency = 0.0000f; + break; + case ALUMINIUM: + ambientColor.set(0.3000f, 0.3000f, 0.3000f); + diffuseColor.set(0.3000f, 0.3000f, 0.3000f); + specularColor.set(0.7000f, 0.7000f, 0.8000f); + emissiveColor.set(0.0000f, 0.0000f, 0.0000f); + shininess = 0.0900f; + transparency = 0.0000f; + break; + case OBSIDIAN: + ambientColor.set(0.0538f, 0.0500f, 0.0662f); + diffuseColor.set(0.1828f, 0.1700f, 0.2253f); + specularColor.set(0.3327f, 0.3286f, 0.3464f); + emissiveColor.set(0.0000f, 0.0000f, 0.0000f); + shininess = 0.3000f; + transparency = 0.0000f; + break; + case NEON_PHC: + ambientColor.set(1.0000f, 1.0000f, 1.0000f); + diffuseColor.set(1.0000f, 1.0000f, 1.0000f); + specularColor.set(0.6200f, 0.6200f, 0.6200f); + emissiveColor.set(0.0000f, 0.9000f, 0.4140f); + shininess = 0.0500f; + transparency = 0.0000f; + break; + case JADE: + ambientColor.set(0.1350f, 0.2225f, 0.1575f); + diffuseColor.set(0.5400f, 0.8900f, 0.6300f); + specularColor.set(0.3162f, 0.3162f, 0.3162f); + emissiveColor.set(0.0000f, 0.0000f, 0.0000f); + shininess = 0.1000f; + transparency = 0.0000f; + break; + case RUBY: + ambientColor.set(0.1745f, 0.0118f, 0.0118f); + diffuseColor.set(0.6142f, 0.0414f, 0.0414f); + specularColor.set(0.7278f, 0.6279f, 0.6267f); + emissiveColor.set(0.0000f, 0.0000f, 0.0000f); + shininess = 0.6000f; + transparency = 0.0000f; + break; + case EMERALD: + ambientColor.set(0.0215f, 0.1745f, 0.0215f); + diffuseColor.set(0.0757f, 0.6142f, 0.0757f); + specularColor.set(0.6330f, 0.7278f, 0.6330f); + emissiveColor.set(0.0000f, 0.0000f, 0.0000f); + shininess = 0.6000f; + transparency = 0.0000f; + break; + case USER_DEFINED: + break; + default: + ambientColor.set(0.3333f, 0.3333f, 0.3333f); + diffuseColor.set(0.8000f, 0.8000f, 0.9000f); + specularColor.set(0.5333f, 0.5333f, 0.5333f); + emissiveColor.set(0.0000f, 0.0000f, 0.0000f); + shininess = 0.9000f; + transparency = 0.0000f; + break; } } diff --git a/src/App/Material.h b/src/App/Material.h index fb4297257c..02e32f5490 100644 --- a/src/App/Material.h +++ b/src/App/Material.h @@ -34,7 +34,8 @@ namespace App class AppExport Material { public: - enum MaterialType { + enum MaterialType + { BRASS, BRONZE, COPPER, @@ -66,11 +67,14 @@ public: //@{ /** Sets the USER_DEFINED material type. The user must set the colors afterwards. */ Material(); - /** Defines the colors and shininess for the material \a MatName. If \a MatName isn't defined then USER_DEFINED is - * set and the user must define the colors itself. + /** Copy constructor. */ + Material(const Material& other); + /** Defines the colors and shininess for the material \a MatName. If \a MatName isn't defined + * then USER_DEFINED is set and the user must define the colors itself. */ explicit Material(const char* MatName); - /** Does basically the same as the constructor above unless that it accepts a MaterialType as argument. */ + /** Does basically the same as the constructor above unless that it accepts a MaterialType as + * argument. */ explicit Material(const MaterialType MatType); //@} @@ -97,22 +101,24 @@ public: * \li Jade * \li Ruby * \li Emerald - * Furthermore there two additional modes \a Default which defines a kind of grey metallic and user defined that - * does nothing. - * The Color and the other properties of the material are defined in the range [0-1]. - * If \a MatName is an unknown material name then the type USER_DEFINED is set and the material doesn't get changed. + * Furthermore there two additional modes \a Default which defines a kind of grey metallic and + * user defined that does nothing. The Color and the other properties of the material are + * defined in the range [0-1]. If \a MatName is an unknown material name then the type + * USER_DEFINED is set and the material doesn't get changed. */ void set(const char* MatName); /** - * This method is provided for convenience which does basically the same as the method above unless that it accepts a MaterialType - * as argument. + * This method is provided for convenience which does basically the same as the method above + * unless that it accepts a MaterialType as argument. */ void setType(const MaterialType MatType); /** * Returns the currently set material type. */ MaterialType getType() const - { return _matType; } + { + return _matType; + } /** @name Properties */ //@{ @@ -122,24 +128,26 @@ public: Color emissiveColor; /**< Defines the emissive color. */ float shininess; float transparency; + std::string uuid; //@} bool operator==(const Material& m) const { - return _matType==m._matType && shininess==m.shininess && - transparency==m.transparency && ambientColor==m.ambientColor && - diffuseColor==m.diffuseColor && specularColor==m.specularColor && - emissiveColor==m.emissiveColor; + return _matType == m._matType && shininess == m.shininess && transparency == m.transparency + && ambientColor == m.ambientColor && diffuseColor == m.diffuseColor + && specularColor == m.specularColor && emissiveColor == m.emissiveColor + && uuid == m.uuid; } bool operator!=(const Material& m) const { return !operator==(m); } + Material& operator=(const Material& other); private: MaterialType _matType; }; -} //namespace App +} // namespace App -#endif // APP_MATERIAL_H +#endif // APP_MATERIAL_H diff --git a/src/App/MaterialPy.xml b/src/App/MaterialPy.xml index 494c68eee7..eff0db8c59 100644 --- a/src/App/MaterialPy.xml +++ b/src/App/MaterialPy.xml @@ -30,25 +30,25 @@ Satin, Metalized, Neon GNC, Chrome, Aluminium, Obsidian, Neon PHC, Jade, Ruby or Ambient color - + Diffuse color - + Emissive color - + Specular color - + diff --git a/src/App/MaterialPyImp.cpp b/src/App/MaterialPyImp.cpp index 097e6c832a..dc0c5bbebf 100644 --- a/src/App/MaterialPyImp.cpp +++ b/src/App/MaterialPyImp.cpp @@ -25,12 +25,89 @@ // inclusion of the generated files (generated out of MaterialPy.xml) #include "MaterialPy.h" + #include "MaterialPy.cpp" + #include using namespace App; -PyObject *MaterialPy::PyMake(struct _typeobject *, PyObject *, PyObject *) // Python wrapper +Color parseColor(PyObject* value) +{ + Color cCol; + if (PyTuple_Check(value) && (PyTuple_Size(value) == 3 || PyTuple_Size(value) == 4)) { + PyObject* item; + item = PyTuple_GetItem(value, 0); + if (PyFloat_Check(item)) { + cCol.r = (float)PyFloat_AsDouble(item); + item = PyTuple_GetItem(value, 1); + if (PyFloat_Check(item)) { + cCol.g = (float)PyFloat_AsDouble(item); + } + else { + throw Base::TypeError("Type in tuple must be consistent (float)"); + } + item = PyTuple_GetItem(value, 2); + if (PyFloat_Check(item)) { + cCol.b = (float)PyFloat_AsDouble(item); + } + else { + throw Base::TypeError("Type in tuple must be consistent (float)"); + } + if (PyTuple_Size(value) == 4) { + item = PyTuple_GetItem(value, 3); + if (PyFloat_Check(item)) { + cCol.a = (float)PyFloat_AsDouble(item); + } + else { + throw Base::TypeError("Type in tuple must be consistent (float)"); + } + } + } + else if (PyLong_Check(item)) { + cCol.r = PyLong_AsLong(item) / 255.0; + item = PyTuple_GetItem(value, 1); + if (PyLong_Check(item)) { + cCol.g = PyLong_AsLong(item) / 255.0; + } + else { + throw Base::TypeError("Type in tuple must be consistent (integer)"); + } + item = PyTuple_GetItem(value, 2); + if (PyLong_Check(item)) { + cCol.b = PyLong_AsLong(item) / 255.0; + } + else { + throw Base::TypeError("Type in tuple must be consistent (integer)"); + } + if (PyTuple_Size(value) == 4) { + item = PyTuple_GetItem(value, 3); + if (PyLong_Check(item)) { + cCol.a = PyLong_AsLong(item) / 255.0; + } + else { + throw Base::TypeError("Type in tuple must be consistent (integer)"); + } + } + } + else { + throw Base::TypeError("Type in tuple must be float or integer"); + } + } + else if (PyLong_Check(value)) { + cCol.setPackedValue(PyLong_AsUnsignedLong(value)); + } + else { + std::string error = + std::string("type must be integer or tuple of float or tuple integer, not "); + error += value->ob_type->tp_name; + throw Base::TypeError(error); + } + + return cCol; +} + +PyObject* MaterialPy::PyMake(struct _typeobject*, PyObject*, PyObject*) // Python wrapper { // create a new instance of MaterialPy and the Twin object return new MaterialPy(new Material); @@ -45,28 +122,41 @@ int MaterialPy::PyInit(PyObject* args, PyObject* kwds) PyObject* emissive = nullptr; PyObject* shininess = nullptr; PyObject* transparency = nullptr; - static const std::array kwds_colors{"DiffuseColor", "AmbientColor", "SpecularColor", - "EmissiveColor", "Shininess", "Transparency", nullptr}; + static const std::array kwds_colors {"DiffuseColor", + "AmbientColor", + "SpecularColor", + "EmissiveColor", + "Shininess", + "Transparency", + nullptr}; - if (!Base::Wrapped_ParseTupleAndKeywords(args, kwds, "|OOOOOO", kwds_colors, - &diffuse, &ambient, &specular, &emissive, &shininess, &transparency)) { + if (!Base::Wrapped_ParseTupleAndKeywords(args, + kwds, + "|OOOOOO", + kwds_colors, + &diffuse, + &ambient, + &specular, + &emissive, + &shininess, + &transparency)) { return -1; } if (diffuse) { - setDiffuseColor(Py::Tuple(diffuse)); + setDiffuseColor(Py::Object(diffuse)); } if (ambient) { - setAmbientColor(Py::Tuple(ambient)); + setAmbientColor(Py::Object(ambient)); } if (specular) { - setSpecularColor(Py::Tuple(specular)); + setSpecularColor(Py::Object(specular)); } if (emissive) { - setEmissiveColor(Py::Tuple(emissive)); + setEmissiveColor(Py::Object(emissive)); } if (shininess) { @@ -86,18 +176,19 @@ std::string MaterialPy::representation() const return {""}; } -PyObject* MaterialPy::set(PyObject * args) +PyObject* MaterialPy::set(PyObject* args) { - char *pstr; - if (!PyArg_ParseTuple(args, "s", &pstr)) + char* pstr; + if (!PyArg_ParseTuple(args, "s", &pstr)) { return nullptr; + } getMaterialPtr()->set(pstr); Py_Return; } -Py::Tuple MaterialPy::getAmbientColor() const +Py::Object MaterialPy::getAmbientColor() const { Py::Tuple tuple(4); tuple.setItem(0, Py::Float(getMaterialPtr()->ambientColor.r)); @@ -107,18 +198,12 @@ Py::Tuple MaterialPy::getAmbientColor() const return tuple; } -void MaterialPy::setAmbientColor(Py::Tuple arg) +void MaterialPy::setAmbientColor(Py::Object arg) { - Color c; - c.r = Py::Float(arg.getItem(0)); - c.g = Py::Float(arg.getItem(1)); - c.b = Py::Float(arg.getItem(2)); - if (arg.size() == 4) - c.a = Py::Float(arg.getItem(3)); - getMaterialPtr()->ambientColor = c; + getMaterialPtr()->ambientColor = parseColor(*arg); } -Py::Tuple MaterialPy::getDiffuseColor() const +Py::Object MaterialPy::getDiffuseColor() const { Py::Tuple tuple(4); tuple.setItem(0, Py::Float(getMaterialPtr()->diffuseColor.r)); @@ -128,18 +213,12 @@ Py::Tuple MaterialPy::getDiffuseColor() const return tuple; } -void MaterialPy::setDiffuseColor(Py::Tuple arg) +void MaterialPy::setDiffuseColor(Py::Object arg) { - Color c; - c.r = Py::Float(arg.getItem(0)); - c.g = Py::Float(arg.getItem(1)); - c.b = Py::Float(arg.getItem(2)); - if (arg.size() == 4) - c.a = Py::Float(arg.getItem(3)); - getMaterialPtr()->diffuseColor = c; + getMaterialPtr()->diffuseColor = parseColor(*arg); } -Py::Tuple MaterialPy::getEmissiveColor() const +Py::Object MaterialPy::getEmissiveColor() const { Py::Tuple tuple(4); tuple.setItem(0, Py::Float(getMaterialPtr()->emissiveColor.r)); @@ -149,18 +228,12 @@ Py::Tuple MaterialPy::getEmissiveColor() const return tuple; } -void MaterialPy::setEmissiveColor(Py::Tuple arg) +void MaterialPy::setEmissiveColor(Py::Object arg) { - Color c; - c.r = Py::Float(arg.getItem(0)); - c.g = Py::Float(arg.getItem(1)); - c.b = Py::Float(arg.getItem(2)); - if (arg.size() == 4) - c.a = Py::Float(arg.getItem(3)); - getMaterialPtr()->emissiveColor = c; + getMaterialPtr()->emissiveColor = parseColor(*arg); } -Py::Tuple MaterialPy::getSpecularColor() const +Py::Object MaterialPy::getSpecularColor() const { Py::Tuple tuple(4); tuple.setItem(0, Py::Float(getMaterialPtr()->specularColor.r)); @@ -170,15 +243,9 @@ Py::Tuple MaterialPy::getSpecularColor() const return tuple; } -void MaterialPy::setSpecularColor(Py::Tuple arg) +void MaterialPy::setSpecularColor(Py::Object arg) { - Color c; - c.r = Py::Float(arg.getItem(0)); - c.g = Py::Float(arg.getItem(1)); - c.b = Py::Float(arg.getItem(2)); - if (arg.size() == 4) - c.a = Py::Float(arg.getItem(3)); - getMaterialPtr()->specularColor = c; + getMaterialPtr()->specularColor = parseColor(*arg); } Py::Float MaterialPy::getShininess() const @@ -201,7 +268,7 @@ void MaterialPy::setTransparency(Py::Float arg) getMaterialPtr()->transparency = arg; } -PyObject *MaterialPy::getCustomAttributes(const char* /*attr*/) const +PyObject* MaterialPy::getCustomAttributes(const char* /*attr*/) const { return nullptr; } diff --git a/src/App/PropertyStandard.cpp b/src/App/PropertyStandard.cpp index 5e8abf793b..ef5b1915d6 100644 --- a/src/App/PropertyStandard.cpp +++ b/src/App/PropertyStandard.cpp @@ -461,7 +461,7 @@ void PropertyEnumeration::setPyObject(PyObject *value) hasSetValue(); } else { - FC_THROWM(Base::ValueError, "'" << str + FC_THROWM(Base::ValueError, "'" << str << "' is not part of the enumeration in " << getFullName()); } @@ -585,7 +585,7 @@ bool PropertyEnumeration::getPyPathValue(const ObjectIdentifier &path, Py::Objec } else if (p == ".String") { auto v = getValueAsString(); r = Py::String(v?v:""); - } else + } else r = Py::Int(getValue()); return true; } @@ -2392,19 +2392,34 @@ unsigned int PropertyColorList::getMemSize () const // PropertyMaterial //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -TYPESYSTEM_SOURCE(App::PropertyMaterial , App::Property) +TYPESYSTEM_SOURCE(App::PropertyMaterial, App::Property) PropertyMaterial::PropertyMaterial() = default; PropertyMaterial::~PropertyMaterial() = default; -void PropertyMaterial::setValue(const Material &mat) +void PropertyMaterial::setValue(const Material& mat) { aboutToSetValue(); - _cMat=mat; + _cMat = mat; hasSetValue(); } +void PropertyMaterial::setValue(const Color& col) +{ + setDiffuseColor(col); +} + +void PropertyMaterial::setValue(float r, float g, float b, float a) +{ + setDiffuseColor(r, g, b, a); +} + +void PropertyMaterial::setValue(uint32_t rgba) +{ + setDiffuseColor(rgba); +} + const Material& PropertyMaterial::getValue() const { return _cMat; @@ -2417,6 +2432,20 @@ void PropertyMaterial::setAmbientColor(const Color& col) hasSetValue(); } +void PropertyMaterial::setAmbientColor(float r, float g, float b, float a) +{ + aboutToSetValue(); + _cMat.ambientColor.set(r, g, b, a); + hasSetValue(); +} + +void PropertyMaterial::setAmbientColor(uint32_t rgba) +{ + aboutToSetValue(); + _cMat.ambientColor.setPackedValue(rgba); + hasSetValue(); +} + void PropertyMaterial::setDiffuseColor(const Color& col) { aboutToSetValue(); @@ -2424,6 +2453,20 @@ void PropertyMaterial::setDiffuseColor(const Color& col) hasSetValue(); } +void PropertyMaterial::setDiffuseColor(float r, float g, float b, float a) +{ + aboutToSetValue(); + _cMat.diffuseColor.set(r, g, b, a); + hasSetValue(); +} + +void PropertyMaterial::setDiffuseColor(uint32_t rgba) +{ + aboutToSetValue(); + _cMat.diffuseColor.setPackedValue(rgba); + hasSetValue(); +} + void PropertyMaterial::setSpecularColor(const Color& col) { aboutToSetValue(); @@ -2431,6 +2474,20 @@ void PropertyMaterial::setSpecularColor(const Color& col) hasSetValue(); } +void PropertyMaterial::setSpecularColor(float r, float g, float b, float a) +{ + aboutToSetValue(); + _cMat.specularColor.set(r, g, b, a); + hasSetValue(); +} + +void PropertyMaterial::setSpecularColor(uint32_t rgba) +{ + aboutToSetValue(); + _cMat.specularColor.setPackedValue(rgba); + hasSetValue(); +} + void PropertyMaterial::setEmissiveColor(const Color& col) { aboutToSetValue(); @@ -2438,6 +2495,20 @@ void PropertyMaterial::setEmissiveColor(const Color& col) hasSetValue(); } +void PropertyMaterial::setEmissiveColor(float r, float g, float b, float a) +{ + aboutToSetValue(); + _cMat.emissiveColor.set(r, g, b, a); + hasSetValue(); +} + +void PropertyMaterial::setEmissiveColor(uint32_t rgba) +{ + aboutToSetValue(); + _cMat.emissiveColor.setPackedValue(rgba); + hasSetValue(); +} + void PropertyMaterial::setShininess(float val) { aboutToSetValue(); @@ -2452,36 +2523,135 @@ void PropertyMaterial::setTransparency(float val) hasSetValue(); } -PyObject *PropertyMaterial::getPyObject() +const Color& PropertyMaterial::getAmbientColor() const +{ + return _cMat.ambientColor; +} + +const Color& PropertyMaterial::getDiffuseColor() const +{ + return _cMat.diffuseColor; +} + +const Color& PropertyMaterial::getSpecularColor() const +{ + return _cMat.specularColor; +} + +const Color& PropertyMaterial::getEmissiveColor() const +{ + return _cMat.emissiveColor; +} + +double PropertyMaterial::getShininess() const +{ + return _cMat.shininess; +} + +double PropertyMaterial::getTransparency() const +{ + return _cMat.transparency; +} + +PyObject* PropertyMaterial::getPyObject() { return new MaterialPy(new Material(_cMat)); } -void PropertyMaterial::setPyObject(PyObject *value) +void PropertyMaterial::setPyObject(PyObject* value) { + App::Color cCol; if (PyObject_TypeCheck(value, &(MaterialPy::Type))) { setValue(*static_cast(value)->getMaterialPtr()); } + else if (PyTuple_Check(value) && (PyTuple_Size(value) == 3 || PyTuple_Size(value) == 4)) { + PyObject* item; + item = PyTuple_GetItem(value, 0); + if (PyFloat_Check(item)) { + cCol.r = (float)PyFloat_AsDouble(item); + item = PyTuple_GetItem(value, 1); + if (PyFloat_Check(item)) { + cCol.g = (float)PyFloat_AsDouble(item); + } + else { + throw Base::TypeError("Type in tuple must be consistent (float)"); + } + item = PyTuple_GetItem(value, 2); + if (PyFloat_Check(item)) { + cCol.b = (float)PyFloat_AsDouble(item); + } + else { + throw Base::TypeError("Type in tuple must be consistent (float)"); + } + if (PyTuple_Size(value) == 4) { + item = PyTuple_GetItem(value, 3); + if (PyFloat_Check(item)) { + cCol.a = (float)PyFloat_AsDouble(item); + } + else { + throw Base::TypeError("Type in tuple must be consistent (float)"); + } + } + + setValue(cCol); + } + else if (PyLong_Check(item)) { + cCol.r = PyLong_AsLong(item) / 255.0; + item = PyTuple_GetItem(value, 1); + if (PyLong_Check(item)) { + cCol.g = PyLong_AsLong(item) / 255.0; + } + else { + throw Base::TypeError("Type in tuple must be consistent (integer)"); + } + item = PyTuple_GetItem(value, 2); + if (PyLong_Check(item)) { + cCol.b = PyLong_AsLong(item) / 255.0; + } + else { + throw Base::TypeError("Type in tuple must be consistent (integer)"); + } + if (PyTuple_Size(value) == 4) { + item = PyTuple_GetItem(value, 3); + if (PyLong_Check(item)) { + cCol.a = PyLong_AsLong(item) / 255.0; + } + else { + throw Base::TypeError("Type in tuple must be consistent (integer)"); + } + } + + setValue(cCol); + } + else { + throw Base::TypeError("Type in tuple must be float or integer"); + } + } + else if (PyLong_Check(value)) { + cCol.setPackedValue(PyLong_AsUnsignedLong(value)); + + setValue(cCol); + } else { - std::string error = std::string("type must be 'Material', not "); + std::string error = std::string( + "type must be 'Material', integer, tuple of float, or tuple of integer, not "); error += value->ob_type->tp_name; throw Base::TypeError(error); } } -void PropertyMaterial::Save (Base::Writer &writer) const +void PropertyMaterial::Save(Base::Writer& writer) const { writer.Stream() << writer.ind() << "" << endl; + << _cMat.ambientColor.getPackedValue() << "\" diffuseColor=\"" + << _cMat.diffuseColor.getPackedValue() << "\" specularColor=\"" + << _cMat.specularColor.getPackedValue() << "\" emissiveColor=\"" + << _cMat.emissiveColor.getPackedValue() << "\" shininess=\"" << _cMat.shininess + << "\" transparency=\"" << _cMat.transparency << "\"/>" + << "\" uuid=\"" << _cMat.uuid << "\"/>" << endl; } -void PropertyMaterial::Restore(Base::XMLReader &reader) +void PropertyMaterial::Restore(Base::XMLReader& reader) { // read my Element reader.readElement("PropertyMaterial"); @@ -2493,24 +2663,28 @@ void PropertyMaterial::Restore(Base::XMLReader &reader) _cMat.emissiveColor.setPackedValue(reader.getAttributeAsUnsigned("emissiveColor")); _cMat.shininess = (float)reader.getAttributeAsFloat("shininess"); _cMat.transparency = (float)reader.getAttributeAsFloat("transparency"); + if (reader.hasAttribute("uuid")) { + _cMat.uuid = reader.getAttribute("uuid"); + } hasSetValue(); } const char* PropertyMaterial::getEditorName() const { - if(testStatus(MaterialEdit)) + if (testStatus(MaterialEdit)) { return "Gui::PropertyEditor::PropertyMaterialItem"; + } return ""; } -Property *PropertyMaterial::Copy() const +Property* PropertyMaterial::Copy() const { - PropertyMaterial *p= new PropertyMaterial(); + PropertyMaterial* p = new PropertyMaterial(); p->_cMat = _cMat; return p; } -void PropertyMaterial::Paste(const Property &from) +void PropertyMaterial::Paste(const Property& from) { aboutToSetValue(); _cMat = dynamic_cast(from)._cMat; @@ -2533,20 +2707,474 @@ PropertyMaterialList::~PropertyMaterialList() = default; //************************************************************************** // Base class implementer -PyObject *PropertyMaterialList::getPyObject() +PyObject* PropertyMaterialList::getPyObject() { Py::Tuple tuple(getSize()); - for (int i = 0; i size) { + throw Base::RuntimeError("index out of bound"); + } +} + +void PropertyMaterialList::setSizeOne() +{ + int size = getSize(); + if (size < 1) { + setSize(1); + } +} + +void PropertyMaterialList::setValue() +{ + Material empty; + setValue(empty); +} + +void PropertyMaterialList::setValue(const Material& mat) +{ + aboutToSetValue(); + setSizeOne(); + for (auto& material : _lValueList) { + material = mat; + } + hasSetValue(); +} + +void PropertyMaterialList::setValue(int index, const Material& mat) +{ + verifyIndex(index); + + aboutToSetValue(); + int size = getSize(); + if (index == -1 || index == size) { + index = size; + setSize(index + 1); + } + _lValueList[index] = mat; + hasSetValue(); +} + +void PropertyMaterialList::setAmbientColor(const Color& col) +{ + aboutToSetValue(); + setSizeOne(); + for (auto& material : _lValueList) { + material.ambientColor = col; + } + hasSetValue(); +} + +void PropertyMaterialList::setAmbientColor(float r, float g, float b, float a) +{ + aboutToSetValue(); + setSizeOne(); + for (auto& material : _lValueList) { + material.ambientColor.set(r, g, b, a); + } + hasSetValue(); +} + +void PropertyMaterialList::setAmbientColor(uint32_t rgba) +{ + aboutToSetValue(); + setSizeOne(); + for (auto& material : _lValueList) { + material.ambientColor.setPackedValue(rgba); + } + hasSetValue(); +} + +void PropertyMaterialList::setAmbientColor(int index, const Color& col) +{ + verifyIndex(index); + + aboutToSetValue(); + int size = getSize(); + if (index == -1 || index == size) { + index = size; + setSize(index + 1); + } + _lValueList[index].ambientColor = col; + hasSetValue(); +} + +void PropertyMaterialList::setAmbientColor(int index, float r, float g, float b, float a) +{ + verifyIndex(index); + + aboutToSetValue(); + int size = getSize(); + if (index == -1 || index == size) { + index = size; + setSize(index + 1); + } + _lValueList[index].ambientColor.set(r, g, b, a); + hasSetValue(); +} + +void PropertyMaterialList::setAmbientColor(int index, uint32_t rgba) +{ + verifyIndex(index); + + aboutToSetValue(); + int size = getSize(); + if (index == -1 || index == size) { + index = size; + setSize(index + 1); + } + _lValueList[index].ambientColor.setPackedValue(rgba); + hasSetValue(); +} + +void PropertyMaterialList::setDiffuseColor(const Color& col) +{ + aboutToSetValue(); + setSizeOne(); + for (auto& material : _lValueList) { + material.diffuseColor = col; + } + hasSetValue(); +} + +void PropertyMaterialList::setDiffuseColor(float r, float g, float b, float a) +{ + aboutToSetValue(); + setSizeOne(); + for (auto& material : _lValueList) { + material.diffuseColor.set(r, g, b, a); + } + hasSetValue(); +} + +void PropertyMaterialList::setDiffuseColor(uint32_t rgba) +{ + aboutToSetValue(); + setSizeOne(); + for (auto& material : _lValueList) { + material.diffuseColor.setPackedValue(rgba); + } + hasSetValue(); +} + +void PropertyMaterialList::setDiffuseColor(int index, const Color& col) +{ + verifyIndex(index); + + aboutToSetValue(); + int size = getSize(); + if (index == -1 || index == size) { + index = size; + setSize(index + 1); + } + _lValueList[index].diffuseColor = col; + hasSetValue(); +} + +void PropertyMaterialList::setDiffuseColor(int index, float r, float g, float b, float a) +{ + verifyIndex(index); + + aboutToSetValue(); + int size = getSize(); + if (index == -1 || index == size) { + index = size; + setSize(index + 1); + } + _lValueList[index].diffuseColor.set(r, g, b, a); + hasSetValue(); +} + +void PropertyMaterialList::setDiffuseColor(int index, uint32_t rgba) +{ + verifyIndex(index); + + aboutToSetValue(); + int size = getSize(); + if (index == -1 || index == size) { + index = size; + setSize(index + 1); + } + _lValueList[index].diffuseColor.setPackedValue(rgba); + hasSetValue(); +} + +void PropertyMaterialList::setSpecularColor(const Color& col) +{ + aboutToSetValue(); + setSizeOne(); + for (auto& material : _lValueList) { + material.specularColor = col; + } + hasSetValue(); +} + +void PropertyMaterialList::setSpecularColor(float r, float g, float b, float a) +{ + aboutToSetValue(); + setSizeOne(); + for (auto& material : _lValueList) { + material.specularColor.set(r, g, b, a); + } + hasSetValue(); +} + +void PropertyMaterialList::setSpecularColor(uint32_t rgba) +{ + aboutToSetValue(); + setSizeOne(); + for (auto& material : _lValueList) { + material.specularColor.setPackedValue(rgba); + } + hasSetValue(); +} + +void PropertyMaterialList::setSpecularColor(int index, const Color& col) +{ + verifyIndex(index); + + aboutToSetValue(); + int size = getSize(); + if (index == -1 || index == size) { + index = size; + setSize(index + 1); + } + _lValueList[index].specularColor = col; + hasSetValue(); +} + +void PropertyMaterialList::setSpecularColor(int index, float r, float g, float b, float a) +{ + verifyIndex(index); + + aboutToSetValue(); + int size = getSize(); + if (index == -1 || index == size) { + index = size; + setSize(index + 1); + } + _lValueList[index].specularColor.set(r, g, b, a); + hasSetValue(); +} + +void PropertyMaterialList::setSpecularColor(int index, uint32_t rgba) +{ + verifyIndex(index); + + aboutToSetValue(); + int size = getSize(); + if (index == -1 || index == size) { + index = size; + setSize(index + 1); + } + _lValueList[index].specularColor.setPackedValue(rgba); + hasSetValue(); +} + +void PropertyMaterialList::setEmissiveColor(const Color& col) +{ + aboutToSetValue(); + setSizeOne(); + for (auto& material : _lValueList) { + material.emissiveColor = col; + } + hasSetValue(); +} + +void PropertyMaterialList::setEmissiveColor(float r, float g, float b, float a) +{ + aboutToSetValue(); + setSizeOne(); + for (auto& material : _lValueList) { + material.emissiveColor.set(r, g, b, a); + } + hasSetValue(); +} + +void PropertyMaterialList::setEmissiveColor(uint32_t rgba) +{ + aboutToSetValue(); + setSizeOne(); + for (auto& material : _lValueList) { + material.emissiveColor.setPackedValue(rgba); + } + hasSetValue(); +} + +void PropertyMaterialList::setEmissiveColor(int index, const Color& col) +{ + verifyIndex(index); + + aboutToSetValue(); + int size = getSize(); + if (index == -1 || index == size) { + index = size; + setSize(index + 1); + } + _lValueList[index].emissiveColor = col; + hasSetValue(); +} + +void PropertyMaterialList::setEmissiveColor(int index, float r, float g, float b, float a) +{ + verifyIndex(index); + + aboutToSetValue(); + int size = getSize(); + if (index == -1 || index == size) { + index = size; + setSize(index + 1); + } + _lValueList[index].emissiveColor.set(r, g, b, a); + hasSetValue(); +} + +void PropertyMaterialList::setEmissiveColor(int index, uint32_t rgba) +{ + verifyIndex(index); + + aboutToSetValue(); + int size = getSize(); + if (index == -1 || index == size) { + index = size; + setSize(index + 1); + } + _lValueList[index].emissiveColor.setPackedValue(rgba); + hasSetValue(); +} + +void PropertyMaterialList::setShininess(float val) +{ + aboutToSetValue(); + setSizeOne(); + for (auto& material : _lValueList) { + material.shininess = val; + } + hasSetValue(); +} + +void PropertyMaterialList::setShininess(int index, float val) +{ + verifyIndex(index); + + aboutToSetValue(); + int size = getSize(); + if (index == -1 || index == size) { + index = size; + setSize(index + 1); + } + _lValueList[index].shininess = val; + hasSetValue(); +} + +void PropertyMaterialList::setTransparency(float val) +{ + aboutToSetValue(); + setSizeOne(); + for (auto& material : _lValueList) { + material.transparency = val; + } + hasSetValue(); +} + +void PropertyMaterialList::setTransparency(int index, float val) +{ + verifyIndex(index); + + aboutToSetValue(); + int size = getSize(); + if (index == -1 || index == size) { + index = size; + setSize(index + 1); + } + _lValueList[index].transparency = val; + hasSetValue(); +} + +const Color& PropertyMaterialList::getAmbientColor() const +{ + return _lValueList[0].ambientColor; +} + +const Color& PropertyMaterialList::getAmbientColor(int index) const +{ + return _lValueList[index].ambientColor; +} + +const Color& PropertyMaterialList::getDiffuseColor() const +{ + return _lValueList[0].diffuseColor; +} + +const Color& PropertyMaterialList::getDiffuseColor(int index) const +{ + return _lValueList[index].diffuseColor; +} + +std::vector PropertyMaterialList::getDiffuseColors() const +{ + std::vector list; + for (auto& material : _lValueList) { + list.push_back(material.diffuseColor); + } + + return list; +} + +const Color& PropertyMaterialList::getSpecularColor() const +{ + return _lValueList[0].specularColor; +} + +const Color& PropertyMaterialList::getSpecularColor(int index) const +{ + return _lValueList[index].specularColor; +} + +const Color& PropertyMaterialList::getEmissiveColor() const +{ + return _lValueList[0].emissiveColor; +} + +const Color& PropertyMaterialList::getEmissiveColor(int index) const +{ + return _lValueList[index].emissiveColor; +} + +double PropertyMaterialList::getShininess() const +{ + return _lValueList[0].transparency; +} + +double PropertyMaterialList::getShininess(int index) const +{ + return _lValueList[index].transparency; +} + +double PropertyMaterialList::getTransparency() const +{ + return _lValueList[0].transparency; +} + +double PropertyMaterialList::getTransparency(int index) const +{ + return _lValueList[index].transparency; +} + +Material PropertyMaterialList::getPyValue(PyObject* value) const +{ + if (PyObject_TypeCheck(value, &(MaterialPy::Type))) { return *static_cast(value)->getMaterialPtr(); + } else { std::string error = std::string("type must be 'Material', not "); error += value->ob_type->tp_name; @@ -2554,15 +3182,16 @@ Material PropertyMaterialList::getPyValue(PyObject *value) const { } } -void PropertyMaterialList::Save(Base::Writer &writer) const +void PropertyMaterialList::Save(Base::Writer& writer) const { if (!writer.isForceXML()) { - writer.Stream() << writer.ind() << "" << std::endl; + writer.Stream() << writer.ind() << "" + << std::endl; } } -void PropertyMaterialList::Restore(Base::XMLReader &reader) +void PropertyMaterialList::Restore(Base::XMLReader& reader) { reader.readElement("MaterialList"); if (reader.hasAttribute("file")) { @@ -2575,30 +3204,47 @@ void PropertyMaterialList::Restore(Base::XMLReader &reader) } } -void PropertyMaterialList::SaveDocFile(Base::Writer &writer) const +void PropertyMaterialList::SaveDocFile(Base::Writer& writer) const { Base::OutputStream str(writer.Stream()); + // Write the version. Versions should be negative. A non-negative value is a count + // and should be processed as a V0 + int32_t version = -1; + str << version; uint32_t uCt = (uint32_t)getSize(); str << uCt; - for (const auto & it : _lValueList) { + for (const auto& it : _lValueList) { str << it.ambientColor.getPackedValue(); str << it.diffuseColor.getPackedValue(); str << it.specularColor.getPackedValue(); str << it.emissiveColor.getPackedValue(); str << it.shininess; str << it.transparency; + // str << it.uuid.c_str(); } } -void PropertyMaterialList::RestoreDocFile(Base::Reader &reader) +void PropertyMaterialList::RestoreDocFile(Base::Reader& reader) { Base::InputStream str(reader); - uint32_t uCt = 0; - str >> uCt; - std::vector values(uCt); - uint32_t value; // must be 32 bit long + int32_t version; + str >> version; + if (version < 0) { + RestoreDocFileV1(reader); + } + else { + uint32_t uCt = static_cast(version); + RestoreDocFileV0(uCt, reader); + } +} + +void PropertyMaterialList::RestoreDocFileV0(uint32_t count, Base::Reader& reader) +{ + Base::InputStream str(reader); + std::vector values(count); + uint32_t value; // must be 32 bit long float valueF; - for (auto & it : values) { + for (auto& it : values) { str >> value; it.ambientColor.setPackedValue(value); str >> value; @@ -2615,21 +3261,50 @@ void PropertyMaterialList::RestoreDocFile(Base::Reader &reader) setValues(values); } +void PropertyMaterialList::RestoreDocFileV1(Base::Reader& reader) +{ + Base::InputStream str(reader); + uint32_t count = 0; + str >> count; + std::vector values(count); + uint32_t value; // must be 32 bit long + float valueF; + char valueS[37]; // UUID length is 36 including '-'s + for (auto& it : values) { + str >> value; + it.ambientColor.setPackedValue(value); + str >> value; + it.diffuseColor.setPackedValue(value); + str >> value; + it.specularColor.setPackedValue(value); + str >> value; + it.emissiveColor.setPackedValue(value); + str >> valueF; + it.shininess = valueF; + str >> valueF; + it.transparency = valueF; + // str >> valueS; + // it.uuid = valueS; + } + setValues(values); +} + const char* PropertyMaterialList::getEditorName() const { - if(testStatus(NoMaterialListEdit)) + if (testStatus(NoMaterialListEdit)) { return ""; + } return "Gui::PropertyEditor::PropertyMaterialListItem"; } -Property *PropertyMaterialList::Copy() const +Property* PropertyMaterialList::Copy() const { - PropertyMaterialList *p = new PropertyMaterialList(); + PropertyMaterialList* p = new PropertyMaterialList(); p->_lValueList = _lValueList; return p; } -void PropertyMaterialList::Paste(const Property &from) +void PropertyMaterialList::Paste(const Property& from) { setValues(dynamic_cast(from)._lValueList); } diff --git a/src/App/PropertyStandard.h b/src/App/PropertyStandard.h index 7fb7be85c5..c59e3571a6 100644 --- a/src/App/PropertyStandard.h +++ b/src/App/PropertyStandard.h @@ -467,7 +467,7 @@ public: void Paste(const Property &from) override; unsigned int getMemSize () const override; - + bool isSame(const Property &other) const override { if (&other == this) return true; @@ -954,7 +954,7 @@ public: void Paste(const Property &from) override; unsigned int getMemSize () const override{return sizeof(Color);} - + bool isSame(const Property &other) const override { if (&other == this) return true; @@ -1000,15 +1000,15 @@ protected: Color getPyValue(PyObject *) const override; }; + /** Material properties * This is the father of all properties handling colors. */ -class AppExport PropertyMaterial : public Property +class AppExport PropertyMaterial: public Property { TYPESYSTEM_HEADER_WITH_OVERRIDE(); public: - /** * A constructor. * A more elaborate description of the constructor. @@ -1023,34 +1023,56 @@ public: /** Sets the property */ - void setValue(const Material &mat); + void setValue(const Material& mat); + void setValue(const Color& col); + void setValue(float r, float g, float b, float a = 0.0f); + void setValue(uint32_t rgba); void setAmbientColor(const Color& col); + void setAmbientColor(float r, float g, float b, float a = 0.0f); + void setAmbientColor(uint32_t rgba); void setDiffuseColor(const Color& col); + void setDiffuseColor(float r, float g, float b, float a = 0.0f); + void setDiffuseColor(uint32_t rgba); void setSpecularColor(const Color& col); + void setSpecularColor(float r, float g, float b, float a = 0.0f); + void setSpecularColor(uint32_t rgba); void setEmissiveColor(const Color& col); + void setEmissiveColor(float r, float g, float b, float a = 0.0f); + void setEmissiveColor(uint32_t rgba); void setShininess(float); void setTransparency(float); /** This method returns a string representation of the property */ - const Material &getValue() const; + const Material& getValue() const; + const Color& getAmbientColor() const; + const Color& getDiffuseColor() const; + const Color& getSpecularColor() const; + const Color& getEmissiveColor() const; + double getShininess() const; + double getTransparency() const; - PyObject *getPyObject() override; - void setPyObject(PyObject *) override; + PyObject* getPyObject() override; + void setPyObject(PyObject*) override; - void Save (Base::Writer &writer) const override; - void Restore(Base::XMLReader &reader) override; + void Save(Base::Writer& writer) const override; + void Restore(Base::XMLReader& reader) override; const char* getEditorName() const override; - Property *Copy() const override; - void Paste(const Property &from) override; + Property* Copy() const override; + void Paste(const Property& from) override; - unsigned int getMemSize () const override{return sizeof(_cMat);} - - bool isSame(const Property &other) const override { - if (&other == this) + unsigned int getMemSize() const override + { + return sizeof(_cMat); + } + + bool isSame(const Property& other) const override + { + if (&other == this) { return true; + } return getTypeId() == other.getTypeId() && getValue() == static_cast(&other)->getValue(); } @@ -1060,41 +1082,106 @@ private: }; /** Material properties -*/ -class AppExport PropertyMaterialList : public PropertyListsT + */ +class AppExport PropertyMaterialList: public PropertyListsT { TYPESYSTEM_HEADER_WITH_OVERRIDE(); public: - /** - * A constructor. - * A more elaborate description of the constructor. - */ + * A constructor. + * A more elaborate description of the constructor. + */ PropertyMaterialList(); /** - * A destructor. - * A more elaborate description of the destructor. - */ + * A destructor. + * A more elaborate description of the destructor. + */ ~PropertyMaterialList() override; - PyObject *getPyObject() override; + void setValue(); + void setValue(const std::vector& materials) + { + PropertyListsT::setValue(materials); + } + void setValue(const Material& mat); + void setValue(int index, const Material& mat); - void Save(Base::Writer &writer) const override; - void Restore(Base::XMLReader &reader) override; + void setAmbientColor(const Color& col); + void setAmbientColor(float r, float g, float b, float a = 0.0f); + void setAmbientColor(uint32_t rgba); + void setAmbientColor(int index, const Color& col); + void setAmbientColor(int index, float r, float g, float b, float a = 0.0f); + void setAmbientColor(int index, uint32_t rgba); - void SaveDocFile(Base::Writer &writer) const override; - void RestoreDocFile(Base::Reader &reader) override; + void setDiffuseColor(const Color& col); + void setDiffuseColor(float r, float g, float b, float a = 0.0f); + void setDiffuseColor(uint32_t rgba); + void setDiffuseColor(int index, const Color& col); + void setDiffuseColor(int index, float r, float g, float b, float a = 0.0f); + void setDiffuseColor(int index, uint32_t rgba); + + void setSpecularColor(const Color& col); + void setSpecularColor(float r, float g, float b, float a = 0.0f); + void setSpecularColor(uint32_t rgba); + void setSpecularColor(int index, const Color& col); + void setSpecularColor(int index, float r, float g, float b, float a = 0.0f); + void setSpecularColor(int index, uint32_t rgba); + + void setEmissiveColor(const Color& col); + void setEmissiveColor(float r, float g, float b, float a = 0.0f); + void setEmissiveColor(uint32_t rgba); + void setEmissiveColor(int index, const Color& col); + void setEmissiveColor(int index, float r, float g, float b, float a = 0.0f); + void setEmissiveColor(int index, uint32_t rgba); + + void setShininess(float); + void setShininess(int index, float); + + void setTransparency(float); + void setTransparency(int index, float); + + const Color& getAmbientColor() const; + const Color& getAmbientColor(int index) const; + + const Color& getDiffuseColor() const; + const Color& getDiffuseColor(int index) const; + std::vector getDiffuseColors() const; + + const Color& getSpecularColor() const; + const Color& getSpecularColor(int index) const; + + const Color& getEmissiveColor() const; + const Color& getEmissiveColor(int index) const; + + double getShininess() const; + double getShininess(int index) const; + + double getTransparency() const; + double getTransparency(int index) const; + + PyObject* getPyObject() override; + + void Save(Base::Writer& writer) const override; + void Restore(Base::XMLReader& reader) override; + + void SaveDocFile(Base::Writer& writer) const override; + void RestoreDocFile(Base::Reader& reader) override; const char* getEditorName() const override; - Property *Copy() const override; - void Paste(const Property &from) override; + Property* Copy() const override; + void Paste(const Property& from) override; unsigned int getMemSize() const override; protected: - Material getPyValue(PyObject *) const override; + Material getPyValue(PyObject*) const override; + void verifyIndex(int index) const; + void setSizeOne(); + + void RestoreDocFileV0(uint32_t count, Base::Reader& reader); + void RestoreDocFileV1(Base::Reader& reader); }; diff --git a/src/Gui/CMakeLists.txt b/src/Gui/CMakeLists.txt index f17d4afc86..959c8bee91 100644 --- a/src/Gui/CMakeLists.txt +++ b/src/Gui/CMakeLists.txt @@ -220,6 +220,7 @@ generate_from_xml(DocumentPy) generate_from_xml(PythonWorkbenchPy) generate_from_xml(ViewProviderPy) generate_from_xml(ViewProviderDocumentObjectPy) +generate_from_xml(ViewProviderGeometryObjectPy) generate_from_xml(ViewProviderExtensionPy) generate_from_xml(WorkbenchPy) generate_from_xml(SelectionObjectPy) @@ -233,6 +234,7 @@ generate_from_py(FreeCADGuiInit GuiInitScript.h) # The XML files SET(FreeCADGui_XML_SRCS ViewProviderDocumentObjectPy.xml + ViewProviderGeometryObjectPy.xml ViewProviderPy.xml ViewProviderExtensionPy.xml PythonWorkbenchPy.xml @@ -297,7 +299,6 @@ SET(Gui_UIC_SRCS DlgChooseIcon.ui DlgCreateNewPreferencePack.ui DlgCustomizeSpNavSettings.ui - DlgDisplayProperties.ui DlgInputDialog.ui DlgKeyboard.ui DlgMacroExecute.ui @@ -407,7 +408,6 @@ SET(Dialog_CPP_SRCS DlgActivateWindowImp.cpp DlgCreateNewPreferencePackImp.cpp DlgUnitsCalculatorImp.cpp - DlgDisplayPropertiesImp.cpp DlgInputDialogImp.cpp DlgMacroExecuteImp.cpp DlgRunExternal.cpp @@ -447,7 +447,6 @@ SET(Dialog_HPP_SRCS DlgActivateWindowImp.h DlgCreateNewPreferencePackImp.h DlgUnitsCalculatorImp.h - DlgDisplayPropertiesImp.h DlgInputDialogImp.h DlgMacroExecuteImp.h DlgRunExternal.h @@ -490,7 +489,6 @@ SET(Dialog_SRCS DlgActivateWindow.ui DlgUnitsCalculator.ui DlgAuthorization.ui - DlgDisplayProperties.ui DlgInputDialog.ui DlgAddProperty.ui DlgLocationAngle.ui @@ -900,6 +898,7 @@ SET(Viewprovider_CPP_SRCS ViewProviderDocumentObject.cpp ViewProviderDocumentObjectGroup.cpp ViewProviderDocumentObjectPyImp.cpp + ViewProviderGeometryObjectPyImp.cpp ViewProviderDragger.cpp ViewProviderExtern.cpp ViewProviderFeature.cpp diff --git a/src/Gui/Command.cpp b/src/Gui/Command.cpp index 2c22392437..e263ddc48e 100644 --- a/src/Gui/Command.cpp +++ b/src/Gui/Command.cpp @@ -785,7 +785,8 @@ void Command::_copyVisual(const char *file, int line, const App::DocumentObject if(!from || !from->isAttachedToDocument() || !to || !to->isAttachedToDocument()) return; static std::map attrMap = { - {"ShapeColor","ShapeMaterial.DiffuseColor"}, + // {"ShapeColor","ShapeMaterial.DiffuseColor"}, + {"ShapeAppearance", "ShapeMaterial"}, // {"LineColor","ShapeMaterial.DiffuseColor"}, // {"PointColor","ShapeMaterial.DiffuseColor"}, {"Transparency","Transparency"}, diff --git a/src/Gui/CommandFeat.cpp b/src/Gui/CommandFeat.cpp index 931b3b188a..30b65ee3a7 100644 --- a/src/Gui/CommandFeat.cpp +++ b/src/Gui/CommandFeat.cpp @@ -104,9 +104,11 @@ void StdCmdRandomColor::activated(int iMsg) vpLink->ShapeMaterial.setDiffuseColor(objColor); } else if (view) { - if (auto color = dynamic_cast(view->getPropertyByName("ShapeColor"))) { + auto appearance = + dynamic_cast(view->getPropertyByName("ShapeAppearance")); + if (appearance) { // get the view provider of the selected object and set the shape color - color->setValue(objColor); + appearance->setDiffuseColor(objColor); } } }; diff --git a/src/Gui/CommandView.cpp b/src/Gui/CommandView.cpp index 11dc569b5c..bf39b60cef 100644 --- a/src/Gui/CommandView.cpp +++ b/src/Gui/CommandView.cpp @@ -62,7 +62,6 @@ #include "Control.h" #include "Clipping.h" #include "DemoMode.h" -#include "DlgDisplayPropertiesImp.h" #include "DlgSettingsImageImp.h" #include "Document.h" #include "FileDialog.h" @@ -1262,36 +1261,6 @@ bool StdCmdHideObjects::isActive() return App::GetApplication().getActiveDocument(); } -//=========================================================================== -// Std_SetAppearance -//=========================================================================== -DEF_STD_CMD_A(StdCmdSetAppearance) - -StdCmdSetAppearance::StdCmdSetAppearance() - : Command("Std_SetAppearance") -{ - sGroup = "Standard-View"; - sMenuText = QT_TR_NOOP("Appearance..."); - sToolTipText = QT_TR_NOOP("Sets the display properties of the selected object"); - sWhatsThis = "Std_SetAppearance"; - sStatusTip = QT_TR_NOOP("Sets the display properties of the selected object"); - sPixmap = "Std_SetAppearance"; - sAccel = "Ctrl+D"; - eType = Alter3DView; -} - -void StdCmdSetAppearance::activated(int iMsg) -{ - Q_UNUSED(iMsg); - Gui::Control().showDialog(new Gui::Dialog::TaskDisplayProperties()); -} - -bool StdCmdSetAppearance::isActive() -{ - return (Gui::Control().activeDialog() == nullptr) && - (Gui::Selection().size() != 0); -} - //=========================================================================== // Std_ViewHome //=========================================================================== @@ -4123,7 +4092,6 @@ void CreateViewStdCommands() rcCmdMgr.addCommand(new StdViewLoadImage()); rcCmdMgr.addCommand(new StdMainFullscreen()); rcCmdMgr.addCommand(new StdViewDockUndockFullscreen()); - rcCmdMgr.addCommand(new StdCmdSetAppearance()); rcCmdMgr.addCommand(new StdCmdToggleVisibility()); rcCmdMgr.addCommand(new StdCmdToggleTransparency()); rcCmdMgr.addCommand(new StdCmdToggleSelectability()); diff --git a/src/Gui/DlgMaterialPropertiesImp.h b/src/Gui/DlgMaterialPropertiesImp.h index ad2c4bea7c..8d1e4b458c 100644 --- a/src/Gui/DlgMaterialPropertiesImp.h +++ b/src/Gui/DlgMaterialPropertiesImp.h @@ -28,18 +28,22 @@ #include #include -namespace Gui { +namespace Gui +{ class ViewProvider; -namespace Dialog { +namespace Dialog +{ class Ui_DlgMaterialProperties; -class DlgMaterialPropertiesImp : public QDialog +class GuiExport DlgMaterialPropertiesImp: public QDialog { Q_OBJECT public: - explicit DlgMaterialPropertiesImp(const std::string& mat, QWidget* parent = nullptr, Qt::WindowFlags fl = Qt::WindowFlags()); + explicit DlgMaterialPropertiesImp(const std::string& mat, + QWidget* parent = nullptr, + Qt::WindowFlags fl = Qt::WindowFlags()); ~DlgMaterialPropertiesImp() override; void setViewProviders(const std::vector&); QColor diffuseColor() const; @@ -58,8 +62,7 @@ private: std::vector Objects; }; -} // namespace Dialog -} // namespace Gui - -#endif // GUI_DIALOG_DLGMATERIALPROPERTIES_IMP_H +} // namespace Dialog +} // namespace Gui +#endif // GUI_DIALOG_DLGMATERIALPROPERTIES_IMP_H diff --git a/src/Gui/ManualAlignment.cpp b/src/Gui/ManualAlignment.cpp index 4a243fc49b..0884768a44 100644 --- a/src/Gui/ManualAlignment.cpp +++ b/src/Gui/ManualAlignment.cpp @@ -201,9 +201,11 @@ void AlignmentGroup::setAlignable(bool align) } // leaving alignment mode else if (!align){ - auto pColor = dynamic_cast((*it)->getPropertyByName("ShapeColor")); - if (pColor) - pColor->touch(); // resets to color defined by property + auto pAppearance = + dynamic_cast((*it)->getPropertyByName("ShapeAppearance")); + if (pAppearance) { + pAppearance->touch(); // resets to color defined by property + } } } } diff --git a/src/Gui/StartupProcess.cpp b/src/Gui/StartupProcess.cpp index 9c5e7e571b..0e9b23e327 100644 --- a/src/Gui/StartupProcess.cpp +++ b/src/Gui/StartupProcess.cpp @@ -451,6 +451,9 @@ void StartupPostProcess::showMainWindow() void StartupPostProcess::activateWorkbench() { + // Always activate the material workbench + guiApp.activateWorkbench("MaterialWorkbench"); + // Activate the correct workbench std::string start = App::Application::Config()["StartWorkbench"]; Base::Console().Log("Init: Activating default workbench %s\n", start.c_str()); diff --git a/src/Gui/ViewProviderGeometryObject.cpp b/src/Gui/ViewProviderGeometryObject.cpp index 4cf3109e2c..06bd1b9882 100644 --- a/src/Gui/ViewProviderGeometryObject.cpp +++ b/src/Gui/ViewProviderGeometryObject.cpp @@ -23,17 +23,17 @@ #include "PreCompiled.h" #ifndef _PreComp_ -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include -# include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #endif #include @@ -41,13 +41,13 @@ #include #include -#include "ViewProviderGeometryObject.h" #include "Application.h" #include "Document.h" #include "SoFCBoundingBox.h" #include "SoFCSelection.h" #include "View3DInventorViewer.h" - +#include "ViewProviderGeometryObject.h" +#include "ViewProviderGeometryObjectPy.h" using namespace Gui; @@ -57,44 +57,59 @@ const App::PropertyIntegerConstraint::Constraints intPercent = {0, 100, 5}; ViewProviderGeometryObject::ViewProviderGeometryObject() { - ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/View"); - bool randomColor = hGrp->GetBool("RandomColor", false); - float r, g, b; - - if (randomColor){ - auto fMax = (float)RAND_MAX; - r = (float)rand() / fMax; - g = (float)rand() / fMax; - b = (float)rand() / fMax; - } - else { - unsigned long shcol = hGrp->GetUnsigned("DefaultShapeColor", 3435980543UL); - r = ((shcol >> 24) & 0xff) / 255.0; - g = ((shcol >> 16) & 0xff) / 255.0; - b = ((shcol >> 8) & 0xff) / 255.0; - } + ParameterGrp::handle hGrp = + App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/View"); int initialTransparency = hGrp->GetInt("DefaultShapeTransparency", 0); - static const char *dogroup = "Display Options"; - static const char *sgroup = "Selection"; - static const char *osgroup = "Object Style"; + static const char* dogroup = "Display Options"; + static const char* sgroup = "Selection"; + static const char* osgroup = "Object Style"; - ADD_PROPERTY_TYPE(ShapeColor, (r, g, b), osgroup, App::Prop_None, "Set shape color"); - ADD_PROPERTY_TYPE(Transparency, (initialTransparency), osgroup, App::Prop_None, "Set object transparency"); + ADD_PROPERTY_TYPE(Transparency, + (initialTransparency), + osgroup, + App::Prop_None, + "Set object transparency"); Transparency.setConstraints(&intPercent); + App::Material mat(App::Material::DEFAULT); - mat.transparency = (float)initialTransparency / 100.0f; - ADD_PROPERTY_TYPE(ShapeMaterial,(mat), osgroup, App::Prop_None, "Shape material"); + auto geometry = dynamic_cast(getObject()); + if (geometry) { + mat = geometry->getMaterialAppearance(); + } else { + // This is handled in the material code when using the object appearance + bool randomColor = hGrp->GetBool("RandomColor", false); + float r, g, b; + + if (randomColor) { + auto fMax = (float)RAND_MAX; + r = (float)rand() / fMax; + g = (float)rand() / fMax; + b = (float)rand() / fMax; + } + else { + unsigned long shcol = hGrp->GetUnsigned("DefaultShapeColor", 3435980543UL); + r = ((shcol >> 24) & 0xff) / 255.0; + g = ((shcol >> 16) & 0xff) / 255.0; + b = ((shcol >> 8) & 0xff) / 255.0; + } + mat.diffuseColor = App::Color(r,g,b); + } + + ADD_PROPERTY_TYPE(ShapeAppearance, (mat), osgroup, App::Prop_None, "Shape appearrance"); ADD_PROPERTY_TYPE(BoundingBox, (false), dogroup, App::Prop_None, "Display object bounding box"); - ADD_PROPERTY_TYPE(Selectable, (true), sgroup, App::Prop_None, "Set if the object is selectable in the 3d view"); + ADD_PROPERTY_TYPE(Selectable, + (true), + sgroup, + App::Prop_None, + "Set if the object is selectable in the 3d view"); bool enableSel = hGrp->GetBool("EnableSelection", true); Selectable.setValue(enableSel); pcShapeMaterial = new SoMaterial; - pcShapeMaterial->diffuseColor.setValue(r, g, b); - pcShapeMaterial->transparency = float(initialTransparency); + setSoMaterial(mat); pcShapeMaterial->ref(); pcBoundingBox = new Gui::SoFCBoundingBox; @@ -115,44 +130,32 @@ ViewProviderGeometryObject::~ViewProviderGeometryObject() void ViewProviderGeometryObject::onChanged(const App::Property* prop) { - // Actually, the properties 'ShapeColor' and 'Transparency' are part of the property 'ShapeMaterial'. - // Both redundant properties are kept due to more convenience for the user. But we must keep the values - // consistent of all these properties. + // Actually, the properties 'ShapeColor' and 'Transparency' are part of the property + // 'ShapeMaterial'. Both redundant properties are kept due to more convenience for the user. But + // we must keep the values consistent of all these properties. + std::string propName = prop->getName(); if (prop == &Selectable) { bool Sel = Selectable.getValue(); setSelectable(Sel); } - else if (prop == &ShapeColor) { - const App::Color &c = ShapeColor.getValue(); - pcShapeMaterial->diffuseColor.setValue(c.r, c.g, c.b); - if (c != ShapeMaterial.getValue().diffuseColor) - ShapeMaterial.setDiffuseColor(c); - } else if (prop == &Transparency) { - const App::Material &Mat = ShapeMaterial.getValue(); - long value = (long)(100 * Mat.transparency); + long value = (long)(100 * ShapeAppearance.getTransparency()); if (value != Transparency.getValue()) { - float trans = Transparency.getValue() / 100.0f; + float trans = (float)Transparency.getValue() / 100.0f; pcShapeMaterial->transparency = trans; - ShapeMaterial.setTransparency(trans); + ShapeAppearance.setTransparency(trans); } } - else if (prop == &ShapeMaterial) { - if (getObject() && getObject()->testStatus(App::ObjectStatus::TouchOnColorChange)) + else if (prop == &ShapeAppearance) { + if (getObject() && getObject()->testStatus(App::ObjectStatus::TouchOnColorChange)) { getObject()->touch(true); - const App::Material &Mat = ShapeMaterial.getValue(); - long value = (long)(100 * Mat.transparency); - if (value != Transparency.getValue()) + } + const App::Material& Mat = ShapeAppearance[0]; + long value = (long)(100.0 * ShapeAppearance.getTransparency() + 0.5); + if (value != Transparency.getValue()) { Transparency.setValue(value); - const App::Color &color = Mat.diffuseColor; - if (color != ShapeColor.getValue()) - ShapeColor.setValue(Mat.diffuseColor); - pcShapeMaterial->ambientColor.setValue(Mat.ambientColor.r, Mat.ambientColor.g, Mat.ambientColor.b); - pcShapeMaterial->diffuseColor.setValue(Mat.diffuseColor.r, Mat.diffuseColor.g, Mat.diffuseColor.b); - pcShapeMaterial->specularColor.setValue(Mat.specularColor.r, Mat.specularColor.g, Mat.specularColor.b); - pcShapeMaterial->emissiveColor.setValue(Mat.emissiveColor.r, Mat.emissiveColor.g, Mat.emissiveColor.b); - pcShapeMaterial->shininess.setValue(Mat.shininess); - pcShapeMaterial->transparency.setValue(Mat.transparency); + } + setSoMaterial(Mat); } else if (prop == &BoundingBox) { showBoundingBox(BoundingBox.getValue()); @@ -161,15 +164,22 @@ void ViewProviderGeometryObject::onChanged(const App::Property* prop) ViewProviderDragger::onChanged(prop); } -void ViewProviderGeometryObject::attach(App::DocumentObject *pcObj) +void ViewProviderGeometryObject::attach(App::DocumentObject* pcObj) { ViewProviderDragger::attach(pcObj); } void ViewProviderGeometryObject::updateData(const App::Property* prop) { + std::string propName = prop->getName(); + if (propName == "Shape") { + // Reapply the appearance + const App::Material& Mat = ShapeAppearance[0]; + setSoMaterial(Mat); + } if (prop->isDerivedFrom(App::PropertyComplexGeoData::getClassTypeId())) { - Base::BoundBox3d box = static_cast(prop)->getBoundingBox(); + Base::BoundBox3d box = + static_cast(prop)->getBoundingBox(); pcBoundingBox->minBounds.setValue(box.MinX, box.MinY, box.MinZ); pcBoundingBox->maxBounds.setValue(box.MaxX, box.MaxY, box.MaxZ); } @@ -184,11 +194,21 @@ void ViewProviderGeometryObject::updateData(const App::Property* prop) } } } + else if (std::string(prop->getName()) == "ShapeMaterial") { + // Set the appearance from the material + auto geometry = dynamic_cast(getObject()); + if (geometry) { + auto material = geometry->getMaterialAppearance(); + ShapeAppearance.setValue(material); + } + } ViewProviderDragger::updateData(prop); } -SoPickedPointList ViewProviderGeometryObject::getPickedPoints(const SbVec2s& pos, const View3DInventorViewer& viewer,bool pickAll) const +SoPickedPointList ViewProviderGeometryObject::getPickedPoints(const SbVec2s& pos, + const View3DInventorViewer& viewer, + bool pickAll) const { auto root = new SoSeparator; root->ref(); @@ -207,7 +227,8 @@ SoPickedPointList ViewProviderGeometryObject::getPickedPoints(const SbVec2s& pos return rp.getPickedPointList(); } -SoPickedPoint* ViewProviderGeometryObject::getPickedPoint(const SbVec2s& pos, const View3DInventorViewer& viewer) const +SoPickedPoint* ViewProviderGeometryObject::getPickedPoint(const SbVec2s& pos, + const View3DInventorViewer& viewer) const { auto root = new SoSeparator; root->ref(); @@ -223,31 +244,55 @@ SoPickedPoint* ViewProviderGeometryObject::getPickedPoint(const SbVec2s& pos, co // returns a copy of the point SoPickedPoint* pick = rp.getPickedPoint(); - //return (pick ? pick->copy() : 0); // needs the same instance of CRT under MS Windows + // return (pick ? pick->copy() : 0); // needs the same instance of CRT under MS Windows return (pick ? new SoPickedPoint(*pick) : nullptr); } unsigned long ViewProviderGeometryObject::getBoundColor() const { - ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/View"); - unsigned long bbcol = hGrp->GetUnsigned("BoundingBoxColor",4294967295UL); // white (255,255,255) + ParameterGrp::handle hGrp = + App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/View"); + unsigned long bbcol = + hGrp->GetUnsigned("BoundingBoxColor", 4294967295UL); // white (255,255,255) return bbcol; } -namespace { +void ViewProviderGeometryObject::setSoMaterial(const App::Material& source) +{ + pcShapeMaterial->ambientColor.setValue(source.ambientColor.r, + source.ambientColor.g, + source.ambientColor.b); + pcShapeMaterial->diffuseColor.setValue(source.diffuseColor.r, + source.diffuseColor.g, + source.diffuseColor.b); + pcShapeMaterial->specularColor.setValue(source.specularColor.r, + source.specularColor.g, + source.specularColor.b); + pcShapeMaterial->emissiveColor.setValue(source.emissiveColor.r, + source.emissiveColor.g, + source.emissiveColor.b); + pcShapeMaterial->shininess.setValue(source.shininess); + pcShapeMaterial->transparency.setValue(source.transparency); +} + +namespace +{ float getBoundBoxFontSize() { - ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/View"); + ParameterGrp::handle hGrp = + App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/View"); return hGrp->GetFloat("BoundingBoxFontSize", 10.0); } -} +} // namespace void ViewProviderGeometryObject::showBoundingBox(bool show) { if (!pcBoundSwitch && show) { unsigned long bbcol = getBoundColor(); - float r,g,b; - r = ((bbcol >> 24) & 0xff) / 255.0; g = ((bbcol >> 16) & 0xff) / 255.0; b = ((bbcol >> 8) & 0xff) / 255.0; + float r, g, b; + r = ((bbcol >> 24) & 0xff) / 255.0; + g = ((bbcol >> 16) & 0xff) / 255.0; + b = ((bbcol >> 8) & 0xff) / 255.0; pcBoundSwitch = new SoSwitch(); auto pBoundingSep = new SoSeparator(); @@ -284,9 +329,9 @@ void ViewProviderGeometryObject::setSelectable(bool selectable) sa.setType(Gui::SoFCSelection::getClassTypeId()); sa.apply(pcRoot); - SoPathList & pathList = sa.getPaths(); + SoPathList& pathList = sa.getPaths(); - for (int i=0;i(pathList[i]->getTail()); if (selectable) { if (selNode) { @@ -303,3 +348,33 @@ void ViewProviderGeometryObject::setSelectable(bool selectable) } } } + +PyObject* ViewProviderGeometryObject::getPyObject() +{ + if (!pyViewObject) { + pyViewObject = new ViewProviderGeometryObjectPy(this); + } + pyViewObject->IncRef(); + return pyViewObject; +} + +void ViewProviderGeometryObject::handleChangedPropertyName(Base::XMLReader& reader, + const char* TypeName, + const char* PropName) +{ + if (strcmp(PropName, "ShapeColor") == 0 + && strcmp(TypeName, App::PropertyColor::getClassTypeId().getName()) == 0) { + App::PropertyColor prop; + prop.Restore(reader); + ShapeAppearance.setDiffuseColor(prop.getValue()); + } + else if (strcmp(PropName, "ShapeMaterial") == 0 + && strcmp(TypeName, App::PropertyMaterial::getClassTypeId().getName()) == 0) { + App::PropertyMaterial prop; + prop.Restore(reader); + ShapeAppearance.setValue(prop.getValue()); + } + else { + App::PropertyContainer::handleChangedPropertyName(reader, TypeName, PropName); + } +} diff --git a/src/Gui/ViewProviderGeometryObject.h b/src/Gui/ViewProviderGeometryObject.h index 34fb86f0f0..f968301d62 100644 --- a/src/Gui/ViewProviderGeometryObject.h +++ b/src/Gui/ViewProviderGeometryObject.h @@ -33,17 +33,19 @@ class SoSensor; class SbVec2s; class SoBaseColor; -namespace Gui { +namespace Gui +{ class SoFCSelection; class SoFCBoundingBox; class View3DInventorViewer; /** - * The base class for all view providers that display geometric data, like mesh, point clouds and shapes. + * The base class for all view providers that display geometric data, like mesh, point clouds and + * shapes. * @author Werner Mayer */ -class GuiExport ViewProviderGeometryObject : public ViewProviderDragger +class GuiExport ViewProviderGeometryObject: public ViewProviderDragger { PROPERTY_HEADER_WITH_OVERRIDE(Gui::ViewProviderGeometryObject); @@ -55,30 +57,35 @@ public: ~ViewProviderGeometryObject() override; // Display properties - App::PropertyColor ShapeColor; App::PropertyPercent Transparency; - App::PropertyMaterial ShapeMaterial; + // App::PropertyMaterial ShapeMaterial; // Default appearance and physical properties + App::PropertyMaterialList ShapeAppearance; // May be different from material App::PropertyBool BoundingBox; App::PropertyBool Selectable; /** * Attaches the document object to this view provider. */ - void attach(App::DocumentObject *pcObject) override; + void attach(App::DocumentObject* pcObject) override; void updateData(const App::Property*) override; - bool isSelectable() const override {return Selectable.getValue();} + bool isSelectable() const override + { + return Selectable.getValue(); + } /** * Returns a list of picked points from the geometry under \a getRoot(). - * If \a pickAll is false (the default) only the intersection point closest to the camera will be picked, otherwise - * all intersection points will be picked. + * If \a pickAll is false (the default) only the intersection point closest to the camera will + * be picked, otherwise all intersection points will be picked. */ - SoPickedPointList getPickedPoints(const SbVec2s& pos, const View3DInventorViewer& viewer,bool pickAll=false) const; + SoPickedPointList getPickedPoints(const SbVec2s& pos, + const View3DInventorViewer& viewer, + bool pickAll = false) const; /** - * This method is provided for convenience and does basically the same as getPickedPoints() unless that only the closest - * point to the camera will be picked. - * \note It is in the response of the client programmer to delete the returned SoPickedPoint object. + * This method is provided for convenience and does basically the same as getPickedPoints() + * unless that only the closest point to the camera will be picked. \note It is in the response + * of the client programmer to delete the returned SoPickedPoint object. */ SoPickedPoint* getPickedPoint(const SbVec2s& pos, const View3DInventorViewer& viewer) const; @@ -87,21 +94,29 @@ public: virtual void showBoundingBox(bool); //@} + /// Get the python wrapper for that ViewProvider + PyObject* getPyObject() override; + protected: /// get called by the container whenever a property has been changed void onChanged(const App::Property* prop) override; - void setSelectable(bool Selectable=true); + void setSelectable(bool Selectable = true); virtual unsigned long getBoundColor() const; + void setSoMaterial(const App::Material& source); + void handleChangedPropertyName(Base::XMLReader& reader, + const char* TypeName, + const char* PropName) override; + protected: - SoMaterial * pcShapeMaterial{nullptr}; - SoFCBoundingBox * pcBoundingBox{nullptr}; - SoSwitch * pcBoundSwitch{nullptr}; - SoBaseColor * pcBoundColor{nullptr}; + SoMaterial* pcShapeMaterial {nullptr}; + SoFCBoundingBox* pcBoundingBox {nullptr}; + SoSwitch* pcBoundSwitch {nullptr}; + SoBaseColor* pcBoundColor {nullptr}; }; -} // namespace Gui +} // namespace Gui -#endif // GUI_VIEWPROVIDER_GEOMETRYOBJECT_H +#endif // GUI_VIEWPROVIDER_GEOMETRYOBJECT_H diff --git a/src/Gui/ViewProviderGeometryObjectPy.xml b/src/Gui/ViewProviderGeometryObjectPy.xml new file mode 100644 index 0000000000..a24ec3bfbb --- /dev/null +++ b/src/Gui/ViewProviderGeometryObjectPy.xml @@ -0,0 +1,17 @@ + + + + + + This is the ViewProvider geometry class + + + diff --git a/src/Gui/ViewProviderGeometryObjectPyImp.cpp b/src/Gui/ViewProviderGeometryObjectPyImp.cpp new file mode 100644 index 0000000000..98ba0ac5d4 --- /dev/null +++ b/src/Gui/ViewProviderGeometryObjectPyImp.cpp @@ -0,0 +1,94 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later + +/*************************************************************************** + * Copyright (c) 2024 Werner Mayer * + * * + * This file is part of FreeCAD. * + * * + * FreeCAD is free software: you can redistribute it and/or modify it * + * under the terms of the GNU Lesser General Public License as * + * published by the Free Software Foundation, either version 2.1 of the * + * License, or (at your option) any later version. * + * * + * FreeCAD is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with FreeCAD. If not, see * + * . * + * * + **************************************************************************/ + +#include "PreCompiled.h" + +#ifndef _PreComp_ +#include +#endif + +#include +#include + +#include "ViewProviderGeometryObjectPy.h" + +#include "ViewProviderGeometryObjectPy.cpp" + + +using namespace Gui; + +// returns a string which represents the object e.g. when printed in python +std::string ViewProviderGeometryObjectPy::representation() const +{ + std::stringstream str; + str << ""; + + return str.str(); +} + +PyObject* ViewProviderGeometryObjectPy::getCustomAttributes(const char* attr) const +{ + ViewProviderGeometryObject* vp = getViewProviderGeometryObjectPtr(); + if (strcmp(attr, "ShapeColor") == 0) { + // Get material property of ViewProviderGeometryObject + App::PropertyColor prop; + prop.setValue(vp->ShapeAppearance.getDiffuseColor()); + return prop.getPyObject(); + } + if (strcmp(attr, "ShapeMaterial") == 0) { + // Get material property of ViewProviderGeometryObject + auto geometry = dynamic_cast(vp->getObject()); + if (geometry) { + auto material = geometry->getMaterialAppearance(); + App::PropertyMaterial prop; + prop.setValue(material); + return prop.getPyObject(); + } + } + return nullptr; +} + +int ViewProviderGeometryObjectPy::setCustomAttributes(const char* attr, PyObject* obj) +{ + ViewProviderGeometryObject* vp = getViewProviderGeometryObjectPtr(); + if (strcmp(attr, "ShapeColor") == 0) { + // Get material property of ViewProviderGeometryObject + App::PropertyColor prop; + prop.setPyObject(obj); + vp->ShapeAppearance.setDiffuseColor(prop.getValue()); + // Assign the value to the new property type + // ... + return 1; + } + if (strcmp(attr, "ShapeMaterial") == 0) { + // Get material property of ViewProviderGeometryObject + auto geometry = dynamic_cast(vp->getObject()); + if (geometry) { + App::PropertyMaterial prop; + prop.setPyObject(obj); + geometry->setMaterialAppearance(prop.getValue()); + } + return 1; + } + return 0; +} diff --git a/src/Gui/ViewProviderOriginFeature.cpp b/src/Gui/ViewProviderOriginFeature.cpp index df57b9b044..66f3a2b2c8 100644 --- a/src/Gui/ViewProviderOriginFeature.cpp +++ b/src/Gui/ViewProviderOriginFeature.cpp @@ -50,7 +50,8 @@ ViewProviderOriginFeature::ViewProviderOriginFeature () { ADD_PROPERTY_TYPE ( Size, (ViewProviderOrigin::defaultSize()), 0, App::Prop_ReadOnly, QT_TRANSLATE_NOOP("App::Property", "Visual size of the feature")); - ShapeColor.setValue ( ViewProviderOrigin::defaultColor ); // Set default color for origin (light-blue) + ShapeAppearance.setDiffuseColor( + ViewProviderOrigin::defaultColor); // Set default color for origin (light-blue) Transparency.setValue(0); BoundingBox.setStatus(App::Property::Hidden, true); // Hide Boundingbox from the user due to it doesn't make sense @@ -108,13 +109,13 @@ void ViewProviderOriginFeature::attach(App::DocumentObject* pcObject) auto axisRoles = App::Origin::AxisRoles; if ( strncmp(axisName, axisRoles[0], strlen(axisRoles[0]) ) == 0 ) { // X-axis: red - ShapeColor.setValue ( 0xFF0000FF ); + ShapeAppearance.setDiffuseColor(0xFF0000FF); } else if ( strncmp(axisName, axisRoles[1], strlen(axisRoles[1]) ) == 0 ) { // Y-axis: green - ShapeColor.setValue ( 0x00FF00FF ); + ShapeAppearance.setDiffuseColor(0x00FF00FF); } else if ( strncmp(axisName, axisRoles[2], strlen(axisRoles[2]) ) == 0 ) { // Z-axis: blue - ShapeColor.setValue ( 0x0000FFFF ); + ShapeAppearance.setDiffuseColor(0x0000FFFF); } } font->size.setValue ( defaultSz / fontRatio ); diff --git a/src/Gui/Workbench.cpp b/src/Gui/Workbench.cpp index c19b81848b..45e61e2ddb 100644 --- a/src/Gui/Workbench.cpp +++ b/src/Gui/Workbench.cpp @@ -601,7 +601,7 @@ void StdWorkbench::setupContextMenu(const char* recipient, MenuItem* item) const << "Std_ViewDockUndockFullscreen"; if (Gui::Selection().countObjectsOfType(App::DocumentObject::getClassTypeId()) > 0) { - *item << "Separator" << "Std_SetAppearance" << "Std_ToggleVisibility" + *item << "Separator" << "Std_SetMaterial" << "Std_SetAppearance" << "Std_ToggleVisibility" << "Std_ToggleSelectability" << "Std_TreeSelection" << "Std_RandomColor" << "Std_ToggleTransparency" << "Separator" << "Std_Delete" << "Std_SendToPythonConsole" << "Std_TransformManip" << "Std_Placement"; @@ -613,7 +613,7 @@ void StdWorkbench::setupContextMenu(const char* recipient, MenuItem* item) const *item << "Std_ToggleFreeze" << "Separator" << "Std_Placement" << "Std_ToggleVisibility" << "Std_ShowSelection" << "Std_HideSelection" << "Std_ToggleSelectability" << "Std_TreeSelectAllInstances" << "Separator" - << "Std_SetAppearance" << "Std_RandomColor" << "Std_ToggleTransparency" << "Separator" + << "Std_SetMaterial" << "Std_SetAppearance" << "Std_RandomColor" << "Std_ToggleTransparency" << "Separator" << "Std_Cut" << "Std_Copy" << "Std_Paste" << "Std_Delete" << "Std_SendToPythonConsole" << "Separator"; } @@ -701,6 +701,7 @@ MenuItem* StdWorkbench::setupMenuBar() const #endif << "Separator" << visu << "Std_ToggleNavigation" + << "Std_SetMaterial" << "Std_SetAppearance" << "Std_RandomColor" << "Std_ToggleTransparency" diff --git a/src/Mod/Arch/ArchBuildingPart.py b/src/Mod/Arch/ArchBuildingPart.py index 91da2f5b79..c6bffe8140 100644 --- a/src/Mod/Arch/ArchBuildingPart.py +++ b/src/Mod/Arch/ArchBuildingPart.py @@ -607,7 +607,7 @@ class ViewProviderBuildingPart: vobj.addProperty("App::PropertyColor","ChildrenLineColor","Children",QT_TRANSLATE_NOOP("App::Property","The line color of child objects")) vobj.ChildrenLineColor = params.get_param_view("DefaultShapeLineColor") & 0xFFFFFF00 if not "ChildrenShapeColor" in pl: - vobj.addProperty("App::PropertyColor","ChildrenShapeColor","Children",QT_TRANSLATE_NOOP("App::Property","The shape color of child objects")) + vobj.addProperty("App::PropertyMaterial","ChildrenShapeColor","Children",QT_TRANSLATE_NOOP("App::Property","The shape appearance of child objects")) vobj.ChildrenShapeColor = params.get_param_view("DefaultShapeColor") & 0xFFFFFF00 if not "ChildrenTransparency" in pl: vobj.addProperty("App::PropertyPercent","ChildrenTransparency","Children",QT_TRANSLATE_NOOP("App::Property","The transparency of child objects")) diff --git a/src/Mod/Arch/ArchComponent.py b/src/Mod/Arch/ArchComponent.py index 1faaa34111..d372427270 100644 --- a/src/Mod/Arch/ArchComponent.py +++ b/src/Mod/Arch/ArchComponent.py @@ -1217,7 +1217,6 @@ class ViewProviderComponent: if len(obj.Base.ViewObject.DiffuseColor) > 1: obj.ViewObject.DiffuseColor = obj.Base.ViewObject.DiffuseColor obj.ViewObject.update() - #self.onChanged(obj.ViewObject,"ShapeColor") elif prop == "CloneOf": if obj.CloneOf: mat = None @@ -1229,7 +1228,6 @@ class ViewProviderComponent: if len(obj.CloneOf.ViewObject.DiffuseColor) > 1: obj.ViewObject.DiffuseColor = obj.CloneOf.ViewObject.DiffuseColor obj.ViewObject.update() - #self.onChanged(obj.ViewObject,"ShapeColor") return def getIcon(self): diff --git a/src/Mod/Arch/ArchFence.py b/src/Mod/Arch/ArchFence.py index aa6394cd81..e7930fc251 100644 --- a/src/Mod/Arch/ArchFence.py +++ b/src/Mod/Arch/ArchFence.py @@ -302,7 +302,7 @@ class _ViewProviderFence(ArchComponent.ViewProviderComponent): def applyColors(self, obj): if not hasattr(obj.ViewObject, "UseOriginalColors") or not obj.ViewObject.UseOriginalColors: - obj.ViewObject.DiffuseColor = [obj.ViewObject.ShapeColor] + obj.ViewObject.DiffuseColor = [obj.ViewObject.ShapeAppeaarance.DiffuseColor] else: post = obj.Post section = obj.Section diff --git a/src/Mod/Arch/ArchReference.py b/src/Mod/Arch/ArchReference.py index 2c474f42f8..03f6a9f66d 100644 --- a/src/Mod/Arch/ArchReference.py +++ b/src/Mod/Arch/ArchReference.py @@ -458,7 +458,7 @@ class ViewProviderArchReference: def onChanged(self,vobj,prop): if prop == "ShapeColor": - # prevent ShapeColor to override DiffuseColor + # prevent ShapeColor from overriding DiffuseColor if hasattr(vobj,"DiffuseColor") and hasattr(vobj,"UpdateColors"): if vobj.DiffuseColor and vobj.UpdateColors: vobj.DiffuseColor = vobj.DiffuseColor diff --git a/src/Mod/Arch/ArchSpace.py b/src/Mod/Arch/ArchSpace.py index a1eec138a0..8b51db7b7c 100644 --- a/src/Mod/Arch/ArchSpace.py +++ b/src/Mod/Arch/ArchSpace.py @@ -727,7 +727,7 @@ class _ViewProviderSpace(ArchComponent.ViewProviderComponent): elif prop == "ShapeColor": if hasattr(vobj,"ShapeColor"): - self.fmat.diffuseColor.setValue((vobj.ShapeColor[0],vobj.ShapeColor[1],vobj.ShapeColor[2])) + self.fmat = vobj.ShapeColor.getValue() elif prop == "Transparency": if hasattr(vobj,"Transparency"): diff --git a/src/Mod/Arch/OfflineRenderingUtils.py b/src/Mod/Arch/OfflineRenderingUtils.py index 296c48886c..31554b5d06 100755 --- a/src/Mod/Arch/OfflineRenderingUtils.py +++ b/src/Mod/Arch/OfflineRenderingUtils.py @@ -200,7 +200,7 @@ def getGuiData(filename): """getGuiData(filename): Extract visual data from a saved FreeCAD file. Returns a dictionary ["objectName:dict] where dict contains properties - keys like ShapeColor, Transparency, DiffuseColor or Visibility. If found, + keys like ShapeAppearaance, Transparency, DiffuseColor or Visibility. If found, also contains a GuiCameraSettings key with an iv repr of a coin camera""" guidata = {} @@ -310,7 +310,7 @@ def getStepData(objects,colors): if obj.Name in colors: color = colors[obj.Name] if isinstance(color,tuple): - # this is a ShapeColor. We reformat as a list so it works as a DiffuseColor, + # this is a ShapeAppeaaraance. We reformat as a list so it works as a DiffuseColor, # which is what the exporter expects. DiffuseColor can have either one color, # or the same number of colors as the number of faces color = [color] diff --git a/src/Mod/Arch/importOBJ.py b/src/Mod/Arch/importOBJ.py index b69d6d92a7..70f95f790b 100644 --- a/src/Mod/Arch/importOBJ.py +++ b/src/Mod/Arch/importOBJ.py @@ -242,7 +242,7 @@ def export(exportList,filename,colors=None): outfile.write("usemtl color_" + mn + "\n") materials.append(("color_" + mn,color,0)) elif FreeCAD.GuiUp: - if hasattr(obj.ViewObject,"ShapeColor") and hasattr(obj.ViewObject,"Transparency"): + if hasattr(obj.ViewObject,"ShapeAppearnce") and hasattr(obj.ViewObject,"Transparency"): mn = Draft.getrgb(obj.ViewObject.ShapeColor,testbw=False)[1:] outfile.write("usemtl color_" + mn + "\n") materials.append(("color_" + mn,obj.ViewObject.ShapeColor,obj.ViewObject.Transparency)) diff --git a/src/Mod/CAM/Path/Dressup/Gui/Dogbone.py b/src/Mod/CAM/Path/Dressup/Gui/Dogbone.py index f3b4a8d619..3fb153a2be 100644 --- a/src/Mod/CAM/Path/Dressup/Gui/Dogbone.py +++ b/src/Mod/CAM/Path/Dressup/Gui/Dogbone.py @@ -59,7 +59,7 @@ def debugMarker(vector, label, color=None, radius=0.5): vector, FreeCAD.Rotation(FreeCAD.Vector(0, 0, 1), 0) ) if color: - obj.ViewObject.ShapeColor = color + obj.ViewObject.ShapeAppearance.DiffuseColor = color def debugCircle(vector, r, label, color=None): @@ -73,7 +73,7 @@ def debugCircle(vector, r, label, color=None): ) obj.ViewObject.Transparency = 90 if color: - obj.ViewObject.ShapeColor = color + obj.ViewObject.ShapeAppearance.DiffuseColor = color def addAngle(a1, a2): diff --git a/src/Mod/CAM/Path/Dressup/Gui/ZCorrect.py b/src/Mod/CAM/Path/Dressup/Gui/ZCorrect.py index d4c038c5b4..8de1c58ab2 100644 --- a/src/Mod/CAM/Path/Dressup/Gui/ZCorrect.py +++ b/src/Mod/CAM/Path/Dressup/Gui/ZCorrect.py @@ -231,7 +231,7 @@ class TaskPanel: ) self.interpshape.Shape = obj.interpSurface self.interpshape.ViewObject.Transparency = 60 - self.interpshape.ViewObject.ShapeColor = (1.00000, 1.00000, 0.01961) + self.interpshape.ViewObject.ShapeAppearance.DiffuseColor = (1.00000, 1.00000, 0.01961) self.interpshape.ViewObject.Selectable = False stock = PathUtils.findParentJob(obj).Stock self.interpshape.Placement.Base.z = stock.Shape.BoundBox.ZMax diff --git a/src/Mod/CAM/Path/Dressup/Tags.py b/src/Mod/CAM/Path/Dressup/Tags.py index f9b24ec2d2..52919dc04a 100644 --- a/src/Mod/CAM/Path/Dressup/Tags.py +++ b/src/Mod/CAM/Path/Dressup/Tags.py @@ -83,7 +83,7 @@ def debugMarker(vector, label, color=None, radius=0.5): vector, FreeCAD.Rotation(FreeCAD.Vector(0, 0, 1), 0) ) if color: - obj.ViewObject.ShapeColor = color + obj.ViewObject.ShapeAppearance.DiffuseColor = color def debugCylinder(vector, r, height, label, color=None): @@ -97,7 +97,7 @@ def debugCylinder(vector, r, height, label, color=None): ) obj.ViewObject.Transparency = 90 if color: - obj.ViewObject.ShapeColor = color + obj.ViewObject.ShapeAppearance.DiffuseColor = color def debugCone(vector, r1, r2, height, label, color=None): @@ -112,7 +112,7 @@ def debugCone(vector, r1, r2, height, label, color=None): ) obj.ViewObject.Transparency = 90 if color: - obj.ViewObject.ShapeColor = color + obj.ViewObject.ShapeAppearance.DiffuseColor = color class Tag: diff --git a/src/Mod/CAM/Path/Main/Gui/Fixture.py b/src/Mod/CAM/Path/Main/Gui/Fixture.py index c4d10e0b5b..8f04562810 100644 --- a/src/Mod/CAM/Path/Main/Gui/Fixture.py +++ b/src/Mod/CAM/Path/Main/Gui/Fixture.py @@ -108,7 +108,7 @@ class _ViewProviderFixture: vobj.setEditorMode("DisplayMode", mode) vobj.setEditorMode("BoundingBox", mode) vobj.setEditorMode("Selectable", mode) - vobj.setEditorMode("ShapeColor", mode) + vobj.setEditorMode("ShapeAppearance", mode) vobj.setEditorMode("Transparency", mode) vobj.setEditorMode("Visibility", mode) @@ -129,7 +129,7 @@ class _ViewProviderFixture: vobj.setEditorMode("DisplayMode", mode) vobj.setEditorMode("BoundingBox", mode) vobj.setEditorMode("Selectable", mode) - vobj.setEditorMode("ShapeColor", mode) + vobj.setEditorMode("ShapeAppearance", mode) vobj.setEditorMode("Transparency", mode) vobj.setEditorMode("Visibility", mode) diff --git a/src/Mod/CAM/Path/Main/Gui/Job.py b/src/Mod/CAM/Path/Main/Gui/Job.py index 584fd9d222..67ecb9a147 100644 --- a/src/Mod/CAM/Path/Main/Gui/Job.py +++ b/src/Mod/CAM/Path/Main/Gui/Job.py @@ -94,7 +94,7 @@ class ViewProvider: vobj.setEditorMode("BoundingBox", mode) vobj.setEditorMode("DisplayMode", mode) vobj.setEditorMode("Selectable", mode) - vobj.setEditorMode("ShapeColor", mode) + vobj.setEditorMode("ShapeAppearance", mode) vobj.setEditorMode("Transparency", mode) self.deleteOnReject = True diff --git a/src/Mod/CAM/Path/Main/Gui/Simulator.py b/src/Mod/CAM/Path/Main/Gui/Simulator.py index 0e4b53cf43..98b21d6c5e 100644 --- a/src/Mod/CAM/Path/Main/Gui/Simulator.py +++ b/src/Mod/CAM/Path/Main/Gui/Simulator.py @@ -228,7 +228,7 @@ class PathSimulation: ) self.cutMaterialIn.ViewObject.Proxy = 0 self.cutMaterialIn.ViewObject.show() - self.cutMaterialIn.ViewObject.ShapeColor = (1.0, 0.85, 0.45, 0.0) + self.cutMaterialIn.ViewObject.ShapeAppearance.DiffuseColor = (1.0, 0.85, 0.45, 0.0) else: self.cutMaterial = FreeCAD.ActiveDocument.addObject( "Part::FeaturePython", "CutMaterial" @@ -236,7 +236,7 @@ class PathSimulation: self.cutMaterial.Shape = self.job.Stock.Shape self.cutMaterial.ViewObject.Proxy = 0 self.cutMaterial.ViewObject.show() - self.cutMaterial.ViewObject.ShapeColor = (0.5, 0.25, 0.25, 0.0) + self.cutMaterial.ViewObject.ShapeAppearance.DiffuseColor = (0.5, 0.25, 0.25, 0.0) # Add cut path solid for debug if self.debug: diff --git a/src/Mod/CAM/Path/Op/Gui/Comment.py b/src/Mod/CAM/Path/Op/Gui/Comment.py index 2db5b2468c..160c7d22d9 100644 --- a/src/Mod/CAM/Path/Op/Gui/Comment.py +++ b/src/Mod/CAM/Path/Op/Gui/Comment.py @@ -70,7 +70,7 @@ class _ViewProviderComment: vobj.setEditorMode("DisplayMode", mode) vobj.setEditorMode("BoundingBox", mode) vobj.setEditorMode("Selectable", mode) - vobj.setEditorMode("ShapeColor", mode) + vobj.setEditorMode("ShapeAppearance", mode) vobj.setEditorMode("Transparency", mode) vobj.setEditorMode("Visibility", mode) @@ -91,7 +91,7 @@ class _ViewProviderComment: vobj.setEditorMode("DisplayMode", mode) vobj.setEditorMode("BoundingBox", mode) vobj.setEditorMode("Selectable", mode) - vobj.setEditorMode("ShapeColor", mode) + vobj.setEditorMode("ShapeAppearance", mode) vobj.setEditorMode("Transparency", mode) vobj.setEditorMode("Visibility", mode) diff --git a/src/Mod/CAM/Path/Op/Gui/Stop.py b/src/Mod/CAM/Path/Op/Gui/Stop.py index 92d4efcc12..6133672fbf 100644 --- a/src/Mod/CAM/Path/Op/Gui/Stop.py +++ b/src/Mod/CAM/Path/Op/Gui/Stop.py @@ -77,7 +77,7 @@ class _ViewProviderStop: vobj.setEditorMode("DisplayMode", mode) vobj.setEditorMode("BoundingBox", mode) vobj.setEditorMode("Selectable", mode) - vobj.setEditorMode("ShapeColor", mode) + vobj.setEditorMode("ShapeAppearance", mode) vobj.setEditorMode("Transparency", mode) vobj.setEditorMode("Visibility", mode) @@ -98,7 +98,7 @@ class _ViewProviderStop: vobj.setEditorMode("DisplayMode", mode) vobj.setEditorMode("BoundingBox", mode) vobj.setEditorMode("Selectable", mode) - vobj.setEditorMode("ShapeColor", mode) + vobj.setEditorMode("ShapeAppearance", mode) vobj.setEditorMode("Transparency", mode) vobj.setEditorMode("Visibility", mode) diff --git a/src/Mod/CAM/Path/Tool/Gui/Controller.py b/src/Mod/CAM/Path/Tool/Gui/Controller.py index 420f62e171..3e72b6ee1b 100644 --- a/src/Mod/CAM/Path/Tool/Gui/Controller.py +++ b/src/Mod/CAM/Path/Tool/Gui/Controller.py @@ -59,7 +59,7 @@ class ViewProvider: vobj.setEditorMode("DisplayMode", mode) vobj.setEditorMode("BoundingBox", mode) vobj.setEditorMode("Selectable", mode) - vobj.setEditorMode("ShapeColor", mode) + vobj.setEditorMode("ShapeAppearance", mode) vobj.setEditorMode("Transparency", mode) vobj.setEditorMode("Visibility", mode) self.vobj = vobj diff --git a/src/Mod/Draft/draftfunctions/upgrade.py b/src/Mod/Draft/draftfunctions/upgrade.py index 98c56a3a88..604bd1cfe6 100644 --- a/src/Mod/Draft/draftfunctions/upgrade.py +++ b/src/Mod/Draft/draftfunctions/upgrade.py @@ -227,7 +227,7 @@ def upgrade(objects, delete=False, force=None): # of downgrade, nor do they have the same hashCode(). # Nevertheless, they still keep reference to their original # colors, capture that in facecolors. - # Also, cannot use ShapeColor here, we need a whole array + # Also, cannot use ShapeAppearance here, we need a whole array # matching the colors of the array of faces per object, # only DiffuseColor has that facecolors[0].extend(obj.ViewObject.DiffuseColor) diff --git a/src/Mod/Draft/draftutils/gui_utils.py b/src/Mod/Draft/draftutils/gui_utils.py index 57c21b66f4..ed3d63b046 100644 --- a/src/Mod/Draft/draftutils/gui_utils.py +++ b/src/Mod/Draft/draftutils/gui_utils.py @@ -474,7 +474,7 @@ def format_object(target, origin=None): If construction mode is active target is then placed in the construction group and the `constr` color is applied to its applicable color properties: - TextColor, PointColor, LineColor, and ShapeColor. + TextColor, PointColor, LineColor, and ShapeAppearance. Parameters ---------- diff --git a/src/Mod/Draft/draftutils/utils.py b/src/Mod/Draft/draftutils/utils.py index 4733d95cd6..803b1a601f 100644 --- a/src/Mod/Draft/draftutils/utils.py +++ b/src/Mod/Draft/draftutils/utils.py @@ -88,14 +88,14 @@ def get_default_shape_style(): display_mode_index = params.get_param("DefaultDisplayMode") draw_style_index = params.get_param("DefaultDrawStyle") return { - "DisplayMode": ("index", display_mode_index, DISPLAY_MODES[display_mode_index]), - "DrawStyle": ("index", draw_style_index, DRAW_STYLES[draw_style_index]), - "LineColor": ("color", params.get_param_view("DefaultShapeLineColor")), - "LineWidth": ("int", params.get_param_view("DefaultShapeLineWidth")), - "PointColor": ("color", params.get_param_view("DefaultShapeVertexColor")), - "PointSize": ("int", params.get_param_view("DefaultShapePointSize")), - "ShapeColor": ("color", params.get_param_view("DefaultShapeColor")), - "Transparency": ("int", params.get_param_view("DefaultShapeTransparency")) + "DisplayMode": ("index", display_mode_index, DISPLAY_MODES[display_mode_index]), + "DrawStyle": ("index", draw_style_index, DRAW_STYLES[draw_style_index]), + "LineColor": ("color", params.get_param_view("DefaultShapeLineColor")), + "LineWidth": ("int", params.get_param_view("DefaultShapeLineWidth")), + "PointColor": ("color", params.get_param_view("DefaultShapeVertexColor")), + "PointSize": ("int", params.get_param_view("DefaultShapePointSize")), + "ShapeColor": ("color", params.get_param_view("DefaultShapeColor")), + "Transparency": ("int", params.get_param_view("DefaultShapeTransparency")) } diff --git a/src/Mod/Draft/draftviewproviders/view_layer.py b/src/Mod/Draft/draftviewproviders/view_layer.py index c86eaedf75..064690e9f6 100644 --- a/src/Mod/Draft/draftviewproviders/view_layer.py +++ b/src/Mod/Draft/draftviewproviders/view_layer.py @@ -70,16 +70,16 @@ class ViewProviderLayer: _tip) vobj.OverrideLineColorChildren = True - if "OverrideShapeColorChildren" not in properties: + if "OverrideShapeAppearanceChildren" not in properties: _tip = QT_TRANSLATE_NOOP("App::Property", "If it is true, the objects contained " "within this layer will adopt " "the shape color of the layer") vobj.addProperty("App::PropertyBool", - "OverrideShapeColorChildren", + "OverrideShapeAppearanceChildren", "Layer", _tip) - vobj.OverrideShapeColorChildren = True + vobj.OverrideShapeAppearanceChildren = True if "UsePrintColor" not in properties: _tip = QT_TRANSLATE_NOOP("App::Property", diff --git a/src/Mod/Fem/Gui/ViewProviderFemConstraint.cpp b/src/Mod/Fem/Gui/ViewProviderFemConstraint.cpp index 360bebe908..30323d0961 100644 --- a/src/Mod/Fem/Gui/ViewProviderFemConstraint.cpp +++ b/src/Mod/Fem/Gui/ViewProviderFemConstraint.cpp @@ -59,7 +59,6 @@ ViewProviderFemConstraint::ViewProviderFemConstraint() { ADD_PROPERTY(TextColor, (0.0f, 0.0f, 0.0f)); ADD_PROPERTY(FaceColor, (1.0f, 0.0f, 0.2f)); - ADD_PROPERTY(ShapeColor, (1.0f, 0.0f, 0.2f)); ADD_PROPERTY(FontSize, (18)); ADD_PROPERTY(DistFactor, (1.0)); ADD_PROPERTY(Mirror, (false)); diff --git a/src/Mod/Fem/Gui/ViewProviderFemConstraint.h b/src/Mod/Fem/Gui/ViewProviderFemConstraint.h index f652fa1da6..6f157b9d62 100644 --- a/src/Mod/Fem/Gui/ViewProviderFemConstraint.h +++ b/src/Mod/Fem/Gui/ViewProviderFemConstraint.h @@ -56,7 +56,6 @@ public: // Display properties App::PropertyColor TextColor; App::PropertyColor FaceColor; - App::PropertyColor ShapeColor; App::PropertyInteger FontSize; App::PropertyFloat DistFactor; App::PropertyBool Mirror; diff --git a/src/Mod/Fem/Gui/ViewProviderFemConstraintOnBoundary.cpp b/src/Mod/Fem/Gui/ViewProviderFemConstraintOnBoundary.cpp index 30a09fb79d..4cb062b44a 100644 --- a/src/Mod/Fem/Gui/ViewProviderFemConstraintOnBoundary.cpp +++ b/src/Mod/Fem/Gui/ViewProviderFemConstraintOnBoundary.cpp @@ -69,10 +69,10 @@ void ViewProviderFemConstraintOnBoundary::highlightReferences(const bool on) std::vector colors = originalPointColors[base]; // go through the subelements with constraint and recolor them - // TODO: Replace `ShapeColor` with anything more appropriate - PartGui::ReferenceHighlighter highlighter(base->Shape.getValue(), - colors.empty() ? ShapeColor.getValue() - : colors[0]); + // TODO: Replace `ShapeAppearance` with anything more appropriate + PartGui::ReferenceHighlighter highlighter( + base->Shape.getValue(), + colors.empty() ? ShapeAppearance.getDiffuseColor() : colors[0]); highlighter.getVertexColors(subSet.second, colors); vp->PointColorArray.setValues(colors); } @@ -84,10 +84,10 @@ void ViewProviderFemConstraintOnBoundary::highlightReferences(const bool on) std::vector colors = originalLineColors[base]; // go through the subelements with constraint and recolor them - // TODO: Replace `ShapeColor` with anything more appropriate - PartGui::ReferenceHighlighter highlighter(base->Shape.getValue(), - colors.empty() ? ShapeColor.getValue() - : colors[0]); + // TODO: Replace `ShapeAppearance` with anything more appropriate + PartGui::ReferenceHighlighter highlighter( + base->Shape.getValue(), + colors.empty() ? ShapeAppearance.getDiffuseColor() : colors[0]); highlighter.getEdgeColors(subSet.second, colors); vp->LineColorArray.setValues(colors); } diff --git a/src/Mod/Fem/Gui/ViewProviderFemMesh.cpp b/src/Mod/Fem/Gui/ViewProviderFemMesh.cpp index 97832c4ec5..e2b3dc998c 100644 --- a/src/Mod/Fem/Gui/ViewProviderFemMesh.cpp +++ b/src/Mod/Fem/Gui/ViewProviderFemMesh.cpp @@ -196,7 +196,7 @@ ViewProviderFemMesh::ViewProviderFemMesh() ADD_PROPERTY(LineWidth, (2.0f)); LineWidth.setConstraints(&floatRange); - ShapeColor.setValue(App::Color(1.0f, 0.7f, 0.0f)); + ShapeAppearance.setDiffuseColor(App::Color(1.0f, 0.7f, 0.0f)); Transparency.setValue(0); ADD_PROPERTY(BackfaceCulling, (true)); ADD_PROPERTY(ShowInner, (false)); @@ -597,7 +597,7 @@ void ViewProviderFemMesh::resetColorByNodeId() { pcMatBinding->value = SoMaterialBinding::OVERALL; pcShapeMaterial->diffuseColor.setNum(0); - const App::Color& c = ShapeColor.getValue(); + const App::Color& c = ShapeAppearance.getDiffuseColor(); pcShapeMaterial->diffuseColor.setValue(c.r, c.g, c.b); } @@ -710,7 +710,7 @@ void ViewProviderFemMesh::resetColorByElementId() { pcMatBinding->value = SoMaterialBinding::OVERALL; pcShapeMaterial->diffuseColor.setNum(0); - const App::Color& c = ShapeColor.getValue(); + const App::Color& c = ShapeAppearance.getDiffuseColor(); pcShapeMaterial->diffuseColor.setValue(c.r, c.g, c.b); } diff --git a/src/Mod/Import/App/ImportOCAF.cpp b/src/Mod/Import/App/ImportOCAF.cpp index 40a3177970..8e7710d07a 100644 --- a/src/Mod/Import/App/ImportOCAF.cpp +++ b/src/Mod/Import/App/ImportOCAF.cpp @@ -562,10 +562,10 @@ void ImportXCAF::createShape(const TopoDS_Shape& shape, bool perface, bool setna color.r = jt->second.Red(); color.g = jt->second.Green(); color.b = jt->second.Blue(); - static_cast(vp)->ShapeColor.setValue(color); + static_cast(vp)->ShapeAppearance.setDiffuseColor(color); } - partColor = static_cast(vp)->ShapeColor.getValue(); + partColor = static_cast(vp)->ShapeAppearance.getDiffuseColor(); } #endif diff --git a/src/Mod/Import/Gui/ExportOCAFGui.cpp b/src/Mod/Import/Gui/ExportOCAFGui.cpp index 8d92481c01..b56d1d9688 100644 --- a/src/Mod/Import/Gui/ExportOCAFGui.cpp +++ b/src/Mod/Import/Gui/ExportOCAFGui.cpp @@ -41,7 +41,8 @@ void ExportOCAFGui::findColors(Part::Feature* part, std::vector& col if (vp && vp->isDerivedFrom(PartGui::ViewProviderPartExt::getClassTypeId())) { colors = static_cast(vp)->DiffuseColor.getValues(); if (colors.empty()) { - colors.push_back(static_cast(vp)->ShapeColor.getValue()); + colors.push_back( + static_cast(vp)->ShapeAppearance.getDiffuseColor()); } } } diff --git a/src/Mod/Import/Gui/ImportOCAFGui.cpp b/src/Mod/Import/Gui/ImportOCAFGui.cpp index 99aa445919..cd594a2123 100644 --- a/src/Mod/Import/Gui/ImportOCAFGui.cpp +++ b/src/Mod/Import/Gui/ImportOCAFGui.cpp @@ -50,7 +50,7 @@ void ImportOCAFGui::applyFaceColors(Part::Feature* part, const std::vectorShapeColor.setValue(colors.front()); + vp->ShapeAppearance.setDiffuseColor(colors.front()); vp->Transparency.setValue(100 * colors.front().a); } else { diff --git a/src/Mod/Import/Gui/dxf/ImpExpDxfGui.cpp b/src/Mod/Import/Gui/dxf/ImpExpDxfGui.cpp index 71975dc89c..7c705d06e7 100644 --- a/src/Mod/Import/Gui/dxf/ImpExpDxfGui.cpp +++ b/src/Mod/Import/Gui/dxf/ImpExpDxfGui.cpp @@ -72,7 +72,7 @@ void ImpExpDxfReadGui::ApplyGuiStyles(Part::Feature* object) const App::Color color = ObjectColor(m_entityAttributes.m_Color); view->LineColor.setValue(color); view->PointColor.setValue(color); - view->ShapeColor.setValue(color); + view->ShapeAppearance.setDiffuseColor(color); view->DrawStyle.setValue(GetDrawStyle()); view->Transparency.setValue(0); } diff --git a/src/Mod/Material/App/AppMaterial.cpp b/src/Mod/Material/App/AppMaterial.cpp index b63547925d..ea5b7bf1e1 100644 --- a/src/Mod/Material/App/AppMaterial.cpp +++ b/src/Mod/Material/App/AppMaterial.cpp @@ -36,6 +36,7 @@ #include "ModelPropertyPy.h" #include "ModelPy.h" #include "UUIDsPy.h" +#include "PropertyMaterial.h" namespace Materials { @@ -43,9 +44,9 @@ class Module: public Py::ExtensionModule { public: Module() - : Py::ExtensionModule("Material") + : Py::ExtensionModule("Materials") { - initialize("This module is the Material module."); // register with Python + initialize("This module is the Materials module."); // register with Python } ~Module() override = default; @@ -60,18 +61,18 @@ PyObject* initModule() } // namespace Materials -PyMOD_INIT_FUNC(Material) +PyMOD_INIT_FUNC(Materials) { 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"); - Base::Interpreter().addType(&Materials::UUIDsPy ::Type, module, "UUIDs"); + 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"); + Base::Interpreter().addType(&Materials::UUIDsPy::Type, module, "UUIDs"); // Initialize types @@ -95,5 +96,7 @@ PyMOD_INIT_FUNC(Material) Materials::Material2DArray ::init(); Materials::Material3DArray ::init(); + Materials::PropertyMaterial ::init(); + PyMOD_Return(module); } diff --git a/src/Mod/Material/App/CMakeLists.txt b/src/Mod/Material/App/CMakeLists.txt index 2db2ec775d..81f8543f24 100644 --- a/src/Mod/Material/App/CMakeLists.txt +++ b/src/Mod/Material/App/CMakeLists.txt @@ -20,7 +20,7 @@ include_directories( ) link_directories(${YAML_CPP_LIBRARY_DIR}) -set(Material_LIBS +set(Materials_LIBS ${Boost_LIBRARIES} FreeCADApp ) @@ -28,22 +28,23 @@ set(Material_LIBS include_directories( ${QtConcurrent_INCLUDE_DIRS} ) -list(APPEND Material_LIBS +list(APPEND Materials_LIBS ${QtConcurrent_LIBRARIES} ) if(yaml-cpp_VERSION VERSION_LESS 0.8.0) - list(APPEND Material_LIBS + list(APPEND Materials_LIBS ${YAML_CPP_LIBRARIES} ) else() - list(APPEND Material_LIBS + list(APPEND Materials_LIBS yaml-cpp::yaml-cpp ) endif() generate_from_xml(Array2DPy) generate_from_xml(Array3DPy) +generate_from_xml(MaterialFilterPy) generate_from_xml(MaterialManagerPy) generate_from_xml(MaterialPy) generate_from_xml(ModelManagerPy) @@ -61,6 +62,8 @@ SET(Python_SRCS MaterialManagerPyImpl.cpp MaterialPy.xml MaterialPyImpl.cpp + MaterialFilterPy.xml + MaterialFilterPyImpl.cpp ModelManagerPy.xml ModelManagerPyImpl.cpp ModelPropertyPy.xml @@ -72,7 +75,7 @@ SET(Python_SRCS ) SOURCE_GROUP("Python" FILES ${Python_SRCS}) -SET(Material_SRCS +SET(Materials_SRCS ${Python_SRCS} AppMaterial.cpp FolderTree.h @@ -102,19 +105,21 @@ SET(Material_SRCS ModelUuids.h PreCompiled.cpp PreCompiled.h + PropertyMaterial.cpp + PropertyMaterial.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) + GET_MSVC_PRECOMPILED_SOURCE("PreCompiled.cpp" PCH_SRCS ${Materials_SRCS}) + ADD_MSVC_PRECOMPILED_HEADER(Materials PreCompiled.h PreCompiled.cpp PCH_SRCS) endif(FREECAD_USE_PCH) -add_library(Material SHARED ${Material_SRCS}) -target_link_libraries(Material ${Material_LIBS}) +add_library(Materials SHARED ${Materials_SRCS}) +target_link_libraries(Materials ${Materials_LIBS}) -SET_BIN_DIR(Material Material /Mod/Material) -SET_PYTHON_PREFIX_SUFFIX(Material) +SET_BIN_DIR(Materials Materials /Mod/Material) +SET_PYTHON_PREFIX_SUFFIX(Materials) -INSTALL(TARGETS Material DESTINATION ${CMAKE_INSTALL_LIBDIR}) +INSTALL(TARGETS Materials DESTINATION ${CMAKE_INSTALL_LIBDIR}) diff --git a/src/Mod/Material/App/MaterialFilter.cpp b/src/Mod/Material/App/MaterialFilter.cpp index 03f0e6ba75..2a0450d02b 100644 --- a/src/Mod/Material/App/MaterialFilter.cpp +++ b/src/Mod/Material/App/MaterialFilter.cpp @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (c) 2023 David Carter * + * Copyright (c) 2023-2024 David Carter * * * * This file is part of FreeCAD. * * * @@ -25,7 +25,9 @@ #include +#include "Exceptions.h" #include "MaterialFilter.h" +#include "MaterialManager.h" #include "Materials.h" @@ -56,6 +58,18 @@ bool MaterialFilter::modelIncluded(const std::shared_ptr& material) co return true; } +bool MaterialFilter::modelIncluded(const QString& uuid) const +{ + MaterialManager manager; + try { + auto material = manager.getMaterial(uuid); + return modelIncluded(material); + } + catch (const MaterialNotFound&) { + } + return false; +} + void MaterialFilter::addRequired(const QString& uuid) { // Ignore any uuids already present diff --git a/src/Mod/Material/App/MaterialFilter.h b/src/Mod/Material/App/MaterialFilter.h index d49900f5bc..99ab1d7f3d 100644 --- a/src/Mod/Material/App/MaterialFilter.h +++ b/src/Mod/Material/App/MaterialFilter.h @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (c) 2023 David Carter * + * Copyright (c) 2023-2024 David Carter * * * * This file is part of FreeCAD. * * * @@ -56,9 +56,9 @@ public: { return _includeFolders; } - void setIncludeEmptyFolders(bool include) + void setIncludeEmptyFolders(bool value) { - _includeFolders = include; + _includeFolders = value; } /* Indicates if we should include materials in the older format @@ -80,10 +80,26 @@ public: * Models only need to be included in one set. */ bool modelIncluded(const std::shared_ptr& material) const; + bool modelIncluded(const QString& uuid) const; + /* Add model UUIDs for required models, or models that are both required + * and complete. + */ void addRequired(const QString& uuid); void addRequiredComplete(const QString& uuid); + /* These functions shouldn't normally be called directly. They are + * for use by conversion methods, such as MaterialFilterPy + */ + const QSet* getRequired() const + { + return &_required; + } + const QSet* getRequiredComplete() const + { + return &_requiredComplete; + } + private: bool _includeFolders; bool _includeLegacy; diff --git a/src/Mod/Material/App/MaterialFilterPy.xml b/src/Mod/Material/App/MaterialFilterPy.xml new file mode 100644 index 0000000000..3dbbe10074 --- /dev/null +++ b/src/Mod/Material/App/MaterialFilterPy.xml @@ -0,0 +1,43 @@ + + + + + + Material filters. + + + + Include empty folders in the material list. + + + + + + Include legacy materials in the material list. + + + + + + Materials must include the specified models. + + + + + + Materials must have complete versions of the specified models. + + + + + diff --git a/src/Mod/Material/App/MaterialFilterPyImpl.cpp b/src/Mod/Material/App/MaterialFilterPyImpl.cpp new file mode 100644 index 0000000000..bc8e635c20 --- /dev/null +++ b/src/Mod/Material/App/MaterialFilterPyImpl.cpp @@ -0,0 +1,132 @@ +/*************************************************************************** + * Copyright (c) 2023-2024 David Carter * + * * + * This file is part of FreeCAD. * + * * + * FreeCAD is free software: you can redistribute it and/or modify it * + * under the terms of the GNU Lesser General Public License as * + * published by the Free Software Foundation, either version 2.1 of the * + * License, or (at your option) any later version. * + * * + * FreeCAD is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with FreeCAD. If not, see * + * . * + * * + **************************************************************************/ + +#include "PreCompiled.h" + +#include + +#include +#include +#include +#include + +#include "MaterialFilter.h" + +#include "MaterialFilterPy.h" + +#include "MaterialFilterPy.cpp" + +using namespace Materials; + +// Forward declaration +// static PyObject* _pyObjectFromVariant(const QVariant& value); +// static Py::List getList(const QVariant& value); + +// returns a string which represents the object e.g. when printed in python +std::string MaterialFilterPy::representation() const +{ + std::stringstream str; + str << ""; + + return str.str(); +} + +PyObject* MaterialFilterPy::PyMake(struct _typeobject*, PyObject*, PyObject*) // Python wrapper +{ + // never create such objects with the constructor + return new MaterialFilterPy(new MaterialFilter()); +} + +// constructor method +int MaterialFilterPy::PyInit(PyObject* /*args*/, PyObject* /*kwd*/) +{ + return 0; +} + +Py::Boolean MaterialFilterPy::getIncludeEmptyFolders() const +{ + return {getMaterialFilterPtr()->includeEmptyFolders()}; +} + +void MaterialFilterPy::setIncludeEmptyFolders(const Py::Boolean value) +{ + getMaterialFilterPtr()->setIncludeEmptyFolders(value.isTrue()); +} + +Py::Boolean MaterialFilterPy::getIncludeLegacy() const +{ + return {getMaterialFilterPtr()->includeLegacy()}; +} + +void MaterialFilterPy::setIncludeLegacy(const Py::Boolean value) +{ + getMaterialFilterPtr()->setIncludeLegacy(value.isTrue()); +} + +Py::List MaterialFilterPy::getRequiredModels() const +{ + auto listValue = getMaterialFilterPtr()->getRequired(); + Py::List list; + + for (auto& it : *listValue) { + list.append(Py::String(it.toStdString())); + } + + return list; +} + +void MaterialFilterPy::setRequiredModels(Py::List value) +{ + for (const auto& it : value) { + Py::String uuid(it); + getMaterialFilterPtr()->addRequired(QString::fromStdString(uuid)); + } +} + +Py::List MaterialFilterPy::getRequiredCompleteModels() const +{ + auto listValue = getMaterialFilterPtr()->getRequiredComplete(); + Py::List list; + + for (auto& it : *listValue) { + list.append(Py::String(it.toStdString())); + } + + return list; +} + +void MaterialFilterPy::setRequiredCompleteModels(Py::List value) +{ + for (const auto& it : value) { + Py::String uuid(it); + getMaterialFilterPtr()->addRequiredComplete(QString::fromStdString(uuid)); + } +} + +PyObject* MaterialFilterPy::getCustomAttributes(const char* /*attr*/) const +{ + return nullptr; +} + +int MaterialFilterPy::setCustomAttributes(const char* /*attr*/, PyObject* /*obj*/) +{ + return 0; +} diff --git a/src/Mod/Material/App/MaterialLibrary.cpp b/src/Mod/Material/App/MaterialLibrary.cpp index 87de1c2104..28ffdd27eb 100644 --- a/src/Mod/Material/App/MaterialLibrary.cpp +++ b/src/Mod/Material/App/MaterialLibrary.cpp @@ -21,9 +21,9 @@ #include "PreCompiled.h" #ifndef _PreComp_ -#include #include #include +#include #endif @@ -266,7 +266,7 @@ QString MaterialLibrary::getUUIDFromPath(const QString& path) const } bool MaterialLibrary::materialInTree(const std::shared_ptr& material, - const MaterialFilter* filter) const + const std::shared_ptr& filter) const { if (!filter) { // If there's no filter we always include @@ -283,7 +283,7 @@ bool MaterialLibrary::materialInTree(const std::shared_ptr& material, } std::shared_ptr>> -MaterialLibrary::getMaterialTree(const MaterialFilter* filter) const +MaterialLibrary::getMaterialTree(const std::shared_ptr& filter) const { std::shared_ptr>> materialTree = std::make_shared>>(); diff --git a/src/Mod/Material/App/MaterialLibrary.h b/src/Mod/Material/App/MaterialLibrary.h index 3123d091b9..ec0175743a 100644 --- a/src/Mod/Material/App/MaterialLibrary.h +++ b/src/Mod/Material/App/MaterialLibrary.h @@ -79,7 +79,7 @@ public: std::shared_ptr addMaterial(const std::shared_ptr& material, const QString& path); std::shared_ptr>> - getMaterialTree(const MaterialFilter* filter = nullptr) const; + getMaterialTree(const std::shared_ptr& filter) const; bool isReadOnly() const { @@ -99,7 +99,7 @@ protected: void updatePaths(const QString& oldPath, const QString& newPath); QString getUUIDFromPath(const QString& path) const; bool materialInTree(const std::shared_ptr& material, - const MaterialFilter* filter) const; + const std::shared_ptr& filter) const; bool _readOnly; std::unique_ptr>> _materialPathMap; diff --git a/src/Mod/Material/App/MaterialManager.cpp b/src/Mod/Material/App/MaterialManager.cpp index b1094cba60..b16299c569 100644 --- a/src/Mod/Material/App/MaterialManager.cpp +++ b/src/Mod/Material/App/MaterialManager.cpp @@ -27,12 +27,14 @@ #include #include +#include #include "Exceptions.h" #include "MaterialConfigLoader.h" #include "MaterialLoader.h" #include "MaterialManager.h" #include "ModelManager.h" +#include "ModelUuids.h" using namespace Materials; @@ -108,6 +110,47 @@ bool MaterialManager::isMaterial(const QFileInfo& file) const return false; } +std::shared_ptr MaterialManager::defaultMaterial() +{ + MaterialManager manager; + + ParameterGrp::handle hGrp = + App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/View"); + bool randomColor = hGrp->GetBool("RandomColor", false); + float r, g, b; + + if (randomColor) { + auto fMax = (float)RAND_MAX; + r = (float)rand() / fMax; + g = (float)rand() / fMax; + b = (float)rand() / fMax; + } + else { + unsigned long shcol = hGrp->GetUnsigned("DefaultShapeColor", 3435980543UL); + r = ((shcol >> 24) & 0xff) / 255.0; + g = ((shcol >> 16) & 0xff) / 255.0; + b = ((shcol >> 8) & 0xff) / 255.0; + } + + int initialTransparency = hGrp->GetInt("DefaultShapeTransparency", 0); + + auto material = manager.getMaterial(defaultMaterialUUID()); + if (material->hasAppearanceModel(ModelUUIDs::ModelUUID_Rendering_Basic)) { + material->getAppearanceProperty(QString::fromLatin1("DiffuseColor")) + ->setColor(App::Color(r, g, b)); + material->getAppearanceProperty(QString::fromLatin1("Transparency")) + ->setFloat((float)initialTransparency / 100.0f); + } + + return material; +} + +QString MaterialManager::defaultMaterialUUID() +{ + // Make this a preference + return QString::fromLatin1("7f9fd73b-50c9-41d8-b7b2-575a030c1eeb"); +} + std::shared_ptr MaterialManager::getMaterial(const QString& uuid) const { try { @@ -118,6 +161,13 @@ std::shared_ptr MaterialManager::getMaterial(const QString& uuid) cons } } +std::shared_ptr MaterialManager::getMaterial(const App::Material& material) +{ + MaterialManager manager; + + return manager.getMaterial(QString::fromStdString(material.uuid)); +} + std::shared_ptr MaterialManager::getMaterialByPath(const QString& path) const { QString cleanPath = QDir::cleanPath(path); @@ -126,7 +176,9 @@ std::shared_ptr MaterialManager::getMaterialByPath(const QString& path if (cleanPath.startsWith(library->getDirectory())) { try { return library->getMaterialByPath(cleanPath); - } catch (const MaterialNotFound&) {} + } + catch (const MaterialNotFound&) { + } // See if it's a new file saved by the old editor { diff --git a/src/Mod/Material/App/MaterialManager.h b/src/Mod/Material/App/MaterialManager.h index 400941be6f..ed6926e657 100644 --- a/src/Mod/Material/App/MaterialManager.h +++ b/src/Mod/Material/App/MaterialManager.h @@ -37,6 +37,11 @@ namespace fs = boost::filesystem; +namespace App +{ +class Material; +} + namespace Materials { @@ -50,11 +55,15 @@ public: MaterialManager(); ~MaterialManager() override = default; + static std::shared_ptr defaultMaterial(); + static QString defaultMaterialUUID(); + std::shared_ptr>> getMaterials() const { return _materialMap; } std::shared_ptr getMaterial(const QString& uuid) const; + static std::shared_ptr getMaterial(const App::Material& material); std::shared_ptr getMaterialByPath(const QString& path) const; std::shared_ptr getMaterialByPath(const QString& path, const QString& library) const; std::shared_ptr getParent(const std::shared_ptr& material) const; @@ -66,10 +75,16 @@ public: std::shared_ptr>> getMaterialLibraries() const; std::shared_ptr>> getMaterialTree(const std::shared_ptr& library, - const MaterialFilter* filter = nullptr) const + const std::shared_ptr& filter) const { return library->getMaterialTree(filter); } + std::shared_ptr>> + getMaterialTree(const std::shared_ptr& library) const + { + std::shared_ptr filter; + return library->getMaterialTree(filter); + } std::shared_ptr> getMaterialFolders(const std::shared_ptr& library) const; void createFolder(const std::shared_ptr& library, const QString& path) const diff --git a/src/Mod/Material/App/MaterialPyImpl.cpp b/src/Mod/Material/App/MaterialPyImpl.cpp index 1d7cb75ee8..dacb328875 100644 --- a/src/Mod/Material/App/MaterialPyImpl.cpp +++ b/src/Mod/Material/App/MaterialPyImpl.cpp @@ -103,69 +103,69 @@ int MaterialPy::PyInit(PyObject* /*args*/, PyObject* /*kwd*/) Py::String MaterialPy::getLibraryName() const { auto library = getMaterialPtr()->getLibrary(); - return Py::String(library ? library->getName().toStdString() : ""); + return {library ? library->getName().toStdString() : ""}; } Py::String MaterialPy::getLibraryRoot() const { auto library = getMaterialPtr()->getLibrary(); - return Py::String(library ? library->getDirectoryPath().toStdString() : ""); + return {library ? library->getDirectoryPath().toStdString() : ""}; } Py::String MaterialPy::getLibraryIcon() const { auto library = getMaterialPtr()->getLibrary(); - return Py::String(library ? library->getIconPath().toStdString() : ""); + return {library ? library->getIconPath().toStdString() : ""}; } Py::String MaterialPy::getName() const { - return Py::String(getMaterialPtr()->getName().toStdString()); + return {getMaterialPtr()->getName().toStdString()}; } Py::String MaterialPy::getDirectory() const { - return Py::String(getMaterialPtr()->getDirectory().toStdString()); + return {getMaterialPtr()->getDirectory().toStdString()}; } Py::String MaterialPy::getUUID() const { - return Py::String(getMaterialPtr()->getUUID().toStdString()); + return {getMaterialPtr()->getUUID().toStdString()}; } Py::String MaterialPy::getDescription() const { - return Py::String(getMaterialPtr()->getDescription().toStdString()); + return {getMaterialPtr()->getDescription().toStdString()}; } Py::String MaterialPy::getURL() const { - return Py::String(getMaterialPtr()->getURL().toStdString()); + return {getMaterialPtr()->getURL().toStdString()}; } Py::String MaterialPy::getReference() const { - return Py::String(getMaterialPtr()->getReference().toStdString()); + return {getMaterialPtr()->getReference().toStdString()}; } Py::String MaterialPy::getParent() const { - return Py::String(getMaterialPtr()->getParentUUID().toStdString()); + return {getMaterialPtr()->getParentUUID().toStdString()}; } Py::String MaterialPy::getAuthorAndLicense() const { - return Py::String(getMaterialPtr()->getAuthorAndLicense().toStdString()); + return {getMaterialPtr()->getAuthorAndLicense().toStdString()}; } Py::String MaterialPy::getAuthor() const { - return Py::String(getMaterialPtr()->getAuthor().toStdString()); + return {getMaterialPtr()->getAuthor().toStdString()}; } Py::String MaterialPy::getLicense() const { - return Py::String(getMaterialPtr()->getLicense().toStdString()); + return {getMaterialPtr()->getLicense().toStdString()}; } Py::List MaterialPy::getPhysicalModels() const @@ -173,8 +173,8 @@ Py::List MaterialPy::getPhysicalModels() const auto models = getMaterialPtr()->getPhysicalModels(); Py::List list; - for (auto it = models->begin(); it != models->end(); it++) { - list.append(Py::String(it->toStdString())); + for (auto it : *models) { + list.append(Py::String(it.toStdString())); } return list; @@ -185,8 +185,8 @@ Py::List MaterialPy::getAppearanceModels() const auto models = getMaterialPtr()->getAppearanceModels(); Py::List list; - for (auto it = models->begin(); it != models->end(); it++) { - list.append(Py::String(it->toStdString())); + for (auto it : *models) { + list.append(Py::String(it.toStdString())); } return list; @@ -197,8 +197,8 @@ Py::List MaterialPy::getTags() const auto& tags = getMaterialPtr()->getTags(); Py::List list; - for (auto it = tags.begin(); it != tags.end(); it++) { - list.append(Py::String(it->toStdString())); + for (auto it : tags) { + list.append(Py::String(it.toStdString())); } return list; @@ -298,9 +298,9 @@ Py::Dict MaterialPy::getProperties() const 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; - auto materialProperty = it->second; + for (auto& it : properties) { + QString key = it.first; + auto materialProperty = it.second; if (!materialProperty->isNull()) { auto value = materialProperty->getDictionaryString(); @@ -309,9 +309,9 @@ Py::Dict MaterialPy::getProperties() const } properties = getMaterialPtr()->getAppearanceProperties(); - for (auto it = properties.begin(); it != properties.end(); it++) { - QString key = it->first; - auto materialProperty = it->second; + for (auto& it : properties) { + QString key = it.first; + auto materialProperty = it.second; if (!materialProperty->isNull()) { auto value = materialProperty->getDictionaryString(); @@ -327,9 +327,9 @@ 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; - auto materialProperty = it->second; + for (auto& it : properties) { + QString key = it.first; + auto materialProperty = it.second; if (!materialProperty->isNull()) { auto value = materialProperty->getDictionaryString(); @@ -345,9 +345,9 @@ 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; - auto materialProperty = it->second; + for (auto& it : properties) { + QString key = it.first; + auto materialProperty = it.second; if (!materialProperty->isNull()) { auto value = materialProperty->getDictionaryString(); @@ -425,7 +425,7 @@ PyObject* MaterialPy::getPhysicalValue(PyObject* args) std::static_pointer_cast(property->getMaterialValue()); return new Array2DPy(new Material2DArray(*value)); } - else if (property->getType() == MaterialValue::Array3D) { + if (property->getType() == MaterialValue::Array3D) { auto value = std::static_pointer_cast(property->getMaterialValue()); return new Array3DPy(new Material3DArray(*value)); diff --git a/src/Mod/Material/App/Materials.cpp b/src/Mod/Material/App/Materials.cpp index a0bbc8882c..7ca9f94f97 100644 --- a/src/Mod/Material/App/Materials.cpp +++ b/src/Mod/Material/App/Materials.cpp @@ -34,6 +34,7 @@ #include "MaterialLibrary.h" #include "MaterialManager.h" #include "ModelManager.h" +#include "ModelUuids.h" using namespace Materials; @@ -142,6 +143,32 @@ QString MaterialProperty::getYAMLString() const return _valuePtr->getYAMLString(); } +App::Color MaterialProperty::getColor() const +{ + auto colorString = getValue().toString(); + std::stringstream stream(colorString.toStdString()); + + char c; + stream >> c; // read "(" + float red; + stream >> red; + stream >> c; // "," + float green; + stream >> green; + stream >> c; // "," + float blue; + stream >> blue; + stream >> c; // "," + float alpha = 1.0; + if (c == ',') { + stream >> alpha; + } + + App::Color color(red, green, blue, alpha); + return color; +} + + QString MaterialProperty::getDictionaryString() const { // This method produces a non-localized string. For a localized string use @@ -377,6 +404,13 @@ void MaterialProperty::setURL(const QString& value) _valuePtr->setValue(QVariant(value)); } +void MaterialProperty::setColor(const App::Color& value) +{ + std::stringstream ss; + ss << "(" << value.r << ", " << value.g << ", " << value.b << ", " << value.a << ")"; + _valuePtr->setValue(QVariant(QString::fromStdString(ss.str()))); +} + MaterialProperty& MaterialProperty::operator=(const MaterialProperty& other) { if (this == &other) { @@ -1434,6 +1468,23 @@ Material& Material::operator=(const Material& other) return *this; } +Material& Material::operator=(const App::Material& other) +{ + if (!hasAppearanceModel(ModelUUIDs::ModelUUID_Rendering_Basic)) { + addAppearance(ModelUUIDs::ModelUUID_Rendering_Basic); + } + + getAppearanceProperty(QString::fromLatin1("AmbientColor"))->setColor(other.ambientColor); + getAppearanceProperty(QString::fromLatin1("DiffuseColor"))->setColor(other.diffuseColor); + getAppearanceProperty(QString::fromLatin1("SpecularColor"))->setColor(other.specularColor); + getAppearanceProperty(QString::fromLatin1("EmissiveColor"))->setColor(other.emissiveColor); + getAppearanceProperty(QString::fromLatin1("Shininess"))->setFloat(other.shininess); + getAppearanceProperty(QString::fromLatin1("Transparency"))->setFloat(other.transparency); + // std::string uuid; + + return *this; +} + /* * Normalize models by removing any inherited models */ @@ -1509,3 +1560,50 @@ QStringList Material::inheritedAddedModels(const Material& parent) const */ void Material::inheritedPropertyDiff([[maybe_unused]] const QString& parent) {} + +/* + * Return an App::Material object describing the materials appearance, or DEFAULT if + * undefined. + */ +App::Material Material::getMaterialAppearance() const +{ + App::Material material(App::Material::DEFAULT); + + bool custom = false; + if (hasAppearanceProperty(QString::fromLatin1("AmbientColor"))) { + material.ambientColor = + getAppearanceProperty(QString::fromLatin1("AmbientColor"))->getColor(); + custom = true; + } + if (hasAppearanceProperty(QString::fromLatin1("DiffuseColor"))) { + material.diffuseColor = + getAppearanceProperty(QString::fromLatin1("DiffuseColor"))->getColor(); + custom = true; + } + if (hasAppearanceProperty(QString::fromLatin1("SpecularColor"))) { + material.specularColor = + getAppearanceProperty(QString::fromLatin1("SpecularColor"))->getColor(); + custom = true; + } + if (hasAppearanceProperty(QString::fromLatin1("EmissiveColor"))) { + material.emissiveColor = + getAppearanceProperty(QString::fromLatin1("EmissiveColor"))->getColor(); + custom = true; + } + if (hasAppearanceProperty(QString::fromLatin1("Shininess"))) { + material.shininess = getAppearanceProperty(QString::fromLatin1("Shininess"))->getFloat(); + custom = true; + } + if (hasAppearanceProperty(QString::fromLatin1("Transparency"))) { + material.transparency = + getAppearanceProperty(QString::fromLatin1("Transparency"))->getFloat(); + custom = true; + } + + if (custom) { + material.setType(App::Material::USER_DEFINED); + material.uuid = getUUID().toStdString(); + } + + return material; +} \ No newline at end of file diff --git a/src/Mod/Material/App/Materials.h b/src/Mod/Material/App/Materials.h index d1cd5d0e09..bdc10dca23 100644 --- a/src/Mod/Material/App/Materials.h +++ b/src/Mod/Material/App/Materials.h @@ -31,6 +31,8 @@ #include #include +#include +#include #include #include @@ -79,11 +81,24 @@ public: QString getString() const; QString getYAMLString() const; QString getDictionaryString() const; // Non-localized string - bool getBoolean() const; - int getInt() const; - double getFloat() const; + bool getBoolean() const + { + return getValue().toBool(); + } + int getInt() const + { + return getValue().toInt(); + } + double getFloat() const + { + return getValue().toFloat(); + } const Base::Quantity& getQuantity() const; - const QString getURL() const; + QString getURL() const + { + return getValue().toString(); + } + App::Color getColor() const; MaterialProperty& getColumn(int column); const MaterialProperty& getColumn(int column) const; @@ -109,6 +124,7 @@ public: void setQuantity(const QString& value); void setList(const QList& value); void setURL(const QString& value); + void setColor(const App::Color& value); MaterialProperty& operator=(const MaterialProperty& other); friend QTextStream& operator<<(QTextStream& output, const MaterialProperty& property); @@ -218,6 +234,8 @@ public: return &_appearanceUuids; } + App::Material getMaterialAppearance() const; + void setLibrary(const std::shared_ptr& library) { _library = library; @@ -365,8 +383,24 @@ public: void save(QTextStream& stream, bool overwrite, bool saveAsCopy, bool saveInherited); + /* + * Assignment operator + */ Material& operator=(const Material& other); + /* + * Set the appearance properties + */ + Material& operator=(const App::Material& other); + + bool operator==(const Material& other) const + { + if (&other == this) { + return true; + } + return getTypeId() == other.getTypeId() && _uuid == other._uuid; + } + protected: void addModel(const QString& uuid); static void removeUUID(QSet& uuidList, const QString& uuid); diff --git a/src/Mod/Material/App/ModelPropertyPy.xml b/src/Mod/Material/App/ModelPropertyPy.xml index cffb548f8b..ebe7a5d136 100644 --- a/src/Mod/Material/App/ModelPropertyPy.xml +++ b/src/Mod/Material/App/ModelPropertyPy.xml @@ -15,11 +15,6 @@ Material property descriptions. - Property name. diff --git a/src/Mod/Material/App/PropertyMaterial.cpp b/src/Mod/Material/App/PropertyMaterial.cpp new file mode 100644 index 0000000000..3434b769bb --- /dev/null +++ b/src/Mod/Material/App/PropertyMaterial.cpp @@ -0,0 +1,119 @@ +/*************************************************************************** + * Copyright (c) 2023 David Carter * + * * + * This file is part of FreeCAD. * + * * + * FreeCAD is free software: you can redistribute it and/or modify it * + * under the terms of the GNU Lesser General Public License as * + * published by the Free Software Foundation, either version 2.1 of the * + * License, or (at your option) any later version. * + * * + * FreeCAD is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with FreeCAD. If not, see * + * . * + * * + **************************************************************************/ + +#include "PreCompiled.h" +#ifndef _PreComp_ +#include +#include +#endif + + +#include +#include +#include + +#include "MaterialPy.h" +#include "PropertyMaterial.h" + +using namespace Materials; + +/* TRANSLATOR Material::PropertyMaterial */ + +TYPESYSTEM_SOURCE(Materials::PropertyMaterial, App::Property) + +PropertyMaterial::PropertyMaterial() = default; + +PropertyMaterial::~PropertyMaterial() = default; + +void PropertyMaterial::setValue(const Material& mat) +{ + aboutToSetValue(); + _material = mat; + hasSetValue(); +} + +void PropertyMaterial::setValue(const App::Material& mat) +{ + aboutToSetValue(); + _material = mat; + hasSetValue(); +} + +const Material& PropertyMaterial::getValue() const +{ + return _material; +} + +PyObject* PropertyMaterial::getPyObject() +{ + return new MaterialPy(new Material(_material)); +} + +void PropertyMaterial::setPyObject(PyObject* value) +{ + if (PyObject_TypeCheck(value, &(MaterialPy::Type))) { + setValue(*static_cast(value)->getMaterialPtr()); + } + else { + std::string error = std::string("type must be 'Material' not "); + error += value->ob_type->tp_name; + throw Base::TypeError(error); + } +} + +void PropertyMaterial::Save(Base::Writer& writer) const +{ + writer.Stream() << writer.ind() << "" << std::endl; +} + +void PropertyMaterial::Restore(Base::XMLReader& reader) +{ + // read my Element + reader.readElement("PropertyMaterial"); + // get the value of my Attribute + aboutToSetValue(); + auto uuid = reader.getAttribute("uuid"); + _material.setUUID(QString::fromLatin1(uuid)); + hasSetValue(); +} + +const char* PropertyMaterial::getEditorName() const +{ + if (testStatus(MaterialEdit)) { + return ""; //"Gui::PropertyEditor::PropertyMaterialItem"; + } + return ""; +} + +App::Property* PropertyMaterial::Copy() const +{ + PropertyMaterial* p = new PropertyMaterial(); + p->_material = _material; + return p; +} + +void PropertyMaterial::Paste(const App::Property& from) +{ + aboutToSetValue(); + _material = dynamic_cast(from)._material; + hasSetValue(); +} diff --git a/src/Mod/Material/App/PropertyMaterial.h b/src/Mod/Material/App/PropertyMaterial.h new file mode 100644 index 0000000000..ac0c2f9043 --- /dev/null +++ b/src/Mod/Material/App/PropertyMaterial.h @@ -0,0 +1,101 @@ +/*************************************************************************** + * Copyright (c) 2023-2024 David Carter * + * * + * This file is part of FreeCAD. * + * * + * FreeCAD is free software: you can redistribute it and/or modify it * + * under the terms of the GNU Lesser General Public License as * + * published by the Free Software Foundation, either version 2.1 of the * + * License, or (at your option) any later version. * + * * + * FreeCAD is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with FreeCAD. If not, see * + * . * + * * + **************************************************************************/ + +#ifndef MATERIAL_PROPERTYMATERIAL_H +#define MATERIAL_PROPERTYMATERIAL_H + +#include +#include + +#include "Materials.h" + +namespace App +{ +class Material; +} + +namespace Materials +{ + +/** Material properties + * This is the father of all properties handling colors. + */ +class MaterialsExport PropertyMaterial: public App::Property +{ + TYPESYSTEM_HEADER_WITH_OVERRIDE(); + +public: + /** + * A constructor. + * A more elaborate description of the constructor. + */ + PropertyMaterial(); + + /** + * A destructor. + * A more elaborate description of the destructor. + */ + ~PropertyMaterial() override; + + /** Sets the property + */ + void setValue(const Material& mat); + + /** Sets the appearance properties + */ + void setValue(const App::Material& mat); + + /** This method returns a string representation of the property + */ + const Material& getValue() const; + + PyObject* getPyObject() override; + void setPyObject(PyObject*) override; + + void Save(Base::Writer& writer) const override; + void Restore(Base::XMLReader& reader) override; + + const char* getEditorName() const override; + + Property* Copy() const override; + void Paste(const Property& from) override; + + unsigned int getMemSize() const override + { + return sizeof(_material); + } + + bool isSame(const Property& other) const override + { + if (&other == this) { + return true; + } + return getTypeId() == other.getTypeId() + && getValue() == static_cast(&other)->getValue(); + } + +private: + Material _material; +}; + +} // namespace Materials + +#endif // MATERIAL_PROPERTYMATERIAL_H diff --git a/src/Mod/Material/CMakeLists.txt b/src/Mod/Material/CMakeLists.txt index 778f516b7c..827799c9e3 100644 --- a/src/Mod/Material/CMakeLists.txt +++ b/src/Mod/Material/CMakeLists.txt @@ -34,6 +34,7 @@ SET(Material_Icon_Files # collect all the material cards: SET(MaterialLib_Files + Resources/Materials/Standard/Default.FCMat Resources/Materials/Standard/Aggregate/Concrete-EN-C35_45.FCMat Resources/Materials/Standard/Aggregate/Concrete-Generic.FCMat Resources/Materials/Standard/Aggregate/Reinforcement-FIB-B500.FCMat diff --git a/src/Mod/Material/Gui/CMakeLists.txt b/src/Mod/Material/Gui/CMakeLists.txt index 9c3fb817ad..33c34592df 100644 --- a/src/Mod/Material/Gui/CMakeLists.txt +++ b/src/Mod/Material/Gui/CMakeLists.txt @@ -19,8 +19,9 @@ include_directories( link_directories(${OCC_LIBRARY_DIR}) set(MatGui_LIBS - Material + Materials FreeCADGui + Part ) include_directories( @@ -39,6 +40,8 @@ qt_add_resources(MatGui_QRC_SRCS Resources/Material.qrc ${Material_TR_QRC}) set(MatGui_UIC_SRCS Array2D.ui Array3D.ui + DlgDisplayProperties.ui + DlgMaterial.ui DlgSettingsMaterial.ui ImageEdit.ui ListEdit.ui @@ -67,6 +70,15 @@ SET(MatGui_SRCS BaseDelegate.cpp BaseDelegate.h Command.cpp + DlgDisplayPropertiesImp.cpp + DlgDisplayPropertiesImp.h + DlgDisplayProperties.ui + DlgMaterialImp.cpp + DlgMaterialImp.h + DlgDisplayProperties.ui + DlgMaterialImp.cpp + DlgMaterialImp.h + DlgMaterial.ui DlgSettingsMaterial.cpp DlgSettingsMaterial.h DlgSettingsMaterial.ui @@ -88,6 +100,8 @@ SET(MatGui_SRCS MaterialsEditor.cpp MaterialsEditor.h MaterialsEditor.ui + MaterialTreeWidget.cpp + MaterialTreeWidget.h ModelSelect.cpp ModelSelect.h ModelSelect.ui diff --git a/src/Mod/Material/Gui/Command.cpp b/src/Mod/Material/Gui/Command.cpp index 33e13c24db..b6d7fbbc66 100644 --- a/src/Mod/Material/Gui/Command.cpp +++ b/src/Mod/Material/Gui/Command.cpp @@ -25,8 +25,12 @@ #endif #include +#include #include +#include +#include "DlgDisplayPropertiesImp.h" +#include "DlgMaterialImp.h" #include "MaterialSave.h" #include "MaterialsEditor.h" #include "ModelSelect.h" @@ -71,6 +75,64 @@ bool CmdMaterialsEdit::isActive() return true; } +//=========================================================================== +// Std_SetAppearance +//=========================================================================== +DEF_STD_CMD_A(StdCmdSetAppearance) + +StdCmdSetAppearance::StdCmdSetAppearance() + : Command("Std_SetAppearance") +{ + sGroup = "Standard-View"; + sMenuText = QT_TR_NOOP("Appearance..."); + sToolTipText = QT_TR_NOOP("Sets the display properties of the selected object"); + sWhatsThis = "Std_SetAppearance"; + sStatusTip = QT_TR_NOOP("Sets the display properties of the selected object"); + sPixmap = "Std_SetAppearance"; + sAccel = "Ctrl+D"; + eType = Alter3DView; +} + +void StdCmdSetAppearance::activated(int iMsg) +{ + Q_UNUSED(iMsg); + Gui::Control().showDialog(new MatGui::TaskDisplayProperties()); +} + +bool StdCmdSetAppearance::isActive() +{ + return (Gui::Control().activeDialog() == nullptr) && (Gui::Selection().size() != 0); +} + +//=========================================================================== +// Std_SetMaterial +//=========================================================================== +DEF_STD_CMD_A(StdCmdSetMaterial) + +StdCmdSetMaterial::StdCmdSetMaterial() + : Command("Std_SetMaterial") +{ + sGroup = "Standard-View"; + sMenuText = QT_TR_NOOP("Material..."); + sToolTipText = QT_TR_NOOP("Sets the material of the selected object"); + sWhatsThis = "Std_SetMaterial"; + sStatusTip = QT_TR_NOOP("Sets the material of the selected object"); + sPixmap = "Materials_Edit"; + // sAccel = "Ctrl+D"; + // eType = Alter3DView; +} + +void StdCmdSetMaterial::activated(int iMsg) +{ + Q_UNUSED(iMsg); + Gui::Control().showDialog(new MatGui::TaskMaterial()); +} + +bool StdCmdSetMaterial::isActive() +{ + return (Gui::Control().activeDialog() == nullptr) && (Gui::Selection().size() != 0); +} + //--------------------------------------------------------------- void CreateMaterialCommands() @@ -78,4 +140,6 @@ void CreateMaterialCommands() Gui::CommandManager& rcCmdMgr = Gui::Application::Instance->commandManager(); rcCmdMgr.addCommand(new CmdMaterialsEdit()); + rcCmdMgr.addCommand(new StdCmdSetAppearance()); + rcCmdMgr.addCommand(new StdCmdSetMaterial()); } diff --git a/src/Gui/DlgDisplayProperties.ui b/src/Mod/Material/Gui/DlgDisplayProperties.ui similarity index 95% rename from src/Gui/DlgDisplayProperties.ui rename to src/Mod/Material/Gui/DlgDisplayProperties.ui index 091769dc74..b01b754dab 100644 --- a/src/Gui/DlgDisplayProperties.ui +++ b/src/Mod/Material/Gui/DlgDisplayProperties.ui @@ -1,7 +1,7 @@ - Gui::Dialog::DlgDisplayProperties - + MatGui::DlgDisplayProperties + 0 @@ -100,108 +100,6 @@ - - - - Material - - - - - - 6 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - - - - 0 - 0 - - - - - 40 - 32767 - - - - ... - - - - - - - - - - - Color plot: - - - - - - - ... - - - - - - - Shape color: - - - - - - - - - - - - - - Line color: - - - - - - - - - - Point color: - - - - - - - - - - - @@ -434,6 +332,101 @@ + + + + Material + + + + + + 6 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + + Color plot: + + + + + + + Shape Appearance: + + + + + + + + + + Point color: + + + + + + + Line color: + + + + + + + ... + + + + + + + + + + + 0 + 0 + + + + + 40 + 32767 + + + + ... + + + + + + + + + + + @@ -443,13 +436,16 @@ QPushButton
Gui/Widgets.h
+ + MatGui::MaterialTreeWidget + QWidget +
Mod/Material/Gui/MaterialTreeWidget.h
+ 1 +
changeMode changePlot - changeMaterial - buttonUserDefinedMaterial - buttonColor buttonLineColor spinPointSize spinLineWidth diff --git a/src/Gui/DlgDisplayPropertiesImp.cpp b/src/Mod/Material/Gui/DlgDisplayPropertiesImp.cpp similarity index 63% rename from src/Gui/DlgDisplayPropertiesImp.cpp rename to src/Mod/Material/Gui/DlgDisplayPropertiesImp.cpp index 92eefcaea0..dc367c2c1c 100644 --- a/src/Gui/DlgDisplayPropertiesImp.cpp +++ b/src/Mod/Material/Gui/DlgDisplayPropertiesImp.cpp @@ -1,647 +1,700 @@ -/*************************************************************************** - * Copyright (c) 2002 Jürgen Riegel * - * * - * 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" -#ifndef _PreComp_ -# include -# include -# include -# include -#endif - -#include - -#include "DlgDisplayPropertiesImp.h" -#include "ui_DlgDisplayProperties.h" -#include "Application.h" -#include "Document.h" -#include "DlgMaterialPropertiesImp.h" -#include "DockWindowManager.h" -#include "Selection.h" -#include "ViewProvider.h" -#include "WaitCursor.h" - - -using namespace Gui::Dialog; -using namespace std; -namespace sp = std::placeholders; - - -/* TRANSLATOR Gui::Dialog::DlgDisplayPropertiesImp */ - -#if 0 // needed for Qt's lupdate utility - qApp->translate("QDockWidget", "Display properties"); -#endif - -class DlgDisplayPropertiesImp::Private -{ - using DlgDisplayPropertiesImp_Connection = boost::signals2::connection; -public: - Ui::DlgDisplayProperties ui; - bool floating; - DlgDisplayPropertiesImp_Connection connectChangedObject; - - static void setElementColor(const std::vector& views, const char* property, Gui::ColorButton* buttonColor) - { - bool hasElementColor = false; - for (const auto & view : views) { - if (auto* prop = dynamic_cast(view->getPropertyByName(property))) { - App::Color color = prop->getValue(); - QSignalBlocker block(buttonColor); - buttonColor->setColor(color.asValue()); - hasElementColor = true; - break; - } - } - - buttonColor->setEnabled(hasElementColor); - } - - static void setDrawStyle(const std::vector& views, const char* property, QSpinBox* spinbox) - { - bool hasDrawStyle = false; - for (const auto & view : views) { - if (auto* prop = dynamic_cast(view->getPropertyByName(property))) { - QSignalBlocker block(spinbox); - spinbox->setValue(int(prop->getValue())); - hasDrawStyle = true; - break; - } - } - - spinbox->setEnabled(hasDrawStyle); - } - - static void setTransparency(const std::vector& views, const char* property, QSpinBox* spinbox, QSlider* slider) - { - bool hasTransparency = false; - for (const auto & view : views) { - if (auto* prop = dynamic_cast(view->getPropertyByName(property))) { - QSignalBlocker blockSpinBox(spinbox); - spinbox->setValue(prop->getValue()); - - QSignalBlocker blockSlider(slider); - slider->setValue(prop->getValue()); - hasTransparency = true; - break; - } - } - - spinbox->setEnabled(hasTransparency); - slider->setEnabled(hasTransparency); - } -}; - -/** - * Constructs a DlgDisplayPropertiesImp which is a child of 'parent', with the - * name 'name' and widget flags set to 'f' - * - * The dialog will by default be modeless, unless you set 'modal' to - * true to construct a modal dialog. - */ -DlgDisplayPropertiesImp::DlgDisplayPropertiesImp(bool floating, QWidget* parent, Qt::WindowFlags fl) - : QDialog( parent, fl ) - , d(new Private) -{ - d->ui.setupUi(this); - setupConnections(); - - d->ui.textLabel1_3->hide(); - d->ui.changePlot->hide(); - d->ui.buttonLineColor->setModal(false); - d->ui.buttonPointColor->setModal(false); - d->ui.buttonColor->setModal(false); - d->floating = floating; - - std::vector views = getSelection(); - setDisplayModes(views); - fillupMaterials(); - setMaterial(views); - setColorPlot(views); - setShapeColor(views); - setLineColor(views); - setPointColor(views); - setPointSize(views); - setLineWidth(views); - setTransparency(views); - setLineTransparency(views); - - // embed this dialog into a dockable widget container - if (floating) { - Gui::DockWindowManager* pDockMgr = Gui::DockWindowManager::instance(); - QDockWidget* dw = pDockMgr->addDockWindow("Display properties", this, Qt::AllDockWidgetAreas); - dw->setFeatures(QDockWidget::DockWidgetMovable|QDockWidget::DockWidgetFloatable); - dw->setFloating(true); - dw->show(); - } - - Gui::Selection().Attach(this); - - //NOLINTBEGIN - d->connectChangedObject = - Gui::Application::Instance->signalChangedObject.connect(std::bind - (&DlgDisplayPropertiesImp::slotChangedObject, this, sp::_1, sp::_2)); - //NOLINTEND -} - -/** - * Destroys the object and frees any allocated resources - */ -DlgDisplayPropertiesImp::~DlgDisplayPropertiesImp() -{ - // no need to delete child widgets, Qt does it all for us - d->connectChangedObject.disconnect(); - Gui::Selection().Detach(this); -} - -void DlgDisplayPropertiesImp::setupConnections() -{ -#if QT_VERSION < QT_VERSION_CHECK(5,14,0) - connect(d->ui.changeMode, qOverload(&QComboBox::activated), this, &DlgDisplayPropertiesImp::onChangeModeActivated); - connect(d->ui.changePlot, qOverload(&QComboBox::activated), this, &DlgDisplayPropertiesImp::onChangePlotActivated); -#else - connect(d->ui.changeMode, &QComboBox::textActivated, this, &DlgDisplayPropertiesImp::onChangeModeActivated); - connect(d->ui.changePlot, &QComboBox::textActivated, this, &DlgDisplayPropertiesImp::onChangePlotActivated); -#endif - connect(d->ui.changeMaterial, qOverload(&QComboBox::activated), this, &DlgDisplayPropertiesImp::onChangeMaterialActivated); - connect(d->ui.buttonColor, &ColorButton::changed, this, &DlgDisplayPropertiesImp::onButtonColorChanged); - connect(d->ui.spinTransparency, qOverload(&QSpinBox::valueChanged), this, &DlgDisplayPropertiesImp::onSpinTransparencyValueChanged); - connect(d->ui.spinPointSize, qOverload(&QSpinBox::valueChanged), this, &DlgDisplayPropertiesImp::onSpinPointSizeValueChanged); - connect(d->ui.buttonLineColor, &ColorButton::changed, this, &DlgDisplayPropertiesImp::onButtonLineColorChanged); - connect(d->ui.buttonPointColor, &ColorButton::changed, this, &DlgDisplayPropertiesImp::onButtonPointColorChanged); - connect(d->ui.spinLineWidth, qOverload(&QSpinBox::valueChanged), this, &DlgDisplayPropertiesImp::onSpinLineWidthValueChanged); - connect(d->ui.spinLineTransparency, qOverload(&QSpinBox::valueChanged), this, &DlgDisplayPropertiesImp::onSpinLineTransparencyValueChanged); - connect(d->ui.buttonUserDefinedMaterial, &ColorButton::clicked, this, &DlgDisplayPropertiesImp::onButtonUserDefinedMaterialClicked); - connect(d->ui.buttonColorPlot, &ColorButton::clicked, this, &DlgDisplayPropertiesImp::onButtonColorPlotClicked); -} - -void DlgDisplayPropertiesImp::changeEvent(QEvent *e) -{ - if (e->type() == QEvent::LanguageChange) { - d->ui.retranslateUi(this); - } - QDialog::changeEvent(e); -} - -/// @cond DOXERR -void DlgDisplayPropertiesImp::OnChange(Gui::SelectionSingleton::SubjectType &rCaller, - Gui::SelectionSingleton::MessageType Reason) -{ - Q_UNUSED(rCaller); - if (Reason.Type == SelectionChanges::AddSelection || - Reason.Type == SelectionChanges::RmvSelection || - Reason.Type == SelectionChanges::SetSelection || - Reason.Type == SelectionChanges::ClrSelection) { - std::vector views = getSelection(); - setDisplayModes(views); - setMaterial(views); - setColorPlot(views); - setShapeColor(views); - setLineColor(views); - setPointColor(views); - setPointSize(views); - setLineWidth(views); - setTransparency(views); - setLineTransparency(views); - } -} -/// @endcond - -void DlgDisplayPropertiesImp::slotChangedObject(const Gui::ViewProvider& obj, - const App::Property& prop) -{ - // This method gets called if a property of any view provider is changed. - // We pick out all the properties for which we need to update this dialog. - std::vector Provider = getSelection(); - auto vp = std::find_if(Provider.begin(), - Provider.end(), - [&obj](Gui::ViewProvider* v) { return v == &obj; }); - - if (vp != Provider.end()) { - const char* name = obj.getPropertyName(&prop); - // this is not a property of the view provider but of the document object - if (!name) - return; - std::string prop_name = name; - if (prop.is()) { - App::Color value = static_cast(prop).getValue(); - if (prop_name == "ShapeColor") { - bool blocked = d->ui.buttonColor->blockSignals(true); - d->ui.buttonColor->setColor(QColor((int)(255.0f * value.r), - (int)(255.0f * value.g), - (int)(255.0f * value.b))); - d->ui.buttonColor->blockSignals(blocked); - } - else if (prop_name == "LineColor") { - bool blocked = d->ui.buttonLineColor->blockSignals(true); - d->ui.buttonLineColor->setColor(QColor((int)(255.0f * value.r), - (int)(255.0f * value.g), - (int)(255.0f * value.b))); - d->ui.buttonLineColor->blockSignals(blocked); - } - else if (prop_name == "PointColor") { - bool blocked = d->ui.buttonPointColor->blockSignals(true); - d->ui.buttonPointColor->setColor(QColor((int)(255.0f * value.r), - (int)(255.0f * value.g), - (int)(255.0f * value.b))); - d->ui.buttonPointColor->blockSignals(blocked); - } - } - else if (prop.isDerivedFrom()) { - long value = static_cast(prop).getValue(); - if (prop_name == "Transparency") { - bool blocked = d->ui.spinTransparency->blockSignals(true); - d->ui.spinTransparency->setValue(value); - d->ui.spinTransparency->blockSignals(blocked); - blocked = d->ui.horizontalSlider->blockSignals(true); - d->ui.horizontalSlider->setValue(value); - d->ui.horizontalSlider->blockSignals(blocked); - } - else if (prop_name == "LineTransparency") { - bool blocked = d->ui.spinLineTransparency->blockSignals(true); - d->ui.spinLineTransparency->setValue(value); - d->ui.spinLineTransparency->blockSignals(blocked); - blocked = d->ui.sliderLineTransparency->blockSignals(true); - d->ui.sliderLineTransparency->setValue(value); - d->ui.sliderLineTransparency->blockSignals(blocked); - } - } - else if (prop.isDerivedFrom()) { - double value = static_cast(prop).getValue(); - if (prop_name == "PointSize") { - bool blocked = d->ui.spinPointSize->blockSignals(true); - d->ui.spinPointSize->setValue((int)value); - d->ui.spinPointSize->blockSignals(blocked); - } - else if (prop_name == "LineWidth") { - bool blocked = d->ui.spinLineWidth->blockSignals(true); - d->ui.spinLineWidth->setValue((int)value); - d->ui.spinLineWidth->blockSignals(blocked); - } - } - } -} - -/** - * Destroys the dock window this object is embedded into without destroying itself. - */ -void DlgDisplayPropertiesImp::reject() -{ - if (d->floating) { - // closes the dock window - Gui::DockWindowManager* pDockMgr = Gui::DockWindowManager::instance(); - pDockMgr->removeDockWindow(this); - } - QDialog::reject(); -} - -/** - * Opens a dialog that allows to modify the 'ShapeMaterial' property of all selected view providers. - */ -void DlgDisplayPropertiesImp::onButtonUserDefinedMaterialClicked() -{ - std::vector Provider = getSelection(); - DlgMaterialPropertiesImp dlg("ShapeMaterial", this); - dlg.setViewProviders(Provider); - dlg.exec(); - - d->ui.buttonColor->setColor(dlg.diffuseColor()); -} - -/** - * Opens a dialog that allows to modify the 'ShapeMaterial' property of all selected view providers. - */ -void DlgDisplayPropertiesImp::onButtonColorPlotClicked() -{ - std::vector Provider = getSelection(); - static QPointer dlg = nullptr; - if (!dlg) - dlg = new DlgMaterialPropertiesImp("TextureMaterial", this); - dlg->setModal(false); - dlg->setAttribute(Qt::WA_DeleteOnClose); - dlg->setViewProviders(Provider); - dlg->show(); -} - -/** - * Sets the 'ShapeMaterial' property of all selected view providers. - */ -void DlgDisplayPropertiesImp::onChangeMaterialActivated(int index) -{ - std::vector Provider = getSelection(); - App::Material::MaterialType matType = static_cast(d->ui.changeMaterial->itemData(index).toInt()); - App::Material mat(matType); - App::Color diffuseColor = mat.diffuseColor; - d->ui.buttonColor->setColor(QColor((int)(diffuseColor.r*255.0f), - (int)(diffuseColor.g*255.0f), - (int)(diffuseColor.b*255.0f))); - - for (auto it : Provider) { - if (auto* prop = dynamic_cast(it->getPropertyByName("ShapeMaterial"))) { - prop->setValue(mat); - } - } -} - -/** - * Sets the 'Display' property of all selected view providers. - */ -void DlgDisplayPropertiesImp::onChangeModeActivated(const QString& s) -{ - Gui::WaitCursor wc; - std::vector Provider = getSelection(); - for (auto it : Provider) { - if (auto* prop = dynamic_cast(it->getPropertyByName("DisplayMode"))) { - prop->setValue(static_cast(s.toLatin1())); - } - } -} - -void DlgDisplayPropertiesImp::onChangePlotActivated(const QString&s) -{ - Base::Console().Log("Plot = %s\n",(const char*)s.toLatin1()); -} - -/** - * Sets the 'ShapeColor' property of all selected view providers. - */ -void DlgDisplayPropertiesImp::onButtonColorChanged() -{ - std::vector Provider = getSelection(); - QColor s = d->ui.buttonColor->color(); - App::Color c(s.red() / 255.0, s.green() / 255.0, s.blue() / 255.0); - for (auto it : Provider) { - if (auto* prop = dynamic_cast(it->getPropertyByName("ShapeColor"))) { - prop->setValue(c); - } - } -} - -/** - * Sets the 'Transparency' property of all selected view providers. - */ -void DlgDisplayPropertiesImp::onSpinTransparencyValueChanged(int transparency) -{ - std::vector Provider = getSelection(); - for (auto it : Provider) { - if (auto* prop = dynamic_cast(it->getPropertyByName("Transparency"))) { - prop->setValue(transparency); - } - } -} - -/** - * Sets the 'PointSize' property of all selected view providers. - */ -void DlgDisplayPropertiesImp::onSpinPointSizeValueChanged(int pointsize) -{ - std::vector Provider = getSelection(); - for (auto it : Provider) { - if (auto* prop = dynamic_cast(it->getPropertyByName("PointSize"))) { - prop->setValue(static_cast(pointsize)); - } - } -} - -/** - * Sets the 'LineWidth' property of all selected view providers. - */ -void DlgDisplayPropertiesImp::onSpinLineWidthValueChanged(int linewidth) -{ - std::vector Provider = getSelection(); - for (auto it : Provider) { - if (auto* prop = dynamic_cast(it->getPropertyByName("LineWidth"))) { - prop->setValue(static_cast(linewidth)); - } - } -} - -void DlgDisplayPropertiesImp::onButtonLineColorChanged() -{ - std::vector Provider = getSelection(); - QColor s = d->ui.buttonLineColor->color(); - App::Color c(s.red() / 255.0, s.green() / 255.0, s.blue() / 255.0); - for (auto it : Provider) { - if (auto* prop = dynamic_cast(it->getPropertyByName("LineColor"))) { - prop->setValue(c); - } - } -} - -void DlgDisplayPropertiesImp::onButtonPointColorChanged() -{ - std::vector Provider = getSelection(); - QColor s = d->ui.buttonPointColor->color(); - App::Color c(s.red() / 255.0, s.green() / 255.0, s.blue() / 255.0); - for (auto it : Provider) { - if (auto* prop = dynamic_cast(it->getPropertyByName("PointColor"))) { - prop->setValue(c); - } - } -} - -void DlgDisplayPropertiesImp::onSpinLineTransparencyValueChanged(int transparency) -{ - std::vector Provider = getSelection(); - for (auto it : Provider) { - if (auto* prop = dynamic_cast(it->getPropertyByName("LineTransparency"))) { - prop->setValue(transparency); - } - } -} - -void DlgDisplayPropertiesImp::setDisplayModes(const std::vector& views) -{ - QStringList commonModes, modes; - for (auto it = views.begin(); it != views.end(); ++it) { - if (auto* prop = dynamic_cast((*it)->getPropertyByName("DisplayMode"))) { - if (!prop->hasEnums()) - return; - std::vector value = prop->getEnumVector(); - if (it == views.begin()) { - for (const auto & jt : value) - commonModes << QLatin1String(jt.c_str()); - } - else { - for (const auto & jt : value) { - if (commonModes.contains(QLatin1String(jt.c_str()))) - modes << QLatin1String(jt.c_str()); - } - - commonModes = modes; - modes.clear(); - } - } - } - - d->ui.changeMode->clear(); - d->ui.changeMode->addItems(commonModes); - d->ui.changeMode->setDisabled(commonModes.isEmpty()); - - // find the display mode to activate - for (const auto & view : views) { - if (auto* prop = dynamic_cast(view->getPropertyByName("DisplayMode"))) { - QString activeMode = QString::fromLatin1(prop->getValueAsString()); - int index = d->ui.changeMode->findText(activeMode); - if (index != -1) { - d->ui.changeMode->setCurrentIndex(index); - break; - } - } - } -} - -void DlgDisplayPropertiesImp::setMaterial(const std::vector& views) -{ - bool material = false; - App::Material::MaterialType matType = App::Material::DEFAULT; - for (auto view : views) { - if (auto* prop = dynamic_cast(view->getPropertyByName("ShapeMaterial"))) { - material = true; - matType = prop->getValue().getType(); - break; - } - } - - int index = d->ui.changeMaterial->findData(matType); - if (index >= 0) { - d->ui.changeMaterial->setCurrentIndex(index); - } - d->ui.changeMaterial->setEnabled(material); - d->ui.buttonUserDefinedMaterial->setEnabled(material); -} - -void DlgDisplayPropertiesImp::setColorPlot(const std::vector& views) -{ - bool material = false; - for (auto view : views) { - auto* prop = dynamic_cast(view->getPropertyByName("TextureMaterial")); - if (prop) { - material = true; - break; - } - } - - d->ui.buttonColorPlot->setEnabled(material); -} - -void DlgDisplayPropertiesImp::fillupMaterials() -{ - d->ui.changeMaterial->addItem(tr("Default"), App::Material::DEFAULT); - d->ui.changeMaterial->addItem(tr("Aluminium"), App::Material::ALUMINIUM); - d->ui.changeMaterial->addItem(tr("Brass"), App::Material::BRASS); - d->ui.changeMaterial->addItem(tr("Bronze"), App::Material::BRONZE); - d->ui.changeMaterial->addItem(tr("Copper"), App::Material::COPPER); - d->ui.changeMaterial->addItem(tr("Chrome"), App::Material::CHROME); - d->ui.changeMaterial->addItem(tr("Emerald"), App::Material::EMERALD); - d->ui.changeMaterial->addItem(tr("Gold"), App::Material::GOLD); - d->ui.changeMaterial->addItem(tr("Jade"), App::Material::JADE); - d->ui.changeMaterial->addItem(tr("Metalized"), App::Material::METALIZED); - d->ui.changeMaterial->addItem(tr("Neon GNC"), App::Material::NEON_GNC); - d->ui.changeMaterial->addItem(tr("Neon PHC"), App::Material::NEON_PHC); - d->ui.changeMaterial->addItem(tr("Obsidian"), App::Material::OBSIDIAN); - d->ui.changeMaterial->addItem(tr("Pewter"), App::Material::PEWTER); - d->ui.changeMaterial->addItem(tr("Plaster"), App::Material::PLASTER); - d->ui.changeMaterial->addItem(tr("Plastic"), App::Material::PLASTIC); - d->ui.changeMaterial->addItem(tr("Ruby"), App::Material::RUBY); - d->ui.changeMaterial->addItem(tr("Satin"), App::Material::SATIN); - d->ui.changeMaterial->addItem(tr("Shiny plastic"), App::Material::SHINY_PLASTIC); - d->ui.changeMaterial->addItem(tr("Silver"), App::Material::SILVER); - d->ui.changeMaterial->addItem(tr("Steel"), App::Material::STEEL); - d->ui.changeMaterial->addItem(tr("Stone"), App::Material::STONE); -} - -void DlgDisplayPropertiesImp::setShapeColor(const std::vector& views) -{ - Private::setElementColor(views, "ShapeColor", d->ui.buttonColor); -} - -void DlgDisplayPropertiesImp::setLineColor(const std::vector& views) -{ - Private::setElementColor(views, "LineColor", d->ui.buttonLineColor); -} - -void DlgDisplayPropertiesImp::setPointColor(const std::vector& views) -{ - Private::setElementColor(views, "PointColor", d->ui.buttonPointColor); -} - -void DlgDisplayPropertiesImp::setPointSize(const std::vector& views) -{ - Private::setDrawStyle(views, "PointSize", d->ui.spinPointSize); -} - -void DlgDisplayPropertiesImp::setLineWidth(const std::vector& views) -{ - Private::setDrawStyle(views, "LineWidth", d->ui.spinLineWidth); -} - -void DlgDisplayPropertiesImp::setTransparency(const std::vector& views) -{ - Private::setTransparency(views, "Transparency", d->ui.spinTransparency, d->ui.horizontalSlider); -} - -void DlgDisplayPropertiesImp::setLineTransparency(const std::vector& views) -{ - Private::setTransparency(views, "LineTransparency", d->ui.spinLineTransparency, d->ui.sliderLineTransparency); -} - -std::vector DlgDisplayPropertiesImp::getSelection() const -{ - std::vector views; - - // get the complete selection - std::vector sel = Selection().getCompleteSelection(); - for (const auto & it : sel) { - Gui::ViewProvider* view = Application::Instance->getDocument(it.pDoc)->getViewProvider(it.pObject); - views.push_back(view); - } - - return views; -} - -// ---------------------------------------------------------------------------- - -/* TRANSLATOR Gui::Dialog::TaskDisplayProperties */ - -TaskDisplayProperties::TaskDisplayProperties() -{ - this->setButtonPosition(TaskDisplayProperties::North); - widget = new DlgDisplayPropertiesImp(false); - addTaskBox(widget); -} - -TaskDisplayProperties::~TaskDisplayProperties() = default; - -QDialogButtonBox::StandardButtons TaskDisplayProperties::getStandardButtons() const -{ - return QDialogButtonBox::Close; -} - -bool TaskDisplayProperties::reject() -{ - widget->reject(); - return (widget->result() == QDialog::Rejected); -} - -#include "moc_DlgDisplayPropertiesImp.cpp" - +/*************************************************************************** + * Copyright (c) 2002 Jürgen Riegel * + * * + * 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" +#ifndef _PreComp_ +#include +#include +#include +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "DlgDisplayPropertiesImp.h" +#include "ui_DlgDisplayProperties.h" + + +using namespace MatGui; +using namespace std; +namespace sp = std::placeholders; + + +/* TRANSLATOR Gui::Dialog::DlgDisplayPropertiesImp */ + +#if 0 // needed for Qt's lupdate utility + qApp->translate("QDockWidget", "Display properties"); +#endif + +class DlgDisplayPropertiesImp::Private +{ + using DlgDisplayPropertiesImp_Connection = boost::signals2::connection; + +public: + Ui::DlgDisplayProperties ui; + bool floating; + DlgDisplayPropertiesImp_Connection connectChangedObject; + + static void setElementColor(const std::vector& views, + const char* property, + Gui::ColorButton* buttonColor) + { + bool hasElementColor = false; + for (const auto& view : views) { + if (auto* prop = dynamic_cast(view->getPropertyByName(property))) { + App::Color color = prop->getValue(); + QSignalBlocker block(buttonColor); + buttonColor->setColor(color.asValue()); + hasElementColor = true; + break; + } + } + + buttonColor->setEnabled(hasElementColor); + } + + static void setElementAppearance(const std::vector& views, + const char* property, + Gui::ColorButton* buttonColor) + { + bool hasElementColor = false; + for (const auto& view : views) { + if (auto* prop = + dynamic_cast(view->getPropertyByName(property))) { + App::Color color = prop->getDiffuseColor(); + QSignalBlocker block(buttonColor); + buttonColor->setColor(color.asValue()); + hasElementColor = true; + break; + } + } + + buttonColor->setEnabled(hasElementColor); + } + + static void setDrawStyle(const std::vector& views, + const char* property, + QSpinBox* spinbox) + { + bool hasDrawStyle = false; + for (const auto& view : views) { + if (auto* prop = dynamic_cast(view->getPropertyByName(property))) { + QSignalBlocker block(spinbox); + spinbox->setValue(int(prop->getValue())); + hasDrawStyle = true; + break; + } + } + + spinbox->setEnabled(hasDrawStyle); + } + + static void setTransparency(const std::vector& views, + const char* property, + QSpinBox* spinbox, + QSlider* slider) + { + bool hasTransparency = false; + for (const auto& view : views) { + if (auto* prop = + dynamic_cast(view->getPropertyByName(property))) { + QSignalBlocker blockSpinBox(spinbox); + spinbox->setValue(prop->getValue()); + + QSignalBlocker blockSlider(slider); + slider->setValue(prop->getValue()); + hasTransparency = true; + break; + } + } + + spinbox->setEnabled(hasTransparency); + slider->setEnabled(hasTransparency); + } +}; + +/** + * Constructs a DlgDisplayPropertiesImp which is a child of 'parent', with the + * name 'name' and widget flags set to 'f' + * + * The dialog will by default be modeless, unless you set 'modal' to + * true to construct a modal dialog. + */ +DlgDisplayPropertiesImp::DlgDisplayPropertiesImp(bool floating, QWidget* parent, Qt::WindowFlags fl) + : QDialog(parent, fl) + , d(new Private) +{ + d->ui.setupUi(this); + setupConnections(); + + d->ui.textLabel1_3->hide(); + d->ui.changePlot->hide(); + d->ui.buttonLineColor->setModal(false); + d->ui.buttonPointColor->setModal(false); + d->floating = floating; + + // Create a filter to only include current format materials + // that contain the basic render model. + auto filter = std::make_shared(); + filter->setIncludeEmptyFolders(false); + filter->setIncludeLegacy(false); + filter->addRequiredComplete(Materials::ModelUUIDs::ModelUUID_Rendering_Basic); + d->ui.widgetMaterial->setFilter(filter); + + std::vector views = getSelection(); + setDisplayModes(views); + setMaterial(views); + setColorPlot(views); + setShapeAppearance(views); + setLineColor(views); + setPointColor(views); + setPointSize(views); + setLineWidth(views); + setTransparency(views); + setLineTransparency(views); + + // embed this dialog into a dockable widget container + if (floating) { + Gui::DockWindowManager* pDockMgr = Gui::DockWindowManager::instance(); + QDockWidget* dw = + pDockMgr->addDockWindow("Display properties", this, Qt::AllDockWidgetAreas); + dw->setFeatures(QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetFloatable); + dw->setFloating(true); + dw->show(); + } + + Gui::Selection().Attach(this); + + // NOLINTBEGIN + d->connectChangedObject = Gui::Application::Instance->signalChangedObject.connect( + std::bind(&DlgDisplayPropertiesImp::slotChangedObject, this, sp::_1, sp::_2)); + // NOLINTEND +} + +/** + * Destroys the object and frees any allocated resources + */ +DlgDisplayPropertiesImp::~DlgDisplayPropertiesImp() +{ + // no need to delete child widgets, Qt does it all for us + d->connectChangedObject.disconnect(); + Gui::Selection().Detach(this); +} + +void DlgDisplayPropertiesImp::setupConnections() +{ +#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0) + connect(d->ui.changeMode, + qOverload(&QComboBox::activated), + this, + &DlgDisplayPropertiesImp::onChangeModeActivated); + connect(d->ui.changePlot, + qOverload(&QComboBox::activated), + this, + &DlgDisplayPropertiesImp::onChangePlotActivated); +#else + connect(d->ui.changeMode, + &QComboBox::textActivated, + this, + &DlgDisplayPropertiesImp::onChangeModeActivated); + connect(d->ui.changePlot, + &QComboBox::textActivated, + this, + &DlgDisplayPropertiesImp::onChangePlotActivated); +#endif + connect(d->ui.spinTransparency, + qOverload(&QSpinBox::valueChanged), + this, + &DlgDisplayPropertiesImp::onSpinTransparencyValueChanged); + connect(d->ui.spinPointSize, + qOverload(&QSpinBox::valueChanged), + this, + &DlgDisplayPropertiesImp::onSpinPointSizeValueChanged); + connect(d->ui.buttonLineColor, + &Gui::ColorButton::changed, + this, + &DlgDisplayPropertiesImp::onButtonLineColorChanged); + connect(d->ui.buttonPointColor, + &Gui::ColorButton::changed, + this, + &DlgDisplayPropertiesImp::onButtonPointColorChanged); + connect(d->ui.spinLineWidth, + qOverload(&QSpinBox::valueChanged), + this, + &DlgDisplayPropertiesImp::onSpinLineWidthValueChanged); + connect(d->ui.spinLineTransparency, + qOverload(&QSpinBox::valueChanged), + this, + &DlgDisplayPropertiesImp::onSpinLineTransparencyValueChanged); + connect(d->ui.buttonUserDefinedMaterial, + &Gui::ColorButton::clicked, + this, + &DlgDisplayPropertiesImp::onButtonUserDefinedMaterialClicked); + connect(d->ui.buttonColorPlot, + &Gui::ColorButton::clicked, + this, + &DlgDisplayPropertiesImp::onButtonColorPlotClicked); + connect(d->ui.widgetMaterial, + &MaterialTreeWidget::materialSelected, + this, + &DlgDisplayPropertiesImp::onMaterialSelected); +} + +void DlgDisplayPropertiesImp::changeEvent(QEvent* e) +{ + if (e->type() == QEvent::LanguageChange) { + d->ui.retranslateUi(this); + } + QDialog::changeEvent(e); +} + +/// @cond DOXERR +void DlgDisplayPropertiesImp::OnChange(Gui::SelectionSingleton::SubjectType& rCaller, + Gui::SelectionSingleton::MessageType Reason) +{ + Q_UNUSED(rCaller); + if (Reason.Type == Gui::SelectionChanges::AddSelection + || Reason.Type == Gui::SelectionChanges::RmvSelection + || Reason.Type == Gui::SelectionChanges::SetSelection + || Reason.Type == Gui::SelectionChanges::ClrSelection) { + std::vector views = getSelection(); + setDisplayModes(views); + setMaterial(views); + setColorPlot(views); + setShapeAppearance(views); + setLineColor(views); + setPointColor(views); + setPointSize(views); + setLineWidth(views); + setTransparency(views); + setLineTransparency(views); + } +} +/// @endcond + +void DlgDisplayPropertiesImp::slotChangedObject(const Gui::ViewProvider& obj, + const App::Property& prop) +{ + // This method gets called if a property of any view provider is changed. + // We pick out all the properties for which we need to update this dialog. + std::vector Provider = getSelection(); + auto vp = std::find_if(Provider.begin(), Provider.end(), [&obj](Gui::ViewProvider* v) { + return v == &obj; + }); + + if (vp != Provider.end()) { + const char* name = obj.getPropertyName(&prop); + // this is not a property of the view provider but of the document object + if (!name) { + return; + } + std::string prop_name = name; + if (prop.is()) { + App::Color value = static_cast(prop).getValue(); + if (prop_name == "LineColor") { + bool blocked = d->ui.buttonLineColor->blockSignals(true); + d->ui.buttonLineColor->setColor(QColor((int)(255.0f * value.r), + (int)(255.0f * value.g), + (int)(255.0f * value.b))); + d->ui.buttonLineColor->blockSignals(blocked); + } + else if (prop_name == "PointColor") { + bool blocked = d->ui.buttonPointColor->blockSignals(true); + d->ui.buttonPointColor->setColor(QColor((int)(255.0f * value.r), + (int)(255.0f * value.g), + (int)(255.0f * value.b))); + d->ui.buttonPointColor->blockSignals(blocked); + } + } + else if (prop.isDerivedFrom()) { + auto& value = static_cast(prop).getValue(); + if (prop_name == "ShapeAppearance") { + // bool blocked = d->ui.buttonColor->blockSignals(true); + // auto color = value.diffuseColor; + // d->ui.buttonColor->setColor(QColor((int)(255.0f * color.r), + // (int)(255.0f * color.g), + // (int)(255.0f * color.b))); + // d->ui.buttonColor->blockSignals(blocked); + } + } + else if (prop.isDerivedFrom()) { + long value = static_cast(prop).getValue(); + if (prop_name == "Transparency") { + bool blocked = d->ui.spinTransparency->blockSignals(true); + d->ui.spinTransparency->setValue(value); + d->ui.spinTransparency->blockSignals(blocked); + blocked = d->ui.horizontalSlider->blockSignals(true); + d->ui.horizontalSlider->setValue(value); + d->ui.horizontalSlider->blockSignals(blocked); + } + else if (prop_name == "LineTransparency") { + bool blocked = d->ui.spinLineTransparency->blockSignals(true); + d->ui.spinLineTransparency->setValue(value); + d->ui.spinLineTransparency->blockSignals(blocked); + blocked = d->ui.sliderLineTransparency->blockSignals(true); + d->ui.sliderLineTransparency->setValue(value); + d->ui.sliderLineTransparency->blockSignals(blocked); + } + } + else if (prop.isDerivedFrom()) { + double value = static_cast(prop).getValue(); + if (prop_name == "PointSize") { + bool blocked = d->ui.spinPointSize->blockSignals(true); + d->ui.spinPointSize->setValue((int)value); + d->ui.spinPointSize->blockSignals(blocked); + } + else if (prop_name == "LineWidth") { + bool blocked = d->ui.spinLineWidth->blockSignals(true); + d->ui.spinLineWidth->setValue((int)value); + d->ui.spinLineWidth->blockSignals(blocked); + } + } + } +} + +/** + * Destroys the dock window this object is embedded into without destroying itself. + */ +void DlgDisplayPropertiesImp::reject() +{ + if (d->floating) { + // closes the dock window + Gui::DockWindowManager* pDockMgr = Gui::DockWindowManager::instance(); + pDockMgr->removeDockWindow(this); + } + QDialog::reject(); +} + +/** + * Opens a dialog that allows to modify the 'ShapeMaterial' property of all selected view providers. + */ +void DlgDisplayPropertiesImp::onButtonUserDefinedMaterialClicked() +{ + std::vector Provider = getSelection(); + Gui::Dialog::DlgMaterialPropertiesImp dlg("ShapeMaterial", this); + dlg.setViewProviders(Provider); + dlg.exec(); + + // d->ui.buttonColor->setColor(dlg.diffuseColor()); +} + +/** + * Opens a dialog that allows to modify the 'ShapeMaterial' property of all selected view providers. + */ +void DlgDisplayPropertiesImp::onButtonColorPlotClicked() +{ + std::vector Provider = getSelection(); + static QPointer dlg = nullptr; + if (!dlg) { + dlg = new Gui::Dialog::DlgMaterialPropertiesImp("TextureMaterial", this); + } + dlg->setModal(false); + dlg->setAttribute(Qt::WA_DeleteOnClose); + dlg->setViewProviders(Provider); + dlg->show(); +} + +/** + * Sets the 'Display' property of all selected view providers. + */ +void DlgDisplayPropertiesImp::onChangeModeActivated(const QString& s) +{ + Gui::WaitCursor wc; + std::vector Provider = getSelection(); + for (auto it : Provider) { + if (auto* prop = + dynamic_cast(it->getPropertyByName("DisplayMode"))) { + prop->setValue(static_cast(s.toLatin1())); + } + } +} + +void DlgDisplayPropertiesImp::onChangePlotActivated(const QString& s) +{ + Base::Console().Log("Plot = %s\n", (const char*)s.toLatin1()); +} + +/** + * Sets the 'Transparency' property of all selected view providers. + */ +void DlgDisplayPropertiesImp::onSpinTransparencyValueChanged(int transparency) +{ + std::vector Provider = getSelection(); + for (auto it : Provider) { + if (auto* prop = + dynamic_cast(it->getPropertyByName("Transparency"))) { + prop->setValue(transparency); + } + } +} + +/** + * Sets the 'PointSize' property of all selected view providers. + */ +void DlgDisplayPropertiesImp::onSpinPointSizeValueChanged(int pointsize) +{ + std::vector Provider = getSelection(); + for (auto it : Provider) { + if (auto* prop = dynamic_cast(it->getPropertyByName("PointSize"))) { + prop->setValue(static_cast(pointsize)); + } + } +} + +/** + * Sets the 'LineWidth' property of all selected view providers. + */ +void DlgDisplayPropertiesImp::onSpinLineWidthValueChanged(int linewidth) +{ + std::vector Provider = getSelection(); + for (auto it : Provider) { + if (auto* prop = dynamic_cast(it->getPropertyByName("LineWidth"))) { + prop->setValue(static_cast(linewidth)); + } + } +} + +void DlgDisplayPropertiesImp::onButtonLineColorChanged() +{ + std::vector Provider = getSelection(); + QColor s = d->ui.buttonLineColor->color(); + App::Color c(s.red() / 255.0, s.green() / 255.0, s.blue() / 255.0); + for (auto it : Provider) { + if (auto* prop = dynamic_cast(it->getPropertyByName("LineColor"))) { + prop->setValue(c); + } + } +} + +void DlgDisplayPropertiesImp::onButtonPointColorChanged() +{ + std::vector Provider = getSelection(); + QColor s = d->ui.buttonPointColor->color(); + App::Color c(s.red() / 255.0, s.green() / 255.0, s.blue() / 255.0); + for (auto it : Provider) { + if (auto* prop = dynamic_cast(it->getPropertyByName("PointColor"))) { + prop->setValue(c); + } + } +} + +void DlgDisplayPropertiesImp::onSpinLineTransparencyValueChanged(int transparency) +{ + std::vector Provider = getSelection(); + for (auto it : Provider) { + if (auto* prop = + dynamic_cast(it->getPropertyByName("LineTransparency"))) { + prop->setValue(transparency); + } + } +} + +void DlgDisplayPropertiesImp::setDisplayModes(const std::vector& views) +{ + QStringList commonModes, modes; + for (auto it = views.begin(); it != views.end(); ++it) { + if (auto* prop = + dynamic_cast((*it)->getPropertyByName("DisplayMode"))) { + if (!prop->hasEnums()) { + return; + } + std::vector value = prop->getEnumVector(); + if (it == views.begin()) { + for (const auto& jt : value) { + commonModes << QLatin1String(jt.c_str()); + } + } + else { + for (const auto& jt : value) { + if (commonModes.contains(QLatin1String(jt.c_str()))) { + modes << QLatin1String(jt.c_str()); + } + } + + commonModes = modes; + modes.clear(); + } + } + } + + d->ui.changeMode->clear(); + d->ui.changeMode->addItems(commonModes); + d->ui.changeMode->setDisabled(commonModes.isEmpty()); + + // find the display mode to activate + for (const auto& view : views) { + if (auto* prop = + dynamic_cast(view->getPropertyByName("DisplayMode"))) { + QString activeMode = QString::fromLatin1(prop->getValueAsString()); + int index = d->ui.changeMode->findText(activeMode); + if (index != -1) { + d->ui.changeMode->setCurrentIndex(index); + break; + } + } + } +} + +void DlgDisplayPropertiesImp::setMaterial(const std::vector& views) +{ + bool material = false; + App::Material::MaterialType matType = App::Material::DEFAULT; + for (auto view : views) { + if (auto* prop = + dynamic_cast(view->getPropertyByName("ShapeMaterial"))) { + material = true; + matType = prop->getValue().getType(); + break; + } + } + d->ui.buttonUserDefinedMaterial->setEnabled(material); +} + +void DlgDisplayPropertiesImp::setColorPlot(const std::vector& views) +{ + bool material = false; + for (auto view : views) { + auto* prop = + dynamic_cast(view->getPropertyByName("TextureMaterial")); + if (prop) { + material = true; + break; + } + } + + d->ui.buttonColorPlot->setEnabled(material); +} + +void DlgDisplayPropertiesImp::setShapeAppearance(const std::vector& views) +{ + Q_UNUSED(views) + + // Private::setElementAppearance(views, "ShapeColor", d->ui.buttonColor); +} + +void DlgDisplayPropertiesImp::setLineColor(const std::vector& views) +{ + Private::setElementColor(views, "LineColor", d->ui.buttonLineColor); +} + +void DlgDisplayPropertiesImp::setPointColor(const std::vector& views) +{ + Private::setElementColor(views, "PointColor", d->ui.buttonPointColor); +} + +void DlgDisplayPropertiesImp::setPointSize(const std::vector& views) +{ + Private::setDrawStyle(views, "PointSize", d->ui.spinPointSize); +} + +void DlgDisplayPropertiesImp::setLineWidth(const std::vector& views) +{ + Private::setDrawStyle(views, "LineWidth", d->ui.spinLineWidth); +} + +void DlgDisplayPropertiesImp::setTransparency(const std::vector& views) +{ + Private::setTransparency(views, "Transparency", d->ui.spinTransparency, d->ui.horizontalSlider); +} + +void DlgDisplayPropertiesImp::setLineTransparency(const std::vector& views) +{ + Private::setTransparency(views, + "LineTransparency", + d->ui.spinLineTransparency, + d->ui.sliderLineTransparency); +} + +std::vector DlgDisplayPropertiesImp::getSelection() const +{ + std::vector views; + + // get the complete selection + std::vector sel = Gui::Selection().getCompleteSelection(); + for (const auto& it : sel) { + Gui::ViewProvider* view = + Gui::Application::Instance->getDocument(it.pDoc)->getViewProvider(it.pObject); + views.push_back(view); + } + + return views; +} + +void DlgDisplayPropertiesImp::onMaterialSelected( + const std::shared_ptr& material) +{ + std::vector Provider = getSelection(); + for (auto it : Provider) { + if (auto* prop = dynamic_cast( + it->getPropertyByName("ShapeAppearance"))) { + App::Material mat; + mat.ambientColor = + material->getAppearanceProperty(QString::fromLatin1("AmbientColor"))->getColor(); + mat.diffuseColor = + material->getAppearanceProperty(QString::fromLatin1("DiffuseColor"))->getColor(); + mat.emissiveColor = + material->getAppearanceProperty(QString::fromLatin1("EmissiveColor"))->getColor(); + mat.specularColor = + material->getAppearanceProperty(QString::fromLatin1("SpecularColor"))->getColor(); + mat.shininess = + material->getAppearanceProperty(QString::fromLatin1("Shininess"))->getFloat(); + mat.transparency = + material->getAppearanceProperty(QString::fromLatin1("Transparency"))->getFloat(); + prop->setValue(mat); + } + } +} + +// ---------------------------------------------------------------------------- + +/* TRANSLATOR Gui::Dialog::TaskDisplayProperties */ + +TaskDisplayProperties::TaskDisplayProperties() +{ + this->setButtonPosition(TaskDisplayProperties::North); + widget = new DlgDisplayPropertiesImp(false); + addTaskBox(widget); +} + +TaskDisplayProperties::~TaskDisplayProperties() = default; + +QDialogButtonBox::StandardButtons TaskDisplayProperties::getStandardButtons() const +{ + return QDialogButtonBox::Close; +} + +bool TaskDisplayProperties::reject() +{ + widget->reject(); + return (widget->result() == QDialog::Rejected); +} + +#include "moc_DlgDisplayPropertiesImp.cpp" diff --git a/src/Gui/DlgDisplayPropertiesImp.h b/src/Mod/Material/Gui/DlgDisplayPropertiesImp.h similarity index 66% rename from src/Gui/DlgDisplayPropertiesImp.h rename to src/Mod/Material/Gui/DlgDisplayPropertiesImp.h index 8d0771ab2c..3914256b58 100644 --- a/src/Gui/DlgDisplayPropertiesImp.h +++ b/src/Mod/Material/Gui/DlgDisplayPropertiesImp.h @@ -1,131 +1,136 @@ -/*************************************************************************** - * Copyright (c) 2002 Jürgen Riegel * - * * - * 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 GUI_DIALOG_DLGDISPLAYPROPERTIES_IMP_H -#define GUI_DIALOG_DLGDISPLAYPROPERTIES_IMP_H - -#include -#include -#include - -#include -#include -#include -#include - -namespace App -{ - class Property; -} - -namespace Gui { - - class ViewProvider; - class Command; - -namespace Dialog { - -/** - * The DlgDisplayPropertiesImp class implements a dialog containing all available document - * templates to create a new document. - * \author Jürgen Riegel - */ -class DlgDisplayPropertiesImp : public QDialog, - public Gui::SelectionSingleton::ObserverType -{ - Q_OBJECT - -public: - explicit DlgDisplayPropertiesImp(bool floating, QWidget* parent = nullptr, Qt::WindowFlags fl = Qt::WindowFlags()); - ~DlgDisplayPropertiesImp() override; - /// Observer message from the Selection - void OnChange(Gui::SelectionSingleton::SubjectType &rCaller, - Gui::SelectionSingleton::MessageType Reason) override; - void showDefaultButtons(bool); - void reject() override; - -private Q_SLOTS: - void onChangeMaterialActivated(int); - void onChangeModeActivated(const QString&); - void onChangePlotActivated(const QString&); - void onButtonColorChanged(); - void onSpinTransparencyValueChanged(int); - void onSpinPointSizeValueChanged(int); - void onButtonLineColorChanged(); - void onButtonPointColorChanged(); - void onSpinLineWidthValueChanged(int); - void onSpinLineTransparencyValueChanged(int); - void onButtonUserDefinedMaterialClicked(); - void onButtonColorPlotClicked(); - -protected: - void changeEvent(QEvent *e) override; - -private: - void setupConnections(); - void slotChangedObject(const Gui::ViewProvider&, const App::Property& Prop); - void setDisplayModes(const std::vector&); - void setMaterial(const std::vector&); - void setColorPlot(const std::vector&); - void fillupMaterials(); - void setShapeColor(const std::vector&); - void setLineColor(const std::vector&); - void setPointColor(const std::vector&); - void setPointSize(const std::vector&); - void setLineWidth(const std::vector&); - void setTransparency(const std::vector&); - void setLineTransparency(const std::vector&); - std::vector getSelection() const; - -private: - class Private; - std::unique_ptr d; -}; - -class TaskDisplayProperties : public Gui::TaskView::TaskDialog -{ - Q_OBJECT - -public: - TaskDisplayProperties(); - ~TaskDisplayProperties() override; - -public: - bool reject() override; - - bool isAllowedAlterDocument() const override - { return true; } - bool isAllowedAlterView() const override - { return true; } - bool isAllowedAlterSelection() const override - { return true; } - QDialogButtonBox::StandardButtons getStandardButtons() const override; - -private: - DlgDisplayPropertiesImp* widget; -}; - -} // namespace Dialog -} // namespace Gui - -#endif // GUI_DIALOG_DLGDISPLAYPROPERTIES_IMP_H +/*************************************************************************** + * Copyright (c) 2002 Jürgen Riegel * + * * + * 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 MATGUI_DIALOG_DLGDISPLAYPROPERTIES_IMP_H +#define MATGUI_DIALOG_DLGDISPLAYPROPERTIES_IMP_H + +#include +#include +#include + +#include +#include +#include +#include + +#include + +namespace App +{ +class Property; +} + +namespace MatGui +{ + +class ViewProvider; +class Command; + +/** + * The DlgDisplayPropertiesImp class implements a dialog containing all available document + * templates to create a new document. + * \author Jürgen Riegel + */ +class DlgDisplayPropertiesImp: public QDialog, public Gui::SelectionSingleton::ObserverType +{ + Q_OBJECT + +public: + explicit DlgDisplayPropertiesImp(bool floating, + QWidget* parent = nullptr, + Qt::WindowFlags fl = Qt::WindowFlags()); + ~DlgDisplayPropertiesImp() override; + /// Observer message from the Selection + void OnChange(Gui::SelectionSingleton::SubjectType& rCaller, + Gui::SelectionSingleton::MessageType Reason) override; + void showDefaultButtons(bool); + void reject() override; + +private Q_SLOTS: + void onChangeModeActivated(const QString&); + void onChangePlotActivated(const QString&); + void onSpinTransparencyValueChanged(int); + void onSpinPointSizeValueChanged(int); + void onButtonLineColorChanged(); + void onButtonPointColorChanged(); + void onSpinLineWidthValueChanged(int); + void onSpinLineTransparencyValueChanged(int); + void onButtonUserDefinedMaterialClicked(); + void onButtonColorPlotClicked(); + void onMaterialSelected(const std::shared_ptr& material); + +protected: + void changeEvent(QEvent* e) override; + +private: + void setupConnections(); + void slotChangedObject(const Gui::ViewProvider&, const App::Property& Prop); + void setDisplayModes(const std::vector&); + void setMaterial(const std::vector&); + void setColorPlot(const std::vector&); + void setShapeAppearance(const std::vector&); + void setLineColor(const std::vector&); + void setPointColor(const std::vector&); + void setPointSize(const std::vector&); + void setLineWidth(const std::vector&); + void setTransparency(const std::vector&); + void setLineTransparency(const std::vector&); + std::vector getSelection() const; + +private: + class Private; + std::unique_ptr d; +}; + +class TaskDisplayProperties: public Gui::TaskView::TaskDialog +{ + Q_OBJECT + +public: + TaskDisplayProperties(); + ~TaskDisplayProperties() override; + +public: + bool reject() override; + + bool isAllowedAlterDocument() const override + { + return true; + } + bool isAllowedAlterView() const override + { + return true; + } + bool isAllowedAlterSelection() const override + { + return true; + } + QDialogButtonBox::StandardButtons getStandardButtons() const override; + +private: + DlgDisplayPropertiesImp* widget; +}; + +} // namespace MatGui + +#endif // MATGUI_DIALOG_DLGDISPLAYPROPERTIES_IMP_H diff --git a/src/Mod/Material/Gui/DlgMaterial.ui b/src/Mod/Material/Gui/DlgMaterial.ui new file mode 100644 index 0000000000..3908d17548 --- /dev/null +++ b/src/Mod/Material/Gui/DlgMaterial.ui @@ -0,0 +1,52 @@ + + + MatGui::DlgMaterial + + + + 0 + 0 + 290 + 503 + + + + Material + + + + + + 6 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + + + + + MatGui::MaterialTreeWidget + QWidget +
Mod/Material/Gui/MaterialTreeWidget.h
+ 1 +
+
+ + +
diff --git a/src/Mod/Material/Gui/DlgMaterialImp.cpp b/src/Mod/Material/Gui/DlgMaterialImp.cpp new file mode 100644 index 0000000000..e4c8c60e00 --- /dev/null +++ b/src/Mod/Material/Gui/DlgMaterialImp.cpp @@ -0,0 +1,282 @@ +/*************************************************************************** + * Copyright (c) 2002 Jürgen Riegel * + * * + * 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" +#ifndef _PreComp_ +#include +#include +#include +#include +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "DlgMaterialImp.h" +#include "ui_DlgMaterial.h" + + +using namespace MatGui; +using namespace std; +namespace sp = std::placeholders; + + +/* TRANSLATOR Gui::Dialog::DlgMaterialImp */ + +#if 0 // needed for Qt's lupdate utility + qApp->translate("QDockWidget", "Material"); +#endif + +class DlgMaterialImp::Private +{ + using DlgMaterialImp_Connection = boost::signals2::connection; + +public: + Ui::DlgMaterial ui; + bool floating; + DlgMaterialImp_Connection connectChangedObject; +}; + +/** + * Constructs a DlgMaterialImp which is a child of 'parent', with the + * name 'name' and widget flags set to 'f' + * + * The dialog will by default be modeless, unless you set 'modal' to + * true to construct a modal dialog. + */ +DlgMaterialImp::DlgMaterialImp(bool floating, QWidget* parent, Qt::WindowFlags fl) + : QDialog(parent, fl) + , d(new Private) +{ + d->ui.setupUi(this); + setupConnections(); + + d->floating = floating; + + // // Create a filter to only include current format materials + // // that contain the basic render model. + // auto filter = std::make_shared(); + // filter->setIncludeEmptyFolders(false); + // filter->setIncludeLegacy(false); + // filter->addRequiredComplete(Materials::ModelUUIDs::ModelUUID_Rendering_Basic); + // d->ui.widgetMaterial->setFilter(filter); + + std::vector objects = getSelectionObjects(); + setMaterial(objects); + + // embed this dialog into a dockable widget container + if (floating) { + Gui::DockWindowManager* pDockMgr = Gui::DockWindowManager::instance(); + QDockWidget* dw = + pDockMgr->addDockWindow("Display properties", this, Qt::AllDockWidgetAreas); + dw->setFeatures(QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetFloatable); + dw->setFloating(true); + dw->show(); + } + + Gui::Selection().Attach(this); + + // NOLINTBEGIN + d->connectChangedObject = Gui::Application::Instance->signalChangedObject.connect( + std::bind(&DlgMaterialImp::slotChangedObject, this, sp::_1, sp::_2)); + // NOLINTEND +} + +/** + * Destroys the object and frees any allocated resources + */ +DlgMaterialImp::~DlgMaterialImp() +{ + // no need to delete child widgets, Qt does it all for us + d->connectChangedObject.disconnect(); + Gui::Selection().Detach(this); +} + +void DlgMaterialImp::setupConnections() +{ + connect(d->ui.widgetMaterial, + &MaterialTreeWidget::materialSelected, + this, + &DlgMaterialImp::onMaterialSelected); +} + +void DlgMaterialImp::changeEvent(QEvent* e) +{ + if (e->type() == QEvent::LanguageChange) { + d->ui.retranslateUi(this); + } + QDialog::changeEvent(e); +} + +/// @cond DOXERR +void DlgMaterialImp::OnChange(Gui::SelectionSingleton::SubjectType& rCaller, + Gui::SelectionSingleton::MessageType Reason) +{ + Q_UNUSED(rCaller); + if (Reason.Type == Gui::SelectionChanges::AddSelection + || Reason.Type == Gui::SelectionChanges::RmvSelection + || Reason.Type == Gui::SelectionChanges::SetSelection + || Reason.Type == Gui::SelectionChanges::ClrSelection) { + std::vector objects = getSelectionObjects(); + setMaterial(objects); + } +} +/// @endcond + +void DlgMaterialImp::slotChangedObject(const Gui::ViewProvider& obj, const App::Property& prop) +{ + // This method gets called if a property of any view provider is changed. + // We pick out all the properties for which we need to update this dialog. + std::vector Provider = getSelection(); + auto vp = std::find_if(Provider.begin(), Provider.end(), [&obj](Gui::ViewProvider* v) { + return v == &obj; + }); + + if (vp != Provider.end()) { + const char* name = obj.getPropertyName(&prop); + // this is not a property of the view provider but of the document object + if (!name) { + return; + } + std::string prop_name = name; + if (prop.isDerivedFrom()) { + auto& value = static_cast(prop).getValue(); + if (prop_name == "ShapeMaterial") { + // bool blocked = d->ui.buttonColor->blockSignals(true); + // auto color = value.diffuseColor; + // d->ui.buttonColor->setColor(QColor((int)(255.0f * color.r), + // (int)(255.0f * color.g), + // (int)(255.0f * color.b))); + // d->ui.buttonColor->blockSignals(blocked); + } + } + } +} + +/** + * Destroys the dock window this object is embedded into without destroying itself. + */ +void DlgMaterialImp::reject() +{ + if (d->floating) { + // closes the dock window + Gui::DockWindowManager* pDockMgr = Gui::DockWindowManager::instance(); + pDockMgr->removeDockWindow(this); + } + QDialog::reject(); +} + +void DlgMaterialImp::setMaterial(const std::vector& objects) +{ + for (auto it : objects) { + if (auto* obj = dynamic_cast(it)) { + auto material = obj->ShapeMaterial.getValue(); + try { + std::string mat = material.getUUID().toStdString(); + d->ui.widgetMaterial->setMaterial(material.getUUID()); + return; + } + catch (const Materials::MaterialNotFound&) { + } + } + } + d->ui.widgetMaterial->setMaterial(Materials::MaterialManager::defaultMaterialUUID()); +} + +std::vector DlgMaterialImp::getSelection() const +{ + std::vector views; + + // get the complete selection + std::vector sel = Gui::Selection().getCompleteSelection(); + for (const auto& it : sel) { + Gui::ViewProvider* view = + Gui::Application::Instance->getDocument(it.pDoc)->getViewProvider(it.pObject); + views.push_back(view); + } + + return views; +} + +std::vector DlgMaterialImp::getSelectionObjects() const +{ + std::vector objects; + + // get the complete selection + std::vector sel = Gui::Selection().getCompleteSelection(); + for (const auto& it : sel) { + objects.push_back(it.pObject); + } + + return objects; +} + +void DlgMaterialImp::onMaterialSelected(const std::shared_ptr& material) +{ + std::string mat = material->getUUID().toStdString(); + std::vector objects = getSelectionObjects(); + for (auto it : objects) { + if (auto* obj = dynamic_cast(it)) { + obj->ShapeMaterial.setValue(*material); + } + } +} + +// ---------------------------------------------------------------------------- + +/* TRANSLATOR Gui::Dialog::TaskMaterial */ + +TaskMaterial::TaskMaterial() +{ + this->setButtonPosition(TaskMaterial::North); + widget = new DlgMaterialImp(false); + taskbox = new Gui::TaskView::TaskBox(QPixmap(), widget->windowTitle(), true, nullptr); + taskbox->groupLayout()->addWidget(widget); + Content.push_back(taskbox); +} + +TaskMaterial::~TaskMaterial() = default; + +QDialogButtonBox::StandardButtons TaskMaterial::getStandardButtons() const +{ + return QDialogButtonBox::Close; +} + +bool TaskMaterial::reject() +{ + widget->reject(); + return (widget->result() == QDialog::Rejected); +} + +#include "moc_DlgMaterialImp.cpp" diff --git a/src/Mod/Material/Gui/DlgMaterialImp.h b/src/Mod/Material/Gui/DlgMaterialImp.h new file mode 100644 index 0000000000..a3bcc25ecf --- /dev/null +++ b/src/Mod/Material/Gui/DlgMaterialImp.h @@ -0,0 +1,119 @@ +/*************************************************************************** + * Copyright (c) 2002 Jürgen Riegel * + * * + * 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 MATGUI_DIALOGMATERIALIMP_H +#define MATGUI_DIALOGMATERIALIMP_H + +#include +#include +#include + +#include +#include +#include +#include + +#include + +namespace App +{ +class Property; +} + +namespace MatGui +{ + +class ViewProvider; +class Command; + +/** + * The DlgMaterialImp class implements a dialog containing all available document + * templates to create a new document. + * \author Jürgen Riegel + */ +class DlgMaterialImp: public QDialog, public Gui::SelectionSingleton::ObserverType +{ + Q_OBJECT + +public: + explicit DlgMaterialImp(bool floating, + QWidget* parent = nullptr, + Qt::WindowFlags fl = Qt::WindowFlags()); + ~DlgMaterialImp() override; + /// Observer message from the Selection + void OnChange(Gui::SelectionSingleton::SubjectType& rCaller, + Gui::SelectionSingleton::MessageType Reason) override; + void showDefaultButtons(bool); + void reject() override; + +private Q_SLOTS: + void onMaterialSelected(const std::shared_ptr& material); + +protected: + void changeEvent(QEvent* e) override; + +private: + void setupConnections(); + void slotChangedObject(const Gui::ViewProvider&, const App::Property& Prop); + void setMaterial(const std::vector&); + std::vector getSelection() const; + std::vector getSelectionObjects() const; + +private: + class Private; + std::unique_ptr d; +}; + +class TaskMaterial: public Gui::TaskView::TaskDialog +{ + Q_OBJECT + +public: + TaskMaterial(); + ~TaskMaterial() override; + +public: + bool reject() override; + + bool isAllowedAlterDocument() const override + { + return true; + } + bool isAllowedAlterView() const override + { + return true; + } + bool isAllowedAlterSelection() const override + { + return true; + } + QDialogButtonBox::StandardButtons getStandardButtons() const override; + +private: + DlgMaterialImp* widget; + Gui::TaskView::TaskBox* taskbox; +}; + +} // namespace MatGui + +#endif // MATGUI_DIALOGMATERIALIMP_H diff --git a/src/Mod/Material/Gui/MaterialTreeWidget.cpp b/src/Mod/Material/Gui/MaterialTreeWidget.cpp new file mode 100644 index 0000000000..b4d75dcae0 --- /dev/null +++ b/src/Mod/Material/Gui/MaterialTreeWidget.cpp @@ -0,0 +1,461 @@ +/*************************************************************************** + * Copyright (c) 2023 David Carter * + * * + * This file is part of FreeCAD. * + * * + * FreeCAD is free software: you can redistribute it and/or modify it * + * under the terms of the GNU Lesser General Public License as * + * published by the Free Software Foundation, either version 2.1 of the * + * License, or (at your option) any later version. * + * * + * FreeCAD is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with FreeCAD. If not, see * + * . * + * * + **************************************************************************/ + +#include "PreCompiled.h" +#ifndef _PreComp_ +#include +#include +#endif + +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include "MaterialTreeWidget.h" +#include "MaterialsEditor.h" +#include "ui_MaterialsEditor.h" + + +using Base::Console; +using namespace MatGui; + +/** Constructs a Material tree widget. + */ + +MaterialTreeWidget::MaterialTreeWidget(std::shared_ptr filter, + QWidget* parent) + : QWidget(parent) + , m_expanded(false) + , _filter(filter) +{ + setup(); +} + +MaterialTreeWidget::MaterialTreeWidget(QWidget* parent) + : QWidget(parent) + , m_expanded(false) + , _filter(nullptr) +{ + setup(); +} + +void MaterialTreeWidget::setup() +{ + getFavorites(); + getRecents(); + + createLayout(); + createMaterialTree(); +} + +/** + * Destroys the widget and detaches it from its parameter group. + */ +MaterialTreeWidget::~MaterialTreeWidget() = default; + +void MaterialTreeWidget::createLayout() +{ + m_material = new QLineEdit(this); + m_expand = new QPushButton(this); + m_expand->setIcon(style()->standardIcon(QStyle::SP_TitleBarUnshadeButton)); + m_materialTree = new QTreeView(this); + m_editor = new QPushButton(tr("Launch editor"), this); + + // m_materialTree->setSelectionModel(QAbstractItemView::SingleSelection); + m_materialTree->setSelectionMode(QAbstractItemView::SingleSelection); + m_materialTree->setSelectionBehavior(QAbstractItemView::SelectItems); + + auto materialLayout = new QHBoxLayout(); + materialLayout->addWidget(m_material); + materialLayout->addWidget(m_expand); + + auto treeLayout = new QHBoxLayout(); + treeLayout->addWidget(m_materialTree); + + auto buttonLayout = new QHBoxLayout(); + buttonLayout->addItem(new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Preferred)); + buttonLayout->addWidget(m_editor); + + auto layout = new QVBoxLayout(); + layout->setContentsMargins(0, 9, 0, 9); + layout->addItem(materialLayout); + layout->addItem(treeLayout); + layout->addItem(buttonLayout); + setLayout(layout); + + // Start in an unexpanded state. Store the state? + openWidgetState(false); + + connect(m_expand, &QPushButton::clicked, this, &MaterialTreeWidget::expandClicked); + connect(m_editor, &QPushButton::clicked, this, &MaterialTreeWidget::editorClicked); +} + +void MaterialTreeWidget::openWidgetState(bool open) +{ + m_materialTree->setVisible(open); + m_editor->setVisible(open); + + m_expanded = open; + + if (open) { + m_expand->setIcon(style()->standardIcon(QStyle::SP_TitleBarShadeButton)); + } + else { + m_expand->setIcon(style()->standardIcon(QStyle::SP_TitleBarUnshadeButton)); + } +} + +void MaterialTreeWidget::expandClicked(bool checked) +{ + Q_UNUSED(checked) + + // Toggle the open state + openWidgetState(!m_expanded); +} + +void MaterialTreeWidget::editorClicked(bool checked) +{ + Q_UNUSED(checked) + + MaterialsEditor dialog(_filter, this); + dialog.setModal(true); + if (dialog.exec() == QDialog::Accepted) { + // updateMaterialGeneral(); + // _material->resetEditState(); + // refreshMaterialTree(); + // _materialSelected = true; + auto material = dialog.getMaterial(); + updateMaterialTree(); + setMaterial(material->getUUID()); + } + + // Gui::Application::Instance->commandManager().runCommandByName("Materials_Edit"); + // Toggle the open state + // openWidgetState(!m_expanded); +} + +void MaterialTreeWidget::updateMaterial(const QString& uuid) +{ + if (uuid.isEmpty() || uuid == m_uuid) { + return; + } + + m_uuid = uuid; + + // Fetch the material from the manager + auto material = std::make_shared(); + try { + material = std::make_shared(*getMaterialManager().getMaterial(uuid)); + } + catch (Materials::ModelNotFound const&) { + Base::Console().Log("*** Unable to load material '%s'\n", uuid.toStdString().c_str()); + } + + m_materialDisplay = material->getName(); + m_material->setText(m_materialDisplay); +} + +bool MaterialTreeWidget::findInTree(const QStandardItem& node, + QModelIndex* index, + const QString& uuid) +{ + auto vv = node.data(Qt::UserRole); + if (vv.isValid() && vv == uuid) { + *index = node.index(); + return true; + } + + if (node.hasChildren()) { + int rows = node.rowCount(); + for (int i = 0; i < node.rowCount(); i++) { + auto child = node.child(i); + if (findInTree(*child, index, uuid)) { + return true; + } + } + } + + return false; +} + +QModelIndex MaterialTreeWidget::findInTree(const QString& uuid) +{ + auto model = dynamic_cast(m_materialTree->model()); + auto root = model->invisibleRootItem(); + + QModelIndex index; + if (findInTree(*root, &index, uuid)) { + return index; + } + + return {}; +} + +void MaterialTreeWidget::setMaterial(const QString& uuid) +{ + if (uuid.isEmpty() || uuid == m_uuid) { + return; + } + updateMaterial(uuid); + + // Now select the material in the tree + auto index = findInTree(uuid); + if (index.isValid()) { + QItemSelectionModel* selectionModel = m_materialTree->selectionModel(); + selectionModel->select(index, QItemSelectionModel::SelectCurrent); + } +} + +QString MaterialTreeWidget::getMaterialUUID() const +{ + return m_uuid; +} + +void MaterialTreeWidget::setFilter(std::shared_ptr filter) +{ + _filter.reset(); + _filter = filter; + + updateMaterialTree(); +} + +void MaterialTreeWidget::updateMaterialTree() +{ + _favorites.clear(); + _recents.clear(); + + auto model = dynamic_cast(m_materialTree->model()); + model->clear(); + + getFavorites(); + getRecents(); + fillMaterialTree(); +} + +void MaterialTreeWidget::getFavorites() +{ + _favorites.clear(); + + auto param = App::GetApplication().GetParameterGroupByPath( + "User parameter:BaseApp/Preferences/Mod/Material/Favorites"); + auto count = param->GetInt("Favorites", 0); + for (int i = 0; static_cast(i) < count; i++) { + QString key = QString::fromLatin1("FAV%1").arg(i); + QString uuid = QString::fromStdString(param->GetASCII(key.toStdString().c_str(), "")); + if (!_filter || _filter->modelIncluded(uuid)) { + _favorites.push_back(uuid); + } + } +} + +void MaterialTreeWidget::getRecents() +{ + _recents.clear(); + + auto param = App::GetApplication().GetParameterGroupByPath( + "User parameter:BaseApp/Preferences/Mod/Material/Recent"); + _recentMax = static_cast(param->GetInt("RecentMax", 5)); + auto count = param->GetInt("Recent", 0); + for (int i = 0; static_cast(i) < count; i++) { + QString key = QString::fromLatin1("MRU%1").arg(i); + QString uuid = QString::fromStdString(param->GetASCII(key.toStdString().c_str(), "")); + if (!_filter || _filter->modelIncluded(uuid)) { + _recents.push_back(uuid); + } + } +} + +void MaterialTreeWidget::createMaterialTree() +{ + auto model = new QStandardItemModel(this); + m_materialTree->setModel(model); + m_materialTree->setHeaderHidden(true); + + // This needs to be done after the model is set + QItemSelectionModel* selectionModel = m_materialTree->selectionModel(); + connect(selectionModel, + &QItemSelectionModel::selectionChanged, + this, + &MaterialTreeWidget::onSelectMaterial); + connect(m_materialTree, &QTreeView::doubleClicked, this, &MaterialTreeWidget::onDoubleClick); + + fillMaterialTree(); +} + +void MaterialTreeWidget::fillMaterialTree() +{ + auto model = dynamic_cast(m_materialTree->model()); + + auto lib = new QStandardItem(tr("Favorites")); + lib->setFlags(Qt::ItemIsEnabled); + addExpanded(model, lib); + addFavorites(lib); + + lib = new QStandardItem(tr("Recent")); + lib->setFlags(Qt::ItemIsEnabled); + addExpanded(model, lib); + addRecents(lib); + + // // Create a filter to only include current format materials + // // that contain the basic render model. + // Materials::MaterialFilter filter; + // filter.setIncludeEmptyFolders(false); + // filter.setIncludeLegacy(false); + // filter.addRequired(Materials::ModelUUIDs::ModelUUID_Rendering_Basic); + + auto libraries = _materialManager.getMaterialLibraries(); + for (const auto& library : *libraries) { + lib = new QStandardItem(library->getName()); + lib->setFlags(Qt::ItemIsEnabled); + addExpanded(model, lib); + + QIcon icon(library->getIconPath()); + QIcon folderIcon(QString::fromStdString(":/icons/folder.svg")); + + auto modelTree = _materialManager.getMaterialTree(library, _filter); + addMaterials(*lib, modelTree, folderIcon, icon); + } +} + +void MaterialTreeWidget::addExpanded(QStandardItem* parent, QStandardItem* child) +{ + parent->appendRow(child); + m_materialTree->setExpanded(child->index(), true); +} + +void MaterialTreeWidget::addExpanded(QStandardItemModel* model, QStandardItem* child) +{ + model->appendRow(child); + m_materialTree->setExpanded(child->index(), true); +} + +void MaterialTreeWidget::addRecents(QStandardItem* parent) +{ + for (auto& uuid : _recents) { + try { + auto material = getMaterialManager().getMaterial(uuid); + + QIcon icon = QIcon(material->getLibrary()->getIconPath()); + auto card = new QStandardItem(icon, material->getName()); + card->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); + card->setData(QVariant(uuid), Qt::UserRole); + + addExpanded(parent, card); + } + catch (const Materials::MaterialNotFound&) { + } + } +} + +void MaterialTreeWidget::addFavorites(QStandardItem* parent) +{ + for (auto& uuid : _favorites) { + try { + auto material = getMaterialManager().getMaterial(uuid); + + QIcon icon = QIcon(material->getLibrary()->getIconPath()); + auto card = new QStandardItem(icon, material->getName()); + card->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); + card->setData(QVariant(uuid), Qt::UserRole); + + addExpanded(parent, card); + } + catch (const Materials::MaterialNotFound&) { + } + } +} +void MaterialTreeWidget::addMaterials( + QStandardItem& parent, + const std::shared_ptr>>& + modelTree, + const QIcon& folderIcon, + const QIcon& icon) +{ + for (auto& mat : *modelTree) { + auto nodePtr = mat.second; + if (nodePtr->getType() == Materials::MaterialTreeNode::DataNode) { + auto material = nodePtr->getData(); + QString uuid = material->getUUID(); + // Base::Console().Log("Material path '%s'\n", + // material->getDirectory().toStdString().c_str()); + + // auto card = new QStandardItem(icon, material->getName()); + auto card = new QStandardItem(icon, mat.first); + card->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); + card->setData(QVariant(uuid), Qt::UserRole); + + addExpanded(&parent, card); + } + else { + auto node = new QStandardItem(folderIcon, mat.first); + addExpanded(&parent, node); + node->setFlags(Qt::ItemIsEnabled); + auto treeMap = nodePtr->getFolder(); + addMaterials(*node, treeMap, folderIcon, icon); + } + } +} + +void MaterialTreeWidget::onSelectMaterial(const QItemSelection& selected, + const QItemSelection& deselected) +{ + Q_UNUSED(deselected); + + // Get the UUID before changing the underlying data model + QString uuid; + auto model = dynamic_cast(m_materialTree->model()); + QModelIndexList indexes = selected.indexes(); + for (auto it = indexes.begin(); it != indexes.end(); it++) { + QStandardItem* item = model->itemFromIndex(*it); + + if (item) { + uuid = item->data(Qt::UserRole).toString(); + break; + } + } + + updateMaterial(uuid); + std::string _uuid = uuid.toStdString(); + + Q_EMIT materialSelected(getMaterialManager().getMaterial(uuid)); +} + +void MaterialTreeWidget::onDoubleClick(const QModelIndex& index) +{ + auto model = dynamic_cast(m_materialTree->model()); + auto item = model->itemFromIndex(index); + + if (item) { + auto uuid = item->data(Qt::UserRole).toString(); + updateMaterial(uuid); + } +} \ No newline at end of file diff --git a/src/Mod/Material/Gui/MaterialTreeWidget.h b/src/Mod/Material/Gui/MaterialTreeWidget.h new file mode 100644 index 0000000000..cfcd508d56 --- /dev/null +++ b/src/Mod/Material/Gui/MaterialTreeWidget.h @@ -0,0 +1,177 @@ +/*************************************************************************** + * Copyright (c) 2023 David Carter * + * * + * This file is part of FreeCAD. * + * * + * FreeCAD is free software: you can redistribute it and/or modify it * + * under the terms of the GNU Lesser General Public License as * + * published by the Free Software Foundation, either version 2.1 of the * + * License, or (at your option) any later version. * + * * + * FreeCAD is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with FreeCAD. If not, see * + * . * + * * + **************************************************************************/ + +#ifndef MATGUI_MATERIALTREEWIDGET_H +#define MATGUI_MATERIALTREEWIDGET_H + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + + +#include +#include +#include + +namespace MatGui +{ +class CommandManager; +class WidgetFactoryInst; + +/** The Material Tree widget class + * This widget is intended for use wherever materials are used. It is a light weight + * alternative to the full Materials editor. + * + * The widget itself is the combination of a number of smaller widgets. A simple text + * field shows any currently selected material. An arrow will expand a tree to show + * the widget library, allowing the user to select the material they require. + * + * When expanded, the user will be presented the option to launch the full material + * editor. This will allow them to create/copy/modify as required. + * + * Additionally, they will be given the option to create a material card based on the + * current settings. + * + * \author David Carter + */ +class MatGuiExport MaterialTreeWidget: public QWidget +{ + Q_OBJECT + +public: + explicit MaterialTreeWidget(std::shared_ptr filter, + QWidget* parent = nullptr); + explicit MaterialTreeWidget(QWidget* parent = nullptr); + ~MaterialTreeWidget() override; + + // void setEntryName( const QByteArray& name ); + // QByteArray entryName() const; + // /** Does the same as setEntryName(). + // * This function is added for convenience because the ui compiler + // * will use this function if the attribute stdset isn't set to 0 in a .ui file. + // */ + // void setPrefEntry(const QByteArray& name); + + // void setParamGrpPath( const QByteArray& path ); + // QByteArray paramGrpPath() const; + // /** Does the same as setParamGrpPath(). + // * This function is added for convenience because the ui compiler + // * will use this function if the attribute stdset isn't set to 0 in a .ui file. + // */ + // void setPrefPath(const QByteArray& name); + + // void OnChange(Base::Subject &rCaller, const char * sReason) override; + // void onSave(); + // void onRestore(); + + /** Set the material by specifying its UUID + */ + void setMaterial(const QString& uuid); + /** get the material UUID + */ + QString getMaterialUUID() const; + /** Set the material filter + */ + void setFilter(std::shared_ptr filter); + +Q_SIGNALS: + /** Emits this signal when a material has been selected */ + void materialSelected(const std::shared_ptr& material); + +private Q_SLOTS: + void expandClicked(bool checked); + void editorClicked(bool checked); + void onSelectMaterial(const QItemSelection& selected, const QItemSelection& deselected); + void onDoubleClick(const QModelIndex& index); + +private: + void setup(); + + QLineEdit* m_material; + QPushButton* m_expand; + QTreeView* m_materialTree; + QPushButton* m_editor; + bool m_expanded; + + QString m_materialDisplay; + QString m_uuid; + + std::list _favorites; + std::list _recents; + std::shared_ptr _filter; + int _recentMax; + + Materials::MaterialManager _materialManager; + + // friends + friend class Gui::WidgetFactoryInst; + +protected: + // bool m_Restored = false; + + Materials::MaterialManager& getMaterialManager() + { + return _materialManager; + } + + void getFavorites(); + void getRecents(); + + /** Create the widgets UI objects + */ + void createLayout(); + + bool findInTree(const QStandardItem& node, QModelIndex* index, const QString& uuid); + QModelIndex findInTree(const QString& uuid); + void updateMaterial(const QString& uuid); + void createMaterialTree(); + void fillMaterialTree(); + void updateMaterialTree(); + void addExpanded(QStandardItem* parent, QStandardItem* child); + void addExpanded(QStandardItemModel* model, QStandardItem* child); + void addRecents(QStandardItem* parent); + void addFavorites(QStandardItem* parent); + void addMaterials( + QStandardItem& parent, + const std::shared_ptr>>& + modelTree, + const QIcon& folderIcon, + const QIcon& icon); + + void openWidgetState(bool open); +}; + +} // namespace MatGui + +#endif // MATGUI_MATERIALTREEWIDGET_H \ No newline at end of file diff --git a/src/Mod/Material/Gui/MaterialsEditor.cpp b/src/Mod/Material/Gui/MaterialsEditor.cpp index b6166395a6..8715300bd2 100644 --- a/src/Mod/Material/Gui/MaterialsEditor.cpp +++ b/src/Mod/Material/Gui/MaterialsEditor.cpp @@ -59,14 +59,33 @@ using namespace MatGui; /* TRANSLATOR MatGui::MaterialsEditor */ +MaterialsEditor::MaterialsEditor(std::shared_ptr filter, QWidget* parent) + : QDialog(parent) + , ui(new Ui_MaterialsEditor) + , _material(std::make_shared()) + , _materialSelected(false) + , _rendered(nullptr) + , _recentMax(0) + , _filter(filter) +{ + setup(); +} + MaterialsEditor::MaterialsEditor(QWidget* parent) : QDialog(parent) , ui(new Ui_MaterialsEditor) , _material(std::make_shared()) + , _materialSelected(false) , _rendered(nullptr) - , _edited(false) , _recentMax(0) + , _filter(nullptr) { + setup(); +} + +void MaterialsEditor::setup() +{ + Gui::WaitCursor wc; ui->setupUi(this); _warningIcon = QIcon(QString::fromStdString(":/icons/Warning.svg")); @@ -158,7 +177,9 @@ void MaterialsEditor::getFavorites() for (int i = 0; static_cast(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); + if (!_filter || _filter->modelIncluded(uuid)) { + _favorites.push_back(uuid); + } } } @@ -234,7 +255,9 @@ void MaterialsEditor::getRecents() for (int i = 0; static_cast(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); + if (!_filter || _filter->modelIncluded(uuid)) { + _recents.push_back(uuid); + } } } @@ -342,7 +365,6 @@ void MaterialsEditor::propertyChange(const QString& property, const QString valu updatePreview(); } update(); - _edited = true; } void MaterialsEditor::onURL(bool checked) @@ -486,6 +508,7 @@ void MaterialsEditor::onNewMaterial(bool checked) // Create a new material _material = std::make_shared(); setMaterialDefaults(); + _materialSelected = false; } void MaterialsEditor::onInheritNewMaterial(bool checked) @@ -548,6 +571,7 @@ void MaterialsEditor::saveMaterial() updateMaterialGeneral(); _material->resetEditState(); refreshMaterialTree(); + _materialSelected = true; } } @@ -1147,6 +1171,7 @@ void MaterialsEditor::onSelectMaterial(const QItemSelection& selected, updateMaterial(); _material->resetEditState(); + _materialSelected = true; } void MaterialsEditor::onDoubleClick(const QModelIndex& index) @@ -1162,6 +1187,7 @@ void MaterialsEditor::onDoubleClick(const QModelIndex& index) } } + _materialSelected = true; accept(); } diff --git a/src/Mod/Material/Gui/MaterialsEditor.h b/src/Mod/Material/Gui/MaterialsEditor.h index eef3d20cab..05ce0cd8d4 100644 --- a/src/Mod/Material/Gui/MaterialsEditor.h +++ b/src/Mod/Material/Gui/MaterialsEditor.h @@ -36,6 +36,7 @@ #include #include +#include #include #include #include @@ -52,6 +53,8 @@ class MaterialsEditor: public QDialog Q_OBJECT public: + explicit MaterialsEditor(std::shared_ptr filter, + QWidget* parent = nullptr); explicit MaterialsEditor(QWidget* parent = nullptr); ~MaterialsEditor() override = default; @@ -96,6 +99,15 @@ public: void onDoubleClick(const QModelIndex& index); void onContextMenu(const QPoint& pos); + bool isMaterialSelected() const + { + return _materialSelected; + } + std::shared_ptr getMaterial() + { + return _material; + } + protected: int confirmSave(QWidget* parent); void saveMaterial(); @@ -106,11 +118,14 @@ private: Materials::ModelManager _modelManager; std::shared_ptr _material; AppearancePreview* _rendered; - bool _edited; + bool _materialSelected; std::list _favorites; std::list _recents; int _recentMax; QIcon _warningIcon; + std::shared_ptr _filter; + + void setup(); void saveWindow(); void saveMaterialTreeChildren(const Base::Reference& param, diff --git a/src/Mod/Material/MaterialEditor.py b/src/Mod/Material/MaterialEditor.py index 2757a90076..cbcbde9246 100644 --- a/src/Mod/Material/MaterialEditor.py +++ b/src/Mod/Material/MaterialEditor.py @@ -685,9 +685,9 @@ class MaterialEditor: from importFCMat import write write(filename, d) - import Material + import Materials # Load the material - manager = Material.MaterialManager() + manager = Materials.MaterialManager() manager.getMaterialByPath(filename) self.edited = False self.updateCardsInCombo() diff --git a/src/Mod/Material/MaterialGlobal.h b/src/Mod/Material/MaterialGlobal.h index 24aa8fdfb2..2b8b19452e 100644 --- a/src/Mod/Material/MaterialGlobal.h +++ b/src/Mod/Material/MaterialGlobal.h @@ -26,7 +26,7 @@ // Material #ifndef MaterialsExport -#ifdef Material_EXPORTS +#ifdef Materials_EXPORTS #define MaterialsExport FREECAD_DECL_EXPORT #else #define MaterialsExport FREECAD_DECL_IMPORT diff --git a/src/Mod/Material/Resources/Materials/Standard/Default.FCMat b/src/Mod/Material/Resources/Materials/Standard/Default.FCMat new file mode 100644 index 0000000000..7bdec4b53f --- /dev/null +++ b/src/Mod/Material/Resources/Materials/Standard/Default.FCMat @@ -0,0 +1,15 @@ +--- +# File created by ConvertFCMat.py +General: + UUID: "7f9fd73b-50c9-41d8-b7b2-575a030c1eeb" + Author: "David Carter" + License: "GPL-2.0-or-later" + Name: "Default" + Description: "Generic material with density of 1" +Inherits: + Default: + UUID: "5dbb7be6-8b63-479b-ab4c-87be02ead973" +Models: + Density: + UUID: '454661e5-265b-4320-8e6f-fcf6223ac3af' + Density: "1 kg/m^3" diff --git a/src/Mod/Material/Resources/Models/Rendering/TextureRendering.yml b/src/Mod/Material/Resources/Models/Rendering/TextureRendering.yml index 02150163d6..49fbec7a9d 100644 --- a/src/Mod/Material/Resources/Models/Rendering/TextureRendering.yml +++ b/src/Mod/Material/Resources/Models/Rendering/TextureRendering.yml @@ -35,7 +35,12 @@ AppearanceModel: Type: 'File' Units: '' URL: '' - Description: " " + Description: "Path to file containing a texture image. Only used if TextureImage is unpopulated" + TextureImage: + Type: 'Image' + Units: '' + URL: '' + Description: "Embedded texture image" TextureScaling: DisplayName: "Texture Scaling" Type: 'Float' diff --git a/src/Mod/Material/TestMaterialsApp.py b/src/Mod/Material/TestMaterialsApp.py index 30d562dc6f..c53634d312 100644 --- a/src/Mod/Material/TestMaterialsApp.py +++ b/src/Mod/Material/TestMaterialsApp.py @@ -24,7 +24,7 @@ from os import walk import unittest import FreeCAD -import Material +import Materials from materialtests.TestModels import ModelTestCases from materialtests.TestMaterials import MaterialTestCases diff --git a/src/Mod/Material/importFCMat.py b/src/Mod/Material/importFCMat.py index 406455b632..63865d6018 100644 --- a/src/Mod/Material/importFCMat.py +++ b/src/Mod/Material/importFCMat.py @@ -30,7 +30,7 @@ import os import FreeCAD from materialtools.cardutils import get_material_template -import Material +import Materials if FreeCAD.GuiUp: from PySide import QtGui @@ -99,7 +99,7 @@ def decode(name): # https://github.com/berndhahnebach/FreeCAD_bhb/commits/materialdev def read(filename): - materialManager = Material.MaterialManager() + materialManager = Materials.MaterialManager() material = materialManager.getMaterialByPath(filename) return material.Properties diff --git a/src/Mod/Material/materialtests/TestMaterials.py b/src/Mod/Material/materialtests/TestMaterials.py index 7bf7ba3925..31afa42045 100644 --- a/src/Mod/Material/materialtests/TestMaterials.py +++ b/src/Mod/Material/materialtests/TestMaterials.py @@ -26,7 +26,7 @@ Test module for FreeCAD material cards and APIs import unittest import FreeCAD -import Material +import Materials parseQuantity = FreeCAD.Units.parseQuantity @@ -37,9 +37,9 @@ class MaterialTestCases(unittest.TestCase): def setUp(self): """ Setup function to initialize test data """ - self.ModelManager = Material.ModelManager() - self.MaterialManager = Material.MaterialManager() - self.uuids = Material.UUIDs() + self.ModelManager = Materials.ModelManager() + self.MaterialManager = Materials.MaterialManager() + self.uuids = Materials.UUIDs() def testMaterialManager(self): """ Ensure the MaterialManager has been initialized correctly """ diff --git a/src/Mod/Material/materialtests/TestModels.py b/src/Mod/Material/materialtests/TestModels.py index 0956fdb20b..e6c62aa004 100644 --- a/src/Mod/Material/materialtests/TestModels.py +++ b/src/Mod/Material/materialtests/TestModels.py @@ -26,7 +26,7 @@ Test module for FreeCAD material models import unittest import FreeCAD -import Material +import Materials parseQuantity = FreeCAD.Units.parseQuantity @@ -36,8 +36,8 @@ class ModelTestCases(unittest.TestCase): """ def setUp(self): """ Setup function to initialize test data """ - self.ModelManager = Material.ModelManager() - self.uuids = Material.UUIDs() + self.ModelManager = Materials.ModelManager() + self.uuids = Materials.UUIDs() def testModelManager(self): """ Ensure we can access ModelManager member functions """ diff --git a/src/Mod/Material/materialtools/cardutils.py b/src/Mod/Material/materialtools/cardutils.py index 4f5bbb76dc..2dd19479fc 100644 --- a/src/Mod/Material/materialtools/cardutils.py +++ b/src/Mod/Material/materialtools/cardutils.py @@ -28,7 +28,7 @@ from os.path import join from pathlib import Path import FreeCAD -import Material +import Materials unicode = str @@ -260,7 +260,7 @@ def output_resources(resources): # used in material editor and FEM material task panels def import_materials(category='Solid', template=False): - materialManager = Material.MaterialManager() + materialManager = Materials.MaterialManager() mats = materialManager.Materials materials = {} cards = {} diff --git a/src/Mod/Mesh/Gui/MeshEditor.cpp b/src/Mod/Mesh/Gui/MeshEditor.cpp index 63f014fff3..9572c1a830 100644 --- a/src/Mod/Mesh/Gui/MeshEditor.cpp +++ b/src/Mod/Mesh/Gui/MeshEditor.cpp @@ -23,10 +23,10 @@ #include "PreCompiled.h" #ifndef _PreComp_ -#include -#include #include #include +#include +#include #include #include @@ -51,8 +51,8 @@ #include #include #include -#include #include +#include #include "MeshEditor.h" #include "SoFCMeshObject.h" @@ -117,7 +117,7 @@ void ViewProviderFace::attach(App::DocumentObject* obj) SoBaseColor* basecol = new SoBaseColor; if (mesh) { - App::Color col = mesh->ShapeColor.getValue(); + App::Color col = mesh->ShapeAppearance.getDiffuseColor(); basecol->rgb.setValue(col.r, col.g, col.b); } else { diff --git a/src/Mod/Mesh/Gui/ViewProvider.cpp b/src/Mod/Mesh/Gui/ViewProvider.cpp index a6bd2b286c..2a40a287d1 100644 --- a/src/Mod/Mesh/Gui/ViewProvider.cpp +++ b/src/Mod/Mesh/Gui/ViewProvider.cpp @@ -22,32 +22,32 @@ #include "PreCompiled.h" #ifndef _PreComp_ -#include #include #include +#include #include #include #include #include +#include #include #include #include #include #include #include -#include #include #include +#include #include #include #include #include #include -#include #include +#include #include -#include #endif #include @@ -267,7 +267,7 @@ ViewProviderMesh::ViewProviderMesh() pcHighlight->addChild(pcShapeGroup); pOpenColor = new SoBaseColor(); - setOpenEdgeColorFrom(ShapeColor.getValue()); + setOpenEdgeColorFrom(ShapeAppearance.getDiffuseColor()); pOpenColor->ref(); pcLineStyle = new SoDrawStyle(); @@ -297,12 +297,12 @@ ViewProviderMesh::ViewProviderMesh() Gui::WindowParameter::getDefaultParameter()->GetGroup("Mod/Mesh"); // Mesh color - App::Color color = ShapeColor.getValue(); + App::Color color = ShapeAppearance.getDiffuseColor(); unsigned long current = color.getPackedValue(); unsigned long setting = hGrp->GetUnsigned("MeshColor", current); if (current != setting) { color.setPackedValue((uint32_t)setting); - ShapeColor.setValue(color); + ShapeAppearance.setDiffuseColor(color); } Transparency.setValue(hGrp->GetInt("MeshTransparency", 0)); @@ -353,7 +353,8 @@ ViewProviderMesh::~ViewProviderMesh() void ViewProviderMesh::onChanged(const App::Property* prop) { // we're going to change the number of colors to one - if (prop == &ShapeColor || prop == &ShapeMaterial) { + // if (prop == &ShapeAppearance || prop == &ShapeMaterial) { + if (prop == &ShapeAppearance) { pcMatBinding->value = SoMaterialBinding::OVERALL; } if (prop == &LineTransparency) { @@ -393,12 +394,12 @@ void ViewProviderMesh::onChanged(const App::Property* prop) } else { // Set the inverse color for open edges - if (prop == &ShapeColor) { - setOpenEdgeColorFrom(ShapeColor.getValue()); - } - else if (prop == &ShapeMaterial) { - setOpenEdgeColorFrom(ShapeMaterial.getValue().diffuseColor); + if (prop == &ShapeAppearance) { + setOpenEdgeColorFrom(ShapeAppearance.getDiffuseColor()); } + // else if (prop == &ShapeMaterial) { + // setOpenEdgeColorFrom(ShapeMaterial.getValue().diffuseColor); + // } } ViewProviderGeometryObject::onChanged(prop); @@ -597,7 +598,7 @@ void ViewProviderMesh::tryColorPerVertexOrFace(bool on) } else { pcMatBinding->value = SoMaterialBinding::OVERALL; - const App::Color& c = ShapeColor.getValue(); + const App::Color& c = ShapeAppearance.getDiffuseColor(); pcShapeMaterial->diffuseColor.setValue(c.r, c.g, c.b); pcShapeMaterial->transparency.setValue(Transparency.getValue() / 100.0f); } @@ -1987,7 +1988,7 @@ void ViewProviderMesh::fillHole(Mesh::FacetIndex uFacet) void ViewProviderMesh::setFacetTransparency(const std::vector& facetTransparency) { if (pcShapeMaterial->diffuseColor.getNum() != int(facetTransparency.size())) { - App::Color c = ShapeColor.getValue(); + App::Color c = ShapeAppearance.getDiffuseColor(); pcShapeMaterial->diffuseColor.setNum(facetTransparency.size()); SbColor* cols = pcShapeMaterial->diffuseColor.startEditing(); for (std::size_t index = 0; index < facetTransparency.size(); ++index) { @@ -2009,7 +2010,7 @@ void ViewProviderMesh::setFacetTransparency(const std::vector& facetTrans void ViewProviderMesh::resetFacetTransparency() { pcMatBinding->value = SoMaterialBinding::OVERALL; - App::Color c = ShapeColor.getValue(); + App::Color c = ShapeAppearance.getDiffuseColor(); pcShapeMaterial->diffuseColor.setValue(c.r, c.g, c.b); pcShapeMaterial->transparency.setValue(0); } @@ -2115,7 +2116,7 @@ void ViewProviderMesh::deselectFacet(Mesh::FacetIndex facet) highlightSelection(); } else { - App::Color c = ShapeColor.getValue(); + App::Color c = ShapeAppearance.getDiffuseColor(); pcShapeMaterial->diffuseColor.set1Value(facet, c.r, c.g, c.b); } } @@ -2285,7 +2286,7 @@ void ViewProviderMesh::highlightSelection() // Colorize the selection pcMatBinding->value = SoMaterialBinding::PER_FACE; - App::Color c = ShapeColor.getValue(); + App::Color c = ShapeAppearance.getDiffuseColor(); int uCtFacets = (int)rMesh.countFacets(); pcShapeMaterial->diffuseColor.setNum(uCtFacets); @@ -2301,7 +2302,7 @@ void ViewProviderMesh::highlightSelection() void ViewProviderMesh::unhighlightSelection() { - App::Color c = ShapeColor.getValue(); + App::Color c = ShapeAppearance.getDiffuseColor(); pcMatBinding->value = SoMaterialBinding::OVERALL; pcShapeMaterial->diffuseColor.setNum(1); pcShapeMaterial->diffuseColor.setValue(c.r, c.g, c.b); @@ -2359,7 +2360,7 @@ void ViewProviderMesh::highlightSegments() std::vector colors; const Mesh::MeshObject& rMesh = static_cast(pcObject)->Mesh.getValue(); unsigned long numSegm = rMesh.countSegments(); - colors.resize(numSegm, this->ShapeColor.getValue()); + colors.resize(numSegm, this->ShapeAppearance.getDiffuseColor()); for (unsigned long i = 0; i < numSegm; i++) { App::Color col; diff --git a/src/Mod/Part/App/CMakeLists.txt b/src/Mod/Part/App/CMakeLists.txt index a43945c48a..0e6e3f3637 100644 --- a/src/Mod/Part/App/CMakeLists.txt +++ b/src/Mod/Part/App/CMakeLists.txt @@ -21,6 +21,7 @@ set(Part_LIBS ${OCC_LIBRARIES} ${OCC_DEBUG_LIBRARIES} FreeCADApp + Materials ) if(FREETYPE_FOUND) @@ -567,17 +568,16 @@ if(FREECAD_USE_PCH) endif(FREECAD_USE_PCH) # Suppress some very long Eigen3 warnings of older versions -if (EIGEN3_NO_DEPRECATED_COPY) +if(EIGEN3_NO_DEPRECATED_COPY) set_source_files_properties( GeometryCurvePyImp.cpp GeometrySurfacePyImp.cpp PROPERTIES COMPILE_FLAGS ${EIGEN3_NO_DEPRECATED_COPY}) -endif () +endif() add_library(Part SHARED ${Part_SRCS}) target_link_libraries(Part ${Part_LIBS}) - SET_BIN_DIR(Part Part /Mod/Part) SET_PYTHON_PREFIX_SUFFIX(Part) diff --git a/src/Mod/Part/App/ImportStep.cpp b/src/Mod/Part/App/ImportStep.cpp index 208bd94697..4c13aaf2af 100644 --- a/src/Mod/Part/App/ImportStep.cpp +++ b/src/Mod/Part/App/ImportStep.cpp @@ -147,7 +147,7 @@ int Part::ImportStepParts(App::Document *pcDoc, const char* Name) col.setItem(0, Py::Float(it->second.Red())); col.setItem(1, Py::Float(it->second.Green())); col.setItem(2, Py::Float(it->second.Blue())); - vp.setAttr("ShapeColor", col); + vp.setAttr("ShapeAppearance", col); //Base::Console().Message("Set color to shape\n"); } catch (Py::Exception& e) { diff --git a/src/Mod/Part/App/PartFeature.cpp b/src/Mod/Part/App/PartFeature.cpp index 16cb49dbfe..a359982cb0 100644 --- a/src/Mod/Part/App/PartFeature.cpp +++ b/src/Mod/Part/App/PartFeature.cpp @@ -66,6 +66,7 @@ #include #include #include +#include #include "PartFeature.h" #include "PartFeaturePy.h" @@ -83,6 +84,9 @@ PROPERTY_SOURCE(Part::Feature, App::GeoFeature) Feature::Feature() { ADD_PROPERTY(Shape, (TopoDS_Shape())); + auto mat = Materials::MaterialManager::defaultMaterial(); + // ADD_PROPERTY_TYPE(ShapeMaterial, (mat), osgroup, App::Prop_None, "Shape material"); + ADD_PROPERTY(ShapeMaterial, (*mat)); } Feature::~Feature() = default; @@ -589,6 +593,15 @@ TopoDS_Shape Feature::getShape(const App::DocumentObject *obj, const char *subna return getTopoShape(obj,subname,needSubElement,pmat,powner,resolveLink,transform,true).getShape(); } +App::Material Feature::getMaterialAppearance() const +{ + return ShapeMaterial.getValue().getMaterialAppearance(); +} + +void Feature::setMaterialAppearance(const App::Material& material) +{ + ShapeMaterial.setValue(material); +} // Toponaming project March 2024: This method should be going away when we get to the python layer. void Feature::clearShapeCache() { diff --git a/src/Mod/Part/App/PartFeature.h b/src/Mod/Part/App/PartFeature.h index f4888669ea..56a482d57a 100644 --- a/src/Mod/Part/App/PartFeature.h +++ b/src/Mod/Part/App/PartFeature.h @@ -25,6 +25,7 @@ #include #include +#include #include #include @@ -57,6 +58,7 @@ public: ~Feature() override; PropertyPartShape Shape; + Materials::PropertyMaterial ShapeMaterial; /** @name methods override feature */ //@{ @@ -105,6 +107,9 @@ public: DocumentObject *getSubObject(const char *subname, PyObject **pyObj, Base::Matrix4D *mat, bool transform, int depth) const override; + App::Material getMaterialAppearance() const override; + void setMaterialAppearance(const App::Material& material) override; + /** Convenience function to extract shape from fully qualified subname * * @param obj: the parent object diff --git a/src/Mod/Part/BOPTools/BOPFeatures.py b/src/Mod/Part/BOPTools/BOPFeatures.py index 6244164eb7..a069a01870 100644 --- a/src/Mod/Part/BOPTools/BOPFeatures.py +++ b/src/Mod/Part/BOPTools/BOPFeatures.py @@ -103,7 +103,7 @@ class BOPFeatures: def copy_visual_attributes(self, target, source): if target.ViewObject: - target.ViewObject.ShapeColor = source.ViewObject.ShapeColor + target.ViewObject.ShapeAppearance = source.ViewObject.ShapeAppearance displayMode = source.ViewObject.DisplayMode src = source while displayMode == "Link": diff --git a/src/Mod/Part/Gui/CMakeLists.txt b/src/Mod/Part/Gui/CMakeLists.txt index d2b2f9cf9f..7cdd529d43 100644 --- a/src/Mod/Part/Gui/CMakeLists.txt +++ b/src/Mod/Part/Gui/CMakeLists.txt @@ -15,6 +15,7 @@ link_directories(${OCC_LIBRARY_DIR}) set(PartGui_LIBS Part FreeCADGui + MatGui ) if(MSVC) diff --git a/src/Mod/Part/Gui/Command.cpp b/src/Mod/Part/Gui/Command.cpp index d0f5099f96..4ef844b170 100644 --- a/src/Mod/Part/Gui/Command.cpp +++ b/src/Mod/Part/Gui/Command.cpp @@ -925,7 +925,7 @@ void CmdPartSection::activated(int iMsg) doCommand(Doc,"App.activeDocument().%s.Tool = App.activeDocument().%s",FeatName.c_str(),ToolName.c_str()); doCommand(Gui,"Gui.activeDocument().hide('%s')",BaseName.c_str()); doCommand(Gui,"Gui.activeDocument().hide('%s')",ToolName.c_str()); - doCommand(Gui,"Gui.activeDocument().%s.LineColor = Gui.activeDocument().%s.ShapeColor", FeatName.c_str(),BaseName.c_str()); + doCommand(Gui,"Gui.activeDocument().%s.LineColor = Gui.activeDocument().%s.ShapeAppearance.DiffuseColor",FeatName.c_str(),BaseName.c_str()); updateActive(); commitCommand(); } @@ -1215,7 +1215,7 @@ void CmdPartReverseShape::activated(int iMsg) try { runCommand(Doc, str.toLatin1()); - copyVisual(name.c_str(), "ShapeColor", it->getNameInDocument()); + copyVisual(name.c_str(), "ShapeAppearance", it->getNameInDocument()); copyVisual(name.c_str(), "LineColor" , it->getNameInDocument()); copyVisual(name.c_str(), "PointColor", it->getNameInDocument()); } @@ -1656,7 +1656,7 @@ void CmdPartOffset::activated(int iMsg) adjustCameraPosition(); - copyVisual(offset.c_str(), "ShapeColor", shape->getNameInDocument()); + copyVisual(offset.c_str(), "ShapeAppearance", shape->getNameInDocument()); copyVisual(offset.c_str(), "LineColor" , shape->getNameInDocument()); copyVisual(offset.c_str(), "PointColor", shape->getNameInDocument()); } @@ -1712,7 +1712,7 @@ void CmdPartOffset2D::activated(int iMsg) doCommand(Gui,"Gui.ActiveDocument.setEdit('%s')",offset.c_str()); adjustCameraPosition(); - copyVisual(offset.c_str(), "ShapeColor", shape->getNameInDocument()); + copyVisual(offset.c_str(), "ShapeAppearance", shape->getNameInDocument()); copyVisual(offset.c_str(), "LineColor" , shape->getNameInDocument()); copyVisual(offset.c_str(), "PointColor", shape->getNameInDocument()); } @@ -1896,7 +1896,7 @@ void CmdPartThickness::activated(int iMsg) doCommand(Gui,"Gui.ActiveDocument.setEdit('%s')",thick.c_str()); adjustCameraPosition(); - copyVisual(thick.c_str(), "ShapeColor", obj->getNameInDocument()); + copyVisual(thick.c_str(), "ShapeAppearance", obj->getNameInDocument()); copyVisual(thick.c_str(), "LineColor" , obj->getNameInDocument()); copyVisual(thick.c_str(), "PointColor", obj->getNameInDocument()); } diff --git a/src/Mod/Part/Gui/CommandSimple.cpp b/src/Mod/Part/Gui/CommandSimple.cpp index 60dce779c4..b53392b85e 100644 --- a/src/Mod/Part/Gui/CommandSimple.cpp +++ b/src/Mod/Part/Gui/CommandSimple.cpp @@ -263,7 +263,7 @@ static void _copyShape(const char *cmdName, bool resolve,bool needElement=false, v.second->getNameInDocument(), Gui::Command::getObjectCmd(v.second).c_str()); auto newObj = App::GetApplication().getActiveDocument()->getActiveObject(); - Gui::Command::copyVisual(newObj, "ShapeColor", v.second); + Gui::Command::copyVisual(newObj, "ShapeAppearance", v.second); Gui::Command::copyVisual(newObj, "LineColor", v.second); Gui::Command::copyVisual(newObj, "PointColor", v.second); } @@ -378,7 +378,7 @@ void CmdPartRefineShape::activated(int iMsg) obj->getNameInDocument(), obj->getNameInDocument()); - copyVisual("ActiveObject", "ShapeColor", obj->getNameInDocument()); + copyVisual("ActiveObject", "ShapeAppearance", obj->getNameInDocument()); copyVisual("ActiveObject", "LineColor", obj->getNameInDocument()); copyVisual("ActiveObject", "PointColor", obj->getNameInDocument()); } diff --git a/src/Mod/Part/Gui/DlgExtrusion.cpp b/src/Mod/Part/Gui/DlgExtrusion.cpp index 7556ccfeb1..a8c1f005d6 100644 --- a/src/Mod/Part/Gui/DlgExtrusion.cpp +++ b/src/Mod/Part/Gui/DlgExtrusion.cpp @@ -481,7 +481,7 @@ void DlgExtrusion::apply() this->writeParametersToFeature(*newObj, sourceObj); - Gui::Command::copyVisual(newObj, "ShapeColor", sourceObj); + Gui::Command::copyVisual(newObj, "ShapeAppearance", sourceObj); Gui::Command::copyVisual(newObj, "LineColor", sourceObj); Gui::Command::copyVisual(newObj, "PointColor", sourceObj); diff --git a/src/Mod/Part/Gui/DlgProjectionOnSurface.cpp b/src/Mod/Part/Gui/DlgProjectionOnSurface.cpp index f685db0d89..a84f890a33 100644 --- a/src/Mod/Part/Gui/DlgProjectionOnSurface.cpp +++ b/src/Mod/Part/Gui/DlgProjectionOnSurface.cpp @@ -655,7 +655,7 @@ void PartGui::DlgProjectionOnSurface::show_projected_shapes( if (vp) { const unsigned int color = 0x8ae23400; vp->LineColor.setValue(color); - vp->ShapeColor.setValue(color); + vp->ShapeAppearance.setDiffuseColor(App::Color(color)); vp->PointColor.setValue(color); vp->Transparency.setValue(0); } @@ -716,20 +716,22 @@ void PartGui::DlgProjectionOnSurface::higlight_object(Part::Feature* iCurrentObj } auto index = anIndices.FindIndex(currentShape); - // set color - auto vp = dynamic_cast( - Gui::Application::Instance->getViewProvider(iCurrentObject)); - if (vp) { - std::vector colors; - App::Color defaultColor; - if (currentShapeType == TopAbs_FACE) { - colors = vp->DiffuseColor.getValues(); - defaultColor = vp->ShapeColor.getValue(); - } - else if (currentShapeType == TopAbs_EDGE) { - colors = vp->LineColorArray.getValues(); - defaultColor = vp->LineColor.getValue(); - } + //set color + PartGui::ViewProviderPartExt* vp = dynamic_cast(Gui::Application::Instance->getViewProvider(iCurrentObject)); + if (vp) + { + std::vector colors; + App::Color defaultColor; + if (currentShapeType == TopAbs_FACE) + { + colors = vp->DiffuseColor.getValues(); + defaultColor = vp->ShapeAppearance.getDiffuseColor(); + } + else if ( currentShapeType == TopAbs_EDGE ) + { + colors = vp->LineColorArray.getValues(); + defaultColor = vp->LineColor.getValue(); + } if (static_cast(colors.size()) != anIndices.Extent()) { colors.resize(anIndices.Extent(), defaultColor); diff --git a/src/Mod/Part/Gui/DlgRevolution.cpp b/src/Mod/Part/Gui/DlgRevolution.cpp index bad05e1a1f..b193a1e777 100644 --- a/src/Mod/Part/Gui/DlgRevolution.cpp +++ b/src/Mod/Part/Gui/DlgRevolution.cpp @@ -431,7 +431,7 @@ void DlgRevolution::accept() Gui::Command::runCommand(Gui::Command::App, code.toLatin1()); QByteArray to = name.toLatin1(); QByteArray from = shape.toLatin1(); - Gui::Command::copyVisual(to, "ShapeColor", from); + Gui::Command::copyVisual(to, "ShapeAppearance", from); Gui::Command::copyVisual(to, "LineColor", from); Gui::Command::copyVisual(to, "PointColor", from); } diff --git a/src/Mod/Part/Gui/DlgScale.cpp b/src/Mod/Part/Gui/DlgScale.cpp index d83b017086..4dcd4782f2 100644 --- a/src/Mod/Part/Gui/DlgScale.cpp +++ b/src/Mod/Part/Gui/DlgScale.cpp @@ -235,7 +235,7 @@ void DlgScale::apply() this->writeParametersToFeature(*newObj, sourceObj); - Gui::Command::copyVisual(newObj, "ShapeColor", sourceObj); + Gui::Command::copyVisual(newObj, "ShapeAppearance", sourceObj); Gui::Command::copyVisual(newObj, "LineColor", sourceObj); Gui::Command::copyVisual(newObj, "PointColor", sourceObj); diff --git a/src/Mod/Part/Gui/Mirroring.cpp b/src/Mod/Part/Gui/Mirroring.cpp index ced38bd130..2f8f60963e 100644 --- a/src/Mod/Part/Gui/Mirroring.cpp +++ b/src/Mod/Part/Gui/Mirroring.cpp @@ -342,7 +342,7 @@ bool Mirroring::accept() .arg(selectionString); Gui::Command::runCommand(Gui::Command::App, code.toLatin1()); QByteArray from = shape.toLatin1(); - Gui::Command::copyVisual("ActiveObject", "ShapeColor", from); + Gui::Command::copyVisual("ActiveObject", "ShapeAppearance", from); Gui::Command::copyVisual("ActiveObject", "LineColor", from); Gui::Command::copyVisual("ActiveObject", "PointColor", from); } diff --git a/src/Mod/Part/Gui/SectionCutting.cpp b/src/Mod/Part/Gui/SectionCutting.cpp index d17a281548..3bcad2c2db 100644 --- a/src/Mod/Part/Gui/SectionCutting.cpp +++ b/src/Mod/Part/Gui/SectionCutting.cpp @@ -148,7 +148,7 @@ void SectionCut::initControls(const Base::BoundBox3d& BoundCompound) auto vpBox = dynamic_cast( Gui::Application::Instance->getViewProvider(pcBox)); if (vpBox) { - cutColor = vpBox->ShapeColor.getValue(); + cutColor = vpBox->ShapeAppearance.getDiffuseColor(); cutTransparency = vpBox->Transparency.getValue(); ui->CutColor->setColor(cutColor.asValue()); ui->CutTransparencyHS->setValue(int(cutTransparency)); @@ -295,7 +295,7 @@ void SectionCut::initBooleanFragmentControls(Gui::ViewProviderGeometryObject* co ui->groupBoxIntersecting->setChecked(true); if (compoundBF) { - App::Color compoundColor = compoundBF->ShapeColor.getValue(); + App::Color compoundColor = compoundBF->ShapeAppearance.getDiffuseColor(); ui->BFragColor->setColor(compoundColor.asValue()); long compoundTransparency = compoundBF->Transparency.getValue(); ui->BFragTransparencyHS->setValue(int(compoundTransparency)); @@ -945,7 +945,7 @@ App::Color getFirstColor(const std::vector& objects) auto vpFirstObject = dynamic_cast( Gui::Application::Instance->getViewProvider(objects.front())); if (vpFirstObject) { - cutColor = vpFirstObject->ShapeColor.getValue(); + cutColor = vpFirstObject->ShapeAppearance.getDiffuseColor(); } return cutColor; } @@ -968,7 +968,7 @@ bool isAutoColor(const App::Color& color, const std::vector( Gui::Application::Instance->getViewProvider(itCuts)); if (vpObject) { - if (color != vpObject->ShapeColor.getValue()) { + if (color != vpObject->ShapeAppearance.getDiffuseColor()) { autoColor = false; break; } @@ -1344,7 +1344,7 @@ void SectionCut::createAllObjects(const std::vector& Objec auto vpBox = dynamic_cast( Gui::Application::Instance->getViewProvider(pcBox)); if (vpBox) { - vpBox->ShapeColor.setValue(boxColor); + vpBox->ShapeAppearance.setDiffuseColor(boxColor); vpBox->Transparency.setValue(boxTransparency); } }; @@ -2064,7 +2064,7 @@ void SectionCut::changeCutBoxColors() if (boxVPGO) { App::Color boxColor; boxColor.setValue(ui->CutColor->color()); - boxVPGO->ShapeColor.setValue(boxColor); + boxVPGO->ShapeAppearance.setDiffuseColor(boxColor); int boxTransparency = ui->CutTransparencyHS->value(); boxVPGO->Transparency.setValue(boxTransparency); } @@ -2172,7 +2172,7 @@ void SectionCut::setBooleanFragmentsColor() if (CutCompoundBFGeom) { App::Color BFColor; BFColor.setValue(ui->BFragColor->color()); - CutCompoundBFGeom->ShapeColor.setValue(BFColor); + CutCompoundBFGeom->ShapeAppearance.setDiffuseColor(BFColor); int BFTransparency = ui->BFragTransparencyHS->value(); CutCompoundBFGeom->Transparency.setValue(BFTransparency); compoundObject->recomputeFeature(false); diff --git a/src/Mod/Part/Gui/TaskFaceColors.cpp b/src/Mod/Part/Gui/TaskFaceColors.cpp index a6cf3ef8de..4ab51e6923 100644 --- a/src/Mod/Part/Gui/TaskFaceColors.cpp +++ b/src/Mod/Part/Gui/TaskFaceColors.cpp @@ -115,7 +115,7 @@ public: std::vector current = vp->DiffuseColor.getValues(); if (current.empty()) - current.push_back(vp->ShapeColor.getValue()); + current.push_back(vp->ShapeAppearance.getDiffuseColor()); perface = current; perface.resize(mapOfShape.Extent(), perface.front()); @@ -332,7 +332,7 @@ void FaceColors::onBoxSelectionToggled(bool checked) void FaceColors::onDefaultButtonClicked() { - std::fill(d->perface.begin(), d->perface.end(), d->vp->ShapeColor.getValue()); + std::fill(d->perface.begin(), d->perface.end(), d->vp->ShapeAppearance.getDiffuseColor()); d->vp->DiffuseColor.setValues(d->perface); } diff --git a/src/Mod/Part/Gui/ViewProviderBoolean.cpp b/src/Mod/Part/Gui/ViewProviderBoolean.cpp index 63df4c898d..faeb6b2eb8 100644 --- a/src/Mod/Part/Gui/ViewProviderBoolean.cpp +++ b/src/Mod/Part/Gui/ViewProviderBoolean.cpp @@ -103,14 +103,14 @@ void ViewProviderBoolean::updateData(const App::Property* prop) std::vector colBase = vpBase->DiffuseColor.getValues(); std::vector colTool = vpTool->DiffuseColor.getValues(); std::vector colBool; - colBool.resize(boolMap.Extent(), this->ShapeColor.getValue()); + colBool.resize(boolMap.Extent(), this->ShapeAppearance.getDiffuseColor()); applyTransparency(vpBase->Transparency.getValue(),colBase); applyTransparency(vpTool->Transparency.getValue(),colTool); if (static_cast(colBase.size()) == baseMap.Extent()) { applyColor(hist[0], colBase, colBool); } - else if (!colBase.empty() && colBase[0] != this->ShapeColor.getValue()) { + else if (!colBase.empty() && colBase[0] != this->ShapeAppearance.getDiffuseColor()) { colBase.resize(baseMap.Extent(), colBase[0]); applyColor(hist[0], colBase, colBool); } @@ -118,7 +118,7 @@ void ViewProviderBoolean::updateData(const App::Property* prop) if (static_cast(colTool.size()) == toolMap.Extent()) { applyColor(hist[1], colTool, colBool); } - else if (!colTool.empty() && colTool[0] != this->ShapeColor.getValue()) { + else if (!colTool.empty() && colTool[0] != this->ShapeAppearance.getDiffuseColor()) { colTool.resize(toolMap.Extent(), colTool[0]); applyColor(hist[1], colTool, colBool); } @@ -187,7 +187,7 @@ void ViewProviderMultiFuse::updateData(const App::Property* prop) TopExp::MapShapes(boolShape, TopAbs_FACE, boolMap); std::vector colBool; - colBool.resize(boolMap.Extent(), this->ShapeColor.getValue()); + colBool.resize(boolMap.Extent(), this->ShapeAppearance.getDiffuseColor()); int index=0; for (std::vector::iterator it = sources.begin(); it != sources.end(); ++it, ++index) { @@ -206,7 +206,7 @@ void ViewProviderMultiFuse::updateData(const App::Property* prop) if (static_cast(colBase.size()) == baseMap.Extent()) { applyColor(hist[index], colBase, colBool); } - else if (!colBase.empty() && colBase[0] != this->ShapeColor.getValue()) { + else if (!colBase.empty() && colBase[0] != this->ShapeAppearance.getDiffuseColor()) { colBase.resize(baseMap.Extent(), colBase[0]); applyColor(hist[index], colBase, colBool); } @@ -322,7 +322,7 @@ void ViewProviderMultiCommon::updateData(const App::Property* prop) TopExp::MapShapes(boolShape, TopAbs_FACE, boolMap); std::vector colBool; - colBool.resize(boolMap.Extent(), this->ShapeColor.getValue()); + colBool.resize(boolMap.Extent(), this->ShapeAppearance.getDiffuseColor()); int index=0; for (std::vector::iterator it = sources.begin(); it != sources.end(); ++it, ++index) { @@ -341,7 +341,7 @@ void ViewProviderMultiCommon::updateData(const App::Property* prop) if (static_cast(colBase.size()) == baseMap.Extent()) { applyColor(hist[index], colBase, colBool); } - else if (!colBase.empty() && colBase[0] != this->ShapeColor.getValue()) { + else if (!colBase.empty() && colBase[0] != this->ShapeAppearance.getDiffuseColor()) { colBase.resize(baseMap.Extent(), colBase[0]); applyColor(hist[index], colBase, colBool); } diff --git a/src/Mod/Part/Gui/ViewProviderCompound.cpp b/src/Mod/Part/Gui/ViewProviderCompound.cpp index 37bac27534..d0094e7ac0 100644 --- a/src/Mod/Part/Gui/ViewProviderCompound.cpp +++ b/src/Mod/Part/Gui/ViewProviderCompound.cpp @@ -96,7 +96,7 @@ void ViewProviderCompound::updateData(const App::Property* prop) TopExp::MapShapes(compShape, TopAbs_FACE, compMap); std::vector compCol; - compCol.resize(compMap.Extent(), this->ShapeColor.getValue()); + compCol.resize(compMap.Extent(), this->ShapeAppearance.getDiffuseColor()); int index=0; for (std::vector::iterator it = sources.begin(); it != sources.end(); ++it, ++index) { @@ -116,7 +116,7 @@ void ViewProviderCompound::updateData(const App::Property* prop) if (static_cast(baseCol.size()) == baseMap.Extent()) { applyColor(hist[index], baseCol, compCol); } - else if (!baseCol.empty() && baseCol[0] != this->ShapeColor.getValue()) { + else if (!baseCol.empty() && baseCol[0] != this->ShapeAppearance.getDiffuseColor()) { baseCol.resize(baseMap.Extent(), baseCol[0]); applyColor(hist[index], baseCol, compCol); } diff --git a/src/Mod/Part/Gui/ViewProviderExt.cpp b/src/Mod/Part/Gui/ViewProviderExt.cpp index e0fd102b58..e246d7900f 100644 --- a/src/Mod/Part/Gui/ViewProviderExt.cpp +++ b/src/Mod/Part/Gui/ViewProviderExt.cpp @@ -162,7 +162,7 @@ ViewProviderPartExt::ViewProviderPartExt() ADD_PROPERTY_TYPE(LineColor, (lmat.diffuseColor), osgroup, App::Prop_None, "Set object line color."); ADD_PROPERTY_TYPE(PointColor, (vmat.diffuseColor), osgroup, App::Prop_None, "Set object point color"); ADD_PROPERTY_TYPE(PointColorArray, (PointColor.getValue()), osgroup, App::Prop_None, "Object point color array."); - ADD_PROPERTY_TYPE(DiffuseColor,(ShapeColor.getValue()), osgroup, App::Prop_None, "Object diffuse color."); + ADD_PROPERTY_TYPE(DiffuseColor,(ShapeAppearance.getDiffuseColors()), osgroup, App::Prop_None, "Object diffuse color."); ADD_PROPERTY_TYPE(LineColorArray,(LineColor.getValue()), osgroup, App::Prop_None, "Object line color array."); ADD_PROPERTY_TYPE(LineWidth,(lwidth), osgroup, App::Prop_None, "Set object line width."); LineWidth.setConstraints(&sizeRange); @@ -318,28 +318,28 @@ void ViewProviderPartExt::onChanged(const App::Property* prop) else if (prop == &DiffuseColor) { setHighlightedFaces(DiffuseColor.getValues()); } - else if (prop == &ShapeMaterial || prop == &ShapeColor) { - pcFaceBind->value = SoMaterialBinding::OVERALL; - ViewProviderGeometryObject::onChanged(prop); - App::Color c = ShapeColor.getValue(); - c.a = Transparency.getValue()/100.0f; - DiffuseColor.setValue(c); - } +// else if (prop == &ShapeMaterial) { +// pcFaceBind->value = SoMaterialBinding::OVERALL; +// ViewProviderGeometryObject::onChanged(prop); +// App::Color c = ShapeAppearance.getDiffuseColor(); +// c.a = Transparency.getValue()/100.0f; +// DiffuseColor.setValue(c); +// } else if (prop == &Transparency) { - const App::Material& Mat = ShapeMaterial.getValue(); - long value = (long)(100*Mat.transparency); - if (value != Transparency.getValue()) { - float trans = Transparency.getValue()/100.0f; - auto colors = DiffuseColor.getValues(); - for (auto &c : colors) - c.a = trans; - DiffuseColor.setValues(colors); - - App::PropertyContainer* parent = ShapeMaterial.getContainer(); - ShapeMaterial.setContainer(nullptr); - ShapeMaterial.setTransparency(trans); - ShapeMaterial.setContainer(parent); - } +// const App::Material& Mat = ShapeMaterial.getValue(); +// long value = (long)(100*Mat.transparency); +// if (value != Transparency.getValue()) { +// float trans = Transparency.getValue()/100.0f; +// auto colors = DiffuseColor.getValues(); +// for (auto &c : colors) +// c.a = trans; +// DiffuseColor.setValues(colors); +// +// App::PropertyContainer* parent = ShapeMaterial.getContainer(); +// ShapeMaterial.setContainer(nullptr); +// ShapeMaterial.setTransparency(trans); +// ShapeMaterial.setContainer(parent); +// } } else if (prop == &Lighting) { if (Lighting.getValue() == 0) @@ -652,7 +652,7 @@ std::map ViewProviderPartExt::getElementColors(const cha std::map ret; if(!element || !element[0]) { - auto color = ShapeColor.getValue(); + auto color = ShapeAppearance.getDiffuseColor(); color.a = Transparency.getValue()/100.0f; ret["Face"] = color; ret["Edge"] = LineColor.getValue(); @@ -663,7 +663,7 @@ std::map ViewProviderPartExt::getElementColors(const cha if(boost::starts_with(element,"Face")) { auto size = DiffuseColor.getSize(); if(element[4]=='*') { - auto color = ShapeColor.getValue(); + auto color = ShapeAppearance.getDiffuseColor(); color.a = Transparency.getValue()/100.0f; bool singleColor = true; for(int i=0;i ViewProviderPartExt::getElementColors(const cha if(idx>0 && idx<=size) ret[element] = DiffuseColor[idx-1]; else - ret[element] = ShapeColor.getValue(); + ret[element] = ShapeAppearance.getDiffuseColor(); if(size==1) ret[element].a = Transparency.getValue()/100.0f; } diff --git a/src/Mod/Part/Gui/ViewProviderMirror.cpp b/src/Mod/Part/Gui/ViewProviderMirror.cpp index 1c3393f3d2..eec50b2641 100644 --- a/src/Mod/Part/Gui/ViewProviderMirror.cpp +++ b/src/Mod/Part/Gui/ViewProviderMirror.cpp @@ -265,13 +265,13 @@ void ViewProviderFillet::updateData(const App::Property* prop) if (vpBase) { std::vector colBase = vpBase->DiffuseColor.getValues(); std::vector colFill; - colFill.resize(fillMap.Extent(), vpBase->ShapeColor.getValue()); + colFill.resize(fillMap.Extent(), vpBase->ShapeAppearance.getDiffuseColor()); applyTransparency(vpBase->Transparency.getValue(),colBase); if (static_cast(colBase.size()) == baseMap.Extent()) { applyColor(hist[0], colBase, colFill); } - else if (!colBase.empty() && colBase[0] != this->ShapeColor.getValue()) { + else if (!colBase.empty() && colBase[0] != this->ShapeAppearance.getDiffuseColor()) { colBase.resize(baseMap.Extent(), colBase[0]); applyColor(hist[0], colBase, colFill); } @@ -375,13 +375,13 @@ void ViewProviderChamfer::updateData(const App::Property* prop) if (vpBase) { std::vector colBase = static_cast(vpBase)->DiffuseColor.getValues(); std::vector colCham; - colCham.resize(chamMap.Extent(), static_cast(vpBase)->ShapeColor.getValue()); + colCham.resize(chamMap.Extent(), static_cast(vpBase)->ShapeAppearance.getDiffuseColor()); applyTransparency(static_cast(vpBase)->Transparency.getValue(),colBase); if (static_cast(colBase.size()) == baseMap.Extent()) { applyColor(hist[0], colBase, colCham); } - else if (!colBase.empty() && colBase[0] != this->ShapeColor.getValue()) { + else if (!colBase.empty() && colBase[0] != this->ShapeAppearance.getDiffuseColor()) { colBase.resize(baseMap.Extent(), colBase[0]); applyColor(hist[0], colBase, colCham); } diff --git a/src/Mod/Part/Gui/ViewProviderProjectOnSurface.cpp b/src/Mod/Part/Gui/ViewProviderProjectOnSurface.cpp index 831c681f2c..63ffa9442a 100644 --- a/src/Mod/Part/Gui/ViewProviderProjectOnSurface.cpp +++ b/src/Mod/Part/Gui/ViewProviderProjectOnSurface.cpp @@ -42,7 +42,7 @@ ViewProviderProjectOnSurface::ViewProviderProjectOnSurface() { const unsigned int color = 0x8ae23400; LineColor.setValue(color); - ShapeColor.setValue(color); + ShapeAppearance.setDiffuseColor(color); PointColor.setValue(color); Transparency.setValue(0); } diff --git a/src/Mod/Part/parttests/ColorTransparencyTest.py b/src/Mod/Part/parttests/ColorTransparencyTest.py index f948bdac8a..0d22cdd8df 100644 --- a/src/Mod/Part/parttests/ColorTransparencyTest.py +++ b/src/Mod/Part/parttests/ColorTransparencyTest.py @@ -27,7 +27,7 @@ class ColorTransparencyTest(unittest.TestCase): self._pg.SetInt('DefaultShapeTransparency', transparency) obj = self._doc.addObject('Part::Box') assert obj.ViewObject.Transparency == transparency - obj.ViewObject.ShapeColor = (0.5, 0.0, 0.0) + obj.ViewObject.ShapeAppearance[0].DiffuseColor = (0.5, 0.0, 0.0) self.assertEqual(obj.ViewObject.Transparency, transparency, 'transparency was unexpectedly changed to {} when changing the color.'.format( @@ -38,11 +38,18 @@ class ColorTransparencyTest(unittest.TestCase): """ related: https://github.com/FreeCAD/FreeCAD/pull/11866 """ + + """ + This test isn't currently valid as it draws from the hard coded default material. + """ + self._pg.SetUnsigned('DefaultShapeColor', 0xff000000) # red obj = self._doc.addObject('Part::Box') - self.assertEqual(obj.ViewObject.ShapeColor, (1.0, 0.0, 0.0, 0.0), + self.assertEqual(obj.ViewObject.ShapeAppearance[0].DiffuseColor, (1.0, 0.0, 0.0, 0.0), 'default shape color was not set correctly') + self.assertEqual(obj.ViewObject.ShapeMaterial.DiffuseColor, (1.0, 0.0, 0.0, 0.0), + 'default material color was not set correctly') def test_app_plane_transparency(self): diff --git a/src/Mod/PartDesign/Gui/Command.cpp b/src/Mod/PartDesign/Gui/Command.cpp index c85ae15533..862f2a4825 100644 --- a/src/Mod/PartDesign/Gui/Command.cpp +++ b/src/Mod/PartDesign/Gui/Command.cpp @@ -475,7 +475,7 @@ void CmdPartDesignClone::activated(int iMsg) << "setEditorMode('Placement', 0)"); updateActive(); - copyVisual(cloneObj, "ShapeColor", obj); + copyVisual(cloneObj, "ShapeAppearance", obj); copyVisual(cloneObj, "LineColor", obj); copyVisual(cloneObj, "PointColor", obj); copyVisual(cloneObj, "Transparency", obj); @@ -556,7 +556,7 @@ void finishFeature(const Gui::Command* cmd, App::DocumentObject *Feat, // Do this before calling setEdit to avoid to override the 'Shape preview' mode (#0003621) if (obj) { - cmd->copyVisual(Feat, "ShapeColor", obj); + cmd->copyVisual(Feat, "ShapeAppearance", obj); cmd->copyVisual(Feat, "LineColor", obj); cmd->copyVisual(Feat, "PointColor", obj); cmd->copyVisual(Feat, "Transparency", obj); diff --git a/src/Mod/PartDesign/Gui/CommandPrimitive.cpp b/src/Mod/PartDesign/Gui/CommandPrimitive.cpp index 560ca9e2d5..abea7a4fa8 100644 --- a/src/Mod/PartDesign/Gui/CommandPrimitive.cpp +++ b/src/Mod/PartDesign/Gui/CommandPrimitive.cpp @@ -128,7 +128,7 @@ void CmdPrimtiveCompAdditive::activated(int iMsg) if(!base) base = pcActiveBody; - copyVisual(prm, "ShapeColor", base); + copyVisual(prm, "ShapeAppearance", base); copyVisual(prm, "LineColor", base); copyVisual(prm, "PointColor", base); copyVisual(prm, "Transparency", base); @@ -279,7 +279,7 @@ void CmdPrimtiveCompSubtractive::activated(int iMsg) Gui::Command::updateActive(); auto Feat = pcActiveBody->getDocument()->getObject(FeatName.c_str()); - copyVisual(Feat, "ShapeColor", prevSolid); + copyVisual(Feat, "ShapeAppearance", prevSolid); copyVisual(Feat, "LineColor", prevSolid); copyVisual(Feat, "PointColor", prevSolid); copyVisual(Feat, "Transparency", prevSolid); diff --git a/src/Mod/PartDesign/Gui/ViewProviderDatum.cpp b/src/Mod/PartDesign/Gui/ViewProviderDatum.cpp index 13676e04e0..ae5c93b2d3 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderDatum.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderDatum.cpp @@ -85,7 +85,7 @@ ViewProviderDatum::ViewProviderDatum() unsigned long shcol = hGrp->GetUnsigned ( "DefaultDatumColor", 0xFFD70099 ); App::Color col ( (uint32_t) shcol ); - ShapeColor.setValue ( col ); + ShapeAppearance.setDiffuseColor(col); Transparency.setValue (col.a * 100); diff --git a/src/Mod/PartDesign/Gui/ViewProviderDressUp.cpp b/src/Mod/PartDesign/Gui/ViewProviderDressUp.cpp index 548b376e4c..4f1aa54ef4 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderDressUp.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderDressUp.cpp @@ -104,7 +104,7 @@ void ViewProviderDressUp::highlightReferences(const bool on) originalFaceColors = vp->DiffuseColor.getValues(); std::vector colors = originalFaceColors; - PartGui::ReferenceHighlighter highlighter(base->Shape.getValue(), ShapeColor.getValue()); + PartGui::ReferenceHighlighter highlighter(base->Shape.getValue(), ShapeAppearance.getDiffuseColor()); highlighter.getFaceColors(faces, colors); vp->DiffuseColor.setValues(colors); } diff --git a/src/Mod/PartDesign/Gui/ViewProviderShapeBinder.cpp b/src/Mod/PartDesign/Gui/ViewProviderShapeBinder.cpp index 1119c2dcd8..7dbb522c7a 100644 --- a/src/Mod/PartDesign/Gui/ViewProviderShapeBinder.cpp +++ b/src/Mod/PartDesign/Gui/ViewProviderShapeBinder.cpp @@ -72,7 +72,7 @@ ViewProviderShapeBinder::ViewProviderShapeBinder() unsigned long shcol = hGrp->GetUnsigned("DefaultDatumColor", 0xFFD70099); App::Color col((uint32_t)shcol); - ShapeColor.setValue(col); + ShapeAppearance.setDiffuseColor(col); LineColor.setValue(col); PointColor.setValue(col); Transparency.setValue(60); @@ -155,7 +155,7 @@ void ViewProviderShapeBinder::highlightReferences(bool on) TopExp::MapShapes(static_cast(obj)->Shape.getValue(), TopAbs_FACE, eMap); originalFaceColors = svp->DiffuseColor.getValues(); std::vector fcolors = originalFaceColors; - fcolors.resize(eMap.Extent(), svp->ShapeColor.getValue()); + fcolors.resize(eMap.Extent(), svp->ShapeAppearance.getDiffuseColor()); for (const std::string& e : subs) { // Note: stoi may throw, but it strictly shouldn't happen @@ -248,7 +248,7 @@ void ViewProviderSubShapeBinder::onChanged(const App::Property* prop) { transparency = Gui::ViewParams::instance()->getDefaultShapeTransparency(); linewidth = Gui::ViewParams::instance()->getDefaultShapeLineWidth(); } - ShapeColor.setValue(shapeColor); + ShapeAppearance.setDiffuseColor(shapeColor); LineColor.setValue(lineColor); PointColor.setValue(pointColor); Transparency.setValue(transparency); diff --git a/src/Mod/PartDesign/Gui/Workbench.cpp b/src/Mod/PartDesign/Gui/Workbench.cpp index 193100459c..3ac5c9422f 100644 --- a/src/Mod/PartDesign/Gui/Workbench.cpp +++ b/src/Mod/PartDesign/Gui/Workbench.cpp @@ -237,6 +237,7 @@ void Workbench::setupContextMenu(const char* recipient, Gui::MenuItem* item) con if (Gui::Selection().countObjectsOfType(App::DocumentObject::getClassTypeId()) > 0) { *item << "Std_Placement" + << "Std_SetMaterial" << "Std_ToggleVisibility" << "Std_ShowSelection" << "Std_HideSelection" diff --git a/src/Mod/Surface/Gui/Command.cpp b/src/Mod/Surface/Gui/Command.cpp index ee39f7f32e..17b170adf8 100644 --- a/src/Mod/Surface/Gui/Command.cpp +++ b/src/Mod/Surface/Gui/Command.cpp @@ -98,7 +98,7 @@ void CmdSurfaceCut::activated(int iMsg) App.activeDocument().%s",FeatName.c_str(),ToolName.c_str()); doCommand(Gui,"Gui.activeDocument().hide('%s')",BaseName.c_str()); doCommand(Gui,"Gui.activeDocument().hide('%s')",ToolName.c_str()); - copyVisual(FeatName.c_str(), "ShapeColor", BaseName.c_str()); + copyVisual(FeatName.c_str(), "ShapeAppearance", BaseName.c_str()); copyVisual(FeatName.c_str(), "DisplayMode", BaseName.c_str()); updateActive(); commitCommand();*/ diff --git a/src/Mod/Surface/Gui/TaskFilling.cpp b/src/Mod/Surface/Gui/TaskFilling.cpp index 598e7d9156..e11b52db56 100644 --- a/src/Mod/Surface/Gui/TaskFilling.cpp +++ b/src/Mod/Surface/Gui/TaskFilling.cpp @@ -164,7 +164,7 @@ void ViewProviderFilling::highlightReferences(ShapeType type, const References& std::vector colors; TopTools_IndexedMapOfShape fMap; TopExp::MapShapes(base->Shape.getValue(), TopAbs_FACE, fMap); - colors.resize(fMap.Extent(), svp->ShapeColor.getValue()); + colors.resize(fMap.Extent(), svp->ShapeAppearance.getDiffuseColor()); for (const auto& jt : it.second) { std::size_t idx = diff --git a/src/Mod/Surface/Gui/TaskSections.cpp b/src/Mod/Surface/Gui/TaskSections.cpp index e3cb889c0c..e1e93be19e 100644 --- a/src/Mod/Surface/Gui/TaskSections.cpp +++ b/src/Mod/Surface/Gui/TaskSections.cpp @@ -164,7 +164,7 @@ void ViewProviderSections::highlightReferences(ShapeType type, const References& std::vector colors; TopTools_IndexedMapOfShape fMap; TopExp::MapShapes(base->Shape.getValue(), TopAbs_FACE, fMap); - colors.resize(fMap.Extent(), svp->ShapeColor.getValue()); + colors.resize(fMap.Extent(), svp->ShapeAppearance.getDiffuseColor()); for (const auto& jt : it.second) { std::size_t idx = diff --git a/tests/src/Mod/Material/App/TestMaterials.cpp b/tests/src/Mod/Material/App/TestMaterials.cpp index 024023d4ea..7b0b42ae05 100644 --- a/tests/src/Mod/Material/App/TestMaterials.cpp +++ b/tests/src/Mod/Material/App/TestMaterials.cpp @@ -26,6 +26,7 @@ #ifndef _PreComp_ #endif +#include #include #include @@ -305,8 +306,9 @@ TEST_F(TestMaterial, TestCalculiXSteel) EXPECT_FALSE(properties1[QString::fromStdString("SpecularColor")]->isNull()); EXPECT_FALSE(properties1[QString::fromStdString("Transparency")]->isNull()); + QLocale locale; EXPECT_EQ(properties[QString::fromStdString("Density")]->getString(), parseQuantity("7900.00 kg/m^3")); - EXPECT_EQ(properties[QString::fromStdString("PoissonRatio")]->getString(), QString::fromStdString("0.3")); + EXPECT_EQ(properties[QString::fromStdString("PoissonRatio")]->getString(), locale.toString(0.3)); EXPECT_EQ(properties[QString::fromStdString("YoungsModulus")]->getString(), parseQuantity("210.00 GPa")); EXPECT_EQ(properties[QString::fromStdString("SpecificHeat")]->getString(), parseQuantity("590.00 J/kg/K")); EXPECT_EQ(properties[QString::fromStdString("ThermalConductivity")]->getString(), parseQuantity("43.00 W/m/K")); @@ -314,7 +316,7 @@ TEST_F(TestMaterial, TestCalculiXSteel) EXPECT_EQ(properties1[QString::fromStdString("AmbientColor")]->getString(), QString::fromStdString("(0.0020, 0.0020, 0.0020, 1.0)")); EXPECT_EQ(properties1[QString::fromStdString("DiffuseColor")]->getString(), QString::fromStdString("(0.0000, 0.0000, 0.0000, 1.0)")); EXPECT_EQ(properties1[QString::fromStdString("EmissiveColor")]->getString(), QString::fromStdString("(0.0000, 0.0000, 0.0000, 1.0)")); - EXPECT_EQ(properties1[QString::fromStdString("Shininess")]->getString(), QString::fromStdString("0.06")); + EXPECT_EQ(properties1[QString::fromStdString("Shininess")]->getString(), locale.toString(0.06)); EXPECT_EQ(properties1[QString::fromStdString("SpecularColor")]->getString(), QString::fromStdString("(0.9800, 0.9800, 0.9800, 1.0)")); EXPECT_EQ(properties1[QString::fromStdString("Transparency")]->getString(), QString::fromStdString("0")); diff --git a/tests/src/Mod/Material/CMakeLists.txt b/tests/src/Mod/Material/CMakeLists.txt index ff798efcb3..aab21917da 100644 --- a/tests/src/Mod/Material/CMakeLists.txt +++ b/tests/src/Mod/Material/CMakeLists.txt @@ -9,7 +9,7 @@ target_include_directories(Material_tests_run PUBLIC target_link_libraries(Material_tests_run gtest_main ${Google_Tests_LIBS} - Material + Materials ) add_subdirectory(App)