454 lines
11 KiB
C++
454 lines
11 KiB
C++
/*
|
|
* Copyright 2014 (c) Anna Schumaker.
|
|
*/
|
|
#include <audio.h>
|
|
#include <callback.h>
|
|
#include <idle.h>
|
|
#include <library.h>
|
|
#include <playlist.h>
|
|
|
|
#include <ocarina.h>
|
|
#include <print.h>
|
|
|
|
static bool audio_playing = false;
|
|
static Glib::RefPtr<Gtk::Builder> builder;
|
|
static sigc::connection fav_connection;
|
|
static sigc::connection ban_connection;
|
|
void enable_idle();
|
|
void enable_timeout();
|
|
|
|
template <class T>
|
|
void get_object(const std::string &, Glib::RefPtr<T> &);
|
|
|
|
|
|
|
|
/*
|
|
* Control functions
|
|
*/
|
|
static void on_config_pause()
|
|
{
|
|
Gtk::SpinButton *count;
|
|
Gtk::CheckButton *enabled;
|
|
|
|
builder->get_widget("o_pause_count", count);
|
|
builder->get_widget("o_pause_enabled", enabled);
|
|
|
|
audio :: pause_after(enabled->get_active(), count->get_value());
|
|
}
|
|
|
|
static void on_play()
|
|
{
|
|
get_button("o_play")->hide();
|
|
get_button("o_pause")->show();
|
|
audio_playing = true;
|
|
enable_timeout();
|
|
}
|
|
|
|
static void on_pause()
|
|
{
|
|
get_button("o_play")->show();
|
|
get_button("o_pause")->hide();
|
|
audio_playing = false;
|
|
}
|
|
|
|
static void on_next()
|
|
{
|
|
audio :: next();
|
|
audio :: play();
|
|
}
|
|
|
|
static bool on_seek(Gtk::ScrollType type, double value)
|
|
{
|
|
audio :: seek_to(value);
|
|
return true;
|
|
}
|
|
|
|
static void set_label_text(Gtk::Label *label, const std::string &size,
|
|
const std::string &text)
|
|
{
|
|
label->set_markup("<span size='" + size + "'>" +
|
|
Glib::Markup::escape_text(text) + "</span>");
|
|
}
|
|
|
|
static void on_track_loaded(library :: Song &song)
|
|
{
|
|
Gtk::ToggleButton *ban, *fav;
|
|
Gtk::Label *title, *artist, *album, *duration;
|
|
|
|
builder->get_widget("o_title", title);
|
|
builder->get_widget("o_artist", artist);
|
|
builder->get_widget("o_album", album);
|
|
builder->get_widget("o_total_time", duration);
|
|
builder->get_widget("o_ban", ban);
|
|
builder->get_widget("o_favorite", fav);
|
|
|
|
set_label_text(title, "xx-large", song.track->title);
|
|
set_label_text(artist, "x-large", "By: " + song.artist->primary_key);
|
|
set_label_text(album, "x-large", "From: " + song.album->name);
|
|
duration->set_text(song.track->length_str);
|
|
|
|
std::set<unsigned int> ids = playlist :: get_tracks("Banned");
|
|
bool banned = ids.find(song.track_id) != ids.end();
|
|
|
|
ids = playlist :: get_tracks("Favorites");
|
|
bool favorite = ids.find(song.track_id) != ids.end();
|
|
|
|
ban_connection.block();
|
|
fav_connection.block();
|
|
if (ban->get_active() != banned)
|
|
ban->set_active(banned);
|
|
if (fav->get_active() != favorite)
|
|
fav->set_active(favorite);
|
|
ban_connection.unblock();
|
|
fav_connection.unblock();
|
|
}
|
|
|
|
static void on_pause_count_changed(bool enabled, unsigned int count)
|
|
{
|
|
Gtk::CheckButton *p_enabled;
|
|
Gtk::SpinButton *p_count;
|
|
builder->get_widget("o_pause_enabled", p_enabled);
|
|
builder->get_widget("o_pause_count", p_count);
|
|
|
|
if (p_enabled->get_active() != enabled)
|
|
p_enabled->set_active(enabled);
|
|
if (p_count->get_value() != count)
|
|
p_count->set_value(count);
|
|
}
|
|
|
|
static void on_ban_toggled()
|
|
{
|
|
Gtk::ToggleButton *ban;
|
|
builder->get_widget("o_ban", ban);
|
|
|
|
if (ban->get_active() == true)
|
|
playlist :: add("Banned", audio::current_trackid());
|
|
else
|
|
playlist :: del("Banned", audio::current_trackid());
|
|
}
|
|
|
|
static void on_fav_toggled()
|
|
{
|
|
Gtk::ToggleButton *fav;
|
|
builder->get_widget("o_favorite", fav);
|
|
|
|
if (fav->get_active() == true)
|
|
playlist :: add("Favorites", audio::current_trackid());
|
|
else
|
|
playlist :: del("Favorites", audio::current_trackid());
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* Keyboard shortcuts
|
|
*/
|
|
static bool on_window_key_pressed(GdkEventKey *event)
|
|
{
|
|
Gtk::Window *window;
|
|
std::string key = gdk_keyval_name(event->keyval);
|
|
builder->get_widget("o_window", window);
|
|
|
|
if (key == "Escape")
|
|
window->set_focus(*window);
|
|
else if (key == "n")
|
|
on_next();
|
|
else if (key == "N")
|
|
audio :: previous();
|
|
else if (key == "q")
|
|
queue_selected(false);
|
|
else if (key == "s")
|
|
queue_selected(true);
|
|
else
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
static bool on_window_key_released(GdkEventKey *event)
|
|
{
|
|
Gtk::Window *window;
|
|
std::string key = gdk_keyval_name(event->keyval);
|
|
builder->get_widget("o_window", window);
|
|
|
|
if (key == "space")
|
|
audio :: toggle_play();
|
|
else
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* Collection manager functions
|
|
*/
|
|
static class CollectionColumns : public Gtk::TreeModelColumnRecord {
|
|
public:
|
|
CollectionColumns()
|
|
{ add(c_col_id); add(c_col_enabled); add(c_col_size); add(c_col_path); }
|
|
|
|
Gtk::TreeModelColumn<unsigned int> c_col_id;
|
|
Gtk::TreeModelColumn<bool> c_col_enabled;
|
|
Gtk::TreeModelColumn<unsigned int> c_col_size;
|
|
Gtk::TreeModelColumn<Glib::ustring> c_col_path;
|
|
} collection_cols;
|
|
|
|
static void on_collection_ok()
|
|
{
|
|
std::string path;
|
|
|
|
Gtk::FileChooserWidget *chooser;
|
|
get_builder()->get_widget("o_collection_chooser", chooser);
|
|
path = chooser->get_filename();
|
|
library::add_path(path);
|
|
enable_idle();
|
|
}
|
|
|
|
static void on_collection_update()
|
|
{
|
|
library :: update_all();
|
|
enable_idle();
|
|
}
|
|
|
|
static void on_collection_import()
|
|
{
|
|
library :: import();
|
|
enable_idle();
|
|
}
|
|
|
|
static void on_collection_row_activated(const Gtk::TreePath &path,
|
|
Gtk::TreeViewColumn *col)
|
|
{
|
|
Gtk::FileChooser *chooser;
|
|
Glib::RefPtr<Gtk::ListStore> list;
|
|
|
|
get_object("o_collection_dirs", list);
|
|
builder->get_widget("o_collection_chooser", chooser);
|
|
|
|
Gtk::TreeModel::Row row = *(list->get_iter(path));
|
|
Glib::ustring dir = row[collection_cols.c_col_path];
|
|
chooser->set_current_folder(dir);
|
|
}
|
|
|
|
#ifndef CONFIG_TEST
|
|
static
|
|
#endif /* CONFIG_TEST */
|
|
void do_collection_delete()
|
|
{
|
|
Gtk::TreePath path;
|
|
Gtk::TreeViewColumn *col;
|
|
Gtk::TreeView *treeview;
|
|
|
|
builder->get_widget("o_collection_treeview", treeview);
|
|
treeview->get_cursor(path, col);
|
|
if (path) {
|
|
Glib::RefPtr<Gtk::ListStore> list;
|
|
get_object("o_collection_dirs", list);
|
|
Gtk::TreeModel::Row row = *(list->get_iter(path));
|
|
library :: del_path(row[collection_cols.c_col_id]);
|
|
list->erase(row);
|
|
}
|
|
}
|
|
|
|
static bool on_collection_key_pressed(GdkEventKey *event)
|
|
{
|
|
std::string key = gdk_keyval_name(event->keyval);
|
|
if (key == "Delete") {
|
|
do_collection_delete();
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
#ifndef CONFIG_TEST
|
|
static
|
|
#endif /* CONFIG_TEST */
|
|
void on_collection_toggled(const Glib::ustring &path)
|
|
{
|
|
Glib::RefPtr<Gtk::ListStore> list;
|
|
get_object("o_collection_dirs", list);
|
|
Gtk::TreeModel::Row row = *(list->get_iter(path));
|
|
row[collection_cols.c_col_enabled] = !row[collection_cols.c_col_enabled];
|
|
library :: set_enabled(row[collection_cols.c_col_id],
|
|
row[collection_cols.c_col_enabled]);
|
|
}
|
|
|
|
static void on_library_add(unsigned int id, library :: Library *path)
|
|
{
|
|
Gtk::TreeModel::Row row;
|
|
Glib::RefPtr<Gtk::ListStore> list;
|
|
get_object("o_collection_dirs", list);
|
|
|
|
row = *(list->append());
|
|
row[collection_cols.c_col_id] = id;
|
|
row[collection_cols.c_col_enabled] = path->enabled;
|
|
row[collection_cols.c_col_size] = path->size;
|
|
row[collection_cols.c_col_path] = path->root_path;
|
|
}
|
|
|
|
static void on_library_update(unsigned int id, library :: Library *path)
|
|
{
|
|
Gtk::TreeModel::Row row;
|
|
Glib::RefPtr<Gtk::ListStore> list;
|
|
get_object("o_collection_dirs", list);
|
|
Gtk::TreeModel::Children children = list->children();
|
|
|
|
for (Gtk::TreeModel::Children::iterator it = children.begin();
|
|
it != children.end(); it++) {
|
|
row = *it;
|
|
if (row[collection_cols.c_col_id] == id)
|
|
row[collection_cols.c_col_size] = path->size;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* Idle func
|
|
*/
|
|
bool on_idle()
|
|
{
|
|
Gtk::ProgressBar *prog;
|
|
bool ret = idle::run_task();
|
|
|
|
builder->get_widget("o_idle_progress", prog);
|
|
if (ret == false)
|
|
prog->hide();
|
|
else {
|
|
prog->show();
|
|
prog->set_fraction(idle::get_progress());
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
void enable_idle()
|
|
{
|
|
Glib::signal_idle().connect(sigc::ptr_fun(on_idle));
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* Timeout function
|
|
*/
|
|
bool on_timeout()
|
|
{
|
|
Gtk::Label *position;
|
|
Glib::RefPtr<Gtk::Adjustment> bar;
|
|
|
|
builder->get_widget("o_cur_position", position);
|
|
get_object("o_progress", bar);
|
|
|
|
position->set_text(audio :: position_str());
|
|
bar->set_upper(audio :: duration());
|
|
bar->set_value(audio :: position());
|
|
|
|
return audio_playing;
|
|
}
|
|
|
|
void enable_timeout()
|
|
{
|
|
Glib::signal_timeout().connect(sigc::ptr_fun(on_timeout), 500);
|
|
}
|
|
|
|
|
|
/*
|
|
* Ocarina functions
|
|
*/
|
|
Glib::RefPtr<Gtk::Builder> &get_builder()
|
|
{
|
|
return builder;
|
|
}
|
|
|
|
Gtk::Button *get_button(const std::string &name)
|
|
{
|
|
Gtk::Button *button;
|
|
builder->get_widget(name, button);
|
|
return button;
|
|
}
|
|
|
|
template <class T>
|
|
static void get_object(const std::string &name, Glib::RefPtr<T> &obj)
|
|
{
|
|
obj = Glib::RefPtr<T>::cast_static(builder->get_object(name));
|
|
}
|
|
|
|
static void connect_button(const std::string &name, void (*func)())
|
|
{
|
|
get_button(name)->signal_clicked().connect(sigc::ptr_fun(func));
|
|
}
|
|
|
|
Gtk::Window *connect_wires()
|
|
{
|
|
Gtk::Window *window;
|
|
struct Callbacks *cb = get_callbacks();
|
|
Glib::RefPtr<Gtk::ListStore> list;
|
|
Glib::RefPtr<Gtk::CellRendererToggle> toggle;
|
|
Gtk::TreeView *treeview;
|
|
Gtk::SpinButton *count;
|
|
Gtk::CheckButton *enabled;
|
|
Gtk::Scale *position;
|
|
Gtk::ToggleButton *ban;
|
|
Gtk::ToggleButton *fav;
|
|
|
|
builder = Gtk::Builder::create();
|
|
builder->add_from_file("gui/ocarina6.glade");
|
|
builder->get_widget("o_window", window);
|
|
|
|
|
|
/* Controls */
|
|
cb->on_play = on_play;
|
|
cb->on_pause = on_pause;
|
|
cb->on_track_loaded = on_track_loaded;
|
|
cb->on_pause_count_changed = on_pause_count_changed;
|
|
|
|
builder->get_widget("o_pause_count", count);
|
|
builder->get_widget("o_pause_enabled", enabled);
|
|
builder->get_widget("o_position_scale", position);
|
|
count->signal_changed().connect(sigc::ptr_fun(on_config_pause));
|
|
enabled->signal_toggled().connect(sigc::ptr_fun(on_config_pause));
|
|
position->signal_change_value().connect(sigc::ptr_fun(on_seek));
|
|
|
|
connect_button("o_play", audio::play);
|
|
connect_button("o_pause", audio::pause);
|
|
connect_button("o_stop", audio::stop);
|
|
connect_button("o_prev", audio::previous);
|
|
connect_button("o_next", on_next);
|
|
|
|
|
|
/* Keyboard shortcuts */
|
|
window->signal_key_press_event().connect(sigc::ptr_fun(on_window_key_pressed));
|
|
window->signal_key_release_event().connect(sigc::ptr_fun(on_window_key_released));
|
|
window->set_can_focus();
|
|
|
|
|
|
/* Collection manager */
|
|
cb->on_library_add = on_library_add;
|
|
cb->on_library_update = on_library_update;
|
|
get_object("o_collection_dirs", list);
|
|
list->set_sort_column(collection_cols.c_col_path, Gtk::SORT_ASCENDING);
|
|
|
|
builder->get_widget("o_collection_treeview", treeview);
|
|
get_object("o_collection_toggle", toggle);
|
|
treeview->signal_row_activated().connect(sigc::ptr_fun(on_collection_row_activated));
|
|
treeview->signal_key_press_event().connect(sigc::ptr_fun(on_collection_key_pressed));
|
|
toggle->signal_toggled().connect(sigc::ptr_fun(on_collection_toggled));
|
|
|
|
connect_button("o_collection_ok", on_collection_ok);
|
|
connect_button("o_collection_update", on_collection_update);
|
|
connect_button("o_collection_import", on_collection_import);
|
|
|
|
|
|
/* Favorite and ban buttons */
|
|
builder->get_widget("o_ban", ban);
|
|
builder->get_widget("o_favorite", fav);
|
|
ban_connection = ban->signal_toggled().connect(sigc::ptr_fun(on_ban_toggled));
|
|
fav_connection = fav->signal_toggled().connect(sigc::ptr_fun(on_fav_toggled));
|
|
|
|
|
|
/* Set up other tabs */
|
|
init_tabs();
|
|
|
|
return window;
|
|
}
|