]> www.fi.muni.cz Git - evince.git/blob - ephy-zoom-control.c
66efbaad1af8dc6a114731159dcff56648251664
[evince.git] / ephy-zoom-control.c
1 /*
2  *  Copyright (C) 2003, 2004 Christian Persch
3  *
4  *  Modified 2005 by James Bowes for use in evince.
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; either version 2, or (at your option)
9  *  any later version.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19  *
20  *  $Id$
21  */
22
23 #include "config.h"
24
25 #include "ephy-zoom-control.h"
26 #include "ephy-zoom.h"
27
28 #include <gtk/gtk.h>
29 #include <glib/gi18n.h>
30
31 #define EPHY_ZOOM_CONTROL_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), EPHY_TYPE_ZOOM_CONTROL, EphyZoomControlPrivate))
32
33 struct _EphyZoomControlPrivate
34 {
35         GtkComboBox *combo;
36         float zoom;
37         guint handler_id;
38 };
39
40 enum
41 {
42         COL_TEXT,
43         COL_IS_SEP
44 };
45
46 enum
47 {
48         PROP_0,
49         PROP_ZOOM
50 };
51
52 enum
53 {
54         ZOOM_TO_LEVEL_SIGNAL,
55         LAST_SIGNAL
56 };
57
58 static guint signals[LAST_SIGNAL];
59
60 static GObjectClass *parent_class = NULL;
61
62 static void     ephy_zoom_control_class_init    (EphyZoomControlClass *klass);
63 static void     ephy_zoom_control_init          (EphyZoomControl *control);
64 static void     ephy_zoom_control_finalize      (GObject *o);
65
66 GType
67 ephy_zoom_control_get_type (void)
68 {
69         static GType type = 0;
70
71         if (G_UNLIKELY (type == 0))
72         {
73                 const GTypeInfo our_info =
74                         {
75                                 sizeof (EphyZoomControlClass),
76                                 NULL, /* base_init */
77                                 NULL, /* base_finalize */
78                                 (GClassInitFunc) ephy_zoom_control_class_init,
79                                 NULL,
80                                 NULL, /* class_data */
81                                 sizeof (EphyZoomControl),
82                                 0, /* n_preallocs */
83                                 (GInstanceInitFunc) ephy_zoom_control_init,
84                         };
85
86                 type = g_type_register_static (GTK_TYPE_TOOL_ITEM,
87                                                "EphyZoomControl",
88                                                &our_info, 0);
89         }
90
91         return type;
92 }
93
94 static void
95 combo_changed_cb (GtkComboBox *combo, EphyZoomControl *control)
96 {
97         gint index;
98         float zoom;
99
100         index = gtk_combo_box_get_active (combo);
101         zoom = zoom_levels[index].level;
102
103         if (zoom != control->priv->zoom)
104         {
105                 g_signal_emit (control, signals[ZOOM_TO_LEVEL_SIGNAL], 0, zoom);        
106         }
107 }
108
109 static void
110 sync_zoom_cb (EphyZoomControl *control, GParamSpec *pspec, gpointer data)
111 {
112         EphyZoomControlPrivate *p = control->priv;
113         guint index;
114
115         index = ephy_zoom_get_zoom_level_index (p->zoom);
116
117         g_signal_handler_block (p->combo, p->handler_id);
118         gtk_combo_box_set_active (p->combo, index);
119         g_signal_handler_unblock (p->combo, p->handler_id);     
120 }
121
122 static gboolean
123 row_is_separator (GtkTreeModel *model,
124                   GtkTreeIter  *iter,
125                   gpointer      data)
126 {
127         gboolean is_sep;
128         gtk_tree_model_get (model, iter, COL_IS_SEP, &is_sep, -1);
129         return is_sep;
130 }
131
132 static void
133 ephy_zoom_control_init (EphyZoomControl *control)
134 {
135         EphyZoomControlPrivate *p;
136         GtkWidget *vbox;
137         GtkCellRenderer *renderer;
138         GtkListStore    *store;
139         GtkTreeIter      iter;
140         guint i;
141
142         p = EPHY_ZOOM_CONTROL_GET_PRIVATE (control);
143         control->priv = p;
144
145         p->zoom = 1.0;
146
147         store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_BOOLEAN);
148
149         for (i = 0; i < n_zoom_levels; i++)
150         {
151                 gtk_list_store_append (store, &iter);
152
153                 if (zoom_levels[i].name != NULL) {
154                         gtk_list_store_set (store, &iter,
155                                             COL_TEXT, _(zoom_levels[i].name),
156                                             -1);
157                 } else {
158                         gtk_list_store_set (store, &iter,
159                                             COL_IS_SEP, zoom_levels[i].name == NULL,
160                                             -1);
161                 }
162         }
163
164         p->combo = GTK_COMBO_BOX (gtk_combo_box_new_with_model (GTK_TREE_MODEL (store)));
165         g_object_unref (store);
166
167         renderer = gtk_cell_renderer_text_new ();
168         gtk_cell_layout_pack_start     (GTK_CELL_LAYOUT (p->combo), renderer, TRUE);
169         gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (p->combo), renderer,
170                                         "text", COL_TEXT, NULL);
171         gtk_combo_box_set_row_separator_func (p->combo,
172                                               (GtkTreeViewRowSeparatorFunc) row_is_separator,
173                                               NULL, NULL);
174
175         gtk_combo_box_set_focus_on_click (p->combo, FALSE);
176         g_object_ref_sink (G_OBJECT (p->combo));
177         gtk_widget_show (GTK_WIDGET (p->combo));
178
179         i = ephy_zoom_get_zoom_level_index (p->zoom);
180         gtk_combo_box_set_active (p->combo, i);
181
182         vbox = gtk_vbox_new (TRUE, 0);
183         gtk_box_pack_start (GTK_BOX (vbox), GTK_WIDGET (p->combo), TRUE, FALSE, 0);
184         gtk_widget_show (vbox);
185
186         gtk_container_add (GTK_CONTAINER (control), vbox);
187
188         p->handler_id = g_signal_connect (p->combo, "changed",
189                                           G_CALLBACK (combo_changed_cb), control);
190         
191         g_signal_connect_object (control, "notify::zoom",
192                                  G_CALLBACK (sync_zoom_cb), NULL, 0);
193 }
194
195 static void
196 ephy_zoom_control_set_property (GObject *object,
197                                 guint prop_id,
198                                 const GValue *value,
199                                 GParamSpec *pspec)
200 {
201         EphyZoomControl *control;
202         EphyZoomControlPrivate *p;
203
204         control = EPHY_ZOOM_CONTROL (object);
205         p = control->priv;
206
207         switch (prop_id)
208         {
209                 case PROP_ZOOM:
210                         p->zoom = g_value_get_float (value);
211                         break;
212         }
213 }
214
215 static void
216 ephy_zoom_control_get_property (GObject *object,
217                                 guint prop_id,
218                                 GValue *value,
219                                 GParamSpec *pspec)
220 {
221         EphyZoomControl *control;
222         EphyZoomControlPrivate *p;
223
224         control = EPHY_ZOOM_CONTROL (object);
225         p = control->priv;
226
227         switch (prop_id)
228         {
229                 case PROP_ZOOM:
230                         g_value_set_float (value, p->zoom);
231                         break;
232         }
233 }
234
235 #if !GTK_CHECK_VERSION (2, 11, 5)
236 static void
237 set_combo_tooltip (GtkWidget *widget, 
238                    GtkTooltipsData *data)
239 {
240         if (GTK_IS_BUTTON (widget))
241         {
242                 gtk_tooltips_set_tip (data->tooltips, widget,
243                                       data->tip_text, data->tip_private);
244         }
245 }
246
247 static void
248 combo_realized (GtkWidget *combo,
249                 GtkWidget *control)
250 {
251         GtkTooltipsData *data;
252
253         data = gtk_tooltips_data_get (control);
254         g_return_if_fail (data != NULL);
255
256         gtk_container_forall (GTK_CONTAINER (combo),
257                               (GtkCallback) set_combo_tooltip, data);
258 }
259
260 static gboolean
261 ephy_zoom_control_set_tooltip (GtkToolItem *tool_item,
262                                GtkTooltips *tooltips,
263                                const char *tip_text,
264                                const char *tip_private)
265 {
266         EphyZoomControl *control = EPHY_ZOOM_CONTROL (tool_item);
267         GtkWidget *widget = GTK_WIDGET (tool_item);
268
269         /* hack to make tooltips work also on Ctrl-F1 */
270         gtk_tooltips_set_tip (tooltips, widget, tip_text, tip_private);
271
272         g_signal_handlers_disconnect_by_func
273                 (control->priv->combo, G_CALLBACK (combo_realized), widget);
274
275         if (GTK_WIDGET_REALIZED (tool_item))
276         {
277                 combo_realized (GTK_WIDGET (control->priv->combo), widget);
278         }
279         else
280         {
281                 g_signal_connect_after (control->priv->combo, "realize",
282                                         G_CALLBACK (combo_realized), widget);
283         }
284
285         return TRUE;
286 }
287 #endif /* !GTK_CHECK_VERSION (2, 11, 5) */
288
289 static void
290 ephy_zoom_control_class_init (EphyZoomControlClass *klass)
291 {
292         GObjectClass *object_class;
293         GtkToolItemClass *tool_item_class;
294
295         parent_class = g_type_class_peek_parent (klass);
296
297         object_class = (GObjectClass *)klass;
298         tool_item_class = (GtkToolItemClass *)klass;
299
300         object_class->set_property = ephy_zoom_control_set_property;
301         object_class->get_property = ephy_zoom_control_get_property;
302         object_class->finalize = ephy_zoom_control_finalize;
303
304 #if !GTK_CHECK_VERSION (2, 11, 5)
305         tool_item_class->set_tooltip = ephy_zoom_control_set_tooltip;
306 #endif
307
308         g_object_class_install_property (object_class,
309                                          PROP_ZOOM,
310                                          g_param_spec_float ("zoom",
311                                                              "Zoom",
312                                                              "Zoom level to display in the item.",
313                                                              ZOOM_MINIMAL,
314                                                              ZOOM_MAXIMAL,
315                                                              1.0,
316                                                              G_PARAM_READWRITE));
317
318         signals[ZOOM_TO_LEVEL_SIGNAL] =
319                 g_signal_new ("zoom_to_level",
320                               G_TYPE_FROM_CLASS (klass),
321                               G_SIGNAL_RUN_LAST,
322                               G_STRUCT_OFFSET (EphyZoomControlClass,
323                                                zoom_to_level),
324                               NULL, NULL,
325                               g_cclosure_marshal_VOID__FLOAT,
326                               G_TYPE_NONE,
327                               1,
328                               G_TYPE_FLOAT);
329
330         g_type_class_add_private (object_class, sizeof (EphyZoomControlPrivate));
331 }
332
333 static void
334 ephy_zoom_control_finalize (GObject *o)
335 {
336         EphyZoomControl *control = EPHY_ZOOM_CONTROL (o);
337
338         g_object_unref (control->priv->combo);
339
340         G_OBJECT_CLASS (parent_class)->finalize (o);
341 }
342
343 void
344 ephy_zoom_control_set_zoom_level (EphyZoomControl *control, float zoom)
345 {
346         g_return_if_fail (EPHY_IS_ZOOM_CONTROL (control));
347
348         if (zoom < ZOOM_MINIMAL || zoom > ZOOM_MAXIMAL) return;
349
350         control->priv->zoom = zoom;
351         g_object_notify (G_OBJECT (control), "zoom");
352 }
353
354 float
355 ephy_zoom_control_get_zoom_level (EphyZoomControl *control)
356 {
357         g_return_val_if_fail (EPHY_IS_ZOOM_CONTROL (control), 1.0);
358         
359         return control->priv->zoom;
360 }