Esempio n. 1
0
    def __init__(self, icon_label, status_label, progress_bar):
        """
        :param parent: The model parent.
        :type parent: :class:`~PySide.QtGui.QObject`
        """
        super(ProgressHandler, self).__init__()

        self._icon_label = icon_label
        self._status_label = status_label
        self._progress_bar = progress_bar

        self._icon_lookup = {
            self.PHASE_LOAD:
            QtGui.QPixmap(":/tk_multi_publish2/status_load.png"),
            self.PHASE_VALIDATE:
            QtGui.QPixmap(":/tk_multi_publish2/status_validate.png"),
            self.PHASE_PUBLISH:
            QtGui.QPixmap(":/tk_multi_publish2/status_publish.png"),
            self.PHASE_FINALIZE:
            QtGui.QPixmap(":/tk_multi_publish2/status_success.png"),
        }

        self._icon_warning = QtGui.QPixmap(
            ":/tk_multi_publish2/status_warning.png")
        self._icon_error = QtGui.QPixmap(
            ":/tk_multi_publish2/status_error.png")

        # These colors come from the HIG.
        self._debug_brush = QtGui.QBrush(QtGui.QColor("#88BC47"))  # green
        self._warning_brush = QtGui.QBrush(QtGui.QColor("#F9A332"))  # orange
        self._error_brush = QtGui.QBrush(QtGui.QColor("#EC494A"))  # red

        # parent our progress widget overlay
        self._progress_details = ProgressDetailsWidget(
            self._progress_bar.parent())
        self._progress_details.copy_to_clipboard_clicked.connect(
            self._copy_log_to_clipboard)

        # clicking on the log toggles the logging window
        self._status_label.clicked.connect(self._progress_details.toggle)

        # store all log messages in a list
        self._log_messages = []
        self._current_indent = 0

        # set up our log dispatch
        self._log_wrapper = PublishLogWrapper(self)

        self._logging_parent_item = None  # none means root

        self._current_phase = None
Esempio n. 2
0
def create_round_thumbnail(image):
    """
    Create a 200 px wide circle thumbnail
    
    :param image: QImage representing a thumbnail
    :returns: Round QPixmap
    """
    CANVAS_SIZE = 200

    # get the 512 base image
    base_image = QtGui.QPixmap(CANVAS_SIZE, CANVAS_SIZE)
    base_image.fill(QtCore.Qt.transparent)

    # now attempt to load the image
    # pixmap will be a null pixmap if load fails
    thumb = QtGui.QPixmap.fromImage(image)

    if not thumb.isNull():

        # scale it down to fit inside a frame of maximum 512x512
        thumb_scaled = thumb.scaled(CANVAS_SIZE, CANVAS_SIZE,
                                    QtCore.Qt.KeepAspectRatioByExpanding,
                                    QtCore.Qt.SmoothTransformation)

        # now composite the thumbnail on top of the base image
        # bottom align it to make it look nice
        thumb_img = thumb_scaled.toImage()
        brush = QtGui.QBrush(thumb_img)
        painter = QtGui.QPainter(base_image)
        painter.setRenderHint(QtGui.QPainter.Antialiasing)
        painter.setBrush(brush)
        painter.drawEllipse(0, 0, CANVAS_SIZE, CANVAS_SIZE)
        painter.end()

    return base_image
Esempio n. 3
0
    def paintEvent(self, event):
        """
        Render the UI.
        """
        if self._mode == self.MODE_OFF:
            return
        
        painter = QtGui.QPainter()
        painter.begin(self)
        try:
            # set up semi transparent backdrop
            painter.setRenderHint(QtGui.QPainter.Antialiasing)
            overlay_color = QtGui.QColor(30, 30, 30, 100)
            painter.setBrush( QtGui.QBrush(overlay_color))
            painter.setPen(QtGui.QPen(overlay_color))
            painter.drawRect(0, 0, painter.device().width(), painter.device().height())

            # show the spinner
            painter.translate((painter.device().width() / 2) - 10, 
                              (painter.device().height() / 2) - 10)
            
            pen = QtGui.QPen(QtGui.QColor(self._bundle.style_constants["SG_HIGHLIGHT_COLOR"]))
            pen.setWidth(1)
            painter.setPen(pen)

            r = QtCore.QRectF(0.0, 0.0, 20.0, 20.0)
            start_angle = (0 + self._spin_angle) * 4 * 16
            span_angle = 340 * 16 

            painter.drawArc(r, start_angle, span_angle)
            
        finally:
            painter.end()
    def _get_default_thumbnail(self, sg_entity):
        """
        Get the default icon for the specified entity.

        :param sg_entity:   A Shotgun entity dictionary for the entity to get the
                            icon for.
        :returns:           A QIcon for the entity if available.  For Step entities, a swatch 
                            representing the step colour is returned.  If no icon is available 
                            for the entity type then the default icon is returned
        """
        if sg_entity.get("type") == "Step":
            # special case handling for steps to return a colour swatch:
            step_id = sg_entity.get("id")
            if step_id != None:
                # get the colour from the cache:
                if step_id not in ShotgunEntityModel._SG_STEP_COLOURS:
                    ShotgunEntityModel._SG_STEP_COLOURS[step_id] = None
                    # refresh cache:
                    bundle = sgtk.platform.current_bundle()
                    try:
                        sg_steps = bundle.shotgun.find("Step", [], ["color"])
                        for sg_step in sg_steps:
                            colour = None
                            try:
                                colour = tuple([
                                    int(c)
                                    for c in sg_step.get("color").split(",")
                                ])
                            except:
                                pass
                            ShotgunEntityModel._SG_STEP_COLOURS[
                                sg_step["id"]] = colour
                    except:
                        pass
                colour = ShotgunEntityModel._SG_STEP_COLOURS[step_id]

                if colour and isinstance(colour, tuple) and len(colour) == 3:
                    # get the icon for this colour from the cache:
                    if colour not in self._step_swatch_icons:
                        # build icon and add to cache:
                        pm = QtGui.QPixmap(16, 16)
                        pm.fill(QtCore.Qt.transparent)
                        painter = QtGui.QPainter(pm)
                        try:
                            painter.setBrush(
                                QtGui.QBrush(
                                    QtGui.QColor(colour[0], colour[1],
                                                 colour[2])))
                            painter.setPen(QtCore.Qt.black)
                            painter.drawRect(2, 2, 12, 12)
                        finally:
                            painter.end()
                        self._step_swatch_icons[colour] = QtGui.QIcon(pm)

                    # return the icon:
                    return self._step_swatch_icons[colour]

        # just return the entity icon or the default icon if there is no entity icon:
        return self.get_entity_icon(
            sg_entity.get("type")) or self._default_icon
Esempio n. 5
0
def create_overlayed_user_publish_thumbnail(publish_pixmap, user_pixmap):
    """
    Creates a sqaure 75x75 thumbnail with an optional overlayed pixmap.
    """
    # create a 100x100 base image
    base_image = QtGui.QPixmap(75, 75)
    base_image.fill(QtCore.Qt.transparent)

    painter = QtGui.QPainter(base_image)
    painter.setRenderHint(QtGui.QPainter.Antialiasing)

    # scale down the thumb
    if not publish_pixmap.isNull():
        thumb_scaled = publish_pixmap.scaled(
            75, 75,
            QtCore.Qt.KeepAspectRatioByExpanding,
            QtCore.Qt.SmoothTransformation)

        # now composite the thumbnail on top of the base image
        # bottom align it to make it look nice
        thumb_img = thumb_scaled.toImage()
        brush = QtGui.QBrush(thumb_img)
        painter.save()
        painter.setBrush(brush)
        painter.setPen(QtGui.QPen(QtCore.Qt.NoPen))
        painter.drawRect(0, 0, 75, 75)
        painter.restore()

    if user_pixmap and not user_pixmap.isNull():

        # overlay the user picture on top of the thumbnail
        user_scaled = user_pixmap.scaled(
            30, 30,
            QtCore.Qt.KeepAspectRatioByExpanding,
            QtCore.Qt.SmoothTransformation)
        user_img = user_scaled.toImage()
        user_brush = QtGui.QBrush(user_img)
        painter.save()
        painter.translate(42, 42)
        painter.setBrush(user_brush)
        painter.setPen(QtGui.QPen(QtCore.Qt.NoPen))
        painter.drawRect(0, 0, 30, 30)
        painter.restore()

    painter.end()

    return base_image
Esempio n. 6
0
def create_overlayed_publish_thumbnail(image):
    """
    Given a shotgun thumbnail, create a publish icon
    with the thumbnail composited onto a centered otherwise empty canvas.
    This will return a 512x400 pixmap object.


    :param image: QImage containing a thumbnail
    :returns: QPixmap with a 512x400 px image
    """

    CANVAS_WIDTH = 512
    CANVAS_HEIGHT = 400
    CORNER_RADIUS = 10

    # get the 512 base image
    base_image = QtGui.QPixmap(CANVAS_WIDTH, CANVAS_HEIGHT)
    base_image.fill(QtCore.Qt.transparent)

    # now attempt to load the image
    # pixmap will be a null pixmap if load fails
    thumb = QtGui.QPixmap.fromImage(image)

    if not thumb.isNull():

        # scale it down to fit inside a frame of maximum 512x512
        thumb_scaled = thumb.scaled(CANVAS_WIDTH, CANVAS_HEIGHT,
                                    QtCore.Qt.KeepAspectRatio,
                                    QtCore.Qt.SmoothTransformation)

        # now composite the thumbnail on top of the base image
        # bottom align it to make it look nice
        thumb_img = thumb_scaled.toImage()
        brush = QtGui.QBrush(thumb_img)

        painter = QtGui.QPainter(base_image)
        painter.setRenderHint(QtGui.QPainter.Antialiasing)
        painter.setBrush(brush)

        # figure out the offsets in order to center the thumb
        height_difference = CANVAS_HEIGHT - thumb_scaled.height()
        width_difference = CANVAS_WIDTH - thumb_scaled.width()

        # center it horizontally
        inlay_offset_w = (width_difference / 2) + (CORNER_RADIUS / 2)
        # center it vertically
        inlay_offset_h = (height_difference / 2) + (CORNER_RADIUS / 2)

        # note how we have to compensate for the corner radius
        painter.translate(inlay_offset_w, inlay_offset_h)
        painter.drawRoundedRect(0, 0,
                                thumb_scaled.width() - CORNER_RADIUS,
                                thumb_scaled.height() - CORNER_RADIUS,
                                CORNER_RADIUS, CORNER_RADIUS)

        painter.end()

    return base_image
Esempio n. 7
0
def create_rectangular_thumbnail(thumb):
    """
    Scale a given pixmap down to a given resolution

    :param thumb: pixmap to scale
    :returns: scaled thumbnail
    """
    # TODO: this would be great to add to the qtwidgets framework

    CANVAS_WIDTH = 48
    CANVAS_HEIGHT = 38

    if thumb.isNull():
        # to be safe, if thumb is null, use the empty/default thumbnail
        thumb = QtGui.QPixmap(
            ":/tk_framework_qtwidgets.global_search_widget/no_thumbnail.png"
        )

    # get the 512 base image
    base_image = QtGui.QPixmap(CANVAS_WIDTH, CANVAS_HEIGHT)
    base_image.fill(QtCore.Qt.transparent)

    # scale it down to fit inside a frame of maximum 512x400
    thumb_scaled = thumb.scaled(
        CANVAS_WIDTH,
        CANVAS_HEIGHT,
        QtCore.Qt.KeepAspectRatioByExpanding,
        QtCore.Qt.SmoothTransformation,
    )

    # now composite the thumbnail on top of the base image
    # bottom align it to make it look nice
    thumb_img = thumb_scaled.toImage()
    brush = QtGui.QBrush(thumb_img)

    painter = QtGui.QPainter(base_image)
    painter.setRenderHint(QtGui.QPainter.Antialiasing)
    painter.setBrush(brush)

    # figure out the offset height wise in order to center the thumb
    height_difference = CANVAS_HEIGHT - thumb_scaled.height()
    width_difference = CANVAS_WIDTH - thumb_scaled.width()

    # center it with wise
    inlay_offset_w = width_difference / 2
    # bottom height wise
    # inlay_offset_h = height_difference+CORNER_RADIUS
    inlay_offset_h = height_difference / 2

    # note how we have to compensate for the corner radius
    painter.translate(inlay_offset_w, inlay_offset_h)
    painter.drawRect(0, 0, thumb_scaled.width(), thumb_scaled.height())

    painter.end()

    return base_image
Esempio n. 8
0
 def clear_highlight(self):
     original_format = QtGui.QTextCharFormat()
     original_format.setBackground(
         QtGui.QBrush(QtGui.QColor(0, 0, 0), QtCore.Qt.NoBrush)
     )
     cursor = self.__logs.textCursor()
     cursor.select(QtGui.QTextCursor.Document)
     cursor.mergeCharFormat(original_format)
     cursor.clearSelection()
     self.__logs.setTextCursor(cursor)
    def highlight_current_line(self):
        """Highlight the current line of the input widget."""

        extra_selection = QtGui.QTextEdit.ExtraSelection()
        extra_selection.format.setBackground(
            QtGui.QBrush(self._current_line_color()))
        extra_selection.format.setProperty(
            QtGui.QTextFormat.FullWidthSelection, True)
        extra_selection.cursor = self.textCursor()
        extra_selection.cursor.clearSelection()

        self.setExtraSelections([extra_selection])
Esempio n. 10
0
def create_rectangular_512x400_thumbnail(image):
    """
    Given a QImage shotgun thumbnail, create a rectangular icon
    with the thumbnail composited onto a centered otherwise empty canvas.
    This will return a 512x400 pixmap object.

    :param image: QImage source image
    :returns: QPixmap rectangular thumbnail on a 512x400 rect backdrop
    """
    CANVAS_WIDTH = 512
    CANVAS_HEIGHT = 400
    CORNER_RADIUS = 10

    # get the 512 base image
    base_image = QtGui.QPixmap(CANVAS_WIDTH, CANVAS_HEIGHT)
    base_image.fill(QtCore.Qt.transparent)

    # now attempt to load the image
    # pixmap will be a null pixmap if load fails
    thumb = QtGui.QPixmap.fromImage(image)

    if not thumb.isNull():

        # scale it down to fit inside a frame of maximum 512x512
        thumb_scaled = thumb.scaled(
            CANVAS_WIDTH,
            CANVAS_HEIGHT,
            QtCore.Qt.KeepAspectRatioByExpanding,
            QtCore.Qt.SmoothTransformation,
        )

        # now composite the thumbnail on top of the base image
        # bottom align it to make it look nice
        thumb_img = thumb_scaled.toImage()
        brush = QtGui.QBrush(thumb_img)

        painter = QtGui.QPainter(base_image)
        painter.setRenderHint(QtGui.QPainter.Antialiasing)
        painter.setBrush(brush)
        painter.setPen(QtGui.QPen())

        painter.drawRoundedRect(
            0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, CORNER_RADIUS, CORNER_RADIUS
        )

        painter.end()

    return base_image
Esempio n. 11
0
def __create_rounded_rect_thumbnail(image, canvas_width, canvas_height,
                                    radius):
    """
    Given a qimage shotgun thumbnail, create a publish icon
    with the thumbnail composited onto a centered otherwise empty canvas.
    The thumbnail will be taking up all the space in the image.

    :param image: QImage to load thumbnail from
    :param canvas_width: Width of image to generate, in pixels
    :param canvas_height: Heiht of image to generate, in pixels
    :param radius: Corner radius of image to generate, in pixels
    :returns: QPixmap object
    """
    # get the base image
    base_image = QtGui.QPixmap(canvas_width, canvas_height)
    base_image.fill(QtCore.Qt.transparent)

    # now attempt to load the image
    # pixmap will be a null pixmap if load fails
    thumb = QtGui.QPixmap.fromImage(image)

    if not thumb.isNull():

        # scale it down to fit inside a frame
        thumb_scaled = thumb.scaled(
            canvas_width,
            canvas_height,
            QtCore.Qt.KeepAspectRatioByExpanding,
            QtCore.Qt.SmoothTransformation,
        )

        # now composite the thumbnail on top of the base image
        # bottom align it to make it look nice
        thumb_img = thumb_scaled.toImage()
        brush = QtGui.QBrush(thumb_img)

        painter = QtGui.QPainter(base_image)
        painter.setRenderHint(QtGui.QPainter.Antialiasing)
        painter.setBrush(brush)
        painter.setPen(QtGui.QPen())

        painter.drawRoundedRect(0, 0, canvas_width, canvas_height, radius,
                                radius)

        painter.end()

    return base_image
Esempio n. 12
0
    def __format_thumbnail(self, pixmap_obj):
        """
        Given a screengrab, create a thumbnail object, scaled to 96x75 px
        and with a subtle rounded frame.
        
        :param pixmap_obj: input screenshot
        :returns: 96x75px pixmap 
        """
        CANVAS_WIDTH = 96
        CANVAS_HEIGHT = 75
        CORNER_RADIUS = 6
    
        # get the 512 base image
        base_image = QtGui.QPixmap(CANVAS_WIDTH, CANVAS_HEIGHT)
        base_image.fill(QtCore.Qt.transparent)
        
        # scale it down to fit inside a frame of maximum 512x512
        thumb_scaled = pixmap_obj.scaled(CANVAS_WIDTH, 
                                         CANVAS_HEIGHT, 
                                         QtCore.Qt.KeepAspectRatioByExpanding, 
                                         QtCore.Qt.SmoothTransformation)  

        # now composite the thumbnail on top of the base image
        # bottom align it to make it look nice
        thumb_img = thumb_scaled.toImage()
        brush = QtGui.QBrush(thumb_img)
        
        painter = QtGui.QPainter(base_image)
        painter.setRenderHint(QtGui.QPainter.Antialiasing)
        painter.setBrush(brush)

        pen = QtGui.QPen(QtGui.QColor("#2C93E2"))
        pen.setWidth(3)
        painter.setPen(pen)
        
        # note how we have to compensate for the corner radius
        painter.drawRoundedRect(0,  
                                0, 
                                CANVAS_WIDTH, 
                                CANVAS_HEIGHT, 
                                CORNER_RADIUS, 
                                CORNER_RADIUS)
        
        painter.end()
        
        return base_image        
Esempio n. 13
0
    def paintEvent(self, paint_event):
       """
       Paints the line plain text editor and adds a placeholder on bottom right corner when multiple values are detected.
       """
 
       # If the box does not have focus, draw <multiple values> placeholder when self._show_placeholder is true, even if the widget has text
       if not self.hasFocus() and self._show_placeholder == True:
           p = QtGui.QPainter(self.viewport())

           # right placeholder note in blue
           col = QtGui.QColor(24,167,227) # blue
           p.setPen(QtGui.QPen(col))
           p.setBrush(QtGui.QBrush(col))

           p.drawText(self.rect(),QtCore.Qt.AlignTop | QtCore.Qt.AlignLeft, self._placeholder_text)
 
       else:
           QtGui.QPlainTextEdit.paintEvent(self, paint_event)
Esempio n. 14
0
 def paintEvent(self, event):
     """
     Render the UI.
     """
     if self._mode == self.MODE_OFF:
         return
     
     painter = QtGui.QPainter()
     painter.begin(self)
     try:
         # set up semi transparent backdrop
         painter.setRenderHint(QtGui.QPainter.Antialiasing)
         overlay_color = QtGui.QColor(30, 30, 30, 160)
         painter.setBrush( QtGui.QBrush(overlay_color))
         painter.setPen(QtGui.QPen(overlay_color))
         painter.drawRect(0, 0, painter.device().width(), painter.device().height())            
     finally:
         painter.end()
Esempio n. 15
0
    def paintEvent(self, paint_event):
        """
        Paints the line plain text editor and adds a placeholder on bottom right corner when multiple values are detected.
        """

        # If the box does not have focus, draw <multiple values> placeholder when self._show_placeholder is true, even if the widget has text
        if not self.hasFocus() and self._show_multiple_values is True:
            p = QtGui.QPainter(self.viewport())

            # right placeholder note in blue
            col = QtGui.QColor(self._highlight)  # blue
            p.setPen(QtGui.QPen(col))
            p.setBrush(QtGui.QBrush(col))

            p.drawText(
                self.rect(),
                QtCore.Qt.AlignTop | QtCore.Qt.AlignLeft,
                self._multiple_values_text,
            )

        else:
            super(PublishDescriptionEditBase, self).paintEvent(paint_event)
Esempio n. 16
0
 def find_all(self, pattern, logs):
     highlight_format = QtGui.QTextCharFormat()
     highlight_format.setBackground(
         QtGui.QBrush(QtGui.QColor(80, 80, 80))
     )
     regex = QtCore.QRegExp(pattern, QtCore.Qt.CaseInsensitive)
     matches = []
     pos = 0
     index = regex.indexIn(logs, pos)
     count = 0
     while (index != -1):
         count += 1
         matched_length = regex.matchedLength()
         # append start index and length of last matched string
         # length could be different
         matches.append((index, matched_length))
         # select the matched text and apply the desired format
         self.highlight_one(index, matched_length, highlight_format)
         # Move to the next match
         pos = index + matched_length
         index = regex.indexIn(logs, pos)
     return matches
Esempio n. 17
0
    def paintEvent(self, event):
        """
        Override the Qt method.

        Highlight the background color on mouse hover.
        """

        super(ChoicesFilterItemWidget, self).paintEvent(event)

        option = QtGui.QStyleOption()
        option.initFrom(self)
        painter = QtGui.QPainter()
        painter.begin(self)
        try:
            if option.state & QtGui.QStyle.State_MouseOver:
                painter.setRenderHint(QtGui.QPainter.Antialiasing)
                hover_color = option.palette.highlight().color()
                painter.setBrush(QtGui.QBrush(hover_color))
                painter.setPen(QtGui.QPen(hover_color))
                painter.drawRect(
                    0, 0, painter.device().width(), painter.device().height()
                )
        finally:
            painter.end()
Esempio n. 18
0
def create_overlayed_folder_thumbnail(image):
    """
    Given a shotgun thumbnail, create a folder icon
    with the thumbnail composited on top. This will return a
    512x400 pixmap object.

    :param image: QImage containing a thumbnail
    :returns: QPixmap with a 512x400 px image
    """
    # folder icon size
    CANVAS_WIDTH = 512
    CANVAS_HEIGHT = 400

    # corner radius when we draw
    CORNER_RADIUS = 10

    # maximum sized canvas we can draw on *inside* the
    # folder icon graphic
    MAX_THUMB_WIDTH = 460
    MAX_THUMB_HEIGHT = 280

    # looks like there are some pyside related memory issues here relating to
    # referencing a resource and then operating on it. Just to be sure, make
    # make a full copy of the resource before starting to manipulate.
    base_image = QtGui.QPixmap(":/res/folder_512x400.png")

    # now attempt to load the image
    # pixmap will be a null pixmap if load fails
    thumb = QtGui.QPixmap.fromImage(image)

    if not thumb.isNull():

        thumb_scaled = thumb.scaled(MAX_THUMB_WIDTH, MAX_THUMB_HEIGHT,
                                    QtCore.Qt.KeepAspectRatio,
                                    QtCore.Qt.SmoothTransformation)

        # now composite the thumbnail
        thumb_img = thumb_scaled.toImage()
        brush = QtGui.QBrush(thumb_img)

        painter = QtGui.QPainter(base_image)
        painter.setRenderHint(QtGui.QPainter.Antialiasing)
        painter.setBrush(brush)

        # figure out the offset height wise in order to center the thumb
        height_difference = CANVAS_HEIGHT - thumb_scaled.height()
        width_difference = CANVAS_WIDTH - thumb_scaled.width()

        inlay_offset_w = (width_difference / 2) + (CORNER_RADIUS / 2)
        # add a 30 px offset here to push the image off center to
        # fit nicely inside the folder icon
        inlay_offset_h = (height_difference / 2) + (CORNER_RADIUS / 2) + 30

        # note how we have to compensate for the corner radius
        painter.translate(inlay_offset_w, inlay_offset_h)
        painter.drawRoundedRect(0, 0,
                                thumb_scaled.width() - CORNER_RADIUS,
                                thumb_scaled.height() - CORNER_RADIUS,
                                CORNER_RADIUS, CORNER_RADIUS)

        painter.end()

    return base_image
Esempio n. 19
0
def create_round_512x400_note_thumbnail(image, client=False, unread=False):
    """
    Given a QImage shotgun thumbnail, create a round icon
    with the thumbnail composited onto a centered otherwise empty canvas.
    This will return a 512x400 pixmap object.

    :param image: QImage source image
    :param client: indicates that this is a client note
    :param unread: indicates that this is an unread note
    :returns: QPixmap circular thumbnail, 380px wide, on a
              512x400 rect backdrop
    """
    CANVAS_WIDTH = 512
    CANVAS_HEIGHT = 400
    CIRCLE_SIZE = 380

    # get the 512 base image
    base_image = QtGui.QPixmap(CANVAS_WIDTH, CANVAS_HEIGHT)
    base_image.fill(QtCore.Qt.transparent)

    # now attempt to load the image
    # pixmap will be a null pixmap if load fails
    thumb = QtGui.QPixmap.fromImage(image)

    if not thumb.isNull():

        # scale it to fill a 400x400 square
        thumb_scaled = thumb.scaled(
            CIRCLE_SIZE,
            CIRCLE_SIZE,
            QtCore.Qt.KeepAspectRatioByExpanding,
            QtCore.Qt.SmoothTransformation,
        )

        # now composite the thumbnail on top of the base image
        # bottom align it to make it look nice
        thumb_img = thumb_scaled.toImage()
        brush = QtGui.QBrush(thumb_img)

        painter = QtGui.QPainter(base_image)
        painter.setRenderHint(QtGui.QPainter.Antialiasing)
        painter.setBrush(brush)

        # figure out the offset height wise in order to center the thumb

        # center it
        inlay_offset_h = (CANVAS_HEIGHT - CIRCLE_SIZE) / 2
        inlay_offset_w = (CANVAS_WIDTH - CIRCLE_SIZE) / 2

        # note how we have to compensate for the corner radius
        painter.translate(inlay_offset_w, inlay_offset_h)
        painter.drawEllipse(0, 0, CIRCLE_SIZE, CIRCLE_SIZE)

        if unread:
            UNREAD_NOTE_INDICATOR = QtGui.QPixmap(
                ":/tk_multi_infopanel/unread_indicator.png"
            )
            painter.drawPixmap(-10, -10, UNREAD_NOTE_INDICATOR)

        painter.translate(0, 250)

        if client:
            CLIENT_NOTE_INDICATOR = QtGui.QPixmap(
                ":/tk_multi_infopanel/client_note_indicator.png"
            )
            painter.drawPixmap(0, 0, CLIENT_NOTE_INDICATOR)

        painter.end()

    return base_image