ocarina/gui/tabs.cpp

365 lines
8.9 KiB
C++

/*
* Copyright 2014 (c) Anna Schumaker.
*/
#include <audio.h>
#include <callback.h>
#include <deck.h>
#include <ocarina.h>
#include <playqueue.h>
#include <map>
#include <sstream>
#include <string>
class OcarinaPage;
static std::map<Playqueue *, OcarinaPage *> tab_map;
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); }
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;
} 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("");
}
}
/*
* Tab class definition
*/
class OcarinaTab {
public:
Gtk::Label name_label;
Gtk::Label size_label;
Gtk::Image tab_icon;
Gtk::HBox box;
Gtk::VBox inner_box;
OcarinaTab(const std::string &, const std::string &);
~OcarinaTab();
void set_size(unsigned int);
};
OcarinaTab::OcarinaTab(const std::string &name, const std::string &icon)
: name_label("<big>" + name + "</big>", 0.5, 0.5),
size_label("0", 0.5, 0.5)
{
tab_icon.set_from_icon_name(icon, Gtk::ICON_SIZE_MENU);
tab_icon.set_alignment(0, 0.5);
name_label.set_use_markup();
name_label.set_margin_right(1);
box.set_spacing(5);
inner_box.pack_start(name_label);
inner_box.pack_start(size_label);
box.pack_start(tab_icon);
box.pack_start(inner_box);
box.show_all();
}
OcarinaTab::~OcarinaTab() {}
void OcarinaTab::set_size(unsigned int size)
{
std::stringstream ss;
ss << size;
size_label.set_text(ss.str());
}
/*
* Ocarina class definition
*/
class OcarinaPage : public Gtk::VBox {
private:
unsigned int init_flags;
Glib::RefPtr<PlayqueueModel> model;
Gtk::Notebook *notebook;
OcarinaTab tab;
/* Page widgets */
Gtk::HBox page_toolbar;
Gtk::SearchEntry page_entry;
//Gtk::ToggleButton page_repeat;
Gtk::ScrolledWindow page_scroll;
Gtk::TreeView page_view;
void setup_columns();
void set_tab_size();
public:
Gtk::ToggleButton page_random;
OcarinaPage(const std::string &, const std::string &,
Playqueue *, unsigned int);
~OcarinaPage();
bool is_current_tab();
void check_pq_flags();
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_row_activated(const Gtk::TreePath &, Gtk::TreeViewColumn *);
void on_column_clicked(unsigned int);
};
OcarinaPage::OcarinaPage(const std::string &name, const std::string &icon,
Playqueue *pq, unsigned int flags)
: init_flags(flags), tab(name, icon)
{
get_builder()->get_widget("o_notebook", notebook);
model = Glib::RefPtr<PlayqueueModel>(new PlayqueueModel(pq));
page_toolbar.set_spacing(5);
page_toolbar.pack_start(page_entry);
page_entry.set_margin_top(5);
page_entry.set_margin_bottom(5);
/* Make buttons */
if (flags & PQ_RANDOM) {
page_random.set_image_from_icon_name("media-playlist-shuffle");
page_toolbar.pack_start(page_random, false, false);
}
/* Make page content */
//page_repeat.set_image_from_icon_name("media-playlist-repeat");
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.signal_row_activated().connect(sigc::mem_fun(*this,
&OcarinaPage::on_row_activated));
page_view.set_model(model);
page_view.set_rules_hint();
page_scroll.add(page_view);
setup_columns();
//page_toolbar.pack_start(page_repeat, false, false);
pack_start(page_toolbar, false, false);
pack_start(page_scroll);
show_all();
/* Add to notebook */
notebook->prepend_page(*this, tab.box);
tab_map[pq] = this;
};
OcarinaPage::~OcarinaPage()
{
notebook->remove_page(*this);
tab_map.erase(model->queue);
}
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_RANDOM) {
page_random.set_active(model->queue->get_flags() & PQ_RANDOM);
page_random.signal_toggled().connect(sigc::mem_fun(*this,
&OcarinaPage::on_random_toggled));
}
}
void OcarinaPage::set_tab_size()
{
tab.set_size(model->queue->size());
}
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_random_toggled()
{
if (page_random.get_active())
model->queue->set_flag(PQ_RANDOM);
else
model->queue->unset_flag(PQ_RANDOM);
}
void OcarinaPage::on_row_activated(const Gtk::TreePath &path, Gtk::TreeViewColumn *col)
{
model->on_path_selected(path);
}
void OcarinaPage::on_column_clicked(unsigned int col_index)
{
Gtk::Label *sorting;
get_builder()->get_widget("o_sorting_indicator", sorting);
sorting->set_text("<sorting>");
if (sort_timeout_count == 0)
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), 3);
}
/*
* Do stuff with tabs
*/
static void on_track_added(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_inserted(row);
}
static void on_track_deleted(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_deleted(row);
}
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() - 1)
label->hide();
else {
tab->on_runtime_changed();
label->show();
}
sort_timeout_count = 0;
}
void init_tabs()
{
Gtk::Notebook *notebook;
get_builder()->get_widget("o_notebook", notebook);
new OcarinaPage("History", "document-open-recent", audio::get_recent_pq(), 0);
new OcarinaPage("Collection", "media-optical", deck::get_library_pq(), PQ_RANDOM);
get_callbacks()->on_queue_track_add = on_track_added;
get_callbacks()->on_queue_track_del = on_track_deleted;
get_callbacks()->on_queue_track_changed = on_track_changed;
notebook->signal_switch_page().connect(sigc::ptr_fun(on_switch_page));
notebook->set_current_page(0);
}
void init_tabs2()
{
std::map<Playqueue *, OcarinaPage *>::iterator it;
for (it = tab_map.begin(); it != tab_map.end(); it++)
it->second->check_pq_flags();
}
void cleanup_tabs()
{
std::map<Playqueue *, OcarinaPage *>::iterator it;
for (it = tab_map.begin(); it != tab_map.end(); it++)
delete it->second;
}