def project_list(): """List of the available projects.""" projects = [ Project(id=row[0], name=row[1], description=row[2]) for row in database.get_project_list() ] if not projects: typer.echo("No projects defined.") return for project in projects: typer.echo( f"Project: {project.name}, description: {project.description}, ID: {project.id}" )
def task_create(project_name: str, title: str, description: str = None): """Create new task.""" project_data = database.get_project_by_name(name=project_name) project = Project(id=project_data[0][0], name=project_data[0][1], description=project_data[0][2]) task = Task(id=None, title=title, description=description, status=TaskStatusE.OPEN, project_id=project.id) database.create_task(task) typer.echo(f"Task created: {title} in project {project.name}")
def task_show(task_id: int): """Show the task details with task_id.""" task_data = database.get_task_by_id(task_id=task_id) task = Task(id=task_data[0][0], title=task_data[0][1], description=task_data[0][2], status=task_data[0][3], project_id=task_data[0][4]) project_data = database.get_project_by_id(project_id=task.project_id) project = Project(id=project_data[0][0], name=project_data[0][1], description=project_data[0][2]) typer.echo( f"Task: {task.title}, status: {task.get_display_status()}, description: {task.description}, " f"project: {project.name}/{project.id}")
def task_list(project_name: str): """List of the available tasks in given project.""" project_data = database.get_project_by_name(name=project_name) project = Project(id=project_data[0][0], name=project_data[0][1], description=project_data[0][2]) tasks = [ Task(id=row[0], title=row[1], description=row[2], status=row[3], project_id=row[4]) for row in database.get_task_list(project_id=project.id) ] if not tasks: typer.echo(f"No tasks defined for project {project.name}.") return for task in tasks: typer.echo( f"Task: {task.title}, status: {task.get_display_status()}, description: {task.description}, " f"project: {project.name}/{project.id}")
def __init__(self): QtGui.QMainWindow.__init__(self) self.setAcceptDrops(True) self.dropped.connect(self.importAsLayer) self.project = Project(self) self.toolsWidget = ToolsWidget(self.project) self.optionsWidget = OptionsWidget(self.project) self.paletteWidget = PaletteWidget(self.project) self.onionSkinWidget = OnionSkinWidget(self.project) self.timelineWidget = TimelineWidget(self.project) self.scene = Scene(self.project) self.updateTitle() self.project.updateTitleSign.connect(self.updateTitle) ### layout ##################################################### self.setDockNestingEnabled(True) self.setCentralWidget(self.scene) QtGui.QApplication.setOrganizationName("pixeditor") QtGui.QApplication.setApplicationName("pixeditor") settings = QtCore.QSettings() settings.beginGroup("mainWindow") try: lock = bool(int(settings.value("lock"))) except TypeError: lock = True toolsDock = Dock(self.toolsWidget, "tools", lock) toolsDock.setObjectName("toolsDock") self.addDockWidget(QtCore.Qt.LeftDockWidgetArea, toolsDock) optionsDock = Dock(self.optionsWidget, "options", lock) optionsDock.setObjectName("optionsDock") self.addDockWidget(QtCore.Qt.RightDockWidgetArea, optionsDock) paletteDock = Dock(self.paletteWidget, "palette", lock) paletteDock.setObjectName("paletteDock") self.addDockWidget(QtCore.Qt.RightDockWidgetArea, paletteDock) onionSkinDock = Dock(self.onionSkinWidget, "onion skin", lock) onionSkinDock.setObjectName("onionSkinDock") self.addDockWidget(QtCore.Qt.RightDockWidgetArea, onionSkinDock) timelineDock = Dock(self.timelineWidget, "timeline", lock) timelineDock.setObjectName("timelineDock") self.addDockWidget(QtCore.Qt.BottomDockWidgetArea, timelineDock) ### File menu ### menubar = self.menuBar() openAction = QtGui.QAction('Open', self) openAction.triggered.connect(self.openAction) saveAsAction = QtGui.QAction('Save as', self) saveAsAction.triggered.connect(self.saveAsAction) saveAction = QtGui.QAction('Save', self) saveAction.triggered.connect(self.saveAction) saveAction.setShortcut('Ctrl+S') importNewAction = QtGui.QAction('Import as new', self) importNewAction.triggered.connect(self.importAsNewAction) importLayerAction = QtGui.QAction('Import as layer', self) importLayerAction.triggered.connect(self.importAsLayerAction) exportAction = QtGui.QAction('Export', self) exportAction.triggered.connect(self.exportAction) exportAction.setShortcut('Ctrl+E') exitAction = QtGui.QAction('Exit', self) exitAction.triggered.connect(self.close) exitAction.setShortcut('Ctrl+Q') fileMenu = menubar.addMenu('File') fileMenu.addAction(openAction) fileMenu.addAction(saveAsAction) fileMenu.addAction(saveAction) fileMenu.addSeparator() fileMenu.addAction(importNewAction) fileMenu.addAction(importLayerAction) fileMenu.addAction(exportAction) fileMenu.addSeparator() fileMenu.addAction(exitAction) ### Edit menu ### undoAction = QtGui.QAction('Undo', self) undoAction.triggered.connect(self.project.undo) undoAction.setShortcut('Ctrl+Z') redoAction = QtGui.QAction('Redo', self) redoAction.triggered.connect(self.project.redo) redoAction.setShortcut('Ctrl+Y') cutAction = QtGui.QAction('Cut', self) cutAction.triggered.connect(self.timelineWidget.cut) cutAction.setShortcut('Ctrl+X') copyAction = QtGui.QAction('Copy', self) copyAction.triggered.connect(self.timelineWidget.copy) copyAction.setShortcut('Ctrl+C') pasteAction = QtGui.QAction('Paste', self) pasteAction.triggered.connect(self.timelineWidget.paste) pasteAction.setShortcut('Ctrl+V') editMenu = menubar.addMenu('Edit') editMenu.addAction(undoAction) editMenu.addAction(redoAction) editMenu.addSeparator() editMenu.addAction(cutAction) editMenu.addAction(copyAction) editMenu.addAction(pasteAction) ### project menu ### newAction = QtGui.QAction('New', self) newAction.triggered.connect(self.newAction) cropAction = QtGui.QAction('Crop', self) cropAction.triggered.connect(self.cropAction) resizeAction = QtGui.QAction('Resize', self) resizeAction.triggered.connect(self.resizeAction) replacePaletteAction = QtGui.QAction('replace palette', self) replacePaletteAction.triggered.connect(self.replacePaletteAction) prefAction = QtGui.QAction('Background', self) prefAction.triggered.connect(self.backgroundAction) projectMenu = menubar.addMenu('Project') projectMenu.addAction(newAction) projectMenu.addAction(cropAction) projectMenu.addAction(resizeAction) projectMenu.addAction(replacePaletteAction) projectMenu.addAction(prefAction) ### resources menu ### savePaletteAction = QtGui.QAction('save current palette', self) savePaletteAction.triggered.connect(self.savePaletteAction) savePenAction = QtGui.QAction('save custom pen', self) savePenAction.triggered.connect(self.savePenAction) reloadResourcesAction = QtGui.QAction('reload resources', self) reloadResourcesAction.triggered.connect(self.reloadResourcesAction) resourcesMenu = menubar.addMenu('Resources') resourcesMenu.addAction(savePaletteAction) resourcesMenu.addAction(savePenAction) resourcesMenu.addAction(reloadResourcesAction) ### view menu ### viewMenu = menubar.addMenu('View') dockWidgets = self.findChildren(QtGui.QDockWidget) for dock in dockWidgets: viewMenu.addAction(dock.toggleViewAction()) viewMenu.addSeparator() self.lockLayoutWidget = QtGui.QAction('Lock Layout', self) self.lockLayoutWidget.setCheckable(True) self.lockLayoutWidget.setChecked(lock) self.lockLayoutWidget.toggled.connect(self.lockLayoutAction) viewMenu.addAction(self.lockLayoutWidget) ### shortcuts ### QtGui.QShortcut(QtCore.Qt.Key_Left, self, lambda : self.selectFrame(-1)) QtGui.QShortcut(QtCore.Qt.Key_Right, self, lambda : self.selectFrame(1)) QtGui.QShortcut(QtCore.Qt.Key_Up, self, lambda : self.selectLayer(-1)) QtGui.QShortcut(QtCore.Qt.Key_Down, self, lambda : self.selectLayer(1)) QtGui.QShortcut(QtCore.Qt.Key_Space, self, self.timelineWidget.playPauseClicked) QtGui.QShortcut(QtCore.Qt.Key_1, self, toolsDock.widget().penClicked) QtGui.QShortcut(QtCore.Qt.Key_2, self, toolsDock.widget().pipetteClicked) QtGui.QShortcut(QtCore.Qt.Key_3, self, toolsDock.widget().fillClicked) QtGui.QShortcut(QtCore.Qt.Key_4, self, toolsDock.widget().moveClicked) QtGui.QShortcut(QtCore.Qt.Key_5, self, toolsDock.widget().selectClicked) self.hiddenDock = [] QtGui.QShortcut(QtCore.Qt.Key_Tab, self, self.hideDock) QtGui.QShortcut(QtCore.Qt.Key_E, self, self.project.changeColor) ### settings ### try: self.restoreGeometry(settings.value("geometry")) except TypeError: pass # no geometry to restore so leave as is try: self.restoreState(settings.value("windowState")) except TypeError: pass # no state to restore so leave as is settings.endGroup() self.show()
class MainWindow(QtGui.QMainWindow): """ Main windows of the application """ dropped = QtCore.pyqtSignal(list) def __init__(self): QtGui.QMainWindow.__init__(self) self.setAcceptDrops(True) self.dropped.connect(self.importAsLayer) self.project = Project(self) self.toolsWidget = ToolsWidget(self.project) self.optionsWidget = OptionsWidget(self.project) self.paletteWidget = PaletteWidget(self.project) self.onionSkinWidget = OnionSkinWidget(self.project) self.timelineWidget = TimelineWidget(self.project) self.scene = Scene(self.project) self.updateTitle() self.project.updateTitleSign.connect(self.updateTitle) ### layout ##################################################### self.setDockNestingEnabled(True) self.setCentralWidget(self.scene) QtGui.QApplication.setOrganizationName("pixeditor") QtGui.QApplication.setApplicationName("pixeditor") settings = QtCore.QSettings() settings.beginGroup("mainWindow") try: lock = bool(int(settings.value("lock"))) except TypeError: lock = True toolsDock = Dock(self.toolsWidget, "tools", lock) toolsDock.setObjectName("toolsDock") self.addDockWidget(QtCore.Qt.LeftDockWidgetArea, toolsDock) optionsDock = Dock(self.optionsWidget, "options", lock) optionsDock.setObjectName("optionsDock") self.addDockWidget(QtCore.Qt.RightDockWidgetArea, optionsDock) paletteDock = Dock(self.paletteWidget, "palette", lock) paletteDock.setObjectName("paletteDock") self.addDockWidget(QtCore.Qt.RightDockWidgetArea, paletteDock) onionSkinDock = Dock(self.onionSkinWidget, "onion skin", lock) onionSkinDock.setObjectName("onionSkinDock") self.addDockWidget(QtCore.Qt.RightDockWidgetArea, onionSkinDock) timelineDock = Dock(self.timelineWidget, "timeline", lock) timelineDock.setObjectName("timelineDock") self.addDockWidget(QtCore.Qt.BottomDockWidgetArea, timelineDock) ### File menu ### menubar = self.menuBar() openAction = QtGui.QAction('Open', self) openAction.triggered.connect(self.openAction) saveAsAction = QtGui.QAction('Save as', self) saveAsAction.triggered.connect(self.saveAsAction) saveAction = QtGui.QAction('Save', self) saveAction.triggered.connect(self.saveAction) saveAction.setShortcut('Ctrl+S') importNewAction = QtGui.QAction('Import as new', self) importNewAction.triggered.connect(self.importAsNewAction) importLayerAction = QtGui.QAction('Import as layer', self) importLayerAction.triggered.connect(self.importAsLayerAction) exportAction = QtGui.QAction('Export', self) exportAction.triggered.connect(self.exportAction) exportAction.setShortcut('Ctrl+E') exitAction = QtGui.QAction('Exit', self) exitAction.triggered.connect(self.close) exitAction.setShortcut('Ctrl+Q') fileMenu = menubar.addMenu('File') fileMenu.addAction(openAction) fileMenu.addAction(saveAsAction) fileMenu.addAction(saveAction) fileMenu.addSeparator() fileMenu.addAction(importNewAction) fileMenu.addAction(importLayerAction) fileMenu.addAction(exportAction) fileMenu.addSeparator() fileMenu.addAction(exitAction) ### Edit menu ### undoAction = QtGui.QAction('Undo', self) undoAction.triggered.connect(self.project.undo) undoAction.setShortcut('Ctrl+Z') redoAction = QtGui.QAction('Redo', self) redoAction.triggered.connect(self.project.redo) redoAction.setShortcut('Ctrl+Y') cutAction = QtGui.QAction('Cut', self) cutAction.triggered.connect(self.timelineWidget.cut) cutAction.setShortcut('Ctrl+X') copyAction = QtGui.QAction('Copy', self) copyAction.triggered.connect(self.timelineWidget.copy) copyAction.setShortcut('Ctrl+C') pasteAction = QtGui.QAction('Paste', self) pasteAction.triggered.connect(self.timelineWidget.paste) pasteAction.setShortcut('Ctrl+V') editMenu = menubar.addMenu('Edit') editMenu.addAction(undoAction) editMenu.addAction(redoAction) editMenu.addSeparator() editMenu.addAction(cutAction) editMenu.addAction(copyAction) editMenu.addAction(pasteAction) ### project menu ### newAction = QtGui.QAction('New', self) newAction.triggered.connect(self.newAction) cropAction = QtGui.QAction('Crop', self) cropAction.triggered.connect(self.cropAction) resizeAction = QtGui.QAction('Resize', self) resizeAction.triggered.connect(self.resizeAction) replacePaletteAction = QtGui.QAction('replace palette', self) replacePaletteAction.triggered.connect(self.replacePaletteAction) prefAction = QtGui.QAction('Background', self) prefAction.triggered.connect(self.backgroundAction) projectMenu = menubar.addMenu('Project') projectMenu.addAction(newAction) projectMenu.addAction(cropAction) projectMenu.addAction(resizeAction) projectMenu.addAction(replacePaletteAction) projectMenu.addAction(prefAction) ### resources menu ### savePaletteAction = QtGui.QAction('save current palette', self) savePaletteAction.triggered.connect(self.savePaletteAction) savePenAction = QtGui.QAction('save custom pen', self) savePenAction.triggered.connect(self.savePenAction) reloadResourcesAction = QtGui.QAction('reload resources', self) reloadResourcesAction.triggered.connect(self.reloadResourcesAction) resourcesMenu = menubar.addMenu('Resources') resourcesMenu.addAction(savePaletteAction) resourcesMenu.addAction(savePenAction) resourcesMenu.addAction(reloadResourcesAction) ### view menu ### viewMenu = menubar.addMenu('View') dockWidgets = self.findChildren(QtGui.QDockWidget) for dock in dockWidgets: viewMenu.addAction(dock.toggleViewAction()) viewMenu.addSeparator() self.lockLayoutWidget = QtGui.QAction('Lock Layout', self) self.lockLayoutWidget.setCheckable(True) self.lockLayoutWidget.setChecked(lock) self.lockLayoutWidget.toggled.connect(self.lockLayoutAction) viewMenu.addAction(self.lockLayoutWidget) ### shortcuts ### QtGui.QShortcut(QtCore.Qt.Key_Left, self, lambda : self.selectFrame(-1)) QtGui.QShortcut(QtCore.Qt.Key_Right, self, lambda : self.selectFrame(1)) QtGui.QShortcut(QtCore.Qt.Key_Up, self, lambda : self.selectLayer(-1)) QtGui.QShortcut(QtCore.Qt.Key_Down, self, lambda : self.selectLayer(1)) QtGui.QShortcut(QtCore.Qt.Key_Space, self, self.timelineWidget.playPauseClicked) QtGui.QShortcut(QtCore.Qt.Key_1, self, toolsDock.widget().penClicked) QtGui.QShortcut(QtCore.Qt.Key_2, self, toolsDock.widget().pipetteClicked) QtGui.QShortcut(QtCore.Qt.Key_3, self, toolsDock.widget().fillClicked) QtGui.QShortcut(QtCore.Qt.Key_4, self, toolsDock.widget().moveClicked) QtGui.QShortcut(QtCore.Qt.Key_5, self, toolsDock.widget().selectClicked) self.hiddenDock = [] QtGui.QShortcut(QtCore.Qt.Key_Tab, self, self.hideDock) QtGui.QShortcut(QtCore.Qt.Key_E, self, self.project.changeColor) ### settings ### try: self.restoreGeometry(settings.value("geometry")) except TypeError: pass # no geometry to restore so leave as is try: self.restoreState(settings.value("windowState")) except TypeError: pass # no state to restore so leave as is settings.endGroup() self.show() ######## File menu ################################################# def openAction(self): xml, url = open_pix(self.project.dirUrl) if xml and url: self.project.saveToUndo("all") self.project.importXml(xml) self.project.updateViewSign.emit() self.project.updatePaletteSign.emit() self.project.updateTimelineSign.emit() self.project.updateBackgroundSign.emit() self.project.updateFpsSign.emit() self.project.url = url self.project.dirUrl = os.path.dirname(url) def saveAsAction(self): url = get_save_url(self.project.dirUrl) if url: url = save_pix(self.project.exportXml(), url) if url: self.project.url = url self.project.dirUrl = os.path.dirname(url) self.project.saved = True self.updateTitle() def saveAction(self): if self.project.url: url = save_pix(self.project.exportXml(), self.project.url) if url: self.project.url = url self.project.dirUrl = os.path.dirname(url) self.project.saved = True self.updateTitle() else: self.saveAsAction() def importAsNewAction(self): urls = QtGui.QFileDialog.getOpenFileNames( None, "Import PNG and GIF", self.project.dirUrl or os.path.expanduser("~"), "PNG and GIF files (*.png *.gif);;All files (*)") if not urls: return size, frames, colorTable = import_img(self.project, urls) if size and frames and colorTable: self.project.saveToUndo("all") self.project.initProject(size, colorTable, frames) self.project.updateViewSign.emit() self.project.updatePaletteSign.emit() self.project.updateTimelineSign.emit() def importAsLayerAction(self): urls = QtGui.QFileDialog.getOpenFileNames( None, "Import PNG and GIF", self.project.dirUrl or os.path.expanduser("~"), "PNG and GIF files (*.png *.gif);;All files (*)") if urls: self.importAsLayer(urls) def importAsLayer(self, urls): size, frames, colorTable = import_img(self.project, urls, self.project.size, self.project.colorTable) if size and frames and colorTable: self.project.saveToUndo("all") self.project.importImg(size, colorTable, frames) self.project.updateViewSign.emit() self.project.updatePaletteSign.emit() self.project.updateTimelineSign.emit() def exportAction(self): export_png(self.project, self.project.dirUrl) def closeEvent(self, event): ret = True if not self.project.saved: message = QtGui.QMessageBox() message.setWindowTitle("Quit?") message.setText("Are you sure you want to quit?"); message.setIcon(QtGui.QMessageBox.Warning) message.addButton("Cancel", QtGui.QMessageBox.RejectRole) message.addButton("Yes", QtGui.QMessageBox.AcceptRole) ret = message.exec_(); if ret: settings = QtCore.QSettings() settings.beginGroup("mainWindow") settings.setValue("geometry", self.saveGeometry()) settings.setValue("windowState", self.saveState()) settings.setValue("lock", int(self.lockLayoutWidget.isChecked())) settings.endGroup() event.accept() else: event.ignore() ######## Project menu ############################################## def newAction(self): size, palette = NewDialog().getReturn() if size and palette: self.project.saveToUndo("all") self.project.initProject(size, palette) self.project.updateViewSign.emit() self.project.updatePaletteSign.emit() self.project.updateTimelineSign.emit() self.project.updateBackgroundSign.emit() self.project.updateFpsSign.emit() self.updateTitle() def cropAction(self): rect = CropDialog(self.project.size).getReturn() if rect: self.project.saveToUndo("size") self.project.timeline.applyToAllCanvas( lambda c: Canvas(self.project, c.copy(rect))) self.project.size = rect.size() self.project.updateViewSign.emit() def resizeAction(self): newSize = ResizeDialog(self.project.size).getReturn() if newSize: self.project.saveToUndo("size") self.project.timeline.applyToAllCanvas( lambda c: Canvas(self.project, c.scaled(newSize))) self.project.size = newSize self.project.updateViewSign.emit() def replacePaletteAction(self): url = QtGui.QFileDialog.getOpenFileName(None, "open palette file", os.path.join("resources", "palette"), "Palette files (*.pal, *.gpl );;All files (*)") if url: pal = import_palette(url, len(self.project.colorTable)) if pal: self.project.saveToUndo("colorTable_frames") self.project.colorTable = pal for i in self.project.timeline.getAllCanvas(): i.setColorTable(self.project.colorTable) self.project.updateViewSign.emit() self.project.updatePaletteSign.emit() def backgroundAction(self): color, pattern = BackgroundDialog(self.project.bgColor, self.project.bgPattern).getReturn() if color and pattern: self.project.saveToUndo("background") self.project.bgColor = color self.project.bgPattern = pattern self.project.updateBackgroundSign.emit() def savePaletteAction(self): url = get_save_url(os.path.join("resources", "palette"), "pal") pal = export_palette(self.project.colorTable) if url: try: save = open(url, "w") save.write(pal) save.close() print("saved") except IOError: print("Can't open file") def savePenAction(self): if self.project.penDict["custom"]: url = get_save_url(os.path.join("resources", "pen"), "py") pen = export_pen(self.project.penDict["custom"], os.path.splitext(os.path.basename(url))[0]) if url: try: save = open(url, "w") save.write(pen) save.close() print("saved") except IOError: print("Can't open file") def reloadResourcesAction(self): self.project.importResources() self.toolsWidget.penWidget.loadPen() self.toolsWidget.brushWidget.loadBrush() ######## View menu ############################################## def lockLayoutAction(self, check): for dock in self.findChildren(QtGui.QDockWidget): dock.lock(check) def hideDock(self): hide = False for dock in self.findChildren(QtGui.QDockWidget): if dock.isVisible(): hide = True if hide: self.hiddenDock = [] for dock in self.findChildren(QtGui.QDockWidget): if dock.isVisible(): self.hiddenDock.append(dock.objectName()) dock.hide() elif self.hiddenDock: for dock in self.findChildren(QtGui.QDockWidget): if dock.objectName() in self.hiddenDock: dock.show() else: for dock in self.findChildren(QtGui.QDockWidget): dock.show() ######## Shortcuts ################################################# def selectFrame(self, n): exf = self.project.curFrame f = self.project.curFrame + n lf = self.project.timeline.frameVisibleCount() if f < 0: if self.project.loop: self.project.curFrame = lf -1 elif f >= lf: if self.project.loop: self.project.curFrame = 0 else: self.project.curFrame = f else: self.project.curFrame = f if self.project.curFrame != exf: self.project.updateTimelineSign.emit() self.project.updateViewSign.emit() def selectLayer(self, n): if 0 <= self.project.curLayer+n < len(self.project.timeline): self.project.curLayer += n self.project.updateTimelineSign.emit() self.project.updateViewSign.emit() def updateTitle(self): url, sav = "untitled", "* " if self.project.saved: sav = "" if self.project.url: url = os.path.basename(self.project.url) self.setWindowTitle("%s%s - pixeditor" %(sav, url)) def dragEnterEvent(self, event): if event.mimeData().hasUrls: event.accept() else: event.ignore() def dropEvent(self, event): if event.mimeData().hasUrls: event.accept() l = [] for url in event.mimeData().urls(): l.append(url.toLocalFile()) self.dropped.emit(l) else: event.ignore()
def __init__(self): QtGui.QMainWindow.__init__(self) self.setAcceptDrops(True) self.dropped.connect(self.importAsLayer) self.project = Project(self) self.toolsWidget = ToolsWidget(self.project) self.optionsWidget = OptionsWidget(self.project) self.paletteWidget = PaletteWidget(self.project) self.onionSkinWidget = OnionSkinWidget(self.project) self.timelineWidget = TimelineWidget(self.project) self.scene = Scene(self.project) self.updateTitle() self.project.updateTitleSign.connect(self.updateTitle) ### layout ##################################################### self.setDockNestingEnabled(True) self.setCentralWidget(self.scene) QtGui.QApplication.setOrganizationName("pixeditor") QtGui.QApplication.setApplicationName("pixeditor") settings = QtCore.QSettings() settings.beginGroup("mainWindow") try: lock = bool(int(settings.value("lock"))) except TypeError: lock = True toolsDock = Dock(self.toolsWidget, "tools", lock) toolsDock.setObjectName("toolsDock") self.addDockWidget(QtCore.Qt.LeftDockWidgetArea, toolsDock) self.scene.coords=toolsDock.widget().coords optionsDock = Dock(self.optionsWidget, "options", lock) optionsDock.setObjectName("optionsDock") self.addDockWidget(QtCore.Qt.RightDockWidgetArea, optionsDock) paletteDock = Dock(self.paletteWidget, "palette", lock) paletteDock.setObjectName("paletteDock") self.addDockWidget(QtCore.Qt.RightDockWidgetArea, paletteDock) onionSkinDock = Dock(self.onionSkinWidget, "onion skin", lock) onionSkinDock.setObjectName("onionSkinDock") self.addDockWidget(QtCore.Qt.RightDockWidgetArea, onionSkinDock) timelineDock = Dock(self.timelineWidget, "timeline", lock) timelineDock.setObjectName("timelineDock") self.addDockWidget(QtCore.Qt.BottomDockWidgetArea, timelineDock) ### File menu ### menubar = self.menuBar() openAction = QtGui.QAction('Open', self) openAction.triggered.connect(self.openAction) saveAsAction = QtGui.QAction('Save as', self) saveAsAction.triggered.connect(self.saveAsAction) saveAction = QtGui.QAction('Save', self) saveAction.triggered.connect(self.saveAction) saveAction.setShortcut('Ctrl+S') importNewAction = QtGui.QAction('Import as new', self) importNewAction.triggered.connect(self.importAsNewAction) importLayerAction = QtGui.QAction('Import as layer', self) importLayerAction.triggered.connect(self.importAsLayerAction) exportAction = QtGui.QAction('Export', self) exportAction.triggered.connect(self.exportAction) exportAction.setShortcut('Ctrl+E') exitAction = QtGui.QAction('Exit', self) exitAction.triggered.connect(self.close) exitAction.setShortcut('Ctrl+Q') fileMenu = menubar.addMenu('File') fileMenu.addAction(openAction) fileMenu.addAction(saveAsAction) fileMenu.addAction(saveAction) fileMenu.addSeparator() fileMenu.addAction(importNewAction) fileMenu.addAction(importLayerAction) fileMenu.addAction(exportAction) fileMenu.addSeparator() fileMenu.addAction(exitAction) ### Edit menu ### undoAction = QtGui.QAction('Undo', self) undoAction.triggered.connect(self.project.undo) undoAction.setShortcut('Ctrl+Z') redoAction = QtGui.QAction('Redo', self) redoAction.triggered.connect(self.project.redo) redoAction.setShortcut('Ctrl+Y') cutAction = QtGui.QAction('Cut', self) cutAction.triggered.connect(self.timelineWidget.cut) cutAction.setShortcut('Ctrl+X') copyAction = QtGui.QAction('Copy', self) copyAction.triggered.connect(self.timelineWidget.copy) copyAction.setShortcut('Ctrl+C') pasteAction = QtGui.QAction('Paste', self) pasteAction.triggered.connect(self.timelineWidget.paste) pasteAction.setShortcut('Ctrl+V') editMenu = menubar.addMenu('Edit') editMenu.addAction(undoAction) editMenu.addAction(redoAction) editMenu.addSeparator() editMenu.addAction(cutAction) editMenu.addAction(copyAction) editMenu.addAction(pasteAction) ### project menu ### newAction = QtGui.QAction('New', self) newAction.triggered.connect(self.newAction) cropAction = QtGui.QAction('Crop', self) cropAction.triggered.connect(self.cropAction) resizeAction = QtGui.QAction('Resize', self) resizeAction.triggered.connect(self.resizeAction) replacePaletteAction = QtGui.QAction('replace palette', self) replacePaletteAction.triggered.connect(self.replacePaletteAction) prefAction = QtGui.QAction('Background', self) prefAction.triggered.connect(self.backgroundAction) projectMenu = menubar.addMenu('Project') projectMenu.addAction(newAction) projectMenu.addAction(cropAction) projectMenu.addAction(resizeAction) projectMenu.addAction(replacePaletteAction) projectMenu.addAction(prefAction) ### resources menu ### savePaletteAction = QtGui.QAction('save current palette', self) savePaletteAction.triggered.connect(self.savePaletteAction) savePenAction = QtGui.QAction('save custom pen', self) savePenAction.triggered.connect(self.savePenAction) reloadResourcesAction = QtGui.QAction('reload resources', self) reloadResourcesAction.triggered.connect(self.reloadResourcesAction) resourcesMenu = menubar.addMenu('Resources') resourcesMenu.addAction(savePaletteAction) resourcesMenu.addAction(savePenAction) resourcesMenu.addAction(reloadResourcesAction) ### view menu ### viewMenu = menubar.addMenu('View') dockWidgets = self.findChildren(QtGui.QDockWidget) for dock in dockWidgets: viewMenu.addAction(dock.toggleViewAction()) viewMenu.addSeparator() self.lockLayoutWidget = QtGui.QAction('Lock Layout', self) self.lockLayoutWidget.setCheckable(True) self.lockLayoutWidget.setChecked(lock) self.lockLayoutWidget.toggled.connect(self.lockLayoutAction) viewMenu.addAction(self.lockLayoutWidget) ### shortcuts ### QtGui.QShortcut(QtCore.Qt.Key_Left, self, lambda : self.selectFrame(-1)) QtGui.QShortcut(QtCore.Qt.Key_Right, self, lambda : self.selectFrame(1)) QtGui.QShortcut(QtCore.Qt.Key_Up, self, lambda : self.selectLayer(-1)) QtGui.QShortcut(QtCore.Qt.Key_Down, self, lambda : self.selectLayer(1)) QtGui.QShortcut(QtCore.Qt.Key_Space, self, self.timelineWidget.playPauseClicked) QtGui.QShortcut(QtCore.Qt.Key_1, self, toolsDock.widget().penClicked) QtGui.QShortcut(QtCore.Qt.Key_2, self, toolsDock.widget().pipetteClicked) QtGui.QShortcut(QtCore.Qt.Key_3, self, toolsDock.widget().fillClicked) QtGui.QShortcut(QtCore.Qt.Key_4, self, toolsDock.widget().moveClicked) QtGui.QShortcut(QtCore.Qt.Key_5, self, toolsDock.widget().selectClicked) self.hiddenDock = [] QtGui.QShortcut(QtCore.Qt.Key_Tab, self, self.hideDock) QtGui.QShortcut(QtCore.Qt.Key_E, self, self.project.changeColor) ### settings ### try: self.restoreGeometry(settings.value("geometry")) except TypeError: pass # no geometry to restore so leave as is try: self.restoreState(settings.value("windowState")) except TypeError: pass # no state to restore so leave as is settings.endGroup() self.show()
class MainWindow(QtGui.QMainWindow): """ Main windows of the application """ dropped = QtCore.pyqtSignal(list) def __init__(self): QtGui.QMainWindow.__init__(self) self.setAcceptDrops(True) self.dropped.connect(self.importAsLayer) self.project = Project(self) self.toolsWidget = ToolsWidget(self.project) self.optionsWidget = OptionsWidget(self.project) self.paletteWidget = PaletteWidget(self.project) self.onionSkinWidget = OnionSkinWidget(self.project) self.timelineWidget = TimelineWidget(self.project) self.scene = Scene(self.project) self.updateTitle() self.project.updateTitleSign.connect(self.updateTitle) ### layout ##################################################### self.setDockNestingEnabled(True) self.setCentralWidget(self.scene) QtGui.QApplication.setOrganizationName("pixeditor") QtGui.QApplication.setApplicationName("pixeditor") settings = QtCore.QSettings() settings.beginGroup("mainWindow") try: lock = bool(int(settings.value("lock"))) except TypeError: lock = True toolsDock = Dock(self.toolsWidget, "tools", lock) toolsDock.setObjectName("toolsDock") self.addDockWidget(QtCore.Qt.LeftDockWidgetArea, toolsDock) self.scene.coords=toolsDock.widget().coords optionsDock = Dock(self.optionsWidget, "options", lock) optionsDock.setObjectName("optionsDock") self.addDockWidget(QtCore.Qt.RightDockWidgetArea, optionsDock) paletteDock = Dock(self.paletteWidget, "palette", lock) paletteDock.setObjectName("paletteDock") self.addDockWidget(QtCore.Qt.RightDockWidgetArea, paletteDock) onionSkinDock = Dock(self.onionSkinWidget, "onion skin", lock) onionSkinDock.setObjectName("onionSkinDock") self.addDockWidget(QtCore.Qt.RightDockWidgetArea, onionSkinDock) timelineDock = Dock(self.timelineWidget, "timeline", lock) timelineDock.setObjectName("timelineDock") self.addDockWidget(QtCore.Qt.BottomDockWidgetArea, timelineDock) ### File menu ### menubar = self.menuBar() openAction = QtGui.QAction('Open', self) openAction.triggered.connect(self.openAction) saveAsAction = QtGui.QAction('Save as', self) saveAsAction.triggered.connect(self.saveAsAction) saveAction = QtGui.QAction('Save', self) saveAction.triggered.connect(self.saveAction) saveAction.setShortcut('Ctrl+S') importNewAction = QtGui.QAction('Import as new', self) importNewAction.triggered.connect(self.importAsNewAction) importLayerAction = QtGui.QAction('Import as layer', self) importLayerAction.triggered.connect(self.importAsLayerAction) exportAction = QtGui.QAction('Export', self) exportAction.triggered.connect(self.exportAction) exportAction.setShortcut('Ctrl+E') exitAction = QtGui.QAction('Exit', self) exitAction.triggered.connect(self.close) exitAction.setShortcut('Ctrl+Q') fileMenu = menubar.addMenu('File') fileMenu.addAction(openAction) fileMenu.addAction(saveAsAction) fileMenu.addAction(saveAction) fileMenu.addSeparator() fileMenu.addAction(importNewAction) fileMenu.addAction(importLayerAction) fileMenu.addAction(exportAction) fileMenu.addSeparator() fileMenu.addAction(exitAction) ### Edit menu ### undoAction = QtGui.QAction('Undo', self) undoAction.triggered.connect(self.project.undo) undoAction.setShortcut('Ctrl+Z') redoAction = QtGui.QAction('Redo', self) redoAction.triggered.connect(self.project.redo) redoAction.setShortcut('Ctrl+Y') cutAction = QtGui.QAction('Cut', self) cutAction.triggered.connect(self.timelineWidget.cut) cutAction.setShortcut('Ctrl+X') copyAction = QtGui.QAction('Copy', self) copyAction.triggered.connect(self.timelineWidget.copy) copyAction.setShortcut('Ctrl+C') pasteAction = QtGui.QAction('Paste', self) pasteAction.triggered.connect(self.timelineWidget.paste) pasteAction.setShortcut('Ctrl+V') editMenu = menubar.addMenu('Edit') editMenu.addAction(undoAction) editMenu.addAction(redoAction) editMenu.addSeparator() editMenu.addAction(cutAction) editMenu.addAction(copyAction) editMenu.addAction(pasteAction) ### project menu ### newAction = QtGui.QAction('New', self) newAction.triggered.connect(self.newAction) cropAction = QtGui.QAction('Crop', self) cropAction.triggered.connect(self.cropAction) resizeAction = QtGui.QAction('Resize', self) resizeAction.triggered.connect(self.resizeAction) replacePaletteAction = QtGui.QAction('replace palette', self) replacePaletteAction.triggered.connect(self.replacePaletteAction) prefAction = QtGui.QAction('Background', self) prefAction.triggered.connect(self.backgroundAction) projectMenu = menubar.addMenu('Project') projectMenu.addAction(newAction) projectMenu.addAction(cropAction) projectMenu.addAction(resizeAction) projectMenu.addAction(replacePaletteAction) projectMenu.addAction(prefAction) ### resources menu ### savePaletteAction = QtGui.QAction('save current palette', self) savePaletteAction.triggered.connect(self.savePaletteAction) savePenAction = QtGui.QAction('save custom pen', self) savePenAction.triggered.connect(self.savePenAction) reloadResourcesAction = QtGui.QAction('reload resources', self) reloadResourcesAction.triggered.connect(self.reloadResourcesAction) resourcesMenu = menubar.addMenu('Resources') resourcesMenu.addAction(savePaletteAction) resourcesMenu.addAction(savePenAction) resourcesMenu.addAction(reloadResourcesAction) ### view menu ### viewMenu = menubar.addMenu('View') dockWidgets = self.findChildren(QtGui.QDockWidget) for dock in dockWidgets: viewMenu.addAction(dock.toggleViewAction()) viewMenu.addSeparator() self.lockLayoutWidget = QtGui.QAction('Lock Layout', self) self.lockLayoutWidget.setCheckable(True) self.lockLayoutWidget.setChecked(lock) self.lockLayoutWidget.toggled.connect(self.lockLayoutAction) viewMenu.addAction(self.lockLayoutWidget) ### shortcuts ### QtGui.QShortcut(QtCore.Qt.Key_Left, self, lambda : self.selectFrame(-1)) QtGui.QShortcut(QtCore.Qt.Key_Right, self, lambda : self.selectFrame(1)) QtGui.QShortcut(QtCore.Qt.Key_Up, self, lambda : self.selectLayer(-1)) QtGui.QShortcut(QtCore.Qt.Key_Down, self, lambda : self.selectLayer(1)) QtGui.QShortcut(QtCore.Qt.Key_Space, self, self.timelineWidget.playPauseClicked) QtGui.QShortcut(QtCore.Qt.Key_1, self, toolsDock.widget().penClicked) QtGui.QShortcut(QtCore.Qt.Key_2, self, toolsDock.widget().pipetteClicked) QtGui.QShortcut(QtCore.Qt.Key_3, self, toolsDock.widget().fillClicked) QtGui.QShortcut(QtCore.Qt.Key_4, self, toolsDock.widget().moveClicked) QtGui.QShortcut(QtCore.Qt.Key_5, self, toolsDock.widget().selectClicked) self.hiddenDock = [] QtGui.QShortcut(QtCore.Qt.Key_Tab, self, self.hideDock) QtGui.QShortcut(QtCore.Qt.Key_E, self, self.project.changeColor) ### settings ### try: self.restoreGeometry(settings.value("geometry")) except TypeError: pass # no geometry to restore so leave as is try: self.restoreState(settings.value("windowState")) except TypeError: pass # no state to restore so leave as is settings.endGroup() self.show() ######## File menu ################################################# def openAction(self): xml, url = open_pix(self.project.dirUrl) if xml and url: self.project.saveToUndo("all") self.project.importXml(xml) self.project.updateViewSign.emit() self.project.updatePaletteSign.emit() self.project.updateTimelineSign.emit() self.project.updateBackgroundSign.emit() self.project.updateFpsSign.emit() self.project.url = url self.project.dirUrl = os.path.dirname(url) def saveAsAction(self): url = get_save_url(self.project.dirUrl) if url: url = save_pix(self.project.exportXml(), url) if url: self.project.url = url self.project.dirUrl = os.path.dirname(url) self.project.saved = True self.updateTitle() def saveAction(self): if self.project.url: url = save_pix(self.project.exportXml(), self.project.url) if url: self.project.url = url self.project.dirUrl = os.path.dirname(url) self.project.saved = True self.updateTitle() else: self.saveAsAction() def importAsNewAction(self): urls = QtGui.QFileDialog.getOpenFileNames( None, "Import PNG and GIF", self.project.dirUrl or os.path.expanduser("~"), "PNG and GIF files (*.png *.gif);;All files (*)") if not urls: return size, frames, colorTable = import_img(self.project, urls) if size and frames and colorTable: self.project.saveToUndo("all") self.project.initProject(size, colorTable, frames) self.project.updateViewSign.emit() self.project.updatePaletteSign.emit() self.project.updateTimelineSign.emit() def importAsLayerAction(self): urls = QtGui.QFileDialog.getOpenFileNames( None, "Import PNG and GIF", self.project.dirUrl or os.path.expanduser("~"), "PNG and GIF files (*.png *.gif);;All files (*)") if urls: self.importAsLayer(urls) def importAsLayer(self, urls): size, frames, colorTable = import_img(self.project, urls, self.project.size, self.project.colorTable) if size and frames and colorTable: self.project.saveToUndo("all") self.project.importImg(size, colorTable, frames) self.project.updateViewSign.emit() self.project.updatePaletteSign.emit() self.project.updateTimelineSign.emit() def exportAction(self): export_png(self.project, self.project.dirUrl) def closeEvent(self, event): ret = True if not self.project.saved: message = QtGui.QMessageBox() message.setWindowTitle("Quit?") message.setText("Are you sure you want to quit?"); message.setIcon(QtGui.QMessageBox.Warning) message.addButton("Cancel", QtGui.QMessageBox.RejectRole) message.addButton("Yes", QtGui.QMessageBox.AcceptRole) ret = message.exec_(); if ret: settings = QtCore.QSettings() settings.beginGroup("mainWindow") settings.setValue("geometry", self.saveGeometry()) settings.setValue("windowState", self.saveState()) settings.setValue("lock", int(self.lockLayoutWidget.isChecked())) settings.endGroup() event.accept() else: event.ignore() ######## Project menu ############################################## def newAction(self): size, palette = NewDialog().getReturn() if size and palette: self.project.saveToUndo("all") self.project.initProject(size, palette) self.project.updateViewSign.emit() self.project.updatePaletteSign.emit() self.project.updateTimelineSign.emit() self.project.updateBackgroundSign.emit() self.project.updateFpsSign.emit() self.updateTitle() def cropAction(self): rect = CropDialog(self.project.size).getReturn() if rect: self.project.saveToUndo("size") self.project.timeline.applyToAllCanvas( lambda c: Canvas(self.project, c.copy(rect))) self.project.size = rect.size() self.project.updateViewSign.emit() def resizeAction(self): newSize = ResizeDialog(self.project.size).getReturn() if newSize: self.project.saveToUndo("size") self.project.timeline.applyToAllCanvas( lambda c: Canvas(self.project, c.scaled(newSize))) self.project.size = newSize self.project.updateViewSign.emit() def replacePaletteAction(self): url = QtGui.QFileDialog.getOpenFileName(None, "open palette file", os.path.join("resources", "palette"), "Palette files (*.pal, *.gpl );;All files (*)") if url: pal = import_palette(url, len(self.project.colorTable)) if pal: self.project.saveToUndo("colorTable_frames") self.project.changeColorTable(pal) self.project.color = 1 self.project.currentColor = 1 self.project.updateViewSign.emit() self.project.updatePaletteSign.emit() self.project.colorChangedSign.emit() def backgroundAction(self): color, pattern = BackgroundDialog(self.project.bgColor, self.project.bgPattern).getReturn() if color and pattern: self.project.saveToUndo("background") self.project.bgColor = color self.project.bgPattern = pattern self.project.updateBackgroundSign.emit() def savePaletteAction(self): url = get_save_url(os.path.join("resources", "palette"), "pal") pal = export_palette(self.project.colorTable) if url: try: save = open(url, "w") save.write(pal) save.close() print("saved") except IOError: print("Can't open file") def savePenAction(self): if self.project.penDict["custom"]: url = get_save_url(os.path.join("resources", "pen"), "py") pen = export_pen(self.project.penDict["custom"], os.path.splitext(os.path.basename(url))[0]) if url: try: save = open(url, "w") save.write(pen) save.close() print("saved") except IOError: print("Can't open file") def reloadResourcesAction(self): self.project.importResources() self.toolsWidget.penWidget.loadPen() self.toolsWidget.brushWidget.loadBrush() ######## View menu ############################################## def lockLayoutAction(self, check): for dock in self.findChildren(QtGui.QDockWidget): dock.lock(check) def hideDock(self): hide = False for dock in self.findChildren(QtGui.QDockWidget): if dock.isVisible(): hide = True if hide: self.hiddenDock = [] for dock in self.findChildren(QtGui.QDockWidget): if dock.isVisible(): self.hiddenDock.append(dock.objectName()) dock.hide() elif self.hiddenDock: for dock in self.findChildren(QtGui.QDockWidget): if dock.objectName() in self.hiddenDock: dock.show() else: for dock in self.findChildren(QtGui.QDockWidget): dock.show() ######## Shortcuts ################################################# def selectFrame(self, n): exf = self.project.curFrame f = self.project.curFrame + n lf = self.project.timeline.frameVisibleCount() if f < 0: if self.project.loop: self.project.curFrame = lf -1 elif f >= lf: if self.project.loop: self.project.curFrame = 0 else: self.project.curFrame = f else: self.project.curFrame = f if self.project.curFrame != exf: self.project.updateTimelineSign.emit() self.project.updateViewSign.emit() def selectLayer(self, n): if 0 <= self.project.curLayer+n < len(self.project.timeline): self.project.curLayer += n self.project.updateTimelineSign.emit() self.project.updateViewSign.emit() def updateTitle(self): url, sav = "untitled", "* " if self.project.saved: sav = "" if self.project.url: url = os.path.basename(self.project.url) self.setWindowTitle("%s%s - pixeditor" %(sav, url)) def dragEnterEvent(self, event): if event.mimeData().hasUrls: event.accept() else: event.ignore() def dropEvent(self, event): if event.mimeData().hasUrls: event.accept() l = [] for url in event.mimeData().urls(): l.append(url.toLocalFile()) self.dropped.emit(l) else: event.ignore()
def __init__(self): QMainWindow.__init__(self) QApplication.setOrganizationName("z-uo") QApplication.setApplicationName("pixeditor") self.colorDialog = QColorDialog() self.colorDialog.setOptions(QColorDialog.NoButtons) #self.colorDialog.hide() self.project = Project(self) self.rgbWidget = RgbSlidersWidget(self) self.rgbWidget.colorChanged.connect(self.project.setColor) self.project.colorChanged.connect(lambda widget=self: widget.rgbWidget.setColor(QColor(widget.project.colorTable[widget.project.color]))) self.hsvWidget = HsvSlidersWidget(self) self.hsvWidget.colorChanged.connect(self.project.setColor) self.project.colorChanged.connect(lambda widget=self: widget.hsvWidget.setColor(QColor(widget.project.colorTable[widget.project.color]))) self.hslWidget = HslSlidersWidget(self) self.hslWidget.colorChanged.connect(self.project.setColor) self.project.colorChanged.connect(lambda widget=self: widget.hslWidget.setColor(QColor(widget.project.colorTable[widget.project.color]))) self.cmykWidget = CmykSlidersWidget(self) self.cmykWidget.colorChanged.connect(self.project.setColor) self.project.colorChanged.connect(lambda widget=self: widget.cmykWidget.setColor(QColor(widget.project.colorTable[widget.project.color]))) self.contextWidget = ContextWidget(self.project) self.optionsWidget = OptionsWidget(self.project) self.paletteWidget = PaletteWidget(self.project) self.timelineWidget = TimelineWidget(self.project) self.scene = Scene(self.project) self.toolsWidget = ToolWidget(self) self.updateTitle() self.project.updateTitleSign.connect(self.updateTitle) self.setCentralWidget(self.scene) self.setDockNestingEnabled(True) toolsDock = QDockWidget("Tools") toolsDock.setWidget(self.toolsWidget) toolsDock.setObjectName("toolsDock") self.addDockWidget(Qt.LeftDockWidgetArea, toolsDock) contextDock = QDockWidget("Context") contextDock.setWidget(self.contextWidget) contextDock.setObjectName("contextDock") self.addDockWidget(Qt.LeftDockWidgetArea, contextDock) optionsDock = QDockWidget("Options") optionsDock.setWidget(self.optionsWidget) optionsDock.setObjectName("optionsDock") self.addDockWidget(Qt.LeftDockWidgetArea, optionsDock) paletteDock = QDockWidget("Palette") paletteDock.setWidget(self.paletteWidget) paletteDock.setObjectName("paletteDock") self.addDockWidget(Qt.LeftDockWidgetArea, paletteDock) #colorDialogDock = QDockWidget("Color Dialog") #colorDialogDock.setWidget(self.colorDialog) #colorDialogDock.setObjectName("colorDialog") #self.addDockWidget(Qt.LeftDockWidgetArea, colorDialogDock) rgbDock = QDockWidget("RGB") rgbDock.setWidget(self.rgbWidget) rgbDock.setObjectName("rgbDock") self.addDockWidget(Qt.LeftDockWidgetArea, rgbDock) hsvDock = QDockWidget("HSV") hsvDock.setWidget(self.hsvWidget) hsvDock.setObjectName("hsvDock") self.addDockWidget(Qt.LeftDockWidgetArea, hsvDock) hslDock = QDockWidget("HSL") hslDock.setWidget(self.hslWidget) hslDock.setObjectName("hslDock") self.addDockWidget(Qt.LeftDockWidgetArea, hslDock) cmykDock = QDockWidget("CMYK") cmykDock.setWidget(self.cmykWidget) cmykDock.setObjectName("cmykDock") self.addDockWidget(Qt.LeftDockWidgetArea, cmykDock) self.tabifyDockWidget(rgbDock, hsvDock) self.tabifyDockWidget(hsvDock, hslDock) self.tabifyDockWidget(hslDock, cmykDock) hsvDock.close() cmykDock.close() rgbDock.raise_() timelineDock = Dock("Timeline") timelineDock.setWidget(self.timelineWidget) timelineDock.setObjectName("timelineDock") timelineDock.setFeatures(QDockWidget.DockWidgetVerticalTitleBar | QDockWidget.AllDockWidgetFeatures) self.addDockWidget(Qt.BottomDockWidgetArea, timelineDock) ### Toolbar ### toolActions = QActionGroup(self) toolActions.setExclusive(True) penToolAction = QAction(QIcon("icons/tool_pen.png"), "&Pen", toolActions) penToolAction.setCheckable(True) penToolAction.setChecked(True) penToolAction.triggered.connect(self.penToolAction) pipetteToolAction = QAction(QIcon("icons/tool_pipette.png"), "P&ipette", toolActions) pipetteToolAction.setCheckable(True) pipetteToolAction.triggered.connect(self.pipetteToolAction) fillToolAction = QAction(QIcon("icons/tool_fill.png"), "&Fill", toolActions) fillToolAction.setCheckable(True) fillToolAction.triggered.connect(self.fillToolAction) moveToolAction = QAction(QIcon("icons/tool_move.png"), "&Move", toolActions) moveToolAction.setCheckable(True) moveToolAction.triggered.connect(self.moveToolAction) selectToolAction = QAction(QIcon("icons/tool_select.png"), "&Select", toolActions) selectToolAction.setCheckable(True) selectToolAction.triggered.connect(self.selectToolAction) toolbar = QToolBar("Tools") toolbar.addAction(penToolAction) toolbar.addAction(pipetteToolAction) toolbar.addAction(fillToolAction) toolbar.addAction(moveToolAction) toolbar.addAction(selectToolAction) toolbar.setObjectName("toolsToolbar") #self.addToolBar(toolbar) penToolAction.setShortcut('1') pipetteToolAction.setShortcut('2') fillToolAction.setShortcut('3') moveToolAction.setShortcut('4') selectToolAction.setShortcut('5') self.toolsWidget.addAction(penToolAction) self.toolsWidget.addAction(pipetteToolAction) self.toolsWidget.addAction(fillToolAction) self.toolsWidget.addAction(moveToolAction) self.toolsWidget.addAction(selectToolAction) ### File menu ### menubar = self.menuBar() newAction = QAction('&New', self) newAction.triggered.connect(self.newAction) openAction = QAction('&Open', self) openAction.triggered.connect(self.openAction) openAction.setShortcut(QKeySequence.Open) saveAsAction = QAction('Save &as', self) saveAsAction.triggered.connect(self.saveAsAction) saveAsAction.setShortcut(QKeySequence.SaveAs) saveAction = QAction('&Save', self) saveAction.triggered.connect(self.saveAction) saveAction.setShortcut(QKeySequence.Save) importNewAction = QAction('&Import as new', self) importNewAction.triggered.connect(self.importAsNewAction) importLayerAction = QAction('I&mport as layer', self) importLayerAction.triggered.connect(self.importAsLayerAction) exportAction = QAction('&Export', self) exportAction.triggered.connect(self.exportAction) exportAction.setShortcut('Ctrl+E') exitAction = QAction('E&xit', self) exitAction.triggered.connect(self.exitAction) exitAction.setShortcut(QKeySequence.Quit) fileMenu = menubar.addMenu('&File') fileMenu.addAction(newAction) fileMenu.addAction(openAction) fileMenu.addAction(saveAsAction) fileMenu.addAction(saveAction) fileMenu.addSeparator() fileMenu.addAction(importNewAction) fileMenu.addAction(importLayerAction) fileMenu.addAction(exportAction) fileMenu.addSeparator() fileMenu.addAction(exitAction) ### Edit menu ### undoAction = QAction('&Undo', self) undoAction.triggered.connect(self.project.undo) undoAction.setShortcut(QKeySequence.Undo) redoAction = QAction('&Redo', self) redoAction.triggered.connect(self.project.redo) redoAction.setShortcut(QKeySequence.Redo) cutAction = QAction('&Cut', self) cutAction.triggered.connect(self.timelineWidget.cut) cutAction.setShortcut(QKeySequence.Cut) copyAction = QAction('C&opy', self) copyAction.triggered.connect(self.timelineWidget.copy) copyAction.setShortcut(QKeySequence.Copy) pasteAction = QAction('&Paste', self) pasteAction.triggered.connect(self.timelineWidget.paste) pasteAction.setShortcut(QKeySequence.Paste) editMenu = menubar.addMenu('&Edit') editMenu.addAction(undoAction) editMenu.addAction(redoAction) editMenu.addSeparator() editMenu.addAction(cutAction) editMenu.addAction(copyAction) editMenu.addAction(pasteAction) ### tools menu ### toolsMenu = menubar.addMenu('&Tools') toolsMenu.addAction(penToolAction) toolsMenu.addAction(pipetteToolAction) toolsMenu.addAction(fillToolAction) toolsMenu.addAction(moveToolAction) toolsMenu.addAction(selectToolAction) ### view menu ### viewMenu = menubar.addMenu('&View') toolbars = self.findChildren(QToolBar) for toolbar in toolbars: viewMenu.addAction(toolbar.toggleViewAction()) viewMenu.addSeparator() dockWidgets = self.findChildren(QDockWidget) for dock in dockWidgets: viewMenu.addAction(dock.toggleViewAction()) viewMenu.addSeparator() self.lockLayoutAction = QAction('&Lock Layout', self) self.lockLayoutAction.setCheckable(True) self.lockLayoutAction.triggered.connect(lambda checked, widget=self: widget.setLayoutLocked(checked)) viewMenu.addAction(self.lockLayoutAction) ### project menu ### cropAction = QAction('&Crop', self) cropAction.triggered.connect(self.cropAction) resizeAction = QAction('&Resize', self) resizeAction.triggered.connect(self.resizeAction) replacePaletteAction = QAction('Replace &palette', self) replacePaletteAction.triggered.connect(self.replacePaletteAction) prefAction = QAction('&Background', self) prefAction.triggered.connect(self.backgroundAction) projectMenu = menubar.addMenu('&Project') projectMenu.addAction(cropAction) projectMenu.addAction(resizeAction) projectMenu.addSeparator() projectMenu.addAction(replacePaletteAction) projectMenu.addSeparator() projectMenu.addAction(prefAction) ### resources menu ### savePaletteAction = QAction('Save current &palette', self) savePaletteAction.triggered.connect(self.savePaletteAction) savePenAction = QAction('Save &custom pen', self) savePenAction.triggered.connect(self.savePenAction) reloadResourcesAction = QAction('&Reload resources', self) reloadResourcesAction.triggered.connect(self.reloadResourcesAction) resourcesMenu = menubar.addMenu('&Resources') resourcesMenu.addAction(savePaletteAction) resourcesMenu.addAction(savePenAction) resourcesMenu.addSeparator() resourcesMenu.addAction(reloadResourcesAction) ### shortcuts ### shortcut = QShortcut(self) shortcut.setKey(Qt.Key_Left) shortcut.activated.connect(lambda: self.selectFrame(-1)) shortcut2 = QShortcut(self) shortcut2.setKey(Qt.Key_Right) shortcut2.activated.connect(lambda: self.selectFrame(1)) shortcut3 = QShortcut(self) shortcut3.setKey(Qt.Key_Up) shortcut3.activated.connect(lambda: self.selectLayer(-1)) shortcut4 = QShortcut(self) shortcut4.setKey(Qt.Key_Down) shortcut4.activated.connect(lambda: self.selectLayer(1)) shortcut5 = QShortcut(self) shortcut5.setKey(Qt.Key_Space) shortcut5.activated.connect(self.timelineWidget.playPauseClicked) ### settings ### self.readSettings() self.show()
class MainWindow(QMainWindow): """ Main windows of the application """ def __init__(self): QMainWindow.__init__(self) QApplication.setOrganizationName("z-uo") QApplication.setApplicationName("pixeditor") self.colorDialog = QColorDialog() self.colorDialog.setOptions(QColorDialog.NoButtons) #self.colorDialog.hide() self.project = Project(self) self.rgbWidget = RgbSlidersWidget(self) self.rgbWidget.colorChanged.connect(self.project.setColor) self.project.colorChanged.connect(lambda widget=self: widget.rgbWidget.setColor(QColor(widget.project.colorTable[widget.project.color]))) self.hsvWidget = HsvSlidersWidget(self) self.hsvWidget.colorChanged.connect(self.project.setColor) self.project.colorChanged.connect(lambda widget=self: widget.hsvWidget.setColor(QColor(widget.project.colorTable[widget.project.color]))) self.hslWidget = HslSlidersWidget(self) self.hslWidget.colorChanged.connect(self.project.setColor) self.project.colorChanged.connect(lambda widget=self: widget.hslWidget.setColor(QColor(widget.project.colorTable[widget.project.color]))) self.cmykWidget = CmykSlidersWidget(self) self.cmykWidget.colorChanged.connect(self.project.setColor) self.project.colorChanged.connect(lambda widget=self: widget.cmykWidget.setColor(QColor(widget.project.colorTable[widget.project.color]))) self.contextWidget = ContextWidget(self.project) self.optionsWidget = OptionsWidget(self.project) self.paletteWidget = PaletteWidget(self.project) self.timelineWidget = TimelineWidget(self.project) self.scene = Scene(self.project) self.toolsWidget = ToolWidget(self) self.updateTitle() self.project.updateTitleSign.connect(self.updateTitle) self.setCentralWidget(self.scene) self.setDockNestingEnabled(True) toolsDock = QDockWidget("Tools") toolsDock.setWidget(self.toolsWidget) toolsDock.setObjectName("toolsDock") self.addDockWidget(Qt.LeftDockWidgetArea, toolsDock) contextDock = QDockWidget("Context") contextDock.setWidget(self.contextWidget) contextDock.setObjectName("contextDock") self.addDockWidget(Qt.LeftDockWidgetArea, contextDock) optionsDock = QDockWidget("Options") optionsDock.setWidget(self.optionsWidget) optionsDock.setObjectName("optionsDock") self.addDockWidget(Qt.LeftDockWidgetArea, optionsDock) paletteDock = QDockWidget("Palette") paletteDock.setWidget(self.paletteWidget) paletteDock.setObjectName("paletteDock") self.addDockWidget(Qt.LeftDockWidgetArea, paletteDock) #colorDialogDock = QDockWidget("Color Dialog") #colorDialogDock.setWidget(self.colorDialog) #colorDialogDock.setObjectName("colorDialog") #self.addDockWidget(Qt.LeftDockWidgetArea, colorDialogDock) rgbDock = QDockWidget("RGB") rgbDock.setWidget(self.rgbWidget) rgbDock.setObjectName("rgbDock") self.addDockWidget(Qt.LeftDockWidgetArea, rgbDock) hsvDock = QDockWidget("HSV") hsvDock.setWidget(self.hsvWidget) hsvDock.setObjectName("hsvDock") self.addDockWidget(Qt.LeftDockWidgetArea, hsvDock) hslDock = QDockWidget("HSL") hslDock.setWidget(self.hslWidget) hslDock.setObjectName("hslDock") self.addDockWidget(Qt.LeftDockWidgetArea, hslDock) cmykDock = QDockWidget("CMYK") cmykDock.setWidget(self.cmykWidget) cmykDock.setObjectName("cmykDock") self.addDockWidget(Qt.LeftDockWidgetArea, cmykDock) self.tabifyDockWidget(rgbDock, hsvDock) self.tabifyDockWidget(hsvDock, hslDock) self.tabifyDockWidget(hslDock, cmykDock) hsvDock.close() cmykDock.close() rgbDock.raise_() timelineDock = Dock("Timeline") timelineDock.setWidget(self.timelineWidget) timelineDock.setObjectName("timelineDock") timelineDock.setFeatures(QDockWidget.DockWidgetVerticalTitleBar | QDockWidget.AllDockWidgetFeatures) self.addDockWidget(Qt.BottomDockWidgetArea, timelineDock) ### Toolbar ### toolActions = QActionGroup(self) toolActions.setExclusive(True) penToolAction = QAction(QIcon("icons/tool_pen.png"), "&Pen", toolActions) penToolAction.setCheckable(True) penToolAction.setChecked(True) penToolAction.triggered.connect(self.penToolAction) pipetteToolAction = QAction(QIcon("icons/tool_pipette.png"), "P&ipette", toolActions) pipetteToolAction.setCheckable(True) pipetteToolAction.triggered.connect(self.pipetteToolAction) fillToolAction = QAction(QIcon("icons/tool_fill.png"), "&Fill", toolActions) fillToolAction.setCheckable(True) fillToolAction.triggered.connect(self.fillToolAction) moveToolAction = QAction(QIcon("icons/tool_move.png"), "&Move", toolActions) moveToolAction.setCheckable(True) moveToolAction.triggered.connect(self.moveToolAction) selectToolAction = QAction(QIcon("icons/tool_select.png"), "&Select", toolActions) selectToolAction.setCheckable(True) selectToolAction.triggered.connect(self.selectToolAction) toolbar = QToolBar("Tools") toolbar.addAction(penToolAction) toolbar.addAction(pipetteToolAction) toolbar.addAction(fillToolAction) toolbar.addAction(moveToolAction) toolbar.addAction(selectToolAction) toolbar.setObjectName("toolsToolbar") #self.addToolBar(toolbar) penToolAction.setShortcut('1') pipetteToolAction.setShortcut('2') fillToolAction.setShortcut('3') moveToolAction.setShortcut('4') selectToolAction.setShortcut('5') self.toolsWidget.addAction(penToolAction) self.toolsWidget.addAction(pipetteToolAction) self.toolsWidget.addAction(fillToolAction) self.toolsWidget.addAction(moveToolAction) self.toolsWidget.addAction(selectToolAction) ### File menu ### menubar = self.menuBar() newAction = QAction('&New', self) newAction.triggered.connect(self.newAction) openAction = QAction('&Open', self) openAction.triggered.connect(self.openAction) openAction.setShortcut(QKeySequence.Open) saveAsAction = QAction('Save &as', self) saveAsAction.triggered.connect(self.saveAsAction) saveAsAction.setShortcut(QKeySequence.SaveAs) saveAction = QAction('&Save', self) saveAction.triggered.connect(self.saveAction) saveAction.setShortcut(QKeySequence.Save) importNewAction = QAction('&Import as new', self) importNewAction.triggered.connect(self.importAsNewAction) importLayerAction = QAction('I&mport as layer', self) importLayerAction.triggered.connect(self.importAsLayerAction) exportAction = QAction('&Export', self) exportAction.triggered.connect(self.exportAction) exportAction.setShortcut('Ctrl+E') exitAction = QAction('E&xit', self) exitAction.triggered.connect(self.exitAction) exitAction.setShortcut(QKeySequence.Quit) fileMenu = menubar.addMenu('&File') fileMenu.addAction(newAction) fileMenu.addAction(openAction) fileMenu.addAction(saveAsAction) fileMenu.addAction(saveAction) fileMenu.addSeparator() fileMenu.addAction(importNewAction) fileMenu.addAction(importLayerAction) fileMenu.addAction(exportAction) fileMenu.addSeparator() fileMenu.addAction(exitAction) ### Edit menu ### undoAction = QAction('&Undo', self) undoAction.triggered.connect(self.project.undo) undoAction.setShortcut(QKeySequence.Undo) redoAction = QAction('&Redo', self) redoAction.triggered.connect(self.project.redo) redoAction.setShortcut(QKeySequence.Redo) cutAction = QAction('&Cut', self) cutAction.triggered.connect(self.timelineWidget.cut) cutAction.setShortcut(QKeySequence.Cut) copyAction = QAction('C&opy', self) copyAction.triggered.connect(self.timelineWidget.copy) copyAction.setShortcut(QKeySequence.Copy) pasteAction = QAction('&Paste', self) pasteAction.triggered.connect(self.timelineWidget.paste) pasteAction.setShortcut(QKeySequence.Paste) editMenu = menubar.addMenu('&Edit') editMenu.addAction(undoAction) editMenu.addAction(redoAction) editMenu.addSeparator() editMenu.addAction(cutAction) editMenu.addAction(copyAction) editMenu.addAction(pasteAction) ### tools menu ### toolsMenu = menubar.addMenu('&Tools') toolsMenu.addAction(penToolAction) toolsMenu.addAction(pipetteToolAction) toolsMenu.addAction(fillToolAction) toolsMenu.addAction(moveToolAction) toolsMenu.addAction(selectToolAction) ### view menu ### viewMenu = menubar.addMenu('&View') toolbars = self.findChildren(QToolBar) for toolbar in toolbars: viewMenu.addAction(toolbar.toggleViewAction()) viewMenu.addSeparator() dockWidgets = self.findChildren(QDockWidget) for dock in dockWidgets: viewMenu.addAction(dock.toggleViewAction()) viewMenu.addSeparator() self.lockLayoutAction = QAction('&Lock Layout', self) self.lockLayoutAction.setCheckable(True) self.lockLayoutAction.triggered.connect(lambda checked, widget=self: widget.setLayoutLocked(checked)) viewMenu.addAction(self.lockLayoutAction) ### project menu ### cropAction = QAction('&Crop', self) cropAction.triggered.connect(self.cropAction) resizeAction = QAction('&Resize', self) resizeAction.triggered.connect(self.resizeAction) replacePaletteAction = QAction('Replace &palette', self) replacePaletteAction.triggered.connect(self.replacePaletteAction) prefAction = QAction('&Background', self) prefAction.triggered.connect(self.backgroundAction) projectMenu = menubar.addMenu('&Project') projectMenu.addAction(cropAction) projectMenu.addAction(resizeAction) projectMenu.addSeparator() projectMenu.addAction(replacePaletteAction) projectMenu.addSeparator() projectMenu.addAction(prefAction) ### resources menu ### savePaletteAction = QAction('Save current &palette', self) savePaletteAction.triggered.connect(self.savePaletteAction) savePenAction = QAction('Save &custom pen', self) savePenAction.triggered.connect(self.savePenAction) reloadResourcesAction = QAction('&Reload resources', self) reloadResourcesAction.triggered.connect(self.reloadResourcesAction) resourcesMenu = menubar.addMenu('&Resources') resourcesMenu.addAction(savePaletteAction) resourcesMenu.addAction(savePenAction) resourcesMenu.addSeparator() resourcesMenu.addAction(reloadResourcesAction) ### shortcuts ### shortcut = QShortcut(self) shortcut.setKey(Qt.Key_Left) shortcut.activated.connect(lambda: self.selectFrame(-1)) shortcut2 = QShortcut(self) shortcut2.setKey(Qt.Key_Right) shortcut2.activated.connect(lambda: self.selectFrame(1)) shortcut3 = QShortcut(self) shortcut3.setKey(Qt.Key_Up) shortcut3.activated.connect(lambda: self.selectLayer(-1)) shortcut4 = QShortcut(self) shortcut4.setKey(Qt.Key_Down) shortcut4.activated.connect(lambda: self.selectLayer(1)) shortcut5 = QShortcut(self) shortcut5.setKey(Qt.Key_Space) shortcut5.activated.connect(self.timelineWidget.playPauseClicked) ### settings ### self.readSettings() self.show() def writeSettings(self): settings = QSettings() settings.beginGroup("mainWindow") settings.setValue("geometry", self.saveGeometry()) settings.setValue("windowState", self.saveState()) settings.setValue("layoutLocked", self.lockLayoutAction.isChecked()) settings.endGroup() def readSettings(self): settings = QSettings() settings.beginGroup("mainWindow") try: self.restoreGeometry(settings.value("geometry")) except TypeError: pass # no geometry to restore so leave as is try: self.restoreState(settings.value("windowState")) except TypeError: pass # no state to restore so leave as is try: self.lockLayoutAction.setChecked(settings.value("layoutLocked", type=bool)) self.setLayoutLocked(self.lockLayoutAction.isChecked()) #if self.lockLayoutAction.isChecked(): #self.lockLayoutAction.trigger() # why no work? except TypeError: pass settings.endGroup() ######## Toolbar ##################################################### def penToolAction(self): self.project.tool = "pen" self.project.toolChanged.emit() self.optionsWidget.optionFill.hide() self.optionsWidget.optionSelect.hide() self.optionsWidget.optionMove.hide() def pipetteToolAction(self): self.project.tool = "pipette" self.project.toolChanged.emit() self.optionsWidget.optionFill.hide() self.optionsWidget.optionSelect.hide() self.optionsWidget.optionMove.hide() def fillToolAction(self): self.project.tool = "fill" self.project.toolChanged.emit() self.optionsWidget.optionFill.show() self.optionsWidget.optionSelect.hide() self.optionsWidget.optionMove.hide() def moveToolAction(self): self.project.tool = "move" self.project.toolChanged.emit() self.optionsWidget.optionFill.hide() self.optionsWidget.optionSelect.hide() self.optionsWidget.optionMove.show() def selectToolAction(self): self.project.tool = "select" self.project.toolChanged.emit() self.optionsWidget.optionFill.hide() self.optionsWidget.optionSelect.show() self.optionsWidget.optionMove.hide() ######## File menu ################################################# def openAction(self): xml, url = open_pix(self.project.dirUrl) if xml and url: self.project.saveToUndo("all") self.project.importXml(xml) self.project.updateViewSign.emit() self.project.updatePaletteSign.emit() self.project.updateTimelineSign.emit() self.project.updateBackgroundSign.emit() self.project.updateFpsSign.emit() self.project.url = url self.project.dirUrl = os.path.dirname(url) def saveAsAction(self): url = get_save_url(self.project.dirUrl) if url: url = save_pix(self.project.exportXml(), url) if url: self.project.url = url self.project.dirUrl = os.path.dirname(url) self.project.saved = True self.updateTitle() def saveAction(self): if self.project.url: url = save_pix(self.project.exportXml(), self.project.url) if url: self.project.url = url self.project.dirUrl = os.path.dirname(url) self.project.saved = True self.updateTitle() else: self.saveAsAction() def importAsNewAction(self): size, frames, colorTable = import_img(self.project, self.project.dirUrl) if size and frames and colorTable: self.project.saveToUndo("all") self.project.initProject(size, colorTable, frames) self.project.updateViewSign.emit() self.project.updatePaletteSign.emit() self.project.updateTimelineSign.emit() def importAsLayerAction(self): size, frames, colorTable = import_img(self.project, self.project.dirUrl, self.project.size, self.project.colorTable) if size and frames and colorTable: self.project.saveToUndo("all") self.project.importImg(size, colorTable, frames) self.project.updateViewSign.emit() self.project.updatePaletteSign.emit() self.project.updateTimelineSign.emit() def exportAction(self): export_png(self.project, self.project.dirUrl) def closeEvent(self, event): self.writeSettings() self.exitAction() def exitAction(self): message = QMessageBox() message.setWindowTitle("Quit?") message.setText("Are you sure you want to quit?"); message.setIcon(QMessageBox.Warning) message.addButton("Cancel", QMessageBox.RejectRole) message.addButton("Yes", QMessageBox.AcceptRole) ret = message.exec_(); if ret: qApp.quit() ######## View menu ############################################## def setLayoutLocked(self, isLocked): widgets = self.findChildren(QDockWidget) + self.findChildren(QToolBar) for widget in widgets: if isLocked is True: if widget.isFloating(): if isinstance(widget, QDockWidget): widget.setTitleBarWidget(None) widget.setFeatures(QDockWidget.DockWidgetFloatable) widget.setAllowedAreas(Qt.NoDockWidgetArea) elif isinstance(widget, QToolBar): widget.setAllowedAreas(Qt.NoToolBarArea) else: if isinstance(widget, QDockWidget): widget.setTitleBarWidget(QWidget()) widget.setFeatures(QDockWidget.NoDockWidgetFeatures) elif isinstance(widget, QToolBar): widget.setFloatable(False) widget.setMovable(False) else: if isinstance(widget, QDockWidget): widget.setFeatures(QDockWidget.AllDockWidgetFeatures) widget.setTitleBarWidget(None) widget.setAllowedAreas(Qt.AllDockWidgetAreas) elif isinstance(widget, QToolBar): widget.setFloatable(True) widget.setMovable(True) widget.setAllowedAreas(Qt.AllToolBarAreas) ######## Project menu ############################################## def newAction(self): dialog = NewDialog() if dialog.exec_() == QDialog.Accepted: size = QSize(dialog.resultData["width"], dialog.resultData["height"]) palette = import_palette(dialog.resultData["palette"]) if size and palette: self.project.saveToUndo("all") self.project.initProject(size, palette) self.project.updateViewSign.emit() self.project.updatePaletteSign.emit() self.project.updateTimelineSign.emit() self.project.updateBackgroundSign.emit() self.project.updateFpsSign.emit() self.updateTitle() def cropAction(self): rect = CropDialog(self.project.size).getReturn() if rect: self.project.saveToUndo("size") self.project.timeline.applyToAllCanvas( lambda c: Canvas(self.project, c.copy(rect))) self.project.size = rect.size() self.project.updateViewSign.emit() def resizeAction(self): factor = ResizeDialog(self.project.size).getReturn() if factor and factor != 1: self.project.saveToUndo("size") newSize = self.project.size * factor self.project.timeline.applyToAllCanvas( lambda c: Canvas(self.project, c.scaled(newSize))) self.project.size = newSize self.project.updateViewSign.emit() def replacePaletteAction(self): #dir = QDir.current() #dir.cd("resources/palette") palettePath = os.path.abspath(os.path.join("resources", "palette")) url = QFileDialog.getOpenFileName(None, "open palette file", #dir.path(), palettePath, "Palette files (*.pal, *.gpl);;All files (*)") if url: pal = import_palette(url, len(self.project.colorTable)) if pal: self.project.saveToUndo("colorTable_frames") self.project.colorTable = pal for i in self.project.timeline.getAllCanvas(): i.setColorTable(self.project.colorTable) self.project.updateViewSign.emit() self.project.updatePaletteSign.emit() def backgroundAction(self): color, pattern = BackgroundDialog(self.project.bgColor, self.project.bgPattern).getReturn() if color and pattern: self.project.saveToUndo("background") self.project.bgColor = color self.project.bgPattern = pattern self.project.updateBackgroundSign.emit() def savePaletteAction(self): url = get_save_url(os.path.join("resources", "palette"), "pal") pal = export_palette(self.project.colorTable) if url: try: save = open(url, "w") save.write(pal) save.close() print("saved") except IOError: print("Can't open file") def savePenAction(self): if self.project.penDict["custom"]: url = get_save_url(os.path.join("resources", "pen"), "py") pen = export_pen(self.project.penDict["custom"], os.path.splitext(os.path.basename(url))[0]) if url: try: save = open(url, "w") save.write(pen) save.close() print("saved") except IOError: print("Can't open file") def reloadResourcesAction(self): self.project.importResources() self.toolsWidget.penWidget.loadPen() self.toolsWidget.brushWidget.loadBrush() ######## Shortcuts ################################################# def selectFrame(self, n): maxF = max([len(l) for l in self.project.timeline]) if 0 <= self.project.curFrame + n < maxF: self.project.curFrame += n self.project.updateTimelineSign.emit() self.project.updateViewSign.emit() def selectLayer(self, n): if 0 <= self.project.curLayer + n < len(self.project.timeline): self.project.curLayer += n self.project.updateTimelineSign.emit() self.project.updateViewSign.emit() def updateTitle(self): url, sav = "untitled", "* " if self.project.saved: sav = "" if self.project.url: url = os.path.basename(self.project.url) self.setWindowTitle("%s%s - pixeditor" % (sav, url))
def __init__(self, workingDir): self.workingDir = workingDir self.project = Project()
def project_create(project_name: str, description: str = None): """Create the new project.""" project = Project(id=None, name=project_name, description=description) database.create_project(project) typer.echo(f"Project `{project_name}` created.")
def generate_project(prj: Project): # generate project Makefile project_makefile = project_dir / "Makefile" P = PurePosixPath makefile_cwd = project_dir # relative_source_dir = Path().relative_to(self.output_dir) build_dir_rel = relpath(build_dir, makefile_cwd) input_exe_path = relpath(prj.exe_path, makefile_cwd) prj.output_path = relpath(project_dir / prj.exe_path.name, makefile_cwd) ldscript = relpath("i386pe.x", makefile_cwd) with open(project_makefile, "wt", newline='\n') as f: all_obj = [] for src in prj.sources: obj_path = relpath(build_dir / src.path.stem, makefile_cwd).with_suffix(".o") all_obj.append(obj_path) # link objects obj_paths = " ".join([str(P(obj_path)) for obj_path in all_obj]) # FIXME: un-hardcode! text_start = 0x10001000 print(f""" #PREFIX=i686-w64-mingw32- AS=$(PREFIX)as LD=$(PREFIX)ld OBJCOPY=$(PREFIX)objcopy OBJDUMP=$(PREFIX)objdump ALLCODE_BIN={P(build_dir_rel)}/allcode.bin ALLCODE_O={P(build_dir_rel)}/allcode.o ALLCODE_S={P(build_dir_rel)}/allcode.s OUTPUT_EXE={P(prj.output_path)} OUTPUT_S={P(build_dir_rel)}/output.s COPY_WITH_PATCH={P(relpath("copy_with_patch.py", project_dir))} all: input.s $(OUTPUT_EXE) $(OUTPUT_S) input.s: {P(input_exe_path)} \t$(OBJDUMP) -M intel -D -h $< | tail -n +3 >$@ $(ALLCODE_O): {obj_paths} {P(ldscript)} \tar rcs {P(build_dir_rel)}/allcode.a {obj_paths} \t$(LD) -T {P(ldscript)} -Ttext=0x{text_start:08x} {obj_paths} -o $@ \t$(OBJDUMP) -M intel -D -h $(ALLCODE_O) >$(ALLCODE_S) $(ALLCODE_BIN): $(ALLCODE_O) \t$(OBJCOPY) --only-section=.text -O binary $< $@ $(OUTPUT_EXE): $(ALLCODE_BIN) {P(input_exe_path)} \t$(COPY_WITH_PATCH) {P(input_exe_path)} $@ {exe_patch_offset} $(ALLCODE_BIN) \t#cp {P(input_exe_path)} $@ \t#dd if=$(ALLCODE_BIN) of=$@ obs=1 seek={exe_patch_offset} conv=notrunc 2>&1 $(OUTPUT_S): $(OUTPUT_EXE) \t$(OBJDUMP) -M intel -D -h $< | tail -n +3 >$@ """, file=f) for src in prj.sources: src_path = relpath(src.path, makefile_cwd) obj_path = relpath(build_dir / src.path.stem, makefile_cwd).with_suffix(".o") # TODO DRY print(f"{P(obj_path)}: {P(src_path)}", file=f) if AS == "gas": print(f"\t$(AS) $< -o $@", file=f) print(file=f)
def disassemble_and_make_project(INPUT_PATH, project_dir: Path, disassembler_db: DisassemblerDb): build_dir = project_dir / "build" gen_asm_dir = project_dir / "gen-asm" # create output directories # TODO: gen_asm_dir should be emptied, since cluster boundaries can change between runs for dir in {project_dir, build_dir, gen_asm_dir}: dir.mkdir(parents=True, exist_ok=True) prj = Project(INPUT_PATH, project_dir, disassembler_db_snapshot=deepcopy(disassembler_db)) pe = pefile.PE(INPUT_PATH) exe_patch_offset = pe.sections[0].PointerToRawData clusters = data_io.load_clusters(project_dir / "tmp-clusters") labels_db = data_io.load_labels(project_dir, suffix=".tmp") print(f"Disassembling {len(clusters)} clusters...") for cluster in clusters: filename = gen_asm_dir / f"{cluster.section_name[1:]}_{cluster.start:08X}.s" print(f" - {filename} : {len(cluster.chunks)} chunks") if cluster.start < MIN_OFFSET: continue total_length = sum([len(chunk.bytes) for chunk in cluster.chunks]) cluster_end = cluster.start + total_length with open(filename, 'wt') as f: if AS == "gas": print(f"""\ .intel_syntax .section {cluster.section_name} """, file=f) # export labels for label in sorted(labels_db.values()): if label.address >= cluster_end: break elif label.address >= cluster.start: print( f".global {gnuas_escape_label(label.name):40s} /* {label} */", file=f) print(file=f) disassembly_gas.disassemble_for_GAS( cluster.chunks, f, disassembler_db=disassembler_db, labels_db=labels_db, use_labels=True) if AS == "nasm": print(f"""\ section {cluster.section_name} """, file=f) analysis.disassemble_for_nasm(cluster.chunks, f, labels_db=labels_db, use_labels=True) prj.add_asm_source(filename, cluster.start, total_length) # Generate MinGW project def relpath(path_to, path_from): path_to = Path(path_to).resolve() path_from = Path(path_from).resolve() try: for p in (*reversed(path_from.parents), path_from): head, tail = p, path_to.relative_to(p) except ValueError: # Stop when the paths diverge. pass return Path( '../' * (len(path_from.parents) - len(head.parents))).joinpath(tail) def generate_project(prj: Project): # generate project Makefile project_makefile = project_dir / "Makefile" P = PurePosixPath makefile_cwd = project_dir # relative_source_dir = Path().relative_to(self.output_dir) build_dir_rel = relpath(build_dir, makefile_cwd) input_exe_path = relpath(prj.exe_path, makefile_cwd) prj.output_path = relpath(project_dir / prj.exe_path.name, makefile_cwd) ldscript = relpath("i386pe.x", makefile_cwd) with open(project_makefile, "wt", newline='\n') as f: all_obj = [] for src in prj.sources: obj_path = relpath(build_dir / src.path.stem, makefile_cwd).with_suffix(".o") all_obj.append(obj_path) # link objects obj_paths = " ".join([str(P(obj_path)) for obj_path in all_obj]) # FIXME: un-hardcode! text_start = 0x10001000 print(f""" #PREFIX=i686-w64-mingw32- AS=$(PREFIX)as LD=$(PREFIX)ld OBJCOPY=$(PREFIX)objcopy OBJDUMP=$(PREFIX)objdump ALLCODE_BIN={P(build_dir_rel)}/allcode.bin ALLCODE_O={P(build_dir_rel)}/allcode.o ALLCODE_S={P(build_dir_rel)}/allcode.s OUTPUT_EXE={P(prj.output_path)} OUTPUT_S={P(build_dir_rel)}/output.s COPY_WITH_PATCH={P(relpath("copy_with_patch.py", project_dir))} all: input.s $(OUTPUT_EXE) $(OUTPUT_S) input.s: {P(input_exe_path)} \t$(OBJDUMP) -M intel -D -h $< | tail -n +3 >$@ $(ALLCODE_O): {obj_paths} {P(ldscript)} \tar rcs {P(build_dir_rel)}/allcode.a {obj_paths} \t$(LD) -T {P(ldscript)} -Ttext=0x{text_start:08x} {obj_paths} -o $@ \t$(OBJDUMP) -M intel -D -h $(ALLCODE_O) >$(ALLCODE_S) $(ALLCODE_BIN): $(ALLCODE_O) \t$(OBJCOPY) --only-section=.text -O binary $< $@ $(OUTPUT_EXE): $(ALLCODE_BIN) {P(input_exe_path)} \t$(COPY_WITH_PATCH) {P(input_exe_path)} $@ {exe_patch_offset} $(ALLCODE_BIN) \t#cp {P(input_exe_path)} $@ \t#dd if=$(ALLCODE_BIN) of=$@ obs=1 seek={exe_patch_offset} conv=notrunc 2>&1 $(OUTPUT_S): $(OUTPUT_EXE) \t$(OBJDUMP) -M intel -D -h $< | tail -n +3 >$@ """, file=f) for src in prj.sources: src_path = relpath(src.path, makefile_cwd) obj_path = relpath(build_dir / src.path.stem, makefile_cwd).with_suffix(".o") # TODO DRY print(f"{P(obj_path)}: {P(src_path)}", file=f) if AS == "gas": print(f"\t$(AS) $< -o $@", file=f) print(file=f) # all_obj = [] # # for src in prj.sources: # if src.offset < MIN_OFFSET: continue # # # patch_offset = src.offset + prj.text_vma_to_file_offset # # print(f"makeproject: {src.path} @ {src.offset:08X}h") # # # strategy: compile asm source to .o, export as flat binary, patch exe file (diff in the end) # src_path = relpath(src.path, makefile_cwd) # obj1_path = relpath(prj.output_dir / (src.path.stem + "a"), makefile_cwd).with_suffix(".o") # obj_path = relpath(prj.output_dir / src.path.stem, makefile_cwd).with_suffix(".o") # dasm_path = relpath(prj.output_dir / src.path.stem, makefile_cwd).with_suffix(".s") # bin_path = relpath(prj.output_dir / src.path.stem, makefile_cwd).with_suffix(".bin") # # # print(f"# cluster {src.offset:08X}h: {src.length:6} bytes @ {patch_offset:X}h", file=f) # # if AS == "nasm": # print(f"nasm {P(src_path)} -f elf32 -o {P(obj_path)}", file=f) # #print(f"$LD -Ttext=0x{src.offset:08X} {P(obj1_path)} -o {P(obj_path)}", file=f) # # print(f"$OBJDUMP -M intel -D {P(obj_path)} >{P(dasm_path)}", file=f) # # print(f"$OBJCOPY --only-section=.text -O binary {P(obj_path)} {P(bin_path)}", file=f) # # print(f"dd if={P(bin_path)} of={P(prj.output_path)} obs=1 seek={patch_offset} conv=notrunc", file=f) # # print(file=f) # # all_obj.append(obj_path) #break # print(f""" # # post-diff # cmp -l {P(input_exe_path)} {P(prj.output_path)} | gawk '{{printf "%08X %02X %02X\\n", $1, strtonum(0$2), strtonum(0$3)}}' # """, file=f) # generate linker script # ndisasm bigobj & compare # print(f"ndisasm bigobj.bin -b 32 -o 0x401000 >bigobj.asm", file=f) generate_project(prj) return prj