From 9dad4016ef52ae71c0325ea9d078e499c484d51f Mon Sep 17 00:00:00 2001 From: quou Date: Thu, 13 Jun 2024 20:23:37 +1000 Subject: playlists and stuff --- main.c | 447 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 439 insertions(+), 8 deletions(-) (limited to 'main.c') diff --git a/main.c b/main.c index 0e6d281..9ba07d3 100644 --- a/main.c +++ b/main.c @@ -3,15 +3,66 @@ #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); @@ -52,6 +103,162 @@ void ui_update_seek(void) { 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, @@ -59,35 +266,44 @@ int libtab_msg( 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[lib.indices[m->index]]; + 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 1: + case 2: return snprintf( m->buffer, m->bufferBytes, "%s", song->artist ); - case 2: + case 3: return snprintf( m->buffer, m->bufferBytes, "%s", song->album ); - case 3: + case 4: return snprintf( m->buffer, m->bufferBytes, @@ -102,13 +318,139 @@ int libtab_msg( el->window->cursorX, el->window->cursorY ); - song = &lib.songs[lib.indices[hit]]; + 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, @@ -178,13 +520,32 @@ int seek_msg( 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; - UITable* libtab; + UIPanel* plib, * pctrl, * plist, * pqueue, * row; int r; + srand(time(0)); memory_init(mem); init_arena( &liba, @@ -193,6 +554,8 @@ int prog_main(void* mem) { ); build_library(&liba, &lib, library_path); init_player(&pl); + init_playlist(&queue); + init_playlist(&playlist); UIInitialise(); wi = UIWindowCreate( 0, @@ -280,6 +643,7 @@ int prog_main(void* mem) { "Queue", 5 ); + ui_create_playlist(&pqueue->e, &queue_ui, &queue); plist = UIPanelCreate(&split2->e, UI_PANEL_GRAY); plist->gap = 5; @@ -290,6 +654,57 @@ int prog_main(void* mem) { "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); @@ -299,10 +714,26 @@ int prog_main(void* mem) { "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\tArtist\tAlbum\tFilename" + "Track\tTitle\tArtist\tAlbum\tFilename" ); libtab->itemCount = lib.cnt; libtab->e.messageUser = libtab_msg; -- cgit v1.2.3-54-g00ecf