diff --git a/interface/resources/qml/AssetServer.qml b/interface/resources/qml/AssetServer.qml index 0c4b952331..23fec03ac2 100644 --- a/interface/resources/qml/AssetServer.qml +++ b/interface/resources/qml/AssetServer.qml @@ -72,11 +72,11 @@ ScrollingWindow { function doRenameFile(oldPath, newPath) { - if (newPath[0] != "/") { + if (newPath[0] !== "/") { newPath = "/" + newPath; } - if (oldPath[oldPath.length - 1] == '/' && newPath[newPath.length - 1] != '/') { + if (oldPath[oldPath.length - 1] === '/' && newPath[newPath.length - 1] != '/') { // this is a folder rename but the user neglected to add a trailing slash when providing a new path newPath = newPath + "/"; } @@ -302,7 +302,7 @@ ScrollingWindow { object.selected.connect(function(destinationPath) { destinationPath = destinationPath.trim(); - if (path == destinationPath) { + if (path === destinationPath) { return; } if (fileExists(destinationPath)) { @@ -363,7 +363,7 @@ ScrollingWindow { running: false } - property var uploadOpen: false; + property bool uploadOpen: false; Timer { id: timer } diff --git a/interface/resources/qml/hifi/dialogs/TabletAssetServer.qml b/interface/resources/qml/hifi/dialogs/TabletAssetServer.qml index a7b4ad7a53..cb2635a2ab 100644 --- a/interface/resources/qml/hifi/dialogs/TabletAssetServer.qml +++ b/interface/resources/qml/hifi/dialogs/TabletAssetServer.qml @@ -10,6 +10,7 @@ import QtQuick 2.5 import QtQuick.Controls 1.4 +import QtQuick.Controls.Styles 1.4 import QtQuick.Dialogs 1.2 as OriginalDialogs import Qt.labs.settings 1.0 @@ -105,12 +106,12 @@ Rectangle { function askForOverwrite(path, callback) { var object = tabletRoot.messageBox({ - icon: hifi.icons.question, - buttons: OriginalDialogs.StandardButton.Yes | OriginalDialogs.StandardButton.No, - defaultButton: OriginalDialogs.StandardButton.No, - title: "Overwrite File", - text: path + "\n" + "This file already exists. Do you want to overwrite it?" - }); + icon: hifi.icons.question, + buttons: OriginalDialogs.StandardButton.Yes | OriginalDialogs.StandardButton.No, + defaultButton: OriginalDialogs.StandardButton.No, + title: "Overwrite File", + text: path + "\n" + "This file already exists. Do you want to overwrite it?" + }); object.selected.connect(function(button) { if (button === OriginalDialogs.StandardButton.Yes) { callback(); @@ -149,9 +150,9 @@ Rectangle { function handleGetMappingsError(errorString) { errorMessageBox( - "There was a problem retreiving the list of assets from your Asset Server.\n" - + errorString - ); + "There was a problem retreiving the list of assets from your Asset Server.\n" + + errorString + ); } function addToWorld() { @@ -179,25 +180,25 @@ Rectangle { var SHAPE_TYPE_DEFAULT = SHAPE_TYPE_STATIC_MESH; var DYNAMIC_DEFAULT = false; var prompt = tabletRoot.customInputDialog({ - textInput: { - label: "Model URL", - text: defaultURL - }, - comboBox: { - label: "Automatic Collisions", - index: SHAPE_TYPE_DEFAULT, - items: SHAPE_TYPES - }, - checkBox: { - label: "Dynamic", - checked: DYNAMIC_DEFAULT, - disableForItems: [ - SHAPE_TYPE_STATIC_MESH - ], - checkStateOnDisable: false, - warningOnDisable: "Models with 'Exact' automatic collisions cannot be dynamic, and should not be used as floors" - } - }); + textInput: { + label: "Model URL", + text: defaultURL + }, + comboBox: { + label: "Automatic Collisions", + index: SHAPE_TYPE_DEFAULT, + items: SHAPE_TYPES + }, + checkBox: { + label: "Dynamic", + checked: DYNAMIC_DEFAULT, + disableForItems: [ + SHAPE_TYPE_STATIC_MESH + ], + checkStateOnDisable: false, + warningOnDisable: "Models with 'Exact' automatic collisions cannot be dynamic, and should not be used as floors" + } + }); prompt.selected.connect(function (jsonResult) { if (jsonResult) { @@ -205,23 +206,23 @@ Rectangle { var url = result.textInput.trim(); var shapeType; switch (result.comboBox) { - case SHAPE_TYPE_SIMPLE_HULL: - shapeType = "simple-hull"; - break; - case SHAPE_TYPE_SIMPLE_COMPOUND: - shapeType = "simple-compound"; - break; - case SHAPE_TYPE_STATIC_MESH: - shapeType = "static-mesh"; - break; - case SHAPE_TYPE_BOX: - shapeType = "box"; - break; - case SHAPE_TYPE_SPHERE: - shapeType = "sphere"; - break; - default: - shapeType = "none"; + case SHAPE_TYPE_SIMPLE_HULL: + shapeType = "simple-hull"; + break; + case SHAPE_TYPE_SIMPLE_COMPOUND: + shapeType = "simple-compound"; + break; + case SHAPE_TYPE_STATIC_MESH: + shapeType = "static-mesh"; + break; + case SHAPE_TYPE_BOX: + shapeType = "box"; + break; + case SHAPE_TYPE_SPHERE: + shapeType = "sphere"; + break; + default: + shapeType = "none"; } var dynamic = result.checkBox !== null ? result.checkBox : DYNAMIC_DEFAULT; @@ -230,7 +231,7 @@ Rectangle { print("Error: model cannot be both static mesh and dynamic. This should never happen."); } else if (url) { var name = assetProxyModel.data(treeView.selection.currentIndex); - var addPosition = Vec3.sum(MyAvatar.position, Vec3.multiply(2, Quat.getFront(MyAvatar.orientation))); + var addPosition = Vec3.sum(MyAvatar.position, Vec3.multiply(2, Quat.getForward(MyAvatar.orientation))); var gravity; if (dynamic) { // Create a vector <0, -10, 0>. { x: 0, y: -10, z: 0 } won't work because Qt is dumb and this is a @@ -293,10 +294,10 @@ Rectangle { } var object = tabletRoot.inputDialog({ - label: "Enter new path:", - current: path, - placeholderText: "Enter path here" - }); + label: "Enter new path:", + current: path, + placeholderText: "Enter path here" + }); object.selected.connect(function(destinationPath) { destinationPath = destinationPath.trim(); @@ -339,12 +340,12 @@ Rectangle { } var object = tabletRoot.messageBox({ - icon: hifi.icons.question, - buttons: OriginalDialogs.StandardButton.Yes + OriginalDialogs.StandardButton.No, - defaultButton: OriginalDialogs.StandardButton.Yes, - title: "Delete", - text: modalMessage - }); + icon: hifi.icons.question, + buttons: OriginalDialogs.StandardButton.Yes + OriginalDialogs.StandardButton.No, + defaultButton: OriginalDialogs.StandardButton.Yes, + title: "Delete", + text: modalMessage + }); object.selected.connect(function(button) { if (button === OriginalDialogs.StandardButton.Yes) { doDeleteFile(path); @@ -379,38 +380,38 @@ Rectangle { var filename = fileUrl.slice(fileUrl.lastIndexOf('/') + 1); Assets.uploadFile(fileUrl, directory + filename, - function() { - // Upload started - uploadSpinner.visible = true; - uploadButton.enabled = false; - uploadProgressLabel.text = "In progress..."; - }, - function(err, path) { - print(err, path); - if (err === "") { - uploadProgressLabel.text = "Upload Complete"; - timer.interval = 1000; - timer.repeat = false; - timer.triggered.connect(function() { - uploadSpinner.visible = false; - uploadButton.enabled = true; - uploadOpen = false; - }); - timer.start(); - console.log("Asset Browser - finished uploading: ", fileUrl); - reload(); - } else { - uploadSpinner.visible = false; - uploadButton.enabled = true; - uploadOpen = false; + function() { + // Upload started + uploadSpinner.visible = true; + uploadButton.enabled = false; + uploadProgressLabel.text = "In progress..."; + }, + function(err, path) { + print(err, path); + if (err === "") { + uploadProgressLabel.text = "Upload Complete"; + timer.interval = 1000; + timer.repeat = false; + timer.triggered.connect(function() { + uploadSpinner.visible = false; + uploadButton.enabled = true; + uploadOpen = false; + }); + timer.start(); + console.log("Asset Browser - finished uploading: ", fileUrl); + reload(); + } else { + uploadSpinner.visible = false; + uploadButton.enabled = true; + uploadOpen = false; - if (err !== -1) { - console.log("Asset Browser - error uploading: ", fileUrl, " - error ", err); - var box = errorMessageBox("There was an error uploading:\n" + fileUrl + "\n" + err); - box.selected.connect(reload); - } - } - }, dropping); + if (err !== -1) { + console.log("Asset Browser - error uploading: ", fileUrl, " - error ", err); + var box = errorMessageBox("There was an error uploading:\n" + fileUrl + "\n" + err); + box.selected.connect(reload); + } + } + }, dropping); } function initiateUpload(url) { @@ -421,9 +422,9 @@ Rectangle { doUpload(fileUrl, true); } else { var browser = tabletRoot.fileDialog({ - selectDirectory: false, - dir: currentDirectory - }); + selectDirectory: false, + dir: currentDirectory + }); browser.canceled.connect(function() { uploadOpen = false; @@ -445,11 +446,11 @@ Rectangle { function errorMessageBox(message) { return tabletRoot.messageBox({ - icon: hifi.icons.warning, - defaultButton: OriginalDialogs.StandardButton.Ok, - title: "Error", - text: message - }); + icon: hifi.icons.warning, + defaultButton: OriginalDialogs.StandardButton.Ok, + title: "Error", + text: message + }); } Column { @@ -469,15 +470,6 @@ Rectangle { height: 30 spacing: hifi.dimensions.contentSpacing.x - HifiControls.GlyphButton { - glyph: hifi.glyphs.reload - color: hifi.buttons.black - colorScheme: root.colorScheme - width: hifi.dimensions.controlLineHeight - - onClicked: root.reload() - } - HifiControls.Button { text: "Add To World" color: hifi.buttons.black @@ -510,8 +502,193 @@ Rectangle { onClicked: root.deleteFile() enabled: treeView.selection.hasSelection } + + HifiControls.GlyphButton { + + glyph: hifi.glyphs.reload + color: hifi.buttons.black + colorScheme: root.colorScheme + width: hifi.dimensions.controlLineHeight + + onClicked: root.reload() + } + } + } + + HifiControls.Tree { + id: treeView + anchors.top: assetDirectory.bottom + anchors.bottom: infoRow.top + anchors.margins: hifi.dimensions.contentMargin.x + 2 // Extra for border + anchors.left: parent.left + anchors.right: parent.right + + treeModel: assetProxyModel + selectionMode: SelectionMode.ExtendedSelection + headerVisible: true + sortIndicatorVisible: true + + colorScheme: root.colorScheme + + modifyEl: renameEl + + TableViewColumn { + id: nameColumn + title: "Name:" + role: "name" + width: treeView.width - bakedColumn.width; + } + TableViewColumn { + id: bakedColumn + title: "Use Baked?" + role: "baked" + width: 100 + } + + itemDelegate: Loader { + id: itemDelegateLoader + + anchors { + left: parent ? parent.left : undefined + leftMargin: (styleData.column === 0 ? (2 + styleData.depth) : 1) * hifi.dimensions.tablePadding + right: parent ? parent.right : undefined + rightMargin: hifi.dimensions.tablePadding + verticalCenter: parent ? parent.verticalCenter : undefined + } + + function convertToGlyph(text) { + switch (text) { + case "Not Baked": + return hifi.glyphs.circleSlash; + case "Baked": + return hifi.glyphs.check_2_01; + case "Error": + return hifi.glyphs.alert; + default: + return ""; + } + } + + function getComponent() { + if ((styleData.column === 0) && styleData.selected) { + return textFieldComponent; + } else if (convertToGlyph(styleData.value) != "") { + return glyphComponent; + } else { + return labelComponent; + } + + } + sourceComponent: getComponent() + + Component { + id: labelComponent + FiraSansSemiBold { + text: styleData.value + size: hifi.fontSizes.tableText + color: colorScheme == hifi.colorSchemes.light + ? (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 + } + } + Component { + id: glyphComponent + + HiFiGlyphs { + text: convertToGlyph(styleData.value) + size: hifi.dimensions.frameIconSize + color: colorScheme == hifi.colorSchemes.light + ? (styleData.selected ? hifi.colors.black : hifi.colors.baseGrayHighlight) + : (styleData.selected ? hifi.colors.black : hifi.colors.lightGrayText) + + elide: Text.ElideRight + horizontalAlignment: TextInput.AlignHCenter + + HifiControls.ToolTip { + anchors.fill: parent + + visible: styleData.value === "Error" + + toolTip: assetProxyModel.data(styleData.index, 0x106) + } + } + } + Component { + id: textFieldComponent + + TextField { + id: textField + readOnly: !activeFocus + + text: styleData.value + + FontLoader { id: firaSansSemiBold; source: "../../fonts/FiraSans-SemiBold.ttf"; } + font.family: firaSansSemiBold.name + font.pixelSize: hifi.fontSizes.textFieldInput + height: hifi.dimensions.tableRowHeight + + style: TextFieldStyle { + textColor: readOnly + ? hifi.colors.black + : (treeView.isLightColorScheme ? hifi.colors.black : hifi.colors.white) + background: Rectangle { + visible: !readOnly + color: treeView.isLightColorScheme ? hifi.colors.white : hifi.colors.black + border.color: hifi.colors.primaryHighlight + border.width: 1 + } + selectedTextColor: hifi.colors.black + selectionColor: hifi.colors.primaryHighlight + padding.left: readOnly ? 0 : hifi.dimensions.textPadding + padding.right: readOnly ? 0 : hifi.dimensions.textPadding + } + + validator: RegExpValidator { + regExp: /[^/]+/ + } + + Keys.onPressed: { + if (event.key == Qt.Key_Escape) { + text = styleData.value; + unfocusHelper.forceActiveFocus(); + event.accepted = true; + } + } + onAccepted: { + if (acceptableInput && styleData.selected) { + if (!treeView.modifyEl(treeView.selection.currentIndex, text)) { + text = styleData.value; + } + unfocusHelper.forceActiveFocus(); + } + } + + onReadOnlyChanged: { + // Have to explicily set keyboardRaised because automatic setting fails because readOnly is true at the time. + keyboardRaised = activeFocus; + } + } + } } + + MouseArea { + propagateComposedEvents: true + anchors.fill: parent + acceptedButtons: Qt.RightButton + onClicked: { + if (!HMD.active) { // Popup only displays properly on desktop + var index = treeView.indexAt(mouse.x, mouse.y); + treeView.selection.setCurrentIndex(index, 0x0002); + contextMenu.currentIndex = index; + contextMenu.popup(); + } + } + } + Menu { id: contextMenu title: "Edit" @@ -539,39 +716,51 @@ Rectangle { } } } - } - HifiControls.Tree { - id: treeView - height: 290 - anchors.leftMargin: hifi.dimensions.contentMargin.x + 2 // Extra for border - anchors.rightMargin: hifi.dimensions.contentMargin.x + 2 // Extra for border - anchors.left: parent.left - anchors.right: parent.right - treeModel: assetProxyModel - canEdit: true - colorScheme: root.colorScheme - selectionMode: SelectionMode.ExtendedSelection + Row { + 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 + + RalewayRegular { + size: hifi.fontSizes.sectionName + font.capitalization: Font.AllUppercase + text: selectedItems + " items selected" + color: hifi.colors.lightGrayText + } - modifyEl: renameEl + HifiControls.CheckBox { + function isChecked() { + var status = assetProxyModel.data(treeView.selection.currentIndex, 0x105); + var bakingDisabled = (status === "Not Baked" || status === "--"); + return selectedItems === 1 && !bakingDisabled; + } - MouseArea { - propagateComposedEvents: true - anchors.fill: parent - acceptedButtons: Qt.RightButton + text: "Use baked (optimized) versions" + colorScheme: root.colorScheme + enabled: selectedItems === 1 && assetProxyModel.data(treeView.selection.currentIndex, 0x105) !== "--" + checked: isChecked() onClicked: { - if (!HMD.active) { // Popup only displays properly on desktop - var index = treeView.indexAt(mouse.x, mouse.y); - treeView.selection.setCurrentIndex(index, 0x0002); - contextMenu.currentIndex = index; - contextMenu.popup(); + var mappings = []; + for (var i in treeView.selection.selectedIndexes) { + var index = treeView.selection.selectedIndexes[i]; + var path = assetProxyModel.data(index, 0x100); + mappings.push(path); } + print("Setting baking enabled:" + mappings + checked); + Assets.setBakingEnabled(mappings, checked, function() { + reload(); + }); + + checked = Qt.binding(isChecked); } } } - HifiControls.TabletContentSection { id: uploadSection name: "Upload A File"