| #include "rive/shapes/list_path.hpp" | |
| #include "rive/math/math_types.hpp" | |
| #include "rive/artboard.hpp" | |
| #include "rive/shapes/cubic_detached_vertex.hpp" | |
| #include "rive/shapes/straight_vertex.hpp" | |
| #include "rive/shapes/vertex.hpp" | |
| #include "rive/shapes/path_vertex.hpp" | |
| #include "rive/viewmodel/viewmodel_instance.hpp" | |
| #include "rive/viewmodel/symbol_type.hpp" | |
| #include "rive/viewmodel/viewmodel_instance_number.hpp" | |
| #include "rive/generated/core_registry.hpp" | |
| using namespace rive; | |
| VertexListener::VertexListener(Vertex* vertex, | |
| rcp<ViewModelInstance> instance, | |
| Path* path) : | |
| CoreObjectListener(vertex, instance), m_path(path) | |
| { | |
| createProperties(); | |
| } | |
| void VertexListener::createProperties() | |
| { | |
| CoreObjectListener::createProperties(); | |
| createPropertyListener(SymbolType::vertexX); | |
| createPropertyListener(SymbolType::vertexY); | |
| createPropertyListener(SymbolType::rotation); | |
| createPropertyListener(SymbolType::inRotation); | |
| createPropertyListener(SymbolType::outRotation); | |
| createPropertyListener(SymbolType::distance); | |
| createPropertyListener(SymbolType::inDistance); | |
| createPropertyListener(SymbolType::outDistance); | |
| createInPointPropertyListener(); | |
| createOutPointPropertyListener(); | |
| } | |
| PropertySymbolDependent* VertexListener::createSinglePropertyListener( | |
| SymbolType symbolType) | |
| { | |
| uint16_t propertyKey = 0; | |
| float multiplier = 1.0f; | |
| switch (symbolType) | |
| { | |
| case SymbolType::vertexX: | |
| propertyKey = VertexBase::xPropertyKey; | |
| break; | |
| case SymbolType::vertexY: | |
| propertyKey = VertexBase::yPropertyKey; | |
| break; | |
| case SymbolType::inRotation: | |
| propertyKey = CubicDetachedVertexBase::inRotationPropertyKey; | |
| multiplier = math::PI / 180.0f; | |
| break; | |
| case SymbolType::outRotation: | |
| propertyKey = CubicDetachedVertexBase::outRotationPropertyKey; | |
| multiplier = math::PI / 180.0f; | |
| break; | |
| case SymbolType::inDistance: | |
| propertyKey = CubicDetachedVertexBase::inDistancePropertyKey; | |
| break; | |
| case SymbolType::outDistance: | |
| propertyKey = CubicDetachedVertexBase::outDistancePropertyKey; | |
| break; | |
| default: | |
| break; | |
| } | |
| auto prop = m_instance->propertyValue(symbolType); | |
| if (prop != nullptr && prop->is<ViewModelInstanceNumber>()) | |
| { | |
| auto vpl = new VertexPropertyListenerSingle(m_core, | |
| this, | |
| prop, | |
| propertyKey, | |
| multiplier); | |
| return vpl; | |
| } | |
| return nullptr; | |
| } | |
| PropertySymbolDependent* VertexListener::createDistancePropertyListener() | |
| { | |
| auto prop = m_instance->propertyValue(SymbolType::distance); | |
| if (prop != nullptr && prop->is<ViewModelInstanceNumber>()) | |
| { | |
| std::vector<uint16_t> keys = {}; | |
| auto inPropKey = CubicDetachedVertexBase::inDistancePropertyKey; | |
| keys.push_back(inPropKey); | |
| auto outPropKey = CubicDetachedVertexBase::outDistancePropertyKey; | |
| keys.push_back(outPropKey); | |
| auto vpl = | |
| new VertexPropertyListenerMulti(m_core, this, prop, keys, 1.0f); | |
| return vpl; | |
| } | |
| return nullptr; | |
| } | |
| PropertySymbolDependent* VertexListener::createRotationPropertyListener() | |
| { | |
| auto prop = m_instance->propertyValue(SymbolType::rotation); | |
| if (prop != nullptr && prop->is<ViewModelInstanceNumber>()) | |
| { | |
| std::vector<uint16_t> keys = {}; | |
| auto inPropKey = CubicDetachedVertexBase::inRotationPropertyKey; | |
| keys.push_back(inPropKey); | |
| auto outPropKey = CubicDetachedVertexBase::outRotationPropertyKey; | |
| keys.push_back(outPropKey); | |
| auto vpl = new VertexPropertyListenerMulti(m_core, | |
| this, | |
| prop, | |
| keys, | |
| math::PI / 180.0f); | |
| return vpl; | |
| } | |
| return nullptr; | |
| } | |
| void VertexListener::createInPointPropertyListener() | |
| { | |
| auto xProp = m_instance->propertyValue(SymbolType::cubicVertexInPointX); | |
| auto yProp = m_instance->propertyValue(SymbolType::cubicVertexInPointY); | |
| if ((xProp != nullptr && xProp->is<ViewModelInstanceNumber>()) || | |
| (yProp != nullptr && yProp->is<ViewModelInstanceNumber>())) | |
| { | |
| auto vpl = new VertexPropertyListenerPoint( | |
| m_core, | |
| this, | |
| xProp, | |
| yProp, | |
| CubicDetachedVertexBase::inDistancePropertyKey, | |
| CubicDetachedVertexBase::inRotationPropertyKey); | |
| vpl->writeValue(); | |
| m_properties.push_back(vpl); | |
| } | |
| } | |
| void VertexListener::createOutPointPropertyListener() | |
| { | |
| auto xProp = m_instance->propertyValue(SymbolType::cubicVertexOutPointX); | |
| auto yProp = m_instance->propertyValue(SymbolType::cubicVertexOutPointY); | |
| if ((xProp != nullptr && xProp->is<ViewModelInstanceNumber>()) || | |
| (yProp != nullptr && yProp->is<ViewModelInstanceNumber>())) | |
| { | |
| auto vpl = new VertexPropertyListenerPoint( | |
| m_core, | |
| this, | |
| xProp, | |
| yProp, | |
| CubicDetachedVertexBase::outDistancePropertyKey, | |
| CubicDetachedVertexBase::outRotationPropertyKey); | |
| vpl->writeValue(); | |
| m_properties.push_back(vpl); | |
| } | |
| } | |
| void VertexListener::createPropertyListener(SymbolType symbolType) | |
| { | |
| PropertySymbolDependent* listener = nullptr; | |
| switch (symbolType) | |
| { | |
| case SymbolType::vertexX: | |
| case SymbolType::vertexY: | |
| case SymbolType::inRotation: | |
| case SymbolType::outRotation: | |
| case SymbolType::inDistance: | |
| case SymbolType::outDistance: | |
| listener = createSinglePropertyListener(symbolType); | |
| break; | |
| case SymbolType::distance: | |
| listener = createDistancePropertyListener(); | |
| break; | |
| case SymbolType::rotation: | |
| listener = createRotationPropertyListener(); | |
| break; | |
| default: | |
| break; | |
| } | |
| if (listener != nullptr) | |
| { | |
| listener->writeValue(); | |
| m_properties.push_back(listener); | |
| } | |
| } | |
| VertexPropertyListenerSingle::VertexPropertyListenerSingle( | |
| Core* vertex, | |
| VertexListener* vertexListener, | |
| ViewModelInstanceValue* instanceValue, | |
| uint16_t propertyKey, | |
| float multiplier) : | |
| PropertySymbolDependentSingle(vertex, | |
| vertexListener, | |
| instanceValue, | |
| propertyKey), | |
| m_multiplier(multiplier) | |
| {} | |
| void VertexPropertyListenerSingle::writeValue() | |
| { | |
| CoreRegistry::setDouble( | |
| m_coreObject, | |
| m_propertyKey, | |
| m_instanceValue->as<ViewModelInstanceNumber>()->propertyValue() * | |
| m_multiplier); | |
| } | |
| VertexPropertyListenerMulti::VertexPropertyListenerMulti( | |
| Core* vertex, | |
| VertexListener* vertexListener, | |
| ViewModelInstanceValue* instanceValue, | |
| std::vector<uint16_t> propertyKeys, | |
| float multiplier) : | |
| PropertySymbolDependentMulti(vertex, | |
| vertexListener, | |
| instanceValue, | |
| propertyKeys), | |
| m_multiplier(multiplier) | |
| {} | |
| void VertexPropertyListenerMulti::writeValue() | |
| { | |
| for (auto& key : m_propertyKeys) | |
| { | |
| CoreRegistry::setDouble( | |
| m_coreObject, | |
| key, | |
| m_instanceValue->as<ViewModelInstanceNumber>()->propertyValue() * | |
| m_multiplier); | |
| } | |
| } | |
| VertexPropertyListenerPoint::VertexPropertyListenerPoint( | |
| Core* vertex, | |
| VertexListener* vertexListener, | |
| ViewModelInstanceValue* xValue, | |
| ViewModelInstanceValue* yValue, | |
| uint16_t distKey, | |
| uint16_t rotKey) : | |
| PropertySymbolDependent(vertex, vertexListener, xValue), | |
| m_yValue(yValue), | |
| m_distKey(distKey), | |
| m_rotKey(rotKey) | |
| { | |
| if (m_yValue) | |
| { | |
| m_yValue->addDependent(this); | |
| } | |
| } | |
| VertexPropertyListenerPoint::~VertexPropertyListenerPoint() | |
| { | |
| if (m_yValue) | |
| { | |
| m_yValue->removeDependent(this); | |
| } | |
| } | |
| void VertexPropertyListenerPoint::writeValue() | |
| { | |
| auto x = | |
| m_instanceValue | |
| ? m_instanceValue->as<ViewModelInstanceNumber>()->propertyValue() | |
| : 0; | |
| auto y = | |
| m_yValue ? m_yValue->as<ViewModelInstanceNumber>()->propertyValue() : 0; | |
| auto vec = Vec2D(x, y); | |
| auto length = vec.length(); | |
| auto rotation = std::atan2(vec.y, vec.x); | |
| CoreRegistry::setDouble(m_coreObject, m_distKey, length); | |
| CoreRegistry::setDouble(m_coreObject, m_rotKey, rotation); | |
| } | |
| ListPath::~ListPath() | |
| { | |
| for (auto& vertex : m_vertexListeners) | |
| { | |
| delete vertex; | |
| } | |
| } | |
| void ListPath::updateList(std::vector<rcp<ViewModelInstanceListItem>>* list) | |
| { | |
| auto currentVertexSize = m_vertexListeners.size(); | |
| size_t index = 0; | |
| for (auto& listItem : *list) | |
| { | |
| auto instance = listItem->viewModelInstance(); | |
| if (instance != nullptr) | |
| { | |
| if (index >= currentVertexSize) | |
| { | |
| // We treat all vertices as CubicDetached vertices because all | |
| // others can be expressed by this one. There doesn't seem to be | |
| // significant performance implications of doing so. But in the | |
| // future it might be valuable to be smarter and build the | |
| // corresponding one. | |
| auto vertex = new CubicDetachedVertex(); | |
| auto vertexListener = | |
| new VertexListener(vertex, instance, this); | |
| m_vertexListeners.push_back(vertexListener); | |
| addVertex(vertex); | |
| } | |
| else | |
| { | |
| auto vertexListener = m_vertexListeners[index]; | |
| vertexListener->remap(instance); | |
| } | |
| index++; | |
| } | |
| } | |
| while (m_vertexListeners.size() > index) | |
| { | |
| auto vertex = m_vertexListeners.back(); | |
| m_vertexListeners.pop_back(); | |
| popVertex(); | |
| delete vertex; | |
| } | |
| markPathDirty(); | |
| } |