| 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.