Ejemplo n.º 1
0
    def __init__(self, parent):
        """Exclamation icon graphics item.
        Used to notify that a ProjectItem is missing some configuration.

        Args:
            parent (ProjectItemIcon): the parent item
        """
        super().__init__(parent)
        self._parent = parent
        self._notifications = list()
        self.renderer = QSvgRenderer()
        self.colorizer = QGraphicsColorizeEffect()
        self.colorizer.setColor(QColor("red"))
        # Load SVG
        loading_ok = self.renderer.load(
            ":/icons/project_item_icons/exclamation-circle.svg")
        if not loading_ok:
            return
        size = self.renderer.defaultSize()
        self.setSharedRenderer(self.renderer)
        dim_max = max(size.width(), size.height())
        rect_w = parent.rect().width()  # Parent rect width
        self.setScale(0.2 * rect_w / dim_max)
        self.setGraphicsEffect(self.colorizer)
        self.setAcceptHoverEvents(True)
        self.setFlag(QGraphicsItem.ItemIsSelectable, enabled=False)
        self.hide()
Ejemplo n.º 2
0
 def findIcons(self):
     if hou.applicationVersion()[0] < 15:
         for category in os.listdir(self.path):
             for ico in os.listdir(os.path.join(self.path, category)):
                 iconPath = os.path.join(
                     os.path.join(self.path, category, ico))
                 iconName = '_'.join([category, os.path.splitext(ico)[0]])
                 self.icons[iconName] = QPixmap(iconPath)
     else:
         zf = zipfile.ZipFile(self.path, 'r')
         for f in zf.namelist():
             if f.startswith('old'): continue
             if os.path.splitext(f)[-1] == '.svg':
                 svg = QSvgRenderer(QByteArray(zf.read(f)))
                 if not svg.isValid():
                     continue
                 pixmap = QPixmap(iconSize, iconSize)
                 painter = QPainter()
                 painter.begin(pixmap)
                 pixmap.fill(QColor(Qt.black))
                 svg.render(painter)
                 painter.end()
                 category, ico = f.split('/')
                 iconName = '_'.join([category, os.path.splitext(ico)[0]])
                 self.icons[iconName] = pixmap
         zf.close()
Ejemplo n.º 3
0
class ExclamationIcon(QGraphicsSvgItem):
    def __init__(self, parent):
        """Exclamation icon graphics item.
        Used to notify that a ProjectItem is missing some configuration.

        Args:
            parent (ProjectItemIcon): the parent item
        """
        super().__init__(parent)
        self._parent = parent
        self._notifications = list()
        self.renderer = QSvgRenderer()
        self.colorizer = QGraphicsColorizeEffect()
        self.colorizer.setColor(QColor("red"))
        # Load SVG
        loading_ok = self.renderer.load(
            ":/icons/project_item_icons/exclamation-circle.svg")
        if not loading_ok:
            return
        size = self.renderer.defaultSize()
        self.setSharedRenderer(self.renderer)
        dim_max = max(size.width(), size.height())
        rect_w = parent.rect().width()  # Parent rect width
        self.setScale(0.2 * rect_w / dim_max)
        self.setGraphicsEffect(self.colorizer)
        self.setAcceptHoverEvents(True)
        self.setFlag(QGraphicsItem.ItemIsSelectable, enabled=False)
        self.hide()

    def clear_notifications(self):
        """Clear all notifications."""
        self._notifications.clear()
        self.hide()

    def add_notification(self, text):
        """Add a notification."""
        self._notifications.append(text)
        self.show()

    def hoverEnterEvent(self, event):
        """Shows notifications as tool tip.

        Args:
            event (QGraphicsSceneMouseEvent): Event
        """
        if not self._notifications:
            return
        tip = "<p>" + "<p>".join(self._notifications)
        QToolTip.showText(event.screenPos(), tip)

    def hoverLeaveEvent(self, event):
        """Hides tool tip.

        Args:
            event (QGraphicsSceneMouseEvent): Event
        """
        QToolTip.hideText()
Ejemplo n.º 4
0
 def __load_svg(self, svg_file: str) -> QPixmap:
     """Loads a SVG file and scales it correctly for High-DPI screens"""
     svg_renderer = QSvgRenderer(svg_file)
     pixmap = QPixmap(svg_renderer.defaultSize() * self.devicePixelRatio())
     pixmap.fill(Qt.transparent)
     painter = QPainter()
     painter.begin(pixmap)
     svg_renderer.render(painter)
     painter.end()
     pixmap.setDevicePixelRatio(self.devicePixelRatio())
     return pixmap
Ejemplo n.º 5
0
    def __init__(self, toolbox, x, y, w, h, project_item, icon_file,
                 icon_color, background_color):
        """Base class for project item icons drawn in Design View.

        Args:
            toolbox (ToolBoxUI): QMainWindow instance
            x (float): Icon x coordinate
            y (float): Icon y coordinate
            w (float): Icon width
            h (float): Icon height
            project_item (ProjectItem): Item
            icon_file (str): Path to icon resource
            icon_color (QColor): Icon's color
            background_color (QColor): Background color
        """
        super().__init__()
        self._toolbox = toolbox
        self._project_item = project_item
        self._moved_on_scene = False
        self.renderer = QSvgRenderer()
        self.svg_item = QGraphicsSvgItem()
        self.colorizer = QGraphicsColorizeEffect()
        self.setRect(QRectF(x, y, w, h))  # Set ellipse coordinates and size
        self.text_font_size = 10  # point size
        # Make item name graphics item.
        name = project_item.name if project_item else ""
        self.name_item = QGraphicsSimpleTextItem(name)
        shadow_effect = QGraphicsDropShadowEffect()
        shadow_effect.setOffset(1)
        shadow_effect.setEnabled(False)
        self.setGraphicsEffect(shadow_effect)
        self.set_name_attributes()  # Set font, size, position, etc.
        # Make connector buttons
        self.connectors = dict(
            bottom=ConnectorButton(self, toolbox, position="bottom"),
            left=ConnectorButton(self, toolbox, position="left"),
            right=ConnectorButton(self, toolbox, position="right"),
        )
        # Make exclamation and rank icons
        self.exclamation_icon = ExclamationIcon(self)
        self.rank_icon = RankIcon(self)
        # Group the drawn items together by setting the background rectangle as the parent of other QGraphicsItems
        # NOTE: setting the parent item moves the items as one!
        self.name_item.setParentItem(self)
        for conn in self.connectors.values():
            conn.setParentItem(self)
        self.svg_item.setParentItem(self)
        self.exclamation_icon.setParentItem(self)
        self.rank_icon.setParentItem(self)
        brush = QBrush(background_color)
        self._setup(brush, icon_file, icon_color)
        # Add items to scene
        scene = self._toolbox.ui.graphicsView.scene()
        scene.addItem(self)
Ejemplo n.º 6
0
 def __init__(self, x, y, w, h, parent):
     super().__init__(x, y, w, h, parent)
     self._parent = parent
     color = QColor("slateblue")
     self.setBrush(qApp.palette().window())  # pylint: disable=undefined-variable
     self._text_item = QGraphicsTextItem(self)
     font = QFont('Font Awesome 5 Free Solid')
     self._text_item.setFont(font)
     self._text_item.setDefaultTextColor(color)
     self._svg_item = QGraphicsSvgItem(self)
     self._datapkg_renderer = QSvgRenderer()
     self._datapkg_renderer.load(":/icons/datapkg.svg")
     self.setFlag(QGraphicsItem.ItemIsSelectable, enabled=False)
     self._block_updates = False
Ejemplo n.º 7
0
    def paint(self, painter, option, index):
        row = index.row()
        column = index.column()
        cell_data = self.grid_data[row][column]
        is_word_cell = cell_data[0]
        clue_index = cell_data[1] or cell_data[2]

        painter.save()
        if is_word_cell:
            if clue_index:
                icon_path = os.path.join(icons_folder,
                                         '{}.svg'.format(clue_index))
                renderer = QSvgRenderer(icon_path)
                #pixmap = QPixmap(QSize(grid_cell_size, grid_cell_size))
                #pixmap.fill(Qt.transparent)
                renderer.render(painter, option.rect())
        painter.restore()
Ejemplo n.º 8
0
class _LinkIcon(QGraphicsEllipseItem):
    """An icon to show over a Link."""
    def __init__(self, x, y, w, h, parent):
        super().__init__(x, y, w, h, parent)
        self._parent = parent
        color = QColor("slateblue")
        self.setBrush(qApp.palette().window())  # pylint: disable=undefined-variable
        self._text_item = QGraphicsTextItem(self)
        font = QFont('Font Awesome 5 Free Solid')
        self._text_item.setFont(font)
        self._text_item.setDefaultTextColor(color)
        self._svg_item = QGraphicsSvgItem(self)
        self._datapkg_renderer = QSvgRenderer()
        self._datapkg_renderer.load(":/icons/datapkg.svg")
        self.setFlag(QGraphicsItem.ItemIsSelectable, enabled=False)
        self._block_updates = False

    def update_icon(self):
        """Sets the icon (filter, datapkg, or none), depending on Connection state."""
        connection = self._parent.connection
        if connection.use_datapackage:
            self.setVisible(True)
            self._svg_item.setVisible(True)
            self._svg_item.setSharedRenderer(self._datapkg_renderer)
            scale = 0.8 * self.rect().width(
            ) / self._datapkg_renderer.defaultSize().width()
            self._svg_item.setScale(scale)
            self._svg_item.setPos(0, 0)
            self._svg_item.setPos(self.sceneBoundingRect().center() -
                                  self._svg_item.sceneBoundingRect().center())
            self._text_item.setVisible(False)
            return
        if connection.has_filters():
            self.setVisible(True)
            self._text_item.setVisible(True)
            self._text_item.setPlainText("\uf0b0")
            self._svg_item.setPos(0, 0)
            self._text_item.setPos(
                self.sceneBoundingRect().center() -
                self._text_item.sceneBoundingRect().center())
            self._svg_item.setVisible(False)
            return
        self.setVisible(False)
        self._text_item.setVisible(False)
        self._svg_item.setVisible(False)
Ejemplo n.º 9
0
    def __init__(self, parent, fn, *args):
        super(LoadingBar, self).__init__(parent)

        self.fn = fn
        self.args = args
        self.worker = Worker(fn, *args)
        self.worker.signals.result.connect(
            main_window.MainWindow.get_instance().calc_done)

        main_window.MainWindow.get_instance().threadpool.start(self.worker)

        # overlay
        # make the window frameless
        self.loading_icon = QSvgRenderer('resources/images/loading_icon.svg')
        self.qp = QPainter()

        self.setWindowFlags(Qt.FramelessWindowHint)
        self.setAttribute(Qt.WA_TranslucentBackground)

        self.fillColor = QColor(30, 30, 30, 120)
        self.penColor = QColor("#333333")

        self.close_btn = QPushButton(self)
        self.close_btn.setText("Abbrechen")

        font = QFont()
        font.setPixelSize(18)
        font.setBold(True)
        self.close_btn.setFont(font)
        self.close_btn.setStyleSheet("QPushButton {"
                                     "background-color: #EAEAEA;"
                                     "border: None;"
                                     "padding-top: 12px;"
                                     "padding-bottom: 12px;"
                                     "padding-left: 20px;"
                                     "padding-right: 20px;"
                                     "}"
                                     "QPushButton:hover {"
                                     "background-color: #DFDFDF;"
                                     "}")
        #self.close_btn.setFixedSize(30, 30)
        self.close_btn.clicked.connect(self._onclose)

        self.signals = LoadingBarSignals()
Ejemplo n.º 10
0
    def __init__(self, toolbox, x, y, project_item, icon_file, icon_color,
                 background_color):
        """Base class for project item icons drawn in Design View.

        Args:
            toolbox (ToolBoxUI): QMainWindow instance
            x (float): Icon x coordinate
            y (float): Icon y coordinate
            project_item (ProjectItem): Item
            icon_file (str): Path to icon resource
            icon_color (QColor): Icon's color
            background_color (QColor): Background color
        """
        super().__init__()
        self._toolbox = toolbox
        self._project_item = project_item
        self._moved_on_scene = False
        self._previous_pos = QPointF()
        self._current_pos = QPointF()
        self.icon_group = {self}
        self.renderer = QSvgRenderer()
        self.svg_item = QGraphicsSvgItem(self)
        self.colorizer = QGraphicsColorizeEffect()
        self.setRect(
            QRectF(x - self.ITEM_EXTENT / 2, y - self.ITEM_EXTENT / 2,
                   self.ITEM_EXTENT, self.ITEM_EXTENT))
        self.text_font_size = 10  # point size
        # Make item name graphics item.
        name = project_item.name if project_item else ""
        self.name_item = QGraphicsSimpleTextItem(name, self)
        self.set_name_attributes()  # Set font, size, position, etc.
        # Make connector buttons
        self.connectors = dict(
            bottom=ConnectorButton(self, toolbox, position="bottom"),
            left=ConnectorButton(self, toolbox, position="left"),
            right=ConnectorButton(self, toolbox, position="right"),
        )
        # Make exclamation and rank icons
        self.exclamation_icon = ExclamationIcon(self)
        self.rank_icon = RankIcon(self)
        brush = QBrush(background_color)
        self._setup(brush, icon_file, icon_color)
        self.activate()
Ejemplo n.º 11
0
 def __init__(self, toolbox, icon_file, icon_color, background_color):
     """
     Args:
         toolbox (ToolboxUI): QMainWindow instance
         icon_file (str): Path to icon resource
         icon_color (QColor): Icon's color
         background_color (QColor): Background color
     """
     super().__init__()
     self._toolbox = toolbox
     self.icon_file = icon_file
     self._moved_on_scene = False
     self.previous_pos = QPointF()
     self.current_pos = QPointF()
     self.icon_group = {self}
     self.renderer = QSvgRenderer()
     self.svg_item = QGraphicsSvgItem(self)
     self.colorizer = QGraphicsColorizeEffect()
     self.setRect(
         QRectF(-self.ITEM_EXTENT / 2, -self.ITEM_EXTENT / 2,
                self.ITEM_EXTENT, self.ITEM_EXTENT))
     self.text_font_size = 10  # point size
     # Make item name graphics item.
     self._name = ""
     self.name_item = QGraphicsSimpleTextItem(self._name, self)
     self.set_name_attributes()  # Set font, size, position, etc.
     # Make connector buttons
     self.connectors = dict(
         bottom=ConnectorButton(self, toolbox, position="bottom"),
         left=ConnectorButton(self, toolbox, position="left"),
         right=ConnectorButton(self, toolbox, position="right"),
     )
     # Make exclamation and rank icons
     self.exclamation_icon = ExclamationIcon(self)
     self.execution_icon = ExecutionIcon(self)
     self.rank_icon = RankIcon(self)
     brush = QBrush(background_color)
     self._setup(brush, icon_file, icon_color)
     shadow_effect = QGraphicsDropShadowEffect()
     shadow_effect.setOffset(1)
     shadow_effect.setEnabled(False)
     self.setGraphicsEffect(shadow_effect)
Ejemplo n.º 12
0
    def data(self, index, role=Qt.DisplayRole):
        row = index.row()
        column = index.column()
        cell_data = self.grid_data[row][column]
        is_word_cell = cell_data[0]
        clue_index = cell_data[1] or cell_data[2]

        if role == Qt.DisplayRole:
            return self.solution_data[row][column]
        if role == Qt.EditRole:
            return self.solution_data[row][column]
        #elif role == Qt.DecorationRole:
        #  if clue_index:
        #    icon_path = os.path.join(icons_folder, '{}.svg'.format(clue_index))
        #    return QIcon(icon_path)
        #  else:
        #    return None
        elif role == Qt.BackgroundRole:
            if is_word_cell:
                if clue_index:
                    icon_path = os.path.join(icons_folder,
                                             '{}.svg'.format(clue_index))
                    renderer = QSvgRenderer(icon_path)
                    pixmap = QPixmap(QSize(grid_cell_size, grid_cell_size))
                    pixmap.fill(Qt.transparent)
                    painter = QPainter()
                    renderer.render(painter, pixmap.rect())
                    brush = QBrush()
                    brush.setTexture(pixmap)
                    return brush
                else:
                    return QColor(Qt.white)
            else:
                return QColor(Qt.black)
        elif role == Qt.FontRole:
            font = QFont(font_name, font_size)
            return font
        elif role == Qt.TextAlignmentRole:
            return Qt.AlignCenter
        return None
Ejemplo n.º 13
0
class MCacheDict(object):
    _render = QSvgRenderer()

    def __init__(self, cls):
        super(MCacheDict, self).__init__()
        self.cls = cls
        self._cache_pix_dict = {}

    def _render_svg(self, svg_path, replace_color=None):
        from dayu_widgets import dayu_theme
        replace_color = replace_color or dayu_theme.icon_color
        if (self.cls is QIcon) and (replace_color is None):
            return QIcon(svg_path)
        with open(svg_path, 'r') as f:
            data_content = f.read()
            if replace_color is not None:
                data_content = data_content.replace('#555555', replace_color)
            self._render.load(QByteArray(data_content.encode()))
            pix = QPixmap(128, 128)
            pix.fill(Qt.transparent)
            painter = QPainter(pix)
            self._render.render(painter)
            painter.end()
            if self.cls is QPixmap:
                return pix
            else:
                return self.cls(pix)

    def __call__(self, path, color=None):
        from dayu_widgets import utils
        full_path = utils.get_static_file(path)
        if full_path is None:
            return self.cls()
        key = u'{}{}'.format(full_path.lower(), color or '')
        pix_map = self._cache_pix_dict.get(key, None)
        if pix_map is None:
            if full_path.endswith('svg'):
                pix_map = self._render_svg(full_path, color)
            else:
                pix_map = self.cls(full_path)
            self._cache_pix_dict.update({key: pix_map})
        return pix_map
Ejemplo n.º 14
0
def _svgRenderer(filename) -> QSvgRenderer:
    """Get an QSvgRenderer from an `.svg` filename.  
    This function is for internal use within this file.
    """
    return QSvgRenderer(filename)
Ejemplo n.º 15
0
class ProjectItemIcon(QGraphicsRectItem):

    ITEM_EXTENT = 64

    def __init__(self, toolbox, x, y, project_item, icon_file, icon_color,
                 background_color):
        """Base class for project item icons drawn in Design View.

        Args:
            toolbox (ToolBoxUI): QMainWindow instance
            x (float): Icon x coordinate
            y (float): Icon y coordinate
            project_item (ProjectItem): Item
            icon_file (str): Path to icon resource
            icon_color (QColor): Icon's color
            background_color (QColor): Background color
        """
        super().__init__()
        self._toolbox = toolbox
        self._project_item = project_item
        self._moved_on_scene = False
        self._previous_pos = QPointF()
        self._current_pos = QPointF()
        self.icon_group = {self}
        self.renderer = QSvgRenderer()
        self.svg_item = QGraphicsSvgItem(self)
        self.colorizer = QGraphicsColorizeEffect()
        self.setRect(
            QRectF(x - self.ITEM_EXTENT / 2, y - self.ITEM_EXTENT / 2,
                   self.ITEM_EXTENT, self.ITEM_EXTENT))
        self.text_font_size = 10  # point size
        # Make item name graphics item.
        name = project_item.name if project_item else ""
        self.name_item = QGraphicsSimpleTextItem(name, self)
        self.set_name_attributes()  # Set font, size, position, etc.
        # Make connector buttons
        self.connectors = dict(
            bottom=ConnectorButton(self, toolbox, position="bottom"),
            left=ConnectorButton(self, toolbox, position="left"),
            right=ConnectorButton(self, toolbox, position="right"),
        )
        # Make exclamation and rank icons
        self.exclamation_icon = ExclamationIcon(self)
        self.rank_icon = RankIcon(self)
        brush = QBrush(background_color)
        self._setup(brush, icon_file, icon_color)
        self.activate()

    def activate(self):
        """Adds items to scene and setup graphics effect.
        Called in the constructor and when re-adding the item to the project in the context of undo/redo.
        """
        scene = self._toolbox.ui.graphicsView.scene()
        scene.addItem(self)
        shadow_effect = QGraphicsDropShadowEffect()
        shadow_effect.setOffset(1)
        shadow_effect.setEnabled(False)
        self.setGraphicsEffect(shadow_effect)

    def _setup(self, brush, svg, svg_color):
        """Setup item's attributes.

        Args:
            brush (QBrush): Used in filling the background rectangle
            svg (str): Path to SVG icon file
            svg_color (QColor): Color of SVG icon
        """
        self.setPen(QPen(Qt.black, 1, Qt.SolidLine))
        self.setBrush(brush)
        self.colorizer.setColor(svg_color)
        # Load SVG
        loading_ok = self.renderer.load(svg)
        if not loading_ok:
            self._toolbox.msg_error.emit(
                "Loading SVG icon from resource:{0} failed".format(svg))
            return
        size = self.renderer.defaultSize()
        self.svg_item.setSharedRenderer(self.renderer)
        self.svg_item.setElementId(
            "")  # guess empty string loads the whole file
        dim_max = max(size.width(), size.height())
        rect_w = self.rect().width()  # Parent rect width
        margin = 32
        self.svg_item.setScale((rect_w - margin) / dim_max)
        x_offset = (rect_w - self.svg_item.sceneBoundingRect().width()) / 2
        y_offset = (rect_w - self.svg_item.sceneBoundingRect().height()) / 2
        self.svg_item.setPos(self.rect().x() + x_offset,
                             self.rect().y() + y_offset)
        self.svg_item.setGraphicsEffect(self.colorizer)
        self.setFlag(QGraphicsItem.ItemIsMovable, enabled=True)
        self.setFlag(QGraphicsItem.ItemIsSelectable, enabled=True)
        self.setFlag(QGraphicsItem.ItemIsFocusable, enabled=True)
        self.setFlag(QGraphicsItem.ItemSendsScenePositionChanges, enabled=True)
        self.setAcceptHoverEvents(True)
        self.setCursor(Qt.PointingHandCursor)
        # Set exclamation and rank icons position
        self.exclamation_icon.setPos(
            self.rect().topRight() -
            self.exclamation_icon.sceneBoundingRect().topRight())
        self.rank_icon.setPos(self.rect().topLeft())

    def name(self):
        """Returns name of the item that is represented by this icon."""
        return self._project_item.name

    def update_name_item(self, new_name):
        """Set a new text to name item. Used when a project item is renamed."""
        self.name_item.setText(new_name)
        self.set_name_attributes()

    def set_name_attributes(self):
        """Set name QGraphicsSimpleTextItem attributes (font, size, position, etc.)"""
        # Set font size and style
        font = self.name_item.font()
        font.setPointSize(self.text_font_size)
        font.setBold(True)
        self.name_item.setFont(font)
        # Set name item position (centered on top of the master icon)
        name_width = self.name_item.boundingRect().width()
        name_height = self.name_item.boundingRect().height()
        self.name_item.setPos(
            self.rect().x() + self.rect().width() / 2 - name_width / 2,
            self.rect().y() - name_height - 4)

    def conn_button(self, position="left"):
        """Returns items connector button (QWidget)."""
        return self.connectors.get(position, self.connectors["left"])

    def outgoing_links(self):
        return [
            l for conn in self.connectors.values()
            for l in conn.outgoing_links()
        ]

    def incoming_links(self):
        return [
            l for conn in self.connectors.values()
            for l in conn.incoming_links()
        ]

    def hoverEnterEvent(self, event):
        """Sets a drop shadow effect to icon when mouse enters its boundaries.

        Args:
            event (QGraphicsSceneMouseEvent): Event
        """
        self.prepareGeometryChange()
        self.graphicsEffect().setEnabled(True)
        event.accept()

    def hoverLeaveEvent(self, event):
        """Disables the drop shadow when mouse leaves icon boundaries.

        Args:
            event (QGraphicsSceneMouseEvent): Event
        """
        self.prepareGeometryChange()
        self.graphicsEffect().setEnabled(False)
        event.accept()

    def mousePressEvent(self, event):
        super().mousePressEvent(event)
        self.icon_group = set(x for x in self.scene().selectedItems()
                              if isinstance(x, ProjectItemIcon)) | {self}
        for icon in self.icon_group:
            icon._previous_pos = icon.scenePos()

    def mouseMoveEvent(self, event):
        """Moves icon(s) while the mouse button is pressed.
        Update links that are connected to selected icons.

        Args:
            event (QGraphicsSceneMouseEvent): Event
        """
        super().mouseMoveEvent(event)
        self.update_links_geometry()

    def moveBy(self, dx, dy):
        super().moveBy(dx, dy)
        self.update_links_geometry()

    def update_links_geometry(self):
        """Updates geometry of connected links to reflect this item's most recent position."""
        links = set(link for icon in self.icon_group
                    for conn in icon.connectors.values()
                    for link in conn.links)
        for link in links:
            link.update_geometry()

    def mouseReleaseEvent(self, event):
        for icon in self.icon_group:
            icon._current_pos = icon.scenePos()
        # pylint: disable=undefined-variable
        if (self._current_pos - self._previous_pos
            ).manhattanLength() > qApp.startDragDistance():
            self._toolbox.undo_stack.push(MoveIconCommand(self))
        super().mouseReleaseEvent(event)

    def notify_item_move(self):
        if self._moved_on_scene:
            self._moved_on_scene = False
            scene = self.scene()
            scene.item_move_finished.emit(self)

    def contextMenuEvent(self, event):
        """Show item context menu.

        Args:
            event (QGraphicsSceneMouseEvent): Mouse event
        """
        self.scene().clearSelection()
        self.setSelected(True)
        self._toolbox.show_item_image_context_menu(event.screenPos(),
                                                   self.name())

    def keyPressEvent(self, event):
        """Handles deleting and rotating the selected
        item when dedicated keys are pressed.

        Args:
            event (QKeyEvent): Key event
        """
        if event.key() == Qt.Key_Delete and self.isSelected():
            self._project_item._project.remove_item(self.name())
            event.accept()
        elif event.key() == Qt.Key_R and self.isSelected():
            # TODO:
            # 1. Change name item text direction when rotating
            # 2. Save rotation into project file
            rect = self.mapToScene(self.boundingRect()).boundingRect()
            center = rect.center()
            t = QTransform()
            t.translate(center.x(), center.y())
            t.rotate(90)
            t.translate(-center.x(), -center.y())
            self.setPos(t.map(self.pos()))
            self.setRotation(self.rotation() + 90)
            links = set(lnk for conn in self.connectors.values()
                        for lnk in conn.links)
            for link in links:
                link.update_geometry()
            event.accept()
        else:
            super().keyPressEvent(event)

    def itemChange(self, change, value):
        """
        Reacts to item removal and position changes.

        In particular, destroys the drop shadow effect when the items is removed from a scene
        and keeps track of item's movements on the scene.

        Args:
            change (GraphicsItemChange): a flag signalling the type of the change
            value: a value related to the change

        Returns:
             Whatever super() does with the value parameter
        """
        if change == QGraphicsItem.ItemScenePositionHasChanged:
            self._moved_on_scene = True
        elif change == QGraphicsItem.GraphicsItemChange.ItemSceneChange and value is None:
            self.prepareGeometryChange()
            self.setGraphicsEffect(None)
        return super().itemChange(change, value)

    def show_item_info(self):
        """Update GUI to show the details of the selected item."""
        ind = self._toolbox.project_item_model.find_item(self.name())
        self._toolbox.ui.treeView_project.setCurrentIndex(ind)
Ejemplo n.º 16
0
def svg_to_outlines(root, width_mm=None, height_mm=None, pixels_per_mm=5.0):
    """
    Given an SVG as a Python ElementTree, return a set of straight line
    segments which approximate the outlines in that SVG when rendered.

    Occlusion is not accounted for in the returned list of outlines. Even if
    one shape is completely occluded by another, both of their outlines will be
    reported. Simillarly, overlapping lines will also be passed through.

    .. note::

        This function internally uses the QSvg library from Qt to render the
        provided SVG to a special painting backend which captures the output
        lines. As a consequence, SVG feature support is as good or as bad as
        that library. QSvg is generally regarded as a high quality and
        relatively complete SVG implementation and so most SVG features should
        be supported.

    .. note::

        Due to its internal use of Qt, a PySide2.QtGui.QGuiApplication will be
        created if one has not already been created. Non-Qt users and most Qt
        users should not be affected by this.

    Parameters
    ----------
    root : ElementTree
        The SVG whose outlines should be extracted.
    width_mm, height_mm : float or None
        The page size to render the SVG at (in milimeters). If omitted, this
        will be determined automatically from the SVG's width and height
        attributes. These arguments are mandatory for SVGs lacking these
        attributes.
    pixels_per_mm : float
        Curved outlines will be approximated by straight lines in the output.
        This parameter controls how exactly curves will be approximated.
        Specifically, the curve approximation will be at least fine enough for
        rasterised versions of the lines to 'look right' at the specified pixel
        density.

    Returns
    -------
    [((r, g, b, a) or None, width, [(x, y), ...]), ...]
        A list of polylines described by (colour, line) pairs.

        The 'colour' values define the colour used to draw the line (if a solid
        colour was used) or None (if a gradient or patterned stroke was used).
        Colours are given as four-tuples in RGBA order with values from 0.0 to
        1.0.

        The 'width' value gives the line width used to draw the line (given in
        mm). If the shape being drawn has a non-uniform scaling applied, this
        value may not be meaningful and its actual value should be considered
        undefined.

        The 'line' part of each tuple defines the outline as a series of (x, y)
        coordinates (given in mm) which describe a continuous polyline. These
        polylines may be considered open. Closed lines in the input SVG will
        result in polylines where the first and last coordinate are identical.
        Lines may go beyond the bounds of the designated page size (as in the
        input SVG).
    """
    # This method internally uses various parts of Qt which require that a Qt
    # application exists. If one does not exist, one will be created.
    if QGuiApplication.instance() is None:
        QGuiApplication()

    # Determine the page size from the document if necessary
    if width_mm is None or height_mm is None:
        width_mm, height_mm = get_svg_page_size(root)

    # Load the SVG into QSvg
    xml_stream_reader = QXmlStreamReader()
    xml_stream_reader.addData(ElementTree.tostring(root, "unicode"))
    svg_renderer = QSvgRenderer()
    svg_renderer.load(xml_stream_reader)

    # Paint the SVG into the OutlinePaintDevice which will capture the set of
    # line segments which make up the SVG as rendered.
    outline_paint_device = OutlinePaintDevice(width_mm, height_mm,
                                              pixels_per_mm)
    painter = QPainter(outline_paint_device)
    try:
        svg_renderer.render(painter)
    finally:
        painter.end()

    return outline_paint_device.getOutlines()
Ejemplo n.º 17
0
class LoadingBar(QWidget):
    def __init__(self, parent, fn, *args):
        super(LoadingBar, self).__init__(parent)

        self.fn = fn
        self.args = args
        self.worker = Worker(fn, *args)
        self.worker.signals.result.connect(
            main_window.MainWindow.get_instance().calc_done)

        main_window.MainWindow.get_instance().threadpool.start(self.worker)

        # overlay
        # make the window frameless
        self.loading_icon = QSvgRenderer('resources/images/loading_icon.svg')
        self.qp = QPainter()

        self.setWindowFlags(Qt.FramelessWindowHint)
        self.setAttribute(Qt.WA_TranslucentBackground)

        self.fillColor = QColor(30, 30, 30, 120)
        self.penColor = QColor("#333333")

        self.close_btn = QPushButton(self)
        self.close_btn.setText("Abbrechen")

        font = QFont()
        font.setPixelSize(18)
        font.setBold(True)
        self.close_btn.setFont(font)
        self.close_btn.setStyleSheet("QPushButton {"
                                     "background-color: #EAEAEA;"
                                     "border: None;"
                                     "padding-top: 12px;"
                                     "padding-bottom: 12px;"
                                     "padding-left: 20px;"
                                     "padding-right: 20px;"
                                     "}"
                                     "QPushButton:hover {"
                                     "background-color: #DFDFDF;"
                                     "}")
        #self.close_btn.setFixedSize(30, 30)
        self.close_btn.clicked.connect(self._onclose)

        self.signals = LoadingBarSignals()

    def resizeEvent(self, event=None):
        button_x = (self.width() - self.close_btn.width()) / 2
        button_y = (self.height() - self.close_btn.height()) / 2 + 60
        self.close_btn.move(button_x, button_y)

    def paintEvent(self, event):
        # This method is, in practice, drawing the contents of
        # your window.

        # get current window size
        s = self.size()
        self.qp.begin(self)
        self.qp.setRenderHint(QPainter.Antialiasing, True)
        self.qp.setPen(self.penColor)
        self.qp.setBrush(self.fillColor)
        self.qp.drawRect(0, 0, s.width(), s.height())

        icon_size = 180
        self.loading_icon.render(
            self.qp,
            QRect((self.width() - icon_size) / 2,
                  (self.height() - icon_size) / 2 - 60, icon_size, icon_size))
        self.qp.end()

    def _onclose(self):
        self.signals.close.emit()
Ejemplo n.º 18
0
class ProjectItemIcon(QGraphicsRectItem):
    """Base class for project item icons drawn in Design View."""

    ITEM_EXTENT = 64

    def __init__(self, toolbox, icon_file, icon_color, background_color):
        """
        Args:
            toolbox (ToolboxUI): QMainWindow instance
            icon_file (str): Path to icon resource
            icon_color (QColor): Icon's color
            background_color (QColor): Background color
        """
        super().__init__()
        self._toolbox = toolbox
        self.icon_file = icon_file
        self._moved_on_scene = False
        self.previous_pos = QPointF()
        self.current_pos = QPointF()
        self.icon_group = {self}
        self.renderer = QSvgRenderer()
        self.svg_item = QGraphicsSvgItem(self)
        self.colorizer = QGraphicsColorizeEffect()
        self.setRect(
            QRectF(-self.ITEM_EXTENT / 2, -self.ITEM_EXTENT / 2,
                   self.ITEM_EXTENT, self.ITEM_EXTENT))
        self.text_font_size = 10  # point size
        # Make item name graphics item.
        self._name = ""
        self.name_item = QGraphicsSimpleTextItem(self._name, self)
        self.set_name_attributes()  # Set font, size, position, etc.
        # Make connector buttons
        self.connectors = dict(
            bottom=ConnectorButton(self, toolbox, position="bottom"),
            left=ConnectorButton(self, toolbox, position="left"),
            right=ConnectorButton(self, toolbox, position="right"),
        )
        # Make exclamation and rank icons
        self.exclamation_icon = ExclamationIcon(self)
        self.execution_icon = ExecutionIcon(self)
        self.rank_icon = RankIcon(self)
        brush = QBrush(background_color)
        self._setup(brush, icon_file, icon_color)
        shadow_effect = QGraphicsDropShadowEffect()
        shadow_effect.setOffset(1)
        shadow_effect.setEnabled(False)
        self.setGraphicsEffect(shadow_effect)

    def finalize(self, name, x, y):
        """
        Names the icon and moves it by given amount.

        Args:
            name (str): icon's name
            x (int): horizontal offset
            y (int): vertical offset
        """
        self.update_name_item(name)
        self.moveBy(x, y)

    def _setup(self, brush, svg, svg_color):
        """Setup item's attributes.

        Args:
            brush (QBrush): Used in filling the background rectangle
            svg (str): Path to SVG icon file
            svg_color (QColor): Color of SVG icon
        """
        self.setPen(QPen(Qt.black, 1, Qt.SolidLine))
        self.setBrush(brush)
        self.colorizer.setColor(svg_color)
        # Load SVG
        loading_ok = self.renderer.load(svg)
        if not loading_ok:
            self._toolbox.msg_error.emit(
                "Loading SVG icon from resource:{0} failed".format(svg))
            return
        size = self.renderer.defaultSize()
        self.svg_item.setSharedRenderer(self.renderer)
        self.svg_item.setElementId(
            "")  # guess empty string loads the whole file
        dim_max = max(size.width(), size.height())
        rect_w = self.rect().width()  # Parent rect width
        margin = 32
        self.svg_item.setScale((rect_w - margin) / dim_max)
        self.svg_item.setPos(self.rect().center() -
                             self.svg_item.sceneBoundingRect().center())
        self.svg_item.setGraphicsEffect(self.colorizer)
        self.setFlag(QGraphicsItem.ItemIsMovable, enabled=True)
        self.setFlag(QGraphicsItem.ItemIsSelectable, enabled=True)
        self.setFlag(QGraphicsItem.ItemIsFocusable, enabled=True)
        self.setFlag(QGraphicsItem.ItemSendsScenePositionChanges, enabled=True)
        self.setAcceptHoverEvents(True)
        self.setCursor(Qt.PointingHandCursor)
        # Set exclamation, execution_log, and rank icons position
        self.exclamation_icon.setPos(
            self.rect().topRight() -
            self.exclamation_icon.sceneBoundingRect().topRight())
        self.execution_icon.setPos(
            self.rect().bottomRight() -
            0.5 * self.execution_icon.sceneBoundingRect().bottomRight())
        self.rank_icon.setPos(self.rect().topLeft())

    def name(self):
        """Returns name of the item that is represented by this icon.

        Returns:
            str: icon's name
        """
        return self._name

    def update_name_item(self, new_name):
        """Set a new text to name item.

        Args:
            new_name (str): icon's name
        """
        self._name = new_name
        self.name_item.setText(new_name)
        self.set_name_attributes()

    def set_name_attributes(self):
        """Set name QGraphicsSimpleTextItem attributes (font, size, position, etc.)"""
        # Set font size and style
        font = self.name_item.font()
        font.setPointSize(self.text_font_size)
        font.setBold(True)
        self.name_item.setFont(font)
        # Set name item position (centered on top of the master icon)
        name_width = self.name_item.boundingRect().width()
        name_height = self.name_item.boundingRect().height()
        self.name_item.setPos(
            self.rect().x() + self.rect().width() / 2 - name_width / 2,
            self.rect().y() - name_height - 4)

    def conn_button(self, position="left"):
        """Returns item's connector button.

        Args:
            position (str): "left", "right" or "bottom"

        Returns:
            QWidget: connector button
        """
        return self.connectors.get(position, self.connectors["left"])

    def outgoing_links(self):
        """Collects outgoing links.

        Returns:
            list of LinkBase: outgoing links
        """
        return [
            l for conn in self.connectors.values()
            for l in conn.outgoing_links()
        ]

    def incoming_links(self):
        """Collects incoming links.

        Returns:
            list of LinkBase: outgoing links
        """
        return [
            l for conn in self.connectors.values()
            for l in conn.incoming_links()
        ]

    def run_execution_leave_animation(self, skipped):
        """
        Starts the animation associated with execution leaving the icon.

        Args:
            skipped (bool): True if project item was not actually executed.
        """
        animation_group = QParallelAnimationGroup(self._toolbox)
        for link in self.outgoing_links():
            animation_group.addAnimation(
                link.make_execution_animation(skipped))
        animation_group.start()

    def hoverEnterEvent(self, event):
        """Sets a drop shadow effect to icon when mouse enters its boundaries.

        Args:
            event (QGraphicsSceneMouseEvent): Event
        """
        self.prepareGeometryChange()
        self.graphicsEffect().setEnabled(True)
        event.accept()

    def hoverLeaveEvent(self, event):
        """Disables the drop shadow when mouse leaves icon boundaries.

        Args:
            event (QGraphicsSceneMouseEvent): Event
        """
        self.prepareGeometryChange()
        self.graphicsEffect().setEnabled(False)
        event.accept()

    def mousePressEvent(self, event):
        super().mousePressEvent(event)
        self.icon_group = set(x for x in self.scene().selectedItems()
                              if isinstance(x, ProjectItemIcon)) | {self}
        for icon in self.icon_group:
            icon.previous_pos = icon.scenePos()

    def mouseMoveEvent(self, event):
        """Moves icon(s) while the mouse button is pressed.
        Update links that are connected to selected icons.

        Args:
            event (QGraphicsSceneMouseEvent): Event
        """
        super().mouseMoveEvent(event)
        self.update_links_geometry()

    def moveBy(self, dx, dy):
        super().moveBy(dx, dy)
        self.update_links_geometry()

    def update_links_geometry(self):
        """Updates geometry of connected links to reflect this item's most recent position."""
        links = set(link for icon in self.icon_group
                    for conn in icon.connectors.values()
                    for link in conn.links)
        for link in links:
            link.update_geometry()

    def mouseReleaseEvent(self, event):
        for icon in self.icon_group:
            icon.current_pos = icon.scenePos()
        # pylint: disable=undefined-variable
        if (self.current_pos - self.previous_pos
            ).manhattanLength() > qApp.startDragDistance():
            self._toolbox.undo_stack.push(
                MoveIconCommand(self, self._toolbox.project()))
        super().mouseReleaseEvent(event)

    def notify_item_move(self):
        if self._moved_on_scene:
            self._moved_on_scene = False
            scene = self.scene()
            scene.item_move_finished.emit(self)

    def contextMenuEvent(self, event):
        """Show item context menu.

        Args:
            event (QGraphicsSceneMouseEvent): Mouse event
        """
        event.accept()
        self.scene().clearSelection()
        self.setSelected(True)
        ind = self._toolbox.project_item_model.find_item(self.name())
        self._toolbox.show_project_item_context_menu(event.screenPos(), ind)

    def itemChange(self, change, value):
        """
        Reacts to item removal and position changes.

        In particular, destroys the drop shadow effect when the items is removed from a scene
        and keeps track of item's movements on the scene.

        Args:
            change (GraphicsItemChange): a flag signalling the type of the change
            value: a value related to the change

        Returns:
             Whatever super() does with the value parameter
        """
        if change == QGraphicsItem.ItemScenePositionHasChanged:
            self._moved_on_scene = True
        elif change == QGraphicsItem.GraphicsItemChange.ItemSceneChange and value is None:
            self.prepareGeometryChange()
            self.setGraphicsEffect(None)
        return super().itemChange(change, value)

    def select_item(self):
        """Update GUI to show the details of the selected item."""
        ind = self._toolbox.project_item_model.find_item(self.name())
        self._toolbox.ui.treeView_project.setCurrentIndex(ind)