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(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(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(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. Note: 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