1 /* ncmpc (Ncurses MPD Client)
2 * (c) 2004-2009 The Music Player Daemon Project
3 * Project homepage: http://musicpd.org
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.
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.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 #include "screen_browser.h"
25 #include "screen_utils.h"
32 #define HIGHLIGHT (0x01)
35 static const char playlist_format
[] = "*%s*";
39 /* clear the highlight flag for all items in the filelist */
41 clear_highlights(mpdclient_filelist_t
*fl
)
45 for (i
= 0; i
< filelist_length(fl
); ++i
) {
46 struct filelist_entry
*entry
= filelist_get(fl
, i
);
48 entry
->flags
&= ~HIGHLIGHT
;
52 /* change the highlight flag for a song */
54 set_highlight(mpdclient_filelist_t
*fl
, mpd_Song
*song
, int highlight
)
56 int i
= filelist_find_song(fl
, song
);
57 struct filelist_entry
*entry
;
62 entry
= filelist_get(fl
, i
);
64 entry
->flags
|= HIGHLIGHT
;
66 entry
->flags
&= ~HIGHLIGHT
;
69 /* sync highlight flags with playlist */
71 sync_highlights(mpdclient_t
*c
, mpdclient_filelist_t
*fl
)
75 for (i
= 0; i
< filelist_length(fl
); ++i
) {
76 struct filelist_entry
*entry
= filelist_get(fl
, i
);
77 mpd_InfoEntity
*entity
= entry
->entity
;
79 if ( entity
&& entity
->type
==MPD_INFO_ENTITY_TYPE_SONG
) {
80 mpd_Song
*song
= entity
->info
.song
;
82 if (playlist_get_index_from_same_song(c
, song
) >= 0)
83 entry
->flags
|= HIGHLIGHT
;
85 entry
->flags
&= ~HIGHLIGHT
;
90 /* the playlist has been updated -> fix highlights */
92 browser_playlist_changed(struct screen_browser
*browser
, mpdclient_t
*c
,
93 int event
, gpointer data
)
95 if (browser
->filelist
== NULL
)
99 case PLAYLIST_EVENT_CLEAR
:
100 clear_highlights(browser
->filelist
);
102 case PLAYLIST_EVENT_ADD
:
103 set_highlight(browser
->filelist
, (mpd_Song
*) data
, 1);
105 case PLAYLIST_EVENT_DELETE
:
106 set_highlight(browser
->filelist
, (mpd_Song
*) data
, 0);
108 case PLAYLIST_EVENT_MOVE
:
111 sync_highlights(c
, browser
->filelist
);
118 /* list_window callback */
120 browser_lw_callback(unsigned idx
, bool *highlight
, G_GNUC_UNUSED
char **second_column
, void *data
)
122 static char buf
[BUFSIZE
];
123 mpdclient_filelist_t
*fl
= (mpdclient_filelist_t
*) data
;
124 filelist_entry_t
*entry
;
125 mpd_InfoEntity
*entity
;
127 if (fl
== NULL
|| idx
>= filelist_length(fl
))
130 entry
= filelist_get(fl
, idx
);
131 assert(entry
!= NULL
);
133 entity
= entry
->entity
;
135 *highlight
= (entry
->flags
& HIGHLIGHT
) != 0;
143 if( entity
->type
==MPD_INFO_ENTITY_TYPE_DIRECTORY
) {
144 mpd_Directory
*dir
= entity
->info
.directory
;
145 char *directory
= utf8_to_locale(g_basename(dir
->path
));
147 g_snprintf(buf
, BUFSIZE
, "[%s]", directory
);
150 } else if( entity
->type
==MPD_INFO_ENTITY_TYPE_SONG
) {
151 const mpd_Song
*song
= entity
->info
.song
;
153 strfsong(buf
, BUFSIZE
, options
.list_format
, song
);
155 } else if( entity
->type
==MPD_INFO_ENTITY_TYPE_PLAYLISTFILE
) {
156 mpd_PlaylistFile
*plf
= entity
->info
.playlistFile
;
157 char *filename
= utf8_to_locale(g_basename(plf
->path
));
159 g_snprintf(buf
, BUFSIZE
, playlist_format
, filename
);
164 return "Error: Unknown entry!";
168 load_playlist(mpdclient_t
*c
, const mpd_PlaylistFile
*plf
)
170 char *filename
= utf8_to_locale(plf
->path
);
172 if (mpdclient_cmd_load_playlist(c
, plf
->path
) == 0)
173 screen_status_printf(_("Loading playlist %s..."),
174 g_basename(filename
));
180 enqueue_and_play(mpdclient_t
*c
, filelist_entry_t
*entry
)
183 mpd_InfoEntity
*entity
= entry
->entity
;
184 mpd_Song
*song
= entity
->info
.song
;
187 if (!(entry
->flags
& HIGHLIGHT
)) {
189 if (mpdclient_cmd_add(c
, song
) == 0) {
193 entry
->flags
|= HIGHLIGHT
;
195 strfsong(buf
, BUFSIZE
, options
.list_format
, song
);
196 screen_status_printf(_("Adding \'%s\' to playlist"), buf
);
197 mpdclient_update(c
); /* get song id */
204 idx
= playlist_get_index_from_same_song(c
, song
);
205 mpdclient_cmd_play(c
, idx
);
209 struct filelist_entry
*
210 browser_get_selected_entry(const struct screen_browser
*browser
)
212 if (browser
->filelist
== NULL
||
213 browser
->lw
->selected_start
< browser
->lw
->selected_end
||
214 browser
->lw
->selected
>= filelist_length(browser
->filelist
))
217 return filelist_get(browser
->filelist
, browser
->lw
->selected
);
220 static const struct mpd_InfoEntity
*
221 browser_get_selected_entity(const struct screen_browser
*browser
)
223 const struct filelist_entry
*entry
= browser_get_selected_entry(browser
);
230 static const struct mpd_song
*
231 browser_get_selected_song(const struct screen_browser
*browser
)
233 const struct mpd_InfoEntity
*entity
= browser_get_selected_entity(browser
);
235 return entity
!= NULL
&& entity
->type
== MPD_INFO_ENTITY_TYPE_SONG
240 static struct filelist_entry
*
241 browser_get_index(const struct screen_browser
*browser
, unsigned i
)
243 if (browser
->filelist
== NULL
||
244 i
>= filelist_length(browser
->filelist
))
247 return filelist_get(browser
->filelist
, i
);
251 browser_handle_enter(struct screen_browser
*browser
, mpdclient_t
*c
)
253 struct filelist_entry
*entry
= browser_get_selected_entry(browser
);
254 mpd_InfoEntity
*entity
;
259 entity
= entry
->entity
;
263 if (entity
->type
== MPD_INFO_ENTITY_TYPE_PLAYLISTFILE
)
264 return load_playlist(c
, entity
->info
.playlistFile
);
265 else if (entity
->type
== MPD_INFO_ENTITY_TYPE_SONG
)
266 return enqueue_and_play(c
, entry
);
271 browser_select_entry(mpdclient_t
*c
, filelist_entry_t
*entry
,
272 G_GNUC_UNUSED gboolean toggle
)
274 assert(entry
!= NULL
);
275 assert(entry
->entity
!= NULL
);
277 if (entry
->entity
->type
== MPD_INFO_ENTITY_TYPE_PLAYLISTFILE
)
278 return load_playlist(c
, entry
->entity
->info
.playlistFile
);
280 if (entry
->entity
->type
== MPD_INFO_ENTITY_TYPE_DIRECTORY
) {
281 mpd_Directory
*dir
= entry
->entity
->info
.directory
;
283 if (mpdclient_cmd_add_path(c
, dir
->path
) == 0) {
284 char *tmp
= utf8_to_locale(dir
->path
);
286 screen_status_printf(_("Adding \'%s\' to playlist"), tmp
);
293 if (entry
->entity
->type
!= MPD_INFO_ENTITY_TYPE_SONG
)
296 assert(entry
->entity
->info
.song
!= NULL
);
299 if (!toggle
|| (entry
->flags
& HIGHLIGHT
) == 0)
302 mpd_Song
*song
= entry
->entity
->info
.song
;
305 entry
->flags
|= HIGHLIGHT
;
308 if (mpdclient_cmd_add(c
, song
) == 0) {
311 strfsong(buf
, BUFSIZE
, options
.list_format
, song
);
312 screen_status_printf(_("Adding \'%s\' to playlist"), buf
);
316 /* remove song from playlist */
317 mpd_Song
*song
= entry
->entity
->info
.song
;
320 entry
->flags
&= ~HIGHLIGHT
;
322 while ((idx
= playlist_get_index_from_same_song(c
, song
)) >= 0)
323 mpdclient_cmd_delete(c
, idx
);
331 browser_handle_select(struct screen_browser
*browser
, mpdclient_t
*c
)
333 struct filelist_entry
*entry
;
335 if (browser
->lw
->range_selection
) {
336 for (unsigned i
= browser
->lw
->selected_start
;
337 i
<= browser
->lw
->selected_end
; i
++) {
338 entry
= browser_get_index(browser
, i
);
340 if (entry
!= NULL
&& entry
->entity
!= NULL
)
341 browser_select_entry(c
, entry
, TRUE
);
345 entry
= browser_get_selected_entry(browser
);
347 if (entry
== NULL
|| entry
->entity
== NULL
)
350 return browser_select_entry(c
, entry
, TRUE
);
355 browser_handle_add(struct screen_browser
*browser
, mpdclient_t
*c
)
357 struct filelist_entry
*entry
;
359 if (browser
->lw
->range_selection
) {
360 for (unsigned i
= browser
->lw
->selected_start
;
361 i
<= browser
->lw
->selected_end
; i
++) {
362 entry
= browser_get_index(browser
, i
);
364 if (entry
!= NULL
&& entry
->entity
!= NULL
)
365 browser_select_entry(c
, entry
, FALSE
);
369 entry
= browser_get_selected_entry(browser
);
371 if (entry
== NULL
|| entry
->entity
== NULL
)
374 return browser_select_entry(c
, entry
, FALSE
);
379 browser_handle_select_all(struct screen_browser
*browser
, mpdclient_t
*c
)
383 if (browser
->filelist
== NULL
)
386 for (i
= 0; i
< filelist_length(browser
->filelist
); ++i
) {
387 struct filelist_entry
*entry
= filelist_get(browser
->filelist
, i
);
389 if (entry
!= NULL
&& entry
->entity
!= NULL
)
390 browser_select_entry(c
, entry
, FALSE
);
396 browser_handle_mouse_event(struct screen_browser
*browser
, mpdclient_t
*c
)
399 unsigned prev_selected
= browser
->lw
->selected
;
400 unsigned long bstate
;
403 if (browser
->filelist
)
404 length
= filelist_length(browser
->filelist
);
408 if (screen_get_mouse_event(c
, &bstate
, &row
) ||
409 list_window_mouse(browser
->lw
, length
, bstate
, row
))
412 browser
->lw
->selected
= browser
->lw
->start
+ row
;
413 list_window_check_selected(browser
->lw
, length
);
415 if( bstate
& BUTTON1_CLICKED
) {
416 if (prev_selected
== browser
->lw
->selected
)
417 browser_handle_enter(browser
, c
);
418 } else if (bstate
& BUTTON3_CLICKED
) {
419 if (prev_selected
== browser
->lw
->selected
)
420 browser_handle_select(browser
, c
);
428 browser_cmd(struct screen_browser
*browser
,
429 struct mpdclient
*c
, command_t cmd
)
431 const struct mpd_song
*song
;
433 if (browser
->filelist
== NULL
)
438 browser_handle_enter(browser
, c
);
442 if (browser_handle_select(browser
, c
))
443 /* continue and select next item... */
446 /* call list_window_cmd to go to the next item */
450 if (browser_handle_add(browser
, c
))
451 /* continue and select next item... */
454 /* call list_window_cmd to go to the next item */
458 browser_handle_select_all(browser
, c
);
463 case CMD_LIST_FIND_NEXT
:
464 case CMD_LIST_RFIND_NEXT
:
465 screen_find(browser
->lw
, filelist_length(browser
->filelist
),
466 cmd
, browser_lw_callback
,
470 screen_jump(browser
->lw
, browser_lw_callback
, browser
->filelist
);
474 case CMD_MOUSE_EVENT
:
475 browser_handle_mouse_event(browser
, c
);
479 #ifdef ENABLE_SONG_SCREEN
480 case CMD_SCREEN_SONG
:
481 song
= browser_get_selected_song(browser
);
485 screen_song_switch(c
, song
);
490 song
= browser_get_selected_song(browser
);
494 screen_file_goto_song(c
, song
);
497 #ifdef ENABLE_LYRICS_SCREEN
498 case CMD_SCREEN_LYRICS
:
499 song
= browser_get_selected_song(browser
);
503 screen_lyrics_switch(c
, song
, false);
506 case CMD_SCREEN_SWAP
:
507 screen_swap(c
, browser_get_selected_song(browser
));
514 if (list_window_cmd(browser
->lw
, filelist_length(browser
->filelist
),