コード例 #1
0
	def __init__(self, parentItem, segments, colour):
		QGraphicsItem.__init__(self, parent=parentItem)
		self.colour_name = colour
		self.shape = QPainterPath()
		self.labels = QGraphicsItemGroup(self)
		self.bbox = QRectF(0, 0, 0, 0)
		for (p1, p2), label in segments:
			lvect = QVector2D(p2 - p1)
			lpath = QPainterPath()
			m = TWY_line_margin
			l = lvect.length()
			plst = [QPointF(-m, 0), QPointF(-m/3, -m), QPointF(l + m/3, -m), QPointF(l + m, 0), QPointF(l + m/3, m), QPointF(-m/3, m)]
			lpath.addPolygon(QPolygonF(plst))
			lrot = QTransform()
			lrot.rotateRadians(atan2(lvect.y(), lvect.x()))
			lpath = lrot.map(lpath)
			lpath.translate(p1)
			self.shape.addPath(lpath)
			rect = QRectF(p1, p2).normalized()
			if label != None:
				self.labels.addToGroup(TaxiwayLabelItem(label, rect.center(), self))
			self.bbox |= rect
		self.shape.setFillRule(Qt.WindingFill)
		self.mouse_highlight = False
		self.labels.setVisible(False)
コード例 #2
0
ファイル: trayicon.py プロジェクト: anetczuk/rsscast
    def drawString(self, content, fontSize=256, color=QColor("red")):
        icon = self.icon()

        pixmap = icon.pixmap(512, 512)
        pixSize = pixmap.rect()

        painter = QPainter(pixmap)

        font = painter.font()
        font.setPixelSize(fontSize)
        painter.setFont(font)

        path = QPainterPath()
        path.addText(0, 0, font, content)
        pathBBox = path.boundingRect()

        xOffset = (pixSize.width() - pathBBox.width()) / 2 - pathBBox.left()
        yOffset = (pixSize.height() + pathBBox.height()) / 2

        path.translate(xOffset, yOffset)

        ## paint shadow
        pathPen = QPen(QColor(0, 0, 0, 200))
        pathPen.setWidth(180)
        painter.strokePath(path, pathPen)
        painter.fillPath(path, QBrush(color))

        ## make number bolder
        pathPen = QPen(color)
        pathPen.setWidth(20)
        painter.strokePath(path, pathPen)

        painter.end()

        self.setIcon(QIcon(pixmap))
コード例 #3
0
def createResizeArrow(straight):
    if straight:
        arrowLength = 14
    else:
        arrowLength = 16
    arrowHeadLength = 4.5
    arrowHeadWidth = 5
    bodyWidth = 1.5
    path = QPainterPath()
    path.lineTo(arrowHeadWidth, arrowHeadLength)
    path.lineTo(0 + bodyWidth, arrowHeadLength)
    path.lineTo(0 + bodyWidth, arrowLength - arrowHeadLength)
    path.lineTo(arrowHeadWidth, arrowLength - arrowHeadLength)
    path.lineTo(0, arrowLength)
    path.lineTo(-arrowHeadWidth, arrowLength - arrowHeadLength)
    path.lineTo(0 - bodyWidth, arrowLength - arrowHeadLength)
    path.lineTo(0 - bodyWidth, arrowHeadLength)
    path.lineTo(-arrowHeadWidth, arrowHeadLength)
    path.closeSubpath()
    if straight:
        x = 2
    else:
        x =3
    path.translate(0, x)
    return path
コード例 #4
0
def createResizeArrow(straight):
    if straight:
        arrowLength = 14
    else:
        arrowLength = 16
    arrowHeadLength = 4.5
    arrowHeadWidth = 5
    bodyWidth = 1.5
    path = QPainterPath()
    path.lineTo(arrowHeadWidth, arrowHeadLength)
    path.lineTo(0 + bodyWidth, arrowHeadLength)
    path.lineTo(0 + bodyWidth, arrowLength - arrowHeadLength)
    path.lineTo(arrowHeadWidth, arrowLength - arrowHeadLength)
    path.lineTo(0, arrowLength)
    path.lineTo(-arrowHeadWidth, arrowLength - arrowHeadLength)
    path.lineTo(0 - bodyWidth, arrowLength - arrowHeadLength)
    path.lineTo(0 - bodyWidth, arrowHeadLength)
    path.lineTo(-arrowHeadWidth, arrowHeadLength)
    path.closeSubpath()
    if straight:
        x = 2
    else:
        x = 3
    path.translate(0, x)
    return path
コード例 #5
0
    def _updateSequenceText(self):
        seq_item = self._seq_item
        is_on_top = self._is_on_top
        index = self._insertion.idx()
        base_text = self._seq_text
        font = styles.SEQUENCEFONT
        seq_font_h = styles.SEQUENCEFONTH
        insert_w = styles.INSERTWIDTH
        seq_font_char_w = styles.SEQUENCEFONTCHARWIDTH
        # draw sequence on the insert
        if base_text:  # only draw sequences if they exist i.e. not None!
            len_BT = len(base_text)
            if is_on_top:
                angle_offset = 0
            else:
                angle_offset = 180
            if len_BT > 20:
                base_text = base_text[:17] + '...'
                len_BT = len(base_text)
            fraction_arc_len_per_char = (
                1.0 - 2.0 * _FRACTION_INSERT_TO_PAD) / (len_BT + 1)
            seq_item.setPen(QPen(Qt.NoPen))
            seq_item.setBrush(QBrush(Qt.black))

            seq_path = QPainterPath()
            loop_path = self.path()
            for i in range(len_BT):
                frac = _FRACTION_INSERT_TO_PAD + (
                    i + 1) * fraction_arc_len_per_char
                pt = loop_path.pointAtPercent(frac)
                tang_ang = loop_path.angleAtPercent(frac)

                temp_path = QPainterPath()
                # 1. draw the text
                temp_path.addText(0, 0, font,
                                  base_text[i if is_on_top else -i - 1])
                # 2. center it at the zero point different for top and bottom
                # strands
                if not is_on_top:
                    temp_path.translate(0, -seq_font_h - insert_w)

                temp_path.translate(
                    QPointF(-seq_font_char_w / 2.,
                            -2 if is_on_top else seq_font_h))

                mat = QTransform()
                # 3. rotate it
                mat.rotate(-tang_ang + angle_offset)

                rotated_path = mat.map(temp_path)
                # 4. translate the rotate object to it's position on the part
                rotated_path.translate(pt)
                seq_path.addPath(rotated_path)
            # end for
            seq_item.setPath(seq_path)
コード例 #6
0
ファイル: insertionitem.py プロジェクト: hadim/cadnano2.5
    def _updateSequenceText(self):
        seq_item = self._seq_item
        is_on_top = self._is_on_top
        index = self._insertion.idx()
        base_text = self._seq_text
        font = styles.SEQUENCEFONT
        seq_font_h = styles.SEQUENCEFONTH
        insert_w = styles.INSERTWIDTH
        seq_font_char_w = styles.SEQUENCEFONTCHARWIDTH
        # draw sequence on the insert
        if base_text:  # only draw sequences if they exist i.e. not None!
            len_BT = len(base_text)
            if is_on_top:
                angle_offset = 0
            else:
                angle_offset = 180
            if len_BT > 20:
                base_text = base_text[:17] + '...'
                len_BT = len(base_text)
            fraction_arc_len_per_char = (1.0 - 2.0*_FRACTION_INSERT_TO_PAD) / (len_BT + 1)
            seq_item.setPen(QPen(Qt.NoPen))
            seq_item.setBrush(QBrush(Qt.black))

            seq_path = QPainterPath()
            loop_path = self.path()
            for i in range(len_BT):
                frac = _FRACTION_INSERT_TO_PAD + (i+1)*fraction_arc_len_per_char
                pt = loop_path.pointAtPercent(frac)
                tang_ang = loop_path.angleAtPercent(frac)

                temp_path = QPainterPath()
                # 1. draw the text
                temp_path.addText(0, 0, font, base_text[i if is_on_top else -i-1])
                # 2. center it at the zero point different for top and bottom
                # strands
                if not is_on_top:
                    temp_path.translate(0, -seq_font_h - insert_w)

                temp_path.translate(QPointF(-seq_font_char_w / 2.,
                                          -2 if is_on_top else seq_font_h))


                mat = QTransform()
                # 3. rotate it
                mat.rotate(-tang_ang + angle_offset)

                rotated_path = mat.map(temp_path)
                # 4. translate the rotate object to it's position on the part
                rotated_path.translate(pt)
                seq_path.addPath(rotated_path)
            # end for
            seq_item.setPath(seq_path)
コード例 #7
0
    def _updateSequenceText(self):
        seqItem = self._seqItem
        isOnTop = self._isOnTop
        index = self._insertion.idx()
        baseText = self._seqText
        font = styles.SEQUENCEFONT
        seqFontH = styles.SEQUENCEFONTH
        insertW = styles.INSERTWIDTH
        seqFontCharW = styles.SEQUENCEFONTCHARWIDTH
        # draw sequence on the insert
        if baseText:  # only draw sequences if they exist i.e. not None!
            lenBT = len(baseText)
            if isOnTop:
                angleOffset = 0
            else:
                angleOffset = 180
            if lenBT > 20:
                baseText = baseText[:17] + '...'
                lenBT = len(baseText)
            fractionArclenPerChar = (1.0 -
                                     2.0 * _fractionInsertToPad) / (lenBT + 1)
            seqItem.setPen(QPen(Qt.NoPen))
            seqItem.setBrush(QBrush(Qt.black))

            seqPath = QPainterPath()
            loopPath = self.path()
            for i in range(lenBT):
                frac = _fractionInsertToPad + (i + 1) * fractionArclenPerChar
                pt = loopPath.pointAtPercent(frac)
                tangAng = loopPath.angleAtPercent(frac)

                tempPath = QPainterPath()
                # 1. draw the text
                tempPath.addText(0, 0, font,
                                 baseText[i if isOnTop else -i - 1])
                # 2. center it at the zero point different for top and bottom
                # strands
                if not isOnTop:
                    tempPath.translate(0, -seqFontH - insertW)

                tempPath.translate(
                    QPointF(-seqFontCharW / 2., -2 if isOnTop else seqFontH))
                mat = QMatrix3x3()
                # 3. rotate it
                mat.rotate(-tangAng + angleOffset)
                rotatedPath = mat.map(tempPath)
                # 4. translate the rotate object to it's position on the part
                rotatedPath.translate(pt)
                seqPath.addPath(rotatedPath)
            # end for
            seqItem.setPath(seqPath)
コード例 #8
0
ファイル: insertionitem.py プロジェクト: nate-w/cadnano2.5
    def _updateSequenceText(self):
        seqItem = self._seqItem
        isOnTop = self._isOnTop
        index = self._insertion.idx()
        baseText = self._seqText
        font = styles.SEQUENCEFONT
        seqFontH = styles.SEQUENCEFONTH
        insertW = styles.INSERTWIDTH
        seqFontCharW = styles.SEQUENCEFONTCHARWIDTH
        # draw sequence on the insert
        if baseText:  # only draw sequences if they exist i.e. not None!
            lenBT = len(baseText)
            if isOnTop:
                angleOffset = 0
            else:
                angleOffset = 180
            if lenBT > 20:
                baseText = baseText[:17] + '...'
                lenBT = len(baseText)
            fractionArclenPerChar = (1.0-2.0*_fractionInsertToPad)/(lenBT+1)
            seqItem.setPen(QPen(Qt.NoPen))
            seqItem.setBrush(QBrush(Qt.black))
            
            seqPath = QPainterPath()
            loopPath = self.path()
            for i in range(lenBT):
                frac = _fractionInsertToPad + (i+1)*fractionArclenPerChar
                pt = loopPath.pointAtPercent(frac)
                tangAng = loopPath.angleAtPercent(frac)

                tempPath = QPainterPath()
                # 1. draw the text
                tempPath.addText(0,0, font, baseText[i if isOnTop else -i-1])
                # 2. center it at the zero point different for top and bottom
                # strands
                if not isOnTop:
                    tempPath.translate(0, -seqFontH - insertW)
                    
                tempPath.translate(QPointF(-seqFontCharW/2.,
                                          -2 if isOnTop else seqFontH))
                mat = QMatrix3x3()
                # 3. rotate it
                mat.rotate(-tangAng + angleOffset)
                rotatedPath = mat.map(tempPath)
                # 4. translate the rotate object to it's position on the part
                rotatedPath.translate(pt)
                seqPath.addPath(rotatedPath)
            # end for
            seqItem.setPath(seqPath)
コード例 #9
0
ファイル: XChartMarkers.py プロジェクト: trhallam/trib
def xtooltippath(point):
    print(point)
    path = QPainterPath()
    width = 100
    height = 50
    pointer = 5
    path.lineTo(width, 0), path.lineTo(width, height)
    path.lineTo(width / 2 + pointer, height)
    path.lineTo(width / 2, height + pointer)
    path.lineTo(width / 2 - pointer, height)
    path.lineTo(0, height)
    path.lineTo(0, 0)
    path.closeSubpath()
    path.translate(point.x() - width / 2, point.y() - height - pointer)

    return path
コード例 #10
0
ファイル: floor_plan.py プロジェクト: hibtc/madgui
    def draw_path(self):
        l, s, d = 45, 10, 10
        proj = self.plan.projection.dot
        orig = np.array([0, 0])
        axes = QPainterPath()
        axes.addPath(self.axis_arrow("x", orig, orig+l*proj([1, 0, 0]), s))
        axes.addPath(self.axis_arrow("y", orig, orig+l*proj([0, 1, 0]), s))
        axes.addPath(self.axis_arrow("z", orig, orig+l*proj([0, 0, 1]), s))

        tran = self.deviceTransform(self.plan.viewportTransform()).inverted()[0]
        view = tran.mapRect(QRectF(self.plan.viewport().rect()))
        rect = axes.boundingRect()
        axes.translate(view.left() + view.width()/15 - rect.left(),
                       view.bottom() - view.height()/15 - rect.bottom())
        path = QPainterPath()
        path.addPath(axes)
        path.addEllipse(-d/2, -d/2, d, d)
        return path
コード例 #11
0
    def draw_path(self):
        l, s, d = 45, 10, 10
        proj = self.plan.projection.dot
        orig = np.array([0, 0])
        axes = QPainterPath()
        axes.addPath(self.axis_arrow("x", orig, orig + l * proj([1, 0, 0]), s))
        axes.addPath(self.axis_arrow("y", orig, orig + l * proj([0, 1, 0]), s))
        axes.addPath(self.axis_arrow("z", orig, orig + l * proj([0, 0, 1]), s))

        tran = self.deviceTransform(
            self.plan.viewportTransform()).inverted()[0]
        view = tran.mapRect(QRectF(self.plan.viewport().rect()))
        rect = axes.boundingRect()
        axes.translate(view.left() + view.width() / 15 - rect.left(),
                       view.bottom() - view.height() / 15 - rect.bottom())
        path = QPainterPath()
        path.addPath(axes)
        path.addEllipse(-d / 2, -d / 2, d, d)
        return path
コード例 #12
0
ファイル: quick.py プロジェクト: chemberlen/our-py-lib
    def paint(self, painter, style, widget=None):
        assert isinstance(painter, QPainter)

        if self.isSelected():
            brush = QBrush(Qt.yellow)
        else:
            brush = QBrush(Qt.white)

        pen = QPen(Qt.black)

        circle_path = QPainterPath()
        circle_path.addEllipse(self.boundingRect())
        painter.fillPath(circle_path, brush)
        painter.strokePath(circle_path, pen)

        text_path = QPainterPath()
        text_path.addText(0, 0, QFont(), str(self.node))
        box = text_path.boundingRect()
        text_path.translate(-box.center())

        painter.fillPath(text_path, QBrush(Qt.black))
コード例 #13
0
from PyQt5.QtGui import QColor, QPainter, QPainterPath
from PyQt5.QtWidgets import (QHBoxLayout, QLabel, QSpinBox, QSizePolicy,
                             QWidget)
from trufont.controls.pathButton import PathButton

__all__ = ["StatusBar"]

_minPath = QPainterPath()
_minPath.moveTo(1, 6)
_minPath.lineTo(11, 6)

_plusPath = QPainterPath(_minPath)
_plusPath.moveTo(6, 1)
_plusPath.lineTo(6, 11)

_minPath.translate(5, 7)
_plusPath.translate(5, 7)


def Button():
    btn = PathButton()
    btn.setIsDownColor(QColor(210, 210, 210))
    btn.setIsFlipped(True)
    btn.setSize(QSize(23, 25))
    return btn


class StatusBar(QWidget):
    """
    Use the *sizeChanged* signal for size changes.
コード例 #14
0
    def updateGeometry(self):
        # Calculate path absolute
        branch_abs = QPainterPath()
        branch_abs.moveTo(self.__start)
        branch_abs.cubicTo(self.__spline1, self.__spline2, self.__end)

        branch_middle = self.__get_bezier_middle(branch_abs)
        middle_angle = self.__get_bezier_middle_angle(branch_abs)

        # Calculate arrow absolute
        arrow_abs = self.__calculate_arrow(
            branch_middle,
            middle_angle,
            self.__arrow_height,
            self.__arrow_length,
            self.__arrow_side_spline_depth,
            self.__arrow_back_spline_depth)

        # Calculate arrow mask absolute
        arrow_mask_abs = self.__calculate_arrow(
            branch_middle,
            middle_angle,
            self.__arrow_height + self.__arrow_mask_height_offset,
            self.__arrow_length + self.__arrow_mask_length_offset,
            self.__arrow_side_spline_depth,
            self.__arrow_back_spline_depth)

        # Add some margin to avoid cutting off anti aliasing pixels of branch
        branch_aliasing_margin = 4
        geo_branch = branch_abs.boundingRect() \
                               .toRect().marginsAdded(QMargins(
                                   branch_aliasing_margin,
                                   branch_aliasing_margin,
                                   branch_aliasing_margin,
                                   branch_aliasing_margin))

        # Get bounding rect of arrow mask
        # The mask already has a margin to avoid cuttin of anti aliasing pixels
        geo_arrow_mask = arrow_mask_abs.boundingRect().toRect()

        # Unite arrow mask bounds and branch bounds and set as geometry
        united = geo_branch.united(geo_arrow_mask)
        self.setGeometry(united)
        super().updateGeometry()

        # Translate absolute paths to relative paths for use in widget
        offset = self.mapFromParent(QPoint())
        path_rel = QPainterPath(branch_abs)
        path_rel.translate(offset)
        self.__branch = path_rel

        arrow_rel = QPainterPath(arrow_abs)
        arrow_rel.translate(offset)
        self.__arrow = arrow_rel

        arrow_mask_rel = QPainterPath(arrow_mask_abs)
        arrow_mask_rel.translate(offset)
        self.__arrow_mask = arrow_mask_rel

        stroker = QPainterPathStroker()
        stroker.setWidth(8)
        wide_stroke = stroker.createStroke(self.__branch)
        stroker.setWidth(self.__pen_width)
        narrow_stroke = stroker.createStroke(self.__branch)
        branch_outlet = wide_stroke.united(narrow_stroke).toFillPolygon()
        mask_poly_f = self.__arrow_mask.toFillPolygon().united(branch_outlet)

        region = QRegion(mask_poly_f.toPolygon())
        self.setMask(region)
        self.update()
コード例 #15
0
ファイル: insertionitem.py プロジェクト: hadim/cadnano2.5
    path.quadTo(c1, p1)
    path.quadTo(c2, start)
# end def


_PATH_START = QPointF(_HBW, _HBW)
_PATH_MID_UP = QPointF(_HBW, -_BW)
_PATH_UP_UP_CTRL_PT = QPointF(-_HBW, -_BW)
_PATH_UP_DOWN_CTRL_PT = QPointF(1.5 * _BW, -_BW)
_PATH_MID_DOWN = QPointF(_HBW, 2 * _BW)
_PATH_DOWN_DOWN_CTRL_PT = QPointF(-_HBW, 2 * _BW)
_PATH_DOWN_UP_CTRL_PT = QPointF(1.5 * _BW, 2 * _BW)
_INSERT_PATH_UP = QPainterPath()
_insertGen(_INSERT_PATH_UP, _PATH_START, _PATH_UP_UP_CTRL_PT,\
         _PATH_MID_UP, _PATH_UP_DOWN_CTRL_PT)
_INSERT_PATH_UP.translate(_OFFSET1, 0)
_INSERT_PATH_UP_RECT = _INSERT_PATH_UP.boundingRect()
_INSERT_PATH_DOWN = QPainterPath()
_insertGen(_INSERT_PATH_DOWN, _PATH_START, _PATH_DOWN_DOWN_CTRL_PT,\
         _PATH_MID_DOWN, _PATH_DOWN_UP_CTRL_PT)
_INSERT_PATH_DOWN.translate(_OFFSET1, 0)
_INSERT_PATH_DOWNRect = _INSERT_PATH_DOWN.boundingRect()


_BIG_RECT = _DEFAULT_RECT.united(_INSERT_PATH_UP_RECT)
_BIG_RECT = _BIG_RECT.united(_INSERT_PATH_DOWNRect)
_B_PEN2 = getPenObj(styles.BLUE_STROKE, 2)
_OFFSET2   = _BW*0.75
_FONT = QFont(styles.THE_FONT, styles.THE_FONT_SIZE/2, QFont.Bold)
_BIG_RECT.adjust(-15, -15, 30, 30)
# Bases are drawn along and above the insert path.
コード例 #16
0
ファイル: insertionitem.py プロジェクト: nate-w/cadnano2.5
    path.quadTo(c1, p1)
    path.quadTo(c2, start)
# end def


_pathStart = QPointF(_hbw, _hbw)
_pathMidUp = QPointF(_hbw, -_bw)
_pathUpUpCtrlPt = QPointF(-_hbw, -_bw)
_pathUpDownCtrlPt = QPointF(1.5 * _bw, -_bw)
_pathMidDown = QPointF(_hbw, 2 * _bw)
_pathDownDownCtrlPt = QPointF(-_hbw, 2 * _bw)
_pathDownUpCtrlPt = QPointF(1.5 * _bw, 2 * _bw)
_insertPathUp = QPainterPath()
_insertGen(_insertPathUp, _pathStart, _pathUpUpCtrlPt,\
         _pathMidUp, _pathUpDownCtrlPt)
_insertPathUp.translate(_offset1, 0)
_insertPathUpRect = _insertPathUp.boundingRect()
_insertPathDown = QPainterPath()
_insertGen(_insertPathDown, _pathStart, _pathDownDownCtrlPt,\
         _pathMidDown, _pathDownUpCtrlPt)
_insertPathDown.translate(_offset1, 0)
_insertPathDownRect = _insertPathDown.boundingRect()


_bigRect = _defaultRect.united(_insertPathUpRect)
_bigRect = _bigRect.united(_insertPathDownRect)
_bpen2 = QPen(styles.BLUE_STROKE, 2)
_offset2 = _bw*0.75
_font = QFont(styles.THE_FONT, 10, QFont.Bold)
_bigRect.adjust(-15, -15, 30, 30)
# Bases are drawn along and above the insert path.
コード例 #17
0
def svgToPath(filename):
    """Return QPainterPath instance from an svg file.
       No colors will be included. If the file contains multiple paths,
       they will be connected to form one single path.
       It will also return a boolean indicates if the path is closed or not."""
    path = QPainterPath()
    info = findPath(filename)
    start = QPointF(0, 0)
    last_cp = start     # last control point, for S cubic bezier curve.
    last_qp = start     # last control point, for T quadratic bezier curve.
    for idx in range(len(info)):
        line = info[idx]
        cmd = line[0]
        if (cmd.upper() == 'Z'):
            path.closeSubpath()
            continue

        coords = re.split(r'\s+|,|(?<=\d)(?=-)', line[1])
        if (cmd.upper() == 'V'):
            # only last coordinate matters.
            coord = eval(coords[-1])
            verticalLineTo(path, coord, cmd)
            continue

        if (cmd.upper() == 'H'):
            # only last coordinate matters.
            coord = eval(coords[-1])
            horizontalLineTo(path, coord, cmd)
            continue

        # pair two values into one
        coords = [x+','+y for x, y in zip(coords[::2], coords[1::2])]
        coords = list(map(getPoint, coords))

        if (cmd.upper() == 'M'):
            # if m is at the start of the path
            if (line == info[0]):
                start = coords[0]
                moveTo(path, start, 'M')
            # m is not at the start of the path
            else:
                path.closeSubpath()
                lineTo(path, coords[0], cmd)
            for i in range(1, len(coords)):
                lineTo(path, coords[i], cmd)
            continue

        if (cmd.upper() == 'L'):
            for coord in coords:
                lineTo(path, coord, cmd)
            continue

        if (cmd.upper() == 'C'):
            for i in range(len(coords)//3):
                # Saving coordinates for smoothcurve command
                last_cp = cubicTo(path, *coords[i*3:i*3+3], absolute=cmd)
            continue

        if (cmd.upper() == 'S'):
            if not (info[idx-1][0].upper() in 'SC'):
                last_cp = path.currentPoint()
            for i in range(len(coords)//2):
                last_cp = smoothCubicTo(path, last_cp,
                                        *coords[i*2:i*2+2], absolute=cmd)
            continue

        if (cmd.upper() == 'Q'):
            for i in range(len(coords)//2):
                # Saving coordinates for T smooth curve command
                last_qp = quadTo(path, *coords[i*2:i*2+2], absolute=cmd)
            continue

        if (cmd.upper() == 'T'):
            if not (info[idx-1][0].upper() in 'QT'):
                last_qp = path.currentPoint()
            for coord in coords:
                last_qp = smoothQuadTo(path, last_qp, coord, absolute=cmd)
            continue
        raise Exception('svg file contains command {}, which is not supported'
                        .format(cmd))

    closed = True
    if ((abs((path.currentPosition() - start).x()) > 1) and
       (abs((path.currentPosition() - start).y()) > 1)):
        closed = False
    path.translate(-start)
    path.translate(-path.boundingRect().center())
    return path, closed
コード例 #18
0
ファイル: padulator.py プロジェクト: sparsile/padulator
    def paintEvent(self,event):
        global monster_data
        global dmg
        painter = QPainter(self)
        painter.setRenderHint(QPainter.Antialiasing)
        painter.drawPixmap(event.rect(),self.pixmap)

        if self.card is not None and self.card.ID is not 0:
            card = self.card
            # Draw card level at the bottom centered
            pen = QPen()
            if np.floor(card.lv) == monster_data[card.ID]['max_level']:
                lvstr = 'Lv.Max'
                brush = QBrush(QColor(252,232,131))
            else:
                lvstr = 'Lv.%d' % np.floor(card.lv)
                brush = QBrush(Qt.white)

            path = QPainterPath()
            pen.setWidth(0);
            pen.setBrush(Qt.black)

            font = QFont()
            font.setPointSize(11)
            font.setWeight(QFont.Black)
            
            path.addText(event.rect().x(),event.rect().y()+48,font,lvstr)

            rect = path.boundingRect()
            target = (event.rect().x()+event.rect().width())/2

            # center the rect in event.rect()
            path.translate(target-rect.center().x(), 0)

            painter.setPen(pen)
            painter.setBrush(QBrush(Qt.black))
            painter.drawPath(path.translated(.5,.5))

            painter.setPen(pen)
            painter.setBrush(brush)

            painter.drawPath(path)

            # Draw +eggs at the top right
            eggs = card.plus_atk+card.plus_hp+card.plus_rcv
            if eggs > 0:
                eggstr = '+%d' % eggs
                pen.setBrush(Qt.yellow)
                brush = QBrush(Qt.yellow)

                path = QPainterPath()
                pen.setWidth(0)
                pen.setBrush(Qt.black)
                font = QFont()
                font.setPointSize(11)
                font.setWeight(QFont.Black)
                path.addText(event.rect().x(),event.rect().y()+12,font,eggstr)

                path.translate(50-path.boundingRect().right()-3,0)
                #painter.setFont(font)
                painter.setPen(pen)
                painter.setBrush(QBrush(Qt.black))
                painter.drawPath(path.translated(.5,.5))

                painter.setPen(pen)
                painter.setBrush(brush)
                painter.drawPath(path)
                #painter.drawText(event.rect().adjusted(0,0,0,0),Qt.AlignRight, eggstr)

            # Draw awakenings at the top left in a green circle
            if card.current_awakening > 0:
                path = QPainterPath()
                rect = QRectF(event.rect()).adjusted(4,4,-36,-36)
                path.addEllipse(rect)
                painter.setBrush(QBrush(QColor(34,139,34)))
                pen.setBrush(Qt.white)
                pen.setWidth(1)
                painter.setPen(pen)
                painter.drawPath(path)

                path = QPainterPath()
                font.setPointSize(9)
                awkstr = ('%d' % card.current_awakening if
                        card.current_awakening < card.max_awakening else
                        '★')
                path.addText(rect.x(),rect.bottom(),font,awkstr)
                
                br = path.boundingRect()
                path.translate(rect.center().x()-br.center().x(),
                        rect.center().y()-br.center().y())

                pen.setBrush(QColor(0,0,0,0))
                pen.setWidth(0)
                painter.setPen(pen)
                painter.setBrush(QBrush(Qt.yellow))
                painter.drawPath(path)

            # Draw main attack damage
            #print(self.main_attack)
            if self.main_attack > 0:
                matkstr = '%d' % self.main_attack
                painter.setBrush(QBrush(COLORS[self.card.element[0]]))
                path = QPainterPath()
                font = QFont()
                font.setFamily('Helvetica')
                font.setWeight(QFont.Black)
                #font.setStretch(25)
                font.setPointSize(13)
                path.addText(rect.x(),rect.bottom(),font,matkstr)

                rect = QRectF(event.rect())
                br = path.boundingRect()
                path.translate(rect.center().x()-br.center().x(),
                        rect.center().y()-br.bottom()-1)

                # 
                pen.setBrush(Qt.black)
                pen.setWidthF(.75)
                painter.setPen(pen)
                painter.drawPath(path)

            # Draw sub attack damage
            #print(self.main_attack)
            if self.sub_attack > 0:
                satkstr = '%d' % self.sub_attack
                painter.setBrush(QBrush(COLORS[self.card.element[1]]))
                path = QPainterPath()
                font = QFont()
                font.setFamily('Helvetica')
                font.setWeight(QFont.Black)
                #font.setStretch(25)
                font.setPointSize(12)
                path.addText(rect.x(),rect.bottom(),font,satkstr)

                rect = QRectF(event.rect())
                br = path.boundingRect()
                path.translate(rect.center().x()-br.center().x(),
                        rect.center().y()-br.top()+1)

                # 
                pen.setBrush(Qt.black)
                pen.setWidthF(.75)
                painter.setPen(pen)
                painter.drawPath(path)
コード例 #19
0
    path.quadTo(c1, p1)
    path.quadTo(c2, start)
# end def


_PATH_START = QPointF(_HBW, _HBW)
_PATH_MID_UP = QPointF(_HBW, -_BW)
_PATH_UP_UP_CTRL_PT = QPointF(-_HBW, -_BW)
_PATH_UP_DOWN_CTRL_PT = QPointF(1.5 * _BW, -_BW)
_PATH_MID_DOWN = QPointF(_HBW, 2 * _BW)
_PATH_DOWN_DOWN_CTRL_PT = QPointF(-_HBW, 2 * _BW)
_PATH_DOWN_UP_CTRL_PT = QPointF(1.5 * _BW, 2 * _BW)
_INSERT_PATH_UP = QPainterPath()
_insertGen(_INSERT_PATH_UP, _PATH_START, _PATH_UP_UP_CTRL_PT,
           _PATH_MID_UP, _PATH_UP_DOWN_CTRL_PT)
_INSERT_PATH_UP.translate(_OFFSET1, 0)
_INSERT_PATH_UP_RECT = _INSERT_PATH_UP.boundingRect()
_INSERT_PATH_DOWN = QPainterPath()
_insertGen(_INSERT_PATH_DOWN, _PATH_START, _PATH_DOWN_DOWN_CTRL_PT,
           _PATH_MID_DOWN, _PATH_DOWN_UP_CTRL_PT)
_INSERT_PATH_DOWN.translate(_OFFSET1, 0)
_INSERT_PATH_DOWNRect = _INSERT_PATH_DOWN.boundingRect()


_BIG_RECT = _DEFAULT_RECT.united(_INSERT_PATH_UP_RECT)
_BIG_RECT = _BIG_RECT.united(_INSERT_PATH_DOWNRect)
_B_PEN2 = getPenObj(styles.BLUE_STROKE, 2)
_OFFSET2 = _BW*0.75
_FONT = QFont(styles.THE_FONT, styles.THE_FONT_SIZE/2, QFont.Bold)
_BIG_RECT.adjust(-15, -15, 30, 30)
# Bases are drawn along and above the insert path.
コード例 #20
0
    path.quadTo(c2, start)


# end def

_pathStart = QPointF(_hbw, _hbw)
_pathMidUp = QPointF(_hbw, -_bw)
_pathUpUpCtrlPt = QPointF(-_hbw, -_bw)
_pathUpDownCtrlPt = QPointF(1.5 * _bw, -_bw)
_pathMidDown = QPointF(_hbw, 2 * _bw)
_pathDownDownCtrlPt = QPointF(-_hbw, 2 * _bw)
_pathDownUpCtrlPt = QPointF(1.5 * _bw, 2 * _bw)
_insertPathUp = QPainterPath()
_insertGen(_insertPathUp, _pathStart, _pathUpUpCtrlPt,\
         _pathMidUp, _pathUpDownCtrlPt)
_insertPathUp.translate(_offset1, 0)
_insertPathUpRect = _insertPathUp.boundingRect()
_insertPathDown = QPainterPath()
_insertGen(_insertPathDown, _pathStart, _pathDownDownCtrlPt,\
         _pathMidDown, _pathDownUpCtrlPt)
_insertPathDown.translate(_offset1, 0)
_insertPathDownRect = _insertPathDown.boundingRect()

_bigRect = _defaultRect.united(_insertPathUpRect)
_bigRect = _bigRect.united(_insertPathDownRect)
_bpen2 = QPen(styles.BLUE_STROKE, 2)
_offset2 = _bw * 0.75
_font = QFont(styles.THE_FONT, 10, QFont.Bold)
_bigRect.adjust(-15, -15, 30, 30)
# Bases are drawn along and above the insert path.
# These calculations revolve around fixing the characters at a certain
コード例 #21
0
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()