2025 lines
56 KiB
C#
2025 lines
56 KiB
C#
|
|
/*
|
|||
|
|
********************************************************************************
|
|||
|
|
*Copyright(C),coolae.net
|
|||
|
|
*Author: chenbin
|
|||
|
|
*Version: 2.0
|
|||
|
|
*Date: 2017-01-09
|
|||
|
|
*Description: 在NGUI的uicamera的基础上作了修改,这样支持在3d场景中单独控制操作控制
|
|||
|
|
*Others:
|
|||
|
|
*History:
|
|||
|
|
*********************************************************************************
|
|||
|
|
*/
|
|||
|
|
|
|||
|
|
using UnityEngine;
|
|||
|
|
using System.Collections.Generic;
|
|||
|
|
|
|||
|
|
#if UNITY_EDITOR
|
|||
|
|
using UnityEditor;
|
|||
|
|
#endif
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// This script should be attached to each camera that's used to draw the objects with
|
|||
|
|
/// UI components on them. This may mean only one camera (main camera or your UI camera),
|
|||
|
|
/// or multiple cameras if you happen to have multiple viewports. Failing to attach this
|
|||
|
|
/// script simply means that objects drawn by this camera won't receive UI notifications:
|
|||
|
|
///
|
|||
|
|
/// * OnHover (isOver) is sent when the mouse hovers over a collider or moves away.
|
|||
|
|
/// * OnPress (isDown) is sent when a mouse button gets pressed on the collider.
|
|||
|
|
/// * OnSelect (selected) is sent when a mouse button is first pressed on an object. Repeated presses won't result in an OnSelect(true).
|
|||
|
|
/// * OnClick () is sent when a mouse is pressed and released on the same object.
|
|||
|
|
/// UICamera.currentTouchID tells you which button was clicked.
|
|||
|
|
/// * OnDoubleClick () is sent when the click happens twice within a fourth of a second.
|
|||
|
|
/// UICamera.currentTouchID tells you which button was clicked.
|
|||
|
|
///
|
|||
|
|
/// * OnDragStart () is sent to a game object under the touch just before the OnDrag() notifications begin.
|
|||
|
|
/// * OnDrag (delta) is sent to an object that's being dragged.
|
|||
|
|
/// * OnDragOver (draggedObject) is sent to a game object when another object is dragged over its area.
|
|||
|
|
/// * OnDragOut (draggedObject) is sent to a game object when another object is dragged out of its area.
|
|||
|
|
/// * OnDragEnd () is sent to a dragged object when the drag event finishes.
|
|||
|
|
///
|
|||
|
|
/// * OnTooltip (show) is sent when the mouse hovers over a collider for some time without moving.
|
|||
|
|
/// * OnScroll (float delta) is sent out when the mouse scroll wheel is moved.
|
|||
|
|
/// * OnKey (KeyCode key) is sent when keyboard or controller input is used.
|
|||
|
|
/// </summary>
|
|||
|
|
|
|||
|
|
namespace Coolape
|
|||
|
|
{
|
|||
|
|
|
|||
|
|
[RequireComponent (typeof(Camera))]
|
|||
|
|
public class MyMainCamera : MonoBehaviour
|
|||
|
|
{
|
|||
|
|
/// <summary>
|
|||
|
|
/// The isbe controled.是否是被ui控制,需要和CLUIDrag4World接合起来用
|
|||
|
|
/// </summary>
|
|||
|
|
public bool isbeControled = false;
|
|||
|
|
//add by chenbin
|
|||
|
|
|
|||
|
|
public enum ControlScheme
|
|||
|
|
{
|
|||
|
|
Mouse,
|
|||
|
|
Touch,
|
|||
|
|
Controller,
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Whether the touch event will be sending out the OnClick notification at the end.
|
|||
|
|
/// </summary>
|
|||
|
|
|
|||
|
|
public enum ClickNotification
|
|||
|
|
{
|
|||
|
|
None,
|
|||
|
|
Always,
|
|||
|
|
BasedOnDelta,
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Ambiguous mouse, touch, or controller event.
|
|||
|
|
/// </summary>
|
|||
|
|
|
|||
|
|
public class MouseOrTouch
|
|||
|
|
{
|
|||
|
|
public Vector2 pos;
|
|||
|
|
// Current position of the mouse or touch event
|
|||
|
|
public Vector2 lastPos;
|
|||
|
|
// Previous position of the mouse or touch event
|
|||
|
|
public Vector2 delta;
|
|||
|
|
// Delta since last update
|
|||
|
|
public Vector2 totalDelta;
|
|||
|
|
// Delta since the event started being tracked
|
|||
|
|
|
|||
|
|
public Camera pressedCam;
|
|||
|
|
// Camera that the OnPress(true) was fired with
|
|||
|
|
|
|||
|
|
public GameObject last;
|
|||
|
|
// Last object under the touch or mouse
|
|||
|
|
public GameObject current;
|
|||
|
|
// Current game object under the touch or mouse
|
|||
|
|
public GameObject pressed;
|
|||
|
|
// Last game object to receive OnPress
|
|||
|
|
public GameObject dragged;
|
|||
|
|
// Game object that's being dragged
|
|||
|
|
|
|||
|
|
public float pressTime = 0f;
|
|||
|
|
// When the touch event started
|
|||
|
|
public float clickTime = 0f;
|
|||
|
|
// The last time a click event was sent out
|
|||
|
|
|
|||
|
|
public ClickNotification clickNotification = ClickNotification.Always;
|
|||
|
|
public bool touchBegan = true;
|
|||
|
|
public bool pressStarted = false;
|
|||
|
|
public bool dragStarted = false;
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Delta time since the touch operation started.
|
|||
|
|
/// </summary>
|
|||
|
|
|
|||
|
|
public float deltaTime { get { return RealTime.time - pressTime; } }
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Returns whether this touch is currently over a UI element.
|
|||
|
|
/// </summary>
|
|||
|
|
|
|||
|
|
public bool isOverUI {
|
|||
|
|
get {
|
|||
|
|
return current != null && current != fallThrough && NGUITools.FindInParents<UIRoot> (current) != null;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Camera type controls how raycasts are handled by the UICamera.
|
|||
|
|
/// </summary>
|
|||
|
|
|
|||
|
|
public enum EventType : int
|
|||
|
|
{
|
|||
|
|
World_3D,
|
|||
|
|
// Perform a Physics.Raycast and sort by distance to the point that was hit.
|
|||
|
|
UI_3D,
|
|||
|
|
// Perform a Physics.Raycast and sort by widget depth.
|
|||
|
|
World_2D,
|
|||
|
|
// Perform a Physics2D.OverlapPoint
|
|||
|
|
UI_2D,
|
|||
|
|
// Physics2D.OverlapPoint then sort by widget depth
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// List of all active cameras in the scene.
|
|||
|
|
/// </summary>
|
|||
|
|
|
|||
|
|
static public BetterList<MyMainCamera> list = new BetterList<MyMainCamera> ();
|
|||
|
|
|
|||
|
|
public delegate bool GetKeyStateFunc (KeyCode key);
|
|||
|
|
|
|||
|
|
public delegate float GetAxisFunc (string name);
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// GetKeyDown function -- return whether the specified key was pressed this Update().
|
|||
|
|
/// </summary>
|
|||
|
|
|
|||
|
|
static public GetKeyStateFunc GetKeyDown = Input.GetKeyDown;
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// GetKeyDown function -- return whether the specified key was released this Update().
|
|||
|
|
/// </summary>
|
|||
|
|
|
|||
|
|
static public GetKeyStateFunc GetKeyUp = Input.GetKeyUp;
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// GetKey function -- return whether the specified key is currently held.
|
|||
|
|
/// </summary>
|
|||
|
|
|
|||
|
|
static public GetKeyStateFunc GetKey = Input.GetKey;
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// GetAxis function -- return the state of the specified axis.
|
|||
|
|
/// </summary>
|
|||
|
|
|
|||
|
|
static public GetAxisFunc GetAxis = Input.GetAxis;
|
|||
|
|
|
|||
|
|
public delegate void OnScreenResize ();
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Delegate triggered when the screen size changes for any reason.
|
|||
|
|
/// Subscribe to it if you don't want to compare Screen.width and Screen.height each frame.
|
|||
|
|
/// </summary>
|
|||
|
|
|
|||
|
|
static public OnScreenResize onScreenResize;
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Event type -- use "UI" for your user interfaces, and "World" for your game camera.
|
|||
|
|
/// This setting changes how raycasts are handled. Raycasts have to be more complicated for UI cameras.
|
|||
|
|
/// </summary>
|
|||
|
|
|
|||
|
|
public EventType eventType = EventType.UI_3D;
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// By default, events will go to rigidbodies when the Event Type is not UI.
|
|||
|
|
/// You can change this behaviour back to how it was pre-3.7.0 using this flag.
|
|||
|
|
/// </summary>
|
|||
|
|
|
|||
|
|
public bool eventsGoToColliders = false;
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Which layers will receive events.
|
|||
|
|
/// </summary>
|
|||
|
|
|
|||
|
|
public LayerMask eventReceiverMask = -1;
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// If 'true', currently hovered object will be shown in the top left corner.
|
|||
|
|
/// </summary>
|
|||
|
|
|
|||
|
|
public bool debug = false;
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Whether the mouse input is used.
|
|||
|
|
/// </summary>
|
|||
|
|
|
|||
|
|
public bool useMouse = true;
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Whether the touch-based input is used.
|
|||
|
|
/// </summary>
|
|||
|
|
|
|||
|
|
public bool useTouch = true;
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Whether multi-touch is allowed.
|
|||
|
|
/// </summary>
|
|||
|
|
|
|||
|
|
public bool allowMultiTouch = true;
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Whether the keyboard events will be processed.
|
|||
|
|
/// </summary>
|
|||
|
|
|
|||
|
|
public bool useKeyboard = true;
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Whether the joystick and controller events will be processed.
|
|||
|
|
/// </summary>
|
|||
|
|
|
|||
|
|
public bool useController = true;
|
|||
|
|
|
|||
|
|
[System.Obsolete ("Use new OnDragStart / OnDragOver / OnDragOut / OnDragEnd events instead")]
|
|||
|
|
public bool stickyPress { get { return true; } }
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Whether the tooltip will disappear as soon as the mouse moves (false) or only if the mouse moves outside of the widget's area (true).
|
|||
|
|
/// </summary>
|
|||
|
|
|
|||
|
|
public bool stickyTooltip = true;
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// How long of a delay to expect before showing the tooltip.
|
|||
|
|
/// </summary>
|
|||
|
|
|
|||
|
|
public float tooltipDelay = 1f;
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// If enabled, a tooltip will be shown after touch gets pressed on something and held for more than "tooltipDelay" seconds.
|
|||
|
|
/// </summary>
|
|||
|
|
|
|||
|
|
public bool longPressTooltip = false;
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// How much the mouse has to be moved after pressing a button before it starts to send out drag events.
|
|||
|
|
/// </summary>
|
|||
|
|
|
|||
|
|
public float mouseDragThreshold = 4f;
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// How far the mouse is allowed to move in pixels before it's no longer considered for click events, if the click notification is based on delta.
|
|||
|
|
/// </summary>
|
|||
|
|
|
|||
|
|
public float mouseClickThreshold = 10f;
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// How much the mouse has to be moved after pressing a button before it starts to send out drag events.
|
|||
|
|
/// </summary>
|
|||
|
|
|
|||
|
|
public float touchDragThreshold = 40f;
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// How far the touch is allowed to move in pixels before it's no longer considered for click events, if the click notification is based on delta.
|
|||
|
|
/// </summary>
|
|||
|
|
|
|||
|
|
public float touchClickThreshold = 40f;
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Raycast range distance. By default it's as far as the camera can see.
|
|||
|
|
/// </summary>
|
|||
|
|
|
|||
|
|
public float rangeDistance = -1f;
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Name of the axis used for scrolling.
|
|||
|
|
/// </summary>
|
|||
|
|
|
|||
|
|
public string scrollAxisName = "Mouse ScrollWheel";
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Name of the axis used to send up and down key events.
|
|||
|
|
/// </summary>
|
|||
|
|
|
|||
|
|
public string verticalAxisName = "Vertical";
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Name of the axis used to send left and right key events.
|
|||
|
|
/// </summary>
|
|||
|
|
|
|||
|
|
public string horizontalAxisName = "Horizontal";
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Simulate a right-click on OSX when the Command key is held and a left-click is used (for trackpad).
|
|||
|
|
/// </summary>
|
|||
|
|
|
|||
|
|
public bool commandClick = true;
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Various keys used by the camera.
|
|||
|
|
/// </summary>
|
|||
|
|
|
|||
|
|
public KeyCode submitKey0 = KeyCode.Return;
|
|||
|
|
public KeyCode submitKey1 = KeyCode.JoystickButton0;
|
|||
|
|
public KeyCode cancelKey0 = KeyCode.Escape;
|
|||
|
|
public KeyCode cancelKey1 = KeyCode.JoystickButton1;
|
|||
|
|
|
|||
|
|
public delegate void OnCustomInput ();
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Custom input processing logic, if desired. For example: WP7 touches.
|
|||
|
|
/// Use UICamera.current to get the current camera.
|
|||
|
|
/// </summary>
|
|||
|
|
|
|||
|
|
static public OnCustomInput onCustomInput;
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Whether tooltips will be shown or not.
|
|||
|
|
/// </summary>
|
|||
|
|
|
|||
|
|
static public bool showTooltips = true;
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Position of the last touch (or mouse) event.
|
|||
|
|
/// </summary>
|
|||
|
|
|
|||
|
|
static public Vector2 lastTouchPosition = Vector2.zero;
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Position of the last touch (or mouse) event in the world.
|
|||
|
|
/// </summary>
|
|||
|
|
|
|||
|
|
static public Vector3 lastWorldPosition = Vector3.zero;
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Last raycast hit prior to sending out the event. This is useful if you want detailed information
|
|||
|
|
/// about what was actually hit in your OnClick, OnHover, and other event functions.
|
|||
|
|
/// Note that this is not going to be valid if you're using 2D colliders.
|
|||
|
|
/// </summary>
|
|||
|
|
|
|||
|
|
static public RaycastHit lastHit;
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// UICamera that sent out the event.
|
|||
|
|
/// </summary>
|
|||
|
|
|
|||
|
|
static public MyMainCamera current = null;
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Last camera active prior to sending out the event. This will always be the camera that actually sent out the event.
|
|||
|
|
/// </summary>
|
|||
|
|
|
|||
|
|
static public Camera currentCamera = null;
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Current control scheme. Set automatically when events arrive.
|
|||
|
|
/// </summary>
|
|||
|
|
|
|||
|
|
static public ControlScheme currentScheme = ControlScheme.Controller;
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// ID of the touch or mouse operation prior to sending out the event. Mouse ID is '-1' for left, '-2' for right mouse button, '-3' for middle.
|
|||
|
|
/// </summary>
|
|||
|
|
|
|||
|
|
static public int currentTouchID = -100;
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Key that triggered the event, if any.
|
|||
|
|
/// </summary>
|
|||
|
|
|
|||
|
|
static public KeyCode currentKey = KeyCode.None;
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Ray projected into the screen underneath the current touch.
|
|||
|
|
/// </summary>
|
|||
|
|
|
|||
|
|
static public Ray currentRay {
|
|||
|
|
get {
|
|||
|
|
return (currentCamera != null && currentTouch != null) ?
|
|||
|
|
currentCamera.ScreenPointToRay (currentTouch.pos) : new Ray ();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Current touch, set before any event function gets called.
|
|||
|
|
/// </summary>
|
|||
|
|
|
|||
|
|
static public MouseOrTouch currentTouch = null;
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Whether an input field currently has focus.
|
|||
|
|
/// </summary>
|
|||
|
|
|
|||
|
|
static public bool inputHasFocus = false;
|
|||
|
|
|
|||
|
|
// Obsolete, kept for backwards compatibility.
|
|||
|
|
static GameObject mGenericHandler;
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// If set, this game object will receive all events regardless of whether they were handled or not.
|
|||
|
|
/// </summary>
|
|||
|
|
|
|||
|
|
[System.Obsolete ("Use delegates instead such as UICamera.onClick, UICamera.onHover, etc.")]
|
|||
|
|
static public GameObject genericEventHandler { get { return mGenericHandler; } set { mGenericHandler = value; } }
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// If events don't get handled, they will be forwarded to this game object.
|
|||
|
|
/// </summary>
|
|||
|
|
|
|||
|
|
static public GameObject fallThrough;
|
|||
|
|
|
|||
|
|
public delegate void MoveDelegate (Vector2 delta);
|
|||
|
|
|
|||
|
|
public delegate void VoidDelegate (GameObject go);
|
|||
|
|
|
|||
|
|
public delegate void BoolDelegate (GameObject go, bool state);
|
|||
|
|
|
|||
|
|
public delegate void FloatDelegate (GameObject go, float delta);
|
|||
|
|
|
|||
|
|
public delegate void VectorDelegate (GameObject go, Vector2 delta);
|
|||
|
|
|
|||
|
|
public delegate void ObjectDelegate (GameObject go, GameObject obj);
|
|||
|
|
|
|||
|
|
public delegate void KeyCodeDelegate (GameObject go, KeyCode key);
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// These notifications are sent out prior to the actual event going out.
|
|||
|
|
/// </summary>
|
|||
|
|
|
|||
|
|
static public VoidDelegate onClick;
|
|||
|
|
static public VoidDelegate onDoubleClick;
|
|||
|
|
static public BoolDelegate onHover;
|
|||
|
|
static public BoolDelegate onPress;
|
|||
|
|
static public BoolDelegate onSelect;
|
|||
|
|
static public FloatDelegate onScroll;
|
|||
|
|
static public VectorDelegate onDrag;
|
|||
|
|
static public VoidDelegate onDragStart;
|
|||
|
|
static public ObjectDelegate onDragOver;
|
|||
|
|
static public ObjectDelegate onDragOut;
|
|||
|
|
static public VoidDelegate onDragEnd;
|
|||
|
|
static public ObjectDelegate onDrop;
|
|||
|
|
static public KeyCodeDelegate onKey;
|
|||
|
|
static public BoolDelegate onTooltip;
|
|||
|
|
static public MoveDelegate onMouseMove;
|
|||
|
|
|
|||
|
|
// Selected widget (for input)
|
|||
|
|
static GameObject mCurrentSelection = null;
|
|||
|
|
|
|||
|
|
// Mouse events
|
|||
|
|
static MouseOrTouch[] mMouse = new MouseOrTouch[] { new MouseOrTouch (), new MouseOrTouch (), new MouseOrTouch () };
|
|||
|
|
|
|||
|
|
// The last object to receive OnHover
|
|||
|
|
static GameObject mHover;
|
|||
|
|
|
|||
|
|
// Joystick/controller/keyboard event
|
|||
|
|
static public MouseOrTouch controller = new MouseOrTouch ();
|
|||
|
|
|
|||
|
|
// Used to ensure that joystick-based controls don't trigger that often
|
|||
|
|
static float mNextEvent = 0f;
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// List of all the active touches.
|
|||
|
|
/// </summary>
|
|||
|
|
|
|||
|
|
static public List<MouseOrTouch> activeTouches = new List<MouseOrTouch> ();
|
|||
|
|
|
|||
|
|
// Used internally to store IDs of active touches
|
|||
|
|
static List<int> mTouchIDs = new List<int> ();
|
|||
|
|
|
|||
|
|
// Used to detect screen dimension changes
|
|||
|
|
static int mWidth = 0;
|
|||
|
|
static int mHeight = 0;
|
|||
|
|
|
|||
|
|
// Tooltip widget (mouse only)
|
|||
|
|
GameObject mTooltip = null;
|
|||
|
|
|
|||
|
|
// Mouse input is turned off on iOS
|
|||
|
|
Camera mCam = null;
|
|||
|
|
float mTooltipTime = 0f;
|
|||
|
|
float mNextRaycast = 0f;
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Helper function that determines if this script should be handling the events.
|
|||
|
|
/// </summary>
|
|||
|
|
|
|||
|
|
bool handlesEvents { get { return eventHandler == this; } }
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Caching is always preferable for performance.
|
|||
|
|
/// </summary>
|
|||
|
|
|
|||
|
|
#if UNITY_4_3 || UNITY_4_5 || UNITY_4_6
|
|||
|
|
public Camera cachedCamera { get { if (mCam == null) mCam = camera; return mCam; } }
|
|||
|
|
#else
|
|||
|
|
public Camera cachedCamera {
|
|||
|
|
get {
|
|||
|
|
if (mCam == null)
|
|||
|
|
mCam = GetComponent<Camera> ();
|
|||
|
|
return mCam;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
#endif
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Set to 'true' just before OnDrag-related events are sent. No longer needed, but kept for backwards compatibility.
|
|||
|
|
/// </summary>
|
|||
|
|
|
|||
|
|
static public bool isDragging = false;
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// The object hit by the last Raycast that was the result of a mouse or touch event.
|
|||
|
|
/// </summary>
|
|||
|
|
|
|||
|
|
static public GameObject hoveredObject;
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Whether the last raycast was over the UI.
|
|||
|
|
/// </summary>
|
|||
|
|
|
|||
|
|
static public bool isOverUI {
|
|||
|
|
get {
|
|||
|
|
if (currentTouch != null)
|
|||
|
|
return currentTouch.isOverUI;
|
|||
|
|
if (hoveredObject == null)
|
|||
|
|
return false;
|
|||
|
|
if (hoveredObject == fallThrough)
|
|||
|
|
return false;
|
|||
|
|
return NGUITools.FindInParents<UIRoot> (hoveredObject) != null;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Option to manually set the selected game object.
|
|||
|
|
/// </summary>
|
|||
|
|
|
|||
|
|
static public GameObject selectedObject {
|
|||
|
|
get {
|
|||
|
|
if (mCurrentSelection)
|
|||
|
|
return mCurrentSelection;
|
|||
|
|
return null;
|
|||
|
|
}
|
|||
|
|
set {
|
|||
|
|
if (mCurrentSelection == value)
|
|||
|
|
return;
|
|||
|
|
|
|||
|
|
bool shouldRestore = false;
|
|||
|
|
|
|||
|
|
if (currentTouch == null) {
|
|||
|
|
shouldRestore = true;
|
|||
|
|
currentTouchID = -100;
|
|||
|
|
currentTouch = controller;
|
|||
|
|
currentScheme = ControlScheme.Controller;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
inputHasFocus = false;
|
|||
|
|
if (onSelect != null)
|
|||
|
|
onSelect (selectedObject, false);
|
|||
|
|
Notify (mCurrentSelection, "OnSelect", false);
|
|||
|
|
mCurrentSelection = value;
|
|||
|
|
|
|||
|
|
if (mCurrentSelection != null) {
|
|||
|
|
if (shouldRestore) {
|
|||
|
|
MyMainCamera cam = (mCurrentSelection != null) ? FindCameraForLayer (mCurrentSelection.layer) : MyMainCamera.list [0];
|
|||
|
|
|
|||
|
|
if (cam != null) {
|
|||
|
|
current = cam;
|
|||
|
|
currentCamera = cam.cachedCamera;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
inputHasFocus = (mCurrentSelection.activeInHierarchy && mCurrentSelection.GetComponent<UIInput> () != null);
|
|||
|
|
if (onSelect != null)
|
|||
|
|
onSelect (mCurrentSelection, true);
|
|||
|
|
Notify (mCurrentSelection, "OnSelect", true);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (shouldRestore) {
|
|||
|
|
current = null;
|
|||
|
|
currentCamera = null;
|
|||
|
|
currentTouch = null;
|
|||
|
|
currentTouchID = -100;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Returns 'true' if any of the active touch, mouse or controller is currently holding the specified object.
|
|||
|
|
/// </summary>
|
|||
|
|
|
|||
|
|
static public bool IsPressed (GameObject go)
|
|||
|
|
{
|
|||
|
|
for (int i = 0; i < 3; ++i)
|
|||
|
|
if (mMouse [i].pressed == go)
|
|||
|
|
return true;
|
|||
|
|
for (int i = 0, imax = activeTouches.Count; i < imax; ++i) {
|
|||
|
|
MouseOrTouch touch = activeTouches [i];
|
|||
|
|
if (touch.pressed == go)
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
if (controller.pressed == go)
|
|||
|
|
return true;
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
[System.Obsolete ("Use either 'CountInputSources()' or 'activeTouches.Count'")]
|
|||
|
|
static public int touchCount { get { return CountInputSources (); } }
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Number of active touches from all sources.
|
|||
|
|
/// Note that this will include the sum of touch, mouse and controller events.
|
|||
|
|
/// If you want only touch events, use activeTouches.Count.
|
|||
|
|
/// </summary>
|
|||
|
|
|
|||
|
|
static public int CountInputSources ()
|
|||
|
|
{
|
|||
|
|
int count = 0;
|
|||
|
|
|
|||
|
|
for (int i = 0, imax = activeTouches.Count; i < imax; ++i) {
|
|||
|
|
MouseOrTouch touch = activeTouches [i];
|
|||
|
|
if (touch.pressed != null)
|
|||
|
|
++count;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
for (int i = 0; i < mMouse.Length; ++i)
|
|||
|
|
if (mMouse [i].pressed != null)
|
|||
|
|
++count;
|
|||
|
|
|
|||
|
|
if (controller.pressed != null)
|
|||
|
|
++count;
|
|||
|
|
|
|||
|
|
return count;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Number of active drag events from all sources.
|
|||
|
|
/// </summary>
|
|||
|
|
|
|||
|
|
static public int dragCount {
|
|||
|
|
get {
|
|||
|
|
int count = 0;
|
|||
|
|
|
|||
|
|
for (int i = 0, imax = activeTouches.Count; i < imax; ++i) {
|
|||
|
|
MouseOrTouch touch = activeTouches [i];
|
|||
|
|
if (touch.dragged != null)
|
|||
|
|
++count;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
for (int i = 0; i < mMouse.Length; ++i)
|
|||
|
|
if (mMouse [i].dragged != null)
|
|||
|
|
++count;
|
|||
|
|
|
|||
|
|
if (controller.dragged != null)
|
|||
|
|
++count;
|
|||
|
|
|
|||
|
|
return count;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Convenience function that returns the main HUD camera.
|
|||
|
|
/// </summary>
|
|||
|
|
|
|||
|
|
static public Camera mainCamera {
|
|||
|
|
get {
|
|||
|
|
MyMainCamera mouse = eventHandler;
|
|||
|
|
return (mouse != null) ? mouse.cachedCamera : null;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Event handler for all types of events.
|
|||
|
|
/// </summary>
|
|||
|
|
|
|||
|
|
static public MyMainCamera eventHandler {
|
|||
|
|
get {
|
|||
|
|
for (int i = 0; i < list.size; ++i) {
|
|||
|
|
// Invalid or inactive entry -- keep going
|
|||
|
|
MyMainCamera cam = list.buffer [i];
|
|||
|
|
if (cam == null || !cam.enabled || !NGUITools.GetActive (cam.gameObject))
|
|||
|
|
continue;
|
|||
|
|
return cam;
|
|||
|
|
}
|
|||
|
|
return null;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Static comparison function used for sorting.
|
|||
|
|
/// </summary>
|
|||
|
|
|
|||
|
|
static int CompareFunc (MyMainCamera a, MyMainCamera b)
|
|||
|
|
{
|
|||
|
|
if (a.cachedCamera.depth < b.cachedCamera.depth)
|
|||
|
|
return 1;
|
|||
|
|
if (a.cachedCamera.depth > b.cachedCamera.depth)
|
|||
|
|
return -1;
|
|||
|
|
return 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
struct DepthEntry
|
|||
|
|
{
|
|||
|
|
public int depth;
|
|||
|
|
public RaycastHit hit;
|
|||
|
|
public Vector3 point;
|
|||
|
|
public GameObject go;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
static DepthEntry mHit = new DepthEntry ();
|
|||
|
|
static BetterList<DepthEntry> mHits = new BetterList<DepthEntry> ();
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Find the rigidbody on the parent, but return 'null' if a UIPanel is found instead.
|
|||
|
|
/// The idea is: send events to the rigidbody in the world, but to colliders in the UI.
|
|||
|
|
/// </summary>
|
|||
|
|
|
|||
|
|
static Rigidbody FindRootRigidbody (Transform trans)
|
|||
|
|
{
|
|||
|
|
while (trans != null) {
|
|||
|
|
if (trans.GetComponent<UIPanel> () != null)
|
|||
|
|
return null;
|
|||
|
|
#if UNITY_4_3 || UNITY_4_5 || UNITY_4_6
|
|||
|
|
Rigidbody rb = trans.rigidbody;
|
|||
|
|
#else
|
|||
|
|
Rigidbody rb = trans.GetComponent<Rigidbody> ();
|
|||
|
|
#endif
|
|||
|
|
if (rb != null)
|
|||
|
|
return rb;
|
|||
|
|
trans = trans.parent;
|
|||
|
|
}
|
|||
|
|
return null;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Find the 2D rigidbody on the parent, but return 'null' if a UIPanel is found instead.
|
|||
|
|
/// </summary>
|
|||
|
|
|
|||
|
|
static Rigidbody2D FindRootRigidbody2D (Transform trans)
|
|||
|
|
{
|
|||
|
|
while (trans != null) {
|
|||
|
|
if (trans.GetComponent<UIPanel> () != null)
|
|||
|
|
return null;
|
|||
|
|
#if UNITY_4_3 || UNITY_4_5 || UNITY_4_6
|
|||
|
|
Rigidbody2D rb = trans.rigidbody2D;
|
|||
|
|
#else
|
|||
|
|
Rigidbody2D rb = trans.GetComponent<Rigidbody2D> ();
|
|||
|
|
#endif
|
|||
|
|
if (rb != null)
|
|||
|
|
return rb;
|
|||
|
|
trans = trans.parent;
|
|||
|
|
}
|
|||
|
|
return null;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Returns the object under the specified position.
|
|||
|
|
/// </summary>
|
|||
|
|
|
|||
|
|
static public bool Raycast (Vector3 inPos)
|
|||
|
|
{
|
|||
|
|
for (int i = 0; i < list.size; ++i) {
|
|||
|
|
MyMainCamera cam = list.buffer [i];
|
|||
|
|
|
|||
|
|
// Skip inactive scripts
|
|||
|
|
if (!cam.enabled || !NGUITools.GetActive (cam.gameObject))
|
|||
|
|
continue;
|
|||
|
|
|
|||
|
|
// Convert to view space
|
|||
|
|
currentCamera = cam.cachedCamera;
|
|||
|
|
Vector3 pos = currentCamera.ScreenToViewportPoint (inPos);
|
|||
|
|
if (float.IsNaN (pos.x) || float.IsNaN (pos.y))
|
|||
|
|
continue;
|
|||
|
|
|
|||
|
|
// If it's outside the camera's viewport, do nothing
|
|||
|
|
if (pos.x < 0f || pos.x > 1f || pos.y < 0f || pos.y > 1f)
|
|||
|
|
continue;
|
|||
|
|
|
|||
|
|
// Cast a ray into the screen
|
|||
|
|
Ray ray = currentCamera.ScreenPointToRay (inPos);
|
|||
|
|
|
|||
|
|
// Raycast into the screen
|
|||
|
|
int mask = currentCamera.cullingMask & (int)cam.eventReceiverMask;
|
|||
|
|
float dist = (cam.rangeDistance > 0f) ? cam.rangeDistance : currentCamera.farClipPlane - currentCamera.nearClipPlane;
|
|||
|
|
|
|||
|
|
if (cam.eventType == EventType.World_3D) {
|
|||
|
|
if (Physics.Raycast (ray, out lastHit, dist, mask)) {
|
|||
|
|
lastWorldPosition = lastHit.point;
|
|||
|
|
hoveredObject = lastHit.collider.gameObject;
|
|||
|
|
|
|||
|
|
if (!list [0].eventsGoToColliders) {
|
|||
|
|
Rigidbody rb = FindRootRigidbody (hoveredObject.transform);
|
|||
|
|
if (rb != null)
|
|||
|
|
hoveredObject = rb.gameObject;
|
|||
|
|
}
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
continue;
|
|||
|
|
} else if (cam.eventType == EventType.UI_3D) {
|
|||
|
|
RaycastHit[] hits = Physics.RaycastAll (ray, dist, mask);
|
|||
|
|
|
|||
|
|
if (hits.Length > 1) {
|
|||
|
|
for (int b = 0; b < hits.Length; ++b) {
|
|||
|
|
GameObject go = hits [b].collider.gameObject;
|
|||
|
|
UIWidget w = go.GetComponent<UIWidget> ();
|
|||
|
|
|
|||
|
|
if (w != null) {
|
|||
|
|
if (!w.isVisible)
|
|||
|
|
continue;
|
|||
|
|
if (w.hitCheck != null && !w.hitCheck (hits [b].point))
|
|||
|
|
continue;
|
|||
|
|
} else {
|
|||
|
|
UIRect rect = NGUITools.FindInParents<UIRect> (go);
|
|||
|
|
if (rect != null && rect.finalAlpha < 0.001f)
|
|||
|
|
continue;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
mHit.depth = NGUITools.CalculateRaycastDepth (go);
|
|||
|
|
|
|||
|
|
if (mHit.depth != int.MaxValue) {
|
|||
|
|
mHit.hit = hits [b];
|
|||
|
|
mHit.point = hits [b].point;
|
|||
|
|
mHit.go = hits [b].collider.gameObject;
|
|||
|
|
mHits.Add (mHit);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
mHits.Sort (delegate(DepthEntry r1, DepthEntry r2) {
|
|||
|
|
return r2.depth.CompareTo (r1.depth);
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
for (int b = 0; b < mHits.size; ++b) {
|
|||
|
|
#if UNITY_FLASH
|
|||
|
|
if (IsVisible(mHits.buffer[b]))
|
|||
|
|
#else
|
|||
|
|
if (IsVisible (ref mHits.buffer [b]))
|
|||
|
|
#endif
|
|||
|
|
{
|
|||
|
|
lastHit = mHits [b].hit;
|
|||
|
|
hoveredObject = mHits [b].go;
|
|||
|
|
lastWorldPosition = mHits [b].point;
|
|||
|
|
mHits.Clear ();
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
mHits.Clear ();
|
|||
|
|
} else if (hits.Length == 1) {
|
|||
|
|
GameObject go = hits [0].collider.gameObject;
|
|||
|
|
UIWidget w = go.GetComponent<UIWidget> ();
|
|||
|
|
|
|||
|
|
if (w != null) {
|
|||
|
|
if (!w.isVisible)
|
|||
|
|
continue;
|
|||
|
|
if (w.hitCheck != null && !w.hitCheck (hits [0].point))
|
|||
|
|
continue;
|
|||
|
|
} else {
|
|||
|
|
UIRect rect = NGUITools.FindInParents<UIRect> (go);
|
|||
|
|
if (rect != null && rect.finalAlpha < 0.001f)
|
|||
|
|
continue;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (IsVisible (hits [0].point, hits [0].collider.gameObject)) {
|
|||
|
|
lastHit = hits [0];
|
|||
|
|
lastWorldPosition = hits [0].point;
|
|||
|
|
hoveredObject = lastHit.collider.gameObject;
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
continue;
|
|||
|
|
} else if (cam.eventType == EventType.World_2D) {
|
|||
|
|
if (m2DPlane.Raycast (ray, out dist)) {
|
|||
|
|
Vector3 point = ray.GetPoint (dist);
|
|||
|
|
Collider2D c2d = Physics2D.OverlapPoint (point, mask);
|
|||
|
|
|
|||
|
|
if (c2d) {
|
|||
|
|
lastWorldPosition = point;
|
|||
|
|
hoveredObject = c2d.gameObject;
|
|||
|
|
|
|||
|
|
if (!cam.eventsGoToColliders) {
|
|||
|
|
Rigidbody2D rb = FindRootRigidbody2D (hoveredObject.transform);
|
|||
|
|
if (rb != null)
|
|||
|
|
hoveredObject = rb.gameObject;
|
|||
|
|
}
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
continue;
|
|||
|
|
} else if (cam.eventType == EventType.UI_2D) {
|
|||
|
|
if (m2DPlane.Raycast (ray, out dist)) {
|
|||
|
|
lastWorldPosition = ray.GetPoint (dist);
|
|||
|
|
Collider2D[] hits = Physics2D.OverlapPointAll (lastWorldPosition, mask);
|
|||
|
|
|
|||
|
|
if (hits.Length > 1) {
|
|||
|
|
for (int b = 0; b < hits.Length; ++b) {
|
|||
|
|
GameObject go = hits [b].gameObject;
|
|||
|
|
UIWidget w = go.GetComponent<UIWidget> ();
|
|||
|
|
|
|||
|
|
if (w != null) {
|
|||
|
|
if (!w.isVisible)
|
|||
|
|
continue;
|
|||
|
|
if (w.hitCheck != null && !w.hitCheck (lastWorldPosition))
|
|||
|
|
continue;
|
|||
|
|
} else {
|
|||
|
|
UIRect rect = NGUITools.FindInParents<UIRect> (go);
|
|||
|
|
if (rect != null && rect.finalAlpha < 0.001f)
|
|||
|
|
continue;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
mHit.depth = NGUITools.CalculateRaycastDepth (go);
|
|||
|
|
|
|||
|
|
if (mHit.depth != int.MaxValue) {
|
|||
|
|
mHit.go = go;
|
|||
|
|
mHit.point = lastWorldPosition;
|
|||
|
|
mHits.Add (mHit);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
mHits.Sort (delegate(DepthEntry r1, DepthEntry r2) {
|
|||
|
|
return r2.depth.CompareTo (r1.depth);
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
for (int b = 0; b < mHits.size; ++b) {
|
|||
|
|
#if UNITY_FLASH
|
|||
|
|
if (IsVisible(mHits.buffer[b]))
|
|||
|
|
#else
|
|||
|
|
if (IsVisible (ref mHits.buffer [b]))
|
|||
|
|
#endif
|
|||
|
|
{
|
|||
|
|
hoveredObject = mHits [b].go;
|
|||
|
|
mHits.Clear ();
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
mHits.Clear ();
|
|||
|
|
} else if (hits.Length == 1) {
|
|||
|
|
GameObject go = hits [0].gameObject;
|
|||
|
|
UIWidget w = go.GetComponent<UIWidget> ();
|
|||
|
|
|
|||
|
|
if (w != null) {
|
|||
|
|
if (!w.isVisible)
|
|||
|
|
continue;
|
|||
|
|
if (w.hitCheck != null && !w.hitCheck (lastWorldPosition))
|
|||
|
|
continue;
|
|||
|
|
} else {
|
|||
|
|
UIRect rect = NGUITools.FindInParents<UIRect> (go);
|
|||
|
|
if (rect != null && rect.finalAlpha < 0.001f)
|
|||
|
|
continue;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (IsVisible (lastWorldPosition, go)) {
|
|||
|
|
hoveredObject = go;
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
continue;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
static Plane m2DPlane = new Plane (Vector3.back, 0f);
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Helper function to check if the specified hit is visible by the panel.
|
|||
|
|
/// </summary>
|
|||
|
|
|
|||
|
|
static bool IsVisible (Vector3 worldPoint, GameObject go)
|
|||
|
|
{
|
|||
|
|
UIPanel panel = NGUITools.FindInParents<UIPanel> (go);
|
|||
|
|
|
|||
|
|
while (panel != null) {
|
|||
|
|
if (!panel.IsVisible (worldPoint))
|
|||
|
|
return false;
|
|||
|
|
panel = panel.parentPanel;
|
|||
|
|
}
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Helper function to check if the specified hit is visible by the panel.
|
|||
|
|
/// </summary>
|
|||
|
|
|
|||
|
|
#if UNITY_FLASH
|
|||
|
|
static bool IsVisible (DepthEntry de)
|
|||
|
|
#else
|
|||
|
|
static bool IsVisible (ref DepthEntry de)
|
|||
|
|
#endif
|
|||
|
|
{
|
|||
|
|
UIPanel panel = NGUITools.FindInParents<UIPanel> (de.go);
|
|||
|
|
|
|||
|
|
while (panel != null) {
|
|||
|
|
if (!panel.IsVisible (de.point))
|
|||
|
|
return false;
|
|||
|
|
panel = panel.parentPanel;
|
|||
|
|
}
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Whether the specified object should be highlighted.
|
|||
|
|
/// </summary>
|
|||
|
|
|
|||
|
|
static public bool IsHighlighted (GameObject go)
|
|||
|
|
{
|
|||
|
|
if (MyMainCamera.currentScheme == MyMainCamera.ControlScheme.Mouse)
|
|||
|
|
return (MyMainCamera.hoveredObject == go);
|
|||
|
|
|
|||
|
|
if (MyMainCamera.currentScheme == MyMainCamera.ControlScheme.Controller)
|
|||
|
|
return (MyMainCamera.selectedObject == go);
|
|||
|
|
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Find the camera responsible for handling events on objects of the specified layer.
|
|||
|
|
/// </summary>
|
|||
|
|
|
|||
|
|
static public MyMainCamera FindCameraForLayer (int layer)
|
|||
|
|
{
|
|||
|
|
int layerMask = 1 << layer;
|
|||
|
|
|
|||
|
|
for (int i = 0; i < list.size; ++i) {
|
|||
|
|
MyMainCamera cam = list.buffer [i];
|
|||
|
|
Camera uc = cam.cachedCamera;
|
|||
|
|
if ((uc != null) && (uc.cullingMask & layerMask) != 0)
|
|||
|
|
return cam;
|
|||
|
|
}
|
|||
|
|
return null;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Using the keyboard will result in 1 or -1, depending on whether up or down keys have been pressed.
|
|||
|
|
/// </summary>
|
|||
|
|
|
|||
|
|
static int GetDirection (KeyCode up, KeyCode down)
|
|||
|
|
{
|
|||
|
|
if (GetKeyDown (up))
|
|||
|
|
return 1;
|
|||
|
|
if (GetKeyDown (down))
|
|||
|
|
return -1;
|
|||
|
|
return 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Using the keyboard will result in 1 or -1, depending on whether up or down keys have been pressed.
|
|||
|
|
/// </summary>
|
|||
|
|
|
|||
|
|
static int GetDirection (KeyCode up0, KeyCode up1, KeyCode down0, KeyCode down1)
|
|||
|
|
{
|
|||
|
|
if (GetKeyDown (up0) || GetKeyDown (up1))
|
|||
|
|
return 1;
|
|||
|
|
if (GetKeyDown (down0) || GetKeyDown (down1))
|
|||
|
|
return -1;
|
|||
|
|
return 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Using the joystick to move the UI results in 1 or -1 if the threshold has been passed, mimicking up/down keys.
|
|||
|
|
/// </summary>
|
|||
|
|
|
|||
|
|
static int GetDirection (string axis)
|
|||
|
|
{
|
|||
|
|
float time = RealTime.time;
|
|||
|
|
|
|||
|
|
if (mNextEvent < time && !string.IsNullOrEmpty (axis)) {
|
|||
|
|
float val = GetAxis (axis);
|
|||
|
|
|
|||
|
|
if (val > 0.75f) {
|
|||
|
|
mNextEvent = time + 0.25f;
|
|||
|
|
return 1;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (val < -0.75f) {
|
|||
|
|
mNextEvent = time + 0.25f;
|
|||
|
|
return -1;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
static int mNotifying = 0;
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Generic notification function. Used in place of SendMessage to shorten the code and allow for more than one receiver.
|
|||
|
|
/// </summary>
|
|||
|
|
|
|||
|
|
static public void Notify (GameObject go, string funcName, object obj)
|
|||
|
|
{
|
|||
|
|
if (mNotifying > 10)
|
|||
|
|
return;
|
|||
|
|
|
|||
|
|
if (NGUITools.GetActive (go)) {
|
|||
|
|
++mNotifying;
|
|||
|
|
//NGUIDebug.Log(funcName + "(" + obj + ") on " + (go != null ? go.name : "<null>") + "; " + currentTouchID + ", " + Input.touchCount);
|
|||
|
|
go.SendMessage (funcName, obj, SendMessageOptions.DontRequireReceiver);
|
|||
|
|
if (mGenericHandler != null && mGenericHandler != go)
|
|||
|
|
mGenericHandler.SendMessage (funcName, obj, SendMessageOptions.DontRequireReceiver);
|
|||
|
|
--mNotifying;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Get the details of the specified mouse button.
|
|||
|
|
/// </summary>
|
|||
|
|
|
|||
|
|
static public MouseOrTouch GetMouse (int button)
|
|||
|
|
{
|
|||
|
|
return mMouse [button];
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Get or create a touch event. If you are trying to iterate through a list of active touches, use activeTouches instead.
|
|||
|
|
/// </summary>
|
|||
|
|
|
|||
|
|
static public MouseOrTouch GetTouch (int id)
|
|||
|
|
{
|
|||
|
|
if (id < 0)
|
|||
|
|
return GetMouse (-id - 1);
|
|||
|
|
|
|||
|
|
for (int i = 0, imax = mTouchIDs.Count; i < imax; ++i)
|
|||
|
|
if (mTouchIDs [i] == id)
|
|||
|
|
return activeTouches [i];
|
|||
|
|
|
|||
|
|
MouseOrTouch touch = new MouseOrTouch ();
|
|||
|
|
touch.pressTime = RealTime.time;
|
|||
|
|
touch.touchBegan = true;
|
|||
|
|
activeTouches.Add (touch);
|
|||
|
|
mTouchIDs.Add (id);
|
|||
|
|
return touch;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Remove a touch event from the list.
|
|||
|
|
/// </summary>
|
|||
|
|
|
|||
|
|
static public void RemoveTouch (int id)
|
|||
|
|
{
|
|||
|
|
for (int i = 0, imax = mTouchIDs.Count; i < imax; ++i) {
|
|||
|
|
if (mTouchIDs [i] == id) {
|
|||
|
|
mTouchIDs.RemoveAt (i);
|
|||
|
|
activeTouches.RemoveAt (i);
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Add this camera to the list.
|
|||
|
|
/// </summary>
|
|||
|
|
|
|||
|
|
void Awake ()
|
|||
|
|
{
|
|||
|
|
mWidth = Screen.width;
|
|||
|
|
mHeight = Screen.height;
|
|||
|
|
|
|||
|
|
if (Application.platform == RuntimePlatform.Android ||
|
|||
|
|
Application.platform == RuntimePlatform.IPhonePlayer
|
|||
|
|
|| Application.platform == RuntimePlatform.WP8Player
|
|||
|
|
|| Application.platform == RuntimePlatform.BlackBerryPlayer) {
|
|||
|
|
useTouch = true;
|
|||
|
|
useMouse = false;
|
|||
|
|
useKeyboard = false;
|
|||
|
|
useController = false;
|
|||
|
|
} else if (Application.platform == RuntimePlatform.PS3 ||
|
|||
|
|
Application.platform == RuntimePlatform.XBOX360) {
|
|||
|
|
useMouse = false;
|
|||
|
|
useTouch = false;
|
|||
|
|
useKeyboard = false;
|
|||
|
|
useController = true;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Save the starting mouse position
|
|||
|
|
mMouse [0].pos = Input.mousePosition;
|
|||
|
|
|
|||
|
|
for (int i = 1; i < 3; ++i) {
|
|||
|
|
mMouse [i].pos = mMouse [0].pos;
|
|||
|
|
mMouse [i].lastPos = mMouse [0].pos;
|
|||
|
|
}
|
|||
|
|
lastTouchPosition = mMouse [0].pos;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Sort the list when enabled.
|
|||
|
|
/// </summary>
|
|||
|
|
|
|||
|
|
void OnEnable ()
|
|||
|
|
{
|
|||
|
|
list.Add (this);
|
|||
|
|
list.Sort (CompareFunc);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Remove this camera from the list.
|
|||
|
|
/// </summary>
|
|||
|
|
|
|||
|
|
void OnDisable ()
|
|||
|
|
{
|
|||
|
|
list.Remove (this);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// We don't want the camera to send out any kind of mouse events.
|
|||
|
|
/// </summary>
|
|||
|
|
|
|||
|
|
void Start ()
|
|||
|
|
{
|
|||
|
|
if (eventType != EventType.World_3D && cachedCamera.transparencySortMode != TransparencySortMode.Orthographic)
|
|||
|
|
cachedCamera.transparencySortMode = TransparencySortMode.Orthographic;
|
|||
|
|
|
|||
|
|
if (Application.isPlaying) {
|
|||
|
|
// Always set a fallthrough object
|
|||
|
|
if (fallThrough == null) {
|
|||
|
|
UIRoot root = NGUITools.FindInParents<UIRoot> (gameObject);
|
|||
|
|
|
|||
|
|
if (root != null) {
|
|||
|
|
fallThrough = root.gameObject;
|
|||
|
|
} else {
|
|||
|
|
Transform t = transform;
|
|||
|
|
fallThrough = (t.parent != null) ? t.parent.gameObject : gameObject;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
cachedCamera.eventMask = 0;
|
|||
|
|
}
|
|||
|
|
if (handlesEvents)
|
|||
|
|
NGUIDebug.debugRaycast = debug;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
#if UNITY_EDITOR
|
|||
|
|
void OnValidate ()
|
|||
|
|
{
|
|||
|
|
Start ();
|
|||
|
|
}
|
|||
|
|
#endif
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Check the input and send out appropriate events.
|
|||
|
|
/// </summary>
|
|||
|
|
|
|||
|
|
public void Update ()
|
|||
|
|
{
|
|||
|
|
// Only the first UI layer should be processing events
|
|||
|
|
#if UNITY_EDITOR
|
|||
|
|
if (!Application.isPlaying || !handlesEvents)
|
|||
|
|
return;
|
|||
|
|
#else
|
|||
|
|
if (!handlesEvents) return;
|
|||
|
|
#endif
|
|||
|
|
current = this;
|
|||
|
|
|
|||
|
|
// Process touch events first
|
|||
|
|
if (useTouch)
|
|||
|
|
ProcessTouches ();
|
|||
|
|
else if (useMouse)
|
|||
|
|
ProcessMouse ();
|
|||
|
|
|
|||
|
|
// Custom input processing
|
|||
|
|
if (onCustomInput != null)
|
|||
|
|
onCustomInput ();
|
|||
|
|
|
|||
|
|
// Clear the selection on the cancel key, but only if mouse input is allowed
|
|||
|
|
if (useMouse && mCurrentSelection != null) {
|
|||
|
|
if (cancelKey0 != KeyCode.None && GetKeyDown (cancelKey0)) {
|
|||
|
|
currentScheme = ControlScheme.Controller;
|
|||
|
|
currentKey = cancelKey0;
|
|||
|
|
selectedObject = null;
|
|||
|
|
} else if (cancelKey1 != KeyCode.None && GetKeyDown (cancelKey1)) {
|
|||
|
|
currentScheme = ControlScheme.Controller;
|
|||
|
|
currentKey = cancelKey1;
|
|||
|
|
selectedObject = null;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// If nothing is selected, input focus is lost
|
|||
|
|
if (mCurrentSelection == null) {
|
|||
|
|
inputHasFocus = false;
|
|||
|
|
} else if (!mCurrentSelection || !mCurrentSelection.activeInHierarchy) {
|
|||
|
|
inputHasFocus = false;
|
|||
|
|
mCurrentSelection = null;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Update the keyboard and joystick events
|
|||
|
|
if ((useKeyboard || useController) && mCurrentSelection != null)
|
|||
|
|
ProcessOthers ();
|
|||
|
|
|
|||
|
|
// If it's time to show a tooltip, inform the object we're hovering over
|
|||
|
|
if (useMouse && mHover != null) {
|
|||
|
|
float scroll = !string.IsNullOrEmpty (scrollAxisName) ? GetAxis (scrollAxisName) : 0f;
|
|||
|
|
|
|||
|
|
if (scroll != 0f) {
|
|||
|
|
if (onScroll != null)
|
|||
|
|
onScroll (mHover, scroll);
|
|||
|
|
Notify (mHover, "OnScroll", scroll);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (showTooltips && mTooltipTime != 0f && (mTooltipTime < RealTime.time ||
|
|||
|
|
GetKey (KeyCode.LeftShift) || GetKey (KeyCode.RightShift))) {
|
|||
|
|
mTooltip = mHover;
|
|||
|
|
currentTouch = mMouse [0];
|
|||
|
|
currentTouchID = -1;
|
|||
|
|
ShowTooltip (true);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
current = null;
|
|||
|
|
currentTouchID = -100;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Keep an eye on screen size changes.
|
|||
|
|
/// </summary>
|
|||
|
|
|
|||
|
|
public void LateUpdate ()
|
|||
|
|
{
|
|||
|
|
#if UNITY_EDITOR
|
|||
|
|
if (!Application.isPlaying || !handlesEvents)
|
|||
|
|
return;
|
|||
|
|
#else
|
|||
|
|
if (!handlesEvents) return;
|
|||
|
|
#endif
|
|||
|
|
int w = Screen.width;
|
|||
|
|
int h = Screen.height;
|
|||
|
|
|
|||
|
|
if (w != mWidth || h != mHeight) {
|
|||
|
|
mWidth = w;
|
|||
|
|
mHeight = h;
|
|||
|
|
|
|||
|
|
UIRoot.Broadcast ("UpdateAnchors");
|
|||
|
|
|
|||
|
|
if (onScreenResize != null)
|
|||
|
|
onScreenResize ();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Update mouse input.
|
|||
|
|
/// </summary>
|
|||
|
|
|
|||
|
|
public void ProcessMouse ()
|
|||
|
|
{
|
|||
|
|
// Is any button currently pressed?
|
|||
|
|
bool isPressed = false;
|
|||
|
|
bool justPressed = false;
|
|||
|
|
|
|||
|
|
for (int i = 0; i < 3; ++i) {
|
|||
|
|
if (Input.GetMouseButtonDown (i)) {
|
|||
|
|
currentScheme = ControlScheme.Mouse;
|
|||
|
|
justPressed = true;
|
|||
|
|
isPressed = true;
|
|||
|
|
} else if (Input.GetMouseButton (i)) {
|
|||
|
|
currentScheme = ControlScheme.Mouse;
|
|||
|
|
isPressed = true;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// We're currently using touches -- do nothing
|
|||
|
|
if (currentScheme == ControlScheme.Touch)
|
|||
|
|
return;
|
|||
|
|
|
|||
|
|
// Update the position and delta
|
|||
|
|
Vector2 pos = Input.mousePosition;
|
|||
|
|
Vector2 delta = pos - mMouse [0].pos;
|
|||
|
|
float sqrMag = delta.sqrMagnitude;
|
|||
|
|
bool posChanged = false;
|
|||
|
|
|
|||
|
|
if (currentScheme != ControlScheme.Mouse) {
|
|||
|
|
if (sqrMag < 0.001f)
|
|||
|
|
return; // Nothing changed and we are not using the mouse -- exit
|
|||
|
|
currentScheme = ControlScheme.Mouse;
|
|||
|
|
posChanged = true;
|
|||
|
|
} else if (sqrMag > 0.001f)
|
|||
|
|
posChanged = true;
|
|||
|
|
|
|||
|
|
lastTouchPosition = pos;
|
|||
|
|
|
|||
|
|
// Propagate the updates to the other mouse buttons
|
|||
|
|
for (int i = 0; i < 3; ++i) {
|
|||
|
|
mMouse [i].pos = pos;
|
|||
|
|
mMouse [i].delta = delta;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// No need to perform raycasts every frame
|
|||
|
|
if (isPressed || posChanged || mNextRaycast < RealTime.time) {
|
|||
|
|
mNextRaycast = RealTime.time + 0.02f;
|
|||
|
|
if (!Raycast (Input.mousePosition))
|
|||
|
|
hoveredObject = fallThrough;
|
|||
|
|
if (hoveredObject == null)
|
|||
|
|
hoveredObject = mGenericHandler;
|
|||
|
|
for (int i = 0; i < 3; ++i)
|
|||
|
|
mMouse [i].current = hoveredObject;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
bool highlightChanged = (mMouse [0].last != mMouse [0].current);
|
|||
|
|
if (highlightChanged)
|
|||
|
|
currentScheme = ControlScheme.Mouse;
|
|||
|
|
currentTouch = mMouse [0];
|
|||
|
|
currentTouchID = -1;
|
|||
|
|
|
|||
|
|
if (isPressed) {
|
|||
|
|
// A button was pressed -- cancel the tooltip
|
|||
|
|
mTooltipTime = 0f;
|
|||
|
|
} else if (posChanged && (!stickyTooltip || highlightChanged)) {
|
|||
|
|
if (mTooltipTime != 0f) {
|
|||
|
|
// Delay the tooltip
|
|||
|
|
mTooltipTime = RealTime.time + tooltipDelay;
|
|||
|
|
} else if (mTooltip != null) {
|
|||
|
|
// Hide the tooltip
|
|||
|
|
ShowTooltip (false);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Generic mouse move notifications
|
|||
|
|
if (posChanged && onMouseMove != null) {
|
|||
|
|
onMouseMove (currentTouch.delta);
|
|||
|
|
currentTouch = null;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// The button was released over a different object -- remove the highlight from the previous
|
|||
|
|
if ((justPressed || !isPressed) && mHover != null && highlightChanged) {
|
|||
|
|
if (mTooltip != null)
|
|||
|
|
ShowTooltip (false);
|
|||
|
|
if (onHover != null)
|
|||
|
|
onHover (mHover, false);
|
|||
|
|
Notify (mHover, "OnHover", false);
|
|||
|
|
mHover = null;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Process all 3 mouse buttons as individual touches
|
|||
|
|
for (int i = 0; i < 3; ++i) {
|
|||
|
|
bool pressed = Input.GetMouseButtonDown (i);
|
|||
|
|
bool unpressed = Input.GetMouseButtonUp (i);
|
|||
|
|
if (pressed || unpressed)
|
|||
|
|
currentScheme = ControlScheme.Mouse;
|
|||
|
|
currentTouch = mMouse [i];
|
|||
|
|
|
|||
|
|
#if UNITY_STANDALONE_OSX || UNITY_EDITOR_OSX
|
|||
|
|
if (commandClick && i == 0 && (Input.GetKey (KeyCode.LeftControl) || Input.GetKey (KeyCode.RightControl))) {
|
|||
|
|
currentTouchID = -2;
|
|||
|
|
currentKey = KeyCode.Mouse1;
|
|||
|
|
} else
|
|||
|
|
#endif
|
|||
|
|
{
|
|||
|
|
currentTouchID = -1 - i;
|
|||
|
|
currentKey = KeyCode.Mouse0 + i;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// We don't want to update the last camera while there is a touch happening
|
|||
|
|
if (pressed) {
|
|||
|
|
currentTouch.pressedCam = currentCamera;
|
|||
|
|
currentTouch.pressTime = RealTime.time;
|
|||
|
|
} else if (currentTouch.pressed != null)
|
|||
|
|
currentCamera = currentTouch.pressedCam;
|
|||
|
|
|
|||
|
|
// Process the mouse events
|
|||
|
|
ProcessTouch (pressed, unpressed);
|
|||
|
|
currentKey = KeyCode.None;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// If nothing is pressed and there is an object under the touch, highlight it
|
|||
|
|
if (!isPressed && highlightChanged) {
|
|||
|
|
currentScheme = ControlScheme.Mouse;
|
|||
|
|
mTooltipTime = RealTime.time + tooltipDelay;
|
|||
|
|
mHover = mMouse [0].current;
|
|||
|
|
currentTouch = mMouse [0];
|
|||
|
|
currentTouchID = -1;
|
|||
|
|
if (onHover != null)
|
|||
|
|
onHover (mHover, true);
|
|||
|
|
Notify (mHover, "OnHover", true);
|
|||
|
|
}
|
|||
|
|
currentTouch = null;
|
|||
|
|
|
|||
|
|
// Update the last value
|
|||
|
|
mMouse [0].last = mMouse [0].current;
|
|||
|
|
for (int i = 1; i < 3; ++i)
|
|||
|
|
mMouse [i].last = mMouse [0].last;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
static bool mUsingTouchEvents = true;
|
|||
|
|
|
|||
|
|
public class Touch
|
|||
|
|
{
|
|||
|
|
public int fingerId;
|
|||
|
|
public TouchPhase phase = TouchPhase.Began;
|
|||
|
|
public Vector2 position;
|
|||
|
|
public int tapCount = 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public delegate int GetTouchCountCallback ();
|
|||
|
|
|
|||
|
|
public delegate Touch GetTouchCallback (int index);
|
|||
|
|
|
|||
|
|
static public GetTouchCountCallback GetInputTouchCount;
|
|||
|
|
static public GetTouchCallback GetInputTouch;
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Update touch-based events.
|
|||
|
|
/// </summary>
|
|||
|
|
|
|||
|
|
int oldTouchCount = 0;
|
|||
|
|
// add by chenbin
|
|||
|
|
public void ProcessTouches ()
|
|||
|
|
{
|
|||
|
|
int count = (GetInputTouchCount == null) ? Input.touchCount : GetInputTouchCount ();
|
|||
|
|
|
|||
|
|
for (int i = 0; i < count; ++i) {
|
|||
|
|
int fingerId;
|
|||
|
|
TouchPhase phase;
|
|||
|
|
Vector2 position;
|
|||
|
|
int tapCount;
|
|||
|
|
|
|||
|
|
if (GetInputTouch == null) {
|
|||
|
|
UnityEngine.Touch touch = Input.GetTouch (i);
|
|||
|
|
phase = touch.phase;
|
|||
|
|
fingerId = touch.fingerId;
|
|||
|
|
position = touch.position;
|
|||
|
|
tapCount = touch.tapCount;
|
|||
|
|
} else {
|
|||
|
|
Touch touch = GetInputTouch (i);
|
|||
|
|
phase = touch.phase;
|
|||
|
|
fingerId = touch.fingerId;
|
|||
|
|
position = touch.position;
|
|||
|
|
tapCount = touch.tapCount;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
currentTouchID = allowMultiTouch ? fingerId : 1;
|
|||
|
|
currentTouch = GetTouch (currentTouchID);
|
|||
|
|
|
|||
|
|
bool pressed = (phase == TouchPhase.Began) || currentTouch.touchBegan;
|
|||
|
|
bool unpressed = (phase == TouchPhase.Canceled) || (phase == TouchPhase.Ended);
|
|||
|
|
currentTouch.touchBegan = false;
|
|||
|
|
|
|||
|
|
// Assume touch-based control
|
|||
|
|
currentScheme = ControlScheme.Touch;
|
|||
|
|
|
|||
|
|
// Although input.deltaPosition can be used, calculating it manually is safer (just in case)
|
|||
|
|
// currentTouch.delta = pressed ? Vector2.zero : position - currentTouch.pos;
|
|||
|
|
#region modify by chenbin
|
|||
|
|
if (Input.touchCount == oldTouchCount) {
|
|||
|
|
currentTouch.delta = pressed ? Vector2.zero : position - currentTouch.pos;
|
|||
|
|
} else {
|
|||
|
|
currentTouch.delta = Vector2.zero;
|
|||
|
|
}
|
|||
|
|
#endregion
|
|||
|
|
currentTouch.pos = position;
|
|||
|
|
|
|||
|
|
// Raycast into the screen
|
|||
|
|
if (!Raycast (currentTouch.pos))
|
|||
|
|
hoveredObject = fallThrough;
|
|||
|
|
if (hoveredObject == null)
|
|||
|
|
hoveredObject = mGenericHandler;
|
|||
|
|
currentTouch.last = currentTouch.current;
|
|||
|
|
currentTouch.current = hoveredObject;
|
|||
|
|
lastTouchPosition = currentTouch.pos;
|
|||
|
|
|
|||
|
|
// We don't want to update the last camera while there is a touch happening
|
|||
|
|
if (pressed)
|
|||
|
|
currentTouch.pressedCam = currentCamera;
|
|||
|
|
else if (currentTouch.pressed != null)
|
|||
|
|
currentCamera = currentTouch.pressedCam;
|
|||
|
|
|
|||
|
|
// Double-tap support
|
|||
|
|
if (tapCount > 1)
|
|||
|
|
currentTouch.clickTime = RealTime.time;
|
|||
|
|
|
|||
|
|
// Process the events from this touch
|
|||
|
|
ProcessTouch (pressed, unpressed);
|
|||
|
|
|
|||
|
|
// If the touch has ended, remove it from the list
|
|||
|
|
if (unpressed)
|
|||
|
|
RemoveTouch (currentTouchID);
|
|||
|
|
|
|||
|
|
currentTouch.last = null;
|
|||
|
|
currentTouch = null;
|
|||
|
|
|
|||
|
|
// Don't consider other touches
|
|||
|
|
if (!allowMultiTouch)
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (count == 0) {
|
|||
|
|
// Skip the first frame after using touch events
|
|||
|
|
if (mUsingTouchEvents) {
|
|||
|
|
mUsingTouchEvents = false;
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (useMouse)
|
|||
|
|
ProcessMouse ();
|
|||
|
|
#if UNITY_EDITOR
|
|||
|
|
else if (GetInputTouch == null)
|
|||
|
|
ProcessFakeTouches ();
|
|||
|
|
#endif
|
|||
|
|
} else
|
|||
|
|
mUsingTouchEvents = true;
|
|||
|
|
|
|||
|
|
oldTouchCount = count; // add by chenbin
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Process fake touch events where the mouse acts as a touch device.
|
|||
|
|
/// Useful for testing mobile functionality in the editor.
|
|||
|
|
/// </summary>
|
|||
|
|
|
|||
|
|
void ProcessFakeTouches ()
|
|||
|
|
{
|
|||
|
|
bool pressed = Input.GetMouseButtonDown (0);
|
|||
|
|
bool unpressed = Input.GetMouseButtonUp (0);
|
|||
|
|
bool held = Input.GetMouseButton (0);
|
|||
|
|
|
|||
|
|
if (pressed || unpressed || held) {
|
|||
|
|
currentTouchID = 1;
|
|||
|
|
currentTouch = mMouse [0];
|
|||
|
|
currentTouch.touchBegan = pressed;
|
|||
|
|
if (pressed)
|
|||
|
|
currentTouch.pressTime = RealTime.time;
|
|||
|
|
|
|||
|
|
Vector2 pos = Input.mousePosition;
|
|||
|
|
currentTouch.delta = pressed ? Vector2.zero : pos - currentTouch.pos;
|
|||
|
|
currentTouch.pos = pos;
|
|||
|
|
|
|||
|
|
// Raycast into the screen
|
|||
|
|
if (!Raycast (currentTouch.pos))
|
|||
|
|
hoveredObject = fallThrough;
|
|||
|
|
if (hoveredObject == null)
|
|||
|
|
hoveredObject = mGenericHandler;
|
|||
|
|
currentTouch.last = currentTouch.current;
|
|||
|
|
currentTouch.current = hoveredObject;
|
|||
|
|
lastTouchPosition = currentTouch.pos;
|
|||
|
|
|
|||
|
|
// We don't want to update the last camera while there is a touch happening
|
|||
|
|
if (pressed)
|
|||
|
|
currentTouch.pressedCam = currentCamera;
|
|||
|
|
else if (currentTouch.pressed != null)
|
|||
|
|
currentCamera = currentTouch.pressedCam;
|
|||
|
|
|
|||
|
|
// Process the events from this touch
|
|||
|
|
ProcessTouch (pressed, unpressed);
|
|||
|
|
|
|||
|
|
// If the touch has ended, remove it from the list
|
|||
|
|
if (unpressed)
|
|||
|
|
RemoveTouch (currentTouchID);
|
|||
|
|
currentTouch.last = null;
|
|||
|
|
currentTouch = null;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Process keyboard and joystick events.
|
|||
|
|
/// </summary>
|
|||
|
|
|
|||
|
|
public void ProcessOthers ()
|
|||
|
|
{
|
|||
|
|
currentTouchID = -100;
|
|||
|
|
currentTouch = controller;
|
|||
|
|
|
|||
|
|
bool submitKeyDown = false;
|
|||
|
|
bool submitKeyUp = false;
|
|||
|
|
|
|||
|
|
if (submitKey0 != KeyCode.None && GetKeyDown (submitKey0)) {
|
|||
|
|
currentKey = submitKey0;
|
|||
|
|
submitKeyDown = true;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (submitKey1 != KeyCode.None && GetKeyDown (submitKey1)) {
|
|||
|
|
currentKey = submitKey1;
|
|||
|
|
submitKeyDown = true;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (submitKey0 != KeyCode.None && GetKeyUp (submitKey0)) {
|
|||
|
|
currentKey = submitKey0;
|
|||
|
|
submitKeyUp = true;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (submitKey1 != KeyCode.None && GetKeyUp (submitKey1)) {
|
|||
|
|
currentKey = submitKey1;
|
|||
|
|
submitKeyUp = true;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (submitKeyDown)
|
|||
|
|
currentTouch.pressTime = RealTime.time;
|
|||
|
|
|
|||
|
|
if (submitKeyDown || submitKeyUp) {
|
|||
|
|
currentScheme = ControlScheme.Controller;
|
|||
|
|
currentTouch.last = currentTouch.current;
|
|||
|
|
currentTouch.current = mCurrentSelection;
|
|||
|
|
ProcessTouch (submitKeyDown, submitKeyUp);
|
|||
|
|
currentTouch.last = null;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
int vertical = 0;
|
|||
|
|
int horizontal = 0;
|
|||
|
|
|
|||
|
|
if (useKeyboard) {
|
|||
|
|
if (inputHasFocus) {
|
|||
|
|
vertical += GetDirection (KeyCode.UpArrow, KeyCode.DownArrow);
|
|||
|
|
horizontal += GetDirection (KeyCode.RightArrow, KeyCode.LeftArrow);
|
|||
|
|
} else {
|
|||
|
|
vertical += GetDirection (KeyCode.W, KeyCode.UpArrow, KeyCode.S, KeyCode.DownArrow);
|
|||
|
|
horizontal += GetDirection (KeyCode.D, KeyCode.RightArrow, KeyCode.A, KeyCode.LeftArrow);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (useController) {
|
|||
|
|
if (!string.IsNullOrEmpty (verticalAxisName))
|
|||
|
|
vertical += GetDirection (verticalAxisName);
|
|||
|
|
if (!string.IsNullOrEmpty (horizontalAxisName))
|
|||
|
|
horizontal += GetDirection (horizontalAxisName);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Send out key notifications
|
|||
|
|
if (vertical != 0) {
|
|||
|
|
currentScheme = ControlScheme.Controller;
|
|||
|
|
KeyCode key = vertical > 0 ? KeyCode.UpArrow : KeyCode.DownArrow;
|
|||
|
|
if (onKey != null)
|
|||
|
|
onKey (mCurrentSelection, key);
|
|||
|
|
Notify (mCurrentSelection, "OnKey", key);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (horizontal != 0) {
|
|||
|
|
currentScheme = ControlScheme.Controller;
|
|||
|
|
KeyCode key = horizontal > 0 ? KeyCode.RightArrow : KeyCode.LeftArrow;
|
|||
|
|
if (onKey != null)
|
|||
|
|
onKey (mCurrentSelection, key);
|
|||
|
|
Notify (mCurrentSelection, "OnKey", key);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (useKeyboard && GetKeyDown (KeyCode.Tab)) {
|
|||
|
|
currentKey = KeyCode.Tab;
|
|||
|
|
currentScheme = ControlScheme.Controller;
|
|||
|
|
if (onKey != null)
|
|||
|
|
onKey (mCurrentSelection, KeyCode.Tab);
|
|||
|
|
Notify (mCurrentSelection, "OnKey", KeyCode.Tab);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Send out the cancel key notification
|
|||
|
|
if (cancelKey0 != KeyCode.None && GetKeyDown (cancelKey0)) {
|
|||
|
|
currentKey = cancelKey0;
|
|||
|
|
currentScheme = ControlScheme.Controller;
|
|||
|
|
if (onKey != null)
|
|||
|
|
onKey (mCurrentSelection, KeyCode.Escape);
|
|||
|
|
Notify (mCurrentSelection, "OnKey", KeyCode.Escape);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (cancelKey1 != KeyCode.None && GetKeyDown (cancelKey1)) {
|
|||
|
|
currentKey = cancelKey1;
|
|||
|
|
currentScheme = ControlScheme.Controller;
|
|||
|
|
if (onKey != null)
|
|||
|
|
onKey (mCurrentSelection, KeyCode.Escape);
|
|||
|
|
Notify (mCurrentSelection, "OnKey", KeyCode.Escape);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
currentTouch = null;
|
|||
|
|
currentKey = KeyCode.None;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Process the press part of a touch.
|
|||
|
|
/// </summary>
|
|||
|
|
|
|||
|
|
void ProcessPress (bool pressed, float click, float drag)
|
|||
|
|
{
|
|||
|
|
// Send out the press message
|
|||
|
|
if (pressed) {
|
|||
|
|
if (mTooltip != null)
|
|||
|
|
ShowTooltip (false);
|
|||
|
|
currentTouch.pressStarted = true;
|
|||
|
|
if (onPress != null && currentTouch.pressed)
|
|||
|
|
onPress (currentTouch.pressed, false);
|
|||
|
|
|
|||
|
|
Notify (currentTouch.pressed, "OnPress", false);
|
|||
|
|
|
|||
|
|
currentTouch.pressed = currentTouch.current;
|
|||
|
|
currentTouch.dragged = currentTouch.current;
|
|||
|
|
currentTouch.clickNotification = ClickNotification.BasedOnDelta;
|
|||
|
|
currentTouch.totalDelta = Vector2.zero;
|
|||
|
|
currentTouch.dragStarted = false;
|
|||
|
|
|
|||
|
|
if (onPress != null && currentTouch.pressed)
|
|||
|
|
onPress (currentTouch.pressed, true);
|
|||
|
|
|
|||
|
|
Notify (currentTouch.pressed, "OnPress", true);
|
|||
|
|
|
|||
|
|
if (mTooltip != null)
|
|||
|
|
ShowTooltip (false);
|
|||
|
|
selectedObject = currentTouch.pressed;
|
|||
|
|
} else if (currentTouch.pressed != null && (currentTouch.delta.sqrMagnitude != 0f || currentTouch.current != currentTouch.last)) {
|
|||
|
|
// Keep track of the total movement
|
|||
|
|
currentTouch.totalDelta += currentTouch.delta;
|
|||
|
|
float mag = currentTouch.totalDelta.sqrMagnitude;
|
|||
|
|
bool justStarted = false;
|
|||
|
|
|
|||
|
|
// If the drag process hasn't started yet but we've already moved off the object, start it immediately
|
|||
|
|
if (!currentTouch.dragStarted && currentTouch.last != currentTouch.current) {
|
|||
|
|
currentTouch.dragStarted = true;
|
|||
|
|
currentTouch.delta = currentTouch.totalDelta;
|
|||
|
|
|
|||
|
|
// OnDragOver is sent for consistency, so that OnDragOut is always preceded by OnDragOver
|
|||
|
|
isDragging = true;
|
|||
|
|
|
|||
|
|
if (onDragStart != null)
|
|||
|
|
onDragStart (currentTouch.dragged);
|
|||
|
|
Notify (currentTouch.dragged, "OnDragStart", null);
|
|||
|
|
|
|||
|
|
if (onDragOver != null)
|
|||
|
|
onDragOver (currentTouch.last, currentTouch.dragged);
|
|||
|
|
Notify (currentTouch.last, "OnDragOver", currentTouch.dragged);
|
|||
|
|
|
|||
|
|
isDragging = false;
|
|||
|
|
} else if (!currentTouch.dragStarted && drag < mag) {
|
|||
|
|
// If the drag event has not yet started, see if we've dragged the touch far enough to start it
|
|||
|
|
justStarted = true;
|
|||
|
|
currentTouch.dragStarted = true;
|
|||
|
|
currentTouch.delta = currentTouch.totalDelta;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// If we're dragging the touch, send out drag events
|
|||
|
|
if (currentTouch.dragStarted) {
|
|||
|
|
if (mTooltip != null)
|
|||
|
|
ShowTooltip (false);
|
|||
|
|
|
|||
|
|
isDragging = true;
|
|||
|
|
bool isDisabled = (currentTouch.clickNotification == ClickNotification.None);
|
|||
|
|
|
|||
|
|
if (justStarted) {
|
|||
|
|
if (onDragStart != null)
|
|||
|
|
onDragStart (currentTouch.dragged);
|
|||
|
|
Notify (currentTouch.dragged, "OnDragStart", null);
|
|||
|
|
|
|||
|
|
if (onDragOver != null)
|
|||
|
|
onDragOver (currentTouch.last, currentTouch.dragged);
|
|||
|
|
Notify (currentTouch.current, "OnDragOver", currentTouch.dragged);
|
|||
|
|
} else if (currentTouch.last != currentTouch.current) {
|
|||
|
|
if (onDragStart != null)
|
|||
|
|
onDragStart (currentTouch.dragged);
|
|||
|
|
Notify (currentTouch.last, "OnDragOut", currentTouch.dragged);
|
|||
|
|
|
|||
|
|
if (onDragOver != null)
|
|||
|
|
onDragOver (currentTouch.last, currentTouch.dragged);
|
|||
|
|
Notify (currentTouch.current, "OnDragOver", currentTouch.dragged);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (onDrag != null)
|
|||
|
|
onDrag (currentTouch.dragged, currentTouch.delta);
|
|||
|
|
Notify (currentTouch.dragged, "OnDrag", currentTouch.delta);
|
|||
|
|
|
|||
|
|
currentTouch.last = currentTouch.current;
|
|||
|
|
isDragging = false;
|
|||
|
|
|
|||
|
|
if (isDisabled) {
|
|||
|
|
// If the notification status has already been disabled, keep it as such
|
|||
|
|
currentTouch.clickNotification = ClickNotification.None;
|
|||
|
|
} else if (currentTouch.clickNotification == ClickNotification.BasedOnDelta && click < mag) {
|
|||
|
|
// We've dragged far enough to cancel the click
|
|||
|
|
currentTouch.clickNotification = ClickNotification.None;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Process the release part of a touch.
|
|||
|
|
/// </summary>
|
|||
|
|
#region add by chenbin
|
|||
|
|
public float dragThreshold {
|
|||
|
|
get {
|
|||
|
|
bool isMouse = (currentScheme == ControlScheme.Mouse);
|
|||
|
|
float drag = isMouse ? mouseDragThreshold : touchDragThreshold;
|
|||
|
|
return drag;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public void ProcessRelease ()
|
|||
|
|
{
|
|||
|
|
bool isMouse = (currentScheme == ControlScheme.Mouse);
|
|||
|
|
float drag = isMouse ? mouseDragThreshold : touchDragThreshold;
|
|||
|
|
// So we can use sqrMagnitude below
|
|||
|
|
drag *= drag;
|
|||
|
|
ProcessRelease (isMouse, drag);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
#endregion
|
|||
|
|
|
|||
|
|
void ProcessRelease (bool isMouse, float drag)
|
|||
|
|
{
|
|||
|
|
// Send out the unpress message
|
|||
|
|
if (currentTouch == null)
|
|||
|
|
return;
|
|||
|
|
currentTouch.pressStarted = false;
|
|||
|
|
//if (mTooltip != null) ShowTooltip(false);
|
|||
|
|
|
|||
|
|
if (currentTouch.pressed != null) {
|
|||
|
|
// If there was a drag event in progress, make sure OnDragOut gets sent
|
|||
|
|
if (currentTouch.dragStarted) {
|
|||
|
|
if (onDragOut != null)
|
|||
|
|
onDragOut (currentTouch.last, currentTouch.dragged);
|
|||
|
|
Notify (currentTouch.last, "OnDragOut", currentTouch.dragged);
|
|||
|
|
|
|||
|
|
if (onDragEnd != null)
|
|||
|
|
onDragEnd (currentTouch.dragged);
|
|||
|
|
Notify (currentTouch.dragged, "OnDragEnd", null);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Send the notification of a touch ending
|
|||
|
|
if (onPress != null)
|
|||
|
|
onPress (currentTouch.pressed, false);
|
|||
|
|
Notify (currentTouch.pressed, "OnPress", false);
|
|||
|
|
|
|||
|
|
// Send a hover message to the object
|
|||
|
|
if (isMouse) {
|
|||
|
|
if (onHover != null)
|
|||
|
|
onHover (currentTouch.current, true);
|
|||
|
|
Notify (currentTouch.current, "OnHover", true);
|
|||
|
|
}
|
|||
|
|
mHover = currentTouch.current;
|
|||
|
|
|
|||
|
|
// If the button/touch was released on the same object, consider it a click and select it
|
|||
|
|
if (currentTouch.dragged == currentTouch.current ||
|
|||
|
|
(currentScheme != ControlScheme.Controller &&
|
|||
|
|
currentTouch.clickNotification != ClickNotification.None &&
|
|||
|
|
currentTouch.totalDelta.sqrMagnitude < drag)) {
|
|||
|
|
// If the touch should consider clicks, send out an OnClick notification
|
|||
|
|
if (currentTouch.clickNotification != ClickNotification.None && currentTouch.pressed == currentTouch.current) {
|
|||
|
|
float time = RealTime.time;
|
|||
|
|
|
|||
|
|
if (onClick != null)
|
|||
|
|
onClick (currentTouch.pressed);
|
|||
|
|
Notify (currentTouch.pressed, "OnClick", null);
|
|||
|
|
|
|||
|
|
if (currentTouch.clickTime + 0.35f > time) {
|
|||
|
|
if (onDoubleClick != null)
|
|||
|
|
onDoubleClick (currentTouch.pressed);
|
|||
|
|
Notify (currentTouch.pressed, "OnDoubleClick", null);
|
|||
|
|
}
|
|||
|
|
currentTouch.clickTime = time;
|
|||
|
|
}
|
|||
|
|
} else if (currentTouch.dragStarted) { // The button/touch was released on a different object
|
|||
|
|
// Send a drop notification (for drag & drop)
|
|||
|
|
if (onDrop != null)
|
|||
|
|
onDrop (currentTouch.current, currentTouch.dragged);
|
|||
|
|
Notify (currentTouch.current, "OnDrop", currentTouch.dragged);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
currentTouch.dragStarted = false;
|
|||
|
|
currentTouch.pressed = null;
|
|||
|
|
currentTouch.dragged = null;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Process the events of the specified touch.
|
|||
|
|
/// </summary>
|
|||
|
|
|
|||
|
|
public void ProcessTouch (bool pressed, bool released)
|
|||
|
|
{
|
|||
|
|
// Whether we're using the mouse
|
|||
|
|
bool isMouse = (currentScheme == ControlScheme.Mouse);
|
|||
|
|
float drag = isMouse ? mouseDragThreshold : touchDragThreshold;
|
|||
|
|
float click = isMouse ? mouseClickThreshold : touchClickThreshold;
|
|||
|
|
|
|||
|
|
// So we can use sqrMagnitude below
|
|||
|
|
drag *= drag;
|
|||
|
|
click *= click;
|
|||
|
|
|
|||
|
|
if (currentTouch.pressed != null) {
|
|||
|
|
if (released)
|
|||
|
|
ProcessRelease (isMouse, drag);
|
|||
|
|
ProcessPress (pressed, click, drag);
|
|||
|
|
|
|||
|
|
// Hold event = show tooltip
|
|||
|
|
if (currentTouch.pressed == currentTouch.current &&
|
|||
|
|
currentTouch.clickNotification != ClickNotification.None &&
|
|||
|
|
!currentTouch.dragStarted && currentTouch.deltaTime > tooltipDelay) {
|
|||
|
|
currentTouch.clickNotification = ClickNotification.None;
|
|||
|
|
|
|||
|
|
if (longPressTooltip) {
|
|||
|
|
mTooltip = currentTouch.pressed;
|
|||
|
|
ShowTooltip (true);
|
|||
|
|
}
|
|||
|
|
Notify (currentTouch.current, "OnLongPress", null);
|
|||
|
|
}
|
|||
|
|
} else if (isMouse || pressed || released) {
|
|||
|
|
ProcessPress (pressed, click, drag);
|
|||
|
|
if (released)
|
|||
|
|
ProcessRelease (isMouse, drag);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//modify by chenbin
|
|||
|
|
if (isbeControled && released) {
|
|||
|
|
enabled = false;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// Show or hide the tooltip.
|
|||
|
|
/// </summary>
|
|||
|
|
|
|||
|
|
public void ShowTooltip (bool val)
|
|||
|
|
{
|
|||
|
|
mTooltipTime = 0f;
|
|||
|
|
if (onTooltip != null)
|
|||
|
|
onTooltip (mTooltip, val);
|
|||
|
|
Notify (mTooltip, "OnTooltip", val);
|
|||
|
|
if (!val)
|
|||
|
|
mTooltip = null;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|