/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* eel-labeled-image.c - A labeled image. Copyright (C) 2000 Eazel, Inc. The Mate Library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The Mate Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with the Mate Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. Authors: Ramiro Estrugo */ #include #include "eel-labeled-image.h" #include "eel-art-extensions.h" #include "eel-art-gtk-extensions.h" #include "eel-gtk-container.h" #include "eel-gtk-extensions.h" #include "eel-accessibility.h" #include #include #include #include #define DEFAULT_SPACING 0 #define DEFAULT_X_PADDING 0 #define DEFAULT_Y_PADDING 0 #define DEFAULT_X_ALIGNMENT 0.5 #define DEFAULT_Y_ALIGNMENT 0.5 /* Signals */ enum { ACTIVATE, LAST_SIGNAL }; /* Arguments */ enum { PROP_0, PROP_FILL, PROP_LABEL, PROP_LABEL_POSITION, PROP_PIXBUF, PROP_SHOW_IMAGE, PROP_SHOW_LABEL, PROP_SPACING, PROP_X_ALIGNMENT, PROP_X_PADDING, PROP_Y_ALIGNMENT, PROP_Y_PADDING }; /* Detail member struct */ struct EelLabeledImagePrivate { GtkWidget *image; GtkWidget *label; GtkPositionType label_position; gboolean show_label; gboolean show_image; guint spacing; float x_alignment; float y_alignment; int x_padding; int y_padding; int fixed_image_height; gboolean fill; }; /* derived types so we can add our accessibility interfaces */ static GType eel_labeled_image_button_get_type (void); static GType eel_labeled_image_check_button_get_type (void); static GType eel_labeled_image_radio_button_get_type (void); static GType eel_labeled_image_toggle_button_get_type (void); /* GtkWidgetClass methods */ static GType eel_labeled_image_accessible_get_type (void); /* Private EelLabeledImage methods */ static EelDimensions labeled_image_get_image_dimensions (const EelLabeledImage *labeled_image); static EelDimensions labeled_image_get_label_dimensions (const EelLabeledImage *labeled_image); static void labeled_image_ensure_label (EelLabeledImage *labeled_image); static void labeled_image_ensure_image (EelLabeledImage *labeled_image); static EelIRect labeled_image_get_content_bounds (const EelLabeledImage *labeled_image); static EelDimensions labeled_image_get_content_dimensions (const EelLabeledImage *labeled_image); static void labeled_image_update_alignments (EelLabeledImage *labeled_image); static gboolean labeled_image_show_label (const EelLabeledImage *labeled_image); static gboolean labeled_image_show_image (const EelLabeledImage *labeled_image); static guint labeled_image_signals[LAST_SIGNAL] = { 0 }; G_DEFINE_TYPE_WITH_PRIVATE (EelLabeledImage, eel_labeled_image, GTK_TYPE_CONTAINER) static void eel_labeled_image_init (EelLabeledImage *labeled_image) { gtk_widget_set_has_window (GTK_WIDGET (labeled_image), FALSE); labeled_image->details = eel_labeled_image_get_instance_private (labeled_image); labeled_image->details->show_label = TRUE; labeled_image->details->show_image = TRUE; labeled_image->details->label_position = GTK_POS_BOTTOM; labeled_image->details->spacing = DEFAULT_SPACING; labeled_image->details->x_padding = DEFAULT_X_PADDING; labeled_image->details->y_padding = DEFAULT_Y_PADDING; labeled_image->details->x_alignment = DEFAULT_X_ALIGNMENT; labeled_image->details->y_alignment = DEFAULT_Y_ALIGNMENT; labeled_image->details->fixed_image_height = 0; eel_labeled_image_set_fill (labeled_image, FALSE); } static void eel_labeled_image_destroy (GtkWidget *object) { EelLabeledImage *labeled_image; labeled_image = EEL_LABELED_IMAGE (object); if (labeled_image->details->image != NULL) { gtk_widget_destroy (labeled_image->details->image); } if (labeled_image->details->label != NULL) { gtk_widget_destroy (labeled_image->details->label); } GTK_WIDGET_CLASS (eel_labeled_image_parent_class)->destroy (object); } /* GObjectClass methods */ static void eel_labeled_image_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) { EelLabeledImage *labeled_image; g_assert (EEL_IS_LABELED_IMAGE (object)); labeled_image = EEL_LABELED_IMAGE (object); switch (property_id) { case PROP_PIXBUF: eel_labeled_image_set_pixbuf (labeled_image, g_value_get_object (value)); break; case PROP_LABEL: eel_labeled_image_set_text (labeled_image, g_value_get_string (value)); break; case PROP_LABEL_POSITION: eel_labeled_image_set_label_position (labeled_image, g_value_get_enum (value)); break; case PROP_SHOW_LABEL: eel_labeled_image_set_show_label (labeled_image, g_value_get_boolean (value)); break; case PROP_SHOW_IMAGE: eel_labeled_image_set_show_image (labeled_image, g_value_get_boolean (value)); break; case PROP_SPACING: eel_labeled_image_set_spacing (labeled_image, g_value_get_uint (value)); break; case PROP_X_PADDING: eel_labeled_image_set_x_padding (labeled_image, g_value_get_int (value)); break; case PROP_Y_PADDING: eel_labeled_image_set_y_padding (labeled_image, g_value_get_int (value)); break; case PROP_X_ALIGNMENT: eel_labeled_image_set_x_alignment (labeled_image, g_value_get_float (value)); break; case PROP_Y_ALIGNMENT: eel_labeled_image_set_y_alignment (labeled_image, g_value_get_float (value)); break; case PROP_FILL: eel_labeled_image_set_fill (labeled_image, g_value_get_boolean (value)); break; default: g_assert_not_reached (); } } static void eel_labeled_image_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec) { EelLabeledImage *labeled_image; g_assert (EEL_IS_LABELED_IMAGE (object)); labeled_image = EEL_LABELED_IMAGE (object); switch (property_id) { case PROP_LABEL: if (labeled_image->details->label == NULL) { g_value_set_string (value, NULL); } else { g_value_set_string (value, gtk_label_get_text (GTK_LABEL ( labeled_image->details->label))); } break; case PROP_LABEL_POSITION: g_value_set_enum (value, eel_labeled_image_get_label_position (labeled_image)); break; case PROP_SHOW_LABEL: g_value_set_boolean (value, eel_labeled_image_get_show_label (labeled_image)); break; case PROP_SHOW_IMAGE: g_value_set_boolean (value, eel_labeled_image_get_show_image (labeled_image)); break; case PROP_SPACING: g_value_set_uint (value, eel_labeled_image_get_spacing (labeled_image)); break; case PROP_X_PADDING: g_value_set_int (value, eel_labeled_image_get_x_padding (labeled_image)); break; case PROP_Y_PADDING: g_value_set_int (value, eel_labeled_image_get_y_padding (labeled_image)); break; case PROP_X_ALIGNMENT: g_value_set_float (value, eel_labeled_image_get_x_alignment (labeled_image)); break; case PROP_Y_ALIGNMENT: g_value_set_float (value, eel_labeled_image_get_y_alignment (labeled_image)); break; case PROP_FILL: g_value_set_boolean (value, eel_labeled_image_get_fill (labeled_image)); break; default: g_assert_not_reached (); } } /* GtkWidgetClass methods */ static void eel_labeled_image_size_request (GtkWidget *widget, GtkRequisition *requisition) { EelLabeledImage *labeled_image; EelDimensions content_dimensions; g_assert (EEL_IS_LABELED_IMAGE (widget)); g_assert (requisition != NULL); labeled_image = EEL_LABELED_IMAGE (widget); content_dimensions = labeled_image_get_content_dimensions (labeled_image); requisition->width = MAX (1, content_dimensions.width) + 2 * labeled_image->details->x_padding; requisition->height = MAX (1, content_dimensions.height) + 2 * labeled_image->details->y_padding; } static void eel_labeled_image_get_preferred_width (GtkWidget *widget, gint *minimum_width, gint *natural_width) { GtkRequisition req; eel_labeled_image_size_request (widget, &req); *minimum_width = *natural_width = req.width; } static void eel_labeled_image_get_preferred_height (GtkWidget *widget, gint *minimum_height, gint *natural_height) { GtkRequisition req; eel_labeled_image_size_request (widget, &req); *minimum_height = *natural_height = req.height; } static void eel_labeled_image_size_allocate (GtkWidget *widget, GtkAllocation *allocation) { EelLabeledImage *labeled_image; EelIRect image_bounds; EelIRect label_bounds; g_assert (EEL_IS_LABELED_IMAGE (widget)); g_assert (allocation != NULL); labeled_image = EEL_LABELED_IMAGE (widget); gtk_widget_set_allocation (widget, allocation); label_bounds = eel_labeled_image_get_label_bounds (labeled_image); eel_gtk_container_child_size_allocate (GTK_CONTAINER (widget), labeled_image->details->label, label_bounds); image_bounds = eel_labeled_image_get_image_bounds (labeled_image); eel_gtk_container_child_size_allocate (GTK_CONTAINER (widget), labeled_image->details->image, image_bounds); } static int eel_labeled_image_draw (GtkWidget *widget, cairo_t *cr) { EelLabeledImage *labeled_image; EelIRect label_bounds; GtkStyleContext *context; g_assert (EEL_IS_LABELED_IMAGE (widget)); g_assert (gtk_widget_get_realized (widget)); labeled_image = EEL_LABELED_IMAGE (widget); context = gtk_widget_get_style_context (widget); gtk_style_context_save (context); if (gtk_widget_get_state_flags (widget) == GTK_STATE_FLAG_SELECTED || gtk_widget_get_state_flags (widget) == GTK_STATE_FLAG_ACTIVE) { label_bounds = eel_labeled_image_get_label_bounds (EEL_LABELED_IMAGE (widget)); gtk_widget_get_state_flags (widget); gtk_render_background (context, cr, label_bounds.x0, label_bounds.y0, label_bounds.x1 - label_bounds.x0, label_bounds.y1 - label_bounds.y0); gtk_render_frame (context, cr, label_bounds.x0, label_bounds.y0, label_bounds.x1 - label_bounds.x0, label_bounds.y1 - label_bounds.y0); } if (labeled_image_show_label (labeled_image)) { eel_gtk_container_child_expose_event (GTK_CONTAINER (widget), labeled_image->details->label, cr); } if (labeled_image_show_image (labeled_image)) { eel_gtk_container_child_expose_event (GTK_CONTAINER (widget), labeled_image->details->image, cr); } if (gtk_widget_has_focus (widget)) { label_bounds = eel_labeled_image_get_image_bounds (EEL_LABELED_IMAGE (widget)); gtk_widget_set_state_flags (widget, GTK_STATE_FLAG_NORMAL, TRUE); gtk_render_focus (context, cr, label_bounds.x0, label_bounds.y0, label_bounds.x1 - label_bounds.x0, label_bounds.y1 - label_bounds.y0); } gtk_style_context_restore (context); return FALSE; } static void eel_labeled_image_map (GtkWidget *widget) { EelLabeledImage *labeled_image; g_assert (EEL_IS_LABELED_IMAGE (widget)); labeled_image = EEL_LABELED_IMAGE (widget); gtk_widget_set_mapped (widget, TRUE); if (labeled_image_show_label (labeled_image)) { eel_gtk_container_child_map (GTK_CONTAINER (widget), labeled_image->details->label); } if (labeled_image_show_image (labeled_image)) { eel_gtk_container_child_map (GTK_CONTAINER (widget), labeled_image->details->image); } } static void eel_labeled_image_unmap (GtkWidget *widget) { EelLabeledImage *labeled_image; g_assert (EEL_IS_LABELED_IMAGE (widget)); labeled_image = EEL_LABELED_IMAGE (widget); gtk_widget_set_mapped (widget, FALSE); eel_gtk_container_child_unmap (GTK_CONTAINER (widget), labeled_image->details->label); eel_gtk_container_child_unmap (GTK_CONTAINER (widget), labeled_image->details->image); } /* GtkContainerClass methods */ static void eel_labeled_image_add (GtkContainer *container, GtkWidget *child) { g_assert (GTK_IS_LABEL (child) || GTK_IS_IMAGE (child)); eel_gtk_container_child_add (container, child); } static void eel_labeled_image_remove (GtkContainer *container, GtkWidget *child) { EelLabeledImage *labeled_image; g_assert (GTK_IS_LABEL (child) || GTK_IS_IMAGE (child)); labeled_image = EEL_LABELED_IMAGE (container);; g_assert (child == labeled_image->details->image || child == labeled_image->details->label); eel_gtk_container_child_remove (container, child); if (labeled_image->details->image == child) { labeled_image->details->image = NULL; } if (labeled_image->details->label == child) { labeled_image->details->label = NULL; } } static void eel_labeled_image_forall (GtkContainer *container, gboolean include_internals, GtkCallback callback, gpointer callback_data) { EelLabeledImage *labeled_image; g_assert (EEL_IS_LABELED_IMAGE (container)); g_assert (callback != NULL); labeled_image = EEL_LABELED_IMAGE (container); if (include_internals) { if (labeled_image->details->image != NULL) { (* callback) (labeled_image->details->image, callback_data); } if (labeled_image->details->label != NULL) { (* callback) (labeled_image->details->label, callback_data); } } } /* Class init methods */ static void eel_labeled_image_class_init (EelLabeledImageClass *labeled_image_class) { GObjectClass *gobject_class = G_OBJECT_CLASS (labeled_image_class); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (labeled_image_class); GtkContainerClass *container_class = GTK_CONTAINER_CLASS (labeled_image_class); GtkBindingSet *binding_set; /* GObjectClass */ gobject_class->set_property = eel_labeled_image_set_property; gobject_class->get_property = eel_labeled_image_get_property; widget_class->destroy = eel_labeled_image_destroy; /* GtkWidgetClass */ widget_class->size_allocate = eel_labeled_image_size_allocate; widget_class->get_preferred_width = eel_labeled_image_get_preferred_width; widget_class->get_preferred_height = eel_labeled_image_get_preferred_height; widget_class->draw = eel_labeled_image_draw; widget_class->map = eel_labeled_image_map; widget_class->unmap = eel_labeled_image_unmap; gtk_widget_class_set_accessible_type (widget_class, eel_labeled_image_accessible_get_type ()); /* GtkContainerClass */ container_class->add = eel_labeled_image_add; container_class->remove = eel_labeled_image_remove; container_class->forall = eel_labeled_image_forall; labeled_image_signals[ACTIVATE] = g_signal_new ("activate", G_TYPE_FROM_CLASS (labeled_image_class), G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (EelLabeledImageClass, activate), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); widget_class->activate_signal = labeled_image_signals[ACTIVATE]; binding_set = gtk_binding_set_by_class (gobject_class); gtk_binding_entry_add_signal (binding_set, GDK_KEY_Return, 0, "activate", 0); gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Enter, 0, "activate", 0); gtk_binding_entry_add_signal (binding_set, GDK_KEY_space, 0, "activate", 0); /* Properties */ g_object_class_install_property ( gobject_class, PROP_PIXBUF, g_param_spec_object ("pixbuf", NULL, NULL, GDK_TYPE_PIXBUF, G_PARAM_READWRITE)); g_object_class_install_property ( gobject_class, PROP_LABEL, g_param_spec_string ("label", NULL, NULL, "", G_PARAM_READWRITE)); g_object_class_install_property ( gobject_class, PROP_LABEL_POSITION, g_param_spec_enum ("label_position", NULL, NULL, GTK_TYPE_POSITION_TYPE, GTK_POS_BOTTOM, G_PARAM_READWRITE)); g_object_class_install_property ( gobject_class, PROP_SHOW_LABEL, g_param_spec_boolean ("show_label", NULL, NULL, TRUE, G_PARAM_READWRITE)); g_object_class_install_property ( gobject_class, PROP_SHOW_IMAGE, g_param_spec_boolean ("show_image", NULL, NULL, TRUE, G_PARAM_READWRITE)); g_object_class_install_property ( gobject_class, PROP_SPACING, g_param_spec_uint ("spacing", NULL, NULL, 0, G_MAXINT, DEFAULT_SPACING, G_PARAM_READWRITE)); g_object_class_install_property ( gobject_class, PROP_X_PADDING, g_param_spec_int ("x_padding", NULL, NULL, 0, G_MAXINT, DEFAULT_X_PADDING, G_PARAM_READWRITE)); g_object_class_install_property ( gobject_class, PROP_Y_PADDING, g_param_spec_int ("y_padding", NULL, NULL, 0, G_MAXINT, DEFAULT_Y_PADDING, G_PARAM_READWRITE)); g_object_class_install_property ( gobject_class, PROP_X_ALIGNMENT, g_param_spec_float ("x_alignment", NULL, NULL, 0.0, 1.0, DEFAULT_X_ALIGNMENT, G_PARAM_READWRITE)); g_object_class_install_property ( gobject_class, PROP_Y_ALIGNMENT, g_param_spec_float ("y_alignment", NULL, NULL, 0.0, 1.0, DEFAULT_Y_ALIGNMENT, G_PARAM_READWRITE)); g_object_class_install_property ( gobject_class, PROP_FILL, g_param_spec_boolean ("fill", NULL, NULL, FALSE, G_PARAM_READWRITE)); } /* Private EelLabeledImage methods */ static gboolean is_fixed_height (const EelLabeledImage *labeled_image) { return labeled_image->details->fixed_image_height > 0; } static EelDimensions labeled_image_get_image_dimensions (const EelLabeledImage *labeled_image) { EelDimensions image_dimensions; GtkRequisition image_requisition; g_assert (EEL_IS_LABELED_IMAGE (labeled_image)); if (!labeled_image_show_image (labeled_image)) { return eel_dimensions_empty; } gtk_widget_get_preferred_size (labeled_image->details->image, &image_requisition, NULL); image_dimensions.width = (int) image_requisition.width; image_dimensions.height = (int) image_requisition.height; if (is_fixed_height (labeled_image)) { image_dimensions.height = labeled_image->details->fixed_image_height; } return image_dimensions; } static EelDimensions labeled_image_get_label_dimensions (const EelLabeledImage *labeled_image) { EelDimensions label_dimensions; GtkRequisition label_requisition; g_assert (EEL_IS_LABELED_IMAGE (labeled_image)); if (!labeled_image_show_label (labeled_image)) { return eel_dimensions_empty; } gtk_widget_get_preferred_size (labeled_image->details->label, &label_requisition, NULL); label_dimensions.width = (int) label_requisition.width; label_dimensions.height = (int) label_requisition.height; return label_dimensions; } static EelIRect labeled_image_get_image_bounds_fill (const EelLabeledImage *labeled_image) { EelIRect image_bounds; EelDimensions image_dimensions; EelIRect content_bounds; EelIRect bounds; g_assert (EEL_IS_LABELED_IMAGE (labeled_image)); image_dimensions = labeled_image_get_image_dimensions (labeled_image); if (eel_dimensions_are_empty (image_dimensions)) { return eel_irect_empty; } content_bounds = labeled_image_get_content_bounds (labeled_image); bounds = eel_gtk_widget_get_bounds (GTK_WIDGET (labeled_image)); if (!labeled_image_show_label (labeled_image)) { image_bounds = bounds; } else { switch (labeled_image->details->label_position) { case GTK_POS_LEFT: image_bounds.y0 = bounds.y0; image_bounds.x0 = content_bounds.x1 - image_dimensions.width; image_bounds.y1 = bounds.y1; image_bounds.x1 = bounds.x1; break; case GTK_POS_RIGHT: image_bounds.y0 = bounds.y0; image_bounds.x0 = bounds.x0; image_bounds.y1 = bounds.y1; image_bounds.x1 = content_bounds.x0 + image_dimensions.width; break; case GTK_POS_TOP: image_bounds.x0 = bounds.x0; image_bounds.y0 = content_bounds.y1 - image_dimensions.height; image_bounds.x1 = bounds.x1; image_bounds.y1 = bounds.y1; break; case GTK_POS_BOTTOM: image_bounds.x0 = bounds.x0; image_bounds.y0 = bounds.y0; image_bounds.x1 = bounds.x1; image_bounds.y1 = content_bounds.y0 + image_dimensions.height; break; default: image_bounds.x0 = 0; image_bounds.y0 = 0; image_bounds.x1 = 0; image_bounds.y1 = 0; g_assert_not_reached (); } } return image_bounds; } EelIRect eel_labeled_image_get_image_bounds (const EelLabeledImage *labeled_image) { EelDimensions image_dimensions; EelDimensions label_dimensions; GtkRequisition image_requisition; EelIRect image_bounds; EelIRect content_bounds; g_return_val_if_fail (EEL_IS_LABELED_IMAGE (labeled_image), eel_irect_empty); if (labeled_image->details->fill) { return labeled_image_get_image_bounds_fill (labeled_image); } /* get true real dimensions if we're in fixed height mode */ if (is_fixed_height (labeled_image) && labeled_image_show_image (labeled_image)) { gtk_widget_get_preferred_size (labeled_image->details->image, &image_requisition, NULL); image_dimensions.width = (int) image_requisition.width; image_dimensions.height = (int) image_requisition.height; } else { image_dimensions = labeled_image_get_image_dimensions (labeled_image); } label_dimensions = labeled_image_get_label_dimensions (labeled_image); if (eel_dimensions_are_empty (image_dimensions)) { return eel_irect_empty; } content_bounds = labeled_image_get_content_bounds (labeled_image); if (!labeled_image_show_label (labeled_image)) { image_bounds.x0 = content_bounds.x0 + (eel_irect_get_width (content_bounds) - image_dimensions.width) / 2; image_bounds.y0 = content_bounds.y0 + (eel_irect_get_height (content_bounds) - image_dimensions.height) / 2; } else { switch (labeled_image->details->label_position) { case GTK_POS_LEFT: image_bounds.x0 = content_bounds.x1 - image_dimensions.width; image_bounds.y0 = content_bounds.y0 + (eel_irect_get_height (content_bounds) - image_dimensions.height) / 2; break; case GTK_POS_RIGHT: image_bounds.x0 = content_bounds.x0; image_bounds.y0 = content_bounds.y0 + (eel_irect_get_height (content_bounds) - image_dimensions.height) / 2; break; case GTK_POS_TOP: image_bounds.x0 = content_bounds.x0 + (eel_irect_get_width (content_bounds) - image_dimensions.width) / 2; image_bounds.y0 = content_bounds.y1 - image_dimensions.height; break; case GTK_POS_BOTTOM: image_bounds.x0 = content_bounds.x0 + (eel_irect_get_width (content_bounds) - image_dimensions.width) / 2; if (is_fixed_height (labeled_image)) { image_bounds.y0 = content_bounds.y0 + eel_irect_get_height (content_bounds) - image_dimensions.height - label_dimensions.height - labeled_image->details->spacing; } else { image_bounds.y0 = content_bounds.y0; } break; default: image_bounds.x0 = 0; image_bounds.y0 = 0; g_assert_not_reached (); } } image_bounds.x1 = image_bounds.x0 + image_dimensions.width; image_bounds.y1 = image_bounds.y0 + image_dimensions.height; return image_bounds; } static EelIRect labeled_image_get_label_bounds_fill (const EelLabeledImage *labeled_image) { EelIRect label_bounds; EelDimensions label_dimensions; EelIRect content_bounds; EelIRect bounds; g_assert (EEL_IS_LABELED_IMAGE (labeled_image)); label_dimensions = labeled_image_get_label_dimensions (labeled_image); if (eel_dimensions_are_empty (label_dimensions)) { return eel_irect_empty; } content_bounds = labeled_image_get_content_bounds (labeled_image); bounds = eel_gtk_widget_get_bounds (GTK_WIDGET (labeled_image)); /* Only the label is shown */ if (!labeled_image_show_image (labeled_image)) { label_bounds = bounds; /* Both label and image are shown */ } else { switch (labeled_image->details->label_position) { case GTK_POS_LEFT: label_bounds.y0 = bounds.y0; label_bounds.x0 = bounds.x0; label_bounds.y1 = bounds.y1; label_bounds.x1 = content_bounds.x0 + label_dimensions.width; break; case GTK_POS_RIGHT: label_bounds.y0 = bounds.y0; label_bounds.x0 = content_bounds.x1 - label_dimensions.width; label_bounds.y1 = bounds.y1; label_bounds.x1 = bounds.x1; break; case GTK_POS_TOP: label_bounds.x0 = bounds.x0; label_bounds.y0 = bounds.y0; label_bounds.x1 = bounds.x1; label_bounds.y1 = content_bounds.y0 + label_dimensions.height; break; case GTK_POS_BOTTOM: label_bounds.x0 = bounds.x0; label_bounds.y0 = content_bounds.y1 - label_dimensions.height; label_bounds.x1 = bounds.x1; label_bounds.y1 = bounds.y1; break; default: label_bounds.x0 = 0; label_bounds.y0 = 0; label_bounds.x1 = 0; label_bounds.y1 = 0; g_assert_not_reached (); } } return label_bounds; } EelIRect eel_labeled_image_get_label_bounds (const EelLabeledImage *labeled_image) { EelIRect label_bounds; EelDimensions label_dimensions; EelIRect content_bounds; g_return_val_if_fail (EEL_IS_LABELED_IMAGE (labeled_image), eel_irect_empty); if (labeled_image->details->fill) { return labeled_image_get_label_bounds_fill (labeled_image); } label_dimensions = labeled_image_get_label_dimensions (labeled_image); if (eel_dimensions_are_empty (label_dimensions)) { return eel_irect_empty; } content_bounds = labeled_image_get_content_bounds (labeled_image); /* Only the label is shown */ if (!labeled_image_show_image (labeled_image)) { label_bounds.x0 = content_bounds.x0 + (eel_irect_get_width (content_bounds) - label_dimensions.width) / 2; label_bounds.y0 = content_bounds.y0 + (eel_irect_get_height (content_bounds) - label_dimensions.height) / 2; /* Both label and image are shown */ } else { switch (labeled_image->details->label_position) { case GTK_POS_LEFT: label_bounds.x0 = content_bounds.x0; label_bounds.y0 = content_bounds.y0 + (eel_irect_get_height (content_bounds) - label_dimensions.height) / 2; break; case GTK_POS_RIGHT: label_bounds.x0 = content_bounds.x1 - label_dimensions.width; label_bounds.y0 = content_bounds.y0 + (eel_irect_get_height (content_bounds) - label_dimensions.height) / 2; break; case GTK_POS_TOP: label_bounds.x0 = content_bounds.x0 + (eel_irect_get_width (content_bounds) - label_dimensions.width) / 2; label_bounds.y0 = content_bounds.y0; break; case GTK_POS_BOTTOM: label_bounds.x0 = content_bounds.x0 + (eel_irect_get_width (content_bounds) - label_dimensions.width) / 2; label_bounds.y0 = content_bounds.y1 - label_dimensions.height; break; default: label_bounds.x0 = 0; label_bounds.y0 = 0; g_assert_not_reached (); } } label_bounds.x1 = label_bounds.x0 + label_dimensions.width; label_bounds.y1 = label_bounds.y0 + label_dimensions.height; return label_bounds; } static void labeled_image_update_alignments (EelLabeledImage *labeled_image) { g_assert (EEL_IS_LABELED_IMAGE (labeled_image)); if (labeled_image->details->label != NULL) { if (labeled_image->details->fill) { float x_alignment; float y_alignment; x_alignment = gtk_label_get_xalign (GTK_LABEL (labeled_image->details->label)); y_alignment = gtk_label_get_yalign (GTK_LABEL (labeled_image->details->label)); /* Only the label is shown */ if (!labeled_image_show_image (labeled_image)) { x_alignment = 0.5; y_alignment = 0.5; /* Both label and image are shown */ } else { switch (labeled_image->details->label_position) { case GTK_POS_LEFT: x_alignment = 1.0; y_alignment = 0.5; break; case GTK_POS_RIGHT: x_alignment = 0.0; y_alignment = 0.5; break; case GTK_POS_TOP: x_alignment = 0.5; y_alignment = 1.0; break; case GTK_POS_BOTTOM: x_alignment = 0.5; y_alignment = 0.0; break; } } gtk_label_set_xalign (GTK_LABEL (labeled_image->details->label), x_alignment); gtk_label_set_yalign (GTK_LABEL (labeled_image->details->label), y_alignment); } } if (labeled_image->details->image != NULL) { if (labeled_image->details->fill) { float x_alignment; float y_alignment; x_alignment = gtk_widget_get_halign (labeled_image->details->image); y_alignment = gtk_widget_get_valign (labeled_image->details->image); /* Only the image is shown */ if (!labeled_image_show_label (labeled_image)) { x_alignment = 0.5; y_alignment = 0.5; /* Both label and image are shown */ } else { switch (labeled_image->details->label_position) { case GTK_POS_LEFT: x_alignment = 0.0; y_alignment = 0.5; break; case GTK_POS_RIGHT: x_alignment = 1.0; y_alignment = 0.5; break; case GTK_POS_TOP: x_alignment = 0.5; y_alignment = 0.0; break; case GTK_POS_BOTTOM: x_alignment = 0.5; y_alignment = 1.0; break; } } gtk_widget_set_halign (labeled_image->details->image, x_alignment); gtk_widget_set_valign (labeled_image->details->image, y_alignment); } } } static EelDimensions labeled_image_get_content_dimensions (const EelLabeledImage *labeled_image) { EelDimensions image_dimensions; EelDimensions label_dimensions; EelDimensions content_dimensions; g_assert (EEL_IS_LABELED_IMAGE (labeled_image)); image_dimensions = labeled_image_get_image_dimensions (labeled_image); label_dimensions = labeled_image_get_label_dimensions (labeled_image); content_dimensions = eel_dimensions_empty; /* Both shown */ if (!eel_dimensions_are_empty (image_dimensions) && !eel_dimensions_are_empty (label_dimensions)) { content_dimensions.width = image_dimensions.width + labeled_image->details->spacing + label_dimensions.width; switch (labeled_image->details->label_position) { case GTK_POS_LEFT: case GTK_POS_RIGHT: content_dimensions.width = image_dimensions.width + labeled_image->details->spacing + label_dimensions.width; content_dimensions.height = MAX (image_dimensions.height, label_dimensions.height); break; case GTK_POS_TOP: case GTK_POS_BOTTOM: content_dimensions.width = MAX (image_dimensions.width, label_dimensions.width); content_dimensions.height = image_dimensions.height + labeled_image->details->spacing + label_dimensions.height; break; } /* Only image shown */ } else if (!eel_dimensions_are_empty (image_dimensions)) { content_dimensions.width = image_dimensions.width; content_dimensions.height = image_dimensions.height; /* Only label shown */ } else { content_dimensions.width = label_dimensions.width; content_dimensions.height = label_dimensions.height; } return content_dimensions; } static EelIRect labeled_image_get_content_bounds (const EelLabeledImage *labeled_image) { EelDimensions content_dimensions; EelIRect content_bounds; EelIRect bounds; g_assert (EEL_IS_LABELED_IMAGE (labeled_image)); bounds = eel_gtk_widget_get_bounds (GTK_WIDGET (labeled_image)); content_dimensions = labeled_image_get_content_dimensions (labeled_image); content_bounds = eel_irect_align (bounds, content_dimensions.width, content_dimensions.height, labeled_image->details->x_alignment, labeled_image->details->y_alignment); return content_bounds; } static void labeled_image_ensure_label (EelLabeledImage *labeled_image) { g_assert (EEL_IS_LABELED_IMAGE (labeled_image)); if (labeled_image->details->label != NULL) { return; } labeled_image->details->label = gtk_label_new (NULL); gtk_container_add (GTK_CONTAINER (labeled_image), labeled_image->details->label); gtk_widget_show (labeled_image->details->label); } static void labeled_image_ensure_image (EelLabeledImage *labeled_image) { g_assert (EEL_IS_LABELED_IMAGE (labeled_image)); if (labeled_image->details->image != NULL) { return; } labeled_image->details->image = gtk_image_new (); gtk_container_add (GTK_CONTAINER (labeled_image), labeled_image->details->image); gtk_widget_show (labeled_image->details->image); } static gboolean labeled_image_show_image (const EelLabeledImage *labeled_image) { g_assert (EEL_IS_LABELED_IMAGE (labeled_image)); return labeled_image->details->image != NULL && labeled_image->details->show_image; } static gboolean labeled_image_show_label (const EelLabeledImage *labeled_image) { g_assert (EEL_IS_LABELED_IMAGE (labeled_image)); return labeled_image->details->label != NULL && labeled_image->details->show_label; } /** * eel_labeled_image_new: * @text: Text to use for label or NULL. * @pixbuf: Pixbuf to use for image or NULL. * * Returns A newly allocated EelLabeledImage. If the &text parameter is not * NULL then the LabeledImage will show a label. If the &pixbuf parameter is not * NULL then the LabeledImage will show a pixbuf. Either of these can be NULL at * creation time. * * Later in the lifetime of the widget you can invoke methods that affect the * label and/or the image. If at creation time these were NULL, then they will * be created as neeeded. * * Thus, using this widget in place of EelImage or EelLabel is "free" with * only the GtkWidget and function call overhead. * */ GtkWidget* eel_labeled_image_new (const char *text, GdkPixbuf *pixbuf) { EelLabeledImage *labeled_image; labeled_image = EEL_LABELED_IMAGE (gtk_widget_new (eel_labeled_image_get_type (), NULL)); if (text != NULL) { eel_labeled_image_set_text (labeled_image, text); } if (pixbuf != NULL) { eel_labeled_image_set_pixbuf (labeled_image, pixbuf); } labeled_image_update_alignments (labeled_image); return GTK_WIDGET (labeled_image); } /** * eel_labeled_image_new_from_file_name: * @text: Text to use for label or NULL. * @file_name: File name of picture to use for pixbuf. Cannot be NULL. * * Returns A newly allocated EelLabeledImage. If the &text parameter is not * NULL then the LabeledImage will show a label. * */ GtkWidget* eel_labeled_image_new_from_file_name (const char *text, const char *pixbuf_file_name) { EelLabeledImage *labeled_image; g_return_val_if_fail (pixbuf_file_name != NULL, NULL); labeled_image = EEL_LABELED_IMAGE (eel_labeled_image_new (text, NULL)); eel_labeled_image_set_pixbuf_from_file_name (labeled_image, pixbuf_file_name); return GTK_WIDGET (labeled_image); } /** * eel_labeled_image_set_label_position: * @labeled_image: A EelLabeledImage. * @label_position: The position of the label with respect to the image. * * Set the position of the label with respect to the image as follows: * * GTK_POS_LEFT: * [