| /* |
| * Copyright (C) 2008 Carlos Garcia Campos <carlosgc@gnome.org> |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License as published by |
| * the Free Software Foundation; either version 2, or (at your option) |
| * any later version. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| * |
| * You should have received a copy of the GNU General Public License |
| * along with this program; if not, write to the Free Software |
| * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. |
| */ |
| |
| #include "config.h" |
| |
| #include <gtk/gtk.h> |
| |
| #include "layers.h" |
| |
| enum { |
| LAYERS_TITLE_COLUMN, |
| LAYERS_VISIBILITY_COLUMN, |
| LAYERS_ENABLE_COLUMN, |
| LAYERS_SHOWTOGGLE_COLUMN, |
| LAYERS_RB_GROUP_COLUMN, |
| LAYERS_LAYER_COLUMN, |
| N_COLUMNS |
| }; |
| |
| typedef struct { |
| PopplerDocument *doc; |
| guint page; |
| GtkWidget *treeview; |
| GtkWidget *darea; |
| |
| cairo_surface_t *surface; |
| } PgdLayersDemo; |
| |
| static void |
| pgd_layers_free (PgdLayersDemo *demo) |
| { |
| if (!demo) |
| return; |
| |
| if (demo->doc) { |
| g_object_unref (demo->doc); |
| demo->doc = NULL; |
| } |
| |
| if (demo->surface) { |
| cairo_surface_destroy (demo->surface); |
| demo->surface = NULL; |
| } |
| |
| g_free (demo); |
| } |
| |
| static void |
| build_tree (PopplerDocument *document, |
| GtkTreeModel *model, |
| GtkTreeIter *parent, |
| PopplerLayersIter *iter) |
| { |
| |
| do { |
| GtkTreeIter tree_iter; |
| PopplerLayersIter *child; |
| PopplerLayer *layer; |
| gboolean visible; |
| gchar *markup; |
| gint rb_group = 0; |
| |
| layer = poppler_layers_iter_get_layer (iter); |
| if (layer) { |
| markup = g_markup_escape_text (poppler_layer_get_title (layer), -1); |
| visible = poppler_layer_is_visible (layer); |
| rb_group = poppler_layer_get_radio_button_group_id (layer); |
| } else { |
| gchar *title; |
| |
| title = poppler_layers_iter_get_title (iter); |
| markup = g_markup_escape_text (title, -1); |
| g_free (title); |
| |
| visible = FALSE; |
| layer = NULL; |
| } |
| |
| gtk_tree_store_append (GTK_TREE_STORE (model), &tree_iter, parent); |
| gtk_tree_store_set (GTK_TREE_STORE (model), &tree_iter, |
| LAYERS_TITLE_COLUMN, markup, |
| LAYERS_VISIBILITY_COLUMN, visible, |
| LAYERS_ENABLE_COLUMN, TRUE, /* FIXME */ |
| LAYERS_SHOWTOGGLE_COLUMN, (layer != NULL), |
| LAYERS_RB_GROUP_COLUMN, rb_group, |
| LAYERS_LAYER_COLUMN, layer, |
| -1); |
| if (layer) |
| g_object_unref (layer); |
| g_free (markup); |
| |
| child = poppler_layers_iter_get_child (iter); |
| if (child) |
| build_tree (document, model, &tree_iter, child); |
| poppler_layers_iter_free (child); |
| } while (poppler_layers_iter_next (iter)); |
| } |
| |
| GtkTreeModel * |
| pgd_layers_create_model (PopplerDocument *document) |
| { |
| GtkTreeModel *model; |
| PopplerLayersIter *iter; |
| |
| iter = poppler_layers_iter_new (document); |
| if (iter) { |
| model = GTK_TREE_MODEL ( |
| gtk_tree_store_new (N_COLUMNS, |
| G_TYPE_STRING, |
| G_TYPE_BOOLEAN, |
| G_TYPE_BOOLEAN, |
| G_TYPE_BOOLEAN, |
| G_TYPE_INT, |
| G_TYPE_OBJECT)); |
| build_tree (document, model, NULL, iter); |
| poppler_layers_iter_free (iter); |
| } else { |
| GtkTreeIter tree_iter; |
| gchar *markup; |
| |
| model = GTK_TREE_MODEL (gtk_list_store_new (1, G_TYPE_STRING)); |
| gtk_list_store_append (GTK_LIST_STORE (model), &tree_iter); |
| markup = g_strdup_printf ("<span size=\"larger\" style=\"italic\">%s</span>", |
| "The document doesn't contain layers"); |
| gtk_list_store_set (GTK_LIST_STORE (model), &tree_iter, |
| 0, markup, -1); |
| g_free (markup); |
| } |
| |
| return model; |
| } |
| |
| static cairo_surface_t * |
| pgd_layers_render_page (PgdLayersDemo *demo) |
| { |
| cairo_t *cr; |
| PopplerPage *page; |
| gdouble width, height; |
| cairo_surface_t *surface = NULL; |
| |
| page = poppler_document_get_page (demo->doc, demo->page); |
| if (!page) |
| return NULL; |
| |
| poppler_page_get_size (page, &width, &height); |
| gtk_widget_set_size_request (demo->darea, width, height); |
| |
| surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, |
| width, height); |
| cr = cairo_create (surface); |
| |
| cairo_save (cr); |
| cairo_set_source_rgb (cr, 1, 1, 1); |
| cairo_rectangle (cr, 0, 0, width, height); |
| cairo_fill (cr); |
| cairo_restore (cr); |
| |
| cairo_save (cr); |
| poppler_page_render (page, cr); |
| cairo_restore (cr); |
| |
| cairo_destroy (cr); |
| g_object_unref (page); |
| |
| return surface; |
| } |
| |
| static gboolean |
| pgd_layers_viewer_drawing_area_draw (GtkWidget *area, |
| cairo_t *cr, |
| PgdLayersDemo *demo) |
| { |
| if (!demo->surface) { |
| demo->surface = pgd_layers_render_page (demo); |
| if (!demo->surface) |
| return FALSE; |
| } |
| |
| cairo_set_source_surface (cr, demo->surface, 0, 0); |
| cairo_paint (cr); |
| |
| return TRUE; |
| } |
| |
| static gboolean |
| pgd_layers_viewer_redraw (PgdLayersDemo *demo) |
| { |
| cairo_surface_destroy (demo->surface); |
| demo->surface = NULL; |
| |
| gtk_widget_queue_draw (demo->darea); |
| |
| return FALSE; |
| } |
| |
| static void |
| pgd_layers_viewer_queue_redraw (PgdLayersDemo *demo) |
| { |
| g_idle_add ((GSourceFunc)pgd_layers_viewer_redraw, demo); |
| } |
| |
| static void |
| pgd_layers_page_selector_value_changed (GtkSpinButton *spinbutton, |
| PgdLayersDemo *demo) |
| { |
| demo->page = (gint)gtk_spin_button_get_value (spinbutton) - 1; |
| pgd_layers_viewer_queue_redraw (demo); |
| } |
| |
| static GtkWidget * |
| pgd_layers_create_viewer (PgdLayersDemo *demo) |
| { |
| GtkWidget *vbox, *hbox; |
| GtkWidget *label; |
| GtkWidget *swindow; |
| GtkWidget *page_selector; |
| guint n_pages; |
| gchar *str; |
| |
| vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6); |
| |
| hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6); |
| |
| label = gtk_label_new ("Page:"); |
| gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, TRUE, 0); |
| gtk_widget_show (label); |
| |
| n_pages = poppler_document_get_n_pages (demo->doc); |
| page_selector = gtk_spin_button_new_with_range (1, n_pages, 1); |
| g_signal_connect (G_OBJECT (page_selector), "value-changed", |
| G_CALLBACK (pgd_layers_page_selector_value_changed), |
| (gpointer)demo); |
| gtk_box_pack_start (GTK_BOX (hbox), page_selector, FALSE, TRUE, 0); |
| gtk_widget_show (page_selector); |
| |
| str = g_strdup_printf ("of %d", n_pages); |
| label = gtk_label_new (str); |
| gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, TRUE, 0); |
| gtk_widget_show (label); |
| g_free (str); |
| |
| gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 0); |
| gtk_widget_show (hbox); |
| |
| demo->darea = gtk_drawing_area_new (); |
| g_signal_connect (G_OBJECT (demo->darea), "draw", |
| G_CALLBACK (pgd_layers_viewer_drawing_area_draw), |
| (gpointer)demo); |
| |
| swindow = gtk_scrolled_window_new (NULL, NULL); |
| gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swindow), |
| GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); |
| #if GTK_CHECK_VERSION(3, 7, 8) |
| gtk_container_add(GTK_CONTAINER(swindow), demo->darea); |
| #else |
| gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (swindow), demo->darea); |
| #endif |
| gtk_widget_show (demo->darea); |
| |
| gtk_box_pack_start (GTK_BOX (vbox), swindow, TRUE, TRUE, 0); |
| gtk_widget_show (swindow); |
| |
| return vbox; |
| } |
| |
| static gboolean |
| update_kids (GtkTreeModel *model, |
| GtkTreePath *path, |
| GtkTreeIter *iter, |
| GtkTreeIter *parent) |
| { |
| if (gtk_tree_store_is_ancestor (GTK_TREE_STORE (model), parent, iter)) { |
| gboolean visible; |
| |
| gtk_tree_model_get (model, parent, |
| LAYERS_VISIBILITY_COLUMN, &visible, |
| -1); |
| gtk_tree_store_set (GTK_TREE_STORE (model), iter, |
| LAYERS_ENABLE_COLUMN, visible, |
| -1); |
| } |
| |
| return FALSE; |
| } |
| |
| static gboolean |
| clear_rb_group (GtkTreeModel *model, |
| GtkTreePath *path, |
| GtkTreeIter *iter, |
| gint *rb_group) |
| { |
| gint group; |
| |
| gtk_tree_model_get (model, iter, |
| LAYERS_RB_GROUP_COLUMN, &group, |
| -1); |
| |
| if (group == *rb_group) { |
| gtk_tree_store_set (GTK_TREE_STORE (model), iter, |
| LAYERS_VISIBILITY_COLUMN, FALSE, |
| -1); |
| } |
| |
| return FALSE; |
| } |
| |
| static void |
| pgd_layers_visibility_changed (GtkCellRendererToggle *cell, |
| gchar *path_str, |
| PgdLayersDemo *demo) |
| { |
| GtkTreeModel *model; |
| GtkTreePath *path; |
| GtkTreeIter iter; |
| gboolean visible; |
| PopplerLayer *layer; |
| |
| model = gtk_tree_view_get_model (GTK_TREE_VIEW (demo->treeview)); |
| |
| path = gtk_tree_path_new_from_string (path_str); |
| gtk_tree_model_get_iter (model, &iter, path); |
| gtk_tree_model_get (model, &iter, |
| LAYERS_VISIBILITY_COLUMN, &visible, |
| LAYERS_LAYER_COLUMN, &layer, |
| -1); |
| |
| visible = !visible; |
| visible ? poppler_layer_show (layer) : poppler_layer_hide (layer); |
| |
| if (visible) { |
| gint rb_group; |
| |
| rb_group = poppler_layer_get_radio_button_group_id (layer); |
| if (rb_group) { |
| gtk_tree_model_foreach (model, |
| (GtkTreeModelForeachFunc)clear_rb_group, |
| &rb_group); |
| } |
| } |
| |
| gtk_tree_store_set (GTK_TREE_STORE (model), &iter, |
| LAYERS_VISIBILITY_COLUMN, visible, |
| -1); |
| |
| if (poppler_layer_is_parent (layer)) { |
| gtk_tree_model_foreach (model, |
| (GtkTreeModelForeachFunc)update_kids, |
| &iter); |
| } |
| |
| pgd_layers_viewer_queue_redraw (demo); |
| |
| gtk_tree_path_free (path); |
| g_object_unref (layer); |
| } |
| |
| GtkWidget * |
| pgd_layers_create_widget (PopplerDocument *document) |
| { |
| PgdLayersDemo *demo; |
| GtkWidget *swindow; |
| GtkWidget *treeview; |
| GtkTreeModel *model; |
| GtkCellRenderer *renderer; |
| GtkWidget *hpaned, *viewer; |
| |
| demo = g_new0 (PgdLayersDemo, 1); |
| demo->doc = g_object_ref (document); |
| |
| hpaned = gtk_paned_new (GTK_ORIENTATION_HORIZONTAL); |
| |
| viewer = pgd_layers_create_viewer (demo); |
| |
| swindow = gtk_scrolled_window_new (NULL, NULL); |
| gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swindow), |
| GTK_POLICY_AUTOMATIC, |
| GTK_POLICY_AUTOMATIC); |
| |
| model = pgd_layers_create_model (document); |
| treeview = gtk_tree_view_new_with_model (model); |
| demo->treeview = treeview; |
| g_object_unref (model); |
| |
| renderer = gtk_cell_renderer_text_new (); |
| gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (treeview), |
| 0, "Layer", |
| renderer, |
| "markup", LAYERS_TITLE_COLUMN, |
| NULL); |
| g_object_set (G_OBJECT (renderer), "ellipsize", PANGO_ELLIPSIZE_END, NULL); |
| g_object_set (G_OBJECT (gtk_tree_view_get_column (GTK_TREE_VIEW (treeview), 0)), |
| "expand", TRUE, NULL); |
| |
| if (GTK_IS_TREE_STORE (model)) { |
| renderer = gtk_cell_renderer_toggle_new (); |
| gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (treeview), |
| 1, "Show/Hide", |
| renderer, |
| "active", LAYERS_VISIBILITY_COLUMN, |
| "activatable", LAYERS_ENABLE_COLUMN, |
| "visible", LAYERS_SHOWTOGGLE_COLUMN, |
| NULL); |
| |
| g_signal_connect (renderer, "toggled", |
| G_CALLBACK (pgd_layers_visibility_changed), |
| (gpointer)demo); |
| gtk_tree_view_column_set_clickable (gtk_tree_view_get_column (GTK_TREE_VIEW (treeview), 1), |
| TRUE); |
| } |
| |
| gtk_tree_selection_set_mode (gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview)), |
| GTK_SELECTION_NONE); |
| |
| gtk_container_add (GTK_CONTAINER (swindow), treeview); |
| gtk_widget_show (treeview); |
| |
| gtk_paned_add1 (GTK_PANED (hpaned), swindow); |
| gtk_widget_show (swindow); |
| |
| gtk_paned_add2 (GTK_PANED (hpaned), viewer); |
| gtk_widget_show (viewer); |
| |
| gtk_paned_set_position (GTK_PANED (hpaned), 150); |
| |
| g_object_weak_ref (G_OBJECT (hpaned), |
| (GWeakNotify)pgd_layers_free, |
| (gpointer)demo); |
| |
| return hpaned; |
| } |