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)
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)
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)
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)
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])