efl_ui_pager: Add Efl.Ui.Pager class and related classes

Efl.Ui.Pager is a widget which contains many pages in a linear fashion
and allows users to scroll through them.
Users can attach Efl.Page.Transition and Efl.Page.Indicator to a pager.
This commit is contained in:
Jaeun Choi 2018-04-23 18:43:11 +09:00
parent ea84f4450c
commit e74ebca670
21 changed files with 2242 additions and 2 deletions

View File

@ -1040,7 +1040,8 @@ elementary/themes/edc/efl/textpath.edc \
elementary/themes/edc/efl/tooltip.edc \
elementary/themes/edc/efl/video.edc \
elementary/themes/edc/efl/list.edc \
elementary/themes/edc/efl/win.edc
elementary/themes/edc/efl/win.edc \
elementary/themes/edc/efl/pager.edc
elementary_fdo_actions_128_files = \
elementary/themes/fdo/actions/128/address-book-new.png \

View File

@ -196,4 +196,5 @@ collections {
#include "edc/efl/textpath.edc"
#include "edc/efl/win.edc"
#include "edc/efl/uiclock.edc"
#include "edc/efl/pager.edc"
}

View File

@ -0,0 +1,66 @@
group { "efl/pager";
parts {
spacer { "base";
scale;
desc { "default";
}
}
swallow { "elm.swallow.background";
scale;
desc { "default";
}
}
swallow { "page_root";
scale;
desc { "default";
rel1.relative: 0.0 1.0;
rel1.to: "indicator";
}
}
swallow { "indicator";
scale;
desc { "default";
rel2.relative: 1.0 0.0;
align: 0.5 0.0;
min: 0 50;
}
}
swallow { "event";
scale;
repeat_events: 1;
desc { "default";
}
}
}
}
group { "efl/pager/indicator";
images {
image: "ring_white_middle.png" COMP;
}
parts {
spacer { "base";
scale;
desc { "default";
}
}
image { "icon";
scale;
desc { "default";
image.normal: "ring_white_middle.png";
color: 0 0 0 255;
min: 6 6;
}
desc { "selected";
inherit: "default";
color: 255 0 0 255;
}
}
}
script {
public message(Msg_Type:type, id, ...) {
set_tween_state(PART:"icon", getfarg(2),
"default", 0.0, "selected", 0.0);
}
}
}

View File

@ -105,6 +105,11 @@ elm_public_eolian_files = \
lib/elementary/efl_ui_dnd.eo \
lib/elementary/efl_ui_dnd_container.eo \
lib/elementary/efl_ui_focus_manager_window_root.eo \
lib/elementary/efl_ui_pager.eo \
lib/elementary/efl_page_transition.eo \
lib/elementary/efl_page_transition_scroll.eo \
lib/elementary/efl_page_indicator.eo \
lib/elementary/efl_page_indicator_icon.eo \
$(NULL)
# More public files -- FIXME
@ -400,7 +405,12 @@ includesunstable_HEADERS = \
lib/elementary/efl_ui_widget_scroll_manager.h \
lib/elementary/efl_ui_widget_pan.h \
lib/elementary/efl_ui_nstate_private.h \
lib/elementary/Efl_Ui.h
lib/elementary/Efl_Ui.h \
lib/elementary/efl_ui_widget_pager.h \
lib/elementary/efl_page_transition.h \
lib/elementary/efl_page_transition_scroll.h \
lib/elementary/efl_page_indicator.h \
lib/elementary/efl_page_indicator_icon.h
includesunstabledir = $(includedir)/elementary-@VMAJ@
nodist_includesunstable_HEADERS = \
@ -805,6 +815,11 @@ lib_elementary_libelementary_la_SOURCES = \
lib/elementary/efl_ui_dnd.c \
static_libs/buildsystem/buildsystem.h \
static_libs/buildsystem/buildsystem_autotools.c \
lib/elementary/efl_ui_pager.c \
lib/elementary/efl_page_transition.c \
lib/elementary/efl_page_transition_scroll.c \
lib/elementary/efl_page_indicator.c \
lib/elementary/efl_page_indicator_icon.c \
$(NULL)

View File

@ -341,6 +341,17 @@ typedef Eo Efl_Ui_Focus_Manager;
# include <efl_ui_navigation_bar_part_back_button.eo.h>
# include <efl_ui_navigation_layout.eo.h>
# include <efl_ui_stack.eo.h>
# ifndef _EFL_UI_PAGER_EO_CLASS_TYPE
# define _EFL_UI_PAGER_EO_CLASS_TYPE
typedef Eo Efl_Ui_Pager;
# endif
# include <efl_page_transition.eo.h>
# include <efl_page_transition_scroll.eo.h>
# include <efl_page_indicator.eo.h>
# include <efl_page_indicator_icon.eo.h>
# include <efl_ui_pager.eo.h>
#endif
/* include deprecated calls last of all */

View File

@ -0,0 +1,58 @@
#ifdef HAVE_CONFIG_H
# include "elementary_config.h"
#endif
#include <Elementary.h>
#include "elm_priv.h"
#include "efl_page_indicator.h"
#include "efl_ui_widget_pager.h"
#define MY_CLASS EFL_PAGE_INDICATOR_CLASS
EOLIAN static void
_efl_page_indicator_update(Eo *obj EINA_UNUSED,
Efl_Page_Indicator_Data *pd EINA_UNUSED,
double pos EINA_UNUSED)
{
}
EOLIAN static void
_efl_page_indicator_pack(Eo *obj EINA_UNUSED,
Efl_Page_Indicator_Data *pd,
int index EINA_UNUSED)
{
pd->cnt++;
}
EOLIAN static void
_efl_page_indicator_bind(Eo *obj EINA_UNUSED,
Efl_Page_Indicator_Data *pd,
Eo *pager,
Efl_Canvas_Group *idbox)
{
if (pd->pager.obj == pager) return;
pd->pager.obj = pager;
pd->idbox = idbox;
if (pager)
pd->cnt = efl_content_count(pd->pager.obj);
}
EOAPI EFL_VOID_FUNC_BODYV(efl_page_indicator_update,
EFL_FUNC_CALL(pos), double pos)
EOAPI EFL_VOID_FUNC_BODYV(efl_page_indicator_pack,
EFL_FUNC_CALL(index), int index)
#define EFL_PAGE_INDICATOR_EXTRA_OPS \
EFL_OBJECT_OP_FUNC(efl_page_indicator_update, \
_efl_page_indicator_update), \
EFL_OBJECT_OP_FUNC(efl_page_indicator_pack, \
_efl_page_indicator_pack)
#include "efl_page_indicator.eo.c"

View File

@ -0,0 +1,18 @@
class Efl.Page.Indicator (Efl.Object)
{
[[Page indicator
Page indicator is used with @Efl.Ui.Pager.
It is located on the top layer of pager widget and helps users to know
the number of pages and the current page's index without scrolling.
]]
methods {
bind {
[[set object]]
params {
@in pager: Efl.Ui.Pager; [[pager object]]
@in group: Efl.Canvas.Group; [[a dummy object for layer adjustment]]
}
}
}
}

View File

@ -0,0 +1,23 @@
#ifndef EFL_PAGE_INDICATOR_H
#define EFL_PAGE_INDICATOR_H
typedef struct _Efl_Page_Indicator_Data Efl_Page_Indicator_Data;
struct _Efl_Page_Indicator_Data
{
struct {
Efl_Object *obj;
Efl_Object *group;
Evas_Coord x, y, w, h;
} pager;
Efl_Ui_Box *idbox;
int cnt;
};
#define EFL_PAGE_INDICATOR_DATA_GET(o, pd) \
Efl_Page_Indicator_Data *pd = \
efl_data_scope_get(o, EFL_PAGE_INDICATOR_CLASS)
#endif

View File

@ -0,0 +1,152 @@
#ifdef HAVE_CONFIG_H
# include "elementary_config.h"
#endif
#include <Elementary.h>
#include "elm_priv.h"
#include "efl_page_indicator_icon.h"
#include "efl_page_indicator.h"
#include "efl_ui_widget_pager.h"
#define MY_CLASS EFL_PAGE_INDICATOR_ICON_CLASS
EOLIAN static void
_efl_page_indicator_icon_update(Eo *obj,
Efl_Page_Indicator_Icon_Data *pd,
double pos)
{
EFL_PAGE_INDICATOR_DATA_GET(obj, spd);
Eo *item;
int page = efl_ui_pager_current_page_get(spd->pager.obj);
double delta = fabs(pos);
if (pd->curr)
{
eina_value_set(pd->v, 0.0);
efl_layout_signal_message_send(pd->curr, 1, *(pd->v));
if (pd->adj) efl_layout_signal_message_send(pd->adj, 1, *(pd->v));
}
item = eina_list_nth(pd->items, page);
eina_value_set(pd->v, (1.0 - delta));
efl_layout_signal_message_send(item, 1, *(pd->v));
pd->curr = item;
if (pos < 0)
item = eina_list_nth(pd->items, (page - 1 + spd->cnt) % spd->cnt);
else
item = eina_list_nth(pd->items, (page + 1 + spd->cnt) % spd->cnt);
eina_value_set(pd->v, delta);
efl_layout_signal_message_send(item, 1, *(pd->v));
pd->adj = item;
}
EOLIAN static void
_efl_page_indicator_icon_pack(Eo *obj,
Efl_Page_Indicator_Icon_Data *pd,
int index)
{
EFL_PAGE_INDICATOR_DATA_GET(obj, spd);
Eo *item, *existing;
efl_page_indicator_pack(efl_super(obj, MY_CLASS), index);
item = efl_add(EFL_CANVAS_LAYOUT_CLASS, spd->idbox);
elm_widget_theme_object_set(spd->idbox, item,
"pager", "indicator", "default");
efl_gfx_size_hint_align_set(item, 0.5, 0.5);
efl_gfx_size_hint_weight_set(item, 0, 0);
if (index == 0)
{
pd->items = eina_list_prepend(pd->items, item);
efl_pack_begin(spd->idbox, item);
}
else if (index == (spd->cnt - 1))
{
pd->items = eina_list_append(pd->items, item);
efl_pack_end(spd->idbox, item);
}
else
{
existing = eina_list_nth(pd->items, index);
pd->items = eina_list_prepend_relative(pd->items, item, existing);
efl_pack_before(spd->idbox, item, existing);
}
}
EOLIAN static void
_efl_page_indicator_icon_efl_page_indicator_bind(Eo *obj,
Efl_Page_Indicator_Icon_Data *pd,
Eo *pager,
Efl_Canvas_Group *idbox)
{
EFL_PAGE_INDICATOR_DATA_GET(obj, spd);
Eo *item;
int i, page;
if (spd->pager.obj)
{
EINA_LIST_FREE(pd->items, item)
{
efl_del(item);
}
}
efl_page_indicator_bind(efl_super(obj, MY_CLASS), pager, idbox);
if (spd->pager.obj)
{
efl_ui_direction_set(spd->idbox, EFL_UI_DIR_HORIZONTAL);
efl_pack_padding_set(spd->idbox, 15, 15, EINA_TRUE);
pd->v = eina_value_float_new(0.0);
if (spd->cnt != 0)
{
for (i = 0; i < spd->cnt; i++)
{
item = efl_add(EFL_CANVAS_LAYOUT_CLASS, spd->idbox);
pd->items = eina_list_append(pd->items, item);
elm_widget_theme_object_set(spd->idbox, item,
"pager", "indicator", "default");
efl_gfx_size_hint_align_set(item, 0.5, 0.5);
efl_gfx_size_hint_weight_set(item, 0, 0);
efl_pack_end(spd->idbox, item);
}
page = efl_ui_pager_current_page_get(spd->pager.obj);
item = eina_list_nth(pd->items, page);
eina_value_set(pd->v, 1.0);
efl_layout_signal_message_send(item, 1, *(pd->v));
pd->curr = item;
}
}
}
EOLIAN static void
_efl_page_indicator_icon_efl_object_invalidate(Eo *obj,
Efl_Page_Indicator_Icon_Data *pd)
{
Eo *item;
EINA_LIST_FREE(pd->items, item)
efl_del(item);
efl_invalidate(efl_super(obj, MY_CLASS));
}
#define EFL_PAGE_INDICATOR_ICON_EXTRA_OPS \
EFL_OBJECT_OP_FUNC(efl_page_indicator_update, \
_efl_page_indicator_icon_update), \
EFL_OBJECT_OP_FUNC(efl_page_indicator_pack, \
_efl_page_indicator_icon_pack)
#include "efl_page_indicator_icon.eo.c"

View File

@ -0,0 +1,13 @@
class Efl.Page.Indicator.Icon (Efl.Page.Indicator)
{
[[Icon type page indicator
This class offers icon type indicator for @Efl.Ui.Pager.
This type of page indicator creates the same number of icons as pages and
arrange them in a linear order. An icon has two states: default and selected.
]]
implements {
Efl.Object.invalidate;
Efl.Page.Indicator.bind;
}
}

View File

@ -0,0 +1,19 @@
#ifndef EFL_PAGE_INDICATOR_ICON_H
#define EFL_PAGE_INDICATOR_ICON_H
typedef struct _Efl_Page_Indicator_Icon_Data Efl_Page_Indicator_Icon_Data;
struct _Efl_Page_Indicator_Icon_Data
{
Eo *curr, *adj;
Eina_List *items;
Eina_Value *v;
};
#define EFL_PAGE_INDICATOR_ICON_DATA_GET(o, pd) \
Efl_Page_Indicator_Icon_Data *pd = \
efl_data_scope_get(o, EFL_PAGE_INDICATOR_ICON_CLASS)
#endif

View File

@ -0,0 +1,107 @@
#ifdef HAVE_CONFIG_H
# include "elementary_config.h"
#endif
#include <Elementary.h>
#include "elm_priv.h"
#include "efl_page_transition.h"
#include "efl_ui_widget_pager.h"
#define MY_CLASS EFL_PAGE_TRANSITION_CLASS
EOLIAN static void
_efl_page_transition_page_size_set(Eo *obj EINA_UNUSED,
Efl_Page_Transition_Data *pd,
Eina_Size2D sz)
{
pd->page_spec.sz = sz;
}
EOLIAN static void
_efl_page_transition_padding_size_set(Eo *obj EINA_UNUSED,
Efl_Page_Transition_Data *pd,
int padding)
{
pd->page_spec.padding = padding;
}
EOLIAN static void
_efl_page_transition_bind(Eo *obj EINA_UNUSED,
Efl_Page_Transition_Data *pd,
Eo *pager,
Efl_Canvas_Group *group)
{
Eina_Rect group_rect;
if (pd->pager.obj == pager) return;
pd->pager.obj = pager;
pd->pager.group = group;
if (pager)
{
group_rect = efl_gfx_geometry_get(group);
pd->pager.x = group_rect.x;
pd->pager.y = group_rect.y;
pd->pager.w = group_rect.w;
pd->pager.h = group_rect.h;
pd->page_spec.sz = efl_ui_pager_page_size_get(pager);
pd->page_spec.padding = efl_ui_pager_padding_get(pager);
pd->loop = efl_ui_pager_loop_mode_get(pager);
}
}
EOLIAN static void
_efl_page_transition_update(Eo *obj EINA_UNUSED,
Efl_Page_Transition_Data *pd EINA_UNUSED,
double move EINA_UNUSED)
{
}
EOLIAN static void
_efl_page_transition_curr_page_change(Eo *obj EINA_UNUSED,
Efl_Page_Transition_Data *pd EINA_UNUSED,
int diff EINA_UNUSED)
{
}
EOLIAN static void
_efl_page_transition_loop_set(Eo *obj EINA_UNUSED,
Efl_Page_Transition_Data *pd,
Efl_Ui_Pager_Loop loop)
{
pd->loop = loop;
}
EOAPI EFL_VOID_FUNC_BODYV(efl_page_transition_update,
EFL_FUNC_CALL(move), double move)
EOAPI EFL_VOID_FUNC_BODYV(efl_page_transition_curr_page_change,
EFL_FUNC_CALL(move), double move)
EOAPI EFL_VOID_FUNC_BODYV(efl_page_transition_page_size_set,
EFL_FUNC_CALL(sz), Eina_Size2D sz)
EOAPI EFL_VOID_FUNC_BODYV(efl_page_transition_padding_size_set,
EFL_FUNC_CALL(padding), int padding)
EOAPI EFL_VOID_FUNC_BODYV(efl_page_transition_loop_set,
EFL_FUNC_CALL(loop), Efl_Ui_Pager_Loop loop)
#define EFL_PAGE_TRANSITION_EXTRA_OPS \
EFL_OBJECT_OP_FUNC(efl_page_transition_update, \
_efl_page_transition_update), \
EFL_OBJECT_OP_FUNC(efl_page_transition_curr_page_change, \
_efl_page_transition_curr_page_change), \
EFL_OBJECT_OP_FUNC(efl_page_transition_page_size_set, \
_efl_page_transition_page_size_set), \
EFL_OBJECT_OP_FUNC(efl_page_transition_padding_size_set, \
_efl_page_transition_padding_size_set), \
EFL_OBJECT_OP_FUNC(efl_page_transition_loop_set, \
_efl_page_transition_loop_set)
#include "efl_page_transition.eo.c"

View File

@ -0,0 +1,17 @@
class Efl.Page.Transition (Efl.Object)
{
[[Page transition for @Efl.Ui.Pager
A page transition is essential to @Efl.Ui.Pager object and invoked whenever
pages are rearranged or scrolled (see @Efl.Ui.Pager).
]]
methods {
bind {
[[set object]]
params {
@in pager: Efl.Ui.Pager; [[pager object]]
@in group: Efl.Canvas.Group; [[a dummy object for layer adjustment]]
}
}
}
}

View File

@ -0,0 +1,27 @@
#ifndef EFL_PAGE_TRANSITION_H
#define EFL_PAGE_TRANSITION_H
typedef struct _Efl_Page_Transition_Data Efl_Page_Transition_Data;
struct _Efl_Page_Transition_Data
{
struct {
Efl_Object *obj;
Efl_Canvas_Group *group;
Evas_Coord x, y, w, h;
} pager;
struct {
Eina_Size2D sz;
Evas_Coord padding;
} page_spec;
Efl_Ui_Pager_Loop loop;
};
#define EFL_PAGE_TRANSITION_DATA_GET(o, pd) \
Efl_Page_Transition_Data *pd = \
efl_data_scope_get(o, EFL_PAGE_TRANSITION_CLASS)
#endif

View File

@ -0,0 +1,606 @@
#ifdef HAVE_CONFIG_H
# include "elementary_config.h"
#endif
#include <Elementary.h>
#include "elm_priv.h"
#include "efl_page_transition_scroll.h"
#include "efl_page_transition.h"
#include "efl_ui_widget_pager.h"
#define MY_CLASS EFL_PAGE_TRANSITION_SCROLL_CLASS
static void
_page_info_deallocate(Efl_Page_Transition_Scroll_Data *pd)
{
Page_Info *pi;
EINA_LIST_FREE(pd->page_infos, pi)
{
if (pi->content)
efl_pack_unpack(pi->obj, pi->content);
efl_del(pi->obj);
free(pi);
}
pd->head = NULL;
pd->tail = NULL;
}
static void
_page_info_allocate(Efl_Page_Transition_Scroll_Data *pd,
Efl_Page_Transition_Data *spd)
{
Page_Info *pi, *prev = NULL;
int i;
for (i = 0; i < pd->page_info_num; i++)
{
pi = calloc(1, sizeof(*pi));
if (i == 0) pd->head = pi;
else if (i == (pd->page_info_num - 1)) pd->tail = pi;
pi->id = i;
pi->pos = i - (pd->side_page_num + 1);
pi->content_num = -1;
pi->content = NULL;
pi->obj = efl_add(EFL_UI_BOX_CLASS, spd->pager.obj);
efl_canvas_group_member_add(spd->pager.group, pi->obj);
pd->page_infos = eina_list_append(pd->page_infos, pi);
if (prev)
{
pi->prev = prev;
prev->next = pi;
}
prev = pi;
}
pd->head->prev = pd->tail;
pd->tail->next = pd->head;
}
static void
_content_show(Efl_Page_Transition_Scroll_Data *pd,
Efl_Page_Transition_Data *spd)
{
Eina_List *list;
Page_Info *pi;
int tmp_id;
Eo *tmp;
int curr_page, cnt;
curr_page = efl_ui_pager_current_page_get(spd->pager.obj);
cnt = efl_content_count(spd->pager.obj);
// at this point, the number of visible pages might have been changed,
// so empty all boxes and refill them with the right contents.
// FIXME make logic efficient: don't have to empty all and fill all the time
EINA_LIST_FOREACH(pd->page_infos, list, pi)
{
if (pi->content)
{
efl_pack_unpack(pi->obj, pi->content);
efl_canvas_object_clip_set(pi->content, pd->backclip);
pi->content_num = -1;
pi->content = NULL;
pi->visible = EINA_FALSE;
}
efl_canvas_object_clip_set(pi->obj, pd->backclip);
}
EINA_LIST_FOREACH(pd->page_infos, list, pi)
{
if (pi->vis_page)
{
tmp_id = (curr_page + pi->pos + cnt) % cnt;
if ((spd->loop == EFL_UI_PAGER_LOOP_DISABLED)
&& ((pi->pos) * (tmp_id - curr_page) < 0)) continue;
tmp = efl_pack_content_get(spd->pager.obj, tmp_id);
if (tmp)
{
efl_canvas_object_clip_set(pi->obj, pd->foreclip);
efl_pack(pi->obj, tmp);
efl_canvas_object_clip_set(tmp, pd->foreclip);
pi->content_num = tmp_id;
pi->content = tmp;
pi->visible = EINA_TRUE;
}
}
}
}
//FIXME use ecore_job
static void
_page_info_geometry_change(Efl_Page_Transition_Scroll_Data *pd,
Efl_Page_Transition_Data *spd)
{
Eina_List *list;
Page_Info *pi;
int content_w;
content_w = spd->page_spec.sz.w
+ ((spd->page_spec.sz.w + spd->page_spec.padding) * pd->side_page_num * 2);
if (content_w < spd->pager.w)
{
EINA_RECTANGLE_SET(&pd->viewport,
spd->pager.x + ((spd->pager.w - content_w) / 2),
spd->pager.y,
content_w,
spd->pager.h);
}
else
{
EINA_RECTANGLE_SET(&pd->viewport,
spd->pager.x,
spd->pager.y,
spd->pager.w,
spd->pager.h);
}
efl_gfx_geometry_set(pd->foreclip, (Eina_Rect) pd->viewport);
// this loop resets the geometry of each page based on the geometry of
// the pager object, the page size, and the padding size.
EINA_LIST_FOREACH(pd->page_infos, list, pi)
{
EINA_RECTANGLE_SET(&pi->geometry,
spd->pager.x + (spd->pager.w / 2)
+ pi->pos * (spd->page_spec.sz.w + spd->page_spec.padding)
- (spd->page_spec.sz.w / 2),
spd->pager.y + (spd->pager.h / 2) - (spd->page_spec.sz.h / 2),
spd->page_spec.sz.w,
spd->page_spec.sz.h);
if (eina_rectangles_intersect(&pi->geometry, &pd->viewport) &&
((pi->id != 0) && (pi->id != (pd->page_info_num - 1))))
{
pi->vis_page = EINA_TRUE;
pi->visible = EINA_TRUE;
efl_canvas_object_clip_set(pi->obj, pd->foreclip);
}
else
{
pi->vis_page = EINA_FALSE;
pi->visible = EINA_FALSE;
efl_canvas_object_clip_set(pi->obj, pd->backclip);
}
efl_gfx_geometry_set(pi->obj, (Eina_Rect) pi->geometry);
}
if (efl_content_count(spd->pager.obj) > 0) _content_show(pd, spd);
}
static void
_resize_cb(void *data, const Efl_Event *ev)
{
Efl_Page_Transition_Scroll *obj = data;
EFL_PAGE_TRANSITION_SCROLL_DATA_GET(obj, pd);
EFL_PAGE_TRANSITION_DATA_GET(obj, spd);
Eina_Size2D sz;
Efl_Ui_Pager *pager = ev->object;
sz = efl_gfx_size_get(pager);
spd->pager.w = sz.w;
spd->pager.h = sz.h;
_page_info_geometry_change(pd, spd);
}
static void
_move_cb(void *data, const Efl_Event *ev)
{
Efl_Page_Transition_Scroll *obj = data;
EFL_PAGE_TRANSITION_SCROLL_DATA_GET(obj, pd);
EFL_PAGE_TRANSITION_DATA_GET(obj, spd);
Eina_Position2D pos;
Efl_Ui_Pager *pager = ev->object;
pos = efl_gfx_position_get(pager);
spd->pager.x = pos.x;
spd->pager.y = pos.y;
_page_info_geometry_change(pd, spd);
}
EOLIAN static void
_efl_page_transition_scroll_efl_page_transition_bind(Eo *obj,
Efl_Page_Transition_Scroll_Data *pd,
Eo *pager,
Efl_Canvas_Group *group)
{
EFL_PAGE_TRANSITION_DATA_GET(obj, spd);
if (spd->pager.obj == pager) return;
if (spd->pager.obj)
{
efl_event_callback_del(spd->pager.group, EFL_GFX_EVENT_RESIZE, _resize_cb, obj);
efl_event_callback_del(spd->pager.group, EFL_GFX_EVENT_MOVE, _move_cb, obj);
_page_info_deallocate(pd);
efl_del(pd->foreclip);
efl_del(pd->backclip);
}
efl_page_transition_bind(efl_super(obj, MY_CLASS), pager, group);
if (spd->pager.obj)
{
int cnt, i;
Eo *item;
efl_event_callback_add(spd->pager.group, EFL_GFX_EVENT_RESIZE, _resize_cb, obj);
efl_event_callback_add(spd->pager.group, EFL_GFX_EVENT_MOVE, _move_cb, obj);
pd->foreclip = efl_add(EFL_CANVAS_RECTANGLE_CLASS,
evas_object_evas_get(spd->pager.obj));
evas_object_static_clip_set(pd->foreclip, EINA_TRUE);
pd->backclip = efl_add(EFL_CANVAS_RECTANGLE_CLASS,
evas_object_evas_get(spd->pager.obj));
evas_object_static_clip_set(pd->backclip, EINA_TRUE);
efl_gfx_visible_set(pd->backclip, EINA_FALSE);
cnt = efl_content_count(spd->pager.obj);
for (i = 0; i < cnt; i++)
{
item = efl_pack_content_get(spd->pager.obj, i);
efl_canvas_object_clip_set(item, pd->backclip);
}
_page_info_allocate(pd, spd);
_page_info_geometry_change(pd, spd);
}
}
EOLIAN static void
_efl_page_transition_scroll_page_size_set(Eo *obj,
Efl_Page_Transition_Scroll_Data *pd,
Eina_Size2D sz)
{
EFL_PAGE_TRANSITION_DATA_GET(obj, spd);
efl_page_transition_page_size_set(efl_super(obj, MY_CLASS), sz);
_page_info_geometry_change(pd, spd);
}
EOLIAN static void
_efl_page_transition_scroll_padding_size_set(Eo *obj,
Efl_Page_Transition_Scroll_Data *pd,
int padding)
{
EFL_PAGE_TRANSITION_DATA_GET(obj, spd);
efl_page_transition_padding_size_set(efl_super(obj, MY_CLASS), padding);
_page_info_geometry_change(pd, spd);
}
EOLIAN static void
_efl_page_transition_scroll_update(Eo *obj,
Efl_Page_Transition_Scroll_Data *pd,
double pos)
{
EFL_PAGE_TRANSITION_DATA_GET(obj, spd);
double t;
int tmp_id, curr_page, cnt;
Eo *tmp;
Eina_List *list;
Page_Info *pi, *tpi;
t = pos;
if (t < 0) t *= (-1);
curr_page = efl_ui_pager_current_page_get(spd->pager.obj);
cnt = efl_content_count(spd->pager.obj);
// while pages are scrolled,
// 1. the geometry of each page needs to be changed
// 2. if a page gets out of the viewport, it needs to be hidden
// 3. if a page gets into the viewport, it needs to be shown
EINA_LIST_FOREACH(pd->page_infos, list, pi)
{
if (pos < 0) // if scrolled right, each page takes next page's position
tpi = pi->next;
else // else if scrolled left, each page takes prev page's position
tpi = pi->prev;
EINA_RECTANGLE_SET(&pi->temp,
tpi->geometry.x * t + pi->geometry.x * (1 - t),
tpi->geometry.y,
tpi->geometry.w,
tpi->geometry.h);
efl_gfx_geometry_set(pi->obj, (Eina_Rect) pi->temp);
if (!pi->vis_page && !tpi->vis_page) continue;
if (!eina_rectangles_intersect(&pi->temp, &pd->viewport))
{
if (pi->content)
{
efl_canvas_object_clip_set(pi->obj, pd->backclip);
efl_pack_unpack(pi->obj, pi->content);
efl_canvas_object_clip_set(pi->content, pd->backclip);
pi->content_num = -1;
pi->content = NULL;
pi->visible = EINA_FALSE;
}
}
else
{
tmp_id = (curr_page + pi->pos + cnt) % cnt;
if (pi->content_num != tmp_id)
{
if (pi->content) //FIXME if the content num is the same, do nothing
{
efl_pack_unpack(pi->obj, pi->content);
efl_canvas_object_clip_set(pi->content, pd->backclip);
pi->content_num = -1;
pi->content = NULL;
}
if ((spd->loop == EFL_UI_PAGER_LOOP_DISABLED)
&& ((pi->pos) * (tmp_id - curr_page) < 0)) continue;
tmp = efl_pack_content_get(spd->pager.obj, tmp_id);
if (tmp)
{
efl_canvas_object_clip_set(pi->obj, pd->foreclip);
efl_pack(pi->obj, tmp);
efl_canvas_object_clip_set(tmp, pd->foreclip);
pi->content_num = tmp_id;
pi->content = tmp;
pi->visible = EINA_TRUE;
}
}
}
}
}
EOLIAN static void
_efl_page_transition_scroll_curr_page_change(Eo *obj EINA_UNUSED,
Efl_Page_Transition_Scroll_Data *pd,
double pos)
{
Eina_List *list;
Page_Info *pi, *target;
// after the current page is changed, page infos need to be updated
// with a new id based on the new geometry of the boxes.
EINA_LIST_FOREACH(pd->page_infos, list, pi)
{
if (EINA_DBL_EQ(pos, 1.0))
{
pi->id = (pi->id - 1 + pd->page_info_num) % pd->page_info_num;
target = pi->prev;
}
else if (EINA_DBL_EQ(pos, -1.0))
{
pi->id = (pi->id + 1) % pd->page_info_num;
target = pi->next;
}
pi->pos = pi->id - (pd->side_page_num + 1);
EINA_RECTANGLE_SET(&pi->temp,
target->geometry.x,
target->geometry.y,
target->geometry.w,
target->geometry.h);
if (eina_rectangles_intersect(&pi->temp, &pd->viewport) &&
(pi->id != 0) && (pi->id != (pd->page_info_num - 1)))
{
pi->vis_page = EINA_TRUE;
pi->visible = EINA_TRUE;
efl_canvas_object_clip_set(pi->obj, pd->foreclip);
}
else
{
pi->vis_page = EINA_FALSE;
pi->visible = EINA_FALSE;
efl_canvas_object_clip_set(pi->obj, pd->backclip);
if (pi->content)
{
efl_pack_unpack(pi->obj, pi->content);
efl_canvas_object_clip_set(pi->content, pd->backclip);
}
}
}
if (EINA_DBL_EQ(pos, 1.0))
{
pd->head = pd->head->next;
pd->tail = pd->tail->next;
}
else if (EINA_DBL_EQ(pos, -1.0))
{
pd->head = pd->head->prev;
pd->tail = pd->tail->prev;
}
EINA_LIST_FOREACH(pd->page_infos, list, pi)
{
EINA_RECTANGLE_SET(&pi->geometry,
pi->temp.x,
pi->temp.y,
pi->temp.w,
pi->temp.h);
}
}
EOLIAN static int
_efl_page_transition_scroll_side_page_num_get(const Eo *obj EINA_UNUSED,
Efl_Page_Transition_Scroll_Data *pd)
{
return pd->side_page_num;
}
static Page_Info *
_add_item(Efl_Page_Transition_Scroll_Data *pd, Efl_Page_Transition_Data *spd)
{
Page_Info *pi;
pi = calloc(1, sizeof(*pi));
pi->obj = efl_add(EFL_UI_BOX_CLASS, spd->pager.obj);
efl_canvas_group_member_add(spd->pager.group, pi->obj);
pi->content_num = -1;
pi->content = NULL;
pi->next = pd->head;
pd->head->prev = pi;
pi->prev = pd->tail;
pd->tail->next = pi;
return pi;
}
static void
_remove_item(Page_Info *pi, Efl_Page_Transition_Scroll_Data *pd)
{
efl_canvas_object_clip_set(pi->content, pd->backclip);
efl_pack_unpack(pi->obj, pi->content);
efl_del(pi->obj);
pi->prev->next = pi->next;
pi->next->prev = pi->prev;
pd->page_infos = eina_list_remove(pd->page_infos, pi);
free(pi);
}
EOLIAN static void
_efl_page_transition_scroll_side_page_num_set(Eo *obj,
Efl_Page_Transition_Scroll_Data *pd,
int side_page_num)
{
EFL_PAGE_TRANSITION_DATA_GET(obj, spd);
Page_Info *pi;
int delta, i;
if (pd->side_page_num == side_page_num) return;
delta = side_page_num - pd->side_page_num;
pd->side_page_num = side_page_num;
pd->page_info_num = (side_page_num * 2) + 3;
if (!spd->pager.obj) return;
if (delta > 0)
{
// side_page_num is increased, so add boxes at both ends by the diff
for (i = 0; i < delta; i++)
{
pi = _add_item(pd, spd);
pd->page_infos = eina_list_prepend_relative(pd->page_infos, pi, pd->head);
pd->head = pi;
efl_gfx_stack_below(pi->obj, pi->next->obj);
pi = _add_item(pd, spd);
pd->page_infos = eina_list_append_relative(pd->page_infos, pi, pd->tail);
pd->tail = pi;
efl_gfx_stack_above(pi->obj, pi->prev->obj);
}
}
else
{
// side_page_num is decreased, so remove boxes at both ends by the diff
for (i = 0; i > delta; i--)
{
pi = pd->head;
pd->head = pi->next;
_remove_item(pi, pd);
pi = pd->tail;
pd->tail = pi->prev;
_remove_item(pi, pd);
}
}
pi = pd->head;
for (i = 0; i < pd->page_info_num; i++)
{
pi->id = i;
pi->pos = i - (pd->side_page_num + 1);
pi = pi->next;
}
_page_info_geometry_change(pd, spd);
}
EOLIAN static void
_efl_page_transition_scroll_loop_set(Eo *obj,
Efl_Page_Transition_Scroll_Data *pd,
Efl_Ui_Pager_Loop loop)
{
EFL_PAGE_TRANSITION_DATA_GET(obj, spd);
if (spd->loop == loop) return;
efl_page_transition_loop_set(efl_super(obj, MY_CLASS), loop);
_content_show(pd, spd);
}
EOLIAN static Eo *
_efl_page_transition_scroll_efl_object_constructor(Eo *obj,
Efl_Page_Transition_Scroll_Data *pd)
{
obj = efl_constructor(efl_super(obj, MY_CLASS));
pd->side_page_num = 1;
pd->page_info_num = pd->side_page_num * 2 + 3;
return obj;
}
EOLIAN static void
_efl_page_transition_scroll_efl_object_invalidate(Eo *obj,
Efl_Page_Transition_Scroll_Data *pd)
{
Page_Info *pi;
EINA_LIST_FREE(pd->page_infos, pi)
{
efl_del(pi->obj);
free(pi);
}
efl_invalidate(efl_super(obj, MY_CLASS));
}
#define EFL_PAGE_TRANSITION_SCROLL_EXTRA_OPS \
EFL_OBJECT_OP_FUNC(efl_page_transition_update, \
_efl_page_transition_scroll_update), \
EFL_OBJECT_OP_FUNC(efl_page_transition_curr_page_change, \
_efl_page_transition_scroll_curr_page_change), \
EFL_OBJECT_OP_FUNC(efl_page_transition_page_size_set, \
_efl_page_transition_scroll_page_size_set), \
EFL_OBJECT_OP_FUNC(efl_page_transition_padding_size_set, \
_efl_page_transition_scroll_padding_size_set), \
EFL_OBJECT_OP_FUNC(efl_page_transition_loop_set, \
_efl_page_transition_scroll_loop_set)
#include "efl_page_transition_scroll.eo.c"

View File

@ -0,0 +1,22 @@
class Efl.Page.Transition.Scroll (Efl.Page.Transition)
{
[[Page transition for @Efl.Ui.Pager
With this type of transition, pages are arranged linearly and move parallel
to the screen by scrolling. The current page is displayed at center, and
previous and next pages might be displayed optionally.
]]
methods {
@property side_page_num {
[[The number of pages displayed on each side of the current page]]
values {
side_page_num: int;
}
}
}
implements {
Efl.Object.constructor;
Efl.Object.invalidate;
Efl.Page.Transition.bind;
}
}

View File

@ -0,0 +1,93 @@
#ifndef EFL_PAGE_TRANSITION_SCROLL_H
#define EFL_PAGE_TRANSITION_SCROLL_H
//#include "efl_ui_widget_pager.h"
/**
* This is a description on how scroll transition works.
*
* Regardless of the number of pages, scroll transition maintains a fixed number
* of boxes which can contain pages. The boxes move along with scrolling and
* some of them are emptied or filled as they come in or out of screen area.
* When pager is scrolled left or right, each box takes the position of its
* previous or next box. Since the leftmost and rightmost boxes might move in
* reverse direction, they shouldn't be visible. This is why there are dummy
* boxes at both ends.
*
* Here is an example of box arrangement change by scrolling.
* The pager has 10 pages, numbered from 1 to 10.
* The current page is page5, and side_page_num equals 1.
*
* head |----- screen area ----| tail
* (dummy) | | (dummy)
* ---------- ---------- ---------- ---------- ----------
* | BOX1 | | BOX2 | | BOX3 | | BOX4 | | BOX5 |
* | | | | | | | | | |
* | (empty)| | page4 | | page5 | | page6 | | (empty)|
* | | | | | | | | | |
* | | | | | | | | | |
* | | | | | | | | | |
* ---------- ---------- ---------- ---------- ----------
* | |
* |----------------------|
*
* After scrolling left,
* 1. each box takes the position of it's previous box.
* 2. head and tail is changed.
* 3. The box moved to the end is emptied.
* 4. The box moved from the end is filled with content.
*
* head tail
* ---------- ---------- ---------- ---------- ----------
* | BOX2 | | BOX3 | | BOX4 | | BOX5 | | BOX1 |
* | | | | | | | | | |
* | (empty)| | page5 | | page6 | | page7 | | (empty)|
* |*emptied| | | | | |*filled | | |
* | | | | | | | | | |
* | | | | | | | | | |
* ---------- ---------- ---------- ---------- ----------
*
*/
typedef struct _Page_Info
{
Evas_Map *map;
int id;
int pos;
int content_num;
Eo *obj;
Eo *content;
Eina_Rectangle geometry;
Eina_Rectangle temp;
struct _Page_Info *prev, *next;
Eina_Bool visible;
Eina_Bool vis_page;
} Page_Info;
typedef struct _Efl_Page_Transition_Scroll_Data Efl_Page_Transition_Scroll_Data;
struct _Efl_Page_Transition_Scroll_Data
{
Eina_List *page_infos;
Page_Info *head, *tail;
int page_info_num;
int side_page_num;
Eo *foreclip;
Eo *backclip;
Eina_Rectangle viewport;
};
#define EFL_PAGE_TRANSITION_SCROLL_DATA_GET(o, pd) \
Efl_Page_Transition_Scroll_Data *pd = \
efl_data_scope_get(o, EFL_PAGE_TRANSITION_SCROLL_CLASS)
#endif

View File

@ -0,0 +1,811 @@
#ifdef HAVE_CONFIG_H
# include "elementary_config.h"
#endif
#define EFL_PACK_LAYOUT_PROTECTED
#include <Elementary.h>
#include "elm_priv.h"
#include "efl_ui_widget_pager.h"
#include "efl_page_transition.h"
#define MY_CLASS EFL_UI_PAGER_CLASS
static void
_efl_ui_pager_update(Efl_Ui_Pager_Data *pd)
{
if (pd->cnt == 0) return;
efl_page_transition_update(pd->transition, pd->curr.pos);
if (pd->indicator)
efl_page_indicator_update(pd->indicator, pd->curr.pos);
}
static void
_job(void *data)
{
Evas_Object *obj = data;
EFL_UI_PAGER_DATA_GET(obj, pd);
int prev_page, page_diff;
double prev_pos, pos_diff;
prev_page = pd->curr.page;
prev_pos = pd->curr.pos;
pd->job = NULL;
pos_diff = ((double) pd->down.x - (double) pd->mouse_x) / (double) pd->w;
pd->curr.pos = pd->down.pos + pos_diff;
page_diff = (int) pd->curr.pos;
//FIXME what if (prev_pos != 0.0)
if ((pd->loop == EFL_UI_PAGER_LOOP_DISABLED) &&
(((prev_page == 0) && (pd->curr.pos < 0)) ||
((prev_page == (pd->cnt - 1)) && (pd->curr.pos > 0))))
{
pd->curr.page = prev_page;
pd->curr.pos = prev_pos;
return;
}
pd->curr.page = (pd->down.page + page_diff + pd->cnt) % pd->cnt;
pd->curr.pos -= page_diff;
//FIXME what if (page_diff >= 2 || page_diff <= -2)
if (page_diff != 0)
{
pd->down.x = pd->mouse_x;
pd->down.y = pd->mouse_y;
pd->down.page = pd->curr.page;
pd->down.pos = pd->curr.pos;
efl_page_transition_curr_page_change(pd->transition, page_diff);
}
_efl_ui_pager_update(pd);
return;
}
static void
_page_set_animation(void *data, const Efl_Event *event)
{
Efl_Ui_Pager_Data *pd = data;
double p = ecore_loop_time_get() - pd->change.start_time;
double d, temp_pos;
int temp_page;
if (p >= 1.0) p = 1.0;
p = ecore_animator_pos_map(p, ECORE_POS_MAP_ACCELERATE, 0.0, 0.0);
d = pd->change.src + pd->change.delta * p;
temp_page = d;
temp_pos = d - temp_page;
if ((temp_page < pd->curr.page) && (fabs(pd->curr.page - d) < 1.0))
{
temp_page += 1;
temp_pos -= 1.0;
}
if (pd->curr.page != temp_page)
{
if (pd->change.delta < 0)
efl_page_transition_curr_page_change(pd->transition, -1.0);
else
efl_page_transition_curr_page_change(pd->transition, 1.0);
temp_pos = 0.0;
}
pd->curr.page = temp_page;
pd->curr.pos = temp_pos;
ERR("page %d pos %lf", pd->curr.page, pd->curr.pos);
_efl_ui_pager_update(pd);
if (EINA_DBL_EQ(p, 1.0))
efl_event_callback_del(event->object, EFL_EVENT_ANIMATOR_TICK,
_page_set_animation, pd);
}
static void
_mouse_up_animation(void *data, const Efl_Event *event)
{
Efl_Ui_Pager_Data *pd = data;
double p = ecore_loop_time_get() - pd->mouse_up_time;
if (p >= 1.0) p = 1.0;
p = ecore_animator_pos_map(p, ECORE_POS_MAP_ACCELERATE, 0.0, 0.0);
if (pd->curr.pos < 0.0)
{
if (pd->curr.pos > -0.5)
pd->curr.pos = pd->curr.pos * (1 - p);
else
pd->curr.pos = (-1) - (-1 - pd->curr.pos) * (1 - p);
}
else
{
if (pd->curr.pos < 0.5)
pd->curr.pos = pd->curr.pos * (1 - p);
else
pd->curr.pos = 1 - (1 - pd->curr.pos) * (1 - p);
}
if (EINA_DBL_EQ(pd->curr.pos, 1.0))
{
efl_page_transition_curr_page_change(pd->transition, 1.0);
pd->curr.page = (pd->curr.page + 1 + pd->cnt) % pd->cnt;
pd->curr.pos = 0.0;
}
else if (EINA_DBL_EQ(pd->curr.pos, -1.0))
{
efl_page_transition_curr_page_change(pd->transition, -1.0);
pd->curr.page = (pd->curr.page - 1 + pd->cnt) % pd->cnt;
pd->curr.pos = 0.0;
}
_efl_ui_pager_update(pd);
if (EINA_DBL_EQ(p, 1.0))
efl_event_callback_del(event->object, EFL_EVENT_ANIMATOR_TICK,
_mouse_up_animation, pd);
}
static void
_mouse_down_cb(void *data,
const Efl_Event *event)
{
Efl_Input_Pointer *ev = event->info;
Eo *obj = data;
EFL_UI_PAGER_DATA_GET(obj, pd);
Eina_Position2D pos;
if (efl_input_pointer_button_get(ev) != 1) return;
if (efl_input_event_flags_get(ev) & EFL_INPUT_FLAGS_PROCESSED) return;
efl_event_callback_del(obj, EFL_EVENT_ANIMATOR_TICK, _mouse_up_animation, pd);
efl_event_callback_del(obj, EFL_EVENT_ANIMATOR_TICK, _page_set_animation, pd);
pd->move_started = EINA_FALSE;
pos = efl_input_pointer_position_get(ev);
pd->mouse_x = pos.x - pd->x;
pd->mouse_y = pos.y - pd->y;
pd->down.enabled = EINA_TRUE;
pd->down.x = pd->mouse_x;
pd->down.y = pd->mouse_y;
pd->down.page = pd->curr.page;
pd->down.pos = pd->curr.pos;
}
static void
_mouse_move_cb(void *data,
const Efl_Event *event)
{
Efl_Input_Pointer *ev = event->info;
Eo *obj = data;
EFL_UI_PAGER_DATA_GET(obj, pd);
Eina_Position2D pos;
if (efl_input_event_flags_get(ev) & EFL_INPUT_FLAGS_PROCESSED) return;
if (!pd->down.enabled) return;
pos = efl_input_pointer_position_get(ev);
if (pd->prev_block && (pd->mouse_x < (pos.x - pd->x))) return;
if (pd->next_block && (pd->mouse_x > (pos.x - pd->x))) return;
pd->mouse_x = pos.x - pd->x;
pd->mouse_y = pos.y - pd->y;
if (!pd->move_started)
{
Evas_Coord dx, dy;
dx = pd->mouse_x - pd->down.x;
dy = pd->mouse_y - pd->down.y;
if (((dx * dx) + (dy * dy)) <=
(_elm_config->finger_size * _elm_config->finger_size / 4))
return;
pd->move_started = EINA_TRUE;
}
ecore_job_del(pd->job);
pd->job = ecore_job_add(_job, obj);
}
static void
_mouse_up_cb(void *data,
const Efl_Event *event)
{
Efl_Input_Pointer *ev = event->info;
Eo *obj = data;
EFL_UI_PAGER_DATA_GET(obj, pd);
if (efl_input_event_flags_get(ev) & EFL_INPUT_FLAGS_PROCESSED) return;
if (!pd->down.enabled) return;
pd->down.enabled = EINA_FALSE;
ELM_SAFE_FREE(pd->job, ecore_job_del);
if (EINA_DBL_EQ(pd->curr.pos, 0.0)) return;
pd->mouse_up_time = ecore_loop_time_get();
efl_event_callback_add(obj, EFL_EVENT_ANIMATOR_TICK, _mouse_up_animation, pd);
}
//FIXME sub_object_parent_add? destruction
static void
_event_handler_create(Eo *obj, Efl_Ui_Pager_Data *pd)
{
pd->event = efl_add(EFL_CANVAS_RECTANGLE_CLASS,
evas_object_evas_get(obj));
evas_object_color_set(pd->event, 0, 0, 0, 0);
evas_object_repeat_events_set(pd->event, EINA_TRUE);
efl_content_set(efl_part(obj, "event"), pd->event);
efl_event_callback_add(pd->event, EFL_EVENT_POINTER_DOWN,
_mouse_down_cb, obj);
efl_event_callback_add(pd->event, EFL_EVENT_POINTER_UP,
_mouse_up_cb, obj);
efl_event_callback_add(pd->event, EFL_EVENT_POINTER_MOVE,
_mouse_move_cb, obj);
}
static void
_event_handler_del(Eo *obj, Efl_Ui_Pager_Data *pd)
{
efl_content_unset(efl_part(obj, "event"));
efl_del(pd->event);
pd->event = NULL;
}
static void
_resize_cb(void *data, const Efl_Event *ev)
{
Efl_Ui_Pager_Data *pd = data;
Eina_Size2D sz;
sz = efl_gfx_size_get(ev->object);
pd->w = sz.w;
pd->h = sz.h;
if (pd->fill_width) pd->page_spec.sz.w = pd->w;
if (pd->fill_height) pd->page_spec.sz.h = pd->h;
if (pd->transition)
efl_page_transition_page_size_set(pd->transition, pd->page_spec.sz);
else
{
efl_gfx_size_set(pd->foreclip, sz);
efl_gfx_size_set(pd->page_box, pd->page_spec.sz);
efl_gfx_position_set(pd->page_box,
EINA_POSITION2D(pd->x + (pd->w / 2) - (pd->page_spec.sz.w / 2),
pd->y + (pd->h / 2) - (pd->page_spec.sz.h / 2)));
}
}
static void
_move_cb(void *data, const Efl_Event *ev)
{
Efl_Ui_Pager_Data *pd = data;
Eina_Position2D pos;
pos = efl_gfx_position_get(ev->object);
pd->x = pos.x;
pd->y = pos.y;
if (!pd->transition)
{
efl_gfx_position_set(pd->foreclip, pos);
efl_gfx_position_set(pd->page_box,
EINA_POSITION2D(pd->x + (pd->w / 2) - (pd->page_spec.sz.w / 2),
pd->y + (pd->h / 2) - (pd->page_spec.sz.h / 2)));
}
}
EOLIAN static Eo *
_efl_ui_pager_efl_object_constructor(Eo *obj,
Efl_Ui_Pager_Data *pd)
{
ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd, NULL);
if (!elm_widget_theme_klass_get(obj))
elm_widget_theme_klass_set(obj, "pager");
obj = efl_constructor(efl_super(obj, MY_CLASS));
if (!elm_widget_theme_object_set(obj, wd->resize_obj,
elm_widget_theme_klass_get(obj),
elm_widget_theme_element_get(obj),
elm_widget_theme_style_get(obj)))
CRI("Failed to set layout!");
elm_widget_sub_object_parent_add(obj);
pd->cnt = 0;
pd->loop = EFL_UI_PAGER_LOOP_DISABLED;
pd->curr.page = 0;
pd->curr.pos = 0.0;
pd->transition = NULL;
pd->indicator = NULL;
pd->fill_width = EINA_TRUE;
pd->fill_height = EINA_TRUE;
pd->page_spec.sz.w = -1;
pd->page_spec.sz.h = -1;
elm_widget_can_focus_set(obj, EINA_TRUE);
pd->page_root = efl_add(EFL_CANVAS_GROUP_CLASS, evas_object_evas_get(obj));
efl_content_set(efl_part(obj, "page_root"), pd->page_root);
efl_event_callback_add(pd->page_root, EFL_GFX_EVENT_RESIZE, _resize_cb, pd);
efl_event_callback_add(pd->page_root, EFL_GFX_EVENT_MOVE, _move_cb, pd);
pd->page_box = efl_add(EFL_UI_BOX_CLASS, obj);
efl_canvas_group_member_add(pd->page_root, pd->page_box);
pd->foreclip = efl_add(EFL_CANVAS_RECTANGLE_CLASS,
evas_object_evas_get(obj));
efl_canvas_group_member_add(pd->page_root, pd->foreclip);
evas_object_static_clip_set(pd->foreclip, EINA_TRUE);
efl_canvas_object_clip_set(pd->page_box, pd->foreclip);
pd->backclip = efl_add(EFL_CANVAS_RECTANGLE_CLASS,
evas_object_evas_get(obj));
efl_canvas_group_member_add(pd->page_root, pd->backclip);
evas_object_static_clip_set(pd->backclip, EINA_TRUE);
efl_gfx_visible_set(pd->backclip, EINA_FALSE);
return obj;
}
EOLIAN static int
_efl_ui_pager_efl_container_content_count(Eo *obj EINA_UNUSED,
Efl_Ui_Pager_Data *pd)
{
return pd->cnt;
}
EOLIAN static Eina_Bool
_efl_ui_pager_efl_pack_linear_pack_begin(Eo *obj,
Efl_Ui_Pager_Data *pd,
Efl_Gfx *subobj)
{
efl_parent_set(subobj, obj);
elm_widget_sub_object_add(obj, subobj);
pd->content_list = eina_list_prepend(pd->content_list, subobj);
pd->cnt += 1;
pd->curr.page += 1;
if (pd->transition)
efl_page_transition_update(pd->transition, pd->curr.pos);
else
{
if (pd->cnt == 1)
efl_pack(pd->page_box, subobj);
else efl_canvas_object_clip_set(subobj, pd->backclip);
}
if (pd->indicator)
{
efl_page_indicator_pack(pd->indicator, 0);
efl_page_indicator_update(pd->indicator, pd->curr.pos);
}
return EINA_TRUE;
}
EOLIAN static Eina_Bool
_efl_ui_pager_efl_pack_linear_pack_end(Eo *obj,
Efl_Ui_Pager_Data *pd,
Efl_Gfx *subobj)
{
efl_parent_set(subobj, obj);
elm_widget_sub_object_add(obj, subobj);
pd->content_list = eina_list_append(pd->content_list, subobj);
pd->cnt += 1;
if (pd->transition)
efl_page_transition_update(pd->transition, pd->curr.pos);
else
{
if (pd->cnt == 1)
efl_pack(pd->page_box, subobj);
else efl_canvas_object_clip_set(subobj, pd->backclip);
}
if (pd->indicator)
{
efl_page_indicator_pack(pd->indicator, (pd->cnt - 1));
efl_page_indicator_update(pd->indicator, pd->curr.pos);
}
return EINA_TRUE;
}
EOLIAN static Eina_Bool
_efl_ui_pager_efl_pack_linear_pack_before(Eo *obj,
Efl_Ui_Pager_Data *pd,
Efl_Gfx *subobj,
const Efl_Gfx *existing)
{
int index;
efl_parent_set(subobj, obj);
elm_widget_sub_object_add(obj, subobj);
index = eina_list_data_idx(pd->content_list, (void *)existing);
pd->content_list = eina_list_prepend_relative(pd->content_list, subobj, existing);
pd->cnt += 1;
if (pd->curr.page >= index) pd->curr.page += 1;
if (pd->transition)
efl_page_transition_update(pd->transition, pd->curr.pos);
else efl_canvas_object_clip_set(subobj, pd->backclip);
if (pd->indicator)
{
efl_page_indicator_pack(pd->indicator, index);
efl_page_indicator_update(pd->indicator, pd->curr.pos);
}
return EINA_TRUE;
}
EOLIAN static Eina_Bool
_efl_ui_pager_efl_pack_linear_pack_after(Eo *obj,
Efl_Ui_Pager_Data *pd,
Efl_Gfx *subobj,
const Efl_Gfx *existing)
{
int index;
efl_parent_set(subobj, obj);
elm_widget_sub_object_add(obj, subobj);
index = eina_list_data_idx(pd->content_list, (void *)existing);
pd->content_list = eina_list_append_relative(pd->content_list, subobj, existing);
pd->cnt += 1;
if (pd->curr.page > index) pd->curr.page += 1;
if (pd->transition)
efl_page_transition_update(pd->transition, pd->curr.pos);
else efl_canvas_object_clip_set(subobj, pd->backclip);
if (pd->indicator)
{
efl_page_indicator_pack(pd->indicator, (index + 1));
efl_page_indicator_update(pd->indicator, pd->curr.pos);
}
return EINA_TRUE;
}
EOLIAN static Eina_Bool
_efl_ui_pager_efl_pack_linear_pack_at(Eo *obj,
Efl_Ui_Pager_Data *pd,
Efl_Gfx *subobj,
int index)
{
Efl_Gfx *existing = NULL;
efl_parent_set(subobj, obj);
elm_widget_sub_object_add(obj, subobj);
existing = eina_list_nth(pd->content_list, index);
pd->content_list = eina_list_prepend_relative(pd->content_list, subobj, existing);
pd->cnt += 1;
if (pd->curr.page >= index) pd->curr.page += 1;
if (pd->transition)
efl_page_transition_update(pd->transition, pd->curr.pos);
else efl_canvas_object_clip_set(subobj, pd->backclip);
if (pd->indicator)
{
efl_page_indicator_pack(pd->indicator, index);
efl_page_indicator_update(pd->indicator, pd->curr.pos);
}
return EINA_TRUE;
}
EOLIAN static Efl_Gfx *
_efl_ui_pager_efl_pack_linear_pack_content_get(Eo *obj EINA_UNUSED,
Efl_Ui_Pager_Data *pd,
int index)
{
return eina_list_nth(pd->content_list, index);
}
EOLIAN static int
_efl_ui_pager_efl_pack_linear_pack_index_get(Eo *obj EINA_UNUSED,
Efl_Ui_Pager_Data *pd,
const Efl_Gfx *subobj)
{
return eina_list_data_idx(pd->content_list, (void *)subobj);
}
EOLIAN static void
_efl_ui_pager_current_page_set(Eo *obj,
Efl_Ui_Pager_Data *pd,
int index)
{
if (index == pd->curr.page) return;
efl_event_callback_del(obj, EFL_EVENT_ANIMATOR_TICK, _mouse_up_animation, pd);
efl_event_callback_del(obj, EFL_EVENT_ANIMATOR_TICK, _page_set_animation, pd);
if (index >= pd->cnt)
{
ERR("page set fail");
return;
}
if (!pd->transition)
{
Eo *curr;
curr = eina_list_nth(pd->content_list, pd->curr.page);
efl_pack_unpack(pd->page_box, curr);
efl_canvas_object_clip_set(curr, pd->backclip);
pd->curr.page = index;
curr = eina_list_nth(pd->content_list, pd->curr.page);
efl_pack(pd->page_box, curr);
if (pd->indicator)
efl_page_indicator_update(pd->indicator, pd->curr.pos);
return;
}
pd->change.src = pd->curr.page + pd->curr.pos;
pd->change.delta = index - pd->change.src;
if (pd->change.delta == 0) return;
pd->change.start_time = ecore_loop_time_get();
efl_event_callback_add(obj, EFL_EVENT_ANIMATOR_TICK, _page_set_animation, pd);
}
EOLIAN static int
_efl_ui_pager_current_page_get(const Eo *obj EINA_UNUSED,
Efl_Ui_Pager_Data *pd)
{
return pd->curr.page;
}
EOLIAN static void
_efl_ui_pager_transition_set(Eo *obj,
Efl_Ui_Pager_Data *pd,
Efl_Page_Transition *transition)
{
if (pd->transition == transition) return;
if (pd->transition)
efl_page_transition_bind(pd->transition, NULL, NULL);
else
{
Eo *curr;
curr = eina_list_nth(pd->content_list, pd->curr.page);
efl_pack_unpack(pd->page_box, curr);
efl_canvas_object_clip_set(pd->page_box, pd->backclip);
}
pd->transition = transition;
if (pd->transition)
{
if (!pd->event) _event_handler_create(obj, pd);
efl_page_transition_bind(pd->transition, obj, pd->page_root);
}
else
{
Eina_List *list;
Eo *curr;
_event_handler_del(obj, pd);
efl_canvas_object_clip_set(pd->page_box, pd->foreclip);
EINA_LIST_FOREACH(pd->content_list, list, curr)
{
efl_canvas_object_clip_set(curr, pd->backclip);
}
curr = eina_list_nth(pd->content_list, pd->curr.page);
efl_pack(pd->page_box, curr);
}
}
EOLIAN static void
_efl_ui_pager_indicator_set(Eo *obj EINA_UNUSED,
Efl_Ui_Pager_Data *pd,
Efl_Page_Indicator *indicator)
{
if (pd->indicator == indicator) return;
if (pd->indicator)
{
efl_page_indicator_bind(pd->indicator, NULL, NULL);
pd->indicator = NULL;
}
pd->indicator = indicator;
if (!pd->indicator)
{
if (pd->idbox)
{
efl_del(pd->idbox);
pd->idbox = NULL;
}
return;
}
if (!pd->idbox)
{
pd->idbox = efl_add(EFL_UI_BOX_CLASS, obj);
efl_content_set(efl_part(obj, "indicator"), pd->idbox);
}
efl_page_indicator_bind(pd->indicator, obj, pd->idbox);
}
EOLIAN Eina_Size2D
_efl_ui_pager_page_size_get(const Eo *obj EINA_UNUSED,
Efl_Ui_Pager_Data *pd)
{
return pd->page_spec.sz;
}
EOLIAN static void
_efl_ui_pager_page_size_set(Eo *obj EINA_UNUSED,
Efl_Ui_Pager_Data *pd,
Eina_Size2D sz)
{
if (sz.w < -1 || sz.h < -1) return;
if (sz.w == -1)
{
pd->fill_width = EINA_TRUE;
pd->page_spec.sz.w = pd->w;
}
else
{
pd->fill_width = EINA_FALSE;
pd->page_spec.sz.w = sz.w;
}
if (sz.h == -1)
{
pd->fill_height = EINA_TRUE;
pd->page_spec.sz.h = pd->h;
}
else
{
pd->fill_height = EINA_FALSE;
pd->page_spec.sz.h = sz.h;
}
if (pd->transition)
efl_page_transition_page_size_set(pd->transition, pd->page_spec.sz);
else
efl_gfx_size_set(pd->page_box, pd->page_spec.sz);
}
EOLIAN static int
_efl_ui_pager_padding_get(const Eo *obj EINA_UNUSED,
Efl_Ui_Pager_Data *pd)
{
return pd->page_spec.padding;
}
EOLIAN static void
_efl_ui_pager_padding_set(Eo *obj EINA_UNUSED,
Efl_Ui_Pager_Data *pd,
int padding)
{
pd->page_spec.padding = padding;
efl_page_transition_padding_size_set(pd->transition, padding);
}
EOLIAN static void
_efl_ui_pager_scroll_block_get(const Eo *obj EINA_UNUSED,
Efl_Ui_Pager_Data *pd,
Eina_Bool *prev,
Eina_Bool *next)
{
if (prev) *prev = pd->prev_block;
if (next) *next = pd->next_block;
}
EOLIAN static void
_efl_ui_pager_scroll_block_set(Eo *obj EINA_UNUSED,
Efl_Ui_Pager_Data *pd,
Eina_Bool prev,
Eina_Bool next)
{
pd->prev_block = prev;
pd->next_block = next;
}
EOLIAN static void
_efl_ui_pager_loop_mode_set(Eo *obj EINA_UNUSED,
Efl_Ui_Pager_Data *pd,
Efl_Ui_Pager_Loop loop)
{
pd->loop = loop;
efl_page_transition_loop_set(pd->transition, loop);
}
EOLIAN static Efl_Ui_Pager_Loop
_efl_ui_pager_loop_mode_get(const Eo *obj EINA_UNUSED,
Efl_Ui_Pager_Data *pd)
{
return pd->loop;
}
EOLIAN static Eina_Bool
_efl_ui_pager_efl_pack_pack_clear(Eo *obj EINA_UNUSED,
Efl_Ui_Pager_Data *pd EINA_UNUSED)
{
ERR("Soon to be implemented");
return EINA_FALSE;
}
EOLIAN static Eina_Bool
_efl_ui_pager_efl_pack_unpack_all(Eo *obj EINA_UNUSED,
Efl_Ui_Pager_Data *pd EINA_UNUSED)
{
ERR("Soon to be implemented");
return EINA_FALSE;
}
EOLIAN static Eina_Bool
_efl_ui_pager_efl_pack_unpack(Eo *obj EINA_UNUSED,
Efl_Ui_Pager_Data *pd EINA_UNUSED,
Efl_Gfx *subobj EINA_UNUSED)
{
ERR("Soon to be implemented");
return EINA_FALSE;
}
EOLIAN static Efl_Gfx *
_efl_ui_pager_efl_pack_linear_pack_unpack_at(Eo *obj EINA_UNUSED,
Efl_Ui_Pager_Data *pd EINA_UNUSED,
int index EINA_UNUSED)
{
ERR("Soon to be implemented");
return NULL;
}
#include "efl_ui_pager.eo.c"

View File

@ -0,0 +1,101 @@
enum Efl.Ui.Pager.Loop
{
[[Efl ui pager loop mode]]
disabled,
enabled
}
class Efl.Ui.Pager (Efl.Ui.Layout, Efl.Pack.Linear)
{
[[Pager widget
A pager contains many pages in a linear fashion and allows users to scroll
through pages. Each page is numbered according to linear order and
one of the pages is marked as 'current page' and displayed in the middle.
The way each page is displayed is defined by @Efl.Page.Transition object,
allowing users to adopt different types of transition.
The most common use case of this widget is the home screen of mobile devices.
]]
methods {
@property transition {
[[Page transition effect
Page transition is in charge of displaying pages in a specific way and
invoked every time page layout needs to be updated.
]]
set {
[[Set a page transition effect]]
}
values {
transition: Efl.Page.Transition @nullable; [[transition effect]]
}
}
@property indicator {
[[Page indicator
Page indicator, located on the top layer of pager widget, helps users
to know the number of pages and the current page's index without scrolling.
]]
set {
[[Set a page indicator]]
}
values {
indicator: Efl.Page.Indicator @nullable; [[indicator class]]
}
}
@property current_page {
[[One page is selected as the current page and mainly displayed.]]
set {
[[Set one page as current page]]
}
get {
[[Get the current page]]
}
values {
index: int;
}
}
@property scroll_block {
[[Pages can be scrolled back and forth by default. This property allows
limiting the direction of scrolling, or blocking scroll gesture at all.
]]
values {
prev: bool;
next: bool;
}
}
@property loop_mode {
[[Pager is not scrolled after it's scrolled to the end by default.
This property gives the option to make a loop through pages.
]]
values {
loop: Efl.Ui.Pager.Loop;
}
}
@property page_size {
values {
size: Eina.Size2D;
}
}
@property padding {
values {
padding: int;
}
}
}
implements {
Efl.Object.constructor;
Efl.Container.content_count;
Efl.Pack.pack_clear; //TODO
Efl.Pack.unpack_all; //TODO
Efl.Pack.unpack; //TODO
Efl.Pack.Linear.pack_begin;
Efl.Pack.Linear.pack_end;
Efl.Pack.Linear.pack_before;
Efl.Pack.Linear.pack_after;
Efl.Pack.Linear.pack_at;
Efl.Pack.Linear.pack_content_get;
Efl.Pack.Linear.pack_index_get;
Efl.Pack.Linear.pack_unpack_at; //TODO
}
}

View File

@ -0,0 +1,69 @@
#ifndef EFL_UI_WIDGET_PAGER_H
#define EFL_UI_WIDGET_PAGER_H
#include <Elementary.h>
#include "efl_page_transition.h"
typedef struct _Efl_Ui_Pager_Data
{
Eina_List *page_infos;
Eina_List *content_list;
Efl_Ui_Box *page_box;
Eo *foreclip;
Eo *backclip;
Eo *page_root;
Eo *event;
Efl_Ui_Box *idbox;
Ecore_Job *job;
Ecore_Job *page_info_job;
Evas_Coord x, y, w, h;
Evas_Coord mouse_x, mouse_y;
struct {
Eina_Size2D sz;
Evas_Coord padding;
} page_spec;
struct {
Evas_Coord x, y;
int page;
double pos;
Eina_Bool enabled;
} down;
struct {
int page;
double pos;
} curr;
struct {
double src;
double delta;
double start_time;
Eina_Bool jump;
} change;
int cnt;
double mouse_up_time;
Efl_Ui_Pager_Loop loop;
Efl_Page_Transition *transition;
Efl_Page_Indicator *indicator;
Eina_Bool move_started : 1;
Eina_Bool prev_block : 1;
Eina_Bool next_block: 1;
Eina_Bool fill_width: 1;
Eina_Bool fill_height: 1;
} Efl_Ui_Pager_Data;
#define EFL_UI_PAGER_DATA_GET(o, sd) \
Efl_Ui_Pager_Data *sd = efl_data_scope_get(o, EFL_UI_PAGER_CLASS)
#endif

View File

@ -731,6 +731,16 @@ void *_elm_icon_signal_callback_del(Evas_Object *obj,
/* DO NOT USE THIS this is only for performance optimization! */
void _elm_widget_full_eval(Eo *obj);
EOAPI void efl_page_transition_page_size_set(Eo *obj, Eina_Size2D sz);
EOAPI void efl_page_transition_padding_size_set(Eo *obj, int padding);
EOAPI void efl_page_transition_update(Eo *obj, double pos);
EOAPI void efl_page_transition_curr_page_change(Eo *obj, double move);
EOAPI void efl_page_transition_pack_end(Eo *obj, Efl_Gfx *subobj);
EOAPI void efl_page_transition_loop_set(Eo *obj, Efl_Ui_Pager_Loop loop);
EOAPI void efl_page_indicator_update(Eo *obj, double pos);
EOAPI void efl_page_indicator_pack(Eo *obj, int index);
Eina_Bool _elm_config_accel_preference_parse(const char *pref, Eina_Stringshare **accel, int *gl_depth, int *gl_stencil, int *gl_msaa);
extern char *_elm_appname;