Code

screen_browser: removed redundant highlight check
[ncmpc.git] / src / screen_browser.c
1 /*
2  * $Id$
3  *
4  * (c) 2004 by Kalle Wallin <kaw@linux.se>
5  * Copyright (C) 2008 Max Kellermann <max@duempel.org>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  */
22 #include "screen_browser.h"
23 #include "ncmpc.h"
24 #include "options.h"
25 #include "support.h"
26 #include "strfsong.h"
27 #include "screen_utils.h"
28 #include "gcc.h"
30 #include <string.h>
32 #define USE_OLD_LAYOUT
33 #undef  USE_OLD_ADD
35 #define BUFSIZE 1024
37 #define HIGHLIGHT  (0x01)
39 /* clear the highlight flag for all items in the filelist */
40 static void
41 clear_highlights(mpdclient_filelist_t *fl)
42 {
43         GList *list = g_list_first(fl->list);
45         while( list ) {
46                 filelist_entry_t *entry = list->data;
48                 entry->flags &= ~HIGHLIGHT;
49                 list = list->next;
50         }
51 }
53 /* change the highlight flag for a song */
54 static void
55 set_highlight(mpdclient_filelist_t *fl, mpd_Song *song, int highlight)
56 {
57         GList *list = g_list_first(fl->list);
59         if( !song )
60                 return;
62         while( list ) {
63                 filelist_entry_t *entry = list->data;
64                 mpd_InfoEntity *entity  = entry->entity;
66                 if( entity && entity->type==MPD_INFO_ENTITY_TYPE_SONG ) {
67                         mpd_Song *song2 = entity->info.song;
69                         if( strcmp(song->file, song2->file) == 0 ) {
70                                 if(highlight)
71                                         entry->flags |= HIGHLIGHT;
72                                 else
73                                         entry->flags &= ~HIGHLIGHT;
74                         }
75                 }
76                 list = list->next;
77         }
78 }
80 /* sync highlight flags with playlist */
81 void
82 sync_highlights(mpdclient_t *c, mpdclient_filelist_t *fl)
83 {
84         GList *list = g_list_first(fl->list);
86         while(list) {
87                 filelist_entry_t *entry = list->data;
88                 mpd_InfoEntity *entity = entry->entity;
90                 if( entity && entity->type==MPD_INFO_ENTITY_TYPE_SONG ) {
91                         mpd_Song *song = entity->info.song;
93                         if( playlist_get_index_from_file(c, song->file) >= 0 )
94                                 entry->flags |= HIGHLIGHT;
95                         else
96                                 entry->flags &= ~HIGHLIGHT;
97                 }
98                 list=list->next;
99         }
102 /* the playlist have been updated -> fix highlights */
103 void
104 browser_playlist_changed(struct screen_browser *browser, mpdclient_t *c,
105                          int event, gpointer data)
107         if (browser->filelist == NULL)
108                 return;
110         D("screen_file.c> playlist_callback() [%d]\n", event);
111         switch(event) {
112         case PLAYLIST_EVENT_CLEAR:
113                 clear_highlights(browser->filelist);
114                 break;
115         case PLAYLIST_EVENT_ADD:
116                 set_highlight(browser->filelist, (mpd_Song *) data, 1);
117                 break;
118         case PLAYLIST_EVENT_DELETE:
119                 set_highlight(browser->filelist, (mpd_Song *) data, 0);
120                 break;
121         case PLAYLIST_EVENT_MOVE:
122                 break;
123         default:
124                 sync_highlights(c, browser->filelist);
125                 break;
126         }
129 /* list_window callback */
130 const char *
131 browser_lw_callback(unsigned idx, int *highlight, void *data)
133         static char buf[BUFSIZE];
134         mpdclient_filelist_t *fl = (mpdclient_filelist_t *) data;
135         filelist_entry_t *entry;
136         mpd_InfoEntity *entity;
138         if( (entry=(filelist_entry_t *)g_list_nth_data(fl->list,idx))==NULL )
139                 return NULL;
141         entity = entry->entity;
142         *highlight = (entry->flags & HIGHLIGHT);
144         if( entity == NULL )
145                 return "[..]";
147         if( entity->type==MPD_INFO_ENTITY_TYPE_DIRECTORY ) {
148                 mpd_Directory *dir = entity->info.directory;
149                 char *directory = utf8_to_locale(basename(dir->path));
151                 g_snprintf(buf, BUFSIZE, "[%s]", directory);
152                 g_free(directory);
153                 return buf;
154         } else if( entity->type==MPD_INFO_ENTITY_TYPE_SONG ) {
155                 mpd_Song *song = entity->info.song;
157                 strfsong(buf, BUFSIZE, LIST_FORMAT, song);
158                 return buf;
159         } else if( entity->type==MPD_INFO_ENTITY_TYPE_PLAYLISTFILE ) {
160                 mpd_PlaylistFile *plf = entity->info.playlistFile;
161                 char *filename = utf8_to_locale(basename(plf->path));
163 #ifdef USE_OLD_LAYOUT
164                 g_snprintf(buf, BUFSIZE, "*%s*", filename);
165 #else
166                 g_snprintf(buf, BUFSIZE, "<Playlist> %s", filename);
167 #endif
168                 g_free(filename);
169                 return buf;
170         }
172         return "Error: Unknown entry!";
175 /* chdir */
176 int
177 browser_change_directory(struct screen_browser *browser, mpdclient_t *c,
178                          filelist_entry_t *entry, const char *new_path)
180         mpd_InfoEntity *entity = NULL;
181         gchar *path = NULL;
183         if( entry!=NULL )
184                 entity = entry->entity;
185         else if( new_path==NULL )
186                 return -1;
188         if( entity==NULL ) {
189                 if( entry || 0==strcmp(new_path, "..") ) {
190                         /* return to parent */
191                         char *parent = g_path_get_dirname(browser->filelist->path);
192                         if( strcmp(parent, ".") == 0 )
193                                 parent[0] = '\0';
194                         path = g_strdup(parent);
195                         list_window_reset(browser->lw);
196                         /* restore previous list window state */
197                         list_window_pop_state(browser->lw_state, browser->lw);
198                 } else {
199                         /* entry==NULL, then new_path ("" is root) */
200                         path = g_strdup(new_path);
201                         list_window_reset(browser->lw);
202                         /* restore first list window state (pop while returning true) */
203                         while(list_window_pop_state(browser->lw_state, browser->lw));
204                 }
205         } else if( entity->type==MPD_INFO_ENTITY_TYPE_DIRECTORY) {
206                 /* enter sub */
207                 mpd_Directory *dir = entity->info.directory;
208                 path = utf8_to_locale(dir->path);
209                 /* save current list window state */
210                 list_window_push_state(browser->lw_state, browser->lw);
211         } else
212                 return -1;
214         mpdclient_filelist_free(browser->filelist);
215         browser->filelist = mpdclient_filelist_get(c, path);
216         sync_highlights(c, browser->filelist);
217         list_window_check_selected(browser->lw, browser->filelist->length);
218         g_free(path);
219         return 0;
222 static int
223 load_playlist(mpdclient_t *c, filelist_entry_t *entry)
225         mpd_InfoEntity *entity = entry->entity;
226         mpd_PlaylistFile *plf = entity->info.playlistFile;
227         char *filename = utf8_to_locale(plf->path);
229         if (mpdclient_cmd_load_playlist_utf8(c, plf->path) == 0)
230                 screen_status_printf(_("Loading playlist %s..."), basename(filename));
231         g_free(filename);
232         return 0;
235 static int
236 enqueue_and_play(mpdclient_t *c, filelist_entry_t *entry)
238         int idx;
239         mpd_InfoEntity *entity = entry->entity;
240         mpd_Song *song = entity->info.song;
242         if (!(entry->flags & HIGHLIGHT)) {
243                 if (mpdclient_cmd_add(c, song) == 0) {
244                         char buf[BUFSIZE];
246                         entry->flags |= HIGHLIGHT;
247                         strfsong(buf, BUFSIZE, LIST_FORMAT, song);
248                         screen_status_printf(_("Adding \'%s\' to playlist\n"), buf);
249                         mpdclient_update(c); /* get song id */
250                 } else
251                         return -1;
252         }
254         idx = playlist_get_index_from_file(c, song->file);
255         mpdclient_cmd_play(c, idx);
256         return 0;
259 int
260 browser_handle_enter(struct screen_browser *browser, mpdclient_t *c)
262         filelist_entry_t *entry;
263         mpd_InfoEntity *entity;
265         if (browser->filelist == NULL)
266                 return -1;
267         entry = (filelist_entry_t *) g_list_nth_data(browser->filelist->list,
268                                                      browser->lw->selected);
269         if( entry==NULL )
270                 return -1;
272         entity = entry->entity;
273         if (entity == NULL || entity->type == MPD_INFO_ENTITY_TYPE_DIRECTORY)
274                 return browser_change_directory(browser, c, entry, NULL);
275         else if (entity->type == MPD_INFO_ENTITY_TYPE_PLAYLISTFILE)
276                 return load_playlist(c, entry);
277         else if (entity->type == MPD_INFO_ENTITY_TYPE_SONG)
278                 return enqueue_and_play(c, entry);
279         return -1;
283 #ifdef USE_OLD_ADD
284 /* NOTE - The add_directory functions should move to mpdclient.c */
285 extern gint mpdclient_finish_command(mpdclient_t *c);
287 static int
288 add_directory(mpdclient_t *c, char *dir)
290         mpd_InfoEntity *entity;
291         GList *subdir_list = NULL;
292         GList *list = NULL;
293         char *dirname;
295         dirname = utf8_to_locale(dir);
296         screen_status_printf(_("Adding directory %s...\n"), dirname);
297         doupdate();
298         g_free(dirname);
299         dirname = NULL;
301         mpd_sendLsInfoCommand(c->connection, dir);
302         mpd_sendCommandListBegin(c->connection);
303         while( (entity=mpd_getNextInfoEntity(c->connection)) ) {
304                 if( entity->type==MPD_INFO_ENTITY_TYPE_SONG ) {
305                         mpd_Song *song = entity->info.song;
306                         mpd_sendAddCommand(c->connection, song->file);
307                         mpd_freeInfoEntity(entity);
308                 } else if( entity->type==MPD_INFO_ENTITY_TYPE_DIRECTORY ) {
309                         subdir_list = g_list_append(subdir_list, (gpointer) entity);
310                 } else
311                         mpd_freeInfoEntity(entity);
312         }
313         mpd_sendCommandListEnd(c->connection);
314         mpdclient_finish_command(c);
315         c->need_update = TRUE;
317         list = g_list_first(subdir_list);
318         while( list!=NULL ) {
319                 mpd_Directory *dir;
321                 entity = list->data;
322                 dir = entity->info.directory;
323                 add_directory(c, dir->path);
324                 mpd_freeInfoEntity(entity);
325                 list->data=NULL;
326                 list=list->next;
327         }
328         g_list_free(subdir_list);
329         return 0;
331 #endif
333 static int
334 browser_select_entry(mpdclient_t *c, filelist_entry_t *entry,
335                      gboolean toggle)
337         assert(entry != NULL);
338         assert(entry->entity != NULL);
340         if (entry->entity->type == MPD_INFO_ENTITY_TYPE_PLAYLISTFILE)
341                 return load_playlist(c, entry);
343         if (entry->entity->type == MPD_INFO_ENTITY_TYPE_DIRECTORY) {
344                 mpd_Directory *dir = entry->entity->info.directory;
345 #ifdef USE_OLD_ADD
346                 add_directory(c, tmp);
347 #else
348                 if (mpdclient_cmd_add_path_utf8(c, dir->path) == 0) {
349                         char *tmp = utf8_to_locale(dir->path);
351                         screen_status_printf(_("Adding \'%s\' to playlist\n"), tmp);
352                         g_free(tmp);
353                 }
354 #endif
355                 return 0;
356         }
358         if (entry->entity->type != MPD_INFO_ENTITY_TYPE_SONG)
359                 return -1;
361         if (!toggle || (entry->flags & HIGHLIGHT) == 0) {
362                 mpd_Song *song = entry->entity->info.song;
364                 entry->flags |= HIGHLIGHT;
366                 if (mpdclient_cmd_add(c, song) == 0) {
367                         char buf[BUFSIZE];
369                         strfsong(buf, BUFSIZE, LIST_FORMAT, song);
370                         screen_status_printf(_("Adding \'%s\' to playlist\n"), buf);
371                 }
372         } else {
373                 /* remove song from playlist */
374                 mpd_Song *song = entry->entity->info.song;
376                 entry->flags &= ~HIGHLIGHT;
378                 if (song) {
379                         int idx;
381                         while ((idx = playlist_get_index_from_file(c, song->file)) >=0)
382                                 mpdclient_cmd_delete(c, idx);
383                 }
384         }
386         return 0;
389 int
390 browser_handle_select(struct screen_browser *browser, mpdclient_t *c)
392         filelist_entry_t *entry;
394         if (browser->filelist == NULL)
395                 return -1;
396         entry = g_list_nth_data(browser->filelist->list, browser->lw->selected);
397         if (entry == NULL || entry->entity == NULL)
398                 return -1;
400         return browser_select_entry(c, entry, TRUE);
403 void
404 browser_handle_select_all(struct screen_browser *browser, mpdclient_t *c)
406         filelist_entry_t *entry;
407         GList *temp = browser->filelist->list;
409         if (browser->filelist == NULL)
410                 return;
412         for (browser->filelist->list = g_list_first(browser->filelist->list);
413              browser->filelist->list;
414              browser->filelist->list = g_list_next(browser->filelist->list)) {
415                 entry = browser->filelist->list->data;
416                 if (entry != NULL && entry->entity != NULL)
417                         browser_select_entry(c, entry, FALSE);
418         }
420         browser->filelist->list = temp;
423 #ifdef HAVE_GETMOUSE
424 int
425 browser_handle_mouse_event(struct screen_browser *browser, mpdclient_t *c)
427         int row;
428         unsigned prev_selected = browser->lw->selected;
429         unsigned long bstate;
430         int length;
432         if (browser->filelist)
433                 length = browser->filelist->length;
434         else
435                 length = 0;
437         if( screen_get_mouse_event(c, browser->lw, length, &bstate, &row) )
438                 return 1;
440         browser->lw->selected = browser->lw->start + row;
441         list_window_check_selected(browser->lw, length);
443         if( bstate & BUTTON1_CLICKED ) {
444                 if (prev_selected == browser->lw->selected)
445                         browser_handle_enter(browser, c);
446         } else if (bstate & BUTTON3_CLICKED) {
447                 if (prev_selected == browser->lw->selected)
448                         browser_handle_select(browser, c);
449         }
451         return 1;
453 #endif