ocarina/gui/tabs.cpp

613 lines
13 KiB
C++

/*
* Copyright 2014 (c) Anna Schumaker.
*/
#include <callback.h>
#include <deck.h>
#include <filter.h>
#include <playlist.h>
#include <tabs.h>
#include <map>
#include <sstream>
static std::map<Playqueue *, Tab *> 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<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_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<Gtk::TreeViewColumn *> columns = tab_treeview->get_columns();
for (unsigned int i = 0; i < columns.size(); i++) {
columns[i]->signal_clicked().connect(sigc::bind<unsigned int> (
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<Gtk::Notebook>("o_notebook");
return notebook->page_num(*tab_widget);
}
bool Tab :: tab_is_cur()
{
Gtk::Notebook *notebook = get_widget<Gtk::Notebook>("o_notebook");
return notebook->page_num(*tab_widget) == notebook->get_current_page();
}
void Tab :: tab_runtime_changed()
{
if (tab_is_cur())
get_widget<Gtk::Label>("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<Gtk::Label>("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<unsigned int> &ids)
{
Glib::RefPtr<Gtk::TreeSelection> sel = tab_treeview->get_selection();
std::vector<Gtk::TreeModel::Path> 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<unsigned int> 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<unsigned int> 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<Gtk::Menu>("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<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;
}
static Tab *find_tab(int num)
{
std::map<Playqueue *, Tab *>::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<Playqueue *, Tab *>::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<Gtk::Label>("o_queue_time")->set_text("");
}
void tab_focus_search()
{
int page = get_widget<Gtk::Notebook>("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<Gtk::Notebook>("o_notebook");
notebook->signal_switch_page().connect(sigc::ptr_fun(on_switch_page));
/* Menu signals */
get_widget<Gtk::Menu>("o_rc_menu")->show_all();
get_widget<Gtk::MenuItem>("o_add_to_favorites")->signal_activate().connect(
sigc::ptr_fun(on_add_to_favs));
get_widget<Gtk::MenuItem>("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<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;
}
/*
* Mostly legacy code ....
*/
/*class OcarinaPage;
static std::map<Playqueue *, OcarinaPage *> tab_map;
static std::list<TabType *> 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::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 init_tabs()
{
Gtk::Notebook *notebook;
get_builder()->get_widget("o_notebook", notebook);
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);*/
/*
notebook->signal_page_reordered().connect(sigc::ptr_fun(on_page_reordered));
notebook->set_current_page(0);
}*/