]> www.fi.muni.cz Git - evince.git/blob - shell/ev-sidebar.c
Remove frame around dropdown box and button at the top of the sidebar.
[evince.git] / shell / ev-sidebar.c
1 /* this file is part of evince, a gnome document viewer
2  *
3  *  Copyright (C) 2004 Red Hat, Inc.
4  *
5  *  Author:
6  *    Jonathan Blandford <jrb@alum.mit.edu>
7  *
8  * Evince is free software; you can redistribute it and/or modify it
9  * under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * Evince is distributed in the hope that it will be useful, but
14  * WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
21  */
22
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26
27 #include <string.h>
28 #include <gtk/gtk.h>
29 #include <gdk/gdkkeysyms.h>
30
31 #include "ev-sidebar.h"
32 #include "ev-sidebar-page.h"
33 #include "ev-document-thumbnails.h"
34 #include "ev-document-links.h"
35
36 enum
37 {
38         PAGE_COLUMN_TITLE,
39         PAGE_COLUMN_MENU_ITEM,
40         PAGE_COLUMN_MAIN_WIDGET,
41         PAGE_COLUMN_NOTEBOOK_INDEX,
42         PAGE_COLUMN_NUM_COLS
43 };
44
45 struct _EvSidebarPrivate {
46         GtkWidget *notebook;
47         GtkWidget *menu;
48         GtkWidget *hbox;
49         GtkWidget *label;
50            
51         GtkTreeModel *page_model;
52 };
53
54 G_DEFINE_TYPE (EvSidebar, ev_sidebar, GTK_TYPE_VBOX)
55
56 #define EV_SIDEBAR_GET_PRIVATE(object) \
57                 (G_TYPE_INSTANCE_GET_PRIVATE ((object), EV_TYPE_SIDEBAR, EvSidebarPrivate))
58
59 static void
60 ev_sidebar_destroy (GtkObject *object)
61 {
62         EvSidebar *ev_sidebar = EV_SIDEBAR (object);
63
64         if (ev_sidebar->priv->menu) {
65                 gtk_menu_detach (GTK_MENU (ev_sidebar->priv->menu));
66                 ev_sidebar->priv->menu = NULL;
67         }
68            
69         (* GTK_OBJECT_CLASS (ev_sidebar_parent_class)->destroy) (object);
70 }
71
72 static void
73 ev_sidebar_class_init (EvSidebarClass *ev_sidebar_class)
74 {
75         GObjectClass *g_object_class;
76         GtkWidgetClass *widget_class;
77         GtkObjectClass *gtk_object_klass;
78  
79         g_object_class = G_OBJECT_CLASS (ev_sidebar_class);
80         widget_class = GTK_WIDGET_CLASS (ev_sidebar_class);
81         gtk_object_klass = GTK_OBJECT_CLASS (ev_sidebar_class);
82            
83         g_type_class_add_private (g_object_class, sizeof (EvSidebarPrivate));
84            
85         gtk_object_klass->destroy = ev_sidebar_destroy;
86 }
87
88 static void
89 ev_sidebar_menu_position_under (GtkMenu  *menu,
90                                 int      *x,
91                                 int      *y,
92                                 gboolean *push_in,
93                                 gpointer  user_data)
94 {
95         GtkWidget *widget;
96
97         g_return_if_fail (GTK_IS_BUTTON (user_data));
98         g_return_if_fail (GTK_WIDGET_NO_WINDOW (user_data));
99
100         widget = GTK_WIDGET (user_data);
101            
102         gdk_window_get_origin (widget->window, x, y);
103            
104         *x += widget->allocation.x;
105         *y += widget->allocation.y + widget->allocation.height;
106            
107         *push_in = FALSE;
108 }
109
110 static gboolean
111 ev_sidebar_select_button_press_cb (GtkWidget      *widget,
112                                    GdkEventButton *event,
113                                    gpointer        user_data)
114 {
115         EvSidebar *ev_sidebar = EV_SIDEBAR (user_data);
116
117         if (event->button == 1) {
118                 gtk_widget_grab_focus (widget);
119                          
120                 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), TRUE);
121                 gtk_menu_popup (GTK_MENU (ev_sidebar->priv->menu),
122                                 NULL, NULL, ev_sidebar_menu_position_under, widget,
123                                 event->button, event->time);
124
125                 return TRUE;
126         }
127
128         return FALSE;
129 }
130
131 static gboolean
132 ev_sidebar_select_button_key_press_cb (GtkWidget   *widget,
133                                        GdkEventKey *event,
134                                        gpointer     user_data)
135 {
136         EvSidebar *ev_sidebar = EV_SIDEBAR (user_data);
137            
138         if (event->keyval == GDK_space ||
139             event->keyval == GDK_KP_Space ||
140             event->keyval == GDK_Return ||
141             event->keyval == GDK_KP_Enter) {
142                 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), TRUE);
143                 gtk_menu_popup (GTK_MENU (ev_sidebar->priv->menu),
144                                 NULL, NULL, ev_sidebar_menu_position_under, widget,
145                                 1, event->time);
146                 return TRUE;
147         }
148
149         return FALSE;
150 }
151
152 static void
153 ev_sidebar_close_clicked_cb (GtkWidget *widget,
154                              gpointer   user_data)
155 {
156         EvSidebar *ev_sidebar = EV_SIDEBAR (user_data);
157
158         gtk_widget_hide (GTK_WIDGET (ev_sidebar));
159 }
160
161 static void
162 ev_sidebar_menu_deactivate_cb (GtkWidget *widget,
163                                gpointer   user_data)
164 {
165         GtkWidget *menu_button;
166
167         menu_button = GTK_WIDGET (user_data);
168            
169         gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (menu_button), FALSE);
170 }
171
172 static void
173 ev_sidebar_menu_detach_cb (GtkWidget *widget,
174                            GtkMenu   *menu)
175 {
176         EvSidebar *ev_sidebar = EV_SIDEBAR (widget);
177            
178         ev_sidebar->priv->menu = NULL;
179 }
180
181 static void
182 ev_sidebar_menu_item_activate_cb (GtkWidget *widget,
183                                   gpointer   user_data)
184 {
185         EvSidebar *ev_sidebar = EV_SIDEBAR (user_data);
186         GtkTreeIter iter;
187         GtkWidget *menu_item, *item;
188         gchar *title;
189         gboolean valid;
190         gint index;
191
192         menu_item = gtk_menu_get_active (GTK_MENU (ev_sidebar->priv->menu));
193         valid = gtk_tree_model_get_iter_first (ev_sidebar->priv->page_model, &iter);
194            
195         while (valid) {
196                 gtk_tree_model_get (ev_sidebar->priv->page_model,
197                                     &iter,
198                                     PAGE_COLUMN_TITLE, &title, 
199                                     PAGE_COLUMN_MENU_ITEM, &item,
200                                     PAGE_COLUMN_NOTEBOOK_INDEX, &index,
201                                     -1);
202                          
203                 if (item == menu_item) {
204                         gtk_notebook_set_current_page
205                                 (GTK_NOTEBOOK (ev_sidebar->priv->notebook), index);
206                         gtk_label_set_text (GTK_LABEL (ev_sidebar->priv->label), title);
207                         valid = FALSE;
208                 } else {
209                         valid = gtk_tree_model_iter_next (ev_sidebar->priv->page_model, &iter);
210                 }
211         }
212 }
213
214 static void
215 ev_sidebar_init (EvSidebar *ev_sidebar)
216 {
217         GtkWidget *hbox;
218         GtkWidget *close_button;
219         GtkWidget *select_button;
220         GtkWidget *select_hbox;
221         GtkWidget *arrow;
222         GtkWidget *image;
223
224         ev_sidebar->priv = EV_SIDEBAR_GET_PRIVATE (ev_sidebar);
225
226         /* data model */
227         ev_sidebar->priv->page_model = (GtkTreeModel *)
228                         gtk_list_store_new (PAGE_COLUMN_NUM_COLS,
229                                             G_TYPE_STRING,
230                                             GTK_TYPE_WIDGET,
231                                             GTK_TYPE_WIDGET,
232                                             G_TYPE_INT);
233
234         /* top option menu */
235         hbox = gtk_hbox_new (FALSE, 0);
236         ev_sidebar->priv->hbox = hbox;
237         gtk_box_pack_start (GTK_BOX (ev_sidebar), hbox, FALSE, FALSE, 0);
238         gtk_widget_show (hbox);
239
240         select_button = gtk_toggle_button_new ();
241         gtk_button_set_relief (GTK_BUTTON (select_button), GTK_RELIEF_NONE);
242         g_signal_connect (select_button, "button_press_event",
243                           G_CALLBACK (ev_sidebar_select_button_press_cb),
244                           ev_sidebar);
245         g_signal_connect (select_button, "key_press_event",
246                           G_CALLBACK (ev_sidebar_select_button_key_press_cb),
247                           ev_sidebar);
248
249         select_hbox = gtk_hbox_new (FALSE, 0);
250
251         ev_sidebar->priv->label = gtk_label_new ("");
252         gtk_box_pack_start (GTK_BOX (select_hbox),
253                             ev_sidebar->priv->label,
254                             FALSE, FALSE, 0);
255         gtk_widget_show (ev_sidebar->priv->label);
256
257         arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE);
258         gtk_box_pack_end (GTK_BOX (select_hbox), arrow, FALSE, FALSE, 0);
259         gtk_widget_show (arrow);
260
261         gtk_container_add (GTK_CONTAINER (select_button), select_hbox);
262         gtk_widget_show (select_hbox);
263
264         gtk_box_pack_start (GTK_BOX (hbox), select_button, TRUE, TRUE, 0);
265         gtk_widget_show (select_button);
266
267         close_button = gtk_button_new ();
268         gtk_button_set_relief (GTK_BUTTON (close_button), GTK_RELIEF_NONE);
269         g_signal_connect (close_button, "clicked",
270                           G_CALLBACK (ev_sidebar_close_clicked_cb),
271                           ev_sidebar);
272            
273         image = gtk_image_new_from_stock (GTK_STOCK_CLOSE,
274                                           GTK_ICON_SIZE_SMALL_TOOLBAR);
275         gtk_container_add (GTK_CONTAINER (close_button), image);
276         gtk_widget_show (image);
277    
278         gtk_box_pack_end (GTK_BOX (hbox), close_button, FALSE, FALSE, 0);
279         gtk_widget_show (close_button);
280    
281         ev_sidebar->priv->menu = gtk_menu_new ();
282         g_signal_connect (ev_sidebar->priv->menu, "deactivate",
283                           G_CALLBACK (ev_sidebar_menu_deactivate_cb),
284                           select_button);
285         gtk_menu_attach_to_widget (GTK_MENU (ev_sidebar->priv->menu),
286                                    GTK_WIDGET (ev_sidebar),
287                                    ev_sidebar_menu_detach_cb);
288         gtk_widget_show (ev_sidebar->priv->menu);
289
290         ev_sidebar->priv->notebook = gtk_notebook_new ();
291         gtk_notebook_set_show_border (GTK_NOTEBOOK (ev_sidebar->priv->notebook), FALSE);
292         gtk_notebook_set_show_tabs (GTK_NOTEBOOK (ev_sidebar->priv->notebook), FALSE);
293         gtk_box_pack_start (GTK_BOX (ev_sidebar), ev_sidebar->priv->notebook,
294                             TRUE, TRUE, 0);
295         gtk_widget_show (ev_sidebar->priv->notebook);
296
297         gtk_widget_set_sensitive (GTK_WIDGET (ev_sidebar), FALSE);
298 }
299
300 /* Public functions */
301
302 GtkWidget *
303 ev_sidebar_new (void)
304 {
305         GtkWidget *ev_sidebar;
306
307         ev_sidebar = g_object_new (EV_TYPE_SIDEBAR, NULL);
308
309         return ev_sidebar;
310 }
311
312 void
313 ev_sidebar_add_page (EvSidebar   *ev_sidebar,
314                      GtkWidget   *main_widget)
315 {
316         GtkTreeIter iter;
317         GtkWidget *menu_item;
318         gchar *label_title;
319         const gchar *title;
320         int index;
321            
322         g_return_if_fail (EV_IS_SIDEBAR (ev_sidebar));
323         g_return_if_fail (EV_IS_SIDEBAR_PAGE (main_widget));
324         g_return_if_fail (GTK_IS_WIDGET (main_widget));
325         
326         title = ev_sidebar_page_get_label (EV_SIDEBAR_PAGE (main_widget));
327            
328         index = gtk_notebook_append_page (GTK_NOTEBOOK (ev_sidebar->priv->notebook),
329                                           main_widget, NULL);
330            
331         menu_item = gtk_image_menu_item_new_with_label (title);
332         g_signal_connect (menu_item, "activate",
333                           G_CALLBACK (ev_sidebar_menu_item_activate_cb),
334                           ev_sidebar);
335         gtk_widget_show (menu_item);
336         gtk_menu_shell_append (GTK_MENU_SHELL (ev_sidebar->priv->menu),
337                                menu_item);
338            
339         gtk_list_store_insert_with_values (GTK_LIST_STORE (ev_sidebar->priv->page_model),
340                                            &iter, 0,
341                                            PAGE_COLUMN_TITLE, title,
342                                            PAGE_COLUMN_MENU_ITEM, menu_item,
343                                            PAGE_COLUMN_MAIN_WIDGET, main_widget,
344                                            PAGE_COLUMN_NOTEBOOK_INDEX, index,
345                                            -1);
346            
347         /* Set the first item added as active */
348         gtk_tree_model_get_iter_first (ev_sidebar->priv->page_model, &iter);
349         gtk_tree_model_get (ev_sidebar->priv->page_model,
350                             &iter,
351                             PAGE_COLUMN_TITLE, &label_title,
352                             PAGE_COLUMN_NOTEBOOK_INDEX, &index,
353                             -1);
354
355         gtk_menu_set_active (GTK_MENU (ev_sidebar->priv->menu), index);
356         gtk_label_set_text (GTK_LABEL (ev_sidebar->priv->label), label_title);
357         gtk_notebook_set_current_page (GTK_NOTEBOOK (ev_sidebar->priv->notebook),
358                                        index);
359 }
360
361 void
362 ev_sidebar_set_document (EvSidebar   *sidebar,
363                          EvDocument  *document)
364 {
365         EvSidebarPrivate *priv;
366         GtkTreeIter iter;
367         gboolean valid;
368         gboolean has_pages;
369            
370         g_return_if_fail (EV_IS_SIDEBAR (sidebar));
371         g_return_if_fail (EV_IS_DOCUMENT (document));
372            
373         priv = sidebar->priv;
374         
375         has_pages = FALSE;
376         
377         for (valid = gtk_tree_model_get_iter_first (priv->page_model, &iter);
378              valid;
379              valid = gtk_tree_model_iter_next (priv->page_model, &iter)) {
380                 GtkWidget *widget;
381                 GtkWidget *menu_widget;
382
383                 gtk_tree_model_get (priv->page_model, &iter,
384                                     PAGE_COLUMN_MAIN_WIDGET, &widget,
385                                     PAGE_COLUMN_MENU_ITEM, &menu_widget,
386                                     -1);
387                          
388
389                 if (ev_sidebar_page_support_document (EV_SIDEBAR_PAGE (widget), document)) {
390                                 ev_sidebar_page_set_document (EV_SIDEBAR_PAGE (widget), document);
391                                 has_pages = TRUE;
392                 } else {
393                                 gtk_widget_set_sensitive (menu_widget, FALSE);
394                 }
395         }
396         
397         if (!has_pages) {
398                 gtk_widget_hide (GTK_WIDGET (sidebar));
399         } else {
400                 gtk_widget_set_sensitive (GTK_WIDGET (sidebar), TRUE);
401         }
402 }
403