ocarina: Give each page its own footer

After listening to a long queue, I noticed that there were problems
re-realizing widgets after moving the footer to a different page (the
header might have the same problem?).  I decided to fix this issue by
creating a new footer instance for each notebook page.

If I do the same thing for the page header then I can get rid of the
"move this widget from page X to page Y" logic AND allow pages to use
their own custom header AND allow for separate library and queue
filters.

Signed-off-by: Bryan Schumaker <bjschuma@gmail.com>
This commit is contained in:
Bryan Schumaker 2012-01-29 10:24:07 -05:00
parent 41467524db
commit 56f0e801f5
8 changed files with 142 additions and 112 deletions

View File

@ -4,8 +4,8 @@
#include <ocarina/gtk.h>
#include <libsaria/track.h>
void footer_init();
GtkWidget *get_footer();
void put_footer();
void change_footer(libsaria::Track *);
#endif /* OCARINA_FOOTER */

View File

@ -19,20 +19,15 @@ static int cur_page()
static void switch_page(GtkWidget *notebook, GtkWidget *page, int pagenum)
{
GtkWidget *header = get_header();
GtkWidget *footer = get_footer();
int cur = cur_page();
if (cur != -1) {
pages[cur].remove_header(header);
pages[cur].remove_footer(footer);
}
if (pagenum != -1) {
pages[pagenum].add_header(header);
pages[pagenum].add_footer(footer);
}
if (footer != NULL)
put_footer();
if (header != NULL)
put_header();
}
@ -66,6 +61,7 @@ unsigned int add_page(GtkWidget *label, GtkWidget *content, bool fill)
TRUE,
GTK_PACK_START);
}
page.add_footer(get_footer());
return index;
};

View File

@ -6,8 +6,6 @@
#include <libsaria/controls.h>
#include "footer.h"
static GtkWidget *controls = NULL;
static GtkWidget *make_buttons()
{
GtkWidget *buttons = gtk_hbox_new(FALSE, 0);
@ -28,16 +26,20 @@ static void toggle_pause_after()
libsaria::set_pause_after(!libsaria::get_pause_after());
}
static void make_controls()
GtkWidget *get_controls()
{
controls = gtk_vbox_new(FALSE, 0);
GtkWidget *controls = gtk_vbox_new(FALSE, 0);
gtk_widget_show(controls);
/*
* Putting the button hbox into a vbox will keep them from
* expanding vertically to take up all the space.
*/
box_pack_start(controls, make_buttons(), TRUE, FALSE, 0);
return controls;
}
void controls_init()
{
register_shortcut("Left", libsaria::rewind);
register_shortcut("Right", libsaria::forward);
register_shortcut("space", libsaria::toggle_play);
@ -45,10 +47,3 @@ static void make_controls()
register_shortcut("s", libsaria::audio::stop);
register_shortcut("p", toggle_pause_after);
}
GtkWidget *get_controls()
{
if (controls == NULL)
make_controls();
return controls;
}

View File

@ -2,42 +2,36 @@
#include <ocarina/footer.h>
#include "footer.h"
static GtkWidget *footer = NULL;
static void make_footer()
GtkWidget *get_footer()
{
GtkWidget *sep = gtk_hseparator_new();
GtkWidget *footer = gtk_vbox_new(FALSE, 0);
GtkWidget *sep = gtk_hseparator_new();
GtkWidget *content = gtk_hbox_new(FALSE, 5);
footer = gtk_vbox_new(FALSE, 0);
box_pack_start(footer, sep, FALSE, FALSE, 0);
box_pack_start(footer, get_progress(), FALSE, FALSE, 0);
box_pack_start(footer, content, FALSE, FALSE, 0);
/*
* The pause button begins life hidden, so show everything up until
* this point, and then add the controls
*/
gtk_widget_show_all(footer);
box_pack_start(content, get_nowplaying(), TRUE, TRUE, 0);
box_pack_start(content, get_nowplaying(), TRUE, TRUE, 0);
box_pack_start(content, get_controls(), FALSE, FALSE, 0);
}
GtkWidget *get_footer()
{
if (footer == NULL)
make_footer();
g_object_ref(footer);
return footer;
}
void put_footer()
{
if (footer != NULL)
g_object_unref(footer);
}
void change_footer(libsaria::Track *track)
{
set_now_playing(track);
}
void footer_init()
{
controls_init();
progress_init();
nowplaying_init();
}

View File

@ -7,6 +7,9 @@ GtkWidget *get_controls();
GtkWidget *get_nowplaying();
GtkWidget *get_progress();
void progress_init();
void controls_init();
void nowplaying_init();
void set_now_playing(libsaria::Track *);
#endif /* OCARINA_FOOTER_PRIVATE_H */

View File

@ -3,10 +3,16 @@
#include <ocarina/gtk.h>
#include "footer.h"
static GtkWidget *now_playing = NULL;
static GtkWidget *title = NULL;
static GtkWidget *artist = NULL;
static GtkWidget *album = NULL;
#include <list>
using namespace std;
struct NowPlayingWidgets {
GtkWidget *title;
GtkWidget *artist;
GtkWidget *album;
};
static list<NowPlayingWidgets> nowplaying_widgets;
static void set_label(GtkWidget *label, string text, string size)
{
@ -15,19 +21,18 @@ static void set_label(GtkWidget *label, string text, string size)
gtk_label_set_markup(GTK_LABEL(label), markup.c_str());
}
static void set_title(string new_title)
static void set_now_playing(struct NowPlayingWidgets *widgets, string title,
string artist, string album)
{
set_label(title, new_title, "xx-large");
}
if (artist != "")
artist = "by " + artist;
static void set_artist(string new_artist)
{
set_label(artist, new_artist, "x-large");
}
if (album != "")
album = "from " + album;
static void set_album(string new_album)
{
set_label(album, new_album, "x-large");
set_label(widgets->title, title, "xx-large");
set_label(widgets->artist, artist, "x-large");
set_label(widgets->album, album, "x-large");
}
static GtkWidget *align(GtkWidget *label)
@ -37,51 +42,70 @@ static GtkWidget *align(GtkWidget *label)
return alignment;
}
static GtkWidget *setup_window()
static GtkWidget *setup_window(GtkWidget *box)
{
GtkWidget *viewport = gtk_viewport_new(NULL, NULL);
now_playing = gtk_scrolled_window_new(NULL, NULL);
GtkWidget *window = gtk_scrolled_window_new(NULL, NULL);
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(now_playing),
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(window),
GTK_POLICY_AUTOMATIC,
GTK_POLICY_NEVER);
GTK_POLICY_AUTOMATIC);
gtk_viewport_set_shadow_type(GTK_VIEWPORT(viewport), GTK_SHADOW_NONE);
container_add(now_playing, viewport);
container_add(viewport, box);
container_add(window, viewport);
return viewport;
}
static void make_now_playing()
{
GtkWidget *tag_box = gtk_vbox_new(FALSE, 0);
GtkWidget *container = setup_window();
title = gtk_label_new("");
artist = gtk_label_new("");
album = gtk_label_new("");
set_title(" ");
set_artist(" ");
set_album(" ");
box_pack_start(tag_box, align(title), TRUE, FALSE, 0);
box_pack_start(tag_box, align(artist), TRUE, FALSE, 0);
box_pack_start(tag_box, align(album), TRUE, FALSE, 0);
container_add(container, tag_box);
gtk_widget_show_all(now_playing);
return window;
}
GtkWidget *get_nowplaying()
{
if (now_playing == NULL)
make_now_playing();
return now_playing;
struct NowPlayingWidgets widgets;
GtkWidget *box = gtk_vbox_new(FALSE, 0);
GtkWidget *window = setup_window(box);
widgets.title = gtk_label_new("");
widgets.artist = gtk_label_new("");
widgets.album = gtk_label_new("");
set_now_playing(&widgets, "", "", "");
box_pack_start(box, align(widgets.title), TRUE, FALSE, 0);
box_pack_start(box, align(widgets.artist), TRUE, FALSE, 0);
box_pack_start(box, align(widgets.album), TRUE, FALSE, 0);
nowplaying_widgets.push_back(widgets);
gtk_widget_show_all(window);
return window;
}
/*
* This takes some explanation, so...
* During startup, all the labels are set to the empty string. This
* causes them to initially be rendered blank. This normally isn't
* a problem BUT the three widgets placed on the settings tab don't have
* a call to gtk_widget_show() once the page is added to the notebook and
* for some reason switching tabs isn't enough to realize the widgets.
* As a result, only the very beginning of the widget gets updated (as in,
* you could see half of a "T" if you start ocarina, click "next" and then
* switch to the settings tab). Realizing just one of the widgets before
* trying to use them seems to fix the problem, so that's what I'm doing
* here.
*/
void nowplaying_init()
{
list<struct NowPlayingWidgets>::iterator it;
for (it = nowplaying_widgets.begin(); it != nowplaying_widgets.end(); it++)
gtk_widget_realize(it->title);
}
void set_now_playing(libsaria::Track *track)
{
set_title(track->get_title());
set_artist("by " + track->get_artist());
set_album("from " + track->get_album());
list<struct NowPlayingWidgets>::iterator it;
for (it = nowplaying_widgets.begin(); it != nowplaying_widgets.end(); it++) {
set_now_playing(&(*it),
track->get_title(),
track->get_artist(),
track->get_album());
};
}

View File

@ -4,19 +4,24 @@
#include <libsaria/print.h>
#include "footer.h"
static GtkWidget *progress_box = NULL; /* gtk hbox */
static GtkWidget *position = NULL; /* gtk label */
static GtkWidget *progress = NULL; /* gtk hscale */
static GtkWidget *duration = NULL; /* gtk label */
#include <list>
using namespace std;
static gboolean update_progress(gpointer data)
struct ProgressWidgets {
GtkWidget *position;
GtkWidget *duration;
GtkWidget *progress;
};
static list<ProgressWidgets> widget_list;
static gboolean update_progress(struct ProgressWidgets *widgets)
{
gint64 pos = libsaria::audio::position();
gint64 dur = libsaria::audio::duration() + 1;
gtk_label_set_text(GTK_LABEL(position), libsaria::audio::posstr().c_str());
gtk_label_set_text(GTK_LABEL(duration), libsaria::audio::durstr().c_str());
gtk_range_set_range(GTK_RANGE(progress), 0, dur);
gtk_label_set_text(GTK_LABEL(widgets->position), libsaria::audio::posstr().c_str());
gtk_label_set_text(GTK_LABEL(widgets->duration), libsaria::audio::durstr().c_str());
/*
* This happens when gstreamer's "about-to-finish" signal
@ -25,40 +30,51 @@ static gboolean update_progress(gpointer data)
*/
if (pos > dur)
pos = 0;
gtk_range_set_value(GTK_RANGE(progress), pos);
gtk_range_set_range(GTK_RANGE(widgets->progress), 0, dur);
gtk_range_set_value(GTK_RANGE(widgets->progress), pos);
return TRUE;
}
static gboolean update_progress_widgets(gpointer data)
{
list<ProgressWidgets>::iterator it;
for (it = widget_list.begin(); it != widget_list.end(); it++)
update_progress(&(*it));
return TRUE;
}
void progress_init()
{
gtk_timeout_add(100, update_progress_widgets, NULL);
}
static void slider_changed(GtkWidget *slider, GtkScrollType scroll,
gdouble value, gpointer data)
{
libsaria::audio::seek_to(value);
}
static void make_scale()
static GtkWidget *make_scale()
{
progress = gtk_hscale_new_with_range(0, 1, 1000000000);
gtk_scale_set_draw_value(GTK_SCALE(progress), FALSE);
gtk_timeout_add(100, update_progress, NULL);
GTK_CONNECT(progress, "change-value", slider_changed, NULL);
}
static void make_progress()
{
position = gtk_label_new("");
progress_box = gtk_hbox_new(FALSE, 0);
duration = gtk_label_new("");
make_scale();
box_pack_start(progress_box, position, FALSE, FALSE, 0);
box_pack_start(progress_box, progress, TRUE, TRUE, 0);
box_pack_start(progress_box, duration, FALSE, FALSE, 0);
gtk_widget_show_all(progress_box);
GtkWidget *scale = gtk_hscale_new_with_range(0, 1, 1000000000);
gtk_scale_set_draw_value(GTK_SCALE(scale), FALSE);
GTK_CONNECT(scale, "change-value", slider_changed, NULL);
return scale;
}
GtkWidget *get_progress()
{
if (progress_box == NULL)
make_progress();
return progress_box;
struct ProgressWidgets widgets;
GtkWidget *box = gtk_hbox_new(FALSE, 0);
widgets.position = gtk_label_new("");
widgets.duration = gtk_label_new("");
widgets.progress = make_scale();
box_pack_start(box, widgets.position, FALSE, FALSE, 0);
box_pack_start(box, widgets.progress, TRUE, TRUE, 0);
box_pack_start(box, widgets.duration, FALSE, FALSE, 0);
gtk_widget_show_all(box);
widget_list.push_back(widgets);
return box;
}

View File

@ -3,6 +3,7 @@
#include <ocarina/callback.h>
#include <ocarina/gtk.h>
#include <ocarina/body.h>
#include <ocarina/footer.h>
#include <ocarina/ocarina.h>
#include <ocarina/settings.h>
#include <ocarina/window.h>
@ -59,6 +60,7 @@ namespace ocarina
ocarina::queue::init();
ocarina::library::init();
settings_init();
footer_init();
idle_add();
}