/*----------------------------------------------------------------------------* * .---. * * PornView (_,/\ \ * * photo/movie collection viewer and manager (`a a( ) * * trem0r ) \= ) ( * * (c) 2002 (.--' '--.) * * / (_)^(_) \ * *----------------------------------------------------------------------------*/ /* * These codes are taken from gThumb. * gThumb code Copyright (C) 2001 The Free Software Foundation, Inc. * gThumb author: Paolo Bacchilega */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "gedo-paned.h" #ifndef USE_NORMAL_PANED #ifndef GTK_OBJECT_GET_CLASS #define GTK_OBJECT_GET_CLASS(object) \ GTK_OBJECT (object)->klass #endif char gray50_bits[] = { 0x02, 0x01 }; enum { ARG_0, ARG_GUTTER_SIZE }; static void gedo_paned_class_init (GedoPanedClass * klass); static void gedo_paned_init (GedoPaned * paned); static void gedo_paned_set_arg (GtkObject * object, GtkArg * arg, guint arg_id); static void gedo_paned_get_arg (GtkObject * object, GtkArg * arg, guint arg_id); static void gedo_paned_realize (GtkWidget * widget); static void gedo_paned_map (GtkWidget * widget); static void gedo_paned_unmap (GtkWidget * widget); static void gedo_paned_unrealize (GtkWidget * widget); static gint gedo_paned_expose (GtkWidget * widget, GdkEventExpose * event); static void gedo_paned_add (GtkContainer * container, GtkWidget * widget); static void gedo_paned_remove (GtkContainer * container, GtkWidget * widget); static void gedo_paned_forall (GtkContainer * container, gboolean include_internals, GtkCallback callback, gpointer callback_data); static GtkType gedo_paned_child_type (GtkContainer * container); static gint gedo_paned_motion (GtkWidget * widget, GdkEventMotion * event); static GtkContainerClass *parent_class = NULL; GtkType gedo_paned_get_type (void) { static GtkType paned_type = 0; if (!paned_type) { static const GtkTypeInfo paned_info = { "GedoPaned", sizeof (GedoPaned), sizeof (GedoPanedClass), (GtkClassInitFunc) gedo_paned_class_init, (GtkObjectInitFunc) gedo_paned_init, /* * reserved_1 */ NULL, /* * reserved_2 */ NULL, (GtkClassInitFunc) NULL, }; paned_type = gtk_type_unique (GTK_TYPE_CONTAINER, &paned_info); } return paned_type; } static void gedo_paned_virtual_xor_line (GedoPaned * paned) { g_warning ("gedo_paned_virtual_xor_line reached !"); } static void gedo_paned_class_init (GedoPanedClass * class) { GtkObjectClass *object_class; GtkWidgetClass *widget_class; GtkContainerClass *container_class; object_class = (GtkObjectClass *) class; widget_class = (GtkWidgetClass *) class; container_class = (GtkContainerClass *) class; parent_class = gtk_type_class (GTK_TYPE_CONTAINER); object_class->set_arg = gedo_paned_set_arg; object_class->get_arg = gedo_paned_get_arg; widget_class->realize = gedo_paned_realize; widget_class->map = gedo_paned_map; widget_class->unmap = gedo_paned_unmap; widget_class->unrealize = gedo_paned_unrealize; widget_class->expose_event = gedo_paned_expose; widget_class->motion_notify_event = gedo_paned_motion; container_class->add = gedo_paned_add; container_class->remove = gedo_paned_remove; container_class->forall = gedo_paned_forall; container_class->child_type = gedo_paned_child_type; class->xor_line = gedo_paned_virtual_xor_line; gtk_object_add_arg_type ("GedoPaned::gutter_size", GTK_TYPE_UINT, GTK_ARG_READWRITE, ARG_GUTTER_SIZE); } static GtkType gedo_paned_child_type (GtkContainer * container) { if (!GEDO_PANED (container)->child1 || !GEDO_PANED (container)->child2) return GTK_TYPE_WIDGET; else return GTK_TYPE_NONE; } static void gedo_paned_init (GedoPaned * paned) { GTK_WIDGET_UNSET_FLAGS (paned, GTK_NO_WINDOW); paned->child1 = NULL; paned->child2 = NULL; paned->handle = NULL; paned->xor_gc = NULL; paned->gutter_size = 6; paned->position_set = FALSE; paned->last_allocation = -1; paned->in_drag = FALSE; paned->handle_xpos = -1; paned->handle_ypos = -1; paned->horizontal = TRUE; paned->child1_minsize = 0; paned->child2_minsize = 0; paned->child1_use_minsize = FALSE; paned->child2_use_minsize = FALSE; paned->child_hidden = 0; } static void gedo_paned_set_arg (GtkObject * object, GtkArg * arg, guint arg_id) { GedoPaned *paned = GEDO_PANED (object); switch (arg_id) { case ARG_GUTTER_SIZE: gedo_paned_set_gutter_size (paned, GTK_VALUE_UINT (*arg)); break; } } static void gedo_paned_get_arg (GtkObject * object, GtkArg * arg, guint arg_id) { GedoPaned *paned = GEDO_PANED (object); switch (arg_id) { case ARG_GUTTER_SIZE: GTK_VALUE_UINT (*arg) = paned->gutter_size; break; default: arg->type = GTK_TYPE_INVALID; break; } } static void gedo_paned_realize (GtkWidget * widget) { GedoPaned *paned; GdkWindowAttr attributes; gint attributes_mask; g_return_if_fail (widget != NULL); g_return_if_fail (GEDO_IS_PANED (widget)); GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED); paned = GEDO_PANED (widget); attributes.x = widget->allocation.x; attributes.y = widget->allocation.y; attributes.width = widget->allocation.width; attributes.height = widget->allocation.height; attributes.window_type = GDK_WINDOW_CHILD; attributes.wclass = GDK_INPUT_OUTPUT; attributes.visual = gtk_widget_get_visual (widget); attributes.colormap = gtk_widget_get_colormap (widget); attributes.event_mask = gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK; attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask); gdk_window_set_user_data (widget->window, paned); attributes.x = paned->handle_xpos; attributes.y = paned->handle_ypos; if (paned->horizontal) { attributes.width = paned->gutter_size; attributes.height = widget->allocation.height; attributes.cursor = gdk_cursor_new (GDK_SB_H_DOUBLE_ARROW); } else { attributes.width = widget->allocation.width; attributes.height = paned->gutter_size; attributes.cursor = gdk_cursor_new (GDK_SB_V_DOUBLE_ARROW); } attributes.event_mask |= (GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK); attributes_mask |= GDK_WA_CURSOR; paned->handle = gdk_window_new (widget->window, &attributes, attributes_mask); gdk_window_set_user_data (paned->handle, paned); gdk_cursor_destroy (attributes.cursor); widget->style = gtk_style_attach (widget->style, widget->window); gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL); gtk_style_set_background (widget->style, paned->handle, GTK_STATE_NORMAL); gdk_window_set_back_pixmap (widget->window, NULL, TRUE); gdk_window_show (paned->handle); } static void gedo_paned_map (GtkWidget * widget) { GedoPaned *paned; g_return_if_fail (widget != NULL); g_return_if_fail (GEDO_IS_PANED (widget)); GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED); paned = GEDO_PANED (widget); if (paned->child1 && GTK_WIDGET_VISIBLE (paned->child1) && !GTK_WIDGET_MAPPED (paned->child1)) gtk_widget_map (paned->child1); if (paned->child2 && GTK_WIDGET_VISIBLE (paned->child2) && !GTK_WIDGET_MAPPED (paned->child2)) gtk_widget_map (paned->child2); gdk_window_show (widget->window); } static void gedo_paned_unmap (GtkWidget * widget) { g_return_if_fail (widget != NULL); g_return_if_fail (GEDO_IS_PANED (widget)); GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED); gdk_window_hide (widget->window); } static void gedo_paned_unrealize (GtkWidget * widget) { GedoPaned *paned; g_return_if_fail (widget != NULL); g_return_if_fail (GEDO_IS_PANED (widget)); paned = GEDO_PANED (widget); if (paned->xor_gc) { gdk_gc_destroy (paned->xor_gc); paned->xor_gc = NULL; } if (paned->handle) { gdk_window_set_user_data (paned->handle, NULL); gdk_window_destroy (paned->handle); paned->handle = NULL; } if (GTK_WIDGET_CLASS (parent_class)->unrealize) (*GTK_WIDGET_CLASS (parent_class)->unrealize) (widget); } static gint gedo_paned_expose (GtkWidget * widget, GdkEventExpose * event) { GedoPaned *paned; GdkEventExpose child_event; g_return_val_if_fail (widget != NULL, FALSE); g_return_val_if_fail (GEDO_IS_PANED (widget), FALSE); g_return_val_if_fail (event != NULL, FALSE); if (GTK_WIDGET_DRAWABLE (widget)) { paned = GEDO_PANED (widget); /* * An expose event for the handle */ if (event->window == paned->handle) { gint width, height; gdk_window_get_size (paned->handle, &width, &height); gtk_paint_flat_box (widget->style, paned->handle, GTK_WIDGET_STATE (widget), GTK_SHADOW_NONE, &event->area, widget, "paned", 0, 0, width, height); } else { child_event = *event; if (paned->child1 && GTK_WIDGET_NO_WINDOW (paned->child1) && gtk_widget_intersect (paned->child1, &event->area, &child_event.area)) gtk_widget_event (paned->child1, (GdkEvent *) & child_event); if (paned->child2 && GTK_WIDGET_NO_WINDOW (paned->child2) && gtk_widget_intersect (paned->child2, &event->area, &child_event.area)) gtk_widget_event (paned->child2, (GdkEvent *) & child_event); } } return FALSE; } void gedo_paned_add1 (GedoPaned * paned, GtkWidget * widget) { gedo_paned_pack1 (paned, widget, FALSE, TRUE); } void gedo_paned_add2 (GedoPaned * paned, GtkWidget * widget) { gedo_paned_pack2 (paned, widget, TRUE, TRUE); } void gedo_paned_pack1 (GedoPaned * paned, GtkWidget * child, gboolean resize, gboolean shrink) { g_return_if_fail (paned != NULL); g_return_if_fail (GEDO_IS_PANED (paned)); g_return_if_fail (GTK_IS_WIDGET (child)); if (!paned->child1) { paned->child1 = child; paned->child1_resize = resize; paned->child1_shrink = shrink; gtk_widget_set_parent (child, GTK_WIDGET (paned)); if (GTK_WIDGET_REALIZED (child->parent)) gtk_widget_realize (child); if (GTK_WIDGET_VISIBLE (child->parent) && GTK_WIDGET_VISIBLE (child)) { if (GTK_WIDGET_MAPPED (child->parent)) gtk_widget_map (child); gtk_widget_queue_resize (child); } } } void gedo_paned_pack2 (GedoPaned * paned, GtkWidget * child, gboolean resize, gboolean shrink) { g_return_if_fail (paned != NULL); g_return_if_fail (GEDO_IS_PANED (paned)); g_return_if_fail (GTK_IS_WIDGET (child)); if (!paned->child2) { paned->child2 = child; paned->child2_resize = resize; paned->child2_shrink = shrink; gtk_widget_set_parent (child, GTK_WIDGET (paned)); if (GTK_WIDGET_REALIZED (child->parent)) gtk_widget_realize (child); if (GTK_WIDGET_VISIBLE (child->parent) && GTK_WIDGET_VISIBLE (child)) { if (GTK_WIDGET_MAPPED (child->parent)) gtk_widget_map (child); gtk_widget_queue_resize (child); } } } static void gedo_paned_add (GtkContainer * container, GtkWidget * widget) { GedoPaned *paned; g_return_if_fail (container != NULL); g_return_if_fail (GEDO_IS_PANED (container)); g_return_if_fail (widget != NULL); paned = GEDO_PANED (container); if (!paned->child1) gedo_paned_add1 (GEDO_PANED (container), widget); else if (!paned->child2) gedo_paned_add2 (GEDO_PANED (container), widget); } static void gedo_paned_remove (GtkContainer * container, GtkWidget * widget) { GedoPaned *paned; gboolean was_visible; g_return_if_fail (container != NULL); g_return_if_fail (GEDO_IS_PANED (container)); g_return_if_fail (widget != NULL); paned = GEDO_PANED (container); was_visible = GTK_WIDGET_VISIBLE (widget); if (paned->child1 == widget) { gtk_widget_unparent (widget); paned->child1 = NULL; if (was_visible && GTK_WIDGET_VISIBLE (container)) gtk_widget_queue_resize (GTK_WIDGET (container)); } else if (paned->child2 == widget) { gtk_widget_unparent (widget); paned->child2 = NULL; if (was_visible && GTK_WIDGET_VISIBLE (container)) gtk_widget_queue_resize (GTK_WIDGET (container)); } } static void gedo_paned_forall (GtkContainer * container, gboolean include_internals, GtkCallback callback, gpointer callback_data) { GedoPaned *paned; g_return_if_fail (container != NULL); g_return_if_fail (GEDO_IS_PANED (container)); g_return_if_fail (callback != NULL); paned = GEDO_PANED (container); if (paned->child1) (*callback) (paned->child1, callback_data); if (paned->child2) (*callback) (paned->child2, callback_data); } void gedo_paned_set_position (GedoPaned * paned, gint position) { g_return_if_fail (paned != NULL); g_return_if_fail (GEDO_IS_PANED (paned)); if (position >= 0) { /* * We don't clamp here - the assumption is that * if the total allocation changes at the same time * as the position, the position set is with reference * to the new total size. If only the position changes, * then clamping will occur in gedo_paned_compute_position() */ paned->child1_size = position; paned->position_set = TRUE; paned->child_hidden = 0; } else paned->position_set = FALSE; gtk_widget_queue_resize (GTK_WIDGET (paned)); } gint gedo_paned_get_position (GedoPaned * paned) { g_return_val_if_fail (paned != NULL, 0); g_return_val_if_fail (GEDO_IS_PANED (paned), 0); return paned->child1_size; } void gedo_paned_set_gutter_size (GedoPaned * paned, guint16 size) { g_return_if_fail (paned != NULL); g_return_if_fail (GEDO_IS_PANED (paned)); paned->gutter_size = size; if (GTK_WIDGET_VISIBLE (GTK_WIDGET (paned))) gtk_widget_queue_resize (GTK_WIDGET (paned)); } void gedo_paned_xor_line (GedoPaned * paned) { GEDO_PANED_CLASS (GTK_OBJECT_GET_CLASS (paned))->xor_line (paned); } /* * gedo_paned_child1_use_minsize: Set a minimum size for child 1. * @paned: The paned object. * @use_minsize: Whether or not to use the minimum size option. * @minsize: The minimun size to use if the option is enabled. * * If @use_minsize = TRUE then set @minsize as the minimal size child 1 can * be set to. * If @use_minsize = FALSE then disable this option, that is, child 1 can have * any size. */ void gedo_paned_child1_use_minsize (GedoPaned * paned, gboolean use_minsize, gint minsize) { g_return_if_fail (paned != NULL); g_return_if_fail (GEDO_IS_PANED (paned)); paned->child1_use_minsize = use_minsize; if (use_minsize) paned->child1_minsize = minsize; } /* * gedo_paned_child1_use_minsize: Set a minimum size for child 2. * @paned: The paned object. * @use_minsize: Whether or not to use the minimum size option. * @minsize: The minimun size to use if the option is enabled. * * If @use_minsize = TRUE then set @minsize as the minimal size child 2 can * be set to. * If @use_minsize = FALSE then disable this option, that is, child 2 can have * any size. */ void gedo_paned_child2_use_minsize (GedoPaned * paned, gboolean use_minsize, gint minsize) { g_return_if_fail (paned != NULL); g_return_if_fail (GEDO_IS_PANED (paned)); paned->child2_use_minsize = use_minsize; if (use_minsize) paned->child2_minsize = minsize; } void gedo_paned_compute_position (GedoPaned * paned, gint allocation, gint child1_req, gint child2_req) { gint child2_size; g_return_if_fail (paned != NULL); g_return_if_fail (GEDO_IS_PANED (paned)); paned->min_position = paned->child1_shrink ? 0 : child1_req; paned->max_position = allocation; if (!paned->child2_shrink) paned->max_position = MAX (1, paned->max_position - child2_req); if (!paned->position_set) { if (paned->child1_resize && !paned->child2_resize) paned->child1_size = MAX (1, allocation - child2_req); else if (!paned->child1_resize && paned->child2_resize) paned->child1_size = child1_req; else if (child1_req + child2_req != 0) paned->child1_size = allocation * ((gdouble) child1_req / (child1_req + child2_req)); else paned->child1_size = allocation * 0.5; } else { /* * If the position was set before the initial allocation. * (paned->last_allocation <= 0) just clamp it and leave it. */ if (paned->last_allocation > 0) { if (paned->child1_resize && !paned->child2_resize) paned->child1_size += (allocation - paned->last_allocation); else if (!(!paned->child1_resize && paned->child2_resize)) paned->child1_size = allocation * ((gdouble) paned->child1_size / (paned->last_allocation)); } } paned->child1_size = CLAMP (paned->child1_size, paned->min_position, paned->max_position); child2_size = allocation - paned->child1_size; /* * Ensure that minimum sizes, if enabled, are respected. */ if (paned->child1_use_minsize) { if (paned->child1_size < paned->child1_minsize) paned->child1_size = paned->child1_minsize; } else if (paned->child2_use_minsize) { if (child2_size < paned->child2_minsize) paned->child1_size = paned->child2_minsize; } if (paned->child_hidden == 1) paned->child1_size = 0; else if (paned->child_hidden == 2) { paned->child1_size = allocation; paned->child1_size += paned->gutter_size; } paned->last_allocation = allocation; } /* * gedo_paned_hide_child1: hide child 1. * @paned: The paned widget. * * Hide the child number 1. */ void gedo_paned_hide_child1 (GedoPaned * paned) { g_return_if_fail (paned != NULL); g_return_if_fail (GEDO_IS_PANED (paned)); if (paned->child_hidden != 0) return; paned->child_hidden = 1; gtk_widget_queue_resize (GTK_WIDGET (paned)); } /* * gedo_paned_hide_child2: collapse child 2. * @paned: The paned widget. * * Hide the child number 2. */ void gedo_paned_hide_child2 (GedoPaned * paned) { g_return_if_fail (paned != NULL); g_return_if_fail (GEDO_IS_PANED (paned)); if (paned->child_hidden != 0) return; paned->child_hidden = 2; gtk_widget_queue_resize (GTK_WIDGET (paned)); } /* * gedo_paned_split: split the paned widget in two halves. * @paned: The paned widget. * * Give both children the same size. */ void gedo_paned_split (GedoPaned * paned) { g_return_if_fail (paned != NULL); g_return_if_fail (GEDO_IS_PANED (paned)); gedo_paned_set_position (paned, paned->last_allocation / 2); } guint gedo_paned_which_hidden (GedoPaned * paned) { g_return_val_if_fail (paned != NULL, 0); g_return_val_if_fail (GEDO_IS_PANED (paned), 0); return paned->child_hidden; } static gint gedo_paned_motion (GtkWidget * widget, GdkEventMotion * event) { GedoPaned *paned; gint pos; static gint last_size = -1; g_return_val_if_fail (widget != NULL, FALSE); g_return_val_if_fail (GEDO_IS_PANED (widget), FALSE); paned = GEDO_PANED (widget); if (event->is_hint || event->window != widget->window) { if (paned->horizontal) gtk_widget_get_pointer (widget, &pos, NULL); else gtk_widget_get_pointer (widget, NULL, &pos); } else pos = (paned->horizontal) ? event->x : event->y; if (paned->in_drag) { gint child1_size, child2_size; child1_size = (pos - GTK_CONTAINER (paned)->border_width - paned->gutter_size / 2); child2_size = paned->last_allocation - child1_size; if (paned->child1_use_minsize && (child1_size < paned->child1_minsize)) child1_size = paned->child1_minsize; if (paned->child2_use_minsize && (child2_size < paned->child2_minsize)) child1_size = paned->last_allocation - paned->child2_minsize; /* * Avoid blinking. */ if (child1_size == last_size) return FALSE; last_size = child1_size; gedo_paned_xor_line (paned); paned->child1_size = CLAMP (child1_size, paned->min_position, paned->max_position); gedo_paned_xor_line (paned); } return FALSE; } #else guint gedo_paned_which_hidden (GedoPaned * paned) { if (!GTK_WIDGET_VISIBLE (paned->child1) && GTK_WIDGET_VISIBLE (paned->child2)) { return 1; } else if (GTK_WIDGET_VISIBLE (paned->child1) && !GTK_WIDGET_VISIBLE (paned->child2)) { return 2; } else { return 0; } } #endif /* USE_NORMAL_PANED */