From f2abb369c8fd47126ba430af6baa187eaa941631 Mon Sep 17 00:00:00 2001 From: vladest Date: Sun, 8 Oct 2017 16:09:01 +0200 Subject: [PATCH 01/27] 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/27] 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/27] 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/27] 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/27] 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/27] 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/27] 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/27] 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/27] 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/27] 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/27] 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/27] 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/27] 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/27] 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/27] 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/27] 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/27] 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/27] 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/27] 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/27] 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/27] 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/27] 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/27] 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/27] 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/27] 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 7013f6471409a5658ae473b3e0509a6c299b3a1e Mon Sep 17 00:00:00 2001 From: David Rowe Date: Wed, 3 Jan 2018 10:37:37 +1300 Subject: [PATCH 26/27] 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") { From 6f077f3a92e4ca383458608c5f82cff27ecc1897 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Wed, 3 Jan 2018 11:28:39 -0800 Subject: [PATCH 27/27] Fix Security Pic Change dialog after QML security changes --- .../qml/hifi/commerce/wallet/SecurityImageChange.qml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/resources/qml/hifi/commerce/wallet/SecurityImageChange.qml b/interface/resources/qml/hifi/commerce/wallet/SecurityImageChange.qml index b261743434..2ad2b75553 100644 --- a/interface/resources/qml/hifi/commerce/wallet/SecurityImageChange.qml +++ b/interface/resources/qml/hifi/commerce/wallet/SecurityImageChange.qml @@ -66,7 +66,7 @@ Item { source: "image://security/securityImage"; cache: false; onVisibleChanged: { - commerce.getSecurityImage(); + Commerce.getSecurityImage(); } } Item { @@ -194,7 +194,7 @@ Item { securityImageSubmitButton.text = "Submitting..."; securityImageSubmitButton.enabled = false; var securityImagePath = securityImageSelection.getImagePathFromImageID(securityImageSelection.getSelectedImageIndex()) - commerce.chooseSecurityImage(securityImagePath); + Commerce.chooseSecurityImage(securityImagePath); } } }