From c346a5860a0a3651ec67930a8bf2d30e6859739f Mon Sep 17 00:00:00 2001 From: Anna Schumaker Date: Wed, 22 Jan 2014 22:31:42 -0500 Subject: [PATCH] gui: Implement control buttons Play, pause, stop and so on. I also update labels and progress bars during playback. Signed-off-by: Anna Schumaker --- gui/main.cpp | 8 +++-- gui/ocarina6.glade | 8 ++--- gui/tabs.cpp | 10 +++++-- gui/wires.cpp | 73 ++++++++++++++++++++++++++++++++++++++++++++++ include/audio.h | 3 ++ include/callback.h | 5 ++++ include/ocarina.h | 2 +- lib/audio.cpp | 23 +++++++++++++-- lib/callback.cpp | 6 ++++ tests/gui/gui.cpp | 38 +++++++++++++++++++++++- 10 files changed, 163 insertions(+), 13 deletions(-) diff --git a/gui/main.cpp b/gui/main.cpp index d09c800d..98827d6a 100644 --- a/gui/main.cpp +++ b/gui/main.cpp @@ -1,12 +1,14 @@ /* * Copyright 2014 (c) Anna Schumaker. */ +#include #include #include -Gtk::Window *ocarina_init() +Gtk::Window *ocarina_init(int *argc, char ***argv) { Gtk::Window *window = connect_wires(); + audio::init(argc, argv); deck::init(); library::init(); return window; @@ -15,8 +17,8 @@ Gtk::Window *ocarina_init() #ifndef CONFIG_TEST int main(int argc, char **argv) { - Gtk::Main ocarina(argc, argv); - Gtk::Window *window = ocarina_init(); + Gtk::Main ocarina(&argc, &argv); + Gtk::Window *window = ocarina_init(argc, argv); Gtk::Main::run(*window); cleanup_tabs(); return 0; diff --git a/gui/ocarina6.glade b/gui/ocarina6.glade index 46193733..9a1d6b05 100644 --- a/gui/ocarina6.glade +++ b/gui/ocarina6.glade @@ -362,7 +362,7 @@ Manager - + True True o_progress @@ -627,7 +627,7 @@ Manager True False 0 - <span size='xx-large'>A Random Song Title</span> + <span size='xx-large'></span> True @@ -641,7 +641,7 @@ Manager True False 0 - <span size='x-large'>By: Some Artist</span> + <span size='x-large'></span> True @@ -655,7 +655,7 @@ Manager True False 0 - <span size='x-large'>From: Some Album</span> + <span size='x-large'></span> True diff --git a/gui/tabs.cpp b/gui/tabs.cpp index ebd2cf9e..55aac1d1 100644 --- a/gui/tabs.cpp +++ b/gui/tabs.cpp @@ -183,12 +183,18 @@ void OcarinaTab::on_runtime_changed() */ static void on_track_added(Playqueue *pq, unsigned int row) { - tab_map[pq]->on_row_inserted(row); + std::map::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) { - tab_map[pq]->on_row_deleted(row); + std::map::iterator it; + it = tab_map.find(pq); + if (it != tab_map.end()) + it->second->on_row_deleted(row); } static void on_switch_page(Gtk::Widget *page, unsigned int num) diff --git a/gui/wires.cpp b/gui/wires.cpp index bdc47181..d519ffe5 100644 --- a/gui/wires.cpp +++ b/gui/wires.cpp @@ -1,6 +1,7 @@ /* * Copyright 2014 (c) Anna Schumaker. */ +#include #include #include #include @@ -8,13 +9,49 @@ #include #include +static bool audio_playing = false; static Glib::RefPtr builder; void enable_idle(); +void enable_timeout(); template void get_object(const std::string &, Glib::RefPtr &); + +/* + * Control functions + */ +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_track_loaded(library :: Song &song) +{ + 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); + + title->set_markup("" + song.track->title + ""); + artist->set_markup("By: " + song.artist->primary_key + ""); + album->set_markup("From: " + song.album->name + ""); + duration->set_text(song.track->length_str); +} + + /* * Collection manager functions */ @@ -163,6 +200,31 @@ void enable_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 */ @@ -202,6 +264,17 @@ Gtk::Window *connect_wires() builder->get_widget("o_window", window); + /* Controls */ + cb->on_play = on_play; + cb->on_pause = on_pause; + cb->on_track_loaded = on_track_loaded; + 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", audio::next); + + /* Collection manager */ cb->on_library_add = on_library_add; cb->on_library_update = on_library_update; diff --git a/include/audio.h b/include/audio.h index 8013930c..25d86740 100644 --- a/include/audio.h +++ b/include/audio.h @@ -8,6 +8,8 @@ extern "C" { #include } +#include + namespace audio { @@ -23,6 +25,7 @@ namespace audio void seek_to(long); long position(); + std::string position_str(); long duration(); void pause_after(bool, unsigned int); diff --git a/include/callback.h b/include/callback.h index 9ae04981..71f334cf 100644 --- a/include/callback.h +++ b/include/callback.h @@ -9,6 +9,11 @@ struct Callbacks { + /* Audio callbacks */ + void (*on_play)(); + void (*on_pause)(); + void (*on_track_loaded)(library :: Song &); + /* Library callbacks */ void (*on_library_add)(unsigned int, library :: Library *); void (*on_library_update)(unsigned int, library :: Library *); diff --git a/include/ocarina.h b/include/ocarina.h index ffea6bf5..5c0c7def 100644 --- a/include/ocarina.h +++ b/include/ocarina.h @@ -8,7 +8,7 @@ #include /* main.cpp */ -Gtk::Window *ocarina_init(); +Gtk::Window *ocarina_init(int *, char ***); /* model.cpp */ class PlayqueueModel : public Gtk::TreeModel, public Glib::Object { diff --git a/lib/audio.cpp b/lib/audio.cpp index 7ccd1347..f3bf7da2 100644 --- a/lib/audio.cpp +++ b/lib/audio.cpp @@ -2,9 +2,11 @@ * Copyright 2013 (c) Anna Schumaker. */ #include +#include #include #include +#include #include static GstElement *ocarina_player; @@ -89,6 +91,7 @@ static bool load_song(library :: Song &song) g_object_set(G_OBJECT(ocarina_player), "uri", escaped, NULL); g_free(escaped); + get_callbacks()->on_track_loaded(song); return change_state(state); } @@ -115,14 +118,16 @@ void audio :: play() { if (track_loaded == false) return; - change_state(GST_STATE_PLAYING); + if (change_state(GST_STATE_PLAYING)) + get_callbacks()->on_play(); } void audio :: pause() { if (track_loaded == false) return; - change_state(GST_STATE_PAUSED); + if (change_state(GST_STATE_PAUSED)) + get_callbacks()->on_pause(); } void audio :: stop() @@ -192,6 +197,20 @@ long audio :: position() return position; } +std::string audio :: position_str() +{ + std::stringstream ss; + long cur = position() / GST_SECOND; + unsigned int minutes = cur / 60; + unsigned int seconds = cur % 60; + + ss << minutes << ":"; + if (seconds < 10) + ss << "0"; + ss << seconds; + return ss.str(); +} + long audio :: duration() { long duration; diff --git a/lib/callback.cpp b/lib/callback.cpp index bce26cff..df40c7b6 100644 --- a/lib/callback.cpp +++ b/lib/callback.cpp @@ -4,12 +4,18 @@ #include +static void no_op() {} static void no_op(unsigned int) {} static void no_op(unsigned int id, library :: Library *path) {} static void no_op(Playqueue *, unsigned int) {} +static void no_op(library :: Song &) {} static struct Callbacks callbacks = { + .on_play = no_op, + .on_pause = no_op, + .on_track_loaded = no_op, + .on_library_add = no_op, .on_library_update = no_op, .on_library_track_add = no_op, diff --git a/tests/gui/gui.cpp b/tests/gui/gui.cpp index 05d5dc85..dfa3d366 100644 --- a/tests/gui/gui.cpp +++ b/tests/gui/gui.cpp @@ -73,6 +73,42 @@ bool test_1() on_collection_toggled("3"); break; case 9: + change_page(1); + break; + case 10: + change_page(0); + break; + case 11: + click_button("o_next"); + break; + case 12: + click_button("o_play"); + break; + case 13: + click_button("o_pause"); + break; + case 14: + click_button("o_play"); + break; + case 15: + click_button("o_stop"); + break; + case 16: + click_button("o_next"); + break; + case 17: + click_button("o_next"); + break; + case 18: + click_button("o_prev"); + break; + case 19: + click_button("o_play"); + break; + case 20: + case 21: + case 22: + case 23: break; default: end_test(); @@ -162,7 +198,7 @@ int main(int argc, char **argv) library::init(); library::reset(); - Gtk::Window *window = ocarina_init(); + Gtk::Window *window = ocarina_init(&argc, &argv); schedule_test(test_0);