Beispiel #1
0
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}"
        )
Beispiel #2
0
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}")
Beispiel #3
0
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}")
Beispiel #4
0
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}")
Beispiel #5
0
    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()
Beispiel #6
0
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()
Beispiel #7
0
    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()
Beispiel #8
0
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()
Beispiel #9
0
    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()
Beispiel #10
0
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))
Beispiel #11
0
 def __init__(self, workingDir):
     self.workingDir = workingDir
     self.project = Project()
Beispiel #12
0
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.")
Beispiel #13
0
    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)
Beispiel #14
0
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