summaryrefslogtreecommitdiffstats
path: root/tools/viewer/qml/main.qml
diff options
context:
space:
mode:
Diffstat (limited to 'tools/viewer/qml/main.qml')
-rw-r--r--tools/viewer/qml/main.qml594
1 files changed, 594 insertions, 0 deletions
diff --git a/tools/viewer/qml/main.qml b/tools/viewer/qml/main.qml
new file mode 100644
index 0000000..1357f39
--- /dev/null
+++ b/tools/viewer/qml/main.qml
@@ -0,0 +1,594 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.7
+import QtQuick.Controls 2.2
+import QtQuick.Dialogs 1.2
+import Qt3DStudioViewer 1.0
+import QtStudio3D.OpenGL 2.4
+import QtQuick.Window 2.2
+
+ApplicationWindow {
+ id: window
+ width: 1280
+ height: 768
+ visible: true
+ title: qsTr("Qt 3D Studio Viewer")
+
+ property bool menuOpen: fileMenu.visible || viewMenu.visible
+ property Item loadedContent: contentLoader ? contentLoader.item : null
+ property string error
+ property int previousVisibility
+
+ property color showMatteColor: Qt.rgba(0.2, 0.2, 0.2, 1)
+ property color hideMatteColor: Qt.rgba(0, 0, 0, 1)
+ property color matteColor: hideMatteColor
+ property bool showRenderStats: false
+ property int scaleMode: ViewerSettings.ScaleModeCenter
+
+ function closeMenus() {
+ fileMenu.close();
+ scaleMenu.close();
+ viewMenu.close();
+ }
+
+ Component.onCompleted: {
+ _viewerHelper.restoreWindowState(window);
+ previousVisibility = visibility;
+ }
+
+ onClosing: {
+ _viewerHelper.storeWindowState(window);
+ }
+
+ Timer {
+ id: infoTimer
+ repeat: false
+ interval: 5000
+
+ onTriggered: {
+ infoOverlay.visible = false;
+ }
+ }
+
+ Rectangle {
+ id: infoOverlay
+ visible: false
+ color: "black"
+ border.color: _dialogBorderColor
+ x: parent.width * 0.2
+ y: parent.height * 0.4
+ width: parent.width * 0.6
+ height: parent.height * 0.2
+ z: 20
+ Label {
+ id: infoLabel
+ anchors.fill: parent
+ color: _textColor
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+ font.pixelSize: window.width / 40
+ }
+ }
+
+ Connections {
+ target: _viewerHelper
+ onShowInfoOverlay: {
+ // Show a brief info overlay
+ infoLabel.text = infoStr;
+ infoOverlay.visible = true;
+ infoTimer.restart();
+ }
+ }
+
+ MouseArea {
+ property int swipeStart: 0
+
+ anchors.fill: parent
+ z: 10
+ enabled: !ipEntry.visible
+
+ onPressed: {
+ if (window.visibility === Window.FullScreen)
+ swipeStart = mouse.y;
+ _viewerHelper.handleMousePress(mouse.x, mouse.y, mouse.button, mouse.buttons,
+ mouse.modifiers);
+ mouse.accepted = true;
+ }
+ onReleased: {
+ _viewerHelper.handleMouseRelease(mouse.x, mouse.y, mouse.button, mouse.buttons,
+ mouse.modifiers);
+ mouse.accepted = true;
+ }
+ onPositionChanged: {
+ // Swipe down to exit fullscreen mode
+ if (window.visibility === Window.FullScreen && mouse.y > swipeStart + (height / 8)) {
+ window.visibility = window.previousVisibility;
+ } else {
+ _viewerHelper.handleMouseMove(mouse.x, mouse.y, mouse.button, mouse.buttons,
+ mouse.modifiers);
+ }
+ }
+ }
+
+ DropArea {
+ anchors.fill: parent
+ onEntered: {
+ if (drag.hasUrls) {
+ var filename = _viewerHelper.convertUrlListToFilename(drag.urls);
+ if (filename === "")
+ drag.accepted = false;
+ }
+ }
+ onDropped: {
+ if (drop.hasUrls) {
+ var filename = _viewerHelper.convertUrlListToFilename(drop.urls);
+ if (filename === "")
+ drag.accepted = false;
+ else
+ _viewerHelper.loadFile(filename);
+ }
+ }
+ }
+
+ Loader {
+ id: contentLoader
+ anchors.fill: parent
+ sourceComponent: {
+ switch (_viewerHelper.contentView) {
+ case ViewerHelper.StudioView:
+ return studioContent;
+ case ViewerHelper.ConnectView:
+ return connectContent;
+ case ViewerHelper.SequenceView:
+ return sequenceContent;
+ default:
+ return emptyContent;
+ }
+ }
+ Timer {
+ id: asyncContentChanger
+ repeat: false
+ interval: 0
+ property int view: ViewerHelper.DefaultView
+ function changeView(newView) {
+ view = newView;
+ start();
+ }
+
+ onTriggered: {
+ _viewerHelper.contentView = view;
+ }
+ }
+ }
+
+ Component {
+ id: emptyContent
+ Rectangle {
+ color: "black"
+ Label {
+ anchors.fill: parent
+ text: window.error
+ color: _textColor
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+ font.pixelSize: width / 80
+ }
+ }
+ }
+
+ Component {
+ id: studioContent
+ Studio3D {
+ id: studio3D
+
+ property alias hiderVisible: hider.visible
+
+ focus: true
+ ViewerSettings {
+ matteColor: window.matteColor
+ showRenderStats: window.showRenderStats
+ scaleMode: window.scaleMode
+ }
+
+ // Hider item keeps the Studio3D hidden until it starts running and we reset the
+ // animation time to the start
+ Rectangle {
+ id: hider
+ color: "black"
+ anchors.fill: parent
+ }
+
+ Timer {
+ id: revealTimer
+ repeat: false
+ interval: 0
+ onTriggered: {
+ hider.visible = false;
+ }
+ }
+
+ onRunningChanged: {
+ if (running) {
+ // Successfully opened a presentation, update the open folder
+ _viewerHelper.openFolder = presentation.source.toString();
+ // Force the animation to start from the beginning, as the first frame render
+ // can take some time as shaders are compiled on-demand
+ // Localization note: "Scene" needs to be the same as the default "Scene"
+ // element name generated in the Studio application.
+ presentation.goToTime(qsTr("Scene"), 0);
+ revealTimer.start();
+ }
+ }
+ onErrorChanged: {
+ if (error.length > 0) {
+ window.error = error;
+ asyncContentChanger.changeView(ViewerHelper.DefaultView);
+ }
+ }
+ }
+ }
+
+ Component {
+ id: connectContent
+ Rectangle {
+ color: "black"
+ Label {
+ anchors.fill: parent
+ text: _viewerHelper.connectText
+ color: _textColor
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+ font.pixelSize: width / 40
+ }
+ }
+ }
+
+ Component {
+ id: sequenceContent
+ Rectangle {
+ property alias mainText: mainLabel.text
+ property alias detailsText: detailsLabel.text
+ color: "black"
+ Item {
+ anchors.fill: parent
+ Label {
+ id: mainLabel
+ color: _textColor
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignBottom
+ anchors.top: parent.top
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.bottomMargin: _controlPadding
+ height: parent.height / 2
+ font.pixelSize: width / 40
+ text: qsTr("Image sequence generation initializing...")
+ }
+ Label {
+ id: detailsLabel
+ color: _textColor
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignTop
+ anchors.top: mainLabel.bottom
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.topMargin: _controlPadding
+ height: parent.height / 2
+ font.pixelSize: width / 50
+ }
+ }
+ }
+ }
+
+ Rectangle {
+ id: ipEntry
+ visible: false
+ color: _dialogBackgroundColor
+ border.color: _dialogBorderColor
+ y: (parent.height - height) / 2
+ x: (parent.width - width) / 2
+ z: 100
+ width: connectionEntry.width + (2 * _controlPadding)
+ height: connectionEntry.height + (2 * _controlPadding)
+
+ onVisibleChanged: {
+ if (visible) {
+ connectText.forceActiveFocus();
+ connectText.selectAll();
+ }
+ }
+
+ Grid {
+ id: connectionEntry
+ spacing: _controlPadding
+ columns: 2
+ y: _controlPadding
+ x: _controlPadding
+ Label {
+ id: ipEntryLabel
+ width: _controlBaseWidth
+ height: _controlBaseHeight
+ text: qsTr("Enter IP port:")
+ color: _textColor
+ font.pixelSize: _fontSize
+ verticalAlignment: Text.AlignVCenter
+ padding: _controlPadding / 2
+ }
+ TextField {
+ id: connectText
+ width: _controlBaseWidth
+ height: _controlBaseHeight
+ font.pixelSize: _fontSize
+ color: _textColor
+ selectByMouse: true
+ padding: _controlPadding / 6
+ enabled: ipEntry.visible
+ text: _viewerHelper.connectPort
+ validator: IntValidator {
+ bottom: 1
+ top: 65535
+ }
+
+ onAccepted: {
+ if (ipEntry.visible) {
+ _viewerHelper.contentView = ViewerHelper.ConnectView;
+ _viewerHelper.connectPort = Number(text);
+ _viewerHelper.connectRemote();
+ ipEntry.visible = false;
+ infoOverlay.visible = false;
+ }
+ }
+
+ background: Rectangle {
+ id: textBackground
+ color: _dialogFieldColor
+ border.width: 1
+ border.color: _dialogFieldBorderColor
+ radius: 2
+ }
+ }
+ StyledButton {
+ id: connectButton
+ width: _controlBaseWidth
+ text: qsTr("Connect")
+ onClicked: {
+ _viewerHelper.contentView = ViewerHelper.ConnectView;
+ _viewerHelper.connectPort = Number(connectText.text);
+ _viewerHelper.connectRemote();
+ ipEntry.visible = false;
+ infoOverlay.visible = false;
+ }
+ }
+ StyledButton {
+ id: cancelButton
+ width: _controlBaseWidth
+ text: qsTr("Cancel")
+ onClicked: {
+ ipEntry.visible = false;
+ }
+ }
+ }
+ }
+
+ Component {
+ id: fileDialogComponent
+ FileDialog {
+ id: fileDialog
+ title: qsTr("Choose Presentation or Project")
+ folder: _viewerHelper.openFolder
+ nameFilters: [qsTr("All supported formats (*.uip *.uia)"),
+ qsTr("Studio UI Presentation (*.uip)"),
+ qsTr("Application file (*.uia)")]
+ onAccepted: {
+ _viewerHelper.contentView = ViewerHelper.StudioView;
+ contentLoader.item.presentation.setSource(fileUrls[0]);
+ }
+ }
+ }
+
+ header: Rectangle {
+ height: _controlBaseHeight
+ color: _menuBackgroundColor
+ visible: window.visibility !== Window.FullScreen
+
+ Row {
+ anchors.fill: parent
+ StyledMenuButton {
+ id: fileButton
+ text: qsTr("File")
+ menu: fileMenu
+ window: window
+
+ StyledMenu {
+ id: fileMenu
+ StyledMenuItem {
+ text: qsTr("Open...")
+ shortcut: StandardKey.Open
+ enabled: _viewerHelper.contentView !== ViewerHelper.SequenceView
+ onTriggered: {
+ if (enabled) {
+ fileDialogLoader.sourceComponent = fileDialogComponent;
+ fileDialogLoader.item.open();
+ }
+ }
+ Loader {
+ id: fileDialogLoader
+ sourceComponent: Item {}
+ }
+ }
+ StyledMenuItem {
+ text: _viewerHelper.connected ? qsTr("Disconnect") : qsTr("Connect...")
+ shortcut: "F9"
+ enabled: _viewerHelper.contentView !== ViewerHelper.SequenceView
+ onTriggered: {
+ if (enabled) {
+ if (_viewerHelper.connected)
+ _viewerHelper.disconnectRemote();
+ else
+ ipEntry.visible = !ipEntry.visible;
+ }
+ }
+ }
+ StyledMenuItem {
+ text: qsTr("Reload")
+ enabled: _viewerHelper.contentView === ViewerHelper.StudioView
+ shortcut: "F5"
+ onTriggered: {
+ if (enabled) {
+ contentLoader.item.hiderVisible = true;
+ contentLoader.item.reset();
+ }
+ }
+ }
+ StyledMenuSeparator {}
+ StyledMenuItem {
+ text: qsTr("Quit")
+ shortcut: "Ctrl+Q"
+ onTriggered: {
+ window.close();
+ }
+ }
+ }
+ }
+ StyledMenuButton {
+ id: viewButton
+ text: qsTr("View")
+ menu: viewMenu
+ window: window
+
+ StyledMenu {
+ id: viewMenu
+ StyledMenuItem {
+ text: qsTr("Show Matte")
+ shortcut: "Ctrl+D"
+ enabled: _viewerHelper.contentView === ViewerHelper.StudioView
+ showCheckMark: window.matteColor !== window.hideMatteColor
+ onTriggered: {
+ if (enabled) {
+ if (window.matteColor === window.hideMatteColor)
+ window.matteColor = window.showMatteColor;
+ else
+ window.matteColor = window.hideMatteColor;
+ }
+ }
+ }
+ StyledMenuItem {
+ id: scaleMenuItem
+ text: qsTr("Scale Mode")
+ showArrow: true
+ arrowMenu: scaleMenu
+ shortcut: "Ctrl+Shift+S"
+ enabled: _viewerHelper.contentView === ViewerHelper.StudioView
+ onTriggered: {
+ if (enabled) {
+ scaleMenu.close();
+ if (window.scaleMode === ViewerSettings.ScaleModeCenter)
+ window.scaleMode = ViewerSettings.ScaleModeFit;
+ else if (window.scaleMode === ViewerSettings.ScaleModeFit)
+ window.scaleMode = ViewerSettings.ScaleModeFill;
+ else if (window.scaleMode === ViewerSettings.ScaleModeFill)
+ window.scaleMode = ViewerSettings.ScaleModeCenter;
+ }
+ }
+
+ StyledMenu {
+ id: scaleMenu
+ x: parent.width
+ y: 0
+
+ StyledMenuItem {
+ id: scaleCenter
+ text: qsTr("Center")
+ enabled: _viewerHelper.contentView === ViewerHelper.StudioView
+ showCheckMark: window.scaleMode === ViewerSettings.ScaleModeCenter
+ onTriggered: {
+ if (enabled)
+ window.scaleMode = ViewerSettings.ScaleModeCenter;
+ }
+ }
+ StyledMenuItem {
+ id: scaleFit
+ text: qsTr("Scale to Fit")
+ enabled: _viewerHelper.contentView === ViewerHelper.StudioView
+ showCheckMark: window.scaleMode === ViewerSettings.ScaleModeFit
+ onTriggered: {
+ if (enabled)
+ window.scaleMode = ViewerSettings.ScaleModeFit;
+ }
+ }
+ StyledMenuItem {
+ id: scaleFill
+ text: qsTr("Scale to Fill")
+ enabled: _viewerHelper.contentView === ViewerHelper.StudioView
+ showCheckMark: window.scaleMode === ViewerSettings.ScaleModeFill
+ onTriggered: {
+ if (enabled)
+ window.scaleMode = ViewerSettings.ScaleModeFill;
+ }
+ }
+ }
+ }
+ StyledMenuItem {
+ text: qsTr("Show Render Statistics")
+ shortcut: "F7"
+ enabled: _viewerHelper.contentView === ViewerHelper.StudioView
+ showCheckMark: window.showRenderStats
+ onTriggered: {
+ if (enabled)
+ window.showRenderStats = !window.showRenderStats;
+ }
+ }
+ StyledMenuSeparator {}
+ StyledMenuItem {
+ text: qsTr("Full Screen")
+ shortcut: "F11"
+ Shortcut {
+ sequence: "ESC"
+ context: Qt.ApplicationShortcut
+ enabled: window.visibility === Window.FullScreen
+ onActivated: {
+ window.visibility = window.previousVisibility;
+ }
+ }
+
+ onTriggered: {
+ if (window.visibility !== Window.FullScreen) {
+ window.previousVisibility = window.visibility
+ window.visibility = Window.FullScreen;
+ } else {
+ window.visibility = window.previousVisibility;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}