diff --git a/interface/resources/qml/hifi/AvatarPackager.qml b/interface/resources/qml/hifi/AvatarPackager.qml deleted file mode 100644 index 2492746627..0000000000 --- a/interface/resources/qml/hifi/AvatarPackager.qml +++ /dev/null @@ -1,276 +0,0 @@ -import QtQuick 2.6 -import QtQuick.Controls 2.2 -import QtQuick.Layouts 1.3 -import QtQml.Models 2.1 -import QtGraphicalEffects 1.0 -import "../controlsUit" 1.0 as HifiControls -import "../stylesUit" 1.0 -import "../windows" as Windows -import "../dialogs" -import "./avatarPackager" 1.0 -import "avatarapp" 1.0 as AvatarApp - -Windows.ScrollingWindow { - id: root - objectName: "AvatarPackager" - width: 480 - height: 706 - title: "Avatar Packager" - resizable: false - opacity: parent.opacity - destroyOnHidden: true - implicitWidth: 384; implicitHeight: 640 - minSize: Qt.vector2d(480, 706) - - HifiConstants { id: hifi } - - Item { - id: windowContent - height: pane.height - width: pane.width - - InfoBox { - id: fileListPopup - - title: "List of Files" - - content: Rectangle { - id: fileList - - color: "#404040" - - anchors.fill: parent - anchors.topMargin: 10 - anchors.bottomMargin: 10 - anchors.leftMargin: 29 - anchors.rightMargin: 29 - - clip: true - - ListView { - anchors.fill: parent - model: AvatarPackagerCore.currentAvatarProject === null ? [] : AvatarPackagerCore.currentAvatarProject.projectFiles - delegate: Rectangle { - width: parent.width - height: fileText.implicitHeight + 8 - color: "#404040" - RalewaySemiBold { - id: fileText - size: 16 - elide: Text.ElideLeft - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right - anchors.leftMargin: 16 - anchors.rightMargin: 16 - anchors.topMargin: 4 - width: parent.width - 10 - color: "white" - text: modelData - } - } - } - } - } - - Rectangle { - id: modalOverlay - anchors.fill: parent - z: 20 - color: "#a15d5d5d" - visible: false - - // This mouse area captures the cursor events while the modalOverlay is active - MouseArea { - anchors.fill: parent - propagateComposedEvents: false; - hoverEnabled: true; - } - } - - AvatarApp.MessageBox { - id: popup - anchors.fill: parent - visible: false - closeOnClickOutside: true - } - - Column { - id: avatarPackager - anchors.fill: parent - state: "main" - states: [ - State { - name: AvatarPackagerState.main - PropertyChanges { target: avatarPackagerHeader; title: qsTr("Avatar Packager"); faqEnabled: true; backButtonVisible: false } - PropertyChanges { target: avatarPackagerMain; visible: true } - PropertyChanges { target: avatarPackagerFooter; content: avatarPackagerMain.footer } - }, - State { - name: AvatarPackagerState.createProject - PropertyChanges { target: avatarPackagerHeader; title: qsTr("Create Project") } - PropertyChanges { target: createAvatarProject; visible: true } - PropertyChanges { target: avatarPackagerFooter; content: createAvatarProject.footer } - }, - State { - name: AvatarPackagerState.project - PropertyChanges { target: avatarPackagerHeader; title: AvatarPackagerCore.currentAvatarProject.name; canRename: true } - PropertyChanges { target: avatarProject; visible: true } - PropertyChanges { target: avatarPackagerFooter; content: avatarProject.footer } - }, - State { - name: "project-upload" - PropertyChanges { target: avatarPackagerHeader; title: AvatarPackagerCore.currentAvatarProject.name; backButtonEnabled: false } - PropertyChanges { target: avatarUploader; visible: true } - PropertyChanges { target: avatarPackagerFooter; visible: false } - } - ] - - property alias showModalOverlay: modalOverlay.visible - - function openProject(path) { - let project = AvatarPackagerCore.openAvatarProject(path); - if (project) { - avatarProject.reset(); - avatarPackager.state = "project"; - } - return project; - } - - AvatarPackagerHeader { - id: avatarPackagerHeader - onBackButtonClicked: { - avatarPackager.state = "main" - } - } - - Item { - height: pane.height - avatarPackagerHeader.height - avatarPackagerFooter.height - width: pane.width - - Rectangle { - anchors.fill: parent - color: "#404040" - } - - AvatarProject { - id: avatarProject - colorScheme: root.colorScheme - anchors.fill: parent - } - - AvatarProjectUpload { - id: avatarUploader - anchors.fill: parent - root: avatarProject - } - - CreateAvatarProject { - id: createAvatarProject - colorScheme: root.colorScheme - anchors.fill: parent - } - - Item { - id: avatarPackagerMain - visible: false - anchors.fill: parent - - property var footer: Item { - anchors.fill: parent - anchors.rightMargin: 17 - HifiControls.Button { - id: createProjectButton - anchors.verticalCenter: parent.verticalCenter - anchors.right: openProjectButton.left - anchors.rightMargin: 22 - height: 40 - width: 134 - text: qsTr("New Project") - colorScheme: root.colorScheme - onClicked: { - createAvatarProject.clearInputs(); - avatarPackager.state = AvatarPackagerState.createProject; - } - } - - HifiControls.Button { - id: openProjectButton - anchors.verticalCenter: parent.verticalCenter - anchors.right: parent.right - height: 40 - width: 133 - text: qsTr("Open Project") - color: hifi.buttons.blue - colorScheme: root.colorScheme - onClicked: { - avatarPackager.showModalOverlay = true; - let browser = desktop.fileDialog({ - selectDirectory: false, - dir: fileDialogHelper.pathToUrl(AvatarPackagerCore.AVATAR_PROJECTS_PATH), - filter: "Avatar Project FST Files (*.fst)", - title: "Open Project (.fst)", - }); - - browser.canceled.connect(function() { - avatarPackager.showModalOverlay = false; - }); - - browser.selectedFile.connect(function(fileUrl) { - let fstFilePath = fileDialogHelper.urlToPath(fileUrl); - let currentAvatarProject = avatarPackager.openProject(fstFilePath); - if (currentAvatarProject) { - avatarPackager.showModalOverlay = false; - } - }); - } - } - } - - Flow { - visible: AvatarPackagerCore.recentProjects.length === 0 - anchors { - fill: parent - topMargin: 18 - leftMargin: 16 - rightMargin: 16 - } - RalewayRegular { - size: 20 - color: "white" - text: qsTr("Use a custom avatar to express your identity") - } - RalewayRegular { - size: 20 - color: "white" - text: qsTr("To learn more about using this tool, visit our docs") - } - } - - Column { - visible: AvatarPackagerCore.recentProjects.length > 0 - anchors { - fill: parent - topMargin: 18 - leftMargin: 16 - rightMargin: 16 - } - spacing: 10 - - Repeater { - model: AvatarPackagerCore.recentProjects - AvatarProjectCard { - title: modelData.name - path: modelData.path - onOpen: avatarPackager.openProject(modelData.path) - } - } - } - } - } - AvatarPackagerFooter { - id: avatarPackagerFooter - } - } - } -} diff --git a/interface/resources/qml/hifi/AvatarPackagerWindow.qml b/interface/resources/qml/hifi/AvatarPackagerWindow.qml new file mode 100644 index 0000000000..9d434ef97c --- /dev/null +++ b/interface/resources/qml/hifi/AvatarPackagerWindow.qml @@ -0,0 +1,32 @@ +import QtQuick 2.6 +import QtQuick.Controls 2.2 +import QtQuick.Layouts 1.3 +import QtQml.Models 2.1 +import QtGraphicalEffects 1.0 +import "../controlsUit" 1.0 as HifiControls +import "../stylesUit" 1.0 +import "../windows" as Windows +import "../controls" 1.0 +import "../dialogs" +import "avatarPackager" 1.0 +import "avatarapp" 1.0 as AvatarApp + +Windows.ScrollingWindow { + id: root + objectName: "AvatarPackager" + width: 480 + height: 706 + title: "Avatar Packager" + resizable: false + opacity: parent.opacity + destroyOnHidden: true + implicitWidth: 384; implicitHeight: 640 + minSize: Qt.vector2d(480, 706) + + HifiConstants { id: hifi } + + AvatarPackagerApp { + height: pane.height + width: pane.width + } +} diff --git a/interface/resources/qml/hifi/avatarPackager/AvatarPackagerApp.qml b/interface/resources/qml/hifi/avatarPackager/AvatarPackagerApp.qml new file mode 100644 index 0000000000..2b21b4d938 --- /dev/null +++ b/interface/resources/qml/hifi/avatarPackager/AvatarPackagerApp.qml @@ -0,0 +1,288 @@ +import QtQuick 2.6 +import QtQuick.Controls 2.2 +import QtQuick.Layouts 1.3 +import QtQml.Models 2.1 +import QtGraphicalEffects 1.0 +import "../../controlsUit" 1.0 as HifiControls +import "../../stylesUit" 1.0 +import "../../windows" as Windows +import "../../controls" 1.0 +import "../../dialogs" +import "../avatarapp" 1.0 as AvatarApp + +Item { + HifiConstants { id: hifi } + + property alias desktopObject: avatarPackager.desktopObject + + id: windowContent + // height: pane ? pane.height : parent.width + // width: pane ? pane.width : parent.width + + + MouseArea { + anchors.fill: parent + onClicked: { + unfocusser.forceActiveFocus(); + } + Item { + id: unfocusser + visible: false + } + } + + InfoBox { + id: fileListPopup + + title: "List of Files" + + content: Rectangle { + id: fileList + + color: "#404040" + + anchors.fill: parent + anchors.topMargin: 10 + anchors.bottomMargin: 10 + anchors.leftMargin: 29 + anchors.rightMargin: 29 + + clip: true + + ListView { + anchors.fill: parent + model: AvatarPackagerCore.currentAvatarProject === null ? [] : AvatarPackagerCore.currentAvatarProject.projectFiles + delegate: Rectangle { + width: parent.width + height: fileText.implicitHeight + 8 + color: "#404040" + RalewaySemiBold { + id: fileText + size: 16 + elide: Text.ElideLeft + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + anchors.leftMargin: 16 + anchors.rightMargin: 16 + anchors.topMargin: 4 + width: parent.width - 10 + color: "white" + text: modelData + } + } + } + } + } + + Rectangle { + id: modalOverlay + anchors.fill: parent + z: 20 + color: "#a15d5d5d" + visible: false + + // This mouse area captures the cursor events while the modalOverlay is active + MouseArea { + anchors.fill: parent + propagateComposedEvents: false; + hoverEnabled: true; + } + } + + AvatarApp.MessageBox { + id: popup + anchors.fill: parent + visible: false + closeOnClickOutside: true + } + + Column { + id: avatarPackager + anchors.fill: parent + state: "main" + states: [ + State { + name: AvatarPackagerState.main + PropertyChanges { target: avatarPackagerHeader; title: qsTr("Avatar Packager"); docsEnabled: true; backButtonVisible: false } + PropertyChanges { target: avatarPackagerMain; visible: true } + PropertyChanges { target: avatarPackagerFooter; content: avatarPackagerMain.footer } + }, + State { + name: AvatarPackagerState.createProject + PropertyChanges { target: avatarPackagerHeader; title: qsTr("Create Project") } + PropertyChanges { target: createAvatarProject; visible: true } + PropertyChanges { target: avatarPackagerFooter; content: createAvatarProject.footer } + }, + State { + name: AvatarPackagerState.project + PropertyChanges { target: avatarPackagerHeader; title: AvatarPackagerCore.currentAvatarProject.name; canRename: true } + PropertyChanges { target: avatarProject; visible: true } + PropertyChanges { target: avatarPackagerFooter; content: avatarProject.footer } + }, + State { + name: AvatarPackagerState.projectUpload + PropertyChanges { target: avatarPackagerHeader; title: AvatarPackagerCore.currentAvatarProject.name; backButtonEnabled: false } + PropertyChanges { target: avatarUploader; visible: true } + PropertyChanges { target: avatarPackagerFooter; visible: false } + } + ] + + property alias showModalOverlay: modalOverlay.visible + + property var desktopObject: desktop + + function openProject(path) { + let project = AvatarPackagerCore.openAvatarProject(path); + if (project) { + avatarProject.reset(); + avatarPackager.state = AvatarPackagerState.project; + } + return project; + } + + function openDocs() { + Qt.openUrlExternally("https://docs.highfidelity.com/create/avatars/create-avatars#how-to-package-your-avatar"); + } + + AvatarPackagerHeader { + id: avatarPackagerHeader + colorScheme: root.colorScheme + onBackButtonClicked: { + avatarPackager.state = AvatarPackagerState.main; + } + onDocsButtonClicked: { + avatarPackager.openDocs(); + } + } + + Item { + height: windowContent.height - avatarPackagerHeader.height - avatarPackagerFooter.height + width: windowContent.width + + Rectangle { + anchors.fill: parent + color: "#404040" + } + + AvatarProject { + id: avatarProject + colorScheme: root.colorScheme + anchors.fill: parent + } + + AvatarProjectUpload { + id: avatarUploader + anchors.fill: parent + root: avatarProject + } + + CreateAvatarProject { + id: createAvatarProject + colorScheme: root.colorScheme + anchors.fill: parent + } + + Item { + id: avatarPackagerMain + visible: false + anchors.fill: parent + + property var footer: Item { + anchors.fill: parent + anchors.rightMargin: 17 + HifiControls.Button { + id: createProjectButton + anchors.verticalCenter: parent.verticalCenter + anchors.right: openProjectButton.left + anchors.rightMargin: 22 + height: 40 + width: 134 + text: qsTr("New Project") + colorScheme: root.colorScheme + onClicked: { + createAvatarProject.clearInputs(); + avatarPackager.state = AvatarPackagerState.createProject; + } + } + + HifiControls.Button { + id: openProjectButton + anchors.verticalCenter: parent.verticalCenter + anchors.right: parent.right + height: 40 + width: 133 + text: qsTr("Open Project") + color: hifi.buttons.blue + colorScheme: root.colorScheme + onClicked: { + avatarPackager.showModalOverlay = true; + + let browser = avatarPackager.desktopObject.fileDialog({ + selectDirectory: false, + dir: fileDialogHelper.pathToUrl(AvatarPackagerCore.AVATAR_PROJECTS_PATH), + filter: "Avatar Project FST Files (*.fst)", + title: "Open Project (.fst)", + }); + + browser.canceled.connect(function() { + avatarPackager.showModalOverlay = false; + }); + + browser.selectedFile.connect(function(fileUrl) { + let fstFilePath = fileDialogHelper.urlToPath(fileUrl); + let currentAvatarProject = avatarPackager.openProject(fstFilePath); + if (currentAvatarProject) { + avatarPackager.showModalOverlay = false; + } + }); + } + } + } + + Flow { + visible: AvatarPackagerCore.recentProjects.length === 0 + anchors { + fill: parent + topMargin: 18 + leftMargin: 16 + rightMargin: 16 + } + RalewayRegular { + size: 20 + color: "white" + text: qsTr("Use a custom avatar to express your identity") + } + RalewayRegular { + size: 20 + color: "white" + text: qsTr("To learn more about using this tool, visit our docs") + } + } + + Column { + visible: AvatarPackagerCore.recentProjects.length > 0 + anchors { + fill: parent + topMargin: 18 + leftMargin: 16 + rightMargin: 16 + } + spacing: 10 + + Repeater { + model: AvatarPackagerCore.recentProjects + AvatarProjectCard { + title: modelData.name + path: modelData.projectPath + onOpen: avatarPackager.openProject(modelData.path) + } + } + } + } + } + AvatarPackagerFooter { + id: avatarPackagerFooter + } + } +} diff --git a/interface/resources/qml/hifi/avatarPackager/AvatarPackagerHeader.qml b/interface/resources/qml/hifi/avatarPackager/AvatarPackagerHeader.qml index 5b01005edd..7037aa9d92 100644 --- a/interface/resources/qml/hifi/avatarPackager/AvatarPackagerHeader.qml +++ b/interface/resources/qml/hifi/avatarPackager/AvatarPackagerHeader.qml @@ -11,11 +11,18 @@ Rectangle { color: "#252525" property alias title: title.text - property alias faqEnabled: faq.visible + property alias docsEnabled: docs.visible property bool backButtonVisible: true // If false, is not visible and does not take up space property bool backButtonEnabled: true // If false, is not visible but does not affect space - property bool canRename: false; + property bool canRename: false + property int colorScheme + + property color textColor: "white" + property color hoverTextColor: "gray" + property color pressedTextColor: "#6A6A6A" + signal backButtonClicked + signal docsButtonClicked RalewaySemiBold { id: back @@ -27,7 +34,7 @@ Rectangle { anchors.leftMargin: 16 anchors.verticalCenter: back.verticalCenter text: "◀" - color: "white" + color: textColor MouseArea { anchors.fill: parent onClicked: root.backButtonClicked() @@ -37,37 +44,102 @@ Rectangle { states: [ State { name: "hovering" - PropertyChanges { - target: back - color: "gray" - } + PropertyChanges { target: back; color: hoverTextColor } } ] } } - - RalewaySemiBold { - id: title - size: 28 + Item { + id: titleArea anchors.top: parent.top anchors.bottom: parent.bottom anchors.left: root.backButtonVisible ? back.right : parent.left anchors.leftMargin: root.backButtonVisible ? 11 : 21 anchors.verticalCenter: title.verticalCenter - text: qsTr("Avatar Packager") - color: "white" + anchors.right: docs.left + states: [ + State { + name: "renaming" + PropertyChanges { target: title; visible: false } + PropertyChanges { target: titleInputArea; visible: true } + } + ] + + RalewaySemiBold { + id: title + size: 28 + anchors.fill: parent + text: qsTr("Avatar Packager") + color: "white" + + MouseArea { + anchors.fill: parent + onClicked: { + if (!root.canRename || AvatarPackagerCore.currentAvatarProject === null) { + return; + } + + titleArea.state = "renaming"; + titleInput.text = AvatarPackagerCore.currentAvatarProject.name; + titleInput.selectAll(); + titleInput.forceActiveFocus(Qt.MouseFocusReason); + } + } + } + Item { + id: titleInputArea + visible: false + anchors.fill: parent + + HifiControls.TextField { + id: titleInput + anchors.fill: parent + text: "" + colorScheme: root.colorScheme + font.family: "Fira Sans" + font.pixelSize: 28 + z: 200 + onFocusChanged: { + if (titleArea.state === "renaming" && !titleArea.focus) { + //titleArea.state = ""; + accepted(); + } + } + Keys.onPressed: { + if (event.key === Qt.Key_Escape) { + titleArea.state = ""; + } + } + onAccepted: { + if (acceptableInput) { + //AvatarPackagerCore.renameProject(text); + console.warn(text); + AvatarPackagerCore.currentAvatarProject.name = text; + console.warn(AvatarPackagerCore.currentAvatarProject.name); + + } + titleArea.state = ""; + } + } + } } RalewaySemiBold { - id: faq + id: docs visible: false size: 28 anchors.top: parent.top anchors.bottom: parent.bottom anchors.right: parent.right anchors.rightMargin: 16 - anchors.verticalCenter: faq.verticalCenter + anchors.verticalCenter: docs.verticalCenter text: qsTr("Docs") color: "white" + MouseArea { + anchors.fill: parent + onClicked: { + docsButtonClicked(); + } + } } } diff --git a/interface/resources/qml/hifi/avatarPackager/AvatarPackagerState.qml b/interface/resources/qml/hifi/avatarPackager/AvatarPackagerState.qml index f12edf4952..c81173a080 100644 --- a/interface/resources/qml/hifi/avatarPackager/AvatarPackagerState.qml +++ b/interface/resources/qml/hifi/avatarPackager/AvatarPackagerState.qml @@ -6,4 +6,5 @@ Item { readonly property string main: "main" readonly property string project: "project" readonly property string createProject: "createProject" + readonly property string projectUpload: "projectUpload" } diff --git a/interface/resources/qml/hifi/avatarPackager/AvatarProject.qml b/interface/resources/qml/hifi/avatarPackager/AvatarProject.qml index c94c9570ae..a5a2263346 100644 --- a/interface/resources/qml/hifi/avatarPackager/AvatarProject.qml +++ b/interface/resources/qml/hifi/avatarPackager/AvatarProject.qml @@ -178,7 +178,7 @@ Item { } }); root.uploader.send(); - avatarPackager.state = "project-upload"; + avatarPackager.state = AvatarPackagerState.projectUpload; } function showConfirmUploadPopup() { diff --git a/interface/resources/qml/hifi/avatarPackager/AvatarProjectCard.qml b/interface/resources/qml/hifi/avatarPackager/AvatarProjectCard.qml index 736de2019c..5496711d44 100644 --- a/interface/resources/qml/hifi/avatarPackager/AvatarProjectCard.qml +++ b/interface/resources/qml/hifi/avatarPackager/AvatarProjectCard.qml @@ -53,11 +53,14 @@ Item { RalewayBold { id: title + elide: "ElideRight" anchors { top: parent.top topMargin: 13 left: parent.left leftMargin: 16 + right: parent.right + rightMargin: 16 } text: "