/* * Copyright 2014 (c) Anna Schumaker. */ #include #include #include static void renumber_queues(); static unsigned int q_col_width[] = { 20, 300, 60, 100, 100, 45, 100, 60, 1 }; static class QueueColumns : public Gtk::TreeModelColumnRecord { public: QueueColumns() { add(q_col_track); add(q_col_title); add(q_col_length); add(q_col_artist); add(q_col_album); add(q_col_year); add(q_col_genre); add(q_col_count); add(q_col_played); add(q_col_path); } Gtk::TreeModelColumn q_col_track; Gtk::TreeModelColumn q_col_title; Gtk::TreeModelColumn q_col_length; Gtk::TreeModelColumn q_col_artist; Gtk::TreeModelColumn q_col_album; Gtk::TreeModelColumn q_col_year; Gtk::TreeModelColumn q_col_genre; Gtk::TreeModelColumn q_col_count; Gtk::TreeModelColumn q_col_played; Gtk::TreeModelColumn q_col_path; } queue_cols; class QueueTab : public Tab { private: /** * Queue tab widgets */ Gtk::HBox q_tab_box; Gtk::Label q_tab_number; Gtk::Label q_tab_size; Gtk::Button q_tab_close; /** * Queue page widgets */ Gtk::VBox q_vbox; /** * Toolbar widgets */ Gtk::HBox q_toolbar_box; Gtk::SearchEntry q_search; Gtk::ToggleButton q_random; Gtk::ToggleButton q_repeat; Gtk::Switch q_switch; /* Treeview widgets */ Gtk::ScrolledWindow q_window; Gtk::TreeView q_treeview; public: QueueTab(Queue *, unsigned int num); ~QueueTab(); void on_remove(); /** * Helper functions */ void setup_treeview(); void on_post_init(); bool on_key_press_event(const std::string &); void tab_set_size(); void queue_set_number(unsigned int); void on_tab_reordered(); void on_move_queue(int); void queue_set_sensitive(bool); /** * GTK-MM Callbacks */ void on_close_clicked(); void on_switch_changed(); }; static std::map queue_mapping; QueueTab :: QueueTab(Queue *pq, unsigned int num) : Tab(pq) { /* * Create our tab widget */ q_tab_number.set_alignment(0, 0.5); q_tab_size.set_justify(Gtk::JUSTIFY_CENTER); q_tab_close.set_image_from_icon_name("window-close", Gtk::ICON_SIZE_MENU); q_tab_close.set_relief(Gtk::RELIEF_NONE); q_tab_close.set_alignment(1, 0.5); q_tab_close.signal_clicked().connect(sigc::mem_fun(*this, &QueueTab::on_close_clicked)); q_tab_box.pack_start(q_tab_number, false, true); q_tab_box.pack_start(q_tab_size, true, true); q_tab_box.pack_start(q_tab_close, false, true); tab_set_size(); queue_set_number(num); q_tab_box.show_all(); /* * Now set up the toolbar */ q_repeat.set_image_from_icon_name("media-playlist-repeat", Gtk::ICON_SIZE_BUTTON); q_random.set_image_from_icon_name("media-playlist-shuffle", Gtk::ICON_SIZE_BUTTON); q_toolbar_box.set_margin_left(5); q_toolbar_box.set_margin_right(5); q_toolbar_box.set_spacing(5); q_toolbar_box.set_homogeneous(false); q_toolbar_box.pack_start(q_search, true, true); q_toolbar_box.pack_start(q_switch, false, true); q_toolbar_box.pack_start(q_repeat, false, true); q_toolbar_box.pack_start(q_random, false, true); /* * And the treeview with scrolled window */ q_window.set_shadow_type(Gtk::SHADOW_IN); q_window.set_margin_left(5); q_window.set_margin_right(5); q_window.set_margin_bottom(5); q_window.add(q_treeview); setup_treeview(); /* * Fill in the page! */ q_vbox.set_margin_left(1); q_vbox.set_margin_right(1); q_vbox.set_homogeneous(false); q_vbox.pack_start(q_toolbar_box, false, true, 2); q_vbox.pack_start(q_window, true, true); /* * Set generic tab widgets */ tab_random = &q_random; tab_repeat = &q_repeat; tab_search = &q_search; tab_size = &q_tab_size; tab_treeview = &q_treeview; tab_widget = &q_vbox; tab_finish_init(); queue_mapping[tab_widget] = this; gui :: get_widget("o_notebook")->insert_page(q_vbox, q_tab_box, num); gui :: get_widget("o_notebook")->set_tab_reorderable(q_vbox); q_vbox.show_all(); } QueueTab :: ~QueueTab() {} void QueueTab :: on_remove() { queue_mapping.erase(tab_widget); tab_unmap(); gui :: get_widget("o_notebook")->remove_page(q_vbox); renumber_queues(); delete this; } /** * * Queue tab helper functions * */ void QueueTab :: setup_treeview() { q_treeview.append_column("#", queue_cols.q_col_track); q_treeview.append_column("Title", queue_cols.q_col_title); q_treeview.append_column("Length", queue_cols.q_col_length); q_treeview.append_column("Artist", queue_cols.q_col_artist); q_treeview.append_column("Album", queue_cols.q_col_album); q_treeview.append_column("Year", queue_cols.q_col_year); q_treeview.append_column("Genre", queue_cols.q_col_genre); q_treeview.append_column("Count", queue_cols.q_col_count); q_treeview.append_column("Played", queue_cols.q_col_played); q_treeview.set_tooltip_column(9); q_treeview.set_rules_hint(); q_treeview.set_enable_search(false); q_treeview.get_selection()->set_mode(Gtk::SELECTION_MULTIPLE); q_treeview.set_rubber_banding(); std::vector columns = q_treeview.get_columns(); for (unsigned int i = 0; i < columns.size(); i++) { columns[i]->set_resizable(); columns[i]->set_fixed_width(q_col_width[i]); columns[i]->set_sizing(Gtk::TREE_VIEW_COLUMN_FIXED); columns[i]->set_clickable(); } } void QueueTab :: on_post_init() { tab_init_random(); tab_init_repeat(); bool active = (tab_pq->has_flag(Q_ENABLED)); q_switch.set_active(active); q_switch.property_active().signal_changed().connect( sigc::mem_fun(*this, &QueueTab :: on_switch_changed)); queue_set_sensitive(active); } bool QueueTab :: on_key_press_event(const std::string &key) { std::vector ids; if (key != "Delete") return Tab :: on_key_press_event(key); /* * tab_selected_ids() returns track_ids and not * playlist_ids,so we can't use it here =( */ Glib::RefPtr sel = tab_treeview->get_selection(); std::vector rows = sel->get_selected_rows(); Gtk::TreeModel::Path path; for (unsigned int i = 0; i < rows.size(); i++) { path = tab_filter->convert_path_to_child_path(rows[i]); ids.push_back(path[0]); } for (unsigned int i = ids.size(); i > 0; i--) tab_pq->del(ids[i-1]); return true; } void QueueTab :: tab_set_size() { std::string span = ""; span += string :: utos(tab_pq->size()) + ""; q_tab_size.set_markup(span); } void QueueTab :: queue_set_number(unsigned int num) { std::string span = ""; span += string :: utos(num) + ". "; q_tab_number.set_markup(span); } void QueueTab :: on_tab_reordered() { queue_set_number(tab_page_num()); } void QueueTab :: on_move_queue(int num) { deck :: move(tab_pq, num); } void QueueTab :: queue_set_sensitive(bool sensitive) { q_tab_number.set_sensitive(sensitive); q_tab_size.set_sensitive(sensitive); q_treeview.set_sensitive(sensitive); } /** * * Gtk-MM Callback Functions * */ void QueueTab :: on_close_clicked() { deck :: destroy(tab_pq); } void QueueTab :: on_switch_changed() { if (q_switch.get_active()) { tab_pq->set_flag(Q_ENABLED); queue_set_sensitive(true); } else { tab_pq->unset_flag(Q_ENABLED); queue_set_sensitive(false); } } /** * * Global functions * */ static void renumber_queues() { std::map::iterator it; for (it = queue_mapping.begin(); it != queue_mapping.end(); it++) it->second->on_tab_reordered(); } void on_pq_created(Queue *pq, unsigned int num) { QueueTab *tab = new QueueTab(pq, num); tab->on_post_init(); } static void on_page_reordered(Gtk::Widget *page, int num) { Gtk::Notebook *notebook = gui :: get_widget("o_notebook"); if ((unsigned int)num >= deck :: get_queues().size()) { notebook->reorder_child(*page, deck::get_queues().size() - 1); return; } std::map::iterator it; it = queue_mapping.find(page); if (it != queue_mapping.end()) { it->second->on_move_queue(num); renumber_queues(); } } void init_queue_tabs() { Gtk::Notebook *notebook = gui :: get_widget("o_notebook"); notebook->signal_page_reordered().connect(sigc::ptr_fun(on_page_reordered)); } void post_init_queue_tabs() { std::list::iterator it; unsigned int i = 0; for (it = deck :: get_queues().begin(); it != deck :: get_queues().end(); it++) on_pq_created(&(*it), i++); }