diff --git a/source/MRCommonPlugins/ViewerButtons/MRAddCustomTheme.cpp b/source/MRCommonPlugins/ViewerButtons/MRAddCustomTheme.cpp index 49397951dff3..fe7578445979 100644 --- a/source/MRCommonPlugins/ViewerButtons/MRAddCustomTheme.cpp +++ b/source/MRCommonPlugins/ViewerButtons/MRAddCustomTheme.cpp @@ -282,47 +282,7 @@ std::string AddCustomThemePlugin::save_() { auto visualObjs = getAllObjectsInTree( &SceneRoot::get() ); for ( auto obj : visualObjs ) - { - obj->setFrontColor( SceneColors::get( SceneColors::SelectedObjectMesh ), true ); - obj->setFrontColor( SceneColors::get( SceneColors::UnselectedObjectMesh ), false ); - obj->setBackColor( SceneColors::get( SceneColors::BackFaces ) ); -MR_SUPPRESS_WARNING_PUSH -MR_SUPPRESS_WARNING( "-Wdeprecated-declarations", 4996 ) - obj->setLabelsColor( SceneColors::get( SceneColors::Labels ) ); -MR_SUPPRESS_WARNING_POP -#ifndef MESHLIB_NO_VOXELS - if ( auto objVoxels = std::dynamic_pointer_cast< ObjectVoxels >( obj ) ) - { - objVoxels->setFrontColor( SceneColors::get( SceneColors::SelectedObjectVoxels ), true ); - objVoxels->setFrontColor( SceneColors::get( SceneColors::UnselectedObjectVoxels ), false ); - } - else -#endif - if ( auto objDM = std::dynamic_pointer_cast< ObjectDistanceMap >( obj ) ) - { - objDM->setFrontColor( SceneColors::get( SceneColors::SelectedObjectDistanceMap ), true ); - objDM->setFrontColor( SceneColors::get( SceneColors::UnselectedObjectDistanceMap ), false ); - } - else if ( auto meshObj = std::dynamic_pointer_cast< ObjectMesh >( obj ) ) - { - meshObj->setFrontColor( SceneColors::get( SceneColors::SelectedObjectMesh ), true ); - meshObj->setFrontColor( SceneColors::get( SceneColors::UnselectedObjectMesh ), false ); - meshObj->setSelectedFacesColor( SceneColors::get( SceneColors::SelectedFaces ) ); - meshObj->setSelectedEdgesColor( SceneColors::get( SceneColors::SelectedEdges ) ); - meshObj->setEdgesColor( SceneColors::get( SceneColors::Edges ) ); - meshObj->setPointsColor( SceneColors::get( SceneColors::Points ) ); - } - else if ( auto objPoints = std::dynamic_pointer_cast< ObjectPoints >( obj ) ) - { - objPoints->setFrontColor( SceneColors::get( SceneColors::SelectedObjectPoints ), true ); - objPoints->setFrontColor( SceneColors::get( SceneColors::UnselectedObjectPoints ), false ); - } - else if ( auto objLines = std::dynamic_pointer_cast< ObjectLines >( obj ) ) - { - objLines->setFrontColor( SceneColors::get( SceneColors::SelectedObjectLines ), true ); - objLines->setFrontColor( SceneColors::get( SceneColors::UnselectedObjectLines ), false ); - } - } + obj->resetColors(); } updateThemeNames_(); return {}; diff --git a/source/MRMesh/MRObject.cpp b/source/MRMesh/MRObject.cpp index 7a95c56a12ec..4a5bd88d471e 100644 --- a/source/MRMesh/MRObject.cpp +++ b/source/MRMesh/MRObject.cpp @@ -435,6 +435,11 @@ void Object::serializeFields_( Json::Value& root ) const // Type root["Type"].append( Object::TypeName() ); // will be appended in derived calls + + // tags + auto& tagsJson = root["Tags"] = Json::arrayValue; + for ( const auto& tag : tags_ ) + tagsJson.append( tag ); } Expected Object::deserializeModel_( const std::filesystem::path&, ProgressCallback progressCb ) @@ -463,6 +468,10 @@ void Object::deserializeFields_( const Json::Value& root ) locked_ = root["Locked"].asBool(); if ( const auto& json = root["ParentLocked"]; json.isBool() ) parentLocked_ = json.asBool(); + if ( const auto& tagsJson = root["Tags"]; tagsJson.isArray() ) + for ( const auto& tagJson : tagsJson ) + if ( tagJson.isString() ) + tags_.emplace( tagJson.asString() ); } void Object::sendWorldXfChangedSignal_() diff --git a/source/MRMesh/MRObject.h b/source/MRMesh/MRObject.h index e1257f9c88d0..5285c939f22c 100644 --- a/source/MRMesh/MRObject.h +++ b/source/MRMesh/MRObject.h @@ -1,17 +1,19 @@ #pragma once #include "MRAffineXf3.h" -#include "MRBox.h" #include "MRBitSet.h" -#include "MRViewportProperty.h" -#include "MRProgressCallback.h" +#include "MRBox.h" #include "MRExpected.h" +#include "MRProgressCallback.h" #include "MRSignal.h" -#include -#include +#include "MRViewportProperty.h" + #include -#include #include +#include +#include +#include +#include namespace Json { @@ -250,6 +252,12 @@ class MRMESH_CLASS Object : public ObjectChildrenHolder /// e.g. ObjectMesh has valid mesh() or ObjectPoints has valid pointCloud() [[nodiscard]] virtual bool hasModel() const { return false; } + /// provides read-only access to the tag storage + /// the storage is a set of unique strings + const std::unordered_set& tags() const { return tags_; } + /// provides read-write access to the tag storage + std::unordered_set& varTags() { return tags_; } + /// returns the amount of memory this object occupies on heap [[nodiscard]] MRMESH_API virtual size_t heapBytes() const; @@ -297,6 +305,7 @@ class MRMESH_CLASS Object : public ObjectChildrenHolder bool selected_{ false }; bool ancillary_{ false }; mutable bool needRedraw_{false}; + std::unordered_set tags_; // This calls `onWorldXfChanged_()` for all children recursively, which in turn emits `worldXfChangedSignal`. // This isn't virtual because it wouldn't be very useful, because it doesn't call itself on the children diff --git a/source/MRMesh/MRObjectDistanceMap.cpp b/source/MRMesh/MRObjectDistanceMap.cpp index 2d26825d2854..b5b7d9ce996a 100644 --- a/source/MRMesh/MRObjectDistanceMap.cpp +++ b/source/MRMesh/MRObjectDistanceMap.cpp @@ -178,6 +178,12 @@ Expected>> ObjectDistanceMap::serializeModel_( const } ); } +void ObjectDistanceMap::resetFrontColor() +{ + // cannot implement in the opposite way to keep `setDefaultColors_()` non-virtual + setDefaultColors_(); +} + void ObjectDistanceMap::setDefaultColors_() { setFrontColor( SceneColors::get( SceneColors::SelectedObjectDistanceMap ), true ); diff --git a/source/MRMesh/MRObjectDistanceMap.h b/source/MRMesh/MRObjectDistanceMap.h index 5974946137b8..32901ff72b4e 100644 --- a/source/MRMesh/MRObjectDistanceMap.h +++ b/source/MRMesh/MRObjectDistanceMap.h @@ -72,6 +72,9 @@ class MRMESH_CLASS ObjectDistanceMap : public ObjectMeshHolder MRMESH_API virtual Expected>> serializeModel_( const std::filesystem::path& path ) const override; + /// reset basic object colors to their default values from the current theme + MRMESH_API void resetFrontColor() override; + private: std::shared_ptr dmap_; AffineXf3f dmap2local_; diff --git a/source/MRMesh/MRObjectLinesHolder.cpp b/source/MRMesh/MRObjectLinesHolder.cpp index 5583da785f81..e1248811abae 100644 --- a/source/MRMesh/MRObjectLinesHolder.cpp +++ b/source/MRMesh/MRObjectLinesHolder.cpp @@ -154,6 +154,12 @@ float ObjectLinesHolder::totalLength() const return *totalLength_; } +void ObjectLinesHolder::resetFrontColor() +{ + // cannot implement in the opposite way to keep `setDefaultColors_()` non-virtual + setDefaultColors_(); +} + bool ObjectLinesHolder::supportsVisualizeProperty( AnyVisualizeMaskEnum type ) const { return VisualObject::supportsVisualizeProperty( type ) || type.tryGet().has_value(); diff --git a/source/MRMesh/MRObjectLinesHolder.h b/source/MRMesh/MRObjectLinesHolder.h index 3c7b988e0bda..4e851b85229c 100644 --- a/source/MRMesh/MRObjectLinesHolder.h +++ b/source/MRMesh/MRObjectLinesHolder.h @@ -88,6 +88,9 @@ class MRMESH_CLASS ObjectLinesHolder : public VisualObject /// return cached total length [[nodiscard]] MRMESH_API float totalLength() const; + /// reset basic object colors to their default values from the current theme + MRMESH_API void resetFrontColor() override; + protected: ObjectLinesHolder( const ObjectLinesHolder& other ) = default; diff --git a/source/MRMesh/MRObjectMeshHolder.cpp b/source/MRMesh/MRObjectMeshHolder.cpp index ca01f630fa9e..2134faae2ece 100644 --- a/source/MRMesh/MRObjectMeshHolder.cpp +++ b/source/MRMesh/MRObjectMeshHolder.cpp @@ -693,6 +693,18 @@ void ObjectMeshHolder::setSerializeFormat( const char * newFormat ) serializeFormat_ = newFormat; } +void ObjectMeshHolder::resetFrontColor() +{ + setFrontColor( SceneColors::get( SceneColors::SelectedObjectMesh ), true ); + setFrontColor( SceneColors::get( SceneColors::UnselectedObjectMesh ), false ); +} + +void ObjectMeshHolder::resetColors() +{ + // cannot implement in the opposite way to keep `setDefaultColors_()` non-virtual + setDefaultColors_(); +} + size_t ObjectMeshHolder::numUndirectedEdges() const { if ( !numUndirectedEdges_ ) diff --git a/source/MRMesh/MRObjectMeshHolder.h b/source/MRMesh/MRObjectMeshHolder.h index baa82f24b80c..a8bd3074ea91 100644 --- a/source/MRMesh/MRObjectMeshHolder.h +++ b/source/MRMesh/MRObjectMeshHolder.h @@ -245,6 +245,11 @@ class MRMESH_CLASS ObjectMeshHolder : public VisualObject /// nullptr means serialize in defaultSerializeMeshFormat() MRMESH_API void setSerializeFormat( const char * newFormat ); + /// reset basic object colors to their default values from the current theme + MRMESH_API void resetFrontColor() override; + /// reset all object colors to their default values from the current theme + MRMESH_API void resetColors() override; + /// signal about face selection changing, triggered in selectFaces using SelectionChangedSignal = Signal; SelectionChangedSignal faceSelectionChangedSignal; diff --git a/source/MRMesh/MRObjectPointsHolder.cpp b/source/MRMesh/MRObjectPointsHolder.cpp index 2fbd7be4650e..81bdd1ef9ea5 100644 --- a/source/MRMesh/MRObjectPointsHolder.cpp +++ b/source/MRMesh/MRObjectPointsHolder.cpp @@ -247,6 +247,18 @@ void ObjectPointsHolder::setSerializeFormat( const char * newFormat ) serializeFormat_ = newFormat; } +void ObjectPointsHolder::resetFrontColor() +{ + setFrontColor( SceneColors::get( SceneColors::SelectedObjectPoints ), true ); + setFrontColor( SceneColors::get( SceneColors::UnselectedObjectPoints ), false ); +} + +void ObjectPointsHolder::resetColors() +{ + // cannot implement in the opposite way to keep `setDefaultColors_()` non-virtual + setDefaultColors_(); +} + void ObjectPointsHolder::swapBase_( Object& other ) { if ( auto otherPointsHolder = other.asType() ) diff --git a/source/MRMesh/MRObjectPointsHolder.h b/source/MRMesh/MRObjectPointsHolder.h index cb5ec5f64e24..badf0d078829 100644 --- a/source/MRMesh/MRObjectPointsHolder.h +++ b/source/MRMesh/MRObjectPointsHolder.h @@ -140,6 +140,11 @@ class MRMESH_CLASS ObjectPointsHolder : public VisualObject MRMESH_API void setSerializeFormat( const char * newFormat ); [[deprecated]] MR_BIND_IGNORE void setSavePointsFormat( const char * newFormat ) { setSerializeFormat( newFormat ); } + /// reset basic object colors to their default values from the current theme + MRMESH_API void resetFrontColor() override; + /// reset all object colors to their default values from the current theme + MRMESH_API void resetColors() override; + /// signal about points selection changing, triggered in selectPoints using SelectionChangedSignal = Signal; SelectionChangedSignal pointsSelectionChangedSignal; diff --git a/source/MRMesh/MRString.cpp b/source/MRMesh/MRString.cpp index ec9618ed18db..ce331e35a697 100644 --- a/source/MRMesh/MRString.cpp +++ b/source/MRMesh/MRString.cpp @@ -184,6 +184,19 @@ void replaceInplace( std::string& target, std::string_view from, std::string_vie target = replace( std::move( target ), from, to ); } +std::string_view trim( std::string_view str ) +{ + return trimRight( trimLeft( str ) ); +} + +std::string_view trimLeft( std::string_view str ) +{ + size_t pos = 0; + while ( pos < str.size() && std::isspace( str[pos] ) ) + ++pos; + return str.substr( pos ); +} + std::string_view trimRight( std::string_view str ) { auto l = str.size(); diff --git a/source/MRMesh/MRString.h b/source/MRMesh/MRString.h index 0f1b65dbbc17..968994227a0b 100644 --- a/source/MRMesh/MRString.h +++ b/source/MRMesh/MRString.h @@ -53,6 +53,12 @@ bool split( std::string_view str, std::string_view sep, F&& func ) /// Replaces \param from with \param to in \param target (in-place), zero or more times. MRMESH_API void replaceInplace( std::string& target, std::string_view from, std::string_view to ); +/// Removes all whitespace character (detected by std::isspace) at the beginning and the end of string view +[[nodiscard]] MRMESH_API std::string_view trim( std::string_view str ); + +/// Removes all whitespace character (detected by std::isspace) at the beginning of string view +[[nodiscard]] MRMESH_API std::string_view trimLeft( std::string_view str ); + /// Removes all whitespace character (detected by std::isspace) at the end of string view [[nodiscard]] MRMESH_API std::string_view trimRight( std::string_view str ); diff --git a/source/MRMesh/MRVisualObject.cpp b/source/MRMesh/MRVisualObject.cpp index ade976e4277e..6d1708f7c8c5 100644 --- a/source/MRMesh/MRVisualObject.cpp +++ b/source/MRMesh/MRVisualObject.cpp @@ -412,6 +412,23 @@ std::vector VisualObject::getInfoLines() const return res; } +void VisualObject::resetFrontColor() +{ + setFrontColor( SceneColors::get( SceneColors::SelectedObjectMesh ), true ); + setFrontColor( SceneColors::get( SceneColors::UnselectedObjectMesh ), false ); +} + +void VisualObject::resetColors() +{ + resetFrontColor(); + + setBackColor( SceneColors::get( SceneColors::BackFaces ) ); +MR_SUPPRESS_WARNING_PUSH +MR_SUPPRESS_WARNING( "-Wdeprecated-declarations", 4996 ) + setLabelsColor( SceneColors::get( SceneColors::Labels ) ); +MR_SUPPRESS_WARNING_POP +} + void VisualObject::boundingBoxToInfoLines_( std::vector & res ) const { auto bbox = getBoundingBox(); diff --git a/source/MRMesh/MRVisualObject.h b/source/MRMesh/MRVisualObject.h index 8e05c0358ea6..c6aaadfac0ac 100644 --- a/source/MRMesh/MRVisualObject.h +++ b/source/MRMesh/MRVisualObject.h @@ -293,6 +293,11 @@ class MRMESH_CLASS VisualObject : public Object MRMESH_API void setUseDefaultScenePropertiesOnDeserialization( bool useDefaultScenePropertiesOnDeserialization ) { useDefaultScenePropertiesOnDeserialization_ = useDefaultScenePropertiesOnDeserialization; } + /// reset basic object colors to their default values from the current theme + MRMESH_API virtual void resetFrontColor(); + /// reset all object colors to their default values from the current theme + MRMESH_API virtual void resetColors(); + protected: VisualObject( const VisualObject& obj ) = default; diff --git a/source/MRViewer/MRViewer.vcxproj b/source/MRViewer/MRViewer.vcxproj index 89db85b141c4..53cceebfa0a1 100644 --- a/source/MRViewer/MRViewer.vcxproj +++ b/source/MRViewer/MRViewer.vcxproj @@ -147,6 +147,7 @@ + @@ -309,6 +310,7 @@ + diff --git a/source/MRViewer/MRViewer.vcxproj.filters b/source/MRViewer/MRViewer.vcxproj.filters index 819739e671c8..20f2c9bdf3c3 100644 --- a/source/MRViewer/MRViewer.vcxproj.filters +++ b/source/MRViewer/MRViewer.vcxproj.filters @@ -487,6 +487,9 @@ Render + + Render + @@ -955,6 +958,9 @@ Render + + Render + diff --git a/source/MRViewer/MRViewerSettingsManager.cpp b/source/MRViewer/MRViewerSettingsManager.cpp index 5397a553fcb2..68dc736a72e0 100644 --- a/source/MRViewer/MRViewerSettingsManager.cpp +++ b/source/MRViewer/MRViewerSettingsManager.cpp @@ -18,6 +18,7 @@ #include "MRMesh/MRSerializer.h" #include "MRPch/MRSpdlog.h" #include "MRRibbonSceneObjectsListDrawer.h" +#include "MRVisualObjectTag.h" #include "MRMesh/MRObjectMesh.h" #include "MRMesh/MRObjectPointsHolder.h" #include "MRVoxels/MRObjectVoxels.h" @@ -69,6 +70,7 @@ const std::string cMruInnerPointsFormat = "mruInner.pointsFormat"; const std::string cMruInnerVoxelsFormat = "mruInner.voxelsFormat"; const std::string cSortDroppedFiles = "sortDroppedFiles"; const std::string cScrollForceConfigKey = "scrollForce"; +const std::string cVisualObjectTags = "visualObjectTags"; } namespace Defaults @@ -526,6 +528,12 @@ void ViewerSettingsManager::loadSettings( Viewer& viewer ) format = loadString( cMruInnerVoxelsFormat, ".vdb" ); setDefaultSerializeVoxelsFormat( format ); } + + if ( cfg.hasJsonValue( cVisualObjectTags ) ) + { + auto& manager = VisualObjectTagManager::instance(); + deserializeFromJson( cfg.getJsonValue( cVisualObjectTags ), manager ); + } } void ViewerSettingsManager::saveSettings( const Viewer& viewer ) @@ -674,6 +682,13 @@ void ViewerSettingsManager::saveSettings( const Viewer& viewer ) saveString( cMruInnerPointsFormat, defaultSerializePointsFormat() ); saveString( cMruInnerVoxelsFormat, defaultSerializeVoxelsFormat() ); } + + { + Json::Value visualObjectTagsJson; + const auto& manager = VisualObjectTagManager::instance(); + serializeToJson( manager, visualObjectTagsJson ); + cfg.setJsonValue( cVisualObjectTags, visualObjectTagsJson ); + } } const std::string & ViewerSettingsManager::getLastExtention( ObjType objType ) diff --git a/source/MRViewer/MRVisualObjectTag.cpp b/source/MRViewer/MRVisualObjectTag.cpp new file mode 100644 index 000000000000..885bd8905a90 --- /dev/null +++ b/source/MRViewer/MRVisualObjectTag.cpp @@ -0,0 +1,127 @@ +#include "MRVisualObjectTag.h" + +#include "MRMesh/MRSerializer.h" +#include "MRMesh/MRString.h" +#include "MRMesh/MRStringConvert.h" +#include "MRMesh/MRVisualObject.h" +#include "MRPch/MRJson.h" + +namespace +{ + +constexpr const char* cVisualObjectTagPrefix = "visual-object-tag:"; + +} // namespace + +namespace MR +{ + +std::string VisualObjectTag::canonicalName() const +{ + return toLower( std::string{ trim( name ) } ); +} + +VisualObjectTagManager& VisualObjectTagManager::instance() +{ + static VisualObjectTagManager sInstance; + return sInstance; +} + +const std::unordered_map& VisualObjectTagManager::storage() +{ + return instance().storage_; +} + +std::string VisualObjectTagManager::registerTag( VisualObjectTag tag ) +{ + const auto id = cVisualObjectTagPrefix + tag.canonicalName(); + instance().storage_.emplace( id, std::move( tag ) ); + return id; +} + +void VisualObjectTagManager::updateTag( const std::string& visTagId, VisualObjectTag tag ) +{ + auto it = instance().storage_.find( visTagId ); + if ( it != instance().storage_.end() ) + it->second = std::move( tag ); +} + +void VisualObjectTagManager::unregisterTag( const std::string& visTagId ) +{ + instance().storage_.erase( visTagId ); +} + +std::vector> VisualObjectTagManager::getAllObjectsWithTag( Object* root, const std::string& visTagId, const ObjectSelectivityType& type ) +{ + // TODO: more efficient version + auto results = getAllObjectsInTree( root, type ); + std::erase_if( results, [&] ( const std::shared_ptr& obj ) + { + return !obj->tags().contains( visTagId ); + } ); + return results; +} + +void VisualObjectTagManager::update( VisualObject& visObj, const std::string& visTagId ) +{ + const auto& storage = instance().storage_; + if ( visObj.tags().contains( visTagId ) ) + { + const auto visTagIt = storage.find( visTagId ); + if ( visTagIt == storage.end() ) + return; + const auto& [_, tag] = *visTagIt; + + visObj.setFrontColor( tag.selectedColor, true ); + visObj.setFrontColor( tag.unselectedColor, false ); + } + else + { + visObj.resetFrontColor(); + + // re-apply existing tag + for ( const auto& [id, _] : storage ) + if ( visObj.tags().contains( id ) ) + return update( visObj, id ); + } +} + +void deserializeFromJson( const Json::Value& root, VisualObjectTagManager& manager ) +{ + if ( !root.isArray() ) + return; + + auto& storage = manager.storage_; + for ( const auto& tagObj : root ) + { + if ( !tagObj["Id"].isString() ) + continue; + if ( !tagObj["Name"].isString() ) + continue; + + const auto id = tagObj["Id"].asString(); + VisualObjectTag tag; + tag.name = tagObj["Name"].asString(); + deserializeFromJson( tagObj["SelectedColor"], tag.selectedColor ); + deserializeFromJson( tagObj["UnselectedColor"], tag.unselectedColor ); + + storage.emplace( id, tag ); + } +} + +void serializeToJson( const VisualObjectTagManager& manager, Json::Value& root ) +{ + root = Json::arrayValue; + + auto i = 0; + for ( const auto& [id, tag] : manager.storage() ) + { + auto& tagObj = root[i++] = Json::objectValue; + tagObj["Id"] = id; + tagObj["Name"] = tag.name; + serializeToJson( tag.selectedColor, tagObj["SelectedColor"] ); + serializeToJson( tag.unselectedColor, tagObj["UnselectedColor"] ); + } +} + +} // namespace MR diff --git a/source/MRViewer/MRVisualObjectTag.h b/source/MRViewer/MRVisualObjectTag.h new file mode 100644 index 000000000000..401399edb382 --- /dev/null +++ b/source/MRViewer/MRVisualObjectTag.h @@ -0,0 +1,59 @@ +#pragma once + +#include "exports.h" + +#include "MRMesh/MRColor.h" +#include "MRMesh/MRObjectsAccess.h" + +#include + +namespace Json { class Value; } + +namespace MR +{ + +/// modified color set for visual objects +struct VisualObjectTag +{ + std::string name; + + Color selectedColor; + Color unselectedColor; + + /// canonical name for indexing + [[nodiscard]] MRVIEWER_API std::string canonicalName() const; +}; + +/// class for storing and changing visual object properties based on the object tags +class VisualObjectTagManager +{ +public: + /// get access to the global instance + MRVIEWER_API static VisualObjectTagManager& instance(); + + /// get read-only access to the visual object tags' storage + MRVIEWER_API static const std::unordered_map& storage(); + + /// add visual object tag + MRVIEWER_API static std::string registerTag( VisualObjectTag tag ); + /// update visual object tag; linked objects are NOT updated automatically + MRVIEWER_API static void updateTag( const std::string& visTagId, VisualObjectTag tag ); + /// remove visual object tag; linked objects are NOT updated automatically + MRVIEWER_API static void unregisterTag( const std::string& visTagId ); + + /// find all object in given object tree with the visual object tag + MRVIEWER_API static std::vector> getAllObjectsWithTag( Object* root, const std::string& visTagId, const ObjectSelectivityType& type = ObjectSelectivityType::Selectable ); + + /// update visual object properties according to whether given object has the visual object tag or not + MRVIEWER_API static void update( VisualObject& visObj, const std::string& visTagId ); + +private: + friend MRVIEWER_API void deserializeFromJson( const Json::Value&, VisualObjectTagManager& ); + + std::unordered_map storage_; +}; + +MRVIEWER_API void deserializeFromJson( const Json::Value& root, VisualObjectTagManager& manager ); +MRVIEWER_API void serializeToJson( const VisualObjectTagManager& manager, Json::Value& root ); + +} // namespace MR diff --git a/source/MRVoxels/MRObjectVoxels.cpp b/source/MRVoxels/MRObjectVoxels.cpp index c91d5f9896f1..ef9f24844e77 100644 --- a/source/MRVoxels/MRObjectVoxels.cpp +++ b/source/MRVoxels/MRObjectVoxels.cpp @@ -564,6 +564,12 @@ void ObjectVoxels::setSerializeFormat( const char * newFormat ) serializeFormat_ = newFormat; } +void ObjectVoxels::resetFrontColor() +{ + // cannot implement in the opposite way to keep `setDefaultColors_()` non-virtual + setDefaultColors_(); +} + void ObjectVoxels::swapBase_( Object& other ) { if ( auto otherVoxels = other.asType() ) diff --git a/source/MRVoxels/MRObjectVoxels.h b/source/MRVoxels/MRObjectVoxels.h index 56e962f72c0f..b8a5f91d0ddf 100644 --- a/source/MRVoxels/MRObjectVoxels.h +++ b/source/MRVoxels/MRObjectVoxels.h @@ -216,6 +216,9 @@ class MRVOXELS_CLASS ObjectVoxels : public ObjectMeshHolder /// nullptr means serialize in defaultSerializeVoxelsFormat() MRVOXELS_API void setSerializeFormat( const char * newFormat ); + /// reset basic object colors to their default values from the current theme + MRVOXELS_API void resetFrontColor() override; + /// signal about Iso-surface changes (from updateIsoSurface) using IsoSurfaceChangedSignal = Signal; IsoSurfaceChangedSignal isoSurfaceChangedSignal;