class PhotoViewer(QScrollArea): """ Widget for viewing images by incorporating basic navigation options. """ def __init__(self, parent=None, photo_path=""): QScrollArea.__init__(self, parent) self.setBackgroundRole(QPalette.Dark) self._printer = QPrinter() self._lbl_photo = QLabel() self._lbl_photo.setBackgroundRole(QPalette.Base) self._lbl_photo.setSizePolicy(QSizePolicy.Ignored,QSizePolicy.Ignored) self._lbl_photo.setScaledContents(True) self.setWidget(self._lbl_photo) self._photo_path = photo_path self._ph_image = None self._scale_factor = 1.0 self._aspect_ratio = -1 self._create_actions() if self._photo_path: self.load_document(self._photo_path) def _create_actions(self): """ Create actions for basic image navigation. """ self._zoom_in_act = QAction( QApplication.translate("PhotoViewer","Zoom &In (25%)"), self) self._zoom_in_act.setShortcut( QApplication.translate("PhotoViewer","Ctrl++")) self._zoom_in_act.setEnabled(False) self._zoom_in_act.triggered.connect(self.zoom_in) self._zoom_out_act = QAction( QApplication.translate("PhotoViewer","Zoom &Out (25%)"), self) self._zoom_out_act.setShortcut( QApplication.translate("PhotoViewer","Ctrl+-")) self._zoom_out_act.setEnabled(False) self._zoom_out_act.triggered.connect(self.zoom_out) self._normal_size_act = QAction( QApplication.translate("PhotoViewer","&Normal Size"), self) self._normal_size_act.setShortcut( QApplication.translate("PhotoViewer","Ctrl+S")) self._normal_size_act.setEnabled(False) self._normal_size_act.triggered.connect(self.normal_size) self._fit_to_window_act = QAction( QApplication.translate("PhotoViewer","&Fit to Window"), self) self._fit_to_window_act.setShortcut( QApplication.translate("PhotoViewer","Ctrl+F")) self._fit_to_window_act.setEnabled(False) self._fit_to_window_act.setCheckable(True) self._fit_to_window_act.triggered.connect(self.fit_to_window) self._print_act = QAction( QApplication.translate("PhotoViewer","&Print"), self) self._print_act .setShortcut( QApplication.translate("PhotoViewer","Ctrl+P")) self._print_act .setEnabled(False) self._print_act .triggered.connect(self.print_photo) def zoom_in(self): self.scale_photo(1.25) def zoom_out(self): self.scale_photo(0.8) def normal_size(self): self._lbl_photo.adjustSize() self._scale_factor = 1.0 def fit_to_window(self): fit_to_win = self._fit_to_window_act.isChecked() self.setWidgetResizable(fit_to_win) if not fit_to_win: self.normal_size() self.update_actions() def print_photo(self): print_dialog = QPrintDialog(self._printer,self) if print_dialog.exec_() == QDialog.Accepted: painter = QPainter(self._printer) rect = painter.viewport() size = self._lbl_photo.pixmap().size() size.scale(rect.size(), Qt.KeepAspectRatio) painter.setViewport(rect.x(), rect.y(), size.width(), size.height()) painter.setWindow(self._lbl_photo.pixmap().rect()) painter.drawPixmap(0, 0, self._lbl_photo.pixmap()) def wheelEvent(self, event): """ Zoom the image based on the mouse wheel rotation action. :param event: Event containing the wheel rotation info. :type event: QWheelEvent """ degrees = event.delta() / 8 num_steps = degrees / 15 if num_steps < 0: abs_num_steps = abs(num_steps) zoom_factor = 1 + (abs_num_steps * 0.25) else: zoom_factor = 1 - (num_steps * 0.2) self.scale_photo(zoom_factor) def heightForWidth(self, width): if self._aspect_ratio != -1: return width / self._aspect_ratio else: return -1 def resizeEvent(self, event): """ Event for resizing the widget based on the pixmap's aspect ratio. :param event: Contains event parameters for the resize event. :type event: QResizeEvent """ super(PhotoViewer, self).resizeEvent(event) def update_actions(self): self._zoom_out_act.setEnabled(not self._fit_to_window_act.isChecked()) self._zoom_in_act.setEnabled(not self._fit_to_window_act.isChecked()) self._normal_size_act.setEnabled(not self._fit_to_window_act.isChecked()) def scale_photo(self,factor): """ :param factor: Value by which the image will be increased/decreased in the view. :type factor: float """ if not self._lbl_photo.pixmap().isNull(): self._scale_factor *= factor self._lbl_photo.resize(self._scale_factor * self._lbl_photo.pixmap().size()) self._adjust_scroll_bar(self.horizontalScrollBar(), factor) self._adjust_scroll_bar(self.verticalScrollBar(), factor) self._zoom_in_act.setEnabled(self._scale_factor < 3.0) self._zoom_out_act.setEnabled(self._scale_factor > 0.333) def _adjust_scroll_bar(self, scroll_bar, factor): scroll_bar.setValue(int(factor * scroll_bar.value() + ((factor - 1) * scroll_bar.pageStep()/2))) def load_document(self, photo_path): if photo_path: self._ph_image = QImage(photo_path) if self._ph_image.isNull(): return False self._photo_path = photo_path ph_pixmap = QPixmap.fromImage(self._ph_image) self._lbl_photo.setPixmap(ph_pixmap) self._scale_factor = 1.0 self._aspect_ratio = ph_pixmap.width() / ph_pixmap.height() self._fit_to_window_act.setEnabled(True) self._print_act.setEnabled(True) self._fit_to_window_act.trigger() self.update_actions() return ph_pixmap return True def photo_location(self): """ :returns: Absolute path of the photo in the central document repository. """ return self._photo_path def set_actions(self,menu): """ Add custom actions to the sub-window menu """ menu.addSeparator() menu.addAction(self._zoom_in_act) menu.addAction(self._zoom_out_act) menu.addAction(self._normal_size_act) menu.addAction(self._fit_to_window_act) menu.addSeparator() menu.addAction(self._print_act)
class pngDisplay(QWidget): def __init__(self, parent=None): super(pngDisplay, self).__init__(parent) #self.profiler = cProfile.Profile() # create the label that displays the image - cribbing from the Image # Viewer example in the Qt docs. self.imLabel = QLabel() self.imLabel.setBackgroundRole(QPalette.Base) self.imLabel.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored) self.imLabel.setScaledContents(True) # Create a gray field to use when no png is available self.defaultPM = QPixmap(700,900) self.defaultPM.fill(QColor("gray")) # Create a scroll area within which to display our imLabel, this # enables the creation of horizontal and vertical scroll bars, when # the imLabel exceeds the size of the scroll area. self.scarea = QScrollArea() # The following two lines make sure that page up/dn gets through # the scrollarea widget and up to us. self.setFocusPolicy(Qt.ClickFocus) self.scarea.setFocusProxy(self) self.scarea.setBackgroundRole(QPalette.Dark) #self.scarea.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOn) #self.scarea.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn) self.scarea.setWidget(self.imLabel) # create the text label that will have the page number in it self.txLabel = QLabel(u"No image") self.txLabel.setAlignment(Qt.AlignBottom | Qt.AlignHCenter) self.txLabel.setFrameStyle(QFrame.Sunken | QFrame.StyledPanel) # Create a spinbox to set the zoom from 15 to 200 with a label: # (originally a slider, hence the name) self.minZoom = 0.15 self.maxZoom = 2.00 self.zlider = QSpinBox() self.zlider.setRange(int(100*self.minZoom),int(100*self.maxZoom)) # connect the value change signal to a slot to handle it self.connect(self.zlider, SIGNAL("valueChanged(int)"), self.newZoomFactor) # create the to-width and to-height zoom buttons zoomWidthButton = QPushButton(u'to Width') self.connect(zoomWidthButton, SIGNAL("clicked()"), self.zoomToWidth) zoomHeightButton = QPushButton(u'to Height') self.connect(zoomHeightButton, SIGNAL("clicked()"), self.zoomToHeight) # Make an hbox to contain the spinbox and two pushbuttons, with # stretch on left and right to center the group. zlabel = QLabel( u'&Zoom ' + str(self.zlider.minimum()) + '-' + str(self.zlider.maximum()) + '%') zlabel.setBuddy(self.zlider) zhbox = QHBoxLayout() zhbox.addStretch(1) zhbox.addWidget(zlabel,0,Qt.AlignLeft) zhbox.addWidget(self.zlider,0) zhbox.addStretch(1) zhbox.addWidget(zoomWidthButton) zhbox.addWidget(zoomHeightButton) zhbox.addStretch(1) # With all the pieces in hand, create our layout basically a # vertical stack: scroll area, label, slider box. vbox = QVBoxLayout() # the image gets a high stretch and default alignment, the text # label hugs the bottom and doesn't stretch at all. vbox.addWidget(self.txLabel,0,Qt.AlignBottom) vbox.addWidget(self.scarea,10) vbox.addLayout(zhbox,0) self.setLayout(vbox) # Initialize assuming no book is open. self.ready = False # nothing to display # Recover the last-set zoom factor from the settings object, default 1.0 qv = IMC.settings.value("pngs/zoomFactor",QVariant(1.0)) self.zoomFactor = qv.toFloat()[0] # The following causes entry into newZoomFactor, below, which tests # self.ready, hence the latter has to be assigned-to first. self.zlider.setValue(int(self.zoomFactor*100)) self.clear() # local subroutine to initialize our contents for an empty edit. # called from _init_ and from newPosition when we discover the file # has been cleared on us. Don't reset the zoomFactor, leave it as # the user last set it. def clear(self): # Clear the page name, used by pqNotes IMC.currentImageNumber = None # will be name of last png file e.g. "002" # Clear the page filename, used in our caption label self.lastPage = QString() # last file name e.g. "002.png" # Clear the path to the pngs folder, used to fetch image files self.pngPath = QString() # Clear the index of the last-shown page in the page table # -1 means no page is being displayed. self.lastIndex = -1 # Clear the index of the next page to display, normally same as last self.nextIndex = -1 # Set not-ready to indicate no pngs directory available. self.ready = False # Clear out & release storage of our QImage and QPixmaps self.pixmap = QPixmap() # null pixmap self.image = QImage() self.noImage() # show gray image # Display a blank gray frame and "No Image" below. # Called from clear() above and from showPage when no valid image. def noImage(self) : self.imLabel.setPixmap(self.defaultPM) self.txLabel.setText(u"No image") self.lastIndex = -1 # didn't see a prior page self.nextIndex = -1 # This slot gets the main window's signal shuttingDown. # We save our current zoom factor into IMC.settings. def shuttingDown(self): IMC.settings.setValue("pngs/zoomFactor",QVariant(self.zoomFactor)) # This slot gets pqMain's signal docHasChanged(QString), telling # us that a different document has been loaded. This could be for # a successful File>Open, or a failed File>Open or File>New. # The bookPath is a null QString for File>New, or the full bookPath. # If the latter, we convert that into the path to the pngs folder, # and see if bookPath/pngs is a directory. If so, we set self.ready # to true, indicating it is worthwhile to try opening image files. # At this point the gray image is displayed and previously would remain displayed # until the user moved the cursor in some way, generating cursorPositionChanged. # That's a minor annoyance, to avoid it we will fake that signal now. def newFile(self, bookPath): if not bookPath.isNull(): # this was successful File>Open finf = QFileInfo(bookPath) self.pngPath = finf.absolutePath().append(u"/pngs/") finf = QFileInfo(self.pngPath) if finf.exists() and finf.isDir(): # looking good self.ready = True self.newPosition() else: # We could inform the user we couldn't find a pngs folder, # but you know -- the user is probably already aware of that. self.clear() # just put up the gray default image else: # It was a File>New self.clear() # This function is the slot that is connected to the editor's # cursorPositionChanged signal. Its input is cursor position and # the page table. Its output is to set self.nextIndex to the # desired next image table row, and to call showPage. def newPosition(self): if self.ready : # We have a book and some pngs. Find the position of the higher end # of the current selection. pos = IMC.editWidget.textCursor().selectionEnd() # Get the page table index that matches this position, or -1 # if that is above the first psep, or there is no page data self.nextIndex = IMC.pageTable.getIndex(pos) else :# No file loaded or no pngs folder found. self.nextIndex = -1 if self.nextIndex != self.lastIndex : self.showPage() # Display the page indexed by self.nextIndex. This is called when the cursor # moves to a new page (newPosition, above), or when the PageUp/Dn keys are used, # (keyPressEvent, below) or when the zoom factor changes in any of several ways. def showPage(self): # If self.lastIndex is different from self.nextIndex, the page has # changed, and we need to load a new image. if self.lastIndex != self.nextIndex : self.lastIndex = self.nextIndex # don't come here again until it changes. if self.lastIndex > -1 : # Form the image filename as a Qstring, e.g. "025" and save that for # use by pqNotes: IMC.currentImageNumber = IMC.pageTable.getScan(self.lastIndex) # dbg = unicode(IMC.currentImageNumber) # Form the complete filename by appending ".png" and save as # self.lastPage for use in forming our caption label. self.lastPage = QString(IMC.currentImageNumber).append(QString(u".png")) # dbg = unicode(self.lastPage) # Form the full path to the image. Try to load it as a QImage. pngName = QString(self.pngPath).append(self.lastPage) self.image = QImage(pngName,'PNG') # dbg = unicode(self.image) # dbg = self.image.isNull() # If that successfully loaded an image, make sure it is one byte/pixel. if not self.image.isNull() \ and self.image.format() != QImage.Format_Indexed8 : # It might be Format_Mono (1 bit/pixel) or even Format_RGB32. self.image = self.image.convertToFormat(QImage.Format_Indexed8,Qt.ColorOnly) # Convert the image to a pixmap. If it's null, so is the pixmap. self.pixmap = QPixmap.fromImage(self.image,Qt.ColorOnly) else : IMC.currentImageNumber = QString(u"n.a.") self.lastPage = QString() self.image = QImage() self.pixmap = QPixmap() if not self.pixmap.isNull(): # We successfully found and loaded an image and converted it to pixmap. # Load it in our label for display, set the zoom factor, and the caption. # We do this every time through (even if lastIndex equalled nextIndex) # because the zoomfactor might have changed. self.imLabel.setPixmap(self.pixmap) self.imLabel.resize( self.zoomFactor * self.pixmap.size() ) folio = IMC.pageTable.getDisplay(self.lastIndex) self.txLabel.setText(u"image {0} (folio {1})".format(self.lastPage,folio)) else: # no file was loaded. It's ok if pages are missing self.noImage() # display the gray image. # Catch the signal from the Zoom spinbox with a new value. # Store the new value as a float, and if we have a page, repaint it. def newZoomFactor(self,new_value): self.zoomFactor = new_value / 100 if self.ready : self.showPage() # Catch the click on zoom-to-width and zoom-to height. The job is basically # the same for both. 1: Using the QImage that should be in self.image, # scan the pixels to find the width (height) of the nonwhite area. # 2. Get the ratio of that to our image label's viewport width (height). # 4. Set that ratio as the zoom factor and redraw the image. And finally # 5. Set the scroll position(s) of our scroll area to left-justify the text. # # We get access to the pixels using QImage:bits() which gives us a PyQt4 # "voidptr" that we can index to get byte values. # def zoomToWidth(self): if (not self.ready) or (self.image.isNull()) : return # nothing to do here #self.profiler.enable() #dbg # Query the Color look-up table and build a list of the Green values # corresponding to each possible pixel value. Probably there are just # two colors so colortab is [0,255] but there could be more, depending # on how the PNG was defined, 16 or 32 or even 255 grayscale. colortab = [ int((self.image.color(c) >> 4) & 255) for c in range(self.image.colorCount()) ] ncols = self.image.width() # number of logical pixels across stride = (ncols + 3) & (-4) # number of bytes per scanline nrows = self.image.height() # number of pixels high vptr = self.image.bits() # uchar * bunch-o-pixel-bytes vptr.setsize(stride * nrows) # make the pointer indexable # Scan in from left and right to find the outermost dark spots. # Looking for single pixels yeilds too many false positives, so we # look for three adjacent pixels that sum to less than 32. # Most pages start with many lines of white pixels so in hopes of # establishing the outer edge early, we start at the middle, go to # the end, then do the top half. left_side = int(ncols/2) # leftmost dark spot seen so far # scan from the middle down for r in xrange(int(nrows/2)*stride, (nrows-1)*stride, stride) : pa, pb = 255, 255 # virtual white outside border for c in xrange(left_side): pc = colortab[ ord(vptr[c + r]) ] if (pa + pb + pc) < 32 : # black or dark gray pair left_side = c # new, further-left, left margin break # no need to look further on this line pa = pb pb = pc # scan from the top to the middle, hopefully left_side is small now for r in xrange(0, int(nrows/2)*stride, stride) : pa, pb = 255, 255 # virtual white outside border for c in xrange(left_side): pc = colortab[ ord(vptr[c + r]) ] if (pa + pb + pc) < 32 : # black or dark gray pair left_side = c # new, further-left, left margin break # no need to look further on this line pa = pb pb = pc # Now do the same for the right margin. right_side = int(ncols/2) # rightmost dark spot seen so far for r in xrange(int(nrows/2)*stride, (nrows-1)*stride, stride) : pa, pb = 255, 255 # virtual white outside border for c in xrange(ncols-1,right_side,-1) : pc = colortab[ ord(vptr[c + r]) ] if (pa + pb + pc) < 32 : # black or dark gray pair right_side = c # new, further-right, right margin break pa = pb pb = pc for r in xrange(0, int(nrows/2)*stride, stride) : pa, pb = 255, 255 # virtual white outside border for c in xrange(ncols-1,right_side,-1) : pc = colortab[ ord(vptr[c + r]) ] if (pa + pb + pc) < 32 : # black or dark gray pair right_side = c # new, further-right, right margin break pa = pb pb = pc # The area with color runs from left_side to right_side. How does # that compare to the size of our viewport? Scale to that and redraw. #print('ls {0} rs {1} vp {2}'.format(left_side,right_side,self.scarea.viewport().width())) text_size = right_side - left_side + 2 port_width = self.scarea.viewport().width() self.zoomFactor = max( self.minZoom, min( self.maxZoom, port_width / text_size ) ) # the next line signals newZoomFactor, which calls showPage. self.zlider.setValue(int(100*self.zoomFactor)) # Set the scrollbar to show the page from its left margin. self.scarea.horizontalScrollBar().setValue(int( left_side * self.zoomFactor) ) #self.profiler.disable() #dbg #pstats.Stats(self.profiler).print_stats() # dbg def zoomToHeight(self): if (not self.ready) or (self.image.isNull()) : return # nothing to do here # Query the Color look-up table and build a list of the Green values # corresponding to each possible pixel value. Probably there are just # two colors so colortab is [0,255] but there could be more, depending # on how the PNG was defined, 16 or 32 or even 255 grayscale. colortab = [ int((self.image.color(c) >> 4) & 255) for c in range(self.image.colorCount()) ] ncols = self.image.width() # number of logical pixels across stride = (ncols + 3) & (-4) # number of bytes per scanline nrows = self.image.height() # number of pixels high vptr = self.image.bits() # uchar * bunch-o-pixel-bytes vptr.setsize(stride * nrows) # make the pointer indexable # Scan in from top and bottom to find the outermost rows with # significant pixels. top_side = -1 # The uppermost row with a significant spot of black offset = 0 # vptr index to the first/next pixel row for r in range(nrows) : pa, pb = 255, 255 # virtual white outside border for c in range(ncols) : pc = colortab[ ord(vptr[offset + c]) ] if (pa + pb + pc) < 32 : # black or dark gray triplet top_side = r # that's the row, break # ..so stop scanning pa, pb = pb, pc if top_side >= 0 : # we hit break # ..so don't scan down any further offset += stride # continue to next row # top_side indexes the first row with a significant blot if top_side == -1 : # never found one: an all-white page. bug out. return bottom_side = nrows # The lowest row with a significant blot offset = stride * nrows # vptr index to last/next row of pixels for r in range(nrows,top_side,-1) : offset -= stride pa, pb = 255, 255 # virtual white outside border for c in range(ncols) : pc = colortab[ ord(vptr[offset + c]) ] if (pa + pb + pc) < 32 : # black or dark gray triplet bottom_side = r break pa, pb = pb, pc if bottom_side < nrows : # we hit break # bottom_side is the lowest row with significant pixels. It must be # < nrows, there is at least one row (top_side) with a dot in it. # However if the page is mostly white, don't zoom to that extent. if bottom_side < (top_side+100) : return # seems to be a mostly-white page, give up # The text area runs from scanline top_side to bottom_side. text_height = bottom_side - top_side + 1 port_height = self.scarea.viewport().height() self.zoomFactor = max( self.minZoom, min( self.maxZoom, port_height / text_height ) ) self.zlider.setValue(int(100*self.zoomFactor)) # signals newZoomFactor->showPage # Set the scrollbar to show the page from its top margin. self.scarea.verticalScrollBar().setValue(int( top_side * self.zoomFactor) ) # Re-implement the parent's keyPressEvent in order to provide zoom: # ctrl-plus increases the image size by 1.25 # ctrl-minus decreases the image size by 0.8 # Also trap pageup/dn and use to walk through images. # At this point we do not reposition the editor to match the page viewed. # we page up/dn but as soon as focus returns to the editor and the cursor # moves, this display will snap back to the edited page. As a user that # seems best, come over to Pngs and page ahead to see what's coming, then # back to the editor to read or type. def keyPressEvent(self, event): # assume we will not handle this key and clear its accepted flag event.ignore() # If we are initialized and have displayed some page, look at the key if self.ready: kkey = int( int(event.modifiers()) & IMC.keypadDeModifier) | int(event.key()) if kkey in IMC.zoomKeys : # ctl/cmd + or -, do the zoom event.accept() fac = (0.8) if (kkey == IMC.ctl_minus) else (1.25) fac *= self.zoomFactor # target zoom factor if (fac >= self.minZoom) and (fac <= self.maxZoom): # keep in bounds self.zoomFactor = fac self.zlider.setValue(int(100*fac)) self.showPage() elif (event.key() == Qt.Key_PageUp) or (event.key() == Qt.Key_PageDown) : event.accept() # real pgUp or pgDn, we do it fac = 1 if (event.key() == Qt.Key_PageDown) else -1 fac += self.lastIndex if (fac >= 0) and (fac < IMC.pageTable.size()) : # not off either end of the book, so, self.nextIndex = fac self.showPage() if not event.isAccepted() : # we don't do those, pass them on super(pngDisplay, self).keyPressEvent(event)
def create_locks_tab(self): self.specify_by_currency = QComboBox() def on_change_currency(currency): if currency != self.Locks_currency: self.Locks_currency = LOCKS_CURRENCIES[currency] self.specify_by_currency.clear() otheri = 0 if self.specify_by_currency.findText('BTC') > 0 else 1 self.specify_by_currency.removeItem(otheri) self.specify_by_currency.addItem(str(LOCKS_CURRENCIES[currency])) self.specify_by_currency.addItem('BTC') self.specify_by_currency.setMaximumWidth(60) def on_btc_amount_change(amount): if amount != self.Locks_amount: self.Locks_amount = amount def on_change_action(act): action = LOCK_ACTIONS[act] if action != self.Locks_action: self.Locks_action = action def get_quote(): specifiedCurrency = self.specify_by_currency.currentText() def get_lock(): if specifiedCurrency == 'BTC': amount = float(self.Locks_amount) outAmount = 0 else: amount = 0 outAmount = float(self.Locks_amount) try: lock = self.client.lock(amount=amount, outAmount=outAmount, currency=self.Locks_currency) # print json.dumps(lock, indent=4) pending_locks = self.config.get('pending_locks', []) pending_locks.append(lock) self.config.set_key('pending_locks', pending_locks, True) return lock except (CoinapultError, CoinapultErrorECC) as ce: QMessageBox.warning(None, _('Lock Failed'), _('Lock action failed due to reason: %s') % ce, _('OK')) def get_unlock(): if specifiedCurrency == 'BTC': amount = 0 outAmount = float(self.Locks_amount) else: amount = float(self.Locks_amount) outAmount = 0 for addr in self.wallet.addresses(): u, used = self.wallet.is_used(addr) if not used and u == 0: self.unlock_address = addr break try: unlock = self.client.unlock(amount=amount, outAmount=outAmount, currency=str(self.Locks_currency), address=str(self.unlock_address)) # print json.dumps(unlock, indent=4) pending_unlocks = self.config.get('pending_unlocks', []) pending_unlocks.append(unlock) self.config.set_key('pending_unlocks', pending_unlocks, True) return unlock except (CoinapultError, CoinapultErrorECC) as ce: QMessageBox.warning(None, _('Unlock Failed'), _('Unlock action failed due to reason: %s') % ce, _('OK')) self.quote_button.setDisabled(True) if self.Locks_action == 'Lock': self.waiting_dialog = WaitingDialog(w, 'Requesting Lock Quote', get_lock, self.lock_confirm_dialog) self.waiting_dialog.start() else: self.waiting_dialog = WaitingDialog(w, 'Requesting Unlock Quote', get_unlock, self.unlock_confirm_dialog) self.waiting_dialog.start() w = QWidget() self.tabLayout = QGridLayout(w) self.tabLayout.setColumnMinimumWidth(3, 400) self.tabLayout.setColumnStretch(0, 5) self.tabLayout.setHorizontalSpacing(10) about_locks_label = QLabel(ABOUT_LOCKS) about_locks_label.setWordWrap(True) about_locks_label.setOpenExternalLinks(True) self.tabLayout.addWidget(about_locks_label, 0, 2, 2, 3, Qt.AlignTop) self.balsLayout = QGridLayout(w) self.balsLayout.setColumnMinimumWidth(35, 400) self.balsLayout.setHorizontalSpacing(10) # self.balsLayout.setFrameStyle(QFrame.VLine) row = 0 balw = QLabel(_("<font size='5' style='bold'>Current Locks Balances</font>")) # balw.setBackgroundRole(QPalette_ColorRole=QPalette_ColorRole) balw.setBackgroundRole(QPalette.Midlight) balw.setAutoFillBackground(True) balw.setMinimumWidth(250) self.balsLayout.addWidget(balw, row, 0) row += 1 for cur in LOCKS_CURRENCIES: if cur == 'XAU': disp_cur = "Gold oz" elif cur == 'XAG': disp_cur = "Silver oz" else: disp_cur = cur curw = QLabel(_("<font size='5'>- %s</font>" % disp_cur)) curw.setBackgroundRole(QPalette.Light) curw.setAutoFillBackground(True) curw.setMinimumWidth(250) self.balsLayout.addWidget(curw, row, 0) row += 1 self.tabLayout.addLayout(self.balsLayout, 0, 0, 2, 3, Qt.AlignTop) # self.tabLayout.addWidget(QLabel(_('Estimated Total BTC Value')), row, 0) # self.tabLayout.addWidget(QLabel(_('- BTC')), row, 1) # row += 1 self.tabLayout.addWidget(QLabel(_('What do you want to do?')), 2, 0, Qt.AlignBottom) # row += 1 self.tabLayout.addWidget(QLabel(_('Which Locks asset?')), 2, 1, Qt.AlignBottom) # row += 1 # row += 1 self.tabLayout.addWidget(QLabel(_('Amount')), 2, 2, 1, 2, Qt.AlignBottom) # self.tabLayout.addWidget(QLabel(_('')), row, 0) # self.tabLayout.addWidget(QLabel(_('How much of which?')), 2, 3, Qt.AlignBottom) row += 1 combo_action = QComboBox() combo_action.currentIndexChanged.connect(on_change_action) combo_action.addItems(LOCK_ACTIONS) combo_action.setMaximumWidth(100) self.tabLayout.addWidget(combo_action, 3, 0, Qt.AlignTop) combo_currency = QComboBox() combo_currency.currentIndexChanged.connect(on_change_currency) combo_currency.addItems(LOCKS_CURRENCIES) combo_currency.setMaximumWidth(60) self.tabLayout.addWidget(combo_currency, 3, 1, Qt.AlignTop) btc_amount_edit = QLineEdit('0') btc_amount_edit.textChanged.connect(on_btc_amount_change) btc_amount_edit.setMaximumWidth(100) self.tabLayout.addWidget(btc_amount_edit, 3, 2, Qt.AlignRight) # self.specify_by_currency.currentIndexChanged.connect(on_change_specify_currency) self.specify_by_currency.addItems(['']) self.specify_by_currency.setMaximumWidth(60) self.tabLayout.addWidget(self.specify_by_currency, 3, 3, Qt.AlignLeft) # row += 1 self.quote_button = QPushButton(_('Get Quote')) self.quote_button.clicked.connect(get_quote) self.quote_button.setMaximumWidth(100) self.tabLayout.addWidget(self.quote_button, 5, 0, Qt.AlignBottom) return w
class WTestPng(Document.WDocument): """ Test png widget """ def __init__(self, parent=None, path=None, filename=None, extension=None, nonameId=None, remoteFile=True, repoDest=None, project=0): """ Constructs WScript widget @param parent: @type parent: @param path: @type path: @param filename: @type filename: @param extension: @type extension: @param nonameId: @type nonameId: """ Document.WDocument.__init__(self, parent, path, filename, extension, nonameId, remoteFile, repoDest, project) self.scaleFactor = 0.0 self.rawContent = '' self.createWidgets() self.createActions() self.createToolbar() self.createConnections() def createActions(self): """ Create qt actions """ self.zoomInAct = QtHelper.createAction(self, "&Zoom &In (25%.", self.zoomIn, icon=QIcon(":/zoom-in.png")) self.zoomOutAct = QtHelper.createAction(self, "Zoom &Out (25%.", self.zoomOut, icon=QIcon(":/zoom-out.png")) self.normalSizeAct = QtHelper.createAction( self, "&Normal Size", self.normalSize, icon=QIcon(":/zoom-normal.png")) def createToolbar(self): """ Toolbar creation ||------|------||| || Open | Save ||| ||------|------||| """ self.dockToolbar.setObjectName("Test Config toolbar") self.dockToolbar.addAction(self.zoomInAct) self.dockToolbar.addAction(self.zoomOutAct) self.dockToolbar.addAction(self.normalSizeAct) self.dockToolbar.addSeparator() self.dockToolbar.setIconSize(QSize(16, 16)) def createWidgets(self): """ QtWidgets creation """ self.dockToolbar = QToolBar(self) self.dockToolbar.setStyleSheet( "QToolBar { border: 0px }") # remove 3D border self.imageLabel = QLabel(self) self.imageLabel.setBackgroundRole(QPalette.Base) self.imageLabel.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored) self.imageLabel.setScaledContents(True) self.scrollArea = QScrollArea() self.scrollArea.setBackgroundRole(QPalette.Dark) self.scrollArea.setWidget(self.imageLabel) title = QLabel("Image:") title.setStyleSheet("QLabel { padding-left: 2px; padding-top: 2px }") font = QFont() font.setBold(True) title.setFont(font) layout = QVBoxLayout() layout.addWidget(title) layout.addWidget(self.dockToolbar) layout.addWidget(self.scrollArea) layout.setContentsMargins(2, 2, 2, 2) self.setLayout(layout) def zoomIn(self): """ Zoom in """ self.scaleImage(1.25) def zoomOut(self): """ Zoom out """ self.scaleImage(0.8) def normalSize(self): """ Normal size """ self.imageLabel.adjustSize() self.scaleFactor = 1.0 def scaleImage(self, factor): """ Scale image """ self.scaleFactor *= factor self.imageLabel.resize(self.scaleFactor * self.imageLabel.pixmap().size()) self.adjustScrollBar(self.scrollArea.horizontalScrollBar(), factor) self.adjustScrollBar(self.scrollArea.verticalScrollBar(), factor) def adjustScrollBar(self, scrollBar, factor): """ Adjust scrollbar """ scrollBar.setValue( int(factor * scrollBar.value() + ((factor - 1) * scrollBar.pageStep() / 2))) def createConnections(self): """ QtSignals connection """ pass def write(self, force=False): """ Save """ absPath = '%s/%s.%s' % (self.path, self.filename, self.extension) try: with open(absPath, mode='wb') as myfile: myfile.write(self.rawContent) except Exception as e: self.error("unable to write png file: %s" % e) return None else: self.setUnmodify() return True def load(self, content=None): """ Open file """ if content is None: absPath = '%s/%s.%s' % (self.path, self.filename, self.extension) file = QFile(absPath) if not file.open(QIODevice.ReadOnly): self.error("Error opening image file: %s" % absPath) return False else: content = file.readAll() self.rawContent = content image = QImage() image.loadFromData(content) if image.isNull(): self.error("cannot load image") return False else: self.imageLabel.setPixmap(QPixmap.fromImage(QImage(image))) self.scaleFactor = 1.0 self.imageLabel.adjustSize() return True def getraw_encoded(self): """ Returns raw data encoded """ encoded = '' try: encoded = base64.b64encode(self.rawContent) except Exception as e: self.error('unable to encode raw image: %s' % str(e)) return encoded
class PixmapWidget( QScrollArea ): " The pixmap widget " escapePressed = pyqtSignal() formatStrings = { QImage.Format_Invalid: "invalid", QImage.Format_Mono: "1-bit per pixel", QImage.Format_MonoLSB: "1-bit per pixel", QImage.Format_Indexed8: "8-bit indexes", QImage.Format_RGB32: "32-bit RG", QImage.Format_ARGB32: "32-bit ARGB", QImage.Format_ARGB32_Premultiplied: "32-bit ARGB", QImage.Format_RGB16: "16-bit RGB", QImage.Format_ARGB8565_Premultiplied: "24-bit ARGB", QImage.Format_RGB666: "24-bit RGB", QImage.Format_ARGB6666_Premultiplied: "24-bit ARGB", QImage.Format_RGB555: "16-bit RGB", QImage.Format_ARGB8555_Premultiplied: "24-bit ARGB", QImage.Format_RGB888: "24-bit RGB", QImage.Format_RGB444: "16-bit RGB", QImage.Format_ARGB4444_Premultiplied: "16-bit ARGB" } def __init__( self, parent = None ): QScrollArea.__init__( self, parent ) self.pixmapLabel = QLabel() self.pixmapLabel.setBackgroundRole( QPalette.Base ) self.pixmapLabel.setSizePolicy( QSizePolicy.Ignored, QSizePolicy.Ignored ) self.pixmapLabel.setScaledContents( True ) self.zoom = 1.0 self.info = "" self.formatInfo = "" self.fileSize = 0 self.setBackgroundRole( QPalette.Dark ) self.setWidget( self.pixmapLabel ) self.setAlignment( Qt.AlignCenter ) return def loadFromFile( self, fileName ): " Loads a pixmap from a file " image = QImage( fileName ) if image.isNull(): raise Exception( "Unsupported pixmap format (" + fileName + ")" ) self.pixmapLabel.setPixmap( QPixmap.fromImage( image ) ) self.pixmapLabel.adjustSize() self.fileSize = os.path.getsize( fileName ) if self.fileSize < 1024: fileSizeString = str( self.fileSize ) + "bytes" else: kiloBytes = self.fileSize / 1024 if (self.fileSize % 1024) >= 512: kiloBytes += 1 fileSizeString = str( kiloBytes ) + "kb" self.info = str( image.width() ) + "px/" + \ str( image.height() ) + "px/" + fileSizeString try: self.formatInfo = self.formatStrings[ image.format() ] except: self.formatInfo = "Unknown" return def setPixmap( self, pixmap ): " Shows the provided pixmap " pix = QPixmap.fromImage( pixmap ) self.pixmapLabel.setPixmap( pix ) self.pixmapLabel.adjustSize() self.info = str( pix.width() ) + "px/" + str( pix.height() ) + "px" self.formatInfo = str( pix.depth() ) + " bpp" return def keyPressEvent( self, event ): """ Handles the key press events """ if event.key() == Qt.Key_Escape: self.escapePressed.emit() event.accept() else: QScrollArea.keyPressEvent( self, event ) return def resetZoom( self ): " Resets the zoom " self.zoom = 1.0 self.pixmapLabel.adjustSize() return def doZoom( self, factor ): " Performs zooming " self.zoom *= factor self.pixmapLabel.resize( self.zoom * self.pixmapLabel.pixmap().size() ) self.__adjustScrollBar( self.horizontalScrollBar(), factor ) self.__adjustScrollBar( self.verticalScrollBar(), factor ) return def __adjustScrollBar( self, scrollBar, factor ): " Adjusts a scrollbar by a certain factor " scrollBar.setValue( int( factor * scrollBar.value() + ( (factor - 1) * scrollBar.pageStep()/2) ) ) return def setReadOnly( self, newValue ): " Make it similar to a text editor " return