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:
parent
41467524db
commit
56f0e801f5
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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());
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue