summaryrefslogtreecommitdiffstats
path: root/gtk/src/preview.c
diff options
context:
space:
mode:
Diffstat (limited to 'gtk/src/preview.c')
-rw-r--r--gtk/src/preview.c423
1 files changed, 319 insertions, 104 deletions
diff --git a/gtk/src/preview.c b/gtk/src/preview.c
index 361a5e09d..a32ca8570 100644
--- a/gtk/src/preview.c
+++ b/gtk/src/preview.c
@@ -59,8 +59,11 @@ struct preview_s
gboolean progress_lock;
gint width;
gint height;
+ gint render_width;
+ gint render_height;
GtkWidget * view;
GdkPixbuf * pix;
+ GdkPixbuf * scaled_pix;
gint button_width;
gint button_height;
gint frame;
@@ -111,15 +114,30 @@ ghb_par_scale(signal_user_data_t *ud, gint *width, gint *height, gint par_n, gin
void
preview_set_size(signal_user_data_t *ud, int width, int height)
{
- GtkWidget *widget;
+ ud->preview->width = width;
+ ud->preview->height = height;
+}
+
+void
+preview_set_render_size(signal_user_data_t *ud, int width, int height)
+{
+ GtkWidget * widget;
+ GtkWindow * window;
+ GdkGeometry geo;
widget = GHB_WIDGET (ud->builder, "preview_image");
gtk_widget_set_size_request(widget, width, height);
- widget = GHB_WIDGET (ud->builder, "preview_hud_box");
- gtk_widget_set_size_request(widget, width, height);
-
- ud->preview->width = width;
- ud->preview->height = height;
+ window = GTK_WINDOW(GHB_WIDGET(ud->builder, "preview_window"));
+ gtk_window_unmaximize(window);
+ gtk_window_resize(window, width, height);
+ geo.min_aspect = (double)width / height;
+ geo.max_aspect = (double)width / height;
+ geo.width_inc = geo.height_inc = 2;
+ gtk_window_set_geometry_hints(window, NULL, &geo,
+ GDK_HINT_ASPECT|GDK_HINT_RESIZE_INC);
+
+ ud->preview->render_width = width;
+ ud->preview->render_height = height;
}
void
@@ -306,6 +324,7 @@ caps_set(GstCaps *caps, signal_user_data_t *ud)
else
height = gst_util_uint64_scale_int(width, den, num);
+ preview_set_size(ud, width, height);
if (ghb_dict_get_bool(ud->prefs, "reduce_hd_preview"))
{
GdkScreen *ss;
@@ -326,11 +345,6 @@ caps_set(GstCaps *caps, signal_user_data_t *ud)
width = gst_util_uint64_scale_int(height, num, den);
}
}
-
- if (width != ud->preview->width || height != ud->preview->height)
- {
- preview_set_size(ud, width, height);
- }
}
}
@@ -486,29 +500,51 @@ live_preview_cb(GstBus *bus, GstMessage *msg, gpointer data)
val = gst_structure_get_value(gstStruct, "pixbuf");
if (val != NULL)
{
- GdkPixbuf *pixbuf;
+ GdkPixbuf * pix;
GtkWidget *widget;
int width, height;
- pixbuf = GDK_PIXBUF(g_value_dup_object(val));
- width = gdk_pixbuf_get_width(pixbuf);
- height = gdk_pixbuf_get_height(pixbuf);
+ if (ud->preview->pix != NULL)
+ g_object_unref(ud->preview->pix);
+ if (ud->preview->scaled_pix != NULL)
+ g_object_unref(ud->preview->scaled_pix);
+ pix = GDK_PIXBUF(g_value_dup_object(val));
+ width = gdk_pixbuf_get_width(pix);
+ height = gdk_pixbuf_get_height(pix);
if (width != ud->preview->width ||
- height != ud->preview->height)
+ height != ud->preview->height ||
+ width != ud->preview->render_width ||
+ height != ud->preview->render_height)
{
- GdkPixbuf *tmp;
- tmp = gdk_pixbuf_scale_simple(pixbuf,
- ud->preview->width,
- ud->preview->height,
- GDK_INTERP_BILINEAR);
- g_object_unref(pixbuf);
- pixbuf = tmp;
+ double xscale, yscale;
+
+ xscale = (double)ud->preview->render_width /
+ ud->preview->width;
+ yscale = (double)ud->preview->render_height /
+ ud->preview->height;
+ if (xscale <= yscale)
+ {
+ width = ud->preview->render_width;
+ height = ud->preview->height * xscale;
+ }
+ else
+ {
+ width = ud->preview->width * yscale;
+ height = ud->preview->render_height;
+ }
+
+ ud->preview->scaled_pix =
+ gdk_pixbuf_scale_simple(pix,
+ width, height,
+ GDK_INTERP_BILINEAR);
+ g_object_ref(pix);
}
- if (ud->preview->pix != NULL)
+ else
{
- g_object_unref(ud->preview->pix);
+ ud->preview->scaled_pix = pix;
}
- ud->preview->pix = pixbuf;
+ ud->preview->pix = ud->preview->scaled_pix;
+ g_object_ref(ud->preview->pix);
widget = GHB_WIDGET (ud->builder, "preview_image");
gtk_widget_queue_draw(widget);
}
@@ -764,17 +800,119 @@ live_preview_seek_cb(GtkWidget *widget, signal_user_data_t *ud)
#endif
}
-static void _draw_pixbuf(cairo_t *cr, GdkPixbuf *pixbuf)
+static void _draw_pixbuf(signal_user_data_t * ud, cairo_t *cr, GdkPixbuf *pix)
{
- gdk_cairo_set_source_pixbuf(cr, pixbuf, 0, 0);
+ cairo_set_source_rgb(cr, 0, 0, 0);
+ cairo_rectangle(cr, 0, 0, ud->preview->render_width,
+ ud->preview->render_height);
+ cairo_fill(cr);
+ cairo_rectangle(cr, 0, 0, ud->preview->render_width,
+ ud->preview->render_height);
+ cairo_clip(cr);
+ gdk_cairo_set_source_pixbuf(cr, pix, 0, 0);
cairo_paint(cr);
}
+static void set_mini_preview_image(signal_user_data_t *ud, GdkPixbuf * pix)
+{
+ int preview_width, preview_height, width, height;
+ GdkPixbuf * scaled_preview;
+
+ if (pix == NULL)
+ {
+ return;
+ }
+
+ preview_width = gdk_pixbuf_get_width(pix);
+ preview_height = gdk_pixbuf_get_height(pix);
+
+ // Scale and display the mini-preview
+ height = MIN(ud->preview->button_height, 200);
+ width = preview_width * height / preview_height;
+ if (width > 400)
+ {
+ width = 400;
+ height = preview_height * width / preview_width;
+ }
+ if ((height >= 16) && (width >= 16))
+ {
+ scaled_preview = gdk_pixbuf_scale_simple(pix, width, height,
+ GDK_INTERP_NEAREST);
+ if (scaled_preview != NULL)
+ {
+ GtkWidget * widget;
+
+ widget = GHB_WIDGET (ud->builder, "preview_button_image");
+ gtk_image_set_from_pixbuf(GTK_IMAGE(widget), scaled_preview);
+ g_object_unref(scaled_preview);
+ }
+ }
+}
+
+GdkPixbuf * do_preview_scaling(signal_user_data_t *ud, GdkPixbuf *pix)
+{
+ int preview_width, preview_height, width, height;
+ GdkPixbuf * scaled_preview;
+
+ if (pix == NULL)
+ {
+ return NULL;
+ }
+
+ preview_width = gdk_pixbuf_get_width(pix);
+ preview_height = gdk_pixbuf_get_height(pix);
+
+ if (ud->preview->render_width < 0 || ud->preview->render_height < 0)
+ {
+ // resize preview window to fit preview
+ preview_set_render_size(ud, preview_width, preview_height);
+ g_object_ref(pix);
+ return pix;
+ }
+
+ // Scale if necessary
+ if (preview_width != ud->preview->render_width ||
+ preview_height != ud->preview->render_height)
+ {
+ double xscale, yscale;
+
+ xscale = (double)ud->preview->render_width / preview_width;
+ yscale = (double)ud->preview->render_height / preview_height;
+ if (xscale <= yscale)
+ {
+ width = ud->preview->render_width;
+ height = preview_height * xscale;
+ }
+ else
+ {
+ width = preview_width * yscale;
+ height = ud->preview->render_height;
+ }
+ // Allow some slop in aspect ratio so that we fill the window
+ int delta = ud->preview->render_width - width;
+ if (delta > 0 && delta <= 6)
+ width = ud->preview->render_width;
+
+ delta = ud->preview->render_height - height;
+ if (delta > 0 && delta <= 6)
+ height = ud->preview->render_height;
+
+ scaled_preview = gdk_pixbuf_scale_simple(pix, width, height,
+ GDK_INTERP_BILINEAR);
+ return scaled_preview;
+ }
+ else
+ {
+ g_object_ref(pix);
+ }
+ return pix;
+}
+
void
-ghb_set_preview_image(signal_user_data_t *ud)
+init_preview_image(signal_user_data_t *ud)
{
GtkWidget *widget;
- gint preview_width, preview_height, target_height, width, height;
+ gint width, height;
g_debug("set_preview_button_image ()");
gint title_id, titleindex;
@@ -806,47 +944,75 @@ ghb_set_preview_image(signal_user_data_t *ud)
}
if (ud->preview->pix != NULL)
g_object_unref(ud->preview->pix);
+ if (ud->preview->scaled_pix != NULL)
+ g_object_unref(ud->preview->scaled_pix);
- ud->preview->pix =
- ghb_get_preview_image(title, ud->preview->frame, ud, &width, &height);
- if (ud->preview->pix == NULL) return;
- preview_width = gdk_pixbuf_get_width(ud->preview->pix);
- preview_height = gdk_pixbuf_get_height(ud->preview->pix);
- widget = GHB_WIDGET (ud->builder, "preview_image");
- if (preview_width != ud->preview->width ||
- preview_height != ud->preview->height)
- {
- preview_set_size(ud, preview_width, preview_height);
- }
- gtk_widget_queue_draw(widget);
+ ud->preview->pix = ghb_get_preview_image(title, ud->preview->frame,
+ ud, &width, &height);
+ if (ud->preview->pix == NULL)
+ return;
+
+ int pix_width, pix_height;
+ pix_width = gdk_pixbuf_get_width(ud->preview->pix);
+ pix_height = gdk_pixbuf_get_height(ud->preview->pix);
+ preview_set_size(ud, pix_width, pix_height);
gchar *text = g_strdup_printf("%d x %d", width, height);
- widget = GHB_WIDGET (ud->builder, "preview_dims");
+ widget = GHB_WIDGET(ud->builder, "preview_dims");
gtk_label_set_text(GTK_LABEL(widget), text);
g_free(text);
+}
- g_debug("preview %d x %d", preview_width, preview_height);
- target_height = MIN(ud->preview->button_height, 200);
- height = target_height;
- width = preview_width * height / preview_height;
- if (width > 400)
- {
- width = 400;
- height = preview_height * width / preview_width;
- }
+void
+ghb_set_preview_image(signal_user_data_t *ud)
+{
+ init_preview_image(ud);
- if ((height >= 16) && (width >= 16))
- {
- GdkPixbuf *scaled_preview;
- scaled_preview = gdk_pixbuf_scale_simple (ud->preview->pix, width,
- height, GDK_INTERP_NEAREST);
- if (scaled_preview != NULL)
- {
- widget = GHB_WIDGET (ud->builder, "preview_button_image");
- gtk_image_set_from_pixbuf(GTK_IMAGE(widget), scaled_preview);
- g_object_unref(scaled_preview);
- }
- }
+ // Scale and display the mini-preview
+ set_mini_preview_image(ud, ud->preview->pix);
+
+ // Scale the full size preview
+ ud->preview->scaled_pix = do_preview_scaling(ud, ud->preview->pix);
+
+ // Display full size preview
+ GtkWidget *widget = GHB_WIDGET(ud->builder, "preview_image");
+ gtk_widget_queue_draw(widget);
+}
+
+void
+ghb_rescale_preview_image(signal_user_data_t *ud)
+{
+ double scale = (double)ud->preview->render_width / ud->preview->width;
+ init_preview_image(ud);
+ preview_set_render_size(ud, ud->preview->width * scale,
+ ud->preview->height * scale);
+
+ // Scale and display the mini-preview
+ set_mini_preview_image(ud, ud->preview->pix);
+
+ // Scale the full size preview
+ ud->preview->scaled_pix = do_preview_scaling(ud, ud->preview->pix);
+
+ // Display full size preview
+ GtkWidget *widget = GHB_WIDGET(ud->builder, "preview_image");
+ gtk_widget_queue_draw(widget);
+}
+
+void
+ghb_reset_preview_image(signal_user_data_t *ud)
+{
+ init_preview_image(ud);
+ preview_set_render_size(ud, ud->preview->width, ud->preview->height);
+
+ // Scale and display the mini-preview
+ set_mini_preview_image(ud, ud->preview->pix);
+
+ // Scale the full size preview
+ ud->preview->scaled_pix = do_preview_scaling(ud, ud->preview->pix);
+
+ // Display full size preview
+ GtkWidget *widget = GHB_WIDGET(ud->builder, "preview_image");
+ gtk_widget_queue_draw(widget);
}
G_MODULE_EXPORT gboolean
@@ -855,9 +1021,9 @@ preview_draw_cb(
cairo_t *cr,
signal_user_data_t *ud)
{
- if (ud->preview->pix != NULL)
+ if (ud->preview->scaled_pix != NULL)
{
- _draw_pixbuf(cr, ud->preview->pix);
+ _draw_pixbuf(ud, cr, ud->preview->scaled_pix);
}
return FALSE;
}
@@ -877,7 +1043,7 @@ preview_button_size_allocate_cb(GtkWidget *widget, GtkAllocation *allocation, si
ud->preview->button_height);
ud->preview->button_width = allocation->width;
ud->preview->button_height = allocation->height;
- ghb_set_preview_image(ud);
+ set_mini_preview_image(ud, ud->preview->pix);
}
void
@@ -896,7 +1062,6 @@ ghb_preview_set_visible(signal_user_data_t *ud)
title = ghb_lookup_title(title_id, &titleindex);
active &= title != NULL;
widget = GHB_WIDGET(ud->builder, "preview_window");
- gtk_widget_set_visible(widget, active);
if (active)
{
gint x, y;
@@ -904,7 +1069,9 @@ ghb_preview_set_visible(signal_user_data_t *ud)
y = ghb_dict_get_int(ud->prefs, "preview_y");
if (x >= 0 && y >= 0)
gtk_window_move(GTK_WINDOW(widget), x, y);
+ gtk_window_deiconify(GTK_WINDOW(widget));
}
+ gtk_widget_set_visible(widget, active);
}
static void
@@ -950,46 +1117,24 @@ preview_menu_toggled_cb(GtkWidget *xwidget, signal_user_data_t *ud)
gtk_toggle_tool_button_set_active(button, active);
}
-static gboolean
-go_full(signal_user_data_t *ud)
-{
- GtkWindow *window;
- window = GTK_WINDOW(GHB_WIDGET (ud->builder, "preview_window"));
- gtk_window_fullscreen(window);
- ghb_set_preview_image(ud);
- return FALSE;
-}
-
G_MODULE_EXPORT void
-fullscreen_clicked_cb(GtkWidget *toggle, signal_user_data_t *ud)
+preview_reset_clicked_cb(GtkWidget *toggle, signal_user_data_t *ud)
{
- gboolean active;
- GtkWindow *window;
+ g_debug("preview_reset_clicked_cb()");
+ preview_set_render_size(ud, ud->preview->width, ud->preview->height);
- g_debug("fullscreen_clicked_cb()");
- ghb_widget_to_setting (ud->prefs, toggle);
- ghb_check_dependency(ud, toggle, NULL);
- const gchar *name = ghb_get_setting_key(toggle);
- ghb_pref_save(ud->prefs, name);
+ // On windows, preview_resize_cb does not get called when the size
+ // is reset above. So assume it got reset and disable the
+ // "Source Resolution" button.
+ GtkWidget * widget = GHB_WIDGET(ud->builder, "preview_reset");
+ gtk_widget_hide(widget);
- window = GTK_WINDOW(GHB_WIDGET (ud->builder, "preview_window"));
- active = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(toggle));
- if (active)
- {
- gtk_window_set_resizable(window, TRUE);
- gtk_button_set_label(GTK_BUTTON(toggle), _("Windowed"));
- // Changing resizable property doesn't take effect immediately
- // need to delay fullscreen till after this callback returns
- // to mainloop
- g_idle_add((GSourceFunc)go_full, ud);
- }
- else
- {
- gtk_window_unfullscreen(window);
- gtk_window_set_resizable(window, FALSE);
- gtk_button_set_label(GTK_BUTTON(toggle), _("Fullscreen"));
- ghb_set_preview_image(ud);
- }
+ if (ud->preview->scaled_pix != NULL)
+ g_object_unref(ud->preview->scaled_pix);
+ ud->preview->scaled_pix = do_preview_scaling(ud, ud->preview->pix);
+
+ widget = GHB_WIDGET(ud->builder, "preview_image");
+ gtk_widget_queue_draw(widget);
}
G_MODULE_EXPORT void
@@ -1147,3 +1292,73 @@ preview_configure_cb(
return FALSE;
}
+G_MODULE_EXPORT gboolean
+preview_state_cb(
+ GtkWidget *widget,
+ GdkEvent *event,
+ signal_user_data_t *ud)
+{
+ GdkEventWindowState * wse = (GdkEventWindowState*)event;
+ if (wse->type == GDK_WINDOW_STATE)
+ {
+ // Look for transition to iconified state.
+ // Toggle "Show Preview" button when iconified.
+ // I only do this because there seems to be no
+ // way to reliably disable the iconfy button without
+ // also disabling the maximize button.
+ if (wse->changed_mask & wse->new_window_state &
+ GDK_WINDOW_STATE_ICONIFIED)
+ {
+ live_preview_stop(ud);
+ GtkWidget *widget = GHB_WIDGET(ud->builder, "show_preview");
+ gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(widget), FALSE);
+ }
+ }
+ return FALSE;
+}
+
+G_MODULE_EXPORT void
+preview_resize_cb(
+ GtkWidget *widget,
+ GdkRectangle *rect,
+ signal_user_data_t *ud)
+{
+ if (ud->preview->render_width != rect->width ||
+ ud->preview->render_height != rect->height)
+ {
+ ud->preview->render_width = rect->width;
+ ud->preview->render_height = rect->height;
+ if (ud->preview->scaled_pix != NULL)
+ g_object_unref(ud->preview->scaled_pix);
+ ud->preview->scaled_pix = do_preview_scaling(ud, ud->preview->pix);
+
+ GtkWidget *widget = GHB_WIDGET(ud->builder, "preview_image");
+ gtk_widget_queue_draw(widget);
+
+ if (ABS(ud->preview->render_width - ud->preview->width) <= 2 ||
+ ABS(ud->preview->render_height - ud->preview->height) <= 2)
+ {
+ GtkWidget * widget = GHB_WIDGET(ud->builder, "preview_reset");
+ gtk_widget_hide(widget);
+ }
+ else
+ {
+ GtkWidget * widget = GHB_WIDGET(ud->builder, "preview_reset");
+ gtk_widget_show(widget);
+ }
+ }
+}
+
+G_MODULE_EXPORT void
+show_crop_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
+{
+ g_debug("show_crop_changed_cb ()");
+ ghb_widget_to_setting(ud->prefs, widget);
+ ghb_check_dependency(ud, widget, NULL);
+ ghb_live_reset(ud);
+ if (gtk_widget_is_sensitive(widget))
+ ghb_set_scale(ud, GHB_PIC_KEEP_PAR);
+ ghb_pref_save(ud->prefs, "preview_show_crop");
+ ghb_rescale_preview_image(ud);
+}
+