1'''pageselect.py - The dialog window for the page selector.'''
2
3from gi.repository import Gtk
4
5from mcomix.preferences import prefs
6from mcomix.lib import mt
7from mcomix import callback
8
9
10class Pageselector(Gtk.Dialog):
11
12    '''The Pageselector takes care of the popup page selector
13    '''
14
15    def __init__(self, window):
16        self._window = window
17        super(Pageselector, self).__init__(title=_('Go to page...'),
18                                           modal=True,
19                                           destroy_with_parent=True)
20        self.set_transient_for(window)
21        self.add_buttons(_('_Go'), Gtk.ResponseType.OK,
22                         _('_Cancel'), Gtk.ResponseType.CANCEL,)
23        self.set_default_response(Gtk.ResponseType.OK)
24        self.connect('response', self._response)
25        self.set_resizable(True)
26
27        self._number_of_pages = self._window.imagehandler.get_number_of_pages()
28
29        self._selector_adjustment = Gtk.Adjustment(
30            value=self._window.imagehandler.get_current_page(),
31            lower=1, upper=self._number_of_pages,
32            step_increment=1, page_increment=1)
33
34        self._page_selector = Gtk.VScale.new(self._selector_adjustment)
35        self._page_selector.set_draw_value(False)
36        self._page_selector.set_digits(0)
37
38        self._page_spinner = Gtk.SpinButton.new(self._selector_adjustment, 0.0, 0)
39        self._page_spinner.connect('changed', self._page_text_changed)
40        self._page_spinner.set_activates_default(True)
41        self._page_spinner.set_numeric(True)
42        self._pages_label = Gtk.Label(label=_(' of %s') % self._number_of_pages)
43        self._pages_label.set_alignment(0, 0.5)
44
45        self._image_preview = Gtk.Image()
46        self._image_preview.set_size_request(
47            prefs['thumbnail size'], prefs['thumbnail size'])
48
49        self.connect('configure-event', self._size_changed_cb)
50        self.set_size_request(prefs['pageselector width'],
51                prefs['pageselector height'])
52
53        # Group preview image and page selector next to each other
54        preview_box = Gtk.HBox()
55        preview_box.set_border_width(5)
56        preview_box.set_spacing(5)
57        preview_box.pack_start(self._image_preview, True, True, 0)
58        preview_box.pack_end(self._page_selector, False, True, 0)
59        # Below them, group selection spinner and current page label
60        selection_box = Gtk.HBox()
61        selection_box.set_border_width(5)
62        selection_box.pack_start(self._page_spinner, True, True, 0)
63        selection_box.pack_end(self._pages_label, False, True, 0)
64
65        self.get_content_area().pack_start(preview_box, True, True, 0)
66        self.get_content_area().pack_end(selection_box, False, True, 0)
67        self.show_all()
68
69        self._selector_adjustment.connect('value-changed', self._cb_value_changed)
70
71        # Set focus on the input box.
72        self._page_spinner.select_region(0, -1)
73        self._page_spinner.grab_focus()
74
75        # Currently displayed thumbnail page.
76        self._thumbnail_page = 0
77        self._thread = mt.ThreadPool(name=self.__class__.__name__)
78        self._update_thumbnail(int(self._selector_adjustment.props.value))
79        self._window.imagehandler.page_available += self._page_available
80
81    def _cb_value_changed(self, *args):
82        ''' Called whenever the spinbox value changes. Updates the preview thumbnail. '''
83        page = int(self._selector_adjustment.props.value)
84        if page != self._thumbnail_page:
85            self._update_thumbnail(page)
86
87    def _size_changed_cb(self, *args):
88        # Window cannot be scaled down unless the size request is reset
89        self.set_size_request(-1, -1)
90        # Store dialog size
91        prefs['pageselector width'] = self.get_allocation().width
92        prefs['pageselector height'] = self.get_allocation().height
93
94        self._update_thumbnail(int(self._selector_adjustment.props.value))
95
96    def _page_text_changed(self, control, *args):
97        ''' Called when the page selector has been changed. Used to instantly update
98            the preview thumbnail when entering page numbers by hand. '''
99        if control.get_text().isdigit():
100            page = int(control.get_text())
101            if page > 0 and page <= self._number_of_pages:
102                control.set_value(page)
103
104    def _response(self, widget, event, *args):
105        if event == Gtk.ResponseType.OK:
106            self._window.set_page(int(self._selector_adjustment.props.value))
107
108        self._window.imagehandler.page_available -= self._page_available
109        self._thread.renew()
110        self.destroy()
111
112    def _update_thumbnail(self, page):
113        ''' Trigger a thumbnail update. '''
114        width = self._image_preview.get_allocation().width
115        height = self._image_preview.get_allocation().height
116        self._thumbnail_page = page
117        self._thread.apply_async(
118            self._generate_thumbnail, args=(page, width, height),
119            callback=self._generate_thumbnail_cb)
120
121    def _generate_thumbnail(self, page, width, height):
122        ''' Generate the preview thumbnail for the page selector.
123        A transparent image will be used if the page is not yet available. '''
124        return page, self._window.imagehandler.get_thumbnail(
125            page, width=width, height=height, nowait=True)
126
127    def _generate_thumbnail_cb(self, params):
128        page, pixbuf = params
129        return self._thumbnail_finished(page, pixbuf)
130
131    @callback.Callback
132    def _thumbnail_finished(self, page, pixbuf):
133        # Don't bother if we changed page in the meantime.
134        if page == self._thumbnail_page:
135            self._image_preview.set_from_pixbuf(pixbuf)
136
137    def _page_available(self, page):
138        if page == int(self._selector_adjustment.props.value):
139            self._update_thumbnail(page)
140
141# vim: expandtab:sw=4:ts=4
142