* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
*
* This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
+ * modify it under the terms of the GNU Lesser 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.
+ * Lesser General Public License for more details.
*
- * You should have received a copy of the GNU Library General Public
+ * You should have received a copy of the GNU Lesser 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.
*/
+
+/*
+ * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
+ * file for a list of people on the GTK+ Team. See the ChangeLog
+ * files for a list of changes. These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
#include "gtkscrolledwindow.h"
#include "gtksignal.h"
* under A) at least correspond to the space taken up by its scrollbars.
*/
-#define SCROLLBAR_SPACING(w) (GTK_SCROLLED_WINDOW_CLASS (GTK_OBJECT (w)->klass)->scrollbar_spacing)
+#define SCROLLBAR_SPACING(w) (GTK_SCROLLED_WINDOW_GET_CLASS (w)->scrollbar_spacing)
#define DEFAULT_SCROLLBAR_SPACING 3
ARG_VADJUSTMENT,
ARG_HSCROLLBAR_POLICY,
ARG_VSCROLLBAR_POLICY,
- ARG_WINDOW_PLACEMENT
+ ARG_WINDOW_PLACEMENT,
+ ARG_SHADOW
};
GtkArg *arg,
guint arg_id);
static void gtk_scrolled_window_destroy (GtkObject *object);
-static void gtk_scrolled_window_finalize (GtkObject *object);
+static void gtk_scrolled_window_finalize (GObject *object);
static void gtk_scrolled_window_map (GtkWidget *widget);
static void gtk_scrolled_window_unmap (GtkWidget *widget);
-static void gtk_scrolled_window_draw (GtkWidget *widget,
- GdkRectangle *area);
+static gint gtk_scrolled_window_expose (GtkWidget *widget,
+ GdkEventExpose *event);
static void gtk_scrolled_window_size_request (GtkWidget *widget,
GtkRequisition *requisition);
static void gtk_scrolled_window_size_allocate (GtkWidget *widget,
GtkAllocation *allocation);
+static gint gtk_scrolled_window_scroll_event (GtkWidget *widget,
+ GdkEventScroll *event);
static void gtk_scrolled_window_add (GtkContainer *container,
GtkWidget *widget);
static void gtk_scrolled_window_remove (GtkContainer *container,
static void gtk_scrolled_window_adjustment_changed (GtkAdjustment *adjustment,
gpointer data);
-
static GtkContainerClass *parent_class = NULL;
static void
gtk_scrolled_window_class_init (GtkScrolledWindowClass *class)
{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (class);
GtkObjectClass *object_class;
GtkWidgetClass *widget_class;
GtkContainerClass *container_class;
container_class = (GtkContainerClass*) class;
parent_class = gtk_type_class (GTK_TYPE_BIN);
+ gobject_class->finalize = gtk_scrolled_window_finalize;
+
+ object_class->set_arg = gtk_scrolled_window_set_arg;
+ object_class->get_arg = gtk_scrolled_window_get_arg;
+ object_class->destroy = gtk_scrolled_window_destroy;
+
+ widget_class->map = gtk_scrolled_window_map;
+ widget_class->unmap = gtk_scrolled_window_unmap;
+ widget_class->expose_event = gtk_scrolled_window_expose;
+ widget_class->size_request = gtk_scrolled_window_size_request;
+ widget_class->size_allocate = gtk_scrolled_window_size_allocate;
+ widget_class->scroll_event = gtk_scrolled_window_scroll_event;
+
+ container_class->add = gtk_scrolled_window_add;
+ container_class->remove = gtk_scrolled_window_remove;
+ container_class->forall = gtk_scrolled_window_forall;
+
+ class->scrollbar_spacing = DEFAULT_SCROLLBAR_SPACING;
+
gtk_object_add_arg_type ("GtkScrolledWindow::hadjustment",
GTK_TYPE_ADJUSTMENT,
GTK_ARG_READWRITE | GTK_ARG_CONSTRUCT,
GTK_TYPE_CORNER_TYPE,
GTK_ARG_READWRITE,
ARG_WINDOW_PLACEMENT);
-
- object_class->set_arg = gtk_scrolled_window_set_arg;
- object_class->get_arg = gtk_scrolled_window_get_arg;
- object_class->destroy = gtk_scrolled_window_destroy;
- object_class->finalize = gtk_scrolled_window_finalize;
-
- widget_class->map = gtk_scrolled_window_map;
- widget_class->unmap = gtk_scrolled_window_unmap;
- widget_class->draw = gtk_scrolled_window_draw;
- widget_class->size_request = gtk_scrolled_window_size_request;
- widget_class->size_allocate = gtk_scrolled_window_size_allocate;
-
- container_class->add = gtk_scrolled_window_add;
- container_class->remove = gtk_scrolled_window_remove;
- container_class->forall = gtk_scrolled_window_forall;
-
- class->scrollbar_spacing = DEFAULT_SCROLLBAR_SPACING;
+ gtk_object_add_arg_type ("GtkScrolledWindow::shadow",
+ GTK_TYPE_SHADOW_TYPE,
+ GTK_ARG_READWRITE,
+ ARG_SHADOW);
}
static void
gtk_scrolled_window_set_placement (scrolled_window,
GTK_VALUE_ENUM (*arg));
break;
+ case ARG_SHADOW:
+ gtk_scrolled_window_set_shadow_type (scrolled_window,
+ GTK_VALUE_ENUM (*arg));
+ break;
default:
break;
}
case ARG_WINDOW_PLACEMENT:
GTK_VALUE_ENUM (*arg) = scrolled_window->window_placement;
break;
+ case ARG_SHADOW:
+ GTK_VALUE_ENUM (*arg) = scrolled_window->shadow_type;
+ break;
default:
arg->type = GTK_TYPE_INVALID;
break;
scrolled_window->hscrollbar_visible = FALSE;
scrolled_window->vscrollbar_visible = FALSE;
scrolled_window->window_placement = GTK_CORNER_TOP_LEFT;
+
}
GtkWidget*
return scrolled_window;
}
-void
-gtk_scrolled_window_construct (GtkScrolledWindow *scrolled_window,
- GtkAdjustment *hadjustment,
- GtkAdjustment *vadjustment)
-{
- g_message ("gtk_scrolled_window_construct() is deprecated");
- gtk_scrolled_window_set_hadjustment (scrolled_window, hadjustment);
- gtk_scrolled_window_set_vadjustment (scrolled_window, vadjustment);
- gtk_object_default_construct (GTK_OBJECT (scrolled_window));
-}
-
void
gtk_scrolled_window_set_hadjustment (GtkScrolledWindow *scrolled_window,
GtkAdjustment *hadjustment)
}
}
+/**
+ * gtk_scrolled_window_set_shadow_type:
+ * @scrolled_window: a #GtkScrolledWindow
+ * @type: kind of shadow to draw around scrolled window contents
+ *
+ * Changes the type of shadow drawn around the contents of
+ * @scrolled_window.
+ *
+ **/
+void
+gtk_scrolled_window_set_shadow_type (GtkScrolledWindow *scrolled_window,
+ GtkShadowType type)
+{
+ g_return_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window));
+ g_return_if_fail (type >= GTK_SHADOW_NONE && type <= GTK_SHADOW_ETCHED_OUT);
+
+ if (scrolled_window->shadow_type != type)
+ {
+ scrolled_window->shadow_type = type;
+
+ if (GTK_WIDGET_DRAWABLE (scrolled_window))
+ gtk_widget_queue_clear (GTK_WIDGET (scrolled_window));
+
+ gtk_widget_queue_resize (GTK_WIDGET (scrolled_window));
+ }
+}
+
static void
gtk_scrolled_window_destroy (GtkObject *object)
{
}
static void
-gtk_scrolled_window_finalize (GtkObject *object)
+gtk_scrolled_window_finalize (GObject *object)
{
- GtkScrolledWindow *scrolled_window;
-
- scrolled_window = GTK_SCROLLED_WINDOW (object);
+ GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (object);
gtk_widget_unref (scrolled_window->hscrollbar);
gtk_widget_unref (scrolled_window->vscrollbar);
- GTK_OBJECT_CLASS (parent_class)->finalize (object);
+ G_OBJECT_CLASS (parent_class)->finalize (object);
}
static void
}
static void
-gtk_scrolled_window_draw (GtkWidget *widget,
- GdkRectangle *area)
+gtk_scrolled_window_paint (GtkWidget *widget,
+ GdkRectangle *area)
{
- GtkScrolledWindow *scrolled_window;
- GtkBin *bin;
- GdkRectangle child_area;
+ GtkAllocation relative_allocation;
+ GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (widget);
- g_return_if_fail (widget != NULL);
- g_return_if_fail (GTK_IS_SCROLLED_WINDOW (widget));
- g_return_if_fail (area != NULL);
-
- scrolled_window = GTK_SCROLLED_WINDOW (widget);
- bin = GTK_BIN (widget);
+ if (scrolled_window->shadow_type != GTK_SHADOW_NONE)
+ {
+ gtk_scrolled_window_relative_allocation (widget, &relative_allocation);
+
+ relative_allocation.x -= widget->style->xthickness;
+ relative_allocation.y -= widget->style->ythickness;
+ relative_allocation.width += 2 * widget->style->xthickness;
+ relative_allocation.height += 2 * widget->style->ythickness;
+
+ gtk_paint_shadow (widget->style, widget->window,
+ GTK_STATE_NORMAL, scrolled_window->shadow_type,
+ area, widget, "scrolled_window",
+ widget->allocation.x + relative_allocation.x,
+ widget->allocation.y + relative_allocation.y,
+ relative_allocation.width,
+ relative_allocation.height);
+ }
+}
- if (bin->child && GTK_WIDGET_VISIBLE (bin->child) &&
- gtk_widget_intersect (bin->child, area, &child_area))
- gtk_widget_draw (bin->child, &child_area);
-
- if (GTK_WIDGET_VISIBLE (scrolled_window->hscrollbar) &&
- gtk_widget_intersect (scrolled_window->hscrollbar, area, &child_area))
- gtk_widget_draw (scrolled_window->hscrollbar, &child_area);
-
- if (GTK_WIDGET_VISIBLE (scrolled_window->vscrollbar) &&
- gtk_widget_intersect (scrolled_window->vscrollbar, area, &child_area))
- gtk_widget_draw (scrolled_window->vscrollbar, &child_area);
+static gint
+gtk_scrolled_window_expose (GtkWidget *widget,
+ GdkEventExpose *event)
+{
+ if (GTK_WIDGET_DRAWABLE (widget))
+ {
+ gtk_scrolled_window_paint (widget, &event->area);
+
+ (* GTK_WIDGET_CLASS (parent_class)->expose_event) (widget, event);
+ }
+
+ return FALSE;
}
static void
{
GtkScrolledWindow *scrolled_window;
GtkBin *bin;
- gint extra_height;
gint extra_width;
+ gint extra_height;
+ GtkRequisition hscrollbar_requisition;
+ GtkRequisition vscrollbar_requisition;
+ GtkRequisition child_requisition;
g_return_if_fail (widget != NULL);
g_return_if_fail (GTK_IS_SCROLLED_WINDOW (widget));
scrolled_window = GTK_SCROLLED_WINDOW (widget);
bin = GTK_BIN (scrolled_window);
+ extra_width = 0;
+ extra_height = 0;
requisition->width = 0;
requisition->height = 0;
gtk_widget_size_request (scrolled_window->hscrollbar,
- &scrolled_window->hscrollbar->requisition);
+ &hscrollbar_requisition);
gtk_widget_size_request (scrolled_window->vscrollbar,
- &scrolled_window->vscrollbar->requisition);
+ &vscrollbar_requisition);
if (bin->child && GTK_WIDGET_VISIBLE (bin->child))
{
if (!quark_aux_info)
quark_aux_info = g_quark_from_static_string ("gtk-aux-info");
- gtk_widget_size_request (bin->child, &bin->child->requisition);
+ gtk_widget_size_request (bin->child, &child_requisition);
if (scrolled_window->hscrollbar_policy == GTK_POLICY_NEVER)
- requisition->width += bin->child->requisition.width;
+ requisition->width += child_requisition.width;
else
{
GtkWidgetAuxInfo *aux_info;
aux_info = gtk_object_get_data_by_id (GTK_OBJECT (bin->child), quark_aux_info);
if (aux_info && aux_info->width > 0)
- requisition->width += aux_info->width;
+ {
+ requisition->width += aux_info->width;
+ extra_width = -1;
+ }
else
- requisition->width += scrolled_window->vscrollbar->requisition.width;
+ requisition->width += vscrollbar_requisition.width;
}
if (scrolled_window->vscrollbar_policy == GTK_POLICY_NEVER)
- requisition->height += bin->child->requisition.height;
+ requisition->height += child_requisition.height;
else
{
GtkWidgetAuxInfo *aux_info;
aux_info = gtk_object_get_data_by_id (GTK_OBJECT (bin->child), quark_aux_info);
if (aux_info && aux_info->height > 0)
- requisition->height += aux_info->height;
+ {
+ requisition->height += aux_info->height;
+ extra_height = -1;
+ }
else
- requisition->height += scrolled_window->hscrollbar->requisition.height;
+ requisition->height += hscrollbar_requisition.height;
}
}
- extra_width = 0;
- extra_height = 0;
-
- if ((scrolled_window->hscrollbar_policy == GTK_POLICY_AUTOMATIC) ||
- GTK_WIDGET_VISIBLE (scrolled_window->hscrollbar))
+ if (scrolled_window->hscrollbar_policy == GTK_POLICY_AUTOMATIC ||
+ scrolled_window->hscrollbar_policy == GTK_POLICY_ALWAYS)
{
- requisition->width = MAX (requisition->width, scrolled_window->hscrollbar->requisition.width);
- extra_height = SCROLLBAR_SPACING (scrolled_window) + scrolled_window->hscrollbar->requisition.height;
+ requisition->width = MAX (requisition->width, hscrollbar_requisition.width);
+ if (!extra_height || scrolled_window->hscrollbar_policy == GTK_POLICY_ALWAYS)
+ extra_height = SCROLLBAR_SPACING (scrolled_window) + hscrollbar_requisition.height;
}
- if ((scrolled_window->vscrollbar_policy == GTK_POLICY_AUTOMATIC) ||
- GTK_WIDGET_VISIBLE (scrolled_window->vscrollbar))
+ if (scrolled_window->vscrollbar_policy == GTK_POLICY_AUTOMATIC ||
+ scrolled_window->vscrollbar_policy == GTK_POLICY_ALWAYS)
{
- requisition->height = MAX (requisition->height, scrolled_window->vscrollbar->requisition.height);
- extra_width = SCROLLBAR_SPACING (scrolled_window) + scrolled_window->vscrollbar->requisition.width;
+ requisition->height = MAX (requisition->height, vscrollbar_requisition.height);
+ if (!extra_height || scrolled_window->vscrollbar_policy == GTK_POLICY_ALWAYS)
+ extra_width = SCROLLBAR_SPACING (scrolled_window) + vscrollbar_requisition.width;
}
- requisition->width += GTK_CONTAINER (widget)->border_width * 2 + extra_width;
- requisition->height += GTK_CONTAINER (widget)->border_width * 2 + extra_height;
+ requisition->width += GTK_CONTAINER (widget)->border_width * 2 + MAX (0, extra_width);
+ requisition->height += GTK_CONTAINER (widget)->border_width * 2 + MAX (0, extra_height);
+
+ if (scrolled_window->shadow_type != GTK_SHADOW_NONE)
+ {
+ requisition->width += 2 * widget->style->xthickness;
+ requisition->height += 2 * widget->style->ythickness;
+ }
}
static void
allocation->x = GTK_CONTAINER (widget)->border_width;
allocation->y = GTK_CONTAINER (widget)->border_width;
+
+ if (scrolled_window->shadow_type != GTK_SHADOW_NONE)
+ {
+ allocation->x += widget->style->xthickness;
+ allocation->y += widget->style->ythickness;
+ }
+
allocation->width = MAX (1, (gint)widget->allocation.width - allocation->x * 2);
allocation->height = MAX (1, (gint)widget->allocation.height - allocation->y * 2);
if (scrolled_window->vscrollbar_visible)
{
+ GtkRequisition vscrollbar_requisition;
+ gtk_widget_get_child_requisition (scrolled_window->vscrollbar,
+ &vscrollbar_requisition);
+
if (scrolled_window->window_placement == GTK_CORNER_TOP_RIGHT ||
scrolled_window->window_placement == GTK_CORNER_BOTTOM_RIGHT)
- allocation->x += (scrolled_window->vscrollbar->requisition.width +
+ allocation->x += (vscrollbar_requisition.width +
SCROLLBAR_SPACING (scrolled_window));
allocation->width = MAX (1, (gint)allocation->width -
- ((gint)scrolled_window->vscrollbar->requisition.width +
+ ((gint)vscrollbar_requisition.width +
(gint)SCROLLBAR_SPACING (scrolled_window)));
}
if (scrolled_window->hscrollbar_visible)
{
+ GtkRequisition hscrollbar_requisition;
+ gtk_widget_get_child_requisition (scrolled_window->hscrollbar,
+ &hscrollbar_requisition);
+
if (scrolled_window->window_placement == GTK_CORNER_BOTTOM_LEFT ||
scrolled_window->window_placement == GTK_CORNER_BOTTOM_RIGHT)
- allocation->y += (scrolled_window->hscrollbar->requisition.height +
+ allocation->y += (hscrollbar_requisition.height +
SCROLLBAR_SPACING (scrolled_window));
allocation->height = MAX (1, (gint)allocation->height -
- ((gint)scrolled_window->hscrollbar->requisition.height +
+ ((gint)hscrollbar_requisition.height +
(gint)SCROLLBAR_SPACING (scrolled_window)));
}
}
if (scrolled_window->hscrollbar_visible)
{
+ GtkRequisition hscrollbar_requisition;
+ gtk_widget_get_child_requisition (scrolled_window->hscrollbar,
+ &hscrollbar_requisition);
+
if (!GTK_WIDGET_VISIBLE (scrolled_window->hscrollbar))
gtk_widget_show (scrolled_window->hscrollbar);
scrolled_window->window_placement == GTK_CORNER_TOP_RIGHT)
child_allocation.y = (relative_allocation.y +
relative_allocation.height +
- SCROLLBAR_SPACING (scrolled_window));
+ SCROLLBAR_SPACING (scrolled_window) +
+ (scrolled_window->shadow_type == GTK_SHADOW_NONE ?
+ 0 : widget->style->ythickness));
else
child_allocation.y = GTK_CONTAINER (scrolled_window)->border_width;
child_allocation.width = relative_allocation.width;
- child_allocation.height = scrolled_window->hscrollbar->requisition.height;
+ child_allocation.height = hscrollbar_requisition.height;
child_allocation.x += allocation->x;
child_allocation.y += allocation->y;
+ if (scrolled_window->shadow_type != GTK_SHADOW_NONE)
+ {
+ child_allocation.x -= widget->style->xthickness;
+ child_allocation.width += 2 * widget->style->xthickness;
+ }
+
gtk_widget_size_allocate (scrolled_window->hscrollbar, &child_allocation);
}
else if (GTK_WIDGET_VISIBLE (scrolled_window->hscrollbar))
if (scrolled_window->vscrollbar_visible)
{
+ GtkRequisition vscrollbar_requisition;
if (!GTK_WIDGET_VISIBLE (scrolled_window->vscrollbar))
gtk_widget_show (scrolled_window->vscrollbar);
+ gtk_widget_get_child_requisition (scrolled_window->vscrollbar,
+ &vscrollbar_requisition);
+
if (scrolled_window->window_placement == GTK_CORNER_TOP_LEFT ||
scrolled_window->window_placement == GTK_CORNER_BOTTOM_LEFT)
child_allocation.x = (relative_allocation.x +
relative_allocation.width +
- SCROLLBAR_SPACING (scrolled_window));
+ SCROLLBAR_SPACING (scrolled_window) +
+ (scrolled_window->shadow_type == GTK_SHADOW_NONE ?
+ 0 : widget->style->xthickness));
else
child_allocation.x = GTK_CONTAINER (scrolled_window)->border_width;
child_allocation.y = relative_allocation.y;
- child_allocation.width = scrolled_window->vscrollbar->requisition.width;
+ child_allocation.width = vscrollbar_requisition.width;
child_allocation.height = relative_allocation.height;
child_allocation.x += allocation->x;
child_allocation.y += allocation->y;
+ if (scrolled_window->shadow_type != GTK_SHADOW_NONE)
+ {
+ child_allocation.y -= widget->style->ythickness;
+ child_allocation.height += 2 * widget->style->ythickness;
+ }
+
gtk_widget_size_allocate (scrolled_window->vscrollbar, &child_allocation);
}
else if (GTK_WIDGET_VISIBLE (scrolled_window->vscrollbar))
gtk_widget_hide (scrolled_window->vscrollbar);
}
+static gint
+gtk_scrolled_window_scroll_event (GtkWidget *widget,
+ GdkEventScroll *event)
+{
+ GtkWidget *range;
+
+ g_return_val_if_fail (widget != NULL, FALSE);
+ g_return_val_if_fail (GTK_IS_SCROLLED_WINDOW (widget), FALSE);
+ g_return_val_if_fail (event != NULL, FALSE);
+
+ if (event->direction == GDK_SCROLL_UP || event->direction == GDK_SCROLL_DOWN)
+ range = GTK_SCROLLED_WINDOW (widget)->vscrollbar;
+ else
+ range = GTK_SCROLLED_WINDOW (widget)->hscrollbar;
+
+ if (range && GTK_WIDGET_VISIBLE (range))
+ {
+ GtkAdjustment *adj = GTK_RANGE (range)->adjustment;
+ gdouble new_value;
+
+ if (event->direction == GDK_SCROLL_UP || event->direction == GDK_SCROLL_LEFT)
+ new_value = adj->value - adj->page_increment / 2;
+ else
+ new_value = adj->value + adj->page_increment / 2;
+
+ new_value = CLAMP (new_value, adj->lower, adj->upper - adj->page_size);
+ gtk_adjustment_set_value (adj, new_value);
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
static void
gtk_scrolled_window_adjustment_changed (GtkAdjustment *adjustment,
scrolled_window = GTK_SCROLLED_WINDOW (container);
- gtk_widget_set_parent (child, GTK_WIDGET (bin));
bin->child = child;
+ gtk_widget_set_parent (child, GTK_WIDGET (bin));
/* this is a temporary message */
if (!gtk_widget_set_scroll_adjustments (child,
gtk_range_get_adjustment (GTK_RANGE (scrolled_window->hscrollbar)),
gtk_range_get_adjustment (GTK_RANGE (scrolled_window->vscrollbar))))
- g_message ("gtk_scrolled_window_add(): cannot add non scrollable widget "
+ g_warning ("gtk_scrolled_window_add(): cannot add non scrollable widget "
"use gtk_scrolled_window_add_with_viewport() instead");
- if (GTK_WIDGET_VISIBLE (child->parent))
- {
- if (GTK_WIDGET_REALIZED (child->parent) &&
- !GTK_WIDGET_REALIZED (child))
- gtk_widget_realize (child);
+ if (GTK_WIDGET_REALIZED (child->parent))
+ gtk_widget_realize (child);
- if (GTK_WIDGET_MAPPED (child->parent) &&
- !GTK_WIDGET_MAPPED (child))
+ if (GTK_WIDGET_VISIBLE (child->parent) && GTK_WIDGET_VISIBLE (child))
+ {
+ if (GTK_WIDGET_MAPPED (child->parent))
gtk_widget_map (child);
- }
- if (GTK_WIDGET_VISIBLE (child) && GTK_WIDGET_VISIBLE (container))
- gtk_widget_queue_resize (child);
+ gtk_widget_queue_resize (child);
+ }
}
static void