1
0
mirror of https://gitlab.com/kelteseth/ScreenPlay.git synced 2024-11-25 12:13:00 +01:00

Add edit menu entry

This commit is contained in:
Elias Steurer 2023-11-16 13:27:50 +01:00
parent 99e427b6cb
commit 893844f023
8 changed files with 129 additions and 73 deletions

View File

@ -185,6 +185,7 @@ set(RESOURCES
assets/icons/icon_widgets.svg assets/icons/icon_widgets.svg
assets/icons/icon_window.svg assets/icons/icon_window.svg
assets/icons/item_banner_new.svg assets/icons/item_banner_new.svg
assets/icons/icon_edit.svg
assets/icons/monitor_setup.svg assets/icons/monitor_setup.svg
assets/icons/steam_default_avatar.png assets/icons/steam_default_avatar.png
assets/images/Early_Access.png assets/images/Early_Access.png

View File

@ -58,7 +58,8 @@ class Util : public QObject {
Q_PROPERTY(QString debugMessages READ debugMessages NOTIFY debugMessagesChanged) Q_PROPERTY(QString debugMessages READ debugMessages NOTIFY debugMessagesChanged)
public: public:
Util(); Util(
const std::shared_ptr<GlobalVariables>& globalVariables);
~Util(); ~Util();
QString debugMessages() const { return m_debugMessages; } QString debugMessages() const { return m_debugMessages; }
@ -82,6 +83,7 @@ public slots:
void openFolderInExplorer(const QString& url) const; void openFolderInExplorer(const QString& url) const;
QString toLocal(const QString& url) const; QString toLocal(const QString& url) const;
bool exportProject(QString contentPath, QString exportFileName); bool exportProject(QString contentPath, QString exportFileName);
bool openGodotEditor(QString contentPath) const;
bool importProject(QString archivePath, QString extractionPath); bool importProject(QString archivePath, QString extractionPath);
void requestAllLicenses(); void requestAllLicenses();
void requestDataProtection(); void requestDataProtection();
@ -124,6 +126,7 @@ private:
QFuture<void> m_requestAllLicensesFuture; QFuture<void> m_requestAllLicensesFuture;
std::unique_ptr<QArchive::DiskCompressor> m_compressor; std::unique_ptr<QArchive::DiskCompressor> m_compressor;
std::unique_ptr<QArchive::DiskExtractor> m_extractor; std::unique_ptr<QArchive::DiskExtractor> m_extractor;
const std::shared_ptr<GlobalVariables>& m_globalVariables;
}; };
} }

View File

@ -34,9 +34,11 @@ namespace ScreenPlay {
class Wizards : public QObject { class Wizards : public QObject {
Q_OBJECT Q_OBJECT
QML_ELEMENT QML_ELEMENT
QML_UNCREATABLE("CPP ONLY")
public: public:
explicit Wizards(const std::shared_ptr<GlobalVariables>& globalVariables, QObject* parent = nullptr); explicit Wizards(
Wizards() { } const std::shared_ptr<GlobalVariables>& globalVariables,
QObject* parent = nullptr);
enum class WizardResult { enum class WizardResult {
Ok, Ok,

View File

@ -25,23 +25,23 @@ Item {
function checkIsContentInstalled() { function checkIsContentInstalled() {
if (App.installedListModel.count === 0) { if (App.installedListModel.count === 0) {
loaderHelp.active = true; loaderHelp.active = true
gridView.footerItem.isVisible = true; gridView.footerItem.isVisible = true
gridView.visible = false; gridView.visible = false
navWrapper.visible = false; navWrapper.visible = false
} else { } else {
loaderHelp.active = false; loaderHelp.active = false
gridView.footerItem.isVisible = false; gridView.footerItem.isVisible = false
refresh = false; refresh = false
gridView.contentY = -82; gridView.contentY = -82
gridView.visible = true; gridView.visible = true
navWrapper.visible = true; navWrapper.visible = true
} }
} }
StackView.onActivated: { StackView.onActivated: {
navWrapper.state = "in"; navWrapper.state = "in"
checkIsContentInstalled(); checkIsContentInstalled()
} }
Action { Action {
@ -51,12 +51,12 @@ Item {
Connections { Connections {
function onInstalledLoadingFinished() { function onInstalledLoadingFinished() {
checkIsContentInstalled(); checkIsContentInstalled()
} }
function onCountChanged(count) { function onCountChanged(count) {
if (count === 0) if (count === 0)
checkIsContentInstalled(); checkIsContentInstalled()
} }
target: App.installedListModel target: App.installedListModel
@ -71,7 +71,7 @@ Item {
Connections { Connections {
function onSortChanged() { function onSortChanged() {
gridView.positionViewAtBeginning(); gridView.positionViewAtBeginning()
} }
target: App.installedListFilter target: App.installedListFilter
@ -128,12 +128,12 @@ Item {
} }
onContentYChanged: { onContentYChanged: {
if (contentY <= -180) if (contentY <= -180)
gridView.headerItem.isVisible = true; gridView.headerItem.isVisible = true
else else
gridView.headerItem.isVisible = false; gridView.headerItem.isVisible = false
//Pull to refresh //Pull to refresh
if (contentY <= -180 && !refresh && !isDragging) if (contentY <= -180 && !refresh && !isDragging)
App.installedListModel.reset(); App.installedListModel.reset()
} }
anchors { anchors {
@ -150,11 +150,11 @@ Item {
opacity: 0 opacity: 0
onIsVisibleChanged: { onIsVisibleChanged: {
if (isVisible) { if (isVisible) {
txtHeader.color = Material.accent; txtHeader.color = Material.accent
txtHeader.text = qsTr("Refreshing!"); txtHeader.text = qsTr("Refreshing!")
} else { } else {
txtHeader.color = "gray"; txtHeader.color = "gray"
txtHeader.text = qsTr("Pull to refresh!"); txtHeader.text = qsTr("Pull to refresh!")
} }
} }
@ -162,7 +162,7 @@ Item {
interval: 150 interval: 150
running: true running: true
onTriggered: { onTriggered: {
animFadeIn.start(); animFadeIn.start()
} }
} }
@ -206,7 +206,7 @@ Item {
interval: 400 interval: 400
running: true running: true
onTriggered: { onTriggered: {
animFadeInTxtFooter.start(); animFadeInTxtFooter.start()
} }
} }
@ -236,15 +236,23 @@ Item {
isScrolling: gridView.isScrolling isScrolling: gridView.isScrolling
onOpenContextMenu: function (position) { onOpenContextMenu: function (position) {
// Set the menu to the current item informations // Set the menu to the current item informations
contextMenu.publishedFileID = delegate.publishedFileID; contextMenu.publishedFileID = delegate.publishedFileID
contextMenu.absoluteStoragePath = delegate.absoluteStoragePath; contextMenu.absoluteStoragePath = delegate.absoluteStoragePath
contextMenu.fileName = delegate.customTitle; contextMenu.fileName = delegate.customTitle
const pos = delegate.mapToItem(root, position.x, position.y); contextMenu.type = delegate.type
print(delegate.publishedFileID)
if(contextMenu.godotItem)
contextMenu.godotItem.destroy()
const pos = delegate.mapToItem(root, position.x, position.y)
// Disable duplicate opening. The can happen if we // Disable duplicate opening. The can happen if we
// call popup when we are in the closing animtion. // call popup when we are in the closing animtion.
if (contextMenu.visible || contextMenu.opened) if (contextMenu.visible || contextMenu.opened)
return; return
contextMenu.popup(pos.x, pos.y); if (delegate.type === InstalledType.GodotWallpaper) {
contextMenu.godotItem = editGodotWallpaperComp.createObject()
contextMenu.insertItem(0, contextMenu.godotItem)
}
contextMenu.popup(pos.x, pos.y)
} }
} }
@ -252,21 +260,37 @@ Item {
snapMode: ScrollBar.SnapOnRelease snapMode: ScrollBar.SnapOnRelease
} }
} }
Component {
id: editGodotWallpaperComp
MenuItem {
text: qsTr("Edit Wallpaper")
objectName: "editWallpaper"
enabled: contextMenu.type === InstalledType.GodotWallpaper
icon.source: "qrc:/qml/ScreenPlayApp/assets/icons/icon_edit.svg"
onClicked: {
App.util.openGodotEditor(contextMenu.absoluteStoragePath)
}
}
}
Menu { Menu {
id: contextMenu id: contextMenu
objectName: "installedItemContextMenu" objectName: "installedItemContextMenu"
// Must be var to support 64-bit size! // Must be var to support 64-bit size!
property var publishedFileID: 0 property var publishedFileID: 0
property var type: 0
property url absoluteStoragePath property url absoluteStoragePath
property string fileName property string fileName
// We need to dynamically add this menu item
// if it is a Godot Wallpaper, see onOpenContextMenu
property var godotItem
MenuItem { MenuItem {
text: qsTr("Open containing folder") text: qsTr("Open containing folder")
objectName: "openFolder" objectName: "openFolder"
icon.source: "qrc:/qml/ScreenPlayApp/assets/icons/icon_folder_open.svg" icon.source: "qrc:/qml/ScreenPlayApp/assets/icons/icon_folder_open.svg"
onClicked: { onClicked: {
App.util.openFolderInExplorer(contextMenu.absoluteStoragePath); App.util.openFolderInExplorer(contextMenu.absoluteStoragePath)
} }
} }
@ -275,10 +299,12 @@ Item {
objectName: enabled ? "removeItem" : "removeWorkshopItem" objectName: enabled ? "removeItem" : "removeWorkshopItem"
icon.source: "qrc:/qml/ScreenPlayApp/assets/icons/icon_import_export_.svg" icon.source: "qrc:/qml/ScreenPlayApp/assets/icons/icon_import_export_.svg"
onClicked: { onClicked: {
exportFileDialog.absoluteStoragePath = contextMenu.absoluteStoragePath; exportFileDialog.absoluteStoragePath = contextMenu.absoluteStoragePath
let urlFileName = QCore.StandardPaths.writableLocation(QCore.StandardPaths.DesktopLocation) + "/" + contextMenu.fileName + ".screenplay"; let urlFileName = QCore.StandardPaths.writableLocation(
exportFileDialog.currentFile = urlFileName; QCore.StandardPaths.DesktopLocation) + "/"
exportFileDialog.open(); + contextMenu.fileName + ".screenplay"
exportFileDialog.currentFile = urlFileName
exportFileDialog.open()
} }
} }
@ -286,18 +312,21 @@ Item {
text: enabled ? qsTr("Remove Item") : qsTr("Remove via Workshop") text: enabled ? qsTr("Remove Item") : qsTr("Remove via Workshop")
objectName: enabled ? "removeItem" : "removeWorkshopItem" objectName: enabled ? "removeItem" : "removeWorkshopItem"
icon.source: "qrc:/qml/ScreenPlayApp/assets/icons/icon_delete.svg" icon.source: "qrc:/qml/ScreenPlayApp/assets/icons/icon_delete.svg"
enabled: contextMenu.publishedFileID === 0 || !App.settings.steamVersion enabled: contextMenu.publishedFileID === 0
|| !App.settings.steamVersion
onClicked: { onClicked: {
deleteDialog.open(); deleteDialog.open()
} }
} }
MenuItem { MenuItem {
text: qsTr("Open Workshop Page") text: qsTr("Open Workshop Page")
enabled: contextMenu.publishedFileID !== 0 && App.settings.steamVersion enabled: contextMenu.publishedFileID !== 0
&& App.settings.steamVersion
icon.source: "qrc:/qml/ScreenPlayApp/assets/icons/icon_steam.svg" icon.source: "qrc:/qml/ScreenPlayApp/assets/icons/icon_steam.svg"
onClicked: { onClicked: {
Qt.openUrlExternally("steam://url/CommunityFilePage/" + contextMenu.publishedFileID); Qt.openUrlExternally(
"steam://url/CommunityFilePage/" + contextMenu.publishedFileID)
} }
} }
} }
@ -310,8 +339,9 @@ Item {
modalSource: root.modalSource modalSource: root.modalSource
anchors.centerIn: Overlay.overlay anchors.centerIn: Overlay.overlay
onAccepted: { onAccepted: {
root.sidebar.clear(); root.sidebar.clear()
App.installedListModel.deinstallItemAt(contextMenu.absoluteStoragePath); App.installedListModel.deinstallItemAt(
contextMenu.absoluteStoragePath)
} }
} }
@ -320,7 +350,7 @@ Item {
fileMode: FileDialog.SaveFile fileMode: FileDialog.SaveFile
property string absoluteStoragePath property string absoluteStoragePath
onAccepted: { onAccepted: {
exportFileProgressDialog.open(); exportFileProgressDialog.open()
} }
} }
@ -333,7 +363,9 @@ Item {
modalSource: root.modalSource modalSource: root.modalSource
closePolicy: Popup.NoAutoClose closePolicy: Popup.NoAutoClose
onOpened: { onOpened: {
const success = App.util.exportProject(exportFileDialog.absoluteStoragePath, exportFileDialog.currentFile); const success = App.util.exportProject(
exportFileDialog.absoluteStoragePath,
exportFileDialog.currentFile)
} }
onClosed: exportProgressBar.value = 0 onClosed: exportProgressBar.value = 0
ColumnLayout { ColumnLayout {
@ -358,10 +390,10 @@ Item {
id: exportConnections id: exportConnections
target: App.util target: App.util
function onCompressionProgressChanged(file, proc, total, br, bt) { function onCompressionProgressChanged(file, proc, total, br, bt) {
exportProgressBar.value = (br * 100 / bt); exportProgressBar.value = (br * 100 / bt)
} }
function onCompressionFinished() { function onCompressionFinished() {
exportFileProgressDialog.close(); exportFileProgressDialog.close()
} }
} }
} }
@ -381,28 +413,31 @@ Item {
anchors.fill: parent anchors.fill: parent
property string filePath property string filePath
onEntered: function (drag) { onEntered: function (drag) {
dropPopup.open(); dropPopup.open()
} }
onDropped: function (drop) { onDropped: function (drop) {
dropPopup.close(); dropPopup.close()
dropArea.enabled = false; dropArea.enabled = false
if (drop.urls.length > 1) { if (drop.urls.length > 1) {
importProjectErrorDialog.title = qsTr("We only support adding one item at once."); importProjectErrorDialog.title = qsTr(
importProjectErrorDialog.open(); "We only support adding one item at once.")
return; importProjectErrorDialog.open()
return
} }
var file = ""; // Convert url to string var file = ""
file = "" + drop.urls[0]; // Convert url to string
file = "" + drop.urls[0]
if (!file.endsWith('.screenplay')) { if (!file.endsWith('.screenplay')) {
importProjectErrorDialog.title = qsTr("File type not supported. We only support '.screenplay' files."); importProjectErrorDialog.title = qsTr(
importProjectErrorDialog.open(); "File type not supported. We only support '.screenplay' files.")
return; importProjectErrorDialog.open()
return
} }
importDialog.open(); importDialog.open()
dropArea.filePath = file; dropArea.filePath = file
} }
onExited: { onExited: {
dropPopup.close(); dropPopup.close()
} }
Util.Dialog { Util.Dialog {
@ -423,9 +458,11 @@ Item {
closePolicy: Popup.NoAutoClose closePolicy: Popup.NoAutoClose
onClosed: importProgressBar.value = 0 onClosed: importProgressBar.value = 0
onOpened: { onOpened: {
const success = App.util.importProject(dropArea.filePath, App.globalVariables.localStoragePath); const success = App.util.importProject(
print("finished", success); dropArea.filePath,
dropArea.filePath = ""; App.globalVariables.localStoragePath)
print("finished", success)
dropArea.filePath = ""
} }
ColumnLayout { ColumnLayout {
width: parent.width width: parent.width
@ -447,10 +484,10 @@ Item {
id: importConnections id: importConnections
target: App.util target: App.util
function onExtractionProgressChanged(file, proc, total, br, bt) { function onExtractionProgressChanged(file, proc, total, br, bt) {
importProgressBar.value = (br * 100 / bt); importProgressBar.value = (br * 100 / bt)
} }
function onExtractionFinished() { function onExtractionFinished() {
importDialog.close(); importDialog.close()
} }
} }
} }
@ -466,8 +503,8 @@ Item {
modal: true modal: true
onOpened: fileDropAnimation.state = "fileDrop" onOpened: fileDropAnimation.state = "fileDrop"
onClosed: { onClosed: {
fileDropAnimation.state = ""; fileDropAnimation.state = ""
dropArea.enabled = true; dropArea.enabled = true
} }
Util.FileDropAnimation { Util.FileDropAnimation {

View File

@ -14,6 +14,7 @@ Item {
property string screenId property string screenId
property url absoluteStoragePath property url absoluteStoragePath
property int type: InstalledType.Unknown property int type: InstalledType.Unknown
// Must be var to make it work wit 64bit ints
property var publishedFileID: 0 property var publishedFileID: 0
property int itemIndex property int itemIndex
property bool isScrolling: false property bool isScrolling: false

View File

@ -138,10 +138,9 @@ void App::init()
using std::make_shared, std::make_unique; using std::make_shared, std::make_unique;
// Util should be created as first so we redirect qDebugs etc. into the log
m_util = make_unique<Util>();
m_globalVariables = make_shared<GlobalVariables>(); m_globalVariables = make_shared<GlobalVariables>();
m_monitorListModel = make_shared<MonitorListModel>(); m_monitorListModel = make_shared<MonitorListModel>();
m_util = make_unique<Util>(m_globalVariables);
m_profileListModel = make_shared<ProfileListModel>(m_globalVariables); m_profileListModel = make_shared<ProfileListModel>(m_globalVariables);
m_settings = make_shared<Settings>(m_globalVariables); m_settings = make_shared<Settings>(m_globalVariables);
m_installedListModel = make_shared<InstalledListModel>(m_globalVariables, m_settings); m_installedListModel = make_shared<InstalledListModel>(m_globalVariables, m_settings);

View File

@ -22,7 +22,9 @@ namespace ScreenPlay {
/*! /*!
Constructor Constructor
*/ */
ProfileListModel::ProfileListModel(const std::shared_ptr<GlobalVariables>& globalVariables, QObject* parent) ProfileListModel::ProfileListModel(
const std::shared_ptr<GlobalVariables>& globalVariables,
QObject* parent)
: QAbstractListModel(parent) : QAbstractListModel(parent)
, m_globalVariables { globalVariables } , m_globalVariables { globalVariables }
{ {

View File

@ -23,8 +23,10 @@ namespace ScreenPlay {
/*! /*!
\brief Constructor. \brief Constructor.
*/ */
Util::Util() Util::Util(
const std::shared_ptr<GlobalVariables>& globalVariables)
: QObject(nullptr) : QObject(nullptr)
, m_globalVariables { globalVariables }
{ {
m_extractor = std::make_unique<QArchive::DiskExtractor>(); m_extractor = std::make_unique<QArchive::DiskExtractor>();
m_compressor = std::make_unique<QArchive::DiskCompressor>(); m_compressor = std::make_unique<QArchive::DiskCompressor>();
@ -144,6 +146,15 @@ bool Util::exportProject(QString contentPath, QString exportFileName)
return true; return true;
} }
bool Util::openGodotEditor(QString contentPath) const
{
const QList<QString> godotCmd = { "--editor", "--path", toLocal(contentPath) };
QProcess process;
process.setProgram(m_globalVariables->godotEditorExecutablePath().toString());
process.setArguments(godotCmd);
return process.startDetached();
}
/*! /*!
\brief Imports a given project from a .screenplay zip file. The argument extractionPath \brief Imports a given project from a .screenplay zip file. The argument extractionPath
must be copied otherwise it will get reset in qml before extracting. must be copied otherwise it will get reset in qml before extracting.