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);
}
}
}
diff --git a/interface/resources/qml/hifi/tablet/TabletButton.qml b/interface/resources/qml/hifi/tablet/TabletButton.qml
index 1508367318..4d443fb97c 100644
--- a/interface/resources/qml/hifi/tablet/TabletButton.qml
+++ b/interface/resources/qml/hifi/tablet/TabletButton.qml
@@ -23,11 +23,26 @@ Item {
property double sortOrder: 100
property int stableOrder: 0
property var tabletRoot;
+ property var flickable: null
+ property var gridView: null
+
+ property int buttonIndex: -1
+
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,8 +136,10 @@ Item {
anchors.fill: parent
hoverEnabled: true
enabled: true
- preventStealing: true
+ preventStealing: false
onClicked: {
+ gridView.currentIndex = buttonIndex
+
if (tabletButton.inDebugMode) {
if (tabletButton.isActive) {
tabletButton.isActive = false;
@@ -130,12 +147,15 @@ Item {
tabletButton.isActive = true;
}
}
+
tabletButton.clicked();
if (tabletRoot) {
Tablet.playSound(TabletEnums.ButtonClick);
}
}
+
onEntered: {
+ gridView.currentIndex = buttonIndex
tabletButton.isEntered = true;
Tablet.playSound(TabletEnums.ButtonHover);
diff --git a/interface/resources/qml/hifi/tablet/TabletHome.qml b/interface/resources/qml/hifi/tablet/TabletHome.qml
index 3f9451436c..e934f18ab6 100644
--- a/interface/resources/qml/hifi/tablet/TabletHome.qml
+++ b/interface/resources/qml/hifi/tablet/TabletHome.qml
@@ -1,7 +1,10 @@
-import QtQuick 2.5
+import QtQuick 2.7
+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
@@ -10,7 +13,11 @@ Item {
id: tablet
objectName: "tablet"
property var tabletProxy: Tablet.getTablet("com.highfidelity.interface.tablet.system");
-
+
+ property var currentGridItems: null
+
+ focus: true
+
Rectangle {
id: bgTopBar
height: 90
@@ -85,7 +92,6 @@ Item {
Rectangle {
id: bgMain
- clip: true
gradient: Gradient {
GradientStop {
position: 0
@@ -102,55 +108,186 @@ 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
-
- TabletButton {
- id: tabletButton
- anchors.centerIn: parent
- onClicked: modelData.clicked()
- state: wrapper.GridView.isCurrentItem ? "hover state" : "base state"
+ SwipeView {
+ id: swipeView
+ clip: false
+ currentIndex: -1
+ property int previousIndex: -1
+ Repeater {
+ id: pageRepeater
+ model: Math.ceil(tabletProxy.buttons.rowCount() / TabletEnums.ButtonsOnPage)
+ onItemAdded: {
+ item.proxyModel.sourceModel = tabletProxy.buttons;
+ item.proxyModel.pageIndex = index;
}
- Connections {
- target: modelData;
- onPropertiesChanged: {
- updateProperties();
+ delegate: Item {
+ id: page
+ property TabletButtonsProxyModel proxyModel: TabletButtonsProxyModel {}
+
+ GridView {
+ id: gridView
+ keyNavigationEnabled: false
+ highlightFollowsCurrentItem: false
+ property int previousGridIndex: -1
+ anchors {
+ fill: parent
+ topMargin: 20
+ leftMargin: 30
+ rightMargin: 30
+ bottomMargin: 0
+ }
+
+ function setButtonState(buttonIndex, buttonstate) {
+ if (buttonIndex < 0 || gridView.contentItem === undefined
+ || gridView.contentItem.children.length - 1 < buttonIndex) {
+ return;
+ }
+ var itemat = gridView.contentItem.children[buttonIndex].children[0];
+ if (itemat.isActive) {
+ itemat.state = "active state";
+ } else {
+ itemat.state = buttonstate;
+ }
+ }
+
+ onCurrentIndexChanged: {
+ setButtonState(previousGridIndex, "base state");
+ setButtonState(currentIndex, "hover state");
+ previousGridIndex = currentIndex
+ }
+
+ cellWidth: width/3
+ cellHeight: cellWidth
+ flow: GridView.LeftToRight
+ model: page.proxyModel
+
+ delegate: Item {
+ id: wrapper
+ width: gridView.cellWidth
+ height: gridView.cellHeight
+
+ property var proxy: modelData
+
+ TabletButton {
+ id: tabletButton
+ anchors.centerIn: parent
+ gridView: wrapper.GridView.view
+ buttonIndex: page.proxyModel.buttonIndex(uuid);
+ flickable: swipeView.contentItem;
+ onClicked: modelData.clicked()
+ }
+
+ 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: 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) {
+ return;
}
+
+ currentGridItems = swipeView.itemAt(swipeView.currentIndex).children[0];
+
+ currentGridItems.currentIndex = (previousIndex > swipeView.currentIndex ? currentGridItems.count - 1 : 0);
+ 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
+ }
+ }
+
+ Component.onCompleted: {
+ focus = true;
+ forceActiveFocus();
+ }
+
+ Keys.onRightPressed: {
+ if (!currentGridItems) {
+ return;
+ }
+
+ var index = currentGridItems.currentIndex;
+ currentGridItems.moveCurrentIndexRight();
+ 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.onLeftPressed: {
+ if (!currentGridItems) {
+ return;
+ }
+
+ var index = currentGridItems.currentIndex;
+ currentGridItems.moveCurrentIndexLeft();
+ if (index === 0 && index === currentGridItems.currentIndex) {
+ if (swipeView.currentIndex > 0) {
+ swipeView.decrementCurrentIndex();
+ }
+ }
+ }
+ Keys.onDownPressed: currentGridItems.moveCurrentIndexDown();
+ Keys.onUpPressed: currentGridItems.moveCurrentIndexUp();
Keys.onReturnPressed: {
- if (flickable.currentItem) {
- flickable.currentItem.proxy.clicked();
+ if (currentGridItems.currentItem) {
+ currentGridItems.currentItem.proxy.clicked();
if (tabletRoot) {
tabletRoot.playButtonClickSound();
}
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") {
diff --git a/libraries/ui/src/ui/TabletScriptingInterface.cpp b/libraries/ui/src/ui/TabletScriptingInterface.cpp
index 0e793fef21..c69ec1ce84 100644
--- a/libraries/ui/src/ui/TabletScriptingInterface.cpp
+++ b/libraries/ui/src/ui/TabletScriptingInterface.cpp
@@ -92,8 +92,48 @@ void TabletButtonListModel::removeButton(TabletButtonProxy* button) {
endResetModel();
}
+TabletButtonsProxyModel::TabletButtonsProxyModel(QObject *parent)
+ : 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)
+ return;
+
+ _pageIndex = pageIndex;
+ invalidateFilter();
+ emit pageIndexChanged(_pageIndex);
+}
+
+bool TabletButtonsProxyModel::filterAcceptsRow(int sourceRow,
+ const QModelIndex &sourceParent) const {
+ Q_UNUSED(sourceParent);
+ return (sourceRow >= _pageIndex*TabletScriptingInterface::ButtonsOnPage
+ && sourceRow < (_pageIndex + 1)*TabletScriptingInterface::ButtonsOnPage);
+}
+
TabletScriptingInterface::TabletScriptingInterface() {
qmlRegisterType("TabletScriptingInterface", 1, 0, "TabletEnums");
+ qmlRegisterType("TabletScriptingInterface", 1, 0, "TabletButtonsProxyModel");
}
TabletScriptingInterface::~TabletScriptingInterface() {
@@ -769,6 +809,7 @@ void TabletProxy::sendToQml(const QVariant& msg) {
}
+
OffscreenQmlSurface* TabletProxy::getTabletSurface() {
return _qmlOffscreenSurface;
}
diff --git a/libraries/ui/src/ui/TabletScriptingInterface.h b/libraries/ui/src/ui/TabletScriptingInterface.h
index d24b3b6947..56e3ae257b 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
@@ -46,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;
@@ -118,6 +123,31 @@ protected:
Q_DECLARE_METATYPE(TabletButtonListModel*);
+class TabletButtonsProxyModel : public QSortFilterProxyModel
+{
+ Q_OBJECT
+
+ Q_PROPERTY(int pageIndex READ pageIndex WRITE setPageIndex NOTIFY pageIndexChanged)
+public:
+ TabletButtonsProxyModel(QObject* parent = 0);
+ int pageIndex() const;
+ Q_INVOKABLE int buttonIndex(const QString& uuid);
+
+public slots:
+ void setPageIndex(int pageIndex);
+
+signals:
+ void pageIndexChanged(int pageIndex);
+
+protected:
+ bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override;
+
+private:
+ int _pageIndex { -1 };
+};
+
+Q_DECLARE_METATYPE(TabletButtonsProxyModel*);
+
/**jsdoc
* @class TabletProxy
* @property name {string} READ_ONLY: name of this tablet
@@ -234,6 +264,7 @@ public:
QQuickItem* getQmlMenu() const;
TabletButtonListModel* getButtons() { return &_buttons; }
+
signals:
/**jsdoc
* Signaled when this tablet receives an event from the html/js embedded in the tablet