diff options
author | Benjamin Otte <otte@redhat.com> | 2018-03-15 18:10:01 +0100 |
---|---|---|
committer | Benjamin Otte <otte@redhat.com> | 2018-03-16 06:04:45 +0100 |
commit | c6541853ab6cd593733ab310119fbd95056b32fe (patch) | |
tree | fea61c173419b1f2526a66afa733cd3bd6b56ed0 | |
parent | 0a08c0388587500930a684d3bcf7d26d7dc7bd52 (diff) | |
download | gtk+-c6541853ab6cd593733ab310119fbd95056b32fe.tar.gz |
image: Add gtk_image_set_keep_aspect_ratio()
If set, the image will draw its contents while keeping their aspect
ratio. That means empty areas show up on the top/bottom or left/right.
Also move the special-case snapshotting code for icons to
GtkIconHelper. That's where it belongs.
-rw-r--r-- | docs/reference/gtk/gtk4-sections.txt | 2 | ||||
-rw-r--r-- | gtk/gtkiconhelper.c | 40 | ||||
-rw-r--r-- | gtk/gtkimage.c | 98 | ||||
-rw-r--r-- | gtk/gtkimage.h | 5 |
4 files changed, 132 insertions, 13 deletions
diff --git a/docs/reference/gtk/gtk4-sections.txt b/docs/reference/gtk/gtk4-sections.txt index a653a7558a..9bfaf9bad5 100644 --- a/docs/reference/gtk/gtk4-sections.txt +++ b/docs/reference/gtk/gtk4-sections.txt @@ -1505,6 +1505,8 @@ gtk_image_set_pixel_size gtk_image_get_pixel_size gtk_image_set_icon_size gtk_image_get_icon_size +gtk_image_set_keep_aspect_ratio +gtk_image_get_keep_aspect_ratio <SUBSECTION Standard> GTK_IMAGE GTK_IS_IMAGE diff --git a/gtk/gtkiconhelper.c b/gtk/gtkiconhelper.c index 5a38f2aea2..c9aff693b6 100644 --- a/gtk/gtkiconhelper.c +++ b/gtk/gtkiconhelper.c @@ -249,11 +249,41 @@ gtk_icon_helper_paintable_snapshot (GdkPaintable *paintable, if (self->paintable == NULL) return; - gtk_css_style_snapshot_icon_paintable (style, - snapshot, - self->paintable, - width, height, - self->texture_is_symbolic); + switch (gtk_image_definition_get_storage_type (self->def)) + { + case GTK_IMAGE_ICON_NAME: + case GTK_IMAGE_GICON: + { + double x, y, w, h; + + /* Never scale up icons. */ + w = gdk_paintable_get_intrinsic_width (self->paintable); + h = gdk_paintable_get_intrinsic_height (self->paintable); + w = MIN (w, width); + h = MIN (h, height); + x = (width - w) / 2; + y = (height - h) / 2; + gtk_snapshot_offset (snapshot, x, y); + gtk_css_style_snapshot_icon_paintable (style, + snapshot, + self->paintable, + w, h, + self->texture_is_symbolic); + gtk_snapshot_offset (snapshot, -x, -y); + } + break; + + case GTK_IMAGE_TEXTURE: + case GTK_IMAGE_PAINTABLE: + case GTK_IMAGE_EMPTY: + default: + gtk_css_style_snapshot_icon_paintable (style, + snapshot, + self->paintable, + width, height, + self->texture_is_symbolic); + break; + } } static GdkPaintable * diff --git a/gtk/gtkimage.c b/gtk/gtkimage.c index 2d4d5a0dbb..3d31eb3242 100644 --- a/gtk/gtkimage.c +++ b/gtk/gtkimage.c @@ -86,6 +86,8 @@ struct _GtkImagePrivate gchar *filename; /* Only used with GTK_IMAGE_SURFACE */ gchar *resource_path; /* Only used with GTK_IMAGE_SURFACE */ + + guint keep_aspect_ratio : 1; }; @@ -129,6 +131,7 @@ enum PROP_GICON, PROP_RESOURCE, PROP_USE_FALLBACK, + PROP_KEEP_ASPECT_RATIO, NUM_PROPERTIES }; @@ -261,6 +264,19 @@ gtk_image_class_init (GtkImageClass *class) FALSE, GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY); + /** + * GtkImage:keep-aspect-ratio: + * + * Whether the GtkImage will render its contents trying to preserve the aspect + * ratio of the contents. + */ + image_props[PROP_KEEP_ASPECT_RATIO] = + g_param_spec_boolean ("keep-aspect-ratio", + P_("Keep aspect ratio"), + P_("Render contents respecting the aspect ratio"), + TRUE, + GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY); + g_object_class_install_properties (gobject_class, NUM_PROPERTIES, image_props); gtk_widget_class_set_accessible_type (widget_class, GTK_TYPE_IMAGE_ACCESSIBLE); @@ -277,6 +293,7 @@ gtk_image_init (GtkImage *image) gtk_widget_set_has_window (GTK_WIDGET (image), FALSE); priv->icon_helper = gtk_icon_helper_new (widget_node, GTK_WIDGET (image)); + priv->keep_aspect_ratio = TRUE; } static void @@ -336,6 +353,10 @@ gtk_image_set_property (GObject *object, g_object_notify_by_pspec (object, pspec); break; + case PROP_KEEP_ASPECT_RATIO: + gtk_image_set_keep_aspect_ratio (image, g_value_get_boolean (value)); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -380,6 +401,9 @@ gtk_image_get_property (GObject *object, case PROP_USE_FALLBACK: g_value_set_boolean (value, _gtk_icon_helper_get_use_fallback (priv->icon_helper)); break; + case PROP_KEEP_ASPECT_RATIO: + g_value_set_boolean (value, priv->keep_aspect_ratio); + break; case PROP_STORAGE_TYPE: g_value_set_enum (value, _gtk_icon_helper_get_storage_type (priv->icon_helper)); break; @@ -1203,27 +1227,40 @@ gtk_image_snapshot (GtkWidget *widget, { GtkImage *image = GTK_IMAGE (widget); GtkImagePrivate *priv = gtk_image_get_instance_private (image); - int x, y, width, height; - gint w, h, baseline; + double ratio; + int x, y, width, height, baseline; + double w, h; width = gtk_widget_get_width (widget); height = gtk_widget_get_height (widget); + ratio = gdk_paintable_get_intrinsic_aspect_ratio (GDK_PAINTABLE (priv->icon_helper)); - if (_gtk_icon_helper_get_storage_type (priv->icon_helper) == GTK_IMAGE_PAINTABLE) + if (!priv->keep_aspect_ratio || ratio == 0) { gdk_paintable_snapshot (GDK_PAINTABLE (priv->icon_helper), snapshot, width, height); } else { - _gtk_icon_helper_get_size (priv->icon_helper, &w, &h); - x = (width - w) / 2; + double image_ratio = (double) width / height; - baseline = gtk_widget_get_allocated_baseline (widget); + if (ratio > image_ratio) + { + w = width; + h = width / ratio; + } + else + { + w = height * ratio; + h = height; + } + x = (width - ceil (w)) / 2; + + baseline = gtk_widget_get_allocated_baseline (widget); if (baseline == -1) - y = floor(height - h) / 2; + y = floor(height - ceil (h)) / 2; else - y = CLAMP (baseline - h * gtk_image_get_baseline_align (image), 0, height - h); + y = CLAMP (baseline - h * gtk_image_get_baseline_align (image), 0, height - ceil (h)); gtk_snapshot_offset (snapshot, x, y); gdk_paintable_snapshot (GDK_PAINTABLE (priv->icon_helper), snapshot, w, h); @@ -1463,6 +1500,51 @@ gtk_image_get_icon_size (GtkImage *image) return priv->icon_size; } +/** + * gtk_image_set_keep_aspect_ratio: + * @image: a #GtkImage + * @keep_aspect_ratio: whether to keep aspect ratio + * + * If set to %TRUE, the @image will render its contents according to + * their aspect ratio. That means that empty space may show up at the + * top/bottom or left/right of @image. + * + * If set to %FALSE or if the contents provide no aspect ratio, the + * contents will be stretched over the image's whole area. + */ +void +gtk_image_set_keep_aspect_ratio (GtkImage *image, + gboolean keep_aspect_ratio) +{ + GtkImagePrivate *priv = gtk_image_get_instance_private (image); + + g_return_if_fail (GTK_IS_IMAGE (image)); + + if (priv->keep_aspect_ratio == keep_aspect_ratio) + return; + + priv->keep_aspect_ratio = keep_aspect_ratio; + g_object_notify_by_pspec (G_OBJECT (image), image_props[PROP_KEEP_ASPECT_RATIO]); +} + +/** + * gtk_image_get_keep_aspect_ratio: + * @image: a #GtkImage + * + * Gets the value set via gtk_image_set_keep_aspect_ratio(). + * + * Returns: %TRUE if the image tries to keep the contents' aspect ratio + **/ +gboolean +gtk_image_get_keep_aspect_ratio (GtkImage *image) +{ + GtkImagePrivate *priv = gtk_image_get_instance_private (image); + + g_return_val_if_fail (GTK_IS_IMAGE (image), TRUE); + + return priv->keep_aspect_ratio; +} + void gtk_image_get_image_size (GtkImage *image, int *width, diff --git a/gtk/gtkimage.h b/gtk/gtkimage.h index f4390fab18..d9fa533136 100644 --- a/gtk/gtkimage.h +++ b/gtk/gtkimage.h @@ -148,6 +148,9 @@ void gtk_image_set_pixel_size (GtkImage *image, GDK_AVAILABLE_IN_ALL void gtk_image_set_icon_size (GtkImage *image, GtkIconSize icon_size); +GDK_AVAILABLE_IN_ALL +void gtk_image_set_keep_aspect_ratio (GtkImage *image, + gboolean keep_aspect_ratio); GDK_AVAILABLE_IN_ALL GtkImageType gtk_image_get_storage_type (GtkImage *image); @@ -165,6 +168,8 @@ GDK_AVAILABLE_IN_ALL gint gtk_image_get_pixel_size (GtkImage *image); GDK_AVAILABLE_IN_ALL GtkIconSize gtk_image_get_icon_size (GtkImage *image); +GDK_AVAILABLE_IN_ALL +gboolean gtk_image_get_keep_aspect_ratio (GtkImage *image); G_END_DECLS |