diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/hifi/AssetServer.qml
similarity index 80%
rename from interface/resources/qml/AssetServer.qml
rename to interface/resources/qml/hifi/AssetServer.qml
index 649ea49153..e54d4048ec 100644
--- a/interface/resources/qml/AssetServer.qml
+++ b/interface/resources/qml/hifi/AssetServer.qml
@@ -14,10 +14,10 @@ import QtQuick.Controls.Styles 1.4
import QtQuick.Dialogs 1.2 as OriginalDialogs
import Qt.labs.settings 1.0
-import "styles-uit"
-import "controls-uit" as HifiControls
-import "windows"
-import "dialogs"
+import "../styles-uit"
+import "../controls-uit" as HifiControls
+import "../windows"
+import "../dialogs"
ScrollingWindow {
id: root
@@ -58,6 +58,14 @@ ScrollingWindow {
assetMappingsModel.autoRefreshEnabled = false;
}
+ function letterbox(headerGlyph, headerText, message) {
+ letterboxMessage.headerGlyph = headerGlyph;
+ letterboxMessage.headerText = headerText;
+ letterboxMessage.text = message;
+ letterboxMessage.visible = true;
+ letterboxMessage.popupRadius = 0;
+ }
+
function doDeleteFile(path) {
console.log("Deleting " + path);
@@ -154,10 +162,7 @@ ScrollingWindow {
}
function handleGetMappingsError(errorString) {
- errorMessageBox(
- "There was a problem retreiving the list of assets from your Asset Server.\n"
- + errorString
- );
+ errorMessageBox("There was a problem retreiving the list of assets from your Asset Server.\n" + errorString);
}
function addToWorld() {
@@ -457,10 +462,16 @@ ScrollingWindow {
text: message
});
}
-
+
Item {
width: pane.contentWidth
height: pane.height
+
+ // The letterbox used for popup messages
+ LetterboxMessage {
+ id: letterboxMessage;
+ z: 999; // Force the popup on top of everything else
+ }
HifiControls.ContentSection {
id: assetDirectory
@@ -476,7 +487,7 @@ ScrollingWindow {
HifiControls.Button {
text: "Add To World"
- color: hifi.buttons.black
+ color: hifi.buttons.blue
colorScheme: root.colorScheme
width: 120
@@ -513,6 +524,7 @@ ScrollingWindow {
id: treeView
anchors.top: assetDirectory.bottom
anchors.bottom: infoRow.top
+ anchors.bottomMargin: 2 * hifi.dimensions.contentSpacing.y
anchors.margins: hifi.dimensions.contentMargin.x + 2 // Extra for border
anchors.left: parent.left
anchors.right: parent.right
@@ -584,8 +596,24 @@ ScrollingWindow {
? (styleData.selected ? hifi.colors.black : hifi.colors.baseGrayHighlight)
: (styleData.selected ? hifi.colors.black : hifi.colors.lightGrayText)
- elide: Text.ElideRight
horizontalAlignment: styleData.column === 1 ? TextInput.AlignHCenter : TextInput.AlignLeft
+
+ elide: Text.ElideMiddle
+
+ MouseArea {
+ id: mouseArea
+ anchors.fill: parent
+
+ acceptedButtons: Qt.NoButton
+ hoverEnabled: true
+
+ onEntered: {
+ if (parent.truncated) {
+ treeLabelToolTip.show(parent);
+ }
+ }
+ onExited: treeLabelToolTip.hide();
+ }
}
}
Component {
@@ -668,6 +696,42 @@ ScrollingWindow {
}
}
+ Rectangle {
+ id: treeLabelToolTip
+ visible: false
+ z: 100 // Render on top
+
+ width: toolTipText.width + 2 * hifi.dimensions.textPadding
+ height: hifi.dimensions.tableRowHeight
+ color: colorScheme == hifi.colorSchemes.light ? hifi.colors.tableRowLightOdd : hifi.colors.tableRowDarkOdd
+ border.color: colorScheme == hifi.colorSchemes.light ? hifi.colors.black : hifi.colors.lightGrayText
+
+ FiraSansSemiBold {
+ id: toolTipText
+ anchors.centerIn: parent
+
+ size: hifi.fontSizes.tableText
+ color: colorScheme == hifi.colorSchemes.light ? hifi.colors.black : hifi.colors.lightGrayText
+ }
+
+ Timer {
+ id: showTimer
+ interval: 1000
+ onTriggered: { treeLabelToolTip.visible = true; }
+ }
+ function show(item) {
+ var coord = item.mapToItem(parent, item.x, item.y);
+
+ toolTipText.text = item.text;
+ treeLabelToolTip.x = coord.x - hifi.dimensions.textPadding;
+ treeLabelToolTip.y = coord.y;
+ showTimer.start();
+ }
+ function hide() {
+ showTimer.stop();
+ treeLabelToolTip.visible = false;
+ }
+ }
MouseArea {
propagateComposedEvents: true
@@ -712,31 +776,43 @@ ScrollingWindow {
}
}
- Row {
+ Item {
id: infoRow
anchors.left: treeView.left
anchors.right: treeView.right
anchors.bottom: uploadSection.top
- anchors.bottomMargin: hifi.dimensions.contentSpacing.y
- spacing: hifi.dimensions.contentSpacing.x
+ anchors.topMargin: 2 * hifi.dimensions.contentSpacing.y
+ anchors.bottomMargin: 2 * hifi.dimensions.contentSpacing.y
RalewayRegular {
+ id: treeInfo
+ anchors.left: parent.left
+ anchors.verticalCenter: parent.verticalCenter
+
+ function makeText() {
+ var pendingBakes = assetMappingsModel.bakesPendingCount;
+ if (selectedItems > 1 || pendingBakes === 0) {
+ return selectedItems + " items selected";
+ } else {
+ return pendingBakes + " bakes pending"
+ }
+ }
+
size: hifi.fontSizes.sectionName
font.capitalization: Font.AllUppercase
- text: selectedItems + " items selected"
+ text: makeText()
color: hifi.colors.lightGrayText
}
HifiControls.CheckBox {
- function isChecked() {
- var status = assetProxyModel.data(treeView.selection.currentIndex, 0x105);
- var bakingDisabled = (status === "Not Baked" || status === "--");
- return selectedItems === 1 && !bakingDisabled;
- }
+ id: bakingCheckbox
+ anchors.left: treeInfo.right
+ anchors.leftMargin: 2 * hifi.dimensions.contentSpacing.x
+ anchors.verticalCenter: parent.verticalCenter
- text: "Use baked (optimized) versions"
+ text: " Use baked version"
colorScheme: root.colorScheme
- enabled: selectedItems === 1 && assetProxyModel.data(treeView.selection.currentIndex, 0x105) !== "--"
+ enabled: isEnabled()
checked: isChecked()
onClicked: {
var mappings = [];
@@ -752,7 +828,72 @@ ScrollingWindow {
checked = Qt.binding(isChecked);
}
+
+ function isEnabled() {
+ if (!treeView.selection.hasSelection) {
+ return false;
+ }
+
+ var status = assetProxyModel.data(treeView.selection.currentIndex, 0x105);
+ if (status === "--") {
+ return false;
+ }
+ var bakingEnabled = status !== "Not Baked";
+
+ for (var i in treeView.selection.selectedIndexes) {
+ var thisStatus = assetProxyModel.data(treeView.selection.selectedIndexes[i], 0x105);
+ if (thisStatus === "--") {
+ return false;
+ }
+ var thisBakingEnalbed = (thisStatus !== "Not Baked");
+
+ if (bakingEnabled !== thisBakingEnalbed) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+ function isChecked() {
+ if (!treeView.selection.hasSelection) {
+ return false;
+ }
+
+ var status = assetProxyModel.data(treeView.selection.currentIndex, 0x105);
+ return isEnabled() && status !== "Not Baked";
+ }
}
+
+ Item {
+ anchors.left: bakingCheckbox.right
+ anchors.leftMargin: hifi.dimensions.contentSpacing.x
+ anchors.verticalCenter: parent.verticalCenter
+ width: infoGlyph.size;
+ height: infoGlyph.size;
+
+ HiFiGlyphs {
+ id: infoGlyph;
+ anchors.fill: parent;
+ horizontalAlignment: Text.AlignHCenter;
+ verticalAlignment: Text.AlignVCenter;
+ text: hifi.glyphs.question;
+ size: 35;
+ color: hifi.colors.lightGrayText;
+ }
+ MouseArea {
+ anchors.fill: parent;
+ hoverEnabled: true;
+ onEntered: infoGlyph.color = hifi.colors.blueHighlight;
+ onExited: infoGlyph.color = hifi.colors.lightGrayText;
+ onClicked: letterbox(hifi.glyphs.question,
+ "What is baking?",
+ "Baking is a process we use to compress geometric meshes and textures.
" +
+ "We do this for efficient storage and transmission of models.
" +
+ "In some cases, we have been able to achieve 60% compression of original models.
" +
+ "We highly recommend you leave baking on to enable faster transmission decode of models" +
+ "in interface resulting in better experience for users visiting your domain.");
+ }
+ }
}
HifiControls.ContentSection {
@@ -790,7 +931,7 @@ ScrollingWindow {
id: image
width: 24
height: 24
- source: "../images/Loading-Outer-Ring.png"
+ source: "../../images/Loading-Outer-Ring.png"
RotationAnimation on rotation {
loops: Animation.Infinite
from: 0
@@ -801,7 +942,7 @@ ScrollingWindow {
Image {
width: 24
height: 24
- source: "../images/Loading-Inner-H.png"
+ source: "../../images/Loading-Inner-H.png"
}
HifiControls.Label {
id: uploadProgressLabel
diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp
index e1c3af1939..d538472450 100644
--- a/interface/src/Application.cpp
+++ b/interface/src/Application.cpp
@@ -6398,7 +6398,7 @@ void Application::showAssetServerWidget(QString filePath) {
if (!DependencyManager::get()->getThisNodeCanWriteAssets()) {
return;
}
- static const QUrl url { "AssetServer.qml" };
+ static const QUrl url { "hifi/AssetServer.qml" };
auto startUpload = [=](QQmlContext* context, QObject* newObject){
if (!filePath.isEmpty()) {
diff --git a/interface/src/scripting/AssetMappingsScriptingInterface.cpp b/interface/src/scripting/AssetMappingsScriptingInterface.cpp
index 5031016c3f..6c6f6dc244 100644
--- a/interface/src/scripting/AssetMappingsScriptingInterface.cpp
+++ b/interface/src/scripting/AssetMappingsScriptingInterface.cpp
@@ -239,6 +239,7 @@ void AssetMappingModel::refresh() {
connect(request, &GetAllMappingsRequest::finished, this, [this](GetAllMappingsRequest* request) mutable {
if (request->getError() == MappingRequest::NoError) {
+ int bakesPendingCount = 0;
auto mappings = request->getMappings();
auto existingPaths = _pathToItemMap.keys();
for (auto& mapping : mappings) {
@@ -287,6 +288,9 @@ void AssetMappingModel::refresh() {
auto statusString = isFolder ? "--" : bakingStatusToString(mapping.second.status);
lastItem->setData(statusString, Qt::UserRole + 5);
lastItem->setData(mapping.second.bakingErrors, Qt::UserRole + 6);
+ if (mapping.second.status == Pending) {
+ ++bakesPendingCount;
+ }
}
Q_ASSERT(fullPath == path);
@@ -334,6 +338,11 @@ void AssetMappingModel::refresh() {
item = nextItem;
}
}
+
+ if (bakesPendingCount != _bakesPendingCount) {
+ _bakesPendingCount = bakesPendingCount;
+ emit bakesPendingCountChanged(_bakesPendingCount);
+ }
} else {
emit errorGettingMappings(request->getErrorString());
}
diff --git a/interface/src/scripting/AssetMappingsScriptingInterface.h b/interface/src/scripting/AssetMappingsScriptingInterface.h
index 04ab488838..49d92ec070 100644
--- a/interface/src/scripting/AssetMappingsScriptingInterface.h
+++ b/interface/src/scripting/AssetMappingsScriptingInterface.h
@@ -26,6 +26,7 @@
class AssetMappingModel : public QStandardItemModel {
Q_OBJECT
Q_PROPERTY(bool autoRefreshEnabled READ isAutoRefreshEnabled WRITE setAutoRefreshEnabled)
+ Q_PROPERTY(int bakesPendingCount READ getBakesPendingCount NOTIFY bakesPendingCountChanged)
public:
AssetMappingModel();
@@ -38,10 +39,13 @@ public:
bool isKnownMapping(QString path) const { return _pathToItemMap.contains(path); }
bool isKnownFolder(QString path) const;
+ int getBakesPendingCount() const { return _bakesPendingCount; }
+
public slots:
void clear();
signals:
+ void bakesPendingCountChanged(int newCount);
void errorGettingMappings(QString errorString);
void updated();
@@ -50,6 +54,7 @@ private:
QHash _pathToItemMap;
QTimer _autoRefreshTimer;
+ int _bakesPendingCount{ 0 };
};
Q_DECLARE_METATYPE(AssetMappingModel*)