2 * This file is part of hildon-libs
4 * Copyright (C) 2005 Nokia Corporation.
6 * Contact: Luc Pionchon <luc.pionchon@nokia.com>
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public License
10 * as published by the Free Software Foundation; either version 2.1 of
11 * the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
25 #include <gtk/gtkhbox.h>
26 #include <gtk/gtklabel.h>
27 #include <gtk/gtkimage.h>
28 #include <gtk/gtkentry.h>
29 #include <gtk/gtkcombo.h>
30 #include <gtk/gtkcombobox.h>
31 #include <gtk/gtkcomboboxentry.h>
32 #include <gtk/gtkoptionmenu.h>
33 #include <gtk/gtkmarshal.h>
34 #include <gtk/gtkalignment.h>
37 #include "hildon-caption.h"
38 #include "hildon-defines.h"
44 #define _(String) dgettext(PACKAGE, String)
46 #define HILDON_CAPTION_MANDATORY_ICON "qgn_list_gene_mandat_field"
47 #define HILDON_CAPTION_SPACING 6
49 #define HILDON_CAPTION_GET_PRIVATE(obj) \
50 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \
51 HILDON_TYPE_CAPTION, HildonCaptionPrivate));
54 static GtkEventBox *parent_class = NULL;
56 typedef struct _HildonCaptionPrivate HildonCaptionPrivate;
74 static void hildon_caption_class_init( HildonCaptionClass *caption_class );
75 static void hildon_caption_init( HildonCaption *caption );
76 static void hildon_caption_size_request( GtkWidget *widget,
77 GtkRequisition *requisition );
78 static void hildon_caption_size_allocate( GtkWidget *widget,
79 GtkAllocation *allocation );
80 static void hildon_caption_forall( GtkContainer *container,
81 gboolean include_internals,
82 GtkCallback callback, gpointer data );
83 static void hildon_caption_hierarchy_changed( GtkWidget *widget,
84 GtkWidget *previous_toplevel);
85 static void hildon_caption_set_focus( GtkWindow *window, GtkWidget *widget,
87 static void hildon_caption_activate( GtkWidget *widget );
89 static void hildon_caption_set_property( GObject *object, guint param_id,
90 const GValue *value, GParamSpec *pspec );
91 static void hildon_caption_get_property( GObject *object, guint param_id,
92 GValue *value, GParamSpec *pspec );
93 static gboolean hildon_caption_expose( GtkWidget *widget,
94 GdkEventExpose *event );
95 static void hildon_caption_destroy( GtkObject *self );
96 static gboolean hildon_caption_button_press( GtkWidget *widget, GdkEventButton *event );
98 hildon_caption_set_focus_child( GtkContainer *container, GtkWidget *child );
101 hildon_caption_set_label_text( HildonCaptionPrivate *priv );
103 static void hildon_caption_set_child_property (GtkContainer *container,
108 static void hildon_caption_get_child_property (GtkContainer *container,
113 static void get_first_focusable_child ( GtkWidget *widget, gpointer data );
115 struct _HildonCaptionPrivate
117 GtkWidget *caption_area;
118 GtkWidget *mandatory_icon;
121 GtkWidget *icon_align; /* Arbitrary icon widgets do not support alignment */
125 guint is_focused : 1;
126 guint activate_block : 1;
128 HildonCaptionStatus status;
131 /* Register optional/manatory type enumeration */
133 hildon_caption_status_get_type (void)
135 static GType etype = 0;
137 static const GEnumValue values[] = {
138 { HILDON_CAPTION_OPTIONAL, "HILDON_CAPTION_OPTIONAL", "optional" },
139 { HILDON_CAPTION_MANDATORY, "HILDON_CAPTION_MANDATORY", "mandatory" },
142 etype = g_enum_register_static ("HildonCaptionStatus", values);
148 * hildon_caption_get_type:
149 * @Returns : GType of #HildonCaption.
151 * Initialises, and returns the type of a hildon caption.
153 G_CONST_RETURN GType hildon_caption_get_type( void )
155 static GType caption_type = 0;
159 static const GTypeInfo caption_info = {
160 sizeof(HildonCaptionClass),
161 NULL, /* base_init */
162 NULL, /* base_finalize */
163 (GClassInitFunc) hildon_caption_class_init,
164 NULL, /* class_finalize */
165 NULL, /* class_data */
166 sizeof(HildonCaption),
168 (GInstanceInitFunc) hildon_caption_init,
170 caption_type = g_type_register_static( GTK_TYPE_EVENT_BOX,
171 "HildonCaption", &caption_info, 0 );
177 * Initialises the caption class.
179 static void hildon_caption_class_init( HildonCaptionClass *caption_class )
181 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(caption_class);
182 GObjectClass *gobject_class = G_OBJECT_CLASS(caption_class);
183 GtkContainerClass *container_class = GTK_CONTAINER_CLASS(caption_class);
185 parent_class = g_type_class_peek_parent( caption_class );
187 g_type_class_add_private( caption_class, sizeof(HildonCaptionPrivate) );
189 /* Override virtual functions */
190 gobject_class->get_property = hildon_caption_get_property;
191 gobject_class->set_property = hildon_caption_set_property;
192 caption_class->activate = hildon_caption_activate;
193 GTK_OBJECT_CLASS(caption_class)->destroy = hildon_caption_destroy;
194 container_class->forall = hildon_caption_forall;
195 container_class->set_focus_child = hildon_caption_set_focus_child;
196 container_class->set_child_property = hildon_caption_set_child_property;
197 container_class->get_child_property = hildon_caption_get_child_property;
198 widget_class->expose_event = hildon_caption_expose;
199 widget_class->hierarchy_changed = hildon_caption_hierarchy_changed;
200 widget_class->size_request = hildon_caption_size_request;
201 widget_class->size_allocate = hildon_caption_size_allocate;
202 widget_class->button_press_event = hildon_caption_button_press;
204 /* Create new signals and properties */
205 widget_class->activate_signal = g_signal_new( "activate",
210 G_STRUCT_OFFSET( HildonCaptionClass,
211 activate), NULL, NULL,
212 gtk_marshal_VOID__VOID,
216 * HildonCaption:label:
220 g_object_class_install_property( gobject_class, PROP_LABEL,
221 g_param_spec_string("label",
222 "Current label", "Caption label",
223 NULL, G_PARAM_READABLE | G_PARAM_WRITABLE) );
226 * HildonCaption:icon:
228 * The icon shown on the caption area.
230 g_object_class_install_property( gobject_class, PROP_ICON,
231 g_param_spec_object("icon",
233 "The icon shown on the caption area",
234 GTK_TYPE_WIDGET, G_PARAM_READABLE |
237 * HildonCaption:status:
239 * Mandatory or optional status.
241 g_object_class_install_property( gobject_class, PROP_STATUS,
242 g_param_spec_enum("status",
244 "Mandatory or optional status",
245 HILDON_TYPE_CAPTION_STATUS,
246 HILDON_CAPTION_OPTIONAL,
247 G_PARAM_READABLE | G_PARAM_WRITABLE) );
249 * HildonCaption:size_group:
251 * Current size group the caption is in.
253 g_object_class_install_property( gobject_class, PROP_SIZE_GROUP,
254 g_param_spec_object("size_group",
255 "Current size group",
256 "Current size group the caption is in",
257 GTK_TYPE_SIZE_GROUP, G_PARAM_READABLE |
261 * HildonCaption:separator:
263 * The current separator.
265 g_object_class_install_property( gobject_class, PROP_SEPARATOR,
266 g_param_spec_string("separator",
267 "Current separator", "Current separator",
268 _("Ecdg_ti_caption_separator"),
269 G_PARAM_READABLE | G_PARAM_WRITABLE) );
271 /* Create child properties. These are related to
272 child <-> parent relationship, not to either of objects itself */
273 gtk_container_class_install_child_property (container_class,
275 g_param_spec_boolean ("expand",
276 "Same as GtkBox expand.",
277 "Same as GtkBox expand. Wheter the child should be expanded or not.",
282 /* Destroy can be called multiple times, remember to set pointers to NULL */
283 static void hildon_caption_destroy( GtkObject *self )
285 HildonCaptionPrivate *priv = HILDON_CAPTION_GET_PRIVATE(self);
287 /* Free our internal child */
288 if( priv->caption_area )
290 gtk_widget_unparent( priv->caption_area );
291 priv->caption_area = NULL;
294 /* Free user provided strings */
297 g_free( priv->text );
300 if( priv->separator )
302 g_free( priv->separator );
303 priv->separator = NULL;
306 /* Parent classes destroy takes care of user packed contents */
307 if( GTK_OBJECT_CLASS(parent_class)->destroy )
308 GTK_OBJECT_CLASS(parent_class)->destroy( self );
311 /* Parent, eventbox will run allocate also for the child which may be
312 * owning a window too. This window is then moved and resized and we do not
313 * want to do that -> It causes flickering.
314 * And just because we also want to
316 static gboolean hildon_caption_expose( GtkWidget *widget,
317 GdkEventExpose *event )
319 HildonCaptionPrivate *priv = NULL;
324 g_return_val_if_fail( HILDON_IS_CAPTION(widget), TRUE );
325 priv = HILDON_CAPTION_GET_PRIVATE(widget);
327 if( !GTK_WIDGET_DRAWABLE(widget) )
330 GTK_WIDGET_CLASS(parent_class)->expose_event( widget, event );
332 /* If our child control is focused, we draw nice looking focus
333 graphics for the caption */
334 if ( priv->is_focused )
336 /* Determine focus box dimensions */
337 gtk_widget_get_child_requisition( priv->caption_area, &req );
338 align = hildon_caption_get_label_alignment(HILDON_CAPTION(widget));
340 alloc.width = priv->caption_area->allocation.width + HILDON_CAPTION_SPACING;
341 alloc.height = MIN (req.height + (2 * widget->style->ythickness), priv->caption_area->allocation.height);
342 alloc.x = priv->caption_area->allocation.x;
343 alloc.y = priv->caption_area->allocation.y +
344 MAX(((priv->caption_area->allocation.height - alloc.height) * align), 0);
346 /* Paint the focus box */
347 gtk_paint_box( widget->style, widget->window, GTK_STATE_ACTIVE,
348 GTK_SHADOW_OUT, NULL, widget, "selection",
349 alloc.x, alloc.y, alloc.width, alloc.height );
351 /* Paint caption contents on top of the focus box */
352 GTK_WIDGET_GET_CLASS(priv->caption_area)->expose_event(
353 priv->caption_area, event);
359 static void hildon_caption_set_property( GObject *object, guint param_id,
363 HildonCaptionPrivate *priv = HILDON_CAPTION_GET_PRIVATE(object);
369 /* FIXME: This property setter is badly written.
370 * It does strange if (value)
371 * it calls queue_resize without reason? */
374 g_free( priv->text );
381 priv->text = g_strdup( g_value_get_string(value) );
382 hildon_caption_set_label_text( priv );
384 gtk_widget_queue_resize( GTK_WIDGET(object) );
388 /* Remove old icon */
390 gtk_container_remove( GTK_CONTAINER(priv->icon_align), priv->icon );
392 /* Pack and display new icon */
393 priv->icon = g_value_get_object( value );
396 gtk_container_add(GTK_CONTAINER(priv->icon_align), priv->icon);
397 gtk_widget_show_all( priv->caption_area );
402 priv->status = g_value_get_enum( value );
404 /* For mandatory fields we display a special icon */
405 if( priv->status == HILDON_CAPTION_MANDATORY )
407 if( !priv->mandatory_icon )
411 /* Create mandatory icon */
412 priv->mandatory_icon = gtk_image_new_from_icon_name(
413 HILDON_CAPTION_MANDATORY_ICON,
414 HILDON_ICON_SIZE_NOTE );
416 align = hildon_caption_get_label_alignment(HILDON_CAPTION(object));
417 g_object_set(priv->mandatory_icon, "yalign", align, NULL);
419 /* Pack and show mandatory icon */
420 if( priv->mandatory_icon )
422 gtk_box_pack_end( GTK_BOX(priv->caption_area),
423 priv->mandatory_icon, FALSE, FALSE, 0 );
424 gtk_widget_show_all( priv->caption_area );
430 if( priv->mandatory_icon )
432 /* Remove mandatory icon */
433 gtk_container_remove( GTK_CONTAINER(priv->caption_area),
434 priv->mandatory_icon );
435 priv->mandatory_icon = NULL;
437 /* FIXME: calls queue_draw without reason? */
438 gtk_widget_queue_draw( GTK_WIDGET(object) );
443 case PROP_SIZE_GROUP:
444 /* Detach from previous size group */
446 gtk_size_group_remove_widget( priv->group, priv->caption_area );
448 priv->group = g_value_get_object( value );
450 /* Attach to new size group */
452 gtk_size_group_add_widget( priv->group, priv->caption_area );
453 gtk_widget_queue_draw( GTK_WIDGET(object) );
458 /* Free old separator */
459 if( priv->separator )
461 g_free( priv->separator );
462 priv->separator = NULL;
465 /* FIXME: Value cannot be NULL */
468 priv->separator = g_strdup( g_value_get_string(value) );
469 hildon_caption_set_label_text( priv );
472 /* FIXME: Do we really need to explicitly call this? */
473 gtk_widget_queue_resize( GTK_WIDGET(object) );
477 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, param_id, pspec);
482 static void hildon_caption_get_property( GObject *object, guint param_id,
483 GValue *value, GParamSpec *pspec )
485 HildonCaptionPrivate *priv = HILDON_CAPTION_GET_PRIVATE(object);
490 g_value_set_string( value, priv->text );
493 g_value_set_object( value, priv->icon );
496 g_value_set_enum( value, priv->status );
498 case PROP_SIZE_GROUP:
499 g_value_set_object( value, priv->group );
502 g_value_set_string( value, priv->separator );
505 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, param_id, pspec);
510 static void hildon_caption_set_child_property( GtkContainer *container,
518 case CHILD_PROP_EXPAND:
519 hildon_caption_set_child_expand( HILDON_CAPTION(container),
520 g_value_get_boolean(value) );
524 G_OBJECT_WARN_INVALID_PROPERTY_ID(container, property_id, pspec);
529 static void hildon_caption_get_child_property( GtkContainer *container,
537 case CHILD_PROP_EXPAND:
538 g_value_set_boolean( value, hildon_caption_get_child_expand(
539 HILDON_CAPTION(container)) );
543 G_OBJECT_WARN_INVALID_PROPERTY_ID(container, property_id, pspec);
548 /* We want to activate out child control on button press */
549 static gboolean hildon_caption_button_press( GtkWidget *widget,
550 GdkEventButton *event )
552 HildonCaptionPrivate *priv = HILDON_CAPTION_GET_PRIVATE(widget);
554 /* If child can take focus, we simply grab focus to it */
555 if (GTK_WIDGET_CAN_FOCUS(GTK_BIN(widget)->child) &&
556 GTK_WIDGET_IS_SENSITIVE(GTK_BIN(widget)->child))
558 priv->is_focused = TRUE;
559 gtk_widget_grab_focus( GTK_BIN(widget)->child );
561 /* Containers usually do not accept focus, but can contain focusable widgets */
562 else if ( GTK_IS_CONTAINER(GTK_BIN(widget)->child) )
564 GtkWidget *cwid= NULL;
566 /* go through the children of the container for the first focusable children */
567 /* FIXME: Can we somehow avoid this unintuitive looping. Something like
568 gtk_widget_child_focus ?? */
569 gtk_container_forall (GTK_CONTAINER(GTK_BIN(widget)->child), (GtkCallback) get_first_focusable_child, &cwid );
572 priv->is_focused = TRUE;
573 gtk_widget_grab_focus( GTK_WIDGET(cwid) );
580 static void get_first_focusable_child ( GtkWidget *widget, gpointer data )
582 GtkWidget **child = (GtkWidget**)data;
584 /* if a first child has already been found then do nothing */
587 if (GTK_WIDGET_CAN_FOCUS (widget) &&
588 GTK_WIDGET_IS_SENSITIVE (widget))
590 else if (GTK_IS_CONTAINER(widget)) /* if the child is a container itself then go through them also /including/ internals */
592 gtk_container_forall (GTK_CONTAINER(widget), get_first_focusable_child, child);
596 static void hildon_caption_init( HildonCaption *caption )
598 HildonCaptionPrivate *priv = NULL;
599 g_return_if_fail( HILDON_IS_CAPTION(caption) );
601 /* Initialize startup state */
602 priv = HILDON_CAPTION_GET_PRIVATE(caption);
603 priv->status = HILDON_CAPTION_OPTIONAL;
606 priv->is_focused = FALSE;
608 priv->separator = g_strdup(_("Ecdg_ti_caption_separator"));
610 /* FIXME: We probably should use gtk_widget_set_composite_name as well */
611 gtk_widget_push_composite_child();
613 /* Create caption text */
614 priv->caption_area = gtk_hbox_new( FALSE, HILDON_CAPTION_SPACING );
615 priv->label = gtk_label_new( NULL );
616 priv->icon_align = gtk_alignment_new(0.5f, 0.5f, 0.0f, 0.0f);
618 /* We want to receive button presses for child widget activation */
619 gtk_event_box_set_above_child( GTK_EVENT_BOX(caption), FALSE );
620 gtk_widget_add_events( GTK_WIDGET(caption), GDK_BUTTON_PRESS_MASK );
622 /* Pack text label caption layout */
623 gtk_box_pack_end( GTK_BOX(priv->caption_area), priv->icon_align, FALSE, FALSE, 0);
624 gtk_box_pack_end( GTK_BOX(priv->caption_area), priv->label, FALSE, FALSE, 0 );
625 gtk_widget_set_parent( priv->caption_area, GTK_WIDGET(caption) );
627 gtk_widget_pop_composite_child();
629 gtk_widget_show_all( priv->caption_area );
632 static void hildon_caption_set_focus( GtkWindow *window, GtkWidget *widget,
635 GtkWidget *win = GTK_WIDGET(window);
636 GtkWidget *tmp = widget;
637 HildonCaptionPrivate *priv = HILDON_CAPTION_GET_PRIVATE(caption);
639 /* Try to find caption among the ancestors of widget */
640 /* FIXME: gtk_widget_get_ancestor */
641 while( GTK_IS_WIDGET(tmp) && win != tmp )
645 /* Caption found, so it is now considered focused */
646 priv->is_focused = TRUE;
647 gtk_widget_queue_draw( caption );
650 tmp = gtk_widget_get_parent( tmp );
653 if( priv->is_focused == TRUE )
655 /* Caption wasn't found, so cannot focus */
656 priv->is_focused = FALSE;
657 gtk_widget_queue_draw( caption );
661 /* FIXME: Is this function really needed at all? */
663 hildon_caption_set_focus_child( GtkContainer *container, GtkWidget *child )
665 GtkWidget *parent = gtk_widget_get_parent( GTK_WIDGET(container) );
667 GTK_CONTAINER_CLASS(parent_class)->set_focus_child( container, child );
669 if( parent && child != container->focus_child )
670 gtk_container_set_focus_child( GTK_CONTAINER(parent),
671 GTK_WIDGET(container) );
674 /* We need to connect/disconnect signal handlers to toplevel window
675 in which we reside. Ww want to update connected signals if our
677 static void hildon_caption_hierarchy_changed( GtkWidget *widget,
678 GtkWidget *previous_toplevel)
680 GtkWidget *current_ancestor;
681 HildonCaptionPrivate *priv;
683 g_return_if_fail( HILDON_IS_CAPTION(widget) );
684 priv = HILDON_CAPTION_GET_PRIVATE(widget);
686 if( GTK_WIDGET_CLASS(parent_class)->hierarchy_changed )
687 GTK_WIDGET_CLASS(parent_class)->hierarchy_changed( widget,
690 /* If we already were inside a window, remove old handler */
691 if (previous_toplevel) {
692 /* This is a compilation workaround for gcc > 3.3 since glib is buggy */
693 /* see http://bugzilla.gnome.org/show_bug.cgi?id=310175 */
697 g_signal_handlers_disconnect_by_func
698 (previous_toplevel, (gpointer) hildon_caption_set_focus, widget);
700 current_ancestor = gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW);
702 /* Install new handler for focus movement */
703 if (current_ancestor)
704 g_signal_connect( current_ancestor, "set-focus",
705 G_CALLBACK(hildon_caption_set_focus), widget );
708 static void hildon_caption_size_request( GtkWidget *widget,
709 GtkRequisition *requisition )
712 HildonCaptionPrivate *priv = NULL;
713 g_return_if_fail( HILDON_IS_CAPTION(widget) );
714 priv = HILDON_CAPTION_GET_PRIVATE(widget);
716 /* Use the same size requisition for the main box of the caption */
717 gtk_widget_size_request( priv->caption_area, &req );
719 if( GTK_WIDGET_CLASS(parent_class)->size_request )
720 GTK_WIDGET_CLASS(parent_class)->size_request( widget, requisition );
722 /* Perform some useless calculations so that we can ignore the results <3 */
723 requisition->width += req.width + HILDON_CAPTION_SPACING * 3;
725 if( (req.height + (2 * widget->style->ythickness)) > requisition->height )
726 requisition->height = req.height + (2 * widget->style->ythickness);
729 /* We use HILDON_CAPTION_SPACING to make it look a bit nicer */
730 static void hildon_caption_size_allocate( GtkWidget *widget,
731 GtkAllocation *allocation )
733 GtkAllocation allocA;
734 GtkAllocation allocB;
736 GtkWidget *child = NULL;
737 HildonCaptionPrivate *priv = NULL;
738 g_return_if_fail( HILDON_IS_CAPTION(widget) );
739 priv = HILDON_CAPTION_GET_PRIVATE(widget);
741 /* Position the caption to its allocated location */
742 if( GTK_WIDGET_REALIZED(widget) )
743 gdk_window_move_resize (widget->window,
744 allocation->x + GTK_CONTAINER (widget)->border_width,
745 allocation->y + GTK_CONTAINER (widget)->border_width,
746 MAX (allocation->width - GTK_CONTAINER (widget)->border_width * 2, 0),
747 MAX (allocation->height - GTK_CONTAINER (widget)->border_width * 2, 0));
749 child = GTK_BIN(widget)->child;
751 widget->allocation = *allocation;
752 gtk_widget_get_child_requisition( priv->caption_area, &req );
754 allocA.height = allocB.height = allocation->height;
755 allocA.width = allocB.width = allocation->width;
756 allocA.x = allocB.x = allocB.y = allocA.y = 0;
758 /* Center the captioned widget */
759 if( allocA.width > req.width + HILDON_CAPTION_SPACING )
761 allocA.x += req.width + HILDON_CAPTION_SPACING * 2;
762 allocB.width = req.width;
765 /* Leave room for the other drawable parts of the caption control */
766 allocA.width -= req.width + HILDON_CAPTION_SPACING * 2;
768 /* Give the child at least its minimum requisition, unless it is expandable */
769 if( !priv->expand && child && GTK_WIDGET_VISIBLE(child) )
771 GtkRequisition child_req;
772 gtk_widget_get_child_requisition( child, &child_req );
773 allocA.width = MIN( allocA.width, child_req.width );
774 allocA.height = MIN( allocA.height, child_req.height );
777 /* Ensure there are no negative dimensions */
778 if( allocA.width < 0 )
780 allocB.width = req.width + allocA.width;
782 allocB.width = MAX (allocB.width, 0);
785 allocA.height = MAX (allocA.height, 0);
786 allocB.height = MAX (allocB.height, 0);
788 if (child && GTK_WIDGET_VISIBLE(child) )
789 gtk_widget_size_allocate( child, &allocA );
790 gtk_widget_size_allocate( priv->caption_area, &allocB );
793 static void hildon_caption_forall( GtkContainer *container,
794 gboolean include_internals,
795 GtkCallback callback, gpointer data )
797 HildonCaptionPrivate *priv = NULL;
798 g_return_if_fail( HILDON_IS_CAPTION(container) );
799 priv = HILDON_CAPTION_GET_PRIVATE(container);
801 /* Execute callback for the child widgets */
802 if( GTK_CONTAINER_CLASS(parent_class)->forall )
803 GTK_CONTAINER_CLASS(parent_class)->forall( container, include_internals,
806 if( include_internals )
807 /* Execute callback for the parent box as well */
808 (*callback)( priv->caption_area, data );
813 * hildon_caption_set_sizegroup:
814 * @caption : A #HildonCaption
815 * @new_group : A #GtkSizeGroup
817 * Sets a #GtkSizeGroup of a given captioned control.
819 * Deprecated: Use g_object_set, property "size_group".
821 #ifndef HILDON_DISABLE_DEPRECATED
822 void hildon_caption_set_sizegroup( const HildonCaption *self,
823 GtkSizeGroup *group )
825 g_object_set( G_OBJECT(self), "size_group", group, NULL );
829 * hildon_caption_get_sizegroup:
830 * @caption : A #HildonCaption
831 * @Returns : A #GtkSizeGroup
833 * Query given captioned control for the #GtkSizeGroup assigned to it.
835 * Deprecated: Use g_object_get, property "size_group".
837 #ifndef HILDON_DISABLE_DEPRECATED
838 GtkSizeGroup *hildon_caption_get_sizegroup( const HildonCaption *self )
840 HildonCaptionPrivate *priv;
841 g_return_val_if_fail( HILDON_IS_CAPTION (self), NULL );
842 priv = HILDON_CAPTION_GET_PRIVATE(self);
847 * hildon_caption_new:
848 * @group : a #GtkSizeGroup for controlling the size of related captions.
850 * @value : the caption text to accompany the text entry. The widget makes
851 * a copy of this text.
852 * @control : the control that is to be captioned
853 * @icon : an icon to accompany the label - can be NULL in which case no
855 * @flag : indicates whether this captioned control is mandatory or
857 * @returns : A #GtkWidget pointer of Caption
859 * Creates a new instance of hildon_caption widget, with a specific
861 * Note: Clicking on a focused caption will trigger the activate signal.
862 * The default behaviour for the caption's activate signal is to call
863 * gtk_widget_activate on it's control.
865 GtkWidget *hildon_caption_new( GtkSizeGroup *group, const gchar *value,
866 GtkWidget *control, GtkWidget *icon,
867 HildonCaptionStatus flag)
870 g_return_val_if_fail( GTK_IS_WIDGET(control), NULL );
872 widget = g_object_new( HILDON_TYPE_CAPTION, "label", value,
873 "size_group", group, "icon", icon, "status", flag,
876 /* Pack the captioned widget */
877 hildon_caption_set_child_expand( HILDON_CAPTION(widget), TRUE );
878 gtk_container_add( GTK_CONTAINER(widget), control );
885 * hildon_caption_is_mandatory:
886 * @caption : A #HildonCaption
887 * @returns : is this captioned control a mandatory one?
889 * Query #HildonCaption whether this captioned control is a mandatory one.
893 gboolean hildon_caption_is_mandatory( const HildonCaption *caption )
895 HildonCaptionPrivate *priv;
896 g_return_val_if_fail( HILDON_IS_CAPTION(caption), FALSE );
897 priv = HILDON_CAPTION_GET_PRIVATE(caption);
899 return priv->status == HILDON_CAPTION_MANDATORY;
903 * hildon_caption_set_status:
904 * @caption : A #HildonCaption
905 * @flag : one of the values from #HildonCaptionStatus
907 * Sets #HildonCaption status.
912 void hildon_caption_set_status( HildonCaption *caption,
913 HildonCaptionStatus flag )
915 g_object_set( G_OBJECT(caption), "status", flag, NULL );
919 * hildon_caption_get_status:
920 * @caption : A #HildonCaption
921 * @returns : one of the values from #HildonCaptionStatus
923 * Gets #HildonCaption status.
927 HildonCaptionStatus hildon_caption_get_status( const HildonCaption *caption )
929 HildonCaptionPrivate *priv;
930 g_return_val_if_fail( HILDON_IS_CAPTION(caption), HILDON_CAPTION_OPTIONAL );
931 priv = HILDON_CAPTION_GET_PRIVATE(caption);
937 * hildon_caption_set_icon_image:
938 * @caption : A #HildonCaption
939 * @icon : the #GtkImage to use as the icon.
940 * calls gtk_widget_show on the icon if !GTK_WIDGET_VISIBLE(icon)
942 * Sets the icon to be used by this hildon_caption widget.
946 void hildon_caption_set_icon_image( HildonCaption *caption, GtkWidget *icon )
948 g_object_set( G_OBJECT(caption), "icon", icon, NULL );
952 * hildon_caption_get_icon_image:
953 * @caption : A #HildonCaption
954 * @returns : the #GtkImage that is being used as the icon by the
955 * hildon_caption, or NULL if no icon is in use.
957 * Gets icon of #HildonCaption
961 GtkWidget *hildon_caption_get_icon_image( const HildonCaption *caption )
963 HildonCaptionPrivate *priv;
964 g_return_val_if_fail( HILDON_IS_CAPTION(caption), NULL );
965 priv = HILDON_CAPTION_GET_PRIVATE(caption);
971 * hildon_caption_set_label:
972 * @caption : A #HildonCaption
973 * @label : the text to use
975 * Sets the label text that appears before the control.
976 * Separator character is added to the end of the label string. By default
977 * the separator is ":".
981 void hildon_caption_set_label( HildonCaption *caption, const gchar *label )
983 g_object_set( G_OBJECT(caption), "label", label, NULL );
987 * hildon_caption_get_label:
988 * @caption : A #HildonCaption
989 * @returns : the text currently being used as the label of the caption
990 * control. The string is owned by the label and the caller should never free or
993 * Gets label of #HildonCaption
997 gchar *hildon_caption_get_label( const HildonCaption *caption )
999 HildonCaptionPrivate *priv;
1000 g_return_val_if_fail(HILDON_IS_CAPTION(caption), "");
1001 priv = HILDON_CAPTION_GET_PRIVATE(caption);
1003 return (gchar*)gtk_label_get_text(GTK_LABEL(GTK_LABEL(priv->label)));
1007 * hildon_caption_set_separator:
1008 * @caption : A #HildonCaption
1009 * @separator : the separator to use
1011 * Sets the separator character that appears after the label.
1012 * The default seaparator character is ":"
1018 void hildon_caption_set_separator( HildonCaption *caption,
1019 const gchar *separator )
1021 g_object_set( G_OBJECT(caption), "separator", separator, NULL );
1025 * hildon_caption_get_separator:
1026 * @caption : A #HildonCaption
1027 * @returns : the text currently being used as the separator of the caption
1028 * control. The string is owned by the caption control and the caller should
1029 * never free or modify this value.
1031 * Gets separator string of #HildonCaption
1035 gchar *hildon_caption_get_separator( const HildonCaption *caption )
1037 HildonCaptionPrivate *priv;
1038 g_return_val_if_fail(HILDON_IS_CAPTION(caption), "");
1039 priv = HILDON_CAPTION_GET_PRIVATE(caption);
1041 return priv->separator;
1046 * hildon_caption_get_control:
1047 * @caption : A #HildonCaption
1048 * @returns : A #GtkWidget
1050 * Gets caption's control.
1052 * Deprecated: use gtk_bin_get_child instead
1054 #ifndef HILDON_DISABLE_DEPRECATED
1055 GtkWidget *hildon_caption_get_control( const HildonCaption *caption )
1057 g_return_val_if_fail( HILDON_IS_CAPTION(caption), NULL );
1058 return GTK_BIN(caption)->child;
1061 /*activates the child control
1062 *We have this signal so that if needed an application can
1063 *know when we've been activated (useful for captions with
1066 static void hildon_caption_activate( GtkWidget *widget )
1068 HildonCaptionPrivate *priv;
1069 GtkWidget *child = GTK_BIN(widget)->child;
1070 priv = HILDON_CAPTION_GET_PRIVATE(widget);
1072 /* FIXME: This seems to be related to some functionality
1073 that is already removed? */
1074 if( priv->activate_block )
1076 priv->is_focused = FALSE;
1082 priv->activate_block = TRUE;
1083 gtk_widget_grab_focus( child );
1088 * hildon_caption_set_child_expand:
1089 * @caption : A #HildonCaption
1090 * @expand : gboolean to determine is the child expandable
1092 * Sets child expandability.
1094 void hildon_caption_set_child_expand( HildonCaption *caption, gboolean expand )
1096 HildonCaptionPrivate *priv = NULL;
1097 GtkWidget *child = NULL;
1098 g_return_if_fail( HILDON_IS_CAPTION(caption) );
1100 priv = HILDON_CAPTION_GET_PRIVATE(caption);
1102 /* Did the setting really change? */
1103 if( priv->expand == expand )
1106 priv->expand = expand;
1107 child = GTK_BIN(caption)->child;
1109 /* We do not have a child, nothing to do */
1110 if( !GTK_IS_WIDGET(child) )
1113 if( GTK_WIDGET_VISIBLE (child) && GTK_WIDGET_VISIBLE (caption) )
1114 gtk_widget_queue_resize( child );
1116 gtk_widget_child_notify( child, "expand" );
1120 * hildon_caption_get_child_expand:
1121 * @caption : A #HildonCaption
1122 * @returns : Wheter the child is expandable or not.
1124 * Gets childs expandability.
1126 gboolean hildon_caption_get_child_expand( HildonCaption *caption )
1128 HildonCaptionPrivate *priv = NULL;
1129 g_return_val_if_fail( HILDON_IS_CAPTION(caption), FALSE );
1130 priv = HILDON_CAPTION_GET_PRIVATE(caption);
1131 return priv->expand;
1135 * hildon_caption_set_control:
1136 * @caption : A #HildonCaption
1137 * @control : The control to use. Control should not be NULL.
1139 * Sets the control of the caption.
1140 * The old control will be destroyed, unless the caller has added a
1142 * Function unparents the old control (if there is one) and adds the new
1145 * Deprecated: Use gtk_container_add.
1147 #ifndef HILDON_DISABLE_DEPRECATED
1148 void hildon_caption_set_control( HildonCaption *caption, GtkWidget *control )
1150 GtkWidget *child = NULL;
1151 g_return_if_fail( HILDON_IS_CAPTION(caption) );
1152 child = GTK_BIN(caption)->child;
1155 gtk_container_remove( GTK_CONTAINER(caption), child );
1159 gtk_container_add( GTK_CONTAINER(caption), control );
1168 hildon_caption_set_label_text( HildonCaptionPrivate *priv )
1171 g_return_if_fail ( priv != NULL );
1175 if( priv->separator )
1177 /* Don't duplicate the separator, if the string already contains one */
1178 /* FIXME: The separator was taken from translations originally, it's not
1179 safe to assume that to be a certain constant. */
1180 if( !strcmp( priv->separator, ":" ) &&
1181 priv->text [strlen ( priv->text ) - 1] == ':')
1183 gtk_label_set_text( GTK_LABEL( priv->label ), priv->text );
1187 /* Append separator and set text */
1188 tmp = g_strconcat( priv->text, priv->separator, NULL );
1189 gtk_label_set_text( GTK_LABEL( priv->label ), tmp );
1195 gtk_label_set_text( GTK_LABEL( priv->label ), priv->text );
1200 /* Clear the label */
1201 gtk_label_set_text( GTK_LABEL( priv->label ), "" );
1207 * hildon_caption_set_label_alignment:
1208 * @caption: a #HildonCaption widget.
1209 * @alignment: new vertical alignment.
1211 * Sets the vertical alignment to be used for the
1212 * text part of the caption. Applications need to
1213 * align the child control themselves.
1215 void hildon_caption_set_label_alignment(HildonCaption *caption,
1218 HildonCaptionPrivate *priv;
1220 g_return_if_fail(HILDON_IS_CAPTION(caption));
1222 priv = HILDON_CAPTION_GET_PRIVATE(caption);
1223 g_object_set(priv->label, "yalign", alignment, NULL);
1224 g_object_set(priv->icon_align, "yalign", alignment, NULL);
1226 if (priv->mandatory_icon)
1227 g_object_set(priv->mandatory_icon, "yalign", alignment, NULL);
1231 * hildon_caption_get_label_alignment:
1232 * @caption: a #HildonCaption widget.
1234 * Gets current vertical alignment for the text part.
1236 * Returns: vertical alignment.
1238 gfloat hildon_caption_get_label_alignment(HildonCaption *caption)
1240 HildonCaptionPrivate *priv;
1243 g_return_val_if_fail( HILDON_IS_CAPTION(caption), 0);
1244 priv = HILDON_CAPTION_GET_PRIVATE(caption);
1245 g_object_get(priv->label, "yalign", &result, NULL);