1
/* Eye Of Gnome - Thumbnail Navigator
3
* Copyright (C) 2006 The Free Software Foundation
5
* Author: Lucas Rocha <lucasr@gnome.org>
7
* This program is free software; you can redistribute it and/or modify
8
* it under the terms of the GNU General Public License as published by
9
* the Free Software Foundation; either version 2 of the License, or
10
* (at your option) any later version.
12
* This program is distributed in the hope that it will be useful,
13
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
* GNU General Public License for more details.
17
* You should have received a copy of the GNU General Public License
18
* along with this program; if not, write to the Free Software
19
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23
#include <cheese-config.h>
26
#include "eog-thumb-nav.h"
27
#include "cheese-thumb-view.h"
30
#include <glib/gi18n.h>
31
#include <glib-object.h>
35
#define EOG_THUMB_NAV_GET_PRIVATE(object) \
36
(G_TYPE_INSTANCE_GET_PRIVATE ((object), EOG_TYPE_THUMB_NAV, EogThumbNavPrivate))
38
G_DEFINE_TYPE (EogThumbNav, eog_thumb_nav, GTK_TYPE_HBOX);
40
#define EOG_THUMB_NAV_SCROLL_INC 20
41
#define EOG_THUMB_NAV_SCROLL_MOVE 20
42
#define EOG_THUMB_NAV_SCROLL_TIMEOUT 20
46
PROP_SHOW_BUTTONS = 1,
51
struct _EogThumbNavPrivate
53
gboolean show_buttons;
60
GtkWidget *button_down;
61
GtkWidget *button_left;
62
GtkWidget *button_right;
72
eog_thumb_nav_scroll_event (GtkWidget *widget, GdkEventScroll *event, gpointer user_data)
74
EogThumbNav *nav = EOG_THUMB_NAV (user_data);
75
gint inc = EOG_THUMB_NAV_SCROLL_INC * 3;
76
gdouble value, upper, page_size;
78
nav->priv->adj = nav->priv->vertical ? nav->priv->vadj : nav->priv->hadj;
80
switch (event->direction)
88
case GDK_SCROLL_RIGHT:
92
g_assert_not_reached ();
96
value = gtk_adjustment_get_value (nav->priv->adj);
98
gtk_adjustment_set_value (nav->priv->adj, MAX (0, value + inc));
101
upper = gtk_adjustment_get_upper (nav->priv->adj);
102
page_size = gtk_adjustment_get_page_size (nav->priv->adj);
103
gtk_adjustment_set_value (nav->priv->adj, MIN (upper - page_size, value + inc));
106
gtk_adjustment_value_changed (nav->priv->adj);
112
eog_thumb_nav_vadj_changed (GtkAdjustment *vadj, gpointer user_data)
115
EogThumbNavPrivate *priv;
117
gdouble value, upper, page_size;
119
nav = EOG_THUMB_NAV (user_data);
120
priv = EOG_THUMB_NAV_GET_PRIVATE (nav);
121
ltr = gtk_widget_get_direction (priv->sw) == GTK_TEXT_DIR_LTR;
126
"page_size", &page_size,
128
gtk_widget_set_sensitive (priv->button_up, value > 0);
130
gtk_widget_set_sensitive (priv->button_down,
131
value < upper - page_size);
135
eog_thumb_nav_hadj_changed (GtkAdjustment *hadj, gpointer user_data)
138
EogThumbNavPrivate *priv;
140
gdouble value, upper, page_size;
142
nav = EOG_THUMB_NAV (user_data);
143
priv = EOG_THUMB_NAV_GET_PRIVATE (nav);
144
ltr = gtk_widget_get_direction (priv->sw) == GTK_TEXT_DIR_LTR;
149
"page_size", &page_size,
152
gtk_widget_set_sensitive (ltr ? priv->button_right : priv->button_left,
153
value < upper - page_size);
157
eog_thumb_nav_vadj_value_changed (GtkAdjustment *vadj, gpointer user_data)
160
EogThumbNavPrivate *priv;
162
gdouble value, upper, page_size;
164
nav = EOG_THUMB_NAV (user_data);
165
priv = EOG_THUMB_NAV_GET_PRIVATE (nav);
166
ltr = gtk_widget_get_direction (priv->sw) == GTK_TEXT_DIR_LTR;
171
"page_size", &page_size,
174
gtk_widget_set_sensitive (priv->button_up, value > 0);
176
gtk_widget_set_sensitive (priv->button_down,
177
value < upper - page_size);
181
eog_thumb_nav_hadj_value_changed (GtkAdjustment *hadj, gpointer user_data)
184
EogThumbNavPrivate *priv;
186
gdouble value, upper, page_size;
188
nav = EOG_THUMB_NAV (user_data);
189
priv = EOG_THUMB_NAV_GET_PRIVATE (nav);
190
ltr = gtk_widget_get_direction (priv->sw) == GTK_TEXT_DIR_LTR;
195
"page_size", &page_size,
198
gtk_widget_set_sensitive (ltr ? priv->button_left : priv->button_right, value > 0);
200
gtk_widget_set_sensitive (ltr ? priv->button_right : priv->button_left,
201
value < upper - page_size);
205
eog_thumb_nav_scroll_step (gpointer user_data)
207
EogThumbNav *nav = EOG_THUMB_NAV (user_data);
209
gdouble value, upper, page_size;
211
if (nav->priv->scroll_pos < 10)
212
delta = EOG_THUMB_NAV_SCROLL_INC;
213
else if (nav->priv->scroll_pos < 20)
214
delta = EOG_THUMB_NAV_SCROLL_INC * 2;
215
else if (nav->priv->scroll_pos < 30)
216
delta = EOG_THUMB_NAV_SCROLL_INC * 2 + 5;
218
delta = EOG_THUMB_NAV_SCROLL_INC * 2 + 12;
220
if (!nav->priv->scroll_dir)
223
g_object_get (nav->priv->adj,
226
"page_size", &page_size,
229
if ((gint) (value + (gdouble) delta) >= 0 &&
230
(gint) (value + (gdouble) delta) <= upper - page_size)
232
gtk_adjustment_set_value (nav->priv->adj, value + (gdouble) delta);
233
nav->priv->scroll_pos++;
234
gtk_adjustment_value_changed (nav->priv->adj);
239
gtk_adjustment_set_value (nav->priv->adj, upper - page_size);
241
gtk_adjustment_set_value (nav->priv->adj, 0);
243
nav->priv->scroll_pos = 0;
245
gtk_adjustment_value_changed (nav->priv->adj);
254
eog_thumb_nav_button_clicked (GtkButton *button, EogThumbNav *nav)
256
nav->priv->scroll_pos = 0;
258
if ((GTK_WIDGET (button) == nav->priv->button_right) ||
259
(GTK_WIDGET (button) == nav->priv->button_left))
261
nav->priv->scroll_dir = gtk_widget_get_direction (GTK_WIDGET (button)) == GTK_TEXT_DIR_LTR ?
262
GTK_WIDGET (button) == nav->priv->button_right :
263
GTK_WIDGET (button) == nav->priv->button_left;
267
nav->priv->scroll_dir = (GTK_WIDGET (button) == nav->priv->button_down);
270
nav->priv->adj = ((GTK_WIDGET (button) == nav->priv->button_right) ||
271
(GTK_WIDGET (button) == nav->priv->button_left)) ? nav->priv->hadj : nav->priv->vadj;
273
eog_thumb_nav_scroll_step (nav);
277
eog_thumb_nav_start_scroll (GtkButton *button, EogThumbNav *nav)
279
if ((GTK_WIDGET (button) == nav->priv->button_right) ||
280
(GTK_WIDGET (button) == nav->priv->button_left))
282
nav->priv->scroll_dir = gtk_widget_get_direction (GTK_WIDGET (button)) == GTK_TEXT_DIR_LTR ?
283
GTK_WIDGET (button) == nav->priv->button_right :
284
GTK_WIDGET (button) == nav->priv->button_left;
288
nav->priv->scroll_dir = (GTK_WIDGET (button) == nav->priv->button_down);
291
nav->priv->adj = ((GTK_WIDGET (button) == nav->priv->button_right) ||
292
(GTK_WIDGET (button) == nav->priv->button_left)) ? nav->priv->hadj : nav->priv->vadj;
294
nav->priv->scroll_id = g_timeout_add (EOG_THUMB_NAV_SCROLL_TIMEOUT,
295
eog_thumb_nav_scroll_step,
300
eog_thumb_nav_stop_scroll (GtkButton *button, EogThumbNav *nav)
302
if (nav->priv->scroll_id > 0)
304
g_source_remove (nav->priv->scroll_id);
305
nav->priv->scroll_id = 0;
306
nav->priv->scroll_pos = 0;
311
eog_thumb_nav_get_property (GObject *object,
316
EogThumbNav *nav = EOG_THUMB_NAV (object);
320
case PROP_SHOW_BUTTONS:
321
g_value_set_boolean (value,
322
eog_thumb_nav_get_show_buttons (nav));
325
case PROP_THUMB_VIEW:
326
g_value_set_object (value, nav->priv->thumbview);
332
eog_thumb_nav_set_property (GObject *object,
337
EogThumbNav *nav = EOG_THUMB_NAV (object);
341
case PROP_SHOW_BUTTONS:
342
eog_thumb_nav_set_show_buttons (nav,
343
g_value_get_boolean (value));
346
case PROP_THUMB_VIEW:
347
nav->priv->thumbview =
348
GTK_WIDGET (g_value_get_object (value));
354
eog_thumb_nav_constructor (GType type,
355
guint n_construct_properties,
356
GObjectConstructParam *construct_params)
360
EogThumbNavPrivate *priv;
362
object = G_OBJECT_CLASS (eog_thumb_nav_parent_class)->constructor
363
(type, n_construct_properties, construct_params);
365
nav = EOG_THUMB_NAV (object);
366
priv = EOG_THUMB_NAV_GET_PRIVATE (object);
368
if (priv->thumbview != NULL)
370
gtk_container_add (GTK_CONTAINER (priv->sw), priv->thumbview);
371
gtk_widget_show_all (priv->sw);
374
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->sw),
375
GTK_POLICY_AUTOMATIC,
382
eog_thumb_nav_class_init (EogThumbNavClass *class)
384
GObjectClass *g_object_class = (GObjectClass *) class;
386
g_object_class->constructor = eog_thumb_nav_constructor;
387
g_object_class->get_property = eog_thumb_nav_get_property;
388
g_object_class->set_property = eog_thumb_nav_set_property;
390
g_object_class_install_property (g_object_class,
392
g_param_spec_boolean ("show-buttons",
394
"Whether to show navigation buttons or not",
396
(G_PARAM_READABLE | G_PARAM_WRITABLE)));
398
g_object_class_install_property (g_object_class,
400
g_param_spec_object ("thumbview",
402
"The internal thumbnail viewer widget",
403
CHEESE_TYPE_THUMB_VIEW,
404
(G_PARAM_CONSTRUCT_ONLY |
408
g_type_class_add_private (g_object_class, sizeof (EogThumbNavPrivate));
412
eog_thumb_nav_init (EogThumbNav *nav)
414
EogThumbNavPrivate *priv;
417
nav->priv = EOG_THUMB_NAV_GET_PRIVATE (nav);
421
priv->show_buttons = TRUE;
422
priv->vertical = FALSE;
424
priv->button_left = gtk_button_new ();
425
gtk_button_set_relief (GTK_BUTTON (priv->button_left), GTK_RELIEF_NONE);
427
arrow = gtk_arrow_new (GTK_ARROW_LEFT, GTK_SHADOW_ETCHED_IN);
428
gtk_container_add (GTK_CONTAINER (priv->button_left), arrow);
430
gtk_widget_set_size_request (GTK_WIDGET (priv->button_left), 25, 0);
432
g_signal_connect (priv->button_left,
434
G_CALLBACK (eog_thumb_nav_button_clicked),
437
g_signal_connect (priv->button_left,
438
"button-press-event",
439
G_CALLBACK (eog_thumb_nav_start_scroll),
442
g_signal_connect (priv->button_left,
443
"button-release-event",
444
G_CALLBACK (eog_thumb_nav_stop_scroll),
447
priv->button_left = gtk_button_new ();
448
gtk_button_set_relief (GTK_BUTTON (priv->button_left), GTK_RELIEF_NONE);
450
arrow = gtk_arrow_new (GTK_ARROW_LEFT, GTK_SHADOW_ETCHED_IN);
451
gtk_container_add (GTK_CONTAINER (priv->button_left), arrow);
453
gtk_widget_set_size_request (GTK_WIDGET (priv->button_left), 25, 0);
455
g_signal_connect (priv->button_left,
457
G_CALLBACK (eog_thumb_nav_button_clicked),
460
g_signal_connect (priv->button_left,
461
"button-press-event",
462
G_CALLBACK (eog_thumb_nav_start_scroll),
465
g_signal_connect (priv->button_left,
466
"button-release-event",
467
G_CALLBACK (eog_thumb_nav_stop_scroll),
470
priv->vbox = gtk_vbox_new (FALSE, 0);
472
priv->sw = gtk_scrolled_window_new (NULL, NULL);
474
gtk_widget_set_name (gtk_scrolled_window_get_hscrollbar (GTK_SCROLLED_WINDOW (priv->sw)),
476
gtk_widget_set_name (gtk_scrolled_window_get_vscrollbar (GTK_SCROLLED_WINDOW (priv->sw)),
479
gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (priv->sw),
484
g_signal_connect (priv->sw,
486
G_CALLBACK (eog_thumb_nav_scroll_event),
489
priv->hadj = gtk_scrolled_window_get_hadjustment (GTK_SCROLLED_WINDOW (priv->sw));
491
g_signal_connect (priv->hadj,
493
G_CALLBACK (eog_thumb_nav_hadj_changed),
496
g_signal_connect (priv->hadj,
498
G_CALLBACK (eog_thumb_nav_hadj_value_changed),
501
priv->vadj = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (priv->sw));
503
g_signal_connect (priv->vadj,
505
G_CALLBACK (eog_thumb_nav_vadj_changed),
508
g_signal_connect (priv->vadj,
510
G_CALLBACK (eog_thumb_nav_vadj_value_changed),
513
priv->button_right = gtk_button_new ();
514
gtk_button_set_relief (GTK_BUTTON (priv->button_right), GTK_RELIEF_NONE);
516
arrow = gtk_arrow_new (GTK_ARROW_RIGHT, GTK_SHADOW_NONE);
517
gtk_container_add (GTK_CONTAINER (priv->button_right), arrow);
519
gtk_widget_set_size_request (GTK_WIDGET (priv->button_right), 25, 0);
521
g_signal_connect (priv->button_right,
523
G_CALLBACK (eog_thumb_nav_button_clicked),
526
g_signal_connect (priv->button_right,
527
"button-press-event",
528
G_CALLBACK (eog_thumb_nav_start_scroll),
531
g_signal_connect (priv->button_right,
532
"button-release-event",
533
G_CALLBACK (eog_thumb_nav_stop_scroll),
536
priv->button_down = gtk_button_new ();
537
gtk_button_set_relief (GTK_BUTTON (priv->button_down), GTK_RELIEF_NONE);
539
arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE);
540
gtk_container_add (GTK_CONTAINER (priv->button_down), arrow);
542
gtk_widget_set_size_request (GTK_WIDGET (priv->button_down), 0, 25);
544
g_signal_connect (priv->button_down,
546
G_CALLBACK (eog_thumb_nav_button_clicked),
549
g_signal_connect (priv->button_down,
550
"button-press-event",
551
G_CALLBACK (eog_thumb_nav_start_scroll),
554
g_signal_connect (priv->button_down,
555
"button-release-event",
556
G_CALLBACK (eog_thumb_nav_stop_scroll),
559
priv->button_up = gtk_button_new ();
560
gtk_button_set_relief (GTK_BUTTON (priv->button_up), GTK_RELIEF_NONE);
562
arrow = gtk_arrow_new (GTK_ARROW_UP, GTK_SHADOW_NONE);
563
gtk_container_add (GTK_CONTAINER (priv->button_up), arrow);
565
gtk_widget_set_size_request (GTK_WIDGET (priv->button_up), 0, 25);
567
g_signal_connect (priv->button_up,
569
G_CALLBACK (eog_thumb_nav_button_clicked),
572
g_signal_connect (priv->button_up,
573
"button-press-event",
574
G_CALLBACK (eog_thumb_nav_start_scroll),
577
g_signal_connect (priv->button_up,
578
"button-release-event",
579
G_CALLBACK (eog_thumb_nav_stop_scroll),
583
g_object_ref (priv->button_up);
584
g_object_ref (priv->button_down);
585
gtk_box_pack_start (GTK_BOX (nav), priv->button_left, FALSE, FALSE, 0);
586
gtk_box_pack_start (GTK_BOX (nav), priv->vbox, TRUE, TRUE, 0);
587
gtk_box_pack_start (GTK_BOX (nav), priv->button_right, FALSE, FALSE, 0);
588
gtk_box_pack_start (GTK_BOX (priv->vbox), priv->sw, TRUE, TRUE, 0);
590
gtk_adjustment_value_changed (priv->hadj);
595
* @thumbview: a #CheeseThumbView to embed in the navigation widget.
596
* @mode: The navigation mode.
597
* @show_buttons: Whether to show the navigation buttons.
599
* Creates a new thumbnail navigation widget.
601
* Returns: a new #EogThumbNav object.
604
eog_thumb_nav_new (GtkWidget *thumbview,
605
gboolean show_buttons)
608
EogThumbNavPrivate *priv;
610
nav = g_object_new (EOG_TYPE_THUMB_NAV,
611
"show-buttons", show_buttons,
612
"thumbview", thumbview,
613
"homogeneous", FALSE,
619
return GTK_WIDGET (nav);
623
* eog_thumb_nav_get_show_buttons:
624
* @nav: an #EogThumbNav.
626
* Gets whether the navigation buttons are visible.
628
* Returns: %TRUE if the navigation buttons are visible,
632
eog_thumb_nav_get_show_buttons (EogThumbNav *nav)
634
g_return_val_if_fail (EOG_IS_THUMB_NAV (nav), FALSE);
636
return nav->priv->show_buttons;
640
* eog_thumb_nav_set_show_buttons:
641
* @nav: an #EogThumbNav.
642
* @show_buttons: %TRUE to show the buttons, %FALSE to hide them.
644
* Sets whether the navigation buttons to the left and right of the
645
* widget should be visible.
648
eog_thumb_nav_set_show_buttons (EogThumbNav *nav, gboolean show_buttons)
650
g_return_if_fail (EOG_IS_THUMB_NAV (nav));
651
g_return_if_fail (nav->priv->button_left != NULL);
652
g_return_if_fail (nav->priv->button_right != NULL);
654
nav->priv->show_buttons = show_buttons;
658
gtk_widget_show_all (nav->priv->button_left);
659
gtk_widget_show_all (nav->priv->button_right);
663
gtk_widget_hide (nav->priv->button_left);
664
gtk_widget_hide (nav->priv->button_right);
669
eog_thumb_nav_set_policy (EogThumbNav *nav,
670
GtkPolicyType hscrollbar_policy,
671
GtkPolicyType vscrollbar_policy)
673
EogThumbNavPrivate *priv = EOG_THUMB_NAV_GET_PRIVATE (nav);
675
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->sw),
681
eog_thumb_nav_is_vertical (EogThumbNav *nav)
683
EogThumbNavPrivate *priv = EOG_THUMB_NAV_GET_PRIVATE (nav);
685
return priv->vertical;
689
eog_thumb_nav_set_vertical (EogThumbNav *nav, gboolean vertical)
691
EogThumbNavPrivate *priv = EOG_THUMB_NAV_GET_PRIVATE (nav);
693
g_return_if_fail (EOG_IS_THUMB_NAV (nav));
694
g_return_if_fail (priv->button_left != NULL);
695
g_return_if_fail (priv->button_right != NULL);
696
g_return_if_fail (priv->vbox != NULL);
697
g_return_if_fail (priv->sw != NULL);
699
if (vertical == priv->vertical) return;
701
/* show/hide doesn't work because of a mandatory show_all in cheese-window */
705
g_return_if_fail (!gtk_widget_get_parent (priv->button_up));
706
g_return_if_fail (!gtk_widget_get_parent (priv->button_down));
707
g_return_if_fail (gtk_widget_get_parent (priv->button_left));
708
g_return_if_fail (gtk_widget_get_parent (priv->button_right));
710
gtk_box_pack_start (GTK_BOX (priv->vbox), priv->button_up, FALSE, FALSE, 0);
711
gtk_box_reorder_child (GTK_BOX (priv->vbox), priv->button_up, 0);
712
gtk_box_pack_start (GTK_BOX (priv->vbox), priv->button_down, FALSE, FALSE, 0);
713
g_object_unref (priv->button_up);
714
g_object_unref (priv->button_down);
716
g_object_ref (priv->button_left);
717
gtk_container_remove (GTK_CONTAINER (nav), priv->button_left);
718
g_object_ref (priv->button_right);
719
gtk_container_remove (GTK_CONTAINER (nav), priv->button_right);
720
gtk_adjustment_value_changed (priv->vadj);
722
eog_thumb_nav_set_policy (nav,
724
GTK_POLICY_AUTOMATIC);
725
priv->vertical = TRUE;
729
g_return_if_fail (!gtk_widget_get_parent (priv->button_left));
730
g_return_if_fail (!gtk_widget_get_parent (priv->button_right));
731
g_return_if_fail (gtk_widget_get_parent (priv->button_up));
732
g_return_if_fail (gtk_widget_get_parent (priv->button_down));
734
gtk_box_pack_start (GTK_BOX (nav), priv->button_left, FALSE, FALSE, 0);
735
gtk_box_reorder_child (GTK_BOX (nav), priv->button_left, 0);
736
gtk_box_pack_start (GTK_BOX (nav), priv->button_right, FALSE, FALSE, 0);
737
g_object_unref (priv->button_left);
738
g_object_unref (priv->button_right);
740
g_object_ref (priv->button_up);
741
gtk_container_remove (GTK_CONTAINER (priv->vbox), priv->button_up);
742
g_object_ref (priv->button_down);
743
gtk_container_remove (GTK_CONTAINER (priv->vbox), priv->button_down);
744
gtk_adjustment_value_changed (priv->hadj);
746
eog_thumb_nav_set_policy (nav,
747
GTK_POLICY_AUTOMATIC,
749
priv->vertical = FALSE;
751
gtk_widget_show_all (GTK_WIDGET (nav));