From 7bf3f45e39705e3a1ca1e7404645ca5ba9bfd034 Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Fri, 21 Jul 2017 23:32:25 +0100 Subject: [PATCH] finished the locked default scripts --- .../qml/hifi/DesktopLetterboxMessage.qml | 161 ++++++++++++++++++ .../qml/hifi/dialogs/RunningScripts.qml | 83 ++++++++- .../qml/hifi/dialogs/TabletRunningScripts.qml | 80 ++++++++- interface/src/Menu.cpp | 6 +- 4 files changed, 313 insertions(+), 17 deletions(-) create mode 100644 interface/resources/qml/hifi/DesktopLetterboxMessage.qml diff --git a/interface/resources/qml/hifi/DesktopLetterboxMessage.qml b/interface/resources/qml/hifi/DesktopLetterboxMessage.qml new file mode 100644 index 0000000000..750cc38247 --- /dev/null +++ b/interface/resources/qml/hifi/DesktopLetterboxMessage.qml @@ -0,0 +1,161 @@ +// +// LetterboxMessage.qml +// qml/hifi +// +// Created by Dante Ruiz on 7/21/2017 +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +import QtQuick 2.5 +import QtQuick.Controls 1.4 +import "../styles-uit" + +Item { + property alias text: popupText.text + property alias headerGlyph: headerGlyph.text + property alias headerText: headerText.text + property real popupRadius: hifi.dimensions.borderRadius + property real headerTextPixelSize: 22 + property real popupTextPixelSize: 16 + property bool isDesktop: false + FontLoader { id: ralewayRegular; source: "../../fonts/Raleway-Regular.ttf"; } + FontLoader { id: ralewaySemiBold; source: "../../fonts/Raleway-SemiBold.ttf"; } + visible: false + id: letterbox + anchors.fill: parent + Rectangle { + anchors.fill: parent + color: "black" + opacity: 0.5 + radius: popupRadius + } + Rectangle { + id: textContainer; + width: parent.width * 0.8 + height: contentContainer.height + 50 + anchors.centerIn: parent + radius: popupRadius + color: "white" + Item { + id: contentContainer + width: parent.width - 50 + height: childrenRect.height + anchors.centerIn: parent + Item { + id: popupHeaderContainer + visible: headerText.text !== "" || headerGlyph.text !== "" + height: 30 + // Anchors + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + // Header Glyph + HiFiGlyphs { + id: headerGlyph + visible: headerGlyph.text !== "" + // Size + height: parent.height + // Anchors + anchors.left: parent.left + anchors.leftMargin: -15 + // Text Size + size: headerTextPixelSize*2.5 + // Style + horizontalAlignment: Text.AlignHLeft + verticalAlignment: Text.AlignVCenter + color: hifi.colors.darkGray + } + // Header Text + Text { + id: headerText + visible: headerText.text !== "" + // Size + + height: parent.height + // Anchors + anchors.left: headerGlyph.right + anchors.leftMargin: -5 + // Text Size + font.pixelSize: headerTextPixelSize + // Style + font.family: ralewaySemiBold.name + color: hifi.colors.darkGray + horizontalAlignment: Text.AlignHLeft + verticalAlignment: Text.AlignVCenter + wrapMode: Text.WordWrap + textFormat: Text.StyledText + } + } + // Popup Text + Text { + id: popupText + // Size + width: parent.width + // Anchors + anchors.top: popupHeaderContainer.visible ? popupHeaderContainer.bottom : parent.top + anchors.topMargin: popupHeaderContainer.visible ? 15 : 0 + anchors.left: parent.left + anchors.right: parent.right + // Text alignment + verticalAlignment: Text.AlignVCenter + horizontalAlignment: Text.AlignHLeft + // Style + font.pixelSize: popupTextPixelSize + font.family: ralewayRegular.name + color: hifi.colors.darkGray + wrapMode: Text.WordWrap + textFormat: Text.StyledText + onLinkActivated: { + Qt.openUrlExternally(link) + } + } + } + } + // Left gray MouseArea + MouseArea { + anchors.left: parent.left; + anchors.right: textContainer.left; + anchors.top: textContainer.top; + anchors.bottom: textContainer.bottom; + acceptedButtons: Qt.LeftButton + onClicked: { + letterbox.visible = false + } + } + // Right gray MouseArea + MouseArea { + anchors.left: textContainer.left; + anchors.right: parent.left; + anchors.top: textContainer.top; + anchors.bottom: textContainer.bottom; + acceptedButtons: Qt.LeftButton + onClicked: { + letterbox.visible = false + } + } + // Top gray MouseArea + MouseArea { + anchors.left: parent.left; + anchors.right: parent.right; + anchors.top: parent.top; + anchors.bottom: textContainer.top; + acceptedButtons: Qt.LeftButton + onClicked: { + letterbox.visible = false + } + } + // Bottom gray MouseArea + MouseArea { + anchors.left: parent.left; + anchors.right: parent.right; + anchors.top: textContainer.bottom; + anchors.bottom: parent.bottom; + acceptedButtons: Qt.LeftButton + onClicked: { + letterbox.visible = false + } + } +} diff --git a/interface/resources/qml/hifi/dialogs/RunningScripts.qml b/interface/resources/qml/hifi/dialogs/RunningScripts.qml index da9ffdb07e..f3d81dafbb 100644 --- a/interface/resources/qml/hifi/dialogs/RunningScripts.qml +++ b/interface/resources/qml/hifi/dialogs/RunningScripts.qml @@ -16,6 +16,7 @@ import Qt.labs.settings 1.0 import "../../styles-uit" import "../../controls-uit" as HifiControls import "../../windows" +import "../" ScrollingWindow { id: root @@ -28,10 +29,11 @@ ScrollingWindow { minSize: Qt.vector2d(424, 300) HifiConstants { id: hifi } - + property var scripts: ScriptDiscoveryService; property var scriptsModel: scripts.scriptsModelFilter property var runningScriptsModel: ListModel { } + property bool developerMenuEnabled: false property bool isHMD: false Settings { @@ -39,6 +41,25 @@ ScrollingWindow { property alias x: root.x property alias y: root.y } + + Component { + id: letterBoxMessage + Window { + implicitWidth: 424 + implicitHeight: 400 + minSize: Qt.vector2d(424, 300) + DesktopLetterboxMessage { + visible: true + headerGlyph: hifi.glyphs.lock + headerText: "Need Developer Mode On" + text: ( "In order to edit, delete or reload this script," + + " turn on Developer Mode by going to:" + + " Menu > Settings > Developer Menus") + popupRadius: 0 + } + } + } + Timer { id: refreshTimer @@ -47,6 +68,15 @@ ScrollingWindow { running: false onTriggered: updateRunningScripts(); } + + + Timer { + id: checkMenu + interval: 1000 + repeat: true + running: false + onTriggered: developerMenuEnabled = MenuInterface.isMenuEnabled("Developer Menus"); + } Component { id: listModelBuilder @@ -64,6 +94,8 @@ ScrollingWindow { Component.onCompleted: { isHMD = HMD.active; updateRunningScripts(); + developerMenuEnabled = MenuInterface.isMenuEnabled("Developer Menus"); + checkMenu.restart(); } function updateRunningScripts() { @@ -110,7 +142,17 @@ ScrollingWindow { function reloadAll() { console.log("Reload all scripts"); - scripts.reloadAllScripts(); + if (!developerMenuEnabled) { + for (var index = 0; index < runningScriptsModel.count; index++) { + var url = runningScriptsModel.get(index).url; + var fileName = url.substring(url.lastIndexOf('/')+1); + if (canEditScript(fileName)) { + scripts.stopScript(url, true); + } + } + } else { + scripts.reloadAllScripts(); + } } function loadDefaults() { @@ -120,7 +162,22 @@ ScrollingWindow { function stopAll() { console.log("Stop all scripts"); - scripts.stopAllScripts(); + for (var index = 0; index < runningScriptsModel.count; index++) { + var url = runningScriptsModel.get(index).url; + var fileName = url.substring(url.lastIndexOf('/')+1); + if (canEditScript(fileName)) { + scripts.stopScript(url); + } + } + } + + + function canEditScript(script) { + if ((script === "controllerScripts.js") || (script === "defaultScripts.js")) { + return developerMenuEnabled; + } + + return true; } Column { @@ -162,6 +219,7 @@ ScrollingWindow { expandSelectedRow: true itemDelegate: Item { + property bool canEdit: canEditScript(styleData.value); anchors { left: parent ? parent.left : undefined leftMargin: hifi.dimensions.tablePadding @@ -185,8 +243,9 @@ ScrollingWindow { HiFiGlyphs { id: reloadButton - text: hifi.glyphs.reloadSmall + text: ((canEditScript(styleData.value)) ? hifi.glyphs.reload : hifi.glyphs.lock) color: reloadButtonArea.pressed ? hifi.colors.white : parent.color + size: 21 anchors { top: parent.top right: stopButton.left @@ -195,7 +254,13 @@ ScrollingWindow { MouseArea { id: reloadButtonArea anchors { fill: parent; margins: -2 } - onClicked: reloadScript(model.url) + onClicked: { + if (canEdit) { + reloadScript(model.url) + } else { + letterBoxMessage.createObject(desktop) + } + } } } @@ -203,6 +268,7 @@ ScrollingWindow { id: stopButton text: hifi.glyphs.closeSmall color: stopButtonArea.pressed ? hifi.colors.white : parent.color + visible: canEditScript(styleData.value) anchors { top: parent.top right: parent.right @@ -211,7 +277,11 @@ ScrollingWindow { MouseArea { id: stopButtonArea anchors { fill: parent; margins: -2 } - onClicked: stopScript(model.url) + onClicked: { + if (canEdit) { + stopScript(model.url); + } + } } } @@ -269,6 +339,7 @@ ScrollingWindow { text: "Load Defaults" color: hifi.buttons.black height: 26 + visible: root.developerMenuEnabled; onClicked: loadDefaults() } } diff --git a/interface/resources/qml/hifi/dialogs/TabletRunningScripts.qml b/interface/resources/qml/hifi/dialogs/TabletRunningScripts.qml index 7803e95bac..73fdd17627 100644 --- a/interface/resources/qml/hifi/dialogs/TabletRunningScripts.qml +++ b/interface/resources/qml/hifi/dialogs/TabletRunningScripts.qml @@ -47,23 +47,67 @@ Rectangle { letterBoxMessage.popupRadius = 0; } + Timer { + id: refreshTimer + interval: 100 + repeat: false + running: false + onTriggered: updateRunningScripts(); + } + + Timer { + id: checkMenu + interval: 1000 + repeat: true + running: false + onTriggered: developerMenuEnabled = MenuInterface.isMenuEnabled("Developer Menus"); + } + + Component { + id: listModelBuilder + ListModel {} + } + Connections { target: ScriptDiscoveryService - onScriptCountChanged: updateRunningScripts(); + onScriptCountChanged: { + runningScriptsModel = listModelBuilder.createObject(root); + refreshTimer.restart(); + } } Component.onCompleted: { isHMD = HMD.active; updateRunningScripts(); developerMenuEnabled = MenuInterface.isMenuEnabled("Developer Menus"); + checkMenu.restart(); } function updateRunningScripts() { - var runningScripts = ScriptDiscoveryService.getRunning(); - runningScriptsModel.clear() - for (var i = 0; i < runningScripts.length; ++i) { - runningScriptsModel.append(runningScripts[i]); + function simplify(path) { + // trim URI querystring/fragment + path = (path+'').replace(/[#?].*$/,''); + // normalize separators and grab last path segment (ie: just the filename) + path = path.replace(/\\/g, '/').split('/').pop(); + // return lowercased because we want to sort mnemonically + return path.toLowerCase(); } + var runningScripts = ScriptDiscoveryService.getRunning(); + runningScripts.sort(function(a,b) { + a = simplify(a.path); + b = simplify(b.path); + return a < b ? -1 : a > b ? 1 : 0; + }); + // Calling `runningScriptsModel.clear()` here instead of creating a new object + // triggers some kind of weird heap corruption deep inside Qt. So instead of + // modifying the model in place, possibly triggering behaviors in the table + // instead we create a new `ListModel`, populate it and update the + // existing model atomically. + var newRunningScriptsModel = listModelBuilder.createObject(root); + for (var i = 0; i < runningScripts.length; ++i) { + newRunningScriptsModel.append(runningScripts[i]); + } + runningScriptsModel = newRunningScriptsModel; } function loadScript(script) { @@ -72,6 +116,7 @@ Rectangle { } function reloadScript(script) { + console.log(script); console.log("Reload script " + script); scripts.stopScript(script, true); } @@ -83,7 +128,17 @@ Rectangle { function reloadAll() { console.log("Reload all scripts"); - scripts.reloadAllScripts(); + if (!developerMenuEnabled) { + for (var index = 0; index < runningScriptsModel.count; index++) { + var url = runningScriptsModel.get(index).url; + var fileName = url.substring(url.lastIndexOf('/')+1); + if (canEditScript(fileName)) { + scripts.stopScript(url, true); + } + } + } else { + scripts.reloadAllScripts(); + } } function loadDefaults() { @@ -93,7 +148,14 @@ Rectangle { function stopAll() { console.log("Stop all scripts"); - scripts.stopAllScripts(); + for (var index = 0; index < runningScriptsModel.count; index++) { + var url = runningScriptsModel.get(index).url; + console.log(url); + var fileName = url.substring(url.lastIndexOf('/')+1); + if (canEditScript(fileName)) { + scripts.stopScript(url); + } + } } function canEditScript(script) { @@ -175,8 +237,9 @@ Rectangle { HiFiGlyphs { id: reloadButton - text: ((canEditScript(styleData.value)) ? hifi.glyphs.reloadSmall : hifi.glyphs.lock) + text: ((canEditScript(styleData.value)) ? hifi.glyphs.reload : hifi.glyphs.lock) color: reloadButtonArea.pressed ? hifi.colors.white : parent.color + size: 21 anchors { top: parent.top right: stopButton.left @@ -297,6 +360,7 @@ Rectangle { text: "Load Defaults" color: hifi.buttons.black height: 26 + visible: root.developerMenuEnabled; onClicked: loadDefaults() } } diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 71a681fcc9..c7223be208 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -98,10 +98,10 @@ Menu::Menu() { // Edit > Running Scripts auto action = addActionToQMenuAndActionHash(editMenu, MenuOption::RunningScripts, Qt::CTRL | Qt::Key_J); connect(action, &QAction::triggered, [] { + static const QUrl widgetUrl("hifi/dialogs/RunningScripts.qml"); static const QUrl tabletUrl("../../hifi/dialogs/TabletRunningScripts.qml"); - auto tabletScriptingInterface = DependencyManager::get(); - TabletProxy* tablet = tabletScriptingInterface->getTablet("com.highfidelity.interface.tablet.system"); - tablet->loadQMLSource(tabletUrl); + static const QString name("RunningScripts"); + qApp->showDialog(widgetUrl, tabletUrl, name); }); // Edit > Open and Run Script from File... [advanced]