gui: Implement control buttons

Play, pause, stop and so on.  I also update labels and progress bars
during playback.

Signed-off-by: Anna Schumaker <schumaker.anna@gmail.com>
This commit is contained in:
Anna Schumaker 2014-01-22 22:31:42 -05:00 committed by Anna Schumaker
parent a865ac36a3
commit c346a5860a
10 changed files with 163 additions and 13 deletions

View File

@ -1,12 +1,14 @@
/* /*
* Copyright 2014 (c) Anna Schumaker. * Copyright 2014 (c) Anna Schumaker.
*/ */
#include <audio.h>
#include <deck.h> #include <deck.h>
#include <ocarina.h> #include <ocarina.h>
Gtk::Window *ocarina_init() Gtk::Window *ocarina_init(int *argc, char ***argv)
{ {
Gtk::Window *window = connect_wires(); Gtk::Window *window = connect_wires();
audio::init(argc, argv);
deck::init(); deck::init();
library::init(); library::init();
return window; return window;
@ -15,8 +17,8 @@ Gtk::Window *ocarina_init()
#ifndef CONFIG_TEST #ifndef CONFIG_TEST
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
Gtk::Main ocarina(argc, argv); Gtk::Main ocarina(&argc, &argv);
Gtk::Window *window = ocarina_init(); Gtk::Window *window = ocarina_init(argc, argv);
Gtk::Main::run(*window); Gtk::Main::run(*window);
cleanup_tabs(); cleanup_tabs();
return 0; return 0;

View File

@ -362,7 +362,7 @@ Manager</property>
</packing> </packing>
</child> </child>
<child> <child>
<object class="GtkScale" id="scale1"> <object class="GtkScale" id="o_position_scale">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">True</property> <property name="can_focus">True</property>
<property name="adjustment">o_progress</property> <property name="adjustment">o_progress</property>
@ -627,7 +627,7 @@ Manager</property>
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">False</property> <property name="can_focus">False</property>
<property name="xalign">0</property> <property name="xalign">0</property>
<property name="label" translatable="yes">&lt;span size='xx-large'&gt;A Random Song Title&lt;/span&gt;</property> <property name="label" translatable="yes">&lt;span size='xx-large'&gt;&lt;/span&gt;</property>
<property name="use_markup">True</property> <property name="use_markup">True</property>
</object> </object>
<packing> <packing>
@ -641,7 +641,7 @@ Manager</property>
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">False</property> <property name="can_focus">False</property>
<property name="xalign">0</property> <property name="xalign">0</property>
<property name="label" translatable="yes">&lt;span size='x-large'&gt;By: Some Artist&lt;/span&gt;</property> <property name="label" translatable="yes">&lt;span size='x-large'&gt;&lt;/span&gt;</property>
<property name="use_markup">True</property> <property name="use_markup">True</property>
</object> </object>
<packing> <packing>
@ -655,7 +655,7 @@ Manager</property>
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">False</property> <property name="can_focus">False</property>
<property name="xalign">0</property> <property name="xalign">0</property>
<property name="label" translatable="yes">&lt;span size='x-large'&gt;From: Some Album&lt;/span&gt;</property> <property name="label" translatable="yes">&lt;span size='x-large'&gt;&lt;/span&gt;</property>
<property name="use_markup">True</property> <property name="use_markup">True</property>
</object> </object>
<packing> <packing>

View File

@ -183,12 +183,18 @@ void OcarinaTab::on_runtime_changed()
*/ */
static void on_track_added(Playqueue *pq, unsigned int row) static void on_track_added(Playqueue *pq, unsigned int row)
{ {
tab_map[pq]->on_row_inserted(row); std::map<Playqueue *, OcarinaTab *>::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) static void on_track_deleted(Playqueue *pq, unsigned int row)
{ {
tab_map[pq]->on_row_deleted(row); std::map<Playqueue *, OcarinaTab *>::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) static void on_switch_page(Gtk::Widget *page, unsigned int num)

View File

@ -1,6 +1,7 @@
/* /*
* Copyright 2014 (c) Anna Schumaker. * Copyright 2014 (c) Anna Schumaker.
*/ */
#include <audio.h>
#include <callback.h> #include <callback.h>
#include <idle.h> #include <idle.h>
#include <library.h> #include <library.h>
@ -8,13 +9,49 @@
#include <ocarina.h> #include <ocarina.h>
#include <print.h> #include <print.h>
static bool audio_playing = false;
static Glib::RefPtr<Gtk::Builder> builder; static Glib::RefPtr<Gtk::Builder> builder;
void enable_idle(); void enable_idle();
void enable_timeout();
template <class T> template <class T>
void get_object(const std::string &, Glib::RefPtr<T> &); void get_object(const std::string &, Glib::RefPtr<T> &);
/*
* 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("<span size='xx-large'>" + song.track->title + "</span>");
artist->set_markup("<span size='x-large'>By: " + song.artist->primary_key + "</span>");
album->set_markup("<span size='x-large'>From: " + song.album->name + "</span>");
duration->set_text(song.track->length_str);
}
/* /*
* Collection manager functions * Collection manager functions
*/ */
@ -163,6 +200,31 @@ void enable_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 * Ocarina functions
*/ */
@ -202,6 +264,17 @@ Gtk::Window *connect_wires()
builder->get_widget("o_window", window); 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 */ /* Collection manager */
cb->on_library_add = on_library_add; cb->on_library_add = on_library_add;
cb->on_library_update = on_library_update; cb->on_library_update = on_library_update;

View File

@ -8,6 +8,8 @@ extern "C" {
#include <gst/gst.h> #include <gst/gst.h>
} }
#include <string>
namespace audio namespace audio
{ {
@ -23,6 +25,7 @@ namespace audio
void seek_to(long); void seek_to(long);
long position(); long position();
std::string position_str();
long duration(); long duration();
void pause_after(bool, unsigned int); void pause_after(bool, unsigned int);

View File

@ -9,6 +9,11 @@
struct Callbacks { struct Callbacks {
/* Audio callbacks */
void (*on_play)();
void (*on_pause)();
void (*on_track_loaded)(library :: Song &);
/* Library callbacks */ /* Library callbacks */
void (*on_library_add)(unsigned int, library :: Library *); void (*on_library_add)(unsigned int, library :: Library *);
void (*on_library_update)(unsigned int, library :: Library *); void (*on_library_update)(unsigned int, library :: Library *);

View File

@ -8,7 +8,7 @@
#include <gtkmm.h> #include <gtkmm.h>
/* main.cpp */ /* main.cpp */
Gtk::Window *ocarina_init(); Gtk::Window *ocarina_init(int *, char ***);
/* model.cpp */ /* model.cpp */
class PlayqueueModel : public Gtk::TreeModel, public Glib::Object { class PlayqueueModel : public Gtk::TreeModel, public Glib::Object {

View File

@ -2,9 +2,11 @@
* Copyright 2013 (c) Anna Schumaker. * Copyright 2013 (c) Anna Schumaker.
*/ */
#include <audio.h> #include <audio.h>
#include <callback.h>
#include <deck.h> #include <deck.h>
#include <library.h> #include <library.h>
#include <sstream>
#include <string.h> #include <string.h>
static GstElement *ocarina_player; 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_object_set(G_OBJECT(ocarina_player), "uri", escaped, NULL);
g_free(escaped); g_free(escaped);
get_callbacks()->on_track_loaded(song);
return change_state(state); return change_state(state);
} }
@ -115,14 +118,16 @@ void audio :: play()
{ {
if (track_loaded == false) if (track_loaded == false)
return; return;
change_state(GST_STATE_PLAYING); if (change_state(GST_STATE_PLAYING))
get_callbacks()->on_play();
} }
void audio :: pause() void audio :: pause()
{ {
if (track_loaded == false) if (track_loaded == false)
return; return;
change_state(GST_STATE_PAUSED); if (change_state(GST_STATE_PAUSED))
get_callbacks()->on_pause();
} }
void audio :: stop() void audio :: stop()
@ -192,6 +197,20 @@ long audio :: position()
return 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 audio :: duration()
{ {
long duration; long duration;

View File

@ -4,12 +4,18 @@
#include <callback.h> #include <callback.h>
static void no_op() {}
static void no_op(unsigned int) {} static void no_op(unsigned int) {}
static void no_op(unsigned int id, library :: Library *path) {} static void no_op(unsigned int id, library :: Library *path) {}
static void no_op(Playqueue *, unsigned int) {} static void no_op(Playqueue *, unsigned int) {}
static void no_op(library :: Song &) {}
static struct Callbacks callbacks = { static struct Callbacks callbacks = {
.on_play = no_op,
.on_pause = no_op,
.on_track_loaded = no_op,
.on_library_add = no_op, .on_library_add = no_op,
.on_library_update = no_op, .on_library_update = no_op,
.on_library_track_add = no_op, .on_library_track_add = no_op,

View File

@ -73,6 +73,42 @@ bool test_1()
on_collection_toggled("3"); on_collection_toggled("3");
break; break;
case 9: 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; break;
default: default:
end_test(); end_test();
@ -162,7 +198,7 @@ int main(int argc, char **argv)
library::init(); library::init();
library::reset(); library::reset();
Gtk::Window *window = ocarina_init(); Gtk::Window *window = ocarina_init(&argc, &argv);
schedule_test(test_0); schedule_test(test_0);