[DOC] update documentation

This commit is contained in:
Edouard DUPIN 2014-09-02 21:26:15 +02:00
parent 87f4aedb95
commit d5bd35d0a4
8 changed files with 240 additions and 287 deletions

16
doc/faq.bb Normal file
View File

@ -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<xxx> (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<Object>[/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.

View File

@ -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 :

View File

@ -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<xxx> (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<Object>[/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++]

View File

@ -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<widget::Label> tmpObject = ewol::object::makeShared(new widget::Label());
if (tmpObject == NULL) {
APPL_ERROR("An error occured");
return;
}
std::shared_ptr<ewol::Button> 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<ewol::Object>& _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<ewol::Object>& _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<T>]] 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/Manager.h>
...
ewol::object::Shared<ewol::Object> 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 <ewol/object/Manager.h>
#include <ewol/context/Context.h>
...
ewol::object::Shared<ewol::Object> tmpObject = ewol::getContext().getObjectManager().get("name of the object");
std::shared_ptr<ewol::Object> 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<ewol::Object> 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<ewol::Object> 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<ewol::Object> tmpObject ...;
std::shared_ptr<ewol::Object> tmpObject ...;
ewol::object::Shared<appl::MyOwnObject> myObject = ewol::dynamic_pointer_cast<appl::MyOwnObject>(tmpObject);
std::shared_ptr<appl::MyOwnObject> myObject = std::dynamic_pointer_cast<appl::MyOwnObject>(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 ...

View File

@ -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 <ewol/object/Object.h>
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<bool> 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<T> Basic parameter.
:** ewol::object::ParamRange<T> For numeric parameter that range value are check befor setting new value.
:** ewol::object::ParamList<T> 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.

View File

@ -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<void> signalDown;
ewol::object::Signal<void> signalUp;
...
ewol::object::Signal<bool> 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 <ewol/object/Object.h>
#include <ewol/widget/Button.h>
namespace appl {
class MyObj : public ewol::Object {
private:
std::shared_ptr<ewol::widget::Button> 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 <ewol/object/Object.h>
#include <ewol/widget/Button.h>
namespace appl {
class MyObj : public ewol::Object {
private:
std::shared_ptr<ewol::widget::Button> 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 <ewol/object/Object.h>
#include <ewol/widget/Button.h>
namespace appl {
class MyObj : public ewol::Object {
public:
// Event list of properties
static const char* const eventValue;
public:
ewol::object::Signal<void> signalEmpty;
ewol::object::Signal<bool> signalBoolean;
ewol::object::Signal<std::string> 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...

View File

@ -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

View File

@ -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<std::string> m_name; //!< name of the element ...