enlightenment/src/modules/everything/views/evry_plug_view_thumb.c

972 lines
22 KiB
C

#include "e_mod_main.h"
typedef struct _View View;
typedef struct _Smart_Data Smart_Data;
typedef struct _Item Item;
struct _View
{
Evry_View view;
Evas *evas;
const Evry_State *state;
Tab_View *tabs;
Evas_Object *bg, *sframe, *span;
int iw, ih;
};
struct _Smart_Data
{
View *view;
Eina_List *items;
Item *sel_item;
Ecore_Idle_Enterer *idle_enter;
Ecore_Animator *animator;
Evas_Coord x, y, w, h;
Evas_Coord cx, cy, cw, ch;
Evas_Coord sx, sy;
int id_num;
int sort_num;
double selmove;
Eina_Bool selin : 1;
Eina_Bool selout : 1;
Eina_Bool jump2hi : 1;
/* */
Eina_Bool update : 1;
int zoom;
/* Ecore_Timer *seltimer; */
/* double seltime; */
};
struct _Item
{
Evry_Item *item;
Evas_Object *obj;
Evas_Coord x, y, w, h;
Evas_Object *frame, *image, *thumb;
Eina_Bool selected : 1;
Eina_Bool have_thumb : 1;
Eina_Bool do_thumb : 1;
Eina_Bool get_thumb : 1;
Eina_Bool showing : 1;
Eina_Bool visible : 1;
Eina_Bool changed : 1;
int pos;
};
static Evry_View *view = NULL;
static const char *view_types = NULL;
static void
_thumb_gen(void *data, Evas_Object *obj, void *event_info)
{
Evas_Coord w, h;
Item *it = data;
if (!it->frame) return;
e_icon_size_get(it->thumb, &w, &h);
edje_extern_object_aspect_set(it->thumb, EDJE_ASPECT_CONTROL_BOTH, w, h);
edje_object_part_swallow(it->frame, "e.swallow.icon", it->thumb);
evas_object_show(it->thumb);
it->have_thumb = EINA_TRUE;
it->do_thumb = EINA_FALSE;
if (it->image) evas_object_del(it->image);
it->image = NULL;
}
static int
_e_smart_reconfigure_do(void *data)
{
Evas_Object *obj = data;
Smart_Data *sd = evas_object_smart_data_get(obj);
Eina_List *l;
Item *it;
int iw, ih, redo = 0, changed = 0;
static int recursion = 0;
Evas_Coord x, y, xx, yy, ww, hh, mw, mh, ox, oy, dd;
if (!sd) return 0;
if (sd->cx > (sd->cw - sd->w)) sd->cx = sd->cw - sd->w;
if (sd->cy > (sd->ch - sd->h)) sd->cy = sd->ch - sd->h;
if (sd->cx < 0) sd->cx = 0;
if (sd->cy < 0) sd->cy = 0;
e_scrollframe_child_viewport_size_get(sd->view->sframe,
&sd->view->iw,
&sd->view->ih);
if (sd->zoom == 0)
{
int cnt = eina_list_count(sd->items);
sd->view->iw *= 3;
sd->view->iw /= 4;
if (cnt < 3)
iw = (double)sd->w / 2.5;
else if (cnt < 7)
iw = sd->w / 3;
else
iw = sd->w / 4;
}
else if (sd->zoom == 1)
{
sd->view->iw *= 2;
sd->view->iw /= 3;
iw = sd->w / 3;
}
else if (sd->zoom == 2)
{
iw = sd->w;
}
if (sd->view->iw <= 0) sd->view->iw = 1;
if (sd->view->ih <= 0) sd->view->ih = 1;
x = 0;
y = 0;
ww = iw;
hh = (sd->view->ih * iw) / (sd->view->iw);
ih = hh;
mw = mh = 0;
EINA_LIST_FOREACH(sd->items, l, it)
{
xx = sd->x - sd->cx + x;
if (x > (sd->w - ww))
{
x = 0;
y += hh;
xx = sd->x - sd->cx + x;
}
yy = sd->y - sd->cy + y;
it->x = x;
it->y = y;
it->w = ww;
it->h = hh;
if (it->selected)
{
sd->sx = it->x + (it->w / 2);
sd->sy = it->y + (it->h / 2);
}
if ((x + ww) > mw)mw = x + ww;
if ((y + hh) > mh) mh = y + hh;
x += ww;
}
if ((mw != sd->cw) || (mh != sd->ch))
{
sd->cw = mw;
sd->ch = mh;
if (sd->cx > (sd->cw - sd->w))
{
sd->cx = sd->cw - sd->w;
redo = 1;
}
if (sd->cy > (sd->ch - sd->h))
{
sd->cy = sd->ch - sd->h;
redo = 1;
}
if (sd->cx < 0)
{
sd->cx = 0;
redo = 1;
}
if (sd->cy < 0)
{
sd->cy = 0;
redo = 1;
}
if (redo)
{
recursion = 1;
_e_smart_reconfigure_do(obj);
recursion = 0;
}
changed = 1;
}
ox = 0;
if (sd->w > sd->cw) ox = (sd->w - sd->cw) / 2;
oy = 0;
if (sd->h > sd->ch) oy = (sd->h - sd->ch) / 2;
if (sd->sel_item && !sd->update)
{
int y, h;
it = sd->sel_item;
e_scrollframe_child_pos_get(sd->view->sframe, NULL, &y);
e_scrollframe_child_viewport_size_get(sd->view->sframe, NULL, &h);
if ((it->y + it->h) - y >= h - it->h)
e_scrollframe_child_pos_set(sd->view->sframe, 0, it->y - (2 - sd->zoom) * it->h);
else if (it->y < y)
e_scrollframe_child_pos_set(sd->view->sframe, 0, it->y);
}
EINA_LIST_FOREACH(sd->items, l, it)
{
Evas_Coord dx, dy, vw, vh;
dx = dy = 0;
if ((sd->sx >= 0) &&
(sd->selmove > 0.0))
{
double a, d; //, di;
int sum = 0;
/* char *p; */
// -----0X0+++++
dx = (it->x + (it->w / 2)) - sd->sx;
dy = (it->y + (it->h / 2)) - sd->sy;
if (dx > 0)
{
/* |/
* +-- */
if (dy < 0)
a = -atan(-(double)dy / (double)dx);
/* +--
* |\ */
else
a = atan((double)dy / (double)dx);
}
else if (dx == 0)
{
/* |
* + */
if (dy < 0) a = -M_PI / 2;
/* +
* | */
else a = M_PI / 2;
}
else
{
/* \|
* --+ */
if (dy < 0)
a = -M_PI + atan((double)dy / (double)dx);
/* --+
* /| */
else
a = M_PI - atan(-(double)dy / (double)dx);
}
d = sqrt((double)(dx * dx) + (double)(dy * dy));
dx = dy = 0;
sum = 0;
xx = sd->sx - sd->cx + ox;
yy = sd->sy - sd->cy + oy;
if (xx < (sd->w / 2)) dx = sd->w - xx;
else dx = xx;
if (yy < (sd->h / 2)) dy = sd->h - yy;
else dy = yy;
dd = dx - d;
if (dy > dx) dd = dy - d;
if (dd < 0) dd = 0;
dy = sin(a) * sd->selmove * (dd * 0.9);
dx = cos(a) * sd->selmove * (dd * 0.9);
}
xx = sd->x - sd->cx + it->x + ox;
yy = sd->y - sd->cy + it->y + oy;
evas_object_geometry_get(sd->view->span, NULL, NULL, &vw, &vh);
if (E_INTERSECTS(xx, yy, it->w, it->h, 0, - it->h*2, vw, vh + it->h*4))
{
if (!it->frame)
{
it->frame = edje_object_add(sd->view->evas);
e_theme_edje_object_set(it->frame, "base/theme/widgets",
"e/modules/everything/thumbview/main/mini");
evas_object_smart_member_add(it->frame, obj);
evas_object_clip_set(it->frame, evas_object_clip_get(obj));
edje_object_part_text_set(it->frame, "e.text.label", it->item->label);
if (!it->image && !it->have_thumb &&
it->item->plugin && it->item->plugin->icon_get)
{
it->image = it->item->plugin->icon_get
(it->item->plugin, it->item, sd->view->evas);
edje_object_part_swallow(it->frame, "e.swallow.content", it->image);
evas_object_show(it->image);
}
}
if (it->get_thumb && !it->have_thumb)
{
if (!it->thumb)
{
ITEM_FILE(file, it->item);
it->thumb = e_thumb_icon_add(sd->view->evas);
evas_object_smart_callback_add(it->thumb, "e_thumb_gen", _thumb_gen, it);
e_thumb_icon_file_set(it->thumb, file->uri, NULL);
e_thumb_icon_size_set(it->thumb, iw, ih);
e_thumb_icon_begin(it->thumb);
it->do_thumb = EINA_TRUE;
}
else if (!it->do_thumb)
{
e_thumb_icon_begin(it->thumb);
it->do_thumb = EINA_TRUE;
}
}
if (it->selected && sd->zoom < 2)
edje_object_signal_emit(it->frame, "e,state,selected", "e");
if (sd->update && !it->visible)
edje_object_signal_emit(it->frame, "e,action,thumb,show_delayed", "e");
else if (!it->visible)
edje_object_signal_emit(it->frame, "e,action,thumb,show", "e");
evas_object_move(it->frame,
xx + dx,
yy + dy);
evas_object_resize(it->frame, it->w, it->h);
evas_object_show(it->frame);
it->visible = EINA_TRUE;
}
else
{
if (it->frame)
{
if (it->do_thumb) e_thumb_icon_end(it->thumb);
if (it->thumb) evas_object_del(it->thumb);
if (it->image) evas_object_del(it->image);
evas_object_del(it->frame);
it->thumb = NULL;
it->image = NULL;
it->frame = NULL;
it->have_thumb = EINA_FALSE;
it->do_thumb = EINA_FALSE;
it->visible = EINA_FALSE;
it->changed = TRUE;
}
}
}
if (changed)
evas_object_smart_callback_call(obj, "changed", NULL);
sd->update = EINA_FALSE;
if (recursion == 0)
sd->idle_enter = NULL;
return 0;
}
static void
_e_smart_reconfigure(Evas_Object *obj)
{
Smart_Data *sd = evas_object_smart_data_get(obj);
if (sd->idle_enter) return;
sd->idle_enter = ecore_idle_enterer_before_add(_e_smart_reconfigure_do, obj);
}
static void
_e_smart_add(Evas_Object *obj)
{
Smart_Data *sd = calloc(1, sizeof(Smart_Data));
if (!sd) return;
sd->x = sd->y = sd->w = sd->h = 0;
sd->sx = sd->sy = -1;
evas_object_smart_data_set(obj, sd);
}
static void
_e_smart_del(Evas_Object *obj)
{
Smart_Data *sd = evas_object_smart_data_get(obj);
Item *it;
/* if (sd->seltimer)
* ecore_timer_del(sd->seltimer); */
/* if (sd->animator)
* ecore_animator_del(sd->animator); */
if (sd->idle_enter)
ecore_idle_enterer_del(sd->idle_enter);
// sd->view is just referenced
// sd->child_obj is unused
EINA_LIST_FREE(sd->items, it)
{
if (it->do_thumb) e_thumb_icon_end(it->thumb);
if (it->thumb) evas_object_del(it->thumb);
if (it->frame) evas_object_del(it->frame);
if (it->image) evas_object_del(it->image);
evry_item_free(it->item);
free(it);
}
free(sd);
evas_object_smart_data_set(obj, NULL);
}
static void
_e_smart_move(Evas_Object *obj, Evas_Coord x, Evas_Coord y)
{
Smart_Data *sd = evas_object_smart_data_get(obj);
sd->x = x;
sd->y = y;
_e_smart_reconfigure(obj);
}
static void
_e_smart_resize(Evas_Object *obj, Evas_Coord w, Evas_Coord h)
{
Smart_Data *sd = evas_object_smart_data_get(obj);
sd->w = w;
sd->h = h;
_e_smart_reconfigure(obj);
evas_object_smart_callback_call(obj, "changed", NULL);
}
static void
_e_smart_show(Evas_Object *obj)
{
/* Smart_Data *sd = evas_object_smart_data_get(obj); */
// evas_object_show(sd->child_obj);
}
static void
_e_smart_hide(Evas_Object *obj)
{
/* Smart_Data *sd = evas_object_smart_data_get(obj); */
// evas_object_hide(sd->child_obj);
}
static void
_e_smart_color_set(Evas_Object *obj, int r, int g, int b, int a)
{
/* Smart_Data *sd = evas_object_smart_data_get(obj); */
// evas_object_color_set(sd->child_obj, r, g, b, a);
}
static void
_e_smart_clip_set(Evas_Object *obj, Evas_Object * clip)
{
/* Smart_Data *sd = evas_object_smart_data_get(obj); */
// evas_object_clip_set(sd->child_obj, clip);
}
static void
_e_smart_clip_unset(Evas_Object *obj)
{
/* Smart_Data *sd = evas_object_smart_data_get(obj); */
// evas_object_clip_unset(sd->child_obj);
}
static Evas_Object *
_pan_add(Evas *evas)
{
static Evas_Smart *smart = NULL;
static const Evas_Smart_Class sc =
{
"wp_pan",
EVAS_SMART_CLASS_VERSION,
_e_smart_add,
_e_smart_del,
_e_smart_move,
_e_smart_resize,
_e_smart_show,
_e_smart_hide,
_e_smart_color_set,
_e_smart_clip_set,
_e_smart_clip_unset,
NULL,
NULL,
NULL,
NULL
};
smart = evas_smart_class_new(&sc);
return evas_object_smart_add(evas, smart);
}
static void
_pan_set(Evas_Object *obj, Evas_Coord x, Evas_Coord y)
{
Smart_Data *sd = evas_object_smart_data_get(obj);
if (x > (sd->cw - sd->w)) x = sd->cw - sd->w;
if (y > (sd->ch - sd->h)) y = sd->ch - sd->h;
if (x < 0) x = 0;
if (y < 0) y = 0;
if ((sd->cx == x) && (sd->cy == y)) return;
sd->cx = x;
sd->cy = y;
_e_smart_reconfigure(obj);
}
static void
_pan_get(Evas_Object *obj, Evas_Coord *x, Evas_Coord *y)
{
Smart_Data *sd = evas_object_smart_data_get(obj);
if (x) *x = sd->cx;
if (y) *y = sd->cy;
}
static void
_pan_max_get(Evas_Object *obj, Evas_Coord *x, Evas_Coord *y)
{
Smart_Data *sd = evas_object_smart_data_get(obj);
if (x)
{
if (sd->w < sd->cw) *x = sd->cw - sd->w;
else *x = 0;
}
if (y)
{
if (sd->h < sd->ch) *y = sd->ch - sd->h;
else *y = 0;
}
}
static void
_pan_child_size_get(Evas_Object *obj, Evas_Coord *w, Evas_Coord *h)
{
Smart_Data *sd = evas_object_smart_data_get(obj);
if (w) *w = sd->cw;
if (h) *h = sd->ch;
}
static void
_pan_view_set(Evas_Object *obj, View *view)
{
Smart_Data *sd = evas_object_smart_data_get(obj);
sd->view = view;
}
static int
_check_item(const Evry_Item *it)
{
if (it->plugin->type_out != view_types) return 0;
ITEM_FILE(file, it);
if (!file->uri || !file->mime) return 0;
if (!strncmp(file->mime, "image/", 6))
return 1;
return 0;
}
static Item *
_pan_item_add(Evas_Object *obj, Evry_Item *item)
{
Smart_Data *sd = evas_object_smart_data_get(obj);
Item *it;
it = E_NEW(Item, 1);
if (!it) return NULL;
sd->items = eina_list_append(sd->items, it);
it->obj = obj;
it->item = item;
if (_check_item(item))
it->get_thumb = EINA_TRUE;
evry_item_ref(item);
_e_smart_reconfigure(obj);
return it;
}
static void
_pan_item_remove(Evas_Object *obj, Item *it)
{
Smart_Data *sd = evas_object_smart_data_get(obj);
sd->items = eina_list_remove(sd->items, it);
if (it->do_thumb) e_thumb_icon_end(it->thumb);
if (it->thumb) evas_object_del(it->thumb);
if (it->frame) evas_object_del(it->frame);
if (it->image) evas_object_del(it->image);
evry_item_free(it->item);
E_FREE(it);
_e_smart_reconfigure(obj);
}
static void
_pan_item_select(Evas_Object *obj, Item *it)
{
Smart_Data *sd = evas_object_smart_data_get(obj);
sd->sel_item->selected = EINA_FALSE;
edje_object_signal_emit(sd->sel_item->frame, "e,state,unselected", "e");
sd->sel_item = it;
sd->sel_item->selected = EINA_TRUE;
if (sd->zoom < 2)
edje_object_signal_emit(sd->sel_item->frame, "e,state,selected", "e");
sd->update = EINA_FALSE;
if (sd->idle_enter) ecore_idle_enterer_del(sd->idle_enter);
sd->idle_enter = ecore_idle_enterer_add(_e_smart_reconfigure_do, obj);
}
static void
_view_clear(Evry_View *view)
{
View *v = (View*) view;
Smart_Data *sd = evas_object_smart_data_get(v->span);
Item *it;
EINA_LIST_FREE(sd->items, it)
{
if (it->thumb) evas_object_del(it->thumb);
if (it->frame) evas_object_del(it->frame);
if (it->image) evas_object_del(it->image);
evry_item_free(it->item);
E_FREE(it);
}
if (sd->idle_enter) ecore_idle_enterer_del(sd->idle_enter);
sd->idle_enter = ecore_idle_enterer_add(_e_smart_reconfigure_do, v->span);
v->tabs->clear(v->tabs);
}
static int
_sort_cb(const void *data1, const void *data2)
{
const Item *it1 = data1;
const Item *it2 = data2;
return it1->pos - it2->pos;
}
static int
_view_update(Evry_View *view)
{
VIEW(v, view);
Smart_Data *sd = evas_object_smart_data_get(v->span);
Item *v_it;
Evry_Item *p_it;
Eina_List *l, *ll, *p_items, *v_remove = NULL, *v_items = NULL;
int pos, last_pos;
if (!v->state->plugin)
{
_view_clear(view);
return 1;
}
p_items = v->state->plugin->items;
EINA_LIST_FOREACH(sd->items, l, v_it)
{
last_pos = v_it->pos;
v_it->pos = 0;
pos = 1;
EINA_LIST_FOREACH(p_items, ll, p_it)
{
if (v_it->item == p_it)
{
if (pos != last_pos)
v_it->changed = EINA_TRUE;
v_it->pos = pos;
if (p_it == v->state->sel_item)
{
sd->sel_item = v_it;
v_it->selected = EINA_TRUE;
}
else
v_it->selected = EINA_FALSE;
break;
}
pos++;
}
if(v_it->pos)
{
v_items = eina_list_append(v_items, v_it->item);
if (_check_item(v_it->item))
v_it->get_thumb = EINA_TRUE;
}
else
v_remove = eina_list_append(v_remove, v_it);
}
if (v_remove)
sd->update = EINA_TRUE;
EINA_LIST_FREE(v_remove, v_it)
_pan_item_remove(v->span, v_it);
pos = 1;
int added = 0;
EINA_LIST_FOREACH(p_items, l, p_it)
{
if (!eina_list_data_find_list(v_items, p_it))
{
added = 1;
v_it = _pan_item_add(v->span, p_it);
if (v_it)
{
v_it->pos = pos;
if (p_it == v->state->sel_item)
{
sd->sel_item = v_it;
v_it->selected = EINA_TRUE;
}
}
}
pos++;
}
sd->items = eina_list_sort(sd->items, pos - 1, _sort_cb);
if (added)
sd->update = EINA_TRUE;
if (sd->idle_enter) ecore_idle_enterer_del(sd->idle_enter);
sd->idle_enter = ecore_idle_enterer_add(_e_smart_reconfigure_do, v->span);
if (v_items) eina_list_free(v_items);
v->tabs->update(v->tabs);
return 1;
}
static int
_cb_key_down(Evry_View *view, const Ecore_Event_Key *ev)
{
View *v = (View *) view;
Smart_Data *sd = evas_object_smart_data_get(v->span);
Eina_List *l = NULL, *ll;
Item *it = NULL;
if (!v->state->plugin)
return 0;
if (v->tabs->key_down(v->tabs, ev))
{
_view_update(view);
return 1;
}
if (sd->items)
l = eina_list_data_find_list(sd->items, sd->sel_item);
if (!strcmp(ev->key, "Right"))
{
if (l && l->next)
it = l->next->data;
if (it)
{
_pan_item_select(v->span, it);
evry_item_select(v->state, it->item);
}
goto end;
}
else if (!strcmp(ev->key, "Left"))
{
if (!sd->items) return 1;
if (l && l->prev)
it = l->prev->data;
if (it)
{
_pan_item_select(v->span, it);
evry_item_select(v->state, it->item);
}
goto end;
}
else if (!strcmp(ev->key, "Down"))
{
if (!sd->items) return 1;
EINA_LIST_FOREACH(l, ll, it)
{
if (it->y > sd->sel_item->y &&
it->x >= sd->sel_item->x)
break;
}
if (!it && l && l->next)
it = l->next->data;
if (it)
{
_pan_item_select(v->span, it);
evry_item_select(v->state, it->item);
}
goto end;
}
else if (!strcmp(ev->key, "Up"))
{
if (!sd->items) return 1;
EINA_LIST_REVERSE_FOREACH(l, ll, it)
{
if (it->y < sd->sel_item->y &&
it->x <= sd->sel_item->x)
break;
}
if (!it && l && l->prev)
it = l->prev->data;
if (it)
{
_pan_item_select(v->span, it);
evry_item_select(v->state, it->item);
}
goto end;
}
else if (!strcmp(ev->key, "plus") ||
((ev->modifiers & ECORE_EVENT_MODIFIER_ALT) &&
(!strcmp(ev->key, "z"))))
{
sd->zoom++;
if (sd->zoom > 2) sd->zoom = 0;
if (sd->zoom == 2)
{
EINA_LIST_FOREACH(sd->items, l, it)
{
if (it->have_thumb)
{
evas_object_del(it->thumb);
it->thumb = NULL;
it->have_thumb = EINA_FALSE;
}
else if (it->do_thumb)
{
e_thumb_icon_end(it->thumb);
evas_object_del(it->thumb);
it->thumb = NULL;
it->do_thumb = EINA_FALSE;
}
}
}
if (sd->idle_enter) ecore_idle_enterer_del(sd->idle_enter);
sd->idle_enter = ecore_idle_enterer_add(_e_smart_reconfigure_do, v->span);
goto end;
}
return 0;
end:
return 1;
}
static Evry_View *
_view_create(Evry_View *view, const Evry_State *s, const Evas_Object *swallow)
{
View *v;
if (!s->plugin)
return NULL;
v = E_NEW(View, 1);
v->view = *view;
v->state = s;
v->evas = evas_object_evas_get(swallow);
v->bg = edje_object_add(v->evas);
e_theme_edje_object_set(v->bg, "base/theme/widgets",
"e/modules/everything/thumbview/main/window");
// scrolled thumbs
v->span = _pan_add(v->evas);
_pan_view_set(v->span, v);
// the scrollframe holding the scrolled thumbs
v->sframe = e_scrollframe_add(v->evas);
e_scrollframe_custom_theme_set(v->sframe, "base/theme/widgets",
"e/modules/everything/thumbview/main/scrollframe");
e_scrollframe_extern_pan_set(v->sframe, v->span,
_pan_set, _pan_get, _pan_max_get,
_pan_child_size_get);
edje_object_part_swallow(v->bg, "e.swallow.list", v->sframe);
evas_object_show(v->sframe);
evas_object_show(v->span);
EVRY_VIEW(v)->o_list = v->bg;
v->tabs = evry_tab_view_new(s, v->evas);
v->view.o_bar = v->tabs->o_tabs;
return EVRY_VIEW(v);
}
static void
_view_destroy(Evry_View *view)
{
VIEW(v, view);
/* _view_clear(view); */
evas_object_del(v->bg);
evas_object_del(v->sframe);
evas_object_del(v->span);
evry_tab_view_free(v->tabs);
E_FREE(v);
}
static Eina_Bool
_init(void)
{
view = E_NEW(Evry_View, 1);
view->id = view;
view->name = "Icon View";
view->create = &_view_create;
view->destroy = &_view_destroy;
view->update = &_view_update;
view->clear = &_view_clear;
view->cb_key_down = &_cb_key_down;
evry_view_register(view, 2);
view_types = eina_stringshare_add("FILE");
return EINA_TRUE;
}
static void
_shutdown(void)
{
eina_stringshare_del(view_types);
evry_view_unregister(view);
E_FREE(view);
}
EINA_MODULE_INIT(_init);
EINA_MODULE_SHUTDOWN(_shutdown);