Add zooming to fit width/height if larger
Also, mildly refactor get_surface_dimensions().
This commit is contained in:
parent
33851295d8
commit
ad29013e44
14
fastiv.c
14
fastiv.c
|
@ -119,6 +119,8 @@ static struct key_section help_keys[] = {
|
||||||
{"1...9", "Set zoom to N:1"},
|
{"1...9", "Set zoom to N:1"},
|
||||||
{"plus <control>plus", "Zoom in"},
|
{"plus <control>plus", "Zoom in"},
|
||||||
{"minus <control>minus", "Zoom out"},
|
{"minus <control>minus", "Zoom out"},
|
||||||
|
{"w", "Zoom to fit width if larger"},
|
||||||
|
{"h", "Zoom to fit height if larger"},
|
||||||
{}
|
{}
|
||||||
}},
|
}},
|
||||||
{"Orientation", (struct key[]) {
|
{"Orientation", (struct key[]) {
|
||||||
|
@ -127,6 +129,12 @@ static struct key_section help_keys[] = {
|
||||||
{"greater", "Rotate clockwise"},
|
{"greater", "Rotate clockwise"},
|
||||||
{}
|
{}
|
||||||
}},
|
}},
|
||||||
|
{"Configuration", (struct key[]) {
|
||||||
|
{"x", "Toggle scale to fit if larger"},
|
||||||
|
{"i", "Toggle smooth scaling"},
|
||||||
|
{"t", "Toggle transparency highlighting"},
|
||||||
|
{}
|
||||||
|
}},
|
||||||
{"Control", (struct key[]) {
|
{"Control", (struct key[]) {
|
||||||
{"bracketleft", "Previous page"},
|
{"bracketleft", "Previous page"},
|
||||||
{"bracketright", "Next page"},
|
{"bracketright", "Next page"},
|
||||||
|
@ -135,12 +143,6 @@ static struct key_section help_keys[] = {
|
||||||
{"space", "Toggle playback"},
|
{"space", "Toggle playback"},
|
||||||
{}
|
{}
|
||||||
}},
|
}},
|
||||||
{"Configuration", (struct key[]) {
|
|
||||||
{"x", "Toggle scale to fit"},
|
|
||||||
{"i", "Toggle smooth scaling"},
|
|
||||||
{"t", "Toggle transparency highlighting"},
|
|
||||||
{}
|
|
||||||
}},
|
|
||||||
{"Tools", (struct key[]) {
|
{"Tools", (struct key[]) {
|
||||||
{"<control>p", "Print..."},
|
{"<control>p", "Print..."},
|
||||||
{"<control>s", "Save page as..."},
|
{"<control>s", "Save page as..."},
|
||||||
|
|
89
fiv-view.c
89
fiv-view.c
|
@ -50,6 +50,10 @@ struct _FivView {
|
||||||
|
|
||||||
G_DEFINE_TYPE(FivView, fiv_view, GTK_TYPE_WIDGET)
|
G_DEFINE_TYPE(FivView, fiv_view, GTK_TYPE_WIDGET)
|
||||||
|
|
||||||
|
struct size {
|
||||||
|
double width, height;
|
||||||
|
};
|
||||||
|
|
||||||
static FivIoOrientation view_left[9] = {
|
static FivIoOrientation view_left[9] = {
|
||||||
[FivIoOrientationUnknown] = FivIoOrientationUnknown,
|
[FivIoOrientationUnknown] = FivIoOrientationUnknown,
|
||||||
[FivIoOrientation0] = FivIoOrientation270,
|
[FivIoOrientation0] = FivIoOrientation270,
|
||||||
|
@ -174,12 +178,11 @@ fiv_view_set_property(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static struct size
|
||||||
get_surface_dimensions(FivView *self, double *width, double *height)
|
get_surface_dimensions(FivView *self)
|
||||||
{
|
{
|
||||||
*width = *height = 0;
|
|
||||||
if (!self->image)
|
if (!self->image)
|
||||||
return;
|
return (struct size) {};
|
||||||
|
|
||||||
cairo_rectangle_t extents = {};
|
cairo_rectangle_t extents = {};
|
||||||
switch (cairo_surface_get_type(self->page)) {
|
switch (cairo_surface_get_type(self->page)) {
|
||||||
|
@ -201,23 +204,18 @@ get_surface_dimensions(FivView *self, double *width, double *height)
|
||||||
case FivIoOrientationMirror90:
|
case FivIoOrientationMirror90:
|
||||||
case FivIoOrientation270:
|
case FivIoOrientation270:
|
||||||
case FivIoOrientationMirror270:
|
case FivIoOrientationMirror270:
|
||||||
*width = extents.height;
|
return (struct size) {extents.height, extents.width};
|
||||||
*height = extents.width;
|
|
||||||
return;
|
|
||||||
default:
|
default:
|
||||||
*width = extents.width;
|
return (struct size) {extents.width, extents.height};
|
||||||
*height = extents.height;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
get_display_dimensions(FivView *self, int *width, int *height)
|
get_display_dimensions(FivView *self, int *width, int *height)
|
||||||
{
|
{
|
||||||
double w, h;
|
struct size surface_dimensions = get_surface_dimensions(self);
|
||||||
get_surface_dimensions(self, &w, &h);
|
*width = ceil(surface_dimensions.width * self->scale);
|
||||||
|
*height = ceil(surface_dimensions.height * self->scale);
|
||||||
*width = ceil(w * self->scale);
|
|
||||||
*height = ceil(h * self->scale);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static cairo_matrix_t
|
static cairo_matrix_t
|
||||||
|
@ -265,9 +263,7 @@ fiv_view_get_preferred_height(GtkWidget *widget, gint *minimum, gint *natural)
|
||||||
{
|
{
|
||||||
FivView *self = FIV_VIEW(widget);
|
FivView *self = FIV_VIEW(widget);
|
||||||
if (self->scale_to_fit) {
|
if (self->scale_to_fit) {
|
||||||
double sw, sh;
|
*natural = ceil(get_surface_dimensions(self).height);
|
||||||
get_surface_dimensions(self, &sw, &sh);
|
|
||||||
*natural = ceil(sh);
|
|
||||||
*minimum = 1;
|
*minimum = 1;
|
||||||
} else {
|
} else {
|
||||||
int dw, dh;
|
int dw, dh;
|
||||||
|
@ -281,9 +277,7 @@ fiv_view_get_preferred_width(GtkWidget *widget, gint *minimum, gint *natural)
|
||||||
{
|
{
|
||||||
FivView *self = FIV_VIEW(widget);
|
FivView *self = FIV_VIEW(widget);
|
||||||
if (self->scale_to_fit) {
|
if (self->scale_to_fit) {
|
||||||
double sw, sh;
|
*natural = ceil(get_surface_dimensions(self).width);
|
||||||
get_surface_dimensions(self, &sw, &sh);
|
|
||||||
*natural = ceil(sw);
|
|
||||||
*minimum = 1;
|
*minimum = 1;
|
||||||
} else {
|
} else {
|
||||||
int dw, dh;
|
int dw, dh;
|
||||||
|
@ -301,14 +295,13 @@ fiv_view_size_allocate(GtkWidget *widget, GtkAllocation *allocation)
|
||||||
if (!self->image || !self->scale_to_fit)
|
if (!self->image || !self->scale_to_fit)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
double w, h;
|
struct size surface_dimensions = get_surface_dimensions(self);
|
||||||
get_surface_dimensions(self, &w, &h);
|
|
||||||
|
|
||||||
self->scale = 1;
|
self->scale = 1;
|
||||||
if (ceil(w * self->scale) > allocation->width)
|
|
||||||
self->scale = allocation->width / w;
|
if (ceil(surface_dimensions.width * self->scale) > allocation->width)
|
||||||
if (ceil(h * self->scale) > allocation->height)
|
self->scale = allocation->width / surface_dimensions.width;
|
||||||
self->scale = allocation->height / h;
|
if (ceil(surface_dimensions.height * self->scale) > allocation->height)
|
||||||
|
self->scale = allocation->height / surface_dimensions.height;
|
||||||
g_object_notify_by_pspec(G_OBJECT(widget), view_properties[PROP_SCALE]);
|
g_object_notify_by_pspec(G_OBJECT(widget), view_properties[PROP_SCALE]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -376,9 +369,7 @@ fiv_view_draw(GtkWidget *widget, cairo_t *cr)
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
int w, h;
|
int w, h;
|
||||||
double sw, sh;
|
|
||||||
get_display_dimensions(self, &w, &h);
|
get_display_dimensions(self, &w, &h);
|
||||||
get_surface_dimensions(self, &sw, &sh);
|
|
||||||
|
|
||||||
double x = 0;
|
double x = 0;
|
||||||
double y = 0;
|
double y = 0;
|
||||||
|
@ -387,7 +378,9 @@ fiv_view_draw(GtkWidget *widget, cairo_t *cr)
|
||||||
if (h < allocation.height)
|
if (h < allocation.height)
|
||||||
y = round((allocation.height - h) / 2.);
|
y = round((allocation.height - h) / 2.);
|
||||||
|
|
||||||
cairo_matrix_t matrix = get_orientation_matrix(self->orientation, sw, sh);
|
struct size surface_dimensions = get_surface_dimensions(self);
|
||||||
|
cairo_matrix_t matrix = get_orientation_matrix(
|
||||||
|
self->orientation, surface_dimensions.width, surface_dimensions.height);
|
||||||
cairo_translate(cr, x, y);
|
cairo_translate(cr, x, y);
|
||||||
if (self->checkerboard) {
|
if (self->checkerboard) {
|
||||||
gtk_style_context_save(style);
|
gtk_style_context_save(style);
|
||||||
|
@ -478,6 +471,28 @@ set_scale(FivView *self, double scale)
|
||||||
return set_scale_to_fit(self, false);
|
return set_scale_to_fit(self, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
set_scale_to_fit_width(FivView *self)
|
||||||
|
{
|
||||||
|
double w = get_surface_dimensions(self).width;
|
||||||
|
int allocated = gtk_widget_get_allocated_width(
|
||||||
|
gtk_widget_get_parent(GTK_WIDGET(self)));
|
||||||
|
if (ceil(w * self->scale) > allocated)
|
||||||
|
return set_scale(self, allocated / w);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
set_scale_to_fit_height(FivView *self)
|
||||||
|
{
|
||||||
|
double h = get_surface_dimensions(self).height;
|
||||||
|
int allocated = gtk_widget_get_allocated_height(
|
||||||
|
gtk_widget_get_parent(GTK_WIDGET(self)));
|
||||||
|
if (ceil(h * self->scale) > allocated)
|
||||||
|
return set_scale(self, allocated / h);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
fiv_view_scroll_event(GtkWidget *widget, GdkEventScroll *event)
|
fiv_view_scroll_event(GtkWidget *widget, GdkEventScroll *event)
|
||||||
{
|
{
|
||||||
|
@ -649,12 +664,11 @@ static void
|
||||||
on_draw_page(G_GNUC_UNUSED GtkPrintOperation *operation,
|
on_draw_page(G_GNUC_UNUSED GtkPrintOperation *operation,
|
||||||
GtkPrintContext *context, G_GNUC_UNUSED int page_nr, FivView *self)
|
GtkPrintContext *context, G_GNUC_UNUSED int page_nr, FivView *self)
|
||||||
{
|
{
|
||||||
double surface_width_px = 0, surface_height_px = 0;
|
|
||||||
get_surface_dimensions(self, &surface_width_px, &surface_height_px);
|
|
||||||
|
|
||||||
// Any DPI will be wrong, unless we import that information from the image.
|
// Any DPI will be wrong, unless we import that information from the image.
|
||||||
double scale = 1 / 96.;
|
double scale = 1 / 96.;
|
||||||
double w = surface_width_px * scale, h = surface_height_px * scale;
|
struct size surface_dimensions = get_surface_dimensions(self);
|
||||||
|
double w = surface_dimensions.width * scale;
|
||||||
|
double h = surface_dimensions.height * scale;
|
||||||
|
|
||||||
// Scale down to fit the print area, taking care to not divide by zero.
|
// Scale down to fit the print area, taking care to not divide by zero.
|
||||||
double areaw = gtk_print_context_get_width(context);
|
double areaw = gtk_print_context_get_width(context);
|
||||||
|
@ -665,7 +679,7 @@ on_draw_page(G_GNUC_UNUSED GtkPrintOperation *operation,
|
||||||
cairo_scale(cr, scale, scale);
|
cairo_scale(cr, scale, scale);
|
||||||
cairo_set_source_surface(cr, self->frame, 0, 0);
|
cairo_set_source_surface(cr, self->frame, 0, 0);
|
||||||
cairo_matrix_t matrix = get_orientation_matrix(
|
cairo_matrix_t matrix = get_orientation_matrix(
|
||||||
self->orientation, surface_width_px, surface_height_px);
|
self->orientation, surface_dimensions.width, surface_dimensions.height);
|
||||||
cairo_pattern_set_matrix(cairo_get_source(cr), &matrix);
|
cairo_pattern_set_matrix(cairo_get_source(cr), &matrix);
|
||||||
cairo_paint(cr);
|
cairo_paint(cr);
|
||||||
}
|
}
|
||||||
|
@ -828,6 +842,11 @@ fiv_view_key_press_event(GtkWidget *widget, GdkEventKey *event)
|
||||||
case GDK_KEY_minus:
|
case GDK_KEY_minus:
|
||||||
return command(self, FIV_VIEW_COMMAND_ZOOM_OUT);
|
return command(self, FIV_VIEW_COMMAND_ZOOM_OUT);
|
||||||
|
|
||||||
|
case GDK_KEY_w:
|
||||||
|
return set_scale_to_fit_width(self);
|
||||||
|
case GDK_KEY_h:
|
||||||
|
return set_scale_to_fit_height(self);
|
||||||
|
|
||||||
case GDK_KEY_x: // Inspired by gThumb, which has more such modes.
|
case GDK_KEY_x: // Inspired by gThumb, which has more such modes.
|
||||||
return command(self, FIV_VIEW_COMMAND_TOGGLE_SCALE_TO_FIT);
|
return command(self, FIV_VIEW_COMMAND_TOGGLE_SCALE_TO_FIT);
|
||||||
case GDK_KEY_i:
|
case GDK_KEY_i:
|
||||||
|
|
Loading…
Reference in New Issue