From f2abb369c8fd47126ba430af6baa187eaa941631 Mon Sep 17 00:00:00 2001 From: vladest Date: Sun, 8 Oct 2017 16:09:01 +0200 Subject: [PATCH 01/29] Tablet paginator initial --- .../resources/qml/hifi/tablet/Tablet.qml | 111 +++++++++++++++--- 1 file changed, 94 insertions(+), 17 deletions(-) diff --git a/interface/resources/qml/hifi/tablet/Tablet.qml b/interface/resources/qml/hifi/tablet/Tablet.qml index 66e3dfdbbb..aed626ba67 100644 --- a/interface/resources/qml/hifi/tablet/Tablet.qml +++ b/interface/resources/qml/hifi/tablet/Tablet.qml @@ -1,4 +1,5 @@ -import QtQuick 2.5 +import QtQuick 2.7 +import QtQuick.Controls 2.2 import QtGraphicalEffects 1.0 import QtQuick.Layouts 1.3 @@ -176,23 +177,99 @@ Item { Flickable { id: flickable - width: parent.width - height: parent.height - contentWidth: parent.width - contentHeight: flowMain.childrenRect.height + flowMain.anchors.topMargin + flowMain.anchors.bottomMargin + flowMain.spacing - clip: true - Flow { - id: flowMain - spacing: 16 - anchors.right: parent.right - anchors.rightMargin: 30 - anchors.left: parent.left - anchors.leftMargin: 30 - anchors.bottom: parent.bottom - anchors.bottomMargin: 30 - anchors.top: parent.top - anchors.topMargin: 30 + anchors { + left: parent.left + right: parent.right + top: parent.top + bottom: pageIndicator.top + topMargin: 20 + leftMargin: 30 + rightMargin: 30 + bottomMargin: 0 } + + //required for flick direction calculations + property real oldContentX: 0 + + //flicking direction + property bool flickingLeft: true + + readonly property real pageWidth: width - leftMargin - rightMargin + contentWidth: Math.ceil(flowMain.childrenRect.width / pageWidth) * pageWidth; + contentHeight: flowMain.height + clip: true + boundsBehavior: Flickable.StopAtBounds + flickableDirection: Flickable.HorizontalFlick + + // animate final transition to page edge + Behavior on contentX { + NumberAnimation { duration: 200; } + } + + onContentXChanged: { + flickingLeft = (contentX > oldContentX); + oldContentX = contentX + } + + onFlickEnded: { + if (parseFloat(contentX / flickable.pageWidth) !== pageIndicator.currentIndex * flickable.pageWidth) { + if (flickingLeft) { + pageIndicator.currentIndex++ + } else { + pageIndicator.currentIndex-- + } + + contentX = pageIndicator.currentIndex * flickable.pageWidth + + flowMain.rowSpacing * pageIndicator.currentIndex //compensate spacing + } + } + + Grid { + id: flowMain + rows: 4 + height: parent.height - parent.topMargin - parent.bottomMargin + rowSpacing: 16 + columnSpacing: 16 + flow: Flow.TopToBottom + } + } + + PageIndicator { + id: pageIndicator + currentIndex: 0 + + delegate: Item { + width: 15 + height: 15 + + Rectangle { + anchors.centerIn: parent + opacity: index === pageIndicator.currentIndex ? 0.95 : pressed ? 0.7 : 0.45 + implicitWidth: index == pageIndicator.currentIndex ? 15 : 10 + implicitHeight: implicitWidth + radius: width/2 + color: "white" + Behavior on opacity { + OpacityAnimator { + duration: 100 + } + } + } + + MouseArea { + anchors.fill: parent + onClicked: { + flickable.contentX = flickable.pageWidth * index + + flowMain.rowSpacing * index //compensate spacing + pageIndicator.currentIndex = index + } + } + } + + interactive: false + anchors.bottom: parent.bottom + anchors.horizontalCenter: parent.horizontalCenter + count: Math.ceil(flickable.contentWidth / flickable.pageWidth) } } From 726377db45d2845662b06f2da5101c7fa6560c82 Mon Sep 17 00:00:00 2001 From: vladest Date: Wed, 11 Oct 2017 22:14:01 +0200 Subject: [PATCH 02/29] Refactor to SwipeView --- .../resources/qml/hifi/tablet/Tablet.qml | 139 ++++++++---------- 1 file changed, 58 insertions(+), 81 deletions(-) diff --git a/interface/resources/qml/hifi/tablet/Tablet.qml b/interface/resources/qml/hifi/tablet/Tablet.qml index aed626ba67..a370beb24f 100644 --- a/interface/resources/qml/hifi/tablet/Tablet.qml +++ b/interface/resources/qml/hifi/tablet/Tablet.qml @@ -11,27 +11,30 @@ Item { objectName: "tablet" property int rowIndex: 0 property int columnIndex: 0 - property int count: (flowMain.children.length - 1) + property int count: 0 // used to look up a button by its uuid function findButtonIndex(uuid) { if (!uuid) { return -1; } - - for (var i in flowMain.children) { - var child = flowMain.children[i]; - if (child.uuid === uuid) { - return i; + for (var gridIndex = 0; gridIndex < swipeView.count; gridIndex++) { + var grid = swipeView.itemAt(gridIndex) + for (var i in grid.children) { + var child = grid.children[i]; + if (child.uuid === uuid) { + return { page: gridIndex, index: i}; + } } } return -1; } - function sortButtons() { + function sortButtons(gridIndex) { var children = []; - for (var i = 0; i < flowMain.children.length; i++) { - children[i] = flowMain.children[i]; + var grid = swipeView.itemAt(gridIndex) + for (var i = 0; i < grid.children.length; i++) { + children[i] = grid.children[i]; } children.sort(function (a, b) { @@ -43,13 +46,11 @@ Item { } }); - flowMain.children = children; + grid.children = children; } - // called by C++ code when a button should be added to the tablet - function addButtonProxy(properties) { - var component = Qt.createComponent("TabletButton.qml"); - var button = component.createObject(flowMain); + function doAddButton(grid, gridIndex, component, properties) { + var button = component.createObject(grid); // copy all properites to button var keys = Object.keys(properties).forEach(function (key) { @@ -63,18 +64,37 @@ Item { button.tabletRoot = parent.parent; } - sortButtons(); + sortButtons(gridIndex); + tablet.count++ return button; } + Component { + id: pageComponent + Grid { rows: 4; columns: 3; rowSpacing: 16; columnSpacing: 16; } + } + + // called by C++ code when a button should be added to the tablet + function addButtonProxy(properties) { + var component = Qt.createComponent("TabletButton.qml"); + var grid = swipeView.itemAt(swipeView.count - 1) + if (grid === null || grid.children.length === 12) { + grid = pageComponent.createObject(swipeView) + swipeView.addItem(grid) + } + return doAddButton(grid, swipeView.count - 1, component, properties) + } + // called by C++ code when a button should be removed from the tablet function removeButtonProxy(properties) { var index = findButtonIndex(properties.uuid); - if (index < 0) { + if (index.index < 0) { console.log("Warning: Tablet.qml could not find button with uuid = " + properties.uuid); } else { - flowMain.children[index].destroy(); + var grid = swipeView.itemAt(index.page) + grid.children[index.index].destroy(); + tablet.count-- } } @@ -175,8 +195,10 @@ Item { anchors.top: bgTopBar.bottom anchors.topMargin: 0 - Flickable { - id: flickable + SwipeView { + id: swipeView + clip: true + currentIndex: pageIndicator.currentIndex anchors { left: parent.left right: parent.right @@ -187,56 +209,11 @@ Item { rightMargin: 30 bottomMargin: 0 } - - //required for flick direction calculations - property real oldContentX: 0 - - //flicking direction - property bool flickingLeft: true - - readonly property real pageWidth: width - leftMargin - rightMargin - contentWidth: Math.ceil(flowMain.childrenRect.width / pageWidth) * pageWidth; - contentHeight: flowMain.height - clip: true - boundsBehavior: Flickable.StopAtBounds - flickableDirection: Flickable.HorizontalFlick - - // animate final transition to page edge - Behavior on contentX { - NumberAnimation { duration: 200; } - } - - onContentXChanged: { - flickingLeft = (contentX > oldContentX); - oldContentX = contentX - } - - onFlickEnded: { - if (parseFloat(contentX / flickable.pageWidth) !== pageIndicator.currentIndex * flickable.pageWidth) { - if (flickingLeft) { - pageIndicator.currentIndex++ - } else { - pageIndicator.currentIndex-- - } - - contentX = pageIndicator.currentIndex * flickable.pageWidth + - flowMain.rowSpacing * pageIndicator.currentIndex //compensate spacing - } - } - - Grid { - id: flowMain - rows: 4 - height: parent.height - parent.topMargin - parent.bottomMargin - rowSpacing: 16 - columnSpacing: 16 - flow: Flow.TopToBottom - } } PageIndicator { id: pageIndicator - currentIndex: 0 + currentIndex: swipeView.currentIndex delegate: Item { width: 15 @@ -255,29 +232,28 @@ Item { } } } - - MouseArea { - anchors.fill: parent - onClicked: { - flickable.contentX = flickable.pageWidth * index + - flowMain.rowSpacing * index //compensate spacing - pageIndicator.currentIndex = index - } - } } - interactive: false + interactive: true anchors.bottom: parent.bottom anchors.horizontalCenter: parent.horizontalCenter - count: Math.ceil(flickable.contentWidth / flickable.pageWidth) + count: swipeView.count } } + function getPage(row, column) { + var pageIndex = Math.floor((row + column) / 12) + var index = (row + column) % 12 + var page = swipeView.itemAt(pageIndex) + return { page: page, index: index, pageIndex: pageIndex } + } + function setCurrentItemState(state) { var index = rowIndex + columnIndex; - if (index >= 0 && index <= count ) { - flowMain.children[index].state = state; + var grid = getPage(rowIndex, columnIndex) + grid.page.children[grid.index].state = state; + swipeView.currentIndex = grid.pageIndex } } @@ -285,7 +261,7 @@ Item { setCurrentItemState("base state"); var nextColumnIndex = (columnIndex + 3 + 1) % 3; var nextIndex = rowIndex + nextColumnIndex; - if(nextIndex <= count) { + if(nextIndex < count) { columnIndex = nextColumnIndex; }; setCurrentItemState("hover state"); @@ -294,7 +270,7 @@ Item { function previousItem() { setCurrentItemState("base state"); var prevIndex = (columnIndex + 3 - 1) % 3; - if((rowIndex + prevIndex) <= count){ + if((rowIndex + prevIndex) < count){ columnIndex = prevIndex; } setCurrentItemState("hover state"); @@ -324,7 +300,8 @@ Item { } function selectItem() { - flowMain.children[rowIndex + columnIndex].clicked(); + var grid = getPage(rowIndex, columnIndex) + grid.page.children[grid.index].clicked(); if (tabletRoot) { tabletRoot.playButtonClickSound(); } From f2847168a4f56226f15428115694328707e5a88c Mon Sep 17 00:00:00 2001 From: vladest Date: Fri, 13 Oct 2017 19:12:42 +0200 Subject: [PATCH 03/29] Use MouseArea for interacting instead of default one to be able interact in HMD mode --- interface/resources/qml/hifi/tablet/Tablet.qml | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/interface/resources/qml/hifi/tablet/Tablet.qml b/interface/resources/qml/hifi/tablet/Tablet.qml index a370beb24f..7a97a1809b 100644 --- a/interface/resources/qml/hifi/tablet/Tablet.qml +++ b/interface/resources/qml/hifi/tablet/Tablet.qml @@ -222,7 +222,7 @@ Item { Rectangle { anchors.centerIn: parent opacity: index === pageIndicator.currentIndex ? 0.95 : pressed ? 0.7 : 0.45 - implicitWidth: index == pageIndicator.currentIndex ? 15 : 10 + implicitWidth: index === pageIndicator.currentIndex ? 15 : 10 implicitHeight: implicitWidth radius: width/2 color: "white" @@ -232,9 +232,17 @@ Item { } } } + MouseArea { + anchors.fill: parent + onClicked: { + if (index !== swipeView.currentIndex) { + swipeView.currentIndex = index + } + } + } } - interactive: true + interactive: false anchors.bottom: parent.bottom anchors.horizontalCenter: parent.horizontalCenter count: swipeView.count From 659afcc43b81c1b47199c00185d9d67dda8a26a1 Mon Sep 17 00:00:00 2001 From: vladest Date: Fri, 3 Nov 2017 14:38:46 +0100 Subject: [PATCH 04/29] Make page indicators non clickable. Attempt to enable swipe even over buttons --- interface/resources/qml/hifi/tablet/Tablet.qml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/interface/resources/qml/hifi/tablet/Tablet.qml b/interface/resources/qml/hifi/tablet/Tablet.qml index 7a97a1809b..70acde3aad 100644 --- a/interface/resources/qml/hifi/tablet/Tablet.qml +++ b/interface/resources/qml/hifi/tablet/Tablet.qml @@ -13,6 +13,9 @@ Item { property int columnIndex: 0 property int count: 0 + //timeout for press delay before swipe occurs + readonly property int pressDelayTime: 50 + // used to look up a button by its uuid function findButtonIndex(uuid) { if (!uuid) { @@ -209,6 +212,11 @@ Item { rightMargin: 30 bottomMargin: 0 } + Component.onCompleted: { + if (contentItem !== null) { + contentItem.pressDelay = tablet.pressDelayTime + } + } } PageIndicator { @@ -234,6 +242,7 @@ Item { } MouseArea { anchors.fill: parent + enabled: false //disabled by default onClicked: { if (index !== swipeView.currentIndex) { swipeView.currentIndex = index From 9dbcff040db2fb21e2292faae9afe5264b336e4d Mon Sep 17 00:00:00 2001 From: vladest Date: Sat, 11 Nov 2017 09:43:34 +0100 Subject: [PATCH 05/29] Tune press delay to be able to swipe tablet pages easier --- interface/resources/qml/hifi/tablet/Tablet.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/resources/qml/hifi/tablet/Tablet.qml b/interface/resources/qml/hifi/tablet/Tablet.qml index 70acde3aad..ed144f7087 100644 --- a/interface/resources/qml/hifi/tablet/Tablet.qml +++ b/interface/resources/qml/hifi/tablet/Tablet.qml @@ -14,7 +14,7 @@ Item { property int count: 0 //timeout for press delay before swipe occurs - readonly property int pressDelayTime: 50 + readonly property int pressDelayTime: 100 // used to look up a button by its uuid function findButtonIndex(uuid) { From 50ea08f3d59e7f2056ef9a6431ec7a924f891bb6 Mon Sep 17 00:00:00 2001 From: vladest Date: Sat, 11 Nov 2017 16:10:00 +0100 Subject: [PATCH 06/29] VR stylus and laser need longer timeout than mouse --- interface/resources/qml/hifi/tablet/Tablet.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/resources/qml/hifi/tablet/Tablet.qml b/interface/resources/qml/hifi/tablet/Tablet.qml index ed144f7087..cfa27b9a4c 100644 --- a/interface/resources/qml/hifi/tablet/Tablet.qml +++ b/interface/resources/qml/hifi/tablet/Tablet.qml @@ -14,7 +14,7 @@ Item { property int count: 0 //timeout for press delay before swipe occurs - readonly property int pressDelayTime: 100 + readonly property int pressDelayTime: HMD.active ? 150 : 100 // used to look up a button by its uuid function findButtonIndex(uuid) { From f510b4bcd8ce8dfcc1499d035a32f233d1981c43 Mon Sep 17 00:00:00 2001 From: vladest Date: Thu, 30 Nov 2017 21:10:12 +0100 Subject: [PATCH 07/29] Swipe area expanded to whole tablet. Icons doesnt stick together anymore --- .../resources/qml/hifi/tablet/Tablet.qml | 37 +++++++++++-------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/interface/resources/qml/hifi/tablet/Tablet.qml b/interface/resources/qml/hifi/tablet/Tablet.qml index bef8c679e7..32f94c1329 100644 --- a/interface/resources/qml/hifi/tablet/Tablet.qml +++ b/interface/resources/qml/hifi/tablet/Tablet.qml @@ -22,7 +22,7 @@ Item { return -1; } for (var gridIndex = 0; gridIndex < swipeView.count; gridIndex++) { - var grid = swipeView.itemAt(gridIndex) + var grid = swipeView.itemAt(gridIndex).children[0] for (var i in grid.children) { var child = grid.children[i]; if (child.uuid === uuid) { @@ -35,7 +35,8 @@ Item { function sortButtons(gridIndex) { var children = []; - var grid = swipeView.itemAt(gridIndex) + var grid = swipeView.itemAt(gridIndex).children[0] + for (var i = 0; i < grid.children.length; i++) { children[i] = grid.children[i]; } @@ -53,7 +54,7 @@ Item { } function doAddButton(grid, gridIndex, component, properties) { - var button = component.createObject(grid); + var button = component.createObject(grid.children[0]); // copy all properites to button var keys = Object.keys(properties).forEach(function (key) { @@ -75,14 +76,26 @@ Item { Component { id: pageComponent - Grid { rows: 4; columns: 3; rowSpacing: 16; columnSpacing: 16; } + Item { + visible: SwipeView.isCurrentItem + Grid { + anchors { + fill: parent + topMargin: 20 + leftMargin: 30 + rightMargin: 30 + bottomMargin: 0 + } + rows: 4; columns: 3; rowSpacing: 16; columnSpacing: 16; + } + } } // called by C++ code when a button should be added to the tablet function addButtonProxy(properties) { var component = Qt.createComponent("TabletButton.qml"); var grid = swipeView.itemAt(swipeView.count - 1) - if (grid === null || grid.children.length === 12) { + if (grid === null || grid.children[0].children.length === 12) { grid = pageComponent.createObject(swipeView) swipeView.addItem(grid) } @@ -95,7 +108,7 @@ Item { if (index.index < 0) { console.log("Warning: Tablet.qml could not find button with uuid = " + properties.uuid); } else { - var grid = swipeView.itemAt(index.page) + var grid = swipeView.itemAt(index.page).children[0] grid.children[index.index].destroy(); tablet.count-- } @@ -190,27 +203,19 @@ Item { } } anchors.bottom: parent.bottom - anchors.bottomMargin: 0 anchors.right: parent.right - anchors.rightMargin: 0 anchors.left: parent.left - anchors.leftMargin: 0 anchors.top: bgTopBar.bottom - anchors.topMargin: 0 SwipeView { id: swipeView - clip: true + clip: false currentIndex: pageIndicator.currentIndex anchors { left: parent.left right: parent.right top: parent.top bottom: pageIndicator.top - topMargin: 20 - leftMargin: 30 - rightMargin: 30 - bottomMargin: 0 } Component.onCompleted: { if (contentItem !== null) { @@ -261,7 +266,7 @@ Item { function getPage(row, column) { var pageIndex = Math.floor((row + column) / 12) var index = (row + column) % 12 - var page = swipeView.itemAt(pageIndex) + var page = swipeView.itemAt(pageIndex).children[0] return { page: page, index: index, pageIndex: pageIndex } } From 570be69fcfc732254510019ab050011926a2d1e0 Mon Sep 17 00:00:00 2001 From: vladest Date: Fri, 1 Dec 2017 09:52:45 +0100 Subject: [PATCH 08/29] Fix warnings after apps closed --- interface/resources/qml/hifi/tablet/Tablet.qml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/resources/qml/hifi/tablet/Tablet.qml b/interface/resources/qml/hifi/tablet/Tablet.qml index 32f94c1329..757c0e0a15 100644 --- a/interface/resources/qml/hifi/tablet/Tablet.qml +++ b/interface/resources/qml/hifi/tablet/Tablet.qml @@ -19,7 +19,7 @@ Item { // used to look up a button by its uuid function findButtonIndex(uuid) { if (!uuid) { - return -1; + return { page: -1, index: -1}; } for (var gridIndex = 0; gridIndex < swipeView.count; gridIndex++) { var grid = swipeView.itemAt(gridIndex).children[0] @@ -30,7 +30,7 @@ Item { } } } - return -1; + return { page: -1, index: -1}; } function sortButtons(gridIndex) { From fd9539a9e47a3923c86b0e27a123f13e060ddca4 Mon Sep 17 00:00:00 2001 From: vladest Date: Sat, 2 Dec 2017 13:57:12 +0100 Subject: [PATCH 09/29] Using Flickable signals to remove hover state instead of timer. No more delays --- interface/resources/qml/hifi/tablet/Tablet.qml | 9 +-------- .../resources/qml/hifi/tablet/TabletButton.qml | 14 +++++++++++++- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/interface/resources/qml/hifi/tablet/Tablet.qml b/interface/resources/qml/hifi/tablet/Tablet.qml index 757c0e0a15..d36e216e87 100644 --- a/interface/resources/qml/hifi/tablet/Tablet.qml +++ b/interface/resources/qml/hifi/tablet/Tablet.qml @@ -13,9 +13,6 @@ Item { property int columnIndex: 1 // point to 'go to location' property int count: 0 - //timeout for press delay before swipe occurs - readonly property int pressDelayTime: HMD.active ? 150 : 100 - // used to look up a button by its uuid function findButtonIndex(uuid) { if (!uuid) { @@ -67,6 +64,7 @@ Item { } else { button.tabletRoot = parent.parent; } + button.flickable = swipeView.contentItem sortButtons(gridIndex); @@ -217,11 +215,6 @@ Item { top: parent.top bottom: pageIndicator.top } - Component.onCompleted: { - if (contentItem !== null) { - contentItem.pressDelay = tablet.pressDelayTime - } - } } PageIndicator { diff --git a/interface/resources/qml/hifi/tablet/TabletButton.qml b/interface/resources/qml/hifi/tablet/TabletButton.qml index 8fc31d1cd6..6ad0418e65 100644 --- a/interface/resources/qml/hifi/tablet/TabletButton.qml +++ b/interface/resources/qml/hifi/tablet/TabletButton.qml @@ -23,11 +23,22 @@ Item { property double sortOrder: 100 property int stableOrder: 0 property var tabletRoot; + property var flickable: null width: 129 height: 129 signal clicked() + Connections { + target: flickable + onMovingChanged: { + //when flick/move started, and hover is on, clean hove state + if (flickable.moving && tabletButton.state.indexOf("hover") !== -1) { + tabletButton.state = (tabletButton.isActive) ? "active state" : "base state"; + } + } + } + function changeProperty(key, value) { tabletButton[key] = value; } @@ -121,7 +132,7 @@ Item { anchors.fill: parent hoverEnabled: true enabled: true - preventStealing: true + preventStealing: false onClicked: { console.log("Tablet Button Clicked!"); if (tabletButton.inDebugMode) { @@ -136,6 +147,7 @@ Item { tabletInterface.playSound(TabletEnums.ButtonClick); } } + onEntered: { tabletButton.isEntered = true; tabletInterface.playSound(TabletEnums.ButtonHover); From 3c11d29a7f3313435c02f8181e3a10bc79bba92d Mon Sep 17 00:00:00 2001 From: vladest Date: Thu, 7 Dec 2017 19:13:39 +0100 Subject: [PATCH 10/29] Something intermediate --- .../resources/qml/hifi/tablet/Tablet.qml | 134 ++++++++++++++---- 1 file changed, 104 insertions(+), 30 deletions(-) diff --git a/interface/resources/qml/hifi/tablet/Tablet.qml b/interface/resources/qml/hifi/tablet/Tablet.qml index d36e216e87..dad7896a9e 100644 --- a/interface/resources/qml/hifi/tablet/Tablet.qml +++ b/interface/resources/qml/hifi/tablet/Tablet.qml @@ -12,33 +12,80 @@ Item { property int rowIndex: 6 // by default property int columnIndex: 1 // point to 'go to location' property int count: 0 + property var tabletButtons: new Array() + + onTabletButtonsChanged: console.warn("tablet buttons", tabletButtons) + + Timer { + id: gridsRecreateTimer + interval: 100 + repeat: false + onTriggered: { + console.warn("timer triggered", tabletButtons.length) + doRecreateGrids() + } + } + + Item { + id: fakeParent + visible: parent + } + + function doRecreateGrids() { + console.warn("buttons length", tabletButtons.length) + for (var i = 0; i < swipeView.count; i++) { + var gridOuter = swipeView.itemAt(i); + gridOuter.destroy(); + swipeView.removeItem(i); + } + for (var buttonIndex = 0; buttonIndex < tabletButtons.length; buttonIndex++) { + console.warn("button index", buttonIndex) + var grid = swipeView.itemAt(swipeView.count - 1); + if (grid === null || grid.children[0].children.length === 12) { + grid = pageComponent.createObject(swipeView); + console.warn("grid index", swipeView.count) + //swipeView.addItem(grid); + } + var button = tabletButtons[buttonIndex] + button.parent = grid.children[0] + grid.children[0].children.push(button); + } + } // used to look up a button by its uuid function findButtonIndex(uuid) { if (!uuid) { - return { page: -1, index: -1}; + return -1;//{ page: -1, index: -1}; } - for (var gridIndex = 0; gridIndex < swipeView.count; gridIndex++) { - var grid = swipeView.itemAt(gridIndex).children[0] - for (var i in grid.children) { - var child = grid.children[i]; - if (child.uuid === uuid) { - return { page: gridIndex, index: i}; - } + for (var i in tabletButtons) { + var child = tabletButtons[i]; + if (child.uuid === uuid) { + return i; } } - return { page: -1, index: -1}; + +// for (var gridIndex = 0; gridIndex < swipeView.count; gridIndex++) { +// var grid = swipeView.itemAt(gridIndex).children[0] +// for (var i in grid.children) { +// var child = grid.children[i]; +// if (child.uuid === uuid) { +// return { page: gridIndex, index: i}; +// } +// } +// } + return -1;//{ page: -1, index: -1}; } - function sortButtons(gridIndex) { - var children = []; - var grid = swipeView.itemAt(gridIndex).children[0] + function sortButtons(/*gridIndex*/) { + //var children = []; - for (var i = 0; i < grid.children.length; i++) { - children[i] = grid.children[i]; - } +// var grid = swipeView.itemAt(gridIndex).children[0] - children.sort(function (a, b) { +// for (var i = 0; i < grid.children.length; i++) { +// children[i] = grid.children[i]; +// } + + tabletButtons.sort(function (a, b) { if (a.sortOrder === b.sortOrder) { // subsort by stableOrder, because JS sort is not stable in qml. return a.stableOrder - b.stableOrder; @@ -47,11 +94,11 @@ Item { } }); - grid.children = children; + //grid.children = children; } - function doAddButton(grid, gridIndex, component, properties) { - var button = component.createObject(grid.children[0]); + function doAddButton(/*grid, gridIndex,*/ component, properties) { + var button = component.createObject(/*swipeView.itemAt(0).children[0]*/fakeParent); // copy all properites to button var keys = Object.keys(properties).forEach(function (key) { @@ -65,17 +112,22 @@ Item { button.tabletRoot = parent.parent; } button.flickable = swipeView.contentItem + tabletButtons.push(button) - sortButtons(gridIndex); + //sortButtons(/*gridIndex*/); tablet.count++ + //redraw pages + doRecreateGrids() +// console.warn("timer restarted", tabletButtons.length) +// gridsRecreateTimer.restart() + return button; } Component { id: pageComponent Item { - visible: SwipeView.isCurrentItem Grid { anchors { fill: parent @@ -92,23 +144,29 @@ Item { // called by C++ code when a button should be added to the tablet function addButtonProxy(properties) { var component = Qt.createComponent("TabletButton.qml"); - var grid = swipeView.itemAt(swipeView.count - 1) - if (grid === null || grid.children[0].children.length === 12) { - grid = pageComponent.createObject(swipeView) - swipeView.addItem(grid) - } - return doAddButton(grid, swipeView.count - 1, component, properties) +// var grid = swipeView.itemAt(swipeView.count - 1) +// if (grid === null || grid.children[0].children.length === 12) { +// grid = pageComponent.createObject(swipeView) +// swipeView.addItem(grid) +// } + console.warn("component status", component.status); + + return doAddButton(/*grid, swipeView.count - 1,*/ component, properties) } // called by C++ code when a button should be removed from the tablet function removeButtonProxy(properties) { var index = findButtonIndex(properties.uuid); - if (index.index < 0) { + if (index < 0) { console.log("Warning: Tablet.qml could not find button with uuid = " + properties.uuid); } else { - var grid = swipeView.itemAt(index.page).children[0] - grid.children[index.index].destroy(); +// var grid = swipeView.itemAt(index.page).children[0] +// grid.children[index.index].destroy(); + console.warn("remove button proxy"); + tabletButtons.slice(index, 1); tablet.count-- + //redraw grids + gridsRecreateTimer.restart(); } } @@ -187,6 +245,19 @@ Item { } } + Component.onCompleted: { + console.warn("Tablet created") + //pageComponent.createObject(swipeView) +// var tabletq = Tablet.getTablet("com.highfidelity.interface.tablet.system"); +// if (tabletq) { +// // Tablet/toolbar button. +// for (var i = 0; i < 1; i++) { +// tabletq.addButton({ icon: "icons/tablet-icons/avatar-record-i.svg", activeIcon: "icons/tablet-icons/avatar-record-i.svg", +// text: "App " + i, isActive: false }); +// } +// } + } + Rectangle { id: bgMain gradient: Gradient { @@ -209,6 +280,9 @@ Item { id: swipeView clip: false currentIndex: pageIndicator.currentIndex + hoverEnabled: true + onHoveredChanged: console.warn("swipe hovered", hovered) + onCurrentIndexChanged: console.warn("swipe currentIndex", currentIndex) anchors { left: parent.left right: parent.right From 9b3db0725bb9d380c83482efe65ce5de257638ad Mon Sep 17 00:00:00 2001 From: vladest Date: Thu, 7 Dec 2017 22:36:34 +0100 Subject: [PATCH 11/29] Retreive buttons list from tablet proxy --- .../resources/qml/hifi/tablet/Tablet.qml | 102 +++++------------- .../ui/src/ui/TabletScriptingInterface.cpp | 14 +++ .../ui/src/ui/TabletScriptingInterface.h | 9 ++ 3 files changed, 51 insertions(+), 74 deletions(-) diff --git a/interface/resources/qml/hifi/tablet/Tablet.qml b/interface/resources/qml/hifi/tablet/Tablet.qml index dad7896a9e..45130e5306 100644 --- a/interface/resources/qml/hifi/tablet/Tablet.qml +++ b/interface/resources/qml/hifi/tablet/Tablet.qml @@ -12,51 +12,54 @@ Item { property int rowIndex: 6 // by default property int columnIndex: 1 // point to 'go to location' property int count: 0 - property var tabletButtons: new Array() - - onTabletButtonsChanged: console.warn("tablet buttons", tabletButtons) Timer { id: gridsRecreateTimer - interval: 100 + interval: 200 repeat: false onTriggered: { - console.warn("timer triggered", tabletButtons.length) doRecreateGrids() } } + //fake invisible item for initial buttons creations Item { id: fakeParent visible: parent } function doRecreateGrids() { - console.warn("buttons length", tabletButtons.length) + var tabletProxy = Tablet.getTablet("com.highfidelity.interface.tablet.system"); + var tabletButtons = tabletProxy.getButtonsList(); for (var i = 0; i < swipeView.count; i++) { var gridOuter = swipeView.itemAt(i); gridOuter.destroy(); swipeView.removeItem(i); } + sortButtons(tabletButtons); + for (var buttonIndex = 0; buttonIndex < tabletButtons.length; buttonIndex++) { - console.warn("button index", buttonIndex) - var grid = swipeView.itemAt(swipeView.count - 1); - if (grid === null || grid.children[0].children.length === 12) { - grid = pageComponent.createObject(swipeView); - console.warn("grid index", swipeView.count) - //swipeView.addItem(grid); - } var button = tabletButtons[buttonIndex] - button.parent = grid.children[0] - grid.children[0].children.push(button); + if (button !== null) { + var grid = swipeView.itemAt(swipeView.count - 1); + if (grid === null || grid.children[0].children.length === 12) { + grid = pageComponent.createObject(swipeView); + } + //reparent to actual grid + + button.parent = grid.children[0] + grid.children[0].children.push(button); + } } } // used to look up a button by its uuid function findButtonIndex(uuid) { if (!uuid) { - return -1;//{ page: -1, index: -1}; + return -1; } + var tabletProxy = Tablet.getTablet("com.highfidelity.interface.tablet.system"); + var tabletButtons = tabletProxy.getButtonsList(); for (var i in tabletButtons) { var child = tabletButtons[i]; if (child.uuid === uuid) { @@ -64,28 +67,14 @@ Item { } } -// for (var gridIndex = 0; gridIndex < swipeView.count; gridIndex++) { -// var grid = swipeView.itemAt(gridIndex).children[0] -// for (var i in grid.children) { -// var child = grid.children[i]; -// if (child.uuid === uuid) { -// return { page: gridIndex, index: i}; -// } -// } -// } - return -1;//{ page: -1, index: -1}; + return -1; } - function sortButtons(/*gridIndex*/) { - //var children = []; - -// var grid = swipeView.itemAt(gridIndex).children[0] - -// for (var i = 0; i < grid.children.length; i++) { -// children[i] = grid.children[i]; -// } - + function sortButtons(tabletButtons) { tabletButtons.sort(function (a, b) { + if (a === null || b === null) { + return 0; + } if (a.sortOrder === b.sortOrder) { // subsort by stableOrder, because JS sort is not stable in qml. return a.stableOrder - b.stableOrder; @@ -93,12 +82,10 @@ Item { return a.sortOrder - b.sortOrder; } }); - - //grid.children = children; } - function doAddButton(/*grid, gridIndex,*/ component, properties) { - var button = component.createObject(/*swipeView.itemAt(0).children[0]*/fakeParent); + function doAddButton(component, properties) { + var button = component.createObject(fakeParent); // copy all properites to button var keys = Object.keys(properties).forEach(function (key) { @@ -112,15 +99,8 @@ Item { button.tabletRoot = parent.parent; } button.flickable = swipeView.contentItem - tabletButtons.push(button) - - //sortButtons(/*gridIndex*/); - tablet.count++ - //redraw pages - doRecreateGrids() -// console.warn("timer restarted", tabletButtons.length) -// gridsRecreateTimer.restart() + gridsRecreateTimer.restart() return button; } @@ -144,14 +124,7 @@ Item { // called by C++ code when a button should be added to the tablet function addButtonProxy(properties) { var component = Qt.createComponent("TabletButton.qml"); -// var grid = swipeView.itemAt(swipeView.count - 1) -// if (grid === null || grid.children[0].children.length === 12) { -// grid = pageComponent.createObject(swipeView) -// swipeView.addItem(grid) -// } - console.warn("component status", component.status); - - return doAddButton(/*grid, swipeView.count - 1,*/ component, properties) + return doAddButton(component, properties) } // called by C++ code when a button should be removed from the tablet @@ -160,10 +133,6 @@ Item { if (index < 0) { console.log("Warning: Tablet.qml could not find button with uuid = " + properties.uuid); } else { -// var grid = swipeView.itemAt(index.page).children[0] -// grid.children[index.index].destroy(); - console.warn("remove button proxy"); - tabletButtons.slice(index, 1); tablet.count-- //redraw grids gridsRecreateTimer.restart(); @@ -245,19 +214,6 @@ Item { } } - Component.onCompleted: { - console.warn("Tablet created") - //pageComponent.createObject(swipeView) -// var tabletq = Tablet.getTablet("com.highfidelity.interface.tablet.system"); -// if (tabletq) { -// // Tablet/toolbar button. -// for (var i = 0; i < 1; i++) { -// tabletq.addButton({ icon: "icons/tablet-icons/avatar-record-i.svg", activeIcon: "icons/tablet-icons/avatar-record-i.svg", -// text: "App " + i, isActive: false }); -// } -// } - } - Rectangle { id: bgMain gradient: Gradient { @@ -281,8 +237,6 @@ Item { clip: false currentIndex: pageIndicator.currentIndex hoverEnabled: true - onHoveredChanged: console.warn("swipe hovered", hovered) - onCurrentIndexChanged: console.warn("swipe currentIndex", currentIndex) anchors { left: parent.left right: parent.right diff --git a/libraries/ui/src/ui/TabletScriptingInterface.cpp b/libraries/ui/src/ui/TabletScriptingInterface.cpp index dd26dd7be7..f0653dec62 100644 --- a/libraries/ui/src/ui/TabletScriptingInterface.cpp +++ b/libraries/ui/src/ui/TabletScriptingInterface.cpp @@ -900,6 +900,16 @@ QQuickItem* TabletProxy::getQmlMenu() const { return menuList; } +QList TabletProxy::getButtonsList() const { + QList buttonsList; + for (auto& buttonProxy : _tabletButtonProxies) { + if (buttonProxy->getQmlButton()) { + buttonsList.append(buttonProxy->getQmlButton()); + } + } + return buttonsList; +} + // // TabletButtonProxy // @@ -980,3 +990,7 @@ void TabletButtonProxy::editProperties(const QVariantMap& properties) { QMetaObject::invokeMethod(_toolbarButtonProxy, "editProperties", Qt::AutoConnection, Q_ARG(QVariantMap, properties)); } } + +QQuickItem *TabletButtonProxy::getQmlButton() const { + return _qmlButton; +} diff --git a/libraries/ui/src/ui/TabletScriptingInterface.h b/libraries/ui/src/ui/TabletScriptingInterface.h index ad6a7c8001..50ea45d841 100644 --- a/libraries/ui/src/ui/TabletScriptingInterface.h +++ b/libraries/ui/src/ui/TabletScriptingInterface.h @@ -204,6 +204,13 @@ public: QQuickItem* getQmlMenu() const; + /**jsdoc + * Returns a list of currently created button items. + * @function TabletProxy#getButtonsList + * @returns {QList} + */ + Q_INVOKABLE QList getButtonsList() const; + signals: /**jsdoc * Signaled when this tablet receives an event from the html/js embedded in the tablet @@ -297,6 +304,8 @@ public: */ Q_INVOKABLE void editProperties(const QVariantMap& properties); + QQuickItem *getQmlButton() const; + public slots: void clickedSlot() { emit clicked(); } From cc78fc1f534b07fda5faae4c3a45b0cfd52c5677 Mon Sep 17 00:00:00 2001 From: vladest Date: Mon, 11 Dec 2017 17:50:16 +0100 Subject: [PATCH 12/29] Added buttons list mutex protection. Reworked keyboard tablet navigation. no more double selections --- .../resources/qml/hifi/tablet/Tablet.qml | 156 ++++++++++++------ .../qml/hifi/tablet/TabletButton.qml | 11 ++ .../ui/src/ui/TabletScriptingInterface.cpp | 31 +++- .../ui/src/ui/TabletScriptingInterface.h | 1 + 4 files changed, 145 insertions(+), 54 deletions(-) diff --git a/interface/resources/qml/hifi/tablet/Tablet.qml b/interface/resources/qml/hifi/tablet/Tablet.qml index 45130e5306..87d2a9c9d0 100644 --- a/interface/resources/qml/hifi/tablet/Tablet.qml +++ b/interface/resources/qml/hifi/tablet/Tablet.qml @@ -12,6 +12,11 @@ Item { property int rowIndex: 6 // by default property int columnIndex: 1 // point to 'go to location' property int count: 0 + readonly property int buttonsOnPage: 12 + readonly property int buttonsRowsOnPage: 4 + readonly property int buttonsColumnsOnPage: 3 + + focus: true Timer { id: gridsRecreateTimer @@ -42,11 +47,12 @@ Item { var button = tabletButtons[buttonIndex] if (button !== null) { var grid = swipeView.itemAt(swipeView.count - 1); - if (grid === null || grid.children[0].children.length === 12) { + if (grid === null || grid.children[0].children.length === buttonsOnPage) { grid = pageComponent.createObject(swipeView); } + button.row = Math.floor(grid.children[0].children.length / buttonsColumnsOnPage); + button.column = grid.children[0].children.length % buttonsColumnsOnPage; //reparent to actual grid - button.parent = grid.children[0] grid.children[0].children.push(button); } @@ -236,6 +242,11 @@ Item { id: swipeView clip: false currentIndex: pageIndicator.currentIndex + onCurrentIndexChanged: { + rowIndex = 0 + columnIndex = 0 + } + hoverEnabled: true anchors { left: parent.left @@ -266,15 +277,6 @@ Item { } } } - MouseArea { - anchors.fill: parent - enabled: false //disabled by default - onClicked: { - if (index !== swipeView.currentIndex) { - swipeView.currentIndex = index - } - } - } } interactive: false @@ -284,75 +286,135 @@ Item { } } - function getPage(row, column) { - var pageIndex = Math.floor((row + column) / 12) - var index = (row + column) % 12 - var page = swipeView.itemAt(pageIndex).children[0] - return { page: page, index: index, pageIndex: pageIndex } + function setCurrentItemState(state) { + var index = rowIndex*buttonsColumnsOnPage + columnIndex; + var currentGridItems = swipeView.currentItem.children[0].children + if (currentGridItems !== null && index >= 0 && index < currentGridItems.length) { + if (currentGridItems[index].isActive) { + currentGridItems[index].state = "active state"; + } else { + currentGridItems[index].state = state; + } + } } - function setCurrentItemState(state) { - var index = rowIndex + columnIndex; - if (index >= 0 && index <= count ) { - var grid = getPage(rowIndex, columnIndex) - grid.page.children[grid.index].state = state; - swipeView.currentIndex = grid.pageIndex + function previousPage() { + setCurrentItemState("base state"); + var currentPage = swipeView.currentIndex + currentPage = currentPage - 1 + if (currentPage < 0) { + currentPage = swipeView.count - 1 } + swipeView.currentIndex = currentPage + } + + function nextPage() { + setCurrentItemState("base state"); + var currentPage = swipeView.currentIndex + currentPage = currentPage + 1 + if (currentPage >= swipeView.count) { + currentPage = 0 + } + swipeView.currentIndex = currentPage } function nextItem() { setCurrentItemState("base state"); - var nextColumnIndex = (columnIndex + 3 + 1) % 3; - var nextIndex = rowIndex + nextColumnIndex; - if(nextIndex < count) { - columnIndex = nextColumnIndex; - }; + var currentGridItems = swipeView.currentItem.children[0].children + var nextColumnIndex = columnIndex + 1; + var index = rowIndex*buttonsColumnsOnPage + nextColumnIndex; + if(index >= currentGridItems.length || nextColumnIndex >= buttonsColumnsOnPage) { + nextColumnIndex = 0; + } + columnIndex = nextColumnIndex; setCurrentItemState("hover state"); } function previousItem() { setCurrentItemState("base state"); - var prevIndex = (columnIndex + 3 - 1) % 3; - if((rowIndex + prevIndex) < count){ - columnIndex = prevIndex; + var column = columnIndex + column = column - 1; + + if (column < 0 ) { + column = buttonsColumnsOnPage - 1; + var index = rowIndex*buttonsColumnsOnPage + column; + var currentGridItems = swipeView.currentItem.children[0].children + while(index >= currentGridItems.length) { + column = column - 1 + index = rowIndex*buttonsColumnsOnPage + column; + } } + columnIndex = column setCurrentItemState("hover state"); } function upItem() { setCurrentItemState("base state"); - rowIndex = rowIndex - 3; - if (rowIndex < 0 ) { - rowIndex = (count - (count % 3)); - var index = rowIndex + columnIndex; - if(index > count) { - rowIndex = rowIndex - 3; + var row = rowIndex + row = row - 1; + + if (row < 0 ) { + row = buttonsRowsOnPage - 1; + var index = row*buttonsColumnsOnPage + columnIndex; + var currentGridItems = swipeView.currentItem.children[0].children + while(index >= currentGridItems.length) { + row = row - 1 + index = row*buttonsColumnsOnPage + columnIndex; } } + rowIndex = row setCurrentItemState("hover state"); } function downItem() { setCurrentItemState("base state"); - rowIndex = rowIndex + 3; - var index = rowIndex + columnIndex; - if (index > count ) { + rowIndex = rowIndex + 1; + var currentGridItems = swipeView.currentItem.children[0].children + var index = rowIndex*buttonsColumnsOnPage + columnIndex; + if (index >= currentGridItems.length) { rowIndex = 0; } setCurrentItemState("hover state"); } function selectItem() { - var grid = getPage(rowIndex, columnIndex) - grid.page.children[grid.index].clicked(); - if (tabletRoot) { - tabletRoot.playButtonClickSound(); + var index = rowIndex*buttonsColumnsOnPage + columnIndex; + var currentGridItems = swipeView.currentItem.children[0].children + if (currentGridItems !== null && index >= 0 && index < currentGridItems.length) { + currentGridItems[index].clicked(); + if (tabletRoot) { + tabletRoot.playButtonClickSound(); + } } } - Keys.onRightPressed: nextItem(); - Keys.onLeftPressed: previousItem(); - Keys.onDownPressed: downItem(); - Keys.onUpPressed: upItem(); + Keys.onRightPressed: { + if (event.modifiers & Qt.ShiftModifier) { + nextPage(); + } else { + nextItem(); + } + } + Keys.onLeftPressed: { + if (event.modifiers & Qt.ShiftModifier) { + previousPage(); + } else { + previousItem(); + } + } + Keys.onDownPressed: { + if (event.modifiers & Qt.ShiftModifier) { + nextPage(); + } else { + downItem(); + } + } + Keys.onUpPressed: { + if (event.modifiers & Qt.ShiftModifier) { + previousPage(); + } else { + upItem(); + } + } Keys.onReturnPressed: selectItem(); } diff --git a/interface/resources/qml/hifi/tablet/TabletButton.qml b/interface/resources/qml/hifi/tablet/TabletButton.qml index 6ad0418e65..4555095d57 100644 --- a/interface/resources/qml/hifi/tablet/TabletButton.qml +++ b/interface/resources/qml/hifi/tablet/TabletButton.qml @@ -24,6 +24,10 @@ Item { property int stableOrder: 0 property var tabletRoot; property var flickable: null + + property int row: -1 + property int column: -1 + width: 129 height: 129 @@ -135,6 +139,7 @@ Item { preventStealing: false onClicked: { console.log("Tablet Button Clicked!"); + tablet.setCurrentItemState("base state"); if (tabletButton.inDebugMode) { if (tabletButton.isActive) { tabletButton.isActive = false; @@ -142,6 +147,9 @@ Item { tabletButton.isActive = true; } } + tablet.rowIndex = tabletButton.row + tablet.columnIndex = tabletButton.column + tabletButton.clicked(); if (tabletRoot) { tabletInterface.playSound(TabletEnums.ButtonClick); @@ -149,6 +157,7 @@ Item { } onEntered: { + tablet.setCurrentItemState("base state"); tabletButton.isEntered = true; tabletInterface.playSound(TabletEnums.ButtonHover); @@ -157,6 +166,8 @@ Item { } else { tabletButton.state = "hover state"; } + tablet.rowIndex = tabletButton.row + tablet.columnIndex = tabletButton.column } onExited: { tabletButton.isEntered = false; diff --git a/libraries/ui/src/ui/TabletScriptingInterface.cpp b/libraries/ui/src/ui/TabletScriptingInterface.cpp index f0653dec62..ec5392a82d 100644 --- a/libraries/ui/src/ui/TabletScriptingInterface.cpp +++ b/libraries/ui/src/ui/TabletScriptingInterface.cpp @@ -716,7 +716,11 @@ TabletButtonProxy* TabletProxy::addButton(const QVariant& properties) { } auto tabletButtonProxy = QSharedPointer(new TabletButtonProxy(properties.toMap())); - _tabletButtonProxies.push_back(tabletButtonProxy); + { + QMutexLocker locker(&_tabletButtonsListMutex); + _tabletButtonProxies.push_back(tabletButtonProxy); + + } if (!_toolbarMode && _qmlTabletRoot) { auto tablet = getQmlTablet(); if (tablet) { @@ -764,7 +768,10 @@ void TabletProxy::removeButton(TabletButtonProxy* tabletButtonProxy) { return; } buttonProxy = *iter; - _tabletButtonProxies.erase(iter); + { + QMutexLocker locker(&_tabletButtonsListMutex); + _tabletButtonProxies.erase(iter); + } } if (!_toolbarMode && _qmlTabletRoot) { @@ -813,8 +820,12 @@ void TabletProxy::addButtonsToHomeScreen() { if (!tablet || _toolbarMode) { return; } - for (auto& buttonProxy : _tabletButtonProxies) { - addButtonProxyToQmlTablet(tablet, buttonProxy.data()); + + { + QMutexLocker locker(&_tabletButtonsListMutex); + for (auto& buttonProxy : _tabletButtonProxies) { + addButtonProxyToQmlTablet(tablet, buttonProxy.data()); + } } auto loader = _qmlTabletRoot->findChild("loader"); QObject::disconnect(loader, SIGNAL(loaded()), this, SLOT(addButtonsToHomeScreen())); @@ -841,9 +852,12 @@ void TabletProxy::desktopWindowClosed() { void TabletProxy::addButtonsToToolbar() { Q_ASSERT(QThread::currentThread() == thread()); ToolbarProxy* toolbarProxy = DependencyManager::get()->getSystemToolbarProxy(); - for (auto& buttonProxy : _tabletButtonProxies) { - // copy properties from tablet button proxy to toolbar button proxy. - buttonProxy->setToolbarButtonProxy(toolbarProxy->addButton(buttonProxy->getProperties())); + { + QMutexLocker locker(&_tabletButtonsListMutex); + for (auto& buttonProxy : _tabletButtonProxies) { + // copy properties from tablet button proxy to toolbar button proxy. + buttonProxy->setToolbarButtonProxy(toolbarProxy->addButton(buttonProxy->getProperties())); + } } // make the toolbar visible @@ -902,11 +916,14 @@ QQuickItem* TabletProxy::getQmlMenu() const { QList TabletProxy::getButtonsList() const { QList buttonsList; + QMutexLocker locker(&_tabletButtonsListMutex); + for (auto& buttonProxy : _tabletButtonProxies) { if (buttonProxy->getQmlButton()) { buttonsList.append(buttonProxy->getQmlButton()); } } + return buttonsList; } diff --git a/libraries/ui/src/ui/TabletScriptingInterface.h b/libraries/ui/src/ui/TabletScriptingInterface.h index 50ea45d841..f7775e8709 100644 --- a/libraries/ui/src/ui/TabletScriptingInterface.h +++ b/libraries/ui/src/ui/TabletScriptingInterface.h @@ -270,6 +270,7 @@ protected: std::pair _initialWebPathParams; bool _landscape { false }; bool _showRunningScripts { false }; + mutable QMutex _tabletButtonsListMutex; }; Q_DECLARE_METATYPE(TabletProxy*); From e0527844313332c370f0698fb52c0af5fc987581 Mon Sep 17 00:00:00 2001 From: vladest Date: Tue, 12 Dec 2017 14:12:03 +0100 Subject: [PATCH 13/29] Code style --- .../resources/qml/hifi/tablet/Tablet.qml | 54 +++++++++---------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/interface/resources/qml/hifi/tablet/Tablet.qml b/interface/resources/qml/hifi/tablet/Tablet.qml index 87d2a9c9d0..ff5259e041 100644 --- a/interface/resources/qml/hifi/tablet/Tablet.qml +++ b/interface/resources/qml/hifi/tablet/Tablet.qml @@ -53,7 +53,7 @@ Item { button.row = Math.floor(grid.children[0].children.length / buttonsColumnsOnPage); button.column = grid.children[0].children.length % buttonsColumnsOnPage; //reparent to actual grid - button.parent = grid.children[0] + button.parent = grid.children[0]; grid.children[0].children.push(button); } } @@ -104,9 +104,9 @@ Item { } else { button.tabletRoot = parent.parent; } - button.flickable = swipeView.contentItem + button.flickable = swipeView.contentItem; tablet.count++ - gridsRecreateTimer.restart() + gridsRecreateTimer.restart(); return button; } @@ -130,7 +130,7 @@ Item { // called by C++ code when a button should be added to the tablet function addButtonProxy(properties) { var component = Qt.createComponent("TabletButton.qml"); - return doAddButton(component, properties) + return doAddButton(component, properties); } // called by C++ code when a button should be removed from the tablet @@ -139,7 +139,7 @@ Item { if (index < 0) { console.log("Warning: Tablet.qml could not find button with uuid = " + properties.uuid); } else { - tablet.count-- + tablet.count--; //redraw grids gridsRecreateTimer.restart(); } @@ -243,8 +243,8 @@ Item { clip: false currentIndex: pageIndicator.currentIndex onCurrentIndexChanged: { - rowIndex = 0 - columnIndex = 0 + rowIndex = 0; + columnIndex = 0; } hoverEnabled: true @@ -288,7 +288,7 @@ Item { function setCurrentItemState(state) { var index = rowIndex*buttonsColumnsOnPage + columnIndex; - var currentGridItems = swipeView.currentItem.children[0].children + var currentGridItems = swipeView.currentItem.children[0].children; if (currentGridItems !== null && index >= 0 && index < currentGridItems.length) { if (currentGridItems[index].isActive) { currentGridItems[index].state = "active state"; @@ -300,27 +300,27 @@ Item { function previousPage() { setCurrentItemState("base state"); - var currentPage = swipeView.currentIndex - currentPage = currentPage - 1 + var currentPage = swipeView.currentIndex; + currentPage = currentPage - 1; if (currentPage < 0) { - currentPage = swipeView.count - 1 + currentPage = swipeView.count - 1; } - swipeView.currentIndex = currentPage + swipeView.currentIndex = currentPage; } function nextPage() { setCurrentItemState("base state"); - var currentPage = swipeView.currentIndex - currentPage = currentPage + 1 + var currentPage = swipeView.currentIndex; + currentPage = currentPage + 1; if (currentPage >= swipeView.count) { - currentPage = 0 + currentPage = 0; } - swipeView.currentIndex = currentPage + swipeView.currentIndex = currentPage; } function nextItem() { setCurrentItemState("base state"); - var currentGridItems = swipeView.currentItem.children[0].children + var currentGridItems = swipeView.currentItem.children[0].children; var nextColumnIndex = columnIndex + 1; var index = rowIndex*buttonsColumnsOnPage + nextColumnIndex; if(index >= currentGridItems.length || nextColumnIndex >= buttonsColumnsOnPage) { @@ -332,44 +332,44 @@ Item { function previousItem() { setCurrentItemState("base state"); - var column = columnIndex + var column = columnIndex; column = column - 1; if (column < 0 ) { column = buttonsColumnsOnPage - 1; var index = rowIndex*buttonsColumnsOnPage + column; - var currentGridItems = swipeView.currentItem.children[0].children + var currentGridItems = swipeView.currentItem.children[0].children; while(index >= currentGridItems.length) { - column = column - 1 + column = column - 1; index = rowIndex*buttonsColumnsOnPage + column; } } - columnIndex = column + columnIndex = column; setCurrentItemState("hover state"); } function upItem() { setCurrentItemState("base state"); - var row = rowIndex + var row = rowIndex; row = row - 1; if (row < 0 ) { row = buttonsRowsOnPage - 1; var index = row*buttonsColumnsOnPage + columnIndex; - var currentGridItems = swipeView.currentItem.children[0].children + var currentGridItems = swipeView.currentItem.children[0].children; while(index >= currentGridItems.length) { - row = row - 1 + row = row - 1; index = row*buttonsColumnsOnPage + columnIndex; } } - rowIndex = row + rowIndex = row; setCurrentItemState("hover state"); } function downItem() { setCurrentItemState("base state"); rowIndex = rowIndex + 1; - var currentGridItems = swipeView.currentItem.children[0].children + var currentGridItems = swipeView.currentItem.children[0].children; var index = rowIndex*buttonsColumnsOnPage + columnIndex; if (index >= currentGridItems.length) { rowIndex = 0; @@ -379,7 +379,7 @@ Item { function selectItem() { var index = rowIndex*buttonsColumnsOnPage + columnIndex; - var currentGridItems = swipeView.currentItem.children[0].children + var currentGridItems = swipeView.currentItem.children[0].children; if (currentGridItems !== null && index >= 0 && index < currentGridItems.length) { currentGridItems[index].clicked(); if (tabletRoot) { From cdb9d7238708f40f80d62c26da7ded4a6c5aeaa5 Mon Sep 17 00:00:00 2001 From: vladest Date: Sat, 16 Dec 2017 20:27:19 +0100 Subject: [PATCH 14/29] Added smart pointer for qml buttons. removed extra modifiers. page changed using left and right buttons --- .../resources/qml/hifi/tablet/Tablet.qml | 141 +++++++----------- .../ui/src/ui/TabletScriptingInterface.cpp | 2 +- .../ui/src/ui/TabletScriptingInterface.h | 4 +- 3 files changed, 61 insertions(+), 86 deletions(-) diff --git a/interface/resources/qml/hifi/tablet/Tablet.qml b/interface/resources/qml/hifi/tablet/Tablet.qml index ff5259e041..07f85bd747 100644 --- a/interface/resources/qml/hifi/tablet/Tablet.qml +++ b/interface/resources/qml/hifi/tablet/Tablet.qml @@ -16,11 +16,13 @@ Item { readonly property int buttonsRowsOnPage: 4 readonly property int buttonsColumnsOnPage: 3 + property var currentGridItems: null + focus: true Timer { id: gridsRecreateTimer - interval: 200 + interval: 50 repeat: false onTriggered: { doRecreateGrids() @@ -57,6 +59,7 @@ Item { grid.children[0].children.push(button); } } + swipeView.currentIndex = 0; } // used to look up a button by its uuid @@ -241,10 +244,29 @@ Item { SwipeView { id: swipeView clip: false - currentIndex: pageIndicator.currentIndex - onCurrentIndexChanged: { - rowIndex = 0; - columnIndex = 0; + property int previousIndex: -1 + + onCurrentItemChanged: { + if (swipeView.currentIndex < 0 + || swipeView.itemAt(swipeView.currentIndex) === null + || swipeView.itemAt(swipeView.currentIndex).children[0] === null + || swipeView.itemAt(swipeView.currentIndex).children[0].children === null) { + return; + } + + currentGridItems = swipeView.itemAt(swipeView.currentIndex).children[0].children; + + var row = rowIndex < 0 ? 0 : rowIndex; + var column = previousIndex > swipeView.currentIndex ? buttonsColumnsOnPage - 1 : 0; + var index = row * buttonsColumnsOnPage + column; + if (index < 0 || index >= currentGridItems.length) { + column = 0; + row = 0; + } + rowIndex = row; + columnIndex = column; + setCurrentItemState("hover state"); + previousIndex = currentIndex; } hoverEnabled: true @@ -266,7 +288,7 @@ Item { Rectangle { anchors.centerIn: parent - opacity: index === pageIndicator.currentIndex ? 0.95 : pressed ? 0.7 : 0.45 + opacity: index === pageIndicator.currentIndex ? 0.95 : 0.45 implicitWidth: index === pageIndicator.currentIndex ? 15 : 10 implicitHeight: implicitWidth radius: width/2 @@ -287,44 +309,27 @@ Item { } function setCurrentItemState(state) { - var index = rowIndex*buttonsColumnsOnPage + columnIndex; - var currentGridItems = swipeView.currentItem.children[0].children; - if (currentGridItems !== null && index >= 0 && index < currentGridItems.length) { - if (currentGridItems[index].isActive) { - currentGridItems[index].state = "active state"; + var buttonIndex = rowIndex * buttonsColumnsOnPage + columnIndex; + if (currentGridItems !== null && buttonIndex >= 0 && buttonIndex < currentGridItems.length) { + if (currentGridItems[buttonIndex].isActive) { + currentGridItems[buttonIndex].state = "active state"; } else { - currentGridItems[index].state = state; + currentGridItems[buttonIndex].state = state; } } } - function previousPage() { + function nextItem() { setCurrentItemState("base state"); - var currentPage = swipeView.currentIndex; - currentPage = currentPage - 1; - if (currentPage < 0) { - currentPage = swipeView.count - 1; - } - swipeView.currentIndex = currentPage; - } - - function nextPage() { - setCurrentItemState("base state"); - var currentPage = swipeView.currentIndex; - currentPage = currentPage + 1; - if (currentPage >= swipeView.count) { - currentPage = 0; - } - swipeView.currentIndex = currentPage; - } - - function nextItem() { - setCurrentItemState("base state"); - var currentGridItems = swipeView.currentItem.children[0].children; var nextColumnIndex = columnIndex + 1; - var index = rowIndex*buttonsColumnsOnPage + nextColumnIndex; - if(index >= currentGridItems.length || nextColumnIndex >= buttonsColumnsOnPage) { - nextColumnIndex = 0; + var index = rowIndex * buttonsColumnsOnPage + nextColumnIndex; + if (index >= currentGridItems.length || nextColumnIndex >= buttonsColumnsOnPage) { + if (swipeView.currentIndex < swipeView.count - 1) { + swipeView.incrementCurrentIndex(); + } else { + setCurrentItemState("hover state"); + } + return; } columnIndex = nextColumnIndex; setCurrentItemState("hover state"); @@ -332,17 +337,15 @@ Item { function previousItem() { setCurrentItemState("base state"); - var column = columnIndex; - column = column - 1; + var column = columnIndex - 1; - if (column < 0 ) { - column = buttonsColumnsOnPage - 1; - var index = rowIndex*buttonsColumnsOnPage + column; - var currentGridItems = swipeView.currentItem.children[0].children; - while(index >= currentGridItems.length) { - column = column - 1; - index = rowIndex*buttonsColumnsOnPage + column; + if (column < 0) { + if (swipeView.currentIndex > 0) { + swipeView.decrementCurrentIndex(); + } else { + setCurrentItemState("hover state"); } + return; } columnIndex = column; setCurrentItemState("hover state"); @@ -350,16 +353,14 @@ Item { function upItem() { setCurrentItemState("base state"); - var row = rowIndex; - row = row - 1; + var row = rowIndex - 1; if (row < 0 ) { row = buttonsRowsOnPage - 1; - var index = row*buttonsColumnsOnPage + columnIndex; - var currentGridItems = swipeView.currentItem.children[0].children; - while(index >= currentGridItems.length) { + var index = row * buttonsColumnsOnPage + columnIndex; + while (index >= currentGridItems.length) { row = row - 1; - index = row*buttonsColumnsOnPage + columnIndex; + index = row * buttonsColumnsOnPage + columnIndex; } } rowIndex = row; @@ -369,8 +370,7 @@ Item { function downItem() { setCurrentItemState("base state"); rowIndex = rowIndex + 1; - var currentGridItems = swipeView.currentItem.children[0].children; - var index = rowIndex*buttonsColumnsOnPage + columnIndex; + var index = rowIndex * buttonsColumnsOnPage + columnIndex; if (index >= currentGridItems.length) { rowIndex = 0; } @@ -379,7 +379,6 @@ Item { function selectItem() { var index = rowIndex*buttonsColumnsOnPage + columnIndex; - var currentGridItems = swipeView.currentItem.children[0].children; if (currentGridItems !== null && index >= 0 && index < currentGridItems.length) { currentGridItems[index].clicked(); if (tabletRoot) { @@ -388,33 +387,9 @@ Item { } } - Keys.onRightPressed: { - if (event.modifiers & Qt.ShiftModifier) { - nextPage(); - } else { - nextItem(); - } - } - Keys.onLeftPressed: { - if (event.modifiers & Qt.ShiftModifier) { - previousPage(); - } else { - previousItem(); - } - } - Keys.onDownPressed: { - if (event.modifiers & Qt.ShiftModifier) { - nextPage(); - } else { - downItem(); - } - } - Keys.onUpPressed: { - if (event.modifiers & Qt.ShiftModifier) { - previousPage(); - } else { - upItem(); - } - } + Keys.onRightPressed: nextItem(); + Keys.onLeftPressed: previousItem(); + Keys.onDownPressed: downItem(); + Keys.onUpPressed: upItem(); Keys.onReturnPressed: selectItem(); } diff --git a/libraries/ui/src/ui/TabletScriptingInterface.cpp b/libraries/ui/src/ui/TabletScriptingInterface.cpp index ec5392a82d..91e32c1468 100644 --- a/libraries/ui/src/ui/TabletScriptingInterface.cpp +++ b/libraries/ui/src/ui/TabletScriptingInterface.cpp @@ -1008,6 +1008,6 @@ void TabletButtonProxy::editProperties(const QVariantMap& properties) { } } -QQuickItem *TabletButtonProxy::getQmlButton() const { +QPointer TabletButtonProxy::getQmlButton() const { return _qmlButton; } diff --git a/libraries/ui/src/ui/TabletScriptingInterface.h b/libraries/ui/src/ui/TabletScriptingInterface.h index f7775e8709..d29b17b565 100644 --- a/libraries/ui/src/ui/TabletScriptingInterface.h +++ b/libraries/ui/src/ui/TabletScriptingInterface.h @@ -305,7 +305,7 @@ public: */ Q_INVOKABLE void editProperties(const QVariantMap& properties); - QQuickItem *getQmlButton() const; + QPointer getQmlButton() const; public slots: void clickedSlot() { emit clicked(); } @@ -321,7 +321,7 @@ signals: protected: QUuid _uuid; int _stableOrder; - QQuickItem* _qmlButton { nullptr }; + QPointer _qmlButton; QObject* _toolbarButtonProxy { nullptr }; QVariantMap _properties; }; From 38453afb3b604f44071acc7aea9097bd7ea3d1af Mon Sep 17 00:00:00 2001 From: vladest Date: Mon, 18 Dec 2017 14:56:33 +0100 Subject: [PATCH 15/29] Create pages and store in global array, makes sure it will not be cleared by garbage collector whe out of scope --- .../resources/qml/hifi/tablet/Tablet.qml | 41 ++++++++++++++----- 1 file changed, 31 insertions(+), 10 deletions(-) diff --git a/interface/resources/qml/hifi/tablet/Tablet.qml b/interface/resources/qml/hifi/tablet/Tablet.qml index 07f85bd747..e950c50deb 100644 --- a/interface/resources/qml/hifi/tablet/Tablet.qml +++ b/interface/resources/qml/hifi/tablet/Tablet.qml @@ -17,12 +17,13 @@ Item { readonly property int buttonsColumnsOnPage: 3 property var currentGridItems: null + property var gridPages: []; focus: true Timer { id: gridsRecreateTimer - interval: 50 + interval: 1 repeat: false onTriggered: { doRecreateGrids() @@ -32,34 +33,53 @@ Item { //fake invisible item for initial buttons creations Item { id: fakeParent - visible: parent + visible: false } function doRecreateGrids() { var tabletProxy = Tablet.getTablet("com.highfidelity.interface.tablet.system"); var tabletButtons = tabletProxy.getButtonsList(); - for (var i = 0; i < swipeView.count; i++) { - var gridOuter = swipeView.itemAt(i); - gridOuter.destroy(); + + if (tabletButtons.length <= 0) { + console.warn("Tablet buttons list is empty"); + return; + } + + for (var i = swipeView.count - 1; i >= 0; i--) { swipeView.removeItem(i); } + gridPages = []; + + swipeView.setCurrentIndex(-1); sortButtons(tabletButtons); + var pagesNum = Math.ceil(tabletButtons.length / 12); + var currentPage = 0; + gridPages.push(pageComponent.createObject(null)); + for (var buttonIndex = 0; buttonIndex < tabletButtons.length; buttonIndex++) { var button = tabletButtons[buttonIndex] if (button !== null) { - var grid = swipeView.itemAt(swipeView.count - 1); - if (grid === null || grid.children[0].children.length === buttonsOnPage) { - grid = pageComponent.createObject(swipeView); + var grid = gridPages[currentPage]; + if (grid.children[0].children.length === buttonsOnPage) { + gridPages.push(pageComponent.createObject(null)); + currentPage = currentPage + 1; + grid = gridPages[currentPage]; } button.row = Math.floor(grid.children[0].children.length / buttonsColumnsOnPage); button.column = grid.children[0].children.length % buttonsColumnsOnPage; //reparent to actual grid button.parent = grid.children[0]; grid.children[0].children.push(button); + } else { + console.warn("Button is null:", buttonIndex); } } - swipeView.currentIndex = 0; + for (var pageIndex = 0; pageIndex < gridPages.length; pageIndex++) { + swipeView.addItem(gridPages[pageIndex]); + } + + swipeView.setCurrentIndex(0); } // used to look up a button by its uuid @@ -244,9 +264,10 @@ Item { SwipeView { id: swipeView clip: false + currentIndex: -1 property int previousIndex: -1 - onCurrentItemChanged: { + onCurrentIndexChanged: { if (swipeView.currentIndex < 0 || swipeView.itemAt(swipeView.currentIndex) === null || swipeView.itemAt(swipeView.currentIndex).children[0] === null From 79f9b54f6a9cee31c1c0b32ee3f284fd40575fb7 Mon Sep 17 00:00:00 2001 From: vladest Date: Wed, 20 Dec 2017 22:59:07 +0100 Subject: [PATCH 16/29] Store button list in the resources section of fake item instead of C++ space --- .../resources/qml/hifi/tablet/Tablet.qml | 24 +++++----- .../ui/src/ui/TabletScriptingInterface.cpp | 44 +++---------------- .../ui/src/ui/TabletScriptingInterface.h | 12 +---- 3 files changed, 22 insertions(+), 58 deletions(-) diff --git a/interface/resources/qml/hifi/tablet/Tablet.qml b/interface/resources/qml/hifi/tablet/Tablet.qml index e950c50deb..42396073e9 100644 --- a/interface/resources/qml/hifi/tablet/Tablet.qml +++ b/interface/resources/qml/hifi/tablet/Tablet.qml @@ -30,21 +30,26 @@ Item { } } - //fake invisible item for initial buttons creations + //fake invisible item for initial buttons creations. + //Also used as a holder for buttons list Item { id: fakeParent visible: false } function doRecreateGrids() { - var tabletProxy = Tablet.getTablet("com.highfidelity.interface.tablet.system"); - var tabletButtons = tabletProxy.getButtonsList(); - if (tabletButtons.length <= 0) { - console.warn("Tablet buttons list is empty"); + if (fakeParent.resources.length <= 0) { + console.warn("Tablet buttons list is empty", fakeParent.resources.length); return; } + //copy buttons list to JS array to be able to sort it + var tabletButtons = []; + for (var btnIndex = 0; btnIndex < fakeParent.resources.length; btnIndex++) { + tabletButtons.push(fakeParent.resources[btnIndex]); + } + for (var i = swipeView.count - 1; i >= 0; i--) { swipeView.removeItem(i); } @@ -53,7 +58,6 @@ Item { swipeView.setCurrentIndex(-1); sortButtons(tabletButtons); - var pagesNum = Math.ceil(tabletButtons.length / 12); var currentPage = 0; gridPages.push(pageComponent.createObject(null)); @@ -87,10 +91,8 @@ Item { if (!uuid) { return -1; } - var tabletProxy = Tablet.getTablet("com.highfidelity.interface.tablet.system"); - var tabletButtons = tabletProxy.getButtonsList(); - for (var i in tabletButtons) { - var child = tabletButtons[i]; + for (var i in fakeParent.resources) { + var child = fakeParent.resources[i]; if (child.uuid === uuid) { return i; } @@ -129,6 +131,7 @@ Item { } button.flickable = swipeView.contentItem; tablet.count++ + fakeParent.resources.push(button); gridsRecreateTimer.restart(); return button; @@ -163,6 +166,7 @@ Item { console.log("Warning: Tablet.qml could not find button with uuid = " + properties.uuid); } else { tablet.count--; + fakeParent.resources[index] = null; //redraw grids gridsRecreateTimer.restart(); } diff --git a/libraries/ui/src/ui/TabletScriptingInterface.cpp b/libraries/ui/src/ui/TabletScriptingInterface.cpp index 91e32c1468..d91d746f09 100644 --- a/libraries/ui/src/ui/TabletScriptingInterface.cpp +++ b/libraries/ui/src/ui/TabletScriptingInterface.cpp @@ -716,11 +716,7 @@ TabletButtonProxy* TabletProxy::addButton(const QVariant& properties) { } auto tabletButtonProxy = QSharedPointer(new TabletButtonProxy(properties.toMap())); - { - QMutexLocker locker(&_tabletButtonsListMutex); - _tabletButtonProxies.push_back(tabletButtonProxy); - - } + _tabletButtonProxies.push_back(tabletButtonProxy); if (!_toolbarMode && _qmlTabletRoot) { auto tablet = getQmlTablet(); if (tablet) { @@ -768,10 +764,7 @@ void TabletProxy::removeButton(TabletButtonProxy* tabletButtonProxy) { return; } buttonProxy = *iter; - { - QMutexLocker locker(&_tabletButtonsListMutex); - _tabletButtonProxies.erase(iter); - } + _tabletButtonProxies.erase(iter); } if (!_toolbarMode && _qmlTabletRoot) { @@ -821,11 +814,8 @@ void TabletProxy::addButtonsToHomeScreen() { return; } - { - QMutexLocker locker(&_tabletButtonsListMutex); - for (auto& buttonProxy : _tabletButtonProxies) { - addButtonProxyToQmlTablet(tablet, buttonProxy.data()); - } + for (auto& buttonProxy : _tabletButtonProxies) { + addButtonProxyToQmlTablet(tablet, buttonProxy.data()); } auto loader = _qmlTabletRoot->findChild("loader"); QObject::disconnect(loader, SIGNAL(loaded()), this, SLOT(addButtonsToHomeScreen())); @@ -852,12 +842,9 @@ void TabletProxy::desktopWindowClosed() { void TabletProxy::addButtonsToToolbar() { Q_ASSERT(QThread::currentThread() == thread()); ToolbarProxy* toolbarProxy = DependencyManager::get()->getSystemToolbarProxy(); - { - QMutexLocker locker(&_tabletButtonsListMutex); - for (auto& buttonProxy : _tabletButtonProxies) { - // copy properties from tablet button proxy to toolbar button proxy. - buttonProxy->setToolbarButtonProxy(toolbarProxy->addButton(buttonProxy->getProperties())); - } + for (auto& buttonProxy : _tabletButtonProxies) { + // copy properties from tablet button proxy to toolbar button proxy. + buttonProxy->setToolbarButtonProxy(toolbarProxy->addButton(buttonProxy->getProperties())); } // make the toolbar visible @@ -914,19 +901,6 @@ QQuickItem* TabletProxy::getQmlMenu() const { return menuList; } -QList TabletProxy::getButtonsList() const { - QList buttonsList; - QMutexLocker locker(&_tabletButtonsListMutex); - - for (auto& buttonProxy : _tabletButtonProxies) { - if (buttonProxy->getQmlButton()) { - buttonsList.append(buttonProxy->getQmlButton()); - } - } - - return buttonsList; -} - // // TabletButtonProxy // @@ -1007,7 +981,3 @@ void TabletButtonProxy::editProperties(const QVariantMap& properties) { QMetaObject::invokeMethod(_toolbarButtonProxy, "editProperties", Qt::AutoConnection, Q_ARG(QVariantMap, properties)); } } - -QPointer TabletButtonProxy::getQmlButton() const { - return _qmlButton; -} diff --git a/libraries/ui/src/ui/TabletScriptingInterface.h b/libraries/ui/src/ui/TabletScriptingInterface.h index d29b17b565..ad6a7c8001 100644 --- a/libraries/ui/src/ui/TabletScriptingInterface.h +++ b/libraries/ui/src/ui/TabletScriptingInterface.h @@ -204,13 +204,6 @@ public: QQuickItem* getQmlMenu() const; - /**jsdoc - * Returns a list of currently created button items. - * @function TabletProxy#getButtonsList - * @returns {QList} - */ - Q_INVOKABLE QList getButtonsList() const; - signals: /**jsdoc * Signaled when this tablet receives an event from the html/js embedded in the tablet @@ -270,7 +263,6 @@ protected: std::pair _initialWebPathParams; bool _landscape { false }; bool _showRunningScripts { false }; - mutable QMutex _tabletButtonsListMutex; }; Q_DECLARE_METATYPE(TabletProxy*); @@ -305,8 +297,6 @@ public: */ Q_INVOKABLE void editProperties(const QVariantMap& properties); - QPointer getQmlButton() const; - public slots: void clickedSlot() { emit clicked(); } @@ -321,7 +311,7 @@ signals: protected: QUuid _uuid; int _stableOrder; - QPointer _qmlButton; + QQuickItem* _qmlButton { nullptr }; QObject* _toolbarButtonProxy { nullptr }; QVariantMap _properties; }; From 2bca0939b3cc68c66db0d9df6d12f093828ca920 Mon Sep 17 00:00:00 2001 From: vladest Date: Thu, 21 Dec 2017 19:32:13 +0100 Subject: [PATCH 17/29] Preliminary proxy model --- .../resources/qml/hifi/tablet/Tablet.qml | 420 ------------------ .../resources/qml/hifi/tablet/TabletHome.qml | 233 ++++++++-- interface/resources/qml/js/Utils.jsc | Bin 6596 -> 6274 bytes .../ui/src/ui/TabletScriptingInterface.cpp | 25 ++ .../ui/src/ui/TabletScriptingInterface.h | 25 ++ 5 files changed, 242 insertions(+), 461 deletions(-) delete mode 100644 interface/resources/qml/hifi/tablet/Tablet.qml diff --git a/interface/resources/qml/hifi/tablet/Tablet.qml b/interface/resources/qml/hifi/tablet/Tablet.qml deleted file mode 100644 index 42396073e9..0000000000 --- a/interface/resources/qml/hifi/tablet/Tablet.qml +++ /dev/null @@ -1,420 +0,0 @@ -import QtQuick 2.7 -import QtQuick.Controls 2.2 -import QtGraphicalEffects 1.0 -import QtQuick.Layouts 1.3 - -import "../../styles-uit" -import "../audio" as HifiAudio - -Item { - id: tablet - objectName: "tablet" - property int rowIndex: 6 // by default - property int columnIndex: 1 // point to 'go to location' - property int count: 0 - readonly property int buttonsOnPage: 12 - readonly property int buttonsRowsOnPage: 4 - readonly property int buttonsColumnsOnPage: 3 - - property var currentGridItems: null - property var gridPages: []; - - focus: true - - Timer { - id: gridsRecreateTimer - interval: 1 - repeat: false - onTriggered: { - doRecreateGrids() - } - } - - //fake invisible item for initial buttons creations. - //Also used as a holder for buttons list - Item { - id: fakeParent - visible: false - } - - function doRecreateGrids() { - - if (fakeParent.resources.length <= 0) { - console.warn("Tablet buttons list is empty", fakeParent.resources.length); - return; - } - - //copy buttons list to JS array to be able to sort it - var tabletButtons = []; - for (var btnIndex = 0; btnIndex < fakeParent.resources.length; btnIndex++) { - tabletButtons.push(fakeParent.resources[btnIndex]); - } - - for (var i = swipeView.count - 1; i >= 0; i--) { - swipeView.removeItem(i); - } - gridPages = []; - - swipeView.setCurrentIndex(-1); - sortButtons(tabletButtons); - - var currentPage = 0; - gridPages.push(pageComponent.createObject(null)); - - for (var buttonIndex = 0; buttonIndex < tabletButtons.length; buttonIndex++) { - var button = tabletButtons[buttonIndex] - if (button !== null) { - var grid = gridPages[currentPage]; - if (grid.children[0].children.length === buttonsOnPage) { - gridPages.push(pageComponent.createObject(null)); - currentPage = currentPage + 1; - grid = gridPages[currentPage]; - } - button.row = Math.floor(grid.children[0].children.length / buttonsColumnsOnPage); - button.column = grid.children[0].children.length % buttonsColumnsOnPage; - //reparent to actual grid - button.parent = grid.children[0]; - grid.children[0].children.push(button); - } else { - console.warn("Button is null:", buttonIndex); - } - } - for (var pageIndex = 0; pageIndex < gridPages.length; pageIndex++) { - swipeView.addItem(gridPages[pageIndex]); - } - - swipeView.setCurrentIndex(0); - } - - // used to look up a button by its uuid - function findButtonIndex(uuid) { - if (!uuid) { - return -1; - } - for (var i in fakeParent.resources) { - var child = fakeParent.resources[i]; - if (child.uuid === uuid) { - return i; - } - } - - return -1; - } - - function sortButtons(tabletButtons) { - tabletButtons.sort(function (a, b) { - if (a === null || b === null) { - return 0; - } - if (a.sortOrder === b.sortOrder) { - // subsort by stableOrder, because JS sort is not stable in qml. - return a.stableOrder - b.stableOrder; - } else { - return a.sortOrder - b.sortOrder; - } - }); - } - - function doAddButton(component, properties) { - var button = component.createObject(fakeParent); - - // copy all properites to button - var keys = Object.keys(properties).forEach(function (key) { - button[key] = properties[key]; - }); - - // pass a reference to the tabletRoot object to the button. - if (tabletRoot) { - button.tabletRoot = tabletRoot; - } else { - button.tabletRoot = parent.parent; - } - button.flickable = swipeView.contentItem; - tablet.count++ - fakeParent.resources.push(button); - gridsRecreateTimer.restart(); - - return button; - } - - Component { - id: pageComponent - Item { - Grid { - anchors { - fill: parent - topMargin: 20 - leftMargin: 30 - rightMargin: 30 - bottomMargin: 0 - } - rows: 4; columns: 3; rowSpacing: 16; columnSpacing: 16; - } - } - } - - // called by C++ code when a button should be added to the tablet - function addButtonProxy(properties) { - var component = Qt.createComponent("TabletButton.qml"); - return doAddButton(component, properties); - } - - // called by C++ code when a button should be removed from the tablet - function removeButtonProxy(properties) { - var index = findButtonIndex(properties.uuid); - if (index < 0) { - console.log("Warning: Tablet.qml could not find button with uuid = " + properties.uuid); - } else { - tablet.count--; - fakeParent.resources[index] = null; - //redraw grids - gridsRecreateTimer.restart(); - } - } - - Rectangle { - id: bgTopBar - height: 90 - - anchors { - top: parent.top - topMargin: 0 - left: parent.left - leftMargin: 0 - right: parent.right - rightMargin: 0 - } - - gradient: Gradient { - GradientStop { - position: 0 - color: "#2b2b2b" - } - - GradientStop { - position: 1 - color: "#1e1e1e" - } - } - - HifiAudio.MicBar { - anchors { - left: parent.left - leftMargin: 30 - verticalCenter: parent.verticalCenter - } - } - - Item { - width: 150 - height: 50 - anchors.right: parent.right - anchors.rightMargin: 30 - anchors.verticalCenter: parent.verticalCenter - - ColumnLayout { - anchors.fill: parent - - RalewaySemiBold { - text: Account.loggedIn ? qsTr("Log out") : qsTr("Log in") - horizontalAlignment: Text.AlignRight - anchors.right: parent.right - font.pixelSize: 20 - color: "#afafaf" - } - - RalewaySemiBold { - visible: Account.loggedIn - height: Account.loggedIn ? parent.height/2 - parent.spacing/2 : 0 - text: Account.loggedIn ? "[" + tabletRoot.usernameShort + "]" : "" - horizontalAlignment: Text.AlignRight - anchors.right: parent.right - font.pixelSize: 20 - color: "#afafaf" - } - } - - MouseArea { - anchors.fill: parent - onClicked: { - if (!Account.loggedIn) { - DialogsManager.showLoginDialog() - } else { - Account.logOut() - } - } - } - } - } - - Rectangle { - id: bgMain - gradient: Gradient { - GradientStop { - position: 0 - color: "#2b2b2b" - } - - GradientStop { - position: 1 - color: "#0f212e" - } - } - anchors.bottom: parent.bottom - anchors.right: parent.right - anchors.left: parent.left - anchors.top: bgTopBar.bottom - - SwipeView { - id: swipeView - clip: false - currentIndex: -1 - property int previousIndex: -1 - - onCurrentIndexChanged: { - if (swipeView.currentIndex < 0 - || swipeView.itemAt(swipeView.currentIndex) === null - || swipeView.itemAt(swipeView.currentIndex).children[0] === null - || swipeView.itemAt(swipeView.currentIndex).children[0].children === null) { - return; - } - - currentGridItems = swipeView.itemAt(swipeView.currentIndex).children[0].children; - - var row = rowIndex < 0 ? 0 : rowIndex; - var column = previousIndex > swipeView.currentIndex ? buttonsColumnsOnPage - 1 : 0; - var index = row * buttonsColumnsOnPage + column; - if (index < 0 || index >= currentGridItems.length) { - column = 0; - row = 0; - } - rowIndex = row; - columnIndex = column; - setCurrentItemState("hover state"); - previousIndex = currentIndex; - } - - hoverEnabled: true - anchors { - left: parent.left - right: parent.right - top: parent.top - bottom: pageIndicator.top - } - } - - PageIndicator { - id: pageIndicator - currentIndex: swipeView.currentIndex - - delegate: Item { - width: 15 - height: 15 - - Rectangle { - anchors.centerIn: parent - opacity: index === pageIndicator.currentIndex ? 0.95 : 0.45 - implicitWidth: index === pageIndicator.currentIndex ? 15 : 10 - implicitHeight: implicitWidth - radius: width/2 - color: "white" - Behavior on opacity { - OpacityAnimator { - duration: 100 - } - } - } - } - - interactive: false - anchors.bottom: parent.bottom - anchors.horizontalCenter: parent.horizontalCenter - count: swipeView.count - } - } - - function setCurrentItemState(state) { - var buttonIndex = rowIndex * buttonsColumnsOnPage + columnIndex; - if (currentGridItems !== null && buttonIndex >= 0 && buttonIndex < currentGridItems.length) { - if (currentGridItems[buttonIndex].isActive) { - currentGridItems[buttonIndex].state = "active state"; - } else { - currentGridItems[buttonIndex].state = state; - } - } - } - - function nextItem() { - setCurrentItemState("base state"); - var nextColumnIndex = columnIndex + 1; - var index = rowIndex * buttonsColumnsOnPage + nextColumnIndex; - if (index >= currentGridItems.length || nextColumnIndex >= buttonsColumnsOnPage) { - if (swipeView.currentIndex < swipeView.count - 1) { - swipeView.incrementCurrentIndex(); - } else { - setCurrentItemState("hover state"); - } - return; - } - columnIndex = nextColumnIndex; - setCurrentItemState("hover state"); - } - - function previousItem() { - setCurrentItemState("base state"); - var column = columnIndex - 1; - - if (column < 0) { - if (swipeView.currentIndex > 0) { - swipeView.decrementCurrentIndex(); - } else { - setCurrentItemState("hover state"); - } - return; - } - columnIndex = column; - setCurrentItemState("hover state"); - } - - function upItem() { - setCurrentItemState("base state"); - var row = rowIndex - 1; - - if (row < 0 ) { - row = buttonsRowsOnPage - 1; - var index = row * buttonsColumnsOnPage + columnIndex; - while (index >= currentGridItems.length) { - row = row - 1; - index = row * buttonsColumnsOnPage + columnIndex; - } - } - rowIndex = row; - setCurrentItemState("hover state"); - } - - function downItem() { - setCurrentItemState("base state"); - rowIndex = rowIndex + 1; - var index = rowIndex * buttonsColumnsOnPage + columnIndex; - if (index >= currentGridItems.length) { - rowIndex = 0; - } - setCurrentItemState("hover state"); - } - - function selectItem() { - var index = rowIndex*buttonsColumnsOnPage + columnIndex; - if (currentGridItems !== null && index >= 0 && index < currentGridItems.length) { - currentGridItems[index].clicked(); - if (tabletRoot) { - tabletRoot.playButtonClickSound(); - } - } - } - - Keys.onRightPressed: nextItem(); - Keys.onLeftPressed: previousItem(); - Keys.onDownPressed: downItem(); - Keys.onUpPressed: upItem(); - Keys.onReturnPressed: selectItem(); -} diff --git a/interface/resources/qml/hifi/tablet/TabletHome.qml b/interface/resources/qml/hifi/tablet/TabletHome.qml index 3f9451436c..4bacf078e7 100644 --- a/interface/resources/qml/hifi/tablet/TabletHome.qml +++ b/interface/resources/qml/hifi/tablet/TabletHome.qml @@ -1,4 +1,5 @@ -import QtQuick 2.5 +import QtQuick 2.7 +import QtQuick.Controls 2.2 import QtGraphicalEffects 1.0 import QtQuick.Layouts 1.3 @@ -10,7 +11,16 @@ Item { id: tablet objectName: "tablet" property var tabletProxy: Tablet.getTablet("com.highfidelity.interface.tablet.system"); - + + property int rowIndex: 6 // by default + property int columnIndex: 1 // point to 'go to location' + readonly property int buttonsOnPage: 12 + readonly property int buttonsRowsOnPage: 4 + readonly property int buttonsColumnsOnPage: 3 + + property var currentGridItems: null + property var gridPages: []; + Rectangle { id: bgTopBar height: 90 @@ -85,7 +95,6 @@ Item { Rectangle { id: bgMain - clip: true gradient: Gradient { GradientStop { position: 0 @@ -102,58 +111,200 @@ Item { anchors.left: parent.left anchors.top: bgTopBar.bottom - GridView { - id: flickable - anchors.top: parent.top - anchors.topMargin: 15 - anchors.bottom: parent.bottom - anchors.horizontalCenter: parent.horizontalCenter - width: cellWidth * 3 - cellHeight: 145 - cellWidth: 145 - model: tabletProxy.buttons - delegate: Item { - width: flickable.cellWidth - height: flickable.cellHeight - property var proxy: modelData + SwipeView { + id: swipeView + clip: false + currentIndex: -1 + property int previousIndex: -1 - TabletButton { - id: tabletButton - anchors.centerIn: parent - onClicked: modelData.clicked() - state: wrapper.GridView.isCurrentItem ? "hover state" : "base state" + Repeater { + id: pageRepeater + model: Math.ceil(tabletProxy.buttons.rowCount() / buttonsOnPage) + onCountChanged: console.warn("repeat count", count, tabletProxy.buttons.rowCount()) + onItemAdded: { + item.pageIndex = index } - Connections { - target: modelData; - onPropertiesChanged: { - updateProperties(); + delegate: Item { + id: page + property int pageIndex + onPageIndexChanged: console.warn("page index", pageIndex) + Grid { + anchors { + fill: parent + topMargin: 20 + leftMargin: 30 + rightMargin: 30 + bottomMargin: 0 + } + rows: 4; columns: 3; rowSpacing: 16; columnSpacing: 16; + Repeater { + id: buttonsRepeater + model: tabletProxy.buttons.rowCount() - (((page.pageIndex + 1) * buttonsOnPage) % buttonsOnPage) + delegate: Item { + id: wrapper + width: 129 + height: 129 + property var proxy: modelData + + TabletButton { + id: tabletButton + anchors.centerIn: parent + onClicked: modelData.clicked() + state: wrapper.GridView.isCurrentItem ? "hover state" : "base state" + } + + Connections { + target: modelData; + onPropertiesChanged: { + updateProperties(); + } + } + + Component.onCompleted: updateProperties() + + function updateProperties() { + var keys = Object.keys(modelData.properties).forEach(function (key) { + if (tabletButton[key] !== modelData.properties[key]) { + tabletButton[key] = modelData.properties[key]; + } + }); + } + } + } + Component.onCompleted: { +// tabletProxy.buttonsOnPage.setCurrentPage(page.index); +// buttonsRepeater.model = tabletProxy.buttonsOnPage; +// console.warn("buttons on page:", page.index, tabletProxy.buttonsOnPage.rowCount()) + } } } + } - Component.onCompleted: updateProperties() + onCurrentIndexChanged: { +// if (swipeView.currentIndex < 0 +// || swipeView.itemAt(swipeView.currentIndex) === null +// || swipeView.itemAt(swipeView.currentIndex).children[0] === null +// || swipeView.itemAt(swipeView.currentIndex).children[0].children === null) { +// return; +// } - function updateProperties() { - var keys = Object.keys(modelData.properties).forEach(function (key) { - if (tabletButton[key] !== modelData.properties[key]) { - tabletButton[key] = modelData.properties[key]; +// currentGridItems = swipeView.itemAt(swipeView.currentIndex).children[0].children; + +// var row = rowIndex < 0 ? 0 : rowIndex; +// var column = previousIndex > swipeView.currentIndex ? buttonsColumnsOnPage - 1 : 0; +// var index = row * buttonsColumnsOnPage + column; +// if (index < 0 || index >= currentGridItems.length) { +// column = 0; +// row = 0; +// } +// rowIndex = row; +// columnIndex = column; +// setCurrentItemState("hover state"); +// previousIndex = currentIndex; + } + + hoverEnabled: true + anchors { + left: parent.left + right: parent.right + top: parent.top + bottom: pageIndicator.top + } + } + + PageIndicator { + id: pageIndicator + currentIndex: swipeView.currentIndex + + delegate: Item { + width: 15 + height: 15 + + Rectangle { + anchors.centerIn: parent + opacity: index === pageIndicator.currentIndex ? 0.95 : 0.45 + implicitWidth: index === pageIndicator.currentIndex ? 15 : 10 + implicitHeight: implicitWidth + radius: width/2 + color: "white" + Behavior on opacity { + OpacityAnimator { + duration: 100 } - }); + } } } + + interactive: false + anchors.bottom: parent.bottom + anchors.horizontalCenter: parent.horizontalCenter + count: swipeView.count } +// GridView { +// id: flickable +// anchors.top: parent.top +// anchors.topMargin: 15 +// anchors.bottom: parent.bottom +// anchors.horizontalCenter: parent.horizontalCenter +// width: cellWidth * 3 +// cellHeight: 145 +// cellWidth: 145 +// flow: GridView.LeftToRight +// model: tabletProxy.buttons +// delegate: Item { +// width: flickable.cellWidth +// height: flickable.cellHeight +// property var proxy: modelData + +// TabletButton { +// id: tabletButton +// anchors.centerIn: parent +// onClicked: modelData.clicked() +// state: wrapper.GridView.isCurrentItem ? "hover state" : "base state" +// } + +// Connections { +// target: modelData; +// onPropertiesChanged: { +// updateProperties(); +// } +// } + +// Component.onCompleted: updateProperties() + +// function updateProperties() { +// var keys = Object.keys(modelData.properties).forEach(function (key) { +// if (tabletButton[key] !== modelData.properties[key]) { +// tabletButton[key] = modelData.properties[key]; +// } +// }); +// } +// } +// } } - Keys.onRightPressed: flickable.moveCurrentIndexRight(); - Keys.onLeftPressed: flickable.moveCurrentIndexLeft(); - Keys.onDownPressed: flickable.moveCurrentIndexDown(); - Keys.onUpPressed: flickable.moveCurrentIndexUp(); - Keys.onReturnPressed: { - if (flickable.currentItem) { - flickable.currentItem.proxy.clicked(); - if (tabletRoot) { - tabletRoot.playButtonClickSound(); + function setCurrentItemState(state) { + var buttonIndex = rowIndex * buttonsColumnsOnPage + columnIndex; + if (currentGridItems !== null && buttonIndex >= 0 && buttonIndex < currentGridItems.length) { + if (currentGridItems[buttonIndex].isActive) { + currentGridItems[buttonIndex].state = "active state"; + } else { + currentGridItems[buttonIndex].state = state; } } } + +// Keys.onRightPressed: flickable.moveCurrentIndexRight(); +// Keys.onLeftPressed: flickable.moveCurrentIndexLeft(); +// Keys.onDownPressed: flickable.moveCurrentIndexDown(); +// Keys.onUpPressed: flickable.moveCurrentIndexUp(); +// Keys.onReturnPressed: { +// if (flickable.currentItem) { +// flickable.currentItem.proxy.clicked(); +// if (tabletRoot) { +// tabletRoot.playButtonClickSound(); +// } +// } +// } } diff --git a/interface/resources/qml/js/Utils.jsc b/interface/resources/qml/js/Utils.jsc index ab20e996b9469915ac6a89901da175143e6b5024..eded46b485e5e9b6b6bb8f6c731dee09de5b40b5 100644 GIT binary patch literal 6274 zcmcIoUu;`f8UNYW85s<27+V>vj0!Ggsz$w`YMM}`#hEi~aHhbrsGUaFEOC~U{9EEy z=~N(H8WhV^_+hFH;=vD<=7&D`VL~PpD?mjj;Gx~R(N24qrcFww2xS(3sxfBtJLfys z_qx|fqli;gC-*zw{r>*G?|j$K9osiJG>{qi902RqHYDo#olk~<6K%k`zkINN;YSar zfAhw#FLv$z{O&ISxCb|`uLJlpfCFKm4M1L4&Nl63c{ckOTJtxKQKJ9TnVh6T8C`!sn&xm!7bL!vMVUrkukhWri9F-` zl`!yD82Bg*++hLxEFf+HeHJie0T~N8VF9Ns;Aa+a)&gF(fb$k`!236xPLJ&0mc38*UfH{4 ze^T~?=u+~gF^QupGCEH5FNH}AVgO@E<8fp#t!#c)*|$qD?TzPQ6~9r%|1Ct-zY!Jb zG@=-DrA5(?NAL(9LpS;m#WBn%U&d6FeuyZBkXD}aohghXjR|BB#Rx_*to}1g;w_PgKkcu_b~wnTe+mIhs;W2QDw0d}sExRuCl|ZqhFpCiFGH0U zYP;_D+O;=CpW;p>dAiT3R4G++Ey80xuZ4!PD*XtM^^S^x^Gk zL!-~GDZi|S^*&kO@ylvN!Y9k2EH~T9`L$kVHkCWNlFE&*r*i4*iTMk?Klo#VXZ3IO zdfnt4TgMZdWH6q3ayxo*-*2zQ?2fLETFm}z+^KkJcWGMLOWUPsrJmf5*u}2<8T~5T zmrg;+o6i48K#Hvx-V}yH>|)%xfL#{&$1<~!%*CAo5%UVIi#rvq_L6=o>!+(k({h#7 ztpe z0qO?+y&&3dq6Ykd6tz-b9F|nBJmtj?0#6N`T$=;1X&GE$Bil0mcPL#!_o25hN&hNp z+P%qKIFai-OdAV6(g;a;A8CrDMIULFq&Y8Xjvgknr<_?{#;S2@C39@=JeX=e;8zk4 zMw$-_a&Wl$fQ7|34(J0mSWfLa;gTaJrz38_zU%|LG|M?pS!jbjm7xul;^5obKuuWD z1RACZ>zY7=G~s$;$rPen%F-5ky*K_;gs#M$LgOMEPS_LDz>8W~emG(O_)_YD6>=84 zbA8T>v6CP2BCr?u`BRJ8d-|OGYA1l$??1d<%{aRmq|+yye5`(^9QKS4|FwYB11n0+ z>Zi$-i#vHkF?QrT$?!_eK6E)z`QhV8wV?VrA+n%nj)nc1o(w6rLeUNx4k zYqM(hfotA4;QYmRvdHcSQyt{tV#vie=$N+%hAuEZ{El z8Y)%U%bI)XqjGiln$jFcM23fbiAm;9GnBE&dn&K*&Sh`GaYW<`d2$uWRnT1g!NtAv zt_fFDvDpH8UZHzlT_vJSy`4J5SG<+P_@8y_)V#`)-t&(C)vwB{2HJ1e>;qT4z$mWj zY8H#dFaAX1T5PVGqNExfp2l>Oyd@E;RS*Ye5~d zV0yI|B8Bai`$Ui`_gWyTjNYp?yW`L7t~L89U(qWY8jx?eTMTx$*zE56LEY0-MY9bD zU-SBJ0HDy+;!7)MW^e%uAsh@A{Y}*xEHNX=onwQ*a<_0brrjX0{L@U%%;3ubU?~Sj zuiPBHb3qNe90Zm!RhU8EkM2n zXjl7O2dDtRuNCd{@)jY-)d!#zenqKY4sn&W{weu)twmlb!$4JTzv65rm+K1vDC#!F zU$|ZVIZ9zlW+S<`HL;hgR&M8~1sQiLyXg~6*Kx4qHtya=?){4Iz`gR%B^6)FqD(EX zPx0NgjXdr9YAbNP75KOnxYqy<89DFo`<=jA05hh+!CUJc)7q5K-I-U<4BwMhw#!Kold03qHB1qPh=(m57jV zQZO*TlsKpO<^4D&)ji|-UBpF<$-`KmCFTK~acFxKqv8qb`vJ}(jwnv6ynF{ogq(=F zep_Ap)wNGud)4)O>UtbUguEF{VOB&&#)x21=BI^yoeI;=cpet< z8yEavN0<0LF8)1^DU2eDE}X7EzTC=9#(VVvU%?VLXPX@E8u^tC$cdhzrY~ z5|TzSE|9{#2}}z<=It55SzSj%iNA*yHv6nZbjwP_N>*aF82-K7|F|4Z{3((gYY*l1 z1HmPNES&HK!VAmo!G#Z7%nSc2m&=jFSbJz;vopy0hR~Acw-O%(%P$^o0YVGQoxRBc zfA58N%nJ{-l0bHGCbwg^#q(qrrDi+!w<_$cdfT#JQtVa6B|0HZKTvD>SPT8{3FK*i zWU(iZU!oSteUbW{j!MrrowDh%hwMA*Wz%5~+1G_Km+UHco!!3?d2`uawWQAO`Fhz^ zFY9DKQ7^k1!8+Li%B~H>BZmbX7dAVWSkh#gI3&0r zaF0rAW;@0YRTR^~w|fH1=rq7T1!gIn>dAFt!Sy*C45#|hZ zyKMQfPE=zR8BZ12Iu&e;jZ`qZ;(XBNe0X7VdI#CX&hyK$=>L{qIw{h|R_2l4RI7AY z^-G-Fg*Pl@c)U6&I`)6~vWKqD3?b!JxCu1uN`cA?Q-i-75ra?*w4> z7DLeZEXfck*xy13exhOT)~XM$^JKYWuGBjYFUK{J-kQV9*AmCcI=9Ipz3t&zt&~o& zbp5o=j@d0M5iMDXSkX$%t~YJ^dxYvnP2X7@RT0fd+JSJgHI(cgqRD9&=_E-h7ipTL zi!Ra}N%Kz9JRJ@v&Ijf=afs?ImCUopaAUf5Bc(P@)^4QL#!&4B4=hC;lN+q^_W+Q1 zP^n|i{5|@(6kNweRp@!g!IB0$&XzP(9WOq8UKl6|MM0Czbbp-MJtdAmS4|C?43SDf)z9}dNlLtGo5xl*UM-i)V9TyEvOFWw5I(m_-&8|fx011{`>NNH;(6Df(rr#QsN>-}$CJna|wOpzoRcq-Fq`bAH8fghvwNyJ`N_RlpJYiGQZuHu}HZ5Pa zdE8c|q5`8P==g;$uId?L_>-ZdTT7Ja(9^jWIyw}4%`oqUj`vkn%QKo+>hkt%Am^R8 zT%)}GyrqJUtqMAFDsNlV@= _currentPage*12 && sourceRow < _currentPage*12); +} + +bool TabletButtonsProxyModel::lessThan(const QModelIndex &left, + const QModelIndex &right) const { + return true; +} + TabletScriptingInterface::TabletScriptingInterface() { qmlRegisterType("TabletScriptingInterface", 1, 0, "TabletEnums"); + qmlRegisterType("TabletScriptingInterface", 1, 0, "TabletButtonsProxyModel"); } TabletScriptingInterface::~TabletScriptingInterface() { @@ -276,6 +300,7 @@ TabletProxy::TabletProxy(QObject* parent, const QString& name) : QObject(parent) qCWarning(uiLogging) << "Creating tablet proxy on wrong thread " << _name; } connect(this, &TabletProxy::tabletShownChanged, this, &TabletProxy::onTabletShown); + _buttonsProxy.setSourceModel(&_buttons); } TabletProxy::~TabletProxy() { diff --git a/libraries/ui/src/ui/TabletScriptingInterface.h b/libraries/ui/src/ui/TabletScriptingInterface.h index d24b3b6947..1fa1165a02 100644 --- a/libraries/ui/src/ui/TabletScriptingInterface.h +++ b/libraries/ui/src/ui/TabletScriptingInterface.h @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -118,6 +119,26 @@ protected: Q_DECLARE_METATYPE(TabletButtonListModel*); +class TabletButtonsProxyModel : public QSortFilterProxyModel +{ + Q_OBJECT + +public: + TabletButtonsProxyModel(QObject *parent = 0); + + int currentPage() const; + Q_INVOKABLE void setCurrentPage(int currentPage); + +protected: + bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override; + bool lessThan(const QModelIndex &left, const QModelIndex &right) const override; + +private: + int _currentPage; +}; + +Q_DECLARE_METATYPE(TabletButtonsProxyModel*); + /**jsdoc * @class TabletProxy * @property name {string} READ_ONLY: name of this tablet @@ -131,6 +152,7 @@ class TabletProxy : public QObject { Q_PROPERTY(bool landscape READ getLandscape WRITE setLandscape) Q_PROPERTY(bool tabletShown MEMBER _tabletShown NOTIFY tabletShownChanged) Q_PROPERTY(TabletButtonListModel* buttons READ getButtons CONSTANT) + Q_PROPERTY(TabletButtonsProxyModel* buttonsOnPage READ getButtonsOnPage CONSTANT) public: TabletProxy(QObject* parent, const QString& name); ~TabletProxy(); @@ -234,6 +256,8 @@ public: QQuickItem* getQmlMenu() const; TabletButtonListModel* getButtons() { return &_buttons; } + TabletButtonsProxyModel* getButtonsOnPage() { return &_buttonsProxy; } + signals: /**jsdoc * Signaled when this tablet receives an event from the html/js embedded in the tablet @@ -293,6 +317,7 @@ protected: bool _showRunningScripts { false }; TabletButtonListModel _buttons; + TabletButtonsProxyModel _buttonsProxy; }; Q_DECLARE_METATYPE(TabletProxy*); From a1a752743acb5ceaf240ba873b992e9b3dcc0a77 Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Fri, 22 Dec 2017 13:57:28 -0800 Subject: [PATCH 18/29] fix issue --- libraries/entities/src/EntityItem.cpp | 35 +++++++++---------- .../dressing_room/.#doppelganger.js | 1 + 2 files changed, 18 insertions(+), 18 deletions(-) create mode 100644 script-archive/dressing_room/.#doppelganger.js diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 271fef33c8..87dbc23611 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -2071,9 +2071,25 @@ bool EntityItem::removeActionInternal(const QUuid& actionID, EntitySimulationPoi } EntityDynamicPointer action = _objectActions[actionID]; - + auto removedActionType = action->getType(); + if ((removedActionType == DYNAMIC_TYPE_HOLD || removedActionType == DYNAMIC_TYPE_FAR_GRAB) && !stillHasGrabActions()) { + _dirtyFlags &= ~Simulation::NO_BOOTSTRAPPING; + _dirtyFlags |= Simulation::DIRTY_COLLISION_GROUP; // may need to not collide with own avatar + forEachDescendant([&](SpatiallyNestablePointer child) { + if (child->getNestableType() == NestableType::Entity) { + EntityItemPointer entity = std::static_pointer_cast(child); + entity->markDirtyFlags(Simulation::DIRTY_COLLISION_GROUP); + entity->clearDirtyFlags(Simulation::NO_BOOTSTRAPPING); + } + }); + } else { + // NO-OP: we assume NO_BOOTSTRAPPING bits and collision group are correct + // because they should have been set correctly when the action was added + // and/or when children were linked + } action->setOwnerEntity(nullptr); action->setIsMine(false); + _objectActions.remove(actionID); if (simulation) { action->removeFromSimulation(simulation); @@ -2082,23 +2098,6 @@ bool EntityItem::removeActionInternal(const QUuid& actionID, EntitySimulationPoi bool success = true; serializeActions(success, _allActionsDataCache); _dirtyFlags |= Simulation::DIRTY_PHYSICS_ACTIVATION; - auto removedActionType = action->getType(); - if ((removedActionType == DYNAMIC_TYPE_HOLD || removedActionType == DYNAMIC_TYPE_FAR_GRAB) && !stillHasGrabActions()) { - _dirtyFlags &= ~Simulation::NO_BOOTSTRAPPING; - _dirtyFlags |= Simulation::DIRTY_COLLISION_GROUP; // may need to not collide with own avatar - forEachDescendant([&](SpatiallyNestablePointer child) { - if (child->getNestableType() == NestableType::Entity) { - EntityItemPointer entity = std::static_pointer_cast(child); - entity->markDirtyFlags(Simulation::DIRTY_COLLISION_GROUP); - entity->clearDirtyFlags(Simulation::NO_BOOTSTRAPPING); - } - }); - } else { - // NO-OP: we assume NO_BOOTSTRAPPING bits and collision group are correct - // because they should have been set correctly when the action was added - // and/or when children were linked - } - _objectActions.remove(actionID); setDynamicDataNeedsTransmit(true); return success; } diff --git a/script-archive/dressing_room/.#doppelganger.js b/script-archive/dressing_room/.#doppelganger.js new file mode 100644 index 0000000000..e212fd31a7 --- /dev/null +++ b/script-archive/dressing_room/.#doppelganger.js @@ -0,0 +1 @@ +dante@0228-DESKTOP-PC.36668:1512668335 \ No newline at end of file From d74f7f846cbad243b9dd6bf83bee6997599a1abe Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Fri, 22 Dec 2017 13:58:42 -0800 Subject: [PATCH 19/29] delete dot file --- script-archive/dressing_room/.#doppelganger.js | 1 - 1 file changed, 1 deletion(-) delete mode 100644 script-archive/dressing_room/.#doppelganger.js diff --git a/script-archive/dressing_room/.#doppelganger.js b/script-archive/dressing_room/.#doppelganger.js deleted file mode 100644 index e212fd31a7..0000000000 --- a/script-archive/dressing_room/.#doppelganger.js +++ /dev/null @@ -1 +0,0 @@ -dante@0228-DESKTOP-PC.36668:1512668335 \ No newline at end of file From fe61d7efc75854b09d5eee3ffd0107abb52f29e1 Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Fri, 22 Dec 2017 14:13:04 -0800 Subject: [PATCH 20/29] fix spacing --- libraries/entities/src/EntityItem.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 87dbc23611..b60220c1bc 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -2076,12 +2076,12 @@ bool EntityItem::removeActionInternal(const QUuid& actionID, EntitySimulationPoi _dirtyFlags &= ~Simulation::NO_BOOTSTRAPPING; _dirtyFlags |= Simulation::DIRTY_COLLISION_GROUP; // may need to not collide with own avatar forEachDescendant([&](SpatiallyNestablePointer child) { - if (child->getNestableType() == NestableType::Entity) { - EntityItemPointer entity = std::static_pointer_cast(child); - entity->markDirtyFlags(Simulation::DIRTY_COLLISION_GROUP); - entity->clearDirtyFlags(Simulation::NO_BOOTSTRAPPING); - } - }); + if (child->getNestableType() == NestableType::Entity) { + EntityItemPointer entity = std::static_pointer_cast(child); + entity->markDirtyFlags(Simulation::DIRTY_COLLISION_GROUP); + entity->clearDirtyFlags(Simulation::NO_BOOTSTRAPPING); + } + }); } else { // NO-OP: we assume NO_BOOTSTRAPPING bits and collision group are correct // because they should have been set correctly when the action was added From a497047666a676f21c3d2b8ad1d3714c4e2f0024 Mon Sep 17 00:00:00 2001 From: vladest Date: Sat, 23 Dec 2017 17:44:26 +0100 Subject: [PATCH 21/29] Refactored using new GridView approach --- .../resources/qml/hifi/tablet/TabletHome.qml | 216 ++++++++---------- .../ui/src/ui/TabletScriptingInterface.cpp | 22 +- .../ui/src/ui/TabletScriptingInterface.h | 18 +- 3 files changed, 123 insertions(+), 133 deletions(-) diff --git a/interface/resources/qml/hifi/tablet/TabletHome.qml b/interface/resources/qml/hifi/tablet/TabletHome.qml index 4bacf078e7..382e1f3f1e 100644 --- a/interface/resources/qml/hifi/tablet/TabletHome.qml +++ b/interface/resources/qml/hifi/tablet/TabletHome.qml @@ -3,6 +3,8 @@ import QtQuick.Controls 2.2 import QtGraphicalEffects 1.0 import QtQuick.Layouts 1.3 +import TabletScriptingInterface 1.0 + import "." import "../../styles-uit" import "../audio" as HifiAudio @@ -14,12 +16,10 @@ Item { property int rowIndex: 6 // by default property int columnIndex: 1 // point to 'go to location' - readonly property int buttonsOnPage: 12 - readonly property int buttonsRowsOnPage: 4 - readonly property int buttonsColumnsOnPage: 3 property var currentGridItems: null - property var gridPages: []; + + focus: true Rectangle { id: bgTopBar @@ -116,20 +116,21 @@ Item { clip: false currentIndex: -1 property int previousIndex: -1 - Repeater { id: pageRepeater - model: Math.ceil(tabletProxy.buttons.rowCount() / buttonsOnPage) - onCountChanged: console.warn("repeat count", count, tabletProxy.buttons.rowCount()) + model: Math.ceil(tabletProxy.buttons.rowCount() / TabletEnums.ButtonsOnPage) onItemAdded: { - item.pageIndex = index + item.proxyModel.sourceModel = tabletProxy.buttons; + item.proxyModel.pageIndex = index; } delegate: Item { id: page - property int pageIndex - onPageIndexChanged: console.warn("page index", pageIndex) - Grid { + property TabletButtonsProxyModel proxyModel: TabletButtonsProxyModel {} + + GridView { + id: flickable + keyNavigationEnabled: false anchors { fill: parent topMargin: 20 @@ -137,71 +138,57 @@ Item { rightMargin: 30 bottomMargin: 0 } - rows: 4; columns: 3; rowSpacing: 16; columnSpacing: 16; - Repeater { - id: buttonsRepeater - model: tabletProxy.buttons.rowCount() - (((page.pageIndex + 1) * buttonsOnPage) % buttonsOnPage) - delegate: Item { - id: wrapper - width: 129 - height: 129 - property var proxy: modelData + cellWidth: width/3 + cellHeight: cellWidth + flow: GridView.LeftToRight + model: page.proxyModel - TabletButton { - id: tabletButton - anchors.centerIn: parent - onClicked: modelData.clicked() - state: wrapper.GridView.isCurrentItem ? "hover state" : "base state" - } + delegate: Item { + id: wrapper + width: flickable.cellWidth + height: flickable.cellHeight - Connections { - target: modelData; - onPropertiesChanged: { - updateProperties(); - } - } + property var proxy: modelData - Component.onCompleted: updateProperties() + TabletButton { + id: tabletButton + anchors.centerIn: parent + onClicked: modelData.clicked() + state: wrapper.GridView.isCurrentItem ? "hover state" : "base state" + } - function updateProperties() { - var keys = Object.keys(modelData.properties).forEach(function (key) { - if (tabletButton[key] !== modelData.properties[key]) { - tabletButton[key] = modelData.properties[key]; - } - }); + Connections { + target: modelData; + onPropertiesChanged: { + updateProperties(); } } - } - Component.onCompleted: { -// tabletProxy.buttonsOnPage.setCurrentPage(page.index); -// buttonsRepeater.model = tabletProxy.buttonsOnPage; -// console.warn("buttons on page:", page.index, tabletProxy.buttonsOnPage.rowCount()) + + Component.onCompleted: updateProperties() + + function updateProperties() { + var keys = Object.keys(modelData.properties).forEach(function (key) { + if (tabletButton[key] !== modelData.properties[key]) { + tabletButton[key] = modelData.properties[key]; + } + }); + } } } } } onCurrentIndexChanged: { -// if (swipeView.currentIndex < 0 -// || swipeView.itemAt(swipeView.currentIndex) === null -// || swipeView.itemAt(swipeView.currentIndex).children[0] === null -// || swipeView.itemAt(swipeView.currentIndex).children[0].children === null) { -// return; -// } + if (swipeView.currentIndex < 0 + || swipeView.itemAt(swipeView.currentIndex) === null + || swipeView.itemAt(swipeView.currentIndex).children[0] === null) { + return; + } -// currentGridItems = swipeView.itemAt(swipeView.currentIndex).children[0].children; + currentGridItems = swipeView.itemAt(swipeView.currentIndex).children[0]; -// var row = rowIndex < 0 ? 0 : rowIndex; -// var column = previousIndex > swipeView.currentIndex ? buttonsColumnsOnPage - 1 : 0; -// var index = row * buttonsColumnsOnPage + column; -// if (index < 0 || index >= currentGridItems.length) { -// column = 0; -// row = 0; -// } -// rowIndex = row; -// columnIndex = column; -// setCurrentItemState("hover state"); -// previousIndex = currentIndex; + currentGridItems.currentIndex = (previousIndex > swipeView.currentIndex ? currentGridItems.count - 1 : 0); + previousIndex = currentIndex; } hoverEnabled: true @@ -241,70 +228,61 @@ Item { anchors.horizontalCenter: parent.horizontalCenter count: swipeView.count } -// GridView { -// id: flickable -// anchors.top: parent.top -// anchors.topMargin: 15 -// anchors.bottom: parent.bottom -// anchors.horizontalCenter: parent.horizontalCenter -// width: cellWidth * 3 -// cellHeight: 145 -// cellWidth: 145 -// flow: GridView.LeftToRight -// model: tabletProxy.buttons -// delegate: Item { -// width: flickable.cellWidth -// height: flickable.cellHeight -// property var proxy: modelData + } -// TabletButton { -// id: tabletButton -// anchors.centerIn: parent -// onClicked: modelData.clicked() -// state: wrapper.GridView.isCurrentItem ? "hover state" : "base state" -// } - -// Connections { -// target: modelData; -// onPropertiesChanged: { -// updateProperties(); -// } -// } - -// Component.onCompleted: updateProperties() - -// function updateProperties() { -// var keys = Object.keys(modelData.properties).forEach(function (key) { -// if (tabletButton[key] !== modelData.properties[key]) { -// tabletButton[key] = modelData.properties[key]; -// } -// }); -// } + function setCurrentItemState(state) { +// var buttonIndex = rowIndex * TabletEnums.ButtonsColumnsOnPage + columnIndex; +// if (currentGridItems !== null && buttonIndex >= 0 && buttonIndex < currentGridItems.length) { +// if (currentGridItems[buttonIndex].isActive) { +// currentGridItems[buttonIndex].state = "active state"; +// } else { +// currentGridItems[buttonIndex].state = state; // } // } } - function setCurrentItemState(state) { - var buttonIndex = rowIndex * buttonsColumnsOnPage + columnIndex; - if (currentGridItems !== null && buttonIndex >= 0 && buttonIndex < currentGridItems.length) { - if (currentGridItems[buttonIndex].isActive) { - currentGridItems[buttonIndex].state = "active state"; - } else { - currentGridItems[buttonIndex].state = state; + Component.onCompleted: { + focus = true; + forceActiveFocus(); + } + + Keys.onRightPressed: { + if (!currentGridItems) { + return; + } + + var index = currentGridItems.currentIndex; + currentGridItems.moveCurrentIndexRight(); + console.warn("onRightPressed", index, currentGridItems.currentIndex, currentGridItems.count) + if (index === currentGridItems.count - 1 && index === currentGridItems.currentIndex) { + if (swipeView.currentIndex < swipeView.count - 1) { + swipeView.incrementCurrentIndex(); } } } -// Keys.onRightPressed: flickable.moveCurrentIndexRight(); -// Keys.onLeftPressed: flickable.moveCurrentIndexLeft(); -// Keys.onDownPressed: flickable.moveCurrentIndexDown(); -// Keys.onUpPressed: flickable.moveCurrentIndexUp(); -// Keys.onReturnPressed: { -// if (flickable.currentItem) { -// flickable.currentItem.proxy.clicked(); -// if (tabletRoot) { -// tabletRoot.playButtonClickSound(); -// } -// } -// } + Keys.onLeftPressed: { + if (!currentGridItems) { + return; + } + + var index = currentGridItems.currentIndex; + currentGridItems.moveCurrentIndexLeft(); + console.warn("onLeftPressed", index, currentGridItems.currentIndex, currentGridItems.count) + if (index === 0 && index === currentGridItems.currentIndex) { + if (swipeView.currentIndex > 0) { + swipeView.decrementCurrentIndex(); + } + } + } + Keys.onDownPressed: currentGridItems.moveCurrentIndexDown(); + Keys.onUpPressed: currentGridItems.moveCurrentIndexUp(); + Keys.onReturnPressed: { + if (currentGridItems.currentItem) { + currentGridItems.currentItem.proxy.clicked(); + if (tabletRoot) { + tabletRoot.playButtonClickSound(); + } + } + } } diff --git a/libraries/ui/src/ui/TabletScriptingInterface.cpp b/libraries/ui/src/ui/TabletScriptingInterface.cpp index d192f4a7bc..5e5b3f83ea 100644 --- a/libraries/ui/src/ui/TabletScriptingInterface.cpp +++ b/libraries/ui/src/ui/TabletScriptingInterface.cpp @@ -93,21 +93,28 @@ void TabletButtonListModel::removeButton(TabletButtonProxy* button) { } TabletButtonsProxyModel::TabletButtonsProxyModel(QObject *parent) - : QSortFilterProxyModel(parent){ + : QSortFilterProxyModel(parent), _pageIndex(-1) { } -int TabletButtonsProxyModel::currentPage() const { - return _currentPage; +int TabletButtonsProxyModel::pageIndex() const { + return _pageIndex; } -void TabletButtonsProxyModel::setCurrentPage(int currentPage) { - _currentPage = currentPage; +void TabletButtonsProxyModel::setPageIndex(int pageIndex) +{ + if (_pageIndex == pageIndex) + return; + + _pageIndex = pageIndex; invalidateFilter(); + emit pageIndexChanged(_pageIndex); } bool TabletButtonsProxyModel::filterAcceptsRow(int sourceRow, - const QModelIndex &sourceParent) const { - return (sourceRow >= _currentPage*12 && sourceRow < _currentPage*12); + const QModelIndex &sourceParent) const { + Q_UNUSED(sourceParent); + return (sourceRow >= _pageIndex*TabletScriptingInterface::ButtonsOnPage + && sourceRow < (_pageIndex + 1)*TabletScriptingInterface::ButtonsOnPage); } bool TabletButtonsProxyModel::lessThan(const QModelIndex &left, @@ -300,7 +307,6 @@ TabletProxy::TabletProxy(QObject* parent, const QString& name) : QObject(parent) qCWarning(uiLogging) << "Creating tablet proxy on wrong thread " << _name; } connect(this, &TabletProxy::tabletShownChanged, this, &TabletProxy::onTabletShown); - _buttonsProxy.setSourceModel(&_buttons); } TabletProxy::~TabletProxy() { diff --git a/libraries/ui/src/ui/TabletScriptingInterface.h b/libraries/ui/src/ui/TabletScriptingInterface.h index 1fa1165a02..a69bcd2f75 100644 --- a/libraries/ui/src/ui/TabletScriptingInterface.h +++ b/libraries/ui/src/ui/TabletScriptingInterface.h @@ -47,6 +47,10 @@ public: enum TabletAudioEvents { ButtonClick, ButtonHover, TabletOpen, TabletHandsIn, TabletHandsOut, Last}; Q_ENUM(TabletAudioEvents) + //Different useful constants + enum TabletConstants { ButtonsColumnsOnPage = 3, ButtonsRowsOnPage = 4, ButtonsOnPage = 12 }; + Q_ENUM(TabletConstants) + TabletScriptingInterface(); virtual ~TabletScriptingInterface(); static const QString QML; @@ -123,18 +127,23 @@ class TabletButtonsProxyModel : public QSortFilterProxyModel { Q_OBJECT + Q_PROPERTY(int pageIndex READ pageIndex WRITE setPageIndex NOTIFY pageIndexChanged) public: TabletButtonsProxyModel(QObject *parent = 0); + int pageIndex() const; - int currentPage() const; - Q_INVOKABLE void setCurrentPage(int currentPage); +public slots: + void setPageIndex(int pageIndex); + +signals: + void pageIndexChanged(int pageIndex); protected: bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override; bool lessThan(const QModelIndex &left, const QModelIndex &right) const override; private: - int _currentPage; + int _pageIndex; }; Q_DECLARE_METATYPE(TabletButtonsProxyModel*); @@ -152,7 +161,6 @@ class TabletProxy : public QObject { Q_PROPERTY(bool landscape READ getLandscape WRITE setLandscape) Q_PROPERTY(bool tabletShown MEMBER _tabletShown NOTIFY tabletShownChanged) Q_PROPERTY(TabletButtonListModel* buttons READ getButtons CONSTANT) - Q_PROPERTY(TabletButtonsProxyModel* buttonsOnPage READ getButtonsOnPage CONSTANT) public: TabletProxy(QObject* parent, const QString& name); ~TabletProxy(); @@ -256,7 +264,6 @@ public: QQuickItem* getQmlMenu() const; TabletButtonListModel* getButtons() { return &_buttons; } - TabletButtonsProxyModel* getButtonsOnPage() { return &_buttonsProxy; } signals: /**jsdoc @@ -317,7 +324,6 @@ protected: bool _showRunningScripts { false }; TabletButtonListModel _buttons; - TabletButtonsProxyModel _buttonsProxy; }; Q_DECLARE_METATYPE(TabletProxy*); From cb7472c27026856b742beea8206e54ca4a8a7f8e Mon Sep 17 00:00:00 2001 From: vladest Date: Mon, 25 Dec 2017 20:14:31 +0100 Subject: [PATCH 22/29] Selection consistency #1 --- .../resources/qml/hifi/tablet/TabletHome.qml | 51 ++++++++++++++----- 1 file changed, 37 insertions(+), 14 deletions(-) diff --git a/interface/resources/qml/hifi/tablet/TabletHome.qml b/interface/resources/qml/hifi/tablet/TabletHome.qml index 382e1f3f1e..5cf27151a7 100644 --- a/interface/resources/qml/hifi/tablet/TabletHome.qml +++ b/interface/resources/qml/hifi/tablet/TabletHome.qml @@ -129,8 +129,10 @@ Item { property TabletButtonsProxyModel proxyModel: TabletButtonsProxyModel {} GridView { - id: flickable + id: gridView keyNavigationEnabled: false + highlightFollowsCurrentItem: false + property int previousGridIndex: -1 anchors { fill: parent topMargin: 20 @@ -138,6 +140,25 @@ Item { rightMargin: 30 bottomMargin: 0 } + + function setButtonState(buttonIndex) { + var itemat = gridView.contentItem.children[buttonIndex]; + if (itemat.isActive) { + itemat.state = "active state"; + } else { + itemat.state = state; + } + } + + onCurrentIndexChanged: { + setButtonState(previousGridIndex) + rowIndex = Math.floor(currentIndex / TabletEnums.ButtonsColumnsOnPage); + columnIndex = currentIndex % TabletEnums.ButtonsColumnsOnPage + console.warn("current index", currentIndex, rowIndex, columnIndex) + setButtonState(currentIndex) + previousGridIndex = currentIndex + } + cellWidth: width/3 cellHeight: cellWidth flow: GridView.LeftToRight @@ -145,16 +166,20 @@ Item { delegate: Item { id: wrapper - width: flickable.cellWidth - height: flickable.cellHeight + width: gridView.cellWidth + height: gridView.cellHeight property var proxy: modelData TabletButton { id: tabletButton anchors.centerIn: parent + flickable: swipeView.contentItem; onClicked: modelData.clicked() - state: wrapper.GridView.isCurrentItem ? "hover state" : "base state" + onStateChanged: console.warn("state", state, uuid) +// Component.onCompleted: { +// state = Qt.binding(function() { return wrapper.GridView.isCurrentItem ? "hover state" : "base state"; }); +// } } Connections { @@ -231,14 +256,14 @@ Item { } function setCurrentItemState(state) { -// var buttonIndex = rowIndex * TabletEnums.ButtonsColumnsOnPage + columnIndex; -// if (currentGridItems !== null && buttonIndex >= 0 && buttonIndex < currentGridItems.length) { -// if (currentGridItems[buttonIndex].isActive) { -// currentGridItems[buttonIndex].state = "active state"; -// } else { -// currentGridItems[buttonIndex].state = state; -// } -// } + var buttonIndex = rowIndex * TabletEnums.ButtonsColumnsOnPage + columnIndex; + if (currentGridItems !== null && buttonIndex >= 0 && buttonIndex < currentGridItems.length) { + if (currentGridItems[buttonIndex].isActive) { + currentGridItems[buttonIndex].state = "active state"; + } else { + currentGridItems[buttonIndex].state = state; + } + } } Component.onCompleted: { @@ -253,7 +278,6 @@ Item { var index = currentGridItems.currentIndex; currentGridItems.moveCurrentIndexRight(); - console.warn("onRightPressed", index, currentGridItems.currentIndex, currentGridItems.count) if (index === currentGridItems.count - 1 && index === currentGridItems.currentIndex) { if (swipeView.currentIndex < swipeView.count - 1) { swipeView.incrementCurrentIndex(); @@ -268,7 +292,6 @@ Item { var index = currentGridItems.currentIndex; currentGridItems.moveCurrentIndexLeft(); - console.warn("onLeftPressed", index, currentGridItems.currentIndex, currentGridItems.count) if (index === 0 && index === currentGridItems.currentIndex) { if (swipeView.currentIndex > 0) { swipeView.decrementCurrentIndex(); From ffcccacfa589cc76f18c06655c2f984e7b01367f Mon Sep 17 00:00:00 2001 From: vladest Date: Mon, 25 Dec 2017 23:46:06 +0100 Subject: [PATCH 23/29] Selection consistency #2 --- .../resources/qml/hifi/tablet/TabletHome.qml | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/interface/resources/qml/hifi/tablet/TabletHome.qml b/interface/resources/qml/hifi/tablet/TabletHome.qml index 5cf27151a7..0b450cc2e7 100644 --- a/interface/resources/qml/hifi/tablet/TabletHome.qml +++ b/interface/resources/qml/hifi/tablet/TabletHome.qml @@ -141,21 +141,27 @@ Item { bottomMargin: 0 } - function setButtonState(buttonIndex) { - var itemat = gridView.contentItem.children[buttonIndex]; + function setButtonState(buttonIndex, buttonstate) { + if (buttonIndex < 0) { + return; + } + + var itemat = gridView.contentItem.children[buttonIndex].children[0]; + console.warn("changing item at", buttonIndex, state, itemat.objectName, + gridView.contentItem.children[buttonIndex].objectName) if (itemat.isActive) { itemat.state = "active state"; } else { - itemat.state = state; + itemat.state = buttonstate; } } onCurrentIndexChanged: { - setButtonState(previousGridIndex) + setButtonState(previousGridIndex, "base state"); rowIndex = Math.floor(currentIndex / TabletEnums.ButtonsColumnsOnPage); columnIndex = currentIndex % TabletEnums.ButtonsColumnsOnPage console.warn("current index", currentIndex, rowIndex, columnIndex) - setButtonState(currentIndex) + setButtonState(currentIndex, "hover state"); previousGridIndex = currentIndex } @@ -166,6 +172,7 @@ Item { delegate: Item { id: wrapper + objectName: "wrapper" width: gridView.cellWidth height: gridView.cellHeight @@ -214,6 +221,7 @@ Item { currentGridItems.currentIndex = (previousIndex > swipeView.currentIndex ? currentGridItems.count - 1 : 0); previousIndex = currentIndex; + setButtonState(currentIndex, "hover state"); } hoverEnabled: true From 35fee739c59132ade4054542ed75396aec1068e5 Mon Sep 17 00:00:00 2001 From: vladest Date: Wed, 27 Dec 2017 23:50:15 +0100 Subject: [PATCH 24/29] Use buttons index --- .../qml/hifi/tablet/TabletButton.qml | 13 ++++----- .../resources/qml/hifi/tablet/TabletHome.qml | 28 +++---------------- .../ui/src/ui/TabletScriptingInterface.cpp | 21 ++++++++++---- .../ui/src/ui/TabletScriptingInterface.h | 6 ++-- 4 files changed, 27 insertions(+), 41 deletions(-) diff --git a/interface/resources/qml/hifi/tablet/TabletButton.qml b/interface/resources/qml/hifi/tablet/TabletButton.qml index 843f8706ed..4d443fb97c 100644 --- a/interface/resources/qml/hifi/tablet/TabletButton.qml +++ b/interface/resources/qml/hifi/tablet/TabletButton.qml @@ -24,9 +24,9 @@ Item { property int stableOrder: 0 property var tabletRoot; property var flickable: null + property var gridView: null - property int row: -1 - property int column: -1 + property int buttonIndex: -1 width: 129 height: 129 @@ -138,7 +138,8 @@ Item { enabled: true preventStealing: false onClicked: { - tablet.setCurrentItemState("base state"); + gridView.currentIndex = buttonIndex + if (tabletButton.inDebugMode) { if (tabletButton.isActive) { tabletButton.isActive = false; @@ -146,8 +147,6 @@ Item { tabletButton.isActive = true; } } - tablet.rowIndex = tabletButton.row - tablet.columnIndex = tabletButton.column tabletButton.clicked(); if (tabletRoot) { @@ -156,7 +155,7 @@ Item { } onEntered: { - tablet.setCurrentItemState("base state"); + gridView.currentIndex = buttonIndex tabletButton.isEntered = true; Tablet.playSound(TabletEnums.ButtonHover); @@ -165,8 +164,6 @@ Item { } else { tabletButton.state = "hover state"; } - tablet.rowIndex = tabletButton.row - tablet.columnIndex = tabletButton.column } onExited: { tabletButton.isEntered = false; diff --git a/interface/resources/qml/hifi/tablet/TabletHome.qml b/interface/resources/qml/hifi/tablet/TabletHome.qml index 0b450cc2e7..2064fb38fa 100644 --- a/interface/resources/qml/hifi/tablet/TabletHome.qml +++ b/interface/resources/qml/hifi/tablet/TabletHome.qml @@ -14,9 +14,6 @@ Item { objectName: "tablet" property var tabletProxy: Tablet.getTablet("com.highfidelity.interface.tablet.system"); - property int rowIndex: 6 // by default - property int columnIndex: 1 // point to 'go to location' - property var currentGridItems: null focus: true @@ -145,10 +142,9 @@ Item { if (buttonIndex < 0) { return; } + console.warn("changing item at", buttonIndex, buttonstate) var itemat = gridView.contentItem.children[buttonIndex].children[0]; - console.warn("changing item at", buttonIndex, state, itemat.objectName, - gridView.contentItem.children[buttonIndex].objectName) if (itemat.isActive) { itemat.state = "active state"; } else { @@ -158,9 +154,7 @@ Item { onCurrentIndexChanged: { setButtonState(previousGridIndex, "base state"); - rowIndex = Math.floor(currentIndex / TabletEnums.ButtonsColumnsOnPage); - columnIndex = currentIndex % TabletEnums.ButtonsColumnsOnPage - console.warn("current index", currentIndex, rowIndex, columnIndex) + console.warn("current index", currentIndex) setButtonState(currentIndex, "hover state"); previousGridIndex = currentIndex } @@ -181,12 +175,10 @@ Item { TabletButton { id: tabletButton anchors.centerIn: parent + gridView: wrapper.GridView.view + buttonIndex: page.proxyModel.buttonIndex(uuid); flickable: swipeView.contentItem; onClicked: modelData.clicked() - onStateChanged: console.warn("state", state, uuid) -// Component.onCompleted: { -// state = Qt.binding(function() { return wrapper.GridView.isCurrentItem ? "hover state" : "base state"; }); -// } } Connections { @@ -221,7 +213,6 @@ Item { currentGridItems.currentIndex = (previousIndex > swipeView.currentIndex ? currentGridItems.count - 1 : 0); previousIndex = currentIndex; - setButtonState(currentIndex, "hover state"); } hoverEnabled: true @@ -263,17 +254,6 @@ Item { } } - function setCurrentItemState(state) { - var buttonIndex = rowIndex * TabletEnums.ButtonsColumnsOnPage + columnIndex; - if (currentGridItems !== null && buttonIndex >= 0 && buttonIndex < currentGridItems.length) { - if (currentGridItems[buttonIndex].isActive) { - currentGridItems[buttonIndex].state = "active state"; - } else { - currentGridItems[buttonIndex].state = state; - } - } - } - Component.onCompleted: { focus = true; forceActiveFocus(); diff --git a/libraries/ui/src/ui/TabletScriptingInterface.cpp b/libraries/ui/src/ui/TabletScriptingInterface.cpp index 5e5b3f83ea..c69ec1ce84 100644 --- a/libraries/ui/src/ui/TabletScriptingInterface.cpp +++ b/libraries/ui/src/ui/TabletScriptingInterface.cpp @@ -93,13 +93,27 @@ void TabletButtonListModel::removeButton(TabletButtonProxy* button) { } TabletButtonsProxyModel::TabletButtonsProxyModel(QObject *parent) - : QSortFilterProxyModel(parent), _pageIndex(-1) { + : QSortFilterProxyModel(parent) { } int TabletButtonsProxyModel::pageIndex() const { return _pageIndex; } +int TabletButtonsProxyModel::buttonIndex(const QString &uuid) { + if (!sourceModel() || _pageIndex < 0) { + return -1; + } + TabletButtonListModel* model = static_cast(sourceModel()); + for (int i = 0; i < model->rowCount(); i++) { + TabletButtonProxy* bproxy = model->data(model->index(i), ButtonProxyRole).value(); + if (bproxy && bproxy->getUuid().toString().contains(uuid)) { + return i - (_pageIndex*TabletScriptingInterface::ButtonsOnPage); + } + } + return -1; +} + void TabletButtonsProxyModel::setPageIndex(int pageIndex) { if (_pageIndex == pageIndex) @@ -117,11 +131,6 @@ bool TabletButtonsProxyModel::filterAcceptsRow(int sourceRow, && sourceRow < (_pageIndex + 1)*TabletScriptingInterface::ButtonsOnPage); } -bool TabletButtonsProxyModel::lessThan(const QModelIndex &left, - const QModelIndex &right) const { - return true; -} - TabletScriptingInterface::TabletScriptingInterface() { qmlRegisterType("TabletScriptingInterface", 1, 0, "TabletEnums"); qmlRegisterType("TabletScriptingInterface", 1, 0, "TabletButtonsProxyModel"); diff --git a/libraries/ui/src/ui/TabletScriptingInterface.h b/libraries/ui/src/ui/TabletScriptingInterface.h index a69bcd2f75..56e3ae257b 100644 --- a/libraries/ui/src/ui/TabletScriptingInterface.h +++ b/libraries/ui/src/ui/TabletScriptingInterface.h @@ -129,8 +129,9 @@ class TabletButtonsProxyModel : public QSortFilterProxyModel Q_PROPERTY(int pageIndex READ pageIndex WRITE setPageIndex NOTIFY pageIndexChanged) public: - TabletButtonsProxyModel(QObject *parent = 0); + TabletButtonsProxyModel(QObject* parent = 0); int pageIndex() const; + Q_INVOKABLE int buttonIndex(const QString& uuid); public slots: void setPageIndex(int pageIndex); @@ -140,10 +141,9 @@ signals: protected: bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override; - bool lessThan(const QModelIndex &left, const QModelIndex &right) const override; private: - int _pageIndex; + int _pageIndex { -1 }; }; Q_DECLARE_METATYPE(TabletButtonsProxyModel*); From afc3082593c3853b3355ff9c9db1668b4806a278 Mon Sep 17 00:00:00 2001 From: vladest Date: Thu, 28 Dec 2017 13:16:51 +0100 Subject: [PATCH 25/29] Cleanup. Errors checks --- interface/resources/qml/hifi/tablet/TabletHome.qml | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/interface/resources/qml/hifi/tablet/TabletHome.qml b/interface/resources/qml/hifi/tablet/TabletHome.qml index 2064fb38fa..e934f18ab6 100644 --- a/interface/resources/qml/hifi/tablet/TabletHome.qml +++ b/interface/resources/qml/hifi/tablet/TabletHome.qml @@ -139,11 +139,10 @@ Item { } function setButtonState(buttonIndex, buttonstate) { - if (buttonIndex < 0) { + if (buttonIndex < 0 || gridView.contentItem === undefined + || gridView.contentItem.children.length - 1 < buttonIndex) { return; } - console.warn("changing item at", buttonIndex, buttonstate) - var itemat = gridView.contentItem.children[buttonIndex].children[0]; if (itemat.isActive) { itemat.state = "active state"; @@ -154,7 +153,6 @@ Item { onCurrentIndexChanged: { setButtonState(previousGridIndex, "base state"); - console.warn("current index", currentIndex) setButtonState(currentIndex, "hover state"); previousGridIndex = currentIndex } @@ -166,7 +164,6 @@ Item { delegate: Item { id: wrapper - objectName: "wrapper" width: gridView.cellWidth height: gridView.cellHeight From 28f164d7e59d02ecf365c356613bab3fc65c8b6a Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 4 Dec 2017 14:43:50 -0800 Subject: [PATCH 26/29] Remove legacy jurisdiction code --- assignment-client/src/Agent.cpp | 15 - assignment-client/src/Agent.h | 1 - .../src/octree/OctreeHeadlessViewer.cpp | 176 +--------- .../src/octree/OctreeHeadlessViewer.h | 4 - .../src/octree/OctreeSendThread.cpp | 5 +- assignment-client/src/octree/OctreeServer.cpp | 44 --- assignment-client/src/octree/OctreeServer.h | 4 - .../src/octree/OctreeServerConsts.h | 1 - .../src/scripts/EntityScriptServer.cpp | 15 - .../src/scripts/EntityScriptServer.h | 1 - interface/src/Application.cpp | 201 +---------- interface/src/Application.h | 5 +- interface/src/ui/OctreeStatsDialog.cpp | 35 +- interface/src/ui/OctreeStatsDialog.h | 2 +- interface/src/ui/OctreeStatsProvider.cpp | 34 +- interface/src/ui/OctreeStatsProvider.h | 3 +- libraries/networking/src/udt/PacketHeaders.h | 2 - libraries/octree/src/JurisdictionListener.cpp | 85 ----- libraries/octree/src/JurisdictionListener.h | 60 ---- libraries/octree/src/JurisdictionMap.cpp | 325 ------------------ libraries/octree/src/JurisdictionMap.h | 88 ----- libraries/octree/src/JurisdictionSender.cpp | 68 ---- libraries/octree/src/JurisdictionSender.h | 58 ---- libraries/octree/src/Octree.cpp | 25 +- libraries/octree/src/Octree.h | 8 - .../octree/src/OctreeEditPacketSender.cpp | 216 ++++-------- libraries/octree/src/OctreeEditPacketSender.h | 11 - libraries/octree/src/OctreeSceneStats.cpp | 95 +---- libraries/octree/src/OctreeSceneStats.h | 12 +- .../octree/src/OctreeScriptingInterface.cpp | 26 +- .../octree/src/OctreeScriptingInterface.h | 7 +- 31 files changed, 113 insertions(+), 1519 deletions(-) delete mode 100644 libraries/octree/src/JurisdictionListener.cpp delete mode 100644 libraries/octree/src/JurisdictionListener.h delete mode 100644 libraries/octree/src/JurisdictionMap.cpp delete mode 100644 libraries/octree/src/JurisdictionMap.h delete mode 100644 libraries/octree/src/JurisdictionSender.cpp delete mode 100644 libraries/octree/src/JurisdictionSender.h diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index f166a780ff..2fc905c6fd 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -94,7 +94,6 @@ Agent::Agent(ReceivedMessage& message) : packetReceiver.registerListenerForTypes( { PacketType::OctreeStats, PacketType::EntityData, PacketType::EntityErase }, this, "handleOctreePacket"); - packetReceiver.registerListener(PacketType::Jurisdiction, this, "handleJurisdictionPacket"); packetReceiver.registerListener(PacketType::SelectedAudioFormat, this, "handleSelectedAudioFormat"); @@ -149,17 +148,6 @@ void Agent::handleOctreePacket(QSharedPointer message, SharedNo } } -void Agent::handleJurisdictionPacket(QSharedPointer message, SharedNodePointer senderNode) { - NodeType_t nodeType; - message->peekPrimitive(&nodeType); - - // PacketType_JURISDICTION, first byte is the node type... - if (nodeType == NodeType::EntityServer) { - DependencyManager::get()->getJurisdictionListener()-> - queueReceivedPacket(message, senderNode); - } -} - void Agent::handleAudioPacket(QSharedPointer message) { _receivedAudioStream.parseData(*message); _lastReceivedAudioLoudness = _receivedAudioStream.getNextOutputFrameLoudness(); @@ -483,10 +471,7 @@ void Agent::executeScript() { auto recordingInterface = DependencyManager::get(); _scriptEngine->registerGlobalObject("Recording", recordingInterface.data()); - // we need to make sure that init has been called for our EntityScriptingInterface - // so that it actually has a jurisdiction listener when we ask it for it next entityScriptingInterface->init(); - _entityViewer.setJurisdictionListener(entityScriptingInterface->getJurisdictionListener()); _entityViewer.init(); diff --git a/assignment-client/src/Agent.h b/assignment-client/src/Agent.h index 168da185b6..1229f06276 100644 --- a/assignment-client/src/Agent.h +++ b/assignment-client/src/Agent.h @@ -73,7 +73,6 @@ private slots: void handleAudioPacket(QSharedPointer message); void handleOctreePacket(QSharedPointer message, SharedNodePointer senderNode); - void handleJurisdictionPacket(QSharedPointer message, SharedNodePointer senderNode); void handleSelectedAudioFormat(QSharedPointer message); void nodeActivated(SharedNodePointer activatedNode); diff --git a/assignment-client/src/octree/OctreeHeadlessViewer.cpp b/assignment-client/src/octree/OctreeHeadlessViewer.cpp index 4e885da7a5..d3b20fb623 100644 --- a/assignment-client/src/octree/OctreeHeadlessViewer.cpp +++ b/assignment-client/src/octree/OctreeHeadlessViewer.cpp @@ -23,23 +23,6 @@ void OctreeHeadlessViewer::queryOctree() { char serverType = getMyNodeType(); PacketType packetType = getMyQueryMessageType(); - NodeToJurisdictionMap& jurisdictions = *_jurisdictionListener->getJurisdictions(); - - bool wantExtraDebugging = false; - - if (wantExtraDebugging) { - qCDebug(octree) << "OctreeHeadlessViewer::queryOctree() _jurisdictionListener=" << _jurisdictionListener; - qCDebug(octree) << "---------------"; - qCDebug(octree) << "_jurisdictionListener=" << _jurisdictionListener; - qCDebug(octree) << "Jurisdictions..."; - jurisdictions.withReadLock([&] { - for (NodeToJurisdictionMapIterator i = jurisdictions.begin(); i != jurisdictions.end(); ++i) { - qCDebug(octree) << i.key() << ": " << &i.value(); - } - }); - qCDebug(octree) << "---------------"; - } - _octreeQuery.setCameraPosition(_viewFrustum.getPosition()); _octreeQuery.setCameraOrientation(_viewFrustum.getOrientation()); _octreeQuery.setCameraFov(_viewFrustum.getFieldOfView()); @@ -51,159 +34,22 @@ void OctreeHeadlessViewer::queryOctree() { _octreeQuery.setOctreeSizeScale(_voxelSizeScale); _octreeQuery.setBoundaryLevelAdjust(_boundaryLevelAdjust); - // Iterate all of the nodes, and get a count of how many voxel servers we have... - int totalServers = 0; - int inViewServers = 0; - int unknownJurisdictionServers = 0; - - DependencyManager::get()->eachNode([&](const SharedNodePointer& node){ - // only send to the NodeTypes that are serverType - if (node->getActiveSocket() && node->getType() == serverType) { - totalServers++; - - // get the server bounds for this server - QUuid nodeUUID = node->getUUID(); - - // if we haven't heard from this voxel server, go ahead and send it a query, so we - // can get the jurisdiction... - VoxelPositionSize rootDetails; - bool foundRootDetails = false; - jurisdictions.withReadLock([&] { - if (jurisdictions.find(nodeUUID) == jurisdictions.end()) { - unknownJurisdictionServers++; - return; - } - const JurisdictionMap& map = (jurisdictions)[nodeUUID]; - - auto rootCode = map.getRootOctalCode(); - if (!rootCode) { - return; - } - - voxelDetailsForCode(rootCode.get(), rootDetails); - foundRootDetails = true; - }); - - if (foundRootDetails) { - AACube serverBounds(glm::vec3(rootDetails.x, rootDetails.y, rootDetails.z), rootDetails.s); - if ((bool)(_viewFrustum.calculateCubeKeyholeIntersection(serverBounds))) { - inViewServers++; - } - } - } - }); - - if (wantExtraDebugging) { - qCDebug(octree, "Servers: total %d, in view %d, unknown jurisdiction %d", - totalServers, inViewServers, unknownJurisdictionServers); - } - - int perServerPPS = 0; - const int SMALL_BUDGET = 10; - int perUnknownServer = SMALL_BUDGET; - int totalPPS = getMaxPacketsPerSecond(); - - // determine PPS based on number of servers - if (inViewServers >= 1) { - // set our preferred PPS to be exactly evenly divided among all of the voxel servers... and allocate 1 PPS - // for each unknown jurisdiction server - perServerPPS = (totalPPS / inViewServers) - (unknownJurisdictionServers * perUnknownServer); - } else { - if (unknownJurisdictionServers > 0) { - perUnknownServer = (totalPPS / unknownJurisdictionServers); - } - } - - if (wantExtraDebugging) { - qCDebug(octree, "perServerPPS: %d perUnknownServer: %d", perServerPPS, perUnknownServer); - } - auto nodeList = DependencyManager::get(); - nodeList->eachNode([&](const SharedNodePointer& node){ - // only send to the NodeTypes that are serverType - if (node->getActiveSocket() && node->getType() == serverType) { - // get the server bounds for this server - QUuid nodeUUID = node->getUUID(); + auto node = nodeList->soloNodeOfType(serverType); + if (node && node->getActiveSocket()) { + _octreeQuery.setMaxQueryPacketsPerSecond(getMaxPacketsPerSecond()); - bool inView = false; - bool unknownView = false; + auto queryPacket = NLPacket::create(packetType); - // if we haven't heard from this voxel server, go ahead and send it a query, so we - // can get the jurisdiction... - VoxelPositionSize rootDetails; - bool foundRootDetails = false; - jurisdictions.withReadLock([&] { - if (jurisdictions.find(nodeUUID) == jurisdictions.end()) { - unknownView = true; // assume it's in view - if (wantExtraDebugging) { - qCDebug(octree) << "no known jurisdiction for node " << *node << ", assume it's visible."; - } - return; - } + // encode the query data + auto packetData = reinterpret_cast(queryPacket->getPayload()); + int packetSize = _octreeQuery.getBroadcastData(packetData); + queryPacket->setPayloadSize(packetSize); - const JurisdictionMap& map = (jurisdictions)[nodeUUID]; - auto rootCode = map.getRootOctalCode(); - - if (!rootCode) { - if (wantExtraDebugging) { - qCDebug(octree) << "Jurisdiction without RootCode for node " << *node << ". That's unusual!"; - } - return; - } - voxelDetailsForCode(rootCode.get(), rootDetails); - foundRootDetails = true; - }); - - if (foundRootDetails) { - AACube serverBounds(glm::vec3(rootDetails.x, rootDetails.y, rootDetails.z), rootDetails.s); - inView = (bool)(_viewFrustum.calculateCubeKeyholeIntersection(serverBounds)); - } - - if (inView) { - _octreeQuery.setMaxQueryPacketsPerSecond(perServerPPS); - if (wantExtraDebugging) { - qCDebug(octree) << "inView for node " << *node << ", give it budget of " << perServerPPS; - } - } else if (unknownView) { - if (wantExtraDebugging) { - qCDebug(octree) << "no known jurisdiction for node " << *node << ", give it budget of " - << perUnknownServer << " to send us jurisdiction."; - } - - // set the query's position/orientation to be degenerate in a manner that will get the scene quickly - // If there's only one server, then don't do this, and just let the normal voxel query pass through - // as expected... this way, we will actually get a valid scene if there is one to be seen - if (totalServers > 1) { - _octreeQuery.setCameraPosition(glm::vec3(-0.1,-0.1,-0.1)); - const glm::quat OFF_IN_NEGATIVE_SPACE = glm::quat(-0.5, 0, -0.5, 1.0); - _octreeQuery.setCameraOrientation(OFF_IN_NEGATIVE_SPACE); - _octreeQuery.setCameraNearClip(0.1f); - _octreeQuery.setCameraFarClip(0.1f); - if (wantExtraDebugging) { - qCDebug(octree) << "Using 'minimal' camera position for node" << *node; - } - } else { - if (wantExtraDebugging) { - qCDebug(octree) << "Using regular camera position for node" << *node; - } - } - _octreeQuery.setMaxQueryPacketsPerSecond(perUnknownServer); - } else { - _octreeQuery.setMaxQueryPacketsPerSecond(0); - } - - // setup the query packet - auto queryPacket = NLPacket::create(packetType); - - // read the data to our packet and set the payload size to fit the query - int querySize = _octreeQuery.getBroadcastData(reinterpret_cast(queryPacket->getPayload())); - queryPacket->setPayloadSize(querySize); - - // ask the NodeList to send it - nodeList->sendPacket(std::move(queryPacket), *node); - } - }); + // make sure we still have an active socket + nodeList->sendUnreliablePacket(*queryPacket, *node); + } } diff --git a/assignment-client/src/octree/OctreeHeadlessViewer.h b/assignment-client/src/octree/OctreeHeadlessViewer.h index 5a7544498d..feb8211c39 100644 --- a/assignment-client/src/octree/OctreeHeadlessViewer.h +++ b/assignment-client/src/octree/OctreeHeadlessViewer.h @@ -13,7 +13,6 @@ #define hifi_OctreeHeadlessViewer_h #include -#include #include @@ -23,8 +22,6 @@ class OctreeHeadlessViewer : public OctreeProcessor { public: OctreeHeadlessViewer(); virtual ~OctreeHeadlessViewer() {}; - - void setJurisdictionListener(JurisdictionListener* jurisdictionListener) { _jurisdictionListener = jurisdictionListener; } OctreeQuery& getOctreeQuery() { return _octreeQuery; } @@ -57,7 +54,6 @@ public slots: unsigned getOctreeElementsCount() const { return _tree->getOctreeElementsCount(); } private: - JurisdictionListener* _jurisdictionListener = nullptr; OctreeQuery _octreeQuery; ViewFrustum _viewFrustum; diff --git a/assignment-client/src/octree/OctreeSendThread.cpp b/assignment-client/src/octree/OctreeSendThread.cpp index 3ae653307f..d5b9da7353 100644 --- a/assignment-client/src/octree/OctreeSendThread.cpp +++ b/assignment-client/src/octree/OctreeSendThread.cpp @@ -391,8 +391,7 @@ int OctreeSendThread::packetDistributor(SharedNodePointer node, OctreeQueryNode* nodeData->sceneStart(usecTimestampNow() - CHANGE_FUDGE); // start tracking our stats - nodeData->stats.sceneStarted(isFullScene, viewFrustumChanged, - _myServer->getOctree()->getRoot(), _myServer->getJurisdiction()); + nodeData->stats.sceneStarted(isFullScene, viewFrustumChanged, _myServer->getOctree()->getRoot()); preStartNewScene(nodeData, isFullScene); } @@ -507,7 +506,7 @@ void OctreeSendThread::traverseTreeAndSendContents(SharedNodePointer node, Octre float octreeSizeScale = nodeData->getOctreeSizeScale(); EncodeBitstreamParams params(INT_MAX, WANT_EXISTS_BITS, DONT_CHOP, viewFrustumChanged, boundaryLevelAdjust, octreeSizeScale, - isFullScene, _myServer->getJurisdiction(), nodeData); + isFullScene, nodeData); // Our trackSend() function is implemented by the server subclass, and will be called back as new entities/data elements are sent params.trackSend = [this](const QUuid& dataID, quint64 dataEdited) { _myServer->trackSend(dataID, dataEdited, _nodeUuid); diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp index c535c48dda..42494ea7ee 100644 --- a/assignment-client/src/octree/OctreeServer.cpp +++ b/assignment-client/src/octree/OctreeServer.cpp @@ -237,8 +237,6 @@ OctreeServer::OctreeServer(ReceivedMessage& message) : _debugSending(false), _debugReceiving(false), _verboseDebug(false), - _jurisdiction(NULL), - _jurisdictionSender(NULL), _octreeInboundPacketProcessor(NULL), _persistThread(NULL), _started(time(0)), @@ -257,12 +255,6 @@ OctreeServer::~OctreeServer() { delete[] _parsedArgV; } - if (_jurisdictionSender) { - _jurisdictionSender->terminating(); - _jurisdictionSender->terminate(); - _jurisdictionSender->deleteLater(); - } - if (_octreeInboundPacketProcessor) { _octreeInboundPacketProcessor->terminating(); _octreeInboundPacketProcessor->terminate(); @@ -275,9 +267,6 @@ OctreeServer::~OctreeServer() { _persistThread->deleteLater(); } - delete _jurisdiction; - _jurisdiction = NULL; - // cleanup our tree here... qDebug() << qPrintable(_safeServerName) << "server START cleaning up octree... [" << this << "]"; _tree.reset(); @@ -933,10 +922,6 @@ void OctreeServer::handleOctreeDataNackPacket(QSharedPointer me } } -void OctreeServer::handleJurisdictionRequestPacket(QSharedPointer message, SharedNodePointer senderNode) { - _jurisdictionSender->queueReceivedPacket(message, senderNode); -} - void OctreeServer::handleOctreeFileReplacement(QSharedPointer message) { if (!_isFinished && !_isShuttingDown) { // these messages are only allowed to come from the domain server, so make sure that is the case @@ -1111,23 +1096,6 @@ void OctreeServer::readConfiguration() { qDebug() << "statusPort= DISABLED"; } - QString jurisdictionFile; - if (readOptionString(QString("jurisdictionFile"), settingsSectionObject, jurisdictionFile)) { - qDebug("jurisdictionFile=%s", qPrintable(jurisdictionFile)); - qDebug("about to readFromFile().... jurisdictionFile=%s", qPrintable(jurisdictionFile)); - _jurisdiction = new JurisdictionMap(qPrintable(jurisdictionFile)); - qDebug("after readFromFile().... jurisdictionFile=%s", qPrintable(jurisdictionFile)); - } else { - QString jurisdictionRoot; - bool hasRoot = readOptionString(QString("jurisdictionRoot"), settingsSectionObject, jurisdictionRoot); - QString jurisdictionEndNodes; - bool hasEndNodes = readOptionString(QString("jurisdictionEndNodes"), settingsSectionObject, jurisdictionEndNodes); - - if (hasRoot || hasEndNodes) { - _jurisdiction = new JurisdictionMap(qPrintable(jurisdictionRoot), qPrintable(jurisdictionEndNodes)); - } - } - readOptionBool(QString("verboseDebug"), settingsSectionObject, _verboseDebug); qDebug("verboseDebug=%s", debug::valueOf(_verboseDebug)); @@ -1241,7 +1209,6 @@ void OctreeServer::domainSettingsRequestComplete() { auto& packetReceiver = DependencyManager::get()->getPacketReceiver(); packetReceiver.registerListener(getMyQueryMessageType(), this, "handleOctreeQueryPacket"); packetReceiver.registerListener(PacketType::OctreeDataNack, this, "handleOctreeDataNackPacket"); - packetReceiver.registerListener(PacketType::JurisdictionRequest, this, "handleJurisdictionRequestPacket"); packetReceiver.registerListener(PacketType::OctreeFileReplacement, this, "handleOctreeFileReplacement"); packetReceiver.registerListener(PacketType::OctreeFileReplacementFromUrl, this, "handleOctreeFileReplacementFromURL"); @@ -1365,13 +1332,6 @@ void OctreeServer::domainSettingsRequestComplete() { _persistThread->initialize(true); } - // set up our jurisdiction broadcaster... - if (_jurisdiction) { - _jurisdiction->setNodeType(getMyNodeType()); - } - _jurisdictionSender = new JurisdictionSender(_jurisdiction, getMyNodeType()); - _jurisdictionSender->initialize(true); - // set up our OctreeServerPacketProcessor _octreeInboundPacketProcessor = new OctreeInboundPacketProcessor(this); _octreeInboundPacketProcessor->initialize(true); @@ -1441,10 +1401,6 @@ void OctreeServer::aboutToFinish() { _octreeInboundPacketProcessor->terminating(); } - if (_jurisdictionSender) { - _jurisdictionSender->terminating(); - } - // Shut down all the send threads for (auto& it : _sendThreads) { auto& sendThread = *it.second; diff --git a/assignment-client/src/octree/OctreeServer.h b/assignment-client/src/octree/OctreeServer.h index f930f299f3..0eba914064 100644 --- a/assignment-client/src/octree/OctreeServer.h +++ b/assignment-client/src/octree/OctreeServer.h @@ -44,7 +44,6 @@ public: bool wantsVerboseDebug() const { return _verboseDebug; } OctreePointer getOctree() { return _tree; } - JurisdictionMap* getJurisdiction() { return _jurisdiction; } int getPacketsPerClientPerInterval() const { return std::min(_packetsPerClientPerInterval, std::max(1, getPacketsTotalPerInterval() / std::max(1, getCurrentClientCount()))); } @@ -138,7 +137,6 @@ private slots: void domainSettingsRequestComplete(); void handleOctreeQueryPacket(QSharedPointer message, SharedNodePointer senderNode); void handleOctreeDataNackPacket(QSharedPointer message, SharedNodePointer senderNode); - void handleJurisdictionRequestPacket(QSharedPointer message, SharedNodePointer senderNode); void handleOctreeFileReplacement(QSharedPointer message); void handleOctreeFileReplacementFromURL(QSharedPointer message); void removeSendThread(); @@ -190,8 +188,6 @@ protected: bool _debugReceiving; bool _debugTimestampNow; bool _verboseDebug; - JurisdictionMap* _jurisdiction; - JurisdictionSender* _jurisdictionSender; OctreeInboundPacketProcessor* _octreeInboundPacketProcessor; OctreePersistThread* _persistThread; diff --git a/assignment-client/src/octree/OctreeServerConsts.h b/assignment-client/src/octree/OctreeServerConsts.h index 30b55b8786..2706b3ef73 100644 --- a/assignment-client/src/octree/OctreeServerConsts.h +++ b/assignment-client/src/octree/OctreeServerConsts.h @@ -14,7 +14,6 @@ #include #include // for MAX_PACKET_SIZE -#include const int MAX_FILENAME_LENGTH = 1024; diff --git a/assignment-client/src/scripts/EntityScriptServer.cpp b/assignment-client/src/scripts/EntityScriptServer.cpp index c8067ce81f..b4a6b3af93 100644 --- a/assignment-client/src/scripts/EntityScriptServer.cpp +++ b/assignment-client/src/scripts/EntityScriptServer.cpp @@ -79,7 +79,6 @@ EntityScriptServer::EntityScriptServer(ReceivedMessage& message) : ThreadedAssig auto& packetReceiver = DependencyManager::get()->getPacketReceiver(); packetReceiver.registerListenerForTypes({ PacketType::OctreeStats, PacketType::EntityData, PacketType::EntityErase }, this, "handleOctreePacket"); - packetReceiver.registerListener(PacketType::Jurisdiction, this, "handleJurisdictionPacket"); packetReceiver.registerListener(PacketType::SelectedAudioFormat, this, "handleSelectedAudioFormat"); auto avatarHashMap = DependencyManager::set(); @@ -283,11 +282,8 @@ void EntityScriptServer::run() { // Setup Script Engine resetEntitiesScriptEngine(); - // we need to make sure that init has been called for our EntityScriptingInterface - // so that it actually has a jurisdiction listener when we ask it for it next auto entityScriptingInterface = DependencyManager::get(); entityScriptingInterface->init(); - _entityViewer.setJurisdictionListener(entityScriptingInterface->getJurisdictionListener()); _entityViewer.init(); @@ -566,17 +562,6 @@ void EntityScriptServer::handleOctreePacket(QSharedPointer mess } } -void EntityScriptServer::handleJurisdictionPacket(QSharedPointer message, SharedNodePointer senderNode) { - NodeType_t nodeType; - message->peekPrimitive(&nodeType); - - // PacketType_JURISDICTION, first byte is the node type... - if (nodeType == NodeType::EntityServer) { - DependencyManager::get()->getJurisdictionListener()-> - queueReceivedPacket(message, senderNode); - } -} - void EntityScriptServer::aboutToFinish() { shutdownScriptEngine(); diff --git a/assignment-client/src/scripts/EntityScriptServer.h b/assignment-client/src/scripts/EntityScriptServer.h index f9c5e921f0..9c6c4c752e 100644 --- a/assignment-client/src/scripts/EntityScriptServer.h +++ b/assignment-client/src/scripts/EntityScriptServer.h @@ -41,7 +41,6 @@ public slots: private slots: void handleOctreePacket(QSharedPointer message, SharedNodePointer senderNode); - void handleJurisdictionPacket(QSharedPointer message, SharedNodePointer senderNode); void handleSelectedAudioFormat(QSharedPointer message); void handleReloadEntityServerScriptPacket(QSharedPointer message, SharedNodePointer senderNode); diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 459197f1e3..e96ce0967c 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1189,8 +1189,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo userActivityLogger.logAction("launch", properties); } - // Tell our entity edit sender about our known jurisdictions - _entityEditSender.setServerJurisdictions(&_entityServerJurisdictions); _entityEditSender.setMyAvatar(myAvatar.get()); // The entity octree will have to know about MyAvatar for the parentJointName import @@ -4557,7 +4555,7 @@ void Application::reloadResourceCaches() { _lastQueriedTime = 0; _octreeQuery.incrementConnectionID(); - queryOctree(NodeType::EntityServer, PacketType::EntityQuery, _entityServerJurisdictions); + queryOctree(NodeType::EntityServer, PacketType::EntityQuery); DependencyManager::get()->clearCache(); @@ -5050,7 +5048,7 @@ void Application::update(float deltaTime) { if (queryIsDue || viewIsDifferentEnough) { _lastQueriedTime = now; if (DependencyManager::get()->shouldRenderEntities()) { - queryOctree(NodeType::EntityServer, PacketType::EntityQuery, _entityServerJurisdictions); + queryOctree(NodeType::EntityServer, PacketType::EntityQuery); } sendAvatarViewFrustum(); _lastQueriedViewFrustum = _viewFrustum; @@ -5271,15 +5269,12 @@ int Application::sendNackPackets() { return packetsSent; } -void Application::queryOctree(NodeType_t serverType, PacketType packetType, NodeToJurisdictionMap& jurisdictions) { +void Application::queryOctree(NodeType_t serverType, PacketType packetType) { if (!_settingsLoaded) { return; // bail early if settings are not loaded } - //qCDebug(interfaceapp) << ">>> inside... queryOctree()... _viewFrustum.getFieldOfView()=" << _viewFrustum.getFieldOfView(); - bool wantExtraDebugging = getLogger()->extraDebugging(); - ViewFrustum viewFrustum; copyViewFrustum(viewFrustum); _octreeQuery.setCameraPosition(viewFrustum.getPosition()); @@ -5294,147 +5289,22 @@ void Application::queryOctree(NodeType_t serverType, PacketType packetType, Node _octreeQuery.setOctreeSizeScale(lodManager->getOctreeSizeScale()); _octreeQuery.setBoundaryLevelAdjust(lodManager->getBoundaryLevelAdjust()); - // Iterate all of the nodes, and get a count of how many octree servers we have... - int totalServers = 0; - int inViewServers = 0; - int unknownJurisdictionServers = 0; - auto nodeList = DependencyManager::get(); - nodeList->eachNode([&](const SharedNodePointer& node) { - // only send to the NodeTypes that are serverType - if (node->getActiveSocket() && node->getType() == serverType) { - totalServers++; + auto node = nodeList->soloNodeOfType(serverType); + if (node && node->getActiveSocket()) { + _octreeQuery.setMaxQueryPacketsPerSecond(getMaxOctreePacketsPerSecond()); - // get the server bounds for this server - QUuid nodeUUID = node->getUUID(); + auto queryPacket = NLPacket::create(packetType); - // if we haven't heard from this voxel server, go ahead and send it a query, so we - // can get the jurisdiction... - if (jurisdictions.find(nodeUUID) == jurisdictions.end()) { - unknownJurisdictionServers++; - } else { - const JurisdictionMap& map = (jurisdictions)[nodeUUID]; + // encode the query data + auto packetData = reinterpret_cast(queryPacket->getPayload()); + int packetSize = _octreeQuery.getBroadcastData(packetData); + queryPacket->setPayloadSize(packetSize); - auto rootCode = map.getRootOctalCode(); - - if (rootCode) { - VoxelPositionSize rootDetails; - voxelDetailsForCode(rootCode.get(), rootDetails); - AACube serverBounds(glm::vec3(rootDetails.x * TREE_SCALE, - rootDetails.y * TREE_SCALE, - rootDetails.z * TREE_SCALE) - glm::vec3(HALF_TREE_SCALE), - rootDetails.s * TREE_SCALE); - if (viewFrustum.cubeIntersectsKeyhole(serverBounds)) { - inViewServers++; - } - } - } - } - }); - - if (wantExtraDebugging) { - qCDebug(interfaceapp, "Servers: total %d, in view %d, unknown jurisdiction %d", - totalServers, inViewServers, unknownJurisdictionServers); + // make sure we still have an active socket + nodeList->sendUnreliablePacket(*queryPacket, *node); } - - int perServerPPS = 0; - const int SMALL_BUDGET = 10; - int perUnknownServer = SMALL_BUDGET; - int totalPPS = getMaxOctreePacketsPerSecond(); - - // determine PPS based on number of servers - if (inViewServers >= 1) { - // set our preferred PPS to be exactly evenly divided among all of the voxel servers... and allocate 1 PPS - // for each unknown jurisdiction server - perServerPPS = (totalPPS / inViewServers) - (unknownJurisdictionServers * perUnknownServer); - } else { - if (unknownJurisdictionServers > 0) { - perUnknownServer = (totalPPS / unknownJurisdictionServers); - } - } - - if (wantExtraDebugging) { - qCDebug(interfaceapp, "perServerPPS: %d perUnknownServer: %d", perServerPPS, perUnknownServer); - } - - auto queryPacket = NLPacket::create(packetType); - - nodeList->eachNode([&](const SharedNodePointer& node) { - // only send to the NodeTypes that are serverType - if (node->getActiveSocket() && node->getType() == serverType) { - - // get the server bounds for this server - QUuid nodeUUID = node->getUUID(); - - bool inView = false; - bool unknownView = false; - - // if we haven't heard from this voxel server, go ahead and send it a query, so we - // can get the jurisdiction... - if (jurisdictions.find(nodeUUID) == jurisdictions.end()) { - unknownView = true; // assume it's in view - if (wantExtraDebugging) { - qCDebug(interfaceapp) << "no known jurisdiction for node " << *node << ", assume it's visible."; - } - } else { - const JurisdictionMap& map = (jurisdictions)[nodeUUID]; - - auto rootCode = map.getRootOctalCode(); - - if (rootCode) { - VoxelPositionSize rootDetails; - voxelDetailsForCode(rootCode.get(), rootDetails); - AACube serverBounds(glm::vec3(rootDetails.x * TREE_SCALE, - rootDetails.y * TREE_SCALE, - rootDetails.z * TREE_SCALE) - glm::vec3(HALF_TREE_SCALE), - rootDetails.s * TREE_SCALE); - - - inView = viewFrustum.cubeIntersectsKeyhole(serverBounds); - } else if (wantExtraDebugging) { - qCDebug(interfaceapp) << "Jurisdiction without RootCode for node " << *node << ". That's unusual!"; - } - } - - if (inView) { - _octreeQuery.setMaxQueryPacketsPerSecond(perServerPPS); - } else if (unknownView) { - if (wantExtraDebugging) { - qCDebug(interfaceapp) << "no known jurisdiction for node " << *node << ", give it budget of " - << perUnknownServer << " to send us jurisdiction."; - } - - // set the query's position/orientation to be degenerate in a manner that will get the scene quickly - // If there's only one server, then don't do this, and just let the normal voxel query pass through - // as expected... this way, we will actually get a valid scene if there is one to be seen - if (totalServers > 1) { - _octreeQuery.setCameraPosition(glm::vec3(-0.1,-0.1,-0.1)); - const glm::quat OFF_IN_NEGATIVE_SPACE = glm::quat(-0.5, 0, -0.5, 1.0); - _octreeQuery.setCameraOrientation(OFF_IN_NEGATIVE_SPACE); - _octreeQuery.setCameraNearClip(0.1f); - _octreeQuery.setCameraFarClip(0.1f); - if (wantExtraDebugging) { - qCDebug(interfaceapp) << "Using 'minimal' camera position for node" << *node; - } - } else { - if (wantExtraDebugging) { - qCDebug(interfaceapp) << "Using regular camera position for node" << *node; - } - } - _octreeQuery.setMaxQueryPacketsPerSecond(perUnknownServer); - } else { - _octreeQuery.setMaxQueryPacketsPerSecond(0); - } - - // encode the query data - int packetSize = _octreeQuery.getBroadcastData(reinterpret_cast(queryPacket->getPayload())); - queryPacket->setPayloadSize(packetSize); - - // make sure we still have an active socket - nodeList->sendUnreliablePacket(*queryPacket, *node); - } - }); } @@ -5549,11 +5419,6 @@ void Application::clearDomainOctreeDetails() { resetPhysicsReadyInformation(); - // reset our node to stats and node to jurisdiction maps... since these must be changing... - _entityServerJurisdictions.withWriteLock([&] { - _entityServerJurisdictions.clear(); - }); - _octreeServerSceneStats.withWriteLock([&] { _octreeServerSceneStats.clear(); }); @@ -5755,8 +5620,6 @@ bool Application::nearbyEntitiesAreReadyForPhysics() { } int Application::processOctreeStats(ReceivedMessage& message, SharedNodePointer sendingNode) { - // But, also identify the sender, and keep track of the contained jurisdiction root for this server - // parse the incoming stats datas stick it in a temporary object for now, while we // determine which server it belongs to int statsMessageLength = 0; @@ -5771,42 +5634,6 @@ int Application::processOctreeStats(ReceivedMessage& message, SharedNodePointer if (octreeStats.isFullScene()) { _fullSceneReceivedCounter++; } - - // see if this is the first we've heard of this node... - NodeToJurisdictionMap* jurisdiction = nullptr; - QString serverType; - if (sendingNode->getType() == NodeType::EntityServer) { - jurisdiction = &_entityServerJurisdictions; - serverType = "Entity"; - } - - bool found = false; - - jurisdiction->withReadLock([&] { - if (jurisdiction->find(nodeUUID) != jurisdiction->end()) { - found = true; - return; - } - - VoxelPositionSize rootDetails; - voxelDetailsForCode(octreeStats.getJurisdictionRoot().get(), rootDetails); - - qCDebug(interfaceapp, "stats from new %s server... [%f, %f, %f, %f]", - qPrintable(serverType), - (double)rootDetails.x, (double)rootDetails.y, (double)rootDetails.z, (double)rootDetails.s); - }); - - if (!found) { - // store jurisdiction details for later use - // This is bit of fiddling is because JurisdictionMap assumes it is the owner of the values used to construct it - // but OctreeSceneStats thinks it's just returning a reference to its contents. So we need to make a copy of the - // details from the OctreeSceneStats to construct the JurisdictionMap - JurisdictionMap jurisdictionMap; - jurisdictionMap.copyContents(octreeStats.getJurisdictionRoot(), octreeStats.getJurisdictionEndNodes()); - jurisdiction->withWriteLock([&] { - (*jurisdiction)[nodeUUID] = jurisdictionMap; - }); - } }); return statsMessageLength; @@ -5827,7 +5654,7 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEnginePointe return !entityServerNode || isPhysicsEnabled(); }); - // setup the packet senders and jurisdiction listeners of the script engine's scripting interfaces so + // setup the packet sender of the script engine's scripting interfaces so // we can use the same ones from the application. auto entityScriptingInterface = DependencyManager::get(); entityScriptingInterface->setPacketSender(&_entityEditSender); diff --git a/interface/src/Application.h b/interface/src/Application.h index ee16740f20..5267d50cf6 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -228,8 +228,6 @@ public: FileLogger* getLogger() const { return _logger; } - NodeToJurisdictionMap& getEntityServerJurisdictions() { return _entityServerJurisdictions; } - float getRenderResolutionScale() const; qint64 getCurrentSessionRuntime() const { return _sessionRunTimer.elapsed(); } @@ -450,7 +448,7 @@ private: void updateThreads(float deltaTime); void updateDialogs(float deltaTime) const; - void queryOctree(NodeType_t serverType, PacketType packetType, NodeToJurisdictionMap& jurisdictions); + void queryOctree(NodeType_t serverType, PacketType packetType); int sendNackPackets(); void sendAvatarViewFrustum(); @@ -571,7 +569,6 @@ private: StDev _idleLoopStdev; float _idleLoopMeasuredJitter; - NodeToJurisdictionMap _entityServerJurisdictions; NodeToOctreeSceneStats _octreeServerSceneStats; ControllerScriptingInterface* _controllerScriptingInterface{ nullptr }; QPointer _logDialog; diff --git a/interface/src/ui/OctreeStatsDialog.cpp b/interface/src/ui/OctreeStatsDialog.cpp index fc0e6781d7..77ed29d5ae 100644 --- a/interface/src/ui/OctreeStatsDialog.cpp +++ b/interface/src/ui/OctreeStatsDialog.cpp @@ -378,8 +378,7 @@ void OctreeStatsDialog::paintEvent(QPaintEvent* event) { void OctreeStatsDialog::showAllOctreeServers() { int serverCount = 0; - showOctreeServersOfType(serverCount, NodeType::EntityServer, "Entity", - qApp->getEntityServerJurisdictions()); + showOctreeServersOfType(serverCount, NodeType::EntityServer, "Entity"); if (_octreeServerLabelsCount > serverCount) { for (int i = serverCount; i < _octreeServerLabelsCount; i++) { @@ -391,8 +390,7 @@ void OctreeStatsDialog::showAllOctreeServers() { } } -void OctreeStatsDialog::showOctreeServersOfType(int& serverCount, NodeType_t serverType, const char* serverTypeName, - NodeToJurisdictionMap& serverJurisdictions) { +void OctreeStatsDialog::showOctreeServersOfType(int& serverCount, NodeType_t serverType, const char* serverTypeName) { QLocale locale(QLocale::English); @@ -424,35 +422,6 @@ void OctreeStatsDialog::showOctreeServersOfType(int& serverCount, NodeType_t ser QUuid nodeUUID = node->getUUID(); - // lookup our nodeUUID in the jurisdiction map, if it's missing then we're - // missing at least one jurisdiction - serverJurisdictions.withReadLock([&] { - if (serverJurisdictions.find(nodeUUID) == serverJurisdictions.end()) { - serverDetails << " unknown jurisdiction "; - return; - } - const JurisdictionMap& map = serverJurisdictions[nodeUUID]; - - auto rootCode = map.getRootOctalCode(); - - if (rootCode) { - QString rootCodeHex = octalCodeToHexString(rootCode.get()); - - VoxelPositionSize rootDetails; - voxelDetailsForCode(rootCode.get(), rootDetails); - AACube serverBounds(glm::vec3(rootDetails.x, rootDetails.y, rootDetails.z), rootDetails.s); - serverDetails << " jurisdiction: " - << qPrintable(rootCodeHex) - << " [" - << rootDetails.x << ", " - << rootDetails.y << ", " - << rootDetails.z << ": " - << rootDetails.s << "] "; - } else { - serverDetails << " jurisdiction has no rootCode"; - } // root code - }); - // now lookup stats details for this server... if (_extraServerDetails[serverCount-1] != LESS) { NodeToOctreeSceneStats* sceneStats = qApp->getOcteeSceneStats(); diff --git a/interface/src/ui/OctreeStatsDialog.h b/interface/src/ui/OctreeStatsDialog.h index 67f5c01f65..7686b7c726 100644 --- a/interface/src/ui/OctreeStatsDialog.h +++ b/interface/src/ui/OctreeStatsDialog.h @@ -48,7 +48,7 @@ protected: void showAllOctreeServers(); void showOctreeServersOfType(int& serverNumber, NodeType_t serverType, - const char* serverTypeName, NodeToJurisdictionMap& serverJurisdictions); + const char* serverTypeName); private: diff --git a/interface/src/ui/OctreeStatsProvider.cpp b/interface/src/ui/OctreeStatsProvider.cpp index 5f40b9916d..e35524f5f8 100644 --- a/interface/src/ui/OctreeStatsProvider.cpp +++ b/interface/src/ui/OctreeStatsProvider.cpp @@ -239,16 +239,14 @@ void OctreeStatsProvider::updateOctreeStatsData() { void OctreeStatsProvider::updateOctreeServers() { int serverCount = 0; - showOctreeServersOfType(serverCount, NodeType::EntityServer, "Entity", - qApp->getEntityServerJurisdictions()); + showOctreeServersOfType(serverCount, NodeType::EntityServer, "Entity"); if (m_serversNum != serverCount) { m_serversNum = serverCount; emit serversNumChanged(m_serversNum); } } -void OctreeStatsProvider::showOctreeServersOfType(int& serverCount, NodeType_t serverType, const char* serverTypeName, - NodeToJurisdictionMap& serverJurisdictions) { +void OctreeStatsProvider::showOctreeServersOfType(int& serverCount, NodeType_t serverType, const char* serverTypeName) { m_servers.clear(); @@ -270,35 +268,7 @@ void OctreeStatsProvider::showOctreeServersOfType(int& serverCount, NodeType_t s } QUuid nodeUUID = node->getUUID(); - - // lookup our nodeUUID in the jurisdiction map, if it's missing then we're - // missing at least one jurisdiction - serverJurisdictions.withReadLock([&] { - if (serverJurisdictions.find(nodeUUID) == serverJurisdictions.end()) { - lesserDetails += " unknown jurisdiction "; - return; - } - const JurisdictionMap& map = serverJurisdictions[nodeUUID]; - auto rootCode = map.getRootOctalCode(); - - if (rootCode) { - QString rootCodeHex = octalCodeToHexString(rootCode.get()); - - VoxelPositionSize rootDetails; - voxelDetailsForCode(rootCode.get(), rootDetails); - AACube serverBounds(glm::vec3(rootDetails.x, rootDetails.y, rootDetails.z), rootDetails.s); - lesserDetails += QString(" jurisdiction: %1 [%2, %3, %4: %5]") - .arg(rootCodeHex) - .arg(rootDetails.x) - .arg(rootDetails.y) - .arg(rootDetails.z) - .arg(rootDetails.s); - } else { - lesserDetails += " jurisdiction has no rootCode"; - } // root code - }); - // now lookup stats details for this server... NodeToOctreeSceneStats* sceneStats = qApp->getOcteeSceneStats(); sceneStats->withReadLock([&] { diff --git a/interface/src/ui/OctreeStatsProvider.h b/interface/src/ui/OctreeStatsProvider.h index c919ca102f..04aff24edd 100644 --- a/interface/src/ui/OctreeStatsProvider.h +++ b/interface/src/ui/OctreeStatsProvider.h @@ -121,8 +121,7 @@ private slots: void updateOctreeStatsData(); protected: void updateOctreeServers(); - void showOctreeServersOfType(int& serverNumber, NodeType_t serverType, - const char* serverTypeName, NodeToJurisdictionMap& serverJurisdictions); + void showOctreeServersOfType(int& serverNumber, NodeType_t serverType, const char* serverTypeName); private: NodeToOctreeSceneStats* _model; diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index 85f321a198..e23cdad7d3 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -56,8 +56,6 @@ public: ICEServerPeerInformation, ICEServerQuery, OctreeStats, - Jurisdiction, - JurisdictionRequest, AssignmentClientStatus, NoisyMute, AvatarIdentity, diff --git a/libraries/octree/src/JurisdictionListener.cpp b/libraries/octree/src/JurisdictionListener.cpp deleted file mode 100644 index 76c5069006..0000000000 --- a/libraries/octree/src/JurisdictionListener.cpp +++ /dev/null @@ -1,85 +0,0 @@ -// -// JurisdictionListener.cpp -// libraries/octree/src -// -// Created by Brad Hefta-Gaub on 8/12/13. -// Copyright 2013 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 -// - -#include - -#include -#include -#include -#include "JurisdictionListener.h" - -JurisdictionListener::JurisdictionListener(NodeType_t type) : - _nodeType(type), - _packetSender(JurisdictionListener::DEFAULT_PACKETS_PER_SECOND) -{ - setObjectName("Jurisdiction Listener"); - - connect(DependencyManager::get().data(), &NodeList::nodeKilled, this, &JurisdictionListener::nodeKilled); - - // tell our NodeList we want to hear about nodes with our node type - DependencyManager::get()->addNodeTypeToInterestSet(type); -} - -void JurisdictionListener::nodeKilled(SharedNodePointer node) { - if (_jurisdictions.find(node->getUUID()) != _jurisdictions.end()) { - _jurisdictions.erase(_jurisdictions.find(node->getUUID())); - } -} - -bool JurisdictionListener::queueJurisdictionRequest() { - auto nodeList = DependencyManager::get(); - - int nodeCount = 0; - - nodeList->eachNode([&](const SharedNodePointer& node) { - if (node->getType() == getNodeType() && node->getActiveSocket()) { - auto packet = NLPacket::create(PacketType::JurisdictionRequest, 0); - _packetSender.queuePacketForSending(node, std::move(packet)); - nodeCount++; - } - }); - - if (nodeCount > 0){ - _packetSender.setPacketsPerSecond(nodeCount); - } else { - _packetSender.setPacketsPerSecond(NO_SERVER_CHECK_RATE); - } - - // keep going if still running - return isStillRunning(); -} - -void JurisdictionListener::processPacket(QSharedPointer message, SharedNodePointer sendingNode) { - if (message->getType() == PacketType::Jurisdiction) { - JurisdictionMap map; - map.unpackFromPacket(*message); - _jurisdictions[message->getSourceID()] = map; - } -} - -bool JurisdictionListener::process() { - bool continueProcessing = isStillRunning(); - - // If we're still running, and we don't have any requests waiting to be sent, then queue our jurisdiction requests - if (continueProcessing && !_packetSender.hasPacketsToSend()) { - queueJurisdictionRequest(); - } - - if (continueProcessing) { - continueProcessing = _packetSender.process(); - } - if (continueProcessing) { - // NOTE: This will sleep if there are no pending packets to process - continueProcessing = ReceivedPacketProcessor::process(); - } - - return continueProcessing; -} diff --git a/libraries/octree/src/JurisdictionListener.h b/libraries/octree/src/JurisdictionListener.h deleted file mode 100644 index 7aee1659ff..0000000000 --- a/libraries/octree/src/JurisdictionListener.h +++ /dev/null @@ -1,60 +0,0 @@ -// -// JurisdictionListener.h -// libraries/octree/src -// -// Created by Brad Hefta-Gaub on 8/12/13. -// Copyright 2013 High Fidelity, Inc. -// -// Voxel Packet Sender -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#ifndef hifi_JurisdictionListener_h -#define hifi_JurisdictionListener_h - -#include -#include -#include - -#include "JurisdictionMap.h" - -/// Sends out PacketType::_JURISDICTION_REQUEST packets to all voxel servers and then listens for and processes -/// the PacketType::_JURISDICTION packets it receives in order to maintain an accurate state of all jurisidictions -/// within the domain. As with other ReceivedPacketProcessor classes the user is responsible for reading inbound packets -/// and adding them to the processing queue by calling queueReceivedPacket() -class JurisdictionListener : public ReceivedPacketProcessor { - Q_OBJECT -public: - static const int DEFAULT_PACKETS_PER_SECOND = 1; - static const int NO_SERVER_CHECK_RATE = 60; // if no servers yet detected, keep checking at 60fps - - JurisdictionListener(NodeType_t type = NodeType::EntityServer); - - virtual bool process() override; - - NodeToJurisdictionMap* getJurisdictions() { return &_jurisdictions; } - - - NodeType_t getNodeType() const { return _nodeType; } - void setNodeType(NodeType_t type) { _nodeType = type; } - -public slots: - /// Called by NodeList to inform us that a node has been killed. - void nodeKilled(SharedNodePointer node); - -protected: - /// Callback for processing of received packets. Will process any queued PacketType::_JURISDICTION and update the - /// jurisdiction map member variable - virtual void processPacket(QSharedPointer messsage, SharedNodePointer sendingNode) override; - -private: - NodeToJurisdictionMap _jurisdictions; - NodeType_t _nodeType; - - bool queueJurisdictionRequest(); - - PacketSender _packetSender; -}; -#endif // hifi_JurisdictionListener_h diff --git a/libraries/octree/src/JurisdictionMap.cpp b/libraries/octree/src/JurisdictionMap.cpp deleted file mode 100644 index fcbc085339..0000000000 --- a/libraries/octree/src/JurisdictionMap.cpp +++ /dev/null @@ -1,325 +0,0 @@ -// -// JurisdictionMap.cpp -// libraries/octree/src -// -// Created by Brad Hefta-Gaub on 8/1/13. -// Copyright 2013 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 -// - -#include -#include -#include -#include - -#include -#include -#include - -#include "OctreeLogging.h" -#include "JurisdictionMap.h" - -void myDebugOutputBits(unsigned char byte, bool withNewLine) { - if (isalnum(byte)) { - printf("[ %d (%c): ", byte, byte); - } else { - printf("[ %d (0x%x): ", byte, byte); - } - - for (int i = 0; i < 8; i++) { - printf("%d", byte >> (7 - i) & 1); - } - printf(" ] "); - - if (withNewLine) { - printf("\n"); - } -} - -void myDebugPrintOctalCode(const unsigned char* octalCode, bool withNewLine) { - if (!octalCode) { - printf("nullptr"); - } else { - for (size_t i = 0; i < bytesRequiredForCodeLength(numberOfThreeBitSectionsInCode(octalCode)); i++) { - myDebugOutputBits(octalCode[i], false); - } - } - if (withNewLine) { - printf("\n"); - } -} - -// standard assignment -// copy assignment -JurisdictionMap& JurisdictionMap::operator=(const JurisdictionMap& other) { - copyContents(other); - return *this; -} - -// Copy constructor -JurisdictionMap::JurisdictionMap(const JurisdictionMap& other) : _rootOctalCode(nullptr) { - copyContents(other); -} - -void JurisdictionMap::copyContents(const OctalCodePtr& rootCodeIn, const OctalCodePtrList& endNodesIn) { - OctalCodePtr rootCode = rootCodeIn; - if (!rootCode) { - rootCode = createOctalCodePtr(1); - *rootCode = 0; - } - - OctalCodePtrList emptyEndNodes; - init(rootCode, endNodesIn); -} - -void JurisdictionMap::copyContents(const JurisdictionMap& other) { - _nodeType = other._nodeType; - - OctalCodePtr rootOctalCode; - OctalCodePtrList endNodes; - - std::tie(rootOctalCode, endNodes) = other.getRootAndEndNodeOctalCodes(); - - init(rootOctalCode, endNodes); -} - -JurisdictionMap::~JurisdictionMap() { -} - -JurisdictionMap::JurisdictionMap(NodeType_t type) : _rootOctalCode(nullptr) { - _nodeType = type; - OctalCodePtr rootCode = createOctalCodePtr(1); - *rootCode = 0; - - OctalCodePtrList emptyEndNodes; - init(rootCode, emptyEndNodes); -} - -JurisdictionMap::JurisdictionMap(const char* filename) : _rootOctalCode(nullptr) { - readFromFile(filename); -} - -JurisdictionMap::JurisdictionMap(const char* rootHexCode, const char* endNodesHexCodes) { - - qCDebug(octree, "JurisdictionMap::JurisdictionMap(const char* rootHexCode=[%p] %s, const char* endNodesHexCodes=[%p] %s)", - rootHexCode, rootHexCode, endNodesHexCodes, endNodesHexCodes); - - _rootOctalCode = hexStringToOctalCode(QString(rootHexCode)); - - qCDebug(octree, "JurisdictionMap::JurisdictionMap() _rootOctalCode=%p octalCode=", _rootOctalCode.get()); - myDebugPrintOctalCode(_rootOctalCode.get(), true); - - QString endNodesHexStrings(endNodesHexCodes); - QString delimiterPattern(","); - QStringList endNodeList = endNodesHexStrings.split(delimiterPattern); - - for (int i = 0; i < endNodeList.size(); i++) { - QString endNodeHexString = endNodeList.at(i); - - auto endNodeOctcode = hexStringToOctalCode(endNodeHexString); - - qCDebug(octree, "JurisdictionMap::JurisdictionMap() endNodeList(%d)=%s", - i, endNodeHexString.toLocal8Bit().constData()); - - //printOctalCode(endNodeOctcode); - _endNodes.push_back(endNodeOctcode); - - qCDebug(octree, "JurisdictionMap::JurisdictionMap() endNodeOctcode=%p octalCode=", endNodeOctcode.get()); - myDebugPrintOctalCode(endNodeOctcode.get(), true); - - } -} - -std::tuple JurisdictionMap::getRootAndEndNodeOctalCodes() const { - std::lock_guard lock(_octalCodeMutex); - return std::tuple(_rootOctalCode, _endNodes); -} - -OctalCodePtr JurisdictionMap::getRootOctalCode() const { - std::lock_guard lock(_octalCodeMutex); - return _rootOctalCode; -} - -OctalCodePtrList JurisdictionMap::getEndNodeOctalCodes() const { - std::lock_guard lock(_octalCodeMutex); - return _endNodes; -} - -void JurisdictionMap::init(OctalCodePtr rootOctalCode, const OctalCodePtrList& endNodes) { - std::lock_guard lock(_octalCodeMutex); - _rootOctalCode = rootOctalCode; - _endNodes = endNodes; -} - -JurisdictionMap::Area JurisdictionMap::isMyJurisdiction(const unsigned char* nodeOctalCode, int childIndex) const { - // to be in our jurisdiction, we must be under the root... - - std::lock_guard lock(_octalCodeMutex); - - // if the node is an ancestor of my root, then we return ABOVE - if (isAncestorOf(nodeOctalCode, _rootOctalCode.get())) { - return ABOVE; - } - - // otherwise... - bool isInJurisdiction = isAncestorOf(_rootOctalCode.get(), nodeOctalCode, childIndex); - // if we're under the root, then we can't be under any of the endpoints - if (isInJurisdiction) { - for (size_t i = 0; i < _endNodes.size(); i++) { - bool isUnderEndNode = isAncestorOf(_endNodes[i].get(), nodeOctalCode); - if (isUnderEndNode) { - isInJurisdiction = false; - break; - } - } - } - return isInJurisdiction ? WITHIN : BELOW; -} - - -bool JurisdictionMap::readFromFile(const char* filename) { - QString settingsFile(filename); - QSettings settings(settingsFile, QSettings::IniFormat); - QString rootCode = settings.value("root","00").toString(); - qCDebug(octree) << "rootCode=" << rootCode; - - std::lock_guard lock(_octalCodeMutex); - _rootOctalCode = hexStringToOctalCode(rootCode); - printOctalCode(_rootOctalCode.get()); - - settings.beginGroup("endNodes"); - const QStringList childKeys = settings.childKeys(); - QHash values; - foreach (const QString &childKey, childKeys) { - QString childValue = settings.value(childKey).toString(); - values.insert(childKey, childValue); - qCDebug(octree) << childKey << "=" << childValue; - - auto octcode = hexStringToOctalCode(childValue); - printOctalCode(octcode.get()); - - _endNodes.push_back(octcode); - } - settings.endGroup(); - return true; -} - -void JurisdictionMap::displayDebugDetails() const { - std::lock_guard lock(_octalCodeMutex); - - QString rootNodeValue = octalCodeToHexString(_rootOctalCode.get()); - - qCDebug(octree) << "root:" << rootNodeValue; - - for (size_t i = 0; i < _endNodes.size(); i++) { - QString value = octalCodeToHexString(_endNodes[i].get()); - qCDebug(octree) << "End node[" << i << "]: " << rootNodeValue; - } -} - - -bool JurisdictionMap::writeToFile(const char* filename) { - QString settingsFile(filename); - QSettings settings(settingsFile, QSettings::IniFormat); - - std::lock_guard lock(_octalCodeMutex); - - QString rootNodeValue = octalCodeToHexString(_rootOctalCode.get()); - - settings.setValue("root", rootNodeValue); - - settings.beginGroup("endNodes"); - for (size_t i = 0; i < _endNodes.size(); i++) { - QString key = QString("endnode%1").arg(i); - QString value = octalCodeToHexString(_endNodes[i].get()); - settings.setValue(key, value); - } - settings.endGroup(); - return true; -} - -std::unique_ptr JurisdictionMap::packEmptyJurisdictionIntoMessage(NodeType_t type) { - int bytes = 0; - auto packet = NLPacket::create(PacketType::Jurisdiction, sizeof(type) + sizeof(bytes)); - - // Pack the Node Type in first byte - packet->writePrimitive(type); - // No root or end node details to pack! - packet->writePrimitive(bytes); - - return packet; // includes header! -} - -std::unique_ptr JurisdictionMap::packIntoPacket() { - auto packet = NLPacket::create(PacketType::Jurisdiction); - - // Pack the Node Type in first byte - NodeType_t type = getNodeType(); - packet->writePrimitive(type); - - // add the root jurisdiction - std::lock_guard lock(_octalCodeMutex); - if (_rootOctalCode) { - size_t bytes = bytesRequiredForCodeLength(numberOfThreeBitSectionsInCode(_rootOctalCode.get())); - // No root or end node details to pack! - packet->writePrimitive(bytes); - packet->write(reinterpret_cast(_rootOctalCode.get()), bytes); - - // if and only if there's a root jurisdiction, also include the end nodes - int endNodeCount = (int)_endNodes.size(); - packet->writePrimitive(endNodeCount); - - for (int i=0; i < endNodeCount; i++) { - auto endNodeCode = _endNodes[i].get(); - size_t bytes = 0; - if (endNodeCode) { - bytes = bytesRequiredForCodeLength(numberOfThreeBitSectionsInCode(endNodeCode)); - } - packet->writePrimitive(bytes); - packet->write(reinterpret_cast(endNodeCode), bytes); - } - } else { - int bytes = 0; - packet->writePrimitive(bytes); - } - - return packet; -} - -int JurisdictionMap::unpackFromPacket(ReceivedMessage& message) { - // read the root jurisdiction - int bytes = 0; - message.readPrimitive(&bytes); - - std::lock_guard lock(_octalCodeMutex); - _rootOctalCode = nullptr; - _endNodes.clear(); - - if (bytes > 0 && bytes <= message.getBytesLeftToRead()) { - _rootOctalCode = createOctalCodePtr(bytes); - message.read(reinterpret_cast(_rootOctalCode.get()), bytes); - - // if and only if there's a root jurisdiction, also include the end nodes - int endNodeCount = 0; - message.readPrimitive(&endNodeCount); - - for (int i = 0; i < endNodeCount; i++) { - int bytes = 0; - message.readPrimitive(&bytes); - - if (bytes <= message.getBytesLeftToRead()) { - auto endNodeCode = createOctalCodePtr(bytes); - message.read(reinterpret_cast(endNodeCode.get()), bytes); - - // if the endNodeCode was 0 length then don't add it - if (bytes > 0) { - _endNodes.push_back(endNodeCode); - } - } - } - } - - return message.getPosition(); // excludes header -} diff --git a/libraries/octree/src/JurisdictionMap.h b/libraries/octree/src/JurisdictionMap.h deleted file mode 100644 index b5a311c3d9..0000000000 --- a/libraries/octree/src/JurisdictionMap.h +++ /dev/null @@ -1,88 +0,0 @@ -// -// JurisdictionMap.h -// libraries/octree/src -// -// Created by Brad Hefta-Gaub on 8/1/13. -// Copyright 2013 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 -// - -#ifndef hifi_JurisdictionMap_h -#define hifi_JurisdictionMap_h - -#include -#include -#include - -#include -#include - -#include - -#include -#include -#include - -class JurisdictionMap { -public: - enum Area { - ABOVE, - WITHIN, - BELOW - }; - - // standard constructors - JurisdictionMap(NodeType_t type = NodeType::EntityServer); // default constructor - JurisdictionMap(const JurisdictionMap& other); // copy constructor - - // standard assignment - JurisdictionMap& operator=(const JurisdictionMap& other); // copy assignment - - // application constructors - JurisdictionMap(const char* filename); - JurisdictionMap(const char* rootHextString, const char* endNodesHextString); - - ~JurisdictionMap(); - - Area isMyJurisdiction(const unsigned char* nodeOctalCode, int childIndex) const; - - bool writeToFile(const char* filename); - bool readFromFile(const char* filename); - - // Provide an atomic way to get both the rootOctalCode and endNodeOctalCodes. - std::tuple getRootAndEndNodeOctalCodes() const; - OctalCodePtr getRootOctalCode() const; - OctalCodePtrList getEndNodeOctalCodes() const; - - void copyContents(const OctalCodePtr& rootCodeIn, const OctalCodePtrList& endNodesIn); - - int unpackFromPacket(ReceivedMessage& message); - std::unique_ptr packIntoPacket(); - - /// Available to pack an empty or unknown jurisdiction into a network packet, used when no JurisdictionMap is available - static std::unique_ptr packEmptyJurisdictionIntoMessage(NodeType_t type); - - void displayDebugDetails() const; - - NodeType_t getNodeType() const { return _nodeType; } - void setNodeType(NodeType_t type) { _nodeType = type; } - -private: - void copyContents(const JurisdictionMap& other); // use assignment instead - void init(OctalCodePtr rootOctalCode, const OctalCodePtrList& endNodes); - - mutable std::mutex _octalCodeMutex; - OctalCodePtr _rootOctalCode { nullptr }; - OctalCodePtrList _endNodes; - NodeType_t _nodeType; -}; - -/// Map between node IDs and their reported JurisdictionMap. Typically used by classes that need to know which nodes are -/// managing which jurisdictions. -class NodeToJurisdictionMap : public QMap, public ReadWriteLockable {}; -typedef QMap::iterator NodeToJurisdictionMapIterator; - - -#endif // hifi_JurisdictionMap_h diff --git a/libraries/octree/src/JurisdictionSender.cpp b/libraries/octree/src/JurisdictionSender.cpp deleted file mode 100644 index dfe1a6d872..0000000000 --- a/libraries/octree/src/JurisdictionSender.cpp +++ /dev/null @@ -1,68 +0,0 @@ -// -// JurisdictionSender.cpp -// libraries/octree/src -// -// Created by Brad Hefta-Gaub on 8/12/13. -// Copyright 2013 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 -// - -#include - -#include -#include -#include -#include "JurisdictionSender.h" - - -JurisdictionSender::JurisdictionSender(JurisdictionMap* map, NodeType_t type) : - ReceivedPacketProcessor(), - _jurisdictionMap(map), - _nodeType(type), - _packetSender(JurisdictionSender::DEFAULT_PACKETS_PER_SECOND) -{ -} - -JurisdictionSender::~JurisdictionSender() { -} - -void JurisdictionSender::processPacket(QSharedPointer message, SharedNodePointer sendingNode) { - if (message->getType() == PacketType::JurisdictionRequest) { - lockRequestingNodes(); - _nodesRequestingJurisdictions.push(sendingNode->getUUID()); - unlockRequestingNodes(); - } -} - -bool JurisdictionSender::process() { - bool continueProcessing = isStillRunning(); - - // call our ReceivedPacketProcessor base class process so we'll get any pending packets - if (continueProcessing && (continueProcessing = ReceivedPacketProcessor::process())) { - int nodeCount = 0; - - lockRequestingNodes(); - while (!_nodesRequestingJurisdictions.empty()) { - - QUuid nodeUUID = _nodesRequestingJurisdictions.front(); - _nodesRequestingJurisdictions.pop(); - SharedNodePointer node = DependencyManager::get()->nodeWithUUID(nodeUUID); - - if (node && node->getActiveSocket()) { - auto packet = (_jurisdictionMap) ? _jurisdictionMap->packIntoPacket() - : JurisdictionMap::packEmptyJurisdictionIntoMessage(getNodeType()); - _packetSender.queuePacketForSending(node, std::move(packet)); - nodeCount++; - } - } - unlockRequestingNodes(); - - // set our packets per second to be the number of nodes - _packetSender.setPacketsPerSecond(nodeCount); - - continueProcessing = _packetSender.process(); - } - return continueProcessing; -} diff --git a/libraries/octree/src/JurisdictionSender.h b/libraries/octree/src/JurisdictionSender.h deleted file mode 100644 index b2d738cd36..0000000000 --- a/libraries/octree/src/JurisdictionSender.h +++ /dev/null @@ -1,58 +0,0 @@ -// -// JurisdictionSender.h -// libraries/octree/src -// -// Created by Brad Hefta-Gaub on 8/12/13. -// Copyright 2013 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 -// - -#ifndef hifi_JurisdictionSender_h -#define hifi_JurisdictionSender_h - -#include -#include - -#include -#include -#include "JurisdictionMap.h" - -/// Will process PacketType::_JURISDICTION_REQUEST packets and send out PacketType::_JURISDICTION packets -/// to requesting parties. As with other ReceivedPacketProcessor classes the user is responsible for reading inbound packets -/// and adding them to the processing queue by calling queueReceivedPacket() -class JurisdictionSender : public ReceivedPacketProcessor { - Q_OBJECT -public: - static const int DEFAULT_PACKETS_PER_SECOND = 1; - - JurisdictionSender(JurisdictionMap* map, NodeType_t type = NodeType::EntityServer); - ~JurisdictionSender(); - - void setJurisdiction(JurisdictionMap* map) { _jurisdictionMap = map; } - - virtual bool process() override; - - NodeType_t getNodeType() const { return _nodeType; } - void setNodeType(NodeType_t type) { _nodeType = type; } - -protected: - virtual void processPacket(QSharedPointer message, SharedNodePointer sendingNode) override; - - /// Locks all the resources of the thread. - void lockRequestingNodes() { _requestingNodeMutex.lock(); } - - /// Unlocks all the resources of the thread. - void unlockRequestingNodes() { _requestingNodeMutex.unlock(); } - - -private: - QMutex _requestingNodeMutex; - JurisdictionMap* _jurisdictionMap; - std::queue _nodesRequestingJurisdictions; - NodeType_t _nodeType; - - PacketSender _packetSender; -}; -#endif // hifi_JurisdictionSender_h diff --git a/libraries/octree/src/Octree.cpp b/libraries/octree/src/Octree.cpp index 3190f25d7e..c63ff2f560 100644 --- a/libraries/octree/src/Octree.cpp +++ b/libraries/octree/src/Octree.cpp @@ -1020,16 +1020,6 @@ int Octree::encodeTreeBitstreamRecursion(const OctreeElementPointer& element, return bytesAtThisLevel; } - // If we've been provided a jurisdiction map, then we need to honor it. - if (params.jurisdictionMap) { - // here's how it works... if we're currently above our root jurisdiction, then we proceed normally. - // but once we're in our own jurisdiction, then we need to make sure we're not below it. - if (JurisdictionMap::BELOW == params.jurisdictionMap->isMyJurisdiction(element->getOctalCode(), CHECK_NODE_ONLY)) { - params.stopReason = EncodeBitstreamParams::OUT_OF_JURISDICTION; - return bytesAtThisLevel; - } - } - ViewFrustum::intersection nodeLocationThisView = ViewFrustum::INSIDE; // assume we're inside if (octreeQueryNode->getUsesFrustum() && !params.recurseEverything) { float boundaryDistance = boundaryDistanceForRenderLevel(element->getLevel() + params.boundaryLevelAdjust, @@ -1152,18 +1142,9 @@ int Octree::encodeTreeBitstreamRecursion(const OctreeElementPointer& element, for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { OctreeElementPointer childElement = element->getChildAtIndex(i); - // if the caller wants to include childExistsBits, then include them even if not in view, if however, - // we're in a portion of the tree that's not our responsibility, then we assume the child nodes exist - // even if they don't in our local tree - bool notMyJurisdiction = false; - if (params.jurisdictionMap) { - notMyJurisdiction = JurisdictionMap::WITHIN != params.jurisdictionMap->isMyJurisdiction(element->getOctalCode(), i); - } - if (params.includeExistsBits) { - // If the child is known to exist, OR, it's not my jurisdiction, then we mark the bit as existing - if (childElement || notMyJurisdiction) { - childrenExistInTreeBits += (1 << (7 - i)); - } + // if the caller wants to include childExistsBits, then include them + if (params.includeExistsBits && childElement) { + childrenExistInTreeBits += (1 << (7 - i)); } sortedChildren[i] = childElement; diff --git a/libraries/octree/src/Octree.h b/libraries/octree/src/Octree.h index ec6a0e810d..1648cb0f47 100644 --- a/libraries/octree/src/Octree.h +++ b/libraries/octree/src/Octree.h @@ -24,7 +24,6 @@ #include #include -#include "JurisdictionMap.h" #include "OctreeElement.h" #include "OctreeElementBag.h" #include "OctreePacketData.h" @@ -62,7 +61,6 @@ const int NO_BOUNDARY_ADJUST = 0; const int LOW_RES_MOVING_ADJUST = 1; #define IGNORE_COVERAGE_MAP NULL -#define IGNORE_JURISDICTION_MAP NULL class EncodeBitstreamParams { public: @@ -77,7 +75,6 @@ public: int boundaryLevelAdjust; float octreeElementSizeScale; bool forceSendScene; - JurisdictionMap* jurisdictionMap; NodeData* nodeData; // output hints from the encode process @@ -87,7 +84,6 @@ public: NULL_NODE, NULL_NODE_DATA, TOO_DEEP, - OUT_OF_JURISDICTION, LOD_SKIP, OUT_OF_VIEW, WAS_IN_VIEW, @@ -105,7 +101,6 @@ public: int boundaryLevelAdjust = NO_BOUNDARY_ADJUST, float octreeElementSizeScale = DEFAULT_OCTREE_SIZE_SCALE, bool forceSendScene = true, - JurisdictionMap* jurisdictionMap = IGNORE_JURISDICTION_MAP, NodeData* nodeData = nullptr) : maxEncodeLevel(maxEncodeLevel), maxLevelReached(0), @@ -115,7 +110,6 @@ public: boundaryLevelAdjust(boundaryLevelAdjust), octreeElementSizeScale(octreeElementSizeScale), forceSendScene(forceSendScene), - jurisdictionMap(jurisdictionMap), nodeData(nodeData), stopReason(UNKNOWN) { @@ -131,7 +125,6 @@ public: case DIDNT_FIT: qDebug("DIDNT_FIT"); break; case NULL_NODE: qDebug("NULL_NODE"); break; case TOO_DEEP: qDebug("TOO_DEEP"); break; - case OUT_OF_JURISDICTION: qDebug("OUT_OF_JURISDICTION"); break; case LOD_SKIP: qDebug("LOD_SKIP"); break; case OUT_OF_VIEW: qDebug("OUT_OF_VIEW"); break; case WAS_IN_VIEW: qDebug("WAS_IN_VIEW"); break; @@ -148,7 +141,6 @@ public: case DIDNT_FIT: return QString("DIDNT_FIT"); break; case NULL_NODE: return QString("NULL_NODE"); break; case TOO_DEEP: return QString("TOO_DEEP"); break; - case OUT_OF_JURISDICTION: return QString("OUT_OF_JURISDICTION"); break; case LOD_SKIP: return QString("LOD_SKIP"); break; case OUT_OF_VIEW: return QString("OUT_OF_VIEW"); break; case WAS_IN_VIEW: return QString("WAS_IN_VIEW"); break; diff --git a/libraries/octree/src/OctreeEditPacketSender.cpp b/libraries/octree/src/OctreeEditPacketSender.cpp index 7e46831faa..4f10c9bf79 100644 --- a/libraries/octree/src/OctreeEditPacketSender.cpp +++ b/libraries/octree/src/OctreeEditPacketSender.cpp @@ -22,13 +22,10 @@ const int OctreeEditPacketSender::DEFAULT_MAX_PENDING_MESSAGES = PacketSender::D OctreeEditPacketSender::OctreeEditPacketSender() : - PacketSender(), _shouldSend(true), _maxPendingMessages(DEFAULT_MAX_PENDING_MESSAGES), - _releaseQueuedMessagesPending(false), - _serverJurisdictions(NULL) + _releaseQueuedMessagesPending(false) { - } OctreeEditPacketSender::~OctreeEditPacketSender() { @@ -40,34 +37,8 @@ OctreeEditPacketSender::~OctreeEditPacketSender() { bool OctreeEditPacketSender::serversExist() const { - bool hasServers = false; - bool atLeastOneJurisdictionMissing = false; // assume the best - - DependencyManager::get()->eachNodeBreakable([&](const SharedNodePointer& node){ - if (node->getType() == getMyNodeType() && node->getActiveSocket()) { - - QUuid nodeUUID = node->getUUID(); - // If we've got Jurisdictions set, then check to see if we know the jurisdiction for this server - if (_serverJurisdictions) { - // lookup our nodeUUID in the jurisdiction map, if it's missing then we're - // missing at least one jurisdiction - _serverJurisdictions->withReadLock([&] { - if ((*_serverJurisdictions).find(nodeUUID) == (*_serverJurisdictions).end()) { - atLeastOneJurisdictionMissing = true; - } - }); - } - hasServers = true; - } - - if (atLeastOneJurisdictionMissing) { - return false; // no point in looking further - return false from anonymous function - } else { - return true; - } - }); - - return (hasServers && !atLeastOneJurisdictionMissing); + auto node = DependencyManager::get()->soloNodeOfType(getMyNodeType()); + return node && node->getActiveSocket(); } // This method is called when the edit packet layer has determined that it has a fully formed packet destined for @@ -132,7 +103,7 @@ void OctreeEditPacketSender::queuePacketListToNode(const QUuid& nodeUUID, std::u } void OctreeEditPacketSender::processPreServerExistsPackets() { - assert(serversExist()); // we should only be here if we have jurisdictions + assert(serversExist()); // we should only be here if we have servers // First send out all the single message packets... _pendingPacketsLock.lock(); @@ -150,7 +121,7 @@ void OctreeEditPacketSender::processPreServerExistsPackets() { _pendingPacketsLock.unlock(); - // if while waiting for the jurisdictions the caller called releaseQueuedMessages() + // if while waiting for the servers the caller called releaseQueuedMessages() // then we want to honor that request now. if (_releaseQueuedMessagesPending) { releaseQueuedMessages(); @@ -178,34 +149,12 @@ void OctreeEditPacketSender::queuePacketToNodes(std::unique_ptr packet return; // bail early } - assert(serversExist()); // we must have jurisdictions to be here!! + assert(serversExist()); // we must have servers to be here!! - const unsigned char* octCode = reinterpret_cast(packet->getPayload()) + sizeof(short) + sizeof(quint64); - - // We want to filter out edit messages for servers based on the server's Jurisdiction - // But we can't really do that with a packed message, since each edit message could be destined - // for a different server... So we need to actually manage multiple queued packets... one - // for each server - - DependencyManager::get()->eachNode([&](const SharedNodePointer& node){ - // only send to the NodeTypes that are getMyNodeType() - if (node->getActiveSocket() && node->getType() == getMyNodeType()) { - QUuid nodeUUID = node->getUUID(); - bool isMyJurisdiction = true; - // we need to get the jurisdiction for this - // here we need to get the "pending packet" for this server - _serverJurisdictions->withReadLock([&] { - const JurisdictionMap& map = (*_serverJurisdictions)[nodeUUID]; - isMyJurisdiction = (map.isMyJurisdiction(octCode, CHECK_NODE_ONLY) == JurisdictionMap::WITHIN); - }); - - if (isMyJurisdiction) { - // make a copy of this packet for this node and queue - auto packetCopy = NLPacket::createCopy(*packet); - queuePacketToNode(nodeUUID, std::move(packetCopy)); - } - } - }); + auto node = DependencyManager::get()->soloNodeOfType(getMyNodeType()); + if (node && node->getActiveSocket()) { + queuePacketToNode(node->getUUID(), std::move(packet)); + } } @@ -216,8 +165,8 @@ void OctreeEditPacketSender::queueOctreeEditMessage(PacketType type, QByteArray& return; // bail early } - // If we don't have jurisdictions, then we will simply queue up all of these packets and wait till we have - // jurisdictions for processing + // If we don't have servers, then we will simply queue up all of these packets and wait till we have + // servers for processing if (!serversExist()) { if (_maxPendingMessages > 0) { EditMessagePair messagePair { type, QByteArray(editMessage) }; @@ -235,107 +184,80 @@ void OctreeEditPacketSender::queueOctreeEditMessage(PacketType type, QByteArray& return; // bail early } - // We want to filter out edit messages for servers based on the server's Jurisdiction - // But we can't really do that with a packed message, since each edit message could be destined - // for a different server... So we need to actually manage multiple queued packets... one - // for each server _packetsQueueLock.lock(); - DependencyManager::get()->eachNode([&](const SharedNodePointer& node){ - // only send to the NodeTypes that are getMyNodeType() - if (node->getActiveSocket() && node->getType() == getMyNodeType()) { - QUuid nodeUUID = node->getUUID(); - bool isMyJurisdiction = true; + auto node = DependencyManager::get()->soloNodeOfType(getMyNodeType()); + if (node && node->getActiveSocket()) { + QUuid nodeUUID = node->getUUID(); - if (type == PacketType::EntityErase) { - isMyJurisdiction = true; // send erase messages to all servers - } else if (_serverJurisdictions) { - // we need to get the jurisdiction for this - // here we need to get the "pending packet" for this server - _serverJurisdictions->withReadLock([&] { - if ((*_serverJurisdictions).find(nodeUUID) != (*_serverJurisdictions).end()) { - const JurisdictionMap& map = (*_serverJurisdictions)[nodeUUID]; - isMyJurisdiction = (map.isMyJurisdiction(reinterpret_cast(editMessage.data()), - CHECK_NODE_ONLY) == JurisdictionMap::WITHIN); - } else { - isMyJurisdiction = false; - } - }); + // for edit messages, we will attempt to combine multiple edit commands where possible, we + // don't do this for add because we send those reliably + if (type == PacketType::EntityAdd) { + auto newPacket = NLPacketList::create(type, QByteArray(), true, true); + auto nodeClockSkew = node->getClockSkewUsec(); + + // pack sequence number + quint16 sequence = _outgoingSequenceNumbers[nodeUUID]++; + newPacket->writePrimitive(sequence); + + // pack in timestamp + quint64 now = usecTimestampNow() + nodeClockSkew; + newPacket->writePrimitive(now); + + + // We call this virtual function that allows our specific type of EditPacketSender to + // fixup the buffer for any clock skew + if (nodeClockSkew != 0) { + adjustEditPacketForClockSkew(type, editMessage, nodeClockSkew); } - if (isMyJurisdiction) { - // for edit messages, we will attempt to combine multiple edit commands where possible, we - // don't do this for add because we send those reliably - if (type == PacketType::EntityAdd) { + newPacket->write(editMessage); - auto newPacket = NLPacketList::create(type, QByteArray(), true, true); - auto nodeClockSkew = node->getClockSkewUsec(); + // release the new packet + releaseQueuedPacketList(nodeUUID, std::move(newPacket)); - // pack sequence number - quint16 sequence = _outgoingSequenceNumbers[nodeUUID]++; - newPacket->writePrimitive(sequence); + // tell the sent packet history that we used a sequence number for an untracked packet + auto& sentPacketHistory = _sentPacketHistories[nodeUUID]; + sentPacketHistory.untrackedPacketSent(sequence); + } else { + // only a NLPacket for now + std::unique_ptr& bufferedPacket = _pendingEditPackets[nodeUUID].first; - // pack in timestamp - quint64 now = usecTimestampNow() + nodeClockSkew; - newPacket->writePrimitive(now); + if (!bufferedPacket) { + bufferedPacket = initializePacket(type, node->getClockSkewUsec()); + } else { + // If we're switching type, then we send the last one and start over + if ((type != bufferedPacket->getType() && bufferedPacket->getPayloadSize() > 0) || + (editMessage.size() >= bufferedPacket->bytesAvailableForWrite())) { + // create the new packet and swap it with the packet in _pendingEditPackets + auto packetToRelease = initializePacket(type, node->getClockSkewUsec()); + bufferedPacket.swap(packetToRelease); - // We call this virtual function that allows our specific type of EditPacketSender to - // fixup the buffer for any clock skew - if (nodeClockSkew != 0) { - adjustEditPacketForClockSkew(type, editMessage, nodeClockSkew); - } - - newPacket->write(editMessage); - - // release the new packet - releaseQueuedPacketList(nodeUUID, std::move(newPacket)); - - // tell the sent packet history that we used a sequence number for an untracked packet - auto& sentPacketHistory = _sentPacketHistories[nodeUUID]; - sentPacketHistory.untrackedPacketSent(sequence); - } else { - - std::unique_ptr& bufferedPacket = _pendingEditPackets[nodeUUID].first; //only a NLPacket for now - - if (!bufferedPacket) { - bufferedPacket = initializePacket(type, node->getClockSkewUsec()); - } else { - // If we're switching type, then we send the last one and start over - if ((type != bufferedPacket->getType() && bufferedPacket->getPayloadSize() > 0) || - (editMessage.size() >= bufferedPacket->bytesAvailableForWrite())) { - - // create the new packet and swap it with the packet in _pendingEditPackets - auto packetToRelease = initializePacket(type, node->getClockSkewUsec()); - bufferedPacket.swap(packetToRelease); - - // release the previously buffered packet - releaseQueuedPacket(nodeUUID, std::move(packetToRelease)); - } - } - - // This is really the first time we know which server/node this particular edit message - // is going to, so we couldn't adjust for clock skew till now. But here's our chance. - // We call this virtual function that allows our specific type of EditPacketSender to - // fixup the buffer for any clock skew - if (node->getClockSkewUsec() != 0) { - adjustEditPacketForClockSkew(type, editMessage, node->getClockSkewUsec()); - } - - bufferedPacket->write(editMessage); - + // release the previously buffered packet + releaseQueuedPacket(nodeUUID, std::move(packetToRelease)); } } + + // This is really the first time we know which server/node this particular edit message + // is going to, so we couldn't adjust for clock skew till now. But here's our chance. + // We call this virtual function that allows our specific type of EditPacketSender to + // fixup the buffer for any clock skew + if (node->getClockSkewUsec() != 0) { + adjustEditPacketForClockSkew(type, editMessage, node->getClockSkewUsec()); + } + + bufferedPacket->write(editMessage); } - }); + } _packetsQueueLock.unlock(); } void OctreeEditPacketSender::releaseQueuedMessages() { - // if we don't yet have jurisdictions then we can't actually release messages yet because we don't - // know where to send them to. Instead, just remember this request and when we eventually get jurisdictions + // if we don't yet have servers then we can't actually release messages yet because we don't + // know where to send them to. Instead, just remember this request and when we eventually get servers // call release again at that time. if (!serversExist()) { _releaseQueuedMessagesPending = true; @@ -397,8 +319,8 @@ std::unique_ptr OctreeEditPacketSender::initializePacket(PacketType ty } bool OctreeEditPacketSender::process() { - // if we have server jurisdiction details, and we have pending pre-jurisdiction packets, then process those - // before doing our normal process step. This processPreJurisdictionPackets() + // if we have servers, and we have pending pre-servers exist packets, then process those + // before doing our normal process step. This processPreServerExistPackets() if (serversExist() && (!_preServerEdits.empty() || !_preServerSingleMessagePackets.empty() )) { processPreServerExistsPackets(); } diff --git a/libraries/octree/src/OctreeEditPacketSender.h b/libraries/octree/src/OctreeEditPacketSender.h index 79c363bec5..8a33eb8b73 100644 --- a/libraries/octree/src/OctreeEditPacketSender.h +++ b/libraries/octree/src/OctreeEditPacketSender.h @@ -17,7 +17,6 @@ #include #include -#include "JurisdictionMap.h" #include "SentPacketHistory.h" /// Utility for processing, packing, queueing and sending of outbound edit messages. @@ -49,14 +48,6 @@ public: /// in an application like interface when all octree features are disabled. void setShouldSend(bool shouldSend) { _shouldSend = shouldSend; } - /// call this to inform the OctreeEditPacketSender of the server jurisdictions. This is required for normal operation. - /// The internal contents of the jurisdiction map may change throughout the lifetime of the OctreeEditPacketSender. This map - /// can be set prior to servers being present, so long as the contents of the map accurately reflect the current - /// known jurisdictions. - void setServerJurisdictions(NodeToJurisdictionMap* serverJurisdictions) { - _serverJurisdictions = serverJurisdictions; - } - /// if you're running in non-threaded mode, you must call this method regularly virtual bool process() override; @@ -108,8 +99,6 @@ protected: std::list _preServerEdits; // these will get packed into other larger packets std::list> _preServerSingleMessagePackets; // these will go out as is - NodeToJurisdictionMap* _serverJurisdictions; - QMutex _releaseQueuedPacketMutex; // TODO: add locks for this and _pendingEditPackets diff --git a/libraries/octree/src/OctreeSceneStats.cpp b/libraries/octree/src/OctreeSceneStats.cpp index 09b2d6ddf5..054603440d 100644 --- a/libraries/octree/src/OctreeSceneStats.cpp +++ b/libraries/octree/src/OctreeSceneStats.cpp @@ -37,15 +37,13 @@ OctreeSceneStats::OctreeSceneStats() : _incomingBytes(0), _incomingWastedBytes(0), _incomingOctreeSequenceNumberStats(), - _incomingFlightTimeAverage(samples), - _jurisdictionRoot(NULL) + _incomingFlightTimeAverage(samples) { reset(); } // copy constructor -OctreeSceneStats::OctreeSceneStats(const OctreeSceneStats& other) : -_jurisdictionRoot(NULL) { +OctreeSceneStats::OctreeSceneStats(const OctreeSceneStats& other) { copyFromOther(other); } @@ -109,26 +107,6 @@ void OctreeSceneStats::copyFromOther(const OctreeSceneStats& other) { _existsInPacketBitsWritten = other._existsInPacketBitsWritten; _treesRemoved = other._treesRemoved; - // before copying the jurisdictions, delete any current values... - _jurisdictionRoot = nullptr; - _jurisdictionEndNodes.clear(); - - // Now copy the values from the other - if (other._jurisdictionRoot) { - auto bytes = bytesRequiredForCodeLength(numberOfThreeBitSectionsInCode(other._jurisdictionRoot.get())); - _jurisdictionRoot = createOctalCodePtr(bytes); - memcpy(_jurisdictionRoot.get(), other._jurisdictionRoot.get(), bytes); - } - for (size_t i = 0; i < other._jurisdictionEndNodes.size(); i++) { - auto& endNodeCode = other._jurisdictionEndNodes[i]; - if (endNodeCode) { - auto bytes = bytesRequiredForCodeLength(numberOfThreeBitSectionsInCode(endNodeCode.get())); - auto endNodeCodeCopy = createOctalCodePtr(bytes); - memcpy(endNodeCodeCopy.get(), endNodeCode.get(), bytes); - _jurisdictionEndNodes.push_back(endNodeCodeCopy); - } - } - _incomingPacket = other._incomingPacket; _incomingBytes = other._incomingBytes; _incomingWastedBytes = other._incomingWastedBytes; @@ -141,8 +119,7 @@ OctreeSceneStats::~OctreeSceneStats() { reset(); } -void OctreeSceneStats::sceneStarted(bool isFullScene, bool isMoving, const OctreeElementPointer& root, - JurisdictionMap* jurisdictionMap) { +void OctreeSceneStats::sceneStarted(bool isFullScene, bool isMoving, const OctreeElementPointer& root) { reset(); // resets packet and octree stats _isStarted = true; _start = usecTimestampNow(); @@ -153,14 +130,6 @@ void OctreeSceneStats::sceneStarted(bool isFullScene, bool isMoving, const Octre _isFullScene = isFullScene; _isMoving = isMoving; - - // setup jurisdictions - if (jurisdictionMap) { - std::tie(_jurisdictionRoot, _jurisdictionEndNodes) = jurisdictionMap->getRootAndEndNodeOctalCodes(); - } else { - _jurisdictionRoot = nullptr; - _jurisdictionEndNodes.clear(); - } } void OctreeSceneStats::sceneCompleted() { @@ -236,9 +205,6 @@ void OctreeSceneStats::reset() { _existsBitsWritten = 0; _existsInPacketBitsWritten = 0; _treesRemoved = 0; - - _jurisdictionRoot = nullptr; - _jurisdictionEndNodes.clear(); } void OctreeSceneStats::packetSent(int bytes) { @@ -374,29 +340,6 @@ int OctreeSceneStats::packIntoPacket() { _statsPacket->writePrimitive(_existsInPacketBitsWritten); _statsPacket->writePrimitive(_treesRemoved); - // add the root jurisdiction - if (_jurisdictionRoot) { - // copy the - int bytes = (int)bytesRequiredForCodeLength(numberOfThreeBitSectionsInCode(_jurisdictionRoot.get())); - _statsPacket->writePrimitive(bytes); - _statsPacket->write(reinterpret_cast(_jurisdictionRoot.get()), bytes); - - // if and only if there's a root jurisdiction, also include the end elements - int endNodeCount = (int)_jurisdictionEndNodes.size(); - - _statsPacket->writePrimitive(endNodeCount); - - for (int i=0; i < endNodeCount; i++) { - auto& endNodeCode = _jurisdictionEndNodes[i]; - auto bytes = bytesRequiredForCodeLength(numberOfThreeBitSectionsInCode(endNodeCode.get())); - _statsPacket->writePrimitive(bytes); - _statsPacket->write(reinterpret_cast(endNodeCode.get()), bytes); - } - } else { - int bytes = 0; - _statsPacket->writePrimitive(bytes); - } - return _statsPacket->getPayloadSize(); } @@ -458,38 +401,6 @@ int OctreeSceneStats::unpackFromPacket(ReceivedMessage& packet) { packet.readPrimitive(&_existsBitsWritten); packet.readPrimitive(&_existsInPacketBitsWritten); packet.readPrimitive(&_treesRemoved); - // before allocating new juridiction, clean up existing ones - _jurisdictionRoot = nullptr; - _jurisdictionEndNodes.clear(); - - // read the root jurisdiction - int bytes = 0; - packet.readPrimitive(&bytes); - - if (bytes == 0) { - _jurisdictionRoot = nullptr; - _jurisdictionEndNodes.clear(); - } else { - _jurisdictionRoot = createOctalCodePtr(bytes); - packet.read(reinterpret_cast(_jurisdictionRoot.get()), bytes); - - // if and only if there's a root jurisdiction, also include the end elements - _jurisdictionEndNodes.clear(); - - int endNodeCount = 0; - packet.readPrimitive(&endNodeCount); - - for (int i=0; i < endNodeCount; i++) { - int bytes = 0; - - packet.readPrimitive(&bytes); - - auto endNodeCode = createOctalCodePtr(bytes); - packet.read(reinterpret_cast(endNodeCode.get()), bytes); - - _jurisdictionEndNodes.push_back(endNodeCode); - } - } // running averages _elapsedAverage.updateAverage((float)_elapsed); diff --git a/libraries/octree/src/OctreeSceneStats.h b/libraries/octree/src/OctreeSceneStats.h index 3774d4287d..78b4dfd26f 100644 --- a/libraries/octree/src/OctreeSceneStats.h +++ b/libraries/octree/src/OctreeSceneStats.h @@ -17,7 +17,6 @@ #include #include -#include "JurisdictionMap.h" #include "OctreePacketData.h" #include "SequenceNumberStats.h" #include "OctalCode.h" @@ -39,7 +38,7 @@ public: OctreeSceneStats& operator= (const OctreeSceneStats& other); // copy assignment /// Call when beginning the computation of a scene. Initializes internal structures - void sceneStarted(bool fullScene, bool moving, const OctreeElementPointer& root, JurisdictionMap* jurisdictionMap); + void sceneStarted(bool fullScene, bool moving, const OctreeElementPointer& root); bool getIsSceneStarted() const { return _isStarted; } /// Call when the computation of a scene is completed. Finalizes internal structures @@ -143,12 +142,6 @@ public: /// \param Item item The item from the stats you're interested in. const char* getItemValue(Item item); - /// Returns OctCode for root element of the jurisdiction of this particular octree server - OctalCodePtr getJurisdictionRoot() const { return _jurisdictionRoot; } - - /// Returns list of OctCodes for end elements of the jurisdiction of this particular octree server - const OctalCodePtrList& getJurisdictionEndNodes() const { return _jurisdictionEndNodes; } - bool isMoving() const { return _isMoving; } bool isFullScene() const { return _isFullScene; } quint64 getTotalElements() const { return _totalElements; } @@ -277,9 +270,6 @@ private: static ItemInfo _ITEMS[]; static const int MAX_ITEM_VALUE_LENGTH = 128; char _itemValueBuffer[MAX_ITEM_VALUE_LENGTH]; - - OctalCodePtr _jurisdictionRoot; - std::vector _jurisdictionEndNodes; }; /// Map between element IDs and their reported OctreeSceneStats. Typically used by classes that need to know which elements sent diff --git a/libraries/octree/src/OctreeScriptingInterface.cpp b/libraries/octree/src/OctreeScriptingInterface.cpp index 8913e88cf5..618e8ac469 100644 --- a/libraries/octree/src/OctreeScriptingInterface.cpp +++ b/libraries/octree/src/OctreeScriptingInterface.cpp @@ -13,12 +13,9 @@ #include "OctreeScriptingInterface.h" -OctreeScriptingInterface::OctreeScriptingInterface(OctreeEditPacketSender* packetSender, - JurisdictionListener* jurisdictionListener) : +OctreeScriptingInterface::OctreeScriptingInterface(OctreeEditPacketSender* packetSender) : _packetSender(packetSender), - _jurisdictionListener(jurisdictionListener), - _managedPacketSender(false), - _managedJurisdictionListener(false), + _managedPacketSender(false), _initialized(false) { } @@ -28,12 +25,6 @@ OctreeScriptingInterface::~OctreeScriptingInterface() { } void OctreeScriptingInterface::cleanupManagedObjects() { - if (_managedJurisdictionListener) { - _jurisdictionListener->terminate(); - _jurisdictionListener->deleteLater(); - _managedJurisdictionListener = false; - _jurisdictionListener = NULL; - } if (_managedPacketSender) { _packetSender->terminate(); _packetSender->deleteLater(); @@ -46,29 +37,16 @@ void OctreeScriptingInterface::setPacketSender(OctreeEditPacketSender* packetSen _packetSender = packetSender; } -void OctreeScriptingInterface::setJurisdictionListener(JurisdictionListener* jurisdictionListener) { - _jurisdictionListener = jurisdictionListener; -} - void OctreeScriptingInterface::init() { if (_initialized) { return; } - if (_jurisdictionListener) { - _managedJurisdictionListener = false; - } else { - _managedJurisdictionListener = true; - _jurisdictionListener = new JurisdictionListener(getServerNodeType()); - _jurisdictionListener->initialize(true); - } - if (_packetSender) { _managedPacketSender = false; } else { _managedPacketSender = true; _packetSender = createPacketSender(); - _packetSender->setServerJurisdictions(_jurisdictionListener->getJurisdictions()); } if (QCoreApplication::instance()) { diff --git a/libraries/octree/src/OctreeScriptingInterface.h b/libraries/octree/src/OctreeScriptingInterface.h index 86b9730393..c31da94532 100644 --- a/libraries/octree/src/OctreeScriptingInterface.h +++ b/libraries/octree/src/OctreeScriptingInterface.h @@ -14,21 +14,18 @@ #include -#include "JurisdictionListener.h" #include "OctreeEditPacketSender.h" /// handles scripting of Particle commands from JS passed to assigned clients class OctreeScriptingInterface : public QObject { Q_OBJECT public: - OctreeScriptingInterface(OctreeEditPacketSender* packetSender = NULL, JurisdictionListener* jurisdictionListener = NULL); + OctreeScriptingInterface(OctreeEditPacketSender* packetSender = nullptr); ~OctreeScriptingInterface(); OctreeEditPacketSender* getPacketSender() const { return _packetSender; } - JurisdictionListener* getJurisdictionListener() const { return _jurisdictionListener; } void setPacketSender(OctreeEditPacketSender* packetSender); - void setJurisdictionListener(JurisdictionListener* jurisdictionListener); void init(); virtual NodeType_t getServerNodeType() const = 0; @@ -86,9 +83,7 @@ public slots: protected: /// attached OctreeEditPacketSender that handles queuing and sending of packets to VS OctreeEditPacketSender* _packetSender = nullptr; - JurisdictionListener* _jurisdictionListener = nullptr; bool _managedPacketSender; - bool _managedJurisdictionListener; bool _initialized; }; From 06e2f394f9e23819c4e04e62b74d560f6feb1ca9 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 4 Dec 2017 17:12:09 -0800 Subject: [PATCH 27/29] Update Octree server stats to handle single server --- .../hifi/dialogs/TabletEntityStatistics.qml | 146 +++++++------- interface/src/ui/OctreeStatsDialog.cpp | 153 ++++++-------- interface/src/ui/OctreeStatsDialog.h | 35 ++-- interface/src/ui/OctreeStatsProvider.cpp | 187 ++++++++---------- interface/src/ui/OctreeStatsProvider.h | 13 +- 5 files changed, 234 insertions(+), 300 deletions(-) diff --git a/interface/resources/qml/hifi/dialogs/TabletEntityStatistics.qml b/interface/resources/qml/hifi/dialogs/TabletEntityStatistics.qml index da295917a0..cf3e39a885 100644 --- a/interface/resources/qml/hifi/dialogs/TabletEntityStatistics.qml +++ b/interface/resources/qml/hifi/dialogs/TabletEntityStatistics.qml @@ -154,90 +154,86 @@ Rectangle { color: OctreeStats.getColor() } - Repeater { - model: OctreeStats.serversNum + Column { + id: serverColumn + width: scrollView.width - 10 + x: 5 + spacing: 5 - delegate: Column { - id: serverColumn - width: scrollView.width - 10 - x: 5 - spacing: 5 + state: "less" - state: "less" + TabletEntityStatisticsItem { + id: serverStats + width: parent.width + titleText: qsTr("Entity Server") + ":" + colorScheme: root.colorScheme + color: OctreeStats.getColor() + } - TabletEntityStatisticsItem { - id: serverStats - width: parent.width - titleText: qsTr("Entity Server ") + (index+1) + ":" + Row { + id: buttonsRow + width: parent.width + height: 30 + spacing: 10 + + HifiControls.Button { + id: moreButton + color: hifi.buttons.blue colorScheme: root.colorScheme - color: OctreeStats.getColor() - } - - Row { - id: buttonsRow - width: parent.width + width: parent.width / 2 - 10 height: 30 - spacing: 10 - - HifiControls.Button { - id: moreButton - color: hifi.buttons.blue - colorScheme: root.colorScheme - width: parent.width / 2 - 10 - height: 30 - onClicked: { - if (serverColumn.state === "less") { - serverColumn.state = "more" - } else if (serverColumn.state === "more") { - serverColumn.state = "most" - } else { - serverColumn.state = "more" - } + onClicked: { + if (serverColumn.state === "less") { + serverColumn.state = "more" + } else if (serverColumn.state === "more") { + serverColumn.state = "most" + } else { + serverColumn.state = "more" } } - HifiControls.Button { - id: mostButton - color: hifi.buttons.blue - colorScheme: root.colorScheme - height: 30 - width: parent.width / 2 - 10 - onClicked: { - if (serverColumn.state === "less") { - serverColumn.state = "most" - } else if (serverColumn.state === "more") { - serverColumn.state = "less" - } else { - serverColumn.state = "less" - } - } - - } } - states: [ - State { - name: "less" - PropertyChanges { target: moreButton; text: qsTr("more..."); } - PropertyChanges { target: mostButton; text: qsTr("most..."); } - PropertyChanges { target: serverStats; text: OctreeStats.servers[index*3]; } - }, - State { - name: "more" - PropertyChanges { target: moreButton; text: qsTr("most..."); } - PropertyChanges { target: mostButton; text: qsTr("less..."); } - PropertyChanges { target: serverStats; text: OctreeStats.servers[index*3] + - OctreeStats.servers[index*3 + 1]; } - }, - State { - name: "most" - PropertyChanges { target: moreButton; text: qsTr("less..."); } - PropertyChanges { target: mostButton; text: qsTr("least..."); } - PropertyChanges { target: serverStats; text: OctreeStats.servers[index*3] + - OctreeStats.servers[index*3 + 1] + - OctreeStats.servers[index*3 + 2]; } + HifiControls.Button { + id: mostButton + color: hifi.buttons.blue + colorScheme: root.colorScheme + height: 30 + width: parent.width / 2 - 10 + onClicked: { + if (serverColumn.state === "less") { + serverColumn.state = "most" + } else if (serverColumn.state === "more") { + serverColumn.state = "less" + } else { + serverColumn.state = "less" + } } - ] - } //servers column - } //repeater + + } + } + states: [ + State { + name: "less" + PropertyChanges { target: moreButton; text: qsTr("more..."); } + PropertyChanges { target: mostButton; text: qsTr("most..."); } + PropertyChanges { target: serverStats; text: OctreeStats.servers[0]; } + }, + State { + name: "more" + PropertyChanges { target: moreButton; text: qsTr("most..."); } + PropertyChanges { target: mostButton; text: qsTr("less..."); } + PropertyChanges { target: serverStats; text: OctreeStats.servers[0] + + OctreeStats.servers[1]; } + }, + State { + name: "most" + PropertyChanges { target: moreButton; text: qsTr("less..."); } + PropertyChanges { target: mostButton; text: qsTr("least..."); } + PropertyChanges { target: serverStats; text: OctreeStats.servers[0] + + OctreeStats.servers[1] + + OctreeStats.servers[2]; } + } + ] + } //servers column } //column } //flickable } diff --git a/interface/src/ui/OctreeStatsDialog.cpp b/interface/src/ui/OctreeStatsDialog.cpp index 77ed29d5ae..ec5d800042 100644 --- a/interface/src/ui/OctreeStatsDialog.cpp +++ b/interface/src/ui/OctreeStatsDialog.cpp @@ -26,27 +26,17 @@ OctreeStatsDialog::OctreeStatsDialog(QWidget* parent, NodeToOctreeSceneStats* model) : QDialog(parent, Qt::Window | Qt::WindowCloseButtonHint | Qt::WindowStaysOnTopHint), - _model(model), - _averageUpdatesPerSecond(SAMPLES_PER_SECOND) + _model(model) { - - _statCount = 0; - _octreeServerLabelsCount = 0; - - for (int i = 0; i < MAX_VOXEL_SERVERS; i++) { - _octreeServerLables[i] = 0; - _extraServerDetails[i] = LESS; - } - for (int i = 0; i < MAX_STATS; i++) { - _labels[i] = NULL; + _labels[i] = nullptr; } - this->setWindowTitle("Octree Server Statistics"); + setWindowTitle("Octree Server Statistics"); // Create layouter _form = new QFormLayout(); - this->QDialog::setLayout(_form); + setLayout(_form); // Setup stat items _serverElements = AddStatItem("Elements on Servers"); @@ -63,7 +53,14 @@ OctreeStatsDialog::OctreeStatsDialog(QWidget* parent, NodeToOctreeSceneStats* mo _entityUpdateTime = AddStatItem("Entity Update Time"); _entityUpdates = AddStatItem("Entity Updates"); - + + + _octreeServerLabel = AddStatItem("Entity Server"); + _labels[_octreeServerLabel]->setTextFormat(Qt::RichText); + _labels[_octreeServerLabel]->setTextInteractionFlags(Qt::TextBrowserInteraction); + connect(_labels[_octreeServerLabel], SIGNAL(linkActivated(const QString&)), + this, SLOT(moreless(const QString&))); + layout()->setSizeConstraint(QLayout::SetFixedSize); } @@ -74,23 +71,16 @@ void OctreeStatsDialog::RemoveStatItem(int item) { _form->removeWidget(automaticLabel); automaticLabel->deleteLater(); myLabel->deleteLater(); - _labels[item] = NULL; + _labels[item] = nullptr; } void OctreeStatsDialog::moreless(const QString& link) { - QStringList linkDetails = link.split("-"); - const int COMMAND_ITEM = 0; - const int SERVER_NUMBER_ITEM = 1; - QString serverNumberString = linkDetails[SERVER_NUMBER_ITEM]; - QString command = linkDetails[COMMAND_ITEM]; - int serverNumber = serverNumberString.toInt(); - - if (command == "more") { - _extraServerDetails[serverNumber-1] = MORE; - } else if (command == "most") { - _extraServerDetails[serverNumber-1] = MOST; + if (link == "more") { + _extraServerDetails = MORE; + } else if (link == "most") { + _extraServerDetails = MOST; } else { - _extraServerDetails[serverNumber-1] = LESS; + _extraServerDetails = LESS; } } @@ -376,60 +366,34 @@ void OctreeStatsDialog::paintEvent(QPaintEvent* event) { QDialog::paintEvent(event); } void OctreeStatsDialog::showAllOctreeServers() { - int serverCount = 0; - - showOctreeServersOfType(serverCount, NodeType::EntityServer, "Entity"); - - if (_octreeServerLabelsCount > serverCount) { - for (int i = serverCount; i < _octreeServerLabelsCount; i++) { - int serverLabel = _octreeServerLables[i]; - RemoveStatItem(serverLabel); - _octreeServerLables[i] = 0; - } - _octreeServerLabelsCount = serverCount; - } + showOctreeServersOfType(NodeType::EntityServer); } -void OctreeStatsDialog::showOctreeServersOfType(int& serverCount, NodeType_t serverType, const char* serverTypeName) { - +void OctreeStatsDialog::showOctreeServersOfType(NodeType_t serverType) { QLocale locale(QLocale::English); - auto nodeList = DependencyManager::get(); - nodeList->eachNode([&](const SharedNodePointer& node){ - - // only send to the NodeTypes that are NodeType_t_VOXEL_SERVER - if (node->getType() == serverType) { - serverCount++; - - if (serverCount > _octreeServerLabelsCount) { - QString label = QString("%1 Server %2").arg(serverTypeName).arg(serverCount); - int thisServerRow = _octreeServerLables[serverCount-1] = AddStatItem(label.toUtf8().constData()); - _labels[thisServerRow]->setTextFormat(Qt::RichText); - _labels[thisServerRow]->setTextInteractionFlags(Qt::TextBrowserInteraction); - connect(_labels[thisServerRow], SIGNAL(linkActivated(const QString&)), this, SLOT(moreless(const QString&))); - _octreeServerLabelsCount++; - } - - std::stringstream serverDetails(""); - std::stringstream extraDetails(""); - std::stringstream linkDetails(""); - - if (node->getActiveSocket()) { - serverDetails << "active "; - } else { - serverDetails << "inactive "; - } - - QUuid nodeUUID = node->getUUID(); - - // now lookup stats details for this server... - if (_extraServerDetails[serverCount-1] != LESS) { - NodeToOctreeSceneStats* sceneStats = qApp->getOcteeSceneStats(); - sceneStats->withReadLock([&] { - if (sceneStats->find(nodeUUID) != sceneStats->end()) { - OctreeSceneStats& stats = sceneStats->at(nodeUUID); + auto node = DependencyManager::get()->soloNodeOfType(serverType); + if (node) { + std::stringstream serverDetails(""); + std::stringstream extraDetails(""); + std::stringstream linkDetails(""); - switch (_extraServerDetails[serverCount - 1]) { + if (node->getActiveSocket()) { + serverDetails << "active "; + } else { + serverDetails << "inactive "; + } + + QUuid nodeUUID = node->getUUID(); + + // now lookup stats details for this server... + if (_extraServerDetails != LESS) { + NodeToOctreeSceneStats* sceneStats = qApp->getOcteeSceneStats(); + sceneStats->withReadLock([&] { + if (sceneStats->find(nodeUUID) != sceneStats->end()) { + OctreeSceneStats& stats = sceneStats->at(nodeUUID); + + switch (_extraServerDetails) { case MOST: { extraDetails << "
"; @@ -507,7 +471,7 @@ void OctreeStatsDialog::showOctreeServersOfType(int& serverCount, NodeType_t ser " Average Ping Time: " << qPrintable(incomingPingTimeString) << " msecs"; serverDetails << "
" << - " Average Clock Skew: " << qPrintable(incomingClockSkewString) << " msecs" << + " Average Clock Skew: " << qPrintable(incomingClockSkewString) << " msecs" << " [" << qPrintable(formattedClockSkewString) << "]"; @@ -516,38 +480,37 @@ void OctreeStatsDialog::showOctreeServersOfType(int& serverCount, NodeType_t ser " Wasted Bytes: " << qPrintable(incomingWastedBytesString); serverDetails << extraDetails.str(); - if (_extraServerDetails[serverCount - 1] == MORE) { - linkDetails << " " << " [most...]"; - linkDetails << " " << " [less...]"; + if (_extraServerDetails == MORE) { + linkDetails << " [most...]"; + linkDetails << " [less...]"; } else { - linkDetails << " " << " [less...]"; - linkDetails << " " << " [least...]"; + linkDetails << " [less...]"; + linkDetails << " [least...]"; } } break; case LESS: { // nothing } break; - } } - }); - } else { - linkDetails << " " << " [more...]"; - linkDetails << " " << " [most...]"; - } - serverDetails << linkDetails.str(); - _labels[_octreeServerLables[serverCount - 1]]->setText(serverDetails.str().c_str()); - } // is VOXEL_SERVER - }); + } + }); + } else { + linkDetails << " [more...]"; + linkDetails << " [most...]"; + } + serverDetails << linkDetails.str(); + _labels[_octreeServerLabel]->setText(serverDetails.str().c_str()); + } } void OctreeStatsDialog::reject() { // Just regularly close upon ESC - this->QDialog::close(); + QDialog::close(); } void OctreeStatsDialog::closeEvent(QCloseEvent* event) { - this->QDialog::closeEvent(event); + QDialog::closeEvent(event); emit closed(); } diff --git a/interface/src/ui/OctreeStatsDialog.h b/interface/src/ui/OctreeStatsDialog.h index 7686b7c726..81bf5f251f 100644 --- a/interface/src/ui/OctreeStatsDialog.h +++ b/interface/src/ui/OctreeStatsDialog.h @@ -19,7 +19,6 @@ #include #define MAX_STATS 100 -#define MAX_VOXEL_SERVERS 50 #define DEFAULT_COLOR 0 class OctreeStatsDialog : public QDialog { @@ -47,18 +46,22 @@ protected: void RemoveStatItem(int item); void showAllOctreeServers(); - void showOctreeServersOfType(int& serverNumber, NodeType_t serverType, - const char* serverTypeName); + void showOctreeServersOfType(NodeType_t serverType); private: + enum details { + LESS, + MORE, + MOST + }; - typedef enum { LESS, MORE, MOST } details; - - QFormLayout* _form; + QFormLayout* _form { nullptr }; QLabel* _labels[MAX_STATS]; - NodeToOctreeSceneStats* _model; - int _statCount; - + NodeToOctreeSceneStats* _model { nullptr }; + int _statCount { 0 }; + + int _octreeServerLabel; + int _sendingMode; int _serverElements; int _localElements; @@ -72,16 +75,14 @@ private: int _processedPacketsTiming; int _outboundEditPackets; - const int SAMPLES_PER_SECOND = 10; - SimpleMovingAverage _averageUpdatesPerSecond; - quint64 _lastWindowAt = usecTimestampNow(); - quint64 _lastKnownTrackedEdits = 0; + const int SAMPLES_PER_SECOND { 10 }; + SimpleMovingAverage _averageUpdatesPerSecond { SAMPLES_PER_SECOND }; + quint64 _lastWindowAt { usecTimestampNow() }; + quint64 _lastKnownTrackedEdits { 0 }; - quint64 _lastRefresh = 0; + quint64 _lastRefresh { 0 }; - int _octreeServerLables[MAX_VOXEL_SERVERS]; - int _octreeServerLabelsCount; - details _extraServerDetails[MAX_VOXEL_SERVERS]; + details _extraServerDetails { LESS }; }; #endif // hifi_OctreeStatsDialog_h diff --git a/interface/src/ui/OctreeStatsProvider.cpp b/interface/src/ui/OctreeStatsProvider.cpp index e35524f5f8..0358685d70 100644 --- a/interface/src/ui/OctreeStatsProvider.cpp +++ b/interface/src/ui/OctreeStatsProvider.cpp @@ -16,9 +16,9 @@ OctreeStatsProvider::OctreeStatsProvider(QObject* parent, NodeToOctreeSceneStats* model) : QObject(parent), - _model(model) - , _statCount(0) - , _averageUpdatesPerSecond(SAMPLES_PER_SECOND) + _model(model), + _statCount(0), + _averageUpdatesPerSecond(SAMPLES_PER_SECOND) { //schedule updates connect(&_updateTimer, &QTimer::timeout, this, &OctreeStatsProvider::updateOctreeStatsData); @@ -57,10 +57,6 @@ OctreeStatsProvider::~OctreeStatsProvider() { _updateTimer.stop(); } -int OctreeStatsProvider::serversNum() const { - return m_serversNum; -} - void OctreeStatsProvider::updateOctreeStatsData() { // Processed Entities Related stats @@ -237,110 +233,97 @@ void OctreeStatsProvider::updateOctreeStatsData() { } void OctreeStatsProvider::updateOctreeServers() { - int serverCount = 0; - - showOctreeServersOfType(serverCount, NodeType::EntityServer, "Entity"); - if (m_serversNum != serverCount) { - m_serversNum = serverCount; - emit serversNumChanged(m_serversNum); - } + showOctreeServersOfType(NodeType::EntityServer); } -void OctreeStatsProvider::showOctreeServersOfType(int& serverCount, NodeType_t serverType, const char* serverTypeName) { - +void OctreeStatsProvider::showOctreeServersOfType(NodeType_t serverType) { m_servers.clear(); - auto nodeList = DependencyManager::get(); - nodeList->eachNode([&](const SharedNodePointer& node) { - - // only send to the NodeTypes that are NodeType_t_VOXEL_SERVER - if (node->getType() == serverType) { - serverCount++; - - QString lesserDetails; - QString moreDetails; - QString mostDetails; - - if (node->getActiveSocket()) { - lesserDetails += "active "; - } else { - lesserDetails += "inactive "; - } - - QUuid nodeUUID = node->getUUID(); + auto node = DependencyManager::get()->soloNodeOfType(serverType); + if (node) { + QString lesserDetails; + QString moreDetails; + QString mostDetails; - // now lookup stats details for this server... - NodeToOctreeSceneStats* sceneStats = qApp->getOcteeSceneStats(); - sceneStats->withReadLock([&] { - if (sceneStats->find(nodeUUID) != sceneStats->end()) { - OctreeSceneStats& stats = sceneStats->at(nodeUUID); + if (node->getActiveSocket()) { + lesserDetails += "active "; + } else { + lesserDetails += "inactive "; + } - float lastFullEncode = stats.getLastFullTotalEncodeTime() / USECS_PER_MSEC; - float lastFullSend = stats.getLastFullElapsedTime() / USECS_PER_MSEC; - float lastFullSendInSeconds = stats.getLastFullElapsedTime() / USECS_PER_SECOND; - float lastFullPackets = stats.getLastFullTotalPackets(); - float lastFullPPS = lastFullPackets; - if (lastFullSendInSeconds > 0) { - lastFullPPS = lastFullPackets / lastFullSendInSeconds; - } + QUuid nodeUUID = node->getUUID(); - mostDetails += QString("

Last Full Scene... Encode: %1 ms Send: %2 ms Packets: %3 Bytes: %4 Rate: %5 PPS") - .arg(lastFullEncode) - .arg(lastFullSend) - .arg(lastFullPackets) - .arg(stats.getLastFullTotalBytes()) - .arg(lastFullPPS); + // now lookup stats details for this server... + NodeToOctreeSceneStats* sceneStats = qApp->getOcteeSceneStats(); + sceneStats->withReadLock([&] { + if (sceneStats->find(nodeUUID) != sceneStats->end()) { + OctreeSceneStats& stats = sceneStats->at(nodeUUID); - for (int i = 0; i < OctreeSceneStats::ITEM_COUNT; i++) { - OctreeSceneStats::Item item = (OctreeSceneStats::Item)(i); - OctreeSceneStats::ItemInfo& itemInfo = stats.getItemInfo(item); - mostDetails += QString("
%1 %2") - .arg(itemInfo.caption).arg(stats.getItemValue(item)); - } - - moreDetails += "
Node UUID: " +nodeUUID.toString() + " "; - - moreDetails += QString("
Elements: %1 total %2 internal %3 leaves ") - .arg(stats.getTotalElements()) - .arg(stats.getTotalInternal()) - .arg(stats.getTotalLeaves()); - - const SequenceNumberStats& seqStats = stats.getIncomingOctreeSequenceNumberStats(); - qint64 clockSkewInUsecs = node->getClockSkewUsec(); - qint64 clockSkewInMS = clockSkewInUsecs / (qint64)USECS_PER_MSEC; - - moreDetails += QString("
Incoming Packets: %1/ Lost: %2/ Recovered: %3") - .arg(stats.getIncomingPackets()) - .arg(seqStats.getLost()) - .arg(seqStats.getRecovered()); - - moreDetails += QString("
Out of Order: %1/ Early: %2/ Late: %3/ Unreasonable: %4") - .arg(seqStats.getOutOfOrder()) - .arg(seqStats.getEarly()) - .arg(seqStats.getLate()) - .arg(seqStats.getUnreasonable()); - - moreDetails += QString("
Average Flight Time: %1 msecs") - .arg(stats.getIncomingFlightTimeAverage()); - - moreDetails += QString("
Average Ping Time: %1 msecs") - .arg(node->getPingMs()); - - moreDetails += QString("
Average Clock Skew: %1 msecs [%2]") - .arg(clockSkewInMS) - .arg(formatUsecTime(clockSkewInUsecs)); - - - moreDetails += QString("
Incoming Bytes: %1 Wasted Bytes: %2") - .arg(stats.getIncomingBytes()) - .arg(stats.getIncomingWastedBytes()); + float lastFullEncode = stats.getLastFullTotalEncodeTime() / USECS_PER_MSEC; + float lastFullSend = stats.getLastFullElapsedTime() / USECS_PER_MSEC; + float lastFullSendInSeconds = stats.getLastFullElapsedTime() / USECS_PER_SECOND; + float lastFullPackets = stats.getLastFullTotalPackets(); + float lastFullPPS = lastFullPackets; + if (lastFullSendInSeconds > 0) { + lastFullPPS = lastFullPackets / lastFullSendInSeconds; } - }); - m_servers.append(lesserDetails); - m_servers.append(moreDetails); - m_servers.append(mostDetails); - } // is VOXEL_SERVER - }); + + mostDetails += QString("

Last Full Scene... Encode: %1 ms Send: %2 ms Packets: %3 Bytes: %4 Rate: %5 PPS") + .arg(lastFullEncode) + .arg(lastFullSend) + .arg(lastFullPackets) + .arg(stats.getLastFullTotalBytes()) + .arg(lastFullPPS); + + for (int i = 0; i < OctreeSceneStats::ITEM_COUNT; i++) { + OctreeSceneStats::Item item = (OctreeSceneStats::Item)(i); + OctreeSceneStats::ItemInfo& itemInfo = stats.getItemInfo(item); + mostDetails += QString("
%1 %2") + .arg(itemInfo.caption).arg(stats.getItemValue(item)); + } + + moreDetails += "
Node UUID: " +nodeUUID.toString() + " "; + + moreDetails += QString("
Elements: %1 total %2 internal %3 leaves ") + .arg(stats.getTotalElements()) + .arg(stats.getTotalInternal()) + .arg(stats.getTotalLeaves()); + + const SequenceNumberStats& seqStats = stats.getIncomingOctreeSequenceNumberStats(); + qint64 clockSkewInUsecs = node->getClockSkewUsec(); + qint64 clockSkewInMS = clockSkewInUsecs / (qint64)USECS_PER_MSEC; + + moreDetails += QString("
Incoming Packets: %1/ Lost: %2/ Recovered: %3") + .arg(stats.getIncomingPackets()) + .arg(seqStats.getLost()) + .arg(seqStats.getRecovered()); + + moreDetails += QString("
Out of Order: %1/ Early: %2/ Late: %3/ Unreasonable: %4") + .arg(seqStats.getOutOfOrder()) + .arg(seqStats.getEarly()) + .arg(seqStats.getLate()) + .arg(seqStats.getUnreasonable()); + + moreDetails += QString("
Average Flight Time: %1 msecs") + .arg(stats.getIncomingFlightTimeAverage()); + + moreDetails += QString("
Average Ping Time: %1 msecs") + .arg(node->getPingMs()); + + moreDetails += QString("
Average Clock Skew: %1 msecs [%2]") + .arg(clockSkewInMS) + .arg(formatUsecTime(clockSkewInUsecs)); + + + moreDetails += QString("
Incoming Bytes: %1 Wasted Bytes: %2") + .arg(stats.getIncomingBytes()) + .arg(stats.getIncomingWastedBytes()); + } + }); + m_servers.append(lesserDetails); + m_servers.append(moreDetails); + m_servers.append(mostDetails); + } emit serversChanged(m_servers); } diff --git a/interface/src/ui/OctreeStatsProvider.h b/interface/src/ui/OctreeStatsProvider.h index 04aff24edd..c73f0960f6 100644 --- a/interface/src/ui/OctreeStatsProvider.h +++ b/interface/src/ui/OctreeStatsProvider.h @@ -18,15 +18,10 @@ #include "DependencyManager.h" -#define MAX_STATS 100 -#define MAX_VOXEL_SERVERS 50 -#define DEFAULT_COLOR 0 - class OctreeStatsProvider : public QObject, public Dependency { Q_OBJECT SINGLETON_DEPENDENCY - Q_PROPERTY(int serversNum READ serversNum NOTIFY serversNumChanged) Q_PROPERTY(QString serverElements READ serverElements NOTIFY serverElementsChanged) Q_PROPERTY(QString localElements READ localElements NOTIFY localElementsChanged) Q_PROPERTY(QString localElementsMemory READ localElementsMemory NOTIFY localElementsMemoryChanged) @@ -45,8 +40,6 @@ public: OctreeStatsProvider(QObject* parent, NodeToOctreeSceneStats* model); ~OctreeStatsProvider(); - int serversNum() const; - QString serverElements() const { return m_serverElements; } @@ -96,8 +89,6 @@ public: } signals: - - void serversNumChanged(int serversNum); void serverElementsChanged(const QString &serverElements); void localElementsChanged(const QString &localElements); void sendingModeChanged(const QString &sendingMode); @@ -121,7 +112,7 @@ private slots: void updateOctreeStatsData(); protected: void updateOctreeServers(); - void showOctreeServersOfType(int& serverNumber, NodeType_t serverType, const char* serverTypeName); + void showOctreeServersOfType(NodeType_t serverType); private: NodeToOctreeSceneStats* _model; @@ -135,7 +126,7 @@ private: quint64 _lastRefresh = 0; QTimer _updateTimer; - int m_serversNum {0}; + QString m_serverElements; QString m_localElements; QString m_localElementsMemory; From aec5ab59213457e4558910fce32ec07b50344cb0 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 7 Dec 2017 11:49:05 -0800 Subject: [PATCH 28/29] CR --- .../hifi/dialogs/TabletEntityStatistics.qml | 144 +++++++++--------- interface/src/ui/OctreeStatsProvider.cpp | 12 ++ interface/src/ui/OctreeStatsProvider.h | 7 +- libraries/networking/src/LimitedNodeList.cpp | 5 +- 4 files changed, 96 insertions(+), 72 deletions(-) diff --git a/interface/resources/qml/hifi/dialogs/TabletEntityStatistics.qml b/interface/resources/qml/hifi/dialogs/TabletEntityStatistics.qml index cf3e39a885..da295917a0 100644 --- a/interface/resources/qml/hifi/dialogs/TabletEntityStatistics.qml +++ b/interface/resources/qml/hifi/dialogs/TabletEntityStatistics.qml @@ -154,86 +154,90 @@ Rectangle { color: OctreeStats.getColor() } - Column { - id: serverColumn - width: scrollView.width - 10 - x: 5 - spacing: 5 + Repeater { + model: OctreeStats.serversNum - state: "less" + delegate: Column { + id: serverColumn + width: scrollView.width - 10 + x: 5 + spacing: 5 - TabletEntityStatisticsItem { - id: serverStats - width: parent.width - titleText: qsTr("Entity Server") + ":" - colorScheme: root.colorScheme - color: OctreeStats.getColor() - } + state: "less" - Row { - id: buttonsRow - width: parent.width - height: 30 - spacing: 10 - - HifiControls.Button { - id: moreButton - color: hifi.buttons.blue + TabletEntityStatisticsItem { + id: serverStats + width: parent.width + titleText: qsTr("Entity Server ") + (index+1) + ":" colorScheme: root.colorScheme - width: parent.width / 2 - 10 + color: OctreeStats.getColor() + } + + Row { + id: buttonsRow + width: parent.width height: 30 - onClicked: { - if (serverColumn.state === "less") { - serverColumn.state = "more" - } else if (serverColumn.state === "more") { - serverColumn.state = "most" - } else { - serverColumn.state = "more" + spacing: 10 + + HifiControls.Button { + id: moreButton + color: hifi.buttons.blue + colorScheme: root.colorScheme + width: parent.width / 2 - 10 + height: 30 + onClicked: { + if (serverColumn.state === "less") { + serverColumn.state = "more" + } else if (serverColumn.state === "more") { + serverColumn.state = "most" + } else { + serverColumn.state = "more" + } } } - } - HifiControls.Button { - id: mostButton - color: hifi.buttons.blue - colorScheme: root.colorScheme - height: 30 - width: parent.width / 2 - 10 - onClicked: { - if (serverColumn.state === "less") { - serverColumn.state = "most" - } else if (serverColumn.state === "more") { - serverColumn.state = "less" - } else { - serverColumn.state = "less" + HifiControls.Button { + id: mostButton + color: hifi.buttons.blue + colorScheme: root.colorScheme + height: 30 + width: parent.width / 2 - 10 + onClicked: { + if (serverColumn.state === "less") { + serverColumn.state = "most" + } else if (serverColumn.state === "more") { + serverColumn.state = "less" + } else { + serverColumn.state = "less" + } } - } + } } - } - states: [ - State { - name: "less" - PropertyChanges { target: moreButton; text: qsTr("more..."); } - PropertyChanges { target: mostButton; text: qsTr("most..."); } - PropertyChanges { target: serverStats; text: OctreeStats.servers[0]; } - }, - State { - name: "more" - PropertyChanges { target: moreButton; text: qsTr("most..."); } - PropertyChanges { target: mostButton; text: qsTr("less..."); } - PropertyChanges { target: serverStats; text: OctreeStats.servers[0] + - OctreeStats.servers[1]; } - }, - State { - name: "most" - PropertyChanges { target: moreButton; text: qsTr("less..."); } - PropertyChanges { target: mostButton; text: qsTr("least..."); } - PropertyChanges { target: serverStats; text: OctreeStats.servers[0] + - OctreeStats.servers[1] + - OctreeStats.servers[2]; } - } - ] - } //servers column + states: [ + State { + name: "less" + PropertyChanges { target: moreButton; text: qsTr("more..."); } + PropertyChanges { target: mostButton; text: qsTr("most..."); } + PropertyChanges { target: serverStats; text: OctreeStats.servers[index*3]; } + }, + State { + name: "more" + PropertyChanges { target: moreButton; text: qsTr("most..."); } + PropertyChanges { target: mostButton; text: qsTr("less..."); } + PropertyChanges { target: serverStats; text: OctreeStats.servers[index*3] + + OctreeStats.servers[index*3 + 1]; } + }, + State { + name: "most" + PropertyChanges { target: moreButton; text: qsTr("less..."); } + PropertyChanges { target: mostButton; text: qsTr("least..."); } + PropertyChanges { target: serverStats; text: OctreeStats.servers[index*3] + + OctreeStats.servers[index*3 + 1] + + OctreeStats.servers[index*3 + 2]; } + } + ] + } //servers column + } //repeater } //column } //flickable } diff --git a/interface/src/ui/OctreeStatsProvider.cpp b/interface/src/ui/OctreeStatsProvider.cpp index 0358685d70..a393660c17 100644 --- a/interface/src/ui/OctreeStatsProvider.cpp +++ b/interface/src/ui/OctreeStatsProvider.cpp @@ -57,6 +57,10 @@ OctreeStatsProvider::~OctreeStatsProvider() { _updateTimer.stop(); } +int OctreeStatsProvider::serversNum() const { + return m_serversNum; +} + void OctreeStatsProvider::updateOctreeStatsData() { // Processed Entities Related stats @@ -238,9 +242,12 @@ void OctreeStatsProvider::updateOctreeServers() { void OctreeStatsProvider::showOctreeServersOfType(NodeType_t serverType) { m_servers.clear(); + int serverCount = 0; auto node = DependencyManager::get()->soloNodeOfType(serverType); if (node) { + ++serverCount; + QString lesserDetails; QString moreDetails; QString mostDetails; @@ -324,6 +331,11 @@ void OctreeStatsProvider::showOctreeServersOfType(NodeType_t serverType) { m_servers.append(moreDetails); m_servers.append(mostDetails); } + + if (serverCount != m_serversNum) { + m_serversNum = serverCount; + emit serversNumChanged(m_serversNum); + } emit serversChanged(m_servers); } diff --git a/interface/src/ui/OctreeStatsProvider.h b/interface/src/ui/OctreeStatsProvider.h index c73f0960f6..5b3d4d735c 100644 --- a/interface/src/ui/OctreeStatsProvider.h +++ b/interface/src/ui/OctreeStatsProvider.h @@ -22,6 +22,7 @@ class OctreeStatsProvider : public QObject, public Dependency { Q_OBJECT SINGLETON_DEPENDENCY + Q_PROPERTY(int serversNum READ serversNum NOTIFY serversNumChanged) Q_PROPERTY(QString serverElements READ serverElements NOTIFY serverElementsChanged) Q_PROPERTY(QString localElements READ localElements NOTIFY localElementsChanged) Q_PROPERTY(QString localElementsMemory READ localElementsMemory NOTIFY localElementsMemoryChanged) @@ -40,6 +41,8 @@ public: OctreeStatsProvider(QObject* parent, NodeToOctreeSceneStats* model); ~OctreeStatsProvider(); + int serversNum() const; + QString serverElements() const { return m_serverElements; } @@ -89,6 +92,8 @@ public: } signals: + + void serversNumChanged(int serversNum); void serverElementsChanged(const QString &serverElements); void localElementsChanged(const QString &localElements); void sendingModeChanged(const QString &sendingMode); @@ -126,7 +131,7 @@ private: quint64 _lastRefresh = 0; QTimer _updateTimer; - + int m_serversNum { 0 }; QString m_serverElements; QString m_localElements; QString m_localElementsMemory; diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index 94bc4eeff6..1b80c3b3af 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -42,7 +42,10 @@ static Setting::Handle LIMITED_NODELIST_LOCAL_PORT("LimitedNodeList.Loc const std::set SOLO_NODE_TYPES = { NodeType::AvatarMixer, NodeType::AudioMixer, - NodeType::AssetServer + NodeType::AssetServer, + NodeType::EntityServer, + NodeType::MessagesMixer, + NodeType::EntityScriptServer }; LimitedNodeList::LimitedNodeList(int socketListenPort, int dtlsListenPort) : From 7013f6471409a5658ae473b3e0509a6c299b3a1e Mon Sep 17 00:00:00 2001 From: David Rowe Date: Wed, 3 Jan 2018 10:37:37 +1300 Subject: [PATCH 29/29] Remove erroneous "filed" Overlay property --- interface/src/ui/overlays/Base3DOverlay.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/interface/src/ui/overlays/Base3DOverlay.cpp b/interface/src/ui/overlays/Base3DOverlay.cpp index 6922ca87b7..84a6fe1da4 100644 --- a/interface/src/ui/overlays/Base3DOverlay.cpp +++ b/interface/src/ui/overlays/Base3DOverlay.cpp @@ -212,8 +212,6 @@ void Base3DOverlay::setProperties(const QVariantMap& originalProperties) { * parentID set, otherwise the same value as rotation. * @property {boolean} isSolid=false - Synonyms: solid, isFilled, * filled, and filed. Antonyms: isWire and wire. - * Deprecated: The erroneous property spelling "filed" is deprecated and support for it will - * be removed. * @property {boolean} isDashedLine=false - If true, a dashed line is drawn on the overlay's edges. Synonym: * dashed. * @property {boolean} ignoreRayIntersection=false - If true, @@ -241,7 +239,7 @@ QVariant Base3DOverlay::getProperty(const QString& property) { if (property == "localRotation" || property == "localOrientation") { return quatToVariant(getLocalOrientation()); } - if (property == "isSolid" || property == "isFilled" || property == "solid" || property == "filled" || property == "filed") { + if (property == "isSolid" || property == "isFilled" || property == "solid" || property == "filled") { return _isSolid; } if (property == "isWire" || property == "wire") {