#include #include "config.h" #include "library.h" #include "luigi.h" #include "memory.h" #include "plat.h" #include "playlist.h" typedef struct { UITable* tab; Playlist* p; } Playlist_UI; typedef struct { int idx; UIMenu* menu; } PS_Ctx; Library lib; Player pl; Playlist queue, playlist; Playlist_UI queue_ui, playlist_ui; UIButton* play_button; UISlider* seek_slider; UIImageDisplay* cover_image; UILabel* title_text; UILabel* album_text; UILabel* artist_text; UIButton* playlist_select; UITable* libtab; char filter_text[64]; char playlist_names[64][64]; void ui_update_playlist(void) { playlist_ui.tab->itemCount = playlist.cnt; UITableResizeColumns(playlist_ui.tab); UIElementRefresh(&playlist_ui.tab->e); playlist_select->label = UIStringCopy( playlist.name, -1 ); playlist_select->labelBytes = strlen(playlist.name); UIElementRefresh(playlist_select->e.parent); } void ui_update_queue(void) { queue_ui.tab->itemCount = queue.cnt; UITableResizeColumns(queue_ui.tab); UIElementRefresh(&queue_ui.tab->e); } void ui_add_to_playlist(void* cp) { playlist_add(&playlist, cp); ui_update_playlist(); } void ui_add_to_queue(void* cp) { playlist_add(&queue, cp); ui_update_queue(); } void ui_queue_next(void* cp) { playlist_add_first(&queue, cp); ui_update_queue(); } void ui_update_play(void) { UI_FREE(play_button->label); play_button->label = UIStringCopy( pl.play? "Pause": "Play", -1 ); UIImageDisplaySetContent( cover_image, pl.cover, album_cover_w, album_cover_h, album_cover_w * 4 ); UILabelSetContent( title_text, pl.song->name, -1 ); UILabelSetContent( album_text, pl.song->album, -1 ); UILabelSetContent( artist_text, pl.song->artist, -1 ); UIElementRefresh(cover_image->e.parent); } void ui_update_seek(void) { float p; if (!pl.song) return; p = (float)pl.cs / (float)pl.ms; seek_slider->position = p; UIElementRefresh((UIElement*)seek_slider); } int filter_msg( UIElement* el, UIMessage msg, int di, void* dp ) { UITextbox* tb = (UITextbox*)el; (void)di; (void)dp; int s = sizeof filter_text - 1; if (msg == UI_MSG_VALUE_CHANGED) { if (!tb->bytes) { filter_text[0] = 0; libtab->itemCount = lib.cnt; UIElementRefresh((UIElement*)libtab); return 0; } if (s > tb->bytes) s = tb->bytes - 1; memcpy(filter_text, tb->string, s); filter_text[tb->bytes] = 0; filter_library(&lib, filter_text); libtab->itemCount = lib.fcnt; UIElementRefresh((UIElement*)libtab); } return 0; } int new_msg( UIElement* el, UIMessage msg, int di, void* dp ) { char* buf; const char* r; int e; (void)di; (void)dp; if (msg == UI_MSG_CLICKED) { r = UIDialogShow( el->window, 0, "%s%t\n%b%b", "Name", &buf, "Okay", "Cancel" ); if (!strcmp(r, "Okay")) { init_playlist(&playlist); memcpy(playlist.name, buf, sizeof playlist.name); e = sizeof playlist.name - 1; if (playlist.name[e]) playlist.name[e] = 0; ui_update_playlist(); } } return 0; } int save_msg( UIElement* el, UIMessage msg, int di, void* dp ) { char* buf; const char* r; int e; (void)di; (void)dp; if (msg == UI_MSG_CLICKED) { if (!playlist.name[0]) { r = UIDialogShow( el->window, 0, "%s%t\n%b%b", "Name", &buf, "Okay", "Cancel" ); if (!strcmp(r, "Okay")) { memcpy(playlist.name, buf, sizeof playlist.name); e = sizeof playlist.name - 1; if (playlist.name[e]) playlist.name[e] = 0; ui_update_playlist(); } else { return 0; } } playlist_save(&playlist); } return 0; } void ps_select(void* cp) { int idx; const char* n; idx = (int)(uintptr_t)cp; n = playlist_names[idx]; if (playlist_load(&lib, &playlist, n)) ui_update_playlist(); } void ps_iter(void* u, const char* path) { PS_Ctx* ctx = u; UIMenu* menu; const char* name; int nl; menu = ctx->menu; name = path + strlen(path); for (; name != path && *name != '/'; name--); for (nl = 0; name[nl] && name[nl] != '.'; nl++); name++; /* this fails if library path is bad xDDD */ nl--; /* ... or if the path doesn't have an extension */ memcpy(playlist_names[ctx->idx], name, nl); playlist_names[ctx->idx][nl] = 0; UIMenuAddItem( menu, 0, name, nl, ps_select, (void*)(uintptr_t)ctx->idx ); ctx->idx++; } int ps_msg( UIElement* el, UIMessage msg, int di, void* dp ) { (void)di; (void)dp; if (msg == UI_MSG_CLICKED) { UIMenu* menu; char buf[256]; PS_Ctx ctx; get_playlist_dir(buf); if (dir_exist(buf)) { menu = UIMenuCreate( &el->window->e, 0 ); ctx.menu = menu; ctx.idx = 0; iter_dir(buf, ps_iter, &ctx); UIMenuShow(menu); } } return 0; } int libtab_msg( UIElement* el, UIMessage msg, int di, void* dp ) { Song* song; int* ind; (void)di; (void)dp; ind = filter_text[0]? lib.filtered: lib.indices; if (msg == UI_MSG_TABLE_GET_ITEM) { UITableGetItem *m = (UITableGetItem*)dp; song = &lib.songs[ind[m->index]]; m->isSelected = 0; switch (m->column) { case 0: return snprintf( m->buffer, m->bufferBytes, "%d", song->track ); case 1: return snprintf( m->buffer, m->bufferBytes, "%s", song->name ); case 2: return snprintf( m->buffer, m->bufferBytes, "%s", song->artist ); case 3: return snprintf( m->buffer, m->bufferBytes, "%s", song->album ); case 4: return snprintf( m->buffer, m->bufferBytes, "%s", song->path ); default: return 0; } } else if (msg == UI_MSG_LEFT_UP) { int hit = UITableHitTest( (UITable*)el, el->window->cursorX, el->window->cursorY ); song = &lib.songs[ind[hit]]; play_song(&pl, song); ui_update_play(); } else if (msg == UI_MSG_RIGHT_DOWN) { UIMenu* menu; int hit = UITableHitTest( (UITable*)el, el->window->cursorX, el->window->cursorY ); song = &lib.songs[ind[hit]]; menu = UIMenuCreate( &el->window->e, UI_MENU_NO_SCROLL ); UIMenuAddItem( menu, 0, "Add to Playlist", -1, ui_add_to_playlist, song ); UIMenuAddItem( menu, 0, "Add to Queue", -1, ui_add_to_queue, song ); UIMenuAddItem( menu, 0, "Queue Next", -1, ui_queue_next, song ); UIMenuShow(menu); } return 0; } int playlist_tab_msg( UIElement* el, UIMessage msg, int di, void* dp ) { Playlist* p = el->cp; Song* song; int* ind; (void)di; ind = filter_text[0]? lib.filtered: lib.indices; if (msg == UI_MSG_TABLE_GET_ITEM) { UITableGetItem *m = (UITableGetItem*)dp; song = p->songs[m->index]; switch (m->column) { case 0: return snprintf( m->buffer, m->bufferBytes, "%d", song->track ); case 1: return snprintf( m->buffer, m->bufferBytes, "%s", song->name ); case 2: return snprintf( m->buffer, m->bufferBytes, "%s", song->artist ); case 3: return snprintf( m->buffer, m->bufferBytes, "%s", song->album ); default: return 0; } } else if (msg == UI_MSG_RIGHT_DOWN) { if (p == &playlist) { UIMenu* menu; int hit = UITableHitTest( (UITable*)el, el->window->cursorX, el->window->cursorY ); song = playlist.songs[hit]; menu = UIMenuCreate( &el->window->e, UI_MENU_NO_SCROLL ); UIMenuAddItem( menu, 0, "Add to Queue", -1, ui_add_to_queue, song ); UIMenuAddItem( menu, 0, "Queue Next", -1, ui_queue_next, song ); UIMenuShow(menu); } } else if (msg == UI_MSG_LEFT_UP) { int hit = UITableHitTest( (UITable*)el, el->window->cursorX, el->window->cursorY ); song = &lib.songs[ind[hit]]; if (play_song(&pl, song)) ui_update_play(); } return 0; } int playpause_msg( UIElement* el, UIMessage msg, int di, void* dp ) { (void)el; (void)di; (void)dp; if (msg == UI_MSG_CLICKED) { if (!pl.song) return 0; pl.play = !pl.play; ui_update_play(); } return 0; } int start_msg( UIElement* el, UIMessage msg, int di, void* dp ) { (void)el; (void)di; (void)dp; if (msg == UI_MSG_CLICKED) { if (!pl.song) return 0; play_seek(&pl, 0.0f); } return 0; } int end_msg( UIElement* el, UIMessage msg, int di, void* dp ) { (void)el; (void)di; (void)dp; if (msg == UI_MSG_CLICKED) { if (!pl.song) return 0; play_seek(&pl, 1.0f); } return 0; } int seek_msg( UIElement* el, UIMessage msg, int di, void* dp ) { UISlider* sl; (void)el; (void)di; (void)dp; if (msg == UI_MSG_VALUE_CHANGED) { sl = (UISlider*)el; play_seek(&pl, sl->position); } else if (msg == UI_MSG_ANIMATE) { ui_update_seek(); } return 0; } void ui_create_playlist( UIElement* pa, Playlist_UI* pu, Playlist* p ) { UITable* tab; tab = UITableCreate( pa, UI_ELEMENT_H_FILL | UI_ELEMENT_V_FILL, "Track\tTitle\tArtist\tAlbum" ); tab->itemCount = p->cnt; tab->e.messageUser = playlist_tab_msg; tab->e.cp = p; UITableResizeColumns(tab); pu->tab = tab; pu->p = p; } int prog_main(void* mem) { Arena liba; UIWindow* wi; UISplitPane* split1, * split2, * split3; UIPanel* plib, * pctrl, * plist, * pqueue, * row; int r; srand(time(0)); memory_init(mem); init_arena( &liba, galloc(library_memory_size), library_memory_size ); build_library(&liba, &lib, library_path); init_player(&pl); init_playlist(&queue); init_playlist(&playlist); UIInitialise(); wi = UIWindowCreate( 0, 0, app_name, default_window_w, default_window_h ); split1 = UISplitPaneCreate( &wi->e, 0, 0.3f ); split3 = UISplitPaneCreate( &split1->e, UI_SPLIT_PANE_VERTICAL, 0.5f ); split2 = UISplitPaneCreate( &split1->e, 0, 0.5f ); pctrl = UIPanelCreate(&split3->e, UI_PANEL_GRAY); pctrl->gap = 5; pctrl->border = UI_RECT_1(5); title_text = UILabelCreate( &pctrl->e, 0, "", -1 ); album_text = UILabelCreate( &pctrl->e, 0, "", -1 ); artist_text = UILabelCreate( &pctrl->e, 0, "", -1 ); cover_image = UIImageDisplayCreate( &pctrl->e, 0, (unsigned*)pl.cover, album_cover_w, album_cover_h, album_cover_w ); play_button = UIButtonCreate( &pctrl->e, 0, "Play", -1 ); play_button->e.messageUser = playpause_msg; UIButtonCreate( &pctrl->e, 0, "Start", -1 )->e.messageUser = start_msg; UIButtonCreate( &pctrl->e, 0, "End", -1 )->e.messageUser = end_msg; seek_slider = UISliderCreate( &pctrl->e, UI_ELEMENT_H_FILL ); seek_slider->e.messageUser = seek_msg; pqueue = UIPanelCreate(&split3->e, UI_PANEL_GRAY); pqueue->gap = 5; pqueue->border = UI_RECT_1(5); UILabelCreate( &pqueue->e, 0, "Queue", 5 ); ui_create_playlist(&pqueue->e, &queue_ui, &queue); plist = UIPanelCreate(&split2->e, UI_PANEL_GRAY); plist->gap = 5; plist->border = UI_RECT_1(5); UILabelCreate( &plist->e, 0, "Playlist", 8 ); playlist_select = UIButtonCreate( &plist->e, 0, "", 0 ); playlist_select->e.messageUser = ps_msg; row = UIPanelCreate( &plist->e, UI_PANEL_HORIZONTAL | UI_ELEMENT_H_FILL ); UIButtonCreate( &row->e, 0, "New", -1 )->e.messageUser = new_msg; UIButtonCreate( &row->e, 0, "Save", -1 )->e.messageUser = save_msg; UISpacerCreate(&row->e, 0, 10, 0); UIButtonCreate( &row->e, 0, "Play", -1 ); UIButtonCreate( &row->e, 0, "Play Shuffled", -1 ); UISpacerCreate(&row->e, 0, 10, 0); UIButtonCreate( &row->e, 0, "Enqueue", -1 ); UIButtonCreate( &row->e, 0, "Enqueue Shuffled", -1 ); ui_create_playlist(&plist->e, &playlist_ui, &playlist); plib = UIPanelCreate(&split2->e, UI_PANEL_GRAY); plib->gap = 5; plib->border = UI_RECT_1(5); UILabelCreate( &plib->e, 0, "Library", 7 ); row = UIPanelCreate( &plib->e, UI_PANEL_HORIZONTAL | UI_ELEMENT_H_FILL ); UILabelCreate( &row->e, 0, "Filter", -1 ); UISpacerCreate(&row->e, 0, 10, 0); UITextboxCreate( &row->e, UI_ELEMENT_H_FILL )->e.messageUser = filter_msg; libtab = UITableCreate( &plib->e, UI_ELEMENT_H_FILL | UI_ELEMENT_V_FILL, "Track\tTitle\tArtist\tAlbum\tFilename" ); libtab->itemCount = lib.cnt; libtab->e.messageUser = libtab_msg; UITableResizeColumns(libtab); r = UIMessageLoop(); deinit_player(&pl); return r; }