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