#include <Elementary.h>
#include <tizen.h>
+#include <typeinfo>
+
+/**
+ * @brief Define class type so it can be detected from a more derived class instance.
+ * @details Overrides hasType() method by checking against the given static type
+ * and all base types recursively.
+ */
+#define DEFINE_CLASS_TYPE(classType, baseClassType) \
+ virtual bool hasType(const std::type_info &type) const override \
+ { \
+ return typeid(classType) == type || baseClassType::hasType(type); \
+ }
namespace Ui
{
/**
- * @brief Basic Control types.
- */
- enum ControlType
- {
- TypeControl,
- TypeWindow,
- TypeView,
- TypeMax
- };
-
- /**
* @brief Evas_Object wrapper.
* @details Ties the lifetime of this object to the underlying Evas_Object.
* @remark Should always be allocated with operator "new".
class EXPORT_API Control
{
public:
- Control(int type = TypeControl);
+ Control();
Control(const Control &that) = delete;
- Control(Control &&that) = delete;
virtual ~Control();
- Control & operator=(const Control &that) = delete;
- Control & operator=(Control &&that) = delete;
+ Control &operator=(const Control &that) = delete;
/**
* @brief Create underlying Evas_Object by calling onCreate()
void resetCreateTimer();
/**
- * @return Control type.
+ * @return Underlying Evas_Object.
*/
- int getType() const;
+ Evas_Object *getEvasObject() const;
+ /**@{*/
/**
- * @return Underlying Evas_Object.
+ * @brief Get Control object from Evas_Object by type.
+ * @remark The specified type should be either the most derived class or
+ * should be defined using DEFINE_CLASS_TYPE macro in the respective class.
+ * @param[in] object Evas_Object that belongs to some Control
+ * @return Control of the specified type tied to Evas_Object or nullptr if none.
*/
- Evas_Object *getEvasObject() const;
+ template <typename ControlType = Control>
+ static ControlType *getControl(Evas_Object *object);
+ static Control *getControl(Evas_Object *object, const std::type_info &type);
+ /**@}*/
+ /**@{*/
/**
* @brief Find closest parent Control by type.
- * @param[in] object Child object
- * @param[in] type Control type
- * @return Control if found, otherwise nullptr.
+ * @see Control::getControl()
*/
- template <typename ControlType>
- ControlType *findParent() const;
- Control *findParent(int type) const;
-
+ static Control *findParent(Evas_Object *object, const std::type_info &type);
template <typename ControlType>
static ControlType *findParent(Evas_Object *object);
- static Control *findParent(Evas_Object *object, int type);
+ template <typename ControlType>
+ ControlType *findParent() const;
+ /**@}*/
/**
- * @brief Get Control object from Evas_Object
- * @param[in] object Evas_Object that belongs to some Control
- * @return Control tied to Evas_Object
+ * @brief Check if the object has a specified type or is derived from it.
+ * @details A base class MUST override this method using DEFINE_CLASS_TYPE macro
+ * to allow detecting it from a more derived class instance.
+ * @param[in] type Type info to check against
+ * @return Whether the object has a specified type.
*/
- static Control *getControl(Evas_Object *object);
+ virtual bool hasType(const std::type_info &type) const { return typeid(Control) == type; }
protected:
/**
Evas_Object *resetEvasObject();
void destroyEvasObject();
- void onDestroyed(Evas *e, Evas_Object *obj, void *event_info);
+ void onTypeCheck(Evas_Object *obj, void *eventInfo);
+ void onDestroyed(Evas *e, Evas_Object *obj, void *eventInfo);
- int m_Type;
Evas_Object *m_Object;
Ecore_Timer *m_CreateTimer;
};
template <typename ControlType>
+ ControlType *Control::getControl(Evas_Object *object)
+ {
+ return static_cast<ControlType *>(getControl(object, typeid(ControlType)));
+ }
+
+ template <typename ControlType>
+ ControlType *Control::findParent(Evas_Object *object)
+ {
+ return static_cast<ControlType *>(findParent(object, typeid(ControlType)));
+ }
+
+ template <typename ControlType>
ControlType *Control::findParent() const
{
return findParent<ControlType>(m_Object);
class EXPORT_API GenContainer : public Control
{
public:
+ DEFINE_CLASS_TYPE(GenContainer, Control)
+
enum Type
{
TypeGenlist,
*/
typedef std::function<bool()> LastPageCallback;
- /**
- * @brief Create navigator.
- * @param[in] type Navigator type
- */
- explicit Navigator(NavigatorType type);
+ Navigator();
/**
* @return Currently displayed page.
class Navigator;
/**
- * @brief Navigation type supported by Navigator
- */
- enum NavigatorType
- {
- TypeStackNavigator = TypeMax, /**< Allows navigation to the added View or the previous View */
- TypeTabNavigator /**< Allows navigation to any added View */
- };
-
- /**
* @brief Represents content of a Window or Navigator page
*/
class EXPORT_API View : public Control
{
public:
- View(int type = TypeView);
+ DEFINE_CLASS_TYPE(View, Control)
+
+ View();
/**
* @brief Get parent Navigator
* @param[in] type Navigator type
- * @return Innermost parent Navigator of the specified type if exists,
- * otherwise nullptr
+ * @return Innermost parent Naviframe.
*/
- Navigator *getNavigator(NavigatorType type = TypeStackNavigator) const;
+ Navigator *getNavigator() const;
/**
* @return NavigatorPage of this View
private:
friend class Window;
friend class Navigator;
- void onNavigatorAttached(Navigator *stackNavi, Navigator *tabNavi, NavigatorPage *page);
+ void onNavigatorAttached(NavigatorPage *page);
void onNavigation(bool isCurrent, int degree);
void onRotation(int degree);
- Navigator *m_StackNavi;
- Navigator *m_TabNavi;
NavigatorPage *m_Page;
-
- bool m_IsCurrent;
- int m_Rotation;
+ bool m_IsCurrent;
+ int m_Rotation;
};
}
#include "Ui/Control.h"
#include "Utils/Callback.h"
-#define CONTROL_DATA_KEY "Ui::Control"
+#define EVENT_TYPE_CHECK "type_check"
using namespace Ui;
-Control::Control(int type)
- : m_Type(type), m_Object(nullptr), m_CreateTimer(nullptr)
+namespace
+{
+ struct TypeCheckInfo
+ {
+ const std::type_info &type;
+ Control *object;
+ };
+}
+
+Control::Control()
+ : m_Object(nullptr), m_CreateTimer(nullptr)
{
}
}
}
-int Control::getType() const
-{
- return m_Type;
-}
-
Evas_Object *Control::getEvasObject() const
{
return m_Object;
}
-Control *Control::findParent(int type) const
+Control *Control::getControl(Evas_Object *object, const std::type_info &type)
{
- return findParent(getEvasObject(), type);
+ TypeCheckInfo checkInfo = { type, nullptr };
+ evas_object_smart_callback_call(object, EVENT_TYPE_CHECK, &checkInfo);
+ return checkInfo.object;
}
-Control *Control::findParent(Evas_Object *object, int type)
+Control *Control::findParent(Evas_Object *object, const std::type_info &type)
{
while (object) {
- Control *control = getControl(object);
- if (control && control->getType() == type) {
+ if (auto control = getControl(object, type)) {
return control;
}
object = elm_object_parent_widget_get(object);
return nullptr;
}
-Control *Control::getControl(Evas_Object *object)
-{
- return (Control *) evas_object_data_get(object, CONTROL_DATA_KEY);
-}
-
void Control::setEvasObject(Evas_Object *object)
{
m_Object = object;
- if (!evas_object_data_get(m_Object, CONTROL_DATA_KEY)) {
- evas_object_data_set(m_Object, CONTROL_DATA_KEY, this);
- }
-
+ evas_object_smart_callback_add(m_Object, EVENT_TYPE_CHECK,
+ makeCallback(&Control::onTypeCheck), this);
evas_object_event_callback_add(m_Object, EVAS_CALLBACK_DEL,
(Evas_Object_Event_Cb) makeCallback(&Control::onDestroy), this);
evas_object_event_callback_add(m_Object, EVAS_CALLBACK_FREE,
Evas_Object *Control::resetEvasObject()
{
Evas_Object *object = m_Object;
+ evas_object_smart_callback_del_full(m_Object, EVENT_TYPE_CHECK,
+ makeCallback(&Control::onTypeCheck), this);
evas_object_event_callback_del_full(m_Object, EVAS_CALLBACK_DEL,
(Evas_Object_Event_Cb) makeCallback(&Control::onDestroy), this);
evas_object_event_callback_del_full(m_Object, EVAS_CALLBACK_FREE,
}
}
-void Control::onDestroyed(Evas *e, Evas_Object *obj, void *event_info)
+void Control::onTypeCheck(Evas_Object *obj, void *eventInfo)
+{
+ auto checkInfo = (TypeCheckInfo *) eventInfo;
+ if (!checkInfo->object) {
+ if (typeid(*this) == checkInfo->type || hasType(checkInfo->type)) {
+ checkInfo->object = this;
+ }
+ }
+}
+
+void Control::onDestroyed(Evas *e, Evas_Object *obj, void *eventInfo)
{
m_Object = nullptr;
delete this;
GenContainer *GenItem::getParent() const
{
Evas_Object *genlist = elm_object_item_widget_get(getObjectItem());
- return static_cast<GenContainer *>(Control::getControl(genlist));
+ return Control::getControl<GenContainer>(genlist);
}
GenItem *GenItem::getNextItem() const
*/
#include "Ui/Naviframe.h"
-#include "Ui/NaviframePage.h"
-#include "Ui/View.h"
#include "Utils/Callback.h"
using namespace Ui;
+namespace Ui
+{
+ template <>
+ Navigator *Control::findParent<Navigator>(Evas_Object *object)
+ {
+ return findParent<Naviframe>(object);
+ }
+}
+
Naviframe::Naviframe()
- : Navigator(TypeStackNavigator), m_Job(nullptr),
+ : m_Job(nullptr),
m_IsFirstPagePrevButtonVisible(false)
{
}
using namespace Ui;
-namespace Ui
-{
- template <>
- Navigator *Control::findParent<Navigator>(Evas_Object *object)
- {
- return static_cast<Navigator *>(findParent(object, TypeStackNavigator));
- }
-}
-
-Navigator::Navigator(NavigatorType type)
- : View(type), m_CurrentPage(nullptr)
+Navigator::Navigator()
+ : m_CurrentPage(nullptr)
{
}
return;
}
- Navigator *stackNavi = m_StackNavi;
- Navigator *tabNavi = m_TabNavi;
- if (getType() == TypeStackNavigator) {
- stackNavi = this;
- } else {
- tabNavi = this;
- }
-
NavigatorPage *page = addPage(view);
page->onNavigatorAttached(this, view);
- view->onNavigatorAttached(stackNavi, tabNavi, page);
+ view->onNavigatorAttached(page);
if (!m_CurrentPage) {
navigateTo(view);
bool Navigator::removeView(View *view)
{
- if (!view || view->getNavigator(NavigatorType(getType())) != this) {
+ if (!view) {
return false;
}
return;
}
- if (view->getNavigator(NavigatorType(getType())) != this) {
+ if (!view->getNavigator()) {
addView(view);
}
using namespace std::placeholders;
TabNavigator::TabNavigator(Selector *selector)
- : Navigator(TypeTabNavigator),
- m_Selector(selector)
+ : m_Selector(selector)
{
if (m_Selector) {
m_Selector->setSelectCallback(std::bind(&TabNavigator::onSelected, this, _1));
*/
#include "Ui/View.h"
+#include "Ui/Navigator.h"
using namespace Ui;
-namespace Ui
-{
- template <>
- View *Control::findParent<View>(Evas_Object *object)
- {
- return static_cast<View *>(findParent(object, TypeView));
- }
-}
-
-View::View(int type)
- : Control(type),
- m_StackNavi(nullptr), m_TabNavi(nullptr), m_Page(nullptr),
+View::View()
+ : m_Page(nullptr),
m_IsCurrent(false), m_Rotation(-1)
{
}
-Navigator *View::getNavigator(NavigatorType type) const
+Navigator *View::getNavigator() const
{
- return type == TypeStackNavigator ? m_StackNavi : m_TabNavi;
+ return findParent<Navigator>();
}
NavigatorPage *View::getPage() const
return m_Rotation;
}
-void View::onNavigatorAttached(Navigator *stackNavi, Navigator *tabNavi, NavigatorPage *page)
+void View::onNavigatorAttached(NavigatorPage *page)
{
- m_StackNavi = stackNavi;
- m_TabNavi = tabNavi;
-
if (m_Page) {
m_Page->close();
}
template <>
Window *Control::findParent<Window>(Evas_Object *object)
{
- return static_cast<Window *>(getControl(elm_object_top_widget_get(object)));
+ return getControl<Window>(elm_object_top_widget_get(object));
}
}
Window::Window()
- : Control(TypeWindow), m_Conform(nullptr), m_Layout(nullptr), m_MainView(nullptr)
+ : m_Conform(nullptr), m_Layout(nullptr), m_MainView(nullptr)
{
}
}
Evas_Object *layout = elm_object_item_part_content_get(getObjectItem(), PART_THUMBNAIL);
- Ui::Thumbnail *thumbnail = static_cast<Ui::Thumbnail *>(Ui::Control::getControl(layout));
- Evas_Object *image = thumbnail->getImage();
+ Evas_Object *image = Ui::Control::getControl<Ui::Thumbnail>(layout)->getImage();
auto menu = new Ui::Menu();
menu->create(getParent()->getEvasObject());