Finished welcome dialog. New project dialog prototype.

This commit is contained in:
Tiberiu Chibici 2018-08-03 14:30:15 +03:00
parent 59cd033cad
commit 037843d14f
17 changed files with 9466 additions and 8889 deletions

View File

@ -7,8 +7,9 @@ UI_OUT=$(UI:.ui=_ui.py)
all: $(RESOURCES_OUT) $(UI_OUT) all: $(RESOURCES_OUT) $(UI_OUT)
clean: clean:
rm ${UI_OUT} rm -f ${UI_OUT}
rm ${RESOURCES_OUT} rm -f ${RESOURCES_OUT}
find -name '__pycache__' -exec rm -rf "{}" \;
%_rc.py: %.qrc %_rc.py: %.qrc
pyrcc5 $< -o $@ pyrcc5 $< -o $@

View File

@ -0,0 +1 @@
from .project_manager import ProjectManager

View File

@ -1,49 +1,90 @@
from typing import Iterable
from model.project import Project from model.project import Project
from model import Project, RecentProject
from storage import AppDataStorage
class ProjectManager(object): class ProjectManager(object):
def __init__(self, appDataStorage): def __init__(self, appDataStorage : AppDataStorage):
self.__appDataStorage = appDataStorage self.__appDataStorage = appDataStorage
self.__recentProjects = None self.__recentProjects : dict = None
def getRecentProjects(self): """
Gets a list of recent projects. The list is lazily loaded on the first call.
Returns:
list of RecentProjects
"""
def getRecentProjects(self) -> Iterable[RecentProject]:
if self.__recentProjects is None: if self.__recentProjects is None:
self.__recentProjects = {} self.__recentProjects = {}
for item in self.__appDataStorage.readRecentProjects(): for item in self.__appDataStorage.readRecentProjects():
self.__recentProjects[item['path']] = item self.__recentProjects[item.path] = item
return self.__recentProjects.values() return self.__recentProjects.values()
def pinRecentProject(self, entry, isPinned = True): """
entry['pinned'] = isPinned Pins a recent project.
Args:
entry: recent project
isPinned: pinned or not
"""
def pinRecentProject(self, entry : RecentProject, isPinned : bool = True):
entry.pinned = isPinned
self.__appDataStorage.writeRecentProjects(self.__recentProjects.values()) self.__appDataStorage.writeRecentProjects(self.__recentProjects.values())
def deleteRecentProject(self, entry): """
self.__recentProjects.pop(entry['path'], None) Deletes a recent project.
Args:
entry: recent project
"""
def deleteRecentProject(self, entry : RecentProject):
self.__recentProjects.pop(entry.path, None)
self.__appDataStorage.writeRecentProjects(self.__recentProjects.values()) self.__appDataStorage.writeRecentProjects(self.__recentProjects.values())
def debug_populateRecentProjects(self): """
self.__recentProjects['/home/tibi/Videos/project.pro'] = { Creates a new project at the given path, and returns the created project.
'name' : 'Debug project',
'path' : '/home/tibi/Videos/project.pro', Args:
'pinned' : True, path: path to project file
'date' : 1 """
} def newProject(self, path : str) -> Project:
self.__recentProjects['/home/tibi/Videos/project2.pro'] = { return Project(path)
'name' : 'Debug project 2',
'path' : '/home/tibi/Videos/project2.pro', """
'pinned' : False, Opens an existing project.
'date' : 2
} Args:
self.__recentProjects['/home/tibi/Videos/project3.pro'] = { path: path to project file
'name' : 'Debug project 3', """
'path' : '/home/tibi/Videos/project3.pro', def openProject(self, path : str) -> Project:
'pinned' : False, return Project(path)
'date' : 3
} # def debug_populateRecentProjects(self):
self.__recentProjects['/home/tibi/Videos/project4.pro'] = { # self.__recentProjects['/home/tibi/Videos/project.pro'] = {
'name' : 'Debug project 4', # 'name' : 'Debug project',
'path' : '/home/tibi/Videos/project4.pro', # 'path' : '/home/tibi/Videos/project.pro',
'pinned' : False, # 'pinned' : True,
'date' : 4 # 'date' : 1
} # }
# self.__recentProjects['/home/tibi/Videos/project2.pro'] = {
# 'name' : 'Debug project 2',
# 'path' : '/home/tibi/Videos/project2.pro',
# 'pinned' : False,
# 'date' : 2
# }
# self.__recentProjects['/home/tibi/Videos/project3.pro'] = {
# 'name' : 'Debug project 3',
# 'path' : '/home/tibi/Videos/project3.pro',
# 'pinned' : False,
# 'date' : 3
# }
# self.__recentProjects['/home/tibi/Videos/project4.pro'] = {
# 'name' : 'Debug project 4',
# 'path' : '/home/tibi/Videos/project4.pro',
# 'pinned' : False,
# 'date' : 4
# }

View File

@ -0,0 +1,2 @@
from .recent_project import RecentProject
from .project import Project

View File

@ -1,7 +1,7 @@
class Project(object): class Project(object):
def __init__(self): def __init__(self, path):
self.root_dir = None self.root_dir = path
def get_items(self): def get_items(self):
pass pass

60
model/recent_project.py Normal file
View File

@ -0,0 +1,60 @@
import time
from typing import List
class RecentProject(object):
DICT_FIELDS = [ 'path', 'name', 'dateAccessed', 'pinned' ]
"""
Creates new instance of RecentProject.
Args:
name: name of the project
path: path to the project
dateAccessed: date (unix time) when project was last accessed
pinned: the project is pinned by the user
Remarks:
If dateAccessed = None, it will be set to the current date and time.
"""
def __init__(self, name: str, path: str, dateAccessed : int = None, pinned : bool = False):
self.name = name
self.path = path
self.dateAccessed = dateAccessed
self.pinned = pinned
if (self.dateAccessed is None):
self.dateAccessed = int(time.time())
"""
Creates new instance of RecentProject from a dictionary.
If the dateAccessed and pinned fields are strings, they are parsed.
Raises:
ValueError if date cannot be parsed.
"""
@staticmethod
def fromDictionary(data : dict) -> 'RecentProject':
name = data['name']
path = data['path']
dateAccessed = data['dateAccessed']
pinned = data['pinned']
if isinstance(dateAccessed, str):
dateAccessed = int(dateAccessed)
if isinstance(pinned, str):
pinned = pinned.lower() in [ 'yes', 'y', 'true', '1', 'on' ]
return RecentProject(name, path, dateAccessed, pinned)
"""
Serialize to dictionary.
"""
def toDictionary(self) -> dict:
return {
"name" : self.name,
"path" : self.path,
"dateAccessed" : self.dateAccessed,
"pinned" : self.pinned
}

View File

@ -3,4 +3,6 @@ APP_VERSION = "1.0"
APP_AUTHOR = "Tiberiu Chibici" APP_AUTHOR = "Tiberiu Chibici"
APP_AUTHOR_SHORT = "TibiCh" APP_AUTHOR_SHORT = "TibiCh"
PROJECT_EXTENSION = "emproj"
DEBUG = 1 DEBUG = 1

File diff suppressed because it is too large Load Diff

1
storage/__init__.py Normal file
View File

@ -0,0 +1 @@
from .appdata_storage import AppDataStorage

View File

@ -2,14 +2,15 @@ import appdirs
import os import os
from configparser import ConfigParser from configparser import ConfigParser
import csv import csv
from typing import Iterable
from properties import config from properties import config
from model import RecentProject
class AppDataStorage(object): class AppDataStorage(object):
SETTINGS_FILE = "config.ini" SETTINGS_FILE = "config.ini"
RECENT_PROJECTS_FILE = "recent.cfg" RECENT_PROJECTS_FILE = "recent.cfg"
RECENT_PROJECTS_FIELDS = ["path", "name", "date", "pinned"]
def __init__(self): def __init__(self):
self.__appDataPath = appdirs.user_data_dir(config.APP_NAME, config.APP_AUTHOR_SHORT, config.APP_VERSION) self.__appDataPath = appdirs.user_data_dir(config.APP_NAME, config.APP_AUTHOR_SHORT, config.APP_VERSION)
@ -30,20 +31,33 @@ class AppDataStorage(object):
def writeSettings(self, settings): def writeSettings(self, settings):
pass # todo: finish this pass # todo: finish this
def __parseRow(self, row): """
row['date'] = int(row['date']) Reads recent projects list.
row['pinned'] = row['pinned'].lower() in ['true', 'yes', '1', 'on']
return row
def readRecentProjects(self): Returns:
list of recent projects
"""
def readRecentProjects(self) -> Iterable[RecentProject]:
if (os.path.exists(self.__recentProjectsPath)): if (os.path.exists(self.__recentProjectsPath)):
with open(self.__recentProjectsPath, 'r') as recentProjectsFile: with open(self.__recentProjectsPath, 'r') as recentProjectsFile:
csvreader = csv.DictReader(recentProjectsFile, fieldnames=AppDataStorage.RECENT_PROJECTS_FIELDS) csvreader = csv.DictReader(recentProjectsFile, fieldnames=RecentProject.DICT_FIELDS)
for row in csvreader: for row in csvreader:
yield self.__parseRow(row) try:
yield RecentProject.fromDictionary(row)
except ValueError:
print("Recent projects parse error - invalid date.", row)
except KeyError:
print("Recent projects parse error - fields not valid.", row)
def writeRecentProjects(self, items): """
Writes a list of recent projects.
Args:
items: list of RecentProjects
"""
def writeRecentProjects(self, items : Iterable[RecentProject]) -> None:
self.__createPath(self.__recentProjectsPath) self.__createPath(self.__recentProjectsPath)
with open(self.__recentProjectsPath, 'w') as recentProjectsFile: with open(self.__recentProjectsPath, 'w') as recentProjectsFile:
csvwriter = csv.DictWriter(recentProjectsFile, AppDataStorage.RECENT_PROJECTS_FIELDS) csvwriter = csv.DictWriter(recentProjectsFile, RecentProject.DICT_FIELDS)
csvwriter.writerows(items) for item in items:
csvwriter.writerow(item.toDictionary())

View File

@ -1,15 +1,20 @@
from PyQt5.QtWidgets import QMainWindow, QVBoxLayout, QWidget import traceback
from PyQt5.QtWidgets import QMainWindow, QVBoxLayout, QWidget, QApplication, QMessageBox
from PyQt5.QtCore import QTimer
from model import Project
from business import ProjectManager
from ui.project.project_panel import ProjectPanel from ui.project.project_panel import ProjectPanel
from ui.project.new_project_dialog import NewProjectDialog
from ui.welcome.welcome_dialog import WelcomeDialog from ui.welcome.welcome_dialog import WelcomeDialog
class MainWindow(QMainWindow): class MainWindow(QMainWindow):
def __init__(self, projectManager): def __init__(self, projectManager : ProjectManager):
super().__init__() super().__init__()
self.__projectManager = projectManager self.__projectManager = projectManager
self.setupUi() self.setupUi()
self.initializeApp() QTimer.singleShot(0, self.showWelcomeDialog)
def setupUi(self): def setupUi(self):
self.projectPanel = ProjectPanel() self.projectPanel = ProjectPanel()
@ -22,10 +27,28 @@ class MainWindow(QMainWindow):
self.setCentralWidget(cwidget) self.setCentralWidget(cwidget)
def initializeApp(self): def showWelcomeDialog(self):
# Show welcome dialog # Show welcome dialog
welcome = WelcomeDialog(self.__projectManager) welcome = WelcomeDialog(self.__projectManager, self)
res = welcome.exec() if welcome.exec() > 0:
if welcome.resultAction == WelcomeDialog.NEW_PROJECT:
self.newProject()
elif welcome.resultAction == WelcomeDialog.OPEN_PROJECT:
self.openProject(welcome.projectToOpen)
print("Dialog result:", res) def newProject(self):
dialog = NewProjectDialog(self.__projectManager, self)
if dialog.exec() > 0:
self.loadProject(dialog.project)
def openProject(self, projectPath : str = None):
try:
project = self.__projectManager.openProject(projectPath)
except Exception as ex:
print("Failed to open project: ", traceback.format_exc())
QMessageBox.critical(self,
self.tr('An error occurred'),
self.tr('The project could not be open.'))
def loadProject(self, project : Project):
pass

View File

@ -0,0 +1,61 @@
import traceback
from PyQt5.QtWidgets import QDialog, QWidget, QDialogButtonBox, QFileDialog, QPushButton, QMessageBox
from model import Project
from business import ProjectManager
from properties.config import PROJECT_EXTENSION
from ui.project.new_project_dialog_ui import Ui_NewProjectDialog
class NewProjectDialog(QDialog):
def __init__(self, projectManager : ProjectManager, parent : QWidget = None):
super().__init__(parent)
self.__projectManager = projectManager
self.project : Project = None
self.setupUi()
self.setupActions()
self.validate()
def setupUi(self):
self.ui = Ui_NewProjectDialog()
self.ui.setupUi(self)
self.__buttonOk : QPushButton = self.ui.buttonBox.button(QDialogButtonBox.Ok)
def setupActions(self):
self.ui.buttonBrowse.pressed.connect(self.browsePressed)
self.ui.textProjectPath.textChanged.connect(self.projectPathChanged)
self.ui.buttonBox.accepted.connect(self.okPressed)
def validate(self):
valid = True
if not self.ui.textProjectPath.text():
valid = False
self.__buttonOk.setEnabled(valid)
def browsePressed(self):
path = QFileDialog.getSaveFileName(
self,
self.tr('New project'),
'',
self.tr(f'Project files (*.{PROJECT_EXTENSION});;All files (*.*)'))
if path[0]:
self.ui.textProjectPath.setText(path[0])
def projectPathChanged(self):
self.validate()
def okPressed(self):
try:
path = self.ui.textProjectPath.text()
self.project = self.__projectManager.newProject(path)
self.accept()
except Exception as ex:
print("Failed to create project: ", traceback.format_exc())
QMessageBox.critical(self,
self.tr('An error occurred'),
self.tr('The project could not be created in the given location.'))

View File

@ -0,0 +1,239 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>NewProjectDialog</class>
<widget class="QDialog" name="NewProjectDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>486</width>
<height>299</height>
</rect>
</property>
<property name="windowTitle">
<string>New project</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QWidget" name="_panelProjectPath" native="true">
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QLabel" name="labelProjectPath">
<property name="text">
<string>Project path:</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="textProjectPath">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="buttonBrowse">
<property name="text">
<string>&amp;Browse...</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupVideoSettings">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>2</verstretch>
</sizepolicy>
</property>
<property name="title">
<string>Video settings</string>
</property>
<layout class="QFormLayout">
<property name="leftMargin">
<number>20</number>
</property>
<property name="rightMargin">
<number>20</number>
</property>
<item row="0" column="0">
<widget class="QLabel" name="labelColorDepth">
<property name="minimumSize">
<size>
<width>110</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>Color depth:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="comboColorDepth">
<property name="minimumSize">
<size>
<width>150</width>
<height>0</height>
</size>
</property>
<item>
<property name="text">
<string>8 bits/channel</string>
</property>
</item>
<item>
<property name="text">
<string>16 bits/channel</string>
</property>
</item>
<item>
<property name="text">
<string>32 bits/channel (float)</string>
</property>
</item>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="labelColorSpace">
<property name="minimumSize">
<size>
<width>110</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>Color space:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="comboColorSpace">
<item>
<property name="text">
<string>sRGB</string>
</property>
</item>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupAudioSettings">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>1</verstretch>
</sizepolicy>
</property>
<property name="title">
<string>Audio settings</string>
</property>
<layout class="QFormLayout" name="formLayout_2">
<property name="leftMargin">
<number>20</number>
</property>
<property name="rightMargin">
<number>20</number>
</property>
<item row="0" column="0">
<widget class="QLabel" name="labelSampleRate">
<property name="minimumSize">
<size>
<width>110</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>Sample rate:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="comboSampleRate">
<property name="currentIndex">
<number>2</number>
</property>
<item>
<property name="text">
<string>32 kHz</string>
</property>
</item>
<item>
<property name="text">
<string>44.1 kHz</string>
</property>
</item>
<item>
<property name="text">
<string>48 kHz</string>
</property>
</item>
<item>
<property name="text">
<string>88.2 kHz</string>
</property>
</item>
<item>
<property name="text">
<string>96 kHz</string>
</property>
</item>
<item>
<property name="text">
<string>192 kHz</string>
</property>
</item>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>NewProjectDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -0,0 +1,124 @@
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'ui/project/new_project_dialog.ui'
#
# Created by: PyQt5 UI code generator 5.10.1
#
# WARNING! All changes made in this file will be lost!
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_NewProjectDialog(object):
def setupUi(self, NewProjectDialog):
NewProjectDialog.setObjectName("NewProjectDialog")
NewProjectDialog.resize(486, 299)
self.verticalLayout = QtWidgets.QVBoxLayout(NewProjectDialog)
self.verticalLayout.setObjectName("verticalLayout")
self._panelProjectPath = QtWidgets.QWidget(NewProjectDialog)
self._panelProjectPath.setObjectName("_panelProjectPath")
self.horizontalLayout_3 = QtWidgets.QHBoxLayout(self._panelProjectPath)
self.horizontalLayout_3.setObjectName("horizontalLayout_3")
self.labelProjectPath = QtWidgets.QLabel(self._panelProjectPath)
self.labelProjectPath.setObjectName("labelProjectPath")
self.horizontalLayout_3.addWidget(self.labelProjectPath)
self.textProjectPath = QtWidgets.QLineEdit(self._panelProjectPath)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.textProjectPath.sizePolicy().hasHeightForWidth())
self.textProjectPath.setSizePolicy(sizePolicy)
self.textProjectPath.setObjectName("textProjectPath")
self.horizontalLayout_3.addWidget(self.textProjectPath)
self.buttonBrowse = QtWidgets.QPushButton(self._panelProjectPath)
self.buttonBrowse.setObjectName("buttonBrowse")
self.horizontalLayout_3.addWidget(self.buttonBrowse)
self.verticalLayout.addWidget(self._panelProjectPath)
self.groupVideoSettings = QtWidgets.QGroupBox(NewProjectDialog)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Preferred)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(2)
sizePolicy.setHeightForWidth(self.groupVideoSettings.sizePolicy().hasHeightForWidth())
self.groupVideoSettings.setSizePolicy(sizePolicy)
self.groupVideoSettings.setObjectName("groupVideoSettings")
self.formlayout = QtWidgets.QFormLayout(self.groupVideoSettings)
self.formlayout.setContentsMargins(20, -1, 20, -1)
self.formlayout.setObjectName("formlayout")
self.labelColorDepth = QtWidgets.QLabel(self.groupVideoSettings)
self.labelColorDepth.setMinimumSize(QtCore.QSize(110, 0))
self.labelColorDepth.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
self.labelColorDepth.setObjectName("labelColorDepth")
self.formlayout.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.labelColorDepth)
self.comboColorDepth = QtWidgets.QComboBox(self.groupVideoSettings)
self.comboColorDepth.setMinimumSize(QtCore.QSize(150, 0))
self.comboColorDepth.setObjectName("comboColorDepth")
self.comboColorDepth.addItem("")
self.comboColorDepth.addItem("")
self.comboColorDepth.addItem("")
self.formlayout.setWidget(0, QtWidgets.QFormLayout.FieldRole, self.comboColorDepth)
self.labelColorSpace = QtWidgets.QLabel(self.groupVideoSettings)
self.labelColorSpace.setMinimumSize(QtCore.QSize(110, 0))
self.labelColorSpace.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
self.labelColorSpace.setObjectName("labelColorSpace")
self.formlayout.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.labelColorSpace)
self.comboColorSpace = QtWidgets.QComboBox(self.groupVideoSettings)
self.comboColorSpace.setObjectName("comboColorSpace")
self.comboColorSpace.addItem("")
self.formlayout.setWidget(1, QtWidgets.QFormLayout.FieldRole, self.comboColorSpace)
self.verticalLayout.addWidget(self.groupVideoSettings)
self.groupAudioSettings = QtWidgets.QGroupBox(NewProjectDialog)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(1)
sizePolicy.setHeightForWidth(self.groupAudioSettings.sizePolicy().hasHeightForWidth())
self.groupAudioSettings.setSizePolicy(sizePolicy)
self.groupAudioSettings.setObjectName("groupAudioSettings")
self.formLayout_2 = QtWidgets.QFormLayout(self.groupAudioSettings)
self.formLayout_2.setContentsMargins(20, -1, 20, -1)
self.formLayout_2.setObjectName("formLayout_2")
self.labelSampleRate = QtWidgets.QLabel(self.groupAudioSettings)
self.labelSampleRate.setMinimumSize(QtCore.QSize(110, 0))
self.labelSampleRate.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
self.labelSampleRate.setObjectName("labelSampleRate")
self.formLayout_2.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.labelSampleRate)
self.comboSampleRate = QtWidgets.QComboBox(self.groupAudioSettings)
self.comboSampleRate.setObjectName("comboSampleRate")
self.comboSampleRate.addItem("")
self.comboSampleRate.addItem("")
self.comboSampleRate.addItem("")
self.comboSampleRate.addItem("")
self.comboSampleRate.addItem("")
self.comboSampleRate.addItem("")
self.formLayout_2.setWidget(0, QtWidgets.QFormLayout.FieldRole, self.comboSampleRate)
self.verticalLayout.addWidget(self.groupAudioSettings)
self.buttonBox = QtWidgets.QDialogButtonBox(NewProjectDialog)
self.buttonBox.setOrientation(QtCore.Qt.Horizontal)
self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok)
self.buttonBox.setObjectName("buttonBox")
self.verticalLayout.addWidget(self.buttonBox)
self.retranslateUi(NewProjectDialog)
self.comboSampleRate.setCurrentIndex(2)
self.buttonBox.rejected.connect(NewProjectDialog.reject)
QtCore.QMetaObject.connectSlotsByName(NewProjectDialog)
def retranslateUi(self, NewProjectDialog):
_translate = QtCore.QCoreApplication.translate
NewProjectDialog.setWindowTitle(_translate("NewProjectDialog", "New project"))
self.labelProjectPath.setText(_translate("NewProjectDialog", "Project path:"))
self.buttonBrowse.setText(_translate("NewProjectDialog", "&Browse..."))
self.groupVideoSettings.setTitle(_translate("NewProjectDialog", "Video settings"))
self.labelColorDepth.setText(_translate("NewProjectDialog", "Color depth:"))
self.comboColorDepth.setItemText(0, _translate("NewProjectDialog", "8 bits/channel"))
self.comboColorDepth.setItemText(1, _translate("NewProjectDialog", "16 bits/channel"))
self.comboColorDepth.setItemText(2, _translate("NewProjectDialog", "32 bits/channel (float)"))
self.labelColorSpace.setText(_translate("NewProjectDialog", "Color space:"))
self.comboColorSpace.setItemText(0, _translate("NewProjectDialog", "sRGB"))
self.groupAudioSettings.setTitle(_translate("NewProjectDialog", "Audio settings"))
self.labelSampleRate.setText(_translate("NewProjectDialog", "Sample rate:"))
self.comboSampleRate.setItemText(0, _translate("NewProjectDialog", "32 kHz"))
self.comboSampleRate.setItemText(1, _translate("NewProjectDialog", "44.1 kHz"))
self.comboSampleRate.setItemText(2, _translate("NewProjectDialog", "48 kHz"))
self.comboSampleRate.setItemText(3, _translate("NewProjectDialog", "88.2 kHz"))
self.comboSampleRate.setItemText(4, _translate("NewProjectDialog", "96 kHz"))
self.comboSampleRate.setItemText(5, _translate("NewProjectDialog", "192 kHz"))

0
ui/welcome/__init__.py Normal file
View File

View File

@ -1,72 +0,0 @@
from PyQt5.QtWidgets import QWidget, QHBoxLayout, QLabel, QToolButton, QLayout
from PyQt5.QtCore import pyqtSignal
from PyQt5.QtGui import QFont
class RecentProjectWidget(QWidget):
deleted = pyqtSignal()
pinned = pyqtSignal(bool)
def __init__(self, recentProject):
super().__init__()
self.project = recentProject
self.__selected = False
self.setupUi()
self.setupActions()
self.__setProject(recentProject)
self.setSelected(False)
def setupUi(self):
layout = QHBoxLayout()
# label
self.__text = QLabel()
layout.addWidget(self.__text)
# space
layout.addStretch()
# pin button
self.__pin_button = QToolButton()
self.__pin_button.setFont(QFont("Font Awesome 5 Free"))
self.__pin_button.setText("\uf08d")
self.__pin_button.setCheckable(True)
layout.addWidget(self.__pin_button)
# delete button
self.__del_button = QToolButton()
self.__del_button.setFont(QFont("Font Awesome 5 Free"))
self.__del_button.setText("\uf2ed")
layout.addWidget(self.__del_button)
# pin indicator
self.__pin_indicator = QLabel()
self.__pin_indicator.setFont(QFont("Font Awesome 5 Free"))
self.__pin_indicator.setText("\uf08d")
layout.addWidget(self.__pin_indicator)
# done
layout.setSizeConstraint(QLayout.SetMinimumSize)
self.setLayout(layout)
def setupActions(self):
self.__pin_button.toggled.connect(self.__pinnedToggled)
self.__del_button.pressed.connect(self.deleted)
def setSelected(self, selected = True):
self.__selected = selected
self.__pin_button.setVisible(selected)
self.__del_button.setVisible(selected)
self.__pin_indicator.setVisible(not self.__selected and self.__pin_button.isChecked())
def setPinned(self, isPinned = True):
self.__pin_button.setChecked(isPinned)
def __setProject(self, project):
self.__text = project['name']
self.setPinned(project['pinned'])
def __pinnedToggled(self, isPinned):
self.__pin_indicator.setVisible(not self.__selected and isPinned)
if (isPinned != self.project['pinned']):
self.pinned.emit(isPinned)

View File

@ -1,91 +1,171 @@
import traceback import traceback
from PyQt5.QtWidgets import QDialog, QCommandLinkButton, QListWidgetItem from PyQt5.QtWidgets import QDialog, QCommandLinkButton, QListWidgetItem, QFileDialog, QWidget, QHBoxLayout, QLabel, QToolButton, QLayout
from PyQt5.QtGui import QPixmap from PyQt5.QtGui import QPixmap, QResizeEvent, QFont
from PyQt5.QtCore import Qt from PyQt5.QtCore import Qt, pyqtSignal
from ui.welcome.recent_project import RecentProjectWidget
from ui.welcome.welcome_dialog_ui import Ui_WelcomeDialog from ui.welcome.welcome_dialog_ui import Ui_WelcomeDialog
from model import RecentProject
from business import ProjectManager
from properties.config import PROJECT_EXTENSION
class RecentProjectListWidget(QWidget):
deleted = pyqtSignal()
pinned = pyqtSignal(bool)
def __init__(self, recentProject : RecentProject):
super().__init__()
self.project = recentProject
self.__selected = False
self.setupUi()
self.setupActions()
self.__setProject(recentProject)
self.setSelected(False)
def setupUi(self):
layout = QHBoxLayout()
# label
self.__text = QLabel()
layout.addWidget(self.__text)
# space
layout.addStretch()
# pin button
self.__pin_button = QToolButton()
self.__pin_button.setFont(QFont("Font Awesome 5 Free"))
self.__pin_button.setText("\uf08d")
self.__pin_button.setCheckable(True)
layout.addWidget(self.__pin_button)
# delete button
self.__del_button = QToolButton()
self.__del_button.setFont(QFont("Font Awesome 5 Free"))
self.__del_button.setText("\uf2ed")
layout.addWidget(self.__del_button)
# pin indicator
self.__pin_indicator = QLabel()
self.__pin_indicator.setFont(QFont("Font Awesome 5 Free"))
self.__pin_indicator.setText("\uf08d")
layout.addWidget(self.__pin_indicator)
# done
layout.setSizeConstraint(QLayout.SetMinimumSize)
self.setLayout(layout)
def setupActions(self):
self.__pin_button.toggled.connect(self.__pinnedToggled)
self.__del_button.pressed.connect(self.deleted)
def setSelected(self, selected : bool = True):
self.__selected = selected
self.__pin_button.setVisible(selected)
self.__del_button.setVisible(selected)
self.__pin_indicator.setVisible(not self.__selected and self.__pin_button.isChecked())
def setPinned(self, isPinned : bool = True):
self.__pin_button.setChecked(isPinned)
def __setProject(self, project : RecentProject):
self.__text = project.name
self.setPinned(project.pinned)
def __pinnedToggled(self, isPinned : bool):
self.__pin_indicator.setVisible(not self.__selected and isPinned)
if (isPinned != self.project.pinned):
self.pinned.emit(isPinned)
class WelcomeDialog(QDialog): class WelcomeDialog(QDialog):
NEW_PROJECT = 0 NEW_PROJECT = 0
OPEN_PROJECT = 1 OPEN_PROJECT = 1
def __init__(self, projectManager): def __init__(self, projectManager : ProjectManager, parent : QWidget = None):
super().__init__() super().__init__(parent)
self.__projectManager = projectManager self.__projectManager = projectManager
self.resultAction = None self.resultAction : int = None
self.projectToOpen = None self.projectToOpen : str = None
self.setResult(QDialog.Rejected) self.setResult(QDialog.Rejected)
self.setupUi() self.setupUi()
self.setupActions() self.setupActions()
self.populateRecentProjects() self.populateRecentProjects()
def setupUi(self): def setupUi(self) -> None:
self.ui = Ui_WelcomeDialog() self.ui = Ui_WelcomeDialog()
self.ui.setupUi(self) self.ui.setupUi(self)
self.image = QPixmap(self.ui.picture.pixmap()) self.image = QPixmap(self.ui.picture.pixmap())
def setupActions(self): def setupActions(self) -> None:
self.ui.buttonNewProject.pressed.connect(self.newProjectPressed) self.ui.buttonNewProject.pressed.connect(self.newProjectPressed)
self.ui.buttonOpenProject.pressed.connect(self.openProjectPressed) self.ui.buttonOpenProject.pressed.connect(self.openProjectPressed)
self.ui.listRecentProjects.currentItemChanged.connect(self.listRecentProjectsCurrentChanged) self.ui.listRecentProjects.currentItemChanged.connect(self.listRecentProjectsCurrentChanged)
self.ui.listRecentProjects.itemActivated.connect(self.listRecentProjectsItemActivated) self.ui.listRecentProjects.itemActivated.connect(self.listRecentProjectsItemActivated)
def resizeEvent(self, event): def resizeEvent(self, event : QResizeEvent) -> None:
super().resizeEvent(event) super().resizeEvent(event)
picSize = self.ui.picture.size() picSize = self.ui.picture.size()
pic = self.image.scaled(picSize, Qt.KeepAspectRatioByExpanding, Qt.SmoothTransformation) pic = self.image.scaled(picSize, Qt.KeepAspectRatioByExpanding, Qt.SmoothTransformation)
self.ui.picture.setPixmap(pic) self.ui.picture.setPixmap(pic)
def populateRecentProjects(self): def populateRecentProjects(self) -> None:
projects = list(self.__projectManager.getRecentProjects()) projects = list(self.__projectManager.getRecentProjects())
projects = sorted(projects, key=lambda x: (x['pinned'], x['date']), reverse=True) projects = sorted(projects, key=lambda x: (x.pinned, x.dateAccessed), reverse=True)
for project in projects: for project in projects:
widget = RecentProjectWidget(project) widget = RecentProjectListWidget(project)
widget.pinned.connect(self.__projectPinned) widget.pinned.connect(self.__projectPinned)
widget.deleted.connect(self.__projectDeleted) widget.deleted.connect(self.__projectDeleted)
item = QListWidgetItem(project['name']) item = QListWidgetItem(project.name)
item.setData(Qt.UserRole, project) item.setData(Qt.UserRole, project)
item.setSizeHint(widget.sizeHint()) item.setSizeHint(widget.sizeHint())
self.ui.listRecentProjects.addItem(item) self.ui.listRecentProjects.addItem(item)
self.ui.listRecentProjects.setItemWidget(item, widget) self.ui.listRecentProjects.setItemWidget(item, widget)
def newProjectPressed(self): def newProjectPressed(self) -> None:
self.resultAction = WelcomeDialog.NEW_PROJECT self.resultAction = WelcomeDialog.NEW_PROJECT
self.accept() self.accept()
def openProjectPressed(self): def openProjectPressed(self) -> None:
# TODO: show open dialog proj = QFileDialog.getOpenFileName(
self.resultAction = WelcomeDialog.OPEN_PROJECT self,
self.accept() self.tr('Open project'),
'',
self.tr(f'Project files (*.{PROJECT_EXTENSION});;All files (*.*)'))
def listRecentProjectsCurrentChanged(self, current, previous): if proj[0]:
self.projectToOpen = proj[0]
self.resultAction = WelcomeDialog.OPEN_PROJECT
self.accept()
def listRecentProjectsCurrentChanged(self, current : QListWidgetItem, previous : QListWidgetItem) -> None:
if not current is None: if not current is None:
recentProjectWidget = self.ui.listRecentProjects.itemWidget(current) RecentProjectListWidget = self.ui.listRecentProjects.itemWidget(current)
recentProjectWidget.setSelected(True) RecentProjectListWidget.setSelected(True)
if not previous is None: if not previous is None:
recentProjectWidget = self.ui.listRecentProjects.itemWidget(previous) RecentProjectListWidget = self.ui.listRecentProjects.itemWidget(previous)
if not recentProjectWidget is None: if not RecentProjectListWidget is None:
recentProjectWidget.setSelected(False) RecentProjectListWidget.setSelected(False)
def listRecentProjectsItemActivated(self, item): def listRecentProjectsItemActivated(self, item : QListWidgetItem) -> None:
project = item.data(Qt.UserRole) project : RecentProject = item.data(Qt.UserRole)
self.resultAction = WelcomeDialog.OPEN_PROJECT self.resultAction = WelcomeDialog.OPEN_PROJECT
self.projectToOpen = project['path'] self.projectToOpen = project.path
self.accept() self.accept()
def __projectPinned(self, isPinned): def __projectPinned(self, isPinned : bool) -> None:
project = self.ui.listRecentProjects.currentItem().data(Qt.UserRole) project = self.ui.listRecentProjects.currentItem().data(Qt.UserRole)
self.__projectManager.pinRecentProject(project, isPinned) self.__projectManager.pinRecentProject(project, isPinned)
def __projectDeleted(self): def __projectDeleted(self) -> None:
project = self.ui.listRecentProjects.currentItem().data(Qt.UserRole) project = self.ui.listRecentProjects.currentItem().data(Qt.UserRole)
try: try:
self.__projectManager.deleteRecentProject(project) self.__projectManager.deleteRecentProject(project)