/* * Copyright 2014 (c) Anna Schumaker. */ #include #include #include #include #include #include #include static std::map queue_mapping; static sort_t sort_fields[] = { SORT_TRACK, SORT_TITLE, SORT_LENGTH, SORT_ARTIST, SORT_ALBUM, SORT_YEAR, SORT_GENRE, SORT_COUNT, SORT_PLAYED }; /** * * Tab class basics * */ Tab :: Tab(Playqueue *pq) : tab_sorting_count(0), tab_pq(pq), tab_size(NULL) { tab_model = Glib::RefPtr(new PlayqueueModel(tab_pq)); queue_mapping[tab_pq] = this; } Tab :: ~Tab() {} void Tab :: tab_finish_init() { tab_filter = Gtk::TreeModelFilter::create(tab_model); tab_filter->set_visible_func(sigc::mem_fun(*this, &Tab::on_filter_visible)); tab_search->signal_key_release_event().connect(sigc::mem_fun(*this, &Tab::on_entry_key_released)); tab_search->signal_changed().connect(sigc::mem_fun(*this, &Tab::on_entry_changed)); tab_treeview->set_model(tab_filter); tab_treeview->signal_row_activated().connect(sigc::mem_fun(*this, &Tab :: on_row_activated)); tab_treeview->signal_key_press_event().connect(sigc::mem_fun(*this, &Tab :: on_key_pressed)); tab_treeview->signal_button_press_event().connect(sigc::mem_fun(*this, &Tab :: on_button_pressed), false); std::vector columns = tab_treeview->get_columns(); for (unsigned int i = 0; i < columns.size(); i++) { columns[i]->signal_clicked().connect(sigc::bind ( sigc::mem_fun(*this, &Tab::on_column_clicked), i)); } } /** * * Tab internal helper functions * */ void Tab :: tab_init_random() { tab_random->set_active(tab_pq->get_flags() & PQ_RANDOM); tab_random->signal_toggled().connect(sigc::mem_fun(*this, &Tab::on_random_toggled)); } void Tab :: tab_init_repeat() { tab_repeat->set_active(tab_pq->get_flags() & PQ_REPEAT); tab_repeat->signal_toggled().connect(sigc::mem_fun(*this, &Tab::on_repeat_toggled)); } void Tab :: tab_toggle_button(Gtk::ToggleButton *button, playqueue_flags flag) { if (button->get_active()) tab_pq->set_flag(flag); else tab_pq->unset_flag(flag); } int Tab :: tab_page_num() { Gtk::Notebook *notebook = get_widget("o_notebook"); return notebook->page_num(*tab_widget); } bool Tab :: tab_is_cur() { Gtk::Notebook *notebook = get_widget("o_notebook"); return notebook->page_num(*tab_widget) == notebook->get_current_page(); } void Tab :: tab_runtime_changed() { if (tab_is_cur()) get_widget("o_queue_time")->set_text(tab_pq->get_length_str()); } void Tab :: tab_display_sorting() { std::string text = ""; if ((tab_sorting_count > 0) && tab_is_cur()) text = "Sorting within " + tab_sorting_title; get_widget("o_sorting_indicator")->set_text(text); } void Tab :: tab_dec_sort_count() { tab_sorting_count--; tab_display_sorting(); } void Tab :: tab_set_size() { if (tab_size) { std::stringstream ss; ss << tab_pq->size(); tab_size->set_text(ss.str()); } } void Tab :: tab_unmap() { queue_mapping.erase(tab_pq); } void Tab :: tab_focus_search() { tab_search->grab_focus(); } void Tab :: tab_selected_ids(std::vector &ids) { 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(tab_model->path_to_id(path)); } sel->unselect_all(); } void Tab :: tab_queue_add(Playqueue *pq) { std::vector ids; tab_selected_ids(ids); for (unsigned int i = 0; i < ids.size(); i++) pq->add(ids[i]); } bool Tab :: tab_queue_selected(bool random) { if (deck :: size() >= 10) return true; Playqueue *pq = deck :: create(random); tab_queue_add(pq); return true; } bool Tab :: tab_add_to_queue(unsigned int n) { if (n >= deck :: size()) return true; Playqueue *pq = deck :: get(n); tab_queue_add(pq); return true; } bool Tab :: tab_add_to_playlist(const std::string &playlist) { std::vector ids; tab_selected_ids(ids); for (unsigned int i = 0; i < ids.size(); i++) playlist :: add(playlist, ids[i]); return true; } bool Tab :: tab_favorite_selected() { return tab_add_to_playlist("Favorites"); } void Tab :: tab_ban_selected() { tab_add_to_playlist("Banned"); } /** * * Tab callback functions * */ void Tab :: on_post_init() {} void Tab :: on_track_added(unsigned int row) { tab_model->on_row_inserted(row); tab_set_size(); tab_runtime_changed(); } void Tab :: on_track_deleted(unsigned int row) { tab_model->on_row_deleted(row); tab_set_size(); tab_runtime_changed(); } void Tab :: on_track_changed(unsigned int row) { tab_model->on_row_changed(row); tab_runtime_changed(); } bool Tab :: on_key_press_event(const std::string &key) { if (key >= "0" && key <= "9") return tab_add_to_queue(atoi(key.c_str())); else if (key == "f") return tab_favorite_selected(); else if (key == "q" || key == "r") return tab_queue_selected(key == "r"); else return false; return true; } void Tab :: on_show_rc_menu() { } /** * * GTK-MM callback functions * */ void Tab :: on_random_toggled() { tab_toggle_button(tab_random, PQ_RANDOM); } void Tab :: on_repeat_toggled() { tab_toggle_button(tab_repeat, PQ_REPEAT); } void Tab :: on_row_activated(const Gtk::TreePath &path, Gtk::TreeViewColumn *col) { Gtk::TreePath model_path = tab_filter->convert_path_to_child_path(path); tab_model->on_path_selected(model_path); } bool Tab :: on_key_pressed(GdkEventKey *event) { std::string key = gdk_keyval_name(event->keyval); if (key.size() >= 3) { if (key.substr(0, 3) == "KP_") key = key.substr(3); } return on_key_press_event(key); } void Tab :: on_column_clicked(unsigned int col) { if (tab_sorting_count == 0) { tab_sorting_title = tab_treeview->get_column(col)->get_title(); tab_pq->reset_sort(sort_fields[col]); } else tab_pq->add_sort(sort_fields[col]); tab_sorting_count++; tab_display_sorting(); Glib::signal_timeout().connect_seconds_once( sigc::mem_fun(*this, &Tab::tab_dec_sort_count), 2); } bool Tab :: on_button_pressed(GdkEventButton *button) { if (button->button != 3) return false; Gtk::TreeModel::Path path; if (tab_treeview->get_path_at_pos(button->x, button->y, path)) tab_treeview->get_selection()->select(path); on_show_rc_menu(); get_widget("o_rc_menu")->popup(button->button, button->time); return true; } /** * * Tab filtering functions * */ bool Tab :: on_filter_visible(const Gtk::TreeIter &iter) { unsigned int pq_id; std::set::iterator it; if (tab_search->get_text_length() == 0) return true; pq_id = tab_model->iter_to_id(iter); it = visible_ids.find(tab_pq->operator[](pq_id)); return it != visible_ids.end(); } bool Tab :: on_entry_key_released(GdkEventKey *event) { std::string key = gdk_keyval_name(event->keyval); return key == "space"; } void Tab :: on_entry_changed() { filter :: search(tab_search->get_text(), visible_ids); tab_filter->refilter(); } /** * * Global functions * */ Tab *find_tab(Playqueue *pq) { std::map::iterator it; it = queue_mapping.find(pq); if (it != queue_mapping.end()) return it->second; return NULL; } static Tab *find_tab(int num) { std::map::iterator it; for (it = queue_mapping.begin(); it != queue_mapping.end(); it++) { if (it->second->tab_page_num() == num) return it->second; } return NULL; } static Tab *cur_tab() { std::map::iterator it; for (it = queue_mapping.begin(); it != queue_mapping.end(); it++) { if (it->second->tab_is_cur()) return it->second; } return NULL; } static void on_track_added(Playqueue *pq, unsigned int row) { Tab *tab = find_tab(pq); if (tab) tab->on_track_added(row); } static void on_track_deleted(Playqueue *pq, unsigned int row) { Tab *tab = find_tab(pq); if (tab) tab->on_track_deleted(row); } static void on_track_changed(Playqueue *pq, unsigned int row) { Tab *tab = find_tab(pq); if (tab) tab->on_track_changed(row); } static void on_switch_page(Gtk::Widget *page, int num) { Tab *tab = find_tab(num); if (tab) { tab->tab_runtime_changed(); tab->tab_display_sorting(); } else get_widget("o_queue_time")->set_text(""); } void tab_focus_search() { int page = get_widget("o_notebook")->get_current_page(); Tab *tab = find_tab(page); if (tab) tab->tab_focus_search(); } static void on_add_to_favs() { Tab *tab = cur_tab(); if (tab) tab->tab_favorite_selected(); } static void on_add_to_banned() { Tab *tab = cur_tab(); if (tab) tab->tab_ban_selected(); } void init_tabs() { struct Callbacks *cb = get_callbacks(); cb->on_queue_track_add = on_track_added; cb->on_queue_track_del = on_track_deleted; cb->on_queue_track_changed = on_track_changed; /* Notebook signals */ struct Gtk::Notebook *notebook = get_widget("o_notebook"); notebook->signal_switch_page().connect(sigc::ptr_fun(on_switch_page)); /* Menu signals */ get_widget("o_rc_menu")->show_all(); get_widget("o_add_to_favorites")->signal_activate().connect( sigc::ptr_fun(on_add_to_favs)); get_widget("o_add_to_banned")->signal_activate().connect( sigc::ptr_fun(on_add_to_banned)); /* Initialize other tabs */ init_collection_tab(); init_history_tab(); init_playlist_tab(); init_queue_tabs(); } void post_init_tabs() { std::map::iterator it; for (it = queue_mapping.begin(); it != queue_mapping.end(); it++) it->second->on_post_init(); } void cleanup_tabs() { while (queue_mapping.size() > 0) delete queue_mapping.begin()->second; } /* * Mostly legacy code .... */ /*class OcarinaPage; static std::map tab_map; static std::list tab_types; static Gtk::Widget *get_menu_widget(const std::string &name) { Gtk::Widget *widget; get_builder()->get_widget(name, widget); return widget; } static void prepare_rc_menu() { unsigned int size = deck::size(); */ /* Set widgets visible */ /* switch (size) { case 10: get_menu_widget("o_pq_9")->show(); case 9: get_menu_widget("o_pq_8")->show(); case 8: get_menu_widget("o_pq_7")->show(); case 7: get_menu_widget("o_pq_6")->show(); case 6: get_menu_widget("o_pq_5")->show(); case 5: get_menu_widget("o_pq_4")->show(); case 4: get_menu_widget("o_pq_3")->show(); case 3: get_menu_widget("o_pq_2")->show(); case 2: get_menu_widget("o_pq_1")->show(); case 1: get_menu_widget("o_pq_0")->show(); get_menu_widget("o_add_to_pq")->show(); default: if (size != 10) get_menu_widget("o_new_pq")->show(); break; } */ /* Set widgets invisible */ /* switch (size) { case 0: get_menu_widget("o_add_to_pq")->hide(); get_menu_widget("o_pq_0")->hide(); case 1: get_menu_widget("o_pq_1")->hide(); case 2: get_menu_widget("o_pq_2")->hide(); case 3: get_menu_widget("o_pq_3")->hide(); case 4: get_menu_widget("o_pq_4")->hide(); case 5: get_menu_widget("o_pq_5")->hide(); case 6: get_menu_widget("o_pq_6")->hide(); case 7: get_menu_widget("o_pq_7")->hide(); case 8: get_menu_widget("o_pq_8")->hide(); case 9: get_menu_widget("o_pq_9")->hide(); break; case 10: get_menu_widget("o_new_pq")->hide(); }; } bool OcarinaPage::on_view_button_pressed(GdkEventButton *button) { Gtk::Menu *menu; get_builder()->get_widget("o_rc_menu", menu); if (button->button != 3) return false; prepare_rc_menu(); menu->popup(button->button, button->time); return true; } */ /* * Do stuff with tabs */ /* static void init_menu_item(const std::string &name, unsigned int num) { Glib::RefPtrmenu = Glib::RefPtr::cast_static(get_builder()->get_object(name)); menu->signal_activate().connect(sigc::bind ( sigc::ptr_fun(on_add_to_queue), num)); }*/ /* void init_tabs() { Gtk::Notebook *notebook; get_builder()->get_widget("o_notebook", notebook); get_callbacks()->on_queue_track_changed = on_track_changed; */ /*Glib::RefPtr new_pq = Glib::RefPtr::cast_static(get_builder()->get_object("o_new_pq")); new_pq->signal_activate().connect(sigc::ptr_fun(on_new_queue)); init_menu_item("o_pq_0", 0); init_menu_item("o_pq_1", 1); init_menu_item("o_pq_2", 2); init_menu_item("o_pq_3", 3); init_menu_item("o_pq_4", 4); init_menu_item("o_pq_5", 5); init_menu_item("o_pq_6", 6); init_menu_item("o_pq_7", 7); init_menu_item("o_pq_8", 8); init_menu_item("o_pq_9", 9);*/ /* notebook->signal_page_reordered().connect(sigc::ptr_fun(on_page_reordered)); notebook->set_current_page(0); }*/