-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
[ui] Homepage: Highlight the pipeline or project that is being loaded #3080
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Changes from all commits
d63da78
99d5226
6857e77
f3b036a
97e9325
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -9,10 +9,28 @@ import Controls 1.0 | |
| Page { | ||
| id: root | ||
|
|
||
| property bool isLoading: false | ||
|
|
||
| // Schedule an action to run after the current frame has been rendered and | ||
| // displayed, so that visual feedback (highlight, spinner) is visible before | ||
| // the UI thread is blocked by a heavy synchronous operation. | ||
| // Uses _window (the ApplicationWindow id from main.qml) since root.window | ||
| // is not reliably available for Page items inside a StackView. | ||
| function executeAfterFrameRendered(action) { | ||
| function onFrame() { | ||
| _window.frameSwapped.disconnect(onFrame) | ||
| action() | ||
| } | ||
| _window.frameSwapped.connect(onFrame) | ||
| } | ||
|
|
||
| onVisibleChanged: { | ||
| logo.playing = false | ||
| if (visible) { | ||
| logo.playing = true | ||
| isLoading = false | ||
| homepageGridView.loadingIndex = -1 | ||
| pipelinesListView.loadingIndex = -1 | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -242,6 +260,8 @@ Page { | |
| id: pipelinesListView | ||
| visible: tabPanel.currentTab === 0 | ||
|
|
||
| property int loadingIndex: -1 | ||
|
|
||
| anchors.fill: parent | ||
| anchors.margins: 10 | ||
|
|
||
|
|
@@ -251,20 +271,44 @@ Page { | |
| id: pipelineDelegate | ||
| padding: 10 | ||
| width: pipelinesListView.width | ||
| enabled: !root.isLoading || index === pipelinesListView.loadingIndex | ||
| opacity: (!root.isLoading || index === pipelinesListView.loadingIndex) ? 1.0 : 0.4 | ||
|
|
||
| contentItem: RowLayout { | ||
| Label { | ||
| id: pipeline | ||
| Layout.fillWidth: true | ||
| horizontalAlignment: Text.AlignLeft | ||
| verticalAlignment: Text.AlignVCenter | ||
| text: modelData["name"] | ||
| } | ||
| BusyIndicator { | ||
| Layout.preferredWidth: 24 | ||
| Layout.preferredHeight: 24 | ||
| running: index === pipelinesListView.loadingIndex && root.isLoading | ||
| visible: running | ||
| } | ||
| } | ||
|
|
||
| contentItem: Label { | ||
| id: pipeline | ||
| horizontalAlignment: Text.AlignLeft | ||
| verticalAlignment: Text.AlignVCenter | ||
| text: modelData["name"] | ||
| // Highlight overlay shown when this pipeline is being loaded | ||
| Rectangle { | ||
| anchors.fill: parent | ||
| color: "transparent" | ||
| border.color: palette.highlight | ||
| border.width: 2 | ||
| visible: root.isLoading && index === pipelinesListView.loadingIndex | ||
| } | ||
|
|
||
| Connections { | ||
| target: pipelineDelegate | ||
| function onClicked() { | ||
| // Open pipeline | ||
| mainStack.push("Application.qml") | ||
| _currentScene.new(modelData["path"]) | ||
| root.isLoading = true | ||
| pipelinesListView.loadingIndex = index | ||
| let path = modelData["path"] | ||
| root.executeAfterFrameRendered(function() { | ||
|
Comment on lines
304
to
+308
|
||
| mainStack.push("Application.qml") | ||
| _currentScene.new(path) | ||
| }) | ||
| } | ||
| } | ||
| } | ||
|
|
@@ -276,6 +320,8 @@ Page { | |
| anchors.fill: parent | ||
| anchors.topMargin: cellHeight * 0.1 | ||
|
|
||
| property int loadingIndex: -1 | ||
|
|
||
| cellWidth: 195 | ||
| cellHeight: cellWidth | ||
| anchors.margins: 10 | ||
|
|
@@ -311,6 +357,7 @@ Page { | |
|
|
||
| width: homepageGridView.cellWidth | ||
| height: homepageGridView.cellHeight | ||
| opacity: (!root.isLoading || index === homepageGridView.loadingIndex) ? 1.0 : 0.4 | ||
|
|
||
| property var source: modelData["thumbnail"] ? Filepath.stringToUrl(modelData["thumbnail"]) : "" | ||
| property int retryCount: 0 | ||
|
|
@@ -387,6 +434,8 @@ Page { | |
|
|
||
| onClicked: function(mouse) { | ||
|
|
||
| if (root.isLoading) return | ||
|
|
||
| if (mouse.button === Qt.RightButton) { | ||
|
|
||
| if (!modelData["path"]) { return } | ||
|
|
@@ -403,11 +452,18 @@ Page { | |
| } | ||
|
|
||
| else { | ||
| // Open project | ||
| mainStack.push("Application.qml") | ||
| if (_currentScene.load(modelData["path"])) { | ||
| MeshroomApp.addRecentProjectFile(modelData["path"]) | ||
| } | ||
| root.isLoading = true | ||
| homepageGridView.loadingIndex = index | ||
| let path = modelData["path"] | ||
| root.executeAfterFrameRendered(function() { | ||
| mainStack.push("Application.qml") | ||
| if (_currentScene.load(path)) { | ||
| MeshroomApp.addRecentProjectFile(path) | ||
| } else { | ||
| root.isLoading = false | ||
| homepageGridView.loadingIndex = -1 | ||
| } | ||
| }) | ||
|
Comment on lines
+455
to
+466
|
||
| } | ||
| } | ||
| } | ||
|
|
@@ -416,13 +472,21 @@ Page { | |
| id: projectContextMenu | ||
|
|
||
| MenuItem { | ||
| enabled: projectDelegate.fileExists | ||
| enabled: projectDelegate.fileExists && !root.isLoading | ||
| text: "Open" | ||
| onTriggered: { | ||
| if (_currentScene.load(modelData["path"])) { | ||
| onTriggered: { | ||
| root.isLoading = true | ||
| homepageGridView.loadingIndex = index | ||
| let path = modelData["path"] | ||
| root.executeAfterFrameRendered(function() { | ||
| mainStack.push("Application.qml") | ||
| MeshroomApp.addRecentProjectFile(modelData["path"]) | ||
| } | ||
| if (_currentScene.load(path)) { | ||
| MeshroomApp.addRecentProjectFile(path) | ||
| } else { | ||
| root.isLoading = false | ||
| homepageGridView.loadingIndex = -1 | ||
| } | ||
| }) | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -462,8 +526,17 @@ Page { | |
|
|
||
| BusyIndicator { | ||
| anchors.centerIn: parent | ||
| running: homepageGridView.visible && projectContent.thumbnailBusy | ||
| visible: homepageGridView.visible && projectContent.thumbnailBusy | ||
| running: (homepageGridView.visible && projectContent.thumbnailBusy) || (root.isLoading && index === homepageGridView.loadingIndex) | ||
| visible: running | ||
| } | ||
|
|
||
| // Highlight overlay shown when this project is being loaded | ||
| Rectangle { | ||
| anchors.fill: parent | ||
| color: "transparent" | ||
| border.color: palette.highlight | ||
| border.width: 2 | ||
| visible: root.isLoading && index === homepageGridView.loadingIndex | ||
| } | ||
| } | ||
| Label { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
enabled: !root.isLoading || index === pipelinesListView.loadingIndexleaves the selected pipeline button enabled whileroot.isLoadingis true. This allows repeated clicks on the same item during the short window before the heavy operation starts, potentially scheduling multipleexecuteAfterFrameRenderedcallbacks and pushing multiple Application pages / calling_currentScene.newmultiple times. Consider disabling all pipeline delegates while loading (or at least adding a re-entrancy guard so subsequent clicks are ignored).