Esempio n. 1
0
    def add_conf_group(self, conf_group_widget):
        row = conf_group_widget.childCount()

        conformer_item = QTreeWidgetItem(conf_group_widget)
        conf_group_widget.insertChild(row, conformer_item)

        nrg_combobox = FilereaderComboBox(self.session, otherItems=['energy'])
        nrg_combobox.currentIndexChanged.connect(
            lambda *args: self.changes.emit())
        freq_combobox = FilereaderComboBox(self.session,
                                           otherItems=['frequency'])
        freq_combobox.currentIndexChanged.connect(
            lambda *args: self.changes.emit())

        trash_button = QPushButton()
        trash_button.setFlat(True)
        trash_button.clicked.connect(
            lambda *args, combobox=nrg_combobox: combobox.deleteLater())
        trash_button.clicked.connect(
            lambda *args, combobox=freq_combobox: combobox.deleteLater())
        trash_button.clicked.connect(lambda *args, child=conformer_item:
                                     conf_group_widget.removeChild(child))
        trash_button.clicked.connect(lambda *args: self.changes.emit())
        trash_button.setIcon(
            QIcon(self.style().standardIcon(QStyle.SP_DialogCancelButton)))

        self.tree.setItemWidget(conformer_item, 0, nrg_combobox)
        self.tree.setItemWidget(conformer_item, 1, freq_combobox)
        self.tree.setItemWidget(conformer_item, 2, trash_button)

        self.changes.emit()
Esempio n. 2
0
class InputWidgetSingle(InputWidgetRaw):
    """
    This type of widget is used for a simple widgets like buttons, checkboxes etc.
    It consists of horizontal layout widget itself and reset button.
    """
    def __init__(self,
                 parent=None,
                 dataSetCallback=None,
                 defaultValue=None,
                 userStructClass=None,
                 **kwds):
        super(InputWidgetSingle,
              self).__init__(parent=parent,
                             dataSetCallback=dataSetCallback,
                             defaultValue=defaultValue,
                             userStructClass=userStructClass,
                             **kwds)
        # from widget
        self.bWidgetSet = False
        self.gridLayout = QGridLayout(self)
        self.gridLayout.setSpacing(1)
        self.gridLayout.setContentsMargins(0, 0, 0, 0)
        self.gridLayout.setObjectName("gridLayout")
        self.horizontalLayout = QHBoxLayout()
        self.horizontalLayout.setObjectName("horizontalLayout")

        spacerItem = QSpacerItem(40, 20, QSizePolicy.Expanding,
                                 QSizePolicy.Minimum)
        self.horizontalLayout.addItem(spacerItem)
        self.pbReset = QPushButton(self)
        self.pbReset.setMaximumSize(QtCore.QSize(25, 25))
        self.pbReset.setText("")
        self.pbReset.setObjectName("pbReset")
        self.pbReset.setIcon(QtGui.QIcon(":/icons/resources/reset.png"))
        self.horizontalLayout.addWidget(self.pbReset)
        self.pbReset.clicked.connect(self.onResetValue)

        self.gridLayout.addLayout(self.horizontalLayout, 0, 0, 1, 1)
        self._index = 0

    def setWidget(self, widget):
        self.horizontalLayout.insertWidget(self._index, widget)
Esempio n. 3
0
def get_button(button_type):
    button = QPushButton()
    button.setFlat(True)
    if button_type == "success":
        button.setIcon(button.style().standardIcon(
            QStyle.SP_DialogApplyButton))
    elif button_type == "fail":
        button.setIcon(button.style().standardIcon(
            QStyle.SP_MessageBoxCritical))
    elif button_type == "error":
        button.setIcon(button.style().standardIcon(
            QStyle.SP_MessageBoxWarning))
    elif button_type == "skip" or button_type == "expected fail":
        button.setIcon(button.style().standardIcon(
            QStyle.SP_MessageBoxInformation))
    elif button_type == "unexpected success":
        button.setIcon(button.style().standardIcon(
            QStyle.SP_MessageBoxQuestion))

    return button
Esempio n. 4
0
    def add_mol_group(self, *args):
        row = self.tree.topLevelItemCount()

        root_item = self.tree.invisibleRootItem()

        mol_group = QTreeWidgetItem(root_item)
        self.tree.insertTopLevelItem(row, mol_group)
        trash_button = QPushButton()
        trash_button.setFlat(True)

        trash_button.clicked.connect(
            lambda *args, parent=mol_group: self.remove_mol_group(parent))
        trash_button.setIcon(
            QIcon(self.style().standardIcon(QStyle.SP_DialogDiscardButton)))

        add_conf_button = QPushButton("add conformer")
        add_conf_button.setFlat(True)
        add_conf_button.clicked.connect(
            lambda *args, conf_group_widget=mol_group: self.add_conf_group(
                conf_group_widget))

        add_conf_button2 = QPushButton("")
        add_conf_button2.setFlat(True)
        add_conf_button2.clicked.connect(
            lambda *args, conf_group_widget=mol_group: self.add_conf_group(
                conf_group_widget))

        add_conf_child = QTreeWidgetItem(mol_group)
        self.tree.setItemWidget(add_conf_child, 0, add_conf_button)
        self.tree.setItemWidget(add_conf_child, 1, add_conf_button2)
        self.tree.setItemWidget(mol_group, 2, trash_button)

        mol_group.setText(0, "group %i" % row)

        mol_group.addChild(add_conf_child)
        self.add_conf_group(mol_group)

        self.tree.expandItem(mol_group)

        self.changes.emit()
Esempio n. 5
0
class Template(base.BaseWidget):
    templateChecked = Signal(object)

    def __init__(self, parent=None):
        super(Template, self).__init__(parent=parent)

    def ui(self):
        super(Template, self).ui()

        self.setMaximumWidth(160)
        self.setMaximumHeight(200)

        widget_layout = layouts.VerticalLayout(spacing=0, margins=(2, 2, 2, 2))
        main_frame = QFrame()
        main_frame.setFrameStyle(QFrame.StyledPanel | QFrame.Raised)
        main_frame.setLineWidth(1)
        main_frame.setLayout(widget_layout)
        self.main_layout.addWidget(main_frame)

        self.template_btn = QPushButton('', self)
        self.template_btn.setCheckable(True)
        self.template_btn.setIcon(self.get_icon())
        self.template_btn.setIconSize(QSize(120, 120))
        template_lbl = label.BaseLabel(self.name, parent=self)
        template_lbl.setObjectName('templateLabel')
        template_lbl.setAlignment(Qt.AlignCenter)
        widget_layout.addWidget(self.template_btn)
        widget_layout.addWidget(template_lbl)

    def setup_signals(self):
        self.template_btn.toggled.connect(self._on_selected_template)

    def get_icon(self):
        return resources.icon(name='project', extension='png')

    def _on_selected_template(self, template):
        self.templateChecked.emit(self)
Esempio n. 6
0
class UIVariable(QWidget, IPropertiesViewSupport):
    def __init__(self, rawVariable, variablesWidget, parent=None):
        super(UIVariable, self).__init__(parent)
        self._rawVariable = rawVariable
        self.variablesWidget = variablesWidget
        # ui
        self.horizontalLayout = QHBoxLayout(self)
        self.horizontalLayout.setSpacing(1)
        self.horizontalLayout.setContentsMargins(1, 1, 1, 1)
        self.horizontalLayout.setObjectName("horizontalLayout")
        self.widget = TypeWidget(
            findPinClassByType(self._rawVariable.dataType).color(), self)
        self.widget.setObjectName("widget")
        self.horizontalLayout.addWidget(self.widget)
        self.labelName = QLabel(self)
        self.labelName.setStyleSheet("background:transparent")
        self.labelName.setObjectName("labelName")
        self.horizontalLayout.addWidget(self.labelName)
        spacerItem = QSpacerItem(40, 20, QSizePolicy.Expanding,
                                 QSizePolicy.Minimum)
        self.horizontalLayout.addItem(spacerItem)
        # find refs
        self.pbFindRefs = QPushButton("")
        self.pbFindRefs.setIcon(
            QtGui.QIcon(":/searching-magnifying-glass.png"))
        self.pbFindRefs.setObjectName("pbFindRefs")
        self.horizontalLayout.addWidget(self.pbFindRefs)
        self.pbFindRefs.clicked.connect(self.onFindRefsClicked)
        #  kill variable
        self.pbKill = QPushButton("")
        self.pbKill.setIcon(QtGui.QIcon(":/delete_icon.png"))
        self.pbKill.setObjectName("pbKill")
        self.horizontalLayout.addWidget(self.pbKill)
        self.pbKill.clicked.connect(self.onKillClicked)

        QtCore.QMetaObject.connectSlotsByName(self)
        self.setName(self._rawVariable.name)
        self._rawVariable.setWrapper(self)

    def onStructureChanged(self, name):
        self._rawVariable.structure = PinStructure[name]
        self.variablesWidget.pyFlowInstance.onRequestFillProperties(
            self.createPropertiesWidget)
        EditorHistory().saveState("Change variable struct", modify=True)

    def setDataType(self, dataType):
        self.dataType = dataType
        self._rawVariable.dataType = dataType
        EditorHistory().saveState("Change variable data type", modify=True)

    def createPropertiesWidget(self, propertiesWidget):
        baseCategory = CollapsibleFormWidget(headName="Base", modify=True)
        # name
        le_name = QLineEdit(self._rawVariable.name)
        le_name.returnPressed.connect(lambda: self.setName(le_name.text()))
        baseCategory.addWidget("Name", le_name)

        # data type
        cbTypes = EnumComboBox([
            pin.__name__ for pin in getAllPinClasses() if pin.IsValuePin()
            if pin.__name__ != "AnyPin"
        ])
        cbTypes.setCurrentIndex(cbTypes.findText(self.dataType))
        cbTypes.setEditable(False)
        cbTypes.changeCallback.connect(self.setDataType)
        propertiesWidget.addWidget(baseCategory)

        # structure type
        cbStructure = EnumComboBox(
            [i.name for i in (PinStructure.Single, PinStructure.Array)])
        cbStructure.setEditable(False)
        cbStructure.setCurrentIndex(
            cbStructure.findText(self._rawVariable.structure.name))
        cbStructure.changeCallback.connect(self.onStructureChanged)
        propertiesWidget.addWidget(baseCategory)
        baseCategory.addWidget("Type", cbTypes)
        baseCategory.addWidget("Structure", cbStructure)

        valueCategory = CollapsibleFormWidget(headName="Value")

        # current value
        if self._rawVariable.structure == PinStructure.Single:
            if not type(self._rawVariable.value) in {list, set, dict, tuple}:

                def valSetter(x):
                    self._rawVariable.value = x

                w = createInputWidget(
                    self._rawVariable.dataType, valSetter,
                    getPinDefaultValueByType(self._rawVariable.dataType))
                if w:
                    w.setWidgetValue(self._rawVariable.value)
                    w.setObjectName(self._rawVariable.name)
                    valueCategory.addWidget(self._rawVariable.name, w)

        # access level
        cb = QComboBox()
        cb.addItem('public', 0)
        cb.addItem('private', 1)
        cb.addItem('protected', 2)

        def accessLevelChanged(x):
            self._rawVariable.accessLevel = AccessLevel[x]
            EditorHistory().saveState("Change variable access level",
                                      modify=True)

        cb.currentTextChanged.connect(accessLevelChanged)
        cb.setCurrentIndex(self._rawVariable.accessLevel)
        valueCategory.addWidget('Access level', cb)
        propertiesWidget.addWidget(valueCategory)

    def onFindRefsClicked(self):
        from PyFlow.App import PyFlow
        refs = [n.getWrapper() for n in self._rawVariable.findRefs()]
        app = self.variablesWidget.pyFlowInstance
        if "Search results" not in [
                t.name() for t in app.getRegisteredTools()
        ]:
            app.invokeDockToolByName("PyFlowBase", "Search results")
        self.variablesWidget.pyFlowInstance.getCanvas(
        ).requestShowSearchResults.emit(refs)

    def onKillClicked(self):
        # check refs and ask user what to do
        refs = self._rawVariable.findRefs()
        if len(refs) > 0:
            item, accepted = QInputDialog.getItem(
                None,
                'Decide!',
                'What to do with getters and setters in canvas?',
                ['kill', 'leave'],
                editable=False)
            if accepted:
                self.variablesWidget.killVar(self)
                if item == 'kill':
                    for i in refs:
                        i.kill()
                elif item == 'leave':
                    for i in refs:
                        i.var = None
        else:
            self.variablesWidget.killVar(self)

    @property
    def dataType(self):
        return self._rawVariable.dataType

    @dataType.setter
    def dataType(self, value):
        self._rawVariable.dataType = value
        self.widget.color = findPinClassByType(
            self._rawVariable.dataType).color()
        self.widget.update()
        self.variablesWidget.onUpdatePropertyView(self)

    @property
    def packageName(self):
        return self._rawVariable.packageName

    @property
    def accessLevel(self):
        return self._rawVariable.accessLevel

    @accessLevel.setter
    def accessLevel(self, value):
        self._rawVariable.accessLevel = value

    @property
    def uid(self):
        return self._rawVariable.uid

    @uid.setter
    def uid(self, value):
        self._rawVariable.uid = value
        if self._rawVariable.uid in self.graph.getVars():
            self.graph.getVars().pop(self._rawVariable.uid)
            self.graph.getVars()[self._rawVariable.uid] = self._rawVariable

    @staticmethod
    def jsonTemplate():
        template = {
            'name': None,
            'uuid': None,
            'value': None,
            'type': None,
            'package': None,
            'accessLevel': None
        }
        return template

    def serialize(self):
        pinClass = findPinClassByType(self._rawVariable.dataType)

        template = UIVariable.jsonTemplate()
        template['name'] = self._rawVariable.name
        template['uuid'] = str(self._rawVariable.uid)

        if self._rawVariable.dataType == "AnyPin":
            # don't save any variables
            # value will be calculated for this type of variables
            template['value'] = None
        else:
            template['value'] = json.dumps(self._rawVariable.value,
                                           cls=pinClass.jsonEncoderClass())

        template['type'] = self._rawVariable.dataType
        template['package'] = self._rawVariable.packageName
        template['accessLevel'] = self._rawVariable.accessLevel.value
        return template

    @staticmethod
    def deserialize(data, graph):
        pinClass = findPinClassByType(data['dataType'])

        varUid = uuid.UUID(data['uuid'])
        var = graph.getApp().variablesWidget.createVariable(
            dataType=data['dataType'],
            accessLevel=AccessLevel(data['accessLevel']),
            uid=varUid)
        var.setName(data['name'])
        var.setDataType(data['dataType'])

        if data['dataType'] == 'AnyPin':
            var.value = getPinDefaultValueByType('AnyPin')
        else:
            var.value = json.loads(data['value'],
                                   cls=pinClass.jsonDecoderClass())

        return var

    @property
    def value(self):
        return self._rawVariable.value

    @value.setter
    def value(self, data):
        self._rawVariable.value = data

    def mousePressEvent(self, event):
        super(UIVariable, self).mousePressEvent(event)
        self.variablesWidget.onUpdatePropertyView(self)

    def setName(self, name):
        self._rawVariable.name = name
        self.labelName.setText(self._rawVariable.name)
Esempio n. 7
0
class WindowDragger(QFrame, object):
    """
    Class to create custom window dragger for Solstice Tools
    """

    DEFAULT_LOGO_ICON_SIZE = 22

    doubleClicked = Signal()

    def __init__(self, window=None, on_close=None):
        super(WindowDragger, self).__init__(window)

        self._window = window
        self._dragging_enabled = True
        self._lock_window_operations = False
        self._mouse_press_pos = None
        self._mouse_move_pos = None
        self._dragging_threshold = 5
        self._minimize_enabled = True
        self._maximize_enabled = True
        self._on_close = on_close

        self.setObjectName('titleFrame')

        self.ui()

    # =================================================================================================================
    # PROPERTIES
    # =================================================================================================================

    @property
    def contents_layout(self):
        return self._contents_layout

    @property
    def corner_contents_layout(self):
        return self._corner_contents_layout

    # =================================================================================================================
    # OVERRIDES
    # =================================================================================================================

    def mousePressEvent(self, event):
        if event.button() == Qt.LeftButton and self._dragging_enabled:
            self._mouse_press_pos = event.globalPos()
            self._mouse_move_pos = event.globalPos() - self._window.pos()
        super(WindowDragger, self).mousePressEvent(event)

    def mouseMoveEvent(self, event):
        if event.buttons() & Qt.LeftButton:
            global_pos = event.globalPos()
            if self._mouse_press_pos and self._dragging_enabled:
                moved = global_pos - self._mouse_press_pos
                if moved.manhattanLength() > self._dragging_threshold:
                    diff = global_pos - self._mouse_move_pos
                    self._window.move(diff)
                    self._mouse_move_pos = global_pos - self._window.pos()
        super(WindowDragger, self).mouseMoveEvent(event)

    def mouseDoubleClickEvent(self, event):
        if self._lock_window_operations:
            return
        if self._button_maximized.isVisible():
            self._on_maximize_window()
        else:
            self._on_restore_window()
        super(WindowDragger, self).mouseDoubleClickEvent(event)
        self.doubleClicked.emit()

    def mouseReleaseEvent(self, event):
        if self._mouse_press_pos is not None:
            if event.button() == Qt.LeftButton and self._dragging_enabled:
                moved = event.globalPos() - self._mouse_press_pos
                if moved.manhattanLength() > self._dragging_threshold:
                    event.ignore()
                self._mouse_press_pos = None
        super(WindowDragger, self).mouseReleaseEvent(event)

    # =================================================================================================================
    # BASE
    # =================================================================================================================

    def ui(self):
        self.setFixedHeight(qtutils.dpi_scale(40))

        main_layout = layouts.HorizontalLayout(spacing=5,
                                               margins=(15, 0, 15, 0))
        self.setLayout(main_layout)

        self._logo_button = self._setup_logo_button()
        self._title_text = label.ClippedLabel(text=self._window.windowTitle())
        self._title_text.setObjectName('WindowDraggerLabel')
        self._contents_layout = layouts.HorizontalLayout()
        self._corner_contents_layout = layouts.HorizontalLayout()

        main_layout.addWidget(self._logo_button)
        main_layout.addWidget(self._title_text)
        main_layout.addItem(
            QSpacerItem(25, 0, QSizePolicy.Fixed, QSizePolicy.Fixed))
        main_layout.addLayout(self._contents_layout)
        main_layout.addLayout(self._corner_contents_layout)

        buttons_widget = QWidget()
        self.buttons_layout = layouts.HorizontalLayout(spacing=0,
                                                       margins=(0, 0, 0, 0))
        self.buttons_layout.setAlignment(Qt.AlignRight)
        buttons_widget.setLayout(self.buttons_layout)
        main_layout.addWidget(buttons_widget)

        self._button_minimized = QPushButton()
        self._button_minimized.setIconSize(QSize(25, 25))
        # self._button_minimized.setSizePolicy(QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed))
        self._button_minimized.setIcon(
            resources.icon('minimize', theme='window'))
        self._button_minimized.setStyleSheet(
            'QWidget {background-color: rgba(255, 255, 255, 0); border:0px;}')
        self._button_maximized = QPushButton()
        self._button_maximized.setIcon(
            resources.icon('maximize', theme='window'))
        # self._button_maximized.setSizePolicy(QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed))
        self._button_maximized.setStyleSheet(
            'QWidget {background-color: rgba(255, 255, 255, 0); border:0px;}')
        self._button_maximized.setIconSize(QSize(25, 25))
        self._button_restored = QPushButton()
        # self._button_restored.setSizePolicy(QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed))
        self._button_restored.setVisible(False)
        self._button_restored.setIcon(resources.icon('restore',
                                                     theme='window'))
        self._button_restored.setStyleSheet(
            'QWidget {background-color: rgba(255, 255, 255, 0); border:0px;}')
        self._button_restored.setIconSize(QSize(25, 25))
        self._button_closed = QPushButton()
        # button_closed.setSizePolicy(QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed))
        self._button_closed.setIcon(resources.icon('close', theme='window'))
        self._button_closed.setStyleSheet(
            'QWidget {background-color: rgba(255, 255, 255, 0); border:0px;}')
        self._button_closed.setIconSize(QSize(25, 25))

        self.buttons_layout.addWidget(self._button_minimized)
        self.buttons_layout.addWidget(self._button_maximized)
        self.buttons_layout.addWidget(self._button_restored)
        self.buttons_layout.addWidget(self._button_closed)

        self._button_maximized.clicked.connect(self._on_maximize_window)
        self._button_minimized.clicked.connect(self._on_minimize_window)
        self._button_restored.clicked.connect(self._on_restore_window)
        self._button_closed.clicked.connect(self._on_close_window)

    def set_icon(self, icon=None, highlight=False):
        """
        Sets the icon of the window dragger
        :param icon: QIcon
        :param highlight: bool
        """

        icon = icon or self._window.windowIcon()
        if not icon or icon.isNull():
            icon = resources.icon('tpDcc')

        size = self.DEFAULT_LOGO_ICON_SIZE

        if highlight:
            self._logo_button.set_icon(
                [icon],
                colors=[None],
                tint_composition=QPainter.CompositionMode_Plus,
                size=size,
                icon_scaling=[1],
                color_offset=0,
                grayscale=True)
        else:
            self._logo_button.set_icon([icon],
                                       colors=None,
                                       size=size,
                                       icon_scaling=[1],
                                       color_offset=0)

        self._logo_button.set_icon_idle(icon)

        # self._lbl_icon.setPixmap(icon.pixmap(icon.actualSize(QSize(24, 24))))

    def set_height(self, value):
        """
        Sets the size of the dragger and updates icon
        :param value: float
        """

        self.setFixedHeight(qtutils.dpi_scale(value))

    def set_title(self, title):
        """
        Sets the title of the window dragger
        :param title: str
        """

        self._title_text.setText(title)

    def set_dragging_enabled(self, flag):
        """
        Sets whether or not drag functionality is enabled
        :param flag: bool
        """

        self._dragging_enabled = flag

    def set_minimize_enabled(self, flag):
        """
        Sets whether dragger shows minimize button or not
        :param flag: bool
        """

        self._minimize_enabled = flag
        self._button_minimized.setVisible(flag)

    def set_maximized_enabled(self, flag):
        """
        Sets whether dragger shows maximize button or not
        :param flag: bool
        """

        self._maximize_enabled = flag
        self._button_maximized.setVisible(flag)

    def show_logo(self):
        """
        Shows window logo
        """

        self._logo_button.setVisible(True)

    def hide_logo(self):
        """
        Hides window logo
        """

        self._logo_button.setVisible(False)

    def set_window_buttons_state(self, state, show_close_button=False):
        """
        Sets the state of the dragger buttons
        :param state: bool
        :param show_close_button: bool
        """

        self._lock_window_operations = not state
        self._button_closed.setEnabled(state or show_close_button)
        self._button_closed.setVisible(state or show_close_button)

        if self._maximize_enabled:
            self._button_maximized.setEnabled(state)
            self._button_maximized.setVisible(state)
        else:
            self._button_maximized.setEnabled(False)
            self._button_maximized.setVisible(False)

        if self._minimize_enabled:
            self._button_minimized.setEnabled(state)
            self._button_minimized.setVisible(state)
        else:
            self._button_minimized.setEnabled(False)
            self._button_minimized.setVisible(False)

        if not state:
            self._button_restored.setEnabled(state)
            self._button_restored.setVisible(state)
        else:
            if self.isMaximized():
                self._button_restored.setEnabled(state)
                self._button_restored.setVisible(state)

    def set_frameless_enabled(self, frameless=False):
        """
        Enables/Disables frameless mode or OS system default
        :param frameless: bool
        """

        from tpDcc.managers import tools

        tool_inst = tools.ToolsManager().get_tool_by_plugin_instance(
            self._window)
        if not tool_inst:
            return

        offset = QPoint()

        if self._window.docked():
            rect = self._window.rect()
            pos = self._window.mapToGlobal(QPoint(-10, -10))
            rect.setWidth(rect.width() + 21)
            self._window.close()
        else:
            rect = self.window().rect()
            pos = self.window().pos()
            offset = QPoint(3, 15)
            self.window().close()

        tool_inst._launch(launch_frameless=frameless)

        new_tool = tool_inst.latest_tool()

        QTimer.singleShot(
            0,
            lambda: new_tool.window().setGeometry(pos.x() + offset.x(),
                                                  pos.y() + offset.y(),
                                                  rect.width(), rect.height()))
        new_tool.framelessChanged.emit(frameless)
        QApplication.processEvents()

        return new_tool

    def _setup_logo_button(self):
        """
        Internal function that setup window dragger button logo
        :return: IconMenuButton
        """

        from tpDcc.libs.qt.widgets import buttons
        logo_button = buttons.IconMenuButton(parent=self)
        logo_button.setIconSize(QSize(24, 24))
        logo_button.setFixedSize(QSize(30, 30))
        self._toggle_frameless = logo_button.addAction(
            'Toggle Frameless Mode',
            connect=self._on_toggle_frameless_mode,
            checkable=True)
        self._toggle_frameless.setChecked(self._window.is_frameless())
        logo_button.set_menu_align(Qt.AlignLeft)

        return logo_button

    def _on_toggle_frameless_mode(self, action):
        """
        Internal callback function that is called when switch frameless mode button is pressed by user
        :param flag: bool
        """

        self.set_frameless_enabled(action.isChecked())

    def _on_maximize_window(self):
        """
        Internal callback function that is called when the user clicks on maximize button
        """

        self._button_restored.setVisible(True)
        self._button_maximized.setVisible(False)
        self._window.setWindowState(Qt.WindowMaximized)

    def _on_minimize_window(self):
        """
        Internal callback function that is called when the user clicks on minimize button
        """

        self._window.setWindowState(Qt.WindowMinimized)

    def _on_restore_window(self):
        """
        Internal callback function that is called when the user clicks on restore button
        """

        self._button_restored.setVisible(False)
        self._button_maximized.setVisible(True)
        self._window.setWindowState(Qt.WindowNoState)

    def _on_close_window(self):
        """
        Internal callback function that is called when the user clicks on close button
        """

        from tpDcc.managers import tools

        closed = False
        if hasattr(self._window, 'WindowId'):
            closed = tools.ToolsManager().close_tool(self._window.WindowId,
                                                     force=False)

        if not closed:
            if hasattr(self._window, 'docked'):
                if self._window.docked():
                    self._window.fade_close()
                else:
                    self.window().fade_close()
            else:
                self._window.fade_close()
Esempio n. 8
0
    def __init__(self, parent=None):
        QMainWindow.__init__(self, parent)

        self.data = ParticleData()

        toolbar = self.addToolBar("Test")

        openButton = QPushButton("")
        openButton.setFlat(True)
        openButton.setIconSize(QSize(32, 32))
        openButton.setIcon(QIcon("/jobs2/soft/icons/dlight/open.png"))
        openButton.setToolTip("Open File")
        toolbar.addWidget(openButton)
        openButton.clicked.connect(self.openSlot)
        QShortcut(QKeySequence(Qt.CTRL + Qt.Key_O), self, self.openSlot)

        saveButton = QPushButton("")
        saveButton.setFlat(True)
        saveButton.setIconSize(QSize(32, 32))
        saveButton.setIcon(QIcon("/jobs2/soft/icons/dlight/file_save.png"))
        saveButton.setToolTip("Save File")
        toolbar.addWidget(saveButton)
        saveButton.clicked.connect(self.saveSlot)
        QShortcut(QKeySequence(Qt.CTRL + Qt.Key_S), self, self.saveSlot)

        saveDeltaButton = QPushButton("")
        saveDeltaButton.setFlat(True)
        saveDeltaButton.setIconSize(QSize(32, 32))
        saveDeltaButton.setIcon(
            QIcon("/jobs2/soft/icons/dlight/file_save_as.png"))
        saveDeltaButton.setToolTip("Save File As Delta")
        toolbar.addWidget(saveDeltaButton)
        saveDeltaButton.clicked.connect(self.saveDeltaSlot)
        QShortcut(QKeySequence(Qt.CTRL + Qt.SHIFT + Qt.Key_S), self,
                  self.saveDeltaSlot)

        addParticleButton = QPushButton("Particle")
        addParticleButton.setFlat(True)
        addParticleButton.setIconSize(QSize(32, 32))
        addParticleButton.setIcon(QIcon("/jobs2/soft/icons/shared/plus.png"))
        addParticleButton.setToolTip("Add Particle")
        toolbar.addWidget(addParticleButton)
        addParticleButton.clicked.connect(self.addParticleSlot)

        addAttributeButton = QPushButton("Attribute")
        addAttributeButton.setFlat(True)
        addAttributeButton.setIconSize(QSize(32, 32))
        addAttributeButton.setIcon(QIcon("/jobs2/soft/icons/shared/plus.png"))
        addAttributeButton.setToolTip("Add Attribute")
        toolbar.addWidget(addAttributeButton)
        addAttributeButton.clicked.connect(self.addAttributeSlot)

        splitter = QSplitter(self)
        self.setCentralWidget(splitter)

        particleTable = ParticleTableWidget(self.data, self)
        splitter.addWidget(particleTable)

        right = QWidget(self)
        splitter.addWidget(right)
        vbox = QVBoxLayout(right)
        right.setLayout(vbox)

        fixedAttrWidget = FixedAttributesWidget(self.data, self)
        vbox.addWidget(fixedAttrWidget)

        indexedStrings = IndexedStringsWidget(self.data, self)
        vbox.addWidget(indexedStrings)

        vbox.addStretch()

        # TODD: SCROLLABLE AREAS FOR EVERYTHING

        self.data.dirtied.connect(self.dataDirtiedSlot)

        # Configure ctrl-w to close the window
        QShortcut(QKeySequence(Qt.CTRL + Qt.Key_W), self, self.close)
Esempio n. 9
0
def create_flat_button(
    icon=None,
    icon_size=None,
    name='',
    text=200,
    background_color=[54, 51, 51],
    ui_color=68,
    border_color=180,
    push_col=120,
    checkable=True,
    w_max=None,
    w_min=None,
    h_max=None,
    h_min=None,
    policy=None,
    tip=None,
    flat=True,
    hover=True,
    destroy_flag=False,
    context=None,
):

    btn = QPushButton()
    btn.setText(name)
    btn.setCheckable(checkable)
    if icon:
        if isinstance(icon, QIcon):
            btn.setIcon(icon)
        else:
            btn.setIcon(QIcon(icon))
    btn.setFlat(flat)
    if flat:
        change_button_color(button=btn,
                            text_color=text,
                            bg_color=ui_color,
                            hi_color=background_color,
                            mode='button',
                            hover=hover,
                            destroy=destroy_flag,
                            ds_color=border_color)
        btn.toggled.connect(
            lambda: change_button_color(button=btn,
                                        text_color=text,
                                        bg_color=ui_color,
                                        hi_color=background_color,
                                        mode='button',
                                        toggle=True,
                                        hover=hover,
                                        destroy=destroy_flag,
                                        ds_color=border_color))
    else:
        change_button_color(button=btn,
                            text_color=text,
                            bg_color=background_color,
                            hi_color=push_col,
                            mode='button',
                            hover=hover,
                            destroy=destroy_flag,
                            ds_color=border_color)

    if w_max:
        btn.setMaximumWidth(w_max)
    if w_min:
        btn.setMinimumWidth(w_min)
    if h_max:
        btn.setMaximumHeight(h_max)
    if h_min:
        btn.setMinimumHeight(h_min)
    if icon_size:
        btn.setIconSize(QSize(*icon_size))
    if policy:
        btn.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Expanding)
    if tip:
        btn.setToolTip(tip)
    if context:
        btn.setContextMenuPolicy(Qt.CustomContextMenu)
        btn.customContextMenuRequested.connect(context)

    return btn
Esempio n. 10
0
class WindowStatusBar(statusbar.StatusWidget, object):
    def __init__(self, parent=None):
        super(WindowStatusBar, self).__init__(parent)

        self._info_url = None
        self._tool = None

        self.setFixedHeight(25)
        self._info_btn = QPushButton()
        self._info_btn.setIconSize(QSize(25, 25))
        self._info_btn.setSizePolicy(QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed))
        self._info_btn.setIcon(resources.icon('info1'))
        self._info_btn.setStyleSheet('QWidget {background-color: rgba(255, 255, 255, 0); border:0px;}')

        self._bug_btn = QPushButton()
        self._bug_btn.setIconSize(QSize(25, 25))
        self._bug_btn.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
        self._bug_btn.setIcon(resources.icon('bug'))
        self._bug_btn.setStyleSheet('QWidget {background-color: rgba(255, 255, 255, 0); border:0px;}')

        self.main_layout.insertWidget(0, self._info_btn)
        self.main_layout.insertWidget(1, self._bug_btn)

        self._info_btn.clicked.connect(self._on_open_url)
        self._bug_btn.clicked.connect(self._on_send_bug)

    def set_info_url(self, url):
        """
        Sets the URL used to open tool info documentation web
        :param url: str
        """

        self._info_url = url

    def set_tool(self, tool):
        """

        :param tool:
        :return:
        """

        self._tool = tool

    def has_url(self):
        """
        Returns whether the URL documentation web is set or not
        :return: bool
        """

        if self._info_url:
            return True

        return False

    def has_tool(self):
        """
        Returns whether window has a tool attached or not
        :return: bool
        """

        if self._tool:
            return True

        return False

    def show_info(self):
        """
        Shows the info button of the status bar
        """

        self._info_btn.setVisible(True)

    def hide_info(self):
        """
        Hides the info button of the status bar
        """

        self._info_btn.setVisible(False)

    def show_bug(self):
        self._bug_btn.setVisible(True)

    def hide_bug(self):
        self._bug_btn.setVisible(False)

    def open_info_url(self):
        """
        Opens tool documentation URL in user web browser
        """

        if not self._project:
            return False

        if self._info_url:
            webbrowser.open_new_tab(self._info_url)

    def _on_send_bug(self):

        if not self._project:
            return False

        # tools.ToolsManager().run_tool(self._project, 'bugtracker', extra_args={'tool': self._tool})

    def _on_open_url(self):
        """
        Internal callback function that is called when the user presses the info icon button
        :return:
        """

        self.open_info_url()
Esempio n. 11
0
    def __init__(self, parent=None):
        QMainWindow.__init__(self, parent)

        self.data = ParticleData()

        toolbar = self.addToolBar("Test")

        openButton = QPushButton("")
        openButton.setFlat(True)
        openButton.setIconSize( QSize(32, 32) )
        openButton.setIcon(QIcon("/jobs2/soft/icons/dlight/open.png"))
        openButton.setToolTip( "Open File" )
        toolbar.addWidget(openButton)
        openButton.clicked.connect(self.openSlot)
        QShortcut( QKeySequence(Qt.CTRL + Qt.Key_O), self, self.openSlot )

        saveButton = QPushButton("")
        saveButton.setFlat(True)
        saveButton.setIconSize( QSize(32, 32) )
        saveButton.setIcon(QIcon("/jobs2/soft/icons/dlight/file_save.png"))
        saveButton.setToolTip( "Save File" )
        toolbar.addWidget(saveButton)
        saveButton.clicked.connect(self.saveSlot)
        QShortcut( QKeySequence(Qt.CTRL + Qt.Key_S), self, self.saveSlot )

        saveDeltaButton = QPushButton("")
        saveDeltaButton.setFlat(True)
        saveDeltaButton.setIconSize( QSize(32, 32) )
        saveDeltaButton.setIcon(QIcon("/jobs2/soft/icons/dlight/file_save_as.png"))
        saveDeltaButton.setToolTip( "Save File As Delta" )
        toolbar.addWidget(saveDeltaButton)
        saveDeltaButton.clicked.connect(self.saveDeltaSlot)
        QShortcut( QKeySequence(Qt.CTRL + Qt.SHIFT + Qt.Key_S), self, self.saveDeltaSlot )

        addParticleButton = QPushButton("Particle")
        addParticleButton.setFlat(True)
        addParticleButton.setIconSize( QSize(32, 32) )
        addParticleButton.setIcon(QIcon("/jobs2/soft/icons/shared/plus.png"))
        addParticleButton.setToolTip( "Add Particle" )
        toolbar.addWidget(addParticleButton)
        addParticleButton.clicked.connect(self.addParticleSlot)

        addAttributeButton = QPushButton("Attribute")
        addAttributeButton.setFlat(True)
        addAttributeButton.setIconSize( QSize(32, 32) )
        addAttributeButton.setIcon(QIcon("/jobs2/soft/icons/shared/plus.png"))
        addAttributeButton.setToolTip( "Add Attribute" )
        toolbar.addWidget(addAttributeButton)
        addAttributeButton.clicked.connect(self.addAttributeSlot)

        splitter = QSplitter(self)
        self.setCentralWidget(splitter)

        particleTable = ParticleTableWidget(self.data, self)
        splitter.addWidget(particleTable)

        right = QWidget(self)
        splitter.addWidget(right)
        vbox = QVBoxLayout(right)
        right.setLayout(vbox)

        fixedAttrWidget = FixedAttributesWidget(self.data, self)
        vbox.addWidget(fixedAttrWidget)

        indexedStrings = IndexedStringsWidget(self.data, self)
        vbox.addWidget(indexedStrings)

        vbox.addStretch()

        # TODD: SCROLLABLE AREAS FOR EVERYTHING

        self.data.dirtied.connect(self.dataDirtiedSlot)


        # Configure ctrl-w to close the window
        QShortcut( QKeySequence(Qt.CTRL + Qt.Key_W), self, self.close )
Esempio n. 12
0
class MayaShelf(abstract_shelf.AbstractShelf, object):

    def __init__(self, name='MayaShelf', label_background=(0, 0, 0, 0), label_color=(0.9, 0.9, 0.9),
                 category_icon=None, enable_labels=True):
        super(MayaShelf, self).__init__(name=name, label_background=label_background, label_color=label_color,
                                        category_icon=category_icon, enable_labels=enable_labels)

    @staticmethod
    def add_menu_item(parent, label, command='', icon=''):
        """
        Adds a menu item with the given attributes
        :param parent:
        :param label:
        :param command:
        :param icon:
        :return:
        """

        return maya.cmds.menuItem(parent=parent, label=label, command=command, image=icon or '')

    @staticmethod
    def add_sub_menu(parent, label, icon=None):
        """
        Adds a sub menu item with the given label and icon to the given parent popup menu
        :param parent:
        :param label:
        :param icon:
        :return:
        """

        return maya.cmds.menuItem(parent=parent, label=label, icon=icon or '', subMenu=True)

    def create(self, delete_if_exists=True):
        """
        Creates a new shelf
        """

        if delete_if_exists:
            if gui.shelf_exists(shelf_name=self._name):
                gui.delete_shelf(shelf_name=self._name)
        else:
            assert not gui.shelf_exists(self._name), 'Shelf with name {} already exists!'.format(self._name)

        self._name = gui.create_shelf(name=self._name)

        # ========================================================================================================

        self._category_btn = QPushButton('')
        if self._category_icon:
            self._category_btn.setIcon(self._category_icon)
        self._category_btn.setIconSize(QSize(18, 18))
        self._category_menu = QMenu(self._category_btn)
        self._category_btn.setStyleSheet(
            'QPushButton::menu-indicator {image: url(myindicator.png);'
            'subcontrol-position: right center;subcontrol-origin: padding;left: -2px;}')
        self._category_btn.setMenu(self._category_menu)
        self._category_lbl = QLabel('MAIN')
        self._category_lbl.setAlignment(Qt.AlignCenter)
        font = self._category_lbl.font()
        font.setPointSize(6)
        self._category_lbl.setFont(font)
        menu_ptr = maya.OpenMayaUI.MQtUtil.findControl(self._name)
        menu_widget = qtutils.wrapinstance(menu_ptr, QWidget)
        menu_widget.layout().addWidget(self._category_btn)
        menu_widget.layout().addWidget(self._category_lbl)

        self.add_separator()

    def set_as_active(self):
        """
        Sets this shelf as active shelf in current DCC session
        """

        main_shelf = maya.mel.eval("$_tempVar = $gShelfTopLevel")
        maya.cmds.tabLayout(main_shelf, edit=True, selectTab=self._name)

    def add_button(self, label, tooltip=None, icon='customIcon.png', command=None,
                   double_command=None, command_type='python'):
        """
        Adds a shelf button width the given parameters
        :param label:
        :param tooltip:
        :param icon:
        :param command:
        :param double_command:
        :param command_type:
        :return:
        """

        maya.cmds.setParent(self._name)
        command = command or ''
        double_command = double_command or ''

        if not self._enable_labels:
            label = ''

        return maya.cmds.shelfButton(width=37, height=37, image=icon or '', label=label, command=command,
                                     doubleClickCommand=double_command, annotation=tooltip or '',
                                     imageOverlayLabel=label, overlayLabelBackColor=self._label_background,
                                     overlayLabelColor=self._label_color, sourceType=command_type)

    def add_separator(self):
        """
        Adds a separator to shelf
        :param parent:
        :return:
        """

        maya.cmds.separator(
            parent=self._name, manage=True, visible=True, horizontal=False, style='shelf',
            enableBackground=False, preventOverride=False)

    def build_category(self, shelf_file, category_name):

        self._category_lbl.setText(category_name.upper())

        self.load_category(shelf_file, 'general', clear=True)
        if category_name != 'general':
            self.add_separator()
            self.load_category(shelf_file, category_name, clear=False)

    def build_categories(self, shelf_file, categories):
        """
        Builds all categories given
        :param categories: list<str>, list of categories to build
        """

        self._category_lbl.setText('ALL')

        self.load_category(shelf_file, 'general', clear=True)
        for cat in categories:
            if cat == 'general':
                continue
            self.add_separator()
            self.load_category(shelf_file, cat, clear=False)

    def load_category(self, shelf_file, category_name, clear=True):
        """
        Loads into a shelf all the items of given category name, if exists
        :param category_name: str, name of the category
        """

        if clear:
            self.clear_list()
            # self.add_separator()

        with open(shelf_file) as f:
            shelf_data = json.load(f, object_pairs_hook=OrderedDict)

            for item, item_data in shelf_data.items():
                if item != category_name:
                    continue

                for i in item_data:
                    icon = i.get('icon')
                    command = i.get('command')
                    annotation = i.get('annotation')
                    label = i.get('label')

                    if annotation == 'separator':
                        self.add_separator()
                    else:
                        self.add_button(label=label, command=command, icon=icon, tooltip=annotation)
                return

    def build(self, shelf_file):
        """
        Builds shelf from JSON file
        :param shelf_file: str
        """

        first_item = None

        all_categories = list()

        with open(shelf_file) as f:
            shelf_data = json.load(f, object_pairs_hook=OrderedDict)

            for i, item in enumerate(shelf_data.keys()):
                if i == 0:
                    first_item = item

                category_action = self._category_menu.addAction(item.title())
                category_action.triggered.connect(partial(self.build_category, shelf_file, item))
                all_categories.append(item)

            category_action = self._category_menu.addAction('All')
            category_action.triggered.connect(partial(self.build_categories, shelf_file, all_categories))

        if first_item:
            self.load_category(shelf_file, first_item, clear=False)

    def clear_list(self):
        """
        Clears all the elements of the shelf
        """

        if gui.shelf_exists(shelf_name=self._name):
            menu_items = maya.cmds.shelfLayout(self._name, query=True, childArray=True)
            for item in menu_items:
                try:
                    maya.cmds.deleteUI(item)
                except Exception:
                    pass
Esempio n. 13
0
class MyToolBar(QWidget):
    """ ToolBar widget """

    # signal
    trigger = Signal(int)

    def __init__(self, flags, parent=None):
        super(MyToolBar, self).__init__(parent)

        self.setWindowFlags(Qt.ToolTip)
        self.paddingX = 5
        self.paddingY = 2
        self.iconWidth = self.iconHeight = 28
        self.setFixedHeight(self.iconHeight + 2 * self.paddingY)
        # self.setFixedWidth(300)

        self.rectButton = None
        self.ellipseButton = None
        self.arrowButton = None
        self.lineButton = None
        self.freePenButton = None
        self.textButton = None
        self.undoButton = None
        self.cancelButton = None
        self.okButton = None
        self.saveButton = None
        self.button_list = []

        self.initWindow(flags)

    def initDrawButtons(self, flags):
        self.drawButtonGroup = QButtonGroup(self)

        # draw action buttons
        if flags & constant.RECT:
            self.rectButton = QPushButton(self)
            self.rectButton.setIcon(QIcon(":/resource/icon/rect.png"))
            self.rectButton.setFixedSize(self.iconWidth, self.iconHeight)
            self.rectButton.setCheckable(True)
            self.drawButtonGroup.addButton(self.rectButton)
            self.hlayout.addWidget(self.rectButton)
            self.button_list.append(self.rectButton)

        if flags & constant.ELLIPSE:
            self.ellipseButton = QPushButton(self)
            self.ellipseButton.setIcon(QIcon(":/resource/icon/ellipse.png"))
            self.ellipseButton.setFixedSize(self.iconWidth, self.iconHeight)
            self.ellipseButton.setCheckable(True)
            self.drawButtonGroup.addButton(self.ellipseButton)
            self.hlayout.addWidget(self.ellipseButton)
            self.button_list.append(self.ellipseButton)

        if flags & constant.ARROW:
            self.arrowButton = QPushButton(self)
            self.arrowButton.setIcon(QIcon(":/resource/icon/arrow.png"))
            self.arrowButton.setFixedSize(self.iconWidth, self.iconHeight)
            self.arrowButton.setCheckable(True)
            self.drawButtonGroup.addButton(self.arrowButton)
            self.hlayout.addWidget(self.arrowButton)
            self.button_list.append(self.arrowButton)

        if flags & constant.LINE:
            self.lineButton = QPushButton(self)
            self.lineButton.setIcon(QIcon(":/resource/icon/line.png"))
            self.lineButton.setFixedSize(self.iconWidth, self.iconHeight)
            self.lineButton.setCheckable(True)
            self.drawButtonGroup.addButton(self.lineButton)
            self.hlayout.addWidget(self.lineButton)
            self.button_list.append(self.lineButton)

        if flags & constant.FREEPEN:
            self.freePenButton = QPushButton(self)
            self.freePenButton.setIcon(QIcon(":/resource/icon/pen.png"))
            self.freePenButton.setFixedSize(self.iconWidth, self.iconHeight)
            self.freePenButton.setCheckable(True)
            self.drawButtonGroup.addButton(self.freePenButton)
            self.hlayout.addWidget(self.freePenButton)
            self.button_list.append(self.freePenButton)

        if flags & constant.TEXT:
            self.textButton = QPushButton(self)
            self.textButton.setIcon(QIcon(":/resource/icon/text.png"))
            self.textButton.setFixedSize(self.iconWidth, self.iconHeight)
            self.textButton.setCheckable(True)
            self.drawButtonGroup.addButton(self.textButton)
            self.hlayout.addWidget(self.textButton)
            self.button_list.append(self.textButton)

        self.drawButtonGroup.buttonClicked.connect(self.buttonToggled)

    def initOtherButtons(self, flags):
        # other action buttons
        if len(self.button_list) != 0:
            self.separator1 = QFrame(self)
            self.separator1.setFrameShape(QFrame.VLine)
            self.separator1.setFrameShadow(QFrame.Sunken)
            self.hlayout.addWidget(self.separator1)

            self.undoButton = QPushButton(self)
            self.undoButton.setIcon(QIcon(":/resource/icon/undo.png"))
            self.undoButton.setFixedSize(self.iconWidth, self.iconWidth)
            self.undoButton.clicked.connect(self.otherButtonsClicked)
            self.hlayout.addWidget(self.undoButton)

        if flags & constant.SAVE_TO_FILE:
            self.saveButton = QPushButton(self)
            self.saveButton.setIcon(QIcon(":/resource/icon/save.png"))
            self.saveButton.setFixedSize(self.iconWidth, self.iconHeight)
            self.saveButton.clicked.connect(self.otherButtonsClicked)
            self.hlayout.addWidget(self.saveButton)

        self.separator2 = QFrame(self)
        self.separator2.setFrameShape(QFrame.VLine)
        self.separator2.setFrameShadow(QFrame.Sunken)
        self.hlayout.addWidget(self.separator2)

        self.cancelButton = QPushButton(self)
        self.cancelButton.setIcon(QIcon(":/resource/icon/close.png"))
        self.cancelButton.setFixedSize(self.iconWidth, self.iconHeight)
        self.cancelButton.clicked.connect(self.otherButtonsClicked)

        if flags & constant.CLIPBOARD:
            self.okButton = QPushButton(self)
            self.okButton.setIcon(QIcon(":/resource/icon/check.png"))
            self.okButton.setFixedSize(self.iconWidth, self.iconHeight)
            self.okButton.clicked.connect(self.otherButtonsClicked)
            self.hlayout.addWidget(self.okButton)

        self.hlayout.addWidget(self.cancelButton)

    def initWindow(self, flags):
        self.hlayout = QHBoxLayout()
        self.hlayout.setSpacing(2)
        self.hlayout.setContentsMargins(10, 2, 10, 2)
        self.setLayout(self.hlayout)

        self.initDrawButtons(flags)
        self.initOtherButtons(flags)

    # slots
    def buttonToggled(self, button):
        """
        :type button: QPushButton
        :param button:
        :return:
        """
        if button == self.rectButton:
            self.trigger.emit(ACTION_RECT)
        elif button == self.ellipseButton:
            self.trigger.emit(ACTION_ELLIPSE)
        elif button == self.arrowButton:
            self.trigger.emit(ACTION_ARROW)
        elif button == self.lineButton:
            self.trigger.emit(ACTION_LINE)
        elif button == self.freePenButton:
            self.trigger.emit(ACTION_FREEPEN)
        elif button == self.textButton:
            self.trigger.emit(ACTION_TEXT)
        else:
            pass

    def otherButtonsClicked(self):
        if self.sender() == self.undoButton:
            self.trigger.emit(ACTION_UNDO)
        elif self.sender() == self.cancelButton:
            self.trigger.emit(ACTION_CANCEL)
        elif self.sender() == self.okButton:
            self.trigger.emit(ACTION_SURE)
        elif self.sender() == self.saveButton:
            self.trigger.emit(ACTION_SAVE)
Esempio n. 14
0
class Project(base.BaseWidget):
    projectOpened = Signal(object)
    projectRemoved = Signal(str)
    projectImageChanged = Signal(str)

    def __init__(self, project_data, parent=None):

        self._project_data = project_data

        super(Project, self).__init__(parent)

    # ============================================================================================================
    # PROPERTIES
    # ============================================================================================================

    @property
    def name(self):
        return self._project_data.name

    @property
    def path(self):
        return self._project_data.path

    @property
    def full_path(self):
        return self._project_data.full_path

    @property
    def settings(self):
        return self._project_data.settings

    @property
    def project_data(self):
        return self._project_data

    # ============================================================================================================
    # CLASS FUNCTIONS
    # ============================================================================================================

    @classmethod
    def create_project_from_data(cls, project_data_path):
        """
        Creates a new project using a project data JSON file
        :param project_data_path: str, path where project JSON data file is located
        :return: Project
        """

        if project_data_path is None or not path.is_file(project_data_path):
            LOGGER.warning('Project Data Path {} is not valid!'.format(project_data_path))
            return None

        project_data = settings.JSONSettings()
        project_options = settings.JSONSettings()
        project_dir = path.get_dirname(project_data_path)
        project_name = path.get_basename(project_data_path)
        project_data.set_directory(project_dir, project_name)
        project_options.set_directory(project_dir, 'options.json')

        project_name = project_data.get('name')
        project_path = path.get_dirname(path.get_dirname(project_data_path))
        project_image = project_data.get('image')

        LOGGER.debug('New Project found [{}]: {}'.format(project_name, project_path))
        project_data = core_project.ProjectData(
            name=project_name, project_path=project_path, settings=project_data, options=project_options)

        new_project = cls(project_data=project_data)
        if project_image:
            new_project.set_image(project_image)

        return new_project

    # ============================================================================================================
    # OVERRIDES
    # ============================================================================================================

    def ui(self):
        super(Project, self).ui()

        self.setMaximumWidth(qtutils.dpi_scale(160))
        self.setMaximumHeight(qtutils.dpi_scale(200))

        widget_layout = layouts.VerticalLayout(spacing=0, margins=(0, 0, 0, 0))
        main_frame = QFrame()
        main_frame.setFrameStyle(QFrame.StyledPanel | QFrame.Raised)
        main_frame.setLineWidth(1)
        main_frame.setLayout(widget_layout)
        self.main_layout.addWidget(main_frame)

        self.project_btn = QPushButton('', self)
        self.project_btn.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        self.project_btn.setIconSize(QSize(120, 120))
        project_lbl = label.BaseLabel(self.name, parent=self)
        project_lbl.setObjectName('projectLabel')
        project_lbl.setAlignment(Qt.AlignCenter)
        widget_layout.addWidget(self.project_btn)
        widget_layout.addWidget(project_lbl)

    def setup_signals(self):
        self.project_btn.clicked.connect(self._on_open_project)

    def contextMenuEvent(self, event):
        menu = QMenu(self)
        remove_icon = resources.icon(name='delete')
        remove_action = QAction(remove_icon, 'Remove', menu)
        remove_tooltip = 'Delete selected project'
        remove_action.setStatusTip(remove_tooltip)
        remove_action.setToolTip(remove_tooltip)
        remove_action.triggered.connect(self._on_remove_project)

        folder_icon = resources.icon(name='open_folder', extension='png')
        folder_action = QAction(folder_icon, 'Open in Browser', menu)
        open_project_in_explorer_tooltip = 'Open project folder in explorer'
        folder_action.setStatusTip(open_project_in_explorer_tooltip)
        folder_action.setToolTip(open_project_in_explorer_tooltip)
        folder_action.triggered.connect(self._on_open_in_browser)

        image_icon = resources.icon(name='picture', extension='png')
        set_image_action = QAction(image_icon, 'Set Project Image', menu)
        set_project_image_tooltip = 'Set the image used by the project'
        set_image_action.setToolTip(set_project_image_tooltip)
        set_image_action.setStatusTip(set_project_image_tooltip)
        set_image_action.triggered.connect(self._on_set_project_image)

        for action in [remove_action, None, folder_action, None, set_image_action]:
            if action is None:
                menu.addSeparator()
            else:
                menu.addAction(action)

        menu.exec_(self.mapToGlobal(event.pos()))

    # ============================================================================================================
    # BASE
    # ============================================================================================================

    def open(self):
        """
        Opens project
        """

        self._on_open_project()

    def has_option(self, name, group=None):
        """
        Returns whether the current object has given option or not
        :param name: str, name of the option
        :param group: variant, str || None, group of the option (optional)
        :return: bool
        """

        if not self._project_data:
            return False

        return self._project_data.has_option(name=name, group=group)

    def add_option(self, name, value, group=None, option_type=None):
        """
        Adds a new option to the options file
        :param name: str, name of the option
        :param value: variant, value of the option
        :param group: variant, str || None, group of the option (optional)
        :param option_type: variant, str || None, option type (optional)
        """

        if not self._project_data:
            return

        self._project_data.add_option(name, value, group=group, option_type=option_type)

    def get_option(self, name, group=None, default=None):
        """
        Returns option by name and group
        :param name: str, name of the option we want to retrieve
        :param group: variant, str || None, group of the option (optional)
        :return: variant
        """

        if not self._project_data:
            return

        return self._project_data.get_option(name, group=group, default=default)

    def reload_options(self):
        """
        Reload settings
        """

        if not self._project_data:
            return

        self._project_data.reload_options()

    def clear_options(self):
        """
        Clears all the options
        """

        if not self._project_data:
            return

        self._project_data.clear_options()

    def set_image(self, encoded_image):

        from tpDcc.libs.qt.core import image

        if not encoded_image:
            return

        encoded_image = encoded_image.encode('utf-8')
        project_icon = QIcon(QPixmap.fromImage(image.base64_to_image(encoded_image)))
        if project_icon.isNull():
            project_icon = resources.icon('tpDcc')
        self.project_btn.setIcon(project_icon)

    def remove(self, force=False):
        if not path.is_dir(self.full_path):
            LOGGER.warning('Impossible to remove Project Path: {}'.format(self.full_path))
            return False

        project_name = self.project_data.name
        project_path = self.project_data.path

        if not force:
            result = qtutils.get_permission(
                message='Are you sure you want to delete project: "{}"'.format(self.name),
                title='Deleting Project', cancel=False, parent=self)
            if not result:
                return

        valid_delete = folder.delete_folder(folder_name=project_name, directory=project_path)
        if valid_delete is None:
            return False

        return True

    def load_project_data(self):
        """
        Return dictionary data contained in the project
        :return: dict
        """

        if not self.settings:
            return

        return self.settings.data()

    def get_project_nodes(self):
        """
        Returns path where nodes should be stored
        :return: str
        """

        return [os.path.join(self.full_path, 'nodes'), os.path.join(self.full_path, 'components')]

    def get_options(self):
        """
        Returns all options contained in the project
        :return: str
        """

        return self._project_data.get_options()

    def get_project_image(self):
        """
        Returns the image used by the project
        :return: QPixmap
        """

        return self._project_data.get_project_image()

    # ============================================================================================================
    # CALLBACKS
    # ============================================================================================================

    def _on_open_project(self):
        """
        Internal callback function that is called when a project is opened
        """

        LOGGER.info('Loading project "{}" ...'.format(self.full_path))
        self.projectOpened.emit(self)

    def _on_remove_project(self):
        """
        Internal callback function that is called when a project is removed
        """

        valid_remove = self.remove()
        if valid_remove:
            self.projectRemoved.emit(self.name)

    def _on_open_in_browser(self):
        """
        Internal callback function that is called when a project is browsed
        """

        fileio.open_browser(self.full_path)

    def _on_set_project_image(self):
        """
        Internal callback function that is called when project image is set
        """

        image_file = dcc.select_file_dialog(
            title='Select Project Image File',
            pattern="PNG Files (*.png)")

        if image_file is None or not path.is_file(image_file):
            LOGGER.warning('Selected Image "{}" is not valid!'.format(image_file))
            return

        valid_change = self._project_data.set_project_image(image_file)

        if valid_change:
            project_image = self._project_data.settings.get('image')
            if project_image:
                self.set_image(project_image)
            self.projectImageChanged.emit(image_file)
Esempio n. 15
0
    def fill_tree(self, trigger_name=None, trigger_job=None):
        item_stack = [self.tree.invisibleRootItem()]

        self.tree.clear()

        jobs = self.session.seqcrow_job_manager.jobs

        for job in jobs:
            name = job.name
            parent = item_stack[0]
            item = QTreeWidgetItem(parent)
            item_stack.append(item)

            item.setData(self.NAME_COL, Qt.DisplayRole, job)
            item.setText(self.NAME_COL, name)

            if isinstance(job, LocalJob):
                if job.killed:
                    item.setText(self.STATUS_COL, "killed")

                    del_job_widget = QWidget()
                    del_job_layout = QGridLayout(del_job_widget)
                    del_job = QPushButton()
                    del_job.clicked.connect(
                        lambda *args, job=job: self.remove_job(job))
                    del_job.setIcon(
                        QIcon(del_job_widget.style().standardIcon(
                            QStyle.SP_DialogDiscardButton)))
                    del_job.setFlat(True)
                    del_job_layout.addWidget(del_job, 0, 0, 1, 1,
                                             Qt.AlignHCenter)
                    del_job_layout.setColumnStretch(0, 1)
                    del_job_layout.setContentsMargins(0, 0, 0, 0)
                    self.tree.setItemWidget(item, self.DEL_COL, del_job_widget)

                elif job.isRunning():
                    if job in self.session.seqcrow_job_manager.unknown_status_jobs:
                        unk_widget = QWidget()
                        unk_layout = QGridLayout(unk_widget)
                        unk = QPushButton()
                        unk.setIcon(
                            QIcon(unk_widget.style().standardIcon(
                                QStyle.SP_MessageBoxQuestion)))
                        unk.setFlat(True)
                        unk.clicked.connect(lambda *args, job=job: self.
                                            show_ask_if_running(job))
                        unk_layout.addWidget(unk, 0, 0, 1, 1, Qt.AlignHCenter)
                        unk_layout.setColumnStretch(0, 1)
                        unk_layout.setContentsMargins(0, 0, 0, 0)
                        self.tree.setItemWidget(item, self.STATUS_COL,
                                                unk_widget)

                    else:
                        item.setText(self.STATUS_COL, "running")

                        kill_widget = QWidget()
                        kill_layout = QGridLayout(kill_widget)
                        kill = QPushButton()
                        kill.setIcon(
                            QIcon(kill_widget.style().standardIcon(
                                QStyle.SP_DialogCancelButton)))
                        kill.setFlat(True)
                        kill.clicked.connect(lambda *args, job=job: job.kill())
                        kill.clicked.connect(
                            lambda *args, session=self.session: session.
                            seqcrow_job_manager.triggers.activate_trigger(
                                JOB_QUEUED, "resume"))
                        kill_layout.addWidget(kill, 0, 0, 1, 1, Qt.AlignLeft)
                        kill_layout.setColumnStretch(0, 0)
                        kill_layout.setContentsMargins(0, 0, 0, 0)
                        self.tree.setItemWidget(item, self.KILL_COL,
                                                kill_widget)

                elif job.isFinished():
                    if not job.error:
                        item.setText(self.STATUS_COL, "finished")
                    else:
                        error_widget = QWidget()
                        error_layout = QGridLayout(error_widget)
                        error = QPushButton()
                        error.setIcon(
                            QIcon(error_widget.style().standardIcon(
                                QStyle.SP_MessageBoxWarning)))
                        error.setFlat(True)
                        error.setToolTip(
                            "job did not finish without errors or output file cannot be found"
                        )
                        error_layout.addWidget(error, 0, 0, 1, 1,
                                               Qt.AlignHCenter)
                        error_layout.setColumnStretch(0, 1)
                        error_layout.setContentsMargins(0, 0, 0, 0)
                        self.tree.setItemWidget(item, self.STATUS_COL,
                                                error_widget)

                    del_job_widget = QWidget()
                    del_job_layout = QGridLayout(del_job_widget)
                    del_job = QPushButton()
                    del_job.clicked.connect(
                        lambda *args, job=job: self.remove_job(job))
                    del_job.setIcon(
                        QIcon(del_job_widget.style().standardIcon(
                            QStyle.SP_DialogDiscardButton)))
                    del_job.setFlat(True)
                    del_job_layout.addWidget(del_job, 0, 0, 1, 1,
                                             Qt.AlignHCenter)
                    del_job_layout.setColumnStretch(0, 1)
                    del_job_layout.setContentsMargins(0, 0, 0, 0)
                    self.tree.setItemWidget(item, self.DEL_COL, del_job_widget)

                else:
                    item.setText(self.STATUS_COL, "queued")

                    priority_widget = QWidget()
                    priority_layout = QGridLayout(priority_widget)
                    inc_priority = QPushButton()
                    inc_priority.setIcon(
                        QIcon(priority_widget.style().standardIcon(
                            QStyle.SP_ArrowUp)))
                    inc_priority.setFlat(True)
                    inc_priority.clicked.connect(
                        lambda *args, job=job: self.session.seqcrow_job_manager
                        .increase_priotity(job))
                    priority_layout.addWidget(inc_priority, 0, 0, 1, 1,
                                              Qt.AlignRight)
                    dec_priority = QPushButton()
                    dec_priority.setIcon(
                        QIcon(priority_widget.style().standardIcon(
                            QStyle.SP_ArrowDown)))
                    dec_priority.setFlat(True)
                    dec_priority.clicked.connect(
                        lambda *args, job=job: self.session.seqcrow_job_manager
                        .decrease_priotity(job))
                    priority_layout.addWidget(dec_priority, 0, 1, 1, 1,
                                              Qt.AlignLeft)
                    priority_layout.setColumnStretch(0, 1)
                    priority_layout.setColumnStretch(1, 1)
                    priority_layout.setContentsMargins(0, 0, 0, 0)
                    self.tree.setItemWidget(item, self.CHANGE_PRIORITY,
                                            priority_widget)

                    kill_widget = QWidget()
                    kill_layout = QGridLayout(kill_widget)
                    kill = QPushButton()
                    kill.setIcon(
                        QIcon(kill_widget.style().standardIcon(
                            QStyle.SP_DialogCancelButton)))
                    kill.setFlat(True)
                    kill.clicked.connect(lambda *args, job=job: job.kill())
                    kill.clicked.connect(
                        lambda *args, session=self.session: session.
                        seqcrow_job_manager.triggers.activate_trigger(
                            JOB_QUEUED, "resume"))
                    kill_layout.addWidget(kill, 0, 0, 1, 1, Qt.AlignLeft)
                    kill_layout.setColumnStretch(0, 0)
                    kill_layout.setContentsMargins(0, 0, 0, 0)
                    self.tree.setItemWidget(item, self.KILL_COL, kill_widget)

                item.setText(self.SERVER_COL, "local")

                if job.scratch_dir and os.path.exists(job.scratch_dir):
                    browse_widget = QWidget()
                    browse_layout = QGridLayout(browse_widget)
                    browse = QPushButton()
                    browse.clicked.connect(
                        lambda *args, job=job: self.browse_local(job))
                    browse.setIcon(
                        QIcon(browse_widget.style().standardIcon(
                            QStyle.SP_DirOpenIcon)))
                    browse.setFlat(True)
                    browse_layout.addWidget(browse, 0, 0, 1, 1, Qt.AlignLeft)
                    browse_layout.setColumnStretch(0, 1)
                    browse_layout.setContentsMargins(0, 0, 0, 0)
                    self.tree.setItemWidget(item, self.BROWSE_COL,
                                            browse_widget)

            self.tree.expandItem(item)

        self.tree.resizeColumnToContents(self.STATUS_COL)
        self.tree.resizeColumnToContents(self.SERVER_COL)
        self.tree.resizeColumnToContents(self.CHANGE_PRIORITY)
        self.tree.resizeColumnToContents(self.KILL_COL)
        self.tree.resizeColumnToContents(self.DEL_COL)
        self.tree.resizeColumnToContents(self.BROWSE_COL)
Esempio n. 16
0
class UIVariable(QWidget, IPropertiesViewSupport):
    def __init__(self, rawVariable, variablesWidget, parent=None):
        super(UIVariable, self).__init__(parent)
        self._rawVariable = rawVariable
        self.variablesWidget = variablesWidget

        # ui
        self.horizontalLayout = QHBoxLayout(self)
        self.horizontalLayout.setSpacing(1)
        self.horizontalLayout.setContentsMargins(1, 1, 1, 1)
        self.horizontalLayout.setObjectName("horizontalLayout")
        self.widget = TypeWidget(
            findPinClassByType(self._rawVariable.dataType).color(), self)
        self.widget.setObjectName("widget")
        self.horizontalLayout.addWidget(self.widget)
        self.labelName = QLabel(self)
        self.labelName.setObjectName("labelName")
        self.horizontalLayout.addWidget(self.labelName)
        spacerItem = QSpacerItem(40, 20, QSizePolicy.Expanding,
                                 QSizePolicy.Minimum)
        self.horizontalLayout.addItem(spacerItem)
        # find refs
        self.pbFindRefs = QPushButton("")
        self.pbFindRefs.setIcon(
            QtGui.QIcon(RESOURCES_DIR + "/searching-magnifying-glass.png"))
        self.pbFindRefs.setObjectName("pbFindRefs")
        self.horizontalLayout.addWidget(self.pbFindRefs)
        self.pbFindRefs.clicked.connect(self.onFindRefsClicked)
        #  kill variable
        self.pbKill = QPushButton("")
        self.pbKill.setIcon(QtGui.QIcon(RESOURCES_DIR + "/delete_icon.png"))
        self.pbKill.setObjectName("pbKill")
        self.horizontalLayout.addWidget(self.pbKill)
        self.pbKill.clicked.connect(self.onKillClicked)

        QtCore.QMetaObject.connectSlotsByName(self)
        self.setName(self._rawVariable.name)

    def createPropertiesWidget(self, propertiesWidget):
        baseCategory = CollapsibleFormWidget(headName="Base")
        # name
        le_name = QLineEdit(self._rawVariable.name)
        le_name.returnPressed.connect(lambda: self.setName(le_name.text()))
        baseCategory.addWidget("Name", le_name)

        # data type
        cbTypes = VarTypeComboBox(self)
        baseCategory.addWidget("Type", cbTypes)
        propertiesWidget.addWidget(baseCategory)

        valueCategory = CollapsibleFormWidget(headName="Value")

        # current value
        def valSetter(x):
            self._rawVariable.value = x

        w = createInputWidget(
            self._rawVariable.dataType, valSetter,
            getPinDefaultValueByType(self._rawVariable.dataType))
        if w:
            w.setWidgetValue(self._rawVariable.value)
            w.setObjectName(self._rawVariable.name)
            valueCategory.addWidget(self._rawVariable.name, w)

        # access level
        cb = QComboBox()
        cb.addItem('public', 0)
        cb.addItem('private', 1)
        cb.addItem('protected', 2)

        def accessLevelChanged(x):
            self._rawVariable.accessLevel = AccessLevel[x]

        cb.currentTextChanged.connect(accessLevelChanged)
        cb.setCurrentIndex(self._rawVariable.accessLevel)
        valueCategory.addWidget('Access level', cb)
        propertiesWidget.addWidget(valueCategory)

    def onFindRefsClicked(self):
        refs = self._rawVariable.findRefs()
        print(refs)

    def onKillClicked(self):
        # check refs and ask user what to do
        refs = self._rawVariable.findRefs()
        if len(refs) > 0:
            item, accepted = QInputDialog.getItem(
                None,
                'Decide!',
                'What to do with getters and setters in canvas?',
                ['kill', 'leave'],
                editable=False)
            if accepted:
                if item == 'kill':
                    self.variablesWidget.killVar(self)
                elif item == 'leave':
                    # mark node as invalid
                    # TODO: For future. Like in ue4, if variable is removed, it can be recreated from node (e.g. promote to variable)
                    print('leave')
        else:
            self.variablesWidget.killVar(self)

    @property
    def dataType(self):
        return self._rawVariable.dataType

    @dataType.setter
    def dataType(self, value):
        self._rawVariable.dataType = value

    @property
    def packageName(self):
        return self._rawVariable.packageName

    @property
    def accessLevel(self):
        return self._rawVariable.accessLevel

    @accessLevel.setter
    def accessLevel(self, value):
        self._rawVariable.accessLevel = value

    @property
    def uid(self):
        return self._rawVariable.uid

    @uid.setter
    def uid(self, value):
        self._rawVariable.uid = value
        if self._rawVariable.uid in self.graph.vars:
            self.graph.vars.pop(self._rawVariable.uid)
            self.graph.vars[self._rawVariable.uid] = self._rawVariable

    @staticmethod
    def jsonTemplate():
        template = {
            'name': None,
            'uuid': None,
            'value': None,
            'type': None,
            'package': None,
            'accessLevel': None
        }
        return template

    def serialize(self):
        pinClass = findPinClassByType(self._rawVariable.dataType)

        template = UIVariable.jsonTemplate()
        template['name'] = self._rawVariable.name
        template['uuid'] = str(self._rawVariable.uid)

        if self._rawVariable.dataType == "AnyPin":
            # don't save any variables
            # value will be calculated for this type of variables
            template['value'] = None
        else:
            template['value'] = json.dumps(self._rawVariable.value,
                                           cls=pinClass.jsonEncoderClass())

        template['type'] = self._rawVariable.dataType
        template['package'] = self._rawVariable.packageName
        template['accessLevel'] = self._rawVariable.accessLevel.value
        return template

    @staticmethod
    def deserialize(data, graph):
        pinClass = findPinClassByType(data['dataType'])

        varUid = uuid.UUID(data['uuid'])
        # TODO: this is probably bad. Too long call chain
        var = graph.parent.variablesWidget.createVariable(
            dataType=data['dataType'],
            accessLevel=AccessLevel(data['accessLevel']),
            uid=varUid)
        var.setName(data['name'])
        var.setDataType(data['dataType'])

        if data['dataType'] == 'AnyPin':
            var.value = getPinDefaultValueByType('AnyPin')
        else:
            var.value = json.loads(data['value'],
                                   cls=pinClass.jsonDecoderClass())

        return var

    @property
    def value(self):
        return self._rawVariable.value

    @value.setter
    def value(self, data):
        self._rawVariable.value = data

    # Changes variable data type and updates [TypeWidget](@ref PyFlow.Core.Variable.TypeWidget) color
    # @bug in the end of this method we clear undo stack, but we should not. We do this because undo redo goes crazy
    def setDataType(self, dataType, _bJustSpawned=False):
        self._rawVariable.dataType = dataType
        self.widget.color = findPinClassByType(self.dataType).color()
        self.widget.update()
        if _bJustSpawned:
            return
        self.variablesWidget.onUpdatePropertyView(self)

    def mousePressEvent(self, event):
        super(UIVariable, self).mousePressEvent(event)
        self.variablesWidget.onUpdatePropertyView(self)

    def setName(self, name):
        self._rawVariable.name = name
        self.labelName.setText(self._rawVariable.name)
Esempio n. 17
0
class PenSetWidget(QWidget):

    penSizeTrigger = Signal(int)
    penColorTrigger = Signal(str)
    fontChangeTrigger = Signal(QFont)

    def __init__(self, parent=None):
        super(PenSetWidget, self).__init__(parent)

        self.paddingX = 5
        self.paddingY = 2
        self.iconWidth = self.iconHeight = 24
        self.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Fixed)
        self.setWindowFlags(Qt.ToolTip)

        self.initWindows()

        self.prevSizeButton = self.penSize1
        self.penSize1.setChecked(True)
        self.presentColor.setStyleSheet(
            'QPushButton { background-color: %s; }' % PENCOLOR)

    def generateButtons(self, parent=None):
        """ Generate buttons due to colorDic """
        self.colorButtons = []
        for color in self.colorList:
            button = QPushButton(parent)
            button.setObjectName(color[0])
            button.setStyleSheet('QPushButton { background-color: %s; }' %
                                 color[1])
            button.setFixedSize(self.iconWidth / 2, self.iconHeight / 2)
            button.setCheckable(True)
            self.colorButtons.append(button)

    def initWindows(self):
        self.mainLayout = QHBoxLayout()
        self.setLayout(self.mainLayout)
        self.mainLayout.setSpacing(0)
        self.mainLayout.setContentsMargins(5, 2, 5, 2)

        self.initPenSizeButtons()
        self.initFontWidget()
        self.initPenColorButtons()

        self.separator = QFrame(self)
        self.separator.setFrameShape(QFrame.VLine)
        self.separator.setFrameShadow(QFrame.Sunken)

        self.mainLayout.addWidget(self.penSize)
        self.mainLayout.addWidget(self.changeFontButton)
        self.mainLayout.addWidget(self.separator)

        self.mainLayout.addWidget(self.colorSet)

    def initPenSizeButtons(self):
        self.penSize = QWidget(self)
        self.penSizeLayout = QHBoxLayout()
        self.penSize.setLayout(self.penSizeLayout)
        # adjust pen size
        self.penSize1 = QPushButton(self.penSize)
        self.penSize1.setIcon(QIcon(":/resource/icon/pensize1.png"))
        self.penSize1.setObjectName('1')
        self.penSize1.setFixedSize(self.iconWidth, self.iconHeight)
        self.penSize1.setCheckable(True)

        self.penSize2 = QPushButton(self.penSize)
        self.penSize2.setIcon(QIcon(":/resource/icon/pensize2.png"))
        self.penSize2.setObjectName('2')
        self.penSize2.setFixedSize(self.iconWidth, self.iconHeight)
        self.penSize2.setCheckable(True)

        self.penSize3 = QPushButton(self.penSize)
        self.penSize3.setIcon(QIcon(":/resource/icon/pensize3.png"))
        self.penSize3.setObjectName('3')
        self.penSize3.setFixedSize(self.iconWidth, self.iconHeight)
        self.penSize3.setCheckable(True)

        self.sizeButtonGroup = QButtonGroup(self.penSize)
        self.sizeButtonGroup.addButton(self.penSize1)
        self.sizeButtonGroup.addButton(self.penSize2)
        self.sizeButtonGroup.addButton(self.penSize3)
        self.sizeButtonGroup.buttonClicked.connect(self.sizeButtonToggled)

        self.penSizeLayout.addWidget(self.penSize1)
        self.penSizeLayout.addWidget(self.penSize2)
        self.penSizeLayout.addWidget(self.penSize3)

        self.penSizeLayout.setSpacing(5)
        self.penSizeLayout.setContentsMargins(0, 0, 0, 0)

    def initPenColorButtons(self):
        self.colorSet = QWidget(self)
        self.colorLayout = QHBoxLayout()
        self.colorLayout.setSpacing(5)
        self.colorLayout.setContentsMargins(5, 0, 5, 0)
        self.colorSet.setLayout(self.colorLayout)

        self.presentColor = QPushButton(self.colorSet)
        self.presentColor.setFixedSize(self.iconWidth, self.iconHeight)
        self.presentColor.setEnabled(False)

        # adjust pen color

        self.colorPick = QWidget(self.colorSet)
        self.colorGrid = QGridLayout()
        self.colorGrid.setSpacing(0)
        self.colorGrid.setContentsMargins(5, 0, 5, 0)
        self.colorPick.setLayout(self.colorGrid)

        self.colorList = [('white', '#ffffff'), ('red', '#ff0000'),
                          ('green', '#00ff00'), ('blue', '#0000ff'),
                          ('cyan', '#00ffff'), ('magenta', '#ff00ff'),
                          ('yellow', '#ffff00'), ('gray', '#a0a0a4'),
                          ('black', '#000000'), ('darkRed', '#800000'),
                          ('darkGreen', '#008000'), ('darkBlue', '#000080'),
                          ('darkCyan', '#008080'), ('darkMagenta', '#800080'),
                          ('darkYellow', '#808000'), ('darkGray', '#808080')]

        self.generateButtons()

        self.colorButtonGroup = QButtonGroup(self)
        for button in self.colorButtons:
            self.colorButtonGroup.addButton(button)
        self.colorButtonGroup.buttonClicked.connect(self.colorButtonToggled)

        # set the layout
        tmp = 0
        for x in range(0, 2):
            for y in range(0, int(len(self.colorList) / 2)):
                self.colorGrid.addWidget(self.colorButtons[tmp], x, y)
                tmp += 1

        self.colorGrid.setSpacing(0)
        self.colorGrid.setContentsMargins(0, 0, 0, 0)

        self.colorLayout.addWidget(self.presentColor)
        self.colorLayout.addWidget(self.colorPick)

    def initFontWidget(self):
        self.fontDialog = QFontDialog()
        self.changeFontButton = QPushButton(self)
        self.fontDialog.setCurrentFont(QFont('Sans serif'))
        self.changeFontButton.setText('{0} {1}'.format(
            self.fontDialog.currentFont().family(),
            self.fontDialog.currentFont().pointSize()))
        self.changeFontButton.clicked.connect(self.fontButtonClicked)

    def showFontWidget(self):
        self.changeFontButton.show()
        self.penSize1.hide()
        self.penSize2.hide()
        self.penSize3.hide()

    def showPenWidget(self):
        self.changeFontButton.hide()
        self.penSize1.show()
        self.penSize2.show()
        self.penSize3.show()

    # slots
    def colorButtonToggled(self, button):
        self.presentColor.setStyleSheet(
            'QPushButton { background-color: %s; }' % button.objectName())
        self.penColorTrigger.emit(button.objectName())

    def sizeButtonToggled(self, button):
        self.penSizeTrigger.emit(int(button.objectName()) * 2)

    def fontButtonClicked(self):
        ok = True
        font = QFontDialog.getFont(self)
        if font[1]:
            self.changeFontButton.setText('{0} {1}'.format(
                font[0].family(), font[0].pointSize()))
            self.fontChangeTrigger.emit(font[0])
Esempio n. 18
0
class ExpandablePanel(base.BaseWidget, object):

    def __init__(self, header_text, min_height=30, max_height=1000,
                 show_header_text=True, is_opened=False, parent=None):

        self._header_text = header_text
        self._show_header_text = show_header_text
        self._min_height = min_height
        self._max_height = max_height

        if is_opened:
            self._panel_state = PanelState.OPEN
        else:
            self._panel_state = PanelState.CLOSED
        self._collapse_icon = QIcon()
        self._icon = QPushButton()
        self._icon.setMaximumSize(20, 20)
        self._icon.setIcon(self._collapse_icon)

        super(ExpandablePanel, self).__init__(parent=parent)

        self.setObjectName('ExpandablePanel')
        self.update_size()
        self.update_icon()

    def ui(self):
        super(ExpandablePanel, self).ui()

        widget_palette = QPalette()
        widget_palette.setColor(QPalette.Background, QColor.fromRgb(60, 60, 60))

        self.setAutoFillBackground(True)
        self.setPalette(widget_palette)

        frame = QFrame()
        frame.setFrameShape(QFrame.StyledPanel)
        frame.setFrameShadow(QFrame.Sunken)
        self.main_layout.addWidget(frame)

        main_layout = layouts.VerticalLayout(spacing=0, margins=(2, 2, 2, 2), parent=frame)
        main_layout.setAlignment(Qt.AlignTop)

        self._header_area = QWidget()
        self._header_area.setMinimumHeight(20)
        self._widget_area = QWidget()
        self._widget_area.setAutoFillBackground(True)
        self._widget_area.setPalette(widget_palette)

        self._header_text_label = dividers.Divider(self._header_text)

        self._widget_layout = layouts.VerticalLayout(spacing=5)
        self._widget_layout.setMargin(5)
        self._widget_area.setLayout(self._widget_layout)

        header_layout = layouts.HorizontalLayout(margins=(0, 0, 0, 0))
        header_layout.addWidget(self._icon)
        header_layout.addWidget(self._header_text_label)
        self._header_area.setLayout(header_layout)

        main_layout.addWidget(self._header_area)
        main_layout.addWidget(self._widget_area)

        self._icon.clicked.connect(self.change_state)

    def update_icon(self):

        if self._panel_state == PanelState.OPEN:
            self._icon.setStyleSheet(
                'QLabel {image: url(:/icons/open_hover_collapsible_panel) no-repeat;} '
                'QLabel:hover {image:url(:/icons/open_hover_collapsible_panel) no-repeat;}')
            self._icon.setToolTip('Close')
            self._widget_area.show()
        else:
            self._icon.setStyleSheet(
                'QLabel {image: url(:/icons/closed_collapsible_panel) no-repeat;} '
                'QLabel:hover {image:url(:/icons/closed_hover_collapsible_panel) no-repeat;}')
            self._icon.setToolTip('Open')
            self._widget_area.hide()

    def update_size(self):
        if self._panel_state == PanelState.OPEN:
            self.setMaximumHeight(self._max_height)
            self.setMinimumHeight(self._min_height)
        else:
            self.setMaximumHeight(self._min_height)
            self.setMinimumHeight(self._min_height)

    def change_state(self):

        if not self._show_header_text:
            self._header_text_label.setVisible(False)

        if self._panel_state == PanelState.OPEN:
            self._panel_state = PanelState.CLOSED
            # self._header_text_label.setText('Closed')
            self._widget_area.hide()
        else:
            self._panel_state = PanelState.OPEN
            # self._header_text_label.setText('Open')
            self._widget_area.show()
        self.update_icon()
        self.update_size()

    def add_widget(self, widget):
        self._widget_layout.addWidget(widget)

    def add_layout(self, layout):
        self._widget_layout.addLayout(layout)
Esempio n. 19
0
class SaveWidget(BaseSaveWidget, object):
    def __init__(self, item, settings, temp_path=None, parent=None):

        self._script_job = None
        self._sequence_path = None
        self._icon_path = ''

        super(SaveWidget, self).__init__(item=item,
                                         settings=settings,
                                         temp_path=temp_path,
                                         parent=parent)

        self.create_sequence_widget()
        self.update_thumbnail_size()

        try:
            self._on_selection_changed()
            # self.set_script_job_enabled(True)
        except NameError as e:
            LOGGER.error('{} | {}'.format(e, traceback.format_exc()))

    def ui(self):
        super(SaveWidget, self).ui()

        model_panel_layout = layouts.HorizontalLayout()
        model_panel_layout.setContentsMargins(0, 0, 0, 0)
        model_panel_layout.setSpacing(0)
        thumbnail_layout = layouts.VerticalLayout()
        thumbnail_layout.setContentsMargins(0, 0, 0, 0)
        thumbnail_layout.setSpacing(0)
        self._thumbnail_frame = QFrame()
        self._thumbnail_frame.setMinimumSize(QSize(50, 50))
        self._thumbnail_frame.setMaximumSize(QSize(150, 150))
        self._thumbnail_frame.setSizePolicy(QSizePolicy.Expanding,
                                            QSizePolicy.Expanding)
        self._thumbnail_frame.setFrameShape(QFrame.NoFrame)
        self._thumbnail_frame.setFrameShadow(QFrame.Plain)
        self._thumbnail_frame.setLineWidth(0)
        self._thumbnail_frame.setLayout(thumbnail_layout)
        model_panel_layout.addWidget(self._thumbnail_frame)
        self._thumbnail_btn = QPushButton()
        self._thumbnail_btn.setMinimumSize(QSize(0, 0))
        self._thumbnail_btn.setSizePolicy(QSizePolicy.Expanding,
                                          QSizePolicy.Expanding)
        self._thumbnail_btn.setMaximumSize(QSize(150, 150))
        self._thumbnail_btn.setToolTip('Take snapshot')
        self._thumbnail_btn.setStyleSheet(
            'color: rgb(40, 40, 40);border: 0px solid rgb(0, 0, 0, 150);background-color: rgb(254, 255, 230, 200);'
        )
        self._thumbnail_btn.setIcon(resources.icon('thumbnail'))
        self._thumbnail_btn.setToolTip("""
        Click to capture a thumbnail from the current viewport.\n
        CTRL + Click to show the capture window for better framing
        """)
        thumbnail_layout.addWidget(self._thumbnail_btn)

        self._extra_layout.addLayout(model_panel_layout)

    def setup_signals(self):
        super(SaveWidget, self).setup_signals()
        self._thumbnail_btn.clicked.connect(self._on_thumbnail_capture)

    def resizeEvent(self, event):
        """
        Overrides base QWidget resizeEvent function
        :param event: QResizeEvent
        """

        self.update_thumbnail_size()

    def icon_path(self):
        """
        Returns the icon path to be used for the thumbnail
        :return: str
        """

        return self._icon_path

    def set_icon(self, icon):
        """
        Sets the icon for the create widget thumbnail
        :param icon: QIcon
        """

        self._thumbnail_btn.setIcon(icon)
        self._thumbnail_btn.setIconSize(QSize(200, 200))
        self._thumbnail_btn.setText('')

    def sequence_path(self):
        """
        Returns the playblast path
        :return: str
        """

        return self._sequence_path

    def set_sequence_path(self, path):
        """
        Sets the disk location for the image sequence to be saved
        :param path: str
        """

        self._sequence_path = path
        self._thumbnail_btn.set_dirname(os.path.dirname(path))

    def create_sequence_widget(self):
        """
        Creates a sequence widget to replace the static thumbnail widget
        """

        sequence_widget = widgets.LibraryImageSequenceWidget(self)
        sequence_widget.setObjectName('thumbnailButton')
        sequence_widget.setStyleSheet(self._thumbnail_btn.styleSheet())
        sequence_widget.setToolTip(self._thumbnail_btn.toolTip())

        camera_icon = resources.get('icons', 'camera.svg')
        expand_icon = resources.get('icons', 'expand.svg')
        folder_icon = resources.get('icons', 'folder.svg')

        sequence_widget.addAction(camera_icon, 'Capture new image',
                                  'Capture new image',
                                  self._on_thumbnail_capture)
        sequence_widget.addAction(expand_icon, 'Show Capture window',
                                  'Show Capture window',
                                  self._on_show_capture_window)
        sequence_widget.addAction(folder_icon, 'Load image from disk',
                                  'Load image from disk',
                                  self._on_show_browse_image_dialog)

        sequence_widget.setIcon(resources.icon('thumbnail2'))
        self._thumbnail_frame.layout().insertWidget(0, sequence_widget)
        self._thumbnail_btn.hide()
        self._thumbnail_btn = sequence_widget
        self._thumbnail_btn.clicked.connect(self._on_thumbnail_capture)

    def set_sequence(self, source):
        """
        Sets the sequenced path for the thumbnail widget
        :param source: str
        """

        self.set_thumbnail(source, sequence=True)

    def set_thumbnail(self, source, sequence=False):
        """
        Sets the thumbnail
        :param source: str
        :param sequence: bool
        """

        source = os.path.normpath(source)

        # TODO: Find a way to remove temp folder afteer saving the file
        # filename, extension = os.path.splitext(source)
        # with path_utils.temp_dir() as dir_path:
        # dir_path = path_utils.temp_dir()
        # target = os.path.join(dir_path, 'thumbnail{}'.format(extension))
        # shutil.copyfile(source, target)
        # tpQtLib.logger.debug('Source Thumbnail: {}'.format(source))
        # tpQtLib.logger.debug('Target Thumbnail: {}'.format(target))
        # self._icon_path = target
        # self._thumbnail_btn.set_path(target)

        self._icon_path = source
        self._thumbnail_btn.set_path(source)

        if sequence:
            self.set_sequence_path(source)

    def update_thumbnail_size(self):
        """
        Updates the thumbnail button to teh size of the widget
        """

        width = self.width() - 10
        if width > 250:
            width = 250
        size = QSize(width, width)
        self._thumbnail_btn.setIconSize(size)
        self._thumbnail_btn.setMaximumSize(size)
        self._thumbnail_frame.setMaximumSize(size)

    def show_by_frame_dialog(self):
        """
        Show the by frame dialog
        """

        help_text = """
        To help speed up the playblast you can set the "by frame" to another greather than 1.
        For example if the "by frame" is set to 2 it will playblast every second frame
        """

        options = self._options_widget.values()
        by_frame = options.get('byFrame', 1)
        start_frame, end_frame = options.get('frameRange', [None, None])
        duration = 1
        if start_frame is not None and end_frame is not None:
            duration = end_frame - start_frame
        if duration > 100 and by_frame == 1:
            buttons = QDialogButtonBox.Ok | QDialogButtonBox.Cancel
            result = messagebox.MessageBox.question(
                self.library_window(),
                title='Tip',
                text=help_text,
                buttons=buttons,
                enable_dont_show_checkbox=True)
            if result != QDialogButtonBox.Ok:
                raise Exception('Cancelled by user')

    def show_thumbnail_capture_dialog(self):
        """
        Asks the user if they would like to capture a thumbnail
        :return: int
        """

        buttons = QDialogButtonBox.Yes | QDialogButtonBox.Ignore | QDialogButtonBox.Cancel
        parent = self.item().library_window()
        btn = messagebox.MessageBox.question(
            None,
            'Create a thumbnail',
            'Would you like to capture a thumbnail?',
            buttons=buttons)
        if btn == QDialogButtonBox.Yes:
            self.thumbnail_capture()

        return btn

    def thumbnail_capture(self, show=False):
        """
        Captures a playblast and saves it to the temporal thumbnail path
        :param show: bool
        """

        options = self._options_widget.values()
        start_frame, end_frame = options.get('frameRange', [None, None])
        step = options.get('byFrame', 1)

        if not qtutils.is_control_modifier():
            self.show_by_frame_dialog()

        if not self._temp_path or not os.path.isdir(self._temp_path):
            self._temp_path = tempfile.mkdtemp()
        self._temp_path = os.path.join(self._temp_path, 'thumbnail.jpg')

        try:
            snapshot.SnapshotWindow(path=self._temp_path,
                                    on_save=self._on_thumbnail_captured)
            # thumbnail.ThumbnailCaptureDialog.thumbnail_capture(
            #     path=self._temp_path,
            #     show=show,
            #     start_frame=start_frame,
            #     end_frame=end_frame,
            #     step=step,
            #     clear_cache=False,
            #     captured=self._on_thumbnail_captured
            # )
        except Exception as e:
            messagebox.MessageBox.critical(self.library_window(),
                                           'Error while capturing thumbnail',
                                           str(e))
            LOGGER.error(traceback.format_exc())

    def save(self, path, icon_path, objects=None):
        """
        Saves the item with the given objects to the given disk location path
        :param path: list(str)
        :param icon_path: str
        :param objects: str
        """

        item = self.item()
        options = self._options_widget.values()
        sequence_path = self.sequence_path()
        if sequence_path:
            sequence_path = os.path.dirname(sequence_path)

        item.save(path=path,
                  objects=objects,
                  icon_path=icon_path,
                  sequence_path=sequence_path,
                  **options)

        self.close()

    def _on_selection_changed(self):
        """
        Internal callback functino that is called when DCC selection changes
        """

        if self._options_widget:
            self._options_widget.validate()

    def _on_thumbnail_capture(self):
        self.thumbnail_capture(show=False)

    def _on_thumbnail_captured(self, captured_path):
        """
        Internal callback function that is called when thumbnail is captured
        :param captured_path: str
        """

        self.set_sequence(captured_path)

    def _on_show_capture_window(self):
        """
        Internal callback function that shows the capture window for framing
        """

        self.thumbnail_capture(show=True)

    def _on_show_browse_image_dialog(self):
        """
        Internal callback function that shows a file dialog for choosing an image from disk
        """

        file_dialog = QFileDialog(self,
                                  caption='Open Image',
                                  filter='Image Files (*.png *.jpg)')
        file_dialog.fileSelected.connect(self.set_thumbnail)
        file_dialog.exec_()