enjoy/src/bin/page.c

271 lines
7.2 KiB
C

#include "private.h"
#include <ctype.h>
/*
* TODO:
* - create page_folder that contains something other than songs, click one
* should create a new page, stack it into the parent list and recurse.
* - add suffle action for page_songs
*/
/* number of songs to populate at once before going back to mainloop */
#define PAGE_SONGS_POPULATE_ITERATION_COUNT (128)
typedef struct _Page
{
Evas_Object *layout;
Evas_Object *edje;
Evas_Object *list;
Evas_Object *index;
const char *title;
Elm_Genlist_Item *selected;
Elm_Genlist_Item *first;
Eina_Iterator *iterator;
Ecore_Idler *populate;
char last_index_letter[2];
} Page;
#define PAGE_SONGS_GET_OR_RETURN(page, obj, ...) \
Page *page = evas_object_data_get(obj, "_enjoy_page_songs"); \
do { if (!page) return __VA_ARGS__; } while (0)
static char *
_song_item_label_get(void *data, Evas_Object *list __UNUSED__, const char *part)
{
Song *song = data;
if (!strcmp(part, "text.title"))
return strdup(song->title);
else if (!strcmp(part, "text.album-artist"))
{
char *str;
if ((!song->album) && (!song->artist)) return NULL;
else if (!song->album) return strdup(song->artist);
else if (!song->artist) return strdup(song->album);
if (asprintf(&str, "%s - %s", song->album, song->artist) > 0)
return str;
return NULL;
}
else if (!strcmp(part, "text.album"))
return song->album ? strdup(song->album) : NULL;
else if (!strcmp(part, "text.artist"))
return song->artist ? strdup(song->artist) : NULL;
return NULL;
}
static void
_song_item_del(void *data, Evas_Object *list __UNUSED__)
{
db_song_free(data);
}
static const Elm_Genlist_Item_Class _song_item_class = {
"song",
{
_song_item_label_get,
NULL,
NULL,
_song_item_del
}
};
static Eina_Bool
_page_songs_populate(void *data)
{
Page *page = data;
const Song *orig;
Song *copy;
unsigned int count;
for (count = 0; count < PAGE_SONGS_POPULATE_ITERATION_COUNT; count++)
{
Elm_Genlist_Item *it;
char letter;
if (!eina_iterator_next(page->iterator, (void **)&orig)) goto end;
// TODO: evaluate if we should keep a full copy or just store
// fields of interest such as id, title, artist and album
copy = db_song_copy(orig);
if (!copy) goto end;
it = elm_genlist_item_append
(page->list, &_song_item_class, copy,
NULL, ELM_GENLIST_ITEM_NONE, NULL, NULL);
letter = toupper(copy->title[0]);
if (isalpha(letter) && (page->last_index_letter[0] != letter))
{
if ((page->first) && (!page->last_index_letter[0]))
elm_index_item_append(page->index, "Special", page->first);
page->last_index_letter[0] = letter;
elm_index_item_append(page->index, page->last_index_letter, it);
}
if (!page->first) page->first = it;
}
return EINA_TRUE;
end:
page->populate = NULL;
return EINA_FALSE;
}
static void
_page_songs_del(void *data, Evas *e __UNUSED__, Evas_Object *o __UNUSED__, void *event_info __UNUSED__)
{
Page *page = data;
eina_stringshare_del(page->title);
if (page->iterator) eina_iterator_free(page->iterator);
if (page->populate) ecore_idler_del(page->populate);
free(page);
}
static void
_page_songs_selected(void *data, Evas_Object *o __UNUSED__, void *event_info)
{
Page *page = data;
Elm_Genlist_Item *it = event_info;
Song *song = elm_genlist_item_data_get(it);
EINA_SAFETY_ON_NULL_RETURN(song);
if (page->selected == it) return;
page->selected = it;
evas_object_smart_callback_call(page->layout, "song", song);
}
static void
_page_songs_index_changed(void *data __UNUSED__, Evas_Object *o __UNUSED__, void *event_info)
{
Elm_Genlist_Item *it = event_info;
elm_genlist_item_top_bring_in(it);
}
Evas_Object *
page_songs_add(Evas_Object *parent, Eina_Iterator *it, const char *title)
{
Evas_Object *obj;
Page *page;
const char *s;
EINA_SAFETY_ON_NULL_RETURN_VAL(it, NULL);
obj = elm_layout_add(parent);
if (!obj)
{
eina_iterator_free(it);
return NULL;
}
page = calloc(1, sizeof(*page));
if (!page)
{
CRITICAL("could not allocate page memory!");
eina_iterator_free(it);
goto error;
}
evas_object_data_set(obj, "_enjoy_page_songs", page);
evas_object_event_callback_add
(obj, EVAS_CALLBACK_DEL, _page_songs_del, page);
page->layout = obj;
page->iterator = it;
if (!elm_layout_file_set(obj, PACKAGE_DATA_DIR "/default.edj", "page/songs"))
{
CRITICAL("no theme for 'page/songs' at %s",
PACKAGE_DATA_DIR "/default.edj");
goto error;
}
page->title = eina_stringshare_add(title);
page->edje = elm_layout_edje_get(obj);
edje_object_part_text_set(page->edje, "ejy.text.title", page->title);
page->list = elm_genlist_add(obj);
elm_genlist_bounce_set(page->list, EINA_FALSE, EINA_TRUE);
elm_genlist_horizontal_mode_set(page->list, ELM_LIST_COMPRESS);
elm_genlist_compress_mode_set(page->list, EINA_TRUE);
elm_genlist_block_count_set(page->list, 1024);
evas_object_smart_callback_add
(page->list, "selected", _page_songs_selected, page);
s = edje_object_data_get(page->edje, "homogeneous");
elm_genlist_homogeneous_set(page->list, s ? !!atoi(s) : EINA_FALSE);
printf("genlist homogeneous: %d\n", elm_genlist_homogeneous_get(page->list));
elm_layout_content_set(obj, "ejy.swallow.list", page->list);
page->index = elm_index_add(obj);
evas_object_smart_callback_add
(page->index, "delay,changed", _page_songs_index_changed, page);
elm_layout_content_set(obj, "ejy.swallow.index", page->index);
page->first = NULL;
page->populate = ecore_idler_add(_page_songs_populate, page);
return obj;
error:
evas_object_del(obj); /* should delete everything */
return NULL;
}
Song *
page_songs_selected_get(const Evas_Object *obj)
{
PAGE_SONGS_GET_OR_RETURN(page, obj, NULL);
return page->selected ? elm_genlist_item_data_get(page->selected) : NULL;
}
Eina_Bool
page_songs_next_exists(const Evas_Object *obj)
{
PAGE_SONGS_GET_OR_RETURN(page, obj, EINA_FALSE);
Elm_Genlist_Item *it = page->selected;
if (!it) return EINA_FALSE;
it = elm_genlist_item_next_get(it);
return !!it;
}
Song *
page_songs_next_go(Evas_Object *obj)
{
PAGE_SONGS_GET_OR_RETURN(page, obj, NULL);
Elm_Genlist_Item *it = page->selected;
Song *song;
if (!it) return NULL;
it = elm_genlist_item_next_get(it);
song = elm_genlist_item_data_get(it);
page->selected = it;
elm_genlist_item_selected_set(it, EINA_TRUE);
return song;
}
Eina_Bool
page_songs_prev_exists(const Evas_Object *obj)
{
PAGE_SONGS_GET_OR_RETURN(page, obj, EINA_FALSE);
Elm_Genlist_Item *it = page->selected;
if (!it) return EINA_FALSE;
it = elm_genlist_item_prev_get(it);
return !!it;
}
Song *
page_songs_prev_go(Evas_Object *obj)
{
PAGE_SONGS_GET_OR_RETURN(page, obj, NULL);
Elm_Genlist_Item *it = page->selected;
Song *song;
if (!it) return NULL;
it = elm_genlist_item_prev_get(it);
song = elm_genlist_item_data_get(it);
page->selected = it;
elm_genlist_item_selected_set(it, EINA_TRUE);
return song;
}