Support for overflowing tabs
This commit is contained in:
@@ -50,7 +50,7 @@ BoxCollider:
|
||||
m_IsTrigger: 0
|
||||
m_Enabled: 1
|
||||
serializedVersion: 2
|
||||
m_Size: {x: 800, y: 150, z: 0.05}
|
||||
m_Size: {x: 800, y: 150, z: 0.06}
|
||||
m_Center: {x: 0, y: 0, z: 0}
|
||||
--- !u!114 &8798264517337242548
|
||||
MonoBehaviour:
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -45,6 +45,9 @@ namespace QuestAppLauncher
|
||||
// Tab container
|
||||
public GameObject tabContainer;
|
||||
|
||||
// Tab container
|
||||
public GameObject tabContainerContent;
|
||||
|
||||
// Tracking space
|
||||
public GameObject trackingSpace;
|
||||
|
||||
@@ -386,9 +389,9 @@ namespace QuestAppLauncher
|
||||
Dictionary<string, string> iconOverrides)
|
||||
{
|
||||
// Destroy existing scrollviews and tabs
|
||||
for (int i = 0; i < this.tabContainer.transform.childCount; i++)
|
||||
for (int i = 0; i < this.tabContainerContent.transform.childCount; i++)
|
||||
{
|
||||
Destroy(this.tabContainer.transform.GetChild(i).gameObject);
|
||||
Destroy(this.tabContainerContent.transform.GetChild(i).gameObject);
|
||||
Destroy(this.scrollContainer.transform.GetChild(i).gameObject);
|
||||
}
|
||||
|
||||
@@ -453,12 +456,12 @@ namespace QuestAppLauncher
|
||||
SetGridSize(gridContent, config.gridSize.rows, config.gridSize.cols);
|
||||
|
||||
// Create tab
|
||||
var tab = (GameObject)Instantiate(this.prefabTab, this.tabContainer.transform);
|
||||
var tab = (GameObject)Instantiate(this.prefabTab, this.tabContainerContent.transform);
|
||||
tab.GetComponentInChildren<TextMeshProUGUI>().text = tabName;
|
||||
|
||||
var toggle = tab.GetComponent<Toggle>();
|
||||
toggle.isOn = isFirstTab;
|
||||
toggle.group = this.tabContainer.GetComponent<ToggleGroup>();
|
||||
toggle.group = this.tabContainerContent.GetComponent<ToggleGroup>();
|
||||
toggle.onValueChanged.AddListener(scrollView.SetActive);
|
||||
|
||||
if (isNoneTab)
|
||||
@@ -473,6 +476,10 @@ namespace QuestAppLauncher
|
||||
gridContents[tabName] = scrollView.GetComponent<ScrollRect>().content.gameObject;
|
||||
}
|
||||
|
||||
// Refresh tab prev / next buttons
|
||||
this.tabContainer.GetComponent<ScrollButtonHandler>().RefreshScrollContent(tabs.Count);
|
||||
this.tabContainer.GetComponent<ScrollRectColliderMask>().Refresh();
|
||||
|
||||
// Populate grid with app information (name & icon)
|
||||
// Sort by app name
|
||||
foreach (var app in apps.OrderBy(key => key.Value.AppName))
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UnityEngine.EventSystems;
|
||||
|
||||
namespace QuestAppLauncher
|
||||
{
|
||||
public class ScrollButtonHandler : MonoBehaviour
|
||||
{
|
||||
// Child object, used to determine size
|
||||
public GameObject prefabChild;
|
||||
|
||||
// Scroll content
|
||||
public RectTransform content;
|
||||
|
||||
[Tooltip("Button to go to the previous page")]
|
||||
public Button PrevButton;
|
||||
|
||||
[Tooltip("Button to go to the next page")]
|
||||
public Button NextButton;
|
||||
|
||||
// Width of child object
|
||||
private float childWidth;
|
||||
|
||||
// Current rect transform
|
||||
private RectTransform rectTransform;
|
||||
|
||||
private const float CmToInch = 2.54f;
|
||||
private const float DragThresholdCM = 50f;
|
||||
|
||||
// Start is called before the first frame update
|
||||
void Start()
|
||||
{
|
||||
this.PrevButton.onClick.AddListener(() => { ScrollPrev(); });
|
||||
this.NextButton.onClick.AddListener(() => { ScrollNext(); });
|
||||
|
||||
this.PrevButton.gameObject.SetActive(false);
|
||||
this.NextButton.gameObject.SetActive(false);
|
||||
|
||||
this.rectTransform = GetComponent<RectTransform>();
|
||||
this.childWidth = this.prefabChild.GetComponent<RectTransform>().sizeDelta.x;
|
||||
|
||||
RefreshScrollContent(0);
|
||||
|
||||
SetPhysicalDragThreshold();
|
||||
}
|
||||
|
||||
// Update is called once per frame
|
||||
void Update()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void RefreshScrollContent(int numChildren)
|
||||
{
|
||||
Canvas.ForceUpdateCanvases();
|
||||
|
||||
float contentSize = numChildren * this.childWidth;
|
||||
|
||||
if (this.rectTransform.sizeDelta.x >= contentSize)
|
||||
{
|
||||
// Viewport can fit the content, so hide the buttons
|
||||
this.PrevButton.gameObject.SetActive(false);
|
||||
this.NextButton.gameObject.SetActive(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.PrevButton.gameObject.SetActive(true);
|
||||
this.NextButton.gameObject.SetActive(true);
|
||||
}
|
||||
}
|
||||
|
||||
public void SetPhysicalDragThreshold()
|
||||
{
|
||||
Debug.LogFormat("Drag threshold: {0}", EventSystem.current.pixelDragThreshold);
|
||||
|
||||
EventSystem.current.pixelDragThreshold = (int)(DragThresholdCM * Screen.dpi / CmToInch);
|
||||
Debug.LogFormat("Updated drag threshold: {0}", EventSystem.current.pixelDragThreshold);
|
||||
}
|
||||
|
||||
public void ScrollPrev()
|
||||
{
|
||||
Vector2 newPosition = new Vector2(this.content.transform.localPosition.x + this.childWidth,
|
||||
this.content.transform.localPosition.y);
|
||||
this.content.transform.localPosition = newPosition;
|
||||
this.NextButton.interactable = true;
|
||||
}
|
||||
|
||||
public void ScrollNext()
|
||||
{
|
||||
Vector2 newPosition = new Vector2(this.content.transform.localPosition.x - this.childWidth, this.content.transform.localPosition.y);
|
||||
this.content.transform.localPosition = newPosition;
|
||||
this.PrevButton.interactable = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 390013d26c40ccd4ab21b46bd10bf9dc
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,66 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using ControllerSelection;
|
||||
|
||||
public class ScrollRectColliderMask : MonoBehaviour
|
||||
{
|
||||
// Content
|
||||
public RectTransform content;
|
||||
|
||||
// Tracking space used for ray cast
|
||||
public Transform trackingSpace = null;
|
||||
|
||||
// Box collider used for ray cast
|
||||
private BoxCollider boxCollider = null;
|
||||
|
||||
// Whether the pointer is within bounds of the scroll rect
|
||||
private bool isInBounds = true;
|
||||
private bool isInitialized = false;
|
||||
|
||||
private OVRInput.Controller activeController = OVRInput.Controller.None;
|
||||
|
||||
// Start is called before the first frame update
|
||||
void Start()
|
||||
{
|
||||
this.boxCollider = GetComponent<BoxCollider>();
|
||||
}
|
||||
|
||||
public void Refresh()
|
||||
{
|
||||
this.isInBounds = true;
|
||||
}
|
||||
|
||||
// Update is called once per frame
|
||||
void Update()
|
||||
{
|
||||
this.activeController = OVRInputHelpers.GetControllerForButton(OVRInput.Button.PrimaryIndexTrigger, this.activeController);
|
||||
Ray pointer = OVRInputHelpers.GetSelectionRay(this.activeController, this.trackingSpace);
|
||||
|
||||
RaycastHit hit;
|
||||
if (this.boxCollider.Raycast(pointer, out hit, 500))
|
||||
{
|
||||
// We got a hit in the scroll view. Check if we're already within the bounds - if so, do nothing.
|
||||
if (!isInBounds)
|
||||
{
|
||||
// We entered the scroll view, so enable box colliders on children.
|
||||
foreach (var boxCollider in this.content.gameObject.GetComponentsInChildren<BoxCollider>())
|
||||
{
|
||||
boxCollider.enabled = true;
|
||||
}
|
||||
|
||||
isInBounds = true;
|
||||
}
|
||||
}
|
||||
else if (isInBounds)
|
||||
{
|
||||
// We are outside the scroll view and were previously inside, so disable box colliders on children.
|
||||
foreach (var boxCollider in this.content.gameObject.GetComponentsInChildren<BoxCollider>())
|
||||
{
|
||||
boxCollider.enabled = false;
|
||||
}
|
||||
|
||||
isInBounds = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9f2a3df6684af7245a2512d708d72e62
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user