1'''status.py - Statusbar for main window.''' 2 3from gi.repository import Gdk, Gtk 4 5from mcomix import i18n 6from mcomix import constants 7from mcomix.preferences import prefs 8 9class Statusbar(Gtk.EventBox): 10 11 SPACING = 5 12 13 def __init__(self): 14 super(Statusbar, self).__init__() 15 16 self._loading = True 17 18 # Status text, page number, file number, resolution, path, filename, filesize 19 self.status = Gtk.Statusbar() 20 self.add(self.status) 21 22 # Create popup menu for enabling/disabling status boxes. 23 self.ui_manager = Gtk.UIManager() 24 self.tooltipstatus = TooltipStatusHelper(self.ui_manager, self.status) 25 ui_description = ''' 26 <ui> 27 <popup name="Statusbar"> 28 <menuitem action="pagenumber" /> 29 <menuitem action="filenumber" /> 30 <menuitem action="resolution" /> 31 <menuitem action="rootpath" /> 32 <menuitem action="filename" /> 33 <menuitem action="filesize" /> 34 </popup> 35 </ui> 36 ''' 37 self.ui_manager.add_ui_from_string(ui_description) 38 39 actiongroup = Gtk.ActionGroup(name='mcomix-statusbar') 40 actiongroup.add_toggle_actions([ 41 ('pagenumber', None, _('Show page numbers'), None, None, 42 self.toggle_status_visibility), 43 ('filenumber', None, _('Show file numbers'), None, None, 44 self.toggle_status_visibility), 45 ('resolution', None, _('Show resolution'), None, None, 46 self.toggle_status_visibility), 47 ('rootpath', None, _('Show path'), None, None, 48 self.toggle_status_visibility), 49 ('filename', None, _('Show filename'), None, None, 50 self.toggle_status_visibility), 51 ('filesize', None, _('Show filesize'), None, None, 52 self.toggle_status_visibility)]) 53 self.ui_manager.insert_action_group(actiongroup, 0) 54 55 # Hook mouse release event 56 self.connect('button-release-event', self._button_released) 57 self.set_events(Gdk.EventMask.BUTTON_PRESS_MASK|Gdk.EventMask.BUTTON_RELEASE_MASK) 58 59 # Default status information 60 self._page_info = '' 61 self._file_info = '' 62 self._resolution = '' 63 self._root = '' 64 self._filename = '' 65 self._filesize = '' 66 self._update_sensitivity() 67 self.show_all() 68 69 self._loading = False 70 71 def set_message(self, message): 72 '''Set a specific message (such as an error message) on the statusbar, 73 replacing whatever was there earlier. 74 ''' 75 self.status.pop(0) 76 self.status.push(0, ' ' * Statusbar.SPACING + message) 77 78 def set_page_number(self, page, total, this_screen): 79 '''Update the page number.''' 80 p = ','.join(str(page+i) for i in range(this_screen)) 81 self._page_info = '{} / {}'.format(p,total) 82 83 def get_page_number(self): 84 '''Returns the bar's page information.''' 85 return self._page_info 86 87 def set_file_number(self, fileno, total): 88 '''Updates the file number (i.e. number of current file/total 89 files loaded).''' 90 if total > 0: 91 self._file_info = '(%d / %d)' % (fileno, total) 92 else: 93 self._file_info = '' 94 95 def get_file_number(self): 96 ''' Returns the bar's file information.''' 97 return self._file_info 98 99 def set_resolution(self, dimensions): # 2D only 100 '''Update the resolution data. 101 102 Takes an iterable of tuples, (x, y, scale), describing the original 103 resolution of an image as well as the currently displayed scale. 104 ''' 105 self._resolution = ', '.join('{}x{} ({:.1%})'.format(*d) for d in dimensions) 106 107 def set_root(self, root): 108 '''Set the name of the root (directory or archive).''' 109 self._root = i18n.to_unicode(root) 110 111 def set_filename(self, filename): 112 '''Update the filename.''' 113 self._filename = i18n.to_unicode(filename) 114 115 def set_filesize(self, size): 116 '''Update the filesize.''' 117 if size is None: 118 size = '' 119 self._filesize = size 120 121 def update(self): 122 '''Set the statusbar to display the current state.''' 123 124 s = '{0:^{1}}'.format('|',Statusbar.SPACING*2+1) 125 text = s.join(self._get_status_text()) 126 self.status.pop(0) 127 self.status.push(0, '{1:>{2}}{0}'.format(text,'',Statusbar.SPACING)) 128 129 def push(self, context_id, message): 130 ''' Compatibility with Gtk.Statusbar. ''' 131 assert context_id >= 0 132 self.status.push(context_id + 1, message) 133 134 def pop(self, context_id): 135 ''' Compatibility with Gtk.Statusbar. ''' 136 assert context_id >= 0 137 self.status.pop(context_id + 1) 138 139 def _get_status_text(self): 140 ''' Returns an array of text fields that should be displayed. ''' 141 fields = [ 142 (constants.STATUS_PAGE, self._page_info ), 143 (constants.STATUS_FILENUMBER, self._file_info ), 144 (constants.STATUS_RESOLUTION, self._resolution), 145 (constants.STATUS_PATH, self._root ), 146 (constants.STATUS_FILENAME, self._filename ), 147 (constants.STATUS_FILESIZE, self._filesize ), 148 ] 149 p = prefs['statusbar fields'] 150 151 return [s for c,s in filter(lambda f:f[0]&p,fields)] 152 153 def toggle_status_visibility(self, action, *args): 154 ''' Called when status entries visibility is to be changed. ''' 155 156 # Ignore events as long as control is still loading. 157 if self._loading: 158 return 159 160 names = { 161 'pagenumber': constants.STATUS_PAGE, 162 'resolution': constants.STATUS_RESOLUTION, 163 'rootpath': constants.STATUS_PATH, 164 'filename': constants.STATUS_FILENAME, 165 'filenumber': constants.STATUS_FILENUMBER, 166 'filesize': constants.STATUS_FILESIZE, 167 } 168 169 bit = names[action.get_name()] 170 171 if action.get_active(): 172 prefs['statusbar fields'] |= bit 173 else: 174 prefs['statusbar fields'] &= ~bit 175 176 self.update() 177 self._update_sensitivity() 178 179 def _button_released(self, widget, event, *args): 180 ''' Triggered when a mouse button is released to open the context 181 menu. ''' 182 if event.button == 3: 183 self.ui_manager.get_widget('/Statusbar').popup(None, None, None, None, 184 event.button, event.time) 185 186 def _update_sensitivity(self): 187 ''' Updates the action menu's sensitivity based on user preferences. ''' 188 189 p = prefs['statusbar fields'] 190 names = { 191 'pagenumber': p & constants.STATUS_PAGE, 192 'filenumber': p & constants.STATUS_FILENUMBER, 193 'resolution': p & constants.STATUS_RESOLUTION, 194 'rootpath': p & constants.STATUS_PATH, 195 'filename': p & constants.STATUS_FILENAME, 196 'filesize': p & constants.STATUS_FILESIZE, 197 } 198 199 for n,v in names.items(): 200 action = self.ui_manager.get_action('/Statusbar/' + n) 201 action.set_active(v) 202 203 204class TooltipStatusHelper(object): 205 ''' Attaches to a L{Gtk.UIManager} to provide statusbar tooltips when 206 selecting menu items. ''' 207 208 def __init__(self, uimanager, statusbar): 209 self._statusbar = statusbar 210 211 uimanager.connect('connect-proxy', self._on_connect_proxy) 212 uimanager.connect('disconnect-proxy', self._on_disconnect_proxy) 213 214 def _on_connect_proxy(self, uimgr, action, widget): 215 ''' Connects the widget's selection handlers to the status bar update. 216 ''' 217 tooltip = action.get_property('tooltip') 218 if isinstance(widget, Gtk.MenuItem) and tooltip: 219 cid = widget.connect('select', self._on_item_select, tooltip) 220 cid2 = widget.connect('deselect', self._on_item_deselect) 221 setattr(widget, 'app::connect-ids', (cid, cid2)) 222 223 def _on_disconnect_proxy(self, uimgr, action, widget): 224 ''' Disconnects the widget's selection handlers. ''' 225 cids = getattr(widget, 'app::connect-ids', ()) 226 for cid in cids: 227 widget.disconnect(cid) 228 229 def _on_item_select(self, menuitem, tooltip): 230 self._statusbar.push(0, ' ' * Statusbar.SPACING + tooltip) 231 232 def _on_item_deselect(self, menuitem): 233 self._statusbar.pop(0) 234 235# vim: expandtab:sw=4:ts=4 236