#pragma once #include "rbx/signal.h" #include "V8DataModel/CustomEventReceiver.h" #include "V8DataModel/PartInstance.h" #include "V8DataModel/ModelInstance.h" #include "V8DataModel/CollectionService.h" #include "V8Tree/Instance.h" namespace RBX { extern const char* const sCustomEvent; class CustomEvent : public DescribedCreatable { private: typedef DescribedCreatable Super; typedef std::list > ReceiverList; // prevent copy and assign: this class does sensitive pointer // management, which would be complicated by allowing copies/assigns. CustomEvent(const CustomEvent& other); CustomEvent& operator=(const CustomEvent& other); ReceiverList receivers; float currentValue; /*override*/ void onServiceProvider(ServiceProvider* oldProvider, ServiceProvider* newProvider) { if(oldProvider) oldProvider->create()->removeInstance(shared_from(this)); Super::onServiceProvider(oldProvider, newProvider); if(newProvider) { newProvider->create()->addInstance(shared_from(this)); } else { ReceiverList copy = receivers; for (ReceiverList::iterator itr = copy.begin(); itr != copy.end(); ++itr) { shared_ptr receiver = itr->lock(); if (receiver) { receiver->setSource(NULL); } } } } public: CustomEvent() :Super(sCustomEvent), currentValue(0) {} // The persisted current value is just for storage -- it is set from the // SetValue callback, and setPersistedCurrentValue _WILL_NOT_ cause // receivers to get a value update. static Reflection::PropDescriptor prop_PersistedCurrentValue; static Reflection::BoundFuncDesc func_SetValue; static Reflection::BoundFuncDesc() > func_GetAttachedReceivers; static Reflection::EventDesc)> event_ReceiverConnected; static Reflection::EventDesc)> event_ReceiverDisconnected; // signals are public for testing only rbx::signal)> receiverConnected; rbx::signal)> receiverDisconnected; /*override*/ virtual bool askSetParent(const Instance* instance) const { return Instance::fastDynamicCast(instance) != NULL; } /*override*/ virtual bool askForbidChild(const Instance* instance) const { return true; } float getPersistedCurrentValue() const { return currentValue; } // This method is intended for serialization only, it should not be involved // with triggering valueChanged events on receivers. void setPersistedCurrentValue(float newValue) { currentValue = G3D::clamp(newValue, 0 , 1); } void setCurrentValue(float newValue) { currentValue = G3D::clamp(newValue, 0, 1); raiseChanged(prop_PersistedCurrentValue); for (ReceiverList::iterator itr = receivers.begin(); itr != receivers.end(); ++itr) { shared_ptr receiver = itr->lock(); if (receiver && receiver->getCurrentValue() != currentValue) { receiver->sourceValueChanged(currentValue); } } } shared_ptr getAttachedReceivers() { shared_ptr result(new Instances); for (ReceiverList::iterator itr = receivers.begin(); itr != receivers.end(); ++itr) { shared_ptr receiver = itr->lock(); if (receiver) { result->push_back(receiver); } } return result; } void addReceiver(CustomEventReceiver* receiver) { bool found = false; for (ReceiverList::iterator itr = receivers.begin(); itr != receivers.end() && !found; ++itr) { shared_ptr list_receiver = itr->lock(); if (list_receiver.get() == receiver) { found = true; } } if (!found) { receivers.push_back(weak_ptr(shared_from(receiver))); // send event only after internal state has been updated receiverConnected(shared_from(receiver)); } } void removeReceiver(CustomEventReceiver* receiver) { ReceiverList::iterator foundIterator; bool found = false; for (ReceiverList::iterator itr = receivers.begin(); itr != receivers.end() && !found; ++itr) { shared_ptr list_receiver = itr->lock(); if (list_receiver.get() == receiver) { foundIterator = itr; found = true; } } if (found) { receivers.erase(foundIterator); // send event only after internal state has been updated receiverDisconnected(shared_from(receiver)); } } }; } // namespace