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