ocarina/gui/artwork.c

152 lines
4.2 KiB
C

/*
* Copyright 2016 (c) Anna Schumaker.
*/
#include <core/audio.h>
#include <gui/builder.h>
#include <glib/gi18n.h>
#define ARTWORK_PREVIEW_SIZE 150
static struct album *__artwork_cur_album = NULL;
static unsigned int __artwork_timeo_id = 0;
static cairo_surface_t *__artwork_scale_pixbuf(GdkPixbuf *pix)
{
int old_h = gdk_pixbuf_get_height(pix);
int old_w = gdk_pixbuf_get_width(pix);
int new_h = gui_builder_widget_height("o_position") +
gui_builder_widget_height("o_tags");
int new_w = (old_w * new_h) / old_h;
int scale = gtk_widget_get_scale_factor(gui_builder_widget("o_cover"));
cairo_surface_t *orig = gdk_cairo_surface_create_from_pixbuf(pix, 0,
NULL);
cairo_content_t content = cairo_surface_get_content(orig);
cairo_surface_t *new = cairo_surface_create_similar(orig, content,
new_w, new_h);
cairo_t *cairo = cairo_create(new);
cairo_scale(cairo, (double)(scale * new_w) / old_w,
(double)(scale * new_h) / old_h);
cairo_set_source_surface(cairo, orig, 0, 0);
cairo_paint(cairo);
cairo_destroy(cairo);
cairo_surface_destroy(orig);
return new;
}
static cairo_surface_t *__artwork_get_surface(struct track *track)
{
gchar *path = album_artwork_path(track->tr_album);
cairo_surface_t *surface;
GdkPixbuf *pix;
if (!path)
return NULL;
pix = gdk_pixbuf_new_from_file(path, NULL);
if (!pix)
return NULL;
surface = __artwork_scale_pixbuf(pix);
g_object_unref(G_OBJECT(pix));
g_free(path);
return surface;
}
static bool __artwork_set_pixbuf(void)
{
GtkImage *cover = GTK_IMAGE(gui_builder_widget("o_cover"));
struct track *track = audio_cur_track();
cairo_surface_t *surface;
if (!track || track->tr_album == __artwork_cur_album)
return true;
surface = __artwork_get_surface(track);
if (surface) {
gtk_image_set_from_surface(cover, surface);
cairo_surface_destroy(surface);
} else
gtk_image_set_from_icon_name(cover, "image-missing", GTK_ICON_SIZE_DIALOG);
gtk_widget_set_sensitive(GTK_WIDGET(cover), surface != NULL);
__artwork_cur_album = surface ? track->tr_album : NULL;
return (surface != NULL);
}
static gboolean __artwork_timeout(gpointer data)
{
if (__artwork_set_pixbuf()) {
__artwork_timeo_id = 0;
return G_SOURCE_REMOVE;
}
return G_SOURCE_CONTINUE;
}
void gui_artwork_set_cover(void)
{
if (!__artwork_set_pixbuf() && __artwork_timeo_id == 0)
__artwork_timeo_id = g_timeout_add(2000, __artwork_timeout, NULL);
}
void __artwork_update_preview(GtkFileChooser *chooser, gpointer data)
{
GtkWidget *preview = gtk_file_chooser_get_preview_widget(chooser);
gchar *path = gtk_file_chooser_get_preview_filename(chooser);
GdkPixbuf *pix = gdk_pixbuf_new_from_file(path, NULL);
unsigned int old_w, scale;
cairo_surface_t *surface;
if (pix) {
old_w = gdk_pixbuf_get_width(pix);
scale = old_w / ARTWORK_PREVIEW_SIZE;
surface = gdk_cairo_surface_create_from_pixbuf(pix, scale, NULL);
if (surface) {
gtk_image_set_from_surface(GTK_IMAGE(preview), surface);
cairo_surface_destroy(surface);
}
}
g_free(path);
}
void __artwork_select_cover(GtkButton *button)
{
struct track *track = audio_cur_track();
GtkFileFilter *filter;
GtkWidget *dialog;
GtkWidget *preview;
gchar *path;
if (!track)
return;
filter = gtk_file_filter_new();
preview = gtk_image_new_from_icon_name("", GTK_ICON_SIZE_DIALOG);
dialog = gtk_file_chooser_dialog_new("Choose an image",
GTK_WINDOW(gui_builder_widget("o_window")),
GTK_FILE_CHOOSER_ACTION_OPEN,
_("_Cancel"), GTK_RESPONSE_CANCEL,
_("_Open"), GTK_RESPONSE_ACCEPT,
NULL);
gtk_file_filter_add_mime_type(filter, "image/*");
gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(dialog), filter);
gtk_file_chooser_set_show_hidden(GTK_FILE_CHOOSER(dialog), true);
gtk_file_chooser_set_preview_widget(GTK_FILE_CHOOSER(dialog), preview);
gtk_file_chooser_set_use_preview_label(GTK_FILE_CHOOSER(dialog), false);
g_signal_connect(dialog, "update-preview", (GCallback)__artwork_update_preview, NULL);
if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
path = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
album_artwork_import(track->tr_album, path);
__artwork_cur_album = NULL;
gui_artwork_set_cover();
g_free(path);
}
gtk_widget_destroy(dialog);
}