def removeTab(self, tab): ''' hide if there are no tabs ''' FwTabWidget.removeTab(self, tab) if self.count() == 0: self.hide()
def __init__(self): FwTabWidget.__init__(self) self.setMovable(True) self.setSizePolicy( QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding) self.hide()
def addTab(self, *args): ''' show is a tab is added ''' FwTabWidget.addTab(self, *args) if not self.isVisible(): # initialise with size 0: self.show() self.parent().moveSplitter(0, 1)
def __init__(self, display, splitter): QtWidgets.QWidget.__init__(self) self.display = display display.sigLayerChanged.connect(self.toggleDataChanged) display.sigNewLayer.connect(self.toggleNewData) self.setMinimumHeight(30) self.splitter = splitter self._collect = False self._activeWidgets = [] # LAYOUT layout = QtWidgets.QVBoxLayout() layout.setAlignment(QtCore.Qt.AlignTop) # setMargin removed. obsolete, doesn't do anything, not even in PyQt4 self.setLayout(layout) self._hl = QtWidgets.QHBoxLayout() layout.addLayout(self._hl) # BUTTON: show/hide 'Scripts' self.btn_scripts = QtWidgets.QRadioButton('Scripts') f = self.btn_scripts.font() f.setBold(True) self.btn_scripts.setFont(f) self.btn_scripts.clicked.connect(self._uncheckConsole) self.btn_scripts.clicked.connect(self._toggleScriptsFirstTime) self.btn_scripts.clicked.connect(self.updateSize) self._hl.addWidget(self.btn_scripts) # BUTTON: show/hide 'Console' self.btn_console = QtWidgets.QRadioButton('Console') f = self.btn_console.font() f.setBold(True) self.btn_console.setFont(f) self.btn_console.clicked.connect(self._uncheckScripts) self.btn_console.clicked.connect(self._toggleConsoleFirstTime) self.btn_console.clicked.connect(self.updateSize) self._hl.addWidget(self.btn_console) g = QtWidgets.QButtonGroup(self) g.setExclusive(False) g.addButton(self.btn_scripts) g.addButton(self.btn_console) self.splitter.setStretchFactor(0, 0) self.cb_run_on = QtWidgets.QComboBox() self.cb_run_on.addItems(['-', 'New Data', 'Data Changed']) self.tabs = FwTabWidget() self.tabs.hide() self.tabs.setTabsAddable(True) self.tabs.setTabsClosable(True) self.tabs.setTabsRenamable(True)
def addTab(self, *args): ''' show is a tab is added ''' FwTabWidget.addTab(self, *args) if not self.isVisible(): #initialize with size 0: self.show() self.parent().moveSplitter(0,1)
def __init__(self): FwTabWidget.__init__(self) self.setMovable(True) self.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding) self.hide() # pop-out button: s = QtWidgets.QApplication.style() btn = QtWidgets.QToolButton() btn.setIcon(s.standardIcon(QtWidgets.QStyle.SP_TitleBarNormalButton)) btn.setToolTip('Pop-out Dock Preferences') btn.clicked.connect(self._togglePopOut) self.cornerWidget().layout().addWidget(btn)
def __init__(self, display, splitter): QtGui.QWidget.__init__(self) self.display = display display.sigLayerChanged.connect(self.toggleDataChanged) display.sigNewLayer.connect(self.toggleNewData) self.splitter = splitter refreshR = 20 self._collect = False self._activeWidgets = [] #BUTTON: OF/OFF self.btn_show = QtGui.QRadioButton('Console') f=self.btn_show.font() f.setBold(True) self.btn_show.setFont(f) self.btn_show.clicked.connect(self._toggleShow) #COMBOBOX: IMPORT self.combo_import = QtGui.QComboBox() self.combo_import.addItems(( '<import>', 'from file')) self.combo_import.addItems( #don't show '.py' and hide __init__.py [x[:-3] for x in SPRIPT_PATH.listdir() if (x[0] != '_' and x.endswith('.py'))]) self.combo_import.currentIndexChanged.connect(self._importScript) #BUTTON: COLLECT self.btn_collect= QtGui.QPushButton('Collect') self.btn_collect.setToolTip('click on all tool parameters you want to change during the batch process') self.btn_collect.setCheckable(True) self.btn_collect.clicked.connect(self.collectWidgets) #TABWIDGET: SCRIPT self.tabs = FwTabWidget() self.tabs.hide() self.tabs.setTabsAddable(True) self.tabs.setTabsClosable(True) self.tabs.setTabsRenamable(True) self.tabs.defaultTabWidget = lambda: ScriptTab(self, refreshR) self.tabs.addEmptyTab('New') #BUTTON: RUN AT NEW INPUT self.label_run_on = QtGui.QLabel('Activate on') self.cb_run_on = QtGui.QComboBox() self.cb_run_on.addItems(['-', 'New Data', 'Data Changed']) #SPINBOX REFRESHRATE self.label_refresh = QtGui.QLabel('Refresh rate:') self.sb_refreshrate = QtGui.QSpinBox() self.sb_refreshrate.setSuffix(" Hz") self.sb_refreshrate.setMinimum(0) self.sb_refreshrate.setMaximum(100) self.sb_refreshrate.setValue(refreshR) self.sb_refreshrate.valueChanged.connect( lambda hz: self.tabs.currentWidget().thread.setRefreshrate(hz)) #BUTTON: RUN self.btn_run_now = QtGui.QPushButton('Run') self.btn_run_now.setCheckable(True) self.btn_run_now.clicked.connect(self.toggle) #LAYOUT layout = QtGui.QVBoxLayout() layout.setAlignment(QtCore.Qt.AlignTop) layout.setMargin(0) self.setLayout(layout) #top layout hl = QtGui.QHBoxLayout() hl.addWidget(self.btn_show) hl.addWidget(self.btn_collect) #fill layout layout.addLayout(hl) layout.addWidget(self.combo_import) layout.addWidget(self.tabs) hl2 = QtGui.QHBoxLayout() hl2.addWidget(self.label_run_on) hl2.addWidget(self.cb_run_on) hl2.addWidget(self.label_refresh) hl2.addWidget(self.sb_refreshrate) hl2.insertStretch(1,0) hl2.insertStretch(2,0) layout.addLayout(hl2) layout.addWidget(self.btn_run_now) self._toggleShow(False) #automation disabled by default
class Automation(QtGui.QWidget): ''' Widget for easy automation within dataArtist, providing: * On/Of switch * 'Collect' button to grab the address of tool buttons and it's parameters * 'Import' list to load saved scripts * Multiple script editors listed as Tabs * 'Run on new input' - Activate active script as soon as the input has changed * 'Run' - run active script now ''' def __init__(self, display, splitter): QtGui.QWidget.__init__(self) self.display = display display.sigLayerChanged.connect(self.toggleDataChanged) display.sigNewLayer.connect(self.toggleNewData) self.splitter = splitter refreshR = 20 self._collect = False self._activeWidgets = [] #BUTTON: OF/OFF self.btn_show = QtGui.QRadioButton('Console') f=self.btn_show.font() f.setBold(True) self.btn_show.setFont(f) self.btn_show.clicked.connect(self._toggleShow) #COMBOBOX: IMPORT self.combo_import = QtGui.QComboBox() self.combo_import.addItems(( '<import>', 'from file')) self.combo_import.addItems( #don't show '.py' and hide __init__.py [x[:-3] for x in SPRIPT_PATH.listdir() if (x[0] != '_' and x.endswith('.py'))]) self.combo_import.currentIndexChanged.connect(self._importScript) #BUTTON: COLLECT self.btn_collect= QtGui.QPushButton('Collect') self.btn_collect.setToolTip('click on all tool parameters you want to change during the batch process') self.btn_collect.setCheckable(True) self.btn_collect.clicked.connect(self.collectWidgets) #TABWIDGET: SCRIPT self.tabs = FwTabWidget() self.tabs.hide() self.tabs.setTabsAddable(True) self.tabs.setTabsClosable(True) self.tabs.setTabsRenamable(True) self.tabs.defaultTabWidget = lambda: ScriptTab(self, refreshR) self.tabs.addEmptyTab('New') #BUTTON: RUN AT NEW INPUT self.label_run_on = QtGui.QLabel('Activate on') self.cb_run_on = QtGui.QComboBox() self.cb_run_on.addItems(['-', 'New Data', 'Data Changed']) #SPINBOX REFRESHRATE self.label_refresh = QtGui.QLabel('Refresh rate:') self.sb_refreshrate = QtGui.QSpinBox() self.sb_refreshrate.setSuffix(" Hz") self.sb_refreshrate.setMinimum(0) self.sb_refreshrate.setMaximum(100) self.sb_refreshrate.setValue(refreshR) self.sb_refreshrate.valueChanged.connect( lambda hz: self.tabs.currentWidget().thread.setRefreshrate(hz)) #BUTTON: RUN self.btn_run_now = QtGui.QPushButton('Run') self.btn_run_now.setCheckable(True) self.btn_run_now.clicked.connect(self.toggle) #LAYOUT layout = QtGui.QVBoxLayout() layout.setAlignment(QtCore.Qt.AlignTop) layout.setMargin(0) self.setLayout(layout) #top layout hl = QtGui.QHBoxLayout() hl.addWidget(self.btn_show) hl.addWidget(self.btn_collect) #fill layout layout.addLayout(hl) layout.addWidget(self.combo_import) layout.addWidget(self.tabs) hl2 = QtGui.QHBoxLayout() hl2.addWidget(self.label_run_on) hl2.addWidget(self.cb_run_on) hl2.addWidget(self.label_refresh) hl2.addWidget(self.sb_refreshrate) hl2.insertStretch(1,0) hl2.insertStretch(2,0) layout.addLayout(hl2) layout.addWidget(self.btn_run_now) self._toggleShow(False) #automation disabled by default def checkWidgetIsActive(self, widget): #bring widget into list of updated widgets #if not there already a = self._activeWidgets if widget not in a: a.append(widget) def saveState(self): state={} #BUTTONS state['active'] = self.btn_show.isChecked() state['collect'] = self.btn_collect.isChecked() #l['runOnNewInput'] = self.btn_run_new.isChecked() state['runOn'] = unicode(self.cb_run_on.currentText()) state['tabTitles'] = [unicode(self.tabs.tabText(tab)) for tab in self.tabs] #SCRIPTS ss = state['scripts'] = [] for tab in self.tabs: ss.append(tab.editor.toPlainText()) # session.addContentToSave(tab.editor.toPlainText(), # *path+('scripts', '%s.txt' %n)) #--> # session.addContentToSave(l, *path+('automation.txt',)) return state def restoreState(self, state): # l = eval(session.getSavedContent(*path +('automation.txt',) ) ) #BUTTONS self.btn_show.setChecked(state['active']) self._toggleShow(state['active']) self.btn_collect.setChecked(state['collect']) #self.btn_run_new.setChecked(l['runOnNewInput']) self.cb_run_on.setCurrentIndex([self.cb_run_on.itemText(i) for i in range(self.cb_run_on.count())].index( state['runOn'])) #SCRIPTS self.tabs.clear() ss = state['scripts'] for n, title in enumerate(state['tabTitles']): tab = self.tabs.addEmptyTab(title) # txt = ss[n]#session.getSavedContent(*path+('scripts', '%s.txt' %n)) tab.editor.setPlainText(ss[n]) def collectWidgets(self): ''' Get a Tool button or a parameter within the tools menu and add it to the active script ''' #TOGGLE BETWEEN NORMAL- AND PointingHandCursor self._collect = not self._collect if self._collect: QtGui.QApplication.setOverrideCursor(QtGui.QCursor( QtCore.Qt.PointingHandCursor)) else: QtGui.QApplication.restoreOverrideCursor() #TOGGLE BUTTON self.btn_collect.setChecked(self._collect) #add chosen widget to active script: fn = lambda widget: self.tabs.currentWidget().addTool(widget) for tool in self.display.widget.tools.itervalues(): #TOOLS: tool.returnToolOnClick(self._collect, fn) #TOOL-PARAMETERS: if isinstance(tool.menu(), ParameterMenu): tool.menu().pTree.returnParameterOnKlick(self._collect, fn) def _importScript(self, index): ''' Open a file, read it's content and add it to the active script tab ''' self.combo_import.setCurrentIndex(0) if index == 0:# '<import>' placeholder within the comboBox return if index == 1: # import from file f = self.display.workspace.gui.dialogs.getOpenFileName() if f is not None and f.isfile(): tab = self.tabs.addEmptyTab('file') with open(f, 'r') as r: tab.editor.appendPlainText(r.read()) else: # import one of the examples scripts tab = self.tabs.addEmptyTab('ex%s' %str(index-1)) tab.editor.appendPlainText( open(SPRIPT_PATH.join( str(self.combo_import.itemText(index)))+'.py','r').read()) def _updateWidget(self): ''' update all active display widgets ''' for widget in self._activeWidgets: try: widget.updateView(force=True) except Exception: traceback.print_exc() def _toggleShow(self, show): ''' Show/hide all widgets within Automation except of the on/off switch And move the horizontal splitter according to the space needed ''' s = self.splitter l = s.sizes() minSize = 7.0 i = s.indexOf(self) if show: self.tabs.show() self.btn_run_now.show() self.btn_collect.show() self.label_run_on.show() self.cb_run_on.show() self.combo_import.show() self.label_refresh.show() self.sb_refreshrate.show() # move splitter: # assume equal sizes for all to calc the splitter size s.setSizes(np.ones(len(l))*np.mean(l)) else: self.tabs.hide() self.btn_run_now.hide() self.btn_collect.hide() self.label_run_on.hide() self.cb_run_on.hide() self.combo_import.hide() self.label_refresh.hide() self.sb_refreshrate.hide() # move splitter: # smallest possible size of batchTab if l: a = (l[i] - minSize) / len(l) for n,y in enumerate(l): if n != i: l[n] = y+a else: l[n] = minSize s.setSizes(l) def _setRunning(self): '''update button''' self.btn_run_now.setChecked(True) self.btn_run_now.setText('Stop') self.display.workspace.gui.undoRedo.is_active = False #TODO: remove try... if .display if not a weakref.proxy any more try: d = self.display.__repr__.__self__ except: d = self.display #SHOW RUN INDICATOR self._runIndicator = CircleWidget(d) self._runIndicator.move(2,2) self._runIndicator.show() def _setDone(self): '''update button''' self.btn_run_now.setChecked(False) self.btn_run_now.setText('Start') self.display.workspace.gui.undoRedo.is_active = True if hasattr(self, '_runIndicator'): self._runIndicator.close() del self._runIndicator def toggle(self): ''' Start/Stop the active script ''' tab = self.tabs.currentWidget() #STOP if self.btn_run_now.text() == 'Stop': tab.thread.kill() return #START self.display.backupChangedLayer(changes='Script <%s>' %self.tabs.tabText(tab)) self._activeWidgets = [self.display.widget] tab.thread.start() def toggleNewData(self): ''' toggle run settings allow running for new data ''' if self.btn_show.isChecked() and self.cb_run_on.currentIndex() == 1:#=new data self.toggle() def toggleDataChanged(self): ''' toggle run settings allow running for data changed ''' if self.btn_show.isChecked() and self.cb_run_on.currentIndex() == 2:#=data changed self.toggle()
class Automation(QtWidgets.QWidget): ''' Widget for easy automation within dataArtist, providing: * On/Of switch * 'Collect' button to grab the address of tool buttons and it's parameters * 'Import' list to load saved scripts * Multiple script editors listed as Tabs * 'Run on new input' - Activate active script as soon as the input has changed * 'Run' - run active script now ''' def __init__(self, display, splitter): QtWidgets.QWidget.__init__(self) self.display = display display.sigLayerChanged.connect(self.toggleDataChanged) display.sigNewLayer.connect(self.toggleNewData) self.setMinimumHeight(30) self.splitter = splitter self._collect = False self._activeWidgets = [] # LAYOUT layout = QtWidgets.QVBoxLayout() layout.setAlignment(QtCore.Qt.AlignTop) # setMargin removed. obsolete, doesn't do anything, not even in PyQt4 self.setLayout(layout) self._hl = QtWidgets.QHBoxLayout() layout.addLayout(self._hl) # BUTTON: show/hide 'Scripts' self.btn_scripts = QtWidgets.QRadioButton('Scripts') f = self.btn_scripts.font() f.setBold(True) self.btn_scripts.setFont(f) self.btn_scripts.clicked.connect(self._uncheckConsole) self.btn_scripts.clicked.connect(self._toggleScriptsFirstTime) self.btn_scripts.clicked.connect(self.updateSize) self._hl.addWidget(self.btn_scripts) # BUTTON: show/hide 'Console' self.btn_console = QtWidgets.QRadioButton('Console') f = self.btn_console.font() f.setBold(True) self.btn_console.setFont(f) self.btn_console.clicked.connect(self._uncheckScripts) self.btn_console.clicked.connect(self._toggleConsoleFirstTime) self.btn_console.clicked.connect(self.updateSize) self._hl.addWidget(self.btn_console) g = QtWidgets.QButtonGroup(self) g.setExclusive(False) g.addButton(self.btn_scripts) g.addButton(self.btn_console) self.splitter.setStretchFactor(0, 0) self.cb_run_on = QtWidgets.QComboBox() self.cb_run_on.addItems(['-', 'New Data', 'Data Changed']) self.tabs = FwTabWidget() self.tabs.hide() self.tabs.setTabsAddable(True) self.tabs.setTabsClosable(True) self.tabs.setTabsRenamable(True) def _uncheckScripts(self, show): if show and self.btn_scripts.isChecked(): self._toggleScripts(False) self.btn_scripts.setChecked(False) def _uncheckConsole(self, show): if show and self.btn_console.isChecked(): self._toggleConsole(False) self.btn_console.setChecked(False) def _toggleConsoleFirstTime(self): txt = '''This is a Python {} console. it accepts ... * all built-in functions, like 'dir' * already imported modules, like 'np', for numpy * special dataArtist functions, like d', d.l, d.l0,... '''.format(platform.python_version()) namespace = _ExecGlobalsDict(self.display) self.console = console.ConsoleWidget(namespace=namespace, text=txt) self.console.ui.exceptionBtn.hide() self.console.input.sigExecuteCmd.connect( self.display.widget.updateView) self.layout().addWidget(self.console) # update connections: self.btn_console.clicked.disconnect(self._toggleConsoleFirstTime) self.btn_console.clicked.connect(self._toggleConsole) def _toggleConsole(self, show): self.console.setVisible(show) def _toggleScriptsFirstTime(self): # build scripts layout refreshR = 20 # COMBOBOX: IMPORT self.combo_import = QtWidgets.QComboBox() self.combo_import.addItems(('<import>', 'from file')) self.combo_import.addItems( # don't show '.py' and hide __init__.py [ x[:-3] for x in SPRIPT_PATH.listdir() if (x[0] != '_' and x.endswith('.py')) ]) self.combo_import.currentIndexChanged.connect(self._importScript) # BUTTON: COLLECT self.btn_collect = QtWidgets.QPushButton('Collect') self.btn_collect.setToolTip( 'click on all tool parameters you want to change during the batch process' ) self.btn_collect.setCheckable(True) self.btn_collect.clicked.connect(self.collectTools) # TABWIDGET: SCRIPT self.tabs.defaultTabWidget = lambda: ScriptTab(self, refreshR) self.tabs.addEmptyTab('New') # BUTTON: RUN AT NEW INPUT self.label_run_on = QtWidgets.QLabel('Activate on') # SPINBOX REFRESHRATE self.label_refresh = QtWidgets.QLabel('Refresh rate:') self.sb_refreshrate = QtWidgets.QSpinBox() self.sb_refreshrate.setSuffix(" Hz") self.sb_refreshrate.setMinimum(0) self.sb_refreshrate.setMaximum(100) self.sb_refreshrate.setValue(refreshR) self.sb_refreshrate.valueChanged.connect( lambda hz: self.tabs.currentWidget().thread.setRefreshrate(hz)) # BUTTON: RUN self.btn_run_now = QtWidgets.QPushButton('Run') self.btn_run_now.setCheckable(True) self.btn_run_now.clicked.connect(self.toggle) self._hl.addWidget(self.btn_collect) l = self.layout() l.addWidget(self.combo_import) l.addWidget(self.tabs) self.tabs.show() hl2 = QtWidgets.QHBoxLayout() hl2.addWidget(self.label_run_on) hl2.addWidget(self.cb_run_on) hl2.addWidget(self.label_refresh) hl2.addWidget(self.sb_refreshrate) hl2.insertStretch(1, 0) hl2.insertStretch(2, 0) l.addLayout(hl2) l.addWidget(self.btn_run_now) # update connections: self.btn_scripts.clicked.disconnect(self._toggleScriptsFirstTime) self.btn_scripts.clicked.connect(self._toggleScripts) def checkWidgetIsActive(self, widget): # bring widget into list of updated widgets # if not there already a = self._activeWidgets if widget not in a: a.append(widget) def saveState(self): state = { 'scriptOn': self.btn_scripts.isChecked(), 'consoleOn': self.btn_console.isChecked(), 'runOn': str(self.cb_run_on.currentText()), 'tabTitles': [str(self.tabs.tabText(tab)) for tab in self.tabs], 'curTab': self.tabs.currentIndex() } # SCRIPTS ss = state['scripts'] = [] for tab in self.tabs: ss.append(tab.editor.toPlainText()) return state def restoreState(self, state): # BUTTONS self.btn_scripts.setChecked(state['scriptOn']) # self._toggleScripts(state['active']) self.btn_console.setChecked(state['consoleOn']) # self.btn_run_new.setChecked(l['runOnNewInput']) self.cb_run_on.setCurrentIndex([ self.cb_run_on.itemText(i) for i in range(self.cb_run_on.count()) ].index(state['runOn'])) # SCRIPTS ss = state['scripts'] if ss and not hasattr(self, 'combo_import'): self._toggleScriptsFirstTime() self.tabs.clear() for n, title in enumerate(state['tabTitles']): tab = self.tabs.addEmptyTab(title) tab.editor.setPlainText(ss[n]) self.tabs.setCurrentIndex(state['curTab']) def collectTools(self): ''' Get a Tool button or a parameter within the tools menu and add it to the active script ''' # TOGGLE BETWEEN NORMAL- AND PointingHandCursor self._collect = not self._collect if self._collect: QtWidgets.QApplication.setOverrideCursor( QtGui.QCursor(QtCore.Qt.PointingHandCursor)) else: QtWidgets.QApplication.restoreOverrideCursor() # TOGGLE BUTTON self.btn_collect.setChecked(self._collect) # add chosen widget to active script: def fn(tool): return self.tabs.currentWidget().addTool(tool) for tool in self.display.widget.tools.values(): # TOOLS: tool.returnToolOnClick(self._collect, fn) # TOOL-PARAMETERS: if isinstance(tool.menu(), ParameterMenu): tool.menu().pTree.returnParameterOnClick(self._collect, fn) def _importScript(self, index): ''' Open a file, read it's content and add it to the active script tab ''' self.combo_import.setCurrentIndex(0) if index == 0: # '<import>' placeholder within the comboBox return if index == 1: # import from file f = self.display.workspace.gui.dialogs.getOpenFileName() if f is not None and f.isfile(): tab = self.tabs.addEmptyTab('file') with open(f, 'r') as r: tab.editor.appendPlainText(r.read()) else: # import one of the examples scripts tab = self.tabs.addEmptyTab('ex%s' % str(index - 1)) tab.editor.appendPlainText( open( SPRIPT_PATH.join(str(self.combo_import.itemText(index))) + '.py', 'r').read()) def _updateWidget(self): ''' update all active display widgets ''' for widget in self._activeWidgets: try: widget.updateView(force=True) except Exception: traceback.print_exc() def minimumHeight(self): return QtWidgets.QWidget.minimumHeight(self) + 10 def updateSize(self): s = self.splitter l = s.sizes() if self.btn_scripts.isChecked() or self.btn_console.isChecked(): # resize to 50% s.setSizes(np.ones(len(l)) * np.mean(l)) self.splitter.setStretchFactor(0, 1) else: minSize = self.minimumHeight() l[1] = max(0, np.sum(l) - minSize) l[0] = minSize s.setSizes(l) self.splitter.setStretchFactor(0, 0) def _toggleScripts(self, show): ''' Show/hide all widgets within Automation except of the on/off switch And move the horizontal splitter according to the space needed ''' if show: self.tabs.show() self.btn_run_now.show() self.btn_collect.show() self.label_run_on.show() self.cb_run_on.show() self.combo_import.show() self.label_refresh.show() self.sb_refreshrate.show() else: self.tabs.hide() self.btn_run_now.hide() self.btn_collect.hide() self.label_run_on.hide() self.cb_run_on.hide() self.combo_import.hide() self.label_refresh.hide() self.sb_refreshrate.hide() def _setRunning(self): '''update button''' self.btn_run_now.setChecked(True) self.btn_run_now.setText('Stop') self.display.workspace.gui.undoRedo.is_active = False # TODO: remove try... if .display if not a weakref.proxy any more try: d = self.display.__repr__.__self__ except: d = self.display # SHOW RUN INDICATOR self._runIndicator = CircleWidget(d) self._runIndicator.move(2, 2) self._runIndicator.show() def _setDone(self): '''update button''' self.btn_run_now.setChecked(False) self.btn_run_now.setText('Start') self.display.workspace.gui.undoRedo.is_active = True if hasattr(self, '_runIndicator'): self._runIndicator.close() del self._runIndicator def toggle(self): ''' Start/Stop the active script ''' tab = self.tabs.currentWidget() # STOP if self.btn_run_now.text() == 'Stop': tab.thread.kill() return # START self.display.backupChangedLayer(changes='Script <%s>' % self.tabs.tabText(tab)) self._activeWidgets = [self.display.widget] tab.thread.start() def toggleNewData(self): ''' toggle run settings allow running for new data ''' if self.btn_scripts.isChecked() and self.cb_run_on.currentIndex() == 1: self.toggle() def toggleDataChanged(self): ''' toggle run settings allow running for data changed ''' if self.btn_scripts.isChecked() and self.cb_run_on.currentIndex() == 2: self.toggle()
def createWidget(self, parent): return FwTabWidget(parent)
def __init__(self): FwTabWidget.__init__(self) self.setMovable(True) self.setSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding) self.hide()
def __init__(self, display, splitter): QtGui.QWidget.__init__(self) self.display = display display.sigLayerChanged.connect(self.toggleDataChanged) display.sigNewLayer.connect(self.toggleNewData) self.splitter = splitter refreshR = 20 self._collect = False self._activeWidgets = [] #BUTTON: OF/OFF self.btn_show = QtGui.QRadioButton('Console') f = self.btn_show.font() f.setBold(True) self.btn_show.setFont(f) self.btn_show.clicked.connect(self._toggleShow) #COMBOBOX: IMPORT self.combo_import = QtGui.QComboBox() self.combo_import.addItems(('<import>', 'from file')) self.combo_import.addItems( #don't show '.py' and hide __init__.py [ x[:-3] for x in SPRIPT_PATH.listdir() if (x[0] != '_' and x.endswith('.py')) ]) self.combo_import.currentIndexChanged.connect(self._importScript) #BUTTON: COLLECT self.btn_collect = QtGui.QPushButton('Collect') self.btn_collect.setToolTip( 'click on all tool parameters you want to change during the batch process' ) self.btn_collect.setCheckable(True) self.btn_collect.clicked.connect(self.collectWidgets) #TABWIDGET: SCRIPT self.tabs = FwTabWidget() self.tabs.hide() self.tabs.setTabsAddable(True) self.tabs.setTabsClosable(True) self.tabs.setTabsRenamable(True) self.tabs.defaultTabWidget = lambda: ScriptTab(self, refreshR) self.tabs.addEmptyTab('New') #BUTTON: RUN AT NEW INPUT self.label_run_on = QtGui.QLabel('Activate on') self.cb_run_on = QtGui.QComboBox() self.cb_run_on.addItems(['-', 'New Data', 'Data Changed']) #SPINBOX REFRESHRATE self.label_refresh = QtGui.QLabel('Refresh rate:') self.sb_refreshrate = QtGui.QSpinBox() self.sb_refreshrate.setSuffix(" Hz") self.sb_refreshrate.setMinimum(0) self.sb_refreshrate.setMaximum(100) self.sb_refreshrate.setValue(refreshR) self.sb_refreshrate.valueChanged.connect( lambda hz: self.tabs.currentWidget().thread.setRefreshrate(hz)) #BUTTON: RUN self.btn_run_now = QtGui.QPushButton('Run') self.btn_run_now.setCheckable(True) self.btn_run_now.clicked.connect(self.toggle) #LAYOUT layout = QtGui.QVBoxLayout() layout.setAlignment(QtCore.Qt.AlignTop) layout.setMargin(0) self.setLayout(layout) #top layout hl = QtGui.QHBoxLayout() hl.addWidget(self.btn_show) hl.addWidget(self.btn_collect) #fill layout layout.addLayout(hl) layout.addWidget(self.combo_import) layout.addWidget(self.tabs) hl2 = QtGui.QHBoxLayout() hl2.addWidget(self.label_run_on) hl2.addWidget(self.cb_run_on) hl2.addWidget(self.label_refresh) hl2.addWidget(self.sb_refreshrate) hl2.insertStretch(1, 0) hl2.insertStretch(2, 0) layout.addLayout(hl2) layout.addWidget(self.btn_run_now) self._toggleShow(False) #automation disabled by default
class Automation(QtGui.QWidget): ''' Widget for easy automation within dataArtist, providing: * On/Of switch * 'Collect' button to grab the address of tool buttons and it's parameters * 'Import' list to load saved scripts * Multiple script editors listed as Tabs * 'Run on new input' - Activate active script as soon as the input has changed * 'Run' - run active script now ''' def __init__(self, display, splitter): QtGui.QWidget.__init__(self) self.display = display display.sigLayerChanged.connect(self.toggleDataChanged) display.sigNewLayer.connect(self.toggleNewData) self.splitter = splitter refreshR = 20 self._collect = False self._activeWidgets = [] #BUTTON: OF/OFF self.btn_show = QtGui.QRadioButton('Console') f = self.btn_show.font() f.setBold(True) self.btn_show.setFont(f) self.btn_show.clicked.connect(self._toggleShow) #COMBOBOX: IMPORT self.combo_import = QtGui.QComboBox() self.combo_import.addItems(('<import>', 'from file')) self.combo_import.addItems( #don't show '.py' and hide __init__.py [ x[:-3] for x in SPRIPT_PATH.listdir() if (x[0] != '_' and x.endswith('.py')) ]) self.combo_import.currentIndexChanged.connect(self._importScript) #BUTTON: COLLECT self.btn_collect = QtGui.QPushButton('Collect') self.btn_collect.setToolTip( 'click on all tool parameters you want to change during the batch process' ) self.btn_collect.setCheckable(True) self.btn_collect.clicked.connect(self.collectWidgets) #TABWIDGET: SCRIPT self.tabs = FwTabWidget() self.tabs.hide() self.tabs.setTabsAddable(True) self.tabs.setTabsClosable(True) self.tabs.setTabsRenamable(True) self.tabs.defaultTabWidget = lambda: ScriptTab(self, refreshR) self.tabs.addEmptyTab('New') #BUTTON: RUN AT NEW INPUT self.label_run_on = QtGui.QLabel('Activate on') self.cb_run_on = QtGui.QComboBox() self.cb_run_on.addItems(['-', 'New Data', 'Data Changed']) #SPINBOX REFRESHRATE self.label_refresh = QtGui.QLabel('Refresh rate:') self.sb_refreshrate = QtGui.QSpinBox() self.sb_refreshrate.setSuffix(" Hz") self.sb_refreshrate.setMinimum(0) self.sb_refreshrate.setMaximum(100) self.sb_refreshrate.setValue(refreshR) self.sb_refreshrate.valueChanged.connect( lambda hz: self.tabs.currentWidget().thread.setRefreshrate(hz)) #BUTTON: RUN self.btn_run_now = QtGui.QPushButton('Run') self.btn_run_now.setCheckable(True) self.btn_run_now.clicked.connect(self.toggle) #LAYOUT layout = QtGui.QVBoxLayout() layout.setAlignment(QtCore.Qt.AlignTop) layout.setMargin(0) self.setLayout(layout) #top layout hl = QtGui.QHBoxLayout() hl.addWidget(self.btn_show) hl.addWidget(self.btn_collect) #fill layout layout.addLayout(hl) layout.addWidget(self.combo_import) layout.addWidget(self.tabs) hl2 = QtGui.QHBoxLayout() hl2.addWidget(self.label_run_on) hl2.addWidget(self.cb_run_on) hl2.addWidget(self.label_refresh) hl2.addWidget(self.sb_refreshrate) hl2.insertStretch(1, 0) hl2.insertStretch(2, 0) layout.addLayout(hl2) layout.addWidget(self.btn_run_now) self._toggleShow(False) #automation disabled by default def checkWidgetIsActive(self, widget): #bring widget into list of updated widgets #if not there already a = self._activeWidgets if widget not in a: a.append(widget) def saveState(self): state = {} #BUTTONS state['active'] = self.btn_show.isChecked() state['collect'] = self.btn_collect.isChecked() #l['runOnNewInput'] = self.btn_run_new.isChecked() state['runOn'] = unicode(self.cb_run_on.currentText()) state['tabTitles'] = [ unicode(self.tabs.tabText(tab)) for tab in self.tabs ] #SCRIPTS ss = state['scripts'] = [] for tab in self.tabs: ss.append(tab.editor.toPlainText()) # session.addContentToSave(tab.editor.toPlainText(), # *path+('scripts', '%s.txt' %n)) #--> # session.addContentToSave(l, *path+('automation.txt',)) return state def restoreState(self, state): # l = eval(session.getSavedContent(*path +('automation.txt',) ) ) #BUTTONS self.btn_show.setChecked(state['active']) self._toggleShow(state['active']) self.btn_collect.setChecked(state['collect']) #self.btn_run_new.setChecked(l['runOnNewInput']) self.cb_run_on.setCurrentIndex([ self.cb_run_on.itemText(i) for i in range(self.cb_run_on.count()) ].index(state['runOn'])) #SCRIPTS self.tabs.clear() ss = state['scripts'] for n, title in enumerate(state['tabTitles']): tab = self.tabs.addEmptyTab(title) # txt = ss[n]#session.getSavedContent(*path+('scripts', '%s.txt' %n)) tab.editor.setPlainText(ss[n]) def collectWidgets(self): ''' Get a Tool button or a parameter within the tools menu and add it to the active script ''' #TOGGLE BETWEEN NORMAL- AND PointingHandCursor self._collect = not self._collect if self._collect: QtGui.QApplication.setOverrideCursor( QtGui.QCursor(QtCore.Qt.PointingHandCursor)) else: QtGui.QApplication.restoreOverrideCursor() #TOGGLE BUTTON self.btn_collect.setChecked(self._collect) #add chosen widget to active script: fn = lambda widget: self.tabs.currentWidget().addTool(widget) for tool in self.display.widget.tools.itervalues(): #TOOLS: tool.returnToolOnClick(self._collect, fn) #TOOL-PARAMETERS: if isinstance(tool.menu(), ParameterMenu): tool.menu().pTree.returnParameterOnKlick(self._collect, fn) def _importScript(self, index): ''' Open a file, read it's content and add it to the active script tab ''' self.combo_import.setCurrentIndex(0) if index == 0: # '<import>' placeholder within the comboBox return if index == 1: # import from file f = self.display.workspace.gui.dialogs.getOpenFileName() if f is not None and f.isfile(): tab = self.tabs.addEmptyTab('file') with open(f, 'r') as r: tab.editor.appendPlainText(r.read()) else: # import one of the examples scripts tab = self.tabs.addEmptyTab('ex%s' % str(index - 1)) tab.editor.appendPlainText( open( SPRIPT_PATH.join(str(self.combo_import.itemText(index))) + '.py', 'r').read()) def _updateWidget(self): ''' update all active display widgets ''' for widget in self._activeWidgets: try: widget.updateView(force=True) except Exception: traceback.print_exc() def _toggleShow(self, show): ''' Show/hide all widgets within Automation except of the on/off switch And move the horizontal splitter according to the space needed ''' s = self.splitter l = s.sizes() minSize = 7.0 i = s.indexOf(self) if show: self.tabs.show() self.btn_run_now.show() self.btn_collect.show() self.label_run_on.show() self.cb_run_on.show() self.combo_import.show() self.label_refresh.show() self.sb_refreshrate.show() # move splitter: # assume equal sizes for all to calc the splitter size s.setSizes(np.ones(len(l)) * np.mean(l)) else: self.tabs.hide() self.btn_run_now.hide() self.btn_collect.hide() self.label_run_on.hide() self.cb_run_on.hide() self.combo_import.hide() self.label_refresh.hide() self.sb_refreshrate.hide() # move splitter: # smallest possible size of batchTab if l: a = (l[i] - minSize) / len(l) for n, y in enumerate(l): if n != i: l[n] = y + a else: l[n] = minSize s.setSizes(l) def _setRunning(self): '''update button''' self.btn_run_now.setChecked(True) self.btn_run_now.setText('Stop') self.display.workspace.gui.undoRedo.is_active = False #TODO: remove try... if .display if not a weakref.proxy any more try: d = self.display.__repr__.__self__ except: d = self.display #SHOW RUN INDICATOR self._runIndicator = CircleWidget(d) self._runIndicator.move(2, 2) self._runIndicator.show() def _setDone(self): '''update button''' self.btn_run_now.setChecked(False) self.btn_run_now.setText('Start') self.display.workspace.gui.undoRedo.is_active = True if hasattr(self, '_runIndicator'): self._runIndicator.close() del self._runIndicator def toggle(self): ''' Start/Stop the active script ''' tab = self.tabs.currentWidget() #STOP if self.btn_run_now.text() == 'Stop': tab.thread.kill() return #START self.display.backupChangedLayer(changes='Script <%s>' % self.tabs.tabText(tab)) self._activeWidgets = [self.display.widget] tab.thread.start() def toggleNewData(self): ''' toggle run settings allow running for new data ''' if self.btn_show.isChecked() and self.cb_run_on.currentIndex( ) == 1: #=new data self.toggle() def toggleDataChanged(self): ''' toggle run settings allow running for data changed ''' if self.btn_show.isChecked() and self.cb_run_on.currentIndex( ) == 2: #=data changed self.toggle()