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