move code responsible for screen resize to SIGWINCH handler
[ncmpcpp.git] / src / display.cpp
bloba5b86b8307f616cd4bc2133f11c88f2b8bb67df4
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 't':
64 tag = "Title";
65 break;
66 case 'b':
67 tag = "Album";
68 break;
69 case 'y':
70 tag = "Year";
71 break;
72 case 'n':
73 case 'N':
74 tag = "Track";
75 break;
76 case 'g':
77 tag = "Genre";
78 break;
79 case 'c':
80 tag = "Composer";
81 break;
82 case 'p':
83 tag = "Performer";
84 break;
85 case 'd':
86 tag = "Disc";
87 break;
88 case 'C':
89 tag = "Comment";
90 break;
91 default:
92 tag.clear();
93 break;
95 if (it->right_alignment)
96 for (long i = 0; i < long(width-tag.length()-(it != Config.columns.begin())); ++i, result += ' ') { }
98 where += width;
99 result += tag;
101 if (result.length() > where)
102 result = result.substr(0, where);
103 else
104 for (size_t i = result.length(); i <= where && i < size_t(COLS); ++i, result += ' ') { }
106 return result;
109 void Display::SongsInColumns(const MPD::Song &s, void *, Menu<MPD::Song> *menu)
111 if (!s.Localized())
112 const_cast<MPD::Song *>(&s)->Localize();
114 bool is_now_playing = menu == myPlaylist->Items && (menu->isFiltered() ? s.GetPosition() : menu->CurrentlyDrawedPosition()) == size_t(myPlaylist->NowPlaying);
115 if (is_now_playing)
116 *menu << Config.now_playing_prefix;
118 if (Config.columns.empty())
119 return;
121 std::vector<Column>::const_iterator next2last, it;
122 size_t where = 0;
123 int width;
125 bool last_fixed = Config.columns.back().fixed;
126 if (Config.columns.size() > 1)
127 next2last = Config.columns.end()-2;
129 for (it = Config.columns.begin(); it != Config.columns.end(); ++it)
131 if (where)
133 menu->GotoXY(where, menu->Y());
134 *menu << ' ';
135 if ((it-1)->color != clDefault)
136 *menu << clEnd;
139 width = (last_fixed && it == next2last
140 ? COLS-where-(++next2last)->width
141 : (it == Config.columns.end()-1
142 ? menu->GetWidth()-where
143 : (it->width*(it->fixed ? 1 : COLS/100.0))
147 MPD::Song::GetFunction get = 0;
149 switch (it->type)
151 case 'l':
152 get = &MPD::Song::GetLength;
153 break;
154 case 'D':
155 get = &MPD::Song::GetDirectory;
156 break;
157 case 'f':
158 get = &MPD::Song::GetName;
159 break;
160 case 'a':
161 get = &MPD::Song::GetArtist;
162 break;
163 case 'b':
164 get = &MPD::Song::GetAlbum;
165 break;
166 case 'y':
167 get = &MPD::Song::GetDate;
168 break;
169 case 'n':
170 get = &MPD::Song::GetTrackNumber;
171 break;
172 case 'N':
173 get = &MPD::Song::GetTrack;
174 break;
175 case 'g':
176 get = &MPD::Song::GetGenre;
177 break;
178 case 'c':
179 get = &MPD::Song::GetComposer;
180 break;
181 case 'p':
182 get = &MPD::Song::GetPerformer;
183 break;
184 case 'd':
185 get = &MPD::Song::GetDisc;
186 break;
187 case 'C':
188 get = &MPD::Song::GetComment;
189 break;
190 case 't':
191 if (!s.GetTitle().empty())
192 get = &MPD::Song::GetTitle;
193 else
194 get = &MPD::Song::GetName;
195 break;
196 default:
197 break;
199 if (it->color != clDefault)
200 *menu << it->color;
201 whline(menu->Raw(), 32, menu->GetWidth()-where);
202 std::string tag = get ? s.GetTags(get) : "";
203 if (it->right_alignment)
205 if (!tag.empty() || it->display_empty_tag)
207 int x, y;
208 menu->GetXY(x, y);
209 std::basic_string<my_char_t> wtag = TO_WSTRING(tag.empty() ? Config.empty_tag : tag).substr(0, width-!!x);
210 *menu << XY(x+width-Window::Length(wtag)-!!x, y) << wtag;
213 else
215 if (!tag.empty())
216 *menu << tag;
217 else if (it->display_empty_tag)
218 *menu << Config.empty_tag;
220 where += width;
222 if ((--it)->color != clDefault)
223 *menu << clEnd;
224 if (is_now_playing)
225 *menu << Config.now_playing_suffix;
228 void Display::Songs(const MPD::Song &s, void *data, Menu<MPD::Song> *menu)
230 if (!s.Localized())
231 const_cast<MPD::Song *>(&s)->Localize();
233 bool is_now_playing = menu == myPlaylist->Items && (menu->isFiltered() ? s.GetPosition() : menu->CurrentlyDrawedPosition()) == size_t(myPlaylist->NowPlaying);
234 if (is_now_playing)
235 *menu << Config.now_playing_prefix;
237 std::string line = s.toString(*static_cast<std::string *>(data), "$");
238 for (std::string::const_iterator it = line.begin(); it != line.end(); ++it)
240 if (*it == '$')
242 if (++it == line.end()) // end of format
244 *menu << '$';
245 break;
247 else if (isdigit(*it)) // color
249 *menu << Color(*it-'0');
251 else if (*it == 'R') // right align
253 basic_buffer<my_char_t> buf;
254 buf << U(" ");
255 String2Buffer(TO_WSTRING(line.substr(it-line.begin()+1)), buf);
256 if (is_now_playing)
257 buf << Config.now_playing_suffix;
258 *menu << XY(menu->GetWidth()-buf.Str().length(), menu->Y()) << buf;
259 return;
261 else // not a color nor right align, just a random character
262 *menu << *--it;
264 else if (*it == MPD::Song::FormatEscapeCharacter)
266 // treat '$' as a normal character if song format escape char is prepended to it
267 if (++it == line.end() || *it != '$')
268 --it;
269 *menu << *it;
271 else
272 *menu << *it;
274 if (is_now_playing)
275 *menu << Config.now_playing_suffix;
278 void Display::Tags(const MPD::Song &s, void *data, Menu<MPD::Song> *menu)
280 switch (static_cast<Menu<std::string> *>(data)->Choice())
282 case 0:
283 ShowTag(*menu, s.GetTags(&MPD::Song::GetTitle));
284 return;
285 case 1:
286 ShowTag(*menu, s.GetTags(&MPD::Song::GetArtist));
287 return;
288 case 2:
289 ShowTag(*menu, s.GetTags(&MPD::Song::GetAlbum));
290 return;
291 case 3:
292 ShowTag(*menu, s.GetTags(&MPD::Song::GetDate));
293 return;
294 case 4:
295 ShowTag(*menu, s.GetTags(&MPD::Song::GetTrack));
296 return;
297 case 5:
298 ShowTag(*menu, s.GetTags(&MPD::Song::GetGenre));
299 return;
300 case 6:
301 ShowTag(*menu, s.GetTags(&MPD::Song::GetComposer));
302 return;
303 case 7:
304 ShowTag(*menu, s.GetTags(&MPD::Song::GetPerformer));
305 return;
306 case 8:
307 ShowTag(*menu, s.GetTags(&MPD::Song::GetDisc));
308 return;
309 case 9:
310 ShowTag(*menu, s.GetTags(&MPD::Song::GetComment));
311 return;
312 case 11:
313 if (s.GetNewName().empty())
314 *menu << s.GetName();
315 else
316 *menu << s.GetName() << Config.color2 << " -> " << clEnd << s.GetNewName();
317 return;
318 default:
319 return;
323 void Display::Items(const MPD::Item &item, void *, Menu<MPD::Item> *menu)
325 switch (item.type)
327 case MPD::itDirectory:
329 if (item.song)
331 *menu << "[..]";
332 return;
334 *menu << "[" << ExtractTopDirectory(item.name) << "]";
335 return;
337 case MPD::itSong:
338 if (!Config.columns_in_browser)
339 Display::Songs(*item.song, &Config.song_list_format, reinterpret_cast<Menu<MPD::Song> *>(menu));
340 else
341 Display::SongsInColumns(*item.song, 0, reinterpret_cast<Menu<MPD::Song> *>(menu));
342 return;
343 case MPD::itPlaylist:
344 *menu << Config.browser_playlist_prefix << item.name;
345 return;
346 default:
347 return;
351 void Display::SearchEngine(const std::pair<Buffer *, MPD::Song *> &pair, void *, Menu< std::pair<Buffer *, MPD::Song *> > *menu)
353 if (pair.second)
355 if (!Config.columns_in_search_engine)
356 Display::Songs(*pair.second, &Config.song_list_format, reinterpret_cast<Menu<MPD::Song> *>(menu));
357 else
358 Display::SongsInColumns(*pair.second, 0, reinterpret_cast<Menu<MPD::Song> *>(menu));
361 else
362 *menu << *pair.first;