def overlayIndex(self): """ :rtype: int """ return gSettings.value('overlayIndex', 0)
def overlayColor(self): """ :rtype: QColor """ return QColor( gSettings.value('overlayColor', qRgba(255, 255, 255, 255)))
def muteState(): return gSettings.value('mute', 'False') == 'True'
def __init__(self, timer=None, parent=None): super(CurveEditor, self).__init__(parent) self.setWindowTitle('CurveEditor') self.setObjectName('CurveEditor') self.__model = QStandardItemModel() self.__shot = None self.__timer = timer tools = hlayout(spacing=4.0) add = QPushButton(icons.get('Add Node'), '') add.setToolTip('Add channels') add.setStatusTip('Add channels') add.setIconSize(QSize(24, 24)) add.clicked.connect(self._onAddChannel) tools.addWidget(add) delete = QPushButton(icons.get('Delete Node'), '') delete.setToolTip('Delete channels') delete.setStatusTip('Delete channels') delete.setIconSize(QSize(24, 24)) delete.clicked.connect(self._onDeleteChannel) tools.addWidget(delete) # input fields to move keys around with exact numbers self.__relative = CheckBox() tools.addWidget(QLabel('Relative:')) tools.addWidget(self.__relative) self.__relative.setValue( (Qt.Unchecked, Qt.Checked, Qt.Checked)[int(gSettings.value('RelativeKeyInput', 0))]) self.__relative.valueChanged.connect( functools.partial(gSettings.setValue, 'RelativeKeyInput')) self.__time = DoubleSpinBox() self.__time.setDecimals(4) tools.addWidget(QLabel('Time:')) tools.addWidget(self.__time) self.__time.setEnabled(False) self.__time.setFixedWidth(70) self.__time.editingFinished.connect(self.__onShiftSelectedKeyTimes) self.__value = DoubleSpinBox() self.__value.setDecimals(4) tools.addWidget(QLabel('Value:')) tools.addWidget(self.__value) self.__value.setEnabled(False) self.__value.setFixedWidth(70) self.__value.editingFinished.connect(self.__onShiftSelectedKeyValues) # when editing keys with the input fields I'm storing the initial reference poitn so all changes may be relative self.__unshiftedKeyValue = [0.0, 0.0] self.__snapping = EnumBox( ['1/1', '1/2', '1/4', '1/8', '1/16', '1/32', '1/64']) tools.addWidget(QLabel('Beat snap:')) tools.addWidget(self.__snapping) self.__snapping.setValue(int(gSettings.value('KeySnapSetting', 3))) self.__snapping.valueChanged.connect( functools.partial(gSettings.setValue, 'KeySnapSetting')) self.__snapping.valueChanged.connect(self.__updateSnapping) self.__tangentMode = TangentMode() tools.addWidget(self.__tangentMode) self.__tangentMode.valueChanged.connect(self.__setSelectedKeyTangents) # self.__tangentMode.tangentBrokenChanged.connect(self.__toggleBreakSelectedKeyTangents) positionKey = QPushButton(icons.get('Move'), '', self) positionKey.setToolTip('Key camera position into selection') positionKey.setStatusTip('Key camera position into selection') positionKey.setShortcut(QKeySequence(Qt.SHIFT + Qt.Key_I)) tools.addWidget(positionKey) self.requestPositionKey = positionKey.clicked rotationKey = QPushButton(icons.get('3D Rotate'), '', self) rotationKey.setToolTip('Key camera rotation into selection') rotationKey.setStatusTip('Key camera rotation into selection') rotationKey.setShortcut(QKeySequence(Qt.SHIFT + Qt.Key_O)) tools.addWidget(rotationKey) self.requestRotationKey = rotationKey.clicked dupe = QPushButton(icons.get('Duplicate-Keys-24'), '') dupe.setToolTip('Duplicate selected keys') dupe.setStatusTip('Duplicate selected keys') dupe.setIconSize(QSize(24, 24)) dupe.clicked.connect(self.__onDuplicateSelectedKeys) tools.addWidget(dupe) tools.addStretch(1) self.__channels = QListView() self.__channels.setSelectionMode(QAbstractItemView.ExtendedSelection) self.__channels.setModel(self.__model) # can't rename channels self.__channels.setEditTriggers(QAbstractItemView.NoEditTriggers) self.__view = CurveView(timer, self) self.__view.setModel(self.__model, self.__channels.selectionModel()) self.__time.editingFinished.connect(self.__view.repaint) self.__value.editingFinished.connect(self.__view.repaint) self.__updateSnapping(self.__snapping.value()) def forwardFocus(event): self.__view.setFocus(Qt.MouseFocusReason) self.__channels.focusInEvent = forwardFocus self.__channels.selectionModel().selectionChanged.connect( self.__view.onChannelsChanged) self.__view.selectionChanged.connect(self.__onUpdateKeyEditor) widget = QSplitterState('CurveEditor/Channels', Qt.Horizontal) widget.addWidget(self.__channels) widget.addWidget(self.__view) widget.setStretchFactor(1, 1) widget.addWidget(self.__view.createUndoView()) widget.addWidget(self.__view.createCameraUndoView()) widget.setSizes([128, 128, 0, 0]) layout = vlayout() self.setLayout(layout) layout.addLayout(tools) layout.addWidget(widget) layout.setStretch(1, 1) self.setEnabled(False) self.__channels.setContextMenuPolicy(Qt.CustomContextMenu) self.__channels.customContextMenuRequested.connect( self.__channelContextMenu) self.__channelMenu = QMenu() self.__copyAction = self.__channelMenu.addAction( 'Copy selected channel(s)') self.__copyAction.triggered.connect(self.__copySelectedChannels) self.__pasteAction = self.__channelMenu.addAction('Paste channels') self.__pasteAction.triggered.connect(self.__pasteChannels) self.__pasteOverAction = self.__channelMenu.addAction( 'Paste into selected channel') self.__pasteOverAction.triggered.connect(self.__pasteSelectedChannel) self.__clipboard = []
def __init__(self): super(App, self).__init__(gSettings) self.setAnimated(False) month, day, year = time.strftime('%x').split('/') if month == '12': self.setWindowIcon(icons.get('Candy Cane')) else: self.setWindowIcon(icons.get('SqrMelon')) self.setWindowTitle('SqrMelon') self.setDockNestingEnabled(True) self.__menuBar = QMenuBar() self.setMenuBar(self.__menuBar) self.__dockWidgetMenu = QMenu('Components') self.__statusBar = QStatusBar() self.setStatusBar(self.__statusBar) self._timer = Timer() self.__shotsManager = ShotManager() self.__shotsManager.viewShotAction.connect(self.__onViewShot) self.__graphEditor = CurveEditor(self._timer) self.__shotsManager.currentChanged.connect(self.__graphEditor.setShot) self.__overlays = Overlays() self.__sceneView = SceneView(self.__shotsManager, self._timer, self.__overlays) self.__overlays.changed.connect(self.__sceneView.repaint) self._timer.timeChanged.connect(self.__setCurrentShot) self.__shotsManager.shotPinned.connect(self.__setCurrentShot) self.__shotsManager.shotsEnabled.connect(self.__setCurrentShot) self.__shotsManager.shotsDisabled.connect(self.__setCurrentShot) self.setCentralWidget(None) cameraView = Camera(self.__shotsManager, self.__graphEditor, self._timer) cameraView.cameraChanged.connect(self.__sceneView.repaint) self.__graphEditor.requestPositionKey.connect(cameraView.forwardPositionKey) self.__graphEditor.requestRotationKey.connect(cameraView.forwardRotationKey) self.__sceneView.setCamera(cameraView) self.__projectMenu = self.__menuBar.addMenu('&Project') self.__projectMenu.addAction('&New').triggered.connect(self.__onNewProject) self.__projectMenu.addAction('&Open').triggered.connect(self.__onOpenProject) save = self.__projectMenu.addAction('&Save') save.setShortcut(QKeySequence.Save) save.setShortcutContext(Qt.ApplicationShortcut) save.triggered.connect(self.__onCtrlS) self.__sceneList = SceneList() self.__shotsManager.findSceneRequest.connect(self.__sceneList.selectSceneWithName) self.__sceneList.requestCreateShot.connect(self.__shotsManager.createShot) self.__sceneList.setEnabled(False) self.__sceneList.setShotsManager(self.__shotsManager) self.__profiler = Profiler() self.timeSlider = TimeSlider(self._timer, self.__shotsManager) self.__shotsManager.shotChanged.connect(self.timeSlider.repaint) self._addDockWidget(self.__sceneList, where=Qt.TopDockWidgetArea) self._addDockWidget(self.__shotsManager, where=Qt.TopDockWidgetArea) viewDock = self._addDockWidget(self.__sceneView, '3D View', where=Qt.TopDockWidgetArea) logDock = self._addDockWidget(PyDebugLog.create(), 'Python log', where=Qt.TopDockWidgetArea) self.tabifyDockWidget(logDock, viewDock) self._addDockWidget(self.timeSlider, where=Qt.LeftDockWidgetArea) cameraDock = self._addDockWidget(cameraView, where=Qt.LeftDockWidgetArea) overlayDock = self._addDockWidget(self.__overlays, 'Overlays', Qt.LeftDockWidgetArea) self.tabifyDockWidget(overlayDock, cameraDock) self._addDockWidget(self.__graphEditor, where=Qt.BottomDockWidgetArea) self._addDockWidget(self.__profiler, where=Qt.BottomDockWidgetArea, direction=Qt.Vertical) self.__initializeProject() undoStack, cameraUndoStack = self.__graphEditor.undoStacks() undo = undoStack.createUndoAction(self, '&Undo') undo.setShortcut(QKeySequence.Undo) undo.setShortcutContext(Qt.ApplicationShortcut) redo = undoStack.createRedoAction(self, '&Redo') redo.setShortcuts(QKeySequence.Redo) redo.setShortcutContext(Qt.ApplicationShortcut) camUndo = cameraUndoStack.createUndoAction(self, 'Undo') camUndo.setShortcuts(QKeySequence('[')) camUndo.setShortcutContext(Qt.ApplicationShortcut) camRedo = cameraUndoStack.createRedoAction(self, 'Redo') camRedo.setShortcuts(QKeySequence(']')) camRedo.setShortcutContext(Qt.ApplicationShortcut) camKey = QAction('&Key camera', self) camKey.setShortcuts(QKeySequence(Qt.Key_K)) camKey.setShortcutContext(Qt.ApplicationShortcut) camKey.triggered.connect(cameraView.insertKey) camToggle = QAction('&Toggle camera control', self) camToggle.setShortcuts(QKeySequence(Qt.Key_T)) camToggle.setShortcutContext(Qt.ApplicationShortcut) camToggle.triggered.connect(cameraView.toggle) camCopAnim = QAction('Snap came&ra to animation', self) camCopAnim.setShortcuts(QKeySequence(Qt.Key_R)) camCopAnim.setShortcutContext(Qt.ApplicationShortcut) camCopAnim.triggered.connect(cameraView.copyAnim) self.__editMenu = self.__menuBar.addMenu('Edit') self.__editMenu.addAction(undo) self.__editMenu.addAction(redo) self.__editMenu.addAction(camUndo) self.__editMenu.addAction(camRedo) self.__editMenu.addSeparator() self.__editMenu.addAction(camKey) self.__editMenu.addAction(camToggle) self.__editMenu.addAction(camCopAnim) toolsMenu = self.__menuBar.addMenu('Tools') toolsMenu.addAction('Color Picker').triggered.connect(self.__colorPicker) lock = toolsMenu.addAction('Lock UI') lock.setCheckable(True) lock.toggled.connect(self.__toggleUILock) fs = toolsMenu.addAction('Full screen viewport') fs.setShortcut(Qt.Key_F11) fs.setShortcutContext(Qt.ApplicationShortcut) fs.triggered.connect(self.__fullScreenViewport) self.__previewMenu = toolsMenu.addMenu('Preview resolution') previewRadioGroup = QActionGroup(self) # add action & connect it to the setPreviewRes with right parameters hd = self.__previewMenu.addAction('1070p (HD)') hd.triggered.connect(functools.partial(self.__sceneView.setPreviewRes, 1920, 1080, 1.0)) hd.setCheckable(True) hd.setActionGroup(previewRadioGroup) hdready = self.__previewMenu.addAction('720p') hdready.triggered.connect(functools.partial(self.__sceneView.setPreviewRes, 1280, 720, 1.0)) hdready.setCheckable(True) hdready.setActionGroup(previewRadioGroup) sdready = self.__previewMenu.addAction('480p') sdready.triggered.connect(functools.partial(self.__sceneView.setPreviewRes, 854, 480, 1.0)) sdready.setCheckable(True) sdready.setActionGroup(previewRadioGroup) viewport = self.__previewMenu.addAction('Viewport') viewport.triggered.connect(functools.partial(self.__sceneView.setPreviewRes, None, None, 1.0)) viewport.setCheckable(True) viewport.setActionGroup(previewRadioGroup) half = self.__previewMenu.addAction('1/2 view') half.triggered.connect(functools.partial(self.__sceneView.setPreviewRes, None, None, 0.5)) half.setCheckable(True) half.setActionGroup(previewRadioGroup) quart = self.__previewMenu.addAction('1/4 view') quart.triggered.connect(functools.partial(self.__sceneView.setPreviewRes, None, None, 0.25)) quart.setCheckable(True) quart.setActionGroup(previewRadioGroup) eight = self.__previewMenu.addAction('1/8 view') eight.triggered.connect(functools.partial(self.__sceneView.setPreviewRes, None, None, 0.125)) eight.setCheckable(True) eight.setActionGroup(previewRadioGroup) toolsMenu.addAction('Record').triggered.connect(self.__record) option = viewport if gSettings.contains('GLViewScale'): option = {1.0: viewport, 0.5: half, 0.25: quart, 0.125: eight}[float(gSettings.value('GLViewScale'))] option.setChecked(True) self.__menuBar.addMenu(self.__dockWidgetMenu) self.__menuBar.addAction('About').triggered.connect(self.__aboutDialog) self.__restoreUiLock(lock)
def __restoreUiLock(self, action): state = True if gSettings.value('lockui', '0') == '1' else False action.setChecked(state) features = QDockWidget.NoDockWidgetFeatures if state else QDockWidget.AllDockWidgetFeatures for dockWidget in self.findChildren(QDockWidget): dockWidget.setFeatures(features)
def __record(self): diag = QDialog() fId = gSettings.value('RecordFPS', 2) rId = gSettings.value('RecordResolution', 3) layout = QGridLayout() diag.setLayout(layout) layout.addWidget(QLabel('FPS: '), 0, 0) fps = QComboBox() fps.addItems(['12', '24', '30', '48', '60', '120']) fps.setCurrentIndex(fId) layout.addWidget(fps, 0, 1) layout.addWidget(QLabel('Vertical resolution: '), 1, 0) resolution = QComboBox() resolution.addItems(['144', '288', '360', '720', '1080', '2160']) resolution.setCurrentIndex(rId) layout.addWidget(resolution, 1, 1) ok = QPushButton('Ok') ok.clicked.connect(diag.accept) cancel = QPushButton('Cancel') cancel.clicked.connect(diag.reject) layout.addWidget(ok, 2, 0) layout.addWidget(cancel, 2, 1) diag.exec_() if diag.result() != QDialog.Accepted: return gSettings.setValue('RecordFPS', fps.currentIndex()) gSettings.setValue('RecordResolution', resolution.currentIndex()) FPS = int(fps.currentText()) HEIGHT = int(resolution.currentText()) WIDTH = (HEIGHT * 16) / 9 data = (ctypes.c_ubyte * (WIDTH * HEIGHT * 3))() # alloc buffer once flooredStart = self._timer.secondsToBeats(int(self._timer.beatsToSeconds(self._timer.start) * FPS) / float(FPS)) duration = self._timer.beatsToSeconds(self._timer.end - flooredStart) if not fileutil.exists('capture'): os.makedirs('capture') progress = QProgressDialog(self) progress.setMaximum(int(duration * FPS)) prevFrame = 0 for frame in xrange(int(duration * FPS)): deltaTime = (frame - prevFrame) / float(FPS) prevFrame = frame progress.setValue(frame) QApplication.processEvents() if progress.wasCanceled(): break beats = flooredStart + self._timer.secondsToBeats(frame / float(FPS)) shot = self.__shotsManager.shotAtTime(beats) if shot is None: continue sceneFile = os.path.join(ScenesPath(), shot.sceneName + SCENE_EXT) scene = Scene.getScene(sceneFile) scene.setSize(WIDTH, HEIGHT) uniforms = self.__shotsManager.evaluate(beats) textureUniforms = self.__shotsManager.additionalTextures(beats) self.__sceneView._cameraInput.setData(*(uniforms['uOrigin'] + uniforms['uAngles'])) # feed animation into camera so animationprocessor can read it again cameraData = self.__sceneView._cameraInput.data() modifier = os.path.join(ProjectDir(), 'animationprocessor.py') if fileutil.exists(modifier): execfile(modifier, globals(), locals()) for name in self.__sceneView._textures: uniforms[name] = self.__sceneView._textures[name]._id scene.drawToScreen(self._timer.beatsToSeconds(beats), beats, uniforms, (0, 0, WIDTH, HEIGHT), textureUniforms) scene.colorBuffers[-1][0].use() from OpenGL.GL import glGetTexImage, GL_TEXTURE_2D, GL_RGB, GL_UNSIGNED_BYTE glGetTexImage(GL_TEXTURE_2D, 0, GL_RGB, GL_UNSIGNED_BYTE, data) QImage(data, WIDTH, HEIGHT, QImage.Format_RGB888).mirrored(False, True).save('capture/dump_%s_%05d.jpg' % (FPS, int(self._timer.beatsToSeconds(self._timer.start) * FPS) + frame)) progress.close() if not fileutil.exists('convertcapture'): os.makedirs('convertcapture') with fileutil.edit('convertcapture/convert.bat') as fh: start = '' start2 = '' if int(self._timer.start * FPS) > 0: start = '-start_number {} '.format(int(self._timer.beatsToSeconds(self._timer.start) * FPS)) start2 = '-vframes {} '.format(int(self._timer.beatsToSeconds(self._timer.start) * FPS)) fh.write('cd "../capture"\n"../convertcapture/ffmpeg.exe" -framerate {} {}-i dump_{}_%%05d.jpg {}-c:v libx264 -r {} -pix_fmt yuv420p "../convertcapture/output.mp4"'.format(FPS, start, FPS, start2, FPS)) with fileutil.edit('convertcapture/convertGif.bat') as fh: start = '' start2 = '' if int(self._timer.start * FPS) > 0: start = '-start_number {} '.format(int(self._timer.beatsToSeconds(self._timer.start) * FPS)) start2 = '-vframes {} '.format(int(self._timer.beatsToSeconds(self._timer.start) * FPS)) fh.write('cd "../capture"\n"../convertcapture/ffmpeg.exe" -framerate {} {}-i dump_{}_%%05d.jpg {}-r {} "../convertcapture/output.gif"'.format(FPS, start, FPS, start2, FPS)) sound = self.timeSlider.soundtrackPath() if not sound: return with fileutil.edit('convertcapture/merge.bat') as fh: startSeconds = self._timer.beatsToSeconds(self._timer.start) fh.write('ffmpeg -i output.mp4 -itsoffset {} -i "{}" -vcodec copy -shortest merged.mp4'.format(-startSeconds, sound))