Improve some sieve-related translations
[claws.git] / src / gtk / gtkvscrollbutton.c
blobfd7c9231b98954a9dbd6a857972a64cdb2f1516d
1 /* GTK - The GIMP Toolkit
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 3 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
19 * Modified by the GTK+ Team and others 1997-1999. See the AUTHORS
20 * file for a list of people on the GTK+ Team. See the ChangeLog
21 * files for a list of changes. These files are distributed with
22 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
26 * Simple composite widget to provide vertical scrolling, based
27 * on GtkRange widget code.
28 * Modified by the Sylpheed Team and others 2003
31 #ifdef HAVE_CONFIG_H
32 # include "config.h"
33 #include "claws-features.h"
34 #endif
36 #include <glib.h>
37 #include <gtk/gtk.h>
38 #include "utils.h"
39 #include "gtkvscrollbutton.h"
40 #include "gtkutils.h"
42 #define SCROLL_TIMER_LENGTH 20
43 #define SCROLL_INITIAL_DELAY 100 /* must hold button this long before ... */
44 #define SCROLL_LATER_DELAY 20 /* ... it starts repeating at this rate */
45 #define SCROLL_DELAY_LENGTH 300
48 enum {
49 ARG_0,
50 ARG_ADJUSTMENT
53 static void gtk_vscrollbutton_class_init(GtkVScrollbuttonClass * klass);
54 static void gtk_vscrollbutton_init(GtkVScrollbutton * vscrollbutton);
56 GType gtk_vscrollbutton_get_type (void);
57 GtkWidget *gtk_vscrollbutton_new (GtkAdjustment *adjustment);
59 static gint gtk_vscrollbutton_button_release (GtkWidget *widget,
60 GdkEventButton *event,
61 GtkVScrollbutton *scrollbutton);
63 static void gtk_vscrollbutton_set_adjustment (GtkVScrollbutton *scrollbutton,
64 GtkAdjustment *adjustment);
66 static gint gtk_vscrollbutton_button_press (GtkWidget *widget,
67 GdkEventButton *event,
68 GtkVScrollbutton *scrollbutton);
70 static gint gtk_vscrollbutton_button_release (GtkWidget *widget,
71 GdkEventButton *event,
72 GtkVScrollbutton *scrollbutton);
74 gint gtk_vscrollbutton_scroll (GtkVScrollbutton *scrollbutton);
76 static gboolean gtk_vscrollbutton_timer_1st_time(GtkVScrollbutton *scrollbutton);
78 static void gtk_vscrollbutton_add_timer (GtkVScrollbutton *scrollbutton);
80 static void gtk_vscrollbutton_remove_timer (GtkVScrollbutton *scrollbutton);
82 static gboolean gtk_real_vscrollbutton_timer (GtkVScrollbutton *scrollbutton);
84 static void gtk_vscrollbutton_set_sensitivity (GtkAdjustment *adjustment,
85 GtkVScrollbutton *scrollbutton);
87 GType gtk_vscrollbutton_get_type(void)
89 static GType vscrollbutton_type = 0;
91 if (!vscrollbutton_type) {
92 static const GTypeInfo vscrollbutton_info = {
93 sizeof (GtkVScrollbuttonClass),
95 (GBaseInitFunc) NULL,
96 (GBaseFinalizeFunc) NULL,
98 (GClassInitFunc) gtk_vscrollbutton_class_init,
99 (GClassFinalizeFunc) NULL,
100 NULL, /* class_data */
102 sizeof (GtkVScrollbutton),
103 0, /* n_preallocs */
104 (GInstanceInitFunc) gtk_vscrollbutton_init,
106 (const GTypeValueTable *) NULL /* value table */
109 vscrollbutton_type = g_type_register_static (GTK_TYPE_BOX, "GtkVScrollbutton", &vscrollbutton_info, (GTypeFlags)0);
112 return vscrollbutton_type;
115 static void gtk_vscrollbutton_class_init(GtkVScrollbuttonClass *class)
119 static GdkCursor *hand_cursor = NULL;
121 static gboolean vscroll_visi_notify(GtkWidget *widget,
122 GdkEventVisibility *event,
123 gpointer data)
125 gdk_window_set_cursor(gtk_widget_get_window(widget), hand_cursor);
126 return FALSE;
129 static gboolean vscroll_leave_notify(GtkWidget *widget,
130 GdkEventCrossing *event,
131 gpointer data)
133 gdk_window_set_cursor(gtk_widget_get_window(widget), NULL);
134 return FALSE;
137 static gboolean vscroll_enter_notify(GtkWidget *widget,
138 GdkEventCrossing *event,
139 gpointer data)
141 gdk_window_set_cursor(gtk_widget_get_window(widget), hand_cursor);
142 return FALSE;
146 static void gtk_vscrollbutton_init(GtkVScrollbutton *scrollbutton)
148 GtkWidget *arrow;
150 if (!hand_cursor)
151 hand_cursor = gdk_cursor_new_for_display(
152 gtk_widget_get_display(GTK_WIDGET(scrollbutton)),GDK_HAND2);
154 scrollbutton->upbutton = gtk_event_box_new();
155 scrollbutton->downbutton = gtk_event_box_new();
156 arrow = gtk_image_new_from_icon_name("pan-up-symbolic", GTK_ICON_SIZE_MENU);
157 gtk_widget_show(arrow);
158 gtk_container_add(GTK_CONTAINER(scrollbutton->upbutton), arrow);
159 gtk_widget_set_size_request(scrollbutton->upbutton, -1, 16);
160 arrow = gtk_image_new_from_icon_name("pan-down-symbolic", GTK_ICON_SIZE_MENU);
161 gtk_widget_show(arrow);
162 gtk_container_add(GTK_CONTAINER(scrollbutton->downbutton), arrow);
163 gtk_widget_set_size_request(scrollbutton->downbutton, -1, 16);
164 gtk_widget_set_can_focus(scrollbutton->upbutton, FALSE);
165 gtk_widget_set_can_focus(scrollbutton->downbutton, FALSE);
166 gtk_widget_show(scrollbutton->downbutton);
167 gtk_widget_show(scrollbutton->upbutton);
169 g_signal_connect(G_OBJECT(scrollbutton->upbutton), "motion-notify-event",
170 G_CALLBACK(vscroll_visi_notify), NULL);
171 g_signal_connect(G_OBJECT(scrollbutton->upbutton), "leave-notify-event",
172 G_CALLBACK(vscroll_leave_notify), NULL);
173 g_signal_connect(G_OBJECT(scrollbutton->upbutton), "enter-notify-event",
174 G_CALLBACK(vscroll_enter_notify), NULL);
175 g_signal_connect(G_OBJECT(scrollbutton->downbutton), "motion-notify-event",
176 G_CALLBACK(vscroll_visi_notify), NULL);
177 g_signal_connect(G_OBJECT(scrollbutton->downbutton), "leave-notify-event",
178 G_CALLBACK(vscroll_leave_notify), NULL);
179 g_signal_connect(G_OBJECT(scrollbutton->downbutton), "enter-notify-event",
180 G_CALLBACK(vscroll_enter_notify), NULL);
182 g_signal_connect(G_OBJECT(scrollbutton->upbutton),
183 "button_press_event",
184 G_CALLBACK(gtk_vscrollbutton_button_press),
185 scrollbutton);
186 g_signal_connect(G_OBJECT(scrollbutton->downbutton),
187 "button_press_event",
188 G_CALLBACK(gtk_vscrollbutton_button_press),
189 scrollbutton);
190 g_signal_connect(G_OBJECT(scrollbutton->upbutton),
191 "button_release_event",
192 G_CALLBACK
193 (gtk_vscrollbutton_button_release), scrollbutton);
194 g_signal_connect(G_OBJECT(scrollbutton->downbutton),
195 "button_release_event",
196 G_CALLBACK
197 (gtk_vscrollbutton_button_release), scrollbutton);
198 gtk_box_pack_start(GTK_BOX(&scrollbutton->vbox),
199 scrollbutton->upbutton, TRUE, TRUE, 0);
200 gtk_box_pack_end(GTK_BOX(&scrollbutton->vbox),
201 scrollbutton->downbutton, TRUE, TRUE, 0);
202 scrollbutton->timer = 0;
205 GtkWidget *gtk_vscrollbutton_new(GtkAdjustment *adjustment)
207 GtkWidget *vscrollbutton;
208 vscrollbutton = g_object_new (gtk_vscrollbutton_get_type(),
209 NULL);
210 gtk_vscrollbutton_set_adjustment(GTK_VSCROLLBUTTON(vscrollbutton),
211 adjustment);
212 g_signal_connect(G_OBJECT(GTK_VSCROLLBUTTON(vscrollbutton)->adjustment),
213 "value_changed",
214 G_CALLBACK
215 (gtk_vscrollbutton_set_sensitivity), vscrollbutton);
216 g_signal_connect(G_OBJECT(GTK_VSCROLLBUTTON(vscrollbutton)->adjustment),
217 "changed",
218 G_CALLBACK
219 (gtk_vscrollbutton_set_sensitivity), vscrollbutton);
220 return vscrollbutton;
224 void gtk_vscrollbutton_set_adjustment(GtkVScrollbutton *scrollbutton,
225 GtkAdjustment *adjustment)
227 cm_return_if_fail(scrollbutton != NULL);
228 cm_return_if_fail(GTK_IS_VSCROLLBUTTON(scrollbutton));
230 if (!adjustment)
231 adjustment =
232 GTK_ADJUSTMENT(gtk_adjustment_new(0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
233 else
234 cm_return_if_fail(GTK_IS_ADJUSTMENT(adjustment));
236 if (scrollbutton->adjustment != adjustment) {
237 if (scrollbutton->adjustment) {
238 g_signal_handlers_disconnect_matched(scrollbutton->adjustment,
239 G_SIGNAL_MATCH_DATA,
240 0, 0, NULL, NULL,
241 (gpointer) scrollbutton);
242 g_object_unref(G_OBJECT(scrollbutton->adjustment));
245 scrollbutton->adjustment = adjustment;
246 g_object_ref(G_OBJECT(adjustment));
247 g_object_ref_sink (G_OBJECT(adjustment));
251 static gint gtk_vscrollbutton_button_press(GtkWidget *widget,
252 GdkEventButton *event,
253 GtkVScrollbutton *scrollbutton)
255 if (!gtk_widget_has_focus(widget))
256 gtk_widget_grab_focus(widget);
258 if (scrollbutton->button == 0) {
259 gtk_grab_add(widget);
260 scrollbutton->button = event->button;
262 if (widget == scrollbutton->downbutton)
263 scrollbutton->scroll_type = GTK_SCROLL_STEP_FORWARD;
264 else
265 scrollbutton->scroll_type = GTK_SCROLL_STEP_BACKWARD;
266 gtk_vscrollbutton_scroll(scrollbutton);
267 gtk_vscrollbutton_add_timer(scrollbutton);
269 return TRUE;
273 static gint gtk_vscrollbutton_button_release(GtkWidget *widget,
274 GdkEventButton *event,
275 GtkVScrollbutton *scrollbutton)
277 if (!gtk_widget_has_focus(widget))
278 gtk_widget_grab_focus(widget);
280 if (scrollbutton->button == event->button) {
281 gtk_grab_remove(widget);
283 scrollbutton->button = 0;
284 gtk_vscrollbutton_remove_timer(scrollbutton);
285 gtk_vscrollbutton_set_sensitivity(scrollbutton->adjustment, scrollbutton);
287 return TRUE;
290 gboolean gtk_vscrollbutton_scroll(GtkVScrollbutton *scrollbutton)
292 gfloat bound;
293 gfloat new_value;
294 gfloat page_size;
295 gfloat value;
296 gboolean return_val;
298 cm_return_val_if_fail(scrollbutton != NULL, FALSE);
299 cm_return_val_if_fail(GTK_IS_VSCROLLBUTTON(scrollbutton), FALSE);
301 new_value = value = gtk_adjustment_get_value(scrollbutton->adjustment);
302 return_val = TRUE;
304 switch (scrollbutton->scroll_type) {
306 case GTK_SCROLL_STEP_BACKWARD:
307 new_value = value - gtk_adjustment_get_step_increment(scrollbutton->adjustment);
308 bound = gtk_adjustment_get_lower(scrollbutton->adjustment);
309 if (new_value <= bound) {
310 new_value = bound;
311 return_val = FALSE;
312 scrollbutton->timer = 0;
314 break;
316 case GTK_SCROLL_STEP_FORWARD:
317 new_value = value + gtk_adjustment_get_step_increment(scrollbutton->adjustment);
318 bound = gtk_adjustment_get_upper(scrollbutton->adjustment);
319 page_size = gtk_adjustment_get_page_size(scrollbutton->adjustment);
320 if (new_value >= (bound - page_size)) {
321 new_value = bound - page_size;
322 return_val = FALSE;
323 scrollbutton->timer = 0;
325 break;
327 default:
328 break;
332 if (new_value != value) {
333 gtk_adjustment_set_value(scrollbutton->adjustment, new_value);
334 g_signal_emit_by_name(G_OBJECT
335 (scrollbutton->adjustment),
336 "value_changed");
337 gtk_widget_queue_resize(GTK_WIDGET(scrollbutton)); /* ensure resize */
340 return return_val;
343 static gboolean
344 gtk_vscrollbutton_timer_1st_time(GtkVScrollbutton *scrollbutton)
347 * If the real timeout function succeeds and the timeout is still set,
348 * replace it with a quicker one so successive scrolling goes faster.
350 g_object_ref(G_OBJECT(scrollbutton));
351 if (scrollbutton->timer) {
352 /* We explicitely remove ourselves here in the paranoia
353 * that due to things happening above in the callback
354 * above, we might have been removed, and another added.
356 g_source_remove(scrollbutton->timer);
357 scrollbutton->timer = g_timeout_add(SCROLL_LATER_DELAY,
358 (GSourceFunc)
359 gtk_real_vscrollbutton_timer,
360 scrollbutton);
362 g_object_unref(G_OBJECT(scrollbutton));
363 return FALSE; /* don't keep calling this function */
367 static void gtk_vscrollbutton_add_timer(GtkVScrollbutton *scrollbutton)
369 cm_return_if_fail(scrollbutton != NULL);
370 cm_return_if_fail(GTK_IS_VSCROLLBUTTON(scrollbutton));
372 if (!scrollbutton->timer) {
373 scrollbutton->need_timer = TRUE;
374 scrollbutton->timer = g_timeout_add(SCROLL_INITIAL_DELAY,
375 (GSourceFunc)
376 gtk_vscrollbutton_timer_1st_time,
377 scrollbutton);
381 static void gtk_vscrollbutton_remove_timer(GtkVScrollbutton *scrollbutton)
383 cm_return_if_fail(scrollbutton != NULL);
384 cm_return_if_fail(GTK_IS_VSCROLLBUTTON(scrollbutton));
386 if (scrollbutton->timer) {
387 g_source_remove(scrollbutton->timer);
388 scrollbutton->timer = 0;
390 scrollbutton->need_timer = FALSE;
393 static gboolean gtk_real_vscrollbutton_timer(GtkVScrollbutton *scrollbutton)
395 gboolean return_val;
397 GDK_THREADS_ENTER();
399 return_val = TRUE;
400 if (!scrollbutton->timer) {
401 return_val = FALSE;
402 if (scrollbutton->need_timer)
403 scrollbutton->timer =
404 g_timeout_add(SCROLL_TIMER_LENGTH,
405 (GSourceFunc) gtk_real_vscrollbutton_timer,
406 (gpointer) scrollbutton);
407 else {
408 GDK_THREADS_LEAVE();
409 return FALSE;
411 scrollbutton->need_timer = FALSE;
413 GDK_THREADS_LEAVE();
414 return_val = gtk_vscrollbutton_scroll(scrollbutton);
415 return return_val;
418 static void gtk_vscrollbutton_set_sensitivity (GtkAdjustment *adjustment,
419 GtkVScrollbutton *scrollbutton)
421 gfloat value;
422 if (!gtk_widget_get_realized(GTK_WIDGET(scrollbutton))) return;
423 if (scrollbutton->button != 0) return; /* not while something is pressed */
425 value = gtk_adjustment_get_value(adjustment);
426 gtk_widget_set_sensitive(scrollbutton->upbutton,
427 (value > gtk_adjustment_get_lower(adjustment)));
428 gtk_widget_set_sensitive(scrollbutton->downbutton,
429 (value < (gtk_adjustment_get_upper(adjustment) -
430 gtk_adjustment_get_page_size(adjustment))));