Added zoom support.
[raktpdf.git] / src / rakt-window.c
index b929331400187d21b5f1472ae15845c73071525f..f83cb6e524b7a5b247928c2b0a5f1e56867df0e5 100644 (file)
@@ -38,10 +38,15 @@ typedef struct {
        GtkAction *action_prev;
        GtkAction *action_next;
 
-       GtkWidget *image;
-       GdkPixbuf *pixbuf;
+       GtkAction *action_zoom_in;
+       GtkAction *action_zoom_out;
+       GtkAction *action_zoom_100;
+
+       GtkWidget *drawing_area;
        PopplerDocument *document;
+       PopplerPage *page;
        gint page_no;
+       gdouble scale;
 } RaktWindowPriv;
 
 static void window_finalize (GObject *object);
@@ -52,18 +57,25 @@ static void on_action_quit (GtkAction *action, RaktWindow *window);
 static void on_action_open (GtkAction *action, RaktWindow *window);
 static void on_action_go_next (GtkAction *action, RaktWindow *window);
 static void on_action_go_previous (GtkAction *action, RaktWindow *window);
+static void on_action_zoom (GtkAction *action, RaktWindow *window);
 static void on_action_about (GtkAction *action, RaktWindow *window);
 
 static const GtkActionEntry action_entries[] = {
        {
                "FileMenu", NULL, "_File", NULL, NULL, NULL
        },
+       {
+               "GoMenu", NULL, "_Go", NULL, NULL, NULL
+       },
+       {
+               "ViewMenu", NULL, "_View", NULL, NULL, NULL
+       },
        {
                "HelpMenu", NULL, "_Help", NULL, NULL, NULL
        },
        {
-               "Open", GTK_STOCK_OPEN,
-               "_Open", "<control>O", "Open a PDF file",
+               "Open", GTK_STOCK_OPEN, "_Open",
+               "<control>O", "Open a PDF file",
                G_CALLBACK (on_action_open)
        },
        {
@@ -77,13 +89,28 @@ static const GtkActionEntry action_entries[] = {
                G_CALLBACK (on_action_go_previous)
        },
        {
-               "Quit", GTK_STOCK_QUIT,
-               "_Quit", "<control>Q", "Quit the application",
+               "Zoom In", GTK_STOCK_ZOOM_IN, "Zoom _In",
+               "<control>plus", "Zoom In",
+               G_CALLBACK (on_action_zoom)
+       },
+       {
+               "Zoom Out", GTK_STOCK_ZOOM_OUT, "Zoom _Out",
+               "<control>minus", "Zoom Out",
+               G_CALLBACK (on_action_zoom)
+       },
+       {
+               "Zoom 100", GTK_STOCK_ZOOM_100, "Zoom 100%",
+               NULL, "Zoom 100%",
+               G_CALLBACK (on_action_zoom)
+       },
+       {
+               "Quit", GTK_STOCK_QUIT, "_Quit",
+               "<control>Q", "Quit the application",
                G_CALLBACK (on_action_quit)
        },
        {
-               "About", GTK_STOCK_ABOUT,
-               "_About", NULL, "About this application",
+               "About", GTK_STOCK_ABOUT, "_About",
+               NULL, "About this application",
                G_CALLBACK (on_action_about)
        }
 };
@@ -96,6 +123,15 @@ static const gchar *ui_layout =
        "                       <separator action='Sep1'/>"
        "                       <menuitem action='Quit'/>"
        "               </menu>"
+       "               <menu action='GoMenu'>"
+       "                       <menuitem action='Previous'/>"
+       "                       <menuitem action='Next'/>"
+       "               </menu>"
+       "               <menu action='ViewMenu'>"
+       "                       <menuitem action='Zoom In'/>"
+       "                       <menuitem action='Zoom Out'/>"
+       "                       <menuitem action='Zoom 100'/>"
+       "               </menu>"
        "               <menu action='HelpMenu'>"
        "                       <menuitem action='About'/>"
        "               </menu>"
@@ -104,6 +140,9 @@ static const gchar *ui_layout =
        "               <toolitem action='Open'/>"
        "               <toolitem action='Previous'/>"
        "               <toolitem action='Next'/>"
+       "               <toolitem action='Zoom In'/>"
+       "               <toolitem action='Zoom Out'/>"
+       "               <toolitem action='Zoom 100'/>"
        "       </toolbar>"
        "</ui>";
 
@@ -126,7 +165,6 @@ static void
 render_page (RaktWindow *window)
 {
        RaktWindowPriv *priv;
-       PopplerPage *page;
        double tmpw, tmph;
        int width, height, n_pages;
 
@@ -134,38 +172,32 @@ render_page (RaktWindow *window)
 
        n_pages = poppler_document_get_n_pages (priv->document);
        gtk_action_set_sensitive (priv->action_prev, priv->page_no > 0);
-       gtk_action_set_sensitive (priv->action_next, priv->page_no < n_pages);
+       gtk_action_set_sensitive (priv->action_next, priv->page_no < n_pages - 1);
 
-       page = poppler_document_get_page (priv->document, priv->page_no);
+       gtk_action_set_sensitive (priv->action_zoom_in, priv->scale < 3.0);
+       gtk_action_set_sensitive (priv->action_zoom_out, priv->scale > 0.4);
+       gtk_action_set_sensitive (priv->action_zoom_100, priv->scale != 1.0);
 
-       poppler_page_get_size (page, &tmpw, &tmph);
+       priv->page = poppler_document_get_page (priv->document, priv->page_no);
 
-       width = (int) tmpw;
-       height = (int) tmph;
+       poppler_page_get_size (priv->page, &tmpw, &tmph);
 
-       priv->pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8,
-                                      width, height);
+       width = (int) (tmpw * priv->scale + 0.5);
+       height = (int) (tmph * priv->scale + 0.5);
 
-       poppler_page_render_to_pixbuf (page, 0, 0, width, height, 1.0, 0,
-                                      priv->pixbuf);
-       gtk_image_set_from_pixbuf (GTK_IMAGE (priv->image), priv->pixbuf);
+       gtk_widget_set_size_request (priv->drawing_area, width, height);
+       gtk_widget_queue_draw_area (priv->drawing_area, 0, 0, width, height);
 }
 
 static void
-open_document (RaktWindow *window, gchar *file)
+open_document (RaktWindow *window, gchar *uri)
 {
        RaktWindowPriv *priv;
        GError *error = NULL;
-       gchar real[PATH_MAX], buf[16 + PATH_MAX];
 
        priv = GET_PRIV (window);
 
-       realpath (file, real);
-
-       g_strlcpy (buf, "file://", sizeof (buf));
-       g_strlcat (buf, real, sizeof (buf));
-
-       priv->document = poppler_document_new_from_file (buf, NULL, &error);
+       priv->document = poppler_document_new_from_file (uri, NULL, &error);
 
        priv->page_no = 0;
        render_page (window);
@@ -209,9 +241,42 @@ window_create_menu (RaktWindow *window)
                                                       "ui/ToolBar/Previous");
        priv->action_next = gtk_ui_manager_get_action (priv->ui_manager,
                                                       "ui/ToolBar/Next");
+       priv->action_zoom_in = gtk_ui_manager_get_action (priv->ui_manager,
+                                                         "ui/ToolBar/Zoom In");
+       priv->action_zoom_out = gtk_ui_manager_get_action (priv->ui_manager,
+                                                          "ui/ToolBar/Zoom Out");
+       priv->action_zoom_100 = gtk_ui_manager_get_action (priv->ui_manager,
+                                                          "ui/ToolBar/Zoom 100");
 
        gtk_action_set_sensitive (priv->action_prev, false);
        gtk_action_set_sensitive (priv->action_next, false);
+
+       gtk_action_set_sensitive (priv->action_zoom_in, false);
+       gtk_action_set_sensitive (priv->action_zoom_out, false);
+       gtk_action_set_sensitive (priv->action_zoom_100, false);
+}
+
+static gboolean
+on_expose_event (GtkWidget *widget, GdkEvent *event, gpointer user_data)
+{
+       RaktWindowPriv *priv;
+       cairo_t *cr;
+
+       priv = GET_PRIV (user_data);
+
+       cr = gdk_cairo_create (priv->drawing_area->window);
+
+       cairo_set_source_rgb (cr, 255, 255, 255);
+       cairo_paint (cr);
+
+       cairo_scale (cr, priv->scale, priv->scale);
+
+       if (priv->page)
+               poppler_page_render (priv->page, cr);
+
+       cairo_destroy (cr);
+
+       return FALSE;
 }
 
 static gboolean
@@ -219,16 +284,19 @@ on_delete_event (GtkWidget *widget, GdkEvent *event, gpointer user_data)
 {
        gtk_main_quit ();
 
-       return FALSE;
+       return TRUE;
 }
 
 static void
 rakt_window_init (RaktWindow *window)
 {
        RaktWindowPriv *priv;
+       GtkWidget *scrolled;
 
        priv = GET_PRIV (window);
 
+       priv->scale = 1.0;
+
        gtk_window_set_default_size (GTK_WINDOW (window), 640, 480);
        gtk_window_set_position (GTK_WINDOW (window), GTK_WIN_POS_CENTER);
 
@@ -238,10 +306,23 @@ rakt_window_init (RaktWindow *window)
 
        window_create_menu (window);
 
-       priv->image = gtk_image_new ();
+       priv->drawing_area = gtk_drawing_area_new ();
+       gtk_widget_show (priv->drawing_area);
+
+       g_signal_connect (priv->drawing_area, "expose-event",
+                         G_CALLBACK (on_expose_event), window);
+
+       scrolled = gtk_scrolled_window_new (NULL, NULL);
+
+       gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
+                                       GTK_POLICY_AUTOMATIC,
+                                       GTK_POLICY_AUTOMATIC);
 
-       gtk_widget_show (priv->image);
-       gtk_box_pack_start (GTK_BOX (priv->content_vbox), priv->image,
+       gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (scrolled),
+                                              priv->drawing_area);
+       gtk_widget_show (scrolled);
+
+       gtk_box_pack_start (GTK_BOX (priv->content_vbox), scrolled,
                            TRUE, TRUE, 0);
 
        g_signal_connect (GTK_WINDOW (window), "delete-event",
@@ -301,10 +382,11 @@ on_action_open (GtkAction *action, RaktWindow *window)
        n = gtk_dialog_run (GTK_DIALOG (dialog));
 
        if (n == GTK_RESPONSE_ACCEPT) {
-               gchar *file;
+               gchar *uri;
 
-               file = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
-               open_document (window, file);
+               uri = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (dialog));
+               open_document (window, uri);
+               g_free (uri);
        }
 
        gtk_widget_destroy (dialog);
@@ -332,6 +414,23 @@ on_action_go_previous (GtkAction *action, RaktWindow *window)
        render_page (window);
 }
 
+static void
+on_action_zoom (GtkAction *action, RaktWindow *window)
+{
+       RaktWindowPriv *priv;
+
+       priv = GET_PRIV (window);
+
+       if (action == priv->action_zoom_in)
+               priv->scale += 0.2;
+       else if (action == priv->action_zoom_out)
+               priv->scale -= 0.2;
+       else
+               priv->scale = 1.0;
+
+       render_page (window);
+}
+
 static void
 on_action_about (GtkAction *action, RaktWindow *window)
 {