ocarina/gui/tabs.cpp

929 lines
22 KiB
C++

/*
* Copyright 2014 (c) Anna Schumaker.
*/
#include <callback.h>
#include <filter.h>
#include <tabs.h>
#include <map>
#include <sstream>
static std::map<Playqueue *, Tab *> queue_mapping;
/**
* Tab class basics
*/
Tab :: Tab(Playqueue *pq)
: tab_pq(pq), tab_size(NULL)
{
tab_model = Glib::RefPtr<PlayqueueModel>(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 class 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_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);
}
/**
* Tab internal callback functions
*/
void Tab :: on_post_init() {}
void Tab :: on_track_added(unsigned int row)
{
tab_model->on_row_inserted(row);
tab_set_size();
}
void Tab :: on_track_deleted(unsigned int row)
{
tab_model->on_row_deleted(row);
tab_set_size();
}
/**
* GTK-MM callback functions
*/
void Tab :: on_random_toggled()
{
if (tab_random->get_active())
tab_pq->set_flag(PQ_RANDOM);
else
tab_pq->unset_flag(PQ_RANDOM);
}
/**
* Tab filtering functions
*/
bool Tab :: on_filter_visible(const Gtk::TreeIter &iter)
{
unsigned int pq_id;
std::set<unsigned int>::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<Playqueue *, Tab *>::iterator it;
it = queue_mapping.find(pq);
if (it != queue_mapping.end())
return it->second;
return NULL;
}
void on_track_added(Playqueue *pq, unsigned int row)
{
Tab *tab = find_tab(pq);
if (tab)
tab->on_track_added(row);
}
void on_track_deleted(Playqueue *pq, unsigned int row)
{
Tab *tab = find_tab(pq);
if (tab)
tab->on_track_deleted(row);
}
void init_tabs()
{
struct Callbacks *cb = get_callbacks();
cb->on_queue_track_add = on_track_added;
cb->on_queue_track_del = on_track_deleted;
/* Initialize other tabs */
init_collection_tab();
init_history_tab();
init_playlist_tab();
}
void post_init_tabs()
{
std::map<Playqueue *, Tab *>::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;
}
/*
* Generic tab functions for filtering
*/
/*static bool on_entry_key_released(GdkEventKey *event)
{
std::string key = gdk_keyval_name(event->keyval);
return key == "space";
}
static void on_entry_changed(struct FilterDesc *f)
{
filter :: search(f->entry->get_text(), f->visible_ids);
f->filter->refilter();
}
static bool on_filter_visible(const Gtk::TreeIter &iter, struct FilterDesc *f)
{
unsigned int pq_id;
std::set<unsigned int>::iterator it;
if (f->entry->get_text().size() == 0)
return true;
pq_id = f->model->iter_to_id(iter);
it = f->visible_ids.find(f->model->queue->operator[](pq_id));
return it != f->visible_ids.end();
}
void init_filter(struct FilterDesc *filter)
{
filter->filter = Gtk::TreeModelFilter::create(filter->model);
filter->entry->signal_key_release_event().connect(sigc::ptr_fun(on_entry_key_released));
filter->entry->signal_changed().connect(sigc::bind<struct FilterDesc *>(
sigc::ptr_fun(on_entry_changed),
filter));
filter->filter->set_visible_func(sigc::bind<struct FilterDesc *>(
sigc::ptr_fun(on_filter_visible),
filter));
}
*/
/*
* Mostly legacy code ....
*/
/*class OcarinaPage;
static std::map<Playqueue *, OcarinaPage *> tab_map;
static std::list<TabType *> tab_types;
static unsigned int sort_timeout_count = 0;
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<unsigned int> q_col_track;
Gtk::TreeModelColumn<std::string> q_col_title;
Gtk::TreeModelColumn<std::string> q_col_length;
Gtk::TreeModelColumn<std::string> q_col_artist;
Gtk::TreeModelColumn<std::string> q_col_album;
Gtk::TreeModelColumn<unsigned int> q_col_year;
Gtk::TreeModelColumn<std::string> q_col_genre;
Gtk::TreeModelColumn<unsigned int> q_col_count;
Gtk::TreeModelColumn<std::string> q_col_played;
Gtk::TreeModelColumn<std::string> q_col_path;
} queue_cols;
static unsigned int q_col_width[] = { 20, 300, 60, 100, 100, 45, 100, 60, 1 };
static sort_t q_col_sorts[] = {
SORT_TRACK, SORT_TITLE, SORT_LENGTH,
SORT_ARTIST, SORT_ALBUM, SORT_YEAR,
SORT_GENRE, SORT_COUNT, SORT_PLAYED
};
static void dec_sort_timeout()
{
if (sort_timeout_count > 0)
sort_timeout_count--;
if (sort_timeout_count == 0) {
Gtk::Label *label;
get_builder()->get_widget("o_sorting_indicator", label);
label->set_text("");
}
}
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();
};
}
*/
/*
* Tab class definition
*/
/*class OcarinaTab : public Gtk::HBox {
public:
OcarinaTab();
~OcarinaTab();
virtual void set_size(unsigned int) = 0;
virtual void set_number(unsigned int) = 0;
};
OcarinaTab::OcarinaTab() {}
OcarinaTab::~OcarinaTab() {}
class PQTab : public OcarinaTab {
public:
Gtk::Label number_label;
Gtk::Label size_label;
Gtk::Image close_icon;
Gtk::Button close_button;
PQTab();
~PQTab();
void set_size(unsigned int);
void set_number(unsigned int);
};
PQTab::PQTab() : number_label("0", 0, 0.5), size_label("0", 0.5, 0.5)
{
close_icon.set_from_icon_name("window-close", Gtk::ICON_SIZE_MENU);
close_button.set_image(close_icon);
close_button.set_relief(Gtk::RELIEF_NONE);
number_label.set_justify(Gtk::JUSTIFY_CENTER);
pack_start(number_label, false, false);
pack_start(size_label, true, true);
pack_start(close_button, false, false);
show_all();
}
PQTab::~PQTab() {}
void PQTab::set_size(unsigned int size)
{
std::stringstream ss;
ss << "<span size='x-large'>" << size << "</span>";
size_label.set_markup(ss.str());
}
void PQTab::set_number(unsigned int num)
{
std::stringstream ss;
ss << "<span size='x-large'>" << num << ". </span>";
number_label.set_markup(ss.str());
}
*/
/*
* Ocarina class definition
*/
/*class OcarinaPage : public Gtk::VBox {
private:
unsigned int init_flags;
Gtk::Notebook *notebook;
OcarinaTab *tab;
*/
/* Filter state */
// std::set<unsigned int> visible_ids;
/* Page widgets */
/* Gtk::HBox page_toolbar;
Gtk::SearchEntry page_entry;
Gtk::ToggleButton page_repeat;
Gtk::ScrolledWindow page_scroll;
Gtk::HBox page_viewbox;
Gtk::TreeView page_view;
void setup_common(Playqueue *, unsigned int);
void setup_toolbar();
void setup_treeview();
void setup_columns();
void set_tab_size();
public:
Gtk::ToggleButton page_random;
Glib::RefPtr<PlayqueueModel> model;
Glib::RefPtr<Gtk::TreeModelFilter> filter;
OcarinaPage(Playqueue *, unsigned int, unsigned int);
~OcarinaPage();
bool is_current_tab();
void check_pq_flags();
void queue_selected(bool);
void on_close_clicked();
void on_row_inserted(unsigned int);
void on_row_deleted(unsigned int);
void on_row_changed(unsigned int);
void on_runtime_changed();
void on_random_toggled();
void on_repeat_toggled();
void on_row_activated(const Gtk::TreePath &, Gtk::TreeViewColumn *);
void on_column_clicked(unsigned int);
void on_entry_changed();
bool on_entry_key_released(GdkEventKey *);
bool on_filter_visible(const Gtk::TreeIter &);
void on_page_renumbered();
bool on_add_to_pq(unsigned int);
bool on_delete_selected();
bool on_favorite_selected();
bool on_view_key_pressed(GdkEventKey *);
bool on_view_button_pressed(GdkEventButton *);
void on_focus_search();
};
OcarinaPage::OcarinaPage(Playqueue *pq, unsigned int flags, unsigned int pg)
: init_flags(flags)
{
PQTab *pqt = new PQTab();
tab = pqt;
pqt->close_button.signal_clicked().connect(sigc::mem_fun(*this,
&OcarinaPage::on_close_clicked));
setup_common(pq, pg);
notebook->set_tab_reorderable(*this);
}
OcarinaPage::~OcarinaPage()
{
notebook->remove_page(*this);
tab_map.erase(model->queue);
}
void OcarinaPage::setup_common(Playqueue *pq, unsigned int pg)
{
get_builder()->get_widget("o_notebook", notebook);
model = Glib::RefPtr<PlayqueueModel>(new PlayqueueModel(pq));
filter = Gtk::TreeModelFilter::create(model);
filter->set_visible_func(sigc::mem_fun(*this,
&OcarinaPage::on_filter_visible));
set_margin_left(1);
set_margin_right(1);
set_spacing(1);
setup_treeview();
pack_start(page_viewbox);
show_all();
*/
/* Add to notebook */
/* notebook->insert_page(*this, *tab, pg);
tab_map[pq] = this;
set_tab_size();
}
void OcarinaPage::setup_toolbar()
{
page_toolbar.set_spacing(5);
page_toolbar.pack_start(page_entry);
page_toolbar.set_margin_left(5);
page_toolbar.set_margin_right(5);
*/
/* Set up entry */
/* page_entry.set_margin_top(5);
page_entry.set_margin_bottom(5);
page_entry.signal_changed().connect(sigc::mem_fun(*this,
&OcarinaPage::on_entry_changed));
page_entry.signal_key_release_event().connect(sigc::mem_fun(*this,
&OcarinaPage::on_entry_key_released));
*/
/* Make buttons */
/* if (init_flags & PQ_RANDOM) {
page_random.set_image_from_icon_name("media-playlist-shuffle");
page_toolbar.pack_start(page_random, false, false);
}
if (init_flags & PQ_REPEAT) {
page_repeat.set_image_from_icon_name("media-playlist-repeat");
page_toolbar.pack_start(page_repeat, false, false);
}
pack_start(page_toolbar, false, false);
}
void OcarinaPage::setup_treeview()
{*/
/* Make page content */
/*page_view.append_column("#", queue_cols.q_col_track);
page_view.append_column("Title", queue_cols.q_col_title);
page_view.append_column("Length", queue_cols.q_col_length);
page_view.append_column("Artist", queue_cols.q_col_artist);
page_view.append_column("Album", queue_cols.q_col_album);
page_view.append_column("Year", queue_cols.q_col_year);
page_view.append_column("Genre", queue_cols.q_col_genre);
page_view.append_column("Count", queue_cols.q_col_count);
page_view.append_column("Played", queue_cols.q_col_played);
page_view.set_tooltip_column(9);
page_view.signal_row_activated().connect(sigc::mem_fun(*this,
&OcarinaPage::on_row_activated));
page_view.signal_key_press_event().connect(sigc::mem_fun(*this,
&OcarinaPage::on_view_key_pressed));
page_view.signal_button_press_event().connect(sigc::mem_fun(*this,
&OcarinaPage::on_view_button_pressed), false);
page_view.set_model(filter);
page_view.set_rules_hint();
page_view.set_enable_search(false);
page_view.get_selection()->set_mode(Gtk::SELECTION_MULTIPLE);
page_view.set_rubber_banding();
page_scroll.set_shadow_type(Gtk::SHADOW_IN);
page_scroll.set_margin_left(5);
page_scroll.set_margin_right(5);
page_scroll.set_margin_bottom(5);
page_scroll.add(page_view);
setup_columns();
page_viewbox.pack_start(page_scroll, true, true);
};
void OcarinaPage::setup_columns()
{
std::vector<Gtk::TreeViewColumn *> columns = page_view.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();
columns[i]->signal_clicked().connect(sigc::bind<unsigned int> (
sigc::mem_fun(*this, &OcarinaPage::on_column_clicked),
i));
}
}
bool OcarinaPage::is_current_tab()
{
return notebook->page_num(*this) == notebook->get_current_page();
}
void OcarinaPage::check_pq_flags()
{
if (init_flags & PQ_REPEAT) {
page_repeat.set_active(model->queue->get_flags() & PQ_REPEAT);
page_repeat.signal_toggled().connect(sigc::mem_fun(*this,
&OcarinaPage::on_repeat_toggled));
}
}
void OcarinaPage::queue_selected(bool random)
{
Playqueue *pq;
unsigned int track_id;
std::vector<Gtk::TreeModel::Path>::iterator it;
Glib::RefPtr<Gtk::TreeSelection> sel = page_view.get_selection();
if (sel->count_selected_rows() == 0)
return;
pq = deck::create(random);
std::vector<Gtk::TreeModel::Path> rows = sel->get_selected_rows();
for (it = rows.begin(); it != rows.end(); it++) {
track_id = model->path_to_id(filter->convert_path_to_child_path(*it));
pq->add(track_id);
}
}
void OcarinaPage::on_close_clicked()
{
deck :: remove(notebook->page_num(*this));
}
void OcarinaPage::on_row_inserted(unsigned int row)
{
model->on_row_inserted(row);
set_tab_size();
if (is_current_tab())
on_runtime_changed();
}
void OcarinaPage::on_row_deleted(unsigned int row)
{
model->on_row_deleted(row);
set_tab_size();
if (is_current_tab())
on_runtime_changed();
}
void OcarinaPage::on_row_changed(unsigned int row)
{
model->on_row_changed(row);
if (is_current_tab())
on_runtime_changed();
}
void OcarinaPage::on_runtime_changed()
{
Gtk::Label *label;
get_builder()->get_widget("o_queue_time", label);
label->set_text(model->queue->get_length_str());
}
void OcarinaPage::on_repeat_toggled()
{
if (page_repeat.get_active())
model->queue->set_flag(PQ_REPEAT);
else
model->queue->unset_flag(PQ_REPEAT);
}
void OcarinaPage::on_row_activated(const Gtk::TreePath &path, Gtk::TreeViewColumn *col)
{
Gtk::TreePath model_path = filter->convert_path_to_child_path(path);
model->on_path_selected(model_path);
}
void OcarinaPage::on_column_clicked(unsigned int col_index)
{
Gtk::Label *sorting;
get_builder()->get_widget("o_sorting_indicator", sorting);
if (sort_timeout_count == 0) {
sorting->set_text("Sorting within " + page_view.get_column(col_index)->get_title());
model->queue->reset_sort(q_col_sorts[col_index]);
} else
model->queue->add_sort(q_col_sorts[col_index]);
sort_timeout_count++;
Glib::signal_timeout().connect_seconds_once(
sigc::ptr_fun(dec_sort_timeout), 2);
}
void OcarinaPage::on_page_renumbered()
{
tab->set_number(notebook->page_num(*this));
}
bool OcarinaPage::on_add_to_pq(unsigned int n)
{
if (n >= deck :: size())
return true;
Glib::RefPtr<Gtk::TreeSelection> sel = page_view.get_selection();
if (sel->count_selected_rows() == 0)
return true;
Playqueue *pq = deck :: get(n);
std::vector<Gtk::TreeModel::Path>::iterator it;
std::vector<Gtk::TreeModel::Path> rows = sel->get_selected_rows();
for (it = rows.begin(); it != rows.end(); it++) {
unsigned int track_id = model->path_to_id(filter->convert_path_to_child_path(*it));
pq->add(track_id);
}
return true;
}
bool OcarinaPage::on_delete_selected()
{
Glib::RefPtr<Gtk::TreeSelection> sel = page_view.get_selection();
if (sel->count_selected_rows() == 0)
return true;
if ((unsigned int)notebook->page_num(*this) >= deck :: size())
return true;
std::vector<Gtk::TreeModel::Path>::reverse_iterator it;
std::vector<Gtk::TreeModel::Path> rows = sel->get_selected_rows();
for (it = rows.rbegin(); it != rows.rend(); it++) {
unsigned int id = filter->convert_path_to_child_path(*it)[0];
model->queue->del(id);
}
return true;
}
bool OcarinaPage::on_favorite_selected()
{
Glib::RefPtr<Gtk::TreeSelection> sel = page_view.get_selection();
if (sel->count_selected_rows() == 0)
return true;
std::vector<Gtk::TreeModel::Path>::iterator it;
std::vector<Gtk::TreeModel::Path> rows = sel->get_selected_rows();
for (it = rows.begin(); it != rows.end(); it++) {
unsigned int id = model->path_to_id(filter->convert_path_to_child_path(*it));
playlist :: add("Favorites", id);
}
return true;
}
bool OcarinaPage::on_view_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);
}
if (key >= "0" && key <= "9") {
unsigned int n = atoi(key.c_str());
return on_add_to_pq(n);
} else if (key == "f")
return on_favorite_selected();
else if (key == "Delete")
return on_delete_selected();
return false;
}
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;
}
void OcarinaPage::on_focus_search()
{
page_entry.grab_focus();
}
*/
/*
* Do stuff with tabs
*/
/*
static void on_track_changed(Playqueue *pq, unsigned int row)
{
std::map<Playqueue *, OcarinaPage *>::iterator it;
it = tab_map.find(pq);
if (it != tab_map.end())
it->second->on_row_changed(row);
}
static void on_switch_page(Gtk::Widget *page, int num)
{
Gtk::Label *label;
Gtk::Notebook *notebook;
OcarinaPage *tab = (OcarinaPage *)page;
get_builder()->get_widget("o_queue_time", label);
get_builder()->get_widget("o_notebook", notebook);
if (num >= notebook->get_n_pages() - 4)
label->hide();
else {
tab->on_runtime_changed();
label->show();
}
sort_timeout_count = 0;
}
static void renumber_pqs()
{
std::map<Playqueue *, OcarinaPage *>::iterator it;
for (it = tab_map.begin(); it != tab_map.end(); it++)
it->second->on_page_renumbered();
}
static void on_page_reordered(Gtk::Widget *page, int num)
{
Gtk::Notebook *notebook;
OcarinaPage *tab = (OcarinaPage *)page;
get_builder()->get_widget("o_notebook", notebook);
if ((unsigned int)num >= deck :: size())
notebook->reorder_child(*page, deck::size() - 1);
else {
deck :: move(tab->model->queue, num);
renumber_pqs();
}
}
static void on_pq_created(Playqueue *pq, unsigned int num)
{
OcarinaPage *page = new OcarinaPage(pq, PQ_RANDOM | PQ_REPEAT, num);
page->check_pq_flags();
renumber_pqs();
}
static void on_pq_removed(Playqueue *pq)
{
std::map<Playqueue *, OcarinaPage *>::iterator it;
it = tab_map.find(pq);
if (it != tab_map.end())
delete it->second;
renumber_pqs();
}
void queue_selected(bool random)
{
std::map<Playqueue *, OcarinaPage *>::iterator it;
if (deck :: size() >= 10)
return;
for (it = tab_map.begin(); it != tab_map.end(); it++) {
if (it->second->is_current_tab()) {
it->second->queue_selected(random);
return;
}
}
}
*/
/*static void on_new_queue()
{
queue_selected(false);
}
static void on_add_to_queue(unsigned int num)
{
std::map<Playqueue *, OcarinaPage *>::iterator it;
for (it = tab_map.begin(); it != tab_map.end(); it++) {
if (it->second->is_current_tab()) {
it->second->on_add_to_pq(num);
return;
}
}
}
static void init_menu_item(const std::string &name, unsigned int num)
{
Glib::RefPtr<Gtk::MenuItem>menu = Glib::RefPtr<Gtk::MenuItem>::cast_static(get_builder()->get_object(name));
menu->signal_activate().connect(sigc::bind<unsigned int> (
sigc::ptr_fun(on_add_to_queue), num));
}*/
/*void focus_tab_search()
{
std::map<Playqueue *, OcarinaPage *>::iterator it;
for (it = tab_map.begin(); it != tab_map.end(); it++) {
if (it->second->is_current_tab()) {
it->second->on_focus_search();
return;
}
}
}
void init_tabs()
{
Gtk::Notebook *notebook;
get_builder()->get_widget("o_notebook", notebook);
get_callbacks()->on_pq_created = on_pq_created;
get_callbacks()->on_pq_removed = on_pq_removed;
get_callbacks()->on_queue_track_changed = on_track_changed;
*/
/*Glib::RefPtr<Gtk::MenuItem> new_pq = Glib::RefPtr<Gtk::MenuItem>::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);*/
/*
init_history_tab();
init_playlist_tab();
notebook->signal_switch_page().connect(sigc::ptr_fun(on_switch_page));
notebook->signal_page_reordered().connect(sigc::ptr_fun(on_page_reordered));
notebook->set_current_page(0);
}*/