1 /* 2 * Copyright (c) 2024 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16 #ifndef SCENE_SRC_CONVERTING_VALUE_H 17 #define SCENE_SRC_CONVERTING_VALUE_H 18 19 #include <atomic> 20 #include <scene/ext/intf_converting_value.h> 21 22 #include <meta/api/event_handler.h> 23 #include <meta/api/make_callback.h> 24 #include <meta/ext/minimal_object.h> 25 #include <meta/interface/property/intf_stack_property.h> 26 #include <meta/interface/property/intf_stack_resetable.h> 27 #include <meta/interface/resource/intf_dynamic_resource.h> 28 #include <meta/interface/serialization/intf_serializable.h> 29 30 SCENE_BEGIN_NAMESPACE() 31 32 META_REGISTER_CLASS( 33 ConvertingValueBase, "41474a42-d7d1-4d4a-a6cd-5a53973e8f9e", META_NS::ObjectCategoryBits::NO_CATEGORY) 34 35 template<typename PropertyType> 36 class ConvertingValueBase : public META_NS::IntroduceInterfaces<META_NS::MinimalObject, META_NS::INotifyOnChange, 37 META_NS::IStackResetable, META_NS::IValue, IConvertingValue, META_NS::ISerializable> { META_IMPLEMENT_OBJECT_TYPE_INTERFACE(ClassId::ConvertingValueBase)38 META_IMPLEMENT_OBJECT_TYPE_INTERFACE(ClassId::ConvertingValueBase) 39 public: 40 ConvertingValueBase(META_NS::IAny::Ptr any, PropertyType p) : any_(BASE_NS::move(any)), p_(p) {} 41 ProcessOnReset(const META_NS::IAny & value)42 META_NS::ResetResult ProcessOnReset(const META_NS::IAny& value) override 43 { 44 SetValue(value); 45 return META_NS::RESET_CONTINUE; 46 } 47 EventOnChanged(META_NS::MetadataQuery)48 BASE_NS::shared_ptr<META_NS::IEvent> EventOnChanged(META_NS::MetadataQuery) const override 49 { 50 return p_->OnChanged(); 51 } 52 GetTargetProperty()53 META_NS::IProperty::Ptr GetTargetProperty() override 54 { 55 return p_; 56 } 57 Export(META_NS::IExportContext & c)58 META_NS::ReturnError Export(META_NS::IExportContext& c) const override 59 { 60 if (auto node = c.ExportValueToNode(any_)) { 61 return c.SubstituteThis(node); 62 } 63 return META_NS::GenericError::FAIL; 64 } Import(META_NS::IImportContext &)65 META_NS::ReturnError Import(META_NS::IImportContext&) override 66 { 67 return META_NS::GenericError::FAIL; 68 } 69 70 protected: 71 META_NS::IAny::Ptr any_; 72 PropertyType p_; 73 }; 74 75 template<typename Converter> 76 class ConvertingValue : public ConvertingValueBase<META_NS::Property<typename Converter::TargetType>> { 77 public: 78 using Super = ConvertingValueBase<META_NS::Property<typename Converter::TargetType>>; 79 80 using TargetType = typename Converter::TargetType; 81 using SourceType = typename Converter::SourceType; 82 using TargetProperty = META_NS::Property<TargetType>; 83 84 ConvertingValue(TargetProperty p, Converter convert = {}) Super(META_NS::ConstructAny<SourceType> (),p)85 : Super(META_NS::ConstructAny<SourceType>(), p), convert_(BASE_NS::move(convert)) 86 {} 87 SetValue(const META_NS::IAny & any)88 META_NS::AnyReturnValue SetValue(const META_NS::IAny& any) override 89 { 90 SourceType value {}; 91 auto res = any.GetValue<SourceType>(value); 92 if (res) { 93 res = this->p_->SetValue(convert_.ConvertToTarget(value)); 94 if (res) { 95 InternalSetValue(value); 96 } 97 } 98 return res; 99 } GetValue()100 const META_NS::IAny& GetValue() const override 101 { 102 auto pvalue = this->p_->GetValue(); 103 auto value = convert_.ConvertToSource(*this->any_, pvalue); 104 InternalSetValue(value); 105 return *this->any_; 106 } IsCompatible(const META_NS::TypeId & id)107 bool IsCompatible(const META_NS::TypeId& id) const override 108 { 109 return id == META_NS::UidFromType<SourceType>() || id == META_NS::UidFromType<TargetType>(); 110 } 111 112 private: 113 void OnResourceChanged(bool forceNotification = false) const 114 { 115 SourceType value {}; 116 auto res = this->any_->template GetValue<SourceType>(value); 117 if (res) { 118 auto locked = this->p_.GetLockedAccess(); 119 res = locked->SetValue(convert_.ConvertToTarget(value)); 120 // force notification 121 if (forceNotification && res == META_NS::AnyReturn::NOTHING_TO_DO) { 122 locked->NotifyChange(); 123 } 124 } 125 } InternalSetValue(const SourceType & value)126 void InternalSetValue(const SourceType& value) const 127 { 128 if (this->any_->SetValue(value) == META_NS::AnyReturn::SUCCESS) { 129 if constexpr (META_NS::IsInterfacePtr_v<SourceType>) { 130 if (auto i = interface_cast<META_NS::IDynamicResource>(value)) { 131 changed_.Subscribe<META_NS::IOnChanged>(i->OnResourceChanged(), [this] { 132 // if the object itself says it changed, for the notification 133 OnResourceChanged(true); 134 }); 135 OnResourceChanged(); 136 } else { 137 changed_.Unsubscribe(); 138 } 139 } 140 } 141 } 142 143 private: 144 Converter convert_; 145 mutable META_NS::EventHandler changed_; 146 }; 147 148 template<typename Converter> 149 class ConvertingArrayValue : public ConvertingValueBase<META_NS::ArrayProperty<typename Converter::TargetType>> { 150 public: 151 using Super = ConvertingValueBase<META_NS::ArrayProperty<typename Converter::TargetType>>; 152 153 using TargetType = typename Converter::TargetType; 154 using SourceType = typename Converter::SourceType; 155 using TargetProperty = META_NS::ArrayProperty<TargetType>; 156 157 ConvertingArrayValue(TargetProperty p, Converter convert = {}) Super(META_NS::ConstructArrayAny<SourceType> (),p)158 : Super(META_NS::ConstructArrayAny<SourceType>(), p), convert_(BASE_NS::move(convert)) 159 {} 160 SetValue(const META_NS::IAny & any)161 META_NS::AnyReturnValue SetValue(const META_NS::IAny& any) override 162 { 163 BASE_NS::vector<SourceType> value {}; 164 auto res = any.GetValue<BASE_NS::vector<SourceType>>(value); 165 if (res) { 166 BASE_NS::vector<TargetType> converted; 167 for (auto&& v : value) { 168 converted.push_back(convert_.ConvertToTarget(v)); 169 } 170 res = this->p_->SetValue(converted); 171 if (res) { 172 this->any_->SetValue(converted); 173 } 174 } 175 return res; 176 } GetValue()177 const META_NS::IAny& GetValue() const override 178 { 179 BASE_NS::vector<SourceType> result; 180 for (auto&& v : this->p_->GetValue()) { 181 result.push_back(convert_.ConvertToSource(*this->any_, v)); 182 } 183 this->any_->SetValue(result); 184 return *this->any_; 185 } IsCompatible(const META_NS::TypeId & id)186 bool IsCompatible(const META_NS::TypeId& id) const override 187 { 188 return id == META_NS::ArrayUidFromType<SourceType>() || id == META_NS::ArrayUidFromType<TargetType>(); 189 } 190 191 private: 192 Converter convert_; 193 }; 194 195 SCENE_END_NAMESPACE() 196 197 #endif 198