[simple-scan] Split UI code into three files



commit 30587f6ecc8f21cb7e72838ee22045a144372ed2
Author: Robert Ancell <robert ancell canonical com>
Date:   Wed May 17 20:10:38 2017 +1200

    Split UI code into three files

 src/{simple-scan.ui => app-window.ui}         |    2 +-
 src/{ui.vala => app-window.vala}              |  620 +------------------------
 src/authorize-dialog.vala                     |   37 ++
 src/meson.build                               |    4 +-
 src/{preferences.ui => preferences-dialog.ui} |    0
 src/preferences-dialog.vala                   |  597 ++++++++++++++++++++++++
 src/simple-scan.gresource.xml                 |    4 +-
 src/simple-scan.vala                          |   40 +-
 8 files changed, 664 insertions(+), 640 deletions(-)
---
diff --git a/src/simple-scan.ui b/src/app-window.ui
similarity index 99%
rename from src/simple-scan.ui
rename to src/app-window.ui
index 9c9fd27..f65a0c0 100644
--- a/src/simple-scan.ui
+++ b/src/app-window.ui
@@ -71,7 +71,7 @@
       </object>
     </child>
   </object>
-  <template class="UserInterface" parent="GtkApplicationWindow">
+  <template class="AppWindow" parent="GtkApplicationWindow">
     <property name="can_focus">False</property>
     <property name="title" translatable="yes" comments="Title of scan window">Simple Scan</property>
     <property name="icon_name">scanner</property>
diff --git a/src/ui.vala b/src/app-window.vala
similarity index 76%
rename from src/ui.vala
rename to src/app-window.vala
index f846533..2256dc3 100644
--- a/src/ui.vala
+++ b/src/app-window.vala
@@ -13,8 +13,8 @@
 private const int DEFAULT_TEXT_DPI = 150;
 private const int DEFAULT_PHOTO_DPI = 300;
 
-[GtkTemplate (ui = "/org/gnome/SimpleScan/simple-scan.ui")]
-public class UserInterface : Gtk.ApplicationWindow
+[GtkTemplate (ui = "/org/gnome/SimpleScan/app-window.ui")]
+public class AppWindow : Gtk.ApplicationWindow
 {
     private const GLib.ActionEntry[] action_entries =
     {
@@ -201,7 +201,7 @@ public class UserInterface : Gtk.ApplicationWindow
     public signal void start_scan (string? device, ScanOptions options);
     public signal void stop_scan ();
 
-    public UserInterface ()
+    public AppWindow ()
     {
         settings = new Settings ("org.gnome.SimpleScan");
 
@@ -228,7 +228,7 @@ public class UserInterface : Gtk.ApplicationWindow
         }
     }
 
-    ~UserInterface ()
+    ~AppWindow ()
     {
         book.page_added.disconnect (page_added_cb);
         book.reordered.disconnect (reordered_cb);
@@ -1935,615 +1935,3 @@ public class UserInterface : Gtk.ApplicationWindow
         visible = true;
     }
 }
-
-[GtkTemplate (ui = "/org/gnome/SimpleScan/preferences.ui")]
-private class PreferencesDialog : Gtk.Dialog
-{
-    private Settings settings;
-
-    private bool setting_devices;
-    private bool user_selected_device;
-
-    [GtkChild]
-    private Gtk.ComboBox device_combo;
-    [GtkChild]
-    private Gtk.ComboBox text_dpi_combo;
-    [GtkChild]
-    private Gtk.ComboBox photo_dpi_combo;
-    [GtkChild]
-    private Gtk.ComboBox page_side_combo;
-    [GtkChild]
-    private Gtk.ComboBox paper_size_combo;
-    [GtkChild]
-    private Gtk.Scale brightness_scale;
-    [GtkChild]
-    private Gtk.Scale contrast_scale;
-    [GtkChild]
-    private Gtk.Scale quality_scale;
-    [GtkChild]
-    private Gtk.Scale page_delay_scale;
-    [GtkChild]
-    private Gtk.ListStore device_model;
-    [GtkChild]
-    private Gtk.ListStore text_dpi_model;
-    [GtkChild]
-    private Gtk.ListStore photo_dpi_model;
-    [GtkChild]
-    private Gtk.ListStore page_side_model;
-    [GtkChild]
-    private Gtk.ListStore paper_size_model;
-    [GtkChild]
-    private Gtk.Adjustment brightness_adjustment;
-    [GtkChild]
-    private Gtk.Adjustment contrast_adjustment;
-    [GtkChild]
-    private Gtk.Adjustment quality_adjustment;
-    [GtkChild]
-    private Gtk.Adjustment page_delay_adjustment;
-
-    public PreferencesDialog (Settings settings)
-    {
-        this.settings = settings;
-
-        Gtk.TreeIter iter;
-        paper_size_model.append (out iter);
-        paper_size_model.set (iter, 0, 0, 1, 0, 2,
-                              /* Combo box value for automatic paper size */
-                              _("Automatic"), -1);
-        paper_size_model.append (out iter);
-        paper_size_model.set (iter, 0, 1050, 1, 1480, 2, "A6", -1);
-        paper_size_model.append (out iter);
-        paper_size_model.set (iter, 0, 1480, 1, 2100, 2, "A5", -1);
-        paper_size_model.append (out iter);
-        paper_size_model.set (iter, 0, 2100, 1, 2970, 2, "A4", -1);
-        paper_size_model.append (out iter);
-        paper_size_model.set (iter, 0, 2159, 1, 2794, 2, "Letter", -1);
-        paper_size_model.append (out iter);
-        paper_size_model.set (iter, 0, 2159, 1, 3556, 2, "Legal", -1);
-        paper_size_model.append (out iter);
-        paper_size_model.set (iter, 0, 1016, 1, 1524, 2, "4×6", -1);
-
-        page_delay_scale.add_mark (0, Gtk.PositionType.BOTTOM, null);
-        page_delay_scale.add_mark (500, Gtk.PositionType.BOTTOM, null);
-        page_delay_scale.add_mark (1000, Gtk.PositionType.BOTTOM, null);
-        page_delay_scale.add_mark (2000, Gtk.PositionType.BOTTOM, null);
-        page_delay_scale.add_mark (4000, Gtk.PositionType.BOTTOM, null);
-        page_delay_scale.add_mark (6000, Gtk.PositionType.BOTTOM, null);
-        page_delay_scale.add_mark (8000, Gtk.PositionType.BOTTOM, null);
-        page_delay_scale.add_mark (10000, Gtk.PositionType.BOTTOM, null);
-
-        var renderer = new Gtk.CellRendererText ();
-        device_combo.pack_start (renderer, true);
-        device_combo.add_attribute (renderer, "text", 1);
-
-        renderer = new Gtk.CellRendererText ();
-        page_side_combo.pack_start (renderer, true);
-        page_side_combo.add_attribute (renderer, "text", 1);
-        var dpi = settings.get_int ("text-dpi");
-        if (dpi <= 0)
-            dpi = DEFAULT_TEXT_DPI;
-        set_dpi_combo (text_dpi_combo, DEFAULT_TEXT_DPI, dpi);
-        text_dpi_combo.changed.connect (() => { settings.set_int ("text-dpi", get_text_dpi ()); });
-        dpi = settings.get_int ("photo-dpi");
-        if (dpi <= 0)
-            dpi = DEFAULT_PHOTO_DPI;
-        set_dpi_combo (photo_dpi_combo, DEFAULT_PHOTO_DPI, dpi);
-        photo_dpi_combo.changed.connect (() => { settings.set_int ("photo-dpi", get_photo_dpi ()); });
-
-        set_page_side ((ScanType) settings.get_enum ("page-side"));
-        page_side_combo.changed.connect (() => { settings.set_enum ("page-side", get_page_side ()); });
-
-        renderer = new Gtk.CellRendererText ();
-        paper_size_combo.pack_start (renderer, true);
-        paper_size_combo.add_attribute (renderer, "text", 2);
-
-        var lower = brightness_adjustment.lower;
-        var darker_label = "<small>%s</small>".printf (_("Darker"));
-        var upper = brightness_adjustment.upper;
-        var lighter_label = "<small>%s</small>".printf (_("Lighter"));
-        brightness_scale.add_mark (lower, Gtk.PositionType.BOTTOM, darker_label);
-        brightness_scale.add_mark (0, Gtk.PositionType.BOTTOM, null);
-        brightness_scale.add_mark (upper, Gtk.PositionType.BOTTOM, lighter_label);
-        brightness_adjustment.value = settings.get_int ("brightness");
-        brightness_adjustment.value_changed.connect (() => { settings.set_int ("brightness", get_brightness 
()); });
-
-        lower = contrast_adjustment.lower;
-        var less_label = "<small>%s</small>".printf (_("Less"));
-        upper = contrast_adjustment.upper;
-        var more_label = "<small>%s</small>".printf (_("More"));
-        contrast_scale.add_mark (lower, Gtk.PositionType.BOTTOM, less_label);
-        contrast_scale.add_mark (0, Gtk.PositionType.BOTTOM, null);
-        contrast_scale.add_mark (upper, Gtk.PositionType.BOTTOM, more_label);
-        contrast_adjustment.value = settings.get_int ("contrast");
-        contrast_adjustment.value_changed.connect (() => { settings.set_int ("contrast", get_contrast ()); 
});
-
-        lower = quality_adjustment.lower;
-        var minimum_label = "<small>%s</small>".printf (_("Minimum"));
-        upper = quality_adjustment.upper;
-        var maximum_label = "<small>%s</small>".printf (_("Maximum"));
-        quality_scale.add_mark (lower, Gtk.PositionType.BOTTOM, minimum_label);
-        quality_scale.add_mark (75, Gtk.PositionType.BOTTOM, null);
-        quality_scale.add_mark (upper, Gtk.PositionType.BOTTOM, maximum_label);
-        quality_adjustment.value = settings.get_int ("jpeg-quality");
-        quality_adjustment.value_changed.connect (() => { settings.set_int ("jpeg-quality", get_quality ()); 
});
-
-        var paper_width = settings.get_int ("paper-width");
-        var paper_height = settings.get_int ("paper-height");
-        set_paper_size (paper_width, paper_height);
-        paper_size_combo.changed.connect (() =>
-        {
-            int w, h;
-            get_paper_size (out w, out h);
-            settings.set_int ("paper-width", w);
-            settings.set_int ("paper-height", h);
-        });
-
-        set_page_delay (settings.get_int ("page-delay"));
-        page_delay_scale.format_value.connect ((value) => { return "%.1fs".printf (value / 1000.0); });
-        page_delay_adjustment.value_changed.connect (() => { settings.set_int ("page-delay", get_page_delay 
()); });
-    }
-
-    public void present_device ()
-    {
-        device_combo.grab_focus ();
-        present ();
-    }
-
-    public void set_scan_devices (List<ScanDevice> devices)
-    {
-        setting_devices = true;
-
-        /* If the user hasn't chosen a scanner choose the best available one */
-        var have_selection = false;
-        if (user_selected_device)
-            have_selection = device_combo.active >= 0;
-
-        /* Add new devices */
-        int index = 0;
-        Gtk.TreeIter iter;
-        foreach (var device in devices)
-        {
-            int n_delete = -1;
-
-            /* Find if already exists */
-            if (device_model.iter_nth_child (out iter, null, index))
-            {
-                int i = 0;
-                do
-                {
-                    string name;
-                    bool matched;
-
-                    device_model.get (iter, 0, out name, -1);
-                    matched = name == device.name;
-
-                    if (matched)
-                    {
-                        n_delete = i;
-                        break;
-                    }
-                    i++;
-                } while (device_model.iter_next (ref iter));
-            }
-
-            /* If exists, remove elements up to this one */
-            if (n_delete >= 0)
-            {
-                int i;
-
-                /* Update label */
-                device_model.set (iter, 1, device.label, -1);
-
-                for (i = 0; i < n_delete; i++)
-                {
-                    device_model.iter_nth_child (out iter, null, index);
-#if VALA_0_36
-                    device_model.remove (ref iter);
-#else
-                    device_model.remove (iter);
-#endif
-                }
-            }
-            else
-            {
-                device_model.insert (out iter, index);
-                device_model.set (iter, 0, device.name, 1, device.label, -1);
-            }
-            index++;
-        }
-
-        /* Remove any remaining devices */
-        while (device_model.iter_nth_child (out iter, null, index))
-#if VALA_0_36
-            device_model.remove (ref iter);
-#else
-            device_model.remove (iter);
-#endif
-
-        /* Select the previously selected device or the first available device */
-        if (!have_selection)
-        {
-            var device = settings.get_string ("selected-device");
-            if (device != null && find_scan_device (device, out iter))
-                device_combo.set_active_iter (iter);
-            else
-                device_combo.set_active (0);
-        }
-
-        setting_devices = false;
-    }
-
-    public int get_device_count ()
-    {
-        return device_model.iter_n_children (null);
-    }
-
-    public string? get_selected_device ()
-    {
-        Gtk.TreeIter iter;
-
-        if (device_combo.get_active_iter (out iter))
-        {
-            string device;
-            device_model.get (iter, 0, out device, -1);
-            return device;
-        }
-
-        return null;
-    }
-
-    public void set_selected_device (string device)
-    {
-        user_selected_device = true;
-
-        Gtk.TreeIter iter;
-        if (!find_scan_device (device, out iter))
-            return;
-
-        device_combo.set_active_iter (iter);
-    }
-
-    private bool find_scan_device (string device, out Gtk.TreeIter iter)
-    {
-        bool have_iter = false;
-
-        if (device_model.get_iter_first (out iter))
-        {
-            do
-            {
-                string d;
-                device_model.get (iter, 0, out d, -1);
-                if (d == device)
-                    have_iter = true;
-            } while (!have_iter && device_model.iter_next (ref iter));
-        }
-
-        return have_iter;
-    }
-
-    private void set_page_side (ScanType page_side)
-    {
-        Gtk.TreeIter iter;
-
-        if (page_side_model.get_iter_first (out iter))
-        {
-            do
-            {
-                int s;
-                page_side_model.get (iter, 0, out s, -1);
-                if (s == page_side)
-                {
-                    page_side_combo.set_active_iter (iter);
-                    return;
-                }
-            } while (page_side_model.iter_next (ref iter));
-         }
-    }
-
-    public void set_paper_size (int width, int height)
-    {
-        Gtk.TreeIter iter;
-        bool have_iter;
-
-        for (have_iter = paper_size_model.get_iter_first (out iter);
-             have_iter;
-             have_iter = paper_size_model.iter_next (ref iter))
-        {
-            int w, h;
-            paper_size_model.get (iter, 0, out w, 1, out h, -1);
-            if (w == width && h == height)
-               break;
-        }
-
-        if (!have_iter)
-            have_iter = paper_size_model.get_iter_first (out iter);
-        if (have_iter)
-            paper_size_combo.set_active_iter (iter);
-    }
-
-    public int get_text_dpi ()
-    {
-        Gtk.TreeIter iter;
-        int dpi = DEFAULT_TEXT_DPI;
-
-        if (text_dpi_combo.get_active_iter (out iter))
-            text_dpi_model.get (iter, 0, out dpi, -1);
-
-        return dpi;
-    }
-
-    public int get_photo_dpi ()
-    {
-        Gtk.TreeIter iter;
-        int dpi = DEFAULT_PHOTO_DPI;
-
-        if (photo_dpi_combo.get_active_iter (out iter))
-            photo_dpi_model.get (iter, 0, out dpi, -1);
-
-        return dpi;
-    }
-
-    public ScanType get_page_side ()
-    {
-        Gtk.TreeIter iter;
-        int page_side = ScanType.ADF_BOTH;
-
-        if (page_side_combo.get_active_iter (out iter))
-            page_side_model.get (iter, 0, out page_side, -1);
-
-        return (ScanType) page_side;
-    }
-
-    public bool get_paper_size (out int width, out int height)
-    {
-        Gtk.TreeIter iter;
-
-        width = height = 0;
-        if (paper_size_combo.get_active_iter (out iter))
-        {
-            paper_size_model.get (iter, 0, ref width, 1, ref height, -1);
-            return true;
-        }
-
-        return false;
-    }
-
-    public int get_brightness ()
-    {
-        return (int) brightness_adjustment.value;
-    }
-
-    public void set_brightness (int brightness)
-    {
-        brightness_adjustment.value = brightness;
-    }
-
-    public int get_contrast ()
-    {
-        return (int) contrast_adjustment.value;
-    }
-
-    public void set_contrast (int contrast)
-    {
-        contrast_adjustment.value = contrast;
-    }
-
-    public int get_quality ()
-    {
-        return (int) quality_adjustment.value;
-    }
-
-    public void set_quality (int quality)
-    {
-        quality_adjustment.value = quality;
-    }
-
-    public int get_page_delay ()
-    {
-        return (int) page_delay_adjustment.value;
-    }
-
-    public void set_page_delay (int page_delay)
-    {
-        page_delay_adjustment.value = page_delay;
-    }
-
-    private void set_dpi_combo (Gtk.ComboBox combo, int default_dpi, int current_dpi)
-    {
-        var renderer = new Gtk.CellRendererText ();
-        combo.pack_start (renderer, true);
-        combo.add_attribute (renderer, "text", 1);
-
-        var model = combo.model as Gtk.ListStore;
-        int[] scan_resolutions = {75, 150, 300, 600, 1200, 2400};
-        foreach (var dpi in scan_resolutions)
-        {
-            string label;
-            if (dpi == default_dpi)
-                /* Preferences dialog: Label for default resolution in resolution list */
-                label = _("%d dpi (default)").printf (dpi);
-            else if (dpi == 75)
-                /* Preferences dialog: Label for minimum resolution in resolution list */
-                label = _("%d dpi (draft)").printf (dpi);
-            else if (dpi == 1200)
-                /* Preferences dialog: Label for maximum resolution in resolution list */
-                label = _("%d dpi (high resolution)").printf (dpi);
-            else
-                /* Preferences dialog: Label for resolution value in resolution list (dpi = dots per inch) */
-                label = _("%d dpi").printf (dpi);
-
-            Gtk.TreeIter iter;
-            model.append (out iter);
-            model.set (iter, 0, dpi, 1, label, -1);
-
-            if (dpi == current_dpi)
-                combo.set_active_iter (iter);
-        }
-    }
-
-    [GtkCallback]
-    private void device_combo_changed_cb (Gtk.Widget widget)
-    {
-        if (setting_devices)
-            return;
-        user_selected_device = true;
-        if (get_selected_device () != null)
-            settings.set_string ("selected-device", get_selected_device ());
-    }
-}
-
-private class ProgressBarDialog : Gtk.Window
-{
-    private Gtk.ProgressBar bar;
-
-    public double fraction
-    {
-        get { return bar.fraction; }
-        set { bar.fraction = value; }
-    }
-
-    public string message
-    {
-        get { return bar.text; }
-        set { bar.text = value; }
-    }
-
-    public ProgressBarDialog (Gtk.ApplicationWindow parent, string title)
-    {
-        bar = new Gtk.ProgressBar ();
-        var hbox = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 5);
-        var vbox = new Gtk.Box (Gtk.Orientation.VERTICAL, 5);
-        hbox.hexpand = true;
-
-        bar.text = "";
-        bar.show_text = true;
-        bar.set_size_request (225, 25);
-        set_size_request (250, 50);
-
-        vbox.pack_start (bar, true, false, 0);
-        hbox.pack_start (vbox, true, false, 0);
-        add (hbox);
-        this.title = title;
-
-        transient_for = parent;
-        set_position (Gtk.WindowPosition.CENTER_ON_PARENT);
-        modal = true;
-        resizable = false;
-
-        hbox.visible = true;
-        vbox.visible = true;
-        bar.visible = true;
-    }
-}
-
-private string? get_temporary_filename (string prefix, string extension)
-{
-    /* NOTE: I'm not sure if this is a 100% safe strategy to use g_file_open_tmp(), close and
-     * use the filename but it appears to work in practice */
-
-    var filename = "%sXXXXXX.%s".printf (prefix, extension);
-    string path;
-    try
-    {
-        var fd = FileUtils.open_tmp (filename, out path);
-        Posix.close (fd);
-    }
-    catch (Error e)
-    {
-        warning ("Error creating temporary file: %s", e.message);
-        return null;
-    }
-
-    return path;
-}
-
-private class PageIcon : Gtk.DrawingArea
-{
-    private string text;
-    private double r;
-    private double g;
-    private double b;
-    private const int MINIMUM_WIDTH = 20;
-
-    public PageIcon (string text, double r = 1.0, double g = 1.0, double b = 1.0)
-    {
-        this.text = text;
-        this.r = r;
-        this.g = g;
-        this.b = b;
-    }
-
-    public override void get_preferred_width (out int minimum_width, out int natural_width)
-    {
-        minimum_width = natural_width = MINIMUM_WIDTH;
-    }
-
-    public override void get_preferred_height (out int minimum_height, out int natural_height)
-    {
-        minimum_height = natural_height = (int) Math.round (MINIMUM_WIDTH * Math.SQRT2);
-    }
-
-    public override void get_preferred_height_for_width (int width, out int minimum_height, out int 
natural_height)
-    {
-        minimum_height = natural_height = (int) (width * Math.SQRT2);
-    }
-
-    public override void get_preferred_width_for_height (int height, out int minimum_width, out int 
natural_width)
-    {
-        minimum_width = natural_width = (int) (height / Math.SQRT2);
-    }
-
-    public override bool draw (Cairo.Context c)
-    {
-        var w = get_allocated_width ();
-        var h = get_allocated_height ();
-        if (w * Math.SQRT2 > h)
-            w = (int) Math.round (h / Math.SQRT2);
-        else
-            h = (int) Math.round (w * Math.SQRT2);
-
-        c.translate ((get_allocated_width () - w) / 2, (get_allocated_height () - h) / 2);
-
-        c.rectangle (0.5, 0.5, w - 1, h - 1);
-
-        c.set_source_rgb (r, g, b);
-        c.fill_preserve ();
-
-        c.set_line_width (1.0);
-        c.set_source_rgb (0.0, 0.0, 0.0);
-        c.stroke ();
-
-        Cairo.TextExtents extents;
-        c.text_extents (text, out extents);
-        c.translate ((w - extents.width) * 0.5 - 0.5, (h + extents.height) * 0.5 - 0.5);
-        c.show_text (text);
-
-        return true;
-    }
-}
-
-[GtkTemplate (ui = "/org/gnome/SimpleScan/authorize-dialog.ui")]
-private class AuthorizeDialog : Gtk.Dialog
-{
-    [GtkChild]
-    private Gtk.Label authorize_label;
-    [GtkChild]
-    private Gtk.Entry username_entry;
-    [GtkChild]
-    private Gtk.Entry password_entry;
-
-    public AuthorizeDialog (string title)
-    {
-        authorize_label.set_text (title);
-    }
-
-    public string get_username ()
-    {
-        return username_entry.text;
-    }
-
-    public string get_password ()
-    {
-        return password_entry.text;
-    }
-}
diff --git a/src/authorize-dialog.vala b/src/authorize-dialog.vala
new file mode 100644
index 0000000..a6e5ab0
--- /dev/null
+++ b/src/authorize-dialog.vala
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2009-2017 Canonical Ltd.
+ * Author: Robert Ancell <robert ancell canonical com>,
+ *         Eduard Gotwig <g ox io>
+ *
+ * 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 3 of the License, or (at your option) any later
+ * version. See http://www.gnu.org/copyleft/gpl.html the full text of the
+ * license.
+ */
+
+[GtkTemplate (ui = "/org/gnome/SimpleScan/authorize-dialog.ui")]
+private class AuthorizeDialog : Gtk.Dialog
+{
+    [GtkChild]
+    private Gtk.Label authorize_label;
+    [GtkChild]
+    private Gtk.Entry username_entry;
+    [GtkChild]
+    private Gtk.Entry password_entry;
+
+    public AuthorizeDialog (string title)
+    {
+        authorize_label.set_text (title);
+    }
+
+    public string get_username ()
+    {
+        return username_entry.text;
+    }
+
+    public string get_password ()
+    {
+        return password_entry.text;
+    }
+}
diff --git a/src/meson.build b/src/meson.build
index cfda86d..ed09864 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -15,13 +15,15 @@ endif
 
 simple_scan = executable ('simple-scan',
                           [ 'config.vapi',
+                            'app-window.vala',
+                            'authorize-dialog.vala',
                             'book.vala',
                             'book-view.vala',
                             'page.vala',
                             'page-view.vala',
+                            'preferences-dialog.vala',
                             'simple-scan.vala',
                             'scanner.vala',
-                            'ui.vala',
                             'autosave-manager.vala' ] + resources,
                           dependencies: dependencies,
                           vala_args: vala_args,
diff --git a/src/preferences.ui b/src/preferences-dialog.ui
similarity index 100%
rename from src/preferences.ui
rename to src/preferences-dialog.ui
diff --git a/src/preferences-dialog.vala b/src/preferences-dialog.vala
new file mode 100644
index 0000000..0849583
--- /dev/null
+++ b/src/preferences-dialog.vala
@@ -0,0 +1,597 @@
+/*
+ * Copyright (C) 2009-2017 Canonical Ltd.
+ * Author: Robert Ancell <robert ancell canonical com>,
+ *         Eduard Gotwig <g ox io>
+ *
+ * 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 3 of the License, or (at your option) any later
+ * version. See http://www.gnu.org/copyleft/gpl.html the full text of the
+ * license.
+ */
+
+[GtkTemplate (ui = "/org/gnome/SimpleScan/preferences-dialog.ui")]
+private class PreferencesDialog : Gtk.Dialog
+{
+    private Settings settings;
+
+    private bool setting_devices;
+    private bool user_selected_device;
+
+    [GtkChild]
+    private Gtk.ComboBox device_combo;
+    [GtkChild]
+    private Gtk.ComboBox text_dpi_combo;
+    [GtkChild]
+    private Gtk.ComboBox photo_dpi_combo;
+    [GtkChild]
+    private Gtk.ComboBox page_side_combo;
+    [GtkChild]
+    private Gtk.ComboBox paper_size_combo;
+    [GtkChild]
+    private Gtk.Scale brightness_scale;
+    [GtkChild]
+    private Gtk.Scale contrast_scale;
+    [GtkChild]
+    private Gtk.Scale quality_scale;
+    [GtkChild]
+    private Gtk.Scale page_delay_scale;
+    [GtkChild]
+    private Gtk.ListStore device_model;
+    [GtkChild]
+    private Gtk.ListStore text_dpi_model;
+    [GtkChild]
+    private Gtk.ListStore photo_dpi_model;
+    [GtkChild]
+    private Gtk.ListStore page_side_model;
+    [GtkChild]
+    private Gtk.ListStore paper_size_model;
+    [GtkChild]
+    private Gtk.Adjustment brightness_adjustment;
+    [GtkChild]
+    private Gtk.Adjustment contrast_adjustment;
+    [GtkChild]
+    private Gtk.Adjustment quality_adjustment;
+    [GtkChild]
+    private Gtk.Adjustment page_delay_adjustment;
+
+    public PreferencesDialog (Settings settings)
+    {
+        this.settings = settings;
+
+        Gtk.TreeIter iter;
+        paper_size_model.append (out iter);
+        paper_size_model.set (iter, 0, 0, 1, 0, 2,
+                              /* Combo box value for automatic paper size */
+                              _("Automatic"), -1);
+        paper_size_model.append (out iter);
+        paper_size_model.set (iter, 0, 1050, 1, 1480, 2, "A6", -1);
+        paper_size_model.append (out iter);
+        paper_size_model.set (iter, 0, 1480, 1, 2100, 2, "A5", -1);
+        paper_size_model.append (out iter);
+        paper_size_model.set (iter, 0, 2100, 1, 2970, 2, "A4", -1);
+        paper_size_model.append (out iter);
+        paper_size_model.set (iter, 0, 2159, 1, 2794, 2, "Letter", -1);
+        paper_size_model.append (out iter);
+        paper_size_model.set (iter, 0, 2159, 1, 3556, 2, "Legal", -1);
+        paper_size_model.append (out iter);
+        paper_size_model.set (iter, 0, 1016, 1, 1524, 2, "4×6", -1);
+
+        page_delay_scale.add_mark (0, Gtk.PositionType.BOTTOM, null);
+        page_delay_scale.add_mark (500, Gtk.PositionType.BOTTOM, null);
+        page_delay_scale.add_mark (1000, Gtk.PositionType.BOTTOM, null);
+        page_delay_scale.add_mark (2000, Gtk.PositionType.BOTTOM, null);
+        page_delay_scale.add_mark (4000, Gtk.PositionType.BOTTOM, null);
+        page_delay_scale.add_mark (6000, Gtk.PositionType.BOTTOM, null);
+        page_delay_scale.add_mark (8000, Gtk.PositionType.BOTTOM, null);
+        page_delay_scale.add_mark (10000, Gtk.PositionType.BOTTOM, null);
+
+        var renderer = new Gtk.CellRendererText ();
+        device_combo.pack_start (renderer, true);
+        device_combo.add_attribute (renderer, "text", 1);
+
+        renderer = new Gtk.CellRendererText ();
+        page_side_combo.pack_start (renderer, true);
+        page_side_combo.add_attribute (renderer, "text", 1);
+        var dpi = settings.get_int ("text-dpi");
+        if (dpi <= 0)
+            dpi = DEFAULT_TEXT_DPI;
+        set_dpi_combo (text_dpi_combo, DEFAULT_TEXT_DPI, dpi);
+        text_dpi_combo.changed.connect (() => { settings.set_int ("text-dpi", get_text_dpi ()); });
+        dpi = settings.get_int ("photo-dpi");
+        if (dpi <= 0)
+            dpi = DEFAULT_PHOTO_DPI;
+        set_dpi_combo (photo_dpi_combo, DEFAULT_PHOTO_DPI, dpi);
+        photo_dpi_combo.changed.connect (() => { settings.set_int ("photo-dpi", get_photo_dpi ()); });
+
+        set_page_side ((ScanType) settings.get_enum ("page-side"));
+        page_side_combo.changed.connect (() => { settings.set_enum ("page-side", get_page_side ()); });
+
+        renderer = new Gtk.CellRendererText ();
+        paper_size_combo.pack_start (renderer, true);
+        paper_size_combo.add_attribute (renderer, "text", 2);
+
+        var lower = brightness_adjustment.lower;
+        var darker_label = "<small>%s</small>".printf (_("Darker"));
+        var upper = brightness_adjustment.upper;
+        var lighter_label = "<small>%s</small>".printf (_("Lighter"));
+        brightness_scale.add_mark (lower, Gtk.PositionType.BOTTOM, darker_label);
+        brightness_scale.add_mark (0, Gtk.PositionType.BOTTOM, null);
+        brightness_scale.add_mark (upper, Gtk.PositionType.BOTTOM, lighter_label);
+        brightness_adjustment.value = settings.get_int ("brightness");
+        brightness_adjustment.value_changed.connect (() => { settings.set_int ("brightness", get_brightness 
()); });
+
+        lower = contrast_adjustment.lower;
+        var less_label = "<small>%s</small>".printf (_("Less"));
+        upper = contrast_adjustment.upper;
+        var more_label = "<small>%s</small>".printf (_("More"));
+        contrast_scale.add_mark (lower, Gtk.PositionType.BOTTOM, less_label);
+        contrast_scale.add_mark (0, Gtk.PositionType.BOTTOM, null);
+        contrast_scale.add_mark (upper, Gtk.PositionType.BOTTOM, more_label);
+        contrast_adjustment.value = settings.get_int ("contrast");
+        contrast_adjustment.value_changed.connect (() => { settings.set_int ("contrast", get_contrast ()); 
});
+
+        lower = quality_adjustment.lower;
+        var minimum_label = "<small>%s</small>".printf (_("Minimum"));
+        upper = quality_adjustment.upper;
+        var maximum_label = "<small>%s</small>".printf (_("Maximum"));
+        quality_scale.add_mark (lower, Gtk.PositionType.BOTTOM, minimum_label);
+        quality_scale.add_mark (75, Gtk.PositionType.BOTTOM, null);
+        quality_scale.add_mark (upper, Gtk.PositionType.BOTTOM, maximum_label);
+        quality_adjustment.value = settings.get_int ("jpeg-quality");
+        quality_adjustment.value_changed.connect (() => { settings.set_int ("jpeg-quality", get_quality ()); 
});
+
+        var paper_width = settings.get_int ("paper-width");
+        var paper_height = settings.get_int ("paper-height");
+        set_paper_size (paper_width, paper_height);
+        paper_size_combo.changed.connect (() =>
+        {
+            int w, h;
+            get_paper_size (out w, out h);
+            settings.set_int ("paper-width", w);
+            settings.set_int ("paper-height", h);
+        });
+
+        set_page_delay (settings.get_int ("page-delay"));
+        page_delay_scale.format_value.connect ((value) => { return "%.1fs".printf (value / 1000.0); });
+        page_delay_adjustment.value_changed.connect (() => { settings.set_int ("page-delay", get_page_delay 
()); });
+    }
+
+    public void present_device ()
+    {
+        device_combo.grab_focus ();
+        present ();
+    }
+
+    public void set_scan_devices (List<ScanDevice> devices)
+    {
+        setting_devices = true;
+
+        /* If the user hasn't chosen a scanner choose the best available one */
+        var have_selection = false;
+        if (user_selected_device)
+            have_selection = device_combo.active >= 0;
+
+        /* Add new devices */
+        int index = 0;
+        Gtk.TreeIter iter;
+        foreach (var device in devices)
+        {
+            int n_delete = -1;
+
+            /* Find if already exists */
+            if (device_model.iter_nth_child (out iter, null, index))
+            {
+                int i = 0;
+                do
+                {
+                    string name;
+                    bool matched;
+
+                    device_model.get (iter, 0, out name, -1);
+                    matched = name == device.name;
+
+                    if (matched)
+                    {
+                        n_delete = i;
+                        break;
+                    }
+                    i++;
+                } while (device_model.iter_next (ref iter));
+            }
+
+            /* If exists, remove elements up to this one */
+            if (n_delete >= 0)
+            {
+                int i;
+
+                /* Update label */
+                device_model.set (iter, 1, device.label, -1);
+
+                for (i = 0; i < n_delete; i++)
+                {
+                    device_model.iter_nth_child (out iter, null, index);
+#if VALA_0_36
+                    device_model.remove (ref iter);
+#else
+                    device_model.remove (iter);
+#endif
+                }
+            }
+            else
+            {
+                device_model.insert (out iter, index);
+                device_model.set (iter, 0, device.name, 1, device.label, -1);
+            }
+            index++;
+        }
+
+        /* Remove any remaining devices */
+        while (device_model.iter_nth_child (out iter, null, index))
+#if VALA_0_36
+            device_model.remove (ref iter);
+#else
+            device_model.remove (iter);
+#endif
+
+        /* Select the previously selected device or the first available device */
+        if (!have_selection)
+        {
+            var device = settings.get_string ("selected-device");
+            if (device != null && find_scan_device (device, out iter))
+                device_combo.set_active_iter (iter);
+            else
+                device_combo.set_active (0);
+        }
+
+        setting_devices = false;
+    }
+
+    public int get_device_count ()
+    {
+        return device_model.iter_n_children (null);
+    }
+
+    public string? get_selected_device ()
+    {
+        Gtk.TreeIter iter;
+
+        if (device_combo.get_active_iter (out iter))
+        {
+            string device;
+            device_model.get (iter, 0, out device, -1);
+            return device;
+        }
+
+        return null;
+    }
+
+    public void set_selected_device (string device)
+    {
+        user_selected_device = true;
+
+        Gtk.TreeIter iter;
+        if (!find_scan_device (device, out iter))
+            return;
+
+        device_combo.set_active_iter (iter);
+    }
+
+    private bool find_scan_device (string device, out Gtk.TreeIter iter)
+    {
+        bool have_iter = false;
+
+        if (device_model.get_iter_first (out iter))
+        {
+            do
+            {
+                string d;
+                device_model.get (iter, 0, out d, -1);
+                if (d == device)
+                    have_iter = true;
+            } while (!have_iter && device_model.iter_next (ref iter));
+        }
+
+        return have_iter;
+    }
+
+    private void set_page_side (ScanType page_side)
+    {
+        Gtk.TreeIter iter;
+
+        if (page_side_model.get_iter_first (out iter))
+        {
+            do
+            {
+                int s;
+                page_side_model.get (iter, 0, out s, -1);
+                if (s == page_side)
+                {
+                    page_side_combo.set_active_iter (iter);
+                    return;
+                }
+            } while (page_side_model.iter_next (ref iter));
+         }
+    }
+
+    public void set_paper_size (int width, int height)
+    {
+        Gtk.TreeIter iter;
+        bool have_iter;
+
+        for (have_iter = paper_size_model.get_iter_first (out iter);
+             have_iter;
+             have_iter = paper_size_model.iter_next (ref iter))
+        {
+            int w, h;
+            paper_size_model.get (iter, 0, out w, 1, out h, -1);
+            if (w == width && h == height)
+               break;
+        }
+
+        if (!have_iter)
+            have_iter = paper_size_model.get_iter_first (out iter);
+        if (have_iter)
+            paper_size_combo.set_active_iter (iter);
+    }
+
+    public int get_text_dpi ()
+    {
+        Gtk.TreeIter iter;
+        int dpi = DEFAULT_TEXT_DPI;
+
+        if (text_dpi_combo.get_active_iter (out iter))
+            text_dpi_model.get (iter, 0, out dpi, -1);
+
+        return dpi;
+    }
+
+    public int get_photo_dpi ()
+    {
+        Gtk.TreeIter iter;
+        int dpi = DEFAULT_PHOTO_DPI;
+
+        if (photo_dpi_combo.get_active_iter (out iter))
+            photo_dpi_model.get (iter, 0, out dpi, -1);
+
+        return dpi;
+    }
+
+    public ScanType get_page_side ()
+    {
+        Gtk.TreeIter iter;
+        int page_side = ScanType.ADF_BOTH;
+
+        if (page_side_combo.get_active_iter (out iter))
+            page_side_model.get (iter, 0, out page_side, -1);
+
+        return (ScanType) page_side;
+    }
+
+    public bool get_paper_size (out int width, out int height)
+    {
+        Gtk.TreeIter iter;
+
+        width = height = 0;
+        if (paper_size_combo.get_active_iter (out iter))
+        {
+            paper_size_model.get (iter, 0, ref width, 1, ref height, -1);
+            return true;
+        }
+
+        return false;
+    }
+
+    public int get_brightness ()
+    {
+        return (int) brightness_adjustment.value;
+    }
+
+    public void set_brightness (int brightness)
+    {
+        brightness_adjustment.value = brightness;
+    }
+
+    public int get_contrast ()
+    {
+        return (int) contrast_adjustment.value;
+    }
+
+    public void set_contrast (int contrast)
+    {
+        contrast_adjustment.value = contrast;
+    }
+
+    public int get_quality ()
+    {
+        return (int) quality_adjustment.value;
+    }
+
+    public void set_quality (int quality)
+    {
+        quality_adjustment.value = quality;
+    }
+
+    public int get_page_delay ()
+    {
+        return (int) page_delay_adjustment.value;
+    }
+
+    public void set_page_delay (int page_delay)
+    {
+        page_delay_adjustment.value = page_delay;
+    }
+
+    private void set_dpi_combo (Gtk.ComboBox combo, int default_dpi, int current_dpi)
+    {
+        var renderer = new Gtk.CellRendererText ();
+        combo.pack_start (renderer, true);
+        combo.add_attribute (renderer, "text", 1);
+
+        var model = combo.model as Gtk.ListStore;
+        int[] scan_resolutions = {75, 150, 300, 600, 1200, 2400};
+        foreach (var dpi in scan_resolutions)
+        {
+            string label;
+            if (dpi == default_dpi)
+                /* Preferences dialog: Label for default resolution in resolution list */
+                label = _("%d dpi (default)").printf (dpi);
+            else if (dpi == 75)
+                /* Preferences dialog: Label for minimum resolution in resolution list */
+                label = _("%d dpi (draft)").printf (dpi);
+            else if (dpi == 1200)
+                /* Preferences dialog: Label for maximum resolution in resolution list */
+                label = _("%d dpi (high resolution)").printf (dpi);
+            else
+                /* Preferences dialog: Label for resolution value in resolution list (dpi = dots per inch) */
+                label = _("%d dpi").printf (dpi);
+
+            Gtk.TreeIter iter;
+            model.append (out iter);
+            model.set (iter, 0, dpi, 1, label, -1);
+
+            if (dpi == current_dpi)
+                combo.set_active_iter (iter);
+        }
+    }
+
+    [GtkCallback]
+    private void device_combo_changed_cb (Gtk.Widget widget)
+    {
+        if (setting_devices)
+            return;
+        user_selected_device = true;
+        if (get_selected_device () != null)
+            settings.set_string ("selected-device", get_selected_device ());
+    }
+}
+
+private class ProgressBarDialog : Gtk.Window
+{
+    private Gtk.ProgressBar bar;
+
+    public double fraction
+    {
+        get { return bar.fraction; }
+        set { bar.fraction = value; }
+    }
+
+    public string message
+    {
+        get { return bar.text; }
+        set { bar.text = value; }
+    }
+
+    public ProgressBarDialog (Gtk.ApplicationWindow parent, string title)
+    {
+        bar = new Gtk.ProgressBar ();
+        var hbox = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 5);
+        var vbox = new Gtk.Box (Gtk.Orientation.VERTICAL, 5);
+        hbox.hexpand = true;
+
+        bar.text = "";
+        bar.show_text = true;
+        bar.set_size_request (225, 25);
+        set_size_request (250, 50);
+
+        vbox.pack_start (bar, true, false, 0);
+        hbox.pack_start (vbox, true, false, 0);
+        add (hbox);
+        this.title = title;
+
+        transient_for = parent;
+        set_position (Gtk.WindowPosition.CENTER_ON_PARENT);
+        modal = true;
+        resizable = false;
+
+        hbox.visible = true;
+        vbox.visible = true;
+        bar.visible = true;
+    }
+}
+
+private string? get_temporary_filename (string prefix, string extension)
+{
+    /* NOTE: I'm not sure if this is a 100% safe strategy to use g_file_open_tmp(), close and
+     * use the filename but it appears to work in practice */
+
+    var filename = "%sXXXXXX.%s".printf (prefix, extension);
+    string path;
+    try
+    {
+        var fd = FileUtils.open_tmp (filename, out path);
+        Posix.close (fd);
+    }
+    catch (Error e)
+    {
+        warning ("Error creating temporary file: %s", e.message);
+        return null;
+    }
+
+    return path;
+}
+
+private class PageIcon : Gtk.DrawingArea
+{
+    private string text;
+    private double r;
+    private double g;
+    private double b;
+    private const int MINIMUM_WIDTH = 20;
+
+    public PageIcon (string text, double r = 1.0, double g = 1.0, double b = 1.0)
+    {
+        this.text = text;
+        this.r = r;
+        this.g = g;
+        this.b = b;
+    }
+
+    public override void get_preferred_width (out int minimum_width, out int natural_width)
+    {
+        minimum_width = natural_width = MINIMUM_WIDTH;
+    }
+
+    public override void get_preferred_height (out int minimum_height, out int natural_height)
+    {
+        minimum_height = natural_height = (int) Math.round (MINIMUM_WIDTH * Math.SQRT2);
+    }
+
+    public override void get_preferred_height_for_width (int width, out int minimum_height, out int 
natural_height)
+    {
+        minimum_height = natural_height = (int) (width * Math.SQRT2);
+    }
+
+    public override void get_preferred_width_for_height (int height, out int minimum_width, out int 
natural_width)
+    {
+        minimum_width = natural_width = (int) (height / Math.SQRT2);
+    }
+
+    public override bool draw (Cairo.Context c)
+    {
+        var w = get_allocated_width ();
+        var h = get_allocated_height ();
+        if (w * Math.SQRT2 > h)
+            w = (int) Math.round (h / Math.SQRT2);
+        else
+            h = (int) Math.round (w * Math.SQRT2);
+
+        c.translate ((get_allocated_width () - w) / 2, (get_allocated_height () - h) / 2);
+
+        c.rectangle (0.5, 0.5, w - 1, h - 1);
+
+        c.set_source_rgb (r, g, b);
+        c.fill_preserve ();
+
+        c.set_line_width (1.0);
+        c.set_source_rgb (0.0, 0.0, 0.0);
+        c.stroke ();
+
+        Cairo.TextExtents extents;
+        c.text_extents (text, out extents);
+        c.translate ((w - extents.width) * 0.5 - 0.5, (h + extents.height) * 0.5 - 0.5);
+        c.show_text (text);
+
+        return true;
+    }
+}
diff --git a/src/simple-scan.gresource.xml b/src/simple-scan.gresource.xml
index 93eb564..4100994 100644
--- a/src/simple-scan.gresource.xml
+++ b/src/simple-scan.gresource.xml
@@ -1,8 +1,8 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <gresources>
   <gresource prefix="/org/gnome/SimpleScan">
-    <file preprocess="xml-stripblanks">simple-scan.ui</file>
-    <file preprocess="xml-stripblanks">preferences.ui</file>
+    <file preprocess="xml-stripblanks">app-window.ui</file>
+    <file preprocess="xml-stripblanks">preferences-dialog.ui</file>
     <file preprocess="xml-stripblanks">authorize-dialog.ui</file>
   </gresource>
 </gresources>
diff --git a/src/simple-scan.vala b/src/simple-scan.vala
index a18db11..52258d7 100644
--- a/src/simple-scan.vala
+++ b/src/simple-scan.vala
@@ -32,7 +32,7 @@ public class SimpleScan : Gtk.Application
     private ScanDevice? default_device = null;
     private bool have_devices = false;
     private GUsb.Context usb_context;
-    private UserInterface ui;
+    private AppWindow app;
     private Scanner scanner;
     private Book book;
 
@@ -45,10 +45,10 @@ public class SimpleScan : Gtk.Application
     {
         base.startup ();
 
-        ui = new UserInterface ();
-        book = ui.book;
-        ui.start_scan.connect (scan_cb);
-        ui.stop_scan.connect (cancel_cb);
+        app = new AppWindow ();
+        book = app.book;
+        app.start_scan.connect (scan_cb);
+        app.stop_scan.connect (cancel_cb);
 
         scanner = Scanner.get_instance ();
         scanner.update_devices.connect (update_scan_devices_cb);
@@ -77,15 +77,15 @@ public class SimpleScan : Gtk.Application
             List<ScanDevice> device_list = null;
 
             device_list.append (default_device);
-            ui.set_scan_devices (device_list);
-            ui.selected_device = default_device.name;
+            app.set_scan_devices (device_list);
+            app.selected_device = default_device.name;
         }
     }
 
     public override void activate ()
     {
         base.activate ();
-        ui.start ();
+        app.start ();
         scanner.start ();
     }
 
@@ -93,7 +93,7 @@ public class SimpleScan : Gtk.Application
     {
         base.shutdown ();
         book = null;
-        ui = null;
+        app = null;
         usb_context = null;
         scanner.free ();
     }
@@ -126,7 +126,7 @@ public class SimpleScan : Gtk.Application
         if (!have_devices)
             missing_driver = suggest_driver ();
 
-        ui.set_scan_devices (devices_copy, missing_driver);
+        app.set_scan_devices (devices_copy, missing_driver);
     }
     
     /* Taken from /usr/local/Brother/sane/Brsane.ini from brscan driver */
@@ -211,7 +211,7 @@ public class SimpleScan : Gtk.Application
     private void authorize_cb (Scanner scanner, string resource)
     {
         string username, password;
-        ui.authorize (resource, out username, out password);
+        app.authorize (resource, out username, out password);
         scanner.authorize (username, password);
     }
 
@@ -221,7 +221,7 @@ public class SimpleScan : Gtk.Application
         var page = book.get_page (-1);
         if (page != null && !page.has_data)
         {
-            ui.selected_page = page;
+            app.selected_page = page;
             page.start ();
             return page;
         }
@@ -261,7 +261,7 @@ public class SimpleScan : Gtk.Application
                 page.set_custom_crop (cw, ch);
             page.move_crop (cx, cy);
         }
-        ui.selected_page = page;
+        app.selected_page = page;
         page.start ();
 
         return page;
@@ -384,19 +384,19 @@ public class SimpleScan : Gtk.Application
         remove_empty_page ();
         if (error_code != Sane.Status.CANCELLED)
         {
-            ui.show_error (/* Title of error dialog when scan failed */
-                           _("Failed to scan"),
-                           error_string,
-                           have_devices);
+            app.show_error (/* Title of error dialog when scan failed */
+                            _("Failed to scan"),
+                            error_string,
+                            have_devices);
         }
     }
 
     private void scanner_scanning_changed_cb (Scanner scanner)
     {
-        ui.scanning = scanner.is_scanning ();
+        app.scanning = scanner.is_scanning ();
     }
 
-    private void scan_cb (UserInterface ui, string? device, ScanOptions options)
+    private void scan_cb (AppWindow ui, string? device, ScanOptions options)
     {
         debug ("Requesting scan at %d dpi from device '%s'", options.dpi, device);
 
@@ -406,7 +406,7 @@ public class SimpleScan : Gtk.Application
         scanner.scan (device, options);
     }
 
-    private void cancel_cb (UserInterface ui)
+    private void cancel_cb (AppWindow ui)
     {
         scanner.cancel ();
     }


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]