From 71ae0385eec2dede44a5de91249f3fb20abaa0bf Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Tue, 25 Nov 2025 04:27:27 +0900 Subject: [PATCH] mostly working --- mauplay/CMakeLists.txt | 1 + mauplay/audio.c | 12 +- mauplay/db.c | 32 +++- mauplay/main.c | 176 +++++++++++----------- mauplay/mauplay.h | 23 +-- mauplay/playlist.c | 44 ++++++ mauplay/repeatsong.xpm | 36 +++++ mauplay/ui.c | 327 +++++++++++++++++++++++++++++------------ 8 files changed, 458 insertions(+), 193 deletions(-) create mode 100644 mauplay/playlist.c create mode 100644 mauplay/repeatsong.xpm diff --git a/mauplay/CMakeLists.txt b/mauplay/CMakeLists.txt index dc1f1b9..5d79220 100644 --- a/mauplay/CMakeLists.txt +++ b/mauplay/CMakeLists.txt @@ -4,6 +4,7 @@ setup_project(mauplay ${CMAKE_INSTALL_BINDIR}) pkg_config_add(mauplay sqlite3) pkg_config_add(mauplay samplerate) +pkg_config_add(mauplay inih) target_link_libraries( mauplay diff --git a/mauplay/audio.c b/mauplay/audio.c index 65d6584..19734d2 100644 --- a/mauplay/audio.c +++ b/mauplay/audio.c @@ -8,6 +8,7 @@ pthread_mutex_t audio_mutex; queue_t* queue = NULL; int queue_seek = -1; int paused = 0; +int repeated = 0; static void handler(MDEAudio handle, void* user, void* data, int frames) { memset(data, 0, frames * 2 * 2); @@ -35,9 +36,14 @@ static void handler(MDEAudio handle, void* user, void* data, int frames) { free(to); if(f < from_frames) { - queue_seek++; - if(queue_seek >= arrlen(queue)) { - queue_seek = -1; + if(repeated) { + queue[queue_seek].frames = 0; + MDESoundSeek(queue[queue_seek].sound, 0); + } else { + queue_seek++; + if(queue_seek >= arrlen(queue)) { + queue_seek = -1; + } } } } diff --git a/mauplay/db.c b/mauplay/db.c index 8ba07c1..b782cbb 100644 --- a/mauplay/db.c +++ b/mauplay/db.c @@ -52,7 +52,7 @@ int db_init(void) { free(path); - if((st = db_exec("CREATE TABLE IF NOT EXISTS cache (path TEXT PRIMARY KEY, title TEXT, artist TEXT, album TEXT, genre TEXT, length INTEGER, mtime INTEGER)")) != 0) { + if((st = db_exec("CREATE TABLE IF NOT EXISTS cache (path TEXT PRIMARY KEY, title TEXT, artist TEXT, album TEXT, genre TEXT, length INTEGER, track INTEGER, mtime INTEGER)")) != 0) { sqlite3_close(db); return st; } @@ -68,6 +68,7 @@ static int db_bind(sqlite3_stmt* stmt, const char* path) { const char* s_album; const char* s_genre; int s_length; + int s_track = 0; struct stat s; if(sound == NULL) return 1; @@ -75,6 +76,7 @@ static int db_bind(sqlite3_stmt* stmt, const char* path) { s_artist = sound->context->artist; s_album = sound->context->album; s_genre = sound->context->genre; + s_track = sound->context->track; s_length = sound->context->frames / sound->context->sample_rate; if(s_title == NULL) s_title = path; @@ -92,7 +94,8 @@ static int db_bind(sqlite3_stmt* stmt, const char* path) { sqlite3_bind_text(stmt, 4, s_album, -1, SQLITE_TRANSIENT); sqlite3_bind_text(stmt, 5, s_genre, -1, SQLITE_TRANSIENT); sqlite3_bind_int(stmt, 6, s_length); - sqlite3_bind_int64(stmt, 7, s.st_mtime); + sqlite3_bind_int64(stmt, 7, s_track); + sqlite3_bind_int64(stmt, 8, s.st_mtime); MDESoundClose(sound); @@ -104,7 +107,7 @@ static int db_bind(sqlite3_stmt* stmt, const char* path) { void db_add(const char* path) { sqlite3_stmt* stmt; - if(sqlite3_prepare_v2(db, "INSERT OR REPLACE INTO cache VALUES(?,?,?,?,?,?,?)", -1, &stmt, NULL) != SQLITE_OK) { + if(sqlite3_prepare_v2(db, "INSERT OR REPLACE INTO cache VALUES(?,?,?,?,?,?,?,?)", -1, &stmt, NULL) != SQLITE_OK) { return; } @@ -196,3 +199,26 @@ void db_scan(void) { MwDispatchUserHandler(tree, MwNactivateHandler, ui_last); } + +char** db_find(const char* query, const char* param, const char* additional) { + char** r = NULL; + sqlite3_stmt* stmt; + char q[128]; + + sprintf(q, "SELECT * FROM cache WHERE %s = ? ORDER BY %s ASC", query, additional == NULL ? query : additional); + + if(sqlite3_prepare_v2(db, q, -1, &stmt, NULL) != SQLITE_OK) { + return NULL; + } + + sqlite3_bind_text(stmt, 1, param, -1, SQLITE_TRANSIENT); + + while(sqlite3_step(stmt) == SQLITE_ROW) { + char* p = MDEStringDuplicate(sqlite3_column_text(stmt, 0)); + arrput(r, p); + } + + sqlite3_finalize(stmt); + + return r; +} diff --git a/mauplay/main.c b/mauplay/main.c index 4222ca2..3e6fd64 100644 --- a/mauplay/main.c +++ b/mauplay/main.c @@ -7,15 +7,16 @@ #include "skipfwd.xpm" #include "repeat.xpm" +#include "repeatsong.xpm" #include "shuffle.xpm" MwWidget window; -MwWidget menu, album, infoframe, info, infosep, bskipback, bplay, bpause, bstop, bskipfwd, modesep, brepeat, bshuffle; +MwWidget menu, albumframe, album, infoframe, info, timelabel, infosep, bskipback, bplay, bpause, bstop, bskipfwd, modesep, brepeat, bshuffle; MwWidget mainsep; -MwWidget eltime, seekbar, rmtime; +MwWidget seekbar; MwWidget tree, list; -MwLLPixmap pxalbum, pxskipback, pxplay, pxpause, pxstop, pxskipfwd, pxrepeat, pxshuffle; -MwLLPixmap pxoptical; +MwLLPixmap pxalbum, pxskipback, pxplay, pxpause, pxstop, pxskipfwd, pxrepeat, pxrepeatsong, pxshuffle; +MwLLPixmap pxoptical, pxfoldermusic, pxgenre, pxartist; unsigned char* pxalbumdata; static void resize(MwWidget handle, void* user, void* client) { @@ -23,13 +24,20 @@ static void resize(MwWidget handle, void* user, void* client) { int wh = MwGetInteger(window, MwNheight) - MwGetInteger(menu, MwNheight); int y = MwGetInteger(menu, MwNheight); - MwVaApply(album, + MwVaApply(albumframe, MwNx, 5, MwNy, y + 5, MwNwidth, 32, MwNheight, 32, NULL); + MwVaApply(album, + MwNx, MwDefaultBorderWidth(album), + MwNy, MwDefaultBorderWidth(album), + MwNwidth, 32 - MwDefaultBorderWidth(album) * 2, + MwNheight, 32 - MwDefaultBorderWidth(album) * 2, + NULL); + MwVaApply(infoframe, MwNx, 5 + 32 + 5, MwNy, y + 5, @@ -44,6 +52,13 @@ static void resize(MwWidget handle, void* user, void* client) { MwNheight, MwGetInteger(infoframe, MwNheight) - MwDefaultBorderWidth(infoframe) * 2, NULL); + MwVaApply(timelabel, + MwNx, MwGetInteger(info, MwNwidth) * 2 / 3, + MwNy, MwDefaultBorderWidth(infoframe) + MwGetInteger(info, MwNheight) / 2, + MwNwidth, MwGetInteger(info, MwNwidth) / 3, + MwNheight, MwGetInteger(info, MwNheight) / 2, + NULL); + MwVaApply(infosep, MwNx, 5 + 32 + 5 + MwGetInteger(infoframe, MwNwidth), MwNy, y + 5, @@ -114,24 +129,10 @@ static void resize(MwWidget handle, void* user, void* client) { MwNheight, 10, NULL); - MwVaApply(eltime, + MwVaApply(seekbar, MwNx, 5, MwNy, y + 5 + 32 + 10, - MwNwidth, MwTextWidth(window, "000:00"), - MwNheight, 16, - NULL); - - MwVaApply(seekbar, - MwNx, 5 + MwTextWidth(window, "000:00") + 5, - MwNy, y + 5 + 32 + 10, - MwNwidth, ww - (5 + MwTextWidth(window, "000:00") + 5) * 2, - MwNheight, 16, - NULL); - - MwVaApply(rmtime, - MwNx, ww - 5 - MwTextWidth(window, "000:00"), - MwNy, y + 5 + 32 + 10, - MwNwidth, MwTextWidth(window, "000:00"), + MwNwidth, ww - 5 * 2, MwNheight, 16, NULL); @@ -157,68 +158,67 @@ int main() { MwLibraryInit(); - window = MwVaCreateWidget(MwWindowClass, "main", NULL, MwDEFAULT, MwDEFAULT, 600, 400, - MwNtitle, "mauplay", - NULL); - menu = MwCreateWidget(MwMenuClass, "menu", window, 0, 0, 0, 0); - album = MwCreateWidget(MwImageClass, "album", window, 0, 0, 0, 0); - infoframe = MwVaCreateWidget(MwFrameClass, "infoframe", window, 0, 0, 0, 0, - MwNbackground, "#000", - MwNforeground, "#0f0", - MwNhasBorder, 1, - MwNinverted, 1, - NULL); - info = MwVaCreateWidget(MwLabelClass, "info", infoframe, 0, 0, 0, 0, - MwNalignment, MwALIGNMENT_BEGINNING, - NULL); - infosep = MwVaCreateWidget(MwSeparatorClass, "infosep", window, 0, 0, 0, 0, - MwNorientation, MwVERTICAL, - NULL); - bskipback = MwVaCreateWidget(MwButtonClass, "skipback", window, 0, 0, 0, 0, - MwNflat, 1, - NULL); - bplay = MwVaCreateWidget(MwButtonClass, "play", window, 0, 0, 0, 0, - MwNflat, 1, - NULL); - bpause = MwVaCreateWidget(MwButtonClass, "pause", window, 0, 0, 0, 0, - MwNflat, 1, - NULL); - bstop = MwVaCreateWidget(MwButtonClass, "stop", window, 0, 0, 0, 0, - MwNflat, 1, - NULL); - bskipfwd = MwVaCreateWidget(MwButtonClass, "skipfwd", window, 0, 0, 0, 0, - MwNflat, 1, - NULL); - modesep = MwVaCreateWidget(MwSeparatorClass, "modesep", window, 0, 0, 0, 0, - MwNorientation, MwVERTICAL, - NULL); - brepeat = MwVaCreateWidget(MwButtonClass, "repeat", window, 0, 0, 0, 0, - MwNflat, 1, - NULL); - bshuffle = MwVaCreateWidget(MwButtonClass, "shuffle", window, 0, 0, 0, 0, - MwNflat, 1, - NULL); - mainsep = MwVaCreateWidget(MwSeparatorClass, "mainsep", window, 0, 0, 0, 0, - MwNorientation, MwHORIZONTAL, - NULL); - eltime = MwVaCreateWidget(MwLabelClass, "eltime", window, 0, 0, 0, 0, - MwNalignment, MwALIGNMENT_END, - MwNtext, "000:00", - NULL); - seekbar = MwVaCreateWidget(MwScrollBarClass, "seekbar", window, 0, 0, 0, 0, - MwNorientation, MwHORIZONTAL, - MwNareaShown, 15, - MwNshowArrows, 0, - NULL); - rmtime = MwVaCreateWidget(MwLabelClass, "rmtime", window, 0, 0, 0, 0, - MwNalignment, MwALIGNMENT_END, - MwNtext, "000:00", - NULL); - tree = MwCreateWidget(MwTreeViewClass, "tree", window, 0, 0, 0, 0); - list = MwVaCreateWidget(MwListBoxClass, "list", window, 0, 0, 0, 0, - MwNhasHeading, 1, - MwNleftPadding, 16, - NULL); + window = MwVaCreateWidget(MwWindowClass, "main", NULL, MwDEFAULT, MwDEFAULT, 600, 400, + MwNtitle, "mauplay", + NULL); + menu = MwCreateWidget(MwMenuClass, "menu", window, 0, 0, 0, 0); + albumframe = MwVaCreateWidget(MwFrameClass, "albumframe", window, 0, 0, 0, 0, + MwNhasBorder, 1, + MwNinverted, 1, + NULL); + album = MwCreateWidget(MwImageClass, "album", albumframe, 0, 0, 0, 0); + infoframe = MwVaCreateWidget(MwFrameClass, "infoframe", window, 0, 0, 0, 0, + MwNbackground, "#000", + MwNforeground, "#0f0", + MwNhasBorder, 1, + MwNinverted, 1, + NULL); + info = MwVaCreateWidget(MwLabelClass, "info", infoframe, 0, 0, 0, 0, + MwNalignment, MwALIGNMENT_BEGINNING, + NULL); + timelabel = MwVaCreateWidget(MwLabelClass, "timelabel", infoframe, 0, 0, 0, 0, + MwNalignment, MwALIGNMENT_END, + NULL); + infosep = MwVaCreateWidget(MwSeparatorClass, "infosep", window, 0, 0, 0, 0, + MwNorientation, MwVERTICAL, + NULL); + bskipback = MwVaCreateWidget(MwButtonClass, "skipback", window, 0, 0, 0, 0, + MwNflat, 1, + NULL); + bplay = MwVaCreateWidget(MwButtonClass, "play", window, 0, 0, 0, 0, + MwNflat, 1, + NULL); + bpause = MwVaCreateWidget(MwButtonClass, "pause", window, 0, 0, 0, 0, + MwNflat, 1, + NULL); + bstop = MwVaCreateWidget(MwButtonClass, "stop", window, 0, 0, 0, 0, + MwNflat, 1, + NULL); + bskipfwd = MwVaCreateWidget(MwButtonClass, "skipfwd", window, 0, 0, 0, 0, + MwNflat, 1, + NULL); + modesep = MwVaCreateWidget(MwSeparatorClass, "modesep", window, 0, 0, 0, 0, + MwNorientation, MwVERTICAL, + NULL); + brepeat = MwVaCreateWidget(MwButtonClass, "repeat", window, 0, 0, 0, 0, + MwNflat, 1, + NULL); + bshuffle = MwVaCreateWidget(MwButtonClass, "shuffle", window, 0, 0, 0, 0, + MwNflat, 1, + NULL); + mainsep = MwVaCreateWidget(MwSeparatorClass, "mainsep", window, 0, 0, 0, 0, + MwNorientation, MwHORIZONTAL, + NULL); + seekbar = MwVaCreateWidget(MwScrollBarClass, "seekbar", window, 0, 0, 0, 0, + MwNorientation, MwHORIZONTAL, + MwNareaShown, 15, + MwNshowArrows, 0, + NULL); + tree = MwCreateWidget(MwTreeViewClass, "tree", window, 0, 0, 0, 0); + list = MwVaCreateWidget(MwListBoxClass, "list", window, 0, 0, 0, 0, + MwNhasHeading, 1, + MwNleftPadding, 16, + NULL); pxalbumdata = malloc(ALBUMWIDTH * ALBUMWIDTH * 4); memset(pxalbumdata, 0, ALBUMWIDTH * ALBUMWIDTH * 4); @@ -232,10 +232,14 @@ int main() { free(pxalbumdata); - pxrepeat = MwLoadXPM(window, repeat_xpm); - pxshuffle = MwLoadXPM(window, shuffle_xpm); + pxrepeat = MwLoadXPM(window, repeat_xpm); + pxrepeatsong = MwLoadXPM(window, repeatsong_xpm); + pxshuffle = MwLoadXPM(window, shuffle_xpm); - pxoptical = MwLoadImage(window, ICON128DIR "/optical.png"); + pxoptical = MwLoadImage(window, ICON16DIR "/optical.png"); + pxfoldermusic = MwLoadImage(window, ICON16DIR "/folder-music.png"); + pxartist = MwLoadImage(window, ICON16DIR "/artist.png"); + pxgenre = MwLoadImage(window, ICON16DIR "/genre.png"); MwSetVoid(album, MwNpixmap, pxalbum); diff --git a/mauplay/mauplay.h b/mauplay/mauplay.h index 6ebf43e..bad3b25 100644 --- a/mauplay/mauplay.h +++ b/mauplay/mauplay.h @@ -37,14 +37,14 @@ typedef struct queue { } queue_t; /* main.c */ -extern MwWidget window; -extern MwWidget album, info; +extern MwWidget window, menu; +extern MwWidget album, info, timelabel; extern MwWidget bskipback, bplay, bpause, bstop, bskipfwd, brepeat, bshuffle; -extern MwWidget eltime, seekbar, rmtime; +extern MwWidget seekbar; extern MwWidget tree, list; extern unsigned char* pxalbumdata; -extern MwLLPixmap pxalbum; -extern MwLLPixmap pxoptical; +extern MwLLPixmap pxalbum, pxrepeat, pxrepeatsong; +extern MwLLPixmap pxoptical, pxfoldermusic, pxartist, pxgenre; /* db.c */ extern numkv_t* db_musics; @@ -52,10 +52,11 @@ extern numkv_t* db_albums; extern numkv_t* db_artists; extern numkv_t* db_genres; -int db_exec(const char* s); -int db_init(void); -void db_add(const char* path); -void db_scan(void); +int db_exec(const char* s); +int db_init(void); +void db_add(const char* path); +void db_scan(void); +char** db_find(const char* query, const char* param, const char* additional); /* ui.c */ extern void* ui_last; @@ -74,6 +75,7 @@ extern pthread_mutex_t audio_mutex; extern queue_t* queue; extern int queue_seek; extern int paused; +extern int repeated; void audio_init(void); void audio_queue(const char* path); @@ -81,4 +83,7 @@ void audio_queue(const char* path); /* id3.c */ unsigned char* id3_findimage(const char* path, size_t* size); +/* playlist.c */ +void playlist_add(const char* path); + #endif diff --git a/mauplay/playlist.c b/mauplay/playlist.c new file mode 100644 index 0000000..c3c1ced --- /dev/null +++ b/mauplay/playlist.c @@ -0,0 +1,44 @@ +#include "mauplay.h" + +#include +#include + +typedef struct song { + int key; + char* value; +} song_t; + +song_t* songs = NULL; +int count = 0; + +static int dumper(void* user, const char* section, const char* key, const char* value) { + if(strcmp(section, "playlist") != 0) return 1; + if(strcmp(key, "NumberOfEntries") == 0) { + count = atoi(value); + } + if(strlen(key) > 4 && memcmp(key, "File", 4) == 0) { + song_t s; + s.key = atoi(key + 4); + s.value = MDEStringDuplicate(value); + hmputs(songs, s); + } + + return 1; +} + +void playlist_add(const char* path) { + int i; + ini_parse(path, dumper, NULL); + + for(i = 0; i < count; i++) { + int ind = hmgeti(songs, i + 1); + if(ind == -1) continue; + + db_add(songs[ind].value); + } + for(i = 0; i < hmlen(songs); i++) { + free(songs[i].value); + } + hmfree(songs); + db_scan(); +} diff --git a/mauplay/repeatsong.xpm b/mauplay/repeatsong.xpm new file mode 100644 index 0000000..51aa0ca --- /dev/null +++ b/mauplay/repeatsong.xpm @@ -0,0 +1,36 @@ +/* XPM */ +static char *repeatsong_xpm[] = { +/* columns rows colors chars-per-pixel */ +"28 28 2 1 ", +" c None", +". c black", +/* pixels */ +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" .......... ", +" . . ", +" . . . ", +" . .. . ", +" . . . ", +" . . . ", +" . . . . ", +" . .. . ", +" .. ....... ", +" .. ", +" . ", +" ", +" ", +" ", +" ", +" ", +" ", +" " +}; diff --git a/mauplay/ui.c b/mauplay/ui.c index 5f148ed..e83aeb0 100644 --- a/mauplay/ui.c +++ b/mauplay/ui.c @@ -11,6 +11,10 @@ static void* genres; void* ui_last; static int changed = 0; +static void* file_add_file; +static void* file_add_directory; +static void* file_add_playlist; + void ui_list_reset(const char* merge) { void* p; @@ -90,102 +94,109 @@ void ui_set_genres(int v) { MwTreeViewSetLabel(tree, genres, buf); } -static void tree_activate(MwWidget handle, void* user, void* client) { - if(client == play_queue || client == all_music || client == albums || client == artists || client == genres) { - void* p = MwListBoxCreatePacket(); - int i; - if(client == play_queue) { - pthread_mutex_lock(&audio_mutex); - for(i = 0; i < arrlen(queue); i++) { - char buf[64]; - int ind = shgeti(db_musics, queue[i].path); - int index = MwListBoxPacketInsert(p, -1); - sprintf(buf, "%d", i + 1); +static char* current = NULL; +static char** current_list = NULL; +static void tree_activate(MwWidget handle, void* user, void* client) { + if(client == play_queue || client == all_music || client == albums || client == artists || client == genres) { + void* p = MwListBoxCreatePacket(); + int i; + if(current != NULL) free(current); + current = NULL; + if(client == play_queue) { + pthread_mutex_lock(&audio_mutex); + for(i = 0; i < arrlen(queue); i++) { + char buf[64]; + int ind = shgeti(db_musics, queue[i].path); + int index = MwListBoxPacketInsert(p, -1); + sprintf(buf, "%d", i + 1); - MwListBoxPacketSetIcon(p, index, pxoptical); - MwListBoxPacketSet(p, index, 0, buf); - MwListBoxPacketSet(p, index, 1, db_musics[ind].title); - MwListBoxPacketSet(p, index, 2, db_musics[ind].artist); + MwListBoxPacketSetIcon(p, index, pxoptical); + MwListBoxPacketSet(p, index, 0, buf); + MwListBoxPacketSet(p, index, 1, db_musics[ind].title); + MwListBoxPacketSet(p, index, 2, db_musics[ind].artist); - sprintf(buf, "%d:%02d", db_musics[ind].length / 60, db_musics[ind].length % 60); + sprintf(buf, "%d:%02d", db_musics[ind].length / 60, db_musics[ind].length % 60); - MwListBoxPacketSet(p, index, 3, buf); - } - pthread_mutex_unlock(&audio_mutex); - } - if(client == all_music) { - for(i = 0; i < shlen(db_musics); i++) { - char buf[64]; - int index = MwListBoxPacketInsert(p, -1); - sprintf(buf, "%d", i + 1); + MwListBoxPacketSet(p, index, 3, buf); + } + pthread_mutex_unlock(&audio_mutex); + } + if(client == all_music) { + for(i = 0; i < shlen(db_musics); i++) { + char buf[64]; + int index = MwListBoxPacketInsert(p, -1); + sprintf(buf, "%d", i + 1); - MwListBoxPacketSetIcon(p, index, pxoptical); - MwListBoxPacketSet(p, index, 0, buf); - MwListBoxPacketSet(p, index, 1, db_musics[i].title); - MwListBoxPacketSet(p, index, 2, db_musics[i].artist); + MwListBoxPacketSetIcon(p, index, pxoptical); + MwListBoxPacketSet(p, index, 0, buf); + MwListBoxPacketSet(p, index, 1, db_musics[i].title); + MwListBoxPacketSet(p, index, 2, db_musics[i].artist); - sprintf(buf, "%d:%02d", db_musics[i].length / 60, db_musics[i].length % 60); + sprintf(buf, "%d:%02d", db_musics[i].length / 60, db_musics[i].length % 60); - MwListBoxPacketSet(p, index, 3, buf); - } - } - if(client == albums) { - for(i = 0; i < shlen(db_albums); i++) { - char buf[64]; - int index = MwListBoxPacketInsert(p, -1); - sprintf(buf, "%d", i + 1); + MwListBoxPacketSet(p, index, 3, buf); + } + } + if(client == albums) { + for(i = 0; i < shlen(db_albums); i++) { + char buf[64]; + int index = MwListBoxPacketInsert(p, -1); + sprintf(buf, "%d", i + 1); - MwListBoxPacketSet(p, index, 0, buf); - MwListBoxPacketSet(p, index, 1, db_albums[i].key); + MwListBoxPacketSetIcon(p, index, pxfoldermusic); + MwListBoxPacketSet(p, index, 0, buf); + MwListBoxPacketSet(p, index, 1, db_albums[i].key); - sprintf(buf, "%d:%02d", db_musics[i].length / 60, db_albums[i].length % 60); + sprintf(buf, "%d:%02d", db_albums[i].length / 60, db_albums[i].length % 60); - MwListBoxPacketSet(p, index, 2, buf); - } - } - if(client == artists) { - for(i = 0; i < shlen(db_artists); i++) { - char buf[64]; - int index = MwListBoxPacketInsert(p, -1); - sprintf(buf, "%d", i + 1); + MwListBoxPacketSet(p, index, 2, buf); + } + } + if(client == artists) { + for(i = 0; i < shlen(db_artists); i++) { + char buf[64]; + int index = MwListBoxPacketInsert(p, -1); + sprintf(buf, "%d", i + 1); - MwListBoxPacketSet(p, index, 0, buf); - MwListBoxPacketSet(p, index, 1, db_artists[i].key); + MwListBoxPacketSetIcon(p, index, pxartist); + MwListBoxPacketSet(p, index, 0, buf); + MwListBoxPacketSet(p, index, 1, db_artists[i].key); - sprintf(buf, "%d:%02d", db_artists[i].length / 60, db_artists[i].length % 60); + sprintf(buf, "%d:%02d", db_artists[i].length / 60, db_artists[i].length % 60); - MwListBoxPacketSet(p, index, 2, buf); - } - } - if(client == genres) { - for(i = 0; i < shlen(db_genres); i++) { - char buf[64]; - int index = MwListBoxPacketInsert(p, -1); - sprintf(buf, "%d", i + 1); + MwListBoxPacketSet(p, index, 2, buf); + } + } + if(client == genres) { + for(i = 0; i < shlen(db_genres); i++) { + char buf[64]; + int index = MwListBoxPacketInsert(p, -1); + sprintf(buf, "%d", i + 1); - MwListBoxPacketSet(p, index, 0, buf); - MwListBoxPacketSet(p, index, 1, db_genres[i].key); + MwListBoxPacketSetIcon(p, index, pxgenre); + MwListBoxPacketSet(p, index, 0, buf); + MwListBoxPacketSet(p, index, 1, db_genres[i].key); - sprintf(buf, "%d:%02d", db_genres[i].length / 60, db_genres[i].length % 60); + sprintf(buf, "%d:%02d", db_genres[i].length / 60, db_genres[i].length % 60); - MwListBoxPacketSet(p, index, 2, buf); - } - } + MwListBoxPacketSet(p, index, 2, buf); + } + } - if(client == albums) { - ui_list_reset("Album"); - } else if(client == artists) { - ui_list_reset("Artist"); - } else if(client == genres) { - ui_list_reset("Genre"); - } else { - ui_list_reset(NULL); - } - MwListBoxInsert(list, -1, p); - MwListBoxDestroyPacket(p); + if(client == albums) { + ui_list_reset("Album"); + } else if(client == artists) { + ui_list_reset("Artist"); + } else if(client == genres) { + ui_list_reset("Genre"); + } else { + ui_list_reset(NULL); + } + MwListBoxInsert(list, -1, p); + MwListBoxDestroyPacket(p); - ui_last = client; - } + ui_last = client; + } } static void list_activate(MwWidget handle, void* user, void* client) { @@ -201,6 +212,70 @@ static void list_activate(MwWidget handle, void* user, void* client) { pthread_mutex_unlock(&audio_mutex); } else if(ui_last == all_music) { audio_queue(db_musics[(*(int*)client) - 1].key); + } else if(ui_last == albums || ui_last == artists || ui_last == genres) { + numkv_t* kv = NULL; + const char* n; + if(ui_last == albums) { + kv = db_albums; + n = "album"; + } + if(ui_last == artists) { + kv = db_artists; + n = "artist"; + } + if(ui_last == genres) { + kv = db_genres; + n = "genre"; + } + + if(current == NULL) { + void* p = MwListBoxCreatePacket(); + int i; + int index; + + current = MDEStringDuplicate(kv[(*(int*)client) - 1].key); + + for(i = 0; i < arrlen(current_list); i++) { + free(current_list[i]); + } + arrfree(current_list); + + index = MwListBoxPacketInsert(p, -1); + + MwListBoxPacketSetIcon(p, index, pxfoldermusic); + MwListBoxPacketSet(p, index, 0, ""); + MwListBoxPacketSet(p, index, 1, ".."); + + current_list = db_find(n, current, ui_last == albums ? "track" : NULL); + for(i = 0; i < arrlen(current_list); i++) { + char buf[128]; + numkv_t kv = shgets(db_musics, current_list[i]); + + index = MwListBoxPacketInsert(p, -1); + + sprintf(buf, "%d", i + 1); + + MwListBoxPacketSetIcon(p, index, pxoptical); + MwListBoxPacketSet(p, index, 0, buf); + MwListBoxPacketSet(p, index, 1, kv.title); + MwListBoxPacketSet(p, index, 2, kv.artist); + + sprintf(buf, "%d:%02d", kv.length / 60, kv.length % 60); + + MwListBoxPacketSet(p, index, 3, buf); + } + + ui_list_reset(NULL); + MwListBoxInsert(handle, -1, p); + MwListBoxDestroyPacket(p); + } else { + int index = *(int*)client; + if(index == 1) { + MwDispatchUserHandler(tree, MwNactivateHandler, ui_last); + } else { + audio_queue(current_list[index - 2]); + } + } } } @@ -271,16 +346,11 @@ static void window_tick(MwWidget handle, void* user, void* client) { } if(arrlen(queue) > 0 && queue_seek != -1) { int elsec = queue[queue_seek].frames / queue[queue_seek].sound->context->sample_rate; - int rmsec = (queue[queue_seek].sound->context->frames / queue[queue_seek].sound->context->sample_rate) - elsec; + int ttsec = queue[queue_seek].sound->context->frames / queue[queue_seek].sound->context->sample_rate; char buf[64]; - sprintf(buf, "%d:%02d", elsec / 60, elsec % 60); - MwVaApply(eltime, - MwNtext, buf, - NULL); - - sprintf(buf, "%d:%02d", rmsec / 60, rmsec % 60); - MwVaApply(rmtime, + sprintf(buf, "%d:%02d | %d:%02d", elsec / 60, elsec % 60, ttsec / 60, ttsec % 60); + MwVaApply(timelabel, MwNtext, buf, NULL); @@ -293,12 +363,12 @@ static void window_tick(MwWidget handle, void* user, void* client) { NULL); } } else { - MwVaApply(eltime, - MwNtext, "0:00", - NULL); - MwVaApply(rmtime, - MwNtext, "0:00", + MwVaApply(timelabel, + MwNtext, "", NULL); + memset(((MwLLCommonPixmap)pxalbum)->raw, 0, ALBUMWIDTH * ALBUMWIDTH * 4); + MwLLPixmapUpdate(pxalbum); + MwForceRender(album); } queue_last = queue_seek; pthread_mutex_unlock(&audio_mutex); @@ -362,7 +432,71 @@ static void bskipfwd_activate(MwWidget handle, void* user, void* client) { pthread_mutex_unlock(&audio_mutex); } +static void brepeat_activate(MwWidget handle, void* user, void* client) { + pthread_mutex_lock(&audio_mutex); + repeated = repeated ? 0 : 1; + MwVaApply(brepeat, + MwNpixmap, repeated ? pxrepeatsong : pxrepeat, + NULL); + pthread_mutex_unlock(&audio_mutex); +} + +static void file_fc_chosen(MwWidget handle, void* user, void* client) { + db_add(client); + db_scan(); +} + +static void playlist_fc_chosen(MwWidget handle, void* user, void* client) { + playlist_add(client); +} + +static void menu_menu(MwWidget handle, void* user, void* client) { + if(client == file_add_file) { + MwWidget fc = MwFileChooser(window, "Choose a file to add"); + MwAddUserHandler(fc, MwNfileChosenHandler, file_fc_chosen, NULL); + } else if(client == file_add_playlist) { + MwWidget fc = MwFileChooser(window, "Choose a playlist to add"); + MwAddUserHandler(fc, MwNfileChosenHandler, playlist_fc_chosen, NULL); + } +} + +static void list_mouseup(MwWidget handle, void* user, void* client) { + MwLLMouse* m = client; + int s; + if(ui_last != play_queue) return; + if(m->button != MwLLMouseRight) return; + if((s = MwGetInteger(list, MwNvalue)) == -1) return; + + pthread_mutex_lock(&audio_mutex); + MwListBoxDelete(list, s); + arrdel(queue, s - 1); + ui_set_play_queue(arrlen(queue)); + + if(queue_last == (s - 1)) { + queue_last = -1; + } else if(queue_last > (s - 1)) { + queue_last--; + queue_seek--; + } + if(arrlen(queue) <= queue_seek) { + queue_seek = arrlen(queue) - 1; + } + pthread_mutex_unlock(&audio_mutex); +} + void ui_init(void) { + MwMenu m; + int i; + MwWidget* l; + + m = MwMenuAdd(menu, NULL, "File"); + file_add_file = MwMenuAdd(menu, m, "Add File"); + file_add_directory = MwMenuAdd(menu, m, "Add Directory"); + file_add_playlist = MwMenuAdd(menu, m, "Add Playlist"); + + m = MwMenuAdd(menu, NULL, "?Help"); + MwMenuAdd(menu, m, "About"); + ui_list_reset(NULL); ui_tree_reset(); @@ -372,7 +506,14 @@ void ui_init(void) { ui_set_artists(0); ui_set_genres(0); + MwAddUserHandler(menu, MwNmenuHandler, menu_menu, NULL); + ui_last = all_music; + l = MwGetChildren(list); + for(i = 0; l[i] != NULL; i++) { + if(MwGetClass(l[i]) == MwFrameClass) MwAddUserHandler(l[i], MwNmouseUpHandler, list_mouseup, NULL); + } + free(l); MwAddUserHandler(list, MwNactivateHandler, list_activate, NULL); MwAddUserHandler(tree, MwNactivateHandler, tree_activate, NULL); MwAddUserHandler(window, MwNtickHandler, window_tick, NULL); @@ -383,4 +524,6 @@ void ui_init(void) { MwAddUserHandler(bpause, MwNactivateHandler, bpause_activate, NULL); MwAddUserHandler(bstop, MwNactivateHandler, bstop_activate, NULL); MwAddUserHandler(bskipfwd, MwNactivateHandler, bskipfwd_activate, NULL); + + MwAddUserHandler(brepeat, MwNactivateHandler, brepeat_activate, NULL); }