diff --git a/doc/faq.bb b/doc/faq.bb new file mode 100644 index 00000000..c4a37b52 --- /dev/null +++ b/doc/faq.bb @@ -0,0 +1,16 @@ + + + +== Why we use "DECLARE_FACTORY" Macro ? == + +For some reason!!! But everything might be clear: +:** In ewol we masively use std::shared_ptr (I have create my own but it is not "standard" (I like when we use genecic system)). +:** The main class : [class[ewol::Object]] herited from [i]std::enable_shared_from_this[/i] to permit to access at his own [i]std::shared_ptr[/i]. +:** Acces At his own [i]std::shared_ptr[/i] is not allowed in the class contructor/destructor. +:** Many time for meta-widget we need to propagate our [i]std::shared_ptr[/i] in child. + +Then for all these reasons, I have create a simple MACRO that create a static template funtion that create the object and just after +creation call the init(...) function to permit to create a complex widget or others with some writing convinience. + + + diff --git a/doc/tutorial/000_Build.bb b/doc/tutorial/000_Build.bb index e81c1b1a..1024dac0 100644 --- a/doc/tutorial/000_Build.bb +++ b/doc/tutorial/000_Build.bb @@ -48,7 +48,7 @@ Compile software in debug for the curent platform : You can specify the platform with: [code style=shell] - ./ewol/build/lutin.py -mdebug -tAndroid + ./ewol/build/lutin.py -tAndroid -mdebug [/code] It coud be usefull to disable the package generation in local debug : diff --git a/doc/tutorial/001_HelloWord.bb b/doc/tutorial/001_HelloWord.bb index 07f904ae..9a2cb3ef 100644 --- a/doc/tutorial/001_HelloWord.bb +++ b/doc/tutorial/001_HelloWord.bb @@ -110,16 +110,7 @@ For this point we will create a class that herited form the basic [class[ewol::w #endif [/code] -At this point you will ask an important question : [b]Why we use this really bad "DECLARE_FACTORY" Macro ?[/b] - -For some reason!!! But everything might be clear: -:** In ewol we masively use std::shared_ptr (I have create my own but it is not "standard" (I like when we use genecic system)). -:** The main class : [class[ewol::Object]] herited from [i]std::enable_shared_from_this[/i] to permit to access at his own [i]std::shared_ptr[/i]. -:** Acces At his own [i]std::shared_ptr[/i] is not allowed in the class contructor/destructor. -:** Many time for meta-widget we need to propagate our [i]std::shared_ptr[/i] in child. - -Then for all these reasons, I have create a simple MACRO that create a static template funtion that create the object and just after -creation call the init(...) function to permit to create a complex widget or others with some writing convinience. +See [tutorial[010_ObjectModel | Next: Object model]] to understand why this structure is so complex. [b]Windows.cpp[/b] [code style=c++] diff --git a/doc/tutorial/010_ObjectModel.bb b/doc/tutorial/010_ObjectModel.bb index e32997ee..e7410e47 100644 --- a/doc/tutorial/010_ObjectModel.bb +++ b/doc/tutorial/010_ObjectModel.bb @@ -6,17 +6,18 @@ __________________________________________________ :** Understand ewol basic [class[ewol::Object]] :** Use [class[ewol::Object]] correctly -== Basis of the Object == +== Basis of the ewol::Object == An object in Ewol is a simple class : [class[ewol::Object]] This object is the basis of all element in the ewol system. -This is designed to manage basis element of complexe structure: +This is designed to manage many common things: :** Unique ID :** Name -:** Configuration (decriptive naming of parameters) -:** Event generation and receving +:** Parameters +:** Signal generation :** Xml configuration -:** Delayed removing +:** Removing +:** Perodic calling [note] Please do not compare with the gObject basic class... @@ -25,130 +26,86 @@ Please do not compare with the gObject basic class... == Create an Object: == -In theory you can use a simple new on an object, but you need to remove the refcounting of this one by yoursef ... really awfull. +Creating an object is really simple: -It is really better to use the ewol::object::Shared<> declaration to auto manage it. (same as std::shared_ptr) [code style=c++] - ewol::object::Shared tmpObject = ewol::object::makeShared(new widget::Label()); - if (tmpObject == NULL) { - APPL_ERROR("An error occured"); - return; - } + std::shared_ptr tmpButon = ewol::Button::create(); + APPL_INFO("We just create a button widget with unique ID=" << tmpButon->getId() << " name='" << tmpButon->getName() << "'"); [/code] -The object register itself on the object manager, now it will have a specific Id and no name +Note that all object created are std::shared_ptr. -Force the set of the name : + +Set the name of the object: [code style=c++] - tmpObject->setName("my widget name"); - APPL_INFO("We just create an Object with ID=" << tmpObject->getId() << " name='" << tmpObject->getName() << "'"); + tmpButon->setName("my widget name"); + APPL_INFO("We just create an Object with ID=" << tmpButon->getId() << " name='" << tmpButon->getName() << "'"); [/code] == Remove an Object: == -This is important to note that many element can have a reference on the Object. - -Then we need to use the fuction: -[b]removeObject()[/b] to remove the Object, This will notify avery object in the system that this -specific object has been removed. - - -Then to remove an object call: +Simply use the function: [code style=c++] - tmpObject->removeObject(); + tmpButon->destroy(); [/code] -On every object we can have an herited function: [b]virtual void onObjectRemove(const ewol::object::Shared& _removeObject);[/b] +This function request his parrent to remove the std::shared_ptr it keep on it. +And when all std::shared_ptr is removed the object will be really removed. - -We need to implement this fuction to be notify an object is removed: -[code style=c++] - void namespeceName::ClassName::onObjectRemove(const ewol::object::Shared& _removeObject) { - // Never forget to call upper Object (otherwise many object will keep theire reference) - upperClass::onObjectRemove(_removeObject); - if (_removeObject == m_object) { - m_object.reset(); - markToRedraw(); // set only for graphical object ... - } - } -[/code] +At his point we can think an object is allive all the time someone keep a reference on it, then when you are not a parrent of the object, do not keep a std::shared_ptr but a std::weak_ptr. [note] -If you have well follow the idea, you will never declare an object in local, just use shared pointer on them. +If some Object is not removed when you close the application, the system inform you with displaying all object already alive. [/note] -[note] -For some case it could be interesting to see the [class[ewol::object::Owner]] class that provide an automatic auto remove of object. - -See [class[ewol::widget::Container]] for an example. -[/note] - - -=== Particularity === - -An object can remove itself, just use the function: -[code style=c++] - autoDestroy(); -[/code] - == Retrieve an Object: == In Ewol this is possible to get a object with his name. -This is really simple. -=== In an Object === - -Call a simple function define in the Object: +=== Find a global Object (ouside an Object) === [code style=c++] - #include - - ... - - ewol::object::Shared tmpObject = getObjectManager().get("name of the object"); - if (tmpObject == NULL) { - APPL_ERROR("The Object does not exist"); - } -[/code] - -=== Not in an Object === - -In this case, we need to get the context manager and after the object manager: - -[code style=c++] - #include #include - ... - - ewol::object::Shared tmpObject = ewol::getContext().getObjectManager().get("name of the object"); + std::shared_ptr tmpObject = ewol::getContext().getEObjectManager().getObjectNamed("obj Name"); if (tmpObject == NULL) { APPL_ERROR("The Object does not exist"); } [/code] -=== Casting your object === +=== Find a global Object (inside an Object) === + +[code style=c++] + std::shared_ptr tmpObject = getObjectNamed("obj Name"); + if (tmpObject == NULL) { + APPL_ERROR("The Object does not exist"); + } +[/code] + +=== Find a sub-object === + +[code style=c++] + std::shared_ptr tmpObject = getSubObjectNamed("obj Name"); + if (tmpObject == NULL) { + APPL_ERROR("The Object does not exist"); + } +[/code] + +=== retriving your object type === It could be really interesting to retrive your own instance: [code style=c++] - ewol::object::Shared tmpObject ...; + std::shared_ptr tmpObject ...; - ewol::object::Shared myObject = ewol::dynamic_pointer_cast(tmpObject); + std::shared_ptr myObject = std::dynamic_pointer_cast(tmpObject); [/code] == conclusion == -If you follow these rules, you will not have memory leek and no segmentation fault on the ewol system. - -[note] -To be sure that the name is unique, just add the current creator object Id in the name. - -See [class[ewol::widget::FileChooser]] class for an example. -[/note] - +TODO ... diff --git a/doc/tutorial/011_ObjectConfig.bb b/doc/tutorial/011_ObjectConfig.bb index 280c0a8d..44285a09 100644 --- a/doc/tutorial/011_ObjectConfig.bb +++ b/doc/tutorial/011_ObjectConfig.bb @@ -1,153 +1,101 @@ =?= Tutorial 3: Object Config =?= __________________________________________________ -[left][tutorial[010_ObjectModel | Previous: Object model]][/left] [right][tutorial[012_ObjectMessage | Next: Object message]][/right] +[left][tutorial[010_ObjectModel | Previous: Object model]][/left] [right][tutorial[012_ObjectMessage | Next: Object signals]][/right] === Objectif === :** Understand ewol::Object configuration parameter :** Create an configurable object -== Use of Configuration == +== Configuration using == -Configuration are parameters to set some property on an object, -this is a really generic use in many system, -this is the reason why we implement one. +All [class[ewol::Object]] have a configuration of parameters (the object name is a parameter), Then we need to set get and use xml to update parameters. +=== Set a Parameter === -This is a generic interface to set and get parameter, -when you did not really know it, -but it generate many convertion to string search and many other things... +[note] + Using getter and setter is really better, and faster. +[/note] -If you know the object just interact with it with his own accessors (faster ond conpilation check). +==== With a string configuration ==== - -=== Set config === - -When you have the pointer on the object: [code style=c++] - if (tmpObject->setConfig("name", "new name of object") == false) { - APPL_ERROR("Can not set object property"); + if (tmpObject->parameterSet("name", "new name of object") == false) { + APPL_ERROR("Can not set object parameter"); } [/code] -A second methode is to request the name with his direct config name: -[code style=c++] - // to be sure that the name exist: - if (tmpObject->setConfig(ewol::Object::configName, "new name of object") == false) { - APPL_ERROR("Can not set object property"); - } -[/code] -The only aventage here is to have an automatic update on the name of the parameter. +==== whith the object name ==== -It is possible to configure an object whitout knowing his name: [code style=c++] - // in an ewol::Object only ... - if (setConfigNamed("object name", "ewol::Object::configName, "new name of object") == false) { - APPL_ERROR("Can not set object property"); + if (parameterSetOnWidgetNamed("objectName", "value", "16.2") == false) { + APPL_ERROR("Can not set object parameter"); } [/code] +=== Get Parameter === -=== Get config === - -Direct get the configuration: [code style=c++] - std::string val = tmpObject->getConfig("name"); + std::string val = tmpObject->parameterGet("name"); APPL_INFO("Get Object property : name='" << val << "'"); [/code] -Get with his direct definition name: -[code style=c++] - std::string val = tmpObject->getConfig(ewol::Object::configName); - APPL_INFO("Get Object property : " << ewol::Object::configName << "'" << val << "'"); -[/code] - - == Implement configuration == -=== Declare config === - -In the header file: [code style=c++] #include namespace appl { class MyObj : public ewol::Object { - public: - // Config list of properties - static const char* const configValue; - public: + protected: //! @brief Constructor - MyObj(void); + MyObj(void) : + m_value(*this, "value", false, "Value of the parameter (descrition string)") { + // nothing to do.. + } + void init() { + ewol::Object::init(); + } + public: //! @brief Destructor - virtual ~MyObj(void); + virtual ~MyObj(void) { } + DECLARE_FACTORY(MyObj); private: - bool m_value; //!< Internal Object value + ewol::object::Param m_value; //!< Internal Object value public: //! @brief Setter void setValue(bool _val) { - m_value = _val; + m_value.set(_val); } //! @brief Getter - bool getValue(void) const { - return m_value; + bool getValue() const { + return m_value.get(); } public: // herited function: - bool onSetConfig(const ewol::object::Config& _conf); + void onParameterChangeValue(const ewol::object::ParameterRef& _paramPointer) { + if (_paramPointer == m_value) { + APPL_DEBUG("The internal value has change, new value is : '" << m_value.get() << "'"); + } + } } } [/code] -[note] -By convention declare config started with "configXXXXXX" -[/note] - -In the source file: +In the contructor we need to add: [code style=c++] -// Declare the configuration Name: -const char* const appl::MyObj::configValue = "value"; - -appl::MyObj::MyObj(void) { - // declare the configuration on this object: - registerConfig(configValue, "bool", NULL, "object configuration description"); - // Note : This API is not compleately define ... -} -appl::MyObj::~MyObj(void) { - // nothing to do ... -} +m_value(*this, "value", false, "Value of the parameter (descrition string)") [/code] -Now an extern Object can register configure these parameter, otherwise, they will be rejected!!! +:** [b]'*this':[/b] Reference the main class to call it chen value change. +:** [b]"value":[/b] Is the name of the parameter. +:** [b]false:[/b] The default value. +:** [b]"....."[/b] Description of the parameter (optionnal). -=== Get and Set config === +The function [b]onParameterChangeValue[/b] is called only the parameter change (no historic has been registered) -You can see in these implementation that we not compare the string but just the pointer. -The ewol::Object convert the string in the correct pointer to be faster in many case. +The last point is that the m_value.get() is an inline fuction then it take no more CPU cycle to access the value than normal variable. -==== Set configuration ==== +Some other parameter are availlable : +:** ewol::object::Param Basic parameter. +:** ewol::object::ParamRange For numeric parameter that range value are check befor setting new value. +:** ewol::object::ParamList For List of parameter values. -[code style=c++] -bool appl::MyObj::onSetConfig(const ewol::object::Config& _conf) { - APPL_VERBOSE("[" << getId() << "] {" << getObjectType() << "} set config : " << _conf); - if (_conf.getConfig() == configValue) { - setValue(std::stob(_conf.getData())); - return true; - } - return false; -} -[/code] - -==== Get configuration ==== - -[code style=c++] -bool appl::MyObj::onGetConfig(const char* _config, std::string& _result) const { - if (_config == configValue) { - _result = std::to_string(getValue()); - return true; - } - return false; -} -[/code] - -== Conclusion == - -Now you can choice the methode you want in your application to implement your basic configuration feature. diff --git a/doc/tutorial/012_ObjectMessage.bb b/doc/tutorial/012_ObjectMessage.bb index 9f62f5d6..fdf4e0a3 100644 --- a/doc/tutorial/012_ObjectMessage.bb +++ b/doc/tutorial/012_ObjectMessage.bb @@ -1,4 +1,4 @@ -=?= Tutorial 4: Object Message =?= +=?= Tutorial 4: Object Signals =?= __________________________________________________ [left][tutorial[011_ObjectConfig | Previous: Object config]][/left] [right][tutorial[020_FileAccess | Next: File Access]][/right] @@ -8,123 +8,164 @@ __________________________________________________ == Message system == -The message system is a simple message sending between Object. -This is composed with a pointer (const char* const) that represent the mesage ID (pointer, then unique) -and a value (std::string) +Message system is based on generic std::funtion and std::bind methode: -The message are broadcast or multicast on object watcher. +It permit to an object to generate some [b]'signals'[/b]. -== Receive Message from other object == +All signal are synchronous -=== Register on message === -We will se an example on the widget : [class[ewol::widget::Button]] +== Receive signals from other object == -By default the messageID is the event generated, But to overwrite this message Id just create a new one: +[todo] +Link with the signal name +[/todo] + +Register on the 'up' and 'value' signal of a button: + +Button header : [code style=c++] -// on the global on the file or in private class member: -static const char* const g_backMessage = "local-event-button-pressed"; -static const char* const g_backMessageValue = "local-event-button-value"; -static const char* const g_backMessageDataOverWritte = "local-event-button-data"; + ... + public: + ewol::object::Signal signalDown; + ewol::object::Signal signalUp; + ... + ewol::object::Signal signalValue; + ... [/code] - -Register with his name: -[code style=c++] -registerOnEvent(this, "pressed", g_backMessage); -[/code] - -Register with his direct name: -[code style=c++] -registerOnEvent(this, ewol::widget::Button::eventValue, g_backMessageValue); -[/code] - -It is possible to overwrote the data send by the Object : -[code style=c++] -registerOnEvent(this, ewol::widget::Button::eventPressed, g_backMessageDataOverWritte, "Data we want to receive"); -[/code] - - -=== Receive message === - -To receive message from other widget, just implement this function: +=== simple signal connection: === [code style=c++] - -void appl::ObjectName::onReceiveMessage(const ewol::object::Message& _msg) { - APPL_INFO("Receive Event : " << _msg); - if (_msg.getMessage() == g_backMessage) { - // process here - return; - } - if (_msg.getMessage() == g_backMessageValue) { - APPL_INFO("message value: '" << _msg.getData() << "'"); - return; - } - if (_msg.getMessage() == g_backMessageDataOverWritte) { - APPL_INFO("Overwrite message data: '" << _msg.getData() << "'"); - return; +#include +#include +namespace appl { + class MyObj : public ewol::Object { + private: + std::shared_ptr m_button; + protected: + //! @brief Constructor + MyObj(void) { + // nothing to do.. + } + void init() { + ewol::Object::init(); + m_button = ewol::widget::Button::Create(); + if (m_button == nullptr) { + APPL_ERROR("Can not create button..."); + return; + } + // We connect signals here : + m_button->signalUp.bind(shared_from_this(), &appl::MyObj::onCallbackUp); + m_button->signalValue.bind(shared_from_this(), &appl::MyObj::onCallbackValue); + } + public: + //! @brief Destructor + virtual ~MyObj(void) { } + DECLARE_FACTORY(MyObj); + private: + void onCallbackUp() { + APPL_INFO("button pressed: UP); + } + void onCallbackValue(const bool& _value) { + APPL_INFO("button value: " << _value); + } } } [/code] -== Declare Extern Message == +=== Advenced signal connection: === -=== Declare Message === +Here we will see how to connect an advance function on a signal -In the header file: [code style=c++] #include +#include +namespace appl { + class MyObj : public ewol::Object { + private: + std::shared_ptr m_button; + protected: + //! @brief Constructor + MyObj(void) { + // nothing to do.. + } + void init() { + ewol::Object::init(); + m_button = ewol::widget::Button::Create(); + if (m_button == nullptr) { + APPL_ERROR("Can not create button..."); + return; + } + // We connect signals here : + m_button->signalUp.register(shared_from_this(), std::bind(&appl::MyObj::onCallbackUp, this, std::string("tmpVariableToSend"))); + m_button->signalValue.register(shared_from_this(), std::bind(&appl::MyObj::onCallbackValue, this)); + } + public: + //! @brief Destructor + virtual ~MyObj(void) { } + DECLARE_FACTORY(MyObj); + private: + void onCallbackUp(const std::string& _value) { + APPL_INFO("button pressed: UP inputMessage: " << _value); + } + void onCallbackValue() { + APPL_INFO("button value: " << _value); + } + } +} +[/code] + +=== Connect to a signal with a named widget === + +TODO: documentation : +:** subBind(_type, _name, _event, _obj, _func) +:** globalBind(_type, _name, _event, _obj, _func) +:** externSubBind(_object, _type, _name, _event, _obj, _func) + + +== Declare Signal == + +=== source === + +[code style=c++] +#include +#include namespace appl { class MyObj : public ewol::Object { public: - // Event list of properties - static const char* const eventValue; - public: + ewol::object::Signal signalEmpty; + ewol::object::Signal signalBoolean; + ewol::object::Signal signalString; + protected: //! @brief Constructor - MyObj(void); + MyObj(void) : + signalEmpty(*this, "empty"), + signalBoolean(*this, "boolean"), + signalString(*this, "string") { + // nothing to do.. + } + void init() { + ewol::Object::init(); + } + public: //! @brief Destructor - virtual ~MyObj(void); + virtual ~MyObj(void) { } + DECLARE_FACTORY(MyObj); + private: + void process() { + signalEmpty.emit(); + signalBoolean.emit(false); + signalString.emit("plop... plop"); + } } } [/code] -[note] -By convention declare events started with "eventXXXXXX" -[/note] - -In the source file: -[code style=c++] -// Declare the configuration Name: -const char* const appl::MyObj::eventValue = "value"; - -appl::MyObj::MyObj(void) { - // declare Event generated on this object: - addEventId(eventValue); -} -appl::MyObj::~MyObj(void) { - // nothing to do ... -} -[/code] -Now an extern Object can register event on this object, otherwise, they will be rejected!!! - - -=== Generate Message === - -Now we have register object message, We need to have generated it, This is really simple : - -[code style=c++] - // with no data: - generateEventId(eventValue); - // With a custom data: - generateEventId(eventValue, "My sring custom data ..."); -[/code] - - == Conclusion == -You will now able to generate event between objects... +You will now able to reise signals between objects... diff --git a/doc/tutorial/020_FileAccess.bb b/doc/tutorial/020_FileAccess.bb index c8becf9d..05bfc8f5 100644 --- a/doc/tutorial/020_FileAccess.bb +++ b/doc/tutorial/020_FileAccess.bb @@ -1,6 +1,6 @@ =?= Tutorial 5: File Access =?= __________________________________________________ -[left][tutorial[012_ObjectMessage | Previous: Object message]][/left] [right][tutorial[021_Resources | Next: Resources management]][/right] +[left][tutorial[012_ObjectMessage | Previous: Object signal]][/left] [right][tutorial[021_Resources | Next: Resources management]][/right] === Objectif === :** Understand why we wrap interface on file system diff --git a/sources/ewol/object/Object.h b/sources/ewol/object/Object.h index 78c05066..8f083cc4 100644 --- a/sources/ewol/object/Object.h +++ b/sources/ewol/object/Object.h @@ -138,7 +138,7 @@ namespace ewol { return m_uniqueId; }; public: - // TODO : Rework the position on this function ... This is a convignet function ... + // TODO : Rework the position on this function ... This is a convignent function ... bool parameterSetOnWidgetNamed(const std::string& _objectName, const std::string& _config, const std::string& _value); protected: ewol::object::Param m_name; //!< name of the element ...