mixedreality/com.microsoft.mixedreality..../SDK/Experimental/MixedRealityKeyboardPreview/MixedRealityKeyboardPreview.cs

213 lines
6.2 KiB
C#

// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using Microsoft.MixedReality.Toolkit.Utilities.Solvers;
using System.Collections;
using TMPro;
using UnityEngine;
namespace Microsoft.MixedReality.Toolkit.Experimental.UI
{
/// <summary>
/// Component to manage the visuals for a Mixed Reality Keyboard Preview window.
/// </summary>
[AddComponentMenu("Scripts/MRTK/SDK/MixedRealityKeyboardPreview")]
public class MixedRealityKeyboardPreview : MonoBehaviour
{
[SerializeField, Tooltip("The Text Mesh Pro text field to display the preview text.")]
private TextMeshPro previewText = null;
/// <summary>
/// The Text Mesh Pro text field to display the preview text.
/// </summary>
public TextMeshPro PreviewText
{
get { return previewText; }
set
{
if (previewText != value)
{
previewText = value;
if (previewText != null)
{
previewText.text = Text;
UpdateCaret();
}
}
}
}
[SerializeField, Tooltip("The transform to move based on the preview caret.")]
private Transform previewCaret = null;
/// <summary>
/// The transform to move based on the preview caret.
/// </summary>
public Transform PreviewCaret
{
get { return previewCaret; }
set
{
if (previewCaret != value)
{
previewCaret = value;
UpdateCaret();
}
}
}
private string text = string.Empty;
/// <summary>
/// The text to display in the preview.
/// </summary>
public string Text
{
get { return text; }
set
{
if (value != text)
{
text = value;
if (PreviewText != null)
{
PreviewText.text = text;
PreviewText.ForceMeshUpdate();
}
UpdateCaret();
}
}
}
private int caretIndex = 0;
/// <summary>
/// Where the caret lies within the text.
/// </summary>
public int CaretIndex
{
get { return caretIndex; }
set
{
if (value != caretIndex)
{
caretIndex = value;
UpdateCaret();
}
}
}
/// <summary>
/// Utility method which can be used to toggle if solvers update.
/// </summary>
public void ToggleSolvers()
{
var solverHandler = GetComponent<SolverHandler>();
if (solverHandler != null)
{
solverHandler.UpdateSolvers = !solverHandler.UpdateSolvers;
if (solverHandler.UpdateSolvers)
{
ApplyShellSolverParameters();
}
}
}
#region MonoBehaviour Implementation
private void OnEnable()
{
StartCoroutine(BlinkCaret());
}
private void Start()
{
ApplyShellSolverParameters();
}
#endregion MonoBehaviour Implementation
private void UpdateCaret()
{
caretIndex = Mathf.Clamp(caretIndex, 0, string.IsNullOrEmpty(text) ? 0 : text.Length);
if (previewCaret != null)
{
if (caretIndex == 0)
{
previewCaret.transform.localPosition = Vector3.zero;
}
else
{
Vector3 localPosition;
if (caretIndex == text.Length)
{
localPosition = PreviewText.textInfo.characterInfo[caretIndex - 1].topRight;
}
else
{
localPosition = PreviewText.textInfo.characterInfo[caretIndex].topLeft;
}
localPosition.y = 0.0f;
localPosition.z = 0.0f;
var position = PreviewText.transform.TransformPoint(localPosition);
previewCaret.transform.position = position;
}
}
}
private IEnumerator BlinkCaret()
{
while (previewCaret != null)
{
previewCaret.gameObject.SetActive(!previewCaret.gameObject.activeSelf);
// The default Window's text caret blinks every 530 milliseconds.
const float blinkTime = 0.53f;
yield return new WaitForSeconds(blinkTime);
}
}
private void ApplyShellSolverParameters()
{
var solver = GetComponent<Follow>();
if (solver != null)
{
// Position the keyboard in a comfortable place with a fixed pitch relative to the forward direction.
var solverHandler = solver.GetComponent<SolverHandler>();
if (solverHandler != null)
{
var forward = solverHandler.TransformTarget != null ? solverHandler.TransformTarget.forward : Vector3.forward;
var right = solverHandler.TransformTarget != null ? solverHandler.TransformTarget.right : Vector3.right;
// Calculate the initial view pitch.
var pitchOffsetDegrees = Vector3.SignedAngle(new Vector3(forward.x, 0.0f, forward.z), forward, right);
const float shellPitchOffset = 5.0f;
pitchOffsetDegrees += shellPitchOffset;
const float shellPitchMin = -50.0f;
const float shellPitchMax = 50.0f;
pitchOffsetDegrees = Mathf.Clamp(pitchOffsetDegrees, shellPitchMin, shellPitchMax);
solver.PitchOffset = pitchOffsetDegrees;
solver.SolverUpdate();
}
}
}
}
}