2 * This file is part of hildon-libs
4 * Copyright (C) 2005 Nokia Corporation.
6 * Contact: Luc Pionchon <luc.pionchon@nokia.com>
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public License
10 * as published by the Free Software Foundation; either version 2.1 of
11 * the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
25 /* hildon-scroll-area.c
29 #include "hildon-scroll-area.h"
30 #include <gtk/gtkscrolledwindow.h>
31 #include <gtk/gtkfixed.h>
32 #include <gtk/gtkadjustment.h>
33 #include <gtk/gtkwidget.h>
43 GtkAdjustment *outadj;
49 static void hildon_scroll_area_outer_value_changed (GtkAdjustment *adjustment,
50 HildonScrollArea *sc);
51 static void hildon_scroll_area_inner_value_changed (GtkAdjustment *adjustment,
52 HildonScrollArea *sc);
53 static void hildon_scroll_area_size_allocate (GtkWidget *widget,
54 GtkAllocation *allocation,
55 HildonScrollArea *sc);
56 static void hildon_scroll_area_child_requisition (GtkWidget *widget,
58 HildonScrollArea *sc);
59 static void hildon_scroll_area_fixed_allocate (GtkWidget *widget,
60 GtkAllocation *allocation,
61 HildonScrollArea *sc);
64 * hildon_scroll_area_new:
65 * @sw: #GtkWidget - #GtkScrolledWindow
66 * @child: #GtkWidget - Child to be place inside the sw
68 * This is not a widget. It's a helper function to provide
69 * hildon specified scrolling for applications.
70 * Puts and connects the @child to the @sw.
71 * A common situation where the scroll area should be used
72 * might be following. A view containing @GtkTreeView based widget,
73 * (or any similar widget which has built-in @GtkScrolledWindow support)
74 * and eg. couple buttons. Normaly @GtkScrolledWindow can not handle
75 * the situation so that the @GtkTreeView built-in support
76 * would work. The scroll area is connecting this built-in system to
77 * the scrolled window and also noticing the buttons. To use, one should
78 * create a box to which pack the buttons and the scroll area.
79 * The scroll area then contains the problematic widget eg. the @GtkTreeView.
80 * Then the box should be placed in the @GtkScrolledWindow.
81 * The function is currently assuming that the newly created scroll area
82 * hierarchy is not modified in anyway. Or if it is, it may lead to
83 * unwanted problems. Also assumed, that the @child will be packed
86 * Returns: a @GtkFixed
88 GtkWidget *hildon_scroll_area_new (GtkWidget *sw, GtkWidget *child)
94 g_return_val_if_fail (GTK_IS_SCROLLED_WINDOW (sw)
95 && GTK_IS_WIDGET (child), NULL);
97 swi = gtk_scrolled_window_new (NULL, NULL);
98 fixed = gtk_fixed_new ();
99 sc = g_malloc (sizeof (HildonScrollArea));
100 memset (sc, 0, sizeof (HildonScrollArea));
102 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swi),
103 GTK_POLICY_NEVER, GTK_POLICY_NEVER);
105 gtk_container_add (GTK_CONTAINER (swi), child);
106 gtk_fixed_put (GTK_FIXED (fixed), swi, 0, 0);
112 sc->outadj = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (sw));
113 sc->inadj = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (swi));
115 g_signal_connect_after (G_OBJECT (child), "size-request",
116 G_CALLBACK (hildon_scroll_area_child_requisition), sc);
118 g_signal_connect_after (G_OBJECT (sc->outadj), "value_changed",
119 G_CALLBACK (hildon_scroll_area_outer_value_changed), sc);
120 g_signal_connect_after (G_OBJECT (sc->inadj), "value_changed",
121 G_CALLBACK (hildon_scroll_area_inner_value_changed), sc);
123 g_signal_connect_after (G_OBJECT (sw), "size-allocate",
124 G_CALLBACK (hildon_scroll_area_size_allocate), sc);
125 g_signal_connect (G_OBJECT (sc->fixed), "size-allocate",
126 G_CALLBACK (hildon_scroll_area_fixed_allocate), sc);
127 g_signal_connect_swapped (G_OBJECT (sw), "destroy",
128 G_CALLBACK (g_free), sc);
130 gtk_widget_show_all (sw);
134 static void hildon_scroll_area_fixed_allocate (GtkWidget *widget,
135 GtkAllocation *allocation,
136 HildonScrollArea *sc)
138 gtk_widget_set_size_request (sc->swinner, -1,
139 MIN (sc->outadj->page_size, allocation->height));
142 static void hildon_scroll_area_child_requisition (GtkWidget *widget,
144 HildonScrollArea *sc)
146 gint new_req = MAX (req->height, sc->fixed->allocation.height);
147 gtk_widget_set_size_request (sc->fixed, -1, req->height);
148 gtk_widget_set_size_request (sc->swinner, -1,
149 MIN (sc->outadj->page_size, new_req));
152 static void hildon_scroll_area_outer_value_changed (GtkAdjustment *adjustment,
153 HildonScrollArea *sc)
156 gtk_widget_size_request (sc->child, &req);
158 if ((sc->outadj->value + sc->outadj->page_size) > sc->fixed->allocation.y
159 && sc->outadj->value < (sc->fixed->allocation.y + req.height))
163 new_pos = MAX (sc->outadj->value - sc->fixed->allocation.y, 0);
164 new_pos = MIN (new_pos, req.height - sc->inadj->page_size);
165 new_pos = MAX (new_pos, 0);
167 gtk_fixed_move (GTK_FIXED (sc->fixed), sc->swinner, 0, new_pos);
168 gtk_adjustment_set_value (sc->inadj, new_pos);
172 static void hildon_scroll_area_inner_value_changed (GtkAdjustment *adjustment,
173 HildonScrollArea *sc)
175 if (sc->outadj->value != sc->fixed->allocation.y + adjustment->value)
176 gtk_adjustment_set_value (sc->outadj,
177 sc->fixed->allocation.y + adjustment->value);
180 __inline__ static gint calculate_width (HildonScrollArea *sc)
182 GtkScrolledWindow *scwin = GTK_SCROLLED_WINDOW (sc->swouter);
183 return (scwin->hscrollbar_visible * scwin->hscrollbar->allocation.width);
186 static void hildon_scroll_area_size_allocate (GtkWidget *widget,
187 GtkAllocation *allocation,
188 HildonScrollArea *sc)
190 gtk_widget_set_size_request (sc->fixed, calculate_width (sc), sc->fixed->allocation.height);
191 gtk_widget_set_size_request (sc->child, sc->fixed->allocation.width, -1);