def paintEvent(self, event): """ Called when the widget is painted on the window. """ dpr = self.devicePixelRatioF() buffer = QPixmap(self.width() * dpr, self.height() * dpr) buffer.setDevicePixelRatio(dpr) buffer.fill(Qt.transparent) painter = QPainter(buffer) region = QRegion( QRect(0, 0, self._textWidget.sizeHint().width(), self._textWidget.sizeHint().height())) self._textWidget.render(painter, QPoint(0, 0), region) region = QRegion( QRect(0, 0, self._iconWidget.sizeHint().width(), self._iconWidget.sizeHint().height())) x = self._textWidget.sizeHint().width() + 3 self._iconWidget.render(painter, QPoint(x, 0), region) painter.end() painter = QPainter(self) painter.drawPixmap(event.rect(), buffer, buffer.rect()) painter.end()
class FaderWidget(QtWidgets.QWidget): pixmap_opacity = 1.0 def __init__(self, old_widget, new_widget, duration=300): QtWidgets.QWidget.__init__(self, new_widget) pr = QtWidgets.QApplication.instance().devicePixelRatio() self.old_pixmap = QPixmap(new_widget.size() * pr) self.old_pixmap.setDevicePixelRatio(pr) old_widget.render(self.old_pixmap) self.timeline = QtCore.QTimeLine() self.timeline.valueChanged.connect(self.animate) self.timeline.finished.connect(self.close) self.timeline.setDuration(duration) self.timeline.start() self.resize(new_widget.size()) self.show() def paintEvent(self, event): painter = QPainter() painter.begin(self) painter.setOpacity(self.pixmap_opacity) painter.drawPixmap(0, 0, self.old_pixmap) painter.end() def animate(self, value): self.pixmap_opacity = 1.0 - value self.repaint()
def push_btn(self): resp = request('https://api.nasa.gov/planetary/apod', self.ui.dateEdit.date().toString('yyyy-M-d')) self.ui.title.setText(resp.json()['title']) if resp.json()['media_type'] == 'image': if not os.path.isdir('cache'): os.mkdir('cache') cache_img_name = resp.json()['url'].split('/')[-1] with open('cache/{}'.format(cache_img_name), 'wb') as img: img.write(request_img(resp.json()['url'])) pixmap = QPixmap('cache/{}'.format(cache_img_name)) pixmap.setDevicePixelRatio(1.5) self.ui.image.setPixmap(pixmap) else: self.ui.image.setText(resp.json()['url']) self.ui.date.setText(resp.json()['date']) if 'copyright' in resp.json(): self.ui.copyright.setText(resp.json()['copyright']) else: self.ui.copyright.setText('None') self.ui.explanation.setText(resp.json()['explanation'])
def paint(self, page, painter, rect, callback=None): """Reimplemented to paint all the sub pages on top of each other.""" # make the call back return with the original page, not the overlay page newcallback = CallBack(callback, page) if callback else None # get the device pixel ratio to paint for try: ratio = painter.device().devicePixelRatioF() except AttributeError: ratio = painter.device().devicePixelRatio() pixmaps = [] covered = QRegion() for p, overlayrect in page.visiblePagesAt(rect): pixmap = QPixmap(overlayrect.size() * ratio) if not pixmap.isNull(): pixmap.setDevicePixelRatio(ratio) pt = QPainter(pixmap) pt.translate(p.pos() - overlayrect.topLeft()) p.paint(pt, overlayrect.translated(-p.pos()), newcallback) pt.end() # even an empty pixmap is appended, otherwise the layer count when # compositing goes awry pos = overlayrect.topLeft() pixmaps.append((pos, pixmap)) covered += overlayrect if QRegion(rect).subtracted(covered): painter.fillRect(rect, page.paperColor or self.paperColor) self.combine(painter, pixmaps)
def init_ui(self): main_layout = QHBoxLayout() font = QFont("Sans", 12) self.cart_items.setText(f"\nAgent: Wózek widłowy\nPrzedmioty:") self.cart_items.setFont(font) self.cart_items.setAlignment(Qt.AlignTop) main_layout.addWidget(self.cart_items) for i in range(self.table.columnCount()): self.table.setColumnWidth(i, 55) for i in range(self.table.rowCount()): self.table.setRowHeight(i, 45) self.table.setIconSize(QSize(45, 45)) main_layout.addWidget(self.table) ga_pic = QLabel() pic = QPixmap("images/dna.png") pic.setDevicePixelRatio(8) ga_pic.setPixmap(pic) self.ga_info.setFont(font) ga_title = QLabel("Algorytm genetyczny:") ga_title.setFont(font) ga_info = QFormLayout() ga_info.addRow(ga_pic, ga_title) ga_info.addRow(QLabel(""), self.ga_info) main_layout.addLayout(ga_info) return main_layout
def demo_run(): app = QApplication(sys.argv) # get screen size. desktop = QApplication.desktop().screenGeometry() ratio = QApplication.desktop().screen().devicePixelRatio() width = desktop.width() height = desktop.height() # setting up welcome screen. screen = QPixmap(icon["SCREEN"]) screen.setDevicePixelRatio(ratio) if ratio == 2: # under Mac Retina screen = screen.scaled(height * 0.9, height * 0.9) else: # under Windows and Linux screen = screen.scaled(height * 0.5, height * 0.5) splash = QSplashScreen(screen) splash.show() # handle the main process event. qApp.processEvents() # setting up main window. size = (width * 0.8, height * 0.8) editor = KMBMainWindow(size) stylesheet = load_stylesheet(SS_COMMON) app.setStyleSheet(stylesheet) # Mac: set the icon in dock. app.setWindowIcon(editor.win_icon) # compatible with Mac Retina screen. app.setAttribute(Qt.AA_UseHighDpiPixmaps, True) app.setAttribute(Qt.AA_EnableHighDpiScaling, True) # editor show up editor.show() splash.finish(editor) sys.exit(app.exec_())
def init_icon(self): # set compatible pix = QPixmap(NODE_ICONx85_PATH.format(self.sort, self.name)) ratio = QApplication.desktop().screen().devicePixelRatio() if ratio == 1: pass else: pix.setDevicePixelRatio(ratio) self.icon.setPixmap(pix)
def getPixmap(self): pixmap = QPixmap(self.width * self.pixelRatio, self.height * self.pixelRatio) pixmap.setDevicePixelRatio(self.pixelRatio) pixmap.fill(Qt.transparent) painter = QPainter(pixmap) painter.setRenderHint(QPainter.Antialiasing) painter.translate(0, self.height) painter.scale(1, -1) if self.headerAtBottom: bodyRect = (0, 0, self.width, self.height - self.headerHeight) headerRect = (0, 0, self.width, self.headerHeight) else: bodyRect = (0, 0, self.width, self.height - self.headerHeight) headerRect = (0, 0, self.width, self.headerHeight) # background painter.save() if self.headerAtBottom: h = self.height else: h = self.height - self.headerHeight painter.translate(0, h) painter.scale(1, -1) self.drawCellBackground(painter, bodyRect) painter.restore() # glyph if self.headerAtBottom: painter.translate(0, self.headerHeight) if self.shouldDrawMetrics: self.drawCellHorizontalMetrics(painter, bodyRect) self.drawCellVerticalMetrics(painter, bodyRect) painter.save() painter.setClipRect(0, 0, self.width, self.height - self.headerHeight) painter.translate(self.xOffset, self.yOffset) painter.scale(self.scale, self.scale) self.drawCellGlyph(painter) painter.restore() # foreground painter.save() painter.translate(0, self.height - self.headerHeight) painter.scale(1, -1) self.drawCellForeground(painter, bodyRect) painter.restore() # header if self.shouldDrawHeader: painter.save() if self.headerAtBottom: h = 0 else: h = self.height painter.translate(0, h) painter.scale(1, -1) self.drawCellHeaderBackground(painter, headerRect) self.drawCellHeaderText(painter, headerRect) painter.restore() return pixmap
def mount_user(self, user: str): new_user = QLabel() pixmap = QPixmap(os.path.join(IMG_PATH, USER_ICON)) pixmap.setDevicePixelRatio(DEVICE_PIXEL_RATION['user_icon']) new_user.setPixmap(pixmap) new_user.setAlignment(Qt.AlignLeft) label = QLabel(user) label.setAlignment(Qt.AlignCenter) self.formLayout.addRow(new_user, label)
def getPixmap(self): pixmap = QPixmap(self.width * self.pixelRatio, self.height * self.pixelRatio) pixmap.setDevicePixelRatio(self.pixelRatio) pixmap.fill(Qt.transparent) painter = QPainter(pixmap) painter.setRenderHint(QPainter.Antialiasing) painter.translate(0, self.height) painter.scale(1, -1) if self.headerAtBottom: bodyRect = (0, 0, self.width, self.height-self.headerHeight) headerRect = (0, 0, self.width, self.headerHeight) else: bodyRect = (0, 0, self.width, self.height-self.headerHeight) headerRect = (0, 0, self.width, self.headerHeight) # background painter.save() if self.headerAtBottom: h = self.height else: h = self.height - self.headerHeight painter.translate(0, h) painter.scale(1, -1) self.drawCellBackground(painter, bodyRect) painter.restore() # glyph if self.headerAtBottom: painter.translate(0, self.headerHeight) if self.shouldDrawMetrics: self.drawCellHorizontalMetrics(painter, bodyRect) self.drawCellVerticalMetrics(painter, bodyRect) painter.save() painter.setClipRect(0, 0, self.width, self.height-self.headerHeight) painter.translate(self.xOffset, self.yOffset) painter.scale(self.scale, self.scale) self.drawCellGlyph(painter) painter.restore() # foreground painter.save() painter.translate(0, self.height - self.headerHeight) painter.scale(1, -1) self.drawCellForeground(painter, bodyRect) painter.restore() # header if self.shouldDrawHeader: painter.save() if self.headerAtBottom: h = 0 else: h = self.height painter.translate(0, h) painter.scale(1, -1) self.drawCellHeaderBackground(painter, headerRect) self.drawCellHeaderText(painter, headerRect) painter.restore() return pixmap
def paintEvent(self, event): # noqa: N802 """Called when the widget is being painted.""" # Adjust the buffer size according to the pixel ratio dpr = self.devicePixelRatioF() buffer = QPixmap(self.width() * dpr, self.height() * dpr) buffer.setDevicePixelRatio(dpr) buffer.fill(Qt.transparent) painter = QPainter(buffer) # Paint the server text widget region = QRegion( QRect(QPoint(0, 0), self._servers_text_widget.sizeHint()) ) self._servers_text_widget.render(painter, QPoint(0, 0), region) # Paint the server icon widget region = QRegion( QRect(QPoint(0, 0), self._servers_icon_widget.sizeHint()) ) x = self._servers_text_widget.sizeHint().width() + 3 self._servers_icon_widget.render(painter, QPoint(x, 0), region) # Paint the invites text widget region = QRegion( QRect(QPoint(0, 0), self._invites_text_widget.sizeHint()) ) x += self._servers_icon_widget.sizeHint().width() + 3 self._invites_text_widget.render(painter, QPoint(x, 0), region) # Paint the invites icon widget region = QRegion( QRect(QPoint(0, 0), self._invites_icon_widget.sizeHint()) ) x += self._invites_text_widget.sizeHint().width() + 3 self._invites_icon_widget.render(painter, QPoint(x, 0), region) # Paint the users text widget region = QRegion( QRect(QPoint(0, 0), self._users_text_widget.sizeHint()) ) x += self._invites_icon_widget.sizeHint().width() + 3 self._users_text_widget.render(painter, QPoint(x, 0), region) # Paint the users icon widget region = QRegion( QRect(QPoint(0, 0), self._users_icon_widget.sizeHint()) ) x += self._users_text_widget.sizeHint().width() + 3 self._users_icon_widget.render(painter, QPoint(x, 0), region) painter.end() painter = QPainter(self) painter.drawPixmap(event.rect(), buffer, buffer.rect()) painter.end()
def timerEvent(self, e=None): try: self.image_files = self.getFiles() if self.step >= len(self.image_files): self.timer.stop() self.btnSearchNumberPlate.setText('Slide Show Finished') return self.timer.start(self.delay, self) file = self.image_files[self.step] image = QPixmap(file) image.setDevicePixelRatio(3.6) #self.labelImage.adjustSize() self.labelImage.setPixmap(image) self.setWindowTitle("{} --> {}".format(str(self.step), file)) self.step += 1 except Exception as e: print(e)
def paintEvent(self, event): dpr = self.devicePixelRatioF() buffer = QPixmap(self.width() * dpr, self.height() * dpr) buffer.setDevicePixelRatio(dpr) buffer.fill(Qt.transparent) painter = QPainter(buffer) # Paint the users text widget x = 0 region = QRegion( QRect(QPoint(0, 0), self._users_text_widget.sizeHint())) self._users_text_widget.render(painter, QPoint(0, 0), region) #Paint the users icon widget region = QRegion(QRect(QPoint(0, 0), self._users_icon.sizeHint())) x += self._users_text_widget.sizeHint().width() + 3 self._users_icon.render(painter, QPoint(x, 0), region) painter.end() painter = QPainter(self) painter.drawPixmap(event.rect(), buffer, buffer.rect()) painter.end()
def paintEvent(self, event): """ Called when the widget is being painted """ pixel_ratio = self.devicePixelRatioF() pixmap = QPixmap(self.width() * pixel_ratio, self.height() * pixel_ratio) pixmap.setDevicePixelRatio(pixel_ratio) pixmap.fill(Qt.transparent) painter = QPainter(pixmap) # The server text region to be drawn server_region = QRegion( QRect(QPoint(0, 0), self._server_status_widget.sizeHint())) self._server_status_widget.render(painter, QPoint(0, 0), server_region) painter.end() painter = QPainter(self) painter.drawPixmap(event.rect(), pixmap, pixmap.rect()) painter.end()
def draw(self): """ update grid """ for col in range(self.ddp.imgs): checkbox, label = self.widgets[col] if col < len(self.images): img = self.images[col] checkbox.setText(str(img)) try: checkbox.stateChanged.disconnect() except TypeError: pass checkbox.setCheckState(Qt.Checked if img in self.removed else Qt.Unchecked) checkbox.stateChanged.connect(partial(self.ddp.updt_rm, img_no=self.img_no, img=img)) pix = QPixmap(str(self.images[col])) pix.setDevicePixelRatio(2) label.setPixmap(pix) checkbox.show() label.show() else: checkbox.hide() label.hide()
def transformaImgCirculo(logoPath: str, isLogo=True, raio: int = 39): if logoPath != '': imageBits = open(logoPath, 'rb').read() qImagem = QImage.fromData(imageBits) qImagem.convertToFormat(QImage.Format_ARGB32) imgSize = min(qImagem.width(), qImagem.height()) quadroImg = QRect((qImagem.width() - imgSize) / 2, (qImagem.height() - imgSize) / 2, imgSize, imgSize) qImagem.copy(quadroImg) if isLogo: borda = QImage(imgSize, imgSize, QImage.Format_ARGB32) borda.fill(Qt.transparent) pincel = QBrush(qImagem) pintor = QPainter(borda) pintor.setBrush(pincel) pintor.setPen(Qt.NoPen) pintor.setRenderHint(QPainter.Antialiasing, True) pintor.setRenderHint(QPainter.HighQualityAntialiasing, True) pintor.drawEllipse(0, 0, imgSize, imgSize) pintor.end() pixLogo = QPixmap.fromImage(borda) else: pixLogo = QPixmap(logoPath) pixRatio = QWindow().devicePixelRatio() pixLogo.setDevicePixelRatio(pixRatio) tamanho = raio * 2 * pixRatio return pixLogo.scaled(tamanho, tamanho, Qt.KeepAspectRatio, Qt.SmoothTransformation)
def draw_icon(icon, rect, painter, icon_mode, shadow=False): cache = icon.pixmap(rect.size()) dip_offset = QPoint(1, -2) cache = QPixmap() pixname = "icon {0} {1} {2}".format( icon.cacheKey(), icon_mode, rect.height() ) if QPixmapCache.find(pixname) is None: pix = icon.pixmap(rect.size()) device_pixel_ratio = pix.devicePixelRatio() radius = 3 * device_pixel_ratio offset = dip_offset * device_pixel_ratio cache = QPixmap(pix.size() + QSize(radius * 2, radius * 2)) cache.fill(Qt.transparent) cache_painter = QPainter(cache) if icon_mode == QIcon.Disabled: im = pix.toImage().convertToFormat(QImage.Format_ARGB32) for y in range(0, im.height()): scanline = im.scanLine(y) for x in range(0, im.width()): pixel = scanline intensity = qGray(pixel) scanline = qRgba( intensity, intensity, intensity, qAlpha(pixel)) scanline += 1 pix = QPixmap.fromImage(im) # Draw shadow tmp = QImage(pix.size() + QSize(radius * 2, radius * 2), QImage.Format_ARGB32_Premultiplied) tmp.fill(Qt.transparent) tmp_painter = QPainter(tmp) tmp_painter.setCompositionMode(QPainter.CompositionMode_Source) tmp_painter.drawPixmap( QRect(radius, radius, pix.width(), pix.height()), pix) tmp_painter.end() # Blur the alpha channel blurred = QImage(tmp.size(), QImage.Format_ARGB32_Premultiplied) blur_painter = QPainter(blurred) blur_painter.end() # tmp = blurred tmp_painter.begin(tmp) tmp_painter.setCompositionMode(QPainter.CompositionMode_SourceIn) tmp_painter.fillRect(tmp.rect(), QColor(0, 0, 0, 150)) tmp_painter.end() tmp_painter.begin(tmp) tmp_painter.setCompositionMode(QPainter.CompositionMode_SourceIn) tmp_painter.fillRect(tmp.rect(), QColor(0, 0, 0, 150)) tmp_painter.end() # Draw the blurred drop shadow cache_painter.drawImage( QRect(0, 0, cache.rect().width(), cache.rect().height()), tmp) # Draw the actual pixmap cache_painter.drawPixmap( QRect(QPoint(radius, radius) + offset, QSize(pix.width(), pix.height())), pix) cache_painter.end() cache.setDevicePixelRatio(device_pixel_ratio) QPixmapCache.insert(pixname, cache) target_rect = cache.rect() target_rect.setSize(target_rect.size() / cache.devicePixelRatio()) target_rect.moveCenter(rect.center() - dip_offset) painter.drawPixmap(target_rect, cache)
def _init_mne_qtapp(enable_icon=True, pg_app=False, splash=False): """Get QApplication-instance for MNE-Python. Parameter --------- enable_icon: bool If to set an MNE-icon for the app. pg_app: bool If to create the QApplication with pyqtgraph. For an until know undiscovered reason the pyqtgraph-browser won't show without mkQApp from pyqtgraph. splash : bool | str If not False, display a splash screen. If str, set the message to the given string. Returns ------- app : ``PyQt5.QtWidgets.QApplication`` Instance of QApplication. splash : ``PyQt5.QtWidgets.QSplashScreen`` Instance of QSplashScreen. Only returned if splash is True or a string. """ from PyQt5.QtCore import Qt from PyQt5.QtGui import QIcon, QPixmap, QGuiApplication from PyQt5.QtWidgets import QApplication, QSplashScreen app_name = 'MNE-Python' organization_name = 'MNE' # Fix from cbrnr/mnelab for app name in menu bar # This has to come *before* the creation of the QApplication to work. # It also only affects the title bar, not the application dock. # There seems to be no way to change the application dock from "python" # at runtime. if sys.platform.startswith("darwin"): try: # set bundle name on macOS (app name shown in the menu bar) from Foundation import NSBundle bundle = NSBundle.mainBundle() info = bundle.localizedInfoDictionary() or bundle.infoDictionary() info["CFBundleName"] = app_name except ModuleNotFoundError: pass if pg_app: from pyqtgraph import mkQApp app = mkQApp(app_name) else: app = QApplication.instance() or QApplication(sys.argv or [app_name]) app.setApplicationName(app_name) app.setOrganizationName(organization_name) if enable_icon: # Set icon _init_qt_resources() kind = 'bigsur-' if platform.mac_ver()[0] >= '10.16' else '' app.setWindowIcon(QIcon(f":/mne-{kind}icon.png")) out = app if splash: pixmap = QPixmap(":/mne-splash.png") pixmap.setDevicePixelRatio( QGuiApplication.primaryScreen().devicePixelRatio()) qsplash = QSplashScreen(pixmap, Qt.WindowStaysOnTopHint) if isinstance(splash, str): alignment = int(Qt.AlignBottom | Qt.AlignHCenter) qsplash.showMessage( splash, alignment=alignment, color=Qt.white) qsplash.show() app.processEvents() out = (out, qsplash) return out
class Terminal(TerminalBuffer, QWidget): # Terminal widget. # Note: One should not call functions that begin with _, especially those # linking with painting things. # It is DANGEROUS to call internal painting function outside the main # thread, Qt will crash immediately. Just don't do that. # signal for triggering a on-canvas buffer repaint buffer_repaint_sig = pyqtSignal() # signal for triggering a on-canvas cursor repaint cursor_repaint_sig = pyqtSignal() # signal for triggering a repaint for both the canvas and the widget total_repaint_sig = pyqtSignal() # internal signal for triggering stdout routine for buffering and # painting. Note: Use stdout() method. _stdout_sig = pyqtSignal(bytes) # update scroll bar update_scroll_sig = pyqtSignal() def __init__(self, width, height, logger=None): QWidget.__init__(self) self.scroll_bar: QScrollBar = None self.logger = logger if logger else logging.getLogger() self.logger.info("Initializing Terminal...") TerminalBuffer.__init__(self, 0, 0, logger) # we paint everything to the pixmap first then paint this pixmap # on paint event. This allows us to partially update the canvas. self._canvas = QPixmap(width, height) self._painter_lock = QMutex(QMutex.Recursive) self._width = width self._height = height self.font = None self.char_width = None self.char_height = None self.line_height = None self.row_len = None self.col_len = None self.dpr = self.devicePixelRatioF() self.set_bg(DEFAULT_BG_COLOR) self.set_fg(DEFAULT_FG_COLOR) self.set_font() self.setAutoFillBackground(True) self.setMinimumSize(width, height) # connect reapint signals self.buffer_repaint_sig.connect(self._paint_buffer) self.cursor_repaint_sig.connect(self._paint_cursor) self.total_repaint_sig.connect(self._canvas_repaint) # intializing blinking cursor self._cursor_blinking_lock = QMutex() self._cursor_blinking_state = CursorState.ON self._cursor_blinking_elapse = 0 self._cursor_blinking_timer = QTimer() self._cursor_blinking_timer.timeout.connect(self._blink_cursor) self._switch_cursor_blink(state=CursorState.ON, blink=True) self.update_scroll_sig.connect(self._update_scroll_position) self.setFocusPolicy(Qt.StrongFocus) # terminal options, in case you don't want pty to handle it # self.echo = True # self.canonical_mode = True self._stdout_sig.connect(self._stdout) self.resize(width, height) def set_bg(self, color: QColor): TerminalBuffer.set_bg(self, color) pal = self.palette() pal.setColor(QPalette.Background, color) self.setPalette(pal) def set_fg(self, color: QColor): TerminalBuffer.set_fg(self, color) pal = self.palette() pal.setColor(QPalette.Foreground, color) self.setPalette(pal) def set_font(self, font: QFont = None): qfd = QFontDatabase() if font: info = QFontInfo(font) if info.styleHint() != QFont.Monospace: self.logger.warning("font: Please use monospaced font! " f"Unsupported font {info.family}.") font = qfd.systemFont(QFontDatabase.FixedFont) elif "Menlo" in qfd.families(): font = QFont("Menlo") info = QFontInfo(font) else: font = qfd.systemFont(QFontDatabase.FixedFont) info = QFontInfo(font) font.setPointSize(12) self.font = font metrics = QFontMetrics(font) self.char_width = metrics.horizontalAdvance("A") self.char_height = metrics.height() self.line_height = int(self.char_height * 1.2) self.logger.info(f"font: Font {info.family()} selected, character " f"size {self.char_width}x{self.char_height}.") self.row_len = int(self._width / self.char_width) self.col_len = int(self._height / self.line_height) def resizeEvent(self, event): self.resize(event.size().width(), event.size().height()) # ========================== # PAINT FUNCTIONS # ========================== def paintEvent(self, event): self._painter_lock.lock() _qp = QPainter(self) _qp.setRenderHint(QPainter.Antialiasing) _qp.drawPixmap(int(PADDING) / 2, int(PADDING) / 2, self._canvas) QWidget.paintEvent(self, event) self._painter_lock.unlock() def _paint_buffer(self): self._painter_lock.lock() self._canvas = QPixmap( self.row_len * self.char_width * self.dpr, int((self.col_len + 0.2) * self.line_height * self.dpr)) self._canvas.setDevicePixelRatio(self.dpr) qp = QPainter(self._canvas) qp.fillRect(self.rect(), self._bg_color) if not self._buffer: return cw = self.char_width ch = self.char_height lh = self.line_height ft = self.font fg_color = self._fg_color ht = 0 offset = self._buffer_display_offset qp.fillRect(self.rect(), DEFAULT_BG_COLOR) for ln in range(self.col_len): real_ln = ln + offset if real_ln < 0 or real_ln >= len(self._buffer): break row = self._buffer[ln + offset] ht += lh for cn, c in enumerate(row): if c: ft.setBold(c.bold) ft.setUnderline(c.underline) qp.setFont(ft) if not c.reverse: qp.fillRect(cn * cw, int(ht - 0.8 * ch), cw, lh, c.bg_color) qp.setPen(c.color) qp.drawText(cn * cw, ht, c.char) else: qp.fillRect(cn * cw, int(ht - 0.8 * ch), cw, lh, c.color) qp.setPen(c.bg_color) qp.drawText(cn * cw, ht, c.char) else: qp.setPen(fg_color) ft.setBold(False) ft.setUnderline(False) qp.setFont(ft) qp.drawText(ht, cn * cw, " ") qp.end() self._painter_lock.unlock() def _paint_cursor(self): if not self._buffer: return self._painter_lock.lock() ind_x = self._cursor_position.x ind_y = self._cursor_position.y # if cursor is at the right edge of screen, display half of it x = (ind_x if ind_x < self.row_len else (self.row_len - 0.5)) \ * self.char_width y = (ind_y - self._buffer_display_offset) \ * self.line_height + (self.line_height - self.char_height) \ + int(0.2 * self.line_height) cw = self.char_width ch = self.char_height qp = QPainter(self._canvas) fg = DEFAULT_FG_COLOR bg = DEFAULT_BG_COLOR if self._cursor_blinking_state == CursorState.UNFOCUSED: outline = QPen(fg) outline.setWidth(1) qp.setPen(outline) qp.fillRect(x, y, cw, ch, bg) qp.drawRect(x + 1, y + 1, cw - 2, ch - 2) else: if self._cursor_blinking_state == CursorState.ON: bg = self._fg_color fg = self._bg_color qp.fillRect(x, y, cw, ch, bg) qp.setPen(fg) qp.setFont(self.font) cy = (self._cursor_position.y - self._buffer_display_offset + 1) \ * self.line_height if ind_x == self.row_len: # cursor sitting at the edge of screen pass elif self._buffer[ind_y][ind_x]: qp.drawText(x, cy, self._buffer[ind_y][ind_x].char) else: qp.drawText(x, cy, " ") qp.end() self._painter_lock.unlock() def _canvas_repaint(self): self._paint_buffer() self._paint_cursor() self.repaint() # ========================== # SCREEN BUFFER FUNCTIONS # ========================== def resize(self, width, height): self._save_cursor_state_stop_blinking() QWidget.resize(self, width, height) row_len = int((width - PADDING) / self.char_width) col_len = min(int((height - PADDING) / self.line_height), self.maximum_line_history) TerminalBuffer.resize(self, row_len, col_len) self._paint_buffer() self._restore_cursor_state() # self._log_buffer() def toggle_alt_screen(self, on=True): TerminalBuffer.toggle_alt_screen(self, on) self._canvas_repaint() def toggle_alt_screen_save_cursor(self, on=True): if on: # save current buffer self._alt_cursor_position = self._cursor_position else: if not self._alt_buffer: return self._cursor_position = self._alt_cursor_position self.toggle_alt_screen(on) # ========================== # CURSOR CONTROL # ========================== def _blink_cursor(self): self._cursor_blinking_lock.lock() if self._cursor_blinking_state == CursorState.ON: # On if self._cursor_blinking_elapse < 400: # 50 is the period of the timer self._cursor_blinking_elapse += 50 self._cursor_blinking_lock.unlock() return else: self._cursor_blinking_state = CursorState.OFF elif self._cursor_blinking_state == CursorState.OFF: # Off if self._cursor_blinking_elapse < 250: # 50 is the period of the timer self._cursor_blinking_elapse += 50 self._cursor_blinking_lock.unlock() return else: self._cursor_blinking_state = CursorState.ON self._cursor_blinking_elapse = 0 self._cursor_blinking_lock.unlock() self._paint_cursor() self.repaint() def _switch_cursor_blink(self, state, blink=True): self._cursor_blinking_lock.lock() if state != CursorState.UNFOCUSED and blink: self._cursor_blinking_timer.start(50) else: self._cursor_blinking_timer.stop() self._cursor_blinking_state = state self._cursor_blinking_lock.unlock() self._paint_cursor() self.repaint() def _save_cursor_state_stop_blinking(self): self._saved_cursor_state = self._cursor_blinking_state self._switch_cursor_blink(CursorState.ON, False) def _restore_cursor_state(self): self._cursor_blinking_state = self._saved_cursor_state self._switch_cursor_blink(self._cursor_blinking_state, True) def stdout(self, string: bytes): # Note that this function accepts UTF-8 only (since python use utf-8). # Normally modern programs will determine the encoding of its stdout # from env variable LC_CTYPE and for most systems, it is set to utf-8. self._stdout_sig.emit(string) def _stdout(self, string: bytes): # Note that this function accepts UTF-8 only (since python use utf-8). # Normally modern programs will determine the encoding of its stdout # from env variable LC_CTYPE and for most systems, it is set to utf-8. self._buffer_lock.lock() need_draw = False for char in string: need_draw = self._stdout_char(char) or need_draw self._buffer_lock.unlock() if need_draw: self._paint_buffer() self.repaint() def focusInEvent(self, event): self._switch_cursor_blink(CursorState.ON, True) def focusOutEvent(self, event): self._switch_cursor_blink(CursorState.UNFOCUSED, False) def keyPressEvent(self, event): key = event.key() modifiers = event.modifiers() text = event.text() while True: # This is a one-shot loop, because I want to use 'break' # to jump out of this block if key == Qt.Key_Up: self.input(b'\x1b[A') elif key == Qt.Key_Down: self.input(b'\x1b[B') elif key == Qt.Key_Right: self.input(b'\x1b[C') elif key == Qt.Key_Left: self.input(b'\x1b[D') else: break # avoid the execution of 'return' return if not modifiers: while True: # This is a one-shot loop, because I want to use 'break' # to jump out of this block if key == Qt.Key_Enter or key == Qt.Key_Return: self.input(ControlChar.CR.value) elif key == Qt.Key_Delete or key == Qt.Key_Backspace: self.input(ControlChar.BS.value) elif key == Qt.Key_Escape: self.input(ControlChar.ESC.value) else: break # avoid the execution of 'return' return elif modifiers == Qt.ControlModifier or modifiers == Qt.MetaModifier: if key == Qt.Key_A: self.input(ControlChar.SOH.value) elif key == Qt.Key_B: self.input(ControlChar.STX.value) elif key == Qt.Key_C: self.input(ControlChar.ETX.value) elif key == Qt.Key_D: self.input(ControlChar.EOT.value) elif key == Qt.Key_E: self.input(ControlChar.ENQ.value) elif key == Qt.Key_F: self.input(ControlChar.ACK.value) elif key == Qt.Key_G: self.input(ControlChar.BEL.value) elif key == Qt.Key_H: self.input(ControlChar.BS.value) elif key == Qt.Key_I: self.input(ControlChar.TAB.value) elif key == Qt.Key_J: self.input(ControlChar.LF.value) elif key == Qt.Key_K: self.input(ControlChar.VT.value) elif key == Qt.Key_L: self.input(ControlChar.FF.value) elif key == Qt.Key_M: self.input(ControlChar.CR.value) elif key == Qt.Key_N: self.input(ControlChar.SO.value) elif key == Qt.Key_O: self.input(ControlChar.SI.value) elif key == Qt.Key_P: self.input(ControlChar.DLE.value) elif key == Qt.Key_Q: self.input(ControlChar.DC1.value) elif key == Qt.Key_R: self.input(ControlChar.DC2.value) elif key == Qt.Key_S: self.input(ControlChar.DC3.value) elif key == Qt.Key_T: self.input(ControlChar.DC4.value) elif key == Qt.Key_U: self.input(ControlChar.NAK.value) elif key == Qt.Key_V: self.input(ControlChar.SYN.value) elif key == Qt.Key_W: self.input(ControlChar.ETB.value) elif key == Qt.Key_X: self.input(ControlChar.CAN.value) elif key == Qt.Key_Y: self.input(ControlChar.EM.value) elif key == Qt.Key_Z: self.input(ControlChar.SUB.value) elif key == Qt.Key_BracketLeft: self.input(ControlChar.ESC.value) return if text: self.input(text.encode('utf-8')) # ========================== # SCROLL BAR # ========================== def _update_scroll_position(self): self.scroll_bar.setMinimum(0) self.scroll_bar.setMaximum(len(self._buffer) - self.col_len) self.scroll_bar.setSliderPosition(self._buffer_display_offset) def update_scroll_position(self): if self.scroll_bar: self.update_scroll_sig.emit() def connect_scroll_bar(self, scroll_bar: QScrollBar): self.scroll_bar = scroll_bar self.update_scroll_position() self.scroll_bar.valueChanged.connect(self.scroll_bar_changed) def scroll_bar_changed(self, pos): if 0 <= pos <= len(self._buffer) - self.col_len: self._buffer_display_offset = pos self._paint_buffer() self.repaint()
def drawIconWithShadow(icon: QIcon, rect: QRect, p: QPainter, iconMode: QIcon.Mode = None, dipRadius: int = None, color: QColor = None, dipOffset: QPoint = None): if iconMode is None: iconMode = QIcon.Normal if color is None: color = QColor(0, 0, 0, 130) if dipRadius is None: dipRadius = 3 if dipOffset is None: dipOffset = QPoint(1, -2) devicePixelRatio: int = p.device().devicePixelRatio() pixmapName = "icon %s %s %s %s" % (icon.cacheKey(), iconMode, rect.height(), devicePixelRatio) cache = QPixmapCache.find(pixmapName) if cache is None: # High-dpi support: The in parameters (rect, radius, offset) are in # device-independent pixels. The call to QIcon::pixmap() below might # return a high-dpi pixmap, which will in that case have a devicePixelRatio # different than 1. The shadow drawing caluculations are done in device # pixels. window = p.device().window().windowHandle() px = icon.pixmap(window, rect.size(), iconMode) radius = dipRadius * devicePixelRatio offset = dipOffset * devicePixelRatio cache = QPixmap(px.size() + QSize(radius * 2, radius * 2)) cache.fill(Qt.transparent) cachePainter = QPainter(cache) if iconMode == QIcon.Disabled: hasDisabledState = len(icon.availableSizes()) == len( icon.availableSizes(QIcon.Disabled)) if not hasDisabledState: px = disabledSideBarIcon(icon.pixmap(window, rect.size())) elif TOOLBAR_ICON_SHADOW: # Draw shadow tmp = QImage(px.size() + QSize(radius * 2, radius * 2 + 1), QImage.Format_ARGB32_Premultiplied) tmp.fill(Qt.transparent) tmpPainter = QPainter(tmp) tmpPainter.setCompositionMode(QPainter.CompositionMode_Source) tmpPainter.drawPixmap( QRect(radius, radius, px.width(), px.height()), px) tmpPainter.end() # blur the alpha channel blurred = QImage(tmp.size(), QImage.Format_ARGB32_Premultiplied) blurred.fill(Qt.transparent) blurPainter = QPainter(blurred) #qt_blurImage(blurPainter, tmp, radius, False, True) # implement qt_blurImage via QLabel with QGraphicsBlurEffect # FIXME: alignment is broken scene = QGraphicsScene() item = QGraphicsPixmapItem(QPixmap.fromImage(tmp)) effect = QGraphicsBlurEffect() effect.setBlurRadius(radius) item.setGraphicsEffect(effect) scene.addItem(item) scene.render(blurPainter) blurPainter.end() tmp = blurred # blacken the image... tmpPainter.begin(tmp) tmpPainter.setCompositionMode(QPainter.CompositionMode_SourceIn) tmpPainter.fillRect(tmp.rect(), color) tmpPainter.end() tmpPainter.begin(tmp) tmpPainter.setCompositionMode(QPainter.CompositionMode_SourceIn) tmpPainter.fillRect(tmp.rect(), color) tmpPainter.end() # draw the blurred drop shadow... cachePainter.drawImage( QRect(0, 0, cache.rect().width(), cache.rect().height()), tmp) # Draw the actual pixmap... cachePainter.drawPixmap( QRect( QPoint(radius, radius) + offset, QSize(px.width(), px.height())), px) cachePainter.end() cache.setDevicePixelRatio(devicePixelRatio) QPixmapCache.insert(pixmapName, cache) targetRect = cache.rect() targetRect.setSize(targetRect.size() / cache.devicePixelRatio()) targetRect.moveCenter(rect.center() - dipOffset) p.drawPixmap(targetRect, cache)
def process(self, confidence=0.5, threshold=0.3, input="input/highway.mp4", yolo="yolo-coco", output=os.getcwd() + '\\output\\'): print("Test", output) args = { "confidence": confidence, "threshold": threshold, "input": input, #r"C:\Users\dheer\PycharmProjects\Smart-Video-Analytics\webbasket\ui\input\highway.mp4", "output": output, #r"C:\Users\dheer\PycharmProjects\Smart-Video-Analytics\webbasket\ui\output\highway.avi", "yolo": yolo } labelsPath = os.path.sep.join([args["yolo"], "coco.names"]) LABELS = open(labelsPath).read().strip().split("\n") # initialize a list of colors to represent each possible class label np.random.seed(42) COLORS = np.random.randint(0, 255, size=(200, 3), dtype="uint8") # derive the paths to the YOLO weights and model configuration weightsPath = os.path.sep.join([args["yolo"], "yolov3.weights"]) configPath = os.path.sep.join([args["yolo"], "yolov3.cfg"]) # load our YOLO object detector trained on COCO dataset (80 classes) # and determine only the *output* layer names that we need from YOLO print("[INFO] loading YOLO from disk...") self.textEdit.append("[INFO] loading YOLO from disk...") net = cv2.dnn.readNetFromDarknet(configPath, weightsPath) ln = net.getLayerNames() ln = [ln[i[0] - 1] for i in net.getUnconnectedOutLayers()] # initialize the video stream, pointer to output video file, and # frame dimensions vs = cv2.VideoCapture(args["input"]) writer = None (W, H) = (None, None) frameIndex = 0 # try to determine the total number of frames in the video file try: prop = cv2.cv.CV_CAP_PROP_FRAME_COUNT if imutils.is_cv2() \ else cv2.CAP_PROP_FRAME_COUNT total = int(vs.get(prop)) print("[INFO] {} total frames in video".format(total)) self.textEdit.append( self.textEdit.toPlainText() + "[INFO] {} total frames in video".format(total)) # an error occurred while trying to determine the total # number of frames in the video file except: self.textEdit.append( self.textEdit.toPlainText() + "[INFO] could not determine # of frames in video\n[INFO] no approx. completion time can be provided" ) print("[INFO] could not determine # of frames in video") print("[INFO] no approx. completion time can be provided") total = -1 # loop over frames from the video file stream while True: # read the next frame from the file (grabbed, frame) = vs.read() # if the frame was not grabbed, then we have reached the end # of the stream if not grabbed: break # if the frame dimensions are empty, grab them if W is None or H is None: (H, W) = frame.shape[:2] # construct a blob from the input frame and then perform a forward # pass of the YOLO object detector, giving us our bounding boxes # and associated probabilities blob = cv2.dnn.blobFromImage(frame, 1 / 255.0, (416, 416), swapRB=True, crop=False) net.setInput(blob) start = time.time() layerOutputs = net.forward(ln) end = time.time() # initialize our lists of detected bounding boxes, confidences, # and class IDs, respectively boxes = [] confidences = [] classIDs = [] # loop over each of the layer outputs for output in layerOutputs: # loop over each of the detections for detection in output: # extract the class ID and confidence (i.e., probability) # of the current object detection scores = detection[5:] classID = np.argmax(scores) confidence = scores[classID] # filter out weak predictions by ensuring the detected # probability is greater than the minimum probability if confidence > args["confidence"]: # scale the bounding box coordinates back relative to # the size of the image, keeping in mind that YOLO # actually returns the center (x, y)-coordinates of # the bounding box followed by the boxes' width and # height box = detection[0:4] * np.array([W, H, W, H]) (centerX, centerY, width, height) = box.astype("int") # use the center (x, y)-coordinates to derive the top # and and left corner of the bounding box x = int(centerX - (width / 2)) y = int(centerY - (height / 2)) # update our list of bounding box coordinates, # confidences, and class IDs boxes.append([x, y, int(width), int(height)]) confidences.append(float(confidence)) classIDs.append(classID) # apply non-maxima suppression to suppress weak, overlapping # bounding boxes idxs = cv2.dnn.NMSBoxes(boxes, confidences, args["confidence"], args["threshold"]) dets = [] if len(idxs) > 0: # loop over the indexes we are keeping for i in idxs.flatten(): (x, y) = (boxes[i][0], boxes[i][1]) (w, h) = (boxes[i][2], boxes[i][3]) dets.append([x, y, x + w, y + h, confidences[i]]) np.set_printoptions( formatter={'float': lambda x: "{0:0.3f}".format(x)}) dets = np.asarray(dets) tracks = self.tracker.update(dets) boxes = [] indexIDs = [] c = [] previous = self.memory.copy() self.memory = {} for track in tracks: boxes.append([track[0], track[1], track[2], track[3]]) indexIDs.append(int(track[4])) self.memory[indexIDs[-1]] = boxes[-1] if len(boxes) > 0: i = int(0) for box in boxes: # extract the bounding box coordinates (x, y) = (int(box[0]), int(box[1])) (w, h) = (int(box[2]), int(box[3])) # draw a bounding box rectangle and label on the image # color = [int(c) for c in COLORS[classIDs[i]]] # cv2.rectangle(frame, (x, y), (x + w, y + h), color, 2) color = [int(c) for c in COLORS[indexIDs[i] % len(COLORS)]] cv2.rectangle(frame, (x, y), (w, h), color, 4) if indexIDs[i] in previous: previous_box = previous[indexIDs[i]] (x2, y2) = (int(previous_box[0]), int(previous_box[1])) (w2, h2) = (int(previous_box[2]), int(previous_box[3])) p0 = (int(x + (w - x) / 2), int(y + (h - y) / 2)) p1 = (int(x2 + (w2 - x2) / 2), int(y2 + (h2 - y2) / 2)) cv2.line(frame, p0, p1, color, 3) if intersect(p0, p1, self.line[0], self.line[1]): self.counter += 1 # text = "{}: {:.4f}".format(LABELS[classIDs[i]], confidences[i]) text = "{}".format(indexIDs[i]) cv2.putText(frame, text, (x, y - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.5, color, 2) i += 1 # draw line cv2.line(frame, self.line[0], self.line[1], (0, 255, 255), 5) # draw counter cv2.putText(frame, str(self.counter), (100, 200), cv2.FONT_HERSHEY_DUPLEX, 5.0, (0, 255, 255), 10) # counter += 1 # saves image file cv2.imwrite(args['output'] + "frame-{}.png".format(frameIndex), frame) height, width, channel = frame.shape bytesPerLine = 3 * width qImg = QImage(frame.data, width, height, bytesPerLine, QImage.Format_RGB888) image = QPixmap(qImg) image.setDevicePixelRatio(3.6) # self.labelImage.adjustSize() self.labelImage.setPixmap(image) # check if the video writer is None if writer is None: # initialize our video writer fourcc = cv2.VideoWriter_fourcc(*"MJPG") writer = cv2.VideoWriter(args["output"], fourcc, 30, (frame.shape[1], frame.shape[0]), True) # some information on processing single frame if total > 0: elap = (end - start) self.textEdit.append( "[INFO] single frame took {:.4f} seconds".format(elap)) print( "[INFO] single frame took {:.4f} seconds".format(elap)) self.textEdit.append( "[INFO] estimated total time to finish: {:.4f}".format( elap * total)) print( "[INFO] estimated total time to finish: {:.4f}".format( elap * total)) # write the output frame to disk writer.write(frame) # increase frame index frameIndex += 1 print("[INFO] cleaning up...") self.textEdit.append("[INFO] cleaning up...") vs.release()
class PopMessageBox(QMessageBox): """ Popup message box. """ TYPE_OK = 0 TYPE_ALERT = 2 TYPE_ERROR = 4 TYPE_YES_OR_NO = 8 TYPE_SAVE_OR_NOT = 16 TYPE_EXPORT_WARNING = 32 def __init__(self, title: str, parent=None, run=False): super().__init__(parent) self.title = title self.run = run # it will run after making. # for Win & Mac: Retina compatible. # the dpr of Normal(1) or Retina(2) screen. self.ratio = QApplication.desktop().screen().devicePixelRatio() # icons self.win_icon = QIcon(icon['WINICON']) self.alert_icon = QPixmap(icon['ALERT']) self.quest_icon = QPixmap(icon['QUESTION']) self.ok_icon = QPixmap(icon['EXPORT_OK']) self.error_icon = QPixmap(icon['EXPORT_ERR']) # set for dpr. self.alert_icon.setDevicePixelRatio(self.ratio) self.quest_icon.setDevicePixelRatio(self.ratio) self.ok_icon.setDevicePixelRatio(self.ratio) self.error_icon.setDevicePixelRatio(self.ratio) # init basic ui self.setWindowTitle(self.title) self.setWindowIcon(self.win_icon) def make(self, text: str, pop_message_type=TYPE_ALERT, extra_text: str = None): # make one message box. if pop_message_type == self.TYPE_OK: self._make_ok() elif pop_message_type == self.TYPE_ALERT: self._make_alert() elif pop_message_type == self.TYPE_ERROR: self._make_export_error() elif pop_message_type == self.TYPE_YES_OR_NO: self._make_yes_or_no() elif pop_message_type == self.TYPE_SAVE_OR_NOT: self._make_save_or_not() elif pop_message_type == self.TYPE_EXPORT_WARNING: self._make_export_warning() else: # default will be ALERT type. self._make_alert() # common settings self.setText(text) self.setDetailedText(extra_text) if self.run: # run immediately. self.exec() def _make_ok(self): self.setIconPixmap(self.ok_icon) self.setStandardButtons(QMessageBox.Ok) def _make_alert(self): self.setIconPixmap(self.alert_icon) self.setStandardButtons(QMessageBox.Close) self.setInformativeText('<i>Press Close to return.</i>') def _make_yes_or_no(self): self.setIconPixmap(self.quest_icon) self.setStandardButtons(QMessageBox.Yes | QMessageBox.No | QMessageBox.Cancel) self.setDefaultButton(QMessageBox.Yes) def _make_save_or_not(self): self.setIconPixmap(self.quest_icon) self.setStandardButtons(QMessageBox.Save | QMessageBox.Discard | QMessageBox.Cancel) self.setDefaultButton(QMessageBox.Save) def _make_export_error(self): self.setIconPixmap(self.error_icon) self.setStandardButtons(QMessageBox.Close) self.setInformativeText('<i>Please fix then retry.</i>') def _make_export_warning(self): self.setIconPixmap(self.alert_icon) self.setStandardButtons(QMessageBox.Close) self.setInformativeText('<i>Press Details to see more.</i>')
class AboutKMB(QDialog): def __init__(self, parent=None): super().__init__(parent) # init components. self.header = QLabel(self) self.header_img = QPixmap(icon['COVER']) self.body = QLabel(self) self.foot = QLabel(self) self.git_link = QLabel(self) self.git_img = QLabel(self) self.github = QPixmap(icon['GIT']) # init configures. self.width = 500 self.height = 370 # compatible with Mac Retina screen. self.ratio = QApplication.desktop().screen().devicePixelRatio() if self.ratio == 1: self.github = self.github.scaled(32, 32) else: self.github.setDevicePixelRatio(self.ratio) self.font = QFont('monospace') # init UI. self.setup_ui() def setup_ui(self): # setup self ui. self.setFixedSize(self.width, self.height) self.setWindowFlag(Qt.FramelessWindowHint) # setup header img. self.header.setGeometry(0, 0, self.width, self.height // 3) self.header.setPixmap(self.header_img.scaled(self.width, self.width)) # setup body context. self.body.setGeometry(60, 80, self.width, self.height - 80) self.body.setFont(self.font) self.body.setText(""" <h1>Karken: KMB {}</h1> Created by <b>{}</b><br> License under <b>GNU General Public License v3.0</b> <p> Karken: KMB(Keras Model Builder) is a software based on Keras <br> functional API. Build your model easily and very convenient to <br> generate Python code. </p> <p> <b>Thanks</b> to Fullzoon_(:3」ㄥ)_ </p> """.format(__version__, __author__)) # setup foot context. self.foot.setGeometry(60, 310, self.width, 50) self.foot.setText("<i>Press any key to leave.</i>") # setup git link. self.git_link.setGeometry(320, 310, self.width, 50) self.git_link.setOpenExternalLinks(True) self.git_link.setText( '<a href="https://github.com/ShawnHXH/Karken-KMB">' 'View on GitHub</a>') # setup icon for github. self.git_img.setGeometry(420, 300, 64, 64) self.git_img.setPixmap(self.github) def __call__(self, *args, **kwargs): self.exec() def keyPressEvent(self, event): self.close() super().keyPressEvent(event)
class KMBNodeGraphicItem(QGraphicsPixmapItem): def __init__(self, node, name, sort, main_editor, parent=None): super().__init__(parent) self.node = node # the wrapper of itself self.name = name self.sort = sort self.main_editor = main_editor self.current_pos = None self.id_str = str(id(self)) self.z_value = 1 # compatible with Mac Retina screen. self.ratio = QApplication.desktop().screen().devicePixelRatio() if self.ratio == 2: self.pix = QPixmap(NODE_ICONx120_PATH.format(self.sort, self.name)) self.width = 60 self.height = 60 else: self.pix = QPixmap(NODE_ICONx85_PATH.format(self.sort, self.name)) self.width = 85 self.height = 85 self.pix.setDevicePixelRatio(self.ratio) self._arg_model = None # right menu for pin self.right_menu = QMenu() self.rm_pin = QIcon(icon['PIN_RM']) self.rm_pin_up = QIcon(icon['PIN_UPDATE']) # right menu for ref self.rm_token = QIcon(icon['TOKEN']) self.rm_free = QIcon(icon['FREE']) self._ref_item = None # right menu for io self.rm_input = QIcon(icon['INPUTS']) self.rm_output = QIcon(icon['OUTPUTS']) self._io_item = None self._io_edge_id = None self._ref_edge_id = None # text around item self.text = KMBNodeTextItem(self.name, self, self.height) # manager of pos attr, used only for animate. self.pos_manager = GrPosManager(self.pos()) self.pos_manager.POS_CHANGED.connect(self.setPos) self.setPixmap(self.pix) self.setFlag(QGraphicsItem.ItemIsSelectable) self.setFlag(QGraphicsItem.ItemIsMovable) self.setAcceptHoverEvents(True) self.setTransformationMode(Qt.SmoothTransformation) self.setCacheMode(QGraphicsItem.DeviceCoordinateCache) def __repr__(self): return f"<NodeGrItem {self.name} {id(self)}>" def set_pos(self, x, y): dis = self.width / 2 self.setPos(x - dis, y - dis) def move_to_pos(self, x: float, y: float): # move node to one pos with animation. # call by organize thread in athreads. move = QPropertyAnimation(self.pos_manager, b'pos', self.pos_manager) move.setDuration(600) move.setStartValue(self.pos()) move.setEndValue(QPointF(x, y)) move.setEasingCurve(QEasingCurve.OutQuart) # also update the edges that connect with. move.valueChanged.connect(self.node.update_connect_edges) move.start() self.is_modified() def is_modified(self): # send self modified state. self.main_editor.send_modify_state_to_main() def feed_args(self, dst_model): self._arg_model = dst_model def feed_ref(self, ref_item, edge_id): # get ref edge's (wrapper) start item. self._ref_item = ref_item self._ref_edge_id = edge_id def feed_io(self, io_item, edge_id): self._io_item = io_item # the id of edge wrapper. self._io_edge_id = edge_id def clean_feed(self): self._arg_model = None self._ref_item = None self._io_item = None self._io_edge_id = None self._ref_edge_id = None # ------------OVERRIDE METHODS-------------- def mousePressEvent(self, event): super().mousePressEvent(event) self.setZValue(self.z_value) self.z_value += 1 def mouseMoveEvent(self, event): super().mouseMoveEvent(event) self.is_modified() # update selected node and its edge for node in self.scene().scene.history.nodes.values(): if node.gr_node.isSelected(): node.update_connect_edges() def mouseReleaseEvent(self, event): super().mouseReleaseEvent(event) def hoverEnterEvent(self, event): self.text.appear() def hoverLeaveEvent(self, event): self.text.disappear() def contextMenuEvent(self, event): # add header title at right menu. header = self._make_a_main_header() self.right_menu.addAction(header) self.right_menu.addSeparator() # then add menu items. actions_list = self.get_context_menu() for actions in actions_list: self.right_menu.addActions(actions) self.right_menu.addSeparator() # show right menu. self.right_menu.exec(QCursor.pos()) # clean all after using. self.clean_feed() # ------------OPERATIONS ON RIGHT MENU-------------- def get_context_menu(self): """ Right menu all has three different contents: 1.For Layer node, right menu shows items that can be referenced. 2.For PlaceHolder or Units (etc.), menu shows items that already has been referenced. 3.For Model, menu shows inputs and outputs items. """ if self._arg_model.node_type == 'Layers': # case 1 return self._get_reference_table() elif self._arg_model.node_name == 'Model': # case 3 return self._get_model_io_table() else: # case 2 return self._get_referenced_table() def _get_reference_table(self): # for Layer node. can pin. def conditions() -> bool: """ Only show items that fulfill these conditions here for reference table on right menu. :return: True """ if arg_value.dtype == 'Reference': return True else: return False inh_actions = [] # actions for inherit args org_actions = [] # actions for original args for idx, arg_name, arg_value in self._arg_model.items(): if conditions(): # make a action with different state mark. if arg_value.is_referenced: action = QAction(self.rm_token, arg_name.text() + ' ~ ' + arg_value.var_name) action.setDisabled(True) else: action = QAction(self.rm_free, arg_name.text()) # only after dragging ref curve to a node # will get attribute: '_ref_item'. if self._ref_item is not None: self._pre_activate_ref_action(action, arg_name.text(), idx) # collect actions if idx <= self._arg_model.io_separator: inh_actions.append(action) else: org_actions.append(action) # add `add to pin` item. if self._ref_item is None: pin = self._make_a_pin_item() return inh_actions, org_actions, pin return inh_actions, org_actions def _get_referenced_table(self): # for PlaceHolder, Units and so on. actions_list = [] if self._arg_model.ref_by: for node_id, items in self._arg_model.ref_by.items(): var_name = self._arg_model.rb_semaphore.get_var_name(node_id) # make one block. sub_header = [self._make_a_sub_header(f'{var_name}')] actions = [QAction(self.rm_token, f' - {item.belong_to}') for item in items.values()] actions_list.append(sub_header + actions) # only Units can be pined. if self._arg_model.node_type == 'Units': pin = self._make_a_pin_item() actions_list.append(pin) return actions_list def _get_model_io_table(self): # especially for Model. cannot pin. inputs = [] outputs = [] for idx, arg_name, arg_value in self._arg_model.items(): item_name = arg_name.text() # sub header show with INPUTS. if item_name == 'model_name': sub = self._make_a_sub_header(f'Model Name: {arg_value.value}') inputs.append(sub) # also show the I/O items. if item_name == 'inputs' or item_name == 'outputs': action = QAction(item_name.upper()) # normally after right clicking on Model, # it will get all the I/O info. # but if it gets an I/O, then popup I/O to choose. if self._io_item is not None: self._pre_activate_io_action(action, item_name[0]) # collect item into different container. if item_name == 'inputs': action.setIcon(self.rm_input) inputs.append(action) else: action.setIcon(self.rm_output) outputs.append(action) # display the I/O items if have. if self._arg_model.io: i_items, o_items = self._arg_model.io for i_item in i_items.values(): i_action = self._make_a_sub_header(' ' * 6 + i_item.value) inputs.append(i_action) for o_item in o_items.values(): o_action = self._make_a_sub_header(' ' * 6 + o_item.value) outputs.append(o_action) return inputs, outputs def _make_a_main_header(self): """ The main header of popup right menu. """ if self._ref_item is not None: # it means this right menu is called after ref edge. # add custom sign at head. sign = QAction(f'Create reference ~ {self._ref_item.gr_name}') else: if self._arg_model.node_name == 'Model': sign = QAction(f'Model I/O Table') else: sign = QAction(f'Reference Table of <{self._arg_model.var_name}>') sign.setEnabled(False) return sign @classmethod def _make_a_sub_header(cls, msg: str): """ Use a disabled action to represent header. """ sub_header = QAction(msg) sub_header.setEnabled(False) return sub_header def _make_a_pin_item(self): # about pin actions. actions = [] # actions about pined node itself. if self.node.pin_id is not None: update = QAction(self.rm_pin_up, 'Update pin') update.triggered.connect(self._exec_update_pin_action) actions.append(update) # for those who are not be pined. else: pin = QAction(self.rm_pin, 'Add to pins') pin.triggered.connect(self._exec_add_pin_action) actions.append(pin) return actions def _pre_activate_ref_action(self, action, *args): """ If one item (also action) is ready to accept ref, then must pre-activate that action by setting different signals and functions. :return: One pre-activated action. """ def action_units_type_check() -> bool: """ Check whether this arg support this type. Usually, those args which accept the support_type, always contains the support_type. eg. activation <=accept Activations. bias_initializer <=accept Initializers. but always with plural form, so get rid of the 's'. """ if arg_name.__contains__(support_type[:-2]): return True return False def action_layer_type_check() -> bool: """ TimeDistributed and Bidirectional are able to have ref edges, but only available for arg `layer`. """ if arg_name == 'layer': return True return False arg_name, idx = args support_type = self._ref_item.gr_sort.lower() # if ref src is Units, then only few arg item can add ref. # or get the layer node that can accept other layer as its arg. # so here do some simple check. if self._ref_item.gr_type == 'Units': if not action_units_type_check(): action.setDisabled(True) elif self.name in ("TimeDistributed", "Bidirectional") and\ self._ref_item.gr_type == 'Layers': if not action_layer_type_check(): action.setDisabled(True) # signal field: # TYPE - DST_ID - SRC-ID - ARG_IDX - EDGE_ID action.setObjectName(f'REF-{self.id_str}' f'-{self._ref_item.gr_node.id_str}' f'-{idx}-{self._ref_edge_id}') action.triggered.connect(self.node.gr_scene.right_menu_listener) def _pre_activate_io_action(self, action, mark): """ Pre-activate IO action. """ # signal field: # TYPE - DST_ID - SRC-ID - SIGN - EDGE_ID action.setObjectName(f'IO-{self.id_str}' f'-{self._io_item.gr_node.id_str}' f'-{mark}-{self._io_edge_id}') # mark: 'i' is inputs, 'o' is outputs. action.triggered.connect(self.node.gr_scene.right_menu_listener) # ------------OPERATIONS ON PINS-------------- def _popup_input_dialog(self): # get pin item custom name before save. name, ok = QInputDialog.getText(self.main_editor, "Please input Pin Node name", "This node will be added in Pins with its arguments.") return name if ok else False # TODO: node after adding in pins. def _exec_add_pin_action(self): """ Execute Pin action here. Add item to Pin panel. """ pin_name = self._popup_input_dialog() # give up this operation if got cancel. if not pin_name: debug('[PIN] canceled.') return debug(f'[PIN] item => {pin_name}') # pin only save its changed args not referenced. write_custom_pin(pin_name, *self._arg_model.extract_pin()) def _exec_update_pin_action(self): """ Execute update pin action by its pin_id. """ update_custom_pin(self.node.pin_id, self._arg_model.extract_pin()[0]) debug(f'[PIN] item update successfully.')
def draw_icon(icon, rect, painter, icon_mode, shadow=False): cache = icon.pixmap(rect.size()) dip_offset = QPoint(1, -2) cache = QPixmap() pixname = "icon {0} {1} {2}".format(icon.cacheKey(), icon_mode, rect.height()) if QPixmapCache.find(pixname) is None: pix = icon.pixmap(rect.size()) device_pixel_ratio = pix.devicePixelRatio() radius = 3 * device_pixel_ratio offset = dip_offset * device_pixel_ratio cache = QPixmap(pix.size() + QSize(radius * 2, radius * 2)) cache.fill(Qt.transparent) cache_painter = QPainter(cache) if icon_mode == QIcon.Disabled: im = pix.toImage().convertToFormat(QImage.Format_ARGB32) for y in range(0, im.height()): scanline = im.scanLine(y) for x in range(0, im.width()): pixel = scanline intensity = qGray(pixel) scanline = qRgba(intensity, intensity, intensity, qAlpha(pixel)) scanline += 1 pix = QPixmap.fromImage(im) # Draw shadow tmp = QImage(pix.size() + QSize(radius * 2, radius * 2), QImage.Format_ARGB32_Premultiplied) tmp.fill(Qt.transparent) tmp_painter = QPainter(tmp) tmp_painter.setCompositionMode(QPainter.CompositionMode_Source) tmp_painter.drawPixmap( QRect(radius, radius, pix.width(), pix.height()), pix) tmp_painter.end() # Blur the alpha channel blurred = QImage(tmp.size(), QImage.Format_ARGB32_Premultiplied) blur_painter = QPainter(blurred) blur_painter.end() # tmp = blurred tmp_painter.begin(tmp) tmp_painter.setCompositionMode(QPainter.CompositionMode_SourceIn) tmp_painter.fillRect(tmp.rect(), QColor(0, 0, 0, 150)) tmp_painter.end() tmp_painter.begin(tmp) tmp_painter.setCompositionMode(QPainter.CompositionMode_SourceIn) tmp_painter.fillRect(tmp.rect(), QColor(0, 0, 0, 150)) tmp_painter.end() # Draw the blurred drop shadow cache_painter.drawImage( QRect(0, 0, cache.rect().width(), cache.rect().height()), tmp) # Draw the actual pixmap cache_painter.drawPixmap( QRect( QPoint(radius, radius) + offset, QSize(pix.width(), pix.height())), pix) cache_painter.end() cache.setDevicePixelRatio(device_pixel_ratio) QPixmapCache.insert(pixname, cache) target_rect = cache.rect() target_rect.setSize(target_rect.size() / cache.devicePixelRatio()) target_rect.moveCenter(rect.center() - dip_offset) painter.drawPixmap(target_rect, cache)
def scaledPixmap(path: str, scale: float) -> QPixmap: pixmap = QPixmap(path) if scale > 1.0: pixmap = pixmap.scaledToWidth(pixmap.width() * scale, Qt.SmoothTransformation) pixmap.setDevicePixelRatio(scale) return pixmap