add support for album artist tag
[ncmpcpp.git] / src / display.cpp
blob6cdfa6256362f6bd4d24c74e70364bb3e030ad71
1 /***************************************************************************
2 * Copyright (C) 2008-2009 by Andrzej Rybczak *
3 * electricityispower@gmail.com *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
19 ***************************************************************************/
21 #include "display.h"
22 #include "helpers.h"
23 #include "playlist.h"
25 std::string Display::Columns()
27 if (Config.columns.empty())
28 return "";
30 std::string result, tag;
31 size_t where = 0;
32 int width;
34 std::vector<Column>::const_iterator next2last;
35 bool last_fixed = Config.columns.back().fixed;
36 if (Config.columns.size() > 1)
37 next2last = Config.columns.end()-2;
39 for (std::vector<Column>::const_iterator it = Config.columns.begin(); it != Config.columns.end(); ++it)
41 width = (last_fixed && it == next2last
42 ? COLS-where-(++next2last)->width
43 : (it == Config.columns.end()-1
44 ? COLS-where
45 : (it->width*(it->fixed ? 1 : COLS/100.0))
49 switch (it->type)
51 case 'l':
52 tag = "Time";
53 break;
54 case 'f':
55 tag = "Filename";
56 break;
57 case 'D':
58 tag = "Directory";
59 break;
60 case 'a':
61 tag = "Artist";
62 break;
63 case 'A':
64 tag = "Album Artist";
65 break;
66 case 't':
67 tag = "Title";
68 break;
69 case 'b':
70 tag = "Album";
71 break;
72 case 'y':
73 tag = "Year";
74 break;
75 case 'n':
76 case 'N':
77 tag = "Track";
78 break;
79 case 'g':
80 tag = "Genre";
81 break;
82 case 'c':
83 tag = "Composer";
84 break;
85 case 'p':
86 tag = "Performer";
87 break;
88 case 'd':
89 tag = "Disc";
90 break;
91 case 'C':
92 tag = "Comment";
93 break;
94 default:
95 tag.clear();
96 break;
98 if (it->right_alignment)
99 for (long i = 0; i < long(width-tag.length()-(it != Config.columns.begin())); ++i, result += ' ') { }
101 where += width;
102 result += tag;
104 if (result.length() > where)
105 result = result.substr(0, where);
106 else
107 for (size_t i = result.length(); i <= where && i < size_t(COLS); ++i, result += ' ') { }
109 return result;
112 void Display::SongsInColumns(const MPD::Song &s, void *, Menu<MPD::Song> *menu)
114 if (!s.Localized())
115 const_cast<MPD::Song *>(&s)->Localize();
117 bool is_now_playing = menu == myPlaylist->Items && (menu->isFiltered() ? s.GetPosition() : menu->CurrentlyDrawedPosition()) == size_t(myPlaylist->NowPlaying);
118 if (is_now_playing)
119 *menu << Config.now_playing_prefix;
121 if (Config.columns.empty())
122 return;
124 std::vector<Column>::const_iterator next2last, it;
125 size_t where = 0;
126 int width;
128 bool last_fixed = Config.columns.back().fixed;
129 if (Config.columns.size() > 1)
130 next2last = Config.columns.end()-2;
132 for (it = Config.columns.begin(); it != Config.columns.end(); ++it)
134 if (where)
136 menu->GotoXY(where, menu->Y());
137 *menu << ' ';
138 if ((it-1)->color != clDefault)
139 *menu << clEnd;
142 width = (last_fixed && it == next2last
143 ? COLS-where-(++next2last)->width
144 : (it == Config.columns.end()-1
145 ? menu->GetWidth()-where
146 : (it->width*(it->fixed ? 1 : COLS/100.0))
150 MPD::Song::GetFunction get = 0;
152 switch (it->type)
154 case 'l':
155 get = &MPD::Song::GetLength;
156 break;
157 case 'D':
158 get = &MPD::Song::GetDirectory;
159 break;
160 case 'f':
161 get = &MPD::Song::GetName;
162 break;
163 case 'a':
164 get = &MPD::Song::GetArtist;
165 break;
166 case 'A':
167 get = &MPD::Song::GetAlbumArtist;
168 break;
169 case 'b':
170 get = &MPD::Song::GetAlbum;
171 break;
172 case 'y':
173 get = &MPD::Song::GetDate;
174 break;
175 case 'n':
176 get = &MPD::Song::GetTrackNumber;
177 break;
178 case 'N':
179 get = &MPD::Song::GetTrack;
180 break;
181 case 'g':
182 get = &MPD::Song::GetGenre;
183 break;
184 case 'c':
185 get = &MPD::Song::GetComposer;
186 break;
187 case 'p':
188 get = &MPD::Song::GetPerformer;
189 break;
190 case 'd':
191 get = &MPD::Song::GetDisc;
192 break;
193 case 'C':
194 get = &MPD::Song::GetComment;
195 break;
196 case 't':
197 if (!s.GetTitle().empty())
198 get = &MPD::Song::GetTitle;
199 else
200 get = &MPD::Song::GetName;
201 break;
202 default:
203 break;
205 if (it->color != clDefault)
206 *menu << it->color;
207 whline(menu->Raw(), 32, menu->GetWidth()-where);
208 std::string tag = get ? s.GetTags(get) : "";
209 if (it->right_alignment)
211 if (!tag.empty() || it->display_empty_tag)
213 int x, y;
214 menu->GetXY(x, y);
215 std::basic_string<my_char_t> wtag = TO_WSTRING(tag.empty() ? Config.empty_tag : tag).substr(0, width-!!x);
216 *menu << XY(x+width-Window::Length(wtag)-!!x, y) << wtag;
219 else
221 if (!tag.empty())
222 *menu << tag;
223 else if (it->display_empty_tag)
224 *menu << Config.empty_tag;
226 where += width;
228 if ((--it)->color != clDefault)
229 *menu << clEnd;
230 if (is_now_playing)
231 *menu << Config.now_playing_suffix;
234 void Display::Songs(const MPD::Song &s, void *data, Menu<MPD::Song> *menu)
236 if (!s.Localized())
237 const_cast<MPD::Song *>(&s)->Localize();
239 bool is_now_playing = menu == myPlaylist->Items && (menu->isFiltered() ? s.GetPosition() : menu->CurrentlyDrawedPosition()) == size_t(myPlaylist->NowPlaying);
240 if (is_now_playing)
241 *menu << Config.now_playing_prefix;
243 std::string line = s.toString(*static_cast<std::string *>(data), "$");
244 for (std::string::const_iterator it = line.begin(); it != line.end(); ++it)
246 if (*it == '$')
248 if (++it == line.end()) // end of format
250 *menu << '$';
251 break;
253 else if (isdigit(*it)) // color
255 *menu << Color(*it-'0');
257 else if (*it == 'R') // right align
259 basic_buffer<my_char_t> buf;
260 buf << U(" ");
261 String2Buffer(TO_WSTRING(line.substr(it-line.begin()+1)), buf);
262 if (is_now_playing)
263 buf << Config.now_playing_suffix;
264 *menu << XY(menu->GetWidth()-buf.Str().length()-(menu->isSelected(menu->CurrentlyDrawedPosition()) ? Config.selected_item_suffix_length : 0), menu->Y()) << buf;
265 return;
267 else // not a color nor right align, just a random character
268 *menu << *--it;
270 else if (*it == MPD::Song::FormatEscapeCharacter)
272 // treat '$' as a normal character if song format escape char is prepended to it
273 if (++it == line.end() || *it != '$')
274 --it;
275 *menu << *it;
277 else
278 *menu << *it;
280 if (is_now_playing)
281 *menu << Config.now_playing_suffix;
284 void Display::Tags(const MPD::Song &s, void *data, Menu<MPD::Song> *menu)
286 switch (static_cast<Menu<std::string> *>(data)->Choice())
288 case 0:
289 ShowTag(*menu, s.GetTags(&MPD::Song::GetTitle));
290 return;
291 case 1:
292 ShowTag(*menu, s.GetTags(&MPD::Song::GetArtist));
293 return;
294 case 2:
295 ShowTag(*menu, s.GetTags(&MPD::Song::GetAlbumArtist));
296 return;
297 case 3:
298 ShowTag(*menu, s.GetTags(&MPD::Song::GetAlbum));
299 return;
300 case 4:
301 ShowTag(*menu, s.GetTags(&MPD::Song::GetDate));
302 return;
303 case 5:
304 ShowTag(*menu, s.GetTags(&MPD::Song::GetTrack));
305 return;
306 case 6:
307 ShowTag(*menu, s.GetTags(&MPD::Song::GetGenre));
308 return;
309 case 7:
310 ShowTag(*menu, s.GetTags(&MPD::Song::GetComposer));
311 return;
312 case 8:
313 ShowTag(*menu, s.GetTags(&MPD::Song::GetPerformer));
314 return;
315 case 9:
316 ShowTag(*menu, s.GetTags(&MPD::Song::GetDisc));
317 return;
318 case 10:
319 ShowTag(*menu, s.GetTags(&MPD::Song::GetComment));
320 return;
321 case 12:
322 if (s.GetNewName().empty())
323 *menu << s.GetName();
324 else
325 *menu << s.GetName() << Config.color2 << " -> " << clEnd << s.GetNewName();
326 return;
327 default:
328 return;
332 void Display::Items(const MPD::Item &item, void *, Menu<MPD::Item> *menu)
334 switch (item.type)
336 case MPD::itDirectory:
338 if (item.song)
340 *menu << "[..]";
341 return;
343 *menu << "[" << ExtractTopDirectory(item.name) << "]";
344 return;
346 case MPD::itSong:
347 if (!Config.columns_in_browser)
348 Display::Songs(*item.song, &Config.song_list_format, reinterpret_cast<Menu<MPD::Song> *>(menu));
349 else
350 Display::SongsInColumns(*item.song, 0, reinterpret_cast<Menu<MPD::Song> *>(menu));
351 return;
352 case MPD::itPlaylist:
353 *menu << Config.browser_playlist_prefix << item.name;
354 return;
355 default:
356 return;
360 void Display::SearchEngine(const std::pair<Buffer *, MPD::Song *> &pair, void *, Menu< std::pair<Buffer *, MPD::Song *> > *menu)
362 if (pair.second)
364 if (!Config.columns_in_search_engine)
365 Display::Songs(*pair.second, &Config.song_list_format, reinterpret_cast<Menu<MPD::Song> *>(menu));
366 else
367 Display::SongsInColumns(*pair.second, 0, reinterpret_cast<Menu<MPD::Song> *>(menu));
370 else
371 *menu << *pair.first;