diff options
Diffstat (limited to 'Runtime/Export/GUI.txt')
-rw-r--r-- | Runtime/Export/GUI.txt | 1723 |
1 files changed, 1723 insertions, 0 deletions
diff --git a/Runtime/Export/GUI.txt b/Runtime/Export/GUI.txt new file mode 100644 index 0000000..bda95db --- /dev/null +++ b/Runtime/Export/GUI.txt @@ -0,0 +1,1723 @@ +C++RAW + +#include "UnityPrefix.h" + +#include "External/shaderlab/Library/FastPropertyName.h" +#include "External/shaderlab/Library/properties.h" + +#include "Runtime/IMGUI/GUIState.h" +#include "Runtime/IMGUI/IDList.h" +#include "Runtime/IMGUI/GUIContent.h" +#include "Runtime/IMGUI/GUILabel.h" +#include "Runtime/IMGUI/GUIToggle.h" +#include "Runtime/IMGUI/GUIButton.h" +#include "Runtime/IMGUI/GUIWindows.h" +#include "Runtime/IMGUI/IMGUIUtils.h" +#include "Runtime/IMGUI/GUIManager.h" +#include "Runtime/IMGUI/GUIStyle.h" +#include "Runtime/Math/Color.h" +#include "Runtime/Scripting/ScriptingUtility.h" +#include "Runtime/Scripting/Scripting.h" +#include "Runtime/Scripting/ScriptingObjectWithIntPtrField.h" +#include "Runtime/Shaders/Material.h" + +#if UNITY_EDITOR +# include "Editor/Platform/Interface/EditorWindows.h" +#endif + +using namespace Unity; +using namespace std; + + +CSRAW +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Collections; +using System.Collections.Generic; + +namespace UnityEngine +{ + +// Scaling mode to draw textures with +ENUM ScaleMode + // Stretches the texture to fill the complete rectangle passed in to GUI.DrawTexture + StretchToFill = 0, + // Scales the texture, maintaining aspect ratio, so it completely covers the /position/ rectangle passed to GUI.DrawTexture. If the texture is being draw to a rectangle with a different aspect ratio than the original, the image is cropped. + ScaleAndCrop = 1, + // Scales the texture, maintaining aspect ratio, so it completely fits withing the /position/ rectangle passed to GUI.DrawTexture. + ScaleToFit = 2 +END + +// The GUI class is the interface for Unity's GUI with manual positioning. +NONSEALED_CLASS GUI + CSRAW + static float scrollStepSize = 10f; + internal static DateTime nextScrollStepTime { get; set; } + static int scrollControlID; + internal static int scrollTroughSide { get; set; } + + #if UNITY_IPHONE || UNITY_ANDROID || UNITY_BB10 || UNITY_WP8 || UNITY_TIZEN + static int hotTextField = -1; + #endif + + // *undocumented* + CSRAW static GUI() + { + nextScrollStepTime = DateTime.Now; // whatever but null + } + + CSRAW static UnityEngine.GUISkin s_Skin; + + // The global skin to use. + CSRAW public static GUISkin skin { + set { + GUIUtility.CheckOnGUI(); + if (!value) + value = GUIUtility.GetDefaultSkin (); + s_Skin = value; + value.MakeCurrent (); + } + get { GUIUtility.CheckOnGUI(); return s_Skin; } + } + +// COLORS + // Global tinting color for the GUI. + CUSTOM_PROP static Color color + { return IMGUI::GetColor (GetGUIState()); } + { IMGUI::SetColor (GetGUIState(), value); } + + // Global tinting color for all background elements rendered by the GUI. + CUSTOM_PROP static Color backgroundColor + { return IMGUI::GetBackgroundColor (GetGUIState()); } + { IMGUI::SetBackgroundColor (GetGUIState(), value); } + + // Tinting color for all text rendered by the GUI. + CUSTOM_PROP static Color contentColor + { return IMGUI::GetContentColor (GetGUIState()); } + { IMGUI::SetContentColor (GetGUIState(), value); } + + // Returns true if any controls changed the value of the input data. + CUSTOM_PROP static bool changed + { return IMGUI::GetChanged (GetGUIState()); } + { IMGUI::SetChanged (GetGUIState(), value); } + +// ENABLED + // Is the GUI enabled? + CUSTOM_PROP static bool enabled + { return IMGUI::GetEnabled (GetGUIState()); } + { IMGUI::SetEnabled (GetGUIState(), value); } + +// MATRIX + // The GUI transform matrix. + CSRAW public static Matrix4x4 matrix { + get { return GUIClip.GetMatrix (); } + set { GUIClip.SetMatrix (value); } + } + + + // The tooltip of the control the mouse is currently over, or which has keyboard focus. (RO). + CSRAW public static string tooltip { + get { + string str = Internal_GetTooltip (); + if (str != null) + return str; + return ""; + } + set { Internal_SetTooltip (value); } + } + CUSTOM private static string Internal_GetTooltip () + { + GUIState &cState = GetGUIState(); + UTF16String *mouseTooltip = cState.m_OnGUIState.m_MouseTooltip; + UTF16String *keyTooltip = cState.m_OnGUIState.m_KeyTooltip; + UTF16String *tooltip = NULL; + if (mouseTooltip) + { + tooltip = mouseTooltip; + } + else if (keyTooltip) + { + tooltip = keyTooltip; + } + if (tooltip) + return tooltip->GetScriptingString (); + return SCRIPTING_NULL; + } + + CUSTOM private static void Internal_SetTooltip (string value) + { +#if ENABLE_MONO + UTF16String str (value.AsUTF8().c_str()); + GUIState &cState = GetGUIState(); + cState.m_OnGUIState.SetMouseTooltip (str); + cState.m_OnGUIState.SetKeyTooltip (str); +#endif + } + + // *undocumented* + CSRAW static protected string mouseTooltip { get { return Internal_GetMouseTooltip (); } } + CUSTOM private static string Internal_GetMouseTooltip () + { + GUIState &cState = GetGUIState(); + UTF16String *mouseTooltip = cState.m_OnGUIState.m_MouseTooltip; + return mouseTooltip ? mouseTooltip->GetScriptingString () : SCRIPTING_NULL; + } + + // *undocumented* + CSRAW protected static Rect tooltipRect { get { return s_ToolTipRect; } set { s_ToolTipRect = value; } } + CSRAW static internal Rect s_ToolTipRect; + + + + // The sorting depth of the currently executing GUI behaviour. + CUSTOM_PROP static int depth + { return IMGUI::GetDepth (GetGUIState()); } + { IMGUI::SetDepth (GetGUIState(), value); } + + + /// *listonly* + CSRAW public static void Label (Rect position, string text) { Label (position, GUIContent.Temp (text), s_Skin.label); } + /// *listonly* + CSRAW public static void Label (Rect position, Texture image) { Label (position, GUIContent.Temp (image), s_Skin.label); } + /// *listonly* + CSRAW public static void Label (Rect position, GUIContent content) { Label (position, content, s_Skin.label); } + /// *listonly* + CSRAW public static void Label (Rect position, string text, GUIStyle style) { Label (position, GUIContent.Temp (text), style); } + /// *listonly* + CSRAW public static void Label (Rect position, Texture image, GUIStyle style) { Label (position, GUIContent.Temp (image), style); } + + // Make a text or texture label on screen. + public static void Label (Rect position, GUIContent content, GUIStyle style) { + DoLabel (position, content, style.m_Ptr); + } + + CUSTOM private static void DoLabel (Rect position, GUIContent content, IntPtr style) + { + IMGUI::GUILabel ( + GetGUIState(), + position, + MonoGUIContentToTempNative (content), + *reinterpret_cast<GUIStyle*>(style) + ); + } + + + CUSTOM private static void InitializeGUIClipTexture () { InitializeGUIClipTexture(); } + + // Draw a texture within a rectangle. + CSRAW public static void DrawTexture (Rect position, Texture image, ScaleMode scaleMode = ScaleMode.StretchToFill, bool alphaBlend = true, float imageAspect = 0) { + if (Event.current.type == EventType.Repaint) { + if (image == null) { + Debug.LogWarning("null texture passed to GUI.DrawTexture"); + return; + } + + if (imageAspect == 0) + imageAspect = (float)image.width / image.height; + + Material mat = alphaBlend ? blendMaterial : blitMaterial; + float destAspect = position.width / position.height; + + InternalDrawTextureArguments arguments = new InternalDrawTextureArguments (); + #if UNITY_WINRT + arguments.textureInstanceId = image.GetInstanceID(); + #else + arguments.texture = image; + #endif + arguments.leftBorder = 0; + arguments.rightBorder = 0; + arguments.topBorder = 0; + arguments.bottomBorder = 0; + arguments.color = GUI.color; + #if UNITY_WINRT + arguments.matInstanceId = mat.GetInstanceID(); + #else + arguments.mat = mat; + #endif + + switch (scaleMode) { + case ScaleMode.StretchToFill: + arguments.screenRect = position; + arguments.sourceRect = new Rect (0,0,1,1); + Graphics.DrawTexture (ref arguments); + break; + case ScaleMode.ScaleAndCrop: + if (destAspect > imageAspect) { + float stretch = imageAspect / destAspect; + arguments.screenRect = position; + arguments.sourceRect = new Rect (0, (1 - stretch) * .5f, 1, stretch); + Graphics.DrawTexture (ref arguments); + } else { + float stretch = destAspect / imageAspect; + arguments.screenRect = position; + arguments.sourceRect = new Rect (.5f - stretch * .5f, 0, stretch, 1); + Graphics.DrawTexture (ref arguments); + } break; + case ScaleMode.ScaleToFit: + if (destAspect > imageAspect) { + float stretch = imageAspect / destAspect; + arguments.screenRect = new Rect (position.xMin + position.width * (1.0f - stretch) * .5f, position.yMin, stretch * position.width, position.height); + arguments.sourceRect = new Rect (0, 0, 1, 1); + Graphics.DrawTexture (ref arguments); + } else { + float stretch = destAspect / imageAspect; + arguments.screenRect = new Rect (position.xMin, position.yMin + position.height * (1.0f - stretch) * .5f, position.width, stretch * position.height); + arguments.sourceRect = new Rect (0, 0, 1, 1); + Graphics.DrawTexture (ref arguments); + } break; + } + } + } + + // Calculate screenrect and sourcerect for different scalemodes + CSRAW internal static bool CalculateScaledTextureRects(Rect position, ScaleMode scaleMode, float imageAspect, ref Rect outScreenRect, ref Rect outSourceRect) + { + float destAspect = position.width / position.height; + bool ret = false; + + switch (scaleMode) + { + case ScaleMode.StretchToFill: + outScreenRect = position; + outSourceRect = new Rect (0,0,1,1); + ret = true; + break; + case ScaleMode.ScaleAndCrop: + if (destAspect > imageAspect) { + float stretch = imageAspect / destAspect; + outScreenRect = position; + outSourceRect = new Rect (0, (1 - stretch) * .5f, 1, stretch); + ret = true; + } else { + float stretch = destAspect / imageAspect; + outScreenRect = position; + outSourceRect = new Rect (.5f - stretch * .5f, 0, stretch, 1); + ret = true; + } break; + case ScaleMode.ScaleToFit: + if (destAspect > imageAspect) { + float stretch = imageAspect / destAspect; + outScreenRect = new Rect (position.xMin + position.width * (1.0f - stretch) * .5f, position.yMin, stretch * position.width, position.height); + outSourceRect = new Rect (0, 0, 1, 1); + ret = true; + } else { + float stretch = destAspect / imageAspect; + outScreenRect = new Rect (position.xMin, position.yMin + position.height * (1.0f - stretch) * .5f, position.width, stretch * position.height); + outSourceRect = new Rect (0, 0, 1, 1); + ret = true; + } break; + } + + return ret; + } + + // Draw a texture within a rectangle with the given texture coordinates. Use this function for clipping or tiling the image within the given rectangle. + CSRAW public static void DrawTextureWithTexCoords (Rect position, Texture image, Rect texCoords, bool alphaBlend = true) + { + if (Event.current.type == EventType.Repaint) { + + Material mat = alphaBlend ? blendMaterial : blitMaterial; + + InternalDrawTextureArguments arguments = new InternalDrawTextureArguments (); + #if UNITY_WINRT + arguments.textureInstanceId = image.GetInstanceID(); + #else + arguments.texture = image; + #endif + arguments.leftBorder = 0; + arguments.rightBorder = 0; + arguments.topBorder = 0; + arguments.bottomBorder = 0; + arguments.color = GUI.color; + #if UNITY_WINRT + arguments.matInstanceId = mat.GetInstanceID(); + #else + arguments.mat = mat; + #endif + arguments.screenRect = position; + arguments.sourceRect = texCoords; + Graphics.DrawTexture (ref arguments); + } + } + + CUSTOM_PROP static private Material blendMaterial + { + return Scripting::ScriptingWrapperFor(GetGUIBlendMaterial()); + } + + CUSTOM_PROP static private Material blitMaterial + { + return Scripting::ScriptingWrapperFor(GetGUIBlitMaterial()); + } + + /// *listonly* + CSRAW public static void Box (Rect position, string text) { Box (position, GUIContent.Temp (text), s_Skin.box); } + /// *listonly* + CSRAW public static void Box (Rect position, Texture image) { Box (position, GUIContent.Temp (image), s_Skin.box); } + /// *listonly* + CSRAW public static void Box (Rect position, GUIContent content) { Box (position, content, s_Skin.box); } + /// *listonly* + CSRAW public static void Box (Rect position, string text, GUIStyle style) { Box (position, GUIContent.Temp (text), style); } + /// *listonly* + CSRAW public static void Box (Rect position, Texture image, GUIStyle style) { Box (position, GUIContent.Temp (image), style); } + + // Make a graphical box. + public static void Box (Rect position, GUIContent content, GUIStyle style) { + GUIUtility.CheckOnGUI (); + int id = GUIUtility.GetControlID (boxHash, FocusType.Passive); + if (Event.current.type == EventType.Repaint) { + style.Draw (position, content, id); + } + } + static int boxHash = "Box".GetHashCode (); + + /// *listonly* + CSRAW public static bool Button (Rect position, string text) { return DoButton (position, GUIContent.Temp (text), s_Skin.button.m_Ptr); } + /// *listonly* + CSRAW public static bool Button (Rect position, Texture image) { return DoButton (position, GUIContent.Temp (image), s_Skin.button.m_Ptr); } + /// *listonly* + CSRAW public static bool Button (Rect position, GUIContent content) { return DoButton (position, content, s_Skin.button.m_Ptr); } + /// *listonly* + CSRAW public static bool Button (Rect position, string text, GUIStyle style) { return DoButton (position, GUIContent.Temp (text), style.m_Ptr); } + /// *listonly* + CSRAW public static bool Button (Rect position, Texture image, GUIStyle style) { return DoButton (position, GUIContent.Temp (image), style.m_Ptr); } + + // Make a single press button. The user clicks them and something happens immediately. + CSRAW public static bool Button (Rect position, GUIContent content, GUIStyle style) + { return DoButton (position, content, style.m_Ptr); } + + CUSTOM private static bool DoButton (Rect position, GUIContent content, IntPtr style) + { + return IMGUI::GUIButton ( + GetGUIState(), + position, + MonoGUIContentToTempNative (content), + *reinterpret_cast<GUIStyle*>(style) + ); + } + + /// *listonly* + CSRAW public static bool RepeatButton (Rect position, string text) { return DoRepeatButton (position, GUIContent.Temp (text), s_Skin.button, FocusType.Native); } + /// *listonly* + CSRAW public static bool RepeatButton (Rect position, Texture image) { return DoRepeatButton (position, GUIContent.Temp (image), s_Skin.button, FocusType.Native); } + /// *listonly* + CSRAW public static bool RepeatButton (Rect position, GUIContent content) { return DoRepeatButton (position, content, s_Skin.button, FocusType.Native); } + /// *listonly* + CSRAW public static bool RepeatButton (Rect position, string text, GUIStyle style) { return DoRepeatButton (position, GUIContent.Temp (text), style, FocusType.Native); } + /// *listonly* + CSRAW public static bool RepeatButton (Rect position, Texture image, GUIStyle style) { return DoRepeatButton (position, GUIContent.Temp (image), style, FocusType.Native); } + + // Make a button that is active as long as the user holds it down. + CSRAW public static bool RepeatButton (Rect position, GUIContent content, GUIStyle style) { return DoRepeatButton (position, content, style, FocusType.Native); } + + CSRAW static bool DoRepeatButton (Rect position, GUIContent content, GUIStyle style, FocusType focusType) { + GUIUtility.CheckOnGUI (); + int id = GUIUtility.GetControlID (repeatButtonHash, focusType, position); + switch (Event.current.GetTypeForControl (id)) { + case EventType.MouseDown: + // If the mouse is inside the button, we say that we're the hot control + if (position.Contains (Event.current.mousePosition)) { + GUIUtility.hotControl = id; + Event.current.Use (); + } + return false; + case EventType.MouseUp: + if (GUIUtility.hotControl == id) { + GUIUtility.hotControl = 0; + + // If we got the mousedown, the mouseup is ours as well + // (no matter if the click was in the button or not) + Event.current.Use (); + + // But we only return true if the button was actually clicked + return position.Contains (Event.current.mousePosition); + } + return false; + case EventType.Repaint: + style.Draw (position, content, id); + // Handles.Repaint (); + return id == GUIUtility.hotControl && position.Contains (Event.current.mousePosition); + } + return false; + } + static int repeatButtonHash = "repeatButton".GetHashCode (); + +// ====================================================== TEXTFIELDS =============================== + /// *listonly* + CSRAW public static string TextField (Rect position, string text) { + GUIContent t = GUIContent.Temp (text); + DoTextField (position, GUIUtility.GetControlID (FocusType.Keyboard, position), t, false, -1, GUI.skin.textField); + return t.text; + } + /// *listonly* + CSRAW public static string TextField (Rect position, string text, int maxLength) { + GUIContent t = GUIContent.Temp (text); + DoTextField (position, GUIUtility.GetControlID (FocusType.Keyboard, position), t, false, maxLength, GUI.skin.textField); + return t.text; + } + /// *listonly* + CSRAW public static string TextField (Rect position, string text, GUIStyle style) { + GUIContent t = GUIContent.Temp (text); + DoTextField (position, GUIUtility.GetControlID (FocusType.Keyboard, position), t, false, -1, style); + return t.text; + } + // Make a single-line text field where the user can edit a string. + CSRAW public static string TextField (Rect position, string text, int maxLength, GUIStyle style) { + GUIContent t = GUIContent.Temp (text); + DoTextField (position, GUIUtility.GetControlID (FocusType.Keyboard, position), t, true, maxLength, style); + return t.text; + } + + + // PASSWORDFIELD HERE =============================================================== + /// *listonly* + CSRAW public static string PasswordField (Rect position, string password, char maskChar) { + return PasswordField (position, password, maskChar, -1, GUI.skin.textField); + } + + /// *listonly* + CSRAW public static string PasswordField (Rect position, string password, char maskChar, int maxLength) { + return PasswordField (position, password, maskChar, maxLength, GUI.skin.textField); + } + /// *listonly* + CSRAW public static string PasswordField (Rect position, string password, char maskChar, GUIStyle style) { + return PasswordField (position, password, maskChar, -1, style); + } + + // Make a text field where the user can enter a password. + CSRAW public static string PasswordField (Rect position, string password, char maskChar, int maxLength, GUIStyle style) { + string strPassword = PasswordFieldGetStrToShow(password, maskChar); + + GUIContent t = GUIContent.Temp (strPassword); + bool oldGUIChanged = GUI.changed; + GUI.changed = false; +#if UNITY_IPHONE || UNITY_ANDROID || UNITY_BB10 || UNITY_WP8 || UNITY_TIZEN + DoTextField (position, GUIUtility.GetControlID (FocusType.Keyboard), t, false, maxLength, style, password, maskChar); +#else + DoTextField (position, GUIUtility.GetControlID (FocusType.Keyboard, position), t, false, maxLength, style); +#endif + + strPassword = GUI.changed ? t.text : password; + + GUI.changed |= oldGUIChanged; + + return strPassword; + } + + // *undocumented* + CSRAW internal static string PasswordFieldGetStrToShow(string password, char maskChar) + { +#if !UNITY_WEBGL + return (Event.current.type == EventType.repaint || Event.current.type == EventType.mouseDown) ? + "".PadRight(password.Length, maskChar) : password; +#else + return password; +#endif + } + + // TEXTAREA HERE ==================================================================== + /// *listonly* + CSRAW public static string TextArea (Rect position, string text) { + GUIContent t = GUIContent.Temp (text); + DoTextField (position, GUIUtility.GetControlID (FocusType.Keyboard, position), t, true, -1, GUI.skin.textArea); + return t.text; + } + /// *listonly* + CSRAW public static string TextArea (Rect position, string text, int maxLength) { + GUIContent t = GUIContent.Temp (text); + DoTextField (position, GUIUtility.GetControlID (FocusType.Keyboard, position), t, true, maxLength, GUI.skin.textArea); + return t.text; + } + /// *listonly* + CSRAW public static string TextArea (Rect position, string text, GUIStyle style) { + GUIContent t = GUIContent.Temp (text); + DoTextField (position, GUIUtility.GetControlID (FocusType.Keyboard, position), t, true, -1, style); + return t.text; + } + // Make a Multi-line text area where the user can edit a string. + CSRAW public static string TextArea (Rect position, string text, int maxLength, GUIStyle style) { + GUIContent t = GUIContent.Temp (text); + DoTextField (position, GUIUtility.GetControlID (FocusType.Keyboard, position), t, false, maxLength, style); + return t.text; + } + // LATER... + static string TextArea (Rect position, GUIContent content, int maxLength, GUIStyle style) { + GUIContent t = GUIContent.Temp (content.text, content.image); + DoTextField (position, GUIUtility.GetControlID (FocusType.Keyboard, position), t, false, maxLength, style); + return t.text; + } + + CSRAW + internal static void DoTextField (Rect position, int id, GUIContent content, bool multiline, int maxLength, GUIStyle style +#if UNITY_IPHONE || UNITY_ANDROID || UNITY_BB10 || UNITY_WP8 || UNITY_TIZEN + , string secureText = null, char maskChar = '\0' +#endif + ) { + + //Pre-cull input string to maxLength. + if (maxLength >= 0 && content.text.Length > maxLength) + content.text = content.text.Substring (0, maxLength); + + GUIUtility.CheckOnGUI (); + TextEditor editor = (TextEditor)GUIUtility.GetStateObject (typeof (TextEditor), id); + editor.content.text = content.text; + editor.SaveBackup (); + editor.position = position; + editor.style = style; + editor.multiline = multiline; + editor.controlID = id; + editor.ClampPos (); + Event evt = Event.current; + +#if UNITY_IPHONE || UNITY_ANDROID || UNITY_BB10 || UNITY_WP8 || UNITY_TIZEN + switch (evt.type) { + case EventType.MouseDown: + if (position.Contains (evt.mousePosition)) { + GUIUtility.hotControl = id; + + // Disable keyboard for previously active text field, if any + if (hotTextField != -1 && hotTextField != id) { + TextEditor currentEditor = (TextEditor)GUIUtility.GetStateObject (typeof (TextEditor), hotTextField); + currentEditor.keyboardOnScreen = null; + } + + hotTextField = id; + + // in player setting keyboard control calls OnFocus every time, don't want that. In editor it does not do that for some reason + if (GUIUtility.keyboardControl != id) + GUIUtility.keyboardControl = id; + + editor.keyboardOnScreen = TouchScreenKeyboard.Open( + (secureText != null) ? secureText : content.text, + TouchScreenKeyboardType.Default, + true, // autocorrection + multiline, + (secureText != null)); + + evt.Use (); + } + break; + case EventType.Repaint: + if (editor.keyboardOnScreen != null) { + content.text = editor.keyboardOnScreen.text; + if (maxLength >= 0 && content.text.Length > maxLength) + content.text = content.text.Substring (0, maxLength); + + if (editor.keyboardOnScreen.done) { + editor.keyboardOnScreen = null; + changed = true; + } + } + + // if we use system keyboard we will have normal text returned (hiding symbols is done inside os) + // so before drawing make sure we hide them ourselves + string clearText = content.text; + + if(secureText != null) + content.text = PasswordFieldGetStrToShow(clearText, maskChar); + + style.Draw (position, content, id, false); + content.text = clearText; + + break; + } +#else // #if UNITY_IPHONE || UNITY_ANDROID || UNITY_BB10 || UNITY_WP8 || UNITY_TIZEN + bool change = false; + switch (evt.type) { + case EventType.MouseDown: + if (position.Contains (evt.mousePosition)) { + GUIUtility.hotControl = id; + GUIUtility.keyboardControl = id; + editor.m_HasFocus = true; + editor.MoveCursorToPosition (Event.current.mousePosition); + if (Event.current.clickCount == 2 && GUI.skin.settings.doubleClickSelectsWord) { + editor.SelectCurrentWord (); + editor.DblClickSnap(TextEditor.DblClickSnapping.WORDS); + editor.MouseDragSelectsWholeWords (true); + } if (Event.current.clickCount == 3 && GUI.skin.settings.tripleClickSelectsLine) { + editor.SelectCurrentParagraph (); + editor.MouseDragSelectsWholeWords (true); + editor.DblClickSnap(TextEditor.DblClickSnapping.PARAGRAPHS); + } + evt.Use (); + } + break; + case EventType.MouseDrag: + if (GUIUtility.hotControl == id) + { + if (evt.shift) + editor.MoveCursorToPosition (Event.current.mousePosition); + else + editor.SelectToPosition (Event.current.mousePosition); + evt.Use (); + } + break; + case EventType.MouseUp: + if (GUIUtility.hotControl == id) { + editor.MouseDragSelectsWholeWords (false); + GUIUtility.hotControl = 0; + evt.Use (); + } + break; + case EventType.KeyDown: + if (GUIUtility.keyboardControl != id) + return; + + if (editor.HandleKeyEvent (evt)) { + evt.Use (); + change = true; + content.text = editor.content.text; + break; + } + + // Ignore tab & shift-tab in textfields + if (evt.keyCode == KeyCode.Tab || evt.character == '\t') + return; + + char c = evt.character; + + if (c == '\n' && !multiline && !evt.alt) + return; + + + // Simplest test: only allow the character if the display font supports it. + Font font = style.font; + if (!font) + font = GUI.skin.font; + + if (font.HasCharacter (c) || c == '\n') { + editor.Insert (c); + change = true; + break; + } + + // On windows, keypresses also send events with keycode but no character. Eat them up here. + if (c == 0) { + + // if we have a composition string, make sure we clear the previous selection. + if (Input.compositionString.Length > 0) + { + editor.ReplaceSelection (""); + change = true; + } + + evt.Use (); + } +// else { +// REALLY USEFUL: +// Debug.Log ("unhandled " +evt); +// evt.Use (); +// } + break; + case EventType.Repaint: + // If we have keyboard focus, draw the cursor + // TODO: check if this OpenGL view has keyboard focus + if (GUIUtility.keyboardControl != id) { + style.Draw (position, content, id, false); + } else { + editor.DrawCursor (content.text); + } + break; + } + + if (GUIUtility.keyboardControl == id) + GUIUtility.textFieldInput = true; + + if (change) { + changed = true; + content.text = editor.content.text; + if (maxLength >= 0 && content.text.Length > maxLength) + content.text = content.text.Substring (0, maxLength); + evt.Use (); + } + #endif // #if UNITY_IPHONE || UNITY_ANDROID || UNITY_BB10 || UNITY_WP8 || UNITY_TIZEN + } + + +// INPUT CONTROLS + + // Set the name of the next control. + CUSTOM static void SetNextControlName (string name) + { + GetGUIState().SetNameOfNextKeyboardControl (name); + } + + // Get the name of named control that has focus. + CUSTOM static string GetNameOfFocusedControl () + { + return scripting_string_new(GetGUIState().GetNameOfFocusedControl ().c_str()); + } + + + + // Move keyboard focus to a named control. + CUSTOM static void FocusControl (string name) + { + GetGUIState().FocusKeyboardControl (name); + } + + +// ====================================================== TOGGLES =============================== + /// *listonly* + CSRAW public static bool Toggle (Rect position, bool value, string text) { return Toggle (position, value, GUIContent.Temp (text), s_Skin.toggle); } + /// *listonly* + CSRAW public static bool Toggle (Rect position, bool value, Texture image) { return Toggle (position, value, GUIContent.Temp (image), s_Skin.toggle); } + /// *listonly* + CSRAW public static bool Toggle (Rect position, bool value, GUIContent content) { return Toggle (position, value, content, s_Skin.toggle); } + /// *listonly* + CSRAW public static bool Toggle (Rect position, bool value, string text, GUIStyle style) { return Toggle (position, value, GUIContent.Temp (text), style); } + /// *listonly* + CSRAW public static bool Toggle (Rect position, bool value, Texture image, GUIStyle style) { return Toggle (position, value, GUIContent.Temp (image), style); } + // Make an on/off toggle button. + CSRAW public static bool Toggle (Rect position, bool value, GUIContent content, GUIStyle style) + { return DoToggle (position, GUIUtility.GetControlID (toggleHash, FocusType.Native, position), value, content, style.m_Ptr); } + + CSRAW static int toggleHash = "Toggle".GetHashCode (); + CUSTOM internal static bool DoToggle (Rect position, int id, bool value, GUIContent content, IntPtr style) + { + return IMGUI::GUIToggle ( + GetGUIState(), + position, + value, + MonoGUIContentToTempNative (content), + *reinterpret_cast<GUIStyle*>(style), + id + ); + } + + /// *listonly* + CSRAW public static int Toolbar (Rect position, int selected, string[] texts) { return Toolbar (position, selected, GUIContent.Temp (texts), s_Skin.button); } + /// *listonly* + CSRAW public static int Toolbar (Rect position, int selected, Texture[] images) { return Toolbar (position, selected, GUIContent.Temp (images), s_Skin.button); } + /// *listonly* + public static int Toolbar (Rect position, int selected, GUIContent[] content) { return Toolbar (position, selected, content, s_Skin.button); } + /// *listonly* + CSRAW public static int Toolbar (Rect position, int selected, string[] texts, GUIStyle style) { return Toolbar (position, selected, GUIContent.Temp (texts), style); } + /// *listonly* + CSRAW public static int Toolbar (Rect position, int selected, Texture[] images, GUIStyle style) { return Toolbar (position, selected, GUIContent.Temp (images), style); } + // Make a toolbar + CSRAW public static int Toolbar (Rect position, int selected, GUIContent[] contents, GUIStyle style) { + // Get the styles here + GUIStyle firstStyle, midStyle, lastStyle; + FindStyles (ref style, out firstStyle, out midStyle, out lastStyle, "left", "mid", "right"); + + return DoButtonGrid (position, selected, contents, contents.Length, style, firstStyle, midStyle, lastStyle); + } + + + /// *listonly* + CSRAW public static int SelectionGrid (Rect position, int selected, string[] texts, int xCount) { return SelectionGrid (position, selected, GUIContent.Temp (texts), xCount, null); } + /// *listonly* + CSRAW public static int SelectionGrid (Rect position, int selected, Texture[] images, int xCount) { return SelectionGrid (position, selected, GUIContent.Temp (images), xCount, null); } + /// *listonly* + CSRAW public static int SelectionGrid (Rect position, int selected, GUIContent[] content, int xCount) { return SelectionGrid (position, selected, content, xCount, null); } + /// *listonly* + CSRAW public static int SelectionGrid (Rect position, int selected, string[] texts, int xCount, GUIStyle style) { return SelectionGrid (position, selected, GUIContent.Temp (texts), xCount, style); } + /// *listonly* + CSRAW public static int SelectionGrid (Rect position, int selected, Texture[] images, int xCount, GUIStyle style) { return SelectionGrid (position, selected, GUIContent.Temp (images), xCount, style); } + // Make a grid of buttons. + CSRAW public static int SelectionGrid (Rect position, int selected, GUIContent[] contents, int xCount, GUIStyle style) { + if (style == null) style = s_Skin.button; + return DoButtonGrid (position, selected, contents, xCount, style, style, style, style); + } + + // Internal toolbar & buttongrid code + // ============================================= + CSRAW + // Find many GUIStyles from style.name permutations (Helper function for toolbars). + internal static void FindStyles (ref GUIStyle style, out GUIStyle firstStyle, out GUIStyle midStyle, out GUIStyle lastStyle, string first, string mid, string last) { + if (style == null) + style = GUI.skin.button; + string baseName = style.name; + midStyle = GUI.skin.FindStyle (baseName + mid); + if (midStyle == null) + midStyle = style; + firstStyle = GUI.skin.FindStyle (baseName + first); + if (firstStyle == null) + firstStyle = midStyle; + lastStyle = GUI.skin.FindStyle (baseName + last); + if (lastStyle == null) + lastStyle = midStyle; + } + + static internal int CalcTotalHorizSpacing (int xCount, GUIStyle style, GUIStyle firstStyle, GUIStyle midStyle, GUIStyle lastStyle) { + if (xCount < 2) + return 0; + if (xCount == 2) + return Mathf.Max (firstStyle.margin.right, lastStyle.margin.left); + + int internalSpace = Mathf.Max (midStyle.margin.left, midStyle.margin.right); + return Mathf.Max (firstStyle.margin.right, midStyle.margin.left) + Mathf.Max (midStyle.margin.right, lastStyle.margin.left) + internalSpace * (xCount - 3); + } + + // Make a button grid + static int DoButtonGrid (Rect position, int selected, GUIContent[] contents, int xCount, GUIStyle style, GUIStyle firstStyle, GUIStyle midStyle, GUIStyle lastStyle) { + GUIUtility.CheckOnGUI (); + int count = contents.Length; + if (count == 0) + return selected; + if (xCount <= 0) + { + Debug.LogWarning("You are trying to create a SelectionGrid with zero or less elements to be displayed in the horizontal direction. Set xCount to a positive value."); + return selected; + } + int id = GUIUtility.GetControlID (buttonGridHash, FocusType.Native, position); + + // Figure out how large each element should be + int rows = count / xCount; + if (count % xCount != 0) + rows++; + float totalHorizSpacing = CalcTotalHorizSpacing (xCount, style, firstStyle, midStyle, lastStyle); + float totalVerticalSpacing = Mathf.Max (style.margin.top, style.margin.bottom) * (rows - 1); + float elemWidth = (position.width - totalHorizSpacing) / xCount; + float elemHeight = (position.height - totalVerticalSpacing) / (float)rows; + + if (style.fixedWidth != 0) + elemWidth = style.fixedWidth; + if (style.fixedHeight != 0) + elemHeight = style.fixedHeight; + + Rect[] buttonRects; + switch (Event.current.GetTypeForControl (id)) { + case EventType.MouseDown: + if (position.Contains (Event.current.mousePosition)) { + //Check if the mouse is over a button (nobody says the grid is filled out) + buttonRects = CalcMouseRects (position, count, xCount, elemWidth, elemHeight, style, firstStyle, midStyle, lastStyle, false); + if (GetButtonGridMouseSelection (buttonRects, Event.current.mousePosition, true) != -1) { + GUIUtility.hotControl = id; + Event.current.Use (); + } + } + break; + case EventType.MouseDrag: + if (GUIUtility.hotControl == id) + Event.current.Use (); + break; + case EventType.MouseUp: + if (GUIUtility.hotControl == id) { + GUIUtility.hotControl = 0; + Event.current.Use (); + + buttonRects = CalcMouseRects (position, count, xCount, elemWidth, elemHeight, style, firstStyle, midStyle, lastStyle, false); + int mouseSel = GetButtonGridMouseSelection (buttonRects, Event.current.mousePosition, true); + + GUI.changed = true; + return mouseSel; + } + break; + case EventType.Repaint: + GUIStyle selStyle = null; + + GUIClip.Push (position, Vector2.zero, Vector2.zero, false); + position = new Rect (0,0,position.width, position.height); + + buttonRects = CalcMouseRects (position, count, xCount, elemWidth, elemHeight, style, firstStyle, midStyle, lastStyle, false); + int mouseOverSel = GetButtonGridMouseSelection (buttonRects, Event.current.mousePosition, id == GUIUtility.hotControl); + + bool mouseInside = position.Contains (Event.current.mousePosition); + GUIUtility.mouseUsed |= mouseInside; + + for (int i =0; i < count;i++) { + // Figure out the style + GUIStyle s = null; + if (i != 0) + s = midStyle; + else + s = firstStyle; + if (i == count - 1) + s = lastStyle; + if (count == 1) + s = style; + + if (i != selected) // We draw the selected one last, so it overflows nicer + { + s.Draw (buttonRects[i], contents[i], i == mouseOverSel && (enabled || id == GUIUtility.hotControl) && (id == GUIUtility.hotControl || GUIUtility.hotControl == 0), id == GUIUtility.hotControl && GUI.enabled, false, false); + } else + { + selStyle = s; + } + } + + // Draw it at the end + if (selected < count && selected > -1) + { + selStyle.Draw (buttonRects[selected], contents[selected], selected == mouseOverSel && (enabled || id == GUIUtility.hotControl) && (id == GUIUtility.hotControl || GUIUtility.hotControl == 0), id == GUIUtility.hotControl, true, false); +// selStyle.Draw (buttonRects[selected], contents[selected], selected == mouseOverSel, id == GUIUtility.hotControl || (selected == mouseOverSel && GUIUtility.hotControl = 0), true, false); + } + + if (mouseOverSel >= 0) + { + tooltip = contents[mouseOverSel].tooltip; + } + + GUIClip.Pop (); + break; + } + return selected; + } + static int buttonGridHash = "ButtonGrid".GetHashCode (); + + // Helper function: Get all mouse rects + static Rect[] CalcMouseRects (Rect position, int count, int xCount, float elemWidth, float elemHeight, GUIStyle style, GUIStyle firstStyle, GUIStyle midStyle, GUIStyle lastStyle, bool addBorders) { + int y = 0; + int x = 0; + float xPos = position.xMin, yPos = position.yMin; + GUIStyle currentButtonStyle = style; + Rect[] retval = new Rect[count]; + if (count > 1) + currentButtonStyle = firstStyle; + for (int i = 0; i < count; i++) { + if (!addBorders) + retval[i] = new Rect (xPos, yPos, elemWidth, elemHeight); + else + retval[i] = currentButtonStyle.margin.Add (new Rect (xPos, yPos, elemWidth, elemHeight)); + + // Correct way to get the rounded width: + retval[i].width = Mathf.Round (retval[i].xMax) - Mathf.Round (retval[i].x); + // Round the position *after* the position has been rounded: + retval[i].x = Mathf.Round (retval[i].x); + + // Don't round xPos here. If rounded, the right edge of this rect may + // not line up correctly with the left edge of the next, + // plus it can cause cumulative rounding errors. + // (See case 366967) + + GUIStyle nextStyle = midStyle; + if (i == count - 2) + nextStyle = lastStyle; + xPos += elemWidth + Mathf.Max (currentButtonStyle.margin.right, nextStyle.margin.left); + + x++; + if (x >= xCount) { + y++; + x = 0; + yPos += elemHeight + Mathf.Max (style.margin.top, style.margin.bottom); + xPos = position.xMin; + } + } + return retval; + } + + + // Helper function: Get the index of the element under the mouse position + static int GetButtonGridMouseSelection (Rect[] buttonRects, Vector2 mousePos, bool findNearest) { + // This could be implemented faster, but for now this is not supposed to be used for a gazillion elements :) + + for (int i = 0; i < buttonRects.Length; i++) { + if (buttonRects[i].Contains (mousePos)) + return i; + } + if (!findNearest) + return -1; + // We haven't found any we're over, so we need to find the closest button. + float minDist = 10000000; + int minIndex = -1; + for (int i = 0; i < buttonRects.Length; i++) { + Rect r = buttonRects[i]; + Vector2 v = new Vector2 (Mathf.Clamp (mousePos.x, r.xMin, r.xMax), Mathf.Clamp (mousePos.y, r.yMin, r.yMax)); + float dSqr = (mousePos - v).sqrMagnitude; + if (dSqr < minDist) { + minIndex = i; + minDist = dSqr; + } + } + + return minIndex; + } + + /// *listonly* + CSRAW public static float HorizontalSlider(Rect position, float value, float leftValue, float rightValue) + { return Slider (position, value, 0, leftValue, rightValue, skin.horizontalSlider, skin.horizontalSliderThumb, true, GUIUtility.GetControlID (sliderHash, FocusType.Native, position)); } + // A horizontal slider the user can drag to change a value between a min and a max. + CSRAW public static float HorizontalSlider (Rect position, float value, float leftValue, float rightValue, GUIStyle slider, GUIStyle thumb) + { return Slider (position, value, 0, leftValue, rightValue, slider, thumb, true, GUIUtility.GetControlID (sliderHash, FocusType.Native, position)); } + + /// *listonly* + CSRAW public static float VerticalSlider (Rect position, float value, float topValue, float bottomValue) + { return Slider (position, value, 0, topValue, bottomValue, skin.verticalSlider, skin.verticalSliderThumb, false, GUIUtility.GetControlID (sliderHash, FocusType.Native, position)); } + // A vertical slider the user can drag to change a value between a min and a max. + CSRAW public static float VerticalSlider (Rect position, float value, float topValue, float bottomValue, GUIStyle slider, GUIStyle thumb) + { return Slider (position, value, 0, topValue, bottomValue, slider, thumb, false, GUIUtility.GetControlID (sliderHash, FocusType.Native, position)); } + + + // Main slider function. + // Handles scrollbars & sliders in both horizontal & vertical directions. + //*undocumented* + CSRAW public static float Slider (Rect position, float value, float size, float start, float end, GUIStyle slider, GUIStyle thumb, bool horiz, int id) { + GUIUtility.CheckOnGUI (); + return new SliderHandler(position, value, size, start, end, slider, thumb, horiz, id).Handle(); + } + static int sliderHash = "Slider".GetHashCode (); + + // should scrollbars do paging + CUSTOM_PROP static internal bool usePageScrollbars + { + #if UNITY_OSX + //respect system preference. + Boolean exists; + Boolean scroll = CFPreferencesGetAppBooleanValue(CFSTR("AppleScrollerPagingBehavior"),CFSTR("Apple Global Domain"),&exists); + return !scroll; + #else + return true; + #endif + } + + + /// *listonly* + CSRAW public static float HorizontalScrollbar (Rect position, float value, float size, float leftValue, float rightValue) + { return Scroller (position, value, size, leftValue, rightValue, skin.horizontalScrollbar, skin.horizontalScrollbarThumb, skin.horizontalScrollbarLeftButton, skin.horizontalScrollbarRightButton, true); } + // Make a horizontal scrollbar. Scrollbars are what you use to scroll through a document. Most likely, you want to use scrollViews instead. + CSRAW public static float HorizontalScrollbar (Rect position, float value, float size, float leftValue, float rightValue, GUIStyle style) + { return Scroller (position, value, size, leftValue, rightValue, style, skin.GetStyle (style.name + "thumb"), skin.GetStyle (style.name + "leftbutton"), skin.GetStyle (style.name + "rightbutton"), true); } + + // *undocumented* + CUSTOM static internal void InternalRepaintEditorWindow() + { + #if UNITY_EDITOR + GUIView *view = GUIView::GetCurrent (); + if (view) { + view->RequestRepaint (); + } else { + ErrorString ("InternalRepaint called outside an editor OnGUI"); + } + #endif + } + + // *undocumented* + CSRAW internal static bool ScrollerRepeatButton(int scrollerID, Rect rect, GUIStyle style) + { + bool changed = false; + + if (DoRepeatButton (rect, GUIContent.none, style, FocusType.Passive)) + { + bool firstClick = scrollControlID != scrollerID; + scrollControlID = scrollerID; + + if (firstClick) + { + changed = true; + nextScrollStepTime = DateTime.Now.AddMilliseconds(ScrollWaitDefinitions.firstWait); + } + else + { + if (DateTime.Now >= nextScrollStepTime) + { + changed = true; + nextScrollStepTime = DateTime.Now.AddMilliseconds(ScrollWaitDefinitions.regularWait); + } + } + + if (Event.current.type == EventType.Repaint) + InternalRepaintEditorWindow(); + } + + return changed; + } + + /// *listonly* + CSRAW public static float VerticalScrollbar (Rect position, float value, float size, float topValue, float bottomValue) + { return Scroller (position, value, size, topValue, bottomValue, skin.verticalScrollbar, skin.verticalScrollbarThumb, skin.verticalScrollbarUpButton, skin.verticalScrollbarDownButton, false); } + // Make a vertical scrollbar. Scrollbars are what you use to scroll through a document. Most likely, you want to use scrollViews instead. + CSRAW public static float VerticalScrollbar (Rect position, float value, float size, float topValue, float bottomValue, GUIStyle style) + { return Scroller (position, value, size, topValue, bottomValue, style, skin.GetStyle (style.name + "thumb"), skin.GetStyle (style.name + "upbutton"), skin.GetStyle (style.name + "downbutton"), false); } + + static float Scroller (Rect position, float value, float size, float leftValue, float rightValue, GUIStyle slider, GUIStyle thumb, GUIStyle leftButton, GUIStyle rightButton, bool horiz) { + GUIUtility.CheckOnGUI (); + + int id = GUIUtility.GetControlID (sliderHash, FocusType.Passive, position); + + Rect sliderRect, minRect, maxRect; + + if (horiz) { + sliderRect = new Rect ( + position.x + leftButton.fixedWidth, position.y, + position.width - leftButton.fixedWidth - rightButton.fixedWidth, position.height + ); + minRect = new Rect (position.x, position.y, leftButton.fixedWidth, position.height); + maxRect = new Rect (position.xMax - rightButton.fixedWidth, position.y, rightButton.fixedWidth, position.height); + } else { + sliderRect = new Rect ( + position.x, position.y + leftButton.fixedHeight, + position.width, position.height - leftButton.fixedHeight - rightButton.fixedHeight + ); + minRect = new Rect (position.x, position.y, position.width, leftButton.fixedHeight); + maxRect = new Rect (position.x, position.yMax - rightButton.fixedHeight, position.width, rightButton.fixedHeight); + } + + value = Slider (sliderRect, value, size, leftValue, rightValue, slider, thumb, horiz, id); + + bool wasMouseUpEvent = false; + if (Event.current.type == EventType.MouseUp) + wasMouseUpEvent = true; + + if (ScrollerRepeatButton(id, minRect, leftButton)) + value -= scrollStepSize * (leftValue < rightValue ? 1f : -1f); + + if (ScrollerRepeatButton(id, maxRect, rightButton)) + value += scrollStepSize * (leftValue < rightValue ? 1f : -1f); + + if (wasMouseUpEvent && Event.current.type == EventType.Used) // repeat buttons ate mouse up event - release scrolling + scrollControlID = 0; + + if (leftValue < rightValue) + value = Mathf.Clamp (value, leftValue, rightValue - size); + else + value = Mathf.Clamp (value, rightValue, leftValue - size); + return value; + } + + + /// *listonly* + CSRAW public static void BeginGroup (Rect position) { BeginGroup (position, GUIContent.none, GUIStyle.none); } + /// *listonly* + CSRAW public static void BeginGroup (Rect position, string text) { BeginGroup (position, GUIContent.Temp (text), GUIStyle.none); } + /// *listonly* + CSRAW public static void BeginGroup (Rect position, Texture image) { BeginGroup (position, GUIContent.Temp (image), GUIStyle.none); } + /// *listonly* + CSRAW public static void BeginGroup (Rect position, GUIContent content) { BeginGroup (position, content, GUIStyle.none); } + /// *listonly* + CSRAW public static void BeginGroup (Rect position, GUIStyle style) { BeginGroup (position, GUIContent.none, style); } + /// *listonly* + CSRAW public static void BeginGroup (Rect position, string text, GUIStyle style) { BeginGroup (position, GUIContent.Temp (text), style); } + /// *listonly* + CSRAW public static void BeginGroup (Rect position, Texture image, GUIStyle style) { BeginGroup (position, GUIContent.Temp (image), style); } + + // Begin a group. Must be matched with a call to ::ref::EndGroup. + CSRAW public static void BeginGroup (Rect position, GUIContent content, GUIStyle style) { + GUIUtility.CheckOnGUI (); + + int id = GUIUtility.GetControlID (beginGroupHash, FocusType.Passive); + + if (content != GUIContent.none || style != GUIStyle.none) { + switch (Event.current.type) { + case EventType.Repaint: + style.Draw (position, content, id); + break; + default: + if (position.Contains (Event.current.mousePosition)) + GUIUtility.mouseUsed = true; + break; + } + } + + GUIClip.Push (position, Vector2.zero, Vector2.zero, false); + } + static int beginGroupHash = "BeginGroup".GetHashCode (); + + // End a group. + CSRAW public static void EndGroup () { + GUIClip.Pop (); + } + + /// *listonly* + CSRAW public static Vector2 BeginScrollView (Rect position, Vector2 scrollPosition, Rect viewRect) + { return BeginScrollView (position, scrollPosition, viewRect, false, false, skin.horizontalScrollbar, skin.verticalScrollbar, GUI.skin.scrollView); } + /// *listonly* + CSRAW public static Vector2 BeginScrollView (Rect position, Vector2 scrollPosition, Rect viewRect, bool alwaysShowHorizontal, bool alwaysShowVertical) + { return BeginScrollView (position, scrollPosition, viewRect, alwaysShowHorizontal, alwaysShowVertical, skin.horizontalScrollbar, skin.verticalScrollbar, GUI.skin.scrollView); } + /// *listonly* + CSRAW public static Vector2 BeginScrollView (Rect position, Vector2 scrollPosition, Rect viewRect, GUIStyle horizontalScrollbar, GUIStyle verticalScrollbar) + { return BeginScrollView (position, scrollPosition, viewRect, false, false, horizontalScrollbar, verticalScrollbar, GUI.skin.scrollView); } + // Begin a scrolling view inside your GUI. + CSRAW public static Vector2 BeginScrollView (Rect position, Vector2 scrollPosition, Rect viewRect, bool alwaysShowHorizontal, bool alwaysShowVertical, GUIStyle horizontalScrollbar, GUIStyle verticalScrollbar) + { return BeginScrollView (position, scrollPosition, viewRect, alwaysShowHorizontal, alwaysShowVertical, horizontalScrollbar, verticalScrollbar, null); } + + // *undocumented + CSRAW protected static Vector2 DoBeginScrollView (Rect position, Vector2 scrollPosition, Rect viewRect, bool alwaysShowHorizontal, bool alwaysShowVertical, GUIStyle horizontalScrollbar, GUIStyle verticalScrollbar, GUIStyle background) { + return BeginScrollView (position, scrollPosition, viewRect, alwaysShowHorizontal, alwaysShowVertical, horizontalScrollbar, verticalScrollbar, background); + } + CSRAW internal static Vector2 BeginScrollView (Rect position, Vector2 scrollPosition, Rect viewRect, bool alwaysShowHorizontal, bool alwaysShowVertical, GUIStyle horizontalScrollbar, GUIStyle verticalScrollbar, GUIStyle background) { + GUIUtility.CheckOnGUI (); + + #if UNITY_EDITOR + if (Event.current.type == EventType.DragUpdated && position.Contains(Event.current.mousePosition)) + { + if (Mathf.Abs(Event.current.mousePosition.y - position.y) < 8) + { + scrollPosition.y -= 16; + InternalRepaintEditorWindow (); + } + else if (Mathf.Abs(Event.current.mousePosition.y - position.yMax) < 8) + { + scrollPosition.y += 16; + InternalRepaintEditorWindow (); + } + } + #endif + + int id = GUIUtility.GetControlID (scrollviewHash, FocusType.Passive); + ScrollViewState state = (ScrollViewState)GUIUtility.GetStateObject (typeof (ScrollViewState), id); + + if (state.apply) { + scrollPosition = state.scrollPosition; + state.apply = false; + } + state.position = position; + state.scrollPosition = scrollPosition; + state.visibleRect = state.viewRect = viewRect; + state.visibleRect.width = position.width; + state.visibleRect.height = position.height; + s_ScrollViewStates.Push (state); + + Rect clipRect = new Rect (position); + switch (Event.current.type) { + case EventType.Layout: + GUIUtility.GetControlID (sliderHash, FocusType.Passive); + GUIUtility.GetControlID (repeatButtonHash, FocusType.Passive); + GUIUtility.GetControlID (repeatButtonHash, FocusType.Passive); + GUIUtility.GetControlID (sliderHash, FocusType.Passive); + GUIUtility.GetControlID (repeatButtonHash, FocusType.Passive); + GUIUtility.GetControlID (repeatButtonHash, FocusType.Passive); + break; + case EventType.Used: + break; + default: + bool needsVertical = alwaysShowVertical, needsHorizontal = alwaysShowHorizontal; + + // Check if we need a horizontal scrollbar + if (needsHorizontal || viewRect.width > clipRect.width) { + state.visibleRect.height = position.height - horizontalScrollbar.fixedHeight + horizontalScrollbar.margin.top; + clipRect.height -= horizontalScrollbar.fixedHeight + horizontalScrollbar.margin.top; + needsHorizontal = true; + } + if (needsVertical || viewRect.height > clipRect.height) { + state.visibleRect.width = position.width - verticalScrollbar.fixedWidth + verticalScrollbar.margin.left; + clipRect.width -= verticalScrollbar.fixedWidth + verticalScrollbar.margin.left; + needsVertical = true; + if (!needsHorizontal && viewRect.width > clipRect.width) { + state.visibleRect.height = position.height - horizontalScrollbar.fixedHeight + horizontalScrollbar.margin.top; + clipRect.height -= horizontalScrollbar.fixedHeight + horizontalScrollbar.margin.top; + needsHorizontal = true; + } + } + + if (Event.current.type == EventType.Repaint && background != GUIStyle.none) { + background.Draw (position, position.Contains (Event.current.mousePosition), false, needsHorizontal && needsVertical, false); + } + if (needsHorizontal && horizontalScrollbar != GUIStyle.none) { + scrollPosition.x = HorizontalScrollbar (new Rect (position.x, position.yMax - horizontalScrollbar.fixedHeight, clipRect.width, horizontalScrollbar.fixedHeight), + scrollPosition.x, clipRect.width, 0, viewRect.width, + horizontalScrollbar); + } else { + GUIUtility.GetControlID (sliderHash, FocusType.Passive); + GUIUtility.GetControlID (repeatButtonHash, FocusType.Passive); + GUIUtility.GetControlID (repeatButtonHash, FocusType.Passive); + if (horizontalScrollbar != GUIStyle.none) + scrollPosition.x = 0; + else + scrollPosition.x = Mathf.Clamp (scrollPosition.x, 0, Mathf.Max (viewRect.width - position.width, 0)); + } + + if (needsVertical && verticalScrollbar != GUIStyle.none) { + scrollPosition.y = VerticalScrollbar (new Rect (clipRect.xMax + verticalScrollbar.margin.left, clipRect.y, verticalScrollbar.fixedWidth, clipRect.height), + scrollPosition.y, clipRect.height, 0, viewRect.height, + verticalScrollbar); + } else { + GUIUtility.GetControlID (sliderHash, FocusType.Passive); + GUIUtility.GetControlID (repeatButtonHash, FocusType.Passive); + GUIUtility.GetControlID (repeatButtonHash, FocusType.Passive); + if (verticalScrollbar != GUIStyle.none) + scrollPosition.y = 0; + else + scrollPosition.y = Mathf.Clamp (scrollPosition.y, 0, Mathf.Max (viewRect.height - position.height, 0)); + } + break; + } + GUIClip.Push (clipRect, new Vector2 (Mathf.Round (-scrollPosition.x - viewRect.x), Mathf.Round (-scrollPosition.y - viewRect.y)),Vector2.zero, false); + return scrollPosition; + } + static int scrollviewHash = "scrollView".GetHashCode (); + static UnityEngineInternal.GenericStack s_ScrollViewStates = new UnityEngineInternal.GenericStack (); + CLASS internal ScrollViewState + CSRAW + //*undocumented* + public Rect position, visibleRect, viewRect; + //*undocumented* + public Vector2 scrollPosition; + //*undocumented* + public bool apply = false; + //*undocumented* + public bool hasScrollTo = false; + + //*undocumented* + /*public void ScrollTo (Rect position) { + Vector2 pos = GUIClip.Unclip (new Vector2 (position.xMin, position.yMin)); + if (!hasScrollTo) { + hasScrollTo = true; + scrollTo.xMin = pos.x; + scrollTo.yMin = pos.y; + pos = GUIClip.Unclip (new Vector2 (position.xMax, position.yMax)); + scrollTo.xMax = pos.x; + scrollTo.yMax = pos.y; + hasScrollTo = true; + } else { + scrollTo.x = Mathf.Min (pos.x, scrollTo.x); + scrollTo.y = Mathf.Min (pos.y, scrollTo.y); + pos = GUIClip.Unclip (new Vector2 (position.xMax, position.yMax)); + scrollTo.xMax = Mathf.Max (pos.x, scrollTo.xMax); + scrollTo.yMax = Mathf.Max (pos.y, scrollTo.yMax); + } + }*/ + + /*internal void ScrollTo (Rect position) { + Vector2 pos = new Vector2 (position.xMin, position.yMin); + if (!hasScrollTo) { + // Is hasScrollTo ever true outside of this method? + // The ScrollTo method doesn't seems to have any recursive logic so not sure what it's used for. + hasScrollTo = true; + + // scrollTo is being set to the same as position but in a really cumbersome way? + scrollTo.xMin = pos.x; + scrollTo.yMin = pos.y; + pos = new Vector2 (position.xMax, position.yMax); + scrollTo.xMax = pos.x; + scrollTo.yMax = pos.y; + hasScrollTo = true; + + Rect r = visibleRect; + r.x += scrollPosition.x; + r.y += scrollPosition.y; + + Vector2 bottomRight = new Vector2 (scrollTo.xMax, scrollTo.yMax); + Vector2 topLeft = new Vector2 (scrollTo.xMin, scrollTo.yMin); + + if (bottomRight.x > r.xMax) + scrollPosition.x += bottomRight.x - r.xMax; + if (topLeft.x < r.xMin) + scrollPosition.x -= r.xMin - topLeft.x; + + if (bottomRight.y > r.yMax) + scrollPosition.y += bottomRight.y - r.yMax; + if (topLeft.y < r.yMin) + scrollPosition.y -= r.yMin - topLeft.y; + + apply = true; + hasScrollTo = false; + } else { + scrollTo.x = Mathf.Min (pos.x, scrollTo.x); + scrollTo.y = Mathf.Min (pos.y, scrollTo.y); + pos = new Vector2 (position.xMax, position.yMax); + scrollTo.xMax = Mathf.Max (pos.x, scrollTo.xMax); + scrollTo.yMax = Mathf.Max (pos.y, scrollTo.yMax); + } + }*/ + + internal void ScrollTo (Rect position) + { + ScrollTowards (position, Mathf.Infinity); + } + + internal bool ScrollTowards (Rect position, float maxDelta) + { + Vector2 scrollVector = ScrollNeeded (position); + + // If we don't need scrolling, return false + if (scrollVector.sqrMagnitude < 0.0001f) + return false; + + // If we need scrolling but don't actually allow any, just return true to + // indicate scrolling is needed to be able to see position + if (maxDelta == 0) + return true; + + // Clamp scrolling to max allowed delta + if (scrollVector.magnitude > maxDelta) + scrollVector = scrollVector.normalized * maxDelta; + + // Apply scrolling + scrollPosition += scrollVector; + apply = true; + + return true; + } + + internal Vector2 ScrollNeeded (Rect position) + { + Rect r = visibleRect; + r.x += scrollPosition.x; + r.y += scrollPosition.y; + + // If the rect we want to see is larger than the visible rect, then trim it, + // otherwise we can get oscillation or other unwanted behavior + float excess = position.height - visibleRect.height; + if (excess > 0) + { + position.width -= excess; + position.x += excess * 0.5f; + } + excess = position.height - visibleRect.height; + if (excess > 0) + { + position.height -= excess; + position.y += excess * 0.5f; + } + + Vector2 scrollVector = Vector2.zero; + + // Calculate needed x scrolling + if (position.xMax > r.xMax) + scrollVector.x += position.xMax - r.xMax; + else if (position.xMin < r.xMin) + scrollVector.x -= r.xMin - position.xMin; + + // Calculate needed y scrolling + if (position.yMax > r.yMax) + scrollVector.y += position.yMax - r.yMax; + else if (position.yMin < r.yMin) + scrollVector.y -= r.yMin - position.yMin; + + // Clamp scrolling to bounds so we don't request to scroll past the edge + scrollVector.x = Mathf.Clamp (scrollVector.x, viewRect.xMin-scrollPosition.x, viewRect.xMax-visibleRect.width-scrollPosition.x); + scrollVector.y = Mathf.Clamp (scrollVector.y, viewRect.yMin-scrollPosition.y, viewRect.yMax-visibleRect.height-scrollPosition.y); + + return scrollVector; + } + END + + // Ends a scrollview started with a call to BeginScrollView. + public static void EndScrollView () { + EndScrollView (true); + } + + public static void EndScrollView (bool handleScrollWheel) { + ScrollViewState state = (ScrollViewState)s_ScrollViewStates.Peek (); + + GUIUtility.CheckOnGUI (); + GUIClip.Pop (); + + s_ScrollViewStates.Pop (); + + // This is the mac way of handling things: if the mouse is over a scrollview, the scrollview gets the event. + if (handleScrollWheel && Event.current.type == EventType.scrollWheel && state.position.Contains (Event.current.mousePosition)) { + state.scrollPosition.x = Mathf.Clamp (state.scrollPosition.x + (Event.current.delta.x * 20f), 0f, state.viewRect.width - state.visibleRect.width); + state.scrollPosition.y = Mathf.Clamp (state.scrollPosition.y + (Event.current.delta.y * 20f), 0f, state.viewRect.height - state.visibleRect.height); + state.apply = true; + Event.current.Use (); + } + } + + internal static ScrollViewState GetTopScrollView() + { + if (s_ScrollViewStates.Count != 0) + return (ScrollViewState)s_ScrollViewStates.Peek (); + return null; + } + + // Scrolls all enclosing scrollviews so they try to make /position/ visible. + public static void ScrollTo (Rect position) + { + ScrollViewState topmost = GetTopScrollView(); + if (topmost != null) + topmost.ScrollTo(position); + } + + // Scrolls all enclosing scrollviews towards making /position/ visible. + public static bool ScrollTowards (Rect position, float maxDelta) + { + ScrollViewState topmost = GetTopScrollView(); + if (topmost == null) + return false; + return topmost.ScrollTowards(position, maxDelta); + } + +CSRAW +// ====================================================== WINDOWS =============================== + + + /// *listonly* + public delegate void WindowFunction(int id); + /// *listonly* + CSRAW public static Rect Window (int id, Rect clientRect, WindowFunction func, string text) + { return DoWindow (id, clientRect, func, GUIContent.Temp (text), GUI.skin.window, GUI.skin, true); } + /// *listonly* + CSRAW public static Rect Window (int id, Rect clientRect, WindowFunction func, Texture image) + { return DoWindow (id, clientRect, func, GUIContent.Temp (image), GUI.skin.window, GUI.skin, true); } + /// *listonly* + CSRAW public static Rect Window (int id, Rect clientRect, WindowFunction func, GUIContent content) + { return DoWindow (id, clientRect, func, content, GUI.skin.window, GUI.skin, true); } + /// *listonly* + CSRAW public static Rect Window (int id, Rect clientRect, WindowFunction func, string text, GUIStyle style) + { return DoWindow (id, clientRect, func, GUIContent.Temp (text), style, GUI.skin, true); } + /// *listonly* + CSRAW public static Rect Window (int id, Rect clientRect, WindowFunction func, Texture image, GUIStyle style) + { return DoWindow (id, clientRect, func, GUIContent.Temp (image), style, GUI.skin, true); } + + // Make a popup window. + +BEGIN DOC + + Windows float above normal GUI controls, feature click-to-focus and can optionally be dragged around by the end user. + Unlike other controls, you need to pass them a separate function for the GUI controls to put inside the window. + + <b>Note:</b> If you are using [[GUILayout]] to place your components inside the window, you should use GUILayout.Window. + Here is a small example to get you started: + + You can use the same function to create multiple windows. Just make sure that ''each window has its own ID''. Example: + + To stop showing a window, simply stop calling GUI.Window from inside your main OnGUI function: + + To make a window that gets its size from automatic GUI layouting, use GUILayout.Window. + + __Call Ordering__ + + Windows need to be drawn back-to-front; windows on top of other windows need to be drawn later than the ones below them. This means that you can not count on your DoWindow functions to + be called in any particular order. In order for this to work seamlessly, the following values are stored when you create your window (using the __Window__ function), and retrieved when your DoWindow gets called: + GUI.skin, GUI.enabled, GUI.color, GUI.backgroundColor, GUI.contentColor, GUI.matrix + + + This means it's easy to do colored windows like this: + Hint: you can use the alpha component of GUI.color to fade windows in and out. + + + SA: ::ref::DragWindow, ::ref::BringWindowToFront, ::ref::BringWindowToBack + + @param id A unique ID to use for each window. This is the ID you'll use to interface to. + @param clientRect Rectangle on the screen to use for the group. + @param func The function that creates the GUI /inside/ the window. This function must take one parameter - the /id/ of the window it's currently making GUI for. + @param text Text to display as a title for the window. + @param image [[Texture]] to display an image in the titlebar. + @param content Text, image and tooltip for this window. + @param style An optional style to use for the window. If left out, the /window/ style from the current [[GUISkin]] is used. + @returns the rectangle the window is at. +END DOC + + CSRAW public static Rect Window (int id, Rect clientRect, WindowFunction func, GUIContent title, GUIStyle style) { return DoWindow (id, clientRect, func, title, style, GUI.skin, true); } + + // TODO: DOCME + CSRAW public static Rect ModalWindow (int id, Rect clientRect, WindowFunction func, string text) + { return DoModalWindow(id, clientRect, func, GUIContent.Temp(text), GUI.skin.window, GUI.skin); } + + CSRAW public static Rect ModalWindow (int id, Rect clientRect, WindowFunction func, Texture image) + { return DoModalWindow(id, clientRect, func, GUIContent.Temp(image), GUI.skin.window, GUI.skin); } + + CSRAW public static Rect ModalWindow (int id, Rect clientRect, WindowFunction func, GUIContent content) + { return DoModalWindow(id, clientRect, func, content, GUI.skin.window, GUI.skin); } + + CSRAW public static Rect ModalWindow (int id, Rect clientRect, WindowFunction func, string text, GUIStyle style) + { return DoModalWindow(id, clientRect, func, GUIContent.Temp(text), style, GUI.skin); } + + CSRAW public static Rect ModalWindow (int id, Rect clientRect, WindowFunction func, Texture image, GUIStyle style) + { return DoModalWindow(id, clientRect, func, GUIContent.Temp(image), style, GUI.skin); } + + CSRAW public static Rect ModalWindow (int id, Rect clientRect, WindowFunction func, GUIContent content, GUIStyle style) + { return DoModalWindow(id, clientRect, func, content, style, GUI.skin); } + + CUSTOM private static Rect DoModalWindow (int id, Rect clientRect, WindowFunction func, GUIContent content, GUIStyle style, GUISkin skin) + { + return IMGUI::DoWindow (GetGUIState (), id, clientRect, func, MonoGUIContentToTempNative (content), style.GetScriptingObject(), skin, true, true); + } + + CSRAW internal static void CallWindowDelegate (WindowFunction func, int id, GUISkin _skin, int forceRect, float width, float height, GUIStyle style) + { + GUILayoutUtility.SelectIDList (id, true); + GUISkin temp = skin; + if (Event.current.type == EventType.Layout) + { + if (forceRect != 0) { + GUILayoutOption[] options = { GUILayout.Width (width), GUILayout.Height(height) }; + + // Tell the GUILayout system we're starting a window, our style and our size. Then layouting is just the same as anything else + GUILayoutUtility.BeginWindow (id, style, options); + } else { + // If we don't want to force the rect (which is when we come from GUILayout.window), don't pass in the fixedsize options + GUILayoutUtility.BeginWindow (id, style, null); + } + } + skin = _skin; + func (id); + + if (Event.current.type == EventType.Layout) + { + // Now layout the window. + GUILayoutUtility.Layout (); + } + skin = temp; + } + + CUSTOM private static Rect DoWindow (int id, Rect clientRect, WindowFunction func, GUIContent title, GUIStyle style, GUISkin skin, bool forceRectOnLayout) { + return IMGUI::DoWindow (GetGUIState (), id, clientRect, func, MonoGUIContentToTempNative (title), style.GetScriptingObject(), skin, forceRectOnLayout); + } + + // Make a window draggable. + CUSTOM static void DragWindow (Rect position) + { IMGUI::DragWindow (GetGUIState(), position); } + + + // If you want to have the entire window background to act as a drag area, use the version of DragWindow that takes no parameters and put it at the end of the window function. + CSRAW public static void DragWindow () { DragWindow (new Rect (0,0, 10000,10000)); } + + // Bring a specific window to front of the floating windows. + CUSTOM static void BringWindowToFront (int windowID) + { + IMGUI::BringWindowToFront (GetGUIState(), windowID); + } + + // Bring a specific window to back of the floating windows. + CUSTOM static void BringWindowToBack (int windowID) + { + IMGUI::BringWindowToBack (GetGUIState(), windowID); + } + + // Make a window become the active window. + CUSTOM static void FocusWindow (int windowID) + { + IMGUI::FocusWindow (GetGUIState(), windowID); + } + + // Remove focus from all windows. + CUSTOM static void UnfocusWindow () { + IMGUI::FocusWindow (GetGUIState(), -1); + } + + CSRAW + // Call at the beginning of a frame. + // e event to process + // windowInfo - the list of windows we're currently using. + // *undocumented* + internal static void BeginWindows (int skinMode, int editorWindowInstanceID) { + // Let's just remember where we came from + GUILayoutGroup oldTopLevel = GUILayoutUtility.current.topLevel; + UnityEngineInternal.GenericStack oldLayoutGroups = GUILayoutUtility.current.layoutGroups; + GUILayoutGroup oldWindows = GUILayoutUtility.current.windows; + Matrix4x4 mat = GUI.matrix; + + // Call into C++ land + Internal_BeginWindows (); + + GUI.matrix = mat; + GUILayoutUtility.current.topLevel = oldTopLevel; + GUILayoutUtility.current.layoutGroups = oldLayoutGroups; + GUILayoutUtility.current.windows = oldWindows; + } + + CUSTOM private static void Internal_BeginWindows () + { + IMGUI::BeginWindows (GetGUIState(), false); + } + + // Call at the end of frame (at layer 0) to do all windows + CSRAW internal static void EndWindows () { + // Let's just remember where we came from + GUILayoutGroup oldTopLevel = GUILayoutUtility.current.topLevel; + UnityEngineInternal.GenericStack oldLayoutGroups = GUILayoutUtility.current.layoutGroups; + GUILayoutGroup oldWindows = GUILayoutUtility.current.windows; + + // Call Into C++ land + Internal_EndWindows (); + + GUILayoutUtility.current.topLevel = oldTopLevel; + GUILayoutUtility.current.layoutGroups = oldLayoutGroups; + GUILayoutUtility.current.windows = oldWindows; + } + + CUSTOM private static void Internal_EndWindows () + { + IMGUI::EndWindows (GetGUIState()); + } +END + + +CSRAW + +} // namespace |