Finished welcome dialog. New project dialog prototype.
This commit is contained in:
parent
59cd033cad
commit
037843d14f
5
Makefile
5
Makefile
@ -7,8 +7,9 @@ UI_OUT=$(UI:.ui=_ui.py)
|
||||
all: $(RESOURCES_OUT) $(UI_OUT)
|
||||
|
||||
clean:
|
||||
rm ${UI_OUT}
|
||||
rm ${RESOURCES_OUT}
|
||||
rm -f ${UI_OUT}
|
||||
rm -f ${RESOURCES_OUT}
|
||||
find -name '__pycache__' -exec rm -rf "{}" \;
|
||||
|
||||
%_rc.py: %.qrc
|
||||
pyrcc5 $< -o $@
|
||||
|
@ -0,0 +1 @@
|
||||
from .project_manager import ProjectManager
|
@ -1,49 +1,90 @@
|
||||
from typing import Iterable
|
||||
|
||||
from model.project import Project
|
||||
from model import Project, RecentProject
|
||||
from storage import AppDataStorage
|
||||
|
||||
class ProjectManager(object):
|
||||
|
||||
def __init__(self, appDataStorage):
|
||||
def __init__(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:
|
||||
self.__recentProjects = {}
|
||||
for item in self.__appDataStorage.readRecentProjects():
|
||||
self.__recentProjects[item['path']] = item
|
||||
self.__recentProjects[item.path] = item
|
||||
|
||||
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())
|
||||
|
||||
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())
|
||||
|
||||
def debug_populateRecentProjects(self):
|
||||
self.__recentProjects['/home/tibi/Videos/project.pro'] = {
|
||||
'name' : 'Debug project',
|
||||
'path' : '/home/tibi/Videos/project.pro',
|
||||
'pinned' : True,
|
||||
'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
|
||||
}
|
||||
"""
|
||||
Creates a new project at the given path, and returns the created project.
|
||||
|
||||
Args:
|
||||
path: path to project file
|
||||
"""
|
||||
def newProject(self, path : str) -> Project:
|
||||
return Project(path)
|
||||
|
||||
"""
|
||||
Opens an existing project.
|
||||
|
||||
Args:
|
||||
path: path to project file
|
||||
"""
|
||||
def openProject(self, path : str) -> Project:
|
||||
return Project(path)
|
||||
|
||||
# def debug_populateRecentProjects(self):
|
||||
# self.__recentProjects['/home/tibi/Videos/project.pro'] = {
|
||||
# 'name' : 'Debug project',
|
||||
# 'path' : '/home/tibi/Videos/project.pro',
|
||||
# 'pinned' : True,
|
||||
# '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
|
||||
# }
|
@ -0,0 +1,2 @@
|
||||
from .recent_project import RecentProject
|
||||
from .project import Project
|
@ -1,7 +1,7 @@
|
||||
class Project(object):
|
||||
|
||||
def __init__(self):
|
||||
self.root_dir = None
|
||||
def __init__(self, path):
|
||||
self.root_dir = path
|
||||
|
||||
def get_items(self):
|
||||
pass
|
60
model/recent_project.py
Normal file
60
model/recent_project.py
Normal 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
|
||||
}
|
@ -3,4 +3,6 @@ APP_VERSION = "1.0"
|
||||
APP_AUTHOR = "Tiberiu Chibici"
|
||||
APP_AUTHOR_SHORT = "TibiCh"
|
||||
|
||||
PROJECT_EXTENSION = "emproj"
|
||||
|
||||
DEBUG = 1
|
17460
resources_rc.py
17460
resources_rc.py
File diff suppressed because it is too large
Load Diff
1
storage/__init__.py
Normal file
1
storage/__init__.py
Normal file
@ -0,0 +1 @@
|
||||
from .appdata_storage import AppDataStorage
|
@ -2,14 +2,15 @@ import appdirs
|
||||
import os
|
||||
from configparser import ConfigParser
|
||||
import csv
|
||||
from typing import Iterable
|
||||
|
||||
from properties import config
|
||||
from model import RecentProject
|
||||
|
||||
class AppDataStorage(object):
|
||||
|
||||
SETTINGS_FILE = "config.ini"
|
||||
RECENT_PROJECTS_FILE = "recent.cfg"
|
||||
RECENT_PROJECTS_FIELDS = ["path", "name", "date", "pinned"]
|
||||
|
||||
def __init__(self):
|
||||
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):
|
||||
pass # todo: finish this
|
||||
|
||||
def __parseRow(self, row):
|
||||
row['date'] = int(row['date'])
|
||||
row['pinned'] = row['pinned'].lower() in ['true', 'yes', '1', 'on']
|
||||
return row
|
||||
"""
|
||||
Reads recent projects list.
|
||||
|
||||
def readRecentProjects(self):
|
||||
Returns:
|
||||
list of recent projects
|
||||
"""
|
||||
def readRecentProjects(self) -> Iterable[RecentProject]:
|
||||
if (os.path.exists(self.__recentProjectsPath)):
|
||||
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:
|
||||
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)
|
||||
with open(self.__recentProjectsPath, 'w') as recentProjectsFile:
|
||||
csvwriter = csv.DictWriter(recentProjectsFile, AppDataStorage.RECENT_PROJECTS_FIELDS)
|
||||
csvwriter.writerows(items)
|
||||
csvwriter = csv.DictWriter(recentProjectsFile, RecentProject.DICT_FIELDS)
|
||||
for item in items:
|
||||
csvwriter.writerow(item.toDictionary())
|
@ -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.new_project_dialog import NewProjectDialog
|
||||
from ui.welcome.welcome_dialog import WelcomeDialog
|
||||
|
||||
class MainWindow(QMainWindow):
|
||||
|
||||
def __init__(self, projectManager):
|
||||
def __init__(self, projectManager : ProjectManager):
|
||||
super().__init__()
|
||||
self.__projectManager = projectManager
|
||||
self.setupUi()
|
||||
self.initializeApp()
|
||||
QTimer.singleShot(0, self.showWelcomeDialog)
|
||||
|
||||
def setupUi(self):
|
||||
self.projectPanel = ProjectPanel()
|
||||
@ -22,10 +27,28 @@ class MainWindow(QMainWindow):
|
||||
|
||||
self.setCentralWidget(cwidget)
|
||||
|
||||
def initializeApp(self):
|
||||
|
||||
def showWelcomeDialog(self):
|
||||
# Show welcome dialog
|
||||
welcome = WelcomeDialog(self.__projectManager)
|
||||
res = welcome.exec()
|
||||
welcome = WelcomeDialog(self.__projectManager, self)
|
||||
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
|
61
ui/project/new_project_dialog.py
Normal file
61
ui/project/new_project_dialog.py
Normal 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.'))
|
||||
|
||||
|
||||
|
239
ui/project/new_project_dialog.ui
Normal file
239
ui/project/new_project_dialog.ui
Normal 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>&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>
|
124
ui/project/new_project_dialog_ui.py
Normal file
124
ui/project/new_project_dialog_ui.py
Normal 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
0
ui/welcome/__init__.py
Normal 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)
|
@ -1,91 +1,171 @@
|
||||
import traceback
|
||||
|
||||
from PyQt5.QtWidgets import QDialog, QCommandLinkButton, QListWidgetItem
|
||||
from PyQt5.QtGui import QPixmap
|
||||
from PyQt5.QtCore import Qt
|
||||
from PyQt5.QtWidgets import QDialog, QCommandLinkButton, QListWidgetItem, QFileDialog, QWidget, QHBoxLayout, QLabel, QToolButton, QLayout
|
||||
from PyQt5.QtGui import QPixmap, QResizeEvent, QFont
|
||||
from PyQt5.QtCore import Qt, pyqtSignal
|
||||
|
||||
from ui.welcome.recent_project import RecentProjectWidget
|
||||
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):
|
||||
NEW_PROJECT = 0
|
||||
OPEN_PROJECT = 1
|
||||
|
||||
def __init__(self, projectManager):
|
||||
super().__init__()
|
||||
def __init__(self, projectManager : ProjectManager, parent : QWidget = None):
|
||||
super().__init__(parent)
|
||||
self.__projectManager = projectManager
|
||||
self.resultAction = None
|
||||
self.projectToOpen = None
|
||||
self.resultAction : int = None
|
||||
self.projectToOpen : str = None
|
||||
self.setResult(QDialog.Rejected)
|
||||
self.setupUi()
|
||||
self.setupActions()
|
||||
self.populateRecentProjects()
|
||||
|
||||
def setupUi(self):
|
||||
def setupUi(self) -> None:
|
||||
self.ui = Ui_WelcomeDialog()
|
||||
self.ui.setupUi(self)
|
||||
self.image = QPixmap(self.ui.picture.pixmap())
|
||||
|
||||
def setupActions(self):
|
||||
def setupActions(self) -> None:
|
||||
self.ui.buttonNewProject.pressed.connect(self.newProjectPressed)
|
||||
self.ui.buttonOpenProject.pressed.connect(self.openProjectPressed)
|
||||
self.ui.listRecentProjects.currentItemChanged.connect(self.listRecentProjectsCurrentChanged)
|
||||
self.ui.listRecentProjects.itemActivated.connect(self.listRecentProjectsItemActivated)
|
||||
|
||||
def resizeEvent(self, event):
|
||||
def resizeEvent(self, event : QResizeEvent) -> None:
|
||||
super().resizeEvent(event)
|
||||
|
||||
picSize = self.ui.picture.size()
|
||||
pic = self.image.scaled(picSize, Qt.KeepAspectRatioByExpanding, Qt.SmoothTransformation)
|
||||
self.ui.picture.setPixmap(pic)
|
||||
|
||||
def populateRecentProjects(self):
|
||||
def populateRecentProjects(self) -> None:
|
||||
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:
|
||||
|
||||
widget = RecentProjectWidget(project)
|
||||
widget = RecentProjectListWidget(project)
|
||||
widget.pinned.connect(self.__projectPinned)
|
||||
widget.deleted.connect(self.__projectDeleted)
|
||||
|
||||
item = QListWidgetItem(project['name'])
|
||||
item = QListWidgetItem(project.name)
|
||||
item.setData(Qt.UserRole, project)
|
||||
item.setSizeHint(widget.sizeHint())
|
||||
|
||||
self.ui.listRecentProjects.addItem(item)
|
||||
self.ui.listRecentProjects.setItemWidget(item, widget)
|
||||
|
||||
def newProjectPressed(self):
|
||||
def newProjectPressed(self) -> None:
|
||||
self.resultAction = WelcomeDialog.NEW_PROJECT
|
||||
self.accept()
|
||||
|
||||
def openProjectPressed(self):
|
||||
# TODO: show open dialog
|
||||
def openProjectPressed(self) -> None:
|
||||
proj = QFileDialog.getOpenFileName(
|
||||
self,
|
||||
self.tr('Open project'),
|
||||
'',
|
||||
self.tr(f'Project files (*.{PROJECT_EXTENSION});;All files (*.*)'))
|
||||
|
||||
if proj[0]:
|
||||
self.projectToOpen = proj[0]
|
||||
self.resultAction = WelcomeDialog.OPEN_PROJECT
|
||||
self.accept()
|
||||
|
||||
def listRecentProjectsCurrentChanged(self, current, previous):
|
||||
def listRecentProjectsCurrentChanged(self, current : QListWidgetItem, previous : QListWidgetItem) -> None:
|
||||
if not current is None:
|
||||
recentProjectWidget = self.ui.listRecentProjects.itemWidget(current)
|
||||
recentProjectWidget.setSelected(True)
|
||||
RecentProjectListWidget = self.ui.listRecentProjects.itemWidget(current)
|
||||
RecentProjectListWidget.setSelected(True)
|
||||
|
||||
if not previous is None:
|
||||
recentProjectWidget = self.ui.listRecentProjects.itemWidget(previous)
|
||||
if not recentProjectWidget is None:
|
||||
recentProjectWidget.setSelected(False)
|
||||
RecentProjectListWidget = self.ui.listRecentProjects.itemWidget(previous)
|
||||
if not RecentProjectListWidget is None:
|
||||
RecentProjectListWidget.setSelected(False)
|
||||
|
||||
def listRecentProjectsItemActivated(self, item):
|
||||
project = item.data(Qt.UserRole)
|
||||
def listRecentProjectsItemActivated(self, item : QListWidgetItem) -> None:
|
||||
project : RecentProject = item.data(Qt.UserRole)
|
||||
self.resultAction = WelcomeDialog.OPEN_PROJECT
|
||||
self.projectToOpen = project['path']
|
||||
self.projectToOpen = project.path
|
||||
self.accept()
|
||||
|
||||
def __projectPinned(self, isPinned):
|
||||
def __projectPinned(self, isPinned : bool) -> None:
|
||||
project = self.ui.listRecentProjects.currentItem().data(Qt.UserRole)
|
||||
self.__projectManager.pinRecentProject(project, isPinned)
|
||||
|
||||
def __projectDeleted(self):
|
||||
def __projectDeleted(self) -> None:
|
||||
project = self.ui.listRecentProjects.currentItem().data(Qt.UserRole)
|
||||
try:
|
||||
self.__projectManager.deleteRecentProject(project)
|
||||
|
Loading…
Reference in New Issue
Block a user