Skip to content

Commit

Permalink
picture: Add content-fit property
Browse files Browse the repository at this point in the history
It allows to specify the resize mode of the paintable inside the
GtkPicture allocation. This also deprecates the keep-aspect-ratio
property.

Fixes #5027.
  • Loading branch information
melix99 committed Jul 15, 2022
1 parent 7743f35 commit d8a73cb
Show file tree
Hide file tree
Showing 26 changed files with 192 additions and 45 deletions.
2 changes: 1 addition & 1 deletion demos/gtk-demo/sliding_puzzle.c
Original file line number Diff line number Diff line change
Expand Up @@ -330,7 +330,7 @@ start_puzzle (GdkPaintable *paintable)
x, y,
width, height);
picture = gtk_picture_new_for_paintable (piece);
gtk_picture_set_keep_aspect_ratio (GTK_PICTURE (picture), FALSE);
gtk_picture_set_content_fit (GTK_PICTURE (picture), GTK_CONTENT_FIT_FILL);
gtk_grid_attach (GTK_GRID (grid),
picture,
x, y,
Expand Down
1 change: 0 additions & 1 deletion demos/node-editor/node-editor-window.ui
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,6 @@
<child>
<object class="GtkPicture" id="picture">
<property name="can-shrink">0</property>
<property name="keep-aspect-ratio">1</property>
<property name="halign">center</property>
<property name="valign">center</property>
<child>
Expand Down
2 changes: 2 additions & 0 deletions demos/widget-factory/widget-factory.ui
Original file line number Diff line number Diff line change
Expand Up @@ -1265,6 +1265,8 @@ Suspendisse feugiat quam quis dolor accumsan cursus.</property>
<property name="child">
<object class="GtkPicture">
<property name="file">resource:///org/gtk/WidgetFactory4/sunset.jpg</property>
<property name="content-fit">cover</property>
<property name="overflow">hidden</property>
<child>
<object class="GtkDragSource">
<signal name="prepare" handler="on_picture_drag_prepare" swapped="no"/>
Expand Down
30 changes: 30 additions & 0 deletions gtk/gtkenums.h
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,36 @@ typedef enum
GTK_BASELINE_POSITION_BOTTOM
} GtkBaselinePosition;

/**
* GtkContentFit:
* @GTK_CONTENT_FIT_FILL: Make the content fill the entire allocation,
* without taking its aspect ratio in consideration. The resulting
* content will appear as stretched if its aspect ratio is different
* from the allocation aspect ratio.
* @GTK_CONTENT_FIT_CONTAIN: Scale the content to fit the allocation,
* while taking its aspect ratio in consideration. The resulting
* content will appear as letterboxed if its aspect ratio is different
* from the allocation aspect ratio.
* @GTK_CONTENT_FIT_COVER: Cover the entire allocation, while taking
* the content aspect ratio in consideration. This can result in an overflow
* if the content aspect ratio is different from the allocation aspect ratio.
* For this reason, you may also want to set [[email protected]:overflow]
* to %GTK_OVERFLOW_HIDDEN.
* @GTK_CONTENT_FIT_SCALE_DOWN: The content is scaled down to fit the
* allocation, if needed, otherwise its original size is used.
*
* Controls how a content should be made to fit inside an allocation.
*
* Since: 4.8
*/
typedef enum
{
GTK_CONTENT_FIT_FILL,
GTK_CONTENT_FIT_CONTAIN,
GTK_CONTENT_FIT_COVER,
GTK_CONTENT_FIT_SCALE_DOWN,
} GtkContentFit;

/**
* GtkDeleteType:
* @GTK_DELETE_CHARS: Delete characters.
Expand Down
152 changes: 131 additions & 21 deletions gtk/gtkpicture.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#include "gtkintl.h"
#include "gtkprivate.h"
#include "gtksnapshot.h"
#include "gtktypebuiltins.h"
#include "gtkwidgetprivate.h"
#include "gdkpixbufutilsprivate.h"

Expand Down Expand Up @@ -89,6 +90,7 @@ enum
PROP_ALTERNATIVE_TEXT,
PROP_KEEP_ASPECT_RATIO,
PROP_CAN_SHRINK,
PROP_CONTENT_FIT,
NUM_PROPERTIES
};

Expand All @@ -100,8 +102,8 @@ struct _GtkPicture
GFile *file;

char *alternative_text;
guint keep_aspect_ratio : 1;
guint can_shrink : 1;
GtkContentFit content_fit;
};

struct _GtkPictureClass
Expand Down Expand Up @@ -129,23 +131,47 @@ gtk_picture_snapshot (GtkWidget *widget,
height = gtk_widget_get_height (widget);
ratio = gdk_paintable_get_intrinsic_aspect_ratio (self->paintable);

if (!self->keep_aspect_ratio || ratio == 0)
if (self->content_fit == GTK_CONTENT_FIT_FILL || ratio == 0)
{
gdk_paintable_snapshot (self->paintable, snapshot, width, height);
}
else
{
double picture_ratio = (double) width / height;
int paintable_width = gdk_paintable_get_intrinsic_width (self->paintable);
int paintable_height = gdk_paintable_get_intrinsic_height (self->paintable);

if (ratio > picture_ratio)
if (self->content_fit == GTK_CONTENT_FIT_SCALE_DOWN &&
width >= paintable_width && height >= paintable_height)
{
w = width;
h = width / ratio;
w = paintable_width;
h = paintable_height;
}
else if (ratio > picture_ratio)
{
if (self->content_fit == GTK_CONTENT_FIT_COVER)
{
w = height * ratio;
h = height;
}
else
{
w = width;
h = width / ratio;
}
}
else
{
w = height * ratio;
h = height;
if (self->content_fit == GTK_CONTENT_FIT_COVER)
{
w = width;
h = width / ratio;
}
else
{
w = height * ratio;
h = height;
}
}

x = (width - ceil (w)) / 2;
Expand Down Expand Up @@ -246,13 +272,19 @@ gtk_picture_set_property (GObject *object,
break;

case PROP_KEEP_ASPECT_RATIO:
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
gtk_picture_set_keep_aspect_ratio (self, g_value_get_boolean (value));
G_GNUC_END_IGNORE_DEPRECATIONS
break;

case PROP_CAN_SHRINK:
gtk_picture_set_can_shrink (self, g_value_get_boolean (value));
break;

case PROP_CONTENT_FIT:
gtk_picture_set_content_fit (self, g_value_get_enum (value));
break;

default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
Expand Down Expand Up @@ -282,13 +314,19 @@ gtk_picture_get_property (GObject *object,
break;

case PROP_KEEP_ASPECT_RATIO:
g_value_set_boolean (value, self->keep_aspect_ratio);
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
g_value_set_boolean (value, gtk_picture_get_keep_aspect_ratio (self));
G_GNUC_END_IGNORE_DEPRECATIONS
break;

case PROP_CAN_SHRINK:
g_value_set_boolean (value, self->can_shrink);
break;

case PROP_CONTENT_FIT:
g_value_set_enum (value, self->content_fit);
break;

default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
Expand Down Expand Up @@ -394,11 +432,15 @@ gtk_picture_class_init (GtkPictureClass *class)
*
* Whether the GtkPicture will render its contents trying to preserve the aspect
* ratio.
*
* Deprecated: 4.8: Use [[email protected]:content-fit] instead.
*/
properties[PROP_KEEP_ASPECT_RATIO] =
g_param_spec_boolean ("keep-aspect-ratio", NULL, NULL,
TRUE,
GTK_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
GTK_PARAM_READWRITE |
G_PARAM_EXPLICIT_NOTIFY |
G_PARAM_DEPRECATED);

/**
* GtkPicture:can-shrink: (attributes org.gtk.Property.get=gtk_picture_get_can_shrink org.gtk.Property.set=gtk_picture_set_can_shrink)
Expand All @@ -410,6 +452,17 @@ gtk_picture_class_init (GtkPictureClass *class)
TRUE,
GTK_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);

/**
* GtkPicture:content-fit: (attributes org.gtk.Property.get=gtk_picture_get_content_fit org.gtk.Property.set=gtk_picture_set_content_fit)
*
* How the content should be resized to fit inside the `GtkPicture`.
*/
properties[PROP_CONTENT_FIT] =
g_param_spec_enum ("content-fit", NULL, NULL,
GTK_TYPE_CONTENT_FIT,
GTK_CONTENT_FIT_CONTAIN,
GTK_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);

g_object_class_install_properties (gobject_class, NUM_PROPERTIES, properties);

gtk_widget_class_set_css_name (widget_class, I_("picture"));
Expand All @@ -420,7 +473,7 @@ static void
gtk_picture_init (GtkPicture *self)
{
self->can_shrink = TRUE;
self->keep_aspect_ratio = TRUE;
self->content_fit = GTK_CONTENT_FIT_CONTAIN;
}

/**
Expand Down Expand Up @@ -827,21 +880,20 @@ gtk_picture_get_paintable (GtkPicture *self)
*
* If set to %FALSE or if the contents provide no aspect ratio,
* the contents will be stretched over the picture's whole area.
*
* Deprecated: 4.8: Use [[email protected]_content_fit] instead. If still
* used, this method will always set the [[email protected]:content-fit]
* property to `GTK_CONTENT_FIT_CONTAIN` if @keep_aspect_ratio is true,
* otherwise it will set it to `GTK_CONTENT_FIT_FILL`.
*/
void
gtk_picture_set_keep_aspect_ratio (GtkPicture *self,
gboolean keep_aspect_ratio)
{
g_return_if_fail (GTK_IS_PICTURE (self));

if (self->keep_aspect_ratio == keep_aspect_ratio)
return;

self->keep_aspect_ratio = keep_aspect_ratio;

gtk_widget_queue_draw (GTK_WIDGET (self));

g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_KEEP_ASPECT_RATIO]);
if (keep_aspect_ratio)
gtk_picture_set_content_fit (self, GTK_CONTENT_FIT_CONTAIN);
else
gtk_picture_set_content_fit (self, GTK_CONTENT_FIT_FILL);
}

/**
Expand All @@ -851,13 +903,17 @@ gtk_picture_set_keep_aspect_ratio (GtkPicture *self,
* Returns whether the `GtkPicture` preserves its contents aspect ratio.
*
* Returns: %TRUE if the self tries to keep the contents' aspect ratio
*
* Deprecated: 4.8: Use [[email protected]_content_fit] instead. This will
* now return `FALSE` only if [[email protected]:content-fit] is
* `GTK_CONTENT_FIT_FILL`. Returns `TRUE` otherwise.
*/
gboolean
gtk_picture_get_keep_aspect_ratio (GtkPicture *self)
{
g_return_val_if_fail (GTK_IS_PICTURE (self), TRUE);

return self->keep_aspect_ratio;
return self->content_fit != GTK_CONTENT_FIT_FILL;
}

/**
Expand Down Expand Up @@ -908,6 +964,60 @@ gtk_picture_get_can_shrink (GtkPicture *self)
return self->can_shrink;
}

/**
* gtk_picture_set_content_fit: (attributes org.gtk.Method.set_property=content-fit)
* @self: a `GtkPicture`
* @content_fit: the content fit mode
*
* Sets how the content should be resized to fit the `GtkPicture`.
*
* See [[email protected]] for details.
*
* If you use `GTK_CONTENT_FIT_COVER`, you may also want to set the
* [[email protected]:overflow] to `GTK_OVERFLOW_HIDDEN`, otherwise the
* paintable will overflow the widget allocation if the aspect ratio of the
* paintable is different from the one of the `GtkPicture` allocation.
*/
void
gtk_picture_set_content_fit (GtkPicture *self,
GtkContentFit content_fit)
{
g_return_if_fail (GTK_IS_PICTURE (self));

if (self->content_fit == content_fit)
return;

gboolean notify_keep_aspect_ratio = (content_fit == GTK_CONTENT_FIT_FILL ||
self->content_fit == GTK_CONTENT_FIT_FILL);

self->content_fit = content_fit;

gtk_widget_queue_draw (GTK_WIDGET (self));

g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_CONTENT_FIT]);

if (notify_keep_aspect_ratio)
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_KEEP_ASPECT_RATIO]);
}

/**
* gtk_picture_get_content_fit: (attributes org.gtk.Method.get_property=content-fit)
* @self: a `GtkPicture`
*
* Returns the fit mode for the content of the `GtkPicture`.
*
* See [[email protected]] for details.
*
* Returns: the content fit mode
*/
GtkContentFit
gtk_picture_get_content_fit (GtkPicture *self)
{
g_return_val_if_fail (GTK_IS_PICTURE (self), FALSE);

return self->content_fit;
}

/**
* gtk_picture_set_alternative_text: (attributes org.gtk.Method.set_property=alternative-text)
* @self: a `GtkPicture`
Expand Down
10 changes: 8 additions & 2 deletions gtk/gtkpicture.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,17 +69,23 @@ GDK_AVAILABLE_IN_ALL
void gtk_picture_set_pixbuf (GtkPicture *self,
GdkPixbuf *pixbuf);

GDK_AVAILABLE_IN_ALL
GDK_DEPRECATED_IN_4_8_FOR(gtk_picture_set_fit_mode)
void gtk_picture_set_keep_aspect_ratio (GtkPicture *self,
gboolean keep_aspect_ratio);
GDK_AVAILABLE_IN_ALL
GDK_DEPRECATED_IN_4_8_FOR(gtk_picture_get_fit_mode)
gboolean gtk_picture_get_keep_aspect_ratio (GtkPicture *self);
GDK_AVAILABLE_IN_ALL
void gtk_picture_set_can_shrink (GtkPicture *self,
gboolean can_shrink);
GDK_AVAILABLE_IN_ALL
gboolean gtk_picture_get_can_shrink (GtkPicture *self);

GDK_AVAILABLE_IN_4_8
void gtk_picture_set_content_fit (GtkPicture *self,
GtkContentFit content_fit);
GDK_AVAILABLE_IN_4_8
GtkContentFit gtk_picture_get_content_fit (GtkPicture *self);

GDK_AVAILABLE_IN_ALL
void gtk_picture_set_alternative_text (GtkPicture *self,
const char *alternative_text);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
<child type="overlay">
<object class="GtkPicture">
<property name="paintable">green-100x100.png</property>
<property name="keep-aspect-ratio">0</property>
<property name="content-fit">fill</property>
<property name="can-shrink">1</property>
<property name="halign">center</property>
<property name="valign">center</property>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<child>
<object class="GtkPicture">
<property name="paintable">green-100x100.png</property>
<property name="keep-aspect-ratio">0</property>
<property name="content-fit">fill</property>
<property name="can-shrink">1</property>
<property name="halign">center</property>
<property name="valign">center</property>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
<child type="overlay">
<object class="GtkPicture">
<property name="paintable">green-100x100.png</property>
<property name="keep-aspect-ratio">0</property>
<property name="content-fit">fill</property>
<property name="can-shrink">1</property>
<property name="halign">center</property>
<property name="valign">center</property>
Expand Down
Loading

0 comments on commit d8a73cb

Please sign in to comment.