GTK+ / Gnome Application Development | |||
---|---|---|---|
<<< Previous | Home | Next >>> |
This section quickly describes the GnomeAppBar widget; GnomeAppBar demonstrates how to bundle a pre-packed container and some special functionality into a single new object. the section called GnomeAppBar in the chapter called The Main Window: GnomeApp describes GnomeAppBar from a user's point of view.
A composite widget derives from some kind of container, then adds child widgets and sets up callbacks to implement some sort of functionality. GnomeAppBar derives from GtkHBox; the box is packed with a progress bar and/or a status line. GnomeAppBar has members in its instance struct to store a stack of status messages, and it adds some signals to the class struct for use with its "interactive" mode.
As an aside, GnomeAppBar does not follow the GTK+/Gnome naming conventions; because Bar is capitalized, the functions and macros should have an underscore, i.e. app_bar rather than appbar. Don't copy this aspect of the widget.
Here's the implementation of gnome_appbar_new():
GtkWidget* gnome_appbar_new (gboolean has_progress, gboolean has_status, GnomePreferencesType interactivity) { GnomeAppBar * ab = gtk_type_new (gnome_appbar_get_type ()); gnome_appbar_construct(ab, has_progress, has_status, interactivity); return GTK_WIDGET(ab); } void gnome_appbar_construct(GnomeAppBar * ab, gboolean has_progress, gboolean has_status, GnomePreferencesType interactivity) { GtkBox *box; g_return_if_fail( ((has_status == FALSE) && (interactivity == GNOME_PREFERENCES_NEVER)) || (has_status == TRUE)); box = GTK_BOX (ab); box->spacing = GNOME_PAD_SMALL; box->homogeneous = FALSE; if (has_progress) ab->progress = gtk_progress_bar_new(); else ab->progress = NULL; /* * If the progress meter goes on the right then we place it after we * create the status line. */ if (has_progress && !gnome_preferences_get_statusbar_meter_on_right ()) gtk_box_pack_start (box, ab->progress, FALSE, FALSE, 0); if ( has_status ) { if ( (interactivity == GNOME_PREFERENCES_ALWAYS) || ( (interactivity == GNOME_PREFERENCES_USER) && gnome_preferences_get_statusbar_interactive()) ) { ab->interactive = TRUE; ab->status = gtk_entry_new(); gtk_signal_connect (GTK_OBJECT(ab->status), "delete_text", GTK_SIGNAL_FUNC(entry_delete_text_cb), ab); gtk_signal_connect (GTK_OBJECT(ab->status), "insert_text", GTK_SIGNAL_FUNC(entry_insert_text_cb), ab); gtk_signal_connect_after(GTK_OBJECT(ab->status), "key_press_event", GTK_SIGNAL_FUNC(entry_key_press_cb), ab); gtk_signal_connect(GTK_OBJECT(ab->status), "activate", GTK_SIGNAL_FUNC(entry_activate_cb), ab); /* no prompt now */ gtk_entry_set_editable(GTK_ENTRY(ab->status), FALSE); gtk_box_pack_start (box, ab->status, TRUE, TRUE, 0); } else { GtkWidget * frame; ab->interactive = FALSE; frame = gtk_frame_new (NULL); gtk_frame_set_shadow_type (GTK_FRAME(frame), GTK_SHADOW_IN); ab->status = gtk_label_new (""); gtk_misc_set_alignment (GTK_MISC (ab->status), 0.0, 0.0); gtk_box_pack_start (box, frame, TRUE, TRUE, 0); gtk_container_add (GTK_CONTAINER(frame), ab->status); gtk_widget_show (frame); } } else { ab->status = NULL; ab->interactive = FALSE; } if (has_progress && gnome_preferences_get_statusbar_meter_on_right ()) gtk_box_pack_start (box, ab->progress, FALSE, FALSE, 0); if (ab->status) gtk_widget_show (ab->status); if (ab->progress) gtk_widget_show(ab->progress); } |
Most of this code could be in the instance initializer; it's in the constructor instead because it's dependent on the arguments passed to gnome_appbar_new(). There's not much to explain here; the code is straightforward. Do notice that gtk_widget_show() is called for each child widget; this ensures that the right thing happens when the user calls gtk_widget_show() on GnomeAppBar. Another approach would be to override the map method and map all children (normally, containers such as GtkBox only map children that have been shown). When you're writing a composite container, keep the gtk_widget_show_all() function in mind; never rely on hiding child widgets, because the user might accidentally show them.
A composite widget is just a special case of extending a base widget with additional functionality. You can extend widgets without adding new children to them; for example, GtkClock extends GtkLabel by constantly changing the label to reflect the time.