/* * Copyright 2014 (c) Anna Schumaker. */ #include #include #include #include #include #include #include static bool audio_playing = false; static Glib::RefPtr builder; static sigc::connection fav_connection; static sigc::connection ban_connection; void enable_idle(); void enable_timeout(); template void get_object(const std::string &, Glib::RefPtr &); /* * 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("" + Glib::Markup::escape_text(text) + ""); } 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 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 c_col_id; Gtk::TreeModelColumn c_col_enabled; Gtk::TreeModelColumn c_col_size; Gtk::TreeModelColumn 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 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 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 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 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 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 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 &get_builder() { return builder; } Gtk::Button *get_button(const std::string &name) { Gtk::Button *button; builder->get_widget(name, button); return button; } template static void get_object(const std::string &name, Glib::RefPtr &obj) { obj = Glib::RefPtr::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 list; Glib::RefPtr 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; }