📄 playlist.c
字号:
/* -*- linux-c -*- Copyright (C) 2004 Tom Szilagyi This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. $Id: playlist.c,v 1.116 2006/09/23 14:27:26 pasp Exp $*/#include <config.h>#include <stdio.h>#include <string.h>#include <dirent.h>#include <unistd.h>#include <sys/stat.h>#include <math.h>#include <gtk/gtk.h>#include <gdk/gdkkeysyms.h>#include <glib.h>#include <glib/gstdio.h>#include <libxml/xmlmemory.h>#include <libxml/parser.h>#include "common.h"#include "core.h"#include "rb.h"#include "gui_main.h"#include "music_browser.h"#include "file_info.h"#include "decoder/dec_mod.h"#include "decoder/file_decoder.h"#include "meta_decoder.h"#include "volume.h"#include "options.h"#include "i18n.h"#include "search_playlist.h"#include "playlist.h"#include "ifp_device.h"extern options_t options;extern void assign_audio_fc_filters(GtkFileChooser *fc);extern void assign_playlist_fc_filters(GtkFileChooser *fc);extern char pl_color_active[14];extern char pl_color_inactive[14];extern GtkTooltips * aqualung_tooltips;extern GtkWidget* gui_stock_label_button(gchar *blabel, const gchar *bstock);extern PangoFontDescription *fd_playlist;extern PangoFontDescription *fd_statusbar;GtkWidget * playlist_window;GtkWidget * da_dialog;GtkWidget * scrolled_win;extern GtkWidget * main_window;extern GtkWidget * info_window;extern GtkWidget * vol_window;int playlist_pos_x;int playlist_pos_y;int playlist_size_x;int playlist_size_y;int playlist_on;int playlist_color_is_set;int playlist_drag_y;int playlist_scroll_up_tag = -1;int playlist_scroll_dn_tag = -1;extern int main_size_x;extern int main_size_y;extern int main_pos_x;extern int main_pos_y;extern int browser_pos_x;extern int browser_pos_y;extern int browser_on;extern gulong play_id;extern gulong pause_id;extern GtkWidget * play_button;extern GtkWidget * pause_button;extern int vol_finished;extern int vol_index;int vol_n_tracks;int vol_is_average;vol_queue_t * pl_vol_queue;/* used to store array of tree iters of tracks selected for RVA calc */GtkTreeIter * vol_iters;GtkWidget * play_list;GtkTreeStore * play_store = 0;GtkTreeSelection * play_select;GtkTreeViewColumn * track_column;GtkTreeViewColumn * rva_column;GtkTreeViewColumn * length_column;GtkCellRenderer * track_renderer;GtkCellRenderer * rva_renderer;GtkCellRenderer * length_renderer;GtkWidget * statusbar_total;GtkWidget * statusbar_total_label;GtkWidget * statusbar_selected;GtkWidget * statusbar_selected_label;/* popup menus */GtkWidget * add_menu;GtkWidget * add__files;GtkWidget * add__dir;GtkWidget * sel_menu;GtkWidget * sel__none;GtkWidget * sel__all;GtkWidget * sel__inv;GtkWidget * rem_menu;GtkWidget * cut__sel;GtkWidget * rem__all;GtkWidget * rem__dead;GtkWidget * rem__sel;GtkWidget * plist_menu;GtkWidget * plist__save;GtkWidget * plist__load;GtkWidget * plist__enqueue;GtkWidget * plist__separator1;GtkWidget * plist__rva;GtkWidget * plist__rva_menu;GtkWidget * plist__rva_separate;GtkWidget * plist__rva_average;GtkWidget * plist__reread_file_meta;GtkWidget * plist__separator2;GtkWidget * plist__fileinfo;GtkWidget * plist__search;#ifdef HAVE_IFPGtkWidget * plist__send_songs_to_iriver;GtkWidget * plist__separator3;#endif /* HAVE_IFP */void add_directory(GtkWidget * widget, gpointer data);void init_plist_menu(GtkWidget *append_menu);void show_active_position_in_playlist(void);void show_active_position_in_playlist_toggle(void);void show_last_position_in_playlist(void);void expand_collapse_album_node(void);char command[RB_CONTROL_SIZE];char fileinfo_name[MAXLEN];char fileinfo_file[MAXLEN];extern int is_file_loaded;extern int is_paused;extern int allow_seeks;extern char current_file[MAXLEN];extern rb_t * rb_gui2disk;extern GtkWidget * playlist_toggle;typedef struct _playlist_filemeta { char * title; float duration; float voladj;} playlist_filemeta;playlist_filemeta * playlist_filemeta_get(char * physical_name, char * alt_name, int composit);void playlist_filemeta_free(playlist_filemeta * plfm);void rem__sel_cb(gpointer data);void cut__sel_cb(gpointer data);void plist__search_cb(gpointer data);void add_files(GtkWidget * widget, gpointer data);void recalc_album_node(GtkTreeIter * iter);voidvoladj2str(float voladj, char * str) { if (fabs(voladj) < 0.05f) { sprintf(str, " %.1f dB", 0.0f); } else { if (voladj >= 0.0f) { sprintf(str, " %.1f dB", voladj); } else { sprintf(str, "%.1f dB", voladj); } }}voiddisable_bold_font_in_playlist() { GtkTreeIter iter; int i = 0; while (gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(play_store), &iter, NULL, i++)) { int j = 0; GtkTreeIter iter_child; gtk_tree_store_set(play_store, &iter, 7, PANGO_WEIGHT_NORMAL, -1); while (gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(play_store), &iter_child, &iter, j++)) { gtk_tree_store_set(play_store, &iter_child, 7, PANGO_WEIGHT_NORMAL, -1); } }}voidadjust_playlist_item_color(GtkTreeIter * piter, char * active, char * inactive) { char * str; gtk_tree_model_get(GTK_TREE_MODEL(play_store), piter, 2, &str, -1); if (strcmp(str, pl_color_active) == 0) { gtk_tree_store_set(play_store, piter, 2, active, -1); if (options.show_active_track_name_in_bold) { gtk_tree_store_set(play_store, piter, 7, PANGO_WEIGHT_BOLD, -1); } } if (strcmp(str, pl_color_inactive) == 0) { gtk_tree_store_set(play_store, piter, 2, inactive, -1); gtk_tree_store_set(play_store, piter, 7, PANGO_WEIGHT_NORMAL, -1); } g_free(str);}voidset_playlist_color() { GtkTreeIter iter; char active[14]; char inactive[14]; int i = 0; sprintf(active, "#%04X%04X%04X", play_list->style->fg[SELECTED].red, play_list->style->fg[SELECTED].green, play_list->style->fg[SELECTED].blue); sprintf(inactive, "#%04X%04X%04X", play_list->style->fg[INSENSITIVE].red, play_list->style->fg[INSENSITIVE].green, play_list->style->fg[INSENSITIVE].blue); while (gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(play_store), &iter, NULL, i++)) { int j = 0; GtkTreeIter iter_child; adjust_playlist_item_color(&iter, active, inactive); while (gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(play_store), &iter_child, &iter, j++)) { adjust_playlist_item_color(&iter_child, active, inactive); } } strcpy(pl_color_active, active); strcpy(pl_color_inactive, inactive); }/* Calls foreach on each selected track iter. A track is selected iff it is selected or its parent album node is selected. */voidplaylist_foreach_selected(void (* foreach)(GtkTreeIter *, void *), void * data) { GtkTreeIter iter_top; GtkTreeIter iter; int i; int j; i = 0; while (gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(play_store), &iter_top, NULL, i++)) { gboolean topsel = gtk_tree_selection_iter_is_selected(play_select, &iter_top); if (gtk_tree_model_iter_has_child(GTK_TREE_MODEL(play_store), &iter_top)) { j = 0; while (gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(play_store), &iter, &iter_top, j++)) { if (topsel || gtk_tree_selection_iter_is_selected(play_select, &iter)) { (*foreach)(&iter, data); } } } else if (topsel) { (*foreach)(&iter_top, data); } }}GtkTreePath *get_playing_path(GtkTreeStore * store) { GtkTreeIter iter; GtkTreeIter iter_child; char * str; int i = 0; if (!gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter)) return NULL; do { int j = 0; gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, 2, &str, -1); while (gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(store), &iter_child, &iter, j++)) { gtk_tree_model_get(GTK_TREE_MODEL(store), &iter_child, 2, &str, -1); if (strcmp(str, pl_color_active) == 0) { g_free(str); return gtk_tree_model_get_path(GTK_TREE_MODEL(store), &iter_child); } g_free(str); } if (j == 1) { /* toplevel leafnode a.k.a. ordinary track */ if (strcmp(str, pl_color_active) == 0) { g_free(str); return gtk_tree_model_get_path(GTK_TREE_MODEL(store), &iter); } g_free(str); } } while (i++, gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter)); return NULL;}void start_playback_from_playlist(GtkTreePath * path) { GtkTreeIter iter; GtkTreePath * p; char cmd; cue_t cue; if (!allow_seeks) return; p = get_playing_path(play_store); if (p != NULL) { gtk_tree_model_get_iter(GTK_TREE_MODEL(play_store), &iter, p); gtk_tree_path_free(p); unmark_track(&iter); } gtk_tree_model_get_iter(GTK_TREE_MODEL(play_store), &iter, path); if (gtk_tree_model_iter_n_children(GTK_TREE_MODEL(play_store), &iter) > 0) { GtkTreeIter iter_child; gtk_tree_model_iter_children(GTK_TREE_MODEL(play_store), &iter_child, &iter); mark_track(&iter_child); } else { mark_track(&iter); } p = get_playing_path(play_store); gtk_tree_model_get_iter(GTK_TREE_MODEL(play_store), &iter, p); gtk_tree_path_free(p); cue_track_for_playback(&iter, &cue); if (options.show_sn_title) { refresh_displays(); } toggle_noeffect(PLAY, TRUE); if (is_paused) { is_paused = 0; toggle_noeffect(PAUSE, FALSE); } cmd = CMD_CUE; rb_write(rb_gui2disk, &cmd, sizeof(char)); rb_write(rb_gui2disk, (void *)&cue, sizeof(cue_t)); try_waking_disk_thread(); is_file_loaded = 1;}static gbooleanplaylist_window_close(GtkWidget * widget, GdkEvent * event, gpointer data) { gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(playlist_toggle), FALSE); return TRUE;}gintplaylist_window_key_pressed(GtkWidget * widget, GdkEventKey * kevent) { GtkTreePath * path; GtkTreeViewColumn * column; GtkTreeIter iter; char * pname; char * pfile; switch (kevent->keyval) { case GDK_Insert: case GDK_KP_Insert: if(kevent->state & GDK_SHIFT_MASK) { /* SHIFT + Insert */ add_directory(NULL, NULL); } else { add_files(NULL, NULL); } return TRUE; break; case GDK_q: case GDK_Q: case GDK_Escape: if (!options.playlist_is_embedded) { playlist_window_close(NULL, NULL, NULL); } return TRUE; break; case GDK_F1: case GDK_i: case GDK_I: gtk_tree_view_get_cursor(GTK_TREE_VIEW(play_list), &path, &column); if (path && gtk_tree_model_get_iter(GTK_TREE_MODEL(play_store), &iter, path) && !gtk_tree_model_iter_has_child(GTK_TREE_MODEL(play_store), &iter)) { GtkTreeIter dummy; gtk_tree_model_get(GTK_TREE_MODEL(play_store), &iter, 0, &pname, 1, &pfile, -1); strncpy(fileinfo_name, pname, MAXLEN-1); strncpy(fileinfo_file, pfile, MAXLEN-1); free(pname); free(pfile); show_file_info(fileinfo_name, fileinfo_file, 0, NULL, dummy); } return TRUE; break; case GDK_Return: case GDK_KP_Enter: gtk_tree_view_get_cursor(GTK_TREE_VIEW(play_list), &path, &column); if (path) { start_playback_from_playlist(path); } return TRUE; break; case GDK_u: case GDK_U: cut__sel_cb(NULL); return TRUE; break; case GDK_f: case GDK_F: plist__search_cb(NULL); return TRUE; break; case GDK_a: case GDK_A:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -