fix statusbar scrolling speed with idle mode and bitrate displayed
[ncmpcpp.git] / src / display.cpp
blob990180c86a22bb8bef4b0a7903e61b7c367be07c
1 /***************************************************************************
2 * Copyright (C) 2008-2010 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 "info.h"
24 #include "playlist.h"
26 std::string Display::Columns()
28 if (Config.columns.empty())
29 return "";
31 std::string result, tag;
32 size_t where = 0;
33 int width;
35 std::vector<Column>::const_iterator next2last;
36 bool last_fixed = Config.columns.back().fixed;
37 if (Config.columns.size() > 1)
38 next2last = Config.columns.end()-2;
40 for (std::vector<Column>::const_iterator it = Config.columns.begin(); it != Config.columns.end(); ++it)
42 if (it == Config.columns.end()-1)
43 width = COLS-where;
44 else if (last_fixed && it == next2last)
45 width = COLS-where-(++next2last)->width;
46 else
47 width = 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)
100 long i = width-tag.length()-(it != Config.columns.begin());
101 if (i > 0)
102 result += std::string(i, ' ');
105 where += width;
106 result += tag;
108 if (result.length() > where)
109 result = result.substr(0, where);
110 else
111 for (size_t i = result.length(); i <= where && i < size_t(COLS); ++i, result += ' ') { }
113 return result;
116 void Display::SongsInColumns(const MPD::Song &s, void *, Menu<MPD::Song> *menu)
118 if (!s.Localized())
119 const_cast<MPD::Song *>(&s)->Localize();
121 bool is_now_playing = menu == myPlaylist->Items && (menu->isFiltered() ? s.GetPosition() : menu->CurrentlyDrawedPosition()) == size_t(myPlaylist->NowPlaying);
122 if (is_now_playing)
123 *menu << Config.now_playing_prefix;
125 if (Config.columns.empty())
126 return;
128 std::vector<Column>::const_iterator next2last, last, it;
129 size_t where = 0;
130 int width;
132 bool last_fixed = Config.columns.back().fixed;
133 if (Config.columns.size() > 1)
134 next2last = Config.columns.end()-2;
135 last = Config.columns.end()-1;
137 bool discard_colors = Config.discard_colors_if_item_is_selected && menu->isSelected(menu->CurrentlyDrawedPosition());
139 for (it = Config.columns.begin(); it != Config.columns.end(); ++it)
141 if (where)
143 menu->GotoXY(where, menu->Y());
144 *menu << ' ';
145 if (!discard_colors && (it-1)->color != clDefault)
146 *menu << clEnd;
149 if (it == Config.columns.end()-1)
150 width = menu->GetWidth()-where;
151 else if (last_fixed && it == next2last)
152 width = COLS-where-(++next2last)->width;
153 else
154 width = it->width*(it->fixed ? 1 : COLS/100.0);
156 MPD::Song::GetFunction get = 0;
158 switch (it->type)
160 case 'l':
161 get = &MPD::Song::GetLength;
162 break;
163 case 'D':
164 get = &MPD::Song::GetDirectory;
165 break;
166 case 'f':
167 get = &MPD::Song::GetName;
168 break;
169 case 'a':
170 get = &MPD::Song::GetArtist;
171 break;
172 case 'A':
173 get = &MPD::Song::GetAlbumArtist;
174 break;
175 case 'b':
176 get = &MPD::Song::GetAlbum;
177 break;
178 case 'y':
179 get = &MPD::Song::GetDate;
180 break;
181 case 'n':
182 get = &MPD::Song::GetTrackNumber;
183 break;
184 case 'N':
185 get = &MPD::Song::GetTrack;
186 break;
187 case 'g':
188 get = &MPD::Song::GetGenre;
189 break;
190 case 'c':
191 get = &MPD::Song::GetComposer;
192 break;
193 case 'p':
194 get = &MPD::Song::GetPerformer;
195 break;
196 case 'd':
197 get = &MPD::Song::GetDisc;
198 break;
199 case 'C':
200 get = &MPD::Song::GetComment;
201 break;
202 case 't':
203 if (!s.GetTitle().empty())
204 get = &MPD::Song::GetTitle;
205 else
206 get = &MPD::Song::GetName;
207 break;
208 default:
209 break;
211 if (!discard_colors && it->color != clDefault)
212 *menu << it->color;
213 whline(menu->Raw(), 32, menu->GetWidth()-where);
214 std::string tag = get ? s.GetTags(get) : "";
216 // last column might need to be shrinked to make space for np/sel suffixes
217 if (it == last)
219 if (menu->isSelected(menu->CurrentlyDrawedPosition()))
220 width -= Config.selected_item_suffix_length;
221 if (is_now_playing)
222 width -= Config.now_playing_suffix_length;
225 if (it->right_alignment)
227 if (width > 0 && (!tag.empty() || it->display_empty_tag))
229 int x, y;
230 menu->GetXY(x, y);
231 std::basic_string<my_char_t> wtag = TO_WSTRING(tag.empty() ? Config.empty_tag : tag).substr(0, width-!!x);
232 *menu << XY(x+width-Window::Length(wtag)-!!x, y) << wtag;
235 else
237 if (it == last)
239 if (width > 0)
241 std::basic_string<my_char_t> str;
242 if (!tag.empty())
243 str = TO_WSTRING(tag).substr(0, width-1);
244 else if (it->display_empty_tag)
245 str = TO_WSTRING(Config.empty_tag).substr(0, width-1);
246 *menu << str;
249 else
251 if (!tag.empty())
252 *menu << tag;
253 else if (it->display_empty_tag)
254 *menu << Config.empty_tag;
257 where += width;
259 if (!discard_colors && (--it)->color != clDefault)
260 *menu << clEnd;
261 if (is_now_playing)
262 *menu << Config.now_playing_suffix;
265 void Display::Songs(const MPD::Song &s, void *data, Menu<MPD::Song> *menu)
267 if (!s.Localized())
268 const_cast<MPD::Song *>(&s)->Localize();
270 bool is_now_playing = menu == myPlaylist->Items && (menu->isFiltered() ? s.GetPosition() : menu->CurrentlyDrawedPosition()) == size_t(myPlaylist->NowPlaying);
271 if (is_now_playing)
272 *menu << Config.now_playing_prefix;
274 bool discard_colors = Config.discard_colors_if_item_is_selected && menu->isSelected(menu->CurrentlyDrawedPosition());
276 std::string line = s.toString(*static_cast<std::string *>(data), "$");
277 for (std::string::const_iterator it = line.begin(); it != line.end(); ++it)
279 if (*it == '$')
281 if (++it == line.end()) // end of format
283 *menu << '$';
284 break;
286 else if (isdigit(*it)) // color
288 if (!discard_colors)
289 *menu << Color(*it-'0');
291 else if (*it == 'R') // right align
293 basic_buffer<my_char_t> buf;
294 buf << U(" ");
295 String2Buffer(TO_WSTRING(line.substr(it-line.begin()+1)), buf);
296 if (discard_colors)
297 buf.RemoveFormatting();
298 if (is_now_playing)
299 buf << Config.now_playing_suffix;
300 *menu << XY(menu->GetWidth()-buf.Str().length()-(menu->isSelected(menu->CurrentlyDrawedPosition()) ? Config.selected_item_suffix_length : 0), menu->Y()) << buf;
301 return;
303 else // not a color nor right align, just a random character
304 *menu << *--it;
306 else if (*it == MPD::Song::FormatEscapeCharacter)
308 // treat '$' as a normal character if song format escape char is prepended to it
309 if (++it == line.end() || *it != '$')
310 --it;
311 *menu << *it;
313 else
314 *menu << *it;
316 if (is_now_playing)
317 *menu << Config.now_playing_suffix;
320 void Display::Tags(const MPD::Song &s, void *data, Menu<MPD::Song> *menu)
322 size_t i = static_cast<Menu<std::string> *>(data)->Choice();
323 if (i < 11)
325 ShowTag(*menu, s.GetTags(Info::Tags[i].Get));
327 else if (i == 12)
329 if (s.GetNewName().empty())
330 *menu << s.GetName();
331 else
332 *menu << s.GetName() << Config.color2 << " -> " << clEnd << s.GetNewName();
336 void Display::Items(const MPD::Item &item, void *, Menu<MPD::Item> *menu)
338 switch (item.type)
340 case MPD::itDirectory:
342 if (item.song)
344 *menu << "[..]";
345 return;
347 *menu << "[" << ExtractTopDirectory(item.name) << "]";
348 return;
350 case MPD::itSong:
351 if (!Config.columns_in_browser)
352 Display::Songs(*item.song, &Config.song_list_format, reinterpret_cast<Menu<MPD::Song> *>(menu));
353 else
354 Display::SongsInColumns(*item.song, 0, reinterpret_cast<Menu<MPD::Song> *>(menu));
355 return;
356 case MPD::itPlaylist:
357 *menu << Config.browser_playlist_prefix << item.name;
358 return;
359 default:
360 return;
364 void Display::SearchEngine(const std::pair<Buffer *, MPD::Song *> &pair, void *, Menu< std::pair<Buffer *, MPD::Song *> > *menu)
366 if (pair.second)
368 if (!Config.columns_in_search_engine)
369 Display::Songs(*pair.second, &Config.song_list_format, reinterpret_cast<Menu<MPD::Song> *>(menu));
370 else
371 Display::SongsInColumns(*pair.second, 0, reinterpret_cast<Menu<MPD::Song> *>(menu));
374 else
375 *menu << *pair.first;