[elm] Scroller widget now on scrollable interface.
authorGustavo Lima Chaves <glima@profusion.mobi>
Wed, 4 Jul 2012 21:42:35 +0000 (21:42 +0000)
committerGustavo Lima Chaves <glima@profusion.mobi>
Wed, 4 Jul 2012 21:42:35 +0000 (21:42 +0000)
Its API will be the the common one on ALL scrollable widgets, too.
Any scrollable widget having a function behaviour clashing with one of
the elm_scroller_* will be marked as DEPRECATED from now on.

SVN revision: 73309

src/lib/elm_scroller.c
src/lib/elm_scroller.h

index c253ac7..790e859 100644 (file)
@@ -1,31 +1,67 @@
 #include <Elementary.h>
 #include "elm_priv.h"
-#include "els_scroller.h"
-
-typedef struct _Widget_Data Widget_Data;
-
-struct _Widget_Data
-{
-   Evas_Object *scr;
-   Evas_Object *content;
-   const char *widget_name, *widget_base;
-   Eina_Bool min_w : 1;
-   Eina_Bool min_h : 1;
-   double pagerel_h, pagerel_v;
-   Evas_Coord pagesize_h, pagesize_v;
+#include "elm_interface_scrollable.h"
+#include "elm_widget_layout.h"
+
+typedef struct _Elm_Scroller_Smart_Data Elm_Scroller_Smart_Data;
+
+static const char SCROLLER_SMART_NAME[] = "elm_scroller";
+
+#define ELM_SCROLLER_DATA_GET(o, sd) \
+  Elm_Scroller_Smart_Data * sd = evas_object_smart_data_get(o)
+
+#define ELM_SCROLLER_DATA_GET_OR_RETURN(o, ptr)      \
+  ELM_SCROLLER_DATA_GET(o, ptr);                     \
+  if (!ptr)                                          \
+    {                                                \
+       CRITICAL("No widget data for object %p (%s)", \
+                o, evas_object_type_get(o));         \
+       return;                                       \
+    }
+
+#define ELM_SCROLLER_DATA_GET_OR_RETURN_VAL(o, ptr, val) \
+  ELM_SCROLLER_DATA_GET(o, ptr);                         \
+  if (!ptr)                                              \
+    {                                                    \
+       CRITICAL("No widget data for object %p (%s)",     \
+                o, evas_object_type_get(o));             \
+       return val;                                       \
+    }
+
+#define ELM_SCROLLER_CHECK(obj)                                             \
+  if (!obj || !elm_widget_type_check((obj), SCROLLER_SMART_NAME, __func__)) \
+    return
+
+#define ELM_SCROLLABLE_CHECK(obj, ...)                                       \
+  const Elm_Scrollable_Smart_Interface * s_iface =                           \
+    evas_object_smart_interface_get(obj, ELM_SCROLLABLE_IFACE_NAME);         \
+                                                                             \
+  if (!s_iface)                                                              \
+    {                                                                        \
+       ERR("Passing object (%p) of type '%s' in function %s, but it doesn't" \
+           " implement the Elementary scrollable interface.", obj,           \
+           elm_widget_type_get(obj), __func__);                              \
+       if (getenv("ELM_ERROR_ABORT")) abort();                               \
+       return __VA_ARGS__;                                                   \
+    }
+
+struct _Elm_Scroller_Smart_Data
+{
+   Elm_Layout_Smart_Data                 base; /* base widget smart data as
+                                                * first member obligatory, as
+                                                * we're inheriting from it */
+
+   const Elm_Scrollable_Smart_Interface *s_iface;
+
+   Evas_Object                          *hit_rect;
+   Evas_Object                          *g_layer;
+
+   Evas_Object                          *content;
+
+   Eina_Bool                             min_w : 1;
+   Eina_Bool                             min_h : 1;
 };
 
-static const char *widtype = NULL;
-static void _del_hook(Evas_Object *obj);
-static void _theme_hook(Evas_Object *obj);
-static void _show_region_hook(void *data, Evas_Object *obj);
-static void _sizing_eval(Evas_Object *obj);
-static void _sub_del(void *data, Evas_Object *obj, void *event_info);
-static void _on_focus_hook(void *data, Evas_Object *obj);
-static Eina_Bool _event_hook(Evas_Object *obj, Evas_Object *src,
-                             Evas_Callback_Type type, void *event_info);
-
-
 static const char SIG_SCROLL[] = "scroll";
 static const char SIG_SCROLL_ANIM_START[] = "scroll,anim,start";
 static const char SIG_SCROLL_ANIM_STOP[] = "scroll,anim,stop";
@@ -35,60 +71,74 @@ static const char SIG_EDGE_LEFT[] = "edge,left";
 static const char SIG_EDGE_RIGHT[] = "edge,right";
 static const char SIG_EDGE_TOP[] = "edge,top";
 static const char SIG_EDGE_BOTTOM[] = "edge,bottom";
-static const Evas_Smart_Cb_Description _signals[] = {
-  {SIG_SCROLL, ""},
-  {SIG_SCROLL_ANIM_START, ""},
-  {SIG_SCROLL_ANIM_STOP, ""},
-  {SIG_SCROLL_DRAG_START, ""},
-  {SIG_SCROLL_DRAG_STOP, ""},
-  {SIG_EDGE_LEFT, ""},
-  {SIG_EDGE_RIGHT, ""},
-  {SIG_EDGE_TOP, ""},
-  {SIG_EDGE_BOTTOM, ""},
-  {NULL, NULL}
+static const Evas_Smart_Cb_Description _smart_callbacks[] =
+{
+   {SIG_SCROLL, ""},
+   {SIG_SCROLL_ANIM_START, ""},
+   {SIG_SCROLL_ANIM_STOP, ""},
+   {SIG_SCROLL_DRAG_START, ""},
+   {SIG_SCROLL_DRAG_STOP, ""},
+   {SIG_EDGE_LEFT, ""},
+   {SIG_EDGE_RIGHT, ""},
+   {SIG_EDGE_TOP, ""},
+   {SIG_EDGE_BOTTOM, ""},
+   {NULL, NULL}
 };
 
-static Eina_Bool
-_event_hook(Evas_Object *obj, Evas_Object *src __UNUSED__, Evas_Callback_Type type, void *event_info)
+static const Evas_Smart_Interface *_smart_interfaces[] =
 {
-   if (type != EVAS_CALLBACK_KEY_DOWN) return EINA_FALSE;
-   Evas_Event_Key_Down *ev = event_info;
-   Widget_Data *wd = elm_widget_data_get(obj);
-   if (!wd) return EINA_FALSE;
-   if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return EINA_FALSE;
-   if (elm_widget_disabled_get(obj)) return EINA_FALSE;
+   (Evas_Smart_Interface *)&ELM_SCROLLABLE_IFACE, NULL
+};
 
+EVAS_SMART_SUBCLASS_IFACE_NEW
+  (SCROLLER_SMART_NAME, _elm_scroller, Elm_Layout_Smart_Class,
+  Elm_Layout_Smart_Class, elm_layout_smart_class_get, _smart_callbacks,
+  _smart_interfaces);
+
+static Eina_Bool
+_elm_scroller_smart_event(Evas_Object *obj,
+                          Evas_Object *src __UNUSED__,
+                          Evas_Callback_Type type,
+                          void *event_info)
+{
    Evas_Coord x = 0;
    Evas_Coord y = 0;
-   Evas_Coord step_x = 0;
-   Evas_Coord step_y = 0;
-   Evas_Coord max_x = 0;
-   Evas_Coord max_y = 0;
+   Evas_Coord c_x = 0;
+   Evas_Coord c_y = 0;
    Evas_Coord v_w = 0;
    Evas_Coord v_h = 0;
+   Evas_Coord max_x = 0;
+   Evas_Coord max_y = 0;
    Evas_Coord page_x = 0;
    Evas_Coord page_y = 0;
-   Evas_Coord c_x = 0;
-   Evas_Coord c_y = 0;
+   Evas_Coord step_x = 0;
+   Evas_Coord step_y = 0;
+   Evas_Event_Key_Down *ev = event_info;
+
+   ELM_SCROLLER_DATA_GET(obj, sd);
+
+   if (elm_widget_disabled_get(obj)) return EINA_FALSE;
+   if (type != EVAS_CALLBACK_KEY_DOWN) return EINA_FALSE;
+   if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return EINA_FALSE;
 
-   elm_smart_scroller_child_pos_get(wd->scr, &x, &y);
-   elm_smart_scroller_step_size_get(wd->scr, &step_x, &step_y);
-   elm_smart_scroller_page_size_get(wd->scr, &page_x, &page_y);
-   elm_smart_scroller_child_viewport_size_get(wd->scr, &v_w, &v_h);
-   evas_object_geometry_get(wd->content, &c_x, &c_y, &max_x, &max_y);
+   sd->s_iface->content_pos_get(obj, &x, &y);
+   sd->s_iface->step_size_get(obj, &step_x, &step_y);
+   sd->s_iface->page_size_get(obj, &page_x, &page_y);
+   sd->s_iface->content_viewport_size_get(obj, &v_w, &v_h);
+   evas_object_geometry_get(sd->content, &c_x, &c_y, &max_x, &max_y);
 
    if (((!strcmp(ev->keyname, "Left")) ||
         (!strcmp(ev->keyname, "KP_Left")) ||
         (!strcmp(ev->keyname, "Right")) ||
         (!strcmp(ev->keyname, "KP_Right")) ||
-        (!strcmp(ev->keyname, "Up"))  ||
+        (!strcmp(ev->keyname, "Up")) ||
         (!strcmp(ev->keyname, "KP_Up")) ||
         (!strcmp(ev->keyname, "Down")) ||
         (!strcmp(ev->keyname, "KP_Down"))) && (!ev->string))
      {
         Evas_Object *current_focus = NULL;
-        Evas_Object *new_focus = NULL;
         Eina_List *can_focus_list = NULL;
+        Evas_Object *new_focus = NULL;
         Evas_Coord f_x = 0;
         Evas_Coord f_y = 0;
         Evas_Coord f_w = 0;
@@ -98,19 +148,20 @@ _event_hook(Evas_Object *obj, Evas_Object *src __UNUSED__, Evas_Callback_Type ty
         evas_object_geometry_get(current_focus, &f_x, &f_y, &f_w, &f_h);
         can_focus_list = elm_widget_can_focus_child_list_get(obj);
         if ((current_focus == obj) ||
-            (!ELM_RECTS_INTERSECT(x, y, v_w, v_h,
-                                  (f_x - c_x), (f_y - c_y), f_w, f_h)))
+            (!ELM_RECTS_INTERSECT
+               (x, y, v_w, v_h, (f_x - c_x), (f_y - c_y), f_w, f_h)))
           {
-             Evas_Object *cur;
              Eina_List *l;
+             Evas_Object *cur;
              double weight = 0.0;
 
-             EINA_LIST_FOREACH(can_focus_list, l, cur)
+             EINA_LIST_FOREACH (can_focus_list, l, cur)
                {
                   double cur_weight = 0.0;
+
                   evas_object_geometry_get(cur, &f_x, &f_y, &f_w, &f_h);
-                  if (ELM_RECTS_INTERSECT(x, y, v_w, v_h,
-                                          (f_x - c_x), (f_y - c_y), f_w, f_h))
+                  if (ELM_RECTS_INTERSECT
+                        (x, y, v_w, v_h, (f_x - c_x), (f_y - c_y), f_w, f_h))
                     {
                        if ((f_x - c_x) > x)
                          cur_weight += ((f_x - c_x) - x) * ((f_x - c_x) - x);
@@ -119,6 +170,7 @@ _event_hook(Evas_Object *obj, Evas_Object *src __UNUSED__, Evas_Callback_Type ty
                        if (cur_weight == 0.0)
                          {
                             elm_widget_focus_steal(cur);
+
                             return EINA_TRUE;
                          }
                        cur_weight = 1.0 / cur_weight;
@@ -132,6 +184,7 @@ _event_hook(Evas_Object *obj, Evas_Object *src __UNUSED__, Evas_Callback_Type ty
              if (new_focus)
                {
                   elm_widget_focus_steal(new_focus);
+
                   return EINA_TRUE;
                }
           }
@@ -139,19 +192,26 @@ _event_hook(Evas_Object *obj, Evas_Object *src __UNUSED__, Evas_Callback_Type ty
           {
              Evas_Object *tmp = NULL;
              double degree = 0.0, weight = 0.0;
-             void *(*list_data_get) (const Eina_List *list);
+             void *(*list_data_get)(const Eina_List *list);
+
              list_data_get = eina_list_data_get;
 
-             if ((!strcmp(ev->keyname, "Left")) || (!strcmp(ev->keyname, "KP_Left")))
+             if ((!strcmp(ev->keyname, "Left")) ||
+                 (!strcmp(ev->keyname, "KP_Left")))
                degree = 270.0;
-             else if ((!strcmp(ev->keyname, "Right")) || (!strcmp(ev->keyname, "KP_Right")))
+             else if ((!strcmp(ev->keyname, "Right")) ||
+                      (!strcmp(ev->keyname, "KP_Right")))
                degree = 90.0;
-             else if ((!strcmp(ev->keyname, "Up"))  || (!strcmp(ev->keyname, "KP_Up")))
+             else if ((!strcmp(ev->keyname, "Up")) ||
+                      (!strcmp(ev->keyname, "KP_Up")))
                degree = 0.0;
-             else if ((!strcmp(ev->keyname, "Down")) || (!strcmp(ev->keyname, "KP_Down")))
+             else if ((!strcmp(ev->keyname, "Down")) ||
+                      (!strcmp(ev->keyname, "KP_Down")))
                degree = 180.0;
 
-             if (elm_widget_focus_list_direction_get(obj, current_focus, can_focus_list, list_data_get, degree, &tmp, &weight))
+             if (elm_widget_focus_list_direction_get
+                   (obj, current_focus, can_focus_list, list_data_get, degree,
+                   &tmp, &weight))
                new_focus = tmp;
 
              if (new_focus)
@@ -166,6 +226,7 @@ _event_hook(Evas_Object *obj, Evas_Object *src __UNUSED__, Evas_Callback_Type ty
                   l_y = f_y - c_y - step_y;
                   l_w = f_w + (step_x * 2);
                   l_h = f_h + (step_y * 2);
+
                   if (ELM_RECTS_INTERSECT(x, y, v_w, v_h, l_x, l_y, l_w, l_h))
                     {
                        elm_widget_focus_steal(new_focus);
@@ -227,642 +288,693 @@ _event_hook(Evas_Object *obj, Evas_Object *src __UNUSED__, Evas_Callback_Type ty
    else return EINA_FALSE;
 
    ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
-   elm_smart_scroller_child_pos_set(wd->scr, x, y);
+   sd->s_iface->content_pos_set(obj, x, y);
+
    return EINA_TRUE;
 }
 
 static void
-_on_focus_hook(void *data __UNUSED__, Evas_Object *obj)
+_elm_scroller_smart_sizing_eval(Evas_Object *obj)
 {
-   Widget_Data *wd = elm_widget_data_get(obj);
-   if (!wd) return;
-   if (elm_widget_focus_get(obj))
+   Evas_Coord vw = 0, vh = 0, minw = 0, minh = 0, maxw = 0, maxh = 0, w, h,
+              vmw, vmh;
+   double xw = 0.0, yw = 0.0;
+
+   ELM_SCROLLER_DATA_GET(obj, sd);
+
+   /* parent class' early call */
+   if (!sd->s_iface) return;
+
+   if (sd->content)
      {
-        edje_object_signal_emit(elm_smart_scroller_edje_object_get(wd->scr), "elm,action,focus", "elm");
-        evas_object_focus_set(wd->scr, EINA_TRUE);
+        evas_object_size_hint_min_get(sd->content, &minw, &minh);
+        evas_object_size_hint_max_get(sd->content, &maxw, &maxh);
+        evas_object_size_hint_weight_get(sd->content, &xw, &yw);
      }
-   else
+
+   sd->s_iface->content_viewport_size_get(obj, &vw, &vh);
+   if (xw > 0.0)
      {
-        edje_object_signal_emit(elm_smart_scroller_edje_object_get(wd->scr), "elm,action,unfocus", "elm");
-        evas_object_focus_set(wd->scr, EINA_FALSE);
+        if ((minw > 0) && (vw < minw))
+          vw = minw;
+        else if ((maxw > 0) && (vw > maxw))
+          vw = maxw;
      }
-}
+   else if (minw > 0)
+     vw = minw;
 
-static void
-_del_hook(Evas_Object *obj)
-{
-   Widget_Data *wd = elm_widget_data_get(obj);
-   if (!wd) return;
-   free(wd);
+   if (yw > 0.0)
+     {
+        if ((minh > 0) && (vh < minh))
+          vh = minh;
+        else if ((maxh > 0) && (vh > maxh))
+          vh = maxh;
+     }
+   else if (minh > 0)
+     vh = minh;
+
+   if (sd->content) evas_object_resize(sd->content, vw, vh);
+
+   w = -1;
+   h = -1;
+   edje_object_size_min_calc(ELM_WIDGET_DATA(sd)->resize_obj, &vmw, &vmh);
+
+   if (sd->min_w) w = vmw + minw;
+   if (sd->min_h) h = vmh + minh;
+
+   evas_object_size_hint_max_get(obj, &maxw, &maxh);
+   if ((maxw > 0) && (w > maxw)) w = maxw;
+   if ((maxh > 0) && (h > maxh)) h = maxh;
+
+   evas_object_size_hint_min_set(obj, w, h);
 }
 
 static void
-_mirrored_set(Evas_Object *obj, Eina_Bool mirrored)
+_mirrored_set(Evas_Object *obj,
+              Eina_Bool mirrored)
 {
-   Widget_Data *wd = elm_widget_data_get(obj);
-   if (!wd) return;
-   if (wd->scr)
-     elm_smart_scroller_mirrored_set(wd->scr, mirrored);
+   ELM_SCROLLER_DATA_GET(obj, sd);
+
+   sd->s_iface->mirrored_set(obj, mirrored);
 }
 
-static void
-_theme_hook(Evas_Object *obj)
+static Eina_Bool
+_elm_scroller_smart_theme(Evas_Object *obj)
 {
-   Widget_Data *wd = elm_widget_data_get(obj);
-   if (!wd) return;
-   _elm_widget_mirrored_reload(obj);
-   if (wd->scr)
-     {
-        Evas_Object *edj;
-        const char *str;
-
-        _mirrored_set(obj, elm_widget_mirrored_get(obj));
-        elm_smart_scroller_object_theme_set(obj, wd->scr,
-                                            wd->widget_name, wd->widget_base,
-                                            elm_widget_style_get(obj));
-        //        edje_object_scale_set(wd->scr, elm_widget_scale_get(obj) * _elm_config->scale);
-        edj = elm_smart_scroller_edje_object_get(wd->scr);
-        str = edje_object_data_get(edj, "focus_highlight");
-        if ((str) && (!strcmp(str, "on")))
-          elm_widget_highlight_in_theme_set(obj, EINA_TRUE);
-        else
-          elm_widget_highlight_in_theme_set(obj, EINA_FALSE);
-     }
-   _sizing_eval(obj);
+   const char *str;
+
+   ELM_SCROLLER_DATA_GET(obj, sd);
+
+   if (!ELM_WIDGET_CLASS(_elm_scroller_parent_sc)->theme(obj))
+     return EINA_FALSE;
+
+   _mirrored_set(obj, elm_widget_mirrored_get(obj));
+
+   str = edje_object_data_get
+       (ELM_WIDGET_DATA(sd)->resize_obj, "focus_highlight");
+   if ((str) && (!strcmp(str, "on")))
+     elm_widget_highlight_in_theme_set(obj, EINA_TRUE);
+   else
+     elm_widget_highlight_in_theme_set(obj, EINA_FALSE);
+
+   elm_layout_sizing_eval(obj);
+
+   return EINA_TRUE;
 }
 
 static Eina_Bool
-_elm_scroller_focus_next_hook(const Evas_Object *obj, Elm_Focus_Direction dir, Evas_Object **next)
+_elm_scroller_smart_focus_next(const Evas_Object *obj,
+                               Elm_Focus_Direction dir,
+                               Evas_Object **next)
 {
-   Widget_Data *wd = elm_widget_data_get(obj);
    Evas_Object *cur;
 
-   if ((!wd) || (!wd->content))
-     return EINA_FALSE;
+   ELM_SCROLLER_DATA_GET(obj, sd);
 
-   cur = wd->content;
+   if (!sd->content) return EINA_FALSE;
 
-   /* Try Focus cycle in subitem */
+   cur = sd->content;
+
+   /* Try focus cycle in subitem */
    if (elm_widget_focus_get(obj))
      {
-        if ((elm_widget_can_focus_get(cur)) || (elm_widget_child_can_focus_get(cur)))
+        if ((elm_widget_can_focus_get(cur)) ||
+            (elm_widget_child_can_focus_get(cur)))
           return elm_widget_focus_next_get(cur, dir, next);
      }
 
    /* Return */
    *next = (Evas_Object *)obj;
+
    return !elm_widget_focus_get(obj);
 }
 
 static void
-_signal_emit_hook(Evas_Object *obj, const char *emission, const char *source)
+_show_region_hook(void *data,
+                  Evas_Object *content_obj)
 {
-   Widget_Data *wd = elm_widget_data_get(obj);
-   if (!wd) return;
-   edje_object_signal_emit(elm_smart_scroller_edje_object_get(wd->scr),
-                           emission, source);
-}
+   Evas_Coord x, y, w, h;
 
-static void
-_signal_callback_add_hook(Evas_Object *obj, const char *emission, const char *source, Edje_Signal_Cb func_cb, void *data)
-{
-   Widget_Data *wd = elm_widget_data_get(obj);
-   if (!wd) return;
-   edje_object_signal_callback_add(elm_smart_scroller_edje_object_get(wd->scr),
-                                   emission, source, func_cb, data);
-}
+   ELM_SCROLLER_DATA_GET(data, sd);
 
-static void
-_signal_callback_del_hook(Evas_Object *obj, const char *emission, const char *source, Edje_Signal_Cb func_cb, void *data)
-{
-   Widget_Data *wd = elm_widget_data_get(obj);
-   edje_object_signal_callback_del_full(
-      elm_smart_scroller_edje_object_get(wd->scr), emission, source,
-      func_cb, data);
+   elm_widget_show_region_get(content_obj, &x, &y, &w, &h);
+   sd->s_iface->content_region_show(data, x, y, w, h);
 }
 
 static void
-_show_region_hook(void *data, Evas_Object *obj)
+_focus_region_hook(Evas_Object *obj,
+                   Evas_Coord x,
+                   Evas_Coord y,
+                   Evas_Coord w,
+                   Evas_Coord h)
 {
-   Widget_Data *wd = elm_widget_data_get(data);
-   Evas_Coord x, y, w, h;
-   if (!wd) return;
-   elm_widget_show_region_get(obj, &x, &y, &w, &h);
-   if (wd->scr)
-     elm_smart_scroller_child_region_show(wd->scr, x, y, w, h);
+   ELM_SCROLLER_DATA_GET(obj, sd);
+
+   sd->s_iface->content_region_show(obj, x, y, w, h);
 }
 
 static void
-_focus_region_hook(Evas_Object *obj, Evas_Coord x, Evas_Coord y, Evas_Coord w, Evas_Coord h)
+_changed_size_hints_cb(void *data,
+                       Evas *e __UNUSED__,
+                       Evas_Object *obj __UNUSED__,
+                       void *event_info __UNUSED__)
 {
-   Widget_Data *wd = elm_widget_data_get(obj);
-   if (wd->scr)
-     elm_smart_scroller_child_region_show(wd->scr, x, y, w, h);
+   elm_layout_sizing_eval(data);
 }
 
-static void
-_sizing_eval(Evas_Object *obj)
+static Eina_Bool
+_elm_scroller_smart_sub_object_del(Evas_Object *obj,
+                                   Evas_Object *sobj)
 {
-   Widget_Data *wd = elm_widget_data_get(obj);
-   Evas_Coord  vw = 0, vh = 0, minw = 0, minh = 0, maxw = 0, maxh = 0, w, h, vmw, vmh;
-   double xw = 0.0, yw = 0.0;
+   ELM_SCROLLER_DATA_GET(obj, sd);
 
-   if (!wd) return;
-   if (wd->content)
-     {
-        evas_object_size_hint_min_get(wd->content, &minw, &minh);
-        evas_object_size_hint_max_get(wd->content, &maxw, &maxh);
-        evas_object_size_hint_weight_get(wd->content, &xw, &yw);
-     }
-   if (wd->scr)
+   if (!ELM_WIDGET_CLASS(_elm_scroller_parent_sc)->sub_object_del(obj, sobj))
+     return EINA_FALSE;
+
+   if (sobj == sd->content)
      {
-        elm_smart_scroller_child_viewport_size_get(wd->scr, &vw, &vh);
-        if (xw > 0.0)
-          {
-             if ((minw > 0) && (vw < minw)) vw = minw;
-             else if ((maxw > 0) && (vw > maxw)) vw = maxw;
-          }
-        else if (minw > 0) vw = minw;
-        if (yw > 0.0)
-          {
-             if ((minh > 0) && (vh < minh)) vh = minh;
-             else if ((maxh > 0) && (vh > maxh)) vh = maxh;
-          }
-        else if (minh > 0) vh = minh;
-        if (wd->content) evas_object_resize(wd->content, vw, vh);
-        w = -1;
-        h = -1;
-        edje_object_size_min_calc(elm_smart_scroller_edje_object_get(wd->scr), &vmw, &vmh);
-        if (wd->min_w) w = vmw + minw;
-        if (wd->min_h) h = vmh + minh;
-        evas_object_size_hint_max_get(obj, &maxw, &maxh);
-        if ((maxw > 0) && (w > maxw)) w = maxw;
-        if ((maxh > 0) && (h > maxh)) h = maxh;
-        evas_object_size_hint_min_set(obj, w, h);
+        elm_widget_on_show_region_hook_set(sd->content, NULL, NULL);
+
+        sd->content = NULL;
      }
+
+   return EINA_TRUE;
 }
 
 static void
-_changed_size_hints(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
+_resize_cb(void *data,
+           Evas *e __UNUSED__,
+           Evas_Object *obj __UNUSED__,
+           void *event_info __UNUSED__)
 {
-   _sizing_eval(data);
+   elm_layout_sizing_eval(data);
 }
 
 static void
-_sub_del(void *data __UNUSED__, Evas_Object *obj, void *event_info)
+_edge_left_cb(Evas_Object *obj,
+              void *data __UNUSED__)
 {
-   Widget_Data *wd = elm_widget_data_get(obj);
-   Evas_Object *sub = event_info;
-
-   if (!wd) return;
-   if (sub == wd->content)
-     {
-        elm_widget_on_show_region_hook_set(wd->content, NULL, NULL);
-        evas_object_event_callback_del_full (sub, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
-                                             _changed_size_hints, obj);
-        wd->content = NULL;
-        _sizing_eval(obj);
-     }
-   else if (sub == wd->scr)
-     wd->scr = NULL;
+   evas_object_smart_callback_call(obj, SIG_EDGE_LEFT, NULL);
 }
 
 static void
-_hold_on(void *data __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
+_edge_right_cb(Evas_Object *obj,
+               void *data __UNUSED__)
 {
-   Widget_Data *wd = elm_widget_data_get(obj);
-
-   if (!wd) return;
-   if (wd->scr)
-     elm_smart_scroller_hold_set(wd->scr, 1);
+   evas_object_smart_callback_call(obj, SIG_EDGE_RIGHT, NULL);
 }
 
 static void
-_hold_off(void *data __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
+_edge_top_cb(Evas_Object *obj,
+             void *data __UNUSED__)
 {
-   Widget_Data *wd = elm_widget_data_get(obj);
-
-   if (!wd) return;
-   if (wd->scr)
-     elm_smart_scroller_hold_set(wd->scr, 0);
+   evas_object_smart_callback_call(obj, SIG_EDGE_TOP, NULL);
 }
 
 static void
-_freeze_on(void *data __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
+_edge_bottom_cb(Evas_Object *obj,
+                void *data __UNUSED__)
 {
-   Widget_Data *wd = elm_widget_data_get(obj);
-
-   if (!wd) return;
-   if (wd->scr)
-     elm_smart_scroller_freeze_set(wd->scr, 1);
+   evas_object_smart_callback_call(obj, SIG_EDGE_BOTTOM, NULL);
 }
 
 static void
-_freeze_off(void *data __UNUSED__, Evas_Object *obj, void *event_info __UNUSED__)
+_scroll_cb(Evas_Object *obj,
+           void *data __UNUSED__)
 {
-   Widget_Data *wd = elm_widget_data_get(obj);
-
-   if (!wd) return;
-   if (wd->scr)
-     elm_smart_scroller_freeze_set(wd->scr, 0);
+   evas_object_smart_callback_call(obj, SIG_SCROLL, NULL);
 }
 
 static void
-_resize(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
+_scroll_anim_start_cb(Evas_Object *obj,
+                      void *data __UNUSED__)
 {
-   _sizing_eval(data);
+   evas_object_smart_callback_call(obj, SIG_SCROLL_ANIM_START, NULL);
 }
 
 static void
-_edge_left(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
+_scroll_anim_stop_cb(Evas_Object *obj,
+                     void *data __UNUSED__)
 {
-   evas_object_smart_callback_call(data, SIG_EDGE_LEFT, NULL);
+   evas_object_smart_callback_call(obj, SIG_SCROLL_ANIM_STOP, NULL);
 }
 
 static void
-_edge_right(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
+_scroll_drag_start_cb(Evas_Object *obj,
+                      void *data __UNUSED__)
 {
-   evas_object_smart_callback_call(data, SIG_EDGE_RIGHT, NULL);
+   evas_object_smart_callback_call(obj, SIG_SCROLL_DRAG_START, NULL);
 }
 
 static void
-_edge_top(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
+_scroll_drag_stop_cb(Evas_Object *obj,
+                     void *data __UNUSED__)
 {
-   evas_object_smart_callback_call(data, SIG_EDGE_TOP, NULL);
+   evas_object_smart_callback_call(obj, SIG_SCROLL_DRAG_STOP, NULL);
 }
 
-static void
-_edge_bottom(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
+static Eina_Bool
+_elm_scroller_smart_content_set(Evas_Object *obj,
+                                const char *part,
+                                Evas_Object *content)
 {
-   evas_object_smart_callback_call(data, SIG_EDGE_BOTTOM, NULL);
+   ELM_SCROLLER_DATA_GET(obj, sd);
+
+   if (part && strcmp(part, "default"))
+     return ELM_CONTAINER_CLASS
+              (_elm_scroller_parent_sc)->content_set(obj, part, content);
+
+   if (sd->content == content) return EINA_TRUE;
+
+   if (sd->content) evas_object_del(sd->content);
+   sd->content = content;
+
+   if (content)
+     {
+        elm_widget_on_show_region_hook_set(content, _show_region_hook, obj);
+        elm_widget_sub_object_add(obj, content);
+
+        sd->s_iface->content_set(obj, content);
+     }
+
+   elm_layout_sizing_eval(obj);
+
+   return EINA_TRUE;
 }
 
-static void
-_scroll(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
+static Evas_Object *
+_elm_scroller_smart_content_get(const Evas_Object *obj,
+                                const char *part)
 {
-   evas_object_smart_callback_call(data, SIG_SCROLL, NULL);
+   ELM_SCROLLER_DATA_GET(obj, sd);
+
+   if (part && strcmp(part, "default"))
+     return ELM_CONTAINER_CLASS
+              (_elm_scroller_parent_sc)->content_get(obj, part);
+
+   return sd->content;
 }
 
-static void
-_scroll_anim_start(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
+static Evas_Object *
+_elm_scroller_smart_content_unset(Evas_Object *obj,
+                                  const char *part)
 {
-   evas_object_smart_callback_call(data, SIG_SCROLL_ANIM_START, NULL);
+   Evas_Object *content;
+
+   ELM_SCROLLER_DATA_GET(obj, sd);
+
+   if (part && strcmp(part, "default"))
+     return ELM_CONTAINER_CLASS
+              (_elm_scroller_parent_sc)->content_unset(obj, part);
+
+   if (!sd->content) return NULL;
+
+   content = sd->content;
+   elm_widget_sub_object_del(obj, sd->content);
+   sd->s_iface->content_set(obj, NULL);
+   sd->content = NULL;
+
+   return content;
 }
 
 static void
-_scroll_anim_stop(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
+_elm_scroller_smart_add(Evas_Object *obj)
 {
-   evas_object_smart_callback_call(data, SIG_SCROLL_ANIM_STOP, NULL);
+   EVAS_SMART_DATA_ALLOC(obj, Elm_Scroller_Smart_Data);
+
+   ELM_WIDGET_CLASS(_elm_scroller_parent_sc)->base.add(obj);
+
+   elm_widget_can_focus_set(obj, EINA_TRUE);
 }
 
 static void
-_scroll_drag_start(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
+_elm_scroller_smart_move(Evas_Object *obj,
+                         Evas_Coord x,
+                         Evas_Coord y)
 {
-   evas_object_smart_callback_call(data, SIG_SCROLL_DRAG_START, NULL);
+   ELM_SCROLLER_DATA_GET(obj, sd);
+
+   ELM_WIDGET_CLASS(_elm_scroller_parent_sc)->base.move(obj, x, y);
+
+   evas_object_move(sd->hit_rect, x, y);
 }
 
 static void
-_scroll_drag_stop(void *data, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
+_elm_scroller_smart_resize(Evas_Object *obj,
+                           Evas_Coord w,
+                           Evas_Coord h)
 {
-   evas_object_smart_callback_call(data, SIG_SCROLL_DRAG_STOP, NULL);
-}
+   ELM_SCROLLER_DATA_GET(obj, sd);
 
-Evas_Object *
-_elm_scroller_edje_object_get(Evas_Object *obj)
-{
-   ELM_CHECK_WIDTYPE(obj, widtype) NULL;
-   Widget_Data *wd = elm_widget_data_get(obj);
-   if (!wd) return NULL;
-   return elm_smart_scroller_edje_object_get(wd->scr);
+   ELM_WIDGET_CLASS(_elm_scroller_parent_sc)->base.resize(obj, w, h);
+
+   evas_object_resize(sd->hit_rect, w, h);
 }
 
 static void
-_content_set_hook(Evas_Object *obj, const char *part, Evas_Object *content)
-{
-   ELM_CHECK_WIDTYPE(obj, widtype);
-   Widget_Data *wd;
-   if (part && strcmp(part, "default")) return;
-   wd = elm_widget_data_get(obj);
-   if (!wd) return;
-   if (wd->content == content) return;
-   if (wd->content) evas_object_del(wd->content);
-   wd->content = content;
-   if (content)
-     {
-        elm_widget_on_show_region_hook_set(content, _show_region_hook, obj);
-        elm_widget_sub_object_add(obj, content);
-        if (wd->scr)
-          elm_smart_scroller_child_set(wd->scr, content);
-        evas_object_event_callback_add(content,
-                                       EVAS_CALLBACK_CHANGED_SIZE_HINTS,
-                                       _changed_size_hints, obj);
-     }
-   _sizing_eval(obj);
+_elm_scroller_smart_member_add(Evas_Object *obj,
+                               Evas_Object *member)
+{
+   ELM_SCROLLER_DATA_GET(obj, sd);
+
+   ELM_WIDGET_CLASS(_elm_scroller_parent_sc)->base.member_add(obj, member);
+
+   if (sd->hit_rect)
+     evas_object_raise(sd->hit_rect);
 }
 
-static Evas_Object *
-_content_get_hook(const Evas_Object *obj, const char *part)
+static void
+_elm_scroller_smart_set_user(Elm_Layout_Smart_Class *sc)
 {
-   ELM_CHECK_WIDTYPE(obj, widtype) NULL;
-   Widget_Data *wd;
-   if (part && strcmp(part, "default")) return NULL;
-   wd = elm_widget_data_get(obj);
-   if (!wd) return NULL;
-   return wd->content;
+   ELM_WIDGET_CLASS(sc)->base.add = _elm_scroller_smart_add;
+   ELM_WIDGET_CLASS(sc)->base.move = _elm_scroller_smart_move;
+   ELM_WIDGET_CLASS(sc)->base.resize = _elm_scroller_smart_resize;
+   ELM_WIDGET_CLASS(sc)->base.member_add = _elm_scroller_smart_member_add;
+
+   ELM_WIDGET_CLASS(sc)->sub_object_del = _elm_scroller_smart_sub_object_del;
+   ELM_WIDGET_CLASS(sc)->theme = _elm_scroller_smart_theme;
+   ELM_WIDGET_CLASS(sc)->focus_next = _elm_scroller_smart_focus_next;
+   ELM_WIDGET_CLASS(sc)->event = _elm_scroller_smart_event;
+
+   ELM_CONTAINER_CLASS(sc)->content_set = _elm_scroller_smart_content_set;
+   ELM_CONTAINER_CLASS(sc)->content_get = _elm_scroller_smart_content_get;
+   ELM_CONTAINER_CLASS(sc)->content_unset = _elm_scroller_smart_content_unset;
+
+   ELM_LAYOUT_CLASS(sc)->sizing_eval = _elm_scroller_smart_sizing_eval;
 }
 
-static Evas_Object *
-_content_unset_hook(Evas_Object *obj, const char *part)
+static void
+_elm_scroller_content_min_limit_cb(Evas_Object *obj,
+                                   Eina_Bool w,
+                                   Eina_Bool h)
 {
-   ELM_CHECK_WIDTYPE(obj, widtype) NULL;
-   Widget_Data *wd;
-   Evas_Object *content;
-   if (part && strcmp(part, "default")) return NULL;
-   wd = elm_widget_data_get(obj);
-   if (!wd) return NULL;
-   if (!wd->content) return NULL;
-   content = wd->content;
-   elm_widget_sub_object_del(obj, wd->content);
-   evas_object_event_callback_del_full(wd->content,
-                                       EVAS_CALLBACK_CHANGED_SIZE_HINTS,
-                                       _changed_size_hints, obj);
-   edje_object_part_unswallow(elm_smart_scroller_edje_object_get(wd->scr),
-                              wd->content);
-   wd->content = NULL;
-   return content;
+   ELM_SCROLLER_DATA_GET(obj, sd);
+
+   sd->min_w = !!w;
+   sd->min_h = !!h;
+
+   elm_layout_sizing_eval(obj);
 }
 
 EAPI Evas_Object *
 elm_scroller_add(Evas_Object *parent)
 {
-   Evas_Object *obj;
    Evas *e;
-   Widget_Data *wd;
+   Evas_Object *obj;
    Evas_Coord minw, minh;
 
-   ELM_WIDGET_STANDARD_SETUP(wd, Widget_Data, parent, e, obj, NULL);
-
-   ELM_SET_WIDTYPE(widtype, "scroller");
-   elm_widget_type_set(obj, "scroller");
-   elm_widget_sub_object_add(parent, obj);
-   elm_widget_on_focus_hook_set(obj, _on_focus_hook, NULL);
-   elm_widget_data_set(obj, wd);
-   elm_widget_del_hook_set(obj, _del_hook);
-   elm_widget_theme_hook_set(obj, _theme_hook);
-   elm_widget_signal_emit_hook_set(obj, _signal_emit_hook);
-   elm_widget_signal_callback_add_hook_set(obj, _signal_callback_add_hook);
-   elm_widget_signal_callback_del_hook_set(obj, _signal_callback_del_hook);
-   elm_widget_focus_next_hook_set(obj, _elm_scroller_focus_next_hook);
-   elm_widget_can_focus_set(obj, EINA_TRUE);
-   elm_widget_event_hook_set(obj, _event_hook);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(parent, NULL);
+
+   e = evas_object_evas_get(parent);
+   if (!e) return NULL;
+
+   obj = evas_object_smart_add(e, _elm_scroller_smart_class_new());
+
+   if (!elm_widget_sub_object_add(parent, obj))
+     ERR("could not add %p as sub object of %p", obj, parent);
+
+   ELM_SCROLLER_DATA_GET(obj, sd);
+
+   elm_widget_theme_object_set
+     (obj, ELM_WIDGET_DATA(sd)->resize_obj, "scroller", "base",
+     elm_widget_style_get(obj));
+
+   sd->hit_rect = evas_object_rectangle_add(evas_object_evas_get(obj));
+   evas_object_smart_member_add(sd->hit_rect, obj);
+   elm_widget_sub_object_add(obj, sd->hit_rect);
+
+   /* common scroller hit rectangle setup -- it has to take place
+    * AFTER smart_member_add() */
+   evas_object_color_set(sd->hit_rect, 0, 0, 0, 0);
+   evas_object_show(sd->hit_rect);
+   evas_object_repeat_events_set(sd->hit_rect, EINA_TRUE);
+
+   /* FIXME: rework it */
    elm_widget_focus_region_hook_set(obj, _focus_region_hook);
-   elm_widget_content_set_hook_set(obj, _content_set_hook);
-   elm_widget_content_get_hook_set(obj, _content_get_hook);
-   elm_widget_content_unset_hook_set(obj, _content_unset_hook);
 
-   wd->widget_name = eina_stringshare_add("scroller");
-   wd->widget_base = eina_stringshare_add("base");
+   /* interface's add() routive issued AFTER the object's smart_add() */
+   sd->s_iface = evas_object_smart_interface_get
+       (obj, ELM_SCROLLABLE_IFACE_NAME);
 
-   wd->scr = elm_smart_scroller_add(e);
-   elm_smart_scroller_widget_set(wd->scr, obj);
-   _theme_hook(obj);
-   elm_widget_resize_object_set(obj, wd->scr);
-   evas_object_event_callback_add(wd->scr, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
-                                  _changed_size_hints, obj);
+   sd->s_iface->objects_set
+     (obj, ELM_WIDGET_DATA(sd)->resize_obj, sd->hit_rect);
 
-   edje_object_size_min_calc(elm_smart_scroller_edje_object_get(wd->scr), &minw, &minh);
+   evas_object_event_callback_add
+     (obj, EVAS_CALLBACK_CHANGED_SIZE_HINTS, _changed_size_hints_cb, obj);
+
+   edje_object_size_min_calc(ELM_WIDGET_DATA(sd)->resize_obj, &minw, &minh);
    evas_object_size_hint_min_set(obj, minw, minh);
-   evas_object_event_callback_add(obj, EVAS_CALLBACK_RESIZE, _resize, obj);
-
-   evas_object_smart_callback_add(obj, "sub-object-del", _sub_del, obj);
-   evas_object_smart_callback_add(obj, "scroll-hold-on", _hold_on, obj);
-   evas_object_smart_callback_add(obj, "scroll-hold-off", _hold_off, obj);
-   evas_object_smart_callback_add(obj, "scroll-freeze-on", _freeze_on, obj);
-   evas_object_smart_callback_add(obj, "scroll-freeze-off", _freeze_off, obj);
-
-   evas_object_smart_callback_add(wd->scr, "edge,left", _edge_left, obj);
-   evas_object_smart_callback_add(wd->scr, "edge,right", _edge_right, obj);
-   evas_object_smart_callback_add(wd->scr, "edge,top", _edge_top, obj);
-   evas_object_smart_callback_add(wd->scr, "edge,bottom", _edge_bottom, obj);
-   evas_object_smart_callback_add(wd->scr, "scroll", _scroll, obj);
-   evas_object_smart_callback_add(wd->scr, "animate,start", _scroll_anim_start, obj);
-   evas_object_smart_callback_add(wd->scr, "animate,stop", _scroll_anim_stop, obj);
-   evas_object_smart_callback_add(wd->scr, "drag,start", _scroll_drag_start, obj);
-   evas_object_smart_callback_add(wd->scr, "drag,stop", _scroll_drag_stop, obj);
-
-   _sizing_eval(obj);
-
-   // TODO: convert Elementary to subclassing of Evas_Smart_Class
-   // TODO: and save some bytes, making descriptions per-class and not instance!
-   evas_object_smart_callbacks_descriptions_set(obj, _signals);
-   _mirrored_set(obj, elm_widget_mirrored_get(obj));
+   evas_object_event_callback_add(obj, EVAS_CALLBACK_RESIZE, _resize_cb, obj);
+
+   sd->s_iface->edge_left_cb_set(obj, _edge_left_cb);
+   sd->s_iface->edge_right_cb_set(obj, _edge_right_cb);
+   sd->s_iface->edge_top_cb_set(obj, _edge_top_cb);
+   sd->s_iface->edge_bottom_cb_set(obj, _edge_bottom_cb);
+   sd->s_iface->scroll_cb_set(obj, _scroll_cb);
+   sd->s_iface->animate_start_cb_set(obj, _scroll_anim_start_cb);
+   sd->s_iface->animate_stop_cb_set(obj, _scroll_anim_stop_cb);
+   sd->s_iface->drag_start_cb_set(obj, _scroll_drag_start_cb);
+   sd->s_iface->drag_stop_cb_set(obj, _scroll_drag_stop_cb);
+
+   sd->s_iface->content_min_limit_cb_set
+     (obj, _elm_scroller_content_min_limit_cb);
+
+   _elm_scroller_smart_theme(obj);
+
    return obj;
 }
 
+/* deprecated */
 EAPI void
-elm_scroller_custom_widget_base_theme_set(Evas_Object *obj, const char *widget, const char *base)
+elm_scroller_custom_widget_base_theme_set(Evas_Object *obj,
+                                          const char *klass,
+                                          const char *group)
 {
-   ELM_CHECK_WIDTYPE(obj, widtype);
-   Widget_Data *wd = elm_widget_data_get(obj);
-   if (!wd) return;
-   EINA_SAFETY_ON_NULL_RETURN(widget);
-   EINA_SAFETY_ON_NULL_RETURN(base);
-   if (eina_stringshare_replace(&wd->widget_name, widget) |
-       eina_stringshare_replace(&wd->widget_base, base))
-     _theme_hook(obj);
+   ELM_SCROLLER_CHECK(obj);
+   ELM_SCROLLER_DATA_GET(obj, sd);
+
+   EINA_SAFETY_ON_NULL_RETURN(klass);
+   EINA_SAFETY_ON_NULL_RETURN(group);
+
+   if (eina_stringshare_replace(&(ELM_LAYOUT_DATA(sd)->klass), klass) ||
+       eina_stringshare_replace(&(ELM_LAYOUT_DATA(sd)->group), group))
+     _elm_scroller_smart_theme(obj);
 }
 
 EAPI void
-elm_scroller_content_min_limit(Evas_Object *obj, Eina_Bool w, Eina_Bool h)
+elm_scroller_content_min_limit(Evas_Object *obj,
+                               Eina_Bool w,
+                               Eina_Bool h)
 {
-   ELM_CHECK_WIDTYPE(obj, widtype);
-   Widget_Data *wd = elm_widget_data_get(obj);
-   if (!wd) return;
-   wd->min_w = w;
-   wd->min_h = h;
-   _sizing_eval(obj);
+   ELM_SCROLLABLE_CHECK(obj);
+
+   s_iface->content_min_limit(obj, w, h);
 }
 
 EAPI void
-elm_scroller_region_show(Evas_Object *obj, Evas_Coord x, Evas_Coord y, Evas_Coord w, Evas_Coord h)
+elm_scroller_region_show(Evas_Object *obj,
+                         Evas_Coord x,
+                         Evas_Coord y,
+                         Evas_Coord w,
+                         Evas_Coord h)
 {
-   ELM_CHECK_WIDTYPE(obj, widtype);
-   Widget_Data *wd = elm_widget_data_get(obj);
-   if ((!wd) || (!wd->scr)) return;
-   elm_smart_scroller_child_region_show(wd->scr, x, y, w, h);
+   ELM_SCROLLABLE_CHECK(obj);
+
+   s_iface->content_region_show(obj, x, y, w, h);
 }
 
 EAPI void
-elm_scroller_policy_set(Evas_Object *obj, Elm_Scroller_Policy policy_h, Elm_Scroller_Policy policy_v)
+elm_scroller_policy_set(Evas_Object *obj,
+                        Elm_Scroller_Policy policy_h,
+                        Elm_Scroller_Policy policy_v)
 {
-   ELM_CHECK_WIDTYPE(obj, widtype);
-   Widget_Data *wd = elm_widget_data_get(obj);
-   if ((!wd) || (!wd->scr)) return;
+   ELM_SCROLLABLE_CHECK(obj);
+
    if ((policy_h >= ELM_SCROLLER_POLICY_LAST) ||
        (policy_v >= ELM_SCROLLER_POLICY_LAST))
      return;
-   elm_smart_scroller_policy_set(wd->scr, policy_h, policy_v);
+
+   s_iface->policy_set(obj, policy_h, policy_v);
 }
 
 EAPI void
-elm_scroller_policy_get(const Evas_Object *obj, Elm_Scroller_Policy *policy_h, Elm_Scroller_Policy *policy_v)
+elm_scroller_policy_get(const Evas_Object *obj,
+                        Elm_Scroller_Policy *policy_h,
+                        Elm_Scroller_Policy *policy_v)
 {
-   ELM_CHECK_WIDTYPE(obj, widtype);
-   Widget_Data *wd = elm_widget_data_get(obj);
-   if ((!wd) || (!wd->scr)) return;
-   elm_smart_scroller_policy_get(wd->scr,
-                                 (Elm_Smart_Scroller_Policy *) policy_h,
-                                 (Elm_Smart_Scroller_Policy *) policy_v);
+   ELM_SCROLLABLE_CHECK(obj);
+
+   s_iface->policy_get(obj, policy_h, policy_v);
 }
 
 EAPI void
-elm_scroller_region_get(const Evas_Object *obj, Evas_Coord *x, Evas_Coord *y, Evas_Coord *w, Evas_Coord *h)
+elm_scroller_region_get(const Evas_Object *obj,
+                        Evas_Coord *x,
+                        Evas_Coord *y,
+                        Evas_Coord *w,
+                        Evas_Coord *h)
 {
-   ELM_CHECK_WIDTYPE(obj, widtype);
-   Widget_Data *wd = elm_widget_data_get(obj);
-   if ((!wd) || (!wd->scr)) return;
-   if ((x) || (y)) elm_smart_scroller_child_pos_get(wd->scr, x, y);
-   if ((w) || (h)) elm_smart_scroller_child_viewport_size_get(wd->scr, w, h);
+   ELM_SCROLLABLE_CHECK(obj);
+
+   if ((x) || (y)) s_iface->content_pos_get(obj, x, y);
+   if ((w) || (h)) s_iface->content_viewport_size_get(obj, w, h);
 }
 
 EAPI void
-elm_scroller_child_size_get(const Evas_Object *obj, Evas_Coord *w, Evas_Coord *h)
+elm_scroller_child_size_get(const Evas_Object *obj,
+                            Evas_Coord *w,
+                            Evas_Coord *h)
 {
-   ELM_CHECK_WIDTYPE(obj, widtype);
-   Widget_Data *wd = elm_widget_data_get(obj);
-   if (!wd) return;
-   evas_object_geometry_get(wd->content, NULL, NULL, w, h);
+   ELM_SCROLLABLE_CHECK(obj);
+
+   s_iface->content_size_get(obj, w, h);
 }
 
 EAPI void
-elm_scroller_bounce_set(Evas_Object *obj, Eina_Bool h_bounce, Eina_Bool v_bounce)
+elm_scroller_bounce_set(Evas_Object *obj,
+                        Eina_Bool h_bounce,
+                        Eina_Bool v_bounce)
 {
-   ELM_CHECK_WIDTYPE(obj, widtype);
-   Widget_Data *wd = elm_widget_data_get(obj);
-   if ((!wd) || (!wd->scr)) return;
-   elm_smart_scroller_bounce_allow_set(wd->scr, h_bounce, v_bounce);
+   ELM_SCROLLABLE_CHECK(obj);
+
+   s_iface->bounce_allow_set(obj, h_bounce, v_bounce);
 }
 
 EAPI void
-elm_scroller_bounce_get(const Evas_Object *obj, Eina_Bool *h_bounce, Eina_Bool *v_bounce)
+elm_scroller_bounce_get(const Evas_Object *obj,
+                        Eina_Bool *h_bounce,
+                        Eina_Bool *v_bounce)
 {
-   ELM_CHECK_WIDTYPE(obj, widtype);
-   Widget_Data *wd = elm_widget_data_get(obj);
-   if (!wd) return;
-   elm_smart_scroller_bounce_allow_get(wd->scr, h_bounce, v_bounce);
+   ELM_SCROLLABLE_CHECK(obj);
+
+   s_iface->bounce_allow_get(obj, h_bounce, v_bounce);
 }
 
 EAPI void
-elm_scroller_page_relative_set(Evas_Object *obj, double h_pagerel, double v_pagerel)
+elm_scroller_page_relative_set(Evas_Object *obj,
+                               double h_pagerel,
+                               double v_pagerel)
 {
-   ELM_CHECK_WIDTYPE(obj, widtype);
-   Widget_Data *wd = elm_widget_data_get(obj);
-   if (!wd) return;
-   wd->pagerel_h = h_pagerel;
-   wd->pagerel_v = v_pagerel;
-   if (wd->scr)
-     elm_smart_scroller_paging_set(wd->scr, wd->pagerel_h, wd->pagerel_v,
-                                   wd->pagesize_h, wd->pagesize_v);
+   Evas_Coord pagesize_h, pagesize_v;
+
+   ELM_SCROLLABLE_CHECK(obj);
+
+   s_iface->paging_get(obj, NULL, NULL, &pagesize_h, &pagesize_v);
+
+   s_iface->paging_set
+     (obj, h_pagerel, v_pagerel, pagesize_h, pagesize_v);
 }
 
 EAPI void
-elm_scroller_page_size_set(Evas_Object *obj, Evas_Coord h_pagesize, Evas_Coord v_pagesize)
+elm_scroller_page_size_set(Evas_Object *obj,
+                           Evas_Coord h_pagesize,
+                           Evas_Coord v_pagesize)
 {
-   ELM_CHECK_WIDTYPE(obj, widtype);
-   Widget_Data *wd = elm_widget_data_get(obj);
-   if (!wd) return;
-   wd->pagesize_h = h_pagesize;
-   wd->pagesize_v = v_pagesize;
-   if (wd->scr)
-     elm_smart_scroller_paging_set(wd->scr, wd->pagerel_h, wd->pagerel_v,
-                                   wd->pagesize_h, wd->pagesize_v);
+   double pagerel_h, pagerel_v;
+
+   ELM_SCROLLABLE_CHECK(obj);
+
+   s_iface->paging_get(obj, &pagerel_h, &pagerel_v, NULL, NULL);
+
+   s_iface->paging_set
+     (obj, pagerel_h, pagerel_v, h_pagesize, v_pagesize);
 }
 
 EAPI void
-elm_scroller_current_page_get(const Evas_Object *obj, int *h_pagenumber, int *v_pagenumber)
+elm_scroller_current_page_get(const Evas_Object *obj,
+                              int *h_pagenumber,
+                              int *v_pagenumber)
 {
-   ELM_CHECK_WIDTYPE(obj, widtype);
-   Widget_Data *wd = elm_widget_data_get(obj);
-   if (!wd) return;
-   if (wd->scr)
-     elm_smart_scroller_current_page_get(wd->scr, h_pagenumber, v_pagenumber);
+   ELM_SCROLLABLE_CHECK(obj);
+
+   s_iface->current_page_get(obj, h_pagenumber, v_pagenumber);
 }
 
 EAPI void
-elm_scroller_last_page_get(const Evas_Object *obj, int *h_pagenumber, int *v_pagenumber)
+elm_scroller_last_page_get(const Evas_Object *obj,
+                           int *h_pagenumber,
+                           int *v_pagenumber)
 {
-   ELM_CHECK_WIDTYPE(obj, widtype);
-   Widget_Data *wd = elm_widget_data_get(obj);
-   if (!wd) return;
-   if (wd->scr)
-     elm_smart_scroller_last_page_get(wd->scr, h_pagenumber, v_pagenumber);
+   ELM_SCROLLABLE_CHECK(obj);
+
+   s_iface->last_page_get(obj, h_pagenumber, v_pagenumber);
 }
 
 EAPI void
-elm_scroller_page_show(Evas_Object *obj, int h_pagenumber, int v_pagenumber)
+elm_scroller_page_show(Evas_Object *obj,
+                       int h_pagenumber,
+                       int v_pagenumber)
 {
-   ELM_CHECK_WIDTYPE(obj, widtype);
-   Widget_Data *wd = elm_widget_data_get(obj);
-   if (!wd) return;
-   if (wd->scr)
-     elm_smart_scroller_page_show(wd->scr, h_pagenumber, v_pagenumber);
+   ELM_SCROLLABLE_CHECK(obj);
+
+   s_iface->page_show(obj, h_pagenumber, v_pagenumber);
 }
 
 EAPI void
-elm_scroller_page_bring_in(Evas_Object *obj, int h_pagenumber, int v_pagenumber)
+elm_scroller_page_bring_in(Evas_Object *obj,
+                           int h_pagenumber,
+                           int v_pagenumber)
 {
-   ELM_CHECK_WIDTYPE(obj, widtype);
-   Widget_Data *wd = elm_widget_data_get(obj);
-   if (!wd) return;
-   if (wd->scr)
-     elm_smart_scroller_page_bring_in(wd->scr, h_pagenumber, v_pagenumber);
+   ELM_SCROLLABLE_CHECK(obj);
+
+   s_iface->page_bring_in(obj, h_pagenumber, v_pagenumber);
 }
 
 EAPI void
-elm_scroller_region_bring_in(Evas_Object *obj, Evas_Coord x, Evas_Coord y, Evas_Coord w, Evas_Coord h)
+elm_scroller_region_bring_in(Evas_Object *obj,
+                             Evas_Coord x,
+                             Evas_Coord y,
+                             Evas_Coord w,
+                             Evas_Coord h)
 {
-   ELM_CHECK_WIDTYPE(obj, widtype);
-   Widget_Data *wd = elm_widget_data_get(obj);
-   if ((!wd) || (!wd->scr)) return;
-   elm_smart_scroller_region_bring_in(wd->scr, x, y, w, h);
+   ELM_SCROLLABLE_CHECK(obj);
+
+   s_iface->region_bring_in(obj, x, y, w, h);
 }
 
 EAPI void
-elm_scroller_propagate_events_set(Evas_Object *obj, Eina_Bool propagation)
+elm_scroller_gravity_set(Evas_Object *obj,
+                         double x,
+                         double y)
 {
-   ELM_CHECK_WIDTYPE(obj, widtype);
-   Widget_Data *wd = elm_widget_data_get(obj);
-   if (!wd) return;
+   ELM_SCROLLABLE_CHECK(obj);
 
-   evas_object_propagate_events_set(wd->scr, propagation);
+   s_iface->gravity_set(obj, x, y);
 }
 
-EAPI Eina_Bool
-elm_scroller_propagate_events_get(const Evas_Object *obj)
+EAPI void
+elm_scroller_gravity_get(const Evas_Object *obj,
+                         double *x,
+                         double *y)
 {
-   ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
-   Widget_Data *wd = elm_widget_data_get(obj);
-   if (!wd) return EINA_FALSE;
+   ELM_SCROLLABLE_CHECK(obj);
 
-   return evas_object_propagate_events_get(wd->scr);
+   s_iface->gravity_get(obj, x, y);
 }
 
 EAPI void
-elm_scroller_gravity_set(Evas_Object *obj, double x, double y)
+elm_scroller_propagate_events_set(Evas_Object *obj,
+                                  Eina_Bool propagation)
 {
-   ELM_CHECK_WIDTYPE(obj, widtype);
-   Widget_Data *wd = elm_widget_data_get(obj);
-   if (!wd) return;
+   Elm_Widget_Smart_Data *sd;
+
+   ELM_SCROLLABLE_CHECK(obj);
 
-   elm_smart_scroller_gravity_set(wd->scr, x, y);
+   sd = evas_object_smart_data_get(obj);
+   if (!sd) return;  /* just being paranoid */
+
+   evas_object_propagate_events_set(sd->resize_obj, propagation);
 }
 
-EAPI void
-elm_scroller_gravity_get(const Evas_Object *obj, double *x, double *y)
+EAPI Eina_Bool
+elm_scroller_propagate_events_get(const Evas_Object *obj)
 {
-   ELM_CHECK_WIDTYPE(obj, widtype);
-   Widget_Data *wd = elm_widget_data_get(obj);
-   if (!wd) return;
+   Elm_Widget_Smart_Data *sd;
+
+   ELM_SCROLLABLE_CHECK(obj, EINA_FALSE);
+
+   sd = evas_object_smart_data_get(obj);
+   if (!sd) return EINA_FALSE;  /* just being paranoid */
 
-   elm_smart_scroller_gravity_get(wd->scr, x, y);
+   return evas_object_propagate_events_get(sd->resize_obj);
 }
index b1ad844..447f2aa 100644 (file)
@@ -2,43 +2,52 @@
  * @defgroup Scroller Scroller
  * @ingroup Elementary
  *
- * A scroller holds a single object and "scrolls it around". This means that
- * it allows the user to use a scrollbar (or a finger) to drag the viewable
- * region around, allowing to move through a much larger object that is
- * contained in the scroller. The scroller will always have a small minimum
- * size by default as it won't be limited by the contents of the scroller.
- *
- * Signals that you can add callbacks for are:
- * @li "edge,left" - the left edge of the content has been reached
- * @li "edge,right" - the right edge of the content has been reached
- * @li "edge,top" - the top edge of the content has been reached
- * @li "edge,bottom" - the bottom edge of the content has been reached
- * @li "scroll" - the content has been scrolled (moved)
- * @li "scroll,anim,start" - scrolling animation has started
- * @li "scroll,anim,stop" - scrolling animation has stopped
- * @li "scroll,drag,start" - dragging the contents around has started
- * @li "scroll,drag,stop" - dragging the contents around has stopped
- * @note The "scroll,anim,*" and "scroll,drag,*" signals are only emitted by
- * user intervention.
- *
- * @note When Elementary is in embedded mode the scrollbars will not be
- * draggable, they appear merely as indicators of how much has been scrolled.
- * @note When Elementary is in desktop mode the thumbscroll(a.k.a.
- * fingerscroll) won't work.
- *
- * Default content parts of the scroller widget that you can use for are:
- * @li "default" - A content of the scroller
- *
- * Supported elm_object common APIs.
- * @li @ref elm_object_signal_emit
- * @li @ref elm_object_signal_callback_add
- * @li @ref elm_object_signal_callback_del
- * @li @ref elm_object_part_content_set
- * @li @ref elm_object_part_content_get
- * @li @ref elm_object_part_content_unset
- *
- * In @ref tutorial_scroller you'll find an example of how to use most of
- * this API.
+ * @image html scroller_inheritance_tree.png
+ * @image latex scroller_inheritance_tree.eps
+ *
+ * A scroller holds (and clips) a single object and "scrolls it
+ * around". This means that it allows the user to use a scroll bar (or
+ * a finger) to drag the viewable region around, moving through a much
+ * larger object that is contained in the scroller. The scroller will
+ * always have a small minimum size by default as it won't be limited
+ * by the contents of the scroller.
+ *
+ * This widget inherits from the @ref Layout one, so that all the
+ * functions acting on it also work for scroller objects.
+ *
+ * This widget emits the following signals, besides the ones sent from
+ * @li @c "edge,left" - the left edge of the content has been reached
+ * @li @c "edge,right" - the right edge of the content has been reached
+ * @li @c "edge,top" - the top edge of the content has been reached
+ * @li @c "edge,bottom" - the bottom edge of the content has been reached
+ * @li @c "scroll" - the content has been scrolled (moved)
+ * @li @c "scroll,anim,start" - scrolling animation has started
+ * @li @c "scroll,anim,stop" - scrolling animation has stopped
+ * @li @c "scroll,drag,start" - dragging the contents around has started
+ * @li @c "scroll,drag,stop" - dragging the contents around has stopped
+ *
+ * This widget implements the @ref elm-scrollable-interface interface.
+ * Its (non-deprecated) API functions, except for elm_scroller_add(),
+ * which gives basic scroller objects, are meant to be a basis for all
+ * other scrollable widgets (i.e. widgets implementing @ref
+ * elm-scrollable-interface). So, they will work both on pristine
+ * scroller widgets and on other "specialized" scrollable widgets.
+ *
+ * @note The @c "scroll,anim,*" and @c "scroll,drag,*" signals are
+ * only emitted by user intervention.
+ *
+ * @note When Elementary is under its default profile and theme (meant
+ * for touch interfaces), scroll bars will @b not be draggable --
+ * their function is merely to indicate how much has been scrolled.
+ *
+ * @note When Elementary is under its desktop/standard profile and
+ * theme, the thumb scroll (a.k.a. finger scroll) won't work.
+ *
+ * Default content parts of the scroller widget that you can use are:
+ * @li @c "default" - Content of the scroller
+ *
+ * In @ref tutorial_scroller you'll find an example on how to use most
+ * of this API.
  * @{
  */
 
@@ -72,9 +81,11 @@ EAPI Evas_Object                 *elm_scroller_add(Evas_Object *parent);
  * @param widget The widget name to use (default is "scroller")
  * @param base The base name to use (default is "base")
  *
+ * @deprecated Use elm_layout_theme_set() instead.
+ *
  * @ingroup Scroller
  */
-EAPI void                         elm_scroller_custom_widget_base_theme_set(Evas_Object *obj, const char *widget, const char *base);
+EINA_DEPRECATED EAPI void         elm_scroller_custom_widget_base_theme_set(Evas_Object *obj, const char *widget, const char *base);
 
 /**
  * @brief Make the scroller minimum size limited to the minimum size of the content
@@ -359,8 +370,9 @@ EAPI void                         elm_scroller_region_bring_in(Evas_Object *obj,
  * @param obj The scroller object
  * @param propagation If propagation is enabled or not
  *
- * This enables or disabled event propagation from the scroller content to
- * the scroller and its parent. By default event propagation is disabled.
+ * This enables or disables event propagation from the scroller
+ * content to the scroller and its parent. By default event
+ * propagation is @b enabled.
  *
  * @ingroup Scroller
  */