def paintVerticalCell(self, painter: QPainter, hv: QHeaderView, cellIndex: QModelIndex, leafIndex: QModelIndex, logicalLeafIndex: int, styleOptions: QStyleOptionHeader, sectionRect: QRect, left: int): uniopt = QStyleOptionHeader(styleOptions) self.setForegroundBrush(uniopt, cellIndex) self.setBackgroundBrush(uniopt, cellIndex) width = self.cellSize(cellIndex, hv, uniopt).width() if cellIndex == leafIndex: width = sectionRect.width() - left top = self.currentCellLeft(cellIndex, leafIndex, logicalLeafIndex, sectionRect.top(), hv) height = self.currentCellWidth(cellIndex, leafIndex, logicalLeafIndex, hv) r = QRect(left, top, width, height) uniopt.text = cellIndex.data(Qt.DisplayRole) painter.save() uniopt.rect = r if cellIndex.data(Qt.UserRole): hv.style().drawControl(QStyle.CE_HeaderSection, uniopt, painter, hv) m = QTransform() m.rotate(-90) painter.setWorldMatrix(m, True) new_r = QRect(0, 0, r.height(), r.width()) new_r.moveCenter(QPoint(-r.center().y(), r.center().x())) uniopt.rect = new_r hv.style().drawControl(QStyle.CE_HeaderLabel, uniopt, painter, hv) else: hv.style().drawControl(QStyle.CE_Header, uniopt, painter, hv) painter.restore() return left + width
def paint(self, painter, rect, callback=None): painter.fillRect(rect, self.paperColor or QColor(Qt.white)) page = QRect(0, 0, self.width, self.height) painter.translate(page.center()) painter.rotate(self.computedRotation * 90) if self.computedRotation & 1: page.setSize(page.size().transposed()) painter.translate(-page.center()) self._svg_r.render(painter, QRectF(page))
def paint(self, painter: QPainter, rect: QRect): super().paint(painter, rect) # edge length of a box rotated 45 degrees and within box with edge of 1 edge = min(rect.width(), rect.height()) * 0.7 icon_area = QRect(0, 0, edge, edge) painter.save() painter.translate(rect.center()) rotation = self._animator.currentValue() * 360 / self._frames painter.rotate(rotation) painter.translate(-icon_area.center()) self.icon.paint(painter, icon_area) painter.restore()
def render(self, page): """Generate an image for this Page.""" i = QImage(page.width, page.height, QImage.Format_ARGB32_Premultiplied) i.fill(self.paperColor) painter = QPainter(i) rect = QRect(0, 0, page.width, page.height) painter.translate(rect.center()) painter.rotate(page.computedRotation * 90) if page.computedRotation & 1: rect.setSize(rect.size().transposed()) painter.translate(-rect.center()) page._svg_r.render(painter, QRectF(rect)) return i
def render(self, page): """Generate an image for this Page.""" i = QImage(page.width, page.height, self.imageFormat) i.fill(page.paperColor or self.paperColor or QColor(Qt.white)) painter = QPainter(i) rect = QRect(0, 0, page.width, page.height) painter.translate(rect.center()) painter.rotate(page.computedRotation * 90) if page.computedRotation & 1: rect.setSize(rect.size().transposed()) painter.translate(-rect.center()) page._svg_r.render(painter, QRectF(rect)) return i
def paint_date(self, date, painter, rect, num, is_past): font_not_large = self.settings.app_font != FONT_LARGE ellipse_rect = QRect(rect.x() + 3, rect.y() + 3, self.get_badge_width(num, self.settings.app_font), 20 if font_not_large else 25) text_rect = QRect(ellipse_rect.x() - 3.1, ellipse_rect.y() + (7 if font_not_large else 10), 20, 20) if self.monthShown() == date.month(): if is_past: painter.setBrush(QColor(0, 0, 0)) else: painter.setBrush(QColor(BADGE_COLOR)) else: painter.setBrush(QColor(196, 196, 196)) painter.setPen(Qt.NoPen) painter.drawRect(ellipse_rect) if self.monthShown() == date.month(): painter.setBrush(QColor(BADGE_LETTER_COLOR)) else: painter.setBrush(QColor(255, 255, 255)) painter.setPen(QPen(QColor(255, 255, 255))) num_repr = repr(num) if len(num_repr) > 1 and int(num_repr[-2]) == 1: text = self.tr('events') elif 1 < int(num_repr[-1]) < 5: text = self.tr('events*') else: text = self.tr( 'event{}'.format('s' if int(num_repr[-1]) > 1 or num % 2 == 0 else '')) painter.drawText(text_rect.center(), '{} {}'.format(num, text))
def paintEvent(self, event): self.setWindowFlags(Qt.FramelessWindowHint) self.setAttribute(Qt.WA_TranslucentBackground) self.setStyleSheet("background:transparent;") painter = QtGui.QPainter(self) painter.setRenderHint(QtGui.QPainter.Antialiasing) drawingRect = QRect( QtCore.QPoint(), self.rect().size() - 2 * self.width * QtCore.QSize(1, 1)) drawingRect.moveCenter(self.rect().center()) gradient = QtGui.QConicalGradient() gradient.setCenter(drawingRect.center()) gradient.setAngle(90) gradient.setColorAt(1, QtGui.QColor(0, 0, 0)) gradient.setColorAt( 0, QtGui.QColor(self.color[0], self.color[1], self.color[2])) arcLengthApproximation = self.width + self.width / 3 pen = QtGui.QPen(QtGui.QBrush(gradient), self.width) pen.setCapStyle(QtCore.Qt.RoundCap) painter.setPen(pen) painter.drawArc(drawingRect, 90 * 16 - arcLengthApproximation, -self._loading_angle * 16)
def paint(self, painter: QPainter, rect: QRect): super().paint(painter, rect) painter.save() painter.translate(rect.center()) size = rect.size() # self._size dot_space = min(size.width()/self._dots, size.height()) # self._max_dot_r max_dot_r = dot_space/2 * 0.75 min_dot_r = max_dot_r * 0.6 state = self._animator.currentValue() / self._frames len = self._dots*2-1 painter.translate(-(size.width()/2-dot_space/2), 0) painter.setPen(Qt.NoPen) painter.setBrush(Qt.black) painter.setRenderHint(QPainter.Antialiasing, True) for i in range(self._dots): dot_s = (state - i/len) % 1 dot_s = dot_s * len - 0.5 dot_s = dot_s if dot_s < 0 else min(dot_s / (len-1), 0.5) dot_r = min_dot_r + (max_dot_r - min_dot_r) * cos(dot_s*pi) painter.drawEllipse(QPoint(0, 0), dot_r, dot_r) painter.translate(dot_space, 0) painter.restore()
def mouseReleaseEvent(self, event): if event.button() == Qt.RightButton: self.rubberBand.hide() rb_rect = QRect(self._rb_origin, event.pos()) rb_center = rb_rect.center() rb_size = rb_rect.size() if abs(rb_size.width()) > 3 and abs(rb_size.height()) > 3: viewport_size = self.viewport().geometry().size() zoom_factor_x = abs(viewport_size.width() / rb_size.width()) zoom_factor_y = abs(viewport_size.height() / rb_size.height()) new_center = self.mapToScene(rb_center) zoom_factor = min(zoom_factor_x, zoom_factor_y) self.zoom_view(zoom_factor) self.centerOn(new_center) self.update_grid() if event.button() == Qt.MidButton: self.setCursor(Qt.ArrowCursor) self._mousePressed = None self.update_grid()
def decorate_welcome_icon(icon, background_color): """Return a `QIcon` with a circle shaped background. """ welcome_icon = QIcon() sizes = [32, 48, 64, 80] background_color = NAMED_COLORS.get(background_color, background_color) background_color = QColor(background_color) grad = radial_gradient(background_color) for size in sizes: icon_pixmap = icon.pixmap(5 * size / 8, 5 * size / 8) icon_size = icon_pixmap.size() icon_rect = QRect(QPoint(0, 0), icon_size) pixmap = QPixmap(size, size) pixmap.fill(QColor(0, 0, 0, 0)) p = QPainter(pixmap) p.setRenderHint(QPainter.Antialiasing, True) p.setBrush(QBrush(grad)) p.setPen(Qt.NoPen) ellipse_rect = QRect(0, 0, size, size) p.drawEllipse(ellipse_rect) icon_rect.moveCenter(ellipse_rect.center()) p.drawPixmap(icon_rect.topLeft(), icon_pixmap) p.end() welcome_icon.addPixmap(pixmap) return welcome_icon
def paintTab(self, painter: QPainter, index: int): if not self.isValidIndex(index): return painter.save() tab = self._tabs[index] rect = self._tabRect(index) selected = index == self._currentIndex enabled = self._enabled and tab.enabled if selected: painter.fillRect(rect, FancyToolButtonSelectedColor) tabText = tab.text tabTextRect = QRect(rect) drawIcon = rect.height() > 36 tabIconRect = QRect(rect) tabTextRect.translate(0, -2 if drawIcon else 1) boldFont = QFont(painter.font()) boldFont.setPointSizeF(SIDEBAR_FONT_SIZE) boldFont.setBold(True) painter.setFont(boldFont) #painter.setPen(QColor(255, 255, 255, 160) if selected else QColor(0, 0, 0, 110)) textFlags = Qt.AlignCenter | (Qt.AlignBottom if drawIcon else Qt.AlignVCenter) | Qt.TextWordWrap fader = tab.fader if fader > 0 and not selected and enabled: painter.save() painter.setOpacity(fader) painter.fillRect(rect, FancyToolButtonHoverColor) painter.restore() if not enabled: painter.setOpacity(0.7) if drawIcon: textHeight = (painter.fontMetrics().boundingRect( QRect(0, 0, self.width(), self.height()), Qt.TextWordWrap, tabText).height()) tabIconRect.adjust(0, 4, 0, -textHeight - 4) iconMode = (QIcon.Active if selected else QIcon.Normal) if enabled else QIcon.Disabled iconRect = QRect(0, 0, MODEBAR_ICON_SIZE, MODEBAR_ICON_SIZE) iconRect.moveCenter(tabIconRect.center()) iconRect = iconRect.intersected(tabIconRect) drawIconWithShadow(tab.icon, iconRect, painter, iconMode) if enabled: penColor = FancyTabWidgetEnabledSelectedTextColor if selected else FancyTabWidgetEnabledUnselectedTextColor else: penColor = FancyTabWidgetDisabledSelectedTextColor if selected else FancyTabWidgetDisabledUnselectedTextColor painter.setPen(penColor) painter.translate(0, -1) painter.drawText(tabTextRect, textFlags, tabText) painter.restore()
def draw_center(self, qp, event, w): w *= 0.2 rect = QRect() rect.setSize(QSize(w, w)) rect.moveCenter(event.rect().center()) rad = rect.width() / 2 cap = QRadialGradient(rect.center(), rad) cap.setColorAt(0, Qt.white) cap.setColorAt(1, Qt.gray) qp.setPen(QPen(Qt.black, 1)) qp.setBrush(QBrush(cap)) qp.drawEllipse(rect)
def paintEvent(self, event): painter = QPainter(self) painter.setBrush(Qt.darkGreen) painter.drawRect(self.rect()) img_rect = self.img.rect() dev_rect = QRect(0, 0, painter.device().width(), painter.device().height()) img_rect.moveCenter(dev_rect.center()) painter.drawPixmap(img_rect.topLeft(), self.img)
def drawBackground(self, painter, rect): QGraphicsView.drawBackground(self, painter, rect) if not self.__backgroundIcon.isNull(): painter.setClipRect(rect) vrect = QRect(QPoint(0, 0), self.viewport().size()) vrect = self.mapToScene(vrect).boundingRect() pm = self.__backgroundIcon.pixmap( vrect.size().toSize().boundedTo(QSize(200, 200)) ) pmrect = QRect(QPoint(0, 0), pm.size()) pmrect.moveCenter(vrect.center().toPoint()) if rect.toRect().intersects(pmrect): painter.drawPixmap(pmrect, pm)
def draw_gauge(self, qp, event, w): w *= 0.6 rect = QRect() rect.setSize(QSize(w, w)) rect.moveCenter(event.rect().center()) center = rect.center() qp.setPen(QPen(Qt.white, self.tick_width, cap=Qt.FlatCap)) qp.drawArc(rect, (-45 * 16), (270 * 16)) rad = rect.width() / 2 inc = 270.0 / (self._num_ticks - 1) for i in range(self._num_ticks): p1 = self.qpa[i] * rad p1 += center p2 = self.qpa[i] * (rad + 10) p2 += center line = QLine(p1.toPoint(), p2.toPoint()) qp.drawLine(line)
def mouseMoveEvent(self, ev: QtGui.QMouseEvent) -> None: ev.accept() if self._current_item_index == -1: return current_seed_item = self._circle_seed_items[ self._current_item_index] # type: CircleSeedItem if current_seed_item.change_able: if self._resize_handel_pressed: rect = QRect(current_seed_item.rect().topLeft(), QPoint(ev.pos() + self._mouse_press_offset)) current_seed_item.radius = min(rect.width(), rect.height(), 8) else: rect = current_seed_item.rect() rect.moveTopLeft(ev.pos() - self._mouse_press_offset) rect = rect.adjusted(0, 0, 1, 1) current_seed_item.center_pos = rect.center() self.update()
def paintEvent(self, event): painter = QtGui.QPainter(self) painter.setRenderHint(QtGui.QPainter.Antialiasing) drawingRect = QRect( QtCore.QPoint(), self.rect().size() - 2 * self.width * QtCore.QSize(1, 1)) if drawingRect.width() == 520: painter.rotate(90) painter.translate(0, -drawingRect.height()) elif drawingRect.width() == 470: painter.rotate(60) painter.translate(drawingRect.width() * (6 / 9), -drawingRect.height() * (6 / 9)) elif drawingRect.width() == 420: painter.rotate(40) painter.translate(drawingRect.width() * (4 / 9), -drawingRect.height() * (4 / 9)) elif drawingRect.width() == 370: painter.rotate(20) painter.translate(drawingRect.width() * (2 / 9), -drawingRect.height() * (2 / 9)) elif drawingRect.width() == 320: pass drawingRect.moveCenter(self.rect().center()) gradient = QtGui.QConicalGradient() gradient.setCenter(drawingRect.center()) gradient.setAngle(90) gradient.setColorAt(1, QtGui.QColor(0, 0, 0)) gradient.setColorAt( 0, QtGui.QColor(self.color[0], self.color[1], self.color[2])) arcLengthApproximation = self.width + self.width / 3 pen = QtGui.QPen(QtGui.QBrush(gradient), self.width) pen.setCapStyle(QtCore.Qt.RoundCap) painter.setPen(pen) if self.side == "L": painter.drawLine(0, 0, self.NextStep, self.NextStep) else: painter.drawLine(drawingRect.width(), 0, drawingRect.width() - self.NextStep, self.NextStep)
def paintEvent(self, ev=None): drawing_rect = QRect() drawing_rect.setX(self._padding) drawing_rect.setY(self._padding) drawing_rect.setWidth(self._size) drawing_rect.setHeight(self._size) painter = QPainter(self) painter.setRenderHint(QPainter.Antialiasing) gradient = QConicalGradient() gradient.setCenter(drawing_rect.center()) gradient.setAngle(-self._angle - self._size / 10) gradient.setColorAt(0, QColor(178, 255, 246)) gradient.setColorAt(1, QColor(5, 44, 50)) pen = QPen(QBrush(gradient), self._size // 10) pen.setCapStyle(Qt.RoundCap) painter.setPen(pen) painter.drawArc(drawing_rect, -self._angle * 16, 300 * 16)
def drawThumnail(self, cellNum, pic, thumb : PhotoNode, cell : Rectangle, painter : QPainter): rect = QRect(cell.x, cell.y, cell.width, cell.height) bLeft = rect.bottomLeft() # draw name fontHeight = 20 font = painter.font() font.setPixelSize(fontHeight) textTopRight = QPoint(bLeft.x(), bLeft.y() - fontHeight) textRect = QRect(textTopRight, rect.bottomRight()) thumbName = thumb.name painter.drawText(textRect, Qt.AlignHCenter, thumbName) #painter.drawRect(rect) # draw thumb imageRect = QRect(rect.topLeft(), textRect.topRight()) imageCenter = imageRect.center() imageX = int(imageCenter.x() - pic.width() / 2) imageY = int(imageCenter.y() - pic.height() / 2) imageOrigin = QPoint(imageX, imageY) painter.drawPixmap(imageOrigin, pic)
def _paint_tab(self, painter, index): if not self._is_valid_index(index): return painter.save() tab = self.__tabs[index] rect = self._tab_rect(index) selected = index == self.__current_index enabled = self._is_enabled(index) if selected: painter.fillRect(rect, QColor("#161719")) tab_icon_rect = QRect(rect) if selected: color = QColor(255, 255, 255, 160) else: color = QColor(0, 0, 0, 110) painter.setPen(color) fader = self.__tabs[index].fader if fader > 0 and not selected and enabled: painter.save() painter.setOpacity(fader) painter.fillRect(rect, QColor("#424242")) painter.restore() if tab.icon is not None: icon_rect = QRect(0, 0, 20, 20) icon_rect.moveCenter(tab_icon_rect.center()) tab.icon.paint(painter, rect) painter.setOpacity(1.0) if enabled: painter.setPen(QColor("#ffffff")) else: painter.setPen(QColor("blue")) painter.translate(0, -1) painter.restore()
def drawThumnail(self, cellNum, pic, thumb: PhotoNode, cell: Rectangle, painter: QPainter): rect = QRect(cell.x, cell.y, cell.width, cell.height) bLeft = rect.bottomLeft() # draw name fontHeight = 20 font = painter.font() font.setPixelSize(fontHeight) textTopRight = QPoint(bLeft.x(), bLeft.y() - fontHeight) textRect = QRect(textTopRight, rect.bottomRight()) thumbName = thumb.name painter.drawText(textRect, Qt.AlignHCenter, thumbName) #painter.drawRect(rect) # draw thumb imageRect = QRect(rect.topLeft(), textRect.topRight()) imageCenter = imageRect.center() imageX = int(imageCenter.x() - pic.width() / 2) imageY = int(imageCenter.y() - pic.height() / 2) imageOrigin = QPoint(imageX, imageY) painter.drawPixmap(imageOrigin, pic)
def draw(self, painter: Painting.Painter, is_global: bool = False) -> None: """ The center of the mower is the x and y coordinates The mower is rotated around the center :param painter: :param is_global: Defines if the global or the local position is taken for rendering """ if is_global: rect = QRect(self.global_pos[0].pixel(), self.global_pos[1].pixel(), self.WIDTH.pixel(), self.LENGTH.pixel()) else: rect = QRect(self.local_pos[0].pixel(), self.local_pos[1].pixel(), self.WIDTH.pixel(), self.LENGTH.pixel()) r_x = self.global_pos[0] - self.WIDTH r_y = self.global_pos[1] - self.LENGTH / 2 world_rx = r_x * math.cos(self.look_direction_rad) - math.sin(self.look_direction_rad) * r_y world_ry = r_x * math.sin(self.look_direction_rad) + math.cos(self.look_direction_rad) * r_y #logger.debug(f"{world_rx }, {world_ry}") transform = QtGui.QTransform() center_point = rect.center() # Sets the center as 0;0 coordinate transform.translate((-self.WIDTH / 2).pixel(), (-self.LENGTH).pixel()) # Rotate around the center transform.translate(center_point.x(), center_point.y()) transform.rotate(self.look_direction_deg) transform.translate(-center_point.x(), -center_point.y()) painter.setTransform(transform, combine=True) painter.fillRect(rect, QtGui.QBrush(self.MOWER_COLOR, QtCore.Qt.SolidPattern)) painter.drawImage(rect, self.img_mower) painter.resetTransform()
def __init__(self, parent): super().__init__(parent=parent) self.setWindowTitle('License') self.ed_info = QTextEdit() self.ed_GPL = QPlainTextEdit() self.bt_close = QPushButton('Close') vlay = QVBoxLayout() vlay.addWidget(self.ed_info) vlay.addWidget(self.ed_GPL) vlay.addWidget(self.bt_close) self.bt_close.clicked.connect(self.close) self.setLayout(vlay) font = QFont("Courier", 10) font.setStyleHint(QFont.Monospace) self.ed_GPL.setFont(font) self.ed_info.setText(info_txt) self.ed_GPL.setPlainText(gpl) my_geometry = QRect(0, 0, 640, 400) self.setGeometry(my_geometry) self.move(parent.parent_for_lic.geometry().center() - my_geometry.center())
class ViewFisheye(QWidget): # sample selection SelectionType = Enum('SelectType', 'Exact Closest Rect') SelectionMode = Enum('SelectMode', 'Select Add Remove') SelectionRectMin = 10 # pixels, width and height, scales as photo scales SampleRadius = 10 # pixels, scales as photo scales SelectedPixelBox = 64 # pixels, width and height def __init__(self, parent): super().__init__() # members self.parent = parent self.myPhoto = QImage() self.myPhotoPixels = np.zeros(shape=(1, 1, 4)) self.myPhotoPath = "" self.myPhotoTime = datetime(1,1,1) self.myPhotoSrcRect = QRect() self.myPhotoDestRect = QRect() self.myPhotoRadius = 0 self.myPhotoRotation = 0 self.rawAvailable = False self.coordsMouse = (0, 0) self.viewCenter = (0, 0) self.dragSelectRect = QRect(0, 0, 0, 0) self.sunPosition = (0, 0) # (azimuth (theta), altitude (phi)(90-zenith)) self.sunPositionVisible = (0,0) # point (x,y) of sun location rendered on screen (scaled) self.sunPathPoints = [] # [(azimuth (theta), altitude (phi)(90-zenith), datetime)] self.compassTicks = [] # [[x1, y1, x2, y2, x1lbl, y1lbl, angle]] self.lensIdealRadii = [] # list of radii for ideal lens latitudes to draw self.lensRealRadii = [] # list of radii for real/warped lens latitudes to draw self.samplePoints = [] # (x,y) coords of all samples on the photo rendered on screen (scaled) self.sampleAreaVisible = [] # area of 4 points for each sample rendered on screen (scaled) self.samplePointsInFile = [] # points (x,y) of all samples in the photo on file self.samplesSelected = [] # indices of selected samples self.skyCover = common.SkyCover.UNK # members - preloaded graphics self.painter = QPainter() self.mask = QImage() self.pathSun = QPainterPath() self.penText = QPen(Qt.white, 1, Qt.SolidLine) self.penLens = QPen(Qt.magenta, 1, Qt.SolidLine) self.penSun = QPen(QColor(255, 165, 0), 2, Qt.SolidLine) self.penSelected = [] # list of pens, one for each sampling pattern location self.penSelectRect = QPen(Qt.white, 1, Qt.DashLine) self.penShadowText = QPen(Qt.black, 1, Qt.SolidLine) self.penShadowSun = QPen(Qt.black, 2, Qt.SolidLine) self.penShadowSelected = QPen(Qt.black, 3, Qt.SolidLine) self.brushGrid = QBrush(Qt.white, Qt.SolidPattern) self.fontFixed = QFont('Courier New', 8) self.fontScaled = QFont('Courier New', 8) self.fontMetrics = QFontMetrics(self.fontScaled) self.iconWarning = self.style().standardIcon(QStyle.SP_MessageBoxWarning).pixmap(ViewFisheye.SelectedPixelBox / 2) def dataLoaded(self): # Note - this function only runs once the data directory has been loaded self.setMouseTracking(True) color = QColor(255, 255, 255) self.samplesSelected.clear() self.samplePoints.clear() self.sampleAreaVisible.clear() self.samplePointsInFile.clear() self.penSelected.clear() for t, p in common.SamplingPattern: self.samplePoints.append((0, 0)) # these will need to be recomputed as photo scales self.samplePointsInFile.append((0, 0)) # these only need to be computed once per photo self.sampleAreaVisible.append([]) color.setHsv(t, int(utility.normalize(p, 0, 90) * 127 + 128), 255) self.penSelected.append(QPen(color, 3, Qt.SolidLine)) def setPhoto(self, path, exif=None): # if photo is valid if path is not None and os.path.exists(path): self.myPhotoPath = path self.myPhoto = QImage(path) self.myPhotoSrcRect = QRect(0, 0, self.myPhoto.width(), self.myPhoto.height()) self.myPhotoDestRect = QRect(0, 0, self.width(), self.height()) self.rawAvailable = utility_data.isHDRRawAvailable(path) if exif is not None: self.myPhotoTime = datetime.strptime(str(exif["EXIF DateTimeOriginal"]), '%Y:%m:%d %H:%M:%S') else: self.myPhotoTime = utility_data.imageEXIFDateTime(path) # cache each sample's coordinate in the photo # note: technically doesn't need to be recalculated if all photos have same resolution! self.samplePointsInFile = utility_data.computePointsInImage(path, common.SamplingPattern) # keep a copy the image's pixels in memory (used later for exporting, etc.) ptr = self.myPhoto.bits() ptr.setsize(self.myPhoto.byteCount()) pixbgr = np.asarray(ptr).reshape(self.myPhoto.height(), self.myPhoto.width(), 4) # HACKAROONIE: byte order is not the same as image format, so swapped it around :/ # TODO: should handle this better self.myPhotoPixels = np.copy(pixbgr) red = np.copy(self.myPhotoPixels[:, :, 0]) self.myPhotoPixels[:, :, 0] = self.myPhotoPixels[:, :, 2] self.myPhotoPixels[:, :, 2] = red # rgba = self.myPhoto.pixelColor(center[0], center[1]) # print((rgba.red(), rgba.green(), rgba.blue())) # rgba = pixrgb[center[1], center[0]] # print(rgba) # photo is null or missing else: self.myPhoto = QImage() self.myPhotoPixels = np.zeros(shape=(1,1,4)) self.myPhotoPath = "" self.myPhotoTime = datetime(1, 1, 1) self.myPhotoSrcRect = QRect() self.myPhotoDestRect = QRect() self.rawAvailable = False # precompute as much as we can before any drawing self.computeBounds() def setSunPath(self, sunpath): self.sunPathPoints = sunpath def setSunPosition(self, pos): self.sunPosition = pos def setSkycover(self, sc): self.skyCover = sc def getSamplePatternRGB(self, index): if index < 0 or index >= len(common.SamplingPattern): return (0,0,0) color = self.penSelected[index].color() return (color.red(), color.green(), color.blue()) def resetRotation(self, angles=0): self.myPhotoRotation = angles def selectSamples(self, message="none"): # nothing to do if no photo loaded if self.myPhoto.isNull(): return # handle selection message if message == "none": self.samplesSelected.clear() elif message == "all": self.samplesSelected[:] = [i for i in range(0, len(common.SamplingPattern))] elif message == "inverse": allidx = set([i for i in range(0, len(common.SamplingPattern))]) selidx = set(self.samplesSelected) self.samplesSelected[:] = list(allidx - selidx) # remove samples in circumsolar avoidance region if necessary sunAvoid = common.AppSettings["AvoidSunAngle"] if sunAvoid > 0: sunAvoidRads = math.radians(common.AppSettings["AvoidSunAngle"]) sunPosRads = (math.radians(self.sunPosition[0]), math.radians(self.sunPosition[1])) self.samplesSelected[:] = [idx for idx in self.samplesSelected if utility_angles.CentralAngle(sunPosRads, common.SamplingPatternRads[idx], inRadians=True) > sunAvoidRads] # update self.repaint() self.parent.graphSamples(self.samplesSelected) def mouseMoveEvent(self, event): # nothing to do if no photo loaded if self.myPhoto.isNull(): return # detect primary mouse button drag for sample selection if event.buttons() == Qt.LeftButton: # update drag selection bounds self.dragSelectRect.setWidth(event.x() - self.dragSelectRect.x()) self.dragSelectRect.setHeight(event.y() - self.dragSelectRect.y()) # detect middle mouse button drag for image rotation elif (event.buttons() == Qt.MidButton): old = (self.coordsMouse[0] - self.viewCenter[0], self.coordsMouse[1] - self.viewCenter[1]) new = (event.x() - self.viewCenter[0], event.y() - self.viewCenter[1]) # clockwise drag decreases rotation if old[1]*new[0] < old[0]*new[1]: self.myPhotoRotation -= 1 # counter-clockwise drag increases rotation else: self.myPhotoRotation += 1 # rotation if self.myPhotoRotation >= 0: self.myPhotoRotation %= 360 else: self.myPhotoRotation %= -360 # lastly, cache mouse coordinates and update self.coordsMouse = (event.x(), event.y()) self.repaint() def mousePressEvent(self, event): # nothing to do if no photo loaded if self.myPhoto.isNull(): return # we only care about a left click for point and drag selection # right click is for context menu - handled elsewhere # middle click is for rotation - handled elsewhere if event.buttons() != Qt.LeftButton: return # start logging drag selection (whether user drags or not) self.dragSelectRect.setX(event.x()) self.dragSelectRect.setY(event.y()) self.dragSelectRect.setWidth(0) self.dragSelectRect.setHeight(0) def mouseReleaseEvent(self, event): # nothing to do if no photo loaded if self.myPhoto.isNull(): return # detect primary mouse button release for stopping sample selection if event.button() == Qt.LeftButton: # read modifier keys for user desired selection mode mode = ViewFisheye.SelectionMode.Select if event.modifiers() == Qt.ControlModifier: mode = ViewFisheye.SelectionMode.Add elif event.modifiers() == Qt.ShiftModifier: mode = ViewFisheye.SelectionMode.Remove # unflip coordinates of rect so that width and height are always positive r = self.dragSelectRect r = utility.rectForwardFacing([r.x(), r.y(), r.right(), r.bottom()]) self.dragSelectRect.setCoords(r[0], r[1], r[2], r[3]) # select samples prevSelected = list(self.samplesSelected) if self.dragSelectRect.width() < ViewFisheye.SelectionRectMin and self.dragSelectRect.height() < ViewFisheye.SelectionRectMin: self.computeSelectedSamples(ViewFisheye.SelectionType.Closest, mode) else: self.computeSelectedSamples(ViewFisheye.SelectionType.Rect, mode) # reset drag selection self.dragSelectRect.setX(event.x()) self.dragSelectRect.setY(event.y()) self.dragSelectRect.setWidth(0) self.dragSelectRect.setHeight(0) # update self.repaint() if self.samplesSelected != prevSelected: self.parent.graphSamples(self.samplesSelected) def wheelEvent(self, event): # nothing to do if no photo loaded if self.myPhoto.isNull(): return self.parent.timeChangeWheelEvent(event) def leaveEvent(self, event): self.coordsMouse = (-1, -1) self.repaint() def resizeEvent(self, event): self.computeBounds() def contextMenuEvent(self, event): # nothing to do if no photo loaded if self.myPhoto.isNull(): return self.parent.triggerContextMenu(self, event) def computeSelectedSamples(self, type, mode): px = 0 py = 0 x1 = 0 y1 = 0 x2 = 0 y2 = 0 # in select mode, clear current selection if mode == ViewFisheye.SelectionMode.Select: self.samplesSelected = [] # these are the samples we will be adding or removing sampleAdjustments = [] # which single sample did user select by point if type == ViewFisheye.SelectionType.Exact: px = self.coordsMouse[0] py = self.coordsMouse[1] for i in range(0, len(self.samplePoints)): x, y = self.samplePoints[i] x1 = x - ViewFisheye.SampleRadius y1 = y - ViewFisheye.SampleRadius x2 = x + ViewFisheye.SampleRadius y2 = y + ViewFisheye.SampleRadius if px >= x1 and px <= x2 and py >= y1 and py <= y2: sampleAdjustments.append(i) break # which single sample is the closest to the mouse coordinate elif type == ViewFisheye.SelectionType.Closest: px = self.coordsMouse[0] py = self.coordsMouse[1] dist = math.sqrt((py-self.viewCenter[1])*(py-self.viewCenter[1]) + (px-self.viewCenter[0])*(px-self.viewCenter[0])) if dist <= self.myPhotoRadius: close = math.inf closest = -1 for i in range(0, len(self.samplePoints)): x, y = self.samplePoints[i] dist = math.sqrt((y-py)*(y-py) + (x-px)*(x-px)) if dist < close: close = dist closest = i if closest >= 0: sampleAdjustments.append(closest) # which samples are in the drag selection rect elif type == ViewFisheye.SelectionType.Rect: x1 = self.dragSelectRect.x() y1 = self.dragSelectRect.y() x2 = self.dragSelectRect.x() + self.dragSelectRect.width() y2 = self.dragSelectRect.y() + self.dragSelectRect.height() for i in range(0, len(self.samplePoints)): x, y = self.samplePoints[i] if x >= x1 and x <= x2 and y >= y1 and y <= y2: sampleAdjustments.append(i) # remove samples in circumsolar avoidance region sunAvoid = common.AppSettings["AvoidSunAngle"] if sunAvoid > 0: sunAvoidRads = math.radians(common.AppSettings["AvoidSunAngle"]) sunPosRads = (math.radians(self.sunPosition[0]), math.radians(self.sunPosition[1])) sampleAdjustments[:] = [idx for idx in sampleAdjustments if utility_angles.CentralAngle(sunPosRads, common.SamplingPatternRads[idx], inRadians=True) > sunAvoidRads] # no changes to be made if len(sampleAdjustments) <= 0: return # finally modify sample selection and return difference if mode == ViewFisheye.SelectionMode.Select or mode == ViewFisheye.SelectionMode.Add: for i in range(0, len(sampleAdjustments)): if sampleAdjustments[i] not in self.samplesSelected: # don't readd existing indices self.samplesSelected.append(sampleAdjustments[i]) elif mode == ViewFisheye.SelectionMode.Remove: for i in range(0, len(sampleAdjustments)): try: self.samplesSelected.remove(sampleAdjustments[i]) except: pass # ignore trying to remove indices that aren't currently selected # sort selection for easier searching later self.samplesSelected.sort() def computeBounds(self): if self.myPhoto.isNull(): self.myPhotoDestRect = QRect(0, 0, self.width(), self.height()) self.viewCenter = (self.width() / 2, self.height() / 2) self.myPhotoRadius = 0 self.myPhotoDiameter = 0 for i in range(0, len(common.SamplingPattern)): self.samplePoints[i] = (0, 0) self.sampleAreaVisible[i] = [] return # scale photo destination rect to fit photo on screen # scale by the scaling factor that requires the most scaling ( - 2 to fit in border ) wRatio = self.width() / self.myPhoto.width() hRatio = self.height() / self.myPhoto.height() if wRatio <= hRatio: self.myPhotoDestRect.setWidth(self.myPhotoSrcRect.width() * wRatio - 2) self.myPhotoDestRect.setHeight(self.myPhotoSrcRect.height() * wRatio - 2) else: self.myPhotoDestRect.setWidth(self.myPhotoSrcRect.width() * hRatio - 2) self.myPhotoDestRect.setHeight(self.myPhotoSrcRect.height() * hRatio - 2) # center the photo dest rect self.myPhotoDestRect.moveTo(self.width() / 2 - self.myPhotoDestRect.width() / 2, self.height() / 2 - self.myPhotoDestRect.height() / 2) # NOTE - THESE ARE THE MOST IMPORTANT COMPUTATIONS FROM WHICH EVERYTHING ELSE IS PLOTTED self.viewCenter = (self.width() / 2, self.height() / 2) self.myPhotoRadius = self.myPhotoDestRect.height() / 2 self.myPhotoDiameter = self.myPhotoRadius * 2 self.myPhotoTopLeft = ((self.viewCenter[0] - self.myPhotoRadius), (self.viewCenter[1] - self.myPhotoRadius)) # compute new scaled font size self.fontScaled = QFont('Courier New', self.myPhotoRadius * (1/(101-common.AppSettings["HUDTextScale"]))) self.fontMetrics = QFontMetrics(self.fontScaled) # compute sampling pattern collision bounds ViewFisheye.SampleRadius = self.myPhotoRadius / 50 hFOV = common.DataConfig["RadianceFOV"] / 2 for i in range(0, len(common.SamplingPattern)): # compute sample bounds u, v = utility_angles.SkyCoord2FisheyeUV(common.SamplingPattern[i][0], common.SamplingPattern[i][1]) x = self.myPhotoTopLeft[0] + (u * self.myPhotoDiameter) y = self.myPhotoTopLeft[1] + (v * self.myPhotoDiameter) self.samplePoints[i] = (x, y) # compute sampling pattern actual sampling areas (projected differential angle area) p1 = utility_angles.SkyCoord2FisheyeUV(common.SamplingPattern[i][0] - hFOV, common.SamplingPattern[i][1] - hFOV) p2 = utility_angles.SkyCoord2FisheyeUV(common.SamplingPattern[i][0] - hFOV, common.SamplingPattern[i][1] + hFOV) p3 = utility_angles.SkyCoord2FisheyeUV(common.SamplingPattern[i][0] + hFOV, common.SamplingPattern[i][1] + hFOV) p4 = utility_angles.SkyCoord2FisheyeUV(common.SamplingPattern[i][0] + hFOV, common.SamplingPattern[i][1] - hFOV) p1 = QPoint(self.myPhotoTopLeft[0] + (p1[0] * self.myPhotoDiameter), self.myPhotoTopLeft[1] + (p1[1] * self.myPhotoDiameter)) p2 = QPoint(self.myPhotoTopLeft[0] + (p2[0] * self.myPhotoDiameter), self.myPhotoTopLeft[1] + (p2[1] * self.myPhotoDiameter)) p3 = QPoint(self.myPhotoTopLeft[0] + (p3[0] * self.myPhotoDiameter), self.myPhotoTopLeft[1] + (p3[1] * self.myPhotoDiameter)) p4 = QPoint(self.myPhotoTopLeft[0] + (p4[0] * self.myPhotoDiameter), self.myPhotoTopLeft[1] + (p4[1] * self.myPhotoDiameter)) self.sampleAreaVisible[i] = [p1, p2, p3, p4] # compute compass lines self.compassTicks.clear() tickLength = self.myPhotoRadius / 90 for angle in range(0, 360, 10): theta = 360 - ((angle + 270) % 360) # angles eastward from North, North facing down rads = theta * math.pi / 180.0 cx1 = (math.cos(rads) * (self.myPhotoRadius - tickLength)) + self.viewCenter[0] cy1 = (math.sin(rads) * (self.myPhotoRadius - tickLength)) + self.viewCenter[1] cx2 = (math.cos(rads) * self.myPhotoRadius) + self.viewCenter[0] cy2 = (math.sin(rads) * self.myPhotoRadius) + self.viewCenter[1] lx1 = (math.cos(rads) * (self.myPhotoRadius - tickLength*4)) + self.viewCenter[0] - self.fontMetrics.width(str(angle))/2 ly1 = (math.sin(rads) * (self.myPhotoRadius - tickLength*4)) + self.viewCenter[1] - self.fontMetrics.height()/2 self.compassTicks.append([cx1, cy1, cx2, cy2, lx1, ly1, angle]) # x1, y1, x2, y2, x1lbl, y1lbl, angle # compute new grid for debugging coordinates griddivs = 5 gridwidth = int(round(self.myPhotoDiameter / griddivs)) self.gridpoints = [] self.gridUVs = [] self.gridskycoords = [] for r in range(1, griddivs): for c in range(1, griddivs): point = (self.myPhotoTopLeft[0] + (c * gridwidth), self.myPhotoTopLeft[1] + (r * gridwidth)) self.gridpoints.append(point) u = (point[0] - self.myPhotoTopLeft[0]) / self.myPhotoDiameter v = (point[1] - self.myPhotoTopLeft[1]) / self.myPhotoDiameter self.gridUVs.append((u, v)) t, p = utility_angles.FisheyeUV2SkyCoord(u, v) self.gridskycoords.append((t, p)) # compute lens (ideal and actual) radii for drawn latitude ellipses along zenith self.lensIdealRadii.clear() self.lensRealRadii.clear() for alt in common.SamplingPatternAlts: # ideal lens u, v = utility_angles.SkyCoord2FisheyeUV(90, alt, lenswarp=False) x = self.myPhotoTopLeft[0] + (u * self.myPhotoDiameter) r = x - self.viewCenter[0] self.lensIdealRadii.append((r, alt)) # (radius, altitude) # warped lens u, v = utility_angles.SkyCoord2FisheyeUV(90, alt) x = self.myPhotoTopLeft[0] + (u * self.myPhotoDiameter) r = x - self.viewCenter[0] self.lensRealRadii.append((r, alt)) # (radius, altitude) # compute sun path screen points self.pathSun = QPainterPath() if len(self.sunPathPoints) > 0: azi, alt, dt = self.sunPathPoints[0] u, v = utility_angles.SkyCoord2FisheyeUV(azi, alt) x = self.myPhotoTopLeft[0] + (u * self.myPhotoDiameter) y = self.myPhotoTopLeft[1] + (v * self.myPhotoDiameter) self.pathSun.moveTo(x, y) for i in range(1, len(self.sunPathPoints)): azi, alt, dt = self.sunPathPoints[i] u, v = utility_angles.SkyCoord2FisheyeUV(azi, alt) x = self.myPhotoTopLeft[0] + (u * self.myPhotoDiameter) y = self.myPhotoTopLeft[1] + (v * self.myPhotoDiameter) self.pathSun.lineTo(x, y) # compute sun position screen point u, v = utility_angles.SkyCoord2FisheyeUV(self.sunPosition[0], self.sunPosition[1]) x = self.myPhotoTopLeft[0] + (u * self.myPhotoDiameter) y = self.myPhotoTopLeft[1] + (v * self.myPhotoDiameter) self.sunPositionVisible = (x, y) # compute new mask self.mask = QPixmap(self.width(), self.height()).toImage() def paintEvent(self, event): super().paintEvent(event) painter = QPainter() painter.begin(self) # background brushBG = QBrush(Qt.black, Qt.SolidPattern) if not common.AppSettings["ShowMask"]: brushBG.setColor(Qt.darkGray) brushBG.setStyle(Qt.Dense1Pattern) painter.setBackground(Qt.gray) else: brushBG.setColor(Qt.black) brushBG.setStyle(Qt.SolidPattern) painter.setBackground(Qt.black) painter.setBackgroundMode(Qt.OpaqueMode) painter.setBrush(brushBG) painter.setPen(Qt.NoPen) painter.drawRect(0, 0, self.width(), self.height()) # draw photo if not self.myPhoto.isNull(): # rotate and draw photo as specified by user transform = QTransform() transform.translate(self.myPhotoDestRect.center().x(), self.myPhotoDestRect.center().y()) transform.rotate(-self.myPhotoRotation) transform.translate(-self.myPhotoDestRect.center().x(), -self.myPhotoDestRect.center().y()) painter.setTransform(transform) painter.drawImage(self.myPhotoDestRect, self.myPhoto, self.myPhotoSrcRect) # draw it painter.resetTransform() # useful local vars centerPoint = QPoint(self.viewCenter[0], self.viewCenter[1]) destRect = QRect(0, 0, self.myPhotoDestRect.width(), self.myPhotoDestRect.height()) fontWidth = self.fontMetrics.width("X") # mask if common.AppSettings["ShowMask"]: maskPainter = QPainter() maskPainter.begin(self.mask) maskPainter.setBrush(QBrush(Qt.magenta, Qt.SolidPattern)) maskPainter.drawEllipse(self.viewCenter[0] - self.myPhotoRadius, self.viewCenter[1] - self.myPhotoRadius, self.myPhotoDiameter, self.myPhotoDiameter) maskPainter.end() painter.setCompositionMode(QPainter.CompositionMode_DestinationIn) painter.drawImage(0, 0, self.mask) painter.setCompositionMode(QPainter.CompositionMode_SourceOver) # HUD if common.AppSettings["ShowHUD"]: painter.setBackgroundMode(Qt.TransparentMode) #painter.setBackground(Qt.black) painter.setBrush(Qt.NoBrush) painter.setFont(self.fontScaled) # draw UV grid if common.AppSettings["ShowUVGrid"]: painter.setPen(self.penText) # box tl = self.myPhotoTopLeft tr = (self.viewCenter[0] + self.myPhotoRadius, self.viewCenter[1] - self.myPhotoRadius) bl = (self.viewCenter[0] - self.myPhotoRadius, self.viewCenter[1] + self.myPhotoRadius) br = (self.viewCenter[0] + self.myPhotoRadius, self.viewCenter[1] + self.myPhotoRadius) painter.drawLine(tl[0], tl[1], tr[0], tr[1]) painter.drawLine(bl[0], bl[1], br[0], br[1]) painter.drawLine(tl[0], tl[1], bl[0], bl[1]) painter.drawLine(tr[0], tr[1], br[0], br[1]) # crosshairs painter.drawLine(tl[0], self.viewCenter[1], tr[0], self.viewCenter[1]) painter.drawLine(self.viewCenter[0], tr[1], self.viewCenter[0], br[1]) # labels destRect.setCoords(tl[0] + 4, tl[1] + 4, self.width(), self.height()) painter.drawText(destRect, Qt.AlignTop | Qt.AlignLeft, "0") destRect.setCoords(tr[0] - (fontWidth+4), tr[1] + 4, self.width(), self.height()) painter.drawText(destRect, Qt.AlignTop | Qt.AlignLeft, "1") destRect.setCoords(bl[0] + 3, bl[1] - (self.fontMetrics.height()+3), self.width(), self.height()) painter.drawText(destRect, Qt.AlignTop | Qt.AlignLeft, "1") destRect.setCoords(br[0] - (fontWidth+3), br[1] - (self.fontMetrics.height()+3), self.width(), self.height()) painter.drawText(destRect, Qt.AlignTop | Qt.AlignLeft, "1") # grid coordinates gpntrad = self.myPhotoRadius * 0.005 painter.setPen(self.penText) painter.setBrush(self.brushGrid) painter.setFont(self.fontScaled) for i in range(0, len(self.gridpoints)): point = self.gridpoints[i] u, v = self.gridUVs[i] t, p = self.gridskycoords[i] painter.drawEllipse(QPoint(point[0], point[1]), gpntrad, gpntrad) destRect.setCoords(point[0]+fontWidth/2, point[1]-self.fontMetrics.height(), self.width(), self.height()) textuv = "{0:.1f}u, {1:.1f}v".format(round(u,1), round(v,1)) painter.drawText(destRect, Qt.AlignTop | Qt.AlignLeft, textuv) destRect.setCoords(point[0]+fontWidth/2, point[1], self.width(), self.height()) textuv = "{0:d}°, {1:d}°".format(int(round(t)), int(round(p))) painter.drawText(destRect, Qt.AlignTop | Qt.AlignLeft, textuv) painter.setBrush(Qt.NoBrush) # draw lens warp if common.AppSettings["ShowLensWarp"]: # ideal lens longitudes along azimuth painter.setPen(self.penText) for i in range(0, int(len(self.compassTicks)/2), 3): p1 = QPoint(self.compassTicks[i][2], self.compassTicks[i][3]) p2 = QPoint(self.compassTicks[i+18][2], self.compassTicks[i+18][3]) # tick opposite 180 degrees painter.drawLine(p1, p2) # ideal lens latitudes along zenith for r, alt in self.lensIdealRadii: painter.drawEllipse(centerPoint, r, r) # actual/warped lens latitudes along zenith painter.setPen(self.penLens) for r, alt in self.lensRealRadii: painter.drawEllipse(centerPoint, r, r) destRect.setCoords(self.viewCenter[0] + r + 3, self.viewCenter[1] - (self.fontMetrics.height() + 3), self.width(), self.height()) painter.drawText(destRect, Qt.AlignTop | Qt.AlignLeft, "{0:d}°".format(int(alt))) # draw compass if common.AppSettings["ShowCompass"]: # compass ticks text shadows if common.AppSettings["ShowShadows"]: painter.setPen(self.penShadowText) for tick in self.compassTicks: destRect.setCoords(tick[4] + 1, tick[5] + 1, self.width(), self.height()) painter.drawText(destRect, Qt.AlignTop | Qt.AlignLeft, str(tick[6])+"°") # compass ticks text painter.setPen(self.penText) for tick in self.compassTicks: painter.drawLine(tick[0], tick[1], tick[2], tick[3]) destRect.setCoords(tick[4], tick[5], self.width(), self.height()) painter.drawText(destRect, Qt.AlignTop | Qt.AlignLeft, str(tick[6])+"°") # photo radius #painter.drawEllipse(self.viewCenter[0] - self.myPhotoRadius, self.viewCenter[1] - self.myPhotoRadius, self.myPhotoDiameter, self.myPhotoDiameter) painter.drawEllipse(centerPoint, self.myPhotoRadius, self.myPhotoRadius) # cardinal directions destRect.setCoords(self.viewCenter[0] - self.myPhotoRadius - (fontWidth+4), self.viewCenter[1] - self.fontMetrics.height()/2, self.width(), self.height()) painter.drawText(destRect, Qt.AlignTop | Qt.AlignLeft, "W") destRect.setCoords(self.viewCenter[0] + self.myPhotoRadius + 4, self.viewCenter[1] - self.fontMetrics.height()/2, self.width(), self.height()) painter.drawText(destRect, Qt.AlignTop | Qt.AlignLeft, "E") destRect.setCoords(self.viewCenter[0] - fontWidth/2, self.viewCenter[1] - self.myPhotoRadius - (self.fontMetrics.height()+3), self.width(), self.height()) painter.drawText(destRect, Qt.AlignTop | Qt.AlignLeft, "S") destRect.setCoords(self.viewCenter[0] - fontWidth/2, self.viewCenter[1] + self.myPhotoRadius + 3, self.width(), self.height()) painter.drawText(destRect, Qt.AlignTop | Qt.AlignLeft, "N") # draw sampling pattern if common.AppSettings["ShowSamples"]: painter.setPen(self.penText) for i, points in enumerate(self.sampleAreaVisible): painter.drawLine(QLine(points[0], points[1])) painter.drawLine(QLine(points[1], points[2])) painter.drawLine(QLine(points[2], points[3])) painter.drawLine(QLine(points[3], points[0])) for i in range(0, len(self.samplePoints)): p = self.samplePoints[i] painter.drawEllipse(QPoint(p[0],p[1]), ViewFisheye.SampleRadius, ViewFisheye.SampleRadius) painter.drawText(p[0] + ViewFisheye.SampleRadius, p[1], str(i)) # draw sun path if common.AppSettings["ShowSunPath"]: sunradius = self.myPhotoRadius * 0.1 # shadows painter.setPen(self.penShadowSun) if common.AppSettings["ShowShadows"]: painter.drawEllipse(QPoint(self.sunPositionVisible[0]+1, self.sunPositionVisible[1]+1), sunradius, sunradius) self.pathSun.translate(1.0, 1.0) painter.drawPath(self.pathSun) self.pathSun.translate(-1.0, -1.0) for i in range(0, self.pathSun.elementCount()): e = self.pathSun.elementAt(i) destRect.setCoords(e.x, e.y + self.fontMetrics.height()/2 + 1, self.width(), self.height()) painter.drawText(destRect, Qt.AlignTop | Qt.AlignLeft, str(self.sunPathPoints[i][2].hour)) # sun, path, hours painter.setPen(self.penSun) painter.drawEllipse(QPoint(self.sunPositionVisible[0], self.sunPositionVisible[1]), sunradius, sunradius) painter.drawPath(self.pathSun) for i in range(0, self.pathSun.elementCount()): e = self.pathSun.elementAt(i) destRect.setCoords(e.x, e.y + self.fontMetrics.height() / 2, self.width(), self.height()) painter.drawText(destRect, Qt.AlignTop | Qt.AlignLeft, str(self.sunPathPoints[i][2].hour)) # draw selected samples (ALWAYS) r = QRect() # shadows if common.AppSettings["ShowShadows"]: painter.setPen(self.penShadowSelected) for i in self.samplesSelected: x, y = self.samplePoints[i] painter.drawEllipse(QPoint(x+1, y+1), ViewFisheye.SampleRadius, ViewFisheye.SampleRadius) # samples for i in self.samplesSelected: painter.setPen(self.penSelected[i]) x, y = self.samplePoints[i] painter.drawEllipse(QPoint(x, y), ViewFisheye.SampleRadius, ViewFisheye.SampleRadius) # draw user's selection bounds if (abs(self.dragSelectRect.right()-self.dragSelectRect.left()) >= ViewFisheye.SelectionRectMin and abs(self.dragSelectRect.bottom()-self.dragSelectRect.top()) >= ViewFisheye.SelectionRectMin): painter.setPen(self.penSelectRect) painter.drawRect(self.dragSelectRect) # draw timestamp painter.setPen(self.penText) painter.setFont(self.fontFixed) destRect.setCoords(10, 10, self.width() / 2, 50) painter.drawText(destRect, Qt.AlignTop | Qt.AlignLeft, str(self.myPhotoTime)) # draw sky cover assessment destRect.setCoords(10, 25, self.width(), self.height()) painter.drawText(destRect, Qt.AlignTop | Qt.AlignLeft, self.skyCover.name + "/" + common.SkyCoverDesc[self.skyCover]) # draw photo rotation if self.myPhotoRotation != 0: destRect.setCoords(10, self.height()-25, self.width(), self.height()) painter.drawText(destRect, Qt.AlignTop | Qt.AlignLeft, "Rotation: " + str(self.myPhotoRotation) + "°") # where is the mouse relative to the center? # this is used as an optimization to only display information when mouse is in fisheye portion dx = self.coordsMouse[0] - self.viewCenter[0] dy = self.coordsMouse[1] - self.viewCenter[1] distance = math.sqrt((dx * dx) + (dy * dy)) # distance from mouse to view center # coordinates we are interested in #self.coordsMouse # x,y of this widget coordsxy = (-1, -1) # x,y over photo as scaled/rendered on this widget coordsXY = (-1, -1) # x,y over actual original photo on disk coordsUV = (-1, -1) # u,v coords of fisheye portion of photo w/ 0,0 top left and 1,1 bottom right coordsTP = (-1, -1) # theta,phi polar coordinates # text textxy = "-1, -1 xy" textXY = "-1, -1 xy" textUV = "-1, -1 uv" textTP = "-1, -1 θφ" textPX = "0 0 0 px" # compute all relevant information only when mouse is within fisheye portion of photo if distance < self.myPhotoRadius: coordsxy = (self.coordsMouse[0] - self.myPhotoDestRect.x(), self.coordsMouse[1] - self.myPhotoDestRect.y()) coordsXY = (int(coordsxy[0] / self.myPhotoDestRect.width() * self.myPhoto.width()), int(coordsxy[1] / self.myPhotoDestRect.height() * self.myPhoto.height())) coordsUV = ((self.coordsMouse[0] - self.myPhotoTopLeft[0]) / self.myPhotoDiameter, (self.coordsMouse[1] - self.myPhotoTopLeft[1]) / self.myPhotoDiameter) coordsTP = utility_angles.FisheyeUV2SkyCoord(coordsUV[0], coordsUV[1]) # text textxy = str(coordsxy[0]) + ", " + str(coordsxy[1]) + " xy" textXY = str(coordsXY[0]) + ", " + str(coordsXY[1]) + " xy" textUV = "{:.2f}".format(coordsUV[0]) + ", " + "{:.2f}".format(coordsUV[1]) + " uv" textTP = "{:.2f}".format(coordsTP[0]) + ", " + "{:.2f}".format(coordsTP[1]) + " θφ" # pixels colors pixreg = common.AppSettings["PixelRegion"] colorsRegion = np.zeros((pixreg, pixreg, 4)) colorFinal = colorsRegion[0,0] # RGBA of pixel under mouse of photo on disk # colorFinal = self.myPhoto.pixelColor(coordsXY[0], coordsXY[1]) if distance < self.myPhotoRadius: halfdim = int(pixreg / 2) rstart = coordsXY[1]-halfdim rstop = coordsXY[1]+halfdim+1 cstart = coordsXY[0]-halfdim cstop = coordsXY[0]+halfdim+1 if (rstart >= 0 and rstop<=self.myPhotoPixels.shape[0] and cstart >= 0 and cstop<=self.myPhotoPixels.shape[1]): colorsRegion = self.myPhotoPixels[rstart:rstop, cstart:cstop] colorFinal = colorsRegion[halfdim, halfdim] if pixreg > 1: # with pixel weighting colorFinal = utility_data.collectPixels([coordsXY], [pixreg], pixels=self.myPhotoPixels, weighting=common.PixelWeighting(common.AppSettings["PixelWeighting"]))[0] textPX = str(colorFinal[0]) + " " + str(colorFinal[1]) + " " + str(colorFinal[2]) + " px" # draw HUD text strings # x,y coords destRect.setCoords(0, 0, self.width() - 10, self.height()- 124) painter.drawText(destRect, Qt.AlignBottom | Qt.AlignRight, textxy) # X,Y coords destRect.setCoords(0, 0, self.width() - 10, self.height() - 114) painter.drawText(destRect, Qt.AlignBottom | Qt.AlignRight, textXY) # u,v coords destRect.setCoords(0, 0, self.width() - 10, self.height() - 104) painter.drawText(destRect, Qt.AlignBottom | Qt.AlignRight, textUV) # t,p coords destRect.setCoords(0, 0, self.width() - 10, self.height() - 94) painter.drawText(destRect, Qt.AlignBottom | Qt.AlignRight, textTP) # pixel color destRect.setCoords(0, 0, self.width() - 10, self.height() - 84) painter.drawText(destRect, Qt.AlignBottom | Qt.AlignRight, textPX) # compute pixel visualization coordinates circleX = self.width() - 10 - ViewFisheye.SelectedPixelBox - 10 - ViewFisheye.SelectedPixelBox - 10 - ViewFisheye.SelectedPixelBox circleY = self.height() - 10 - ViewFisheye.SelectedPixelBox pixelsX = self.width() - 10 - ViewFisheye.SelectedPixelBox - 10 - ViewFisheye.SelectedPixelBox pixelsY = self.height() - 10 - ViewFisheye.SelectedPixelBox pixelsWeightedX = self.width() - ViewFisheye.SelectedPixelBox - 10 pixelsWeightedY = self.height() - 10 - ViewFisheye.SelectedPixelBox # draw pixel visualization - fills pixreg = common.AppSettings["PixelRegion"] if distance < self.myPhotoRadius: painter.setPen(Qt.NoPen) # pixel region pixdim = ViewFisheye.SelectedPixelBox / pixreg for row in range(0, pixreg): for col in range(0, pixreg): color = colorsRegion[row, col] color = QColor(color[0], color[1], color[2]) painter.setBrush(QBrush(color, Qt.SolidPattern)) painter.drawRect(pixelsX + (col * pixdim), pixelsY + (row * pixdim), math.ceil(pixdim), math.ceil(pixdim)) # final pixel color color = QColor(colorFinal[0], colorFinal[1], colorFinal[2]) painter.setBrush(QBrush(color, Qt.SolidPattern)) cx = circleX + (coordsUV[0] * ViewFisheye.SelectedPixelBox) cy = circleY + (coordsUV[1] * ViewFisheye.SelectedPixelBox) painter.drawEllipse(cx - 5, cy - 5, 10, 10) painter.drawRect(pixelsWeightedX, pixelsWeightedY, ViewFisheye.SelectedPixelBox, ViewFisheye.SelectedPixelBox) # draw pixel visualization - outlines painter.setPen(self.penText) painter.setBrush(Qt.NoBrush) painter.drawEllipse(circleX, circleY, ViewFisheye.SelectedPixelBox, ViewFisheye.SelectedPixelBox) painter.drawRect(pixelsX, pixelsY, ViewFisheye.SelectedPixelBox, ViewFisheye.SelectedPixelBox) painter.drawRect(pixelsWeightedX, pixelsWeightedY, ViewFisheye.SelectedPixelBox, ViewFisheye.SelectedPixelBox) # raw data missing indicator # if (not self.rawAvailable): # painter.drawPixmap(pixelX + ViewFisheye.SelectedPixelBox / 2, # pixelY + ViewFisheye.SelectedPixelBox / 2, # self.iconWarning) # end draw painter.end()
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 paintEvent(self, evt): """ Protected method handling paint events. @param evt paint event (QPaintEvent) """ if self.__grabbing: # grabWindow() should just get the background return painter = QPainter(self) pal = QPalette(QToolTip.palette()) font = QToolTip.font() handleColor = pal.color(QPalette.Active, QPalette.Highlight) handleColor.setAlpha(160) overlayColor = QColor(0, 0, 0, 160) textColor = pal.color(QPalette.Active, QPalette.Text) textBackgroundColor = pal.color(QPalette.Active, QPalette.Base) painter.drawPixmap(0, 0, self.__pixmap) painter.setFont(font) r = QRect(self.__selection) if not self.__selection.isNull(): grey = QRegion(self.rect()) if self.__mode == SnapshotRegionGrabber.Ellipse: reg = QRegion(r, QRegion.Ellipse) else: reg = QRegion(r) grey = grey.subtracted(reg) painter.setClipRegion(grey) painter.setPen(Qt.NoPen) painter.setBrush(overlayColor) painter.drawRect(self.rect()) painter.setClipRect(self.rect()) drawRect(painter, r, handleColor) if self.__showHelp: painter.setPen(textColor) painter.setBrush(textBackgroundColor) self.__helpTextRect = painter.boundingRect( self.rect().adjusted(2, 2, -2, -2), Qt.TextWordWrap, self.__helpText).translated(-self.__desktop.x(), -self.__desktop.y()) self.__helpTextRect.adjust(-2, -2, 4, 2) drawRect(painter, self.__helpTextRect, textColor, textBackgroundColor) painter.drawText(self.__helpTextRect.adjusted(3, 3, -3, -3), Qt.TextWordWrap, self.__helpText) if self.__selection.isNull(): return # The grabbed region is everything which is covered by the drawn # rectangles (border included). This means that there is no 0px # selection, since a 0px wide rectangle will always be drawn as a line. txt = "{0}, {1} ({2} x {3})".format( self.__locale.toString(self.__selection.x()), self.__locale.toString(self.__selection.y()), self.__locale.toString(self.__selection.width()), self.__locale.toString(self.__selection.height())) textRect = painter.boundingRect(self.rect(), Qt.AlignLeft, txt) boundingRect = textRect.adjusted(-4, 0, 0, 0) if textRect.width() < r.width() - 2 * self.__handleSize and \ textRect.height() < r.height() - 2 * self.__handleSize and \ r.width() > 100 and \ r.height() > 100: # center, unsuitable for small selections boundingRect.moveCenter(r.center()) textRect.moveCenter(r.center()) elif r.y() - 3 > textRect.height() and \ r.x() + textRect.width() < self.rect().width(): # on top, left aligned boundingRect.moveBottomLeft(QPoint(r.x(), r.y() - 3)) textRect.moveBottomLeft(QPoint(r.x() + 2, r.y() - 3)) elif r.x() - 3 > textRect.width(): # left, top aligned boundingRect.moveTopRight(QPoint(r.x() - 3, r.y())) textRect.moveTopRight(QPoint(r.x() - 5, r.y())) elif r.bottom() + 3 + textRect.height() < self.rect().bottom() and \ r.right() > textRect.width(): # at bottom, right aligned boundingRect.moveTopRight(QPoint(r.right(), r.bottom() + 3)) textRect.moveTopRight(QPoint(r.right() - 2, r.bottom() + 3)) elif r.right() + textRect.width() + 3 < self.rect().width(): # right, bottom aligned boundingRect.moveBottomLeft(QPoint(r.right() + 3, r.bottom())) textRect.moveBottomLeft(QPoint(r.right() + 5, r.bottom())) # If the above didn't catch it, you are running on a very # tiny screen... drawRect(painter, boundingRect, textColor, textBackgroundColor) painter.drawText(textRect, Qt.AlignHCenter, txt) if (r.height() > self.__handleSize * 2 and r.width() > self.__handleSize * 2) or \ not self.__mouseDown: self.__updateHandles() painter.setPen(Qt.NoPen) painter.setBrush(handleColor) painter.setClipRegion( self.__handleMask(SnapshotRegionGrabber.StrokeMask)) painter.drawRect(self.rect()) handleColor.setAlpha(60) painter.setBrush(handleColor) painter.setClipRegion( self.__handleMask(SnapshotRegionGrabber.FillMask)) painter.drawRect(self.rect())
class corkDelegate(QStyledItemDelegate): def __init__(self, parent=None): QStyledItemDelegate.__init__(self, parent) self.factor = settings.corkSizeFactor / 100. self.lastPos = None self.editing = None self.margin = 5 self.bgColors = {} def newStyle(self): return settings.corkStyle == "new" def setCorkSizeFactor(self, v): self.factor = v / 100. def sizeHint(self, option, index): if self.newStyle(): defaultSize = QSize(300, 210) else: defaultSize = QSize(300, 200) return defaultSize * self.factor def editorEvent(self, event, model, option, index): # We catch the mouse position in the widget to know which part to edit if type(event) == QMouseEvent: self.lastPos = event.pos() # - option.rect.topLeft() return QStyledItemDelegate.editorEvent(self, event, model, option, index) def createEditor(self, parent, option, index): # When the user performs a global search and selects an Outline result (title or summary), the # associated chapter is selected in cork view, triggering a call to this method with the results # list widget set in self.sender(). In this case we store the searched column so we know which # editor should be created. searchedColumn = None if self.sender() is not None and self.sender().objectName( ) == 'result' and self.sender().currentItem(): searchedColumn = self.sender().currentItem().data( Qt.UserRole).column() self.updateRects(option, index) bgColor = self.bgColors.get(index, "white") if searchedColumn == Outline.summarySentence or ( self.lastPos is not None and self.mainLineRect.contains(self.lastPos)): # One line summary self.editing = Outline.summarySentence edt = QLineEdit(parent) edt.setFocusPolicy(Qt.StrongFocus) edt.setFrame(False) f = QFont(option.font) if self.newStyle(): f.setBold(True) else: f.setItalic(True) edt.setAlignment(Qt.AlignCenter) edt.setPlaceholderText(self.tr("One line summary")) edt.setFont(f) edt.setStyleSheet("background: {}; color: black;".format(bgColor)) return edt elif searchedColumn == Outline.title or (self.lastPos is not None and self.titleRect.contains( self.lastPos)): # Title self.editing = Outline.title edt = QLineEdit(parent) edt.setFocusPolicy(Qt.StrongFocus) edt.setFrame(False) f = QFont(option.font) if self.newStyle(): f.setPointSize(f.pointSize() + 4) else: edt.setAlignment(Qt.AlignCenter) f.setBold(True) edt.setFont(f) edt.setStyleSheet("background: {}; color: black;".format(bgColor)) # edt.setGeometry(self.titleRect) return edt else: # self.mainTextRect.contains(self.lastPos): # Summary self.editing = Outline.summaryFull edt = QPlainTextEdit(parent) edt.setFocusPolicy(Qt.StrongFocus) edt.setFrameShape(QFrame.NoFrame) try: # QPlainTextEdit.setPlaceholderText was introduced in Qt 5.3 edt.setPlaceholderText(self.tr("Full summary")) except AttributeError: pass edt.setStyleSheet("background: {}; color: black;".format(bgColor)) return edt def updateEditorGeometry(self, editor, option, index): if self.editing == Outline.summarySentence: # One line summary editor.setGeometry(self.mainLineRect) elif self.editing == Outline.title: # Title editor.setGeometry(self.titleRect) elif self.editing == Outline.summaryFull: # Summary editor.setGeometry(self.mainTextRect) def setEditorData(self, editor, index): item = index.internalPointer() if self.editing == Outline.summarySentence: # One line summary editor.setText(item.data(Outline.summarySentence)) elif self.editing == Outline.title: # Title editor.setText(index.data()) elif self.editing == Outline.summaryFull: # Summary editor.setPlainText(item.data(Outline.summaryFull)) def setModelData(self, editor, model, index): if self.editing == Outline.summarySentence: # One line summary model.setData(index.sibling(index.row(), Outline.summarySentence), editor.text()) elif self.editing == Outline.title: # Title model.setData(index, editor.text(), Outline.title) elif self.editing == Outline.summaryFull: # Summary model.setData(index.sibling(index.row(), Outline.summaryFull), editor.toPlainText()) def updateRects(self, option, index): if self.newStyle(): self.updateRects_v2(option, index) else: self.updateRects_v1(option, index) def updateRects_v2(self, option, index): margin = self.margin * 2 iconSize = max(24 * self.factor, 18) item = index.internalPointer() fm = QFontMetrics(option.font) h = fm.lineSpacing() self.itemRect = option.rect.adjusted(margin, margin, -margin, -margin) top = 15 * self.factor self.topRect = QRect(self.itemRect) self.topRect.setHeight(top) self.cardRect = QRect(self.itemRect.topLeft() + QPoint(0, top), self.itemRect.bottomRight()) self.iconRect = QRect(self.cardRect.topLeft() + QPoint(margin, margin), QSize(iconSize, iconSize)) self.labelRect = QRect( self.cardRect.topRight() - QPoint(margin + self.factor * 18, 1), self.cardRect.topRight() + QPoint(-margin - self.factor * 4, self.factor * 24)) self.titleRect = QRect( self.iconRect.topRight() + QPoint(margin, 0), self.labelRect.bottomLeft() - QPoint(margin, margin)) self.titleRect.setBottom(self.iconRect.bottom()) self.mainRect = QRect( self.iconRect.bottomLeft() + QPoint(0, margin), self.cardRect.bottomRight() - QPoint(margin, 2 * margin)) self.mainRect.setLeft(self.titleRect.left()) self.mainLineRect = QRect(self.mainRect.topLeft(), self.mainRect.topRight() + QPoint(0, h)) self.mainTextRect = QRect( self.mainLineRect.bottomLeft() + QPoint(0, margin), self.mainRect.bottomRight()) if not item.data(Outline.summarySentence): self.mainTextRect.setTopLeft(self.mainLineRect.topLeft()) def updateRects_v1(self, option, index): margin = self.margin iconSize = max(16 * self.factor, 12) item = index.internalPointer() self.itemRect = option.rect.adjusted(margin, margin, -margin, -margin) self.iconRect = QRect(self.itemRect.topLeft() + QPoint(margin, margin), QSize(iconSize, iconSize)) self.labelRect = QRect( self.itemRect.topRight() - QPoint(iconSize + margin, 0), self.itemRect.topRight() + QPoint(0, iconSize + 2 * margin)) self.titleRect = QRect( self.iconRect.topRight() + QPoint(margin, 0), self.labelRect.bottomLeft() - QPoint(margin, margin)) self.bottomRect = QRect( QPoint(self.itemRect.x(), self.iconRect.bottom() + margin), QPoint(self.itemRect.right(), self.itemRect.bottom())) self.topRect = QRect(self.itemRect.topLeft(), self.bottomRect.topRight()) self.mainRect = self.bottomRect.adjusted(margin, margin, -margin, -margin) self.mainLineRect = QRect( self.mainRect.topLeft(), self.mainRect.topRight() + QPoint(0, iconSize)) self.mainTextRect = QRect( self.mainLineRect.bottomLeft() + QPoint(0, margin), self.mainRect.bottomRight()) if not item.data(Outline.summarySentence): self.mainTextRect.setTopLeft(self.mainLineRect.topLeft()) if item.data(Outline.label) in ["", "0", 0]: self.titleRect.setBottomRight(self.labelRect.bottomRight() - QPoint(self.margin, self.margin)) def paint(self, p, option, index): if self.newStyle(): self.paint_v2(p, option, index) else: self.paint_v1(p, option, index) def paint_v2(self, p, option, index): # QStyledItemDelegate.paint(self, p, option, index) if not index.isValid(): return item = index.internalPointer() self.updateRects(option, index) colors = outlineItemColors(item) style = qApp.style() def _rotate(angle, rect=self.mainRect): p.translate(rect.center()) p.rotate(angle) p.translate(-rect.center()) def drawRect(r): p.save() p.setBrush(Qt.gray) p.drawRect(r) p.restore() # Draw background cg = QPalette.ColorGroup(QPalette.Normal if option.state & QStyle.State_Enabled else QPalette.Disabled) if cg == QPalette.Normal and not option.state & QStyle.State_Active: cg = QPalette.Inactive # Selection if option.state & QStyle.State_Selected: p.save() p.setBrush(option.palette.brush(cg, QPalette.Highlight)) p.setPen(Qt.NoPen) #p.drawRoundedRect(option.rect, 12, 12) p.drawRect(option.rect) p.restore() # Background p.save() if settings.viewSettings["Cork"]["Background"] != "Nothing": c = colors[settings.viewSettings["Cork"]["Background"]] if c == QColor(Qt.transparent): c = QColor(Qt.white) col = mixColors(c, QColor(Qt.white), .2) backgroundColor = col p.setBrush(col) else: p.setBrush(Qt.white) backgroundColor = QColor(Qt.white) # Cache background color self.bgColors[index] = backgroundColor.name() p.setPen(Qt.NoPen) p.drawRect(self.cardRect) if item.isFolder(): itemPoly = QPolygonF([ self.topRect.topLeft(), self.topRect.topLeft() + QPoint(self.topRect.width() * .35, 0), self.cardRect.topLeft() + QPoint(self.topRect.width() * .45, 0), self.cardRect.topRight(), self.cardRect.bottomRight(), self.cardRect.bottomLeft() ]) p.drawPolygon(itemPoly) p.restore() # Label color if settings.viewSettings["Cork"]["Corner"] != "Nothing": p.save() color = colors[settings.viewSettings["Cork"]["Corner"]] p.setPen(Qt.NoPen) p.setBrush(color) p.drawRect(self.labelRect) w = self.labelRect.width() poly = QPolygonF([ self.labelRect.bottomLeft() + QPointF(0, 1), self.labelRect.bottomLeft() + QPointF(0, w / 2), self.labelRect.bottomLeft() + QPointF(w / 2, 1), self.labelRect.bottomRight() + QPointF(1, w / 2), self.labelRect.bottomRight() + QPointF(1, 1), ]) p.drawPolygon(poly) p.restore() if settings.viewSettings["Cork"]["Corner"] == "Nothing" or \ color == Qt.transparent: # No corner, so title can be full width self.titleRect.setRight(self.mainRect.right()) # Draw the icon iconRect = self.iconRect mode = QIcon.Normal if not option.state & style.State_Enabled: mode = QIcon.Disabled elif option.state & style.State_Selected: mode = QIcon.Selected # index.data(Qt.DecorationRole).paint(p, iconRect, option.decorationAlignment, mode) icon = index.data(Qt.DecorationRole).pixmap(iconRect.size()) if settings.viewSettings["Cork"]["Icon"] != "Nothing": color = colors[settings.viewSettings["Cork"]["Icon"]] colorifyPixmap(icon, color) QIcon(icon).paint(p, iconRect, option.decorationAlignment, mode) # Draw title p.save() text = index.data() if text: p.setPen(Qt.black) textColor = QColor(Qt.black) if settings.viewSettings["Cork"]["Text"] != "Nothing": col = colors[settings.viewSettings["Cork"]["Text"]] if col == Qt.transparent: col = Qt.black # If title setting is compile, we have to hack the color # Or we won't see anything in some themes if settings.viewSettings["Cork"]["Text"] == "Compile": if item.compile() in [0, "0"]: col = mixColors(QColor(Qt.black), backgroundColor) else: col = Qt.black textColor = col p.setPen(col) f = QFont(option.font) f.setPointSize(f.pointSize() + 4) f.setBold(True) p.setFont(f) fm = QFontMetrics(f) elidedText = fm.elidedText(text, Qt.ElideRight, self.titleRect.width()) p.drawText(self.titleRect, Qt.AlignLeft | Qt.AlignVCenter, elidedText) p.restore() # One line summary background lineSummary = item.data(Outline.summarySentence) fullSummary = item.data(Outline.summaryFull) # Border if settings.viewSettings["Cork"]["Border"] != "Nothing": p.save() p.setBrush(Qt.NoBrush) pen = p.pen() pen.setWidth(2) col = colors[settings.viewSettings["Cork"]["Border"]] pen.setColor(col) p.setPen(pen) if item.isFolder(): p.drawPolygon(itemPoly) else: p.drawRect(self.cardRect) p.restore() # Draw status status = item.data(Outline.status) if status: it = mainWindow().mdlStatus.item(int(status), 0) if it != None: p.save() p.setClipRegion(QRegion(self.cardRect)) f = p.font() f.setPointSize(f.pointSize() + 12) f.setBold(True) p.setFont(f) p.setPen(QColor(Qt.red).lighter(170)) _rotate(-35, rect=self.cardRect) p.drawText(self.cardRect, Qt.AlignCenter, it.text()) p.restore() # Draw Summary # One line if lineSummary: p.save() f = QFont(option.font) f.setBold(True) p.setFont(f) p.setPen(textColor) fm = QFontMetrics(f) elidedText = fm.elidedText(lineSummary, Qt.ElideRight, self.mainLineRect.width()) p.drawText(self.mainLineRect, Qt.AlignLeft | Qt.AlignVCenter, elidedText) p.restore() # Full summary if fullSummary: p.save() p.setFont(option.font) p.setPen(textColor) p.drawText(self.mainTextRect, Qt.TextWordWrap, fullSummary) p.restore() def paint_v1(self, p, option, index): # QStyledItemDelegate.paint(self, p, option, index) if not index.isValid(): return item = index.internalPointer() self.updateRects(option, index) colors = outlineItemColors(item) style = qApp.style() def _rotate(angle): p.translate(self.mainRect.center()) p.rotate(angle) p.translate(-self.mainRect.center()) # Draw background cg = QPalette.ColorGroup(QPalette.Normal if option.state & QStyle.State_Enabled else QPalette.Disabled) if cg == QPalette.Normal and not option.state & QStyle.State_Active: cg = QPalette.Inactive # Selection if option.state & QStyle.State_Selected: p.save() p.setBrush(option.palette.brush(cg, QPalette.Highlight)) p.setPen(Qt.NoPen) p.drawRoundedRect(option.rect, 12, 12) p.restore() # Stack if item.isFolder() and item.childCount() > 0: p.save() p.setBrush(Qt.white) for i in reversed(range(3)): p.drawRoundedRect( self.itemRect.adjusted(2 * i, 2 * i, -2 * i, 2 * i), 10, 10) p.restore() # Background itemRect = self.itemRect p.save() if settings.viewSettings["Cork"]["Background"] != "Nothing": c = colors[settings.viewSettings["Cork"]["Background"]] col = mixColors(c, QColor(Qt.white), .2) p.setBrush(col) else: p.setBrush(Qt.white) pen = p.pen() pen.setWidth(2) p.setPen(pen) p.drawRoundedRect(itemRect, 10, 10) p.restore() # Title bar topRect = self.topRect p.save() if item.isFolder(): color = QColor(Qt.darkGreen) else: color = QColor(Qt.blue).lighter(175) p.setPen(Qt.NoPen) p.setBrush(color) p.setClipRegion(QRegion(topRect)) p.drawRoundedRect(itemRect, 10, 10) # p.drawRect(topRect) p.restore() # Label color if settings.viewSettings["Cork"]["Corner"] != "Nothing": p.save() color = colors[settings.viewSettings["Cork"]["Corner"]] p.setPen(Qt.NoPen) p.setBrush(color) p.setClipRegion(QRegion(self.labelRect)) p.drawRoundedRect(itemRect, 10, 10) # p.drawRect(topRect) p.restore() if color != Qt.transparent: p.drawLine(self.labelRect.topLeft(), self.labelRect.bottomLeft()) # One line summary background lineSummary = item.data(Outline.summarySentence) fullSummary = item.data(Outline.summaryFull) if lineSummary or not fullSummary: m = self.margin r = self.mainLineRect.adjusted(-m, -m, m, m / 2) p.save() p.setPen(Qt.NoPen) p.setBrush(QColor("#EEE")) p.drawRect(r) p.restore() # Border p.save() p.setBrush(Qt.NoBrush) pen = p.pen() pen.setWidth(2) if settings.viewSettings["Cork"]["Border"] != "Nothing": col = colors[settings.viewSettings["Cork"]["Border"]] if col == Qt.transparent: col = Qt.black pen.setColor(col) p.setPen(pen) p.drawRoundedRect(itemRect, 10, 10) p.restore() # Draw the icon iconRect = self.iconRect mode = QIcon.Normal if not option.state & style.State_Enabled: mode = QIcon.Disabled elif option.state & style.State_Selected: mode = QIcon.Selected # index.data(Qt.DecorationRole).paint(p, iconRect, option.decorationAlignment, mode) icon = index.data(Qt.DecorationRole).pixmap(iconRect.size()) if settings.viewSettings["Cork"]["Icon"] != "Nothing": color = colors[settings.viewSettings["Cork"]["Icon"]] colorifyPixmap(icon, color) QIcon(icon).paint(p, iconRect, option.decorationAlignment, mode) # Draw title p.save() text = index.data() titleRect = self.titleRect if text: if settings.viewSettings["Cork"]["Text"] != "Nothing": col = colors[settings.viewSettings["Cork"]["Text"]] if col == Qt.transparent: col = Qt.black p.setPen(col) f = QFont(option.font) # f.setPointSize(f.pointSize() + 1) f.setBold(True) p.setFont(f) fm = QFontMetrics(f) elidedText = fm.elidedText(text, Qt.ElideRight, titleRect.width()) p.drawText(titleRect, Qt.AlignCenter, elidedText) p.restore() # Draw the line bottomRect = self.bottomRect p.save() # p.drawLine(itemRect.x(), iconRect.bottom() + margin, # itemRect.right(), iconRect.bottom() + margin) p.drawLine(bottomRect.topLeft(), bottomRect.topRight()) p.restore() # Lines if True: p.save() p.setPen(QColor("#EEE")) fm = QFontMetrics(option.font) h = fm.lineSpacing() l = self.mainTextRect.topLeft() + QPoint(0, h) while self.mainTextRect.contains(l): p.drawLine(l, QPoint(self.mainTextRect.right(), l.y())) l.setY(l.y() + h) p.restore() # Draw status mainRect = self.mainRect status = item.data(Outline.status) if status: it = mainWindow().mdlStatus.item(int(status), 0) if it != None: p.save() p.setClipRegion(QRegion(mainRect)) f = p.font() f.setPointSize(f.pointSize() + 12) f.setBold(True) p.setFont(f) p.setPen(QColor(Qt.red).lighter(175)) _rotate(-35) p.drawText(mainRect, Qt.AlignCenter, it.text()) p.restore() # Draw Summary # One line if lineSummary: p.save() f = QFont(option.font) f.setItalic(True) p.setFont(f) fm = QFontMetrics(f) elidedText = fm.elidedText(lineSummary, Qt.ElideRight, self.mainLineRect.width()) p.drawText(self.mainLineRect, Qt.AlignCenter, elidedText) p.restore() # Full summary if fullSummary: p.setFont(option.font) p.drawText(self.mainTextRect, Qt.TextWordWrap, fullSummary)
class PFSTags(QWidget): removed = pyqtSignal(object) def __init__(self, name, use=""): QWidget.__init__(self) self._name = name self._use = use self._font = QFont("Serif", 8) self._rect = QRect(0, 0, 10, 10) self._brush = QBrush(Qt.white, Qt.SolidPattern) def clone(self): ans = PFSTags(self._name, self._use) ans.removed.connect(self.removed.emit) return ans def simpleUse(self): if len(self._use) > 16: return self._use[:8] + "\n" + self._use[8:13] + "..." if len(self._use) > 8: return self._use[:5] + "..." return self._use def simpleName(self): if len(self._name) > 30: return self._name[:10] + "\n" + self._name[ 10:20] + "\n" + self._name[20:27] + "..." if len(self._name) > 20: return self._name[:10] + "\n" + self._name[10:17] + "..." if len(self._name) > 10: return self._name[:7] + "..." return self._name def updateRect(self): fm = QFontMetrics(self._font) self._useRect = fm.size(Qt.TextExpandTabs, self.simpleUse()) self._nameRect = fm.size(Qt.TextExpandTabs, self.simpleName()) self._rect = QRect( 0, 0, self._useRect.width() + self._nameRect.width() + 23, max(self._useRect.height(), self._nameRect.height()) + 4) x = self._useRect.width() + self._nameRect.width() + 12 y = self._rect.center().y() - 3 self._closeRect = QRect(x, y, 6, 6) def paintEvent(self, ev): self.updateRect() p = QPainter(self) p.setBrush(self._brush) p.drawRoundedRect(self._rect, 10, 10) p.drawLine(self._useRect.width() + 6, self._rect.top(), self._useRect.width() + 6, self._rect.bottom()) p.setFont(self._font) p.drawText(3, 0, self._useRect.width(), self._rect.height(), Qt.AlignCenter, self.simpleUse()) p.drawText(self._useRect.width() + 9, 0, self._nameRect.width(), self._rect.height(), Qt.AlignCenter, self.simpleName()) p.drawLine(self._closeRect.topLeft(), self._closeRect.bottomRight()) p.drawLine(self._closeRect.bottomLeft(), self._closeRect.topRight()) def mousePressEvent(self, ev: QMouseEvent): if self._closeRect.contains(ev.pos()): self.removed.emit(self) def __eq__(self, other): if not isinstance(other, PFSTags): return False return self._name == other._name and self._use == other._use
def paintEvent(self, evt): """ Protected method handling paint events. @param evt paint event (QPaintEvent) """ if self.__grabbing: # grabWindow() should just get the background return painter = QPainter(self) pal = QPalette(QToolTip.palette()) font = QToolTip.font() handleColor = pal.color(QPalette.Active, QPalette.Highlight) handleColor.setAlpha(160) overlayColor = QColor(0, 0, 0, 160) textColor = pal.color(QPalette.Active, QPalette.Text) textBackgroundColor = pal.color(QPalette.Active, QPalette.Base) painter.drawPixmap(0, 0, self.__pixmap) painter.setFont(font) r = QRect(self.__selection) if not self.__selection.isNull(): grey = QRegion(self.rect()) if self.__mode == SnapshotRegionGrabber.Ellipse: reg = QRegion(r, QRegion.Ellipse) else: reg = QRegion(r) grey = grey.subtracted(reg) painter.setClipRegion(grey) painter.setPen(Qt.NoPen) painter.setBrush(overlayColor) painter.drawRect(self.rect()) painter.setClipRect(self.rect()) drawRect(painter, r, handleColor) if self.__showHelp: painter.setPen(textColor) painter.setBrush(textBackgroundColor) self.__helpTextRect = painter.boundingRect( self.rect().adjusted(2, 2, -2, -2), Qt.TextWordWrap, self.__helpText).translated( -self.__desktop.x(), -self.__desktop.y()) self.__helpTextRect.adjust(-2, -2, 4, 2) drawRect(painter, self.__helpTextRect, textColor, textBackgroundColor) painter.drawText( self.__helpTextRect.adjusted(3, 3, -3, -3), Qt.TextWordWrap, self.__helpText) if self.__selection.isNull(): return # The grabbed region is everything which is covered by the drawn # rectangles (border included). This means that there is no 0px # selection, since a 0px wide rectangle will always be drawn as a line. txt = "{0:n}, {1:n} ({2:n} x {3:n})".format( self.__selection.x(), self.__selection.y(), self.__selection.width(), self.__selection.height()) textRect = painter.boundingRect(self.rect(), Qt.AlignLeft, txt) boundingRect = textRect.adjusted(-4, 0, 0, 0) if textRect.width() < r.width() - 2 * self.__handleSize and \ textRect.height() < r.height() - 2 * self.__handleSize and \ r.width() > 100 and \ r.height() > 100: # center, unsuitable for small selections boundingRect.moveCenter(r.center()) textRect.moveCenter(r.center()) elif r.y() - 3 > textRect.height() and \ r.x() + textRect.width() < self.rect().width(): # on top, left aligned boundingRect.moveBottomLeft(QPoint(r.x(), r.y() - 3)) textRect.moveBottomLeft(QPoint(r.x() + 2, r.y() - 3)) elif r.x() - 3 > textRect.width(): # left, top aligned boundingRect.moveTopRight(QPoint(r.x() - 3, r.y())) textRect.moveTopRight(QPoint(r.x() - 5, r.y())) elif r.bottom() + 3 + textRect.height() < self.rect().bottom() and \ r.right() > textRect.width(): # at bottom, right aligned boundingRect.moveTopRight(QPoint(r.right(), r.bottom() + 3)) textRect.moveTopRight(QPoint(r.right() - 2, r.bottom() + 3)) elif r.right() + textRect.width() + 3 < self.rect().width(): # right, bottom aligned boundingRect.moveBottomLeft(QPoint(r.right() + 3, r.bottom())) textRect.moveBottomLeft(QPoint(r.right() + 5, r.bottom())) # If the above didn't catch it, you are running on a very # tiny screen... drawRect(painter, boundingRect, textColor, textBackgroundColor) painter.drawText(textRect, Qt.AlignHCenter, txt) if (r.height() > self.__handleSize * 2 and r.width() > self.__handleSize * 2) or \ not self.__mouseDown: self.__updateHandles() painter.setPen(Qt.NoPen) painter.setBrush(handleColor) painter.setClipRegion( self.__handleMask(SnapshotRegionGrabber.StrokeMask)) painter.drawRect(self.rect()) handleColor.setAlpha(60) painter.setBrush(handleColor) painter.setClipRegion( self.__handleMask(SnapshotRegionGrabber.FillMask)) painter.drawRect(self.rect())
def draw_tracker_pixmap(self, cursor_pos): tracker_pixmap = QPixmap(self.parent.size()) tracker_pixmap.fill(QColor(255, 255, 255, 0)) qpainter = QPainter() qpainter.begin(tracker_pixmap) origin = self.calc_gui_point([0, 0]) axis_origin = [ max(min(origin[0], self.parent.width() - self.axis_margin[0]), self.axis_margin[0]), max(min(origin[1], self.parent.height() - self.axis_margin[1]), self.axis_margin[1]) ] qpainter.setPen(self.axis_pen) pnt = self.calc_val_point([cursor_pos.x(), cursor_pos.y()]) x_label = str(round(pnt[0], 2)) y_label = str(round(pnt[1], 2)) str_rect = QRect(cursor_pos.x() + 5, axis_origin[1], qpainter.fontMetrics().width(x_label), 25) g_rect = QRect(str_rect.x() - 30, str_rect.y(), 30, str_rect.height()) gradient = QLinearGradient(QPoint(g_rect.right(), g_rect.center().y()), QPoint(g_rect.left(), g_rect.center().y())) gradient.setColorAt(0, QColor(255, 255, 255)) gradient.setColorAt(1, QColor(255, 255, 255, 0)) qpainter.fillRect(g_rect, gradient) g_rect = QRect(str_rect.right(), str_rect.y(), 30, str_rect.height()) gradient = QLinearGradient(QPoint(g_rect.left(), g_rect.center().y()), QPoint(g_rect.right(), g_rect.center().y())) gradient.setColorAt(0, QColor(255, 255, 255)) gradient.setColorAt(1, QColor(255, 255, 255, 0)) qpainter.fillRect(g_rect, gradient) qpainter.fillRect(str_rect, QColor(255, 255, 255)) qpainter.drawText(str_rect, Qt.AlignLeft | Qt.AlignCenter, x_label) qpainter.drawLine(cursor_pos.x(), axis_origin[1], cursor_pos.x(), axis_origin[1] + 10) label_width = qpainter.fontMetrics().width(y_label) str_rect = QRect(axis_origin[0] - label_width - 1, cursor_pos.y() + 1, label_width, 15) g_rect = QRect(str_rect.x(), str_rect.y() - 10, str_rect.width(), 10) gradient = QLinearGradient( QPoint(g_rect.center().x(), g_rect.bottom()), QPoint(g_rect.center().x(), g_rect.top())) gradient.setColorAt(0, QColor(255, 255, 255)) gradient.setColorAt(1, QColor(255, 255, 255, 0)) qpainter.fillRect(g_rect, gradient) g_rect = QRect(str_rect.x(), str_rect.bottom(), str_rect.width(), 10) gradient = QLinearGradient( QPoint(g_rect.center().x(), g_rect.top()), QPoint(g_rect.center().x(), g_rect.bottom())) gradient.setColorAt(0, QColor(255, 255, 255)) gradient.setColorAt(1, QColor(255, 255, 255, 0)) qpainter.fillRect(g_rect, gradient) qpainter.fillRect(str_rect, QColor(255, 255, 255)) qpainter.drawText(str_rect, Qt.AlignRight | Qt.AlignCenter, y_label) qpainter.drawLine(axis_origin[0], cursor_pos.y(), axis_origin[0] - 10, cursor_pos.y()) qpainter.end() return tracker_pixmap
def __paintEventNoStyle(self): p = QPainter(self) opt = QStyleOptionToolButton() self.initStyleOption(opt) fm = QFontMetrics(opt.font) palette = opt.palette # highlight brush is used as the background for the icon and background # when the tab is expanded and as mouse hover color (lighter). brush_highlight = palette.highlight() foregroundrole = QPalette.ButtonText if opt.state & QStyle.State_Sunken: # State 'down' pressed during a mouse press (slightly darker). background_brush = brush_darker(brush_highlight, 110) foregroundrole = QPalette.HighlightedText elif opt.state & QStyle.State_MouseOver: background_brush = brush_darker(brush_highlight, 95) foregroundrole = QPalette.HighlightedText elif opt.state & QStyle.State_On: background_brush = brush_highlight foregroundrole = QPalette.HighlightedText else: # The default button brush. background_brush = palette.button() rect = opt.rect icon_area_rect = QRect(rect) icon_area_rect.setRight(int(icon_area_rect.height() * 1.26)) text_rect = QRect(rect) text_rect.setLeft(icon_area_rect.right() + 10) # Background (TODO: Should the tab button have native # toolbutton shape, drawn using PE_PanelButtonTool or even # QToolBox tab shape) # Default outline pen pen = QPen(palette.color(QPalette.Mid)) p.save() p.setPen(Qt.NoPen) p.setBrush(QBrush(background_brush)) p.drawRect(rect) # Draw the background behind the icon if the background_brush # is different. if not opt.state & QStyle.State_On: p.setBrush(brush_highlight) p.drawRect(icon_area_rect) # Line between the icon and text p.setPen(pen) p.drawLine(icon_area_rect.topRight(), icon_area_rect.bottomRight()) if opt.state & QStyle.State_HasFocus: # Set the focus frame pen and draw the border pen = QPen(QColor(FOCUS_OUTLINE_COLOR)) p.setPen(pen) p.setBrush(Qt.NoBrush) # Adjust for pen rect = rect.adjusted(0, 0, -1, -1) p.drawRect(rect) else: p.setPen(pen) # Draw the top/bottom border if self.position == QStyleOptionToolBox.OnlyOneTab or \ self.position == QStyleOptionToolBox.Beginning or \ self.selected & \ QStyleOptionToolBox.PreviousIsSelected: p.drawLine(rect.topLeft(), rect.topRight()) p.drawLine(rect.bottomLeft(), rect.bottomRight()) p.restore() p.save() text = fm.elidedText(opt.text, Qt.ElideRight, text_rect.width()) p.setPen(QPen(palette.color(foregroundrole))) p.setFont(opt.font) p.drawText(text_rect, int(Qt.AlignVCenter | Qt.AlignLeft) | \ int(Qt.TextSingleLine), text) if not opt.icon.isNull(): if opt.state & QStyle.State_Enabled: mode = QIcon.Normal else: mode = QIcon.Disabled if opt.state & QStyle.State_On: state = QIcon.On else: state = QIcon.Off icon_area_rect = icon_area_rect icon_rect = QRect(QPoint(0, 0), opt.iconSize) icon_rect.moveCenter(icon_area_rect.center()) opt.icon.paint(p, icon_rect, Qt.AlignCenter, mode, state) p.restore()
class corkDelegate(QStyledItemDelegate): def __init__(self, parent=None): QStyledItemDelegate.__init__(self, parent) self.factor = settings.corkSizeFactor / 100. self.lastPos = None self.editing = None self.margin = 5 self.bgColors = {} def newStyle(self): return settings.corkStyle == "new" def setCorkSizeFactor(self, v): self.factor = v / 100. def sizeHint(self, option, index): if self.newStyle(): defaultSize = QSize(300, 210) else: defaultSize = QSize(300, 200) return defaultSize * self.factor def editorEvent(self, event, model, option, index): # We catch the mouse position in the widget to know which part to edit if type(event) == QMouseEvent: self.lastPos = event.pos() # - option.rect.topLeft() return QStyledItemDelegate.editorEvent(self, event, model, option, index) def createEditor(self, parent, option, index): self.updateRects(option, index) bgColor = self.bgColors.get(index, "white") if self.mainLineRect.contains(self.lastPos): # One line summary self.editing = Outline.summarySentence edt = QLineEdit(parent) edt.setFocusPolicy(Qt.StrongFocus) edt.setFrame(False) f = QFont(option.font) if self.newStyle(): f.setBold(True) else: f.setItalic(True) edt.setAlignment(Qt.AlignCenter) edt.setPlaceholderText(self.tr("One line summary")) edt.setFont(f) edt.setStyleSheet("background: {}; color: black;".format(bgColor)) return edt elif self.titleRect.contains(self.lastPos): # Title self.editing = Outline.title edt = QLineEdit(parent) edt.setFocusPolicy(Qt.StrongFocus) edt.setFrame(False) f = QFont(option.font) if self.newStyle(): f.setPointSize(f.pointSize() + 4) else: edt.setAlignment(Qt.AlignCenter) f.setBold(True) edt.setFont(f) edt.setStyleSheet("background: {}; color: black;".format(bgColor)) # edt.setGeometry(self.titleRect) return edt else: # self.mainTextRect.contains(self.lastPos): # Summary self.editing = Outline.summaryFull edt = QPlainTextEdit(parent) edt.setFocusPolicy(Qt.StrongFocus) edt.setFrameShape(QFrame.NoFrame) try: # QPlainTextEdit.setPlaceholderText was introduced in Qt 5.3 edt.setPlaceholderText(self.tr("Full summary")) except AttributeError: pass edt.setStyleSheet("background: {}; color: black;".format(bgColor)) return edt def updateEditorGeometry(self, editor, option, index): if self.editing == Outline.summarySentence: # One line summary editor.setGeometry(self.mainLineRect) elif self.editing == Outline.title: # Title editor.setGeometry(self.titleRect) elif self.editing == Outline.summaryFull: # Summary editor.setGeometry(self.mainTextRect) def setEditorData(self, editor, index): item = index.internalPointer() if self.editing == Outline.summarySentence: # One line summary editor.setText(item.data(Outline.summarySentence)) elif self.editing == Outline.title: # Title editor.setText(index.data()) elif self.editing == Outline.summaryFull: # Summary editor.setPlainText(item.data(Outline.summaryFull)) def setModelData(self, editor, model, index): if self.editing == Outline.summarySentence: # One line summary model.setData(index.sibling(index.row(), Outline.summarySentence), editor.text()) elif self.editing == Outline.title: # Title model.setData(index, editor.text(), Outline.title) elif self.editing == Outline.summaryFull: # Summary model.setData(index.sibling(index.row(), Outline.summaryFull), editor.toPlainText()) def updateRects(self, option, index): if self.newStyle(): self.updateRects_v2(option, index) else: self.updateRects_v1(option, index) def updateRects_v2(self, option, index): margin = self.margin * 2 iconSize = max(24 * self.factor, 18) item = index.internalPointer() fm = QFontMetrics(option.font) h = fm.lineSpacing() self.itemRect = option.rect.adjusted(margin, margin, -margin, -margin) top = 15 * self.factor self.topRect = QRect(self.itemRect) self.topRect.setHeight(top) self.cardRect = QRect(self.itemRect.topLeft() + QPoint(0, top), self.itemRect.bottomRight()) self.iconRect = QRect(self.cardRect.topLeft() + QPoint(margin, margin), QSize(iconSize, iconSize)) self.labelRect = QRect(self.cardRect.topRight() - QPoint(margin + self.factor * 18, 1), self.cardRect.topRight() + QPoint(- margin - self.factor * 4, self.factor * 24)) self.titleRect = QRect(self.iconRect.topRight() + QPoint(margin, 0), self.labelRect.bottomLeft() - QPoint(margin, margin)) self.titleRect.setBottom(self.iconRect.bottom()) self.mainRect = QRect(self.iconRect.bottomLeft() + QPoint(0, margin), self.cardRect.bottomRight() - QPoint(margin, 2*margin)) self.mainRect.setLeft(self.titleRect.left()) self.mainLineRect = QRect(self.mainRect.topLeft(), self.mainRect.topRight() + QPoint(0, h)) self.mainTextRect = QRect(self.mainLineRect.bottomLeft() + QPoint(0, margin), self.mainRect.bottomRight()) if not item.data(Outline.summarySentence): self.mainTextRect.setTopLeft(self.mainLineRect.topLeft()) def updateRects_v1(self, option, index): margin = self.margin iconSize = max(16 * self.factor, 12) item = index.internalPointer() self.itemRect = option.rect.adjusted(margin, margin, -margin, -margin) self.iconRect = QRect(self.itemRect.topLeft() + QPoint(margin, margin), QSize(iconSize, iconSize)) self.labelRect = QRect(self.itemRect.topRight() - QPoint(iconSize + margin, 0), self.itemRect.topRight() + QPoint(0, iconSize + 2 * margin)) self.titleRect = QRect(self.iconRect.topRight() + QPoint(margin, 0), self.labelRect.bottomLeft() - QPoint(margin, margin)) self.bottomRect = QRect(QPoint(self.itemRect.x(), self.iconRect.bottom() + margin), QPoint(self.itemRect.right(), self.itemRect.bottom())) self.topRect = QRect(self.itemRect.topLeft(), self.bottomRect.topRight()) self.mainRect = self.bottomRect.adjusted(margin, margin, -margin, -margin) self.mainLineRect = QRect(self.mainRect.topLeft(), self.mainRect.topRight() + QPoint(0, iconSize)) self.mainTextRect = QRect(self.mainLineRect.bottomLeft() + QPoint(0, margin), self.mainRect.bottomRight()) if not item.data(Outline.summarySentence): self.mainTextRect.setTopLeft(self.mainLineRect.topLeft()) if item.data(Outline.label) in ["", "0", 0]: self.titleRect.setBottomRight(self.labelRect.bottomRight() - QPoint(self.margin, self.margin)) def paint(self, p, option, index): if self.newStyle(): self.paint_v2(p, option, index) else: self.paint_v1(p, option, index) def paint_v2(self, p, option, index): # QStyledItemDelegate.paint(self, p, option, index) if not index.isValid(): return item = index.internalPointer() self.updateRects(option, index) colors = outlineItemColors(item) style = qApp.style() def _rotate(angle, rect=self.mainRect): p.translate(rect.center()) p.rotate(angle) p.translate(-rect.center()) def drawRect(r): p.save() p.setBrush(Qt.gray) p.drawRect(r) p.restore() # Draw background cg = QPalette.ColorGroup(QPalette.Normal if option.state & QStyle.State_Enabled else QPalette.Disabled) if cg == QPalette.Normal and not option.state & QStyle.State_Active: cg = QPalette.Inactive # Selection if option.state & QStyle.State_Selected: p.save() p.setBrush(option.palette.brush(cg, QPalette.Highlight)) p.setPen(Qt.NoPen) #p.drawRoundedRect(option.rect, 12, 12) p.drawRect(option.rect) p.restore() # Background p.save() if settings.viewSettings["Cork"]["Background"] != "Nothing": c = colors[settings.viewSettings["Cork"]["Background"]] if c == QColor(Qt.transparent): c = QColor(Qt.white) col = mixColors(c, QColor(Qt.white), .2) backgroundColor = col p.setBrush(col) else: p.setBrush(Qt.white) backgroundColor = QColor(Qt.white) # Cache background color self.bgColors[index] = backgroundColor.name() p.setPen(Qt.NoPen) p.drawRect(self.cardRect) if item.isFolder(): itemPoly = QPolygonF([ self.topRect.topLeft(), self.topRect.topLeft() + QPoint(self.topRect.width() * .35, 0), self.cardRect.topLeft() + QPoint(self.topRect.width() * .45, 0), self.cardRect.topRight(), self.cardRect.bottomRight(), self.cardRect.bottomLeft() ]) p.drawPolygon(itemPoly) p.restore() # Label color if settings.viewSettings["Cork"]["Corner"] != "Nothing": p.save() color = colors[settings.viewSettings["Cork"]["Corner"]] p.setPen(Qt.NoPen) p.setBrush(color) p.drawRect(self.labelRect) w = self.labelRect.width() poly = QPolygonF([ self.labelRect.bottomLeft() + QPointF(0, 1), self.labelRect.bottomLeft() + QPointF(0, w / 2), self.labelRect.bottomLeft() + QPointF(w / 2, 1), self.labelRect.bottomRight() + QPointF(1, w / 2), self.labelRect.bottomRight() + QPointF(1, 1), ]) p.drawPolygon(poly) p.restore() if settings.viewSettings["Cork"]["Corner"] == "Nothing" or \ color == Qt.transparent: # No corner, so title can be full width self.titleRect.setRight(self.mainRect.right()) # Draw the icon iconRect = self.iconRect mode = QIcon.Normal if not option.state & style.State_Enabled: mode = QIcon.Disabled elif option.state & style.State_Selected: mode = QIcon.Selected # index.data(Qt.DecorationRole).paint(p, iconRect, option.decorationAlignment, mode) icon = index.data(Qt.DecorationRole).pixmap(iconRect.size()) if settings.viewSettings["Cork"]["Icon"] != "Nothing": color = colors[settings.viewSettings["Cork"]["Icon"]] colorifyPixmap(icon, color) QIcon(icon).paint(p, iconRect, option.decorationAlignment, mode) # Draw title p.save() text = index.data() if text: p.setPen(Qt.black) textColor = QColor(Qt.black) if settings.viewSettings["Cork"]["Text"] != "Nothing": col = colors[settings.viewSettings["Cork"]["Text"]] if col == Qt.transparent: col = Qt.black # If title setting is compile, we have to hack the color # Or we won't see anything in some themes if settings.viewSettings["Cork"]["Text"] == "Compile": if item.compile() in [0, "0"]: col = mixColors(QColor(Qt.black), backgroundColor) else: col = Qt.black textColor = col p.setPen(col) f = QFont(option.font) f.setPointSize(f.pointSize() + 4) f.setBold(True) p.setFont(f) fm = QFontMetrics(f) elidedText = fm.elidedText(text, Qt.ElideRight, self.titleRect.width()) p.drawText(self.titleRect, Qt.AlignLeft | Qt.AlignVCenter, elidedText) p.restore() # One line summary background lineSummary = item.data(Outline.summarySentence) fullSummary = item.data(Outline.summaryFull) # Border if settings.viewSettings["Cork"]["Border"] != "Nothing": p.save() p.setBrush(Qt.NoBrush) pen = p.pen() pen.setWidth(2) col = colors[settings.viewSettings["Cork"]["Border"]] pen.setColor(col) p.setPen(pen) if item.isFolder(): p.drawPolygon(itemPoly) else: p.drawRect(self.cardRect) p.restore() # Draw status status = item.data(Outline.status) if status: it = mainWindow().mdlStatus.item(int(status), 0) if it != None: p.save() p.setClipRegion(QRegion(self.cardRect)) f = p.font() f.setPointSize(f.pointSize() + 12) f.setBold(True) p.setFont(f) p.setPen(QColor(Qt.red).lighter(170)) _rotate(-35, rect=self.cardRect) p.drawText(self.cardRect, Qt.AlignCenter, it.text()) p.restore() # Draw Summary # One line if lineSummary: p.save() f = QFont(option.font) f.setBold(True) p.setFont(f) p.setPen(textColor) fm = QFontMetrics(f) elidedText = fm.elidedText(lineSummary, Qt.ElideRight, self.mainLineRect.width()) p.drawText(self.mainLineRect, Qt.AlignLeft | Qt.AlignVCenter, elidedText) p.restore() # Full summary if fullSummary: p.save() p.setFont(option.font) p.setPen(textColor) p.drawText(self.mainTextRect, Qt.TextWordWrap, fullSummary) p.restore() def paint_v1(self, p, option, index): # QStyledItemDelegate.paint(self, p, option, index) if not index.isValid(): return item = index.internalPointer() self.updateRects(option, index) colors = outlineItemColors(item) style = qApp.style() def _rotate(angle): p.translate(self.mainRect.center()) p.rotate(angle) p.translate(-self.mainRect.center()) # Draw background cg = QPalette.ColorGroup(QPalette.Normal if option.state & QStyle.State_Enabled else QPalette.Disabled) if cg == QPalette.Normal and not option.state & QStyle.State_Active: cg = QPalette.Inactive # Selection if option.state & QStyle.State_Selected: p.save() p.setBrush(option.palette.brush(cg, QPalette.Highlight)) p.setPen(Qt.NoPen) p.drawRoundedRect(option.rect, 12, 12) p.restore() # Stack if item.isFolder() and item.childCount() > 0: p.save() p.setBrush(Qt.white) for i in reversed(range(3)): p.drawRoundedRect(self.itemRect.adjusted(2 * i, 2 * i, -2 * i, 2 * i), 10, 10) p.restore() # Background itemRect = self.itemRect p.save() if settings.viewSettings["Cork"]["Background"] != "Nothing": c = colors[settings.viewSettings["Cork"]["Background"]] col = mixColors(c, QColor(Qt.white), .2) p.setBrush(col) else: p.setBrush(Qt.white) pen = p.pen() pen.setWidth(2) p.setPen(pen) p.drawRoundedRect(itemRect, 10, 10) p.restore() # Title bar topRect = self.topRect p.save() if item.isFolder(): color = QColor(Qt.darkGreen) else: color = QColor(Qt.blue).lighter(175) p.setPen(Qt.NoPen) p.setBrush(color) p.setClipRegion(QRegion(topRect)) p.drawRoundedRect(itemRect, 10, 10) # p.drawRect(topRect) p.restore() # Label color if settings.viewSettings["Cork"]["Corner"] != "Nothing": p.save() color = colors[settings.viewSettings["Cork"]["Corner"]] p.setPen(Qt.NoPen) p.setBrush(color) p.setClipRegion(QRegion(self.labelRect)) p.drawRoundedRect(itemRect, 10, 10) # p.drawRect(topRect) p.restore() if color != Qt.transparent: p.drawLine(self.labelRect.topLeft(), self.labelRect.bottomLeft()) # One line summary background lineSummary = item.data(Outline.summarySentence) fullSummary = item.data(Outline.summaryFull) if lineSummary or not fullSummary: m = self.margin r = self.mainLineRect.adjusted(-m, -m, m, m / 2) p.save() p.setPen(Qt.NoPen) p.setBrush(QColor("#EEE")) p.drawRect(r) p.restore() # Border p.save() p.setBrush(Qt.NoBrush) pen = p.pen() pen.setWidth(2) if settings.viewSettings["Cork"]["Border"] != "Nothing": col = colors[settings.viewSettings["Cork"]["Border"]] if col == Qt.transparent: col = Qt.black pen.setColor(col) p.setPen(pen) p.drawRoundedRect(itemRect, 10, 10) p.restore() # Draw the icon iconRect = self.iconRect mode = QIcon.Normal if not option.state & style.State_Enabled: mode = QIcon.Disabled elif option.state & style.State_Selected: mode = QIcon.Selected # index.data(Qt.DecorationRole).paint(p, iconRect, option.decorationAlignment, mode) icon = index.data(Qt.DecorationRole).pixmap(iconRect.size()) if settings.viewSettings["Cork"]["Icon"] != "Nothing": color = colors[settings.viewSettings["Cork"]["Icon"]] colorifyPixmap(icon, color) QIcon(icon).paint(p, iconRect, option.decorationAlignment, mode) # Draw title p.save() text = index.data() titleRect = self.titleRect if text: if settings.viewSettings["Cork"]["Text"] != "Nothing": col = colors[settings.viewSettings["Cork"]["Text"]] if col == Qt.transparent: col = Qt.black p.setPen(col) f = QFont(option.font) # f.setPointSize(f.pointSize() + 1) f.setBold(True) p.setFont(f) fm = QFontMetrics(f) elidedText = fm.elidedText(text, Qt.ElideRight, titleRect.width()) p.drawText(titleRect, Qt.AlignCenter, elidedText) p.restore() # Draw the line bottomRect = self.bottomRect p.save() # p.drawLine(itemRect.x(), iconRect.bottom() + margin, # itemRect.right(), iconRect.bottom() + margin) p.drawLine(bottomRect.topLeft(), bottomRect.topRight()) p.restore() # Lines if True: p.save() p.setPen(QColor("#EEE")) fm = QFontMetrics(option.font) h = fm.lineSpacing() l = self.mainTextRect.topLeft() + QPoint(0, h) while self.mainTextRect.contains(l): p.drawLine(l, QPoint(self.mainTextRect.right(), l.y())) l.setY(l.y() + h) p.restore() # Draw status mainRect = self.mainRect status = item.data(Outline.status) if status: it = mainWindow().mdlStatus.item(int(status), 0) if it != None: p.save() p.setClipRegion(QRegion(mainRect)) f = p.font() f.setPointSize(f.pointSize() + 12) f.setBold(True) p.setFont(f) p.setPen(QColor(Qt.red).lighter(175)) _rotate(-35) p.drawText(mainRect, Qt.AlignCenter, it.text()) p.restore() # Draw Summary # One line if lineSummary: p.save() f = QFont(option.font) f.setItalic(True) p.setFont(f) fm = QFontMetrics(f) elidedText = fm.elidedText(lineSummary, Qt.ElideRight, self.mainLineRect.width()) p.drawText(self.mainLineRect, Qt.AlignCenter, elidedText) p.restore() # Full summary if fullSummary: p.setFont(option.font) p.drawText(self.mainTextRect, Qt.TextWordWrap, fullSummary)