ocarina/gui/tabs.cpp

432 lines
9.0 KiB
C++

/*
* Copyright 2014 (c) Anna Schumaker.
*/
#include <core/deck.h>
#include <core/playlist.h>
#include <core/string.h>
#include <gui/tabs.h>
#include <map>
#include <sstream>
static std::map<Queue *, 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(Queue *pq)
: tab_sorting_count(0), tab_pq(pq), tab_label(NULL)
{
pq->set_notifier(this);
queue_mapping[tab_pq] = this;
tab_builder = Gtk::Builder::create();
tab_builder->add_from_file(gui :: share_file("QueueToolbar.ui"));
tab_builder->add_from_file(gui :: share_file("QueueWindow.ui"));
tab_builder->get_widget_derived("QueueToolbar", tab_toolbar);
tab_builder->get_widget_derived("QueueWindow", tab_window);
tab_window->init(tab_pq);
tab_window->q_treeview->signal_key_press_event().connect(sigc::mem_fun(*this,
&Tab :: on_key_pressed));
tab_window->q_treeview->signal_button_press_event().connect(sigc::mem_fun(*this,
&Tab :: on_button_pressed), false);
for (unsigned int i = 0; i < tab_window->q_treeview->get_n_columns(); i++)
tab_window->q_treeview->get_column(i)->signal_clicked().connect(
sigc::bind<unsigned int> (sigc::mem_fun(
*this, &Tab::on_column_clicked), i));
tab_vbox.set_margin_start(1);
tab_vbox.set_margin_end(1);
tab_vbox.set_homogeneous(false);
tab_vbox.pack_start(*tab_toolbar, false, true, 2);
tab_vbox.show();
tab_runtime_changed();
}
Tab :: ~Tab() {}
/**
*
* QNotifier implementation.
*
*/
void Tab :: on_track_added(unsigned int row)
{
tab_window->q_model->on_row_inserted(row);
tab_label->set_size();
tab_runtime_changed();
}
void Tab :: on_track_removed(unsigned int row)
{
tab_window->q_model->on_row_deleted(row);
tab_label->set_size();
tab_runtime_changed();
}
void Tab :: on_track_updated(unsigned int row)
{
tab_window->q_model->on_row_changed(row);
tab_runtime_changed();
}
/**
*
* Tab internal helper functions
*
*/
int Tab :: tab_page_num()
{
Gtk::Notebook *notebook = gui :: get_widget<Gtk::Notebook>("o_notebook");
return notebook->page_num(tab_vbox);
}
bool Tab :: tab_is_cur()
{
Gtk::Notebook *notebook = gui :: get_widget<Gtk::Notebook>("o_notebook");
return notebook->page_num(tab_vbox) == notebook->get_current_page();
}
void Tab :: tab_runtime_changed()
{
if (tab_is_cur())
gui :: get_widget<Gtk::Label>("o_queue_time")->set_text(string :: sec2str_detailed(tab_pq->length()));
}
void Tab :: tab_display_sorting()
{
std::string text = "";
if ((tab_sorting_count > 0) && tab_is_cur())
text = "Sorting within " + tab_sorting_title;
gui :: 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_unmap()
{
queue_mapping.erase(tab_pq);
}
void Tab :: tab_focus_search()
{
tab_toolbar->q_search->grab_focus();
}
void Tab :: tab_selected_ids(std::vector<unsigned int> &ids)
{
Glib::RefPtr<Gtk::TreeSelection> sel = tab_window->q_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_window->q_filter->convert_path_to_child_path(rows[i]);
ids.push_back(tab_window->q_model->path_to_id(path));
}
sel->unselect_all();
}
void Tab :: tab_queue_add(Queue *pq)
{
std::vector<unsigned int> ids;
tab_selected_ids(ids);
for (unsigned int i = 0; i < ids.size(); i++)
pq->add(tags :: get_track(ids[i]));
}
bool Tab :: tab_queue_selected(bool random)
{
if (deck :: get_queues().size() >= 10)
return true;
Queue *pq = deck :: create(random);
on_pq_created(pq, deck :: get_queues().size() - 1);
tab_queue_add(pq);
return true;
}
bool Tab :: tab_add_to_queue(unsigned int n)
{
if (n >= deck :: get_queues().size())
return true;
Queue *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(tags :: get_track(ids[i]), playlist);
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
*
*/
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()
{
std::string item;
unsigned int size = deck :: get_queues().size();
if (size == 0) {
gui :: get_widget<Gtk::MenuItem>("o_add_to_pq")->hide();
return;
}
gui :: get_widget<Gtk::MenuItem>("o_add_to_pq")->show();
if (size == 10)
gui :: get_widget<Gtk::MenuItem>("o_new_pq")->hide();
else
gui :: get_widget<Gtk::MenuItem>("o_new_pq")->show();
for (unsigned int i = 0; i < 10; i++) {
item = "o_pq_";
item += '0' + i;
if (i < size)
gui :: get_widget<Gtk::MenuItem>(item)->show();
else
gui :: get_widget<Gtk::MenuItem>(item)->hide();
}
}
/**
*
* GTK-MM callback functions
*
*/
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_window->q_treeview->get_column(col)->get_title();
tab_pq->sort(sort_fields[col], true);
} else
tab_pq->sort(sort_fields[col], false);
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_window->q_treeview->get_path_at_pos(button->x, button->y, path))
tab_window->q_treeview->get_selection()->select(path);
on_show_rc_menu();
gui :: get_widget<Gtk::Menu>("o_rc_menu")->popup(button->button, button->time);
return true;
}
/**
*
* Global functions
*
*/
Tab *find_tab(Queue *pq)
{
std::map<Queue *, 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<Queue *, 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<Queue *, 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_switch_page(Gtk::Widget *page, int num)
{
Tab *tab = find_tab(num);
if (tab) {
tab->tab_runtime_changed();
tab->tab_display_sorting();
} else
gui :: get_widget<Gtk::Label>("o_queue_time")->set_text("");
}
void tab_focus_search()
{
int page = gui :: get_widget<Gtk::Notebook>("o_notebook")->get_current_page();
Tab *tab = find_tab(page);
if (tab)
tab->tab_focus_search();
}
static void on_new_pq()
{
Tab *tab = cur_tab();
if (tab)
tab->tab_queue_selected(false);
}
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();
}
static void on_add_to_queue(unsigned int n)
{
Tab *tab = cur_tab();
if (tab)
tab->tab_add_to_queue(n);
}
static void init_menu_item(const std::string &pq, unsigned int n)
{
gui :: get_widget<Gtk::MenuItem>(pq)->signal_activate().connect(
sigc::bind<unsigned int> (sigc::ptr_fun(on_add_to_queue), n));
}
void init_tabs()
{
/* Notebook signals */
struct Gtk::Notebook *notebook = gui :: get_widget<Gtk::Notebook>("o_notebook");
notebook->signal_switch_page().connect(sigc::ptr_fun(on_switch_page));
/* Menu signals */
gui :: get_widget<Gtk::Menu>("o_rc_menu")->show_all();
gui :: get_widget<Gtk::MenuItem>("o_new_pq")->signal_activate().connect(
sigc::ptr_fun(on_new_pq));
gui :: get_widget<Gtk::MenuItem>("o_add_to_favorites")->signal_activate().connect(
sigc::ptr_fun(on_add_to_favs));
gui :: get_widget<Gtk::MenuItem>("o_add_to_banned")->signal_activate().connect(
sigc::ptr_fun(on_add_to_banned));
for (unsigned int i = 0; i < 10; i++) {
std::string pq = "o_pq_";
pq += '0' + i;
init_menu_item(pq, i);
}
/* Initialize other tabs */
init_history_tab();
init_collection_tab();
init_queue_tabs();
}
void post_init_tabs()
{
post_init_queue_tabs();
unsigned int tab = 0;
for (tab = 0; tab < deck::get_queues().size(); tab++) {
if ((deck :: get(tab)->has_flag(Q_ENABLED)))
break;
}
gui :: get_widget<Gtk::Notebook>("o_notebook")->set_current_page(tab);
}
void cleanup_tabs()
{
while (queue_mapping.size() > 0)
delete queue_mapping.begin()->second;
}