def export(self, filename=None, add_margin=False): pw = QPdfWriter(filename) dpi = int(QApplication.primaryScreen().logicalDotsPerInch()) pw.setResolution(dpi) pw.setPageMargins(QMarginsF(0, 0, 0, 0)) size = QPageSize(self.getTargetRect().size()) pw.setPageSize(size) painter = QPainter(pw) try: self.setExportMode( True, { 'antialias': True, 'background': self.background, 'painter': painter }) painter.setRenderHint(QPainter.Antialiasing, True) painter.setRenderHint(QPainter.LosslessImageRendering, True) source_rect = self.getSourceRect() if add_margin: source_rect.setWidth(source_rect.width() + 25) self.getScene().render(painter, QRectF(self.getTargetRect()), QRectF(source_rect)) finally: self.setExportMode(False) painter.end()
def image_display(self): """ Update the ct_image to be displayed on the DICOM View. """ # Lead CT ct_pixmaps = self.pt_ct_dict_container.get( "ct_pixmaps_" + self.slice_view) slider_id = self.slider.value() ct_image = ct_pixmaps[slider_id].toImage() # Load PT pt_pixmaps = self.pt_ct_dict_container.get( "pt_pixmaps_" + self.slice_view) m = float(len(pt_pixmaps)) / len(ct_pixmaps) pt_image = pt_pixmaps[int(m * slider_id)].toImage() # Get alpha alpha = float(self.alpha_slider.value() / 100) # Merge Images painter = QPainter() painter.begin(ct_image) painter.setOpacity(alpha) painter.drawImage(0, 0, pt_image) painter.end() # Load merged images merged_pixmap = QtGui.QPixmap.fromImage(ct_image) label = QtWidgets.QGraphicsPixmapItem(merged_pixmap) self.scene = QtWidgets.QGraphicsScene() self.scene.addItem(label)
def paintEvent(self, event: QPaintEvent): outerRadius = min(self.width(), self.height()) baseRect = QRectF(1, 1, outerRadius - 2, outerRadius - 2) buffer = QImage(outerRadius, outerRadius, QImage.Format_ARGB32_Premultiplied) p = QPainter(buffer) p.setRenderHint(QPainter.Antialiasing) self.rebuildDataBrushIfNeeded() self.drawBackground(p, buffer.rect()) self.drawBase(p, baseRect) if self.m_value > 0: delta = (self.m_max - self.m_min) / (self.m_value - self.m_min) else: delta = 0 self.drawValue(p, baseRect, self.m_value, delta) innerRect, innerRadius = self.calculateInnerRect(outerRadius) self.drawInnerBackground(p, innerRect) self.drawText(p, innerRect, innerRadius, self.m_value) p.end() painter = QPainter(self) painter.fillRect(baseRect, self.palette().window()) painter.drawImage(0, 0, buffer)
def paintEvent(self, event): """ Paint the widget. """ super(WaTorGraph, self).paintEvent(event) painter = QPainter(self) fish, sharks = self._world.stats() shark = self.helper_calc_y_pos(sharks) fish = self.helper_calc_y_pos(fish) draw = ImageDraw.Draw(self._image) draw.line([(self._prev_tick, self._prev_shark), (self._tick, shark)], (0, 0, 255), 2) draw.line([(self._prev_tick, self._prev_fish), (self._tick, fish)], (0, 255, 0), 2) painter.drawImage(QPoint(0, 0), ImageQt(self._image)) painter.end() self._prev_tick = self._tick self._prev_shark = shark self._prev_fish = fish self._tick += 2 if self._tick >= self._widget_size.width(): self.reset()
def create_blue_green_rect(): pixmap = QPixmap(4, 2) painter = QPainter(pixmap) try: painter.fillRect(0, 0, 2, 2, QColor('blue')) painter.fillRect(2, 0, 2, 2, QColor('green')) finally: painter.end() return pixmap
def create_painter(self) -> typing.Iterator[QPainter]: white = QColor('white') pixmap = QPixmap(self.width, self.height) pixmap.fill(white) painter = QPainter(pixmap) try: yield painter finally: painter.end()
def paint_with_opacity(pixmap: QPixmap, opacity: float): transparent_image = QImage(QSize(36, 36), QImage.Format_ARGB32_Premultiplied) transparent_image.fill(Qt.transparent) painter = QPainter(transparent_image) painter.setOpacity(opacity) painter.drawPixmap(18 - pixmap.width() / 2, 18 - pixmap.height() / 2, pixmap) painter.end() return QPixmap.fromImage(transparent_image)
def paintEvent(self, event): size = self.size() # draw background painter = QPainter() painter.begin(self) painter.setRenderHint(QPainter.Antialiasing) painter.setPen(QColor(255, 255, 255, 255)) painter.setBrush(self.fill_color) painter.drawRect(0, 0, size.width(), size.height()) painter.end()
def slotPrintPreview(self): pix = QPixmap(1000, 200) pix.fill(Qt.white) painter = QPainter(pix) view.print(painter, pix.rect()) painter.end() label = QLabel(this) label.setPixmap(pix) label.show()
def assert_equal(self): __tracebackhide__ = True self.end() self.different_pixels = 0 actual_image: QImage = self.actual.device().toImage() expected_image: QImage = self.expected.device().toImage() diff_pixmap = QPixmap(actual_image.width(), actual_image.height()) diff = QPainter(diff_pixmap) try: white = QColor('white') diff.fillRect(0, 0, actual_image.width(), actual_image.height(), white) for x in range(actual_image.width()): for y in range(actual_image.height()): actual_colour = actual_image.pixelColor(x, y) expected_colour = expected_image.pixelColor(x, y) diff.setPen( self.diff_colour(actual_colour, expected_colour, x, y)) diff.drawPoint(x, y) finally: diff.end() diff_image: QImage = diff.device().toImage() display_diff(actual_image, diff_image, expected_image, self.different_pixels) if self.different_pixels == 0: return actual_image.save(str(self.work_dir / (self.name + '_actual.png'))) expected_image.save(str(self.work_dir / (self.name + '_expected.png'))) diff_path = self.work_dir / (self.name + '_diff.png') is_saved = diff_image.save(str(diff_path)) diff_width = self.diff_max_x - self.diff_min_x + 1 diff_height = self.diff_max_y - self.diff_min_y + 1 diff_section = QImage(diff_width, diff_height, QImage.Format_RGB32) diff_section_painter = QPainter(diff_section) try: diff_section_painter.drawPixmap(0, 0, diff_width, diff_height, QPixmap.fromImage(diff_image), self.diff_min_x, self.diff_min_y, diff_width, diff_height) finally: diff_section_painter.end() # To see an image dumped in the Travis CI log, copy the text from the # log, and paste it in test_pixmap_differ.test_decode_image. print(f'Encoded image of differing section ' f'({self.diff_min_x}, {self.diff_min_y}) - ' f'({self.diff_max_x}, {self.diff_max_y}):') print(encode_image(diff_section)) message = f'Found {self.different_pixels} different pixels, ' message += f'see' if is_saved else 'could not write' message += f' {diff_path.relative_to(Path(__file__).parent.parent)}.' assert self.different_pixels == 0, message
def export_arr(self, frame_index: int): self.scene.update_frame(frame_index) img = QImage(self.video_data.width, self.video_data.height, QImage.Format_ARGB32) painter = QPainter() painter.begin(img) self.scene.render(painter) painter.end() shape = (img.height(), img.bytesPerLine() * 8 // img.depth(), 4) ptr = img.bits() arr = np.array(ptr, dtype=np.uint8).reshape(shape) arr = arr[..., :3] return arr
def create_icon(player_colour: QColor) -> QPixmap: size = 200 icon = QPixmap(size, size) icon.fill(Qt.transparent) painter = QPainter(icon) try: painter.setBrush(player_colour) pen = QPen() pen.setWidth(3) painter.setPen(pen) painter.drawEllipse(1, 1, size - 2, size - 2) finally: painter.end() return icon
def show_synced(self, is_sync: bool) -> None: p1 = QPixmap(self.icon().pixmap(self.icon().actualSize(QSize(1024, 1024)))) p2 = self.get_icon(is_sync) mode = QPainter.CompositionMode_SourceOver s = p1.size().expandedTo(p2.size()) result = QPixmap(s) result.fill(Qt.transparent) painter = QPainter(result) painter.setRenderHint(QPainter.Antialiasing) painter.drawPixmap(QPoint(), p1) painter.setCompositionMode(mode) painter.drawPixmap(result.rect(), p2, p2.rect()) painter.end() self.setIcon(QIcon(result))
def paintEvent(self, event): """ Paint the widget. """ super(WaTorWidget, self).paintEvent(event) painter = QPainter(self) for y in range(self._size.height()): for x in range(self._size.width()): pos = QPoint(x, y) * self._scale painter.drawPixmap(pos, self._water.pixmap) for pos, mob in self._world.mobs.items(): painter.drawPixmap(pos * self._scale, mob.pixmap) painter.end()
def __init__(self): # Sidebar icons are 28x28 points. Should be at least 56x56 pixels for # HiDPI display compatibility. They will be automatically made theme # aware, so you need only provide a grayscale image, where white is # the color of the shape. icon = QImage(56, 56, QImage.Format_RGB32) icon.fill(0) # Render an "H" as the example icon p = QPainter() p.begin(icon) p.setFont(QFont("Open Sans", 56)) p.setPen(QColor(255, 255, 255, 255)) p.drawText(QRectF(0, 0, 56, 56), Qt.AlignCenter, "H") p.end() SidebarWidgetType.__init__(self, icon, "Hello")
def assert_equal(self): __tracebackhide__ = True self.end() self.different_pixels = 0 actual_image: QImage = self.actual.device().toImage() expected_image: QImage = self.expected.device().toImage() diff_pixmap = QPixmap(actual_image.width(), actual_image.height()) diff = QPainter(diff_pixmap) try: white = QColor('white') diff.fillRect(0, 0, actual_image.width(), actual_image.height(), white) for x in range(actual_image.width()): for y in range(actual_image.height()): actual_colour = actual_image.pixelColor(x, y) expected_colour = expected_image.pixelColor(x, y) diff.setPen( self.diff_colour(actual_colour, expected_colour, x, y)) diff.drawPoint(x, y) finally: diff.end() diff_image: QImage = diff.device().toImage() display_diff(actual_image, diff_image, expected_image, self.different_pixels) if self.different_pixels == 0: return actual_image.save(str(self.work_dir / (self.name + '_actual.png'))) expected_image.save(str(self.work_dir / (self.name + '_expected.png'))) diff_path = self.work_dir / (self.name + '_diff.png') is_saved = diff_image.save(str(diff_path)) diff_width = self.diff_max_x - self.diff_min_x + 1 diff_height = self.diff_max_y - self.diff_min_y + 1 diff_section = QImage(diff_width, diff_height, QImage.Format_RGB32) diff_section_painter = QPainter(diff_section) try: diff_section_painter.drawPixmap(0, 0, diff_width, diff_height, QPixmap.fromImage(diff_image), self.diff_min_x, self.diff_min_y, diff_width, diff_height) finally: diff_section_painter.end() message = f'Found {self.different_pixels} different pixels.' assert self.different_pixels == 0, message
def main(): parser = parse_args() pov_file: Path = parser.pov_file stem = pov_file.stem shadow_stem = re.sub(r'-(\d+)$', r'-shadow-\1', stem) temp_file = pov_file.parent / (stem + '-temp.png') temp_shadow_file = pov_file.parent / (shadow_stem + '-temp.png') png_file = pov_file.parent / (shadow_stem + '.png') current_images = Path(__file__).parent.parent / 'shibumi_images' current_file = current_images / png_file.name if current_file.exists(): png_file = current_file args = ['povray', '-D', f'+I{pov_file}', '+V', '-W640', '-H480', '+ua', f'+O{temp_file}'] run(args, check=True) app = QApplication() images_path = Path(__file__).parent shadow_file = images_path / 'ball-r-shadow-1.png' shadow = QPixmap(str(shadow_file)) rendered = QPixmap(str(temp_file)) cropped = rendered.copy(120, 20, 400, 400) scaled = cropped.scaled(98, 102, Qt.KeepAspectRatio, Qt.SmoothTransformation) painter = QPainter(shadow) try: painter.drawPixmap(7, 2, scaled) finally: painter.end() assert app shadow.save(str(temp_shadow_file), 'png') temp_file.unlink() temp_shadow_file.rename(png_file) print(f'Generated {png_file} from {pov_file}.')
def paint_puzzle(self, writer: QPaintDevice): self.check_clues() painter = QPainter(writer) try: print_shuffler = ArtShuffler(self.art_shuffler.rows, self.art_shuffler.cols, writer, QRect(0, 0, writer.width(), round(writer.height() / 2)), clues=self.clues, row_clues=self.row_clues, column_clues=self.column_clues) print_shuffler.cells = self.art_shuffler.cells[:] print_shuffler.is_shuffled = self.art_shuffler.is_shuffled selected_pixmap = self.get_selected_pixmap() print_shuffler.draw(selected_pixmap, painter) print_shuffler.rect.moveTop(writer.height() / 2) print_shuffler.draw_grid(selected_pixmap, painter) finally: painter.end()
def setIcons(self) -> None: settings = QSettings() colored = str(settings.value('iconColors', 'True')) == 'True' self._icons: Dict[str, QIcon] = {} pixmap = QPixmap(str(getRuntimePath('resources/icons/dia.ico'))) painter = QPainter(pixmap) painter.setCompositionMode(QPainter.CompositionMode_SourceIn) painter.fillRect(pixmap.rect(), QColor('#427aa1') if colored else QColor('#333333')) painter.end() self._icons['mod'] = QIcon(pixmap) pixmap = QPixmap(str(getRuntimePath('resources/icons/puzzle.ico'))) painter = QPainter(pixmap) painter.setCompositionMode(QPainter.CompositionMode_SourceIn) painter.fillRect(pixmap.rect(), QColor('#aad576') if colored else QColor('#333333')) painter.end() self._icons['dlc'] = QIcon(pixmap) pixmap = QPixmap(str(getRuntimePath('resources/icons/folder.ico'))) painter = QPainter(pixmap) painter.setCompositionMode(QPainter.CompositionMode_SourceIn) painter.fillRect(pixmap.rect(), QColor('#E55934') if colored else QColor('#333333')) painter.end() self._icons['bin'] = QIcon(pixmap) pixmap = QPixmap(str(getRuntimePath('resources/icons/patch.ico'))) painter = QPainter(pixmap) painter.setCompositionMode(QPainter.CompositionMode_SourceIn) painter.fillRect(pixmap.rect(), QColor('#b08968') if colored else QColor('#333333')) painter.end() self._icons['pat'] = QIcon(pixmap) pixmap = QPixmap(str(getRuntimePath('resources/icons/question.ico'))) painter = QPainter(pixmap) painter.setCompositionMode(QPainter.CompositionMode_SourceIn) painter.fillRect(pixmap.rect(), QColor('#ffcf40') if colored else QColor('#333333')) painter.end() self._icons['udf'] = QIcon(pixmap)
def paintEvent(self, event): painter = QPainter(self) painter.fillRect(event.rect(), self.numberBarColor) block = self.editor.firstVisibleBlock() # Iterate over all visible text blocks in the document. while block.isValid(): blockNumber = block.blockNumber() block_top = self.editor.blockBoundingGeometry( block).translated(self.editor.contentOffset()).top() # Check if the position of the block is out side of the visible area. if not block.isVisible() or block_top >= event.rect().bottom(): break # We want the line number for the selected line to be bold. if blockNumber == self.editor.textCursor().blockNumber(): self.font.setBold(True) painter.setPen(bnstyles["blockSelected"]) else: self.font.setBold(False) painter.setPen(bnstyles["blockNormal"]) painter.setFont(self.font) # Draw the line number right justified at the position of the line. paint_rect = QRect(0, block_top, self.width(), self.editor.fontMetrics().height()) painter.drawText(paint_rect, Qt.AlignLeft, str(blockNumber + 1)) block = block.next() painter.end() QWidget.paintEvent(self, event)
def paintEvent(self, event): super(MouseEventMixin, self).paintEvent(event) if not self.__image: return if self.__image.height() == 0 or self.height( ) == 0 or self.__image.width() == 0: return image_aspect_ratio = self.__image.width() / self.__image.height() view_aspect_ratio = self.width() / self.height() if view_aspect_ratio <= image_aspect_ratio: image_height = self.width() / image_aspect_ratio rect = QRectF(0, (self.height() - image_height) / 2, self.width(), image_height) else: image_widh = self.height() * image_aspect_ratio rect = QRectF((self.width() - image_widh) / 2, 0, image_widh, self.height()) painter = QPainter(self.viewport()) painter.drawImage(rect, self.__image) painter.end()
def setupMenu(self) -> None: self.setMenuBar(QMenuBar(self)) settings = QSettings() # mods menu menuMods: QMenu = self.menuBar().addMenu('&Mods') downIcon = QIcon(str(getRuntimePath('resources/icons/down.ico'))) gearIcon = QIcon(str(getRuntimePath('resources/icons/gear.ico'))) dirsIcon = QIcon(str( getRuntimePath('resources/icons/open-folder.ico'))) colrIcon = QIcon( str(getRuntimePath('resources/icons/color-circle.ico'))) smilIcon = QIcon(str(getRuntimePath('resources/icons/smile.ico'))) actionAddModFromFile = menuMods.addAction('&Add Mods') actionAddModFromFile.triggered.connect(self.showAddModFromFileDialog) actionAddModFromFolder = menuMods.addAction('Add u&npacked Mod') actionAddModFromFolder.triggered.connect( self.showAddModFromFolderDialog) actionDownloadMod = menuMods.addAction('&Download Mod') actionDownloadMod.setIcon(downIcon) actionDownloadMod.triggered.connect(self.showDownloadModDialog) menuMods.addSeparator() actionGetInfo = menuMods.addAction('Update Mod de&tails') actionGetInfo.setIcon(downIcon) actionGetInfo.triggered.connect(self.showGetInfoDialog) actionGetUpdates = menuMods.addAction('Check for Mod &updates') actionGetUpdates.setIcon(downIcon) actionGetUpdates.triggered.connect(self.showGetUpdatesDialog) menuMods.addSeparator() actionExport = menuMods.addAction('&Export Modlist') actionExport.triggered.connect(self.showExportDialog) menuMods.aboutToShow.connect(lambda: [ actionDownloadMod.setDisabled(not str(settings.value('nexusAPIKey'))), actionGetInfo.setDisabled( not str(settings.value('nexusAPIKey')) or \ not len(self.model) or \ not self.mainwidget.modlist.selectionModel().hasSelection()), actionGetUpdates.setDisabled( not str(settings.value('nexusAPIKey')) or \ not len(self.model) or \ not self.mainwidget.modlist.selectionModel().hasSelection()), actionExport.setDisabled(not len(self.model)) ]) # view menu menuView: QMenu = self.menuBar().addMenu('&View') showSummary = menuView.addAction('Show &Summary') showSummary.setCheckable(True) showSummary.setChecked(settings.value('showSummary', 'True') == 'True') showSummary.triggered.connect(lambda checked: [ settings.setValue('showSummary', str(checked)), self.mainwidget.summary.setVisible(checked) ]) menuView.addSeparator() toggleHighlightNewest = menuView.addAction('Highlight &Newest') toggleHighlightNewest.setCheckable(True) toggleHighlightNewest.setChecked( settings.value('highlightNewest', 'True') == 'True') toggleHighlightNewest.triggered.connect(lambda checked: [ settings.setValue('highlightNewest', str(checked)), self.model.updateCallbacks.fire(self.model) ]) iconHighlightNewest = QPixmap(256, 256) iconHighlightNewest.fill(Qt.transparent) painter = QPainter(iconHighlightNewest) painter.setBrush(QBrush(QColor(222, 255, 222))) painter.drawEllipse(10, 10, 236, 236) toggleHighlightNewest.setIcon(QIcon(iconHighlightNewest)) painter.end() toggleHighlightRecent = menuView.addAction('Highlight &Recent') toggleHighlightRecent.setCheckable(True) toggleHighlightRecent.setChecked( settings.value('highlightRecent', 'True') == 'True') toggleHighlightRecent.triggered.connect(lambda checked: [ settings.setValue('highlightRecent', str(checked)), self.model.updateCallbacks.fire(self.model) ]) iconHighlightRecent = QPixmap(256, 256) iconHighlightRecent.fill(Qt.transparent) painter = QPainter(iconHighlightRecent) painter.setBrush(QBrush(QColor(222, 226, 255))) painter.drawEllipse(10, 10, 236, 236) toggleHighlightRecent.setIcon(QIcon(iconHighlightRecent)) painter.end() toggleHighlightUnmanaged = menuView.addAction('Highlight &Unmanaged') toggleHighlightUnmanaged.setCheckable(True) toggleHighlightUnmanaged.setChecked( settings.value('highlightUnmanaged', 'True') == 'True') toggleHighlightUnmanaged.triggered.connect(lambda checked: [ settings.setValue('highlightUnmanaged', str(checked)), self.model.updateCallbacks.fire(self.model) ]) iconHighlightUnmanaged = QPixmap(256, 256) iconHighlightUnmanaged.fill(Qt.transparent) painter = QPainter(iconHighlightUnmanaged) painter.setBrush(QBrush(QColor(250, 220, 220))) painter.drawEllipse(10, 10, 236, 236) toggleHighlightUnmanaged.setIcon(QIcon(iconHighlightUnmanaged)) painter.end() toggleHighlightDisabled = menuView.addAction('Highlight &Disabled') toggleHighlightDisabled.setCheckable(True) toggleHighlightDisabled.setChecked( settings.value('highlightDisabled', 'True') == 'True') toggleHighlightDisabled.triggered.connect(lambda checked: [ settings.setValue('highlightDisabled', str(checked)), self.model.updateCallbacks.fire(self.model) ]) iconHighlightDisabled = QPixmap(256, 256) iconHighlightDisabled.fill(Qt.transparent) painter = QPainter(iconHighlightDisabled) painter.setBrush(QBrush(QColor(230, 230, 230))) painter.drawEllipse(10, 10, 236, 236) toggleHighlightDisabled.setIcon(QIcon(iconHighlightDisabled)) painter.end() menuView.addSeparator() toggleColors = menuView.addAction('&Colored Icons') toggleColors.setCheckable(True) toggleColors.setChecked(settings.value('iconColors', 'True') == 'True') toggleColors.triggered.connect(lambda checked: [ settings.setValue('iconColors', str(checked)), self.mainwidget.modlist.listmodel.setIcons(), self.model.updateCallbacks.fire(self.model) ]) toggleColors.setIcon(colrIcon) menuView.addSeparator() toggleCompact = menuView.addAction('Compact &Mode') toggleCompact.setCheckable(True) toggleCompact.setChecked( settings.value('compactMode', 'False') == 'True') toggleCompact.triggered.connect(lambda checked: [ settings.setValue('compactMode', str(checked)), self.mainwidget.modlist.setSectionSize(checked) ]) # settings menu menuSettings: QMenu = self.menuBar().addMenu('&Tools') actionSettings = menuSettings.addAction('&Settings') actionSettings.setIcon(gearIcon) actionSettings.triggered.connect(self.showSettingsDialog) menuSettings.addSeparator() actionOpenGameDirectory = menuSettings.addAction( 'Open &Game directory') actionOpenGameDirectory.setIcon(dirsIcon) actionOpenGameDirectory.triggered.connect( lambda: util.openDirectory(self.model.gamepath)) actionOpenConfigDirectory = menuSettings.addAction( 'Open &Config directory') actionOpenConfigDirectory.setIcon(dirsIcon) actionOpenConfigDirectory.triggered.connect( lambda: util.openDirectory(self.model.configpath)) # info menu menuInfo: QMenu = self.menuBar().addMenu('&Info') actionFeedback = menuInfo.addAction('Send &Feedback') actionFeedback.setIcon(smilIcon) actionFeedback.triggered.connect( lambda: QDesktopServices.openUrl(QUrl(w3modmanager.URL_ISSUES))) menuInfo.addSeparator() actionAbout = menuInfo.addAction('&About') actionAbout.setIcon(QIcon.fromTheme('document-open')) actionAbout.triggered.connect(self.showAboutDialog)
def paintEvent(self, pe) -> None: if not self.inhibit_paint: extent = 1.5 * np.pi offset = 1.25 * np.pi painter = QPainter(self) # So that we can use the background color painter.setBackgroundMode(Qt.OpaqueMode) # Smooth out the circle painter.setRenderHint(QPainter.Antialiasing) # Use background color bgColor = painter.background().color() painter.setBrush(painter.background()) if self._text not in implementedKnobs: painter.setBrush(QtGui.QBrush(QtGui.QColor(int("0xcccccc", 0)))) # Store color from stylesheet, pen will be overridden pointColor = QColor(painter.pen().color()) # print(QDial.width(self), QDial.height(self)) # draw widget borders pen = QPen(QColor(self._ringColor), 1) pen.setCapStyle(Qt.SquareCap) painter.setPen(pen) # uncomment the following line to draw outer rect # painter.drawRect(0, 0, np.floor(QDial.width(self)), QDial.height(self)) # No border painter.setPen(QPen(Qt.NoPen)) # the heignt of the widget is 2*radius + 2*fontsize1 + 2*fontsize2 # where fontsize1 = .4radius and fontsize2 = .9*.4*radius # so QDial.height = radius * (2+.4*2+.4*.9*2) # fontsize1factor = .4 fontsize2reduction = .9 fontsize2factor = fontsize1factor * fontsize2reduction center_x = QDial.width(self) / 2.0 center_y = QDial.height(self) / 2.0 if not self._hasFixedSize: if not self._hasFixedFontSize: radius = np.min( (QDial.width(self) / 2. - self._knobMargin, QDial.height(self) / (2. + 2 * fontsize1factor + 2 * fontsize2factor) - self._knobMargin)) radius = np.max((radius, 1)) # print("Radius = ", radius, ", height = ", QDial.height(self), ", width = ", QDial.width(self)) center_y = center_y - radius * (fontsize1factor + fontsize2factor) else: radius = np.min( (QDial.width(self) / 2. - self._knobMargin, (QDial.height(self) - 4 * self._fixedFontSize) / 2. - self._knobMargin)) radius = np.max((radius, 1)) center_y = center_y - (self._fixedFontSize * (1 + fontsize2reduction)) else: radius = self._fixedSize / 2. radius = np.max((radius, 1)) center_y = center_y - radius * (fontsize1factor + fontsize2factor) self.radius = radius # Draw arc rectangle = QtCore.QRectF(center_x - radius, center_y - radius, 2 * radius, 2 * radius) """The startAngle and spanAngle must be specified in 1/16th of a degree, i.e. a full circle equals 5760 (16 * 360). Positive values for the angles mean counter-clockwise while negative values mean the clockwise direction. Zero degrees is at the 3 o'clock position.""" linewidth = radius / 30. * 2 # linewidth = 1 pen = QPen(QColor(self._ringColor), linewidth) pen.setCapStyle(Qt.RoundCap) # pen.setCapStyle(Qt.FlatCap) painter.setPen(pen) # adapt to linewidth to make it more pleasant to the eye capRadius = linewidth / 4 angleCap = np.arcsin(capRadius / radius) start_deg = (90 - np.rad2deg(extent / 2)) + np.rad2deg(angleCap) start_16deg = start_deg * 16 extent_deg = np.rad2deg(extent) - 2 * np.rad2deg(angleCap) extent_16deg = extent_deg * 16 painter.drawArc(rectangle, start_16deg, extent_16deg) #draw inner circle pen = QPen(QColor(pointColor), linewidth) pen.setCapStyle(Qt.RoundCap) painter.setPen(pen) painter.setBrush(QtGui.QColor(bgColor)) radius_inner = 15. / 20. * radius painter.drawEllipse(QtCore.QPointF(center_x, center_y), radius_inner, radius_inner) self.center = QtCore.QPointF(center_x, center_y) """ # Get ratio between current value and maximum to calculate angle if (param != NULL): if (param->value != this->value()) param->setValue(this->value()) """ ratio = (QDial.value(self) - QDial.minimum(self)) / ( QDial.maximum(self) - QDial.minimum(self)) # The maximum amount of degrees is 270, offset by 225 angle = ratio * extent - offset # Draw the indicator painter.setBrush(QBrush(pointColor)) a_y = center_y + np.sin(angle) * (radius - .1) a_x = center_x + np.cos(angle) * (radius - .1) pen = QPen(pointColor, linewidth) pen.setCapStyle(Qt.RoundCap) painter.setPen(pen) painter.drawLine(a_x, a_y, np.round(center_x), center_y) if not self._hasFixedFontSize: fontsize1 = radius * fontsize1factor if self.sizeType == 1 and fontsize1 != Knob.fontsize1: Knob.fontsize1 = fontsize1 else: fontsize1 = Knob.fontsize1 fontsize2 = fontsize1 * fontsize2reduction else: fontsize1 = self._fixedFontSize fontsize2 = fontsize1 * fontsize2reduction self.fontsize1 = fontsize1 textRect_ = QtCore.QRectF(0, center_y + radius, QDial.width(self), 2 * fontsize1) if self.coloredTitle: painter.setPen(QColor(int(titleColor, 0))) f = painter.font() f.setPointSizeF(fontsize1) painter.setFont(f) # painter.drawRect(textRect_) painter.drawText(textRect_, Qt.AlignHCenter | Qt.AlignTop, self._text) # painter.drawText(textRect_, Qt.AlignHCenter | Qt.AlignTop, str(fontsize1)) textRect_ = QtCore.QRectF(0, center_y + radius + fontsize1 * 2, QDial.width(self), 2 * fontsize2) if self.hasFocus(): painter.setPen(QtGui.QColor("red")) f.setPointSizeF(fontsize2) painter.setFont(f) # painter.drawRect(textRect_) painter.drawText(textRect_, Qt.AlignHCenter | Qt.AlignTop, str(QDial.value(self))) painter.end()
class ScreenSelection(QtWidgets.QGroupBox): def __init__(self, parent: DisplayCalibration): QtWidgets.QGroupBox.__init__(self, 'Fullscreen selection (double click)') self.main = parent self.setSizePolicy(QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Expanding) self.painter = QPainter() def mouseDoubleClickEvent(self, ev, *args, **kwargs): for screen_id, screen_coords in enumerate( self._get_widget_screen_coords()): rect = QtCore.QRectF(*screen_coords) if not rect.contains(QtCore.QPoint(ev.pos().x(), ev.pos().y())): continue print(f'Set display to fullscreen on screen {screen_id}') screen = access.application.screens()[screen_id] px_ratio = screen.devicePixelRatio() self.main.global_settings.screen_id.set_value(screen_id) self.main.global_settings.win_x_pos.set_value( screen.geometry().x()) self.main.global_settings.win_y_pos.set_value( screen.geometry().y()) self.main.global_settings.win_width.set_value( int(screen.geometry().width() * px_ratio)) self.main.global_settings.win_height.set_value( int(screen.geometry().height() * px_ratio)) access.application.processEvents() @staticmethod def _get_norm_screen_coords() -> np.ndarray: # Get connected screens avail_screens = access.application.screens() # Calculate total display area bounding box area = [[ s.geometry().width() * s.devicePixelRatio(), s.geometry().height() * s.devicePixelRatio() ] for s in avail_screens] area = np.sum(area, axis=0) xmin = np.min([s.geometry().x() for s in avail_screens]) ymin = np.min([s.geometry().y() for s in avail_screens]) # Define normalization functions xnorm = lambda x: (x - xmin) / area[0] ynorm = lambda y: (y - ymin) / area[1] # Add screen dimensions screens = [] for s in avail_screens: g = s.geometry() screens.append([ xnorm(g.x() * s.devicePixelRatio()), # x ynorm(g.y() * s.devicePixelRatio()), # y xnorm(g.width() * s.devicePixelRatio()), # width ynorm(g.height() * s.devicePixelRatio()) ]) # height return np.array(screens) def _get_widget_screen_coords(self): s = self._get_norm_screen_coords() s[:, 0] *= self.size().width() s[:, 1] *= self.size().height() s[:, 2] *= self.size().width() s[:, 3] *= self.size().height() return s.astype(int) def paintEvent(self, QPaintEvent): for i, screen in enumerate(self._get_widget_screen_coords()): rect = QtCore.QRect(*screen) self.painter.begin(self) self.painter.setBrush(QtCore.Qt.BrushStyle.Dense4Pattern) self.painter.drawRect(rect) self.painter.setPen(QColor(168, 34, 3)) self.painter.setFont(QFont('Decorative', 30)) self.painter.drawText(rect, QtCore.Qt.AlignmentFlag.AlignCenter, str(i)) self.painter.end()
def paintEvent(self, event): paint = QPainter() paint.begin(self) paint.save() size = self.size() width = size.width() height = size.height() units = self.data.get('units') proportion = self.getProportion() horizontalOrientation = self.data.get('horizontal_orientation') if horizontalOrientation: rulerLength = width traceLengthLimit = height else: # vertical orientation rulerLength = height traceLengthLimit = width paint.translate(width, 0) paint.rotate(90) # the length of the traces (lines) small = traceLengthLimit / 6 medium = traceLengthLimit / 4 large = traceLengthLimit / 3 limit = rulerLength / proportion # draw less lines for centimeters if units == 'cm': step = 10 else: step = 5 # begin drawing fontSize = 10 font = QFont('Serif', fontSize) fontMetrics = QFontMetrics(font) # draw background background = self.data.get('background_color') paint.fillRect(0, 0, rulerLength, traceLengthLimit, background) # draw the lines paint.setPen(self.data.get('lines_color')) paint.setFont(font) # the builtin range() doesn't support floats def float_range(current, end, rangeStep): while current < end: yield current current += rangeStep # we skip 0 and start in the first step, since there's no point in drawing the first line/text (it would appear cut off, since we're at the limit) for a in float_range(step, limit, step): position = a * proportion if (a % 100) == 0: lineLength = large if units == 'px': text = '{}{}'.format(str(a), units) else: text = '{}{}'.format(str(int(a / 100)), units) textWidth = fontMetrics.boundingRect(text).width() paint.drawText(position - textWidth / 2, traceLengthLimit / 2 + fontSize / 2, text) elif (a % 50) == 0: lineLength = large # since 'cm' has a different step compared to the other units if units == 'cm': lineLength = medium elif (a % 25) == 0: lineLength = medium else: lineLength = small paint.drawLine(position, 0, position, lineLength) paint.drawLine(position, traceLengthLimit, position, traceLengthLimit - lineLength) # paint the division lines if self.data.get('division_lines'): paint.setPen(self.data.get('divisions_color')) halfPoint = rulerLength / 2 quarterPoint = rulerLength / 4 threeQuarterPoint = 3 / 4 * rulerLength paint.drawLine(quarterPoint, 0, quarterPoint, traceLengthLimit) paint.drawLine(halfPoint, 0, halfPoint, traceLengthLimit) paint.drawLine(threeQuarterPoint, 0, threeQuarterPoint, traceLengthLimit) paint.restore() paint.end()
def test_board_size_3(pixmap_differ: PixmapDiffer): actual: QPainter expected: QPainter with pixmap_differ.create_painters(240, 240, 'margo_board_size_3') as (actual, expected): expected_scene = QGraphicsScene(0, 0, 240, 240) full_board = MargoDisplay.load_pixmap('board-1.png') width = full_board.width() height = full_board.height() top_height = round(height * 0.28) mid_height = round(height * 0.21) bottom_height = round(height * 0.29) left_width = round(width * 0.28) mid_width = round(width * 0.22) right_width = round(width * 0.279) assembled_board = QPixmap(left_width + mid_width + right_width, top_height + mid_height + bottom_height) assembled_board.fill(Qt.transparent) assembled_painter = QPainter(assembled_board) # top left assembled_painter.drawPixmap(0, 0, left_width, top_height, full_board, 0, 0, left_width, top_height) # top middle assembled_painter.drawPixmap(left_width, 0, mid_width, top_height, full_board, left_width, 0, mid_width, top_height) # top right assembled_painter.drawPixmap(left_width + mid_width, 0, right_width, top_height, full_board, width - right_width, 0, right_width, top_height) # left middle assembled_painter.drawPixmap(0, top_height, left_width, mid_height, full_board, 0, top_height, left_width, mid_height) # middle middle assembled_painter.drawPixmap(left_width, top_height, mid_width, mid_height, full_board, left_width, top_height, mid_width, mid_height) # right middle assembled_painter.drawPixmap(left_width + mid_width, top_height, right_width, mid_height, full_board, width - right_width, top_height, right_width, mid_height) # bottom left assembled_painter.drawPixmap(0, top_height + mid_height, left_width, bottom_height, full_board, 0, height - bottom_height, left_width, bottom_height) # bottom middle assembled_painter.drawPixmap(left_width, top_height + mid_height, mid_width, bottom_height, full_board, left_width, height - bottom_height, mid_width, bottom_height) # bottom right assembled_painter.drawPixmap(left_width + mid_width, top_height + mid_height, right_width, bottom_height, full_board, width - right_width, height - bottom_height, right_width, bottom_height) assembled_painter.end() scaled_board = assembled_board.scaled(240, 240, Qt.KeepAspectRatio, Qt.SmoothTransformation) board_item = expected_scene.addPixmap(scaled_board) board_item.setPos(2, 0) white_ball = MargoDisplay.load_pixmap('ball-w-shadow-1.png', QSize(76, 76)) black_ball = MargoDisplay.load_pixmap('ball-b-shadow-1.png', QSize(76, 76)) expected_scene.addPixmap(white_ball).setPos(15, 145) expected_scene.addPixmap(black_ball).setPos(81, 79) expected_scene.render(expected) display = MargoDisplay(size=3) display.resize(348, 264) board_text = """\ A C E 5 . . . 5 3 . B . 3 1 W . . 1 A C E >B """ display.update_board(SpargoState(board_text, size=3)) render_display(display, actual)
class PixmapDiffer: def __init__(self): self.name = None self.actual_pixmap = self.expected_pixmap = None self.actual = self.expected = None self.different_pixels = 0 self.diff_min_x = self.diff_min_y = None self.diff_max_x = self.diff_max_y = None self.max_diff = 0 self.names = set() self.work_dir: Path = (Path(__file__).parent.parent / 'tests' / 'pixmap_diffs') self.work_dir.mkdir(exist_ok=True) for work_file in self.work_dir.iterdir(): if work_file.name == 'README.md': continue assert work_file.suffix == '.png', work_file work_file.unlink() @contextmanager def create_painters(self, width: int, height: int, name: str, max_diff: int = 0 ) -> typing.Iterator[typing.Tuple[QPainter, QPainter]]: self.max_diff = max_diff try: yield self.start(width, height, name) finally: self.end() self.assert_equal() def start(self, width: int, height: int, name: str) -> typing.Tuple[QPainter, QPainter]: """ Create painters for the actual and expected images. Caller must either call end() or assert_equal() to properly clean up the painters and pixmaps. Caller may either paint through the returned painters, or call the end() method and create a new painter on the same device. Order matters, though! """ assert name not in self.names, f'Duplicate name: {name!r}.' self.names.add(name) self.name = name white = QColor('white') self.actual_pixmap = QPixmap(width, height) self.actual_pixmap.fill(white) self.actual = QPainter(self.actual_pixmap) self.expected_pixmap = QPixmap(width, height) self.expected_pixmap.fill(white) self.expected = QPainter(self.expected_pixmap) return self.actual, self.expected def end(self): if self.actual and self.actual.isActive(): self.actual.end() if self.expected and self.expected.isActive(): self.expected.end() def assert_equal(self): __tracebackhide__ = True self.end() self.different_pixels = 0 actual_image: QImage = self.actual.device().toImage() expected_image: QImage = self.expected.device().toImage() diff_pixmap = QPixmap(actual_image.width(), actual_image.height()) diff = QPainter(diff_pixmap) try: white = QColor('white') diff.fillRect(0, 0, actual_image.width(), actual_image.height(), white) for x in range(actual_image.width()): for y in range(actual_image.height()): actual_colour = actual_image.pixelColor(x, y) expected_colour = expected_image.pixelColor(x, y) diff.setPen( self.diff_colour(actual_colour, expected_colour, x, y)) diff.drawPoint(x, y) finally: diff.end() diff_image: QImage = diff.device().toImage() display_diff(actual_image, diff_image, expected_image, self.different_pixels) if self.different_pixels == 0: return actual_image.save(str(self.work_dir / (self.name + '_actual.png'))) expected_image.save(str(self.work_dir / (self.name + '_expected.png'))) diff_path = self.work_dir / (self.name + '_diff.png') is_saved = diff_image.save(str(diff_path)) diff_width = self.diff_max_x - self.diff_min_x + 1 diff_height = self.diff_max_y - self.diff_min_y + 1 diff_section = QImage(diff_width, diff_height, QImage.Format_RGB32) diff_section_painter = QPainter(diff_section) try: diff_section_painter.drawPixmap(0, 0, diff_width, diff_height, QPixmap.fromImage(diff_image), self.diff_min_x, self.diff_min_y, diff_width, diff_height) finally: diff_section_painter.end() # To see an image dumped in the Travis CI log, copy the text from the # log, and paste it in test_pixmap_differ.test_decode_image. print(f'Encoded image of differing section ' f'({self.diff_min_x}, {self.diff_min_y}) - ' f'({self.diff_max_x}, {self.diff_max_y}):') print(encode_image(diff_section)) message = f'Found {self.different_pixels} different pixels, ' message += f'see' if is_saved else 'could not write' message += f' {diff_path.relative_to(Path(__file__).parent.parent)}.' assert self.different_pixels == 0, message def diff_colour(self, actual_colour: QColor, expected_colour: QColor, x: int, y: int): diff_size = (abs(actual_colour.red() - expected_colour.red()) + abs(actual_colour.green() - expected_colour.green()) + abs(actual_colour.blue() - expected_colour.blue())) if diff_size <= self.max_diff: diff_colour = actual_colour.toRgb() diff_colour.setAlpha(diff_colour.alpha() // 3) return diff_colour if self.different_pixels == 0: self.diff_min_x = self.diff_max_x = x self.diff_min_y = self.diff_max_y = y else: self.diff_min_x = min(self.diff_min_x, x) self.diff_max_x = max(self.diff_max_x, x) self.diff_min_y = min(self.diff_min_y, y) self.diff_max_y = max(self.diff_max_y, y) self.different_pixels += 1 # Colour dr = 0xff dg = (actual_colour.green() + expected_colour.green()) // 5 db = (actual_colour.blue() + expected_colour.blue()) // 5 # Opacity da = 0xff return QColor(dr, dg, db, da)
def test_board_size_2(pixmap_differ: PixmapDiffer): actual: QPainter expected: QPainter with pixmap_differ.create_painters(240, 240, 'margo_board_size_2') as (actual, expected): expected_scene = QGraphicsScene(0, 0, 240, 240) full_board = MargoDisplay.load_pixmap('board-1.png') width = full_board.width() height = full_board.height() top_height = round(height * 0.28) left_width = round(width * 0.28) right_width = round(width * 0.279) bottom_height = round(height * 0.29) assembled_board = QPixmap(left_width + right_width, top_height + bottom_height) assembled_board.fill(Qt.transparent) assembled_painter = QPainter(assembled_board) # top left assembled_painter.drawPixmap(0, 0, left_width, top_height, full_board, 0, 0, left_width, top_height) # top right assembled_painter.drawPixmap(left_width, 0, right_width, top_height, full_board, width - right_width, 0, right_width, top_height) # bottom left assembled_painter.drawPixmap(0, top_height, left_width, bottom_height, full_board, 0, height - bottom_height, left_width, bottom_height) # bottom right assembled_painter.drawPixmap(left_width, top_height, right_width, bottom_height, full_board, width - right_width, height - bottom_height, right_width, bottom_height) assembled_painter.end() scaled_board = assembled_board.scaled(232, 240, Qt.KeepAspectRatio, Qt.SmoothTransformation) board_item = expected_scene.addPixmap(scaled_board) board_item.setPos(4, 0) white_ball = MargoDisplay.load_pixmap('ball-w-shadow-1.png', QSize(103, 103)) black_ball = MargoDisplay.load_pixmap('ball-b-shadow-1.png', QSize(103, 103)) expected_scene.addPixmap(white_ball).setPos(23, 108) expected_scene.addPixmap(black_ball).setPos(113, 18) expected_scene.render(expected) display = MargoDisplay(size=2) trigger_resize(display, 292, 240) display.resize(348, 264) board_text = """\ A C 3 . B 3 1 W . 1 A C >B """ display.update_board(SpargoState(board_text, size=2)) render_display(display, actual)