X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=gtk%2Fgtkframe.c;h=e118823204405cc3a5ed87d93bf4ad9cdf5e78ae;hb=f35439bfacf90900e2c24f7ae3da173183c79d34;hp=04c622d70dbc482c2c80b756ef34cccd9be71e7c;hpb=fb48f5a356464ee613d206c843c4311023d73460;p=~andy%2Fgtk diff --git a/gtk/gtkframe.c b/gtk/gtkframe.c index 04c622d70..e11882320 100644 --- a/gtk/gtkframe.c +++ b/gtk/gtkframe.c @@ -2,297 +2,527 @@ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald * * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public + * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This 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. + * Lesser General Public License for more details. * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the Free - * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. */ + +/* + * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS + * file for a list of people on the GTK+ Team. See the ChangeLog + * files for a list of changes. These files are distributed with + * GTK+ at ftp://ftp.gtk.org/pub/gtk/. + */ + +#include #include #include "gtkframe.h" +#include "gtklabel.h" +#include "gtkprivate.h" +#include "gtkintl.h" +#include "gtkbuildable.h" +#include "gtkalias.h" + +#define LABEL_PAD 1 +#define LABEL_SIDE_PAD 2 enum { - ARG_0, - ARG_LABEL, - ARG_LABEL_XALIGN, - ARG_LABEL_YALIGN, - ARG_SHADOW + PROP_0, + PROP_LABEL, + PROP_LABEL_XALIGN, + PROP_LABEL_YALIGN, + PROP_SHADOW, + PROP_SHADOW_TYPE, + PROP_LABEL_WIDGET }; - -static void gtk_frame_class_init (GtkFrameClass *klass); -static void gtk_frame_init (GtkFrame *frame); -static void gtk_frame_set_arg (GtkFrame *frame, - GtkArg *arg, - guint arg_id); -static void gtk_frame_get_arg (GtkFrame *frame, - GtkArg *arg, - guint arg_id); -static void gtk_frame_destroy (GtkObject *object); +static void gtk_frame_set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec); +static void gtk_frame_get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec); static void gtk_frame_paint (GtkWidget *widget, GdkRectangle *area); -static void gtk_frame_draw (GtkWidget *widget, - GdkRectangle *area); static gint gtk_frame_expose (GtkWidget *widget, GdkEventExpose *event); static void gtk_frame_size_request (GtkWidget *widget, GtkRequisition *requisition); static void gtk_frame_size_allocate (GtkWidget *widget, GtkAllocation *allocation); - - -static GtkBinClass *parent_class = NULL; - - -guint -gtk_frame_get_type () -{ - static guint frame_type = 0; - - if (!frame_type) - { - GtkTypeInfo frame_info = - { - "GtkFrame", - sizeof (GtkFrame), - sizeof (GtkFrameClass), - (GtkClassInitFunc) gtk_frame_class_init, - (GtkObjectInitFunc) gtk_frame_init, - (GtkArgSetFunc) gtk_frame_set_arg, - (GtkArgGetFunc) gtk_frame_get_arg, - }; - - frame_type = gtk_type_unique (gtk_bin_get_type (), &frame_info); - } - - return frame_type; -} +static void gtk_frame_remove (GtkContainer *container, + GtkWidget *child); +static void gtk_frame_forall (GtkContainer *container, + gboolean include_internals, + GtkCallback callback, + gpointer callback_data); + +static void gtk_frame_compute_child_allocation (GtkFrame *frame, + GtkAllocation *child_allocation); +static void gtk_frame_real_compute_child_allocation (GtkFrame *frame, + GtkAllocation *child_allocation); + +/* GtkBuildable */ +static void gtk_frame_buildable_init (GtkBuildableIface *iface); +static void gtk_frame_buildable_add_child (GtkBuildable *buildable, + GtkBuilder *builder, + GObject *child, + const gchar *type); + +G_DEFINE_TYPE_WITH_CODE (GtkFrame, gtk_frame, GTK_TYPE_BIN, + G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE, + gtk_frame_buildable_init)) static void gtk_frame_class_init (GtkFrameClass *class) { - GtkObjectClass *object_class; + GObjectClass *gobject_class; GtkWidgetClass *widget_class; + GtkContainerClass *container_class; + + gobject_class = (GObjectClass*) class; + widget_class = GTK_WIDGET_CLASS (class); + container_class = GTK_CONTAINER_CLASS (class); + + gobject_class->set_property = gtk_frame_set_property; + gobject_class->get_property = gtk_frame_get_property; + + g_object_class_install_property (gobject_class, + PROP_LABEL, + g_param_spec_string ("label", + P_("Label"), + P_("Text of the frame's label"), + NULL, + GTK_PARAM_READABLE | + GTK_PARAM_WRITABLE)); + g_object_class_install_property (gobject_class, + PROP_LABEL_XALIGN, + g_param_spec_float ("label-xalign", + P_("Label xalign"), + P_("The horizontal alignment of the label"), + 0.0, + 1.0, + 0.0, + GTK_PARAM_READWRITE)); + g_object_class_install_property (gobject_class, + PROP_LABEL_YALIGN, + g_param_spec_float ("label-yalign", + P_("Label yalign"), + P_("The vertical alignment of the label"), + 0.0, + 1.0, + 0.5, + GTK_PARAM_READWRITE)); + g_object_class_install_property (gobject_class, + PROP_SHADOW, + g_param_spec_enum ("shadow", NULL, + P_("Deprecated property, use shadow_type instead"), + GTK_TYPE_SHADOW_TYPE, + GTK_SHADOW_ETCHED_IN, + GTK_PARAM_READWRITE)); + g_object_class_install_property (gobject_class, + PROP_SHADOW_TYPE, + g_param_spec_enum ("shadow-type", + P_("Frame shadow"), + P_("Appearance of the frame border"), + GTK_TYPE_SHADOW_TYPE, + GTK_SHADOW_ETCHED_IN, + GTK_PARAM_READWRITE)); + + g_object_class_install_property (gobject_class, + PROP_LABEL_WIDGET, + g_param_spec_object ("label-widget", + P_("Label widget"), + P_("A widget to display in place of the usual frame label"), + GTK_TYPE_WIDGET, + GTK_PARAM_READWRITE)); + + widget_class->expose_event = gtk_frame_expose; + widget_class->size_request = gtk_frame_size_request; + widget_class->size_allocate = gtk_frame_size_allocate; - object_class = (GtkObjectClass*) class; - widget_class = (GtkWidgetClass*) class; - - parent_class = gtk_type_class (gtk_bin_get_type ()); + container_class->remove = gtk_frame_remove; + container_class->forall = gtk_frame_forall; - gtk_object_add_arg_type ("GtkFrame::label", GTK_TYPE_STRING, ARG_LABEL); - gtk_object_add_arg_type ("GtkFrame::label_xalign", GTK_TYPE_DOUBLE, ARG_LABEL_XALIGN); - gtk_object_add_arg_type ("GtkFrame::label_yalign", GTK_TYPE_DOUBLE, ARG_LABEL_YALIGN); - gtk_object_add_arg_type ("GtkFrame::shadow", GTK_TYPE_ENUM, ARG_SHADOW); + class->compute_child_allocation = gtk_frame_real_compute_child_allocation; +} - object_class->destroy = gtk_frame_destroy; +static void +gtk_frame_buildable_init (GtkBuildableIface *iface) +{ + iface->add_child = gtk_frame_buildable_add_child; +} - widget_class->draw = gtk_frame_draw; - widget_class->expose_event = gtk_frame_expose; - widget_class->size_request = gtk_frame_size_request; - widget_class->size_allocate = gtk_frame_size_allocate; +static void +gtk_frame_buildable_add_child (GtkBuildable *buildable, + GtkBuilder *builder, + GObject *child, + const gchar *type) +{ + if (type && strcmp (type, "label") == 0) + gtk_frame_set_label_widget (GTK_FRAME (buildable), GTK_WIDGET (child)); + else if (!type) + gtk_container_add (GTK_CONTAINER (buildable), GTK_WIDGET (child)); + else + GTK_BUILDER_WARN_INVALID_CHILD_TYPE (GTK_FRAME (buildable), type); } static void gtk_frame_init (GtkFrame *frame) { - GTK_WIDGET_SET_FLAGS (frame, GTK_BASIC); - - frame->label = NULL; + frame->label_widget = NULL; frame->shadow_type = GTK_SHADOW_ETCHED_IN; - frame->label_width = 0; - frame->label_height = 0; frame->label_xalign = 0.0; frame->label_yalign = 0.5; } -static void -gtk_frame_set_arg (GtkFrame *frame, - GtkArg *arg, - guint arg_id) +static void +gtk_frame_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) { - switch (arg_id) + GtkFrame *frame; + + frame = GTK_FRAME (object); + + switch (prop_id) { - case ARG_LABEL: - gtk_frame_set_label (frame, GTK_VALUE_STRING (*arg)); + case PROP_LABEL: + gtk_frame_set_label (frame, g_value_get_string (value)); break; - case ARG_LABEL_XALIGN: - gtk_frame_set_label_align (frame, GTK_VALUE_DOUBLE (*arg), frame->label_yalign); + case PROP_LABEL_XALIGN: + gtk_frame_set_label_align (frame, g_value_get_float (value), + frame->label_yalign); break; - case ARG_LABEL_YALIGN: - gtk_frame_set_label_align (frame, frame->label_xalign, GTK_VALUE_DOUBLE (*arg)); + case PROP_LABEL_YALIGN: + gtk_frame_set_label_align (frame, frame->label_xalign, + g_value_get_float (value)); break; - case ARG_SHADOW: - gtk_frame_set_shadow_type (frame, GTK_VALUE_ENUM (*arg)); + case PROP_SHADOW: + case PROP_SHADOW_TYPE: + gtk_frame_set_shadow_type (frame, g_value_get_enum (value)); break; - default: - arg->type = GTK_TYPE_INVALID; + case PROP_LABEL_WIDGET: + gtk_frame_set_label_widget (frame, g_value_get_object (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } -static void -gtk_frame_get_arg (GtkFrame *frame, - GtkArg *arg, - guint arg_id) +static void +gtk_frame_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) { - switch (arg_id) + GtkFrame *frame; + + frame = GTK_FRAME (object); + + switch (prop_id) { - case ARG_LABEL: - GTK_VALUE_STRING (*arg) = g_strdup (frame->label); + case PROP_LABEL: + g_value_set_string (value, gtk_frame_get_label (frame)); + break; + case PROP_LABEL_XALIGN: + g_value_set_float (value, frame->label_xalign); break; - case ARG_LABEL_XALIGN: - GTK_VALUE_DOUBLE (*arg) = frame->label_xalign; + case PROP_LABEL_YALIGN: + g_value_set_float (value, frame->label_yalign); break; - case ARG_LABEL_YALIGN: - GTK_VALUE_DOUBLE (*arg) = frame->label_yalign; + case PROP_SHADOW: + case PROP_SHADOW_TYPE: + g_value_set_enum (value, frame->shadow_type); break; - case ARG_SHADOW: - GTK_VALUE_ENUM (*arg) = frame->shadow_type; + case PROP_LABEL_WIDGET: + g_value_set_object (value, + frame->label_widget ? + G_OBJECT (frame->label_widget) : NULL); break; default: - arg->type = GTK_TYPE_INVALID; + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } +/** + * gtk_frame_new: + * @label: the text to use as the label of the frame + * + * Creates a new #GtkFrame, with optional label @label. + * If @label is %NULL, the label is omitted. + * + * Return value: a new #GtkFrame widget + **/ GtkWidget* gtk_frame_new (const gchar *label) { - GtkFrame *frame; + return g_object_new (GTK_TYPE_FRAME, "label", label, NULL); +} - frame = gtk_type_new (gtk_frame_get_type ()); +static void +gtk_frame_remove (GtkContainer *container, + GtkWidget *child) +{ + GtkFrame *frame = GTK_FRAME (container); - gtk_frame_set_label (frame, label); + if (frame->label_widget == child) + gtk_frame_set_label_widget (frame, NULL); + else + GTK_CONTAINER_CLASS (gtk_frame_parent_class)->remove (container, child); +} - return GTK_WIDGET (frame); +static void +gtk_frame_forall (GtkContainer *container, + gboolean include_internals, + GtkCallback callback, + gpointer callback_data) +{ + GtkBin *bin = GTK_BIN (container); + GtkFrame *frame = GTK_FRAME (container); + + if (bin->child) + (* callback) (bin->child, callback_data); + + if (frame->label_widget) + (* callback) (frame->label_widget, callback_data); } +/** + * gtk_frame_set_label: + * @frame: a #GtkFrame + * @label: the text to use as the label of the frame + * + * Sets the text of the label. If @label is %NULL, + * the current label is removed. + **/ void gtk_frame_set_label (GtkFrame *frame, const gchar *label) { - g_return_if_fail (frame != NULL); g_return_if_fail (GTK_IS_FRAME (frame)); - if ((label && frame->label && (strcmp (frame->label, label) == 0)) || - (!label && !frame->label)) - return; - - if (frame->label) - g_free (frame->label); - frame->label = NULL; - - if (label) + if (!label) { - frame->label = g_strdup (label); - frame->label_width = gdk_string_measure (GTK_WIDGET (frame)->style->font, frame->label) + 7; - frame->label_height = (GTK_WIDGET (frame)->style->font->ascent + - GTK_WIDGET (frame)->style->font->descent + 1); + gtk_frame_set_label_widget (frame, NULL); } else { - frame->label_width = 0; - frame->label_height = 0; + GtkWidget *child = gtk_label_new (label); + gtk_widget_show (child); + + gtk_frame_set_label_widget (frame, child); } +} - if (GTK_WIDGET_DRAWABLE (frame)) - { - GtkWidget *widget; +/** + * gtk_frame_get_label: + * @frame: a #GtkFrame + * + * If the frame's label widget is a #GtkLabel, returns the + * text in the label widget. (The frame will have a #GtkLabel + * for the label widget if a non-%NULL argument was passed + * to gtk_frame_new().) + * + * Return value: the text in the label, or %NULL if there + * was no label widget or the lable widget was not + * a #GtkLabel. This string is owned by GTK+ and + * must not be modified or freed. + **/ +G_CONST_RETURN gchar * +gtk_frame_get_label (GtkFrame *frame) +{ + g_return_val_if_fail (GTK_IS_FRAME (frame), NULL); + + if (frame->label_widget && GTK_IS_LABEL (frame->label_widget)) + return gtk_label_get_text (GTK_LABEL (frame->label_widget)); + else + return NULL; +} - /* clear the old label area - */ - widget = GTK_WIDGET (frame); - gdk_window_clear_area (widget->window, - widget->allocation.x + GTK_CONTAINER (frame)->border_width, - widget->allocation.y + GTK_CONTAINER (frame)->border_width, - widget->allocation.width - GTK_CONTAINER (frame)->border_width, - widget->allocation.y + frame->label_height); +/** + * gtk_frame_set_label_widget: + * @frame: a #GtkFrame + * @label_widget: the new label widget + * + * Sets the label widget for the frame. This is the widget that + * will appear embedded in the top edge of the frame as a + * title. + **/ +void +gtk_frame_set_label_widget (GtkFrame *frame, + GtkWidget *label_widget) +{ + gboolean need_resize = FALSE; + + g_return_if_fail (GTK_IS_FRAME (frame)); + g_return_if_fail (label_widget == NULL || GTK_IS_WIDGET (label_widget)); + g_return_if_fail (label_widget == NULL || label_widget->parent == NULL); + + if (frame->label_widget == label_widget) + return; + + if (frame->label_widget) + { + need_resize = GTK_WIDGET_VISIBLE (frame->label_widget); + gtk_widget_unparent (frame->label_widget); + } + frame->label_widget = label_widget; + + if (label_widget) + { + frame->label_widget = label_widget; + gtk_widget_set_parent (label_widget, GTK_WIDGET (frame)); + need_resize |= GTK_WIDGET_VISIBLE (label_widget); } - gtk_widget_queue_resize (GTK_WIDGET (frame)); + if (GTK_WIDGET_VISIBLE (frame) && need_resize) + gtk_widget_queue_resize (GTK_WIDGET (frame)); + + g_object_freeze_notify (G_OBJECT (frame)); + g_object_notify (G_OBJECT (frame), "label-widget"); + g_object_notify (G_OBJECT (frame), "label"); + g_object_thaw_notify (G_OBJECT (frame)); +} + +/** + * gtk_frame_get_label_widget: + * @frame: a #GtkFrame + * + * Retrieves the label widget for the frame. See + * gtk_frame_set_label_widget(). + * + * Return value: the label widget, or %NULL if there is none. + **/ +GtkWidget * +gtk_frame_get_label_widget (GtkFrame *frame) +{ + g_return_val_if_fail (GTK_IS_FRAME (frame), NULL); + + return frame->label_widget; } +/** + * gtk_frame_set_label_align: + * @frame: a #GtkFrame + * @xalign: The position of the label along the top edge + * of the widget. A value of 0.0 represents left alignment; + * 1.0 represents right alignment. + * @yalign: The y alignment of the label. A value of 0.0 aligns under + * the frame; 1.0 aligns above the frame. If the values are exactly + * 0.0 or 1.0 the gap in the frame won't be painted because the label + * will be completely above or below the frame. + * + * Sets the alignment of the frame widget's label. The + * default values for a newly created frame are 0.0 and 0.5. + **/ void gtk_frame_set_label_align (GtkFrame *frame, gfloat xalign, gfloat yalign) { - g_return_if_fail (frame != NULL); g_return_if_fail (GTK_IS_FRAME (frame)); xalign = CLAMP (xalign, 0.0, 1.0); yalign = CLAMP (yalign, 0.0, 1.0); - if ((xalign != frame->label_xalign) || (yalign != frame->label_yalign)) + g_object_freeze_notify (G_OBJECT (frame)); + if (xalign != frame->label_xalign) { frame->label_xalign = xalign; + g_object_notify (G_OBJECT (frame), "label-xalign"); + } + + if (yalign != frame->label_yalign) + { frame->label_yalign = yalign; + g_object_notify (G_OBJECT (frame), "label-yalign"); + } - if (GTK_WIDGET_DRAWABLE (frame)) - { - GtkWidget *widget; + g_object_thaw_notify (G_OBJECT (frame)); + gtk_widget_queue_resize (GTK_WIDGET (frame)); +} - /* clear the old label area - */ - widget = GTK_WIDGET (frame); - gdk_window_clear_area (widget->window, - widget->allocation.x + GTK_CONTAINER (frame)->border_width, - widget->allocation.y + GTK_CONTAINER (frame)->border_width, - widget->allocation.width - GTK_CONTAINER (frame)->border_width, - widget->allocation.y + frame->label_height); +/** + * gtk_frame_get_label_align: + * @frame: a #GtkFrame + * @xalign: location to store X alignment of frame's label, or %NULL + * @yalign: location to store X alignment of frame's label, or %NULL + * + * Retrieves the X and Y alignment of the frame's label. See + * gtk_frame_set_label_align(). + **/ +void +gtk_frame_get_label_align (GtkFrame *frame, + gfloat *xalign, + gfloat *yalign) +{ + g_return_if_fail (GTK_IS_FRAME (frame)); - } - gtk_widget_queue_resize (GTK_WIDGET (frame)); - } + if (xalign) + *xalign = frame->label_xalign; + if (yalign) + *yalign = frame->label_yalign; } +/** + * gtk_frame_set_shadow_type: + * @frame: a #GtkFrame + * @type: the new #GtkShadowType + * + * Sets the shadow type for @frame. + **/ void gtk_frame_set_shadow_type (GtkFrame *frame, GtkShadowType type) { - g_return_if_fail (frame != NULL); g_return_if_fail (GTK_IS_FRAME (frame)); if ((GtkShadowType) frame->shadow_type != type) { frame->shadow_type = type; + g_object_notify (G_OBJECT (frame), "shadow-type"); if (GTK_WIDGET_DRAWABLE (frame)) { - gdk_window_clear_area (GTK_WIDGET (frame)->window, - GTK_WIDGET (frame)->allocation.x, - GTK_WIDGET (frame)->allocation.y, - GTK_WIDGET (frame)->allocation.width, - GTK_WIDGET (frame)->allocation.height); + gtk_widget_queue_draw (GTK_WIDGET (frame)); } + gtk_widget_queue_resize (GTK_WIDGET (frame)); } } - -static void -gtk_frame_destroy (GtkObject *object) +/** + * gtk_frame_get_shadow_type: + * @frame: a #GtkFrame + * + * Retrieves the shadow type of the frame. See + * gtk_frame_set_shadow_type(). + * + * Return value: the current shadow type of the frame. + **/ +GtkShadowType +gtk_frame_get_shadow_type (GtkFrame *frame) { - GtkFrame *frame; - - g_return_if_fail (object != NULL); - g_return_if_fail (GTK_IS_FRAME (object)); - - frame = GTK_FRAME (object); + g_return_val_if_fail (GTK_IS_FRAME (frame), GTK_SHADOW_ETCHED_IN); - if (frame->label) - g_free (frame->label); - - if (GTK_OBJECT_CLASS (parent_class)->destroy) - (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); + return frame->shadow_type; } static void @@ -300,98 +530,69 @@ gtk_frame_paint (GtkWidget *widget, GdkRectangle *area) { GtkFrame *frame; - gint height_extra; - gint label_area_width; - gint x, y; - - g_return_if_fail (widget != NULL); - g_return_if_fail (GTK_IS_FRAME (widget)); - g_return_if_fail (area != NULL); + gint x, y, width, height; if (GTK_WIDGET_DRAWABLE (widget)) { frame = GTK_FRAME (widget); - height_extra = frame->label_height - widget->style->klass->xthickness; - height_extra = MAX (height_extra, 0); - - x = GTK_CONTAINER (frame)->border_width; - y = GTK_CONTAINER (frame)->border_width; + x = frame->child_allocation.x - widget->style->xthickness; + y = frame->child_allocation.y - widget->style->ythickness; + width = frame->child_allocation.width + 2 * widget->style->xthickness; + height = frame->child_allocation.height + 2 * widget->style->ythickness; - gtk_draw_shadow (widget->style, widget->window, - GTK_STATE_NORMAL, frame->shadow_type, - widget->allocation.x + x, - widget->allocation.y + y + height_extra / 2, - widget->allocation.width - x * 2, - widget->allocation.height - y * 2 - height_extra / 2); - - if (frame->label) + if (frame->label_widget) { - label_area_width = (widget->allocation.width - - GTK_CONTAINER (frame)->border_width * 2 - - widget->style->klass->xthickness * 2); - - x = ((label_area_width - frame->label_width) * frame->label_xalign + - GTK_CONTAINER (frame)->border_width + widget->style->klass->xthickness); - y = (GTK_CONTAINER (frame)->border_width + widget->style->font->ascent); - - gdk_window_clear_area (widget->window, - widget->allocation.x + x + 2, - widget->allocation.y + GTK_CONTAINER (frame)->border_width, - frame->label_width - 4, - frame->label_height); - gtk_draw_string (widget->style, widget->window, GTK_WIDGET_STATE (widget), - widget->allocation.x + x + 3, - widget->allocation.y + y, - frame->label); + GtkRequisition child_requisition; + gfloat xalign; + gint height_extra; + gint x2; + + gtk_widget_get_child_requisition (frame->label_widget, &child_requisition); + + if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR) + xalign = frame->label_xalign; + else + xalign = 1 - frame->label_xalign; + + height_extra = MAX (0, child_requisition.height - widget->style->ythickness) + - frame->label_yalign * child_requisition.height; + y -= height_extra; + height += height_extra; + + x2 = widget->style->xthickness + (frame->child_allocation.width - child_requisition.width - 2 * LABEL_PAD - 2 * LABEL_SIDE_PAD) * xalign + LABEL_SIDE_PAD; + + /* If the label is completely over or under the frame we can omit the gap */ + if (frame->label_yalign == 0.0 || frame->label_yalign == 1.0) + gtk_paint_shadow (widget->style, widget->window, + widget->state, frame->shadow_type, + area, widget, "frame", + x, y, width, height); + else + gtk_paint_shadow_gap (widget->style, widget->window, + widget->state, frame->shadow_type, + area, widget, "frame", + x, y, width, height, + GTK_POS_TOP, + x2, child_requisition.width + 2 * LABEL_PAD); } + else + gtk_paint_shadow (widget->style, widget->window, + widget->state, frame->shadow_type, + area, widget, "frame", + x, y, width, height); } } -static void -gtk_frame_draw (GtkWidget *widget, - GdkRectangle *area) -{ - GtkBin *bin; - GdkRectangle child_area; - - g_return_if_fail (widget != NULL); - g_return_if_fail (GTK_IS_FRAME (widget)); - g_return_if_fail (area != NULL); - - if (GTK_WIDGET_DRAWABLE (widget)) - { - bin = GTK_BIN (widget); - - gtk_frame_paint (widget, area); - - if (bin->child && gtk_widget_intersect (bin->child, area, &child_area)) - gtk_widget_draw (bin->child, &child_area); - } -} - -static gint +static gboolean gtk_frame_expose (GtkWidget *widget, GdkEventExpose *event) { - GtkBin *bin; - GdkEventExpose child_event; - - g_return_val_if_fail (widget != NULL, FALSE); - g_return_val_if_fail (GTK_IS_FRAME (widget), FALSE); - g_return_val_if_fail (event != NULL, FALSE); - if (GTK_WIDGET_DRAWABLE (widget)) { - bin = GTK_BIN (widget); - gtk_frame_paint (widget, &event->area); - child_event = *event; - if (bin->child && - GTK_WIDGET_NO_WINDOW (bin->child) && - gtk_widget_intersect (bin->child, &event->area, &child_event.area)) - gtk_widget_event (bin->child, (GdkEvent*) &child_event); + (* GTK_WIDGET_CLASS (gtk_frame_parent_class)->expose_event) (widget, event); } return FALSE; @@ -401,84 +602,128 @@ static void gtk_frame_size_request (GtkWidget *widget, GtkRequisition *requisition) { - GtkFrame *frame; - GtkBin *bin; - gint tmp_height; - - g_return_if_fail (widget != NULL); - g_return_if_fail (GTK_IS_FRAME (widget)); - g_return_if_fail (requisition != NULL); - - frame = GTK_FRAME (widget); - bin = GTK_BIN (widget); - - requisition->width = (GTK_CONTAINER (widget)->border_width + - GTK_WIDGET (widget)->style->klass->xthickness) * 2; - - tmp_height = frame->label_height - GTK_WIDGET (widget)->style->klass->ythickness; - tmp_height = MAX (tmp_height, 0); - - requisition->height = tmp_height + (GTK_CONTAINER (widget)->border_width + - GTK_WIDGET (widget)->style->klass->ythickness) * 2; - - if (bin->child && GTK_WIDGET_VISIBLE (bin->child)) + GtkFrame *frame = GTK_FRAME (widget); + GtkBin *bin = GTK_BIN (widget); + GtkRequisition child_requisition; + + if (frame->label_widget && GTK_WIDGET_VISIBLE (frame->label_widget)) { - gtk_widget_size_request (bin->child, &bin->child->requisition); + gtk_widget_size_request (frame->label_widget, &child_requisition); - requisition->width += MAX (bin->child->requisition.width, frame->label_width); - requisition->height += bin->child->requisition.height; + requisition->width = child_requisition.width + 2 * LABEL_PAD + 2 * LABEL_SIDE_PAD; + requisition->height = + MAX (0, child_requisition.height - widget->style->ythickness); } else { - requisition->width += frame->label_width; + requisition->width = 0; + requisition->height = 0; + } + + if (bin->child && GTK_WIDGET_VISIBLE (bin->child)) + { + gtk_widget_size_request (bin->child, &child_requisition); + + requisition->width = MAX (requisition->width, child_requisition.width); + requisition->height += child_requisition.height; } + + requisition->width += (GTK_CONTAINER (widget)->border_width + + GTK_WIDGET (widget)->style->xthickness) * 2; + requisition->height += (GTK_CONTAINER (widget)->border_width + + GTK_WIDGET (widget)->style->ythickness) * 2; } static void gtk_frame_size_allocate (GtkWidget *widget, GtkAllocation *allocation) { - GtkFrame *frame; - GtkBin *bin; - GtkAllocation child_allocation; - - g_return_if_fail (widget != NULL); - g_return_if_fail (GTK_IS_FRAME (widget)); - g_return_if_fail (allocation != NULL); - - frame = GTK_FRAME (widget); - bin = GTK_BIN (widget); - - if (GTK_WIDGET_MAPPED (widget) && - ((widget->allocation.x != allocation->x) || - (widget->allocation.y != allocation->y) || - (widget->allocation.width != allocation->width) || - (widget->allocation.height != allocation->height)) && - (widget->allocation.width != 0) && - (widget->allocation.height != 0)) - gdk_window_clear_area (widget->window, - widget->allocation.x, - widget->allocation.y, - widget->allocation.width, - widget->allocation.height); + GtkFrame *frame = GTK_FRAME (widget); + GtkBin *bin = GTK_BIN (widget); + GtkAllocation new_allocation; widget->allocation = *allocation; + gtk_frame_compute_child_allocation (frame, &new_allocation); + + /* If the child allocation changed, that means that the frame is drawn + * in a new place, so we must redraw the entire widget. + */ + if (GTK_WIDGET_MAPPED (widget) && + (new_allocation.x != frame->child_allocation.x || + new_allocation.y != frame->child_allocation.y || + new_allocation.width != frame->child_allocation.width || + new_allocation.height != frame->child_allocation.height)) + gdk_window_invalidate_rect (widget->window, &widget->allocation, FALSE); + if (bin->child && GTK_WIDGET_VISIBLE (bin->child)) + gtk_widget_size_allocate (bin->child, &new_allocation); + + frame->child_allocation = new_allocation; + + if (frame->label_widget && GTK_WIDGET_VISIBLE (frame->label_widget)) { - child_allocation.x = (GTK_CONTAINER (frame)->border_width + - GTK_WIDGET (frame)->style->klass->xthickness); - child_allocation.width = MAX(0, allocation->width - child_allocation.x * 2); + GtkRequisition child_requisition; + GtkAllocation child_allocation; + gfloat xalign; + + gtk_widget_get_child_requisition (frame->label_widget, &child_requisition); + + if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR) + xalign = frame->label_xalign; + else + xalign = 1 - frame->label_xalign; + + child_allocation.x = frame->child_allocation.x + LABEL_SIDE_PAD + + (frame->child_allocation.width - child_requisition.width - 2 * LABEL_PAD - 2 * LABEL_SIDE_PAD) * xalign + LABEL_PAD; + child_allocation.width = MIN (child_requisition.width, new_allocation.width - 2 * LABEL_PAD - 2 * LABEL_SIDE_PAD); + + child_allocation.y = frame->child_allocation.y - MAX (child_requisition.height, widget->style->ythickness); + child_allocation.height = child_requisition.height; + + gtk_widget_size_allocate (frame->label_widget, &child_allocation); + } +} + +static void +gtk_frame_compute_child_allocation (GtkFrame *frame, + GtkAllocation *child_allocation) +{ + g_return_if_fail (GTK_IS_FRAME (frame)); + g_return_if_fail (child_allocation != NULL); - child_allocation.y = (GTK_CONTAINER (frame)->border_width + - MAX (frame->label_height, GTK_WIDGET (frame)->style->klass->ythickness)); - child_allocation.height = MAX (0, (allocation->height - child_allocation.y - - GTK_CONTAINER (frame)->border_width - - GTK_WIDGET (frame)->style->klass->ythickness)); + GTK_FRAME_GET_CLASS (frame)->compute_child_allocation (frame, child_allocation); +} - child_allocation.x += allocation->x; - child_allocation.y += allocation->y; +static void +gtk_frame_real_compute_child_allocation (GtkFrame *frame, + GtkAllocation *child_allocation) +{ + GtkWidget *widget = GTK_WIDGET (frame); + GtkAllocation *allocation = &widget->allocation; + GtkRequisition child_requisition; + gint top_margin; - gtk_widget_size_allocate (bin->child, &child_allocation); + if (frame->label_widget) + { + gtk_widget_get_child_requisition (frame->label_widget, &child_requisition); + top_margin = MAX (child_requisition.height, widget->style->ythickness); } + else + top_margin = widget->style->ythickness; + + child_allocation->x = (GTK_CONTAINER (frame)->border_width + + widget->style->xthickness); + child_allocation->width = MAX(1, (gint)allocation->width - child_allocation->x * 2); + + child_allocation->y = (GTK_CONTAINER (frame)->border_width + top_margin); + child_allocation->height = MAX (1, ((gint)allocation->height - child_allocation->y - + (gint)GTK_CONTAINER (frame)->border_width - + (gint)widget->style->ythickness)); + + child_allocation->x += allocation->x; + child_allocation->y += allocation->y; } + +#define __GTK_FRAME_C__ +#include "gtkaliasdef.c"