/* $Id: guppi-multiview.c,v 1.8 2001/07/10 02:53:26 trow Exp $ */ /* guppi-multiview.c * * Copyright (C) 2000 Jonathan Blandford * * Modified for use in Guppi by Jon Trowbridge * * This 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. * * 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. * * 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., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include #include "guppi-multiview.h" /* #include */ #include "guppi-memory.h" static void guppi_multiview_init (GuppiMultiview * multiview); static void guppi_multiview_class_init (GuppiMultiviewClass * klass); static void guppi_multiview_size_request (GtkWidget * widget, GtkRequisition * requisition); static void guppi_multiview_size_allocate (GtkWidget * widget, GtkAllocation * allocation); static void guppi_multiview_map (GtkWidget * widget); static void guppi_multiview_unmap (GtkWidget * widget); static int guppi_multiview_expose (GtkWidget * widget, GdkEventExpose * event); static GtkType guppi_multiview_child_type (GtkContainer * container); static void guppi_multiview_forall (GtkContainer * container, gboolean include_internals, GtkCallback callback, gpointer callback_data); static void guppi_multiview_add (GtkContainer * widget, GtkWidget * child); static void guppi_multiview_remove (GtkContainer * widget, GtkWidget * child); static GtkContainerClass *parent_class = NULL; GtkType guppi_multiview_get_type (void) { static GtkType multiview_type = 0; if (!multiview_type) { static const GtkTypeInfo multiview_info = { "GuppiMultiview", sizeof (GuppiMultiview), sizeof (GuppiMultiviewClass), (GtkClassInitFunc) guppi_multiview_class_init, (GtkObjectInitFunc) guppi_multiview_init, /* reserved_1 */ NULL, /* reserved_2 */ NULL, (GtkClassInitFunc) NULL, }; multiview_type = gtk_type_unique (gtk_container_get_type (), &multiview_info); } return multiview_type; } static void guppi_multiview_init (GuppiMultiview * multiview) { GTK_WIDGET_SET_FLAGS (GTK_WIDGET (multiview), GTK_NO_WINDOW); multiview->current = NULL; multiview->children = NULL; } static void finalize (GtkObject *obj) { guppi_finalized (obj); if (GTK_OBJECT_CLASS (parent_class)->finalize) GTK_OBJECT_CLASS (parent_class)->finalize (obj); } static void guppi_multiview_class_init (GuppiMultiviewClass * klass) { GtkObjectClass *object_class; GtkWidgetClass *widget_class; GtkContainerClass *container_class; object_class = (GtkObjectClass *) klass; widget_class = (GtkWidgetClass *) klass; container_class = (GtkContainerClass *) klass; parent_class = gtk_type_class (gtk_container_get_type ()); object_class->finalize = finalize; widget_class->size_request = guppi_multiview_size_request; widget_class->size_allocate = guppi_multiview_size_allocate; widget_class->map = guppi_multiview_map; widget_class->unmap = guppi_multiview_unmap; widget_class->expose_event = guppi_multiview_expose; container_class->forall = guppi_multiview_forall; container_class->add = guppi_multiview_add; container_class->remove = guppi_multiview_remove; container_class->child_type = guppi_multiview_child_type; } static void guppi_multiview_size_request (GtkWidget * widget, GtkRequisition * requisition) { GList *tmp_list; GuppiMultiview *multiview; GtkRequisition child_requisition; GtkWidget *child; multiview = GUPPI_MULTIVIEW (widget); requisition->width = 0; requisition->height = 0; /* We find the maximum size of all children widgets */ tmp_list = multiview->children; while (tmp_list) { child = GTK_WIDGET (tmp_list->data); tmp_list = tmp_list->next; if (GTK_WIDGET_VISIBLE (child)) { gtk_widget_size_request (child, &child_requisition); requisition->width = MAX (requisition->width, child_requisition.width); requisition->height = MAX (requisition->height, child_requisition.height); if (GTK_WIDGET_MAPPED (child) && child != multiview->current) { gtk_widget_unmap (GTK_WIDGET (child)); } } } } static void guppi_multiview_size_allocate (GtkWidget * widget, GtkAllocation * allocation) { GuppiMultiview *multiview; GList *tmp_list; GtkWidget *child; g_return_if_fail (widget != NULL); g_return_if_fail (GUPPI_IS_MULTIVIEW (widget)); multiview = GUPPI_MULTIVIEW (widget); widget->allocation = *allocation; tmp_list = multiview->children; while (tmp_list) { child = GTK_WIDGET (tmp_list->data); tmp_list = tmp_list->next; if (GTK_WIDGET_VISIBLE (child)) { gtk_widget_size_allocate (child, allocation); } } } static void guppi_multiview_map (GtkWidget * widget) { GuppiMultiview *multiview; g_return_if_fail (widget != NULL); g_return_if_fail (GUPPI_IS_MULTIVIEW (widget)); multiview = GUPPI_MULTIVIEW (widget); GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED); if (multiview->current && GTK_WIDGET_VISIBLE (multiview->current) && !GTK_WIDGET_MAPPED (multiview->current)) { gtk_widget_map (GTK_WIDGET (multiview->current)); } } static void guppi_multiview_unmap (GtkWidget * widget) { GuppiMultiview *multiview; g_return_if_fail (widget != NULL); g_return_if_fail (GUPPI_IS_MULTIVIEW (widget)); multiview = GUPPI_MULTIVIEW (widget); GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED); if (multiview->current && GTK_WIDGET_VISIBLE (multiview->current) && GTK_WIDGET_MAPPED (multiview->current)) { gtk_widget_unmap (GTK_WIDGET (multiview->current)); } } static gint guppi_multiview_expose (GtkWidget * widget, GdkEventExpose * event) { GuppiMultiview *multiview; GtkWidget *child; GList *tmp_list; GdkEventExpose child_event; g_return_val_if_fail (widget != NULL, FALSE); g_return_val_if_fail (GUPPI_IS_MULTIVIEW (widget), FALSE); g_return_val_if_fail (event != NULL, FALSE); if (GTK_WIDGET_DRAWABLE (widget)) { multiview = GUPPI_MULTIVIEW (widget); child_event = *event; tmp_list = multiview->children; while (tmp_list) { child = GTK_WIDGET (tmp_list->data); tmp_list = tmp_list->next; if (GTK_WIDGET_DRAWABLE (child) && GTK_WIDGET_NO_WINDOW (child)) { gtk_widget_event (child, (GdkEvent *) event); } } } return FALSE; } static GtkType guppi_multiview_child_type (GtkContainer * container) { return gtk_widget_get_type (); } static void guppi_multiview_forall (GtkContainer * container, gboolean include_internals, GtkCallback callback, gpointer callback_data) { GtkWidget *child; GuppiMultiview *multiview; GList *tmp_list; g_return_if_fail (container != NULL); g_return_if_fail (GUPPI_IS_MULTIVIEW (container)); g_return_if_fail (callback != NULL); multiview = GUPPI_MULTIVIEW (container); tmp_list = multiview->children; while (tmp_list) { child = tmp_list->data; tmp_list = tmp_list->next; (*callback) (GTK_WIDGET (child), callback_data); } } static void guppi_multiview_add (GtkContainer * container, GtkWidget * child) { g_return_if_fail (container != NULL); g_return_if_fail (GUPPI_IS_MULTIVIEW (container)); g_return_if_fail (child != NULL); g_return_if_fail (GTK_IS_WIDGET (child)); guppi_multiview_append_child (GUPPI_MULTIVIEW (container), child); } static void guppi_multiview_remove (GtkContainer * container, GtkWidget * child) { GuppiMultiview *multiview; GList *list; g_return_if_fail (container != NULL); g_return_if_fail (GUPPI_IS_MULTIVIEW (container)); g_return_if_fail (child != NULL); multiview = GUPPI_MULTIVIEW (container); list = g_list_find (multiview->children, child); g_return_if_fail (list != NULL); /* If we are mapped and visible, we want to deal with changing the page. */ if ((GTK_WIDGET_MAPPED (GTK_WIDGET (container))) && (list->data == (gpointer) multiview->current)) { if (list->next != NULL) guppi_multiview_set_current (multiview, GTK_WIDGET (list->next->data)); else multiview->current = NULL; } multiview->children = g_list_remove (multiview->children, child); gtk_widget_unparent (child); } /* Public Functions */ GtkWidget * guppi_multiview_new (void) { return GTK_WIDGET (guppi_type_new (guppi_multiview_get_type ())); } void guppi_multiview_prepend_child (GuppiMultiview * multiview, GtkWidget * child) { g_return_if_fail (multiview != NULL); g_return_if_fail (GUPPI_IS_MULTIVIEW (multiview)); g_return_if_fail (child != NULL); g_return_if_fail (GTK_IS_WIDGET (child)); guppi_multiview_insert_child (multiview, NULL, child); } void guppi_multiview_insert_child (GuppiMultiview * multiview, GtkWidget * back_child, GtkWidget * child) { GList *list; g_return_if_fail (multiview != NULL); g_return_if_fail (GUPPI_IS_MULTIVIEW (multiview)); g_return_if_fail (child != NULL); g_return_if_fail (GTK_IS_WIDGET (child)); list = g_list_find (multiview->children, back_child); if (list == NULL) { multiview->children = g_list_prepend (multiview->children, child); } else { GList *new_el = g_list_alloc (); new_el->next = list->next; new_el->prev = list; if (new_el->next) new_el->next->prev = new_el; new_el->prev->next = new_el; new_el->data = (gpointer) child; } gtk_widget_set_parent (GTK_WIDGET (child), GTK_WIDGET (multiview)); if (GTK_WIDGET_REALIZED (GTK_WIDGET (multiview))) gtk_widget_realize (GTK_WIDGET (child)); if (GTK_WIDGET_VISIBLE (GTK_WIDGET (multiview)) && GTK_WIDGET_VISIBLE (GTK_WIDGET (child))) { if (GTK_WIDGET_MAPPED (GTK_WIDGET (child))) gtk_widget_unmap (GTK_WIDGET (child)); gtk_widget_queue_resize (GTK_WIDGET (multiview)); } /* if it's the first and only entry, we want to bring it to the foreground. */ if (multiview->children->next == NULL) guppi_multiview_set_current (multiview, child); } void guppi_multiview_append_child (GuppiMultiview * multiview, GtkWidget * child) { GList *list; g_return_if_fail (multiview != NULL); g_return_if_fail (GUPPI_IS_MULTIVIEW (multiview)); g_return_if_fail (child != NULL); g_return_if_fail (GTK_IS_WIDGET (child)); list = g_list_last (multiview->children); if (list) { guppi_multiview_insert_child (multiview, GTK_WIDGET (list->data), child); } else { guppi_multiview_insert_child (multiview, NULL, child); } } gboolean guppi_multiview_contains (GuppiMultiview * multiview, GtkWidget * child) { g_return_val_if_fail (multiview != NULL, FALSE); g_return_val_if_fail (GUPPI_IS_MULTIVIEW (multiview), FALSE); g_return_val_if_fail (child != NULL, FALSE); g_return_val_if_fail (GTK_IS_WIDGET (child), FALSE); return g_list_find (multiview->children, child) != NULL; } void guppi_multiview_set_current (GuppiMultiview * multiview, GtkWidget * child) { GList *list; GtkWidget *old = NULL; g_return_if_fail (multiview != NULL); g_return_if_fail (GUPPI_IS_MULTIVIEW (multiview)); g_return_if_fail (child != NULL); g_return_if_fail (GTK_IS_WIDGET (child)); if (multiview->current == child) return; list = g_list_find (multiview->children, child); g_return_if_fail (list != NULL); if ((multiview->current) && (GTK_WIDGET_VISIBLE (multiview->current)) && (GTK_WIDGET_MAPPED (multiview))) { old = GTK_WIDGET (multiview->current); } multiview->current = GTK_WIDGET (list->data); if (GTK_WIDGET_VISIBLE (multiview->current) && (GTK_WIDGET_MAPPED (multiview))) { gtk_widget_map (multiview->current); } if (old && GTK_WIDGET_MAPPED (old)) gtk_widget_unmap (old); gtk_widget_show_all (multiview->current); }