diff options
Diffstat (limited to 'Runtime/Export/GUILayoutUtility.txt')
-rw-r--r-- | Runtime/Export/GUILayoutUtility.txt | 1420 |
1 files changed, 1420 insertions, 0 deletions
diff --git a/Runtime/Export/GUILayoutUtility.txt b/Runtime/Export/GUILayoutUtility.txt new file mode 100644 index 0000000..df94ffa --- /dev/null +++ b/Runtime/Export/GUILayoutUtility.txt @@ -0,0 +1,1420 @@ +C++RAW + +#include "UnityPrefix.h" +#include "Runtime/Math/Rect.h" +#include "Runtime/IMGUI/GUIWindows.h" +#include "Runtime/Scripting/ScriptingUtility.h" + +using namespace Unity; +using namespace std; + +CSRAW +using System; +using System.Collections; +using System.Collections.Generic; + +namespace UnityEngine +{ + +// Utility functions for implementing and extending the GUILayout class. +NONSEALED_CLASS GUILayoutUtility +CSRAW + + CLASS internal LayoutCache + CSRAW + //*undocumented* + internal GUILayoutGroup topLevel = new GUILayoutGroup (); + //*undocumented* + internal UnityEngineInternal.GenericStack layoutGroups = new UnityEngineInternal.GenericStack (); + //*undocumented* + internal GUILayoutGroup windows = new GUILayoutGroup (); + + //*undocumented* + internal LayoutCache () { + layoutGroups.Push (topLevel); + } + + internal LayoutCache (LayoutCache other) + { + topLevel = other.topLevel; + layoutGroups = other.layoutGroups; + windows = other.windows; + } + END + + // TODO: Clean these up after a while + static Dictionary<int, LayoutCache> storedLayouts = new Dictionary<int, LayoutCache> (); + static Dictionary<int, LayoutCache> storedWindows = new Dictionary<int, LayoutCache> (); + + static internal LayoutCache current = new LayoutCache (); + + static Rect kDummyRect = new Rect (0, 0, 1, 1); + + CSRAW static internal LayoutCache SelectIDList (int instanceID, bool isWindow) { + Dictionary<int, LayoutCache> store = isWindow ? storedWindows : storedLayouts; + LayoutCache cache; + if (store.TryGetValue(instanceID, out cache) == false) { +// Debug.Log ("Creating ID " +instanceID + " " + Event.current.type); + cache = new LayoutCache(); + store[instanceID] = cache; + } else { +// Debug.Log ("reusing ID " +instanceID + " " + Event.current.type); + } + current.topLevel = cache.topLevel; + current.layoutGroups = cache.layoutGroups; + current.windows = cache.windows; + return cache; + } + + // Set up the internal GUILayouting + // Called by the main GUI class automatically (from GUI.Begin) + CSRAW static internal void Begin (int instanceID) { + LayoutCache cache = SelectIDList (instanceID, false); + // Make a vertical group to encompass the whole thing + if (Event.current.type == EventType.Layout) { + current.topLevel = cache.topLevel = new GUILayoutGroup (); + current.layoutGroups.Clear (); + current.layoutGroups.Push (current.topLevel); + current.windows = cache.windows = new GUILayoutGroup (); + } else { + current.topLevel = cache.topLevel; + current.layoutGroups = cache.layoutGroups; + current.windows = cache.windows; + } + } + + CSRAW static internal void BeginWindow (int windowID, GUIStyle style, GUILayoutOption[] options) { + LayoutCache cache = SelectIDList (windowID, true); + // Make a vertical group to encompass the whole thing + if (Event.current.type == EventType.Layout) { + current.topLevel = cache.topLevel = new GUILayoutGroup (); + current.topLevel.style = style; + current.topLevel.windowID = windowID; + if (options != null) + current.topLevel.ApplyOptions (options); + current.layoutGroups.Clear (); + current.layoutGroups.Push (current.topLevel); + current.windows = cache.windows = new GUILayoutGroup (); + } else { + current.topLevel = cache.topLevel; + current.layoutGroups = cache. layoutGroups; + current.windows = cache.windows; + } + } + + // TODO: actually make these check... + // *undocumented* + CSRAW static public void BeginGroup (string GroupName) {} + // *undocumented* + CSRAW static public void EndGroup (string groupName) {} + + + static internal void Layout () { + if (current.topLevel.windowID == -1) { + // Normal GUILayout.whatever -outside beginArea calls. + // Here we go over all entries and calculate their sizes + current.topLevel.CalcWidth (); + current.topLevel.SetHorizontal (0, Mathf.Min (Screen.width, current.topLevel.maxWidth)); + current.topLevel.CalcHeight (); + current.topLevel.SetVertical (0, Mathf.Min (Screen.height, current.topLevel.maxHeight)); + +// UNCOMMENT ME TO DEBUG THE ROOT LAYOUT RESULTS +// Debug.Log ("ROOT: " + current.topLevel); + // Layout all beginarea parts... + LayoutFreeGroup (current.windows); + } else { + LayoutSingleGroup (current.topLevel); + LayoutFreeGroup (current.windows); +// Debug.Log ("Windows: " + current.windows); + } + } + + // Global fayout function. Called from EditorWindows (differs from game view in that they use the full window size and try to stretch GUI + // *undocumented* + static internal void LayoutFromEditorWindow () { + current.topLevel.CalcWidth (); + current.topLevel.SetHorizontal (0, Screen.width); + current.topLevel.CalcHeight (); + current.topLevel.SetVertical (0, Screen.height); + +// UNCOMMENT ME TO DEBUG THE EditorWindow ROOT LAYOUT RESULTS +// Debug.Log (current.topLevel); + // Layout all beginarea parts... + LayoutFreeGroup (current.windows); + } + + + // Global layout function. Calculates all sizes of all windows etc & assigns. + // After this call everything has a properly calculated size + // Called by Unity automatically. + // Is public so we can access it from editor inspectors, but not supported by public stuff + // *undocumented* + static internal float LayoutFromInspector (float width) { + if (current.topLevel != null && current.topLevel.windowID == -1) { + // Here we go over all entries and calculate their sizes + current.topLevel.CalcWidth (); + current.topLevel.SetHorizontal (0, width); + current.topLevel.CalcHeight (); + current.topLevel.SetVertical (0, Mathf.Min (Screen.height, current.topLevel.maxHeight)); +// UNCOMMENT ME TO DEBUG THE INSPECTOR +// Debug.Log (current.topLevel); + float height = ((GUILayoutGroup)current.topLevel).minHeight; + // Layout all beginarea parts... + // TODO: NOT SURE HOW THIS WORKS IN AN INSPECTOR + LayoutFreeGroup (current.windows); + return height; + } + else { + if (current.topLevel != null) + LayoutSingleGroup (current.topLevel); + return 0; + } + } + + static internal void LayoutFreeGroup (GUILayoutGroup toplevel) { + foreach (GUILayoutGroup i in toplevel.entries) { + LayoutSingleGroup (i); + } + toplevel.ResetCursor (); + } + + static void LayoutSingleGroup (GUILayoutGroup i) { + if (!i.isWindow) { + // CalcWidth knocks out minWidth with the calculated sizes from its children. Normally, this is fine, but since we're in a fixed-size area, + // we want to maintain that (godammit) + float origMinWidth = i.minWidth; + float origMaxWidth = i.maxWidth; + + // Figure out the group's min & maxWidth. + i.CalcWidth (); + + // Make it as wide as possible, but the Rect supplied takes precedence... + i.SetHorizontal (i.rect.x, Mathf.Clamp (i.maxWidth, origMinWidth, origMaxWidth)); + + // Do the same preservation for CalcHeight... + float origMinHeight = i.minHeight; + float origMaxHeight = i.maxHeight; + + i.CalcHeight (); + // Make it as high as possible, but the Rect supplied takes precedence... + i.SetVertical (i.rect.y, Mathf.Clamp (i.maxHeight, origMinHeight, origMaxHeight)); + +// UNCOMMENT ME TO SEE BEGINAREA/ENDAREA BLOCKS +// Debug.Log (i); + } else { + // Figure out the group's min & maxWidth. + i.CalcWidth (); + + Rect winRect = Internal_GetWindowRect (i.windowID); + + // Make it as wide as possible, but the Rect supplied takes precedence... + i.SetHorizontal (winRect.x, Mathf.Clamp (winRect.width, i.minWidth, i.maxWidth)); + + i.CalcHeight (); + + // Make it as high as possible, but the Rect supplied takes precedence... + i.SetVertical (winRect.y, Mathf.Clamp (winRect.height, i.minHeight, i.maxHeight)); + + // If GUILayout did any resizing, make sure the window reflects this. + + Internal_MoveWindow (i.windowID, i.rect); + } + } + + CUSTOM static private Rect Internal_GetWindowRect (int windowID) + { + return IMGUI::GetWindowRect (GetGUIState (), windowID); + } + + CUSTOM static private void Internal_MoveWindow (int windowID, Rect r) + { + IMGUI::MoveWindowFromLayout (GetGUIState (), windowID, r); + } + + CUSTOM static internal Rect GetWindowsBounds () + { + return IMGUI::GetWindowsBounds (GetGUIState ()); + } + + CSRAW + [System.Security.SecuritySafeCritical] + static GUILayoutGroup CreateGUILayoutGroupInstanceOfType(System.Type LayoutType) + { + if (!typeof(GUILayoutGroup).IsAssignableFrom(LayoutType)) + throw new ArgumentException("LayoutType needs to be of type GUILayoutGroup"); + return (GUILayoutGroup)System.Activator.CreateInstance (LayoutType); + } + + // Generic helper - use this when creating a layoutgroup. It will make sure everything is wired up correctly. + internal static GUILayoutGroup BeginLayoutGroup (GUIStyle style, GUILayoutOption[] options, System.Type LayoutType) { + GUILayoutGroup g; + switch (Event.current.type) { + case EventType.Used: + case EventType.Layout: + g = CreateGUILayoutGroupInstanceOfType (LayoutType); + g.style = style; + if (options != null) + g.ApplyOptions (options); + current.topLevel.Add (g); + break; + default: + g = current.topLevel.GetNext() as GUILayoutGroup; + if (g == null) + throw new ArgumentException("GUILayout: Mismatched LayoutGroup." + Event.current.type); + g.ResetCursor (); + break; + } + current.layoutGroups.Push (g); + current.topLevel = g; + return g; + } + + // The matching end for BeginLayoutGroup + internal static void EndLayoutGroup () { + switch (Event.current.type) { + default: + current.layoutGroups.Pop (); + current.topLevel = (GUILayoutGroup)current.layoutGroups.Peek (); + return; + } + } + + // Generic helper - use this when creating a layoutgroup. It will make sure everything is wired up correctly. + internal static GUILayoutGroup BeginLayoutArea (GUIStyle style, System.Type LayoutType) { + GUILayoutGroup g; + switch (Event.current.type) { + case EventType.Used: + case EventType.Layout: + g = CreateGUILayoutGroupInstanceOfType (LayoutType); + g.style = style; + current.windows.Add (g); + break; + default: + g = current.windows.GetNext() as GUILayoutGroup; + if (g == null) + throw new ArgumentException("GUILayout: Mismatched LayoutGroup." + Event.current.type); + g.ResetCursor (); + break; + } + current.layoutGroups.Push (g); + current.topLevel = g; + return g; + } + + // Trampoline for Editor stuff + //*undocumented* + internal static GUILayoutGroup DoBeginLayoutArea (GUIStyle style, System.Type LayoutType) { + return BeginLayoutArea (style, LayoutType); + } + internal static GUILayoutGroup topLevel { + get { return current.topLevel; } + } + + + /// *listonly* + CSRAW public static Rect GetRect (GUIContent content, GUIStyle style) { return DoGetRect (content, style, null); } + // Reserve layout space for a rectangle for displaying some contents with a specific style. + CSRAW public static Rect GetRect (GUIContent content, GUIStyle style, params GUILayoutOption[] options) { return DoGetRect (content, style, options); } + CSRAW static Rect DoGetRect (GUIContent content, GUIStyle style, GUILayoutOption[] options) { + GUIUtility.CheckOnGUI(); + + switch (Event.current.type) { + case EventType.Layout: { + if (style.isHeightDependantOnWidth) { + current.topLevel.Add (new GUIWordWrapSizer (style, content, options)); + } else { + Vector2 size = style.CalcSize (content); + current.topLevel.Add (new GUILayoutEntry (size.x, size.x, size.y, size.y, style, options)); + } + return kDummyRect; + } + case EventType.Used: + return kDummyRect; + default: + return current.topLevel.GetNext ().rect; + } + } + + /// *listonly* + CSRAW public static Rect GetRect (float width, float height) { return DoGetRect (width, width, height, height, GUIStyle.none, null);} + /// *listonly* + CSRAW public static Rect GetRect (float width, float height, GUIStyle style) {return DoGetRect (width, width, height, height, style, null);} + /// *listonly* + CSRAW public static Rect GetRect (float width, float height, params GUILayoutOption[] options) {return DoGetRect (width, width, height, height, GUIStyle.none, options);} + // Reserve layout space for a rectangle with a fixed content area. + CSRAW public static Rect GetRect (float width, float height, GUIStyle style, params GUILayoutOption[] options) + {return DoGetRect (width, width, height, height, style, options);} + + + + /// *listonly* + CSRAW public static Rect GetRect (float minWidth, float maxWidth, float minHeight, float maxHeight) + { return DoGetRect (minWidth, maxWidth, minHeight, maxHeight, GUIStyle.none, null); } + /// *listonly* + CSRAW public static Rect GetRect (float minWidth, float maxWidth, float minHeight, float maxHeight, GUIStyle style) + { return DoGetRect (minWidth, maxWidth, minHeight, maxHeight, style, null); } + /// *listonly* + CSRAW public static Rect GetRect (float minWidth, float maxWidth, float minHeight, float maxHeight, params GUILayoutOption[] options) + { return DoGetRect (minWidth, maxWidth, minHeight, maxHeight, GUIStyle.none, options); } + // Reserve layout space for a flexible rect. + CSRAW public static Rect GetRect (float minWidth, float maxWidth, float minHeight, float maxHeight, GUIStyle style, params GUILayoutOption[] options) + { return DoGetRect (minWidth, maxWidth, minHeight, maxHeight, style, options); } + CSRAW static Rect DoGetRect (float minWidth, float maxWidth, float minHeight, float maxHeight, GUIStyle style, GUILayoutOption[] options) { + switch (Event.current.type) { + case EventType.Layout: + current.topLevel.Add (new GUILayoutEntry (minWidth, maxWidth, minHeight, maxHeight, style, options)); + return kDummyRect; + case EventType.Used: + return kDummyRect; + default: + return current.topLevel.GetNext ().rect; + } + } + + // Get the rectangle last used by GUILayout for a control. + CSRAW public static Rect GetLastRect () { + switch (Event.current.type) { + case EventType.Layout: + return kDummyRect; + case EventType.Used: + return kDummyRect; + default: + return current.topLevel.GetLast (); + } + } + + /// *listonly* + CSRAW public static Rect GetAspectRect (float aspect) { return DoGetAspectRect (aspect, GUIStyle.none, null); } + /// *listonly* + CSRAW public static Rect GetAspectRect (float aspect, GUIStyle style) { return DoGetAspectRect (aspect, style, null); } + /// *listonly* + CSRAW public static Rect GetAspectRect (float aspect, params GUILayoutOption[] options) { return DoGetAspectRect (aspect, GUIStyle.none, options); } + // Reserve layout space for a rectangle with a specific aspect ratio. + CSRAW public static Rect GetAspectRect (float aspect, GUIStyle style, params GUILayoutOption[] options) { return DoGetAspectRect (aspect, GUIStyle.none, options); } + static Rect DoGetAspectRect (float aspect, GUIStyle style, GUILayoutOption[] options) { + switch (Event.current.type) { + case EventType.Layout: + current.topLevel.Add (new GUIAspectSizer (aspect, options)); + return kDummyRect; + case EventType.Used: + return kDummyRect; + default: + return current.topLevel.GetNext ().rect; + } + } + + // Style used by space elements so we can do special handling of spaces. + CSRAW internal static GUIStyle spaceStyle + { + get + { + if (s_SpaceStyle == null) s_SpaceStyle = new GUIStyle(); + s_SpaceStyle.stretchWidth = false; + return s_SpaceStyle; + } + } + static GUIStyle s_SpaceStyle; +END + + +// Basic layout element +NONSEALED_CLASS internal GUILayoutEntry + CSRAW + // The min and max sizes. Used during calculations... + CSRAW public float minWidth, maxWidth, minHeight, maxHeight; + + // The rectangle that this element ends up having + CSRAW public Rect rect = new Rect (0,0,0,0); + + // Can this element stretch? + CSRAW public int stretchWidth, stretchHeight; + + // The style to use. + CSRAW GUIStyle m_Style = GUIStyle.none; + CSRAW public GUIStyle style { get { return m_Style; } set { m_Style = value; ApplyStyleSettings (value); } } + + CSRAW internal static Rect kDummyRect = new Rect (0,0,1,1); + + // The margins of this element. + public virtual RectOffset margin { get { + return style.margin; + }} + + public GUILayoutEntry (float _minWidth, float _maxWidth, float _minHeight, float _maxHeight, GUIStyle _style) { + minWidth = _minWidth; + maxWidth = _maxWidth; + minHeight = _minHeight; + maxHeight = _maxHeight; + if (_style == null) + _style = GUIStyle.none; + style = _style; + } + + public GUILayoutEntry (float _minWidth, float _maxWidth, float _minHeight, float _maxHeight, GUIStyle _style, GUILayoutOption[] options) { + minWidth = _minWidth; + maxWidth = _maxWidth; + minHeight = _minHeight; + maxHeight = _maxHeight; + style = _style; + ApplyOptions (options); + } + + public virtual void CalcWidth () {} + public virtual void CalcHeight () {} + public virtual void SetHorizontal (float x, float width) { rect.x = x; rect.width = width; } + public virtual void SetVertical (float y, float height) { rect.y = y; rect.height = height; } + + protected virtual void ApplyStyleSettings (GUIStyle style) { + stretchWidth = (style.fixedWidth == 0 && style.stretchWidth) ? 1 : 0; + stretchHeight = (style.fixedHeight == 0 && style.stretchHeight) ? 1 : 0; + m_Style = style; + } + + public virtual void ApplyOptions (GUILayoutOption[] options) { + if (options == null) + return; + foreach (GUILayoutOption i in options) { + switch (i.type) { + case GUILayoutOption.Type.fixedWidth: minWidth = maxWidth = (float)i.value; stretchWidth = 0; break; + case GUILayoutOption.Type.fixedHeight: minHeight = maxHeight = (float)i.value; stretchHeight = 0; break; + case GUILayoutOption.Type.minWidth: minWidth = (float)i.value; if (maxWidth < minWidth) maxWidth = minWidth; break; + case GUILayoutOption.Type.maxWidth: maxWidth = (float)i.value; if (minWidth > maxWidth) minWidth = maxWidth; stretchWidth = 0; break; + case GUILayoutOption.Type.minHeight: minHeight = (float)i.value; if (maxHeight < minHeight) maxHeight = minHeight; break; + case GUILayoutOption.Type.maxHeight: maxHeight = (float)i.value; if (minHeight > maxHeight) minHeight = maxHeight; stretchHeight = 0; break; + case GUILayoutOption.Type.stretchWidth: stretchWidth = (int)i.value; break; + case GUILayoutOption.Type.stretchHeight: stretchHeight = (int)i.value; break; + } + } + if (maxWidth != 0 && maxWidth < minWidth) + maxWidth = minWidth; + if (maxHeight != 0 && maxHeight < minHeight) + maxHeight = minHeight; + + } + + protected static int indent = 0; + public override string ToString () { + string space = ""; + for (int i = 0; i < indent; i++) + space += " "; + return space + UnityString.Format ("{1}-{0} (x:{2}-{3}, y:{4}-{5})", style != null ? style.name : "NULL", GetType(), rect.x, rect.xMax, rect.y, rect.yMax) + + " - W: " + minWidth + "-" + maxWidth + (stretchWidth != 0 ? "+" : "") + ", H: " + minHeight + "-" + maxHeight + (stretchHeight != 0 ? "+" : ""); + } +END + +// *undocumented* +NONSEALED_CLASS internal GUILayoutGroup : GUILayoutEntry + CSRAW + public List<GUILayoutEntry> entries = new List<GUILayoutEntry>(); + public bool isVertical = true; // Is this group vertical + public bool resetCoords = false; // Reset coordinate for GetRect. Used for groups that are part of a window + public float spacing = 0; // Spacing between the elements contained within + public bool sameSize = true; // Are all subelements the same size + public bool isWindow = false; // Is this a window at all? + public int windowID = -1; // Optional window ID for toplevel windows. Used by Layout to tell GUI.Window of size changes... + int cursor = 0; + protected int stretchableCountX = 100, stretchableCountY = 100; + protected bool userSpecifiedWidth = false, userSpecifiedHeight = false; + // Should all elements be the same size? + // TODO: implement +// CSRAW bool equalSize = false; + + // The summed sizes of the children. This is used to determine whether or not the children should be stretched + CSRAW protected float childMinWidth = 100, childMaxWidth = 100, childMinHeight = 100, childMaxHeight = 100; + + // How are subelements justified along the minor direction? + // TODO: implement +// CSRAW enum Align { start, middle, end, justify } +// CSRAW Align align; + + RectOffset m_Margin = new RectOffset(); + public override RectOffset margin { get { + return m_Margin; + }} + + + public GUILayoutGroup () : base (0,0,0,0,GUIStyle.none) {} + +#if !UNITY_FLASH && !UNITY_WEBGL + public GUILayoutGroup (GUIStyle _style, GUILayoutOption[] options) : base (0,0,0,0, _style) { + if (options != null) + ApplyOptions (options); + m_Margin.left = _style.margin.left; + m_Margin.right = _style.margin.right; + m_Margin.top = _style.margin.top; + m_Margin.bottom = _style.margin.bottom; + } +#endif + + public override void ApplyOptions (GUILayoutOption[] options) { + if (options == null) + return; + base.ApplyOptions (options); + foreach (GUILayoutOption i in options) { + switch (i.type) { + case GUILayoutOption.Type.fixedWidth: + case GUILayoutOption.Type.minWidth: + case GUILayoutOption.Type.maxWidth: + userSpecifiedHeight = true; + break; + case GUILayoutOption.Type.fixedHeight: + case GUILayoutOption.Type.minHeight: + case GUILayoutOption.Type.maxHeight: + userSpecifiedWidth = true; + break; +// TODO: +// case GUILayoutOption.Type.alignStart: align = Align.start; break; +// case GUILayoutOption.Type.alignMiddle: align = Align.middle; break; +// case GUILayoutOption.Type.alignEnd: align = Align.end; break; +// case GUILayoutOption.Type.alignJustify: align = Align.justify; break; +// case GUILayoutOption.Type.equalSize: equalSize = true; break; + case GUILayoutOption.Type.spacing: spacing = (int)i.value; break; + } + } + } + + protected override void ApplyStyleSettings (GUIStyle style) { + base.ApplyStyleSettings (style); + RectOffset mar = style.margin; + m_Margin.left = mar.left; + m_Margin.right = mar.right; + m_Margin.top = mar.top; + m_Margin.bottom = mar.bottom; + } + + public void ResetCursor () { cursor = 0; } + + public Rect PeekNext () { + if(cursor < entries.Count) { + GUILayoutEntry e = (GUILayoutEntry)entries[cursor]; + return e.rect; + } else { + throw new ArgumentException("Getting control " + cursor + "'s position in a group with only " + entries.Count + " controls when doing " + Event.current.rawType + "\nAborting"); + } + } + + public GUILayoutEntry GetNext () { + if(cursor < entries.Count) { + GUILayoutEntry e = (GUILayoutEntry)entries[cursor]; + cursor++; + return e; + } else { + throw new ArgumentException("Getting control " + cursor + "'s position in a group with only " + entries.Count + " controls when doing " + Event.current.rawType + "\nAborting"); + } + } + + //* undocumented + public Rect GetLast () { + if (cursor == 0) { + Debug.LogError ("You cannot call GetLast immediately after beginning a group."); + return kDummyRect; + } + if(cursor <= entries.Count) { + GUILayoutEntry e = (GUILayoutEntry)entries[cursor - 1]; + return e.rect; + } else { + Debug.LogError ("Getting control " + cursor + "'s position in a group with only " + entries.Count + " controls when doing " + Event.current.type); + return kDummyRect; + } + } + + + public void Add (GUILayoutEntry e) { + entries.Add (e); + } + + CSRAW public override void CalcWidth () { + if (entries.Count == 0) { + maxWidth = minWidth = style.padding.horizontal; + return; + } + + childMinWidth = 0; childMaxWidth = 0; + int _leftMarginMin = 0, _rightMarginMin = 0; + stretchableCountX = 0; + bool first = true; + if (isVertical) { + foreach (GUILayoutEntry i in entries) { + i.CalcWidth (); + RectOffset margins = i.margin; + if (i.style != GUILayoutUtility.spaceStyle) { + if (!first) { + _leftMarginMin = Mathf.Min (margins.left, _leftMarginMin); + _rightMarginMin = Mathf.Min (margins.right, _rightMarginMin); + } else { + _leftMarginMin = margins.left; + _rightMarginMin = margins.right; + first = false; + } + childMinWidth = Mathf.Max (i.minWidth + margins.horizontal, childMinWidth); + childMaxWidth = Mathf.Max (i.maxWidth + margins.horizontal, childMaxWidth); + } + stretchableCountX += i.stretchWidth; + } + // Before, we added the margins to the width, now we want to suptract them again. + childMinWidth -= _leftMarginMin + _rightMarginMin; + childMaxWidth -= _leftMarginMin + _rightMarginMin; + + } else { + int lastMargin = 0; + foreach (GUILayoutEntry i in entries) { + i.CalcWidth (); + RectOffset m = i.margin; + int margin; + + // Specialcase spaceStyle - instead of handling margins normally, we just want to insert the size... + // This ensure that Space(1) adds ONE space, and doesn't prevent margin collapses + if (i.style != GUILayoutUtility.spaceStyle) { + if (!first) + margin = lastMargin > m.left ? lastMargin : m.left; + else { + // the first element's margins are handles _leftMarginMin and should not be added to the children's sizes + margin = 0; + first = false; + } + childMinWidth += i.minWidth + spacing + margin; + childMaxWidth += i.maxWidth + spacing + margin; + lastMargin = m.right; + stretchableCountX += i.stretchWidth; + } else { + childMinWidth += i.minWidth; + childMaxWidth += i.maxWidth; + stretchableCountX += i.stretchWidth; + } + } + childMinWidth -= spacing; + childMaxWidth -= spacing; + if (entries.Count != 0) { + _leftMarginMin = ((GUILayoutEntry)entries[0]).margin.left; + _rightMarginMin = lastMargin; + } else { + _leftMarginMin = _rightMarginMin = 0; + } + } + // Catch the cases where we have ONLY space elements in a group + + // calculated padding values. + float leftPadding = 0, rightPadding = 0; + + // If we have a style, the margins are handled i.r.t. padding. + if (style != GUIStyle.none || userSpecifiedWidth) { + // Add the padding of this group to the total min & max widths + leftPadding = Mathf.Max (style.padding.left, _leftMarginMin); + rightPadding = Mathf.Max (style.padding.right, _rightMarginMin); + } + else { + // If we don't have a GUIStyle, we pop the min of margins outward from children on to us. + m_Margin.left = _leftMarginMin; + m_Margin.right = _rightMarginMin; + leftPadding = rightPadding = 0; + } + + // If we have a specified minwidth, take that into account... + minWidth = Mathf.Max (minWidth, childMinWidth + leftPadding + rightPadding); + + if (maxWidth == 0) { // if we don't have a max width, take the one that was calculated + stretchWidth += stretchableCountX + (style.stretchWidth ? 1 : 0); + maxWidth = childMaxWidth + leftPadding + rightPadding; + } else { + // Since we have a maximum width, this element can't stretch width. + stretchWidth = 0; + } + // Finally, if our minimum width is greater than our maximum width, minWidth wins + maxWidth = Mathf.Max (maxWidth, minWidth); + + // If the style sets us to be a fixed width that wins completely + if (style.fixedWidth != 0) { + maxWidth = minWidth = style.fixedWidth; + stretchWidth = 0; + } + } + + public override void SetHorizontal (float x, float width) { + base.SetHorizontal (x, width); + + if (resetCoords) + x = 0; + + RectOffset padding = style.padding; + + if (isVertical) { + // If we have a GUIStyle here, spacing from our edges to children are max (our padding, their margins) + if (style != GUIStyle.none) { + foreach (GUILayoutEntry i in entries) { + // NOTE: we can't use .horizontal here (As that could make things like right button margin getting eaten by large left padding - so we need to split up in left and right + float leftMar = Mathf.Max (i.margin.left, padding.left); + float thisX = x + leftMar; + float thisWidth = width - Mathf.Max (i.margin.right, padding.right) - leftMar; + if (i.stretchWidth != 0) + i.SetHorizontal (thisX, thisWidth); + else + i.SetHorizontal (thisX, Mathf.Clamp (thisWidth, i.minWidth, i.maxWidth)); + } + } else { + // If not, PART of the subelements' margins have already been propagated upwards to this group, so we need to subtract that from what we apply + float thisX = x - margin.left; + float thisWidth = width + margin.horizontal; + foreach (GUILayoutEntry i in entries) { + if (i.stretchWidth != 0) { + i.SetHorizontal (thisX + i.margin.left, thisWidth - i.margin.horizontal); + } else + i.SetHorizontal (thisX + i.margin.left, Mathf.Clamp (thisWidth - i.margin.horizontal, i.minWidth, i.maxWidth)); + } + } + } else { // we're horizontally laid out: + // apply margins/padding here + // If we have a style, adjust the sizing to take care of padding (if we don't the horizontal margins have been propagated fully up the hierarchy)... + if (style != GUIStyle.none) { + float leftMar = padding.left, rightMar = padding.right; + if (entries.Count != 0) { + leftMar = Mathf.Max (leftMar, ((GUILayoutEntry)entries[0]).margin.left); + rightMar = Mathf.Max (rightMar, ((GUILayoutEntry)entries[entries.Count - 1]).margin.right); + } + x += leftMar; + width -= rightMar + leftMar; + } + + // Find out how much leftover width we should distribute. + float widthToDistribute = width - spacing * (entries.Count - 1); + // Where to place us in height between min and max + float minMaxScale = 0; + // How much height to add to stretchable elements + if (childMinWidth != childMaxWidth) + minMaxScale = Mathf.Clamp ((widthToDistribute - childMinWidth) / (childMaxWidth - childMinWidth), 0, 1); + + // Handle stretching + float perItemStretch = 0; + if (widthToDistribute > childMaxWidth) { // If we have too much space, we need to distribute it. + if (stretchableCountX > 0) { + perItemStretch = (widthToDistribute - childMaxWidth) / (float)stretchableCountX; + } + } + + // Set the positions + int lastMargin = 0; + bool firstMargin = true; +// Debug.Log ("" + x + ", " + width + " perItemStretch:" + perItemStretch); +// Debug.Log ("MinMaxScale"+ minMaxScale); + foreach (GUILayoutEntry i in entries) { + float thisWidth = Mathf.Lerp (i.minWidth, i.maxWidth, minMaxScale); +// Debug.Log (i.minWidth); + thisWidth += perItemStretch * i.stretchWidth; + + if (i.style != GUILayoutUtility.spaceStyle) { // Skip margins on spaces. + int leftMargin = i.margin.left; + if (firstMargin) { + leftMargin = 0; + firstMargin = false; + } + int margin = lastMargin > leftMargin ? lastMargin : leftMargin; + x += margin; + lastMargin = i.margin.right; + } + + i.SetHorizontal (Mathf.Round (x), Mathf.Round(thisWidth)); + x += thisWidth + spacing; + } + } + } + + public override void CalcHeight () { + if (entries.Count == 0) { + maxHeight = minHeight = style.padding.vertical; + return; + } + + childMinHeight = childMaxHeight = 0; + int _topMarginMin = 0, _bottomMarginMin = 0; + stretchableCountY = 0; + if (isVertical) { + int lastMargin = 0; + bool first = true; + foreach (GUILayoutEntry i in entries) { + i.CalcHeight (); + RectOffset m = i.margin; + int margin; + + // Specialcase spaces - it's a space, so instead of handling margins normally, we just want to insert the size... + // This ensure that Space(1) adds ONE space, and doesn't prevent margin collapses + if (i.style != GUILayoutUtility.spaceStyle) { + if (!first) + margin = Mathf.Max(lastMargin, m.top); + else { + margin = 0; + first = false; + } + + childMinHeight += i.minHeight + spacing + margin; + childMaxHeight += i.maxHeight + spacing + margin; + lastMargin = m.bottom; + stretchableCountY += i.stretchHeight; + } else { + childMinHeight += i.minHeight; + childMaxHeight += i.maxHeight; + stretchableCountY += i.stretchHeight; + } + } + + childMinHeight -= spacing; + childMaxHeight -= spacing; + if (entries.Count != 0) { + _topMarginMin = ((GUILayoutEntry)entries[0]).margin.top; + _bottomMarginMin = lastMargin; + } else { + _bottomMarginMin = _topMarginMin = 0; + } + } else { + bool first = true; + foreach (GUILayoutEntry i in entries) { + i.CalcHeight (); + RectOffset margins = i.margin; + if (i.style != GUILayoutUtility.spaceStyle) { + if (!first) { + _topMarginMin = Mathf.Min (margins.top, _topMarginMin); + _bottomMarginMin = Mathf.Min (margins.bottom, _bottomMarginMin); + } else { + _topMarginMin = margins.top; + _bottomMarginMin = margins.bottom; + first = false; + } + childMinHeight = Mathf.Max (i.minHeight, childMinHeight); + childMaxHeight = Mathf.Max (i.maxHeight, childMaxHeight); + } + stretchableCountY += i.stretchHeight; + } + } + float firstPadding = 0, lastPadding = 0; + + // If we have a style, the margins are handled i.r.t. padding. + if (style != GUIStyle.none || userSpecifiedHeight) { + // Add the padding of this group to the total min & max widths + firstPadding = Mathf.Max (style.padding.top, _topMarginMin); + lastPadding = Mathf.Max (style.padding.bottom, _bottomMarginMin); + } + else { + // If we don't have a GUIStyle, we bubble the margins outward from children on to us. + m_Margin.top = _topMarginMin; + m_Margin.bottom = _bottomMarginMin; + firstPadding = lastPadding = 0; + } + //Debug.Log ("Margins: " + _topMarginMin + ", " + _bottomMarginMin + " childHeights:" + childMinHeight + ", " + childMaxHeight); + // If we have a specified minheight, take that into account... + minHeight = Mathf.Max (minHeight, childMinHeight + firstPadding + lastPadding); + + if (maxHeight == 0) { // if we don't have a max height, take the one that was calculated + stretchHeight += stretchableCountY + (style.stretchHeight ? 1 : 0); + maxHeight = childMaxHeight + firstPadding + lastPadding; + } else { + // Since we have a maximum height, this element can't stretch height. + stretchHeight = 0; + } + // Finally, if out minimum height is greater than our maximum height, minHeight wins + maxHeight = Mathf.Max (maxHeight, minHeight); + + // If the style sets us to be a fixed height + if (style.fixedHeight != 0) { + maxHeight = minHeight = style.fixedHeight; + stretchHeight = 0; + } + } + + public override void SetVertical (float y, float height) { + base.SetVertical (y, height); + + if (entries.Count == 0) + return; + + RectOffset padding = style.padding; + + if (resetCoords) + y = 0; + + if (isVertical) { + // If we have a skin, adjust the sizing to take care of padding (if we don't have a skin the vertical margins have been propagated fully up the hierarchy)... + if (style != GUIStyle.none) { + float topMar = padding.top, bottomMar = padding.bottom; + if (entries.Count != 0) { + topMar = Mathf.Max (topMar, ((GUILayoutEntry)entries[0]).margin.top); + bottomMar = Mathf.Max (bottomMar, ((GUILayoutEntry)entries[entries.Count - 1]).margin.bottom); + } + y += topMar; + height -= bottomMar + topMar; + } + + // Find out how much leftover height we should distribute. + float heightToDistribute = height - spacing * (entries.Count - 1); + // Where to place us in height between min and max + float minMaxScale = 0; + // How much height to add to stretchable elements + if (childMinHeight != childMaxHeight) + minMaxScale = Mathf.Clamp ((heightToDistribute - childMinHeight) / (childMaxHeight - childMinHeight), 0, 1); + + // Handle stretching + float perItemStretch = 0; + if (heightToDistribute > childMaxHeight) { // If we have too much space - stretch any stretchable children + if (stretchableCountY > 0) + perItemStretch = (heightToDistribute - childMaxHeight) / (float)stretchableCountY; + } + + // Set the positions + int lastMargin = 0; + bool firstMargin = true; + foreach (GUILayoutEntry i in entries) { + float thisHeight = Mathf.Lerp (i.minHeight, i.maxHeight, minMaxScale); + thisHeight += perItemStretch * i.stretchHeight; + + if (i.style != GUILayoutUtility.spaceStyle) { // Skip margins on spaces. + int topMargin = i.margin.top; + if (firstMargin) { + topMargin = 0; + firstMargin = false; + } + int margin = lastMargin > topMargin ? lastMargin : topMargin; + y += margin; + lastMargin = i.margin.bottom; + } + i.SetVertical (Mathf.Round (y), Mathf.Round(thisHeight)); + y += thisHeight + spacing; + } + } else { + // If we have a GUIStyle here, we need to respect the subelements' margins + if (style != GUIStyle.none) { + foreach (GUILayoutEntry i in entries) { + float topMar = Mathf.Max (i.margin.top, padding.top); + float thisY = y + topMar; + float thisHeight = height - Mathf.Max (i.margin.bottom, padding.bottom) - topMar; + + if (i.stretchHeight != 0) + i.SetVertical (thisY, thisHeight); + else { + i.SetVertical (thisY, Mathf.Clamp (thisHeight, i.minHeight, i.maxHeight)); + } + } + } else { + // If not, the subelements' margins have already been propagated upwards to this group, so we can safely ignore them + float thisY = y - margin.top; + float thisHeight = height + margin.vertical; + foreach (GUILayoutEntry i in entries) { + if (i.stretchHeight != 0) + i.SetVertical (thisY +i.margin.top, thisHeight - i.margin.vertical); + else { + i.SetVertical (thisY + i.margin.top, Mathf.Clamp (thisHeight - i.margin.vertical, i.minHeight, i.maxHeight)); + } + } + + } + } + } + + public override string ToString () { + string str = "", space = ""; + for (int i = 0; i < indent; i++) + space += " "; + str += /* space + */ base.ToString () + " Margins: " + childMinHeight + " {\n"; + indent += 4; + foreach (GUILayoutEntry i in entries) { + str += i.ToString() + "\n"; + } + str += space + "}"; + indent -= 4; + return str; + } +END + +// Layout controller for content inside scroll views +CLASS internal GUIScrollGroup : GUILayoutGroup + CSRAW + public float calcMinWidth, calcMaxWidth, calcMinHeight, calcMaxHeight; + public float clientWidth, clientHeight; + public bool allowHorizontalScroll = true; + public bool allowVerticalScroll = true; + public bool needsHorizontalScrollbar, needsVerticalScrollbar; + public GUIStyle horizontalScrollbar, verticalScrollbar; + + public override void CalcWidth () { + // Save the size values & reset so we calc the sizes of children without any contraints + float _minWidth = minWidth; + float _maxWidth = maxWidth; + if (allowHorizontalScroll) { + minWidth = 0; + maxWidth = 0; + } + + base.CalcWidth(); + calcMinWidth = minWidth; + calcMaxWidth = maxWidth; + + // restore the stored constraints for our parent's sizing + if (allowHorizontalScroll) { + + // Set an explicit small minWidth so it will correctly scroll when place inside horizontal groups + if (minWidth > 32) + minWidth = 32; + + if (_minWidth != 0) + minWidth = _minWidth; + if (_maxWidth != 0) { + maxWidth = _maxWidth; + stretchWidth = 0; + } + } + } + + public override void SetHorizontal (float x, float width) { + float _cWidth = needsVerticalScrollbar ? width - verticalScrollbar.fixedWidth - verticalScrollbar.margin.left : width; + //if (allowVerticalScroll == false) + // Debug.Log ("width " + width); + // If we get a vertical scrollbar, the width changes, so we need to do a recalculation with the new width. + if (allowHorizontalScroll && _cWidth < calcMinWidth) { + // We're too small horizontally, so we need a horizontal scrollbar. + needsHorizontalScrollbar = true; + + // set the min and max width we calculated for the children so SetHorizontal works correctly + minWidth = calcMinWidth; + maxWidth = calcMaxWidth; + base.SetHorizontal (x, calcMinWidth); + + // SetHorizontal also sets our width, but we know better + rect.width = width; + + clientWidth = calcMinWidth; + } else { + // Got enough space. + needsHorizontalScrollbar = false; + + // set the min and max width we calculated for the children so SetHorizontal works correctly + if (allowHorizontalScroll) { + minWidth = calcMinWidth; + maxWidth = calcMaxWidth; + } + base.SetHorizontal (x, _cWidth); + rect.width = width; + + // Store the client width + clientWidth = _cWidth; + } + } + + public override void CalcHeight () { + // Save the values & reset so we calc the sizes of children without any contraints + float _minHeight = minHeight; + float _maxHeight = maxHeight; + if (allowVerticalScroll) + { + minHeight = 0; + maxHeight = 0; + } + + base.CalcHeight(); + + calcMinHeight = minHeight; + calcMaxHeight = maxHeight; + + // if we KNOW we need a horizontal scrollbar, claim space for it now + // otherwise we get a vertical scrollbar and leftover space beneath the scrollview. + if (needsHorizontalScrollbar) { + float scrollerSize = horizontalScrollbar.fixedHeight + horizontalScrollbar.margin.top; + minHeight += scrollerSize; + maxHeight += scrollerSize; + } + + // restore the stored constraints from user SetHeight calls. + if (allowVerticalScroll) + { + if (minHeight > 32) + minHeight = 32; + + if (_minHeight != 0) + minHeight = _minHeight; + if (_maxHeight != 0) + { + maxHeight = _maxHeight; + stretchHeight = 0; + } + } + } + + public override void SetVertical (float y, float height) { + // if we have a horizontal scrollbar, we have less space than we thought + float availableHeight = height; + if (needsHorizontalScrollbar) + availableHeight -= horizontalScrollbar.fixedHeight + horizontalScrollbar.margin.top; + + // Now we know how much height we have, and hence how much vertical space to distribute. + // If we get a vertical scrollbar, the width changes, so we need to do a recalculation with the new width. + if (allowVerticalScroll && availableHeight < calcMinHeight) + { + // We're too small vertically, so we need a vertical scrollbar. + // This means that we have less horizontal space, which can change the vertical size. + if (!needsHorizontalScrollbar && !needsVerticalScrollbar) { + // Subtract scrollbar width from the size... + clientWidth = rect.width - verticalScrollbar.fixedWidth - verticalScrollbar.margin.left; + + // ...But make sure we never get too small. + if (clientWidth < calcMinWidth) + clientWidth = calcMinWidth; + + // Set the new (smaller) size. + float outsideWidth = rect.width; // store a backup of our own width + SetHorizontal (rect.x, clientWidth); + + // This can have caused a reflow, so we need to recalclate from here on down + // (we already know we need a vertical scrollbar, so this size change cannot bubble upwards. + CalcHeight(); + + rect.width = outsideWidth; + } + + + // set the min and max height we calculated for the children so SetVertical works correctly + float origMinHeight = minHeight, origMaxHeight = maxHeight; + minHeight = calcMinHeight; + maxHeight = calcMaxHeight; + base.SetVertical (y, calcMinHeight); + minHeight = origMinHeight; + maxHeight = origMaxHeight; + + rect.height = height; + clientHeight = calcMinHeight; + } else { + + // set the min and max height we calculated for the children so SetVertical works correctly + if (allowVerticalScroll) + { + minHeight = calcMinHeight; + maxHeight = calcMaxHeight; + } + base.SetVertical (y, availableHeight); + rect.height = height; + clientHeight = availableHeight; + } + } +END + +// Layouter that makes elements which sizes will always conform to a specific aspect ratio. +CLASS internal GUIAspectSizer : GUILayoutEntry + CSRAW float aspect; + + public GUIAspectSizer (float aspect, GUILayoutOption[] options) : base (0,0,0,0,GUIStyle.none) { + this.aspect = aspect; + ApplyOptions (options); + } + + public override void CalcHeight () { + minHeight = maxHeight = rect.width / aspect; + } +END + +// Will layout a button grid so it can fit within the given rect. +// *undocumented* +CLASS internal GUIGridSizer : GUILayoutEntry + CSRAW + // Helper: Create the layout group and scale it to fit + public static Rect GetRect (GUIContent[] contents, int xCount, GUIStyle style, GUILayoutOption[] options) { + Rect r = new Rect (0,0,0,0); + switch (Event.current.type) { + case EventType.Layout: { + GUILayoutUtility.current.topLevel.Add (new GUIGridSizer (contents, xCount, style, options)); + break; + } + case EventType.Used: + return kDummyRect; + default: + r = GUILayoutUtility.current.topLevel.GetNext ().rect; + break; + } + return r; + } + int count; + int xCount; + float minButtonWidth = -1, maxButtonWidth = -1, minButtonHeight = -1, maxButtonHeight = -1; + + // Cache of the content for wordwrapping. + //GUIContent[] cachedContent; + + private GUIGridSizer (GUIContent[] contents, int _xCount, GUIStyle buttonStyle, GUILayoutOption[] options) : base (0,0,0,0,GUIStyle.none) { + count = contents.Length; + xCount = _xCount; + + // Most settings comes from the button style (can we stretch, etc). Hence, I apply the style here + ApplyStyleSettings (buttonStyle); + + // We can have custom options coming from userland. We apply this last so it overrides + ApplyOptions (options); + + if (_xCount == 0 || contents.Length == 0) + return; + + // if we don't have wordwrap, there is no funky width<->height relationship. Hence, we can calculate everything here: + // TODO: Actually make it work with wordwrapping stuff (that is pretty hard) +// if (!buttonStyle.wordWrap) { + + // internal horizontal spacing + float totalHorizSpacing = Mathf.Max (buttonStyle.margin.left,buttonStyle.margin.right) * (xCount - 1); +// Debug.Log (String.Format ("margins: {0}, {1} totalHoriz: {2}", buttonStyle.margin.left, buttonStyle.margin.right, totalHorizSpacing)); + // internal horizontal margins + float totalVerticalSpacing = Mathf.Max (buttonStyle.margin.top, buttonStyle.margin.bottom) * (rows - 1); + + + // Handle fixedSize buttons + if (buttonStyle.fixedWidth != 0) + minButtonWidth = maxButtonWidth = buttonStyle.fixedWidth; +// Debug.Log ("buttonStyle.fixedHeight " + buttonStyle.fixedHeight); + if (buttonStyle.fixedHeight != 0) + minButtonHeight = maxButtonHeight = buttonStyle.fixedHeight; + + // Apply GUILayout.Width/Height/whatever properties. + if (minButtonWidth == -1) { + if (minWidth != 0) + minButtonWidth = (minWidth - totalHorizSpacing) / xCount; + if (maxWidth != 0) + maxButtonWidth = (maxWidth - totalHorizSpacing) / xCount; + } + + if (minButtonHeight == -1) { + if (minHeight != 0) + minButtonHeight = (minHeight - totalVerticalSpacing) / rows; + if (maxHeight != 0) + maxButtonHeight = (maxHeight - totalVerticalSpacing) / rows; + } +// Debug.Log (String.Format ("minButtonWidth {0}, maxButtonWidth {1}, minButtonHeight {2}, maxButtonHeight{3}", minButtonWidth, maxButtonWidth, minButtonHeight, maxButtonHeight)); + + // if anything is left unknown, we need to iterate over all elements and figure out the sizes. + if (minButtonHeight == -1 || maxButtonHeight == -1 || minButtonWidth == -1 || maxButtonWidth == -1) { + // figure out the max size. Since the buttons are in a grid, the max size determines stuff. + float calcHeight = 0, calcWidth = 0; + foreach (GUIContent i in contents) { + Vector2 size = buttonStyle.CalcSize (i); + calcWidth = Mathf.Max (calcWidth, size.x); + calcHeight = Mathf.Max (calcHeight, size.y); + } + + // If the user didn't supply minWidth, we need to calculate that + if (minButtonWidth == -1) { + // if the user has supplied a maxButtonWidth, the buttons can never get larger. + if (maxButtonWidth != -1) + minButtonWidth = Mathf.Min (calcWidth, maxButtonWidth); + else + minButtonWidth = calcWidth; + } + + // If the user didn't supply maxWidth, we need to calculate that + if (maxButtonWidth == -1) { + // if the user has supplied a minButtonWidth, the buttons can never get smaler. + if (minButtonWidth != -1) + maxButtonWidth = Mathf.Max (calcWidth, minButtonWidth); + else + maxButtonWidth = calcWidth; + } + + // If the user didn't supply minWidth, we need to calculate that + if (minButtonHeight == -1) { + // if the user has supplied a maxButtonWidth, the buttons can never get larger. + if (maxButtonHeight != -1) + minButtonHeight = Mathf.Min (calcHeight, maxButtonHeight); + else + minButtonHeight = calcHeight; + } + + // If the user didn't supply maxWidth, we need to calculate that + if (maxButtonHeight == -1) { + // if the user has supplied a minButtonWidth, the buttons can never get smaler. + if (minButtonHeight != -1) + maxHeight = Mathf.Max (maxHeight, minButtonHeight); + maxButtonHeight = maxHeight; + } + + } + // We now know the button sizes. Calculate min & max values from that + minWidth = minButtonWidth * xCount + totalHorizSpacing; + maxWidth = maxButtonWidth * xCount + totalHorizSpacing; + minHeight = minButtonHeight * rows + totalVerticalSpacing; + maxHeight = maxButtonHeight * rows + totalVerticalSpacing; +// Debug.Log (String.Format ("minWidth {0}, maxWidth {1}, minHeight {2}, maxHeight{3}", minWidth, maxWidth, minHeight, maxHeight)); + +/* + } else { + // if we're wordwrapping, we need to copy the contents and then do the whole calculations a bit down the road. + cachedContent = new GUIContent [contents.Length]; + for (int i = 0; i < contents.Length; i++) { + cachedContent[i] = new GUIContent (contents[i]); + } + } +*/ + } + + int rows { + get { + int rows = count / xCount; + if (count % xCount != 0) + rows++; + return rows; + } + } +END + +// Class that can handle word-wrap sizing. this is specialcased as setting width can make the text wordwrap, which would then increase height... +CLASS internal GUIWordWrapSizer : GUILayoutEntry + CSRAW + GUIContent content; + // We need to differentiate between min & maxHeight we calculate for ourselves and one that is forced by the user + // (When inside a scrollview, we can be told to layout twice, so we need to know the difference) + float forcedMinHeight, forcedMaxHeight; + public GUIWordWrapSizer (GUIStyle _style, GUIContent _content, GUILayoutOption[] options) : base (0,0,0,0, _style) { + content = new GUIContent (_content); + base.ApplyOptions (options); + forcedMinHeight = minHeight; + forcedMaxHeight = maxHeight; + } + + public override void CalcWidth () { + if (minWidth == 0 || maxWidth == 0) { + float _minWidth, _maxWidth; + style.CalcMinMaxWidth (content, out _minWidth, out _maxWidth); + if (minWidth == 0) + minWidth = _minWidth; + if (maxWidth == 0) + maxWidth = _maxWidth; + } + } + + public override void CalcHeight () { + // When inside a scrollview, this can get called twice (as vertical scrollbar reduces width, which causes a reflow). + // Hence, we need to use the separately cached values for min & maxHeight coming from the user... + if (forcedMinHeight == 0 || forcedMaxHeight == 0) { + float height = style.CalcHeight (content, rect.width); + if (forcedMinHeight == 0) + minHeight = height; + else + minHeight = forcedMinHeight; + if (forcedMaxHeight == 0) + maxHeight = height; + else + maxHeight = forcedMaxHeight; + } + } +END + +// Class internally used to pass layout options into [[GUILayout]] functions. You don't use these directly, but construct them with the layouting functions in the [[GUILayout]] class. +CLASS GUILayoutOption + CSRAW + internal enum Type { + fixedWidth, fixedHeight, minWidth, maxWidth, minHeight, maxHeight, stretchWidth, stretchHeight, + // These are just for the spacing variables + alignStart, alignMiddle, alignEnd, alignJustify, equalSize, spacing + } + // *undocumented* + internal Type type; + // *undocumented* + internal object value; + // *undocumented* + internal GUILayoutOption (Type type, object value) { + this.type = type; + this.value = value; + } +END + + +CSRAW + +} |