mirror of
https://github.com/JulianGro/overte.git
synced 2025-04-08 01:42:22 +02:00
note: the idea is to make imports like 'import controlsUit 1.0' to work with 'styles-uit'/'controls-uit' it is not possible because of two reasons: 1. import controls-uit 1.0 is invalid syntax 2. qmldir inside controls-uit is 'module controlsUit'
689 lines
22 KiB
QML
689 lines
22 KiB
QML
//
|
|
// ScriptAPI.qml
|
|
//
|
|
// Created by Luis Cuenca on 12/18/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 stylesUit 1.0
|
|
import controlsUit 1.0 as HifiControls
|
|
|
|
Item {
|
|
id: root
|
|
width: parent.width
|
|
height: parent.height
|
|
|
|
property var hideQtMethods: true
|
|
property var maxUpdateValues: 20
|
|
property var maxReloadValues: 200
|
|
property var apiMembers: []
|
|
property var membersWithValues: []
|
|
property var isReloading: false
|
|
property var evaluatingIdx: -1
|
|
property Component scrollSlider
|
|
property Component keyboard
|
|
|
|
Rectangle {
|
|
color: hifi.colors.baseGray
|
|
width: parent.width
|
|
height: parent.height
|
|
}
|
|
|
|
Timer {
|
|
id: updateList
|
|
interval: 200
|
|
repeat: false
|
|
running: false
|
|
onTriggered: {
|
|
scrollSlider.y = 0;
|
|
list.contentY = 0;
|
|
}
|
|
}
|
|
|
|
Row {
|
|
id: topBar
|
|
anchors.left: parent.left
|
|
anchors.leftMargin: 30
|
|
anchors.top: parent.top
|
|
anchors.topMargin: 30
|
|
width: parent.width
|
|
height: 40
|
|
|
|
HifiControls.GlyphButton {
|
|
id: back;
|
|
enabled: true;
|
|
color: hifi.buttons.black
|
|
glyph: hifi.glyphs.backward
|
|
size: 40
|
|
width: 40
|
|
height: 40
|
|
anchors.left: search.right
|
|
anchors.leftMargin: 12
|
|
onClicked: {
|
|
var text = searchBar.text;
|
|
var chain = text.split(".");
|
|
if (chain.length > 2) {
|
|
var result = chain[0]+".";
|
|
for (var i = 1; i < chain.length-2; i++) {
|
|
result += chain[i] + ".";
|
|
}
|
|
result += chain[chain.length-2];
|
|
searchBar.text = result;
|
|
} else {
|
|
searchBar.text = (chain.length > 1) ? chain[0] : "";
|
|
}
|
|
if (chain.length > 1) {
|
|
addListElements(searchBar.text);
|
|
} else {
|
|
addListElements();
|
|
}
|
|
focus = true;
|
|
}
|
|
}
|
|
|
|
HifiControls.TextField {
|
|
id: searchBar
|
|
focus: true
|
|
isSearchField: true
|
|
width: parent.width - 112
|
|
height: 40
|
|
colorScheme: hifi.colorSchemes.dark
|
|
anchors.left: back.right
|
|
anchors.leftMargin: 10
|
|
font.family: firaSansSemiBold.name
|
|
placeholderText: "Search"
|
|
onAccepted: {
|
|
console.log("Enter Pressed");
|
|
addListElements(searchBar.text);
|
|
}
|
|
onActiveFocusChanged: {
|
|
if (activeFocus && HMD.mounted) {
|
|
keyboard.raised = true;
|
|
} else {
|
|
keyboard.raised = false;
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
Row {
|
|
id: topBar2
|
|
anchors.left: parent.left
|
|
anchors.leftMargin: 30
|
|
anchors.top: topBar.bottom
|
|
anchors.topMargin: 30
|
|
width: parent.width -60
|
|
height: 40
|
|
|
|
HifiControls.GlyphButton {
|
|
id: addMember;
|
|
enabled: true;
|
|
color: hifi.buttons.black
|
|
glyph: hifi.glyphs.maximize
|
|
width: 40
|
|
height: 40
|
|
anchors.top: parent.top
|
|
anchors.left: parent.left
|
|
onClicked: {
|
|
addNewMember();
|
|
updateList.start();
|
|
focus = true;
|
|
}
|
|
}
|
|
|
|
HifiControls.Button {
|
|
id: evaluate;
|
|
enabled: true;
|
|
color: hifi.buttons.black
|
|
text: "Eval"
|
|
width: 40
|
|
height: 40
|
|
anchors.left: addMember.right
|
|
anchors.leftMargin: 12
|
|
onClicked: {
|
|
evaluateMember();
|
|
focus = true;
|
|
}
|
|
}
|
|
|
|
HifiControls.TextField {
|
|
id: valueBar
|
|
isSearchField: false
|
|
font.pixelSize: 16
|
|
width: parent.width - 208
|
|
height: 40
|
|
colorScheme: hifi.colorSchemes.dark
|
|
font.family: firaSansSemiBold.name
|
|
placeholderText: "Value"
|
|
anchors.left: evaluate.right
|
|
anchors.leftMargin: 12
|
|
onActiveFocusChanged: {
|
|
if (activeFocus && HMD.mounted) {
|
|
keyboard.raised = true;
|
|
} else {
|
|
keyboard.raised = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
HifiControls.GlyphButton {
|
|
id: reload;
|
|
enabled: false;
|
|
color: hifi.buttons.black
|
|
glyph: hifi.glyphs.reload
|
|
size: 40
|
|
width: 40
|
|
height: 40
|
|
anchors.right: update.left
|
|
anchors.rightMargin: 12
|
|
onClicked: {
|
|
reloadListValues();
|
|
focus = true;
|
|
}
|
|
}
|
|
|
|
HifiControls.GlyphButton {
|
|
id: update;
|
|
enabled: false;
|
|
color: hifi.buttons.black
|
|
glyph: hifi.glyphs.playback_play
|
|
size: 40
|
|
width: 40
|
|
height: 40
|
|
anchors.right: parent.right
|
|
onClicked: {
|
|
if (isReloading) {
|
|
update.glyph = hifi.glyphs.playback_play
|
|
isReloading = false;
|
|
stopReload();
|
|
} else {
|
|
update.glyph = hifi.glyphs.stop_square
|
|
isReloading = true;
|
|
startReload();
|
|
}
|
|
focus = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
Rectangle {
|
|
id: membersBackground
|
|
anchors {
|
|
left: parent.left; right: parent.right; top: topBar2.bottom; bottom: bottomBar.top;
|
|
margins: 30
|
|
}
|
|
color: hifi.colors.tableBackgroundDark
|
|
border.color: hifi.colors.lightGray
|
|
border.width: 2
|
|
radius: 5
|
|
|
|
ListModel {
|
|
id: memberModel
|
|
}
|
|
|
|
Component {
|
|
id: memberDelegate
|
|
Item {
|
|
id: item
|
|
width: parent.width
|
|
anchors.left: parent.left
|
|
height: 26
|
|
clip: true
|
|
|
|
Rectangle {
|
|
width: parent.width
|
|
height: parent.height
|
|
color: index % 2 == 0 ? hifi.colors.tableRowDarkEven : hifi.colors.tableRowDarkOdd
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
|
|
Row {
|
|
id: memberRow
|
|
anchors.bottom: parent.bottom
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
spacing: 10
|
|
|
|
FiraSansSemiBold {
|
|
property var isMainKey: apiType === "class";
|
|
text: apiMember
|
|
size: isMainKey ? 17 : 15
|
|
font.bold: true
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
color: isMainKey ? hifi.colors.faintGray : hifi.colors.lightGrayText
|
|
MouseArea {
|
|
width: list.width
|
|
height: parent.height
|
|
onClicked: {
|
|
searchBar.text = apiType=="function()" ? apiMember + "()" : apiMember;
|
|
valueBar.text = !apiValue ? "" : apiValue;
|
|
list.currentIndex = index;
|
|
evaluatingIdx = index;
|
|
}
|
|
onDoubleClicked: {
|
|
if (apiType === "class") {
|
|
addListElements(apiMember+".");
|
|
} else {
|
|
isolateElement(evaluatingIdx);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
FiraSansRegular {
|
|
text: apiType
|
|
anchors.left: apiMember.right
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
size: 13
|
|
color: hifi.colors.lightGrayText
|
|
}
|
|
|
|
FiraSansRegular {
|
|
text: !apiValue ? "" : apiValue;
|
|
anchors.left: apiType.right
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
size: 14
|
|
color: hifi.colors.primaryHighlight
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Component {
|
|
id: highlight
|
|
Rectangle {
|
|
anchors {
|
|
left: list.left
|
|
right: scrollBar.left
|
|
leftMargin: 2
|
|
rightMargin: 2
|
|
}
|
|
color: hifi.colors.primaryHighlight
|
|
radius: 4
|
|
z: 10
|
|
opacity: 0.5
|
|
}
|
|
}
|
|
|
|
ListView {
|
|
id: list
|
|
anchors {
|
|
top: parent.top
|
|
left: parent.left
|
|
right: scrollBar.left
|
|
bottom: parent.bottom
|
|
topMargin: 2
|
|
leftMargin: 2
|
|
bottomMargin: 2
|
|
}
|
|
clip: true
|
|
cacheBuffer: 4000
|
|
model: memberModel
|
|
delegate: memberDelegate
|
|
highlightMoveDuration: 0
|
|
highlight: highlight
|
|
onMovementStarted: {
|
|
scrollSlider.manual = true;
|
|
}
|
|
onMovementEnded: {
|
|
if (list.contentHeight > list.height) {
|
|
var range = list.contentY/(list.contentHeight-list.height);
|
|
range = range > 1 ? 1 : range;
|
|
var idx = Math.round((list.count-1)*range);
|
|
scrollSlider.positionSlider(idx);
|
|
}
|
|
scrollSlider.manual = false;
|
|
returnToBounds()
|
|
}
|
|
}
|
|
|
|
Rectangle {
|
|
id: scrollBar
|
|
|
|
property bool scrolling: list.contentHeight > list.height
|
|
|
|
anchors {
|
|
top: parent.top
|
|
right: parent.right
|
|
bottom: parent.bottom
|
|
margins: 2
|
|
}
|
|
width: 22
|
|
height: parent.height - 4
|
|
color: hifi.colors.tableScrollBackgroundDark
|
|
|
|
MouseArea {
|
|
anchors.fill: parent
|
|
|
|
onClicked: {
|
|
var index = scrollSlider.y * (list.count - 1) / (scrollBar.height - scrollSlider.height);
|
|
index = Math.round(index);
|
|
var scrollAmount = Math.round(list.count/10);
|
|
index = index + (mouse.y <= scrollSlider.y ? -scrollAmount : scrollAmount);
|
|
if (index < 0) {
|
|
index = 0;
|
|
}
|
|
if (index > list.count - 1) {
|
|
index = list.count - 1;
|
|
}
|
|
scrollSlider.positionSlider(index);
|
|
}
|
|
}
|
|
|
|
Rectangle {
|
|
id: scrollSlider
|
|
|
|
property var manual: false
|
|
|
|
function positionSlider(index){
|
|
y = index*(scrollBar.height - scrollSlider.height)/(list.count - 1);
|
|
}
|
|
|
|
anchors.right: parent.right
|
|
anchors.margins: 2
|
|
width: 18
|
|
height: ((list.height / list.contentHeight) * list.height) < 15 ? 15 : (list.height / list.contentHeight) * list.height
|
|
radius: 5
|
|
color: hifi.colors.tableScrollHandleDark
|
|
|
|
visible: scrollBar.scrolling;
|
|
|
|
onYChanged: {
|
|
var index = y * (list.count - 1) / (scrollBar.height - scrollSlider.height);
|
|
index = Math.round(index);
|
|
if (!manual) {
|
|
list.positionViewAtIndex(index, ListView.Visible);
|
|
}
|
|
}
|
|
|
|
MouseArea {
|
|
anchors.fill: parent
|
|
drag.target: scrollSlider
|
|
drag.axis: Drag.YAxis
|
|
drag.minimumY: 0
|
|
drag.maximumY: scrollBar.height - scrollSlider.height
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Row {
|
|
id: bottomBar
|
|
anchors.left: parent.left
|
|
anchors.leftMargin: 30
|
|
anchors.bottom: parent.bottom
|
|
anchors.bottomMargin: 30
|
|
width: parent.width
|
|
height: 40
|
|
|
|
HifiControls.GlyphButton {
|
|
id: clipboard;
|
|
enabled: true;
|
|
color: hifi.buttons.black
|
|
glyph: hifi.glyphs.scriptNew
|
|
size: 25
|
|
width: 40
|
|
height: 40
|
|
anchors.left: parent.left
|
|
onClicked: {
|
|
var buffer = "";
|
|
for (var i = 0; i < memberModel.count; i++) {
|
|
var datarow = memberModel.get(i);
|
|
buffer += "\n" + datarow.apiMember + " " + datarow.apiType + " " + datarow.apiValue;
|
|
}
|
|
Window.copyToClipboard(buffer);
|
|
focus = true;
|
|
}
|
|
}
|
|
|
|
HifiControls.CheckBox {
|
|
id: hideQt
|
|
colorScheme: hifi.checkbox.dark
|
|
boxSize: 25
|
|
boxRadius: 3
|
|
checked: true
|
|
anchors.left: clipboard.right
|
|
anchors.leftMargin: 10
|
|
anchors.verticalCenter: clipboard.verticalCenter
|
|
onClicked: {
|
|
hideQtMethods = checked;
|
|
addListElements();
|
|
}
|
|
}
|
|
|
|
HifiControls.Label {
|
|
id: hideLabel
|
|
anchors.left: hideQt.right
|
|
anchors.verticalCenter: clipboard.verticalCenter
|
|
anchors.margins: 2
|
|
font.pixelSize: 15
|
|
text: "Hide Qt Methods"
|
|
}
|
|
|
|
HifiControls.Button {
|
|
id: debug;
|
|
enabled: true;
|
|
color: hifi.buttons.black
|
|
text: "Debug Script"
|
|
width: 120
|
|
height: 40
|
|
anchors.right: parent.right
|
|
anchors.rightMargin: 60
|
|
anchors.bottom: parent.bottom
|
|
|
|
onClicked: {
|
|
sendToScript({type: "selectScript"});
|
|
}
|
|
}
|
|
}
|
|
|
|
HifiControls.Keyboard {
|
|
id: keyboard;
|
|
raised: false;
|
|
anchors {
|
|
bottom: parent.bottom;
|
|
left: parent.left;
|
|
right: parent.right;
|
|
}
|
|
|
|
Keys.onPressed: {
|
|
console.log(event.nativeScanCode);
|
|
if (event.key == Qt.Key_Left) {
|
|
keyboard.raised = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
function addNewMember() {
|
|
apiMembers.push({member: searchBar.text, type: "user", value: valueBar.text, hasValue: true});
|
|
var data = {'memberIndex': apiMembers.length-1, 'apiMember': searchBar.text, 'apiType':"user", 'apiValue': valueBar.text};
|
|
memberModel.insert(0, data);
|
|
computeMembersWithValues();
|
|
}
|
|
|
|
function evaluateMember() {
|
|
sendToScript({type: "evaluateMember", data:{member: searchBar.text, index: evaluatingIdx}});
|
|
}
|
|
|
|
function getValuesToRefresh() {
|
|
var valuesToRefresh = [];
|
|
for (var i = 0; i < membersWithValues.length; i++) {
|
|
var index = membersWithValues[i];
|
|
var row = memberModel.get(index);
|
|
valuesToRefresh.push({index: index, member: (row.apiType == "function()") ? row.apiMember+"()" : row.apiMember, value: row.apiValue});
|
|
}
|
|
return valuesToRefresh;
|
|
}
|
|
|
|
|
|
function reloadListValues(){
|
|
var valuesToRefresh = getValuesToRefresh();
|
|
sendToScript({type: "refreshValues", data:valuesToRefresh});
|
|
}
|
|
|
|
function startReload(){
|
|
var valuesToRefresh = getValuesToRefresh();
|
|
sendToScript({type: "startRefreshValues", data:valuesToRefresh});
|
|
}
|
|
|
|
function stopReload(){
|
|
sendToScript({type: "stopRefreshValues"});
|
|
}
|
|
|
|
function refreshValues(data) {
|
|
var buffer = "";
|
|
for (var i = 0; i < data.length; i++) {
|
|
var row = memberModel.get(data[i].index);
|
|
row.apiValue = data[i].value;
|
|
apiMembers[row.memberIndex].value = data[i].value;
|
|
memberModel.set(data[i].index, row);
|
|
buffer += "\n" + apiMembers[row.memberIndex].member + " : " + data[i].value;
|
|
}
|
|
print(buffer);
|
|
}
|
|
|
|
|
|
function fromScript(message) {
|
|
if (message.type === "methods") {
|
|
apiMembers = message.data;
|
|
if (ScriptDiscoveryService.debugScriptUrl != "") {
|
|
addListElements("GlobalDebugger");
|
|
if (memberModel.count == 0) {
|
|
addListElements();
|
|
}
|
|
} else {
|
|
addListElements();
|
|
}
|
|
|
|
} else if (message.type === "debugMethods") {
|
|
addListElements("GlobalDebugger");
|
|
} else if (message.type === "refreshValues") {
|
|
refreshValues(message.data);
|
|
} else if (message.type === "evaluateMember") {
|
|
valueBar.text = message.data.value;
|
|
var selrow = memberModel.get(message.data.index);
|
|
if (selrow.apiMember === searchBar.text || selrow.apiMember === searchBar.text + "()") {
|
|
selrow.apiValue = message.data.value;
|
|
apiMembers[selrow.memberIndex].value = message.data.value;
|
|
apiMembers[selrow.memberIndex].hasValue = true;
|
|
memberModel.set(message.data.index, selrow);
|
|
}
|
|
} else if (message.type === "selectScript") {
|
|
if (message.data.length > 0) {
|
|
ScriptDiscoveryService.debugScriptUrl = message.data;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
function getFilterPairs(filter){
|
|
var filteredArray = [];
|
|
var filterChain;
|
|
filterChain = filter.split(" ");
|
|
for (var i = 0; i < filterChain.length; i++) {
|
|
filterChain[i] = filterChain[i].toUpperCase();
|
|
}
|
|
var matchPairs = [];
|
|
|
|
for (var i = 0; i < apiMembers.length; i++) {
|
|
if (filterChain != undefined) {
|
|
var found = 0;
|
|
var memberComp = apiMembers[i].member.toUpperCase();
|
|
for (var j = 0; j < filterChain.length; j++) {
|
|
found += memberComp.indexOf(filterChain[j]) >= 0 ? 1 : 0;
|
|
}
|
|
if (found === 0) {
|
|
continue;
|
|
}
|
|
matchPairs.push({index: i, found: found, member: apiMembers[i].member});
|
|
}
|
|
}
|
|
|
|
matchPairs.sort(function(a, b){
|
|
if(a.found > b.found) return -1;
|
|
if(a.found < b.found) return 1;
|
|
if(a.member > b.member) return 1;
|
|
if(a.member < b.member) return -1;
|
|
return 0;
|
|
});
|
|
|
|
return matchPairs;
|
|
}
|
|
|
|
function isolateElement(index) {
|
|
var oldElement = memberModel.get(index);
|
|
var newElement = {memberIndex: oldElement.memberIndex, apiMember: oldElement.apiMember, apiType: oldElement.apiType, apiValue: oldElement.apiValue};
|
|
membersWithValues = apiMembers[oldElement.memberIndex].hasValue ? [0] : [];
|
|
memberModel.remove(0, memberModel.count);
|
|
memberModel.append(newElement);
|
|
}
|
|
|
|
function computeMembersWithValues() {
|
|
membersWithValues = [];
|
|
for (var i = 0; i < memberModel.count; i++) {
|
|
var idx = memberModel.get(i).memberIndex;
|
|
if (apiMembers[idx].hasValue) {
|
|
membersWithValues.push(i);
|
|
}
|
|
}
|
|
update.enabled = membersWithValues.length <= maxUpdateValues;
|
|
reload.enabled = membersWithValues.length <= maxReloadValues;
|
|
}
|
|
|
|
function addListElements(filter) {
|
|
valueBar.text = "";
|
|
memberModel.remove(0, memberModel.count);
|
|
|
|
var filteredArray = (filter != undefined) ? [] : apiMembers;
|
|
var matchPairs;
|
|
if (filter != undefined) {
|
|
matchPairs = getFilterPairs(filter);
|
|
for (var i = 0; i < matchPairs.length; i++) {
|
|
if (matchPairs[i].found < matchPairs[0].found) {
|
|
break;
|
|
}
|
|
var idx = matchPairs[i].index;
|
|
filteredArray.push(apiMembers[idx]);
|
|
}
|
|
}
|
|
|
|
for (var i = 0; i < filteredArray.length; i++) {
|
|
var data = {'memberIndex': matchPairs ? matchPairs[i].index : i,
|
|
'apiMember': filteredArray[i].member,
|
|
'apiType': filteredArray[i].type,
|
|
'apiValue': filteredArray[i].value};
|
|
|
|
if (hideQtMethods) {
|
|
var chain = data.apiMember.split(".");
|
|
var method = chain[chain.length-1];
|
|
if (method != "destroyed" &&
|
|
method != "objectName" &&
|
|
method != "objectNameChanged") {
|
|
memberModel.append(data);
|
|
}
|
|
} else {
|
|
memberModel.append(data);
|
|
}
|
|
}
|
|
|
|
computeMembersWithValues();
|
|
|
|
if (isReloading) {
|
|
update.glyph = hifi.glyphs.playback_play
|
|
isReloading = false;
|
|
stopReload();
|
|
}
|
|
|
|
if (memberModel.count > 0) {
|
|
scrollSlider.y = 0;
|
|
list.contentY = 0;
|
|
}
|
|
}
|
|
|
|
signal sendToScript(var message);
|
|
}
|