blob: 2f00370ca9fe6760a16ab37c380946ae669a0be1 [file]
#include "rive/animation/transition_viewmodel_condition.hpp"
#include "rive/animation/state_transition.hpp"
#include "rive/animation/transition_property_component_comparator.hpp"
#include "rive/artboard.hpp"
#include "rive/core/field_types/core_bool_type.hpp"
#include "rive/core/field_types/core_color_type.hpp"
#include "rive/core/field_types/core_double_type.hpp"
#include "rive/core/field_types/core_string_type.hpp"
#include "rive/core/field_types/core_uint_type.hpp"
#include "rive/generated/core_registry.hpp"
#include "rive/generated/custom_property_enum_base.hpp"
#include "rive/generated/custom_property_trigger_base.hpp"
#include "rive/generated/viewmodel/viewmodel_instance_artboard_base.hpp"
#include "rive/generated/viewmodel/viewmodel_instance_asset_base.hpp"
#include "rive/generated/viewmodel/viewmodel_instance_enum_base.hpp"
#include "rive/generated/viewmodel/viewmodel_instance_trigger_base.hpp"
#include "rive/generated/viewmodel/viewmodel_instance_viewmodel_base.hpp"
#include "rive/importers/state_transition_importer.hpp"
#include "rive/importers/state_machine_importer.hpp"
#include "rive/animation/state_machine.hpp"
#include "rive/animation/state_machine_instance.hpp"
#include "rive/component_dirt.hpp"
#include "rive/viewmodel/viewmodel_instance_viewmodel.hpp"
#include <vector>
using namespace rive;
class ConditionComparisonNone : public ConditionComparison
{
public:
ConditionComparisonNone() : ConditionComparison(nullptr) {}
bool compare(const StateMachineInstance* stateMachineInstance,
StateMachineLayerInstance* layerInstance) override
{
return false;
}
};
class ConditionComparisonSelf : public ConditionComparison
{
public:
ConditionComparisonSelf(BindableProperty* property) :
ConditionComparison(nullptr), m_bindableProperty(property)
{}
bool compare(const StateMachineInstance* stateMachineInstance,
StateMachineLayerInstance* layerInstance) override
{
auto bindableInstance =
stateMachineInstance->bindablePropertyInstance(m_bindableProperty);
auto dataBind =
stateMachineInstance->bindableDataBindToTarget(bindableInstance);
if (dataBind != nullptr)
{
auto source = dataBind->source();
if (source != nullptr && source->hasChanged() &&
!source->isUsedInLayer(layerInstance))
{
return true;
}
}
return false;
}
private:
BindableProperty* m_bindableProperty;
};
class ConditionComparisonNumber : public ConditionComparison
{
public:
ConditionComparisonNumber(ConditionComparandNumber* left,
ConditionComparandNumber* right,
ConditionOperation* operation) :
ConditionComparison(operation),
m_leftComparand(left),
m_rightComparand(right)
{}
~ConditionComparisonNumber()
{
delete m_leftComparand;
delete m_rightComparand;
}
bool compare(const StateMachineInstance* stateMachineInstance,
StateMachineLayerInstance* layerInstance) override
{
return compareNumbers(m_leftComparand->value(stateMachineInstance),
m_rightComparand->value(stateMachineInstance));
}
private:
ConditionComparandNumber* m_leftComparand = nullptr;
ConditionComparandNumber* m_rightComparand = nullptr;
};
class ConditionComparisonBoolean : public ConditionComparison
{
public:
ConditionComparisonBoolean(ConditionComparandBoolean* left,
ConditionComparandBoolean* right,
ConditionOperation* operation) :
ConditionComparison(operation),
m_leftComparand(left),
m_rightComparand(right)
{}
~ConditionComparisonBoolean() override
{
delete m_leftComparand;
delete m_rightComparand;
}
bool compare(const StateMachineInstance* stateMachineInstance,
StateMachineLayerInstance* layerInstance) override
{
return compareBooleans(m_leftComparand->value(stateMachineInstance),
m_rightComparand->value(stateMachineInstance));
}
private:
ConditionComparandBoolean* m_leftComparand = nullptr;
ConditionComparandBoolean* m_rightComparand = nullptr;
};
class ConditionComparisonString : public ConditionComparison
{
public:
ConditionComparisonString(ConditionComparandString* left,
ConditionComparandString* right,
ConditionOperation* operation) :
ConditionComparison(operation),
m_leftComparand(left),
m_rightComparand(right)
{}
~ConditionComparisonString()
{
delete m_leftComparand;
delete m_rightComparand;
}
bool compare(const StateMachineInstance* stateMachineInstance,
StateMachineLayerInstance* layerInstance) override
{
return compareStrings(m_leftComparand->value(stateMachineInstance),
m_rightComparand->value(stateMachineInstance));
}
private:
ConditionComparandString* m_leftComparand = nullptr;
ConditionComparandString* m_rightComparand = nullptr;
};
class ConditionComparisonColor : public ConditionComparison
{
public:
ConditionComparisonColor(ConditionComparandColor* left,
ConditionComparandColor* right,
ConditionOperation* operation) :
ConditionComparison(operation),
m_leftComparand(left),
m_rightComparand(right)
{}
~ConditionComparisonColor()
{
delete m_leftComparand;
delete m_rightComparand;
}
bool compare(const StateMachineInstance* stateMachineInstance,
StateMachineLayerInstance* layerInstance) override
{
return compareColors(m_leftComparand->value(stateMachineInstance),
m_rightComparand->value(stateMachineInstance));
}
private:
ConditionComparandColor* m_leftComparand = nullptr;
ConditionComparandColor* m_rightComparand = nullptr;
};
class ConditionComparisonEnum : public ConditionComparison
{
public:
ConditionComparisonEnum(ConditionComparandUint32* left,
ConditionComparandUint32* right,
ConditionOperation* operation) :
ConditionComparison(operation),
m_leftComparand(left),
m_rightComparand(right)
{}
~ConditionComparisonEnum()
{
delete m_leftComparand;
delete m_rightComparand;
}
bool compare(const StateMachineInstance* stateMachineInstance,
StateMachineLayerInstance* layerInstance) override
{
return compareUints32(m_leftComparand->value(stateMachineInstance),
m_rightComparand->value(stateMachineInstance));
}
private:
ConditionComparandUint32* m_leftComparand = nullptr;
ConditionComparandUint32* m_rightComparand = nullptr;
};
class ConditionComparisonUint32 : public ConditionComparison
{
public:
ConditionComparisonUint32(ConditionComparandUint32* left,
ConditionComparandUint32* right,
ConditionOperation* operation) :
ConditionComparison(operation),
m_leftComparand(left),
m_rightComparand(right)
{}
~ConditionComparisonUint32()
{
delete m_leftComparand;
delete m_rightComparand;
}
bool compare(const StateMachineInstance* stateMachineInstance,
StateMachineLayerInstance* layerInstance) override
{
return compareUints32(m_leftComparand->value(stateMachineInstance),
m_rightComparand->value(stateMachineInstance));
}
private:
ConditionComparandUint32* m_leftComparand = nullptr;
ConditionComparandUint32* m_rightComparand = nullptr;
};
class ConditionComparisonViewModel : public ConditionComparison
{
public:
ConditionComparisonViewModel(ConditionComparandViewModel* left,
ConditionComparandViewModel* right,
ConditionOperation* operation) :
ConditionComparison(operation),
m_leftComparand(left),
m_rightComparand(right)
{}
~ConditionComparisonViewModel()
{
delete m_leftComparand;
delete m_rightComparand;
}
bool compare(const StateMachineInstance* stateMachineInstance,
StateMachineLayerInstance* layerInstance) override
{
return comparePointers(m_leftComparand->value(stateMachineInstance),
m_rightComparand->value(stateMachineInstance));
}
private:
ConditionComparandViewModel* m_leftComparand = nullptr;
ConditionComparandViewModel* m_rightComparand = nullptr;
};
namespace
{
Core* resolveComponentTarget(const StateMachineInstance* smi,
const TransitionPropertyComponentComparator* comp)
{
if (smi == nullptr || comp == nullptr)
{
return nullptr;
}
Artboard* artboard = smi->artboard();
if (artboard == nullptr)
{
return nullptr;
}
Core* target = artboard->resolve(comp->objectId());
if (target == nullptr ||
!CoreRegistry::objectSupportsProperty(target, comp->propertyKey()))
{
return nullptr;
}
return target;
}
enum class ComponentComparandKind
{
NumberDouble,
NumberFromUint,
Boolean,
String,
Color,
Enum,
Trigger,
Asset,
Artboard,
ViewModel,
};
bool describeComponentSide(const TransitionPropertyComponentComparator* comp,
ComponentComparandKind* outKind)
{
int fieldId = CoreRegistry::propertyFieldId((int)comp->propertyKey());
if (fieldId < 0)
{
return false;
}
const uint32_t pk = comp->propertyKey();
switch (fieldId)
{
case CoreDoubleType::id:
*outKind = ComponentComparandKind::NumberDouble;
return true;
case CoreBoolType::id:
*outKind = ComponentComparandKind::Boolean;
return true;
case CoreStringType::id:
*outKind = ComponentComparandKind::String;
return true;
case CoreColorType::id:
*outKind = ComponentComparandKind::Color;
return true;
case CoreUintType::id:
if (pk == CustomPropertyEnumBase::propertyValuePropertyKey ||
pk == ViewModelInstanceEnumBase::propertyValuePropertyKey)
{
*outKind = ComponentComparandKind::Enum;
return true;
}
if (pk == CustomPropertyTriggerBase::propertyValuePropertyKey ||
pk == ViewModelInstanceTriggerBase::propertyValuePropertyKey)
{
*outKind = ComponentComparandKind::Trigger;
return true;
}
if (pk == ViewModelInstanceAssetBase::propertyValuePropertyKey)
{
*outKind = ComponentComparandKind::Asset;
return true;
}
if (pk == ViewModelInstanceArtboardBase::propertyValuePropertyKey)
{
*outKind = ComponentComparandKind::Artboard;
return true;
}
if (pk == ViewModelInstanceViewModelBase::propertyValuePropertyKey)
{
*outKind = ComponentComparandKind::ViewModel;
return true;
}
*outKind = ComponentComparandKind::NumberFromUint;
return true;
default:
return false;
}
}
bool componentKindsCompatible(ComponentComparandKind a,
ComponentComparandKind b)
{
auto isNumberKind = [](ComponentComparandKind k) {
return k == ComponentComparandKind::NumberDouble ||
k == ComponentComparandKind::NumberFromUint;
};
if (isNumberKind(a) && isNumberKind(b))
{
return true;
}
return a == b;
}
ConditionComparandNumber* makeComponentNumberComparand(
TransitionPropertyComponentComparator* comp,
ComponentComparandKind kind)
{
if (kind == ComponentComparandKind::NumberDouble)
{
return new ConditionComparandComponentCoreNumber(comp);
}
return new ConditionComparandComponentCoreUintAsNumber(comp);
}
bool describeViewModelBindableKind(BindableProperty* bindable,
ComponentComparandKind* outKind)
{
if (bindable == nullptr)
{
return false;
}
switch (bindable->coreType())
{
case BindablePropertyNumber::typeKey:
*outKind = ComponentComparandKind::NumberDouble;
return true;
case BindablePropertyInteger::typeKey:
*outKind = ComponentComparandKind::NumberFromUint;
return true;
case BindablePropertyBoolean::typeKey:
*outKind = ComponentComparandKind::Boolean;
return true;
case BindablePropertyString::typeKey:
*outKind = ComponentComparandKind::String;
return true;
case BindablePropertyColor::typeKey:
*outKind = ComponentComparandKind::Color;
return true;
case BindablePropertyEnum::typeKey:
*outKind = ComponentComparandKind::Enum;
return true;
case BindablePropertyTrigger::typeKey:
*outKind = ComponentComparandKind::Trigger;
return true;
case BindablePropertyAsset::typeKey:
*outKind = ComponentComparandKind::Asset;
return true;
case BindablePropertyArtboard::typeKey:
*outKind = ComponentComparandKind::Artboard;
return true;
case BindablePropertyViewModel::typeKey:
*outKind = ComponentComparandKind::ViewModel;
return true;
default:
return false;
}
}
enum class ComparatorSide
{
Left,
Right,
};
// Artboard properties and literal values only participate on the left / right
// respectively (matches historical initialize() support).
void appendComparableKinds(TransitionComparator* comparator,
ComparatorSide side,
std::vector<ComponentComparandKind>& out)
{
if (comparator->is<TransitionPropertyArtboardComparator>())
{
if (side == ComparatorSide::Left)
{
out.push_back(ComponentComparandKind::NumberDouble);
}
return;
}
if (comparator->is<TransitionPropertyComponentComparator>())
{
ComponentComparandKind k;
if (describeComponentSide(
comparator->as<TransitionPropertyComponentComparator>(),
&k))
{
out.push_back(k);
}
return;
}
if (comparator->is<TransitionPropertyViewModelComparator>())
{
ComponentComparandKind k;
if (describeViewModelBindableKind(
comparator->as<TransitionPropertyViewModelComparator>()
->bindableProperty(),
&k))
{
out.push_back(k);
}
return;
}
if (side != ComparatorSide::Right)
{
return;
}
if (comparator->is<TransitionValueNumberComparator>())
{
out.push_back(ComponentComparandKind::NumberDouble);
return;
}
if (comparator->is<TransitionValueBooleanComparator>())
{
out.push_back(ComponentComparandKind::Boolean);
return;
}
if (comparator->is<TransitionValueStringComparator>())
{
out.push_back(ComponentComparandKind::String);
return;
}
if (comparator->is<TransitionValueColorComparator>())
{
out.push_back(ComponentComparandKind::Color);
return;
}
if (comparator->is<TransitionValueEnumComparator>())
{
out.push_back(ComponentComparandKind::Enum);
return;
}
if (comparator->is<TransitionValueAssetComparator>())
{
out.push_back(ComponentComparandKind::Asset);
return;
}
if (comparator->is<TransitionValueArtboardComparator>())
{
out.push_back(ComponentComparandKind::Artboard);
return;
}
// Uint32 comparison vs component triggers; VM trigger + value trigger uses
// ConditionComparisonSelf and is handled before kind intersection.
if (comparator->is<TransitionValueTriggerComparator>())
{
out.push_back(ComponentComparandKind::Trigger);
return;
}
}
// Picks the first (lk, rk) pair such that componentKindsCompatible(lk, rk),
// scanning leftKinds in order then rightKinds (deterministic tie-break).
bool intersectCompatibleKinds(
const std::vector<ComponentComparandKind>& leftKinds,
const std::vector<ComponentComparandKind>& rightKinds,
ComponentComparandKind* outLeftKind,
ComponentComparandKind* outRightKind)
{
for (ComponentComparandKind lk : leftKinds)
{
for (ComponentComparandKind rk : rightKinds)
{
if (componentKindsCompatible(lk, rk))
{
*outLeftKind = lk;
*outRightKind = rk;
return true;
}
}
}
return false;
}
enum class ComparisonShape
{
Number,
Boolean,
String,
Color,
Enum,
Uint32,
ViewModel,
};
// Maps compatible kinds to ConditionComparison wrapper. Numeric: any
// NumberDouble in the pair uses float compare (Number); both NumberFromUint
// uses exact uint32 compare (Uint32), including component+component generic
// uint fields and VM integer pairs.
bool resolveComparisonShape(ComponentComparandKind lk,
ComponentComparandKind rk,
ComparisonShape* outShape)
{
if (!componentKindsCompatible(lk, rk))
{
return false;
}
auto isNumberKind = [](ComponentComparandKind k) {
return k == ComponentComparandKind::NumberDouble ||
k == ComponentComparandKind::NumberFromUint;
};
if (isNumberKind(lk) && isNumberKind(rk))
{
if (lk == ComponentComparandKind::NumberFromUint &&
rk == ComponentComparandKind::NumberFromUint)
{
*outShape = ComparisonShape::Uint32;
return true;
}
*outShape = ComparisonShape::Number;
return true;
}
if (lk != rk)
{
return false;
}
switch (lk)
{
case ComponentComparandKind::Boolean:
*outShape = ComparisonShape::Boolean;
return true;
case ComponentComparandKind::String:
*outShape = ComparisonShape::String;
return true;
case ComponentComparandKind::Color:
*outShape = ComparisonShape::Color;
return true;
case ComponentComparandKind::Enum:
*outShape = ComparisonShape::Enum;
return true;
case ComponentComparandKind::Trigger:
case ComponentComparandKind::Asset:
case ComponentComparandKind::Artboard:
*outShape = ComparisonShape::Uint32;
return true;
case ComponentComparandKind::ViewModel:
*outShape = ComparisonShape::ViewModel;
return true;
default:
return false;
}
}
struct ComparandSlot
{
ConditionComparandNumber* number = nullptr;
ConditionComparandBoolean* boolean = nullptr;
ConditionComparandString* string = nullptr;
ConditionComparandColor* color = nullptr;
ConditionComparandUint32* uint32 = nullptr;
ConditionComparandViewModel* viewModel = nullptr;
};
void clearComparandSlot(ComparandSlot& s)
{
delete s.number;
delete s.boolean;
delete s.string;
delete s.color;
delete s.uint32;
delete s.viewModel;
s = ComparandSlot{};
}
// Builds one comparand for `c` and kind `k` given the resolved comparison.
bool makeComparand(TransitionComparator* c,
ComponentComparandKind k,
ComparisonShape shape,
ComparandSlot* slot)
{
switch (shape)
{
case ComparisonShape::Number:
{
if (c->is<TransitionPropertyArtboardComparator>())
{
slot->number = new ConditionComparandArtboardProperty(
c->as<TransitionPropertyArtboardComparator>());
return true;
}
if (c->is<TransitionPropertyViewModelComparator>())
{
auto* bp = c->as<TransitionPropertyViewModelComparator>()
->bindableProperty();
if (bp == nullptr)
{
return false;
}
if (bp->is<BindablePropertyNumber>())
{
slot->number = new ConditionComparandNumberBindable(
bp->as<BindablePropertyNumber>());
return true;
}
if (bp->is<BindablePropertyInteger>())
{
slot->number = new ConditionComparandNumberBindableInteger(
bp->as<BindablePropertyInteger>());
return true;
}
return false;
}
if (c->is<TransitionValueNumberComparator>())
{
slot->number = new ConditionComparandNumberValue(
c->as<TransitionValueNumberComparator>());
return true;
}
if (c->is<TransitionPropertyComponentComparator>())
{
auto* comp = c->as<TransitionPropertyComponentComparator>();
if (k == ComponentComparandKind::NumberDouble)
{
slot->number =
new ConditionComparandComponentCoreNumber(comp);
return true;
}
if (k == ComponentComparandKind::NumberFromUint)
{
slot->number = makeComponentNumberComparand(comp, k);
return true;
}
return false;
}
return false;
}
case ComparisonShape::Boolean:
{
if (c->is<TransitionPropertyViewModelComparator>())
{
auto* bp = c->as<TransitionPropertyViewModelComparator>()
->bindableProperty();
if (bp == nullptr || !bp->is<BindablePropertyBoolean>())
{
return false;
}
slot->boolean = new ConditionComparandBooleanBindable(
bp->as<BindablePropertyBoolean>());
return true;
}
if (c->is<TransitionValueBooleanComparator>())
{
slot->boolean = new ConditionComparandBooleanValue(
c->as<TransitionValueBooleanComparator>());
return true;
}
if (c->is<TransitionPropertyComponentComparator>())
{
slot->boolean = new ConditionComparandComponentCoreBoolean(
c->as<TransitionPropertyComponentComparator>());
return true;
}
return false;
}
case ComparisonShape::String:
{
if (c->is<TransitionPropertyViewModelComparator>())
{
auto* bp = c->as<TransitionPropertyViewModelComparator>()
->bindableProperty();
if (bp == nullptr || !bp->is<BindablePropertyString>())
{
return false;
}
slot->string = new ConditionComparandStringBindable(
bp->as<BindablePropertyString>());
return true;
}
if (c->is<TransitionValueStringComparator>())
{
slot->string = new ConditionComparandStringValue(
c->as<TransitionValueStringComparator>());
return true;
}
if (c->is<TransitionPropertyComponentComparator>())
{
slot->string = new ConditionComparandComponentCoreString(
c->as<TransitionPropertyComponentComparator>());
return true;
}
return false;
}
case ComparisonShape::Color:
{
if (c->is<TransitionPropertyViewModelComparator>())
{
auto* bp = c->as<TransitionPropertyViewModelComparator>()
->bindableProperty();
if (bp == nullptr || !bp->is<BindablePropertyColor>())
{
return false;
}
slot->color = new ConditionComparandColorBindable(
bp->as<BindablePropertyColor>());
return true;
}
if (c->is<TransitionValueColorComparator>())
{
slot->color = new ConditionComparandColorValue(
c->as<TransitionValueColorComparator>());
return true;
}
if (c->is<TransitionPropertyComponentComparator>())
{
slot->color = new ConditionComparandComponentCoreColor(
c->as<TransitionPropertyComponentComparator>());
return true;
}
return false;
}
case ComparisonShape::Enum:
{
if (c->is<TransitionPropertyViewModelComparator>())
{
auto* bp = c->as<TransitionPropertyViewModelComparator>()
->bindableProperty();
if (bp == nullptr || !bp->is<BindablePropertyEnum>())
{
return false;
}
slot->uint32 = new ConditionComparandEnumBindable(
bp->as<BindablePropertyEnum>());
return true;
}
if (c->is<TransitionValueEnumComparator>())
{
slot->uint32 = new ConditionComparandEnumValue(
c->as<TransitionValueEnumComparator>());
return true;
}
if (c->is<TransitionPropertyComponentComparator>())
{
slot->uint32 = new ConditionComparandComponentCoreUint(
c->as<TransitionPropertyComponentComparator>());
return true;
}
return false;
}
case ComparisonShape::Uint32:
{
if (c->is<TransitionPropertyViewModelComparator>())
{
auto* bp = c->as<TransitionPropertyViewModelComparator>()
->bindableProperty();
if (bp == nullptr)
{
return false;
}
if (k == ComponentComparandKind::NumberFromUint &&
bp->is<BindablePropertyInteger>())
{
slot->uint32 = new ConditionComparandIntegerBindable(
bp->as<BindablePropertyInteger>());
return true;
}
if (k == ComponentComparandKind::Trigger &&
bp->is<BindablePropertyTrigger>())
{
slot->uint32 = new ConditionComparandTriggerBindable(
bp->as<BindablePropertyTrigger>());
return true;
}
if (k == ComponentComparandKind::Asset &&
bp->is<BindablePropertyAsset>())
{
slot->uint32 = new ConditionComparandAssetBindable(
bp->as<BindablePropertyAsset>());
return true;
}
if (k == ComponentComparandKind::Artboard &&
bp->is<BindablePropertyArtboard>())
{
slot->uint32 = new ConditionComparandArtboardBindable(
bp->as<BindablePropertyArtboard>());
return true;
}
return false;
}
if (c->is<TransitionValueTriggerComparator>())
{
slot->uint32 = new ConditionComparandTriggerValue(
c->as<TransitionValueTriggerComparator>());
return true;
}
if (c->is<TransitionValueAssetComparator>())
{
slot->uint32 = new ConditionComparandAssetValue(
c->as<TransitionValueAssetComparator>());
return true;
}
if (c->is<TransitionValueArtboardComparator>())
{
slot->uint32 = new ConditionComparandArtboardValue(
c->as<TransitionValueArtboardComparator>());
return true;
}
if (c->is<TransitionPropertyComponentComparator>())
{
slot->uint32 = new ConditionComparandComponentCoreUint(
c->as<TransitionPropertyComponentComparator>());
return true;
}
return false;
}
case ComparisonShape::ViewModel:
{
if (k != ComponentComparandKind::ViewModel)
{
return false;
}
if (c->is<TransitionPropertyViewModelComparator>())
{
auto* bp = c->as<TransitionPropertyViewModelComparator>()
->bindableProperty();
if (bp == nullptr || !bp->is<BindablePropertyViewModel>())
{
return false;
}
slot->viewModel = new ConditionComparandViewModelBindable(
bp->as<BindablePropertyViewModel>());
return true;
}
return false;
}
default:
return false;
}
}
ConditionComparison* wrapComparison(ComparisonShape shape,
ComparandSlot& leftSlot,
ComparandSlot& rightSlot,
ConditionOperation* op)
{
switch (shape)
{
case ComparisonShape::Number:
if (leftSlot.number == nullptr || rightSlot.number == nullptr)
{
return nullptr;
}
return new ConditionComparisonNumber(leftSlot.number,
rightSlot.number,
op);
case ComparisonShape::Boolean:
if (leftSlot.boolean == nullptr || rightSlot.boolean == nullptr)
{
return nullptr;
}
return new ConditionComparisonBoolean(leftSlot.boolean,
rightSlot.boolean,
op);
case ComparisonShape::String:
if (leftSlot.string == nullptr || rightSlot.string == nullptr)
{
return nullptr;
}
return new ConditionComparisonString(leftSlot.string,
rightSlot.string,
op);
case ComparisonShape::Color:
if (leftSlot.color == nullptr || rightSlot.color == nullptr)
{
return nullptr;
}
return new ConditionComparisonColor(leftSlot.color,
rightSlot.color,
op);
case ComparisonShape::Enum:
if (leftSlot.uint32 == nullptr || rightSlot.uint32 == nullptr)
{
return nullptr;
}
return new ConditionComparisonEnum(leftSlot.uint32,
rightSlot.uint32,
op);
case ComparisonShape::Uint32:
if (leftSlot.uint32 == nullptr || rightSlot.uint32 == nullptr)
{
return nullptr;
}
return new ConditionComparisonUint32(leftSlot.uint32,
rightSlot.uint32,
op);
case ComparisonShape::ViewModel:
if (leftSlot.viewModel == nullptr || rightSlot.viewModel == nullptr)
{
return nullptr;
}
return new ConditionComparisonViewModel(leftSlot.viewModel,
rightSlot.viewModel,
op);
default:
return nullptr;
}
}
bool buildComparandsFromIntersect(TransitionComparator* left,
TransitionComparator* right,
ComponentComparandKind lk,
ComponentComparandKind rk,
ConditionOperation* op,
ConditionComparison** outComparison)
{
ComparisonShape shape;
if (!resolveComparisonShape(lk, rk, &shape))
{
return false;
}
ComparandSlot leftSlot, rightSlot;
if (!makeComparand(left, lk, shape, &leftSlot) ||
!makeComparand(right, rk, shape, &rightSlot))
{
clearComparandSlot(leftSlot);
clearComparandSlot(rightSlot);
return false;
}
ConditionComparison* wrapped =
wrapComparison(shape, leftSlot, rightSlot, op);
if (wrapped == nullptr)
{
clearComparandSlot(leftSlot);
clearComparandSlot(rightSlot);
return false;
}
*outComparison = wrapped;
return true;
}
} // namespace
TransitionViewModelCondition::~TransitionViewModelCondition()
{
if (m_leftComparator != nullptr)
{
delete m_leftComparator;
m_leftComparator = nullptr;
}
if (m_rightComparator != nullptr)
{
delete m_rightComparator;
m_rightComparator = nullptr;
}
if (m_comparison != nullptr)
{
delete m_comparison;
m_comparison = nullptr;
}
}
bool TransitionViewModelCondition::canEvaluate(
const StateMachineInstance* stateMachineInstance) const
{
if (!leftComparator() || !rightComparator())
{
return false;
}
if (!stateMachineInstance->dataContext() &&
(rightComparator()->is<TransitionPropertyViewModelComparator>() ||
leftComparator()->is<TransitionPropertyViewModelComparator>()))
{
return false;
}
return true;
}
bool TransitionViewModelCondition::evaluate(
const StateMachineInstance* stateMachineInstance,
StateMachineLayerInstance* layerInstance) const
{
if (canEvaluate(stateMachineInstance) && m_comparison != nullptr)
{
return m_comparison->compare(stateMachineInstance, layerInstance);
}
return false;
}
void TransitionViewModelCondition::useInLayer(
const StateMachineInstance* stateMachineInstance,
StateMachineLayerInstance* layerInstance) const
{
if (leftComparator() != nullptr)
{
return leftComparator()->useInLayer(stateMachineInstance,
layerInstance);
}
}
ConditionOperation* TransitionViewModelCondition::operation(
TransitionConditionOp op)
{
switch (op)
{
case TransitionConditionOp::equal:
return new ConditionOperationEqual();
case TransitionConditionOp::notEqual:
return new ConditionOperationNotEqual();
case TransitionConditionOp::lessThanOrEqual:
return new ConditionOperationLessThanOrEqual();
case TransitionConditionOp::lessThan:
return new ConditionOperationLessThan();
case TransitionConditionOp::greaterThanOrEqual:
return new ConditionOperationGreaterThanOrEqual();
case TransitionConditionOp::greaterThan:
return new ConditionOperationGreaterThan();
}
return new ConditionOperation();
}
void TransitionViewModelCondition::initialize()
{
TransitionComparator* left = leftComparator();
TransitionComparator* right = rightComparator();
if (left == nullptr || right == nullptr)
{
return;
}
// Asymmetric: Self compares the left bindable against its data bind source,
// not a typed comparand intersection.
if (right->is<TransitionSelfComparator>())
{
if (left->is<TransitionPropertyViewModelComparator>())
{
auto* leftBindable =
left->as<TransitionPropertyViewModelComparator>()
->bindableProperty();
if (leftBindable != nullptr)
{
m_comparison = new ConditionComparisonSelf(leftBindable);
return;
}
}
m_comparison = new ConditionComparisonNone();
return;
}
// Asymmetric: value trigger on the right uses ConditionComparisonSelf with
// a VM trigger on the left (not uint32 vs a value comparand).
if (left->is<TransitionPropertyViewModelComparator>() &&
right->is<TransitionValueTriggerComparator>())
{
auto* lbp = left->as<TransitionPropertyViewModelComparator>()
->bindableProperty();
if (lbp != nullptr && lbp->is<BindablePropertyTrigger>())
{
m_comparison = new ConditionComparisonSelf(lbp);
return;
}
}
std::vector<ComponentComparandKind> leftKinds;
std::vector<ComponentComparandKind> rightKinds;
appendComparableKinds(left, ComparatorSide::Left, leftKinds);
appendComparableKinds(right, ComparatorSide::Right, rightKinds);
ComponentComparandKind lk{};
ComponentComparandKind rk{};
if (!intersectCompatibleKinds(leftKinds, rightKinds, &lk, &rk))
{
m_comparison = new ConditionComparisonNone();
return;
}
ConditionOperation* condOp = operation(op());
ConditionComparison* cmp = nullptr;
if (buildComparandsFromIntersect(left, right, lk, rk, condOp, &cmp))
{
m_comparison = cmp;
return;
}
delete condOp;
m_comparison = new ConditionComparisonNone();
}
ConditionComparandComponentCoreNumber::ConditionComparandComponentCoreNumber(
TransitionPropertyComponentComparator* comparator) :
m_comparator(comparator)
{}
float ConditionComparandComponentCoreNumber::value(
const StateMachineInstance* stateMachineInstance)
{
Core* target = resolveComponentTarget(stateMachineInstance, m_comparator);
if (target == nullptr)
{
return 0.0f;
}
return CoreRegistry::getDouble(target, (int)m_comparator->propertyKey());
}
ConditionComparandComponentCoreUintAsNumber::
ConditionComparandComponentCoreUintAsNumber(
TransitionPropertyComponentComparator* comparator) :
m_comparator(comparator)
{}
float ConditionComparandComponentCoreUintAsNumber::value(
const StateMachineInstance* stateMachineInstance)
{
Core* target = resolveComponentTarget(stateMachineInstance, m_comparator);
if (target == nullptr)
{
return 0.0f;
}
return (float)CoreRegistry::getUint(target,
(int)m_comparator->propertyKey());
}
ConditionComparandComponentCoreBoolean::ConditionComparandComponentCoreBoolean(
TransitionPropertyComponentComparator* comparator) :
m_comparator(comparator)
{}
bool ConditionComparandComponentCoreBoolean::value(
const StateMachineInstance* stateMachineInstance)
{
Core* target = resolveComponentTarget(stateMachineInstance, m_comparator);
if (target == nullptr)
{
return false;
}
return CoreRegistry::getBool(target, (int)m_comparator->propertyKey());
}
ConditionComparandComponentCoreString::ConditionComparandComponentCoreString(
TransitionPropertyComponentComparator* comparator) :
m_comparator(comparator)
{}
std::string ConditionComparandComponentCoreString::value(
const StateMachineInstance* stateMachineInstance)
{
Core* target = resolveComponentTarget(stateMachineInstance, m_comparator);
if (target == nullptr)
{
return std::string{};
}
return CoreRegistry::getString(target, (int)m_comparator->propertyKey());
}
ConditionComparandComponentCoreColor::ConditionComparandComponentCoreColor(
TransitionPropertyComponentComparator* comparator) :
m_comparator(comparator)
{}
int ConditionComparandComponentCoreColor::value(
const StateMachineInstance* stateMachineInstance)
{
Core* target = resolveComponentTarget(stateMachineInstance, m_comparator);
if (target == nullptr)
{
return 0;
}
return CoreRegistry::getColor(target, (int)m_comparator->propertyKey());
}
ConditionComparandComponentCoreUint::ConditionComparandComponentCoreUint(
TransitionPropertyComponentComparator* comparator) :
m_comparator(comparator)
{}
uint32_t ConditionComparandComponentCoreUint::value(
const StateMachineInstance* stateMachineInstance)
{
Core* target = resolveComponentTarget(stateMachineInstance, m_comparator);
if (target == nullptr)
{
return 0;
}
return CoreRegistry::getUint(target, (int)m_comparator->propertyKey());
}
bool ConditionComparison::compareNumbers(float left, float right)
{
return m_operation->compareNumbers(left, right);
}
bool ConditionComparison::compareStrings(const std::string& left,
const std::string& right)
{
return m_operation->compareStrings(left, right);
}
bool ConditionComparison::compareBooleans(bool left, bool right)
{
return m_operation->compareBooleans(left, right);
}
bool ConditionComparison::compareColors(int left, int right)
{
return m_operation->compareInts(left, right);
}
bool ConditionComparison::compareUints32(uint32_t left, uint32_t right)
{
return m_operation->compareUints32(left, right);
}
bool ConditionComparison::comparePointers(const void* left, const void* right)
{
return m_operation->compareBooleans(left == right, true);
}