You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

1791 lines
51 KiB

/***************************************************************************
* Copyright (C) 2008 by Andrzej Rybczak *
* electricityispower@gmail.com *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include "ncmpcpp.h"
#include "mpdpp.h"
#include "status_checker.h"
#include "helpers.h"
#include "settings.h"
#include "song.h"
#include "lyrics.h"
#define LOCK_STATUSBAR \
if (Config.statusbar_visibility) \
block_statusbar_update = 1; \
else \
block_progressbar_update = 1; \
allow_statusbar_unblock = 0
#define UNLOCK_STATUSBAR \
allow_statusbar_unblock = 1; \
if (block_statusbar_update_delay <= 0) \
{ \
if (Config.statusbar_visibility) \
block_statusbar_update = 0; \
else \
block_progressbar_update = 0; \
}
#define REFRESH_MEDIA_LIBRARY_SCREEN \
mLibArtists->Display(redraw_me); \
mvvline(main_start_y, lib_albums_start_x-1, 0, main_height); \
mLibAlbums->Display(redraw_me); \
mvvline(main_start_y, lib_songs_start_x-1, 0, main_height); \
mLibSongs->Display(redraw_me)
#ifdef HAVE_TAGLIB_H
const string tag_screen = "Tag editor";
const string tag_screen_keydesc = "\te : Edit song's tags\n";
#else
const string tag_screen = "Tag info";
const string tag_screen_keydesc = "\te : Show song's tags\n";
#endif
ncmpcpp_config Config;
SongList vPlaylist;
SongList vSearched;
ItemList vBrowser;
TagList vArtists;
SongList vSongs;
vector<int> vFoundPositions;
int found_pos = 0;
Window *wCurrent = 0;
Window *wPrev = 0;
Menu *mPlaylist;
Menu *mBrowser;
Menu *mTagEditor;
Menu *mSearcher;
Menu *mLibArtists;
Menu *mLibAlbums;
Menu *mLibSongs;
Scrollpad *sHelp;
Scrollpad *sLyrics;
Window *wHeader;
Window *wFooter;
MPDConnection *Mpd;
time_t block_delay;
time_t timer;
time_t now;
int now_playing = -1;
int playing_song_scroll_begin = 0;
int browsed_dir_scroll_begin = 0;
int stats_scroll_begin = 0;
int block_statusbar_update_delay = -1;
string browsed_dir = "/";
string browsed_subdir;
string song_lyrics;
string player_state;
string volume_state;
string switch_state;
string mpd_repeat;
string mpd_random;
string mpd_crossfade;
string mpd_db_updating;
NcmpcppScreen current_screen;
NcmpcppScreen prev_screen;
Song edited_song;
Song searched_song;
bool main_exit = 0;
bool messages_allowed = 0;
bool title_allowed = 0;
bool header_update_status = 0;
bool dont_change_now_playing = 0;
bool block_progressbar_update = 0;
bool block_statusbar_update = 0;
bool allow_statusbar_unblock = 1;
bool block_playlist_update = 0;
bool block_library_update = 0;
bool search_case_sensitive = 1;
bool search_mode_match = 1;
bool redraw_me = 0;
extern string EMPTY_TAG;
extern string UNKNOWN_ARTIST;
extern string UNKNOWN_TITLE;
extern string UNKNOWN_ALBUM;
extern string playlist_stats;
const string message_part_of_songs_added = "Only part of requested songs' list added to playlist!";
int main(int argc, char *argv[])
{
DefaultConfiguration(Config);
ReadConfiguration(Config);
DefineEmptyTags();
Mpd = new MPDConnection;
if (getenv("MPD_HOST"))
Mpd->SetHostname(getenv("MPD_HOST"));
if (getenv("MPD_PORT"))
Mpd->SetPort(atoi(getenv("MPD_PORT")));
if (getenv("MPD_PASSWORD"))
Mpd->SetPassword(getenv("MPD_PASSWORD"));
Mpd->SetTimeout(Config.mpd_connection_timeout);
if (!Mpd->Connect())
{
printf("Cannot connect to mpd (%s)\n", Mpd->GetLastErrorMessage().c_str());
return -1;
}
setlocale(LC_ALL,"");
initscr();
noecho();
cbreak();
curs_set(0);
if (Config.colors_enabled)
EnableColors();
int main_start_y = 2;
int main_height = LINES-4;
if (!Config.header_visibility)
{
main_start_y -= 2;
main_height += 2;
}
if (!Config.statusbar_visibility)
main_height++;
mPlaylist = new Menu(0, main_start_y, COLS, main_height, "", Config.main_color, brNone);
mBrowser = new Menu(mPlaylist->EmptyClone());
mTagEditor = new Menu(mPlaylist->EmptyClone());
mSearcher = new Menu(mPlaylist->EmptyClone());
int lib_artist_width = COLS/3-1;
int lib_albums_width = COLS/3;
int lib_albums_start_x = lib_artist_width+1;
int lib_songs_width = COLS-COLS/3*2-1;
int lib_songs_start_x = lib_artist_width+lib_albums_width+2;
mLibArtists = new Menu(0, main_start_y, lib_artist_width, main_height, "Artists", Config.main_color, brNone);
mLibAlbums = new Menu(lib_albums_start_x, main_start_y, lib_albums_width, main_height, "Albums", Config.main_color, brNone);
mLibSongs = new Menu(lib_songs_start_x, main_start_y, lib_songs_width, main_height, "Songs", Config.main_color, brNone);
sHelp = new Scrollpad(0, main_start_y, COLS, main_height, "", Config.main_color, brNone);
sLyrics = new Scrollpad(sHelp->EmptyClone());
sHelp->Add(" [b]Keys - Movement\n -----------------------------------------[/b]\n");
sHelp->Add("\tUp : Move Cursor up\n");
sHelp->Add("\tDown : Move Cursor down\n");
sHelp->Add("\tPage up : Page up\n");
sHelp->Add("\tPage down : Page down\n");
sHelp->Add("\tHome : Home\n");
sHelp->Add("\tEnd : End\n\n");
sHelp->Add("\tTab : Switch between playlist and browser\n");
sHelp->Add("\t1 : Help screen\n");
sHelp->Add("\t2 : Playlist screen\n");
sHelp->Add("\t3 : Browse screen\n");
sHelp->Add("\t4 : Search engine\n");
sHelp->Add("\t5 : Media library\n\n\n");
sHelp->Add(" [b]Keys - Global\n -----------------------------------------[/b]\n");
sHelp->Add("\ts : Stop\n");
sHelp->Add("\tP : Pause\n");
sHelp->Add("\t> : Next track\n");
sHelp->Add("\t< : Previous track\n");
sHelp->Add("\tf : Seek forward\n");
sHelp->Add("\tb : Seek backward\n");
sHelp->Add("\t- Left : Decrease volume\n");
sHelp->Add("\t+ Right : Increase volume\n\n");
sHelp->Add("\tr : Toggle repeat mode\n");
sHelp->Add("\tz : Toggle random mode\n");
sHelp->Add("\tZ : Shuffle playlist\n");
sHelp->Add("\tx : Toggle crossfade mode\n");
sHelp->Add("\tX : Set crossfade\n");
sHelp->Add("\tu : Start a music database update\n\n");
sHelp->Add("\t/ : Forward find\n");
sHelp->Add("\t? : Backward find\n");
sHelp->Add("\t, : Go to previous found position\n");
sHelp->Add("\t. : Go to next found position\n");
sHelp->Add(tag_screen_keydesc);
sHelp->Add("\tg : Go to chosen position in current song\n");
sHelp->Add("\tl : Show/hide song's lyrics\n\n");
sHelp->Add("\tQ q : Quit\n\n\n");
sHelp->Add(" [b]Keys - Playlist screen\n -----------------------------------------[/b]\n");
sHelp->Add("\tEnter : Play\n");
sHelp->Add("\tDelete : Delete song from playlist\n");
sHelp->Add("\tc : Clear whole playlist\n");
sHelp->Add("\tC : Clear playlist but hold currently playing song\n");
sHelp->Add("\tm : Move song up\n");
sHelp->Add("\tn : Move song down\n");
sHelp->Add("\tS : Save playlist\n");
sHelp->Add("\to : Go to currently playing position\n\n\n");
sHelp->Add(" [b]Keys - Browse screen\n -----------------------------------------[/b]\n");
sHelp->Add("\tEnter : Enter directory/Add to playlist and play song\n");
sHelp->Add("\tSpace : Add song to playlist\n");
sHelp->Add("\tBackspace : Go to parent directory\n");
sHelp->Add("\tDelete : Delete playlist\n\n\n");
sHelp->Add(" [b]Keys - Search engine\n -----------------------------------------[/b]\n");
sHelp->Add("\tEnter : Change option/Add to playlist and play song\n");
sHelp->Add("\tSpace : Add song to playlist\n\n\n");
sHelp->Add(" [b]Keys - Media library\n -----------------------------------------[/b]\n");
sHelp->Add("\tLeft : Previous column\n");
sHelp->Add("\tRight : Next column\n");
sHelp->Add("\tEnter : Add to playlist and play song/album/artist's songs\n");
sHelp->Add("\tSpace : Add to playlist song/album/artist's songs\n\n\n");
# ifdef HAVE_TAGLIB_H
sHelp->Add(" [b]Keys - Tag editor\n -----------------------------------------[/b]\n");
sHelp->Add("\tEnter : Change option\n");
# else
sHelp->Add(" [b]Keys - Tag info\n -----------------------------------------[/b]\n");
sHelp->Add("\tEnter : Return\n");
# endif
if (Config.header_visibility)
{
wHeader = new Window(0, 0, COLS, 2, "", Config.header_color, brNone);
wHeader->Display();
}
int footer_start_y = LINES-(Config.statusbar_visibility ? 2 : 1);
int footer_height = Config.statusbar_visibility ? 2 : 1;
wFooter = new Window(0, footer_start_y, COLS, footer_height, "", Config.statusbar_color, brNone);
wFooter->Display();
wCurrent = mPlaylist;
current_screen = csPlaylist;
wCurrent->Display();
int input;
timer = time(NULL);
sHelp->Timeout(ncmpcpp_window_timeout);
mPlaylist->Timeout(ncmpcpp_window_timeout);
mBrowser->Timeout(ncmpcpp_window_timeout);
mTagEditor->Timeout(ncmpcpp_window_timeout);
mSearcher->Timeout(ncmpcpp_window_timeout);
mLibArtists->Timeout(ncmpcpp_window_timeout);
mLibAlbums->Timeout(ncmpcpp_window_timeout);
mLibSongs->Timeout(ncmpcpp_window_timeout);
sLyrics->Timeout(ncmpcpp_window_timeout);
wFooter->Timeout(ncmpcpp_window_timeout);
mPlaylist->HighlightColor(Config.main_highlight_color);
mBrowser->HighlightColor(Config.main_highlight_color);
mTagEditor->HighlightColor(Config.main_highlight_color);
mSearcher->HighlightColor(Config.main_highlight_color);
mLibArtists->HighlightColor(Config.main_highlight_color);
mLibArtists->HighlightColor(Config.main_highlight_color);
mLibAlbums->HighlightColor(Config.main_highlight_color);
mLibSongs->HighlightColor(Config.main_highlight_color);
Mpd->SetStatusUpdater(NcmpcppStatusChanged, NULL);
Mpd->SetErrorHandler(NcmpcppErrorCallback, NULL);
while (!main_exit)
{
if (!Mpd->Connected())
{
ShowMessage("Attempting to reconnect...");
Mpd->Disconnect();
if (Mpd->Connect())
ShowMessage("Connected!");
messages_allowed = 0;
}
TraceMpdStatus();
block_playlist_update = 0;
messages_allowed = 1;
if (Config.header_visibility)
{
string title;
const int max_allowed_title_length = wHeader->GetWidth()-volume_state.length();
switch (current_screen)
{
case csHelp:
title = "Help";
break;
case csPlaylist:
title = "Playlist ";
break;
case csBrowser:
title = "Browse: ";
break;
case csTagEditor:
title = tag_screen;
break;
case csSearcher:
title = "Search engine";
break;
case csLibrary:
title = "Media library";
break;
case csLyrics:
title = song_lyrics;
break;
}
if (title_allowed)
{
wHeader->Bold(1);
wHeader->WriteXY(0, 0, max_allowed_title_length, title, 1);
wHeader->Bold(0);
if (current_screen == csPlaylist && !playlist_stats.empty())
wHeader->WriteXY(title.length(), 0, max_allowed_title_length-title.length(), playlist_stats);
if (current_screen == csBrowser)
{
int max_length_without_scroll = wHeader->GetWidth()-volume_state.length()-title.length();
ncmpcpp_string_t wbrowseddir = NCMPCPP_TO_WSTRING(browsed_dir);
wHeader->Bold(1);
if (browsed_dir.length() > max_length_without_scroll)
{
# ifdef UTF8_ENABLED
wbrowseddir += L" ** ";
# else
wbrowseddir += " ** ";
# endif
const int scrollsize = max_length_without_scroll;
ncmpcpp_string_t part = wbrowseddir.substr(browsed_dir_scroll_begin++, scrollsize);
if (part.length() < scrollsize)
part += wbrowseddir.substr(0, scrollsize-part.length());
wHeader->WriteXY(title.length(), 0, part);
if (browsed_dir_scroll_begin >= wbrowseddir.length())
browsed_dir_scroll_begin = 0;
}
else
wHeader->WriteXY(title.length(), 0, browsed_dir);
wHeader->Bold(0);
}
}
else
wHeader->WriteXY(0, 0, max_allowed_title_length, "[b]1:[/b]Help [b]2:[/b]Playlist [b]3:[/b]Browse [b]4:[/b]Search [b]5:[/b]Library", 1);
wHeader->SetColor(Config.volume_color);
wHeader->WriteXY(max_allowed_title_length, 0, volume_state);
wHeader->SetColor(Config.header_color);
}
if (current_screen == csLibrary && !block_library_update)
{
if (wCurrent == mLibAlbums && mLibAlbums->Empty())
{
mLibAlbums->HighlightColor(Config.main_highlight_color);
mLibArtists->HighlightColor(Config.library_active_column_color);
wCurrent = mLibArtists;
}
if (wCurrent == mLibArtists)
{
TagList list;
mLibAlbums->Clear();
Mpd->GetAlbums(mLibArtists->GetCurrentOption(), list);
for (TagList::const_iterator it = list.begin(); it != list.end(); it++)
mLibAlbums->AddOption(*it);
}
if (mLibAlbums->Empty())
{
mLibAlbums->WriteXY(0, 0, "No albums found.");
mLibSongs->Clear(0);
FreeSongList(vSongs);
Mpd->StartSearch(1);
Mpd->AddSearch(MPD_TAG_ITEM_ARTIST, mLibArtists->GetCurrentOption());
Mpd->CommitSearch(vSongs);
}
else
{
FreeSongList(vSongs);
mLibSongs->Clear(0);
Mpd->StartSearch(1);
Mpd->AddSearch(MPD_TAG_ITEM_ARTIST, mLibArtists->GetCurrentOption());
Mpd->AddSearch(MPD_TAG_ITEM_ALBUM, mLibAlbums->GetCurrentOption());
Mpd->CommitSearch(vSongs);
}
sort(vSongs.begin(), vSongs.end(), SortSongsByTrack);
bool bold = 0;
for (SongList::const_iterator it = vSongs.begin(); it != vSongs.end(); it++)
{
for (SongList::const_iterator j = vPlaylist.begin(); j != vPlaylist.end(); j++)
{
if ((*it)->GetHash() == (*j)->GetHash())
{
bold = 1;
break;
}
}
bold ? mLibSongs->AddBoldOption(DisplaySong(**it, Config.song_library_format)) : mLibSongs->AddOption(DisplaySong(**it, Config.song_library_format));
bold = 0;
}
mLibAlbums->Refresh();
mLibSongs->Hide();
mLibSongs->Display();
block_library_update = 1;
}
wCurrent->Refresh(redraw_me);
redraw_me = 0;
wCurrent->ReadKey(input);
if (input == ERR)
continue;
if (current_screen == csLibrary)
block_library_update = 0;
title_allowed = 1;
timer = time(NULL);
switch (current_screen)
{
case csPlaylist:
mPlaylist->Highlighting(1);
break;
case csBrowser:
browsed_dir_scroll_begin--;
break;
case csLibrary:
{
if (input == KEY_UP || input == KEY_DOWN || input == KEY_PPAGE || input == KEY_NPAGE || input == KEY_HOME || input == KEY_END)
{
if (wCurrent == mLibArtists)
{
mLibAlbums->Reset();
mLibSongs->Reset();
}
if (wCurrent == mLibAlbums)
mLibSongs->Reset();
}
break;
}
default:
break;
}
switch (input)
{
case KEY_UP: wCurrent->Go(UP); continue;
case KEY_DOWN: wCurrent->Go(DOWN); continue;
case KEY_PPAGE: wCurrent->Go(PAGE_UP); continue;
case KEY_NPAGE: wCurrent->Go(PAGE_DOWN); continue;
case KEY_HOME: wCurrent->Go(HOME); continue;
case KEY_END: wCurrent->Go(END); continue;
case KEY_RESIZE:
{
int in;
redraw_me = 1;
while (1)
{
wCurrent->ReadKey(in);
if (in == KEY_RESIZE)
continue;
else
break;
}
if (COLS < 20 || LINES < 5)
{
endwin();
printf("Screen too small!\n");
return 1;
}
main_height = LINES-4;
if (!Config.header_visibility)
main_height += 2;
if (!Config.statusbar_visibility)
main_height++;
sHelp->Resize(COLS, main_height);
sHelp->Timeout(ncmpcpp_window_timeout);
mPlaylist->Resize(COLS, main_height);
mBrowser->Resize(COLS, main_height);
mTagEditor->Resize(COLS, main_height);
mSearcher->Resize(COLS, main_height);
sLyrics->Resize(COLS, main_height);
sLyrics->Timeout(ncmpcpp_window_timeout);
lib_artist_width = COLS/3-1;
lib_albums_start_x = lib_artist_width+1;
lib_albums_width = COLS/3;
lib_songs_start_x = lib_artist_width+lib_albums_width+2;
lib_songs_width = COLS-COLS/3*2-1;
mLibArtists->Resize(lib_artist_width, main_height);
mLibAlbums->Resize(lib_albums_width, main_height);
mLibSongs->Resize(lib_songs_width, main_height);
mLibAlbums->MoveTo(lib_albums_start_x, main_start_y);
mLibSongs->MoveTo(lib_songs_start_x, main_start_y);
if (Config.header_visibility)
wHeader->Resize(COLS, wHeader->GetHeight());
footer_start_y = LINES-(Config.statusbar_visibility ? 2 : 1);
wFooter->MoveTo(0, footer_start_y);
wFooter->Resize(COLS, wFooter->GetHeight());
if (wCurrent != sHelp)
wCurrent->Hide();
wCurrent->Display(redraw_me);
if (current_screen == csLibrary)
{
mLibArtists->Hide();
mLibAlbums->Hide();
mLibSongs->Hide();
REFRESH_MEDIA_LIBRARY_SCREEN;
}
header_update_status = 1;
PlayerState mpd_state = Mpd->GetState();
MPDStatusChanges changes;
if (mpd_state == psPlay || mpd_state == psPause)
changes.ElapsedTime = 1; // restore status
else
changes.PlayerState = 1;
NcmpcppStatusChanged(Mpd, changes, NULL);
break;
}
case KEY_BACKSPACE: case 127:
{
if (wCurrent == mBrowser && browsed_dir != "/")
mBrowser->Reset();
else
break;
}
case ENTER:
{
switch (current_screen)
{
case csPlaylist:
{
if (!mPlaylist->Empty())
Mpd->PlayID(vPlaylist[mPlaylist->GetChoice()-1]->GetID());
break;
}
case csBrowser:
{
int ci = mBrowser->GetChoice()-1;
switch (vBrowser[ci].type)
{
case itDirectory:
{
found_pos = 0;
vFoundPositions.clear();
if (browsed_dir != "/" && ci == 0)
{
int i = browsed_dir.size();
while (browsed_dir[--i] != '/');
string tmp = browsed_dir.substr(0, i);
if (tmp != browsed_dir)
{
browsed_subdir = browsed_dir.substr(i+1, browsed_dir.size()-i-1);
GetDirectory(tmp);
}
else
{
browsed_subdir = tmp;
GetDirectory("/");
}
}
else
{
if (browsed_dir != "/")
GetDirectory(browsed_dir + "/" + vBrowser[ci].name);
else
GetDirectory(vBrowser[ci].name);
}
break;
}
case itSong:
{
Song &s = *vBrowser[ci].song;
int id = Mpd->AddSong(s);
if (id >= 0)
{
Mpd->PlayID(id);
ShowMessage("Added to playlist: " + OmitBBCodes(DisplaySong(s)));
}
mBrowser->Refresh();
break;
}
case itPlaylist:
{
SongList list;
Mpd->GetPlaylistContent(vBrowser[ci].name, list);
for (SongList::const_iterator it = list.begin(); it != list.end(); it++)
Mpd->QueueAddSong(**it);
if (Mpd->CommitQueue())
{
ShowMessage("Loading and playing playlist " + vBrowser[ci].name + "...");
Song *s = vPlaylist[vPlaylist.size()-list.size()];
if (s->GetHash() == list[0]->GetHash())
Mpd->PlayID(s->GetID());
else
ShowMessage(message_part_of_songs_added);
}
FreeSongList(list);
break;
}
}
break;
}
case csTagEditor:
{
# ifdef HAVE_TAGLIB_H
int id = mTagEditor->GetRealChoice();
int option = mTagEditor->GetChoice();
LOCK_STATUSBAR;
Song &s = edited_song;
switch (id)
{
case 1:
{
wFooter->WriteXY(0, Config.statusbar_visibility, "[b]New title:[/b] ", 1);
if (s.GetTitle() == UNKNOWN_TITLE)
s.SetTitle(wFooter->GetString("", TraceMpdStatus));
else
s.SetTitle(wFooter->GetString(s.GetTitle(), TraceMpdStatus));
mTagEditor->UpdateOption(option, "[b]Title:[/b] " + s.GetTitle());
break;
}
case 2:
{
wFooter->WriteXY(0, Config.statusbar_visibility, "[b]New artist:[/b] ", 1);
if (s.GetArtist() == UNKNOWN_ARTIST)
s.SetArtist(wFooter->GetString("", TraceMpdStatus));
else
s.SetArtist(wFooter->GetString(s.GetArtist(), TraceMpdStatus));
mTagEditor->UpdateOption(option, "[b]Artist:[/b] " + s.GetArtist());
break;
}
case 3:
{
wFooter->WriteXY(0, Config.statusbar_visibility, "[b]New album:[/b] ", 1);
if (s.GetAlbum() == UNKNOWN_ALBUM)
s.SetAlbum(wFooter->GetString("", TraceMpdStatus));
else
s.SetAlbum(wFooter->GetString(s.GetAlbum(), TraceMpdStatus));
mTagEditor->UpdateOption(option, "[b]Album:[/b] " + s.GetAlbum());
break;
}
case 4:
{
wFooter->WriteXY(0, Config.statusbar_visibility, "[b]New year:[/b] ", 1);
if (s.GetYear() == EMPTY_TAG)
s.SetYear(wFooter->GetString(4, TraceMpdStatus));
else
s.SetYear(wFooter->GetString(s.GetYear(), 4, TraceMpdStatus));
mTagEditor->UpdateOption(option, "[b]Year:[/b] " + s.GetYear());
break;
}
case 5:
{
wFooter->WriteXY(0, Config.statusbar_visibility, "[b]New track:[/b] ", 1);
if (s.GetTrack() == EMPTY_TAG)
s.SetTrack(wFooter->GetString(3, TraceMpdStatus));
else
s.SetTrack(wFooter->GetString(s.GetTrack(), 3, TraceMpdStatus));
mTagEditor->UpdateOption(option, "[b]Track:[/b] " + s.GetTrack());
break;
}
case 6:
{
wFooter->WriteXY(0, Config.statusbar_visibility, "[b]New genre:[/b] ", 1);
if (s.GetGenre() == EMPTY_TAG)
s.SetGenre(wFooter->GetString("", TraceMpdStatus));
else
s.SetGenre(wFooter->GetString(s.GetGenre(), TraceMpdStatus));
mTagEditor->UpdateOption(option, "[b]Genre:[/b] " + s.GetGenre());
break;
}
case 7:
{
wFooter->WriteXY(0, Config.statusbar_visibility, "[b]New comment:[/b] ", 1);
if (s.GetComment() == EMPTY_TAG)
s.SetComment(wFooter->GetString("", TraceMpdStatus));
else
s.SetComment(wFooter->GetString(s.GetComment(), TraceMpdStatus));
mTagEditor->UpdateOption(option, "[b]Comment:[/b] " + s.GetComment());
break;
}
case 8:
{
string path_to_file = Config.mpd_music_dir + "/" + s.GetFile();
TagLib::FileRef f(path_to_file.c_str());
if (!f.isNull())
{
s.GetEmptyFields(1);
f.tag()->setTitle(NCMPCPP_TO_WSTRING(s.GetTitle()));
f.tag()->setArtist(NCMPCPP_TO_WSTRING(s.GetArtist()));
f.tag()->setAlbum(NCMPCPP_TO_WSTRING(s.GetAlbum()));
f.tag()->setYear(atoi(s.GetYear().c_str()));
f.tag()->setTrack(atoi(s.GetTrack().c_str()));
f.tag()->setGenre(NCMPCPP_TO_WSTRING(s.GetGenre()));
f.tag()->setComment(NCMPCPP_TO_WSTRING(s.GetComment()));
s.GetEmptyFields(0);
f.save();
Mpd->UpdateDirectory(s.GetDirectory());
if (prev_screen == csSearcher)
{
int upid = mSearcher->GetChoice()-search_engine_static_option-1;
*vSearched[upid] = s;
mSearcher->UpdateOption(mSearcher->GetChoice(), DisplaySong(s));
}
}
else
ShowMessage("Error writing tags!");
}
case 9:
{
# endif // HAVE_TAGLIB_H
wCurrent->Clear();
wCurrent = wPrev;
current_screen = prev_screen;
redraw_me = 1;
if (current_screen == csLibrary)
{
# ifdef HAVE_TAGLIB_H
if (id == 8)
{
mLibSongs->HighlightColor(Config.main_highlight_color);
mLibArtists->HighlightColor(Config.library_active_column_color);
wCurrent = mLibArtists;
}
else
wCurrent = wPrev;
# else
wCurrent = wPrev;
# endif
REFRESH_MEDIA_LIBRARY_SCREEN;
}
# ifdef HAVE_TAGLIB_H
break;
}
}
UNLOCK_STATUSBAR;
# endif // HAVE_TAGLIB_H
break;
}
case csSearcher:
{
int id = mSearcher->GetChoice();
int option = mSearcher->GetChoice();
LOCK_STATUSBAR;
Song &s = searched_song;
switch (id)
{
case 1:
{
wFooter->WriteXY(0, Config.statusbar_visibility, "[b]Filename:[/b] ", 1);
if (s.GetShortFilename() == EMPTY_TAG)
s.SetShortFilename(wFooter->GetString("", TraceMpdStatus));
else
s.SetShortFilename(wFooter->GetString(s.GetShortFilename(), TraceMpdStatus));
mSearcher->UpdateOption(option, "[b]Filename:[/b] " + s.GetShortFilename());
break;
}
case 2:
{
wFooter->WriteXY(0, Config.statusbar_visibility, "[b]Title:[/b] ", 1);
if (s.GetTitle() == UNKNOWN_TITLE)
s.SetTitle(wFooter->GetString("", TraceMpdStatus));
else
s.SetTitle(wFooter->GetString(s.GetTitle(), TraceMpdStatus));
mSearcher->UpdateOption(option, "[b]Title:[/b] " + s.GetTitle());
break;
}
case 3:
{
wFooter->WriteXY(0, Config.statusbar_visibility, "[b]Artist:[/b] ", 1);
if (s.GetArtist() == UNKNOWN_ARTIST)
s.SetArtist(wFooter->GetString("", TraceMpdStatus));
else
s.SetArtist(wFooter->GetString(s.GetArtist(), TraceMpdStatus));
mSearcher->UpdateOption(option, "[b]Artist:[/b] " + s.GetArtist());
break;
}
case 4:
{
wFooter->WriteXY(0, Config.statusbar_visibility, "[b]Album:[/b] ", 1);
if (s.GetAlbum() == UNKNOWN_ALBUM)
s.SetAlbum(wFooter->GetString("", TraceMpdStatus));
else
s.SetAlbum(wFooter->GetString(s.GetAlbum(), TraceMpdStatus));
mSearcher->UpdateOption(option, "[b]Album:[/b] " + s.GetAlbum());
break;
}
case 5:
{
wFooter->WriteXY(0, Config.statusbar_visibility, "[b]Year:[/b] ", 1);
if (s.GetYear() == EMPTY_TAG)
s.SetYear(wFooter->GetString(4, TraceMpdStatus));
else
s.SetYear(wFooter->GetString(s.GetYear(), 4, TraceMpdStatus));
mSearcher->UpdateOption(option, "[b]Year:[/b] " + s.GetYear());
break;
}
case 6:
{
wFooter->WriteXY(0, Config.statusbar_visibility, "[b]Track:[/b] ", 1);
if (s.GetTrack() == EMPTY_TAG)
s.SetTrack(wFooter->GetString(3, TraceMpdStatus));
else
s.SetTrack(wFooter->GetString(s.GetTrack(), 3, TraceMpdStatus));
mSearcher->UpdateOption(option, "[b]Track:[/b] " + s.GetTrack());
break;
}
case 7:
{
wFooter->WriteXY(0, Config.statusbar_visibility, "[b]Genre:[/b] ", 1);
if (s.GetGenre() == EMPTY_TAG)
s.SetGenre(wFooter->GetString("", TraceMpdStatus));
else
s.SetGenre(wFooter->GetString(s.GetGenre(), TraceMpdStatus));
mSearcher->UpdateOption(option, "[b]Genre:[/b] " + s.GetGenre());
break;
}
case 8:
{
wFooter->WriteXY(0, Config.statusbar_visibility, "[b]Comment:[/b] ", 1);
if (s.GetComment() == EMPTY_TAG)
s.SetComment(wFooter->GetString("", TraceMpdStatus));
else
s.SetComment(wFooter->GetString(s.GetComment(), TraceMpdStatus));
mSearcher->UpdateOption(option, "[b]Comment:[/b] " + s.GetComment());
break;
}
case 10:
{
search_mode_match = !search_mode_match;
mSearcher->UpdateOption(option, "[b]Search mode:[/b] " + (search_mode_match ? search_mode_one : search_mode_two));
break;
}
case 11:
{
search_case_sensitive = !search_case_sensitive;
mSearcher->UpdateOption(option, "[b]Case sensitive:[/b] " + (string)(search_case_sensitive ? "Yes" : "No"));
break;
}
case 13:
{
ShowMessage("Searching...");
Search(vSearched, s);
ShowMessage("Searching finished!");
if (!vSearched.empty())
{
bool bold = 0;
mSearcher->AddSeparator();
mSearcher->AddStaticBoldOption("[white]Search results:[/white] [green]Found " + IntoStr(vSearched.size()) + (vSearched.size() > 1 ? " songs" : " song") + "[/green]");
mSearcher->AddSeparator();
for (SongList::const_iterator it = vSearched.begin(); it != vSearched.end(); it++)
{
for (SongList::const_iterator j = vPlaylist.begin(); j != vPlaylist.end(); j++)
{
if ((*j)->GetHash() == (*it)->GetHash())
{
bold = 1;
break;
}
}
bold ? mSearcher->AddBoldOption(DisplaySong(**it)) : mSearcher->AddOption(DisplaySong(**it));
bold = 0;
}
for (int i = 1; i <=13; i++)
mSearcher->MakeStatic(i, 1);
mSearcher->Go(DOWN);
mSearcher->Go(DOWN);
}
else
ShowMessage("No results found");
break;
}
case 14:
{
found_pos = 0;
vFoundPositions.clear();
vSearched.clear();
PrepareSearchEngine(searched_song);
ShowMessage("Search state reset");
break;
}
default:
{
Song &s = *vSearched[mSearcher->GetRealChoice()-2];
int id = Mpd->AddSong(s);
if (id >= 0)
{
Mpd->PlayID(id);
ShowMessage("Added to playlist: " + OmitBBCodes(DisplaySong(s)));
}
break;
}
}
UNLOCK_STATUSBAR;
break;
}
case csLibrary:
{
Start_Point_For_KEY_SPACE: // same code for KEY_SPACE, but without playing.
SongList list;
if (wCurrent == mLibArtists)
{
const string &artist = mLibArtists->GetCurrentOption();
Mpd->StartSearch(1);
Mpd->AddSearch(MPD_TAG_ITEM_ARTIST, artist);
Mpd->CommitSearch(list);
for (SongList::const_iterator it = list.begin(); it != list.end(); it++)
Mpd->QueueAddSong(**it);
if (Mpd->CommitQueue())
{
ShowMessage("Adding all songs artist's: " + artist);
Song *s = vPlaylist[vPlaylist.size()-list.size()];
if (s->GetHash() == list[0]->GetHash())
{
if (input == ENTER)
Mpd->PlayID(s->GetID());
}
else
ShowMessage(message_part_of_songs_added);
}
}
if (wCurrent == mLibAlbums)
{
for (SongList::const_iterator it = vSongs.begin(); it != vSongs.end(); it++)
Mpd->QueueAddSong(**it);
if (Mpd->CommitQueue())
{
ShowMessage("Adding songs from album: " + mLibAlbums->GetCurrentOption());
Song *s = vPlaylist[vPlaylist.size()-vSongs.size()];
if (s->GetHash() == vSongs[0]->GetHash())
{
if (input == ENTER)
Mpd->PlayID(s->GetID());
}
else
ShowMessage(message_part_of_songs_added);
}
}
if (wCurrent == mLibSongs)
{
if (!vSongs.empty())
{
Song &s = *vSongs[mLibSongs->GetChoice()-1];
int id = Mpd->AddSong(s);
if (id >= 0)
{
ShowMessage("Added to playlist: " + OmitBBCodes(DisplaySong(s)));
if (input == ENTER)
Mpd->PlayID(id);
}
}
}
FreeSongList(list);
if (input == KEY_SPACE)
wCurrent->Go(DOWN);
break;
}
default:
break;
}
break;
}
case KEY_SPACE:
{
if (current_screen == csBrowser)
{
int ci = mBrowser->GetChoice()-1;
switch (vBrowser[ci].type)
{
case itDirectory:
{
string getdir = browsed_dir == "/" ? vBrowser[ci].name : browsed_dir + "/" + vBrowser[ci].name;
SongList list;
Mpd->GetDirectoryRecursive(getdir, list);
for (SongList::const_iterator it = list.begin(); it != list.end(); it++)
Mpd->QueueAddSong(**it);
if (Mpd->CommitQueue())
{
ShowMessage("Added folder: " + getdir);
Song *s = vPlaylist[vPlaylist.size()-list.size()];
if (s->GetHash() != list[0]->GetHash())
ShowMessage(message_part_of_songs_added);
}
FreeSongList(list);
break;
}
case itSong:
{
Song &s = *vBrowser[ci].song;
if (Mpd->AddSong(s) != -1)
ShowMessage("Added to playlist: " + OmitBBCodes(DisplaySong(s)));
break;
}
case itPlaylist:
{
SongList list;
Mpd->GetPlaylistContent(vBrowser[ci].name, list);
for (SongList::const_iterator it = list.begin(); it != list.end(); it++)
Mpd->QueueAddSong(**it);
if (Mpd->CommitQueue())
{
ShowMessage("Loading playlist " + vBrowser[ci].name + "...");
Song *s = vPlaylist[vPlaylist.size()-list.size()];
if (s->GetHash() != list[0]->GetHash())
ShowMessage(message_part_of_songs_added);
}
FreeSongList(list);
break;
}
}
mBrowser->Go(DOWN);
}
if (current_screen == csSearcher && !vSearched.empty())
{
int id = mSearcher->GetChoice()-search_engine_static_option-1;
if (id < 0)
break;
Song &s = *vSearched[id];
if (Mpd->AddSong(s) != -1)
ShowMessage("Added to playlist: " + OmitBBCodes(DisplaySong(s)));
mSearcher->Go(DOWN);
}
if (current_screen == csLibrary)
goto Start_Point_For_KEY_SPACE; // sorry, but that's stupid to copy the same code here.
break;
}
case KEY_RIGHT:
{
if (current_screen == csLibrary)
{
if (wCurrent == mLibArtists)
{
mLibArtists->HighlightColor(Config.main_highlight_color);
wCurrent->Refresh();
wCurrent = mLibAlbums;
mLibAlbums->HighlightColor(Config.library_active_column_color);
if (!mLibAlbums->Empty())
break;
}
if (wCurrent == mLibAlbums)
{
mLibAlbums->HighlightColor(Config.main_highlight_color);
wCurrent->Refresh();
wCurrent = mLibSongs;
mLibSongs->HighlightColor(Config.library_active_column_color);
break;
}
break;
}
}
case '+': // volume up
{
Mpd->SetVolume(Mpd->GetVolume()+1);
break;
}
case KEY_LEFT:
{
if (current_screen == csLibrary)
{
if (wCurrent == mLibSongs)
{
mLibSongs->HighlightColor(Config.main_highlight_color);
wCurrent->Refresh();
wCurrent = mLibAlbums;
mLibAlbums->HighlightColor(Config.library_active_column_color);
if (!mLibAlbums->Empty())
break;
}
if (wCurrent == mLibAlbums)
{
mLibAlbums->HighlightColor(Config.main_highlight_color);
wCurrent->Refresh();
wCurrent = mLibArtists;
mLibArtists->HighlightColor(Config.library_active_column_color);
break;
}
break;
}
}
case '-': // volume down
{
Mpd->SetVolume(Mpd->GetVolume()-1);
break;
}
case KEY_DC: // delete position from list
{
if (!mPlaylist->Empty() && current_screen == csPlaylist)
{
block_playlist_update = 1;
dont_change_now_playing = 1;
mPlaylist->Timeout(50);
int id = mPlaylist->GetChoice()-1;
while (!vPlaylist.empty() && input == KEY_DC)
{
TraceMpdStatus();
timer = time(NULL);
if (input == KEY_DC)
{
id = mPlaylist->GetChoice()-1;
Mpd->QueueDeleteSong(id);
delete vPlaylist[id];
vPlaylist.erase(vPlaylist.begin()+id);
mPlaylist->DeleteOption(id+1);
if (now_playing > id)
now_playing--;
mPlaylist->Refresh();
}
mPlaylist->ReadKey(input);
}
Mpd->CommitQueue();
mPlaylist->Timeout(ncmpcpp_window_timeout);
dont_change_now_playing = 0;
}
if (current_screen == csBrowser)
{
LOCK_STATUSBAR;
int id = mBrowser->GetChoice()-1;
if (vBrowser[id].type == itPlaylist)
{
block_statusbar_update = 1;
wFooter->WriteXY(0, Config.statusbar_visibility, "Delete playlist " + vBrowser[id].name + " ? [y/n] ", 1);
curs_set(1);
int in = 0;
do
{
TraceMpdStatus();
wFooter->ReadKey(in);
}
while (in != 'y' && in != 'n');
block_statusbar_update = 0;
if (in == 'y')
{
Mpd->DeletePlaylist(vBrowser[id].name);
ShowMessage("Playlist " + vBrowser[id].name + " deleted!");
GetDirectory("/");
}
else
ShowMessage("Aborted!");
curs_set(0);
UNLOCK_STATUSBAR;
}
}
break;
}
case '<': // previous
{
Mpd->Prev();
break;
}
case '>': // next
{
Mpd->Next();
break;
}
case 'P': // pause
{
Mpd->Pause();
break;
}
case 'S': // save playlist
{
LOCK_STATUSBAR;
wFooter->WriteXY(0, Config.statusbar_visibility, "Save playlist as: ", 1);
string playlist_name = wFooter->GetString("", TraceMpdStatus);
UNLOCK_STATUSBAR;
if (playlist_name.find("/") != string::npos)
{
ShowMessage("Playlist name cannot contain slashes!");
break;
}
if (!playlist_name.empty())
{
if (Mpd->SavePlaylist(playlist_name))
ShowMessage("Playlist saved as: " + playlist_name);
else
ShowMessage("Playlist already exists!");
}
if (browsed_dir == "/" && !vBrowser.empty())
GetDirectory(browsed_dir);
break;
}
case 's': // stop
{
Mpd->Stop();
break;
}
case 'm': // move song up
{
block_playlist_update = 1;
int pos = mPlaylist->GetChoice()-1;
if (pos > 0 && !mPlaylist->Empty() && current_screen == csPlaylist)
{
std::swap<Song *>(vPlaylist[pos], vPlaylist[pos-1]);
if (pos == now_playing)
{
now_playing--;
mPlaylist->BoldOption(pos, 1);
mPlaylist->BoldOption(pos+1, 0);
}
else
{
if (pos-1 == now_playing)
{
now_playing++;
mPlaylist->BoldOption(pos, 0);
mPlaylist->BoldOption(pos+1, 1);
}
}
mPlaylist->UpdateOption(pos, DisplaySong(*vPlaylist[pos-1]));
mPlaylist->UpdateOption(pos+1, DisplaySong(*vPlaylist[pos]));
Mpd->Move(pos, pos-1);
mPlaylist->Go(UP);
}
break;
}
case 'n': // move song down
{
block_playlist_update = 1;
int pos = mPlaylist->GetChoice()-1;
if (pos+1 < vPlaylist.size() && !mPlaylist->Empty() && current_screen == csPlaylist)
{
std::swap<Song *>(vPlaylist[pos+1], vPlaylist[pos]);
if (pos == now_playing)
{
now_playing++;
mPlaylist->BoldOption(pos+1, 0);
mPlaylist->BoldOption(pos+2, 1);
}
else
{
if (pos+1 == now_playing)
{
now_playing--;
mPlaylist->BoldOption(pos+1, 1);
mPlaylist->BoldOption(pos+2, 0);
}
}
mPlaylist->UpdateOption(pos+2, DisplaySong(*vPlaylist[pos+1]));
mPlaylist->UpdateOption(pos+1, DisplaySong(*vPlaylist[pos]));
Mpd->Move(pos, pos+1);
mPlaylist->Go(DOWN);
}
break;
}
case 'f': case 'b': // seek through song
{
if (now_playing < 0)
break;
block_progressbar_update = 1;
LOCK_STATUSBAR;
int songpos, in;
songpos = Mpd->GetElapsedTime();
Song &s = *vPlaylist[now_playing];
while (1)
{
TraceMpdStatus();
timer = time(NULL);
mPlaylist->ReadKey(in);
if (in == 'f' || in == 'b')
{
if (songpos < s.GetTotalLength() && in == 'f')
songpos++;
if (songpos < s.GetTotalLength() && songpos > 0 && in == 'b')
songpos--;
if (songpos < 0)
songpos = 0;
wFooter->Bold(1);
string tracklength = "[" + ShowTime(songpos) + "/" + s.GetLength() + "]";
wFooter->WriteXY(wFooter->GetWidth()-tracklength.length(), 1, tracklength);
double progressbar_size = (double)songpos/(s.GetTotalLength());
int howlong = wFooter->GetWidth()*progressbar_size;
mvwhline(wFooter->RawWin(), 0, 0, 0, wFooter->GetWidth());
mvwhline(wFooter->RawWin(), 0, 0, '=',howlong);
mvwaddch(wFooter->RawWin(), 0, howlong, '>');
wFooter->Bold(0);
wFooter->Refresh();
}
else
break;
}
Mpd->Seek(songpos);
block_progressbar_update = 0;
UNLOCK_STATUSBAR;
break;
}
case 'u': // update database
{
if (current_screen == csBrowser)
Mpd->UpdateDirectory(browsed_dir);
else
Mpd->UpdateDirectory("/");
break;
}
case 'o': // go to playing song
{
if (current_screen == csPlaylist && now_playing >= 0)
mPlaylist->Highlight(now_playing+1);
break;
}
case 'r': // switch repeat state
{
Mpd->SetRepeat(!Mpd->GetRepeat());
break;
}
case 'Z': // shuffle playlist
{
Mpd->Shuffle();
break;
}
case 'z': // switch random state
{
Mpd->SetRandom(!Mpd->GetRandom());
break;
}
case 'x': // switch crossfade state
{
Mpd->SetCrossfade(Mpd->GetCrossfade() ? 0 : Config.crossfade_time);
break;
}
case 'X': // set crossfade
{
LOCK_STATUSBAR;
wFooter->WriteXY(0, Config.statusbar_visibility, "Set crossfade to: ", 1);
string crossfade = wFooter->GetString(3, TraceMpdStatus);
UNLOCK_STATUSBAR;
int cf = StrToInt(crossfade);
if (cf > 0)
{
Config.crossfade_time = cf;
Mpd->SetCrossfade(cf);
}
break;
}
case 'e': // edit song's tags
{
if ((wCurrent == mPlaylist && !vPlaylist.empty())
|| (wCurrent == mBrowser && vBrowser[mBrowser->GetChoice()-1].type == itSong)
|| (wCurrent == mSearcher && !vSearched.empty() && mSearcher->GetChoice() > search_engine_static_option)
|| (wCurrent == mLibSongs && !vSongs.empty()))
{
int id = wCurrent->GetChoice()-1;
Song *s;
switch (current_screen)
{
case csPlaylist:
s = vPlaylist[id];
break;
case csBrowser:
s = vBrowser[id].song;
break;
case csSearcher:
s = vSearched[id-search_engine_static_option];
break;
case csLibrary:
s = vSongs[id];
break;
default:
break;
}
if (GetSongInfo(*s))
{
wPrev = wCurrent;
wCurrent = mTagEditor;
prev_screen = current_screen;
current_screen = csTagEditor;
}
else
ShowMessage("Cannot read file!");
}
break;
}
case 'g': // go to position in currently playing song
{
if (now_playing < 0)
break;
int newpos = 0;
string position;
LOCK_STATUSBAR;
wFooter->WriteXY(0, Config.statusbar_visibility, "Position to go (in %): ", 1);
position = wFooter->GetString(3, TraceMpdStatus);
newpos = atoi(position.c_str());
if (newpos > 0 && newpos < 100 && !position.empty())
Mpd->Seek(vPlaylist[now_playing]->GetTotalLength()*newpos/100.0);
UNLOCK_STATUSBAR;
break;
}
case 'C': // clear playlist but holds currently playing song
{
if (now_playing < 0)
{
ShowMessage("Nothing is playing now!");
break;
}
for (SongList::iterator it = vPlaylist.begin(); it != vPlaylist.begin()+now_playing; it++)
Mpd->QueueDeleteSongId((*it)->GetID());
for (SongList::iterator it = vPlaylist.begin()+now_playing+1; it != vPlaylist.end(); it++)
Mpd->QueueDeleteSongId((*it)->GetID());
ShowMessage("Deleting all songs except now playing one...");
Mpd->CommitQueue();
ShowMessage("Songs deleted!");
break;
}
case 'c': // clear playlist
{
ShowMessage("Clearing playlist...");
Mpd->ClearPlaylist();
ShowMessage("Cleared playlist!");
break;
}
case '/': case '?': // find forward/backward
{
if ((current_screen != csHelp && current_screen != csSearcher) || (current_screen == csSearcher && !vSearched.empty()))
{
string how = input == '/' ? "forward" : "backward";
found_pos = 0;
vFoundPositions.clear();
Menu *mCurrent = static_cast<Menu *>(wCurrent);
LOCK_STATUSBAR;
wFooter->WriteXY(0, Config.statusbar_visibility, "Find " + how + ": ", 1);
string findme = wFooter->GetString("", TraceMpdStatus);
UNLOCK_STATUSBAR;
timer = time(NULL);
if (findme.empty())
break;
transform(findme.begin(), findme.end(), findme.begin(), tolower);
if (input == '/') // forward
{
for (int i = mCurrent->GetChoice(); i <= mCurrent->MaxChoice(); i++)
{
string name = mCurrent->GetOption(i);
transform(name.begin(), name.end(), name.begin(), tolower);
if (name.find(findme) != string::npos && !mCurrent->IsStatic(i))
vFoundPositions.push_back(i);
}
}
else // backward
{
for (int i = mCurrent->GetChoice(); i > 0; i--)
{
string name = mCurrent->GetOption(i);
transform(name.begin(), name.end(), name.begin(), tolower);
if (name.find(findme) != string::npos && !mCurrent->IsStatic(i))
vFoundPositions.push_back(i);
}
}
if (vFoundPositions.empty())
ShowMessage("Unable to find \"" + findme + "\"");
else
{
mCurrent->Highlight(vFoundPositions.front());
mCurrent->Highlighting(1);
}
}
break;
}
case ',': case '.': // go to previous/next found position
{
if (!vFoundPositions.empty())
{
Menu *mCurrent = static_cast<Menu *>(wCurrent);
try
{
mCurrent->Highlight(vFoundPositions.at(input == '.' ? ++found_pos : --found_pos));
}
catch (std::out_of_range)
{
if (input == '.')
{
mCurrent->Highlight(vFoundPositions.front());
found_pos = 0;
}
else
{
mCurrent->Highlight(vFoundPositions.back());
found_pos = vFoundPositions.size()-1;
}
}
}
break;
}
case 'l': // show lyrics
{
if (wCurrent == sLyrics)
{
wCurrent->Hide();
current_screen = prev_screen;
wCurrent = wPrev;
redraw_me = 1;
if (current_screen == csLibrary)
{
REFRESH_MEDIA_LIBRARY_SCREEN;
}
break;
}
if ((wCurrent == mPlaylist && !vPlaylist.empty())
|| (wCurrent == mBrowser && vBrowser[mBrowser->GetChoice()-1].type == itSong)
|| (wCurrent == mSearcher && !vSearched.empty() && mSearcher->GetChoice() > search_engine_static_option)
|| (wCurrent == mLibSongs && !vSongs.empty()))
{
Song *s;
switch (current_screen)
{
case csPlaylist:
s = vPlaylist[mPlaylist->GetChoice()-1];
break;
case csBrowser:
s = vBrowser[mBrowser->GetChoice()-1].song;
break;
case csSearcher:
s = vSearched[mSearcher->GetRealChoice()-2]; // first one is 'Reset'
break;
case csLibrary:
s = vSongs[mLibSongs->GetChoice()-1];
break;
default:
break;
}
if (s->GetArtist() != UNKNOWN_ARTIST && s->GetTitle() != UNKNOWN_TITLE)
{
wPrev = wCurrent;
prev_screen = current_screen;
wCurrent = sLyrics;
wCurrent->Hide();
wCurrent->Clear();
current_screen = csLyrics;
song_lyrics = "Lyrics: " + s->GetArtist() + " - " + s->GetTitle();
sLyrics->WriteXY(0, 0, "Fetching lyrics...");
sLyrics->Refresh();
sLyrics->Add(GetLyrics(s->GetArtist(), s->GetTitle()));
sLyrics->Timeout(ncmpcpp_window_timeout);
}
}
break;
}
case '1': // help screen
{
if (wCurrent != sHelp)
{
wCurrent = sHelp;
wCurrent->Hide();
current_screen = csHelp;
}
break;
}
case KEY_TAB: // switch between playlist and browser
{
if (wCurrent == mPlaylist)
goto KEY_TAB_BROWSER_REDIRECT;
else
goto KEY_TAB_PLAYLIST_REDIRECT;
}
case '2': // playlist screen
{
KEY_TAB_PLAYLIST_REDIRECT:
if (wCurrent != mPlaylist && current_screen != csTagEditor)
{
found_pos = 0;
vFoundPositions.clear();
wCurrent = mPlaylist;
wCurrent->Hide();
current_screen = csPlaylist;
redraw_me = 1;
}
break;
}
case '3': // browse screen
{
KEY_TAB_BROWSER_REDIRECT:
if (browsed_dir.empty())
browsed_dir = "/";
if (mBrowser->Empty())
GetDirectory(browsed_dir);
else
{
bool bold = 0;
for (int i = 0; i < vBrowser.size(); i++)
{
if (vBrowser[i].type == itSong)
{
for (SongList::const_iterator it = vPlaylist.begin(); it != vPlaylist.end(); it++)
{
if ((*it)->GetHash() == vBrowser[i].song->GetHash())
{
bold = 1;
break;
}
}
mBrowser->BoldOption(i+1, bold);
bold = 0;
}
}
}
if (wCurrent != mBrowser && current_screen != csTagEditor)
{
found_pos = 0;
vFoundPositions.clear();
wCurrent = mBrowser;
wCurrent->Hide();
current_screen = csBrowser;
redraw_me = 1;
}
break;
}
case '4': // search screen
{
if (current_screen != csTagEditor && current_screen != csSearcher)
{
found_pos = 0;
vFoundPositions.clear();
if (vSearched.empty())
PrepareSearchEngine(searched_song);
wCurrent = mSearcher;
wCurrent->Hide();
current_screen = csSearcher;
redraw_me = 1;
if (!vSearched.empty())
{
wCurrent->WriteXY(0, 0, "Updating list...");
bool bold = 0;
int i = search_engine_static_option;
for (SongList::const_iterator it = vSearched.begin(); it != vSearched.end(); it++, i++)
{
for (SongList::const_iterator j = vPlaylist.begin(); j != vPlaylist.end(); j++)
{
if ((*j)->GetHash() == (*it)->GetHash())
{
bold = 1;
break;
}
}
mSearcher->BoldOption(i+1, bold);
bold = 0;
}
}
}
break;
}
case '5': // artist library
{
if (current_screen != csLibrary)
{
found_pos = 0;
vFoundPositions.clear();
if (mLibArtists->Empty())
{
Mpd->GetArtists(vArtists);
sort(vArtists.begin(), vArtists.end(), CaseInsensitiveComparison);
for (TagList::const_iterator it = vArtists.begin(); it != vArtists.end(); it++)
mLibArtists->AddOption(*it);
}
mLibArtists->HighlightColor(Config.library_active_column_color);
mLibAlbums->HighlightColor(Config.main_highlight_color);
mLibSongs->HighlightColor(Config.main_highlight_color);
wCurrent->Hide();
REFRESH_MEDIA_LIBRARY_SCREEN;
wCurrent = mLibArtists;
current_screen = csLibrary;
redraw_me = 1;
}
break;
}
case 'q': case 'Q': // quit
main_exit = 1;
default: continue;
}
}
Mpd->Disconnect();
curs_set(1);
endwin();
printf("\n");
return 0;
}