/// <summary> /// Main layout method /// </summary> /// <param name="width">Width to calculate the layout with</param> /// <param name="axis">0 for horizontal axis, 1 for vertical</param> /// <param name="layoutInput">If true, sets the layout input for the axis. If false, sets child position for axis</param> public float SetLayout(float width, int axis, bool layoutInput) { var groupHeight = rectTransform.rect.height; // Width that is available after padding is subtracted var workingWidth = rectTransform.rect.width - padding.left - padding.right; // Accumulates the total height of the rows, including spacing and padding. var yOffset = IsLowerAlign ? (float)padding.bottom : (float)padding.top; var currentRowWidth = 0f; var currentRowHeight = 0f; for (var i = 0; i < rectChildren.Count; i++) { // LowerAlign works from back to front var index = IsLowerAlign ? rectChildren.Count - 1 - i : i; var child = rectChildren[index]; var childWidth = LayoutUtility.GetPreferredSize(child, 0); var childHeight = LayoutUtility.GetPreferredSize(child, 1); var childFlexibleWidth = LayoutUtility.GetFlexibleSize(child, 0); if (childFlexibleWidth > 0f) { childWidth = workingWidth; } // Max child width is layout group with - padding childWidth = Mathf.Min(childWidth, workingWidth); // If adding this element would exceed the bounds of the row, // go to a new line after processing the current row if (currentRowWidth + childWidth > workingWidth) { currentRowWidth -= Spacing; // Process current row elements positioning if (!layoutInput) { var h = CalculateRowVerticalOffset(groupHeight, yOffset, currentRowHeight); LayoutRow(_rowList, currentRowWidth, currentRowHeight, workingWidth, padding.left, h, axis); } // Clear existing row _rowList.Clear(); // Add the current row height to total height accumulator, and reset to 0 for the next row yOffset += currentRowHeight; yOffset += Spacing; currentRowHeight = 0; currentRowWidth = 0; } currentRowWidth += childWidth; _rowList.Add(child); // We need the largest element height to determine the starting position of the next line if (childHeight > currentRowHeight) { currentRowHeight = childHeight; } currentRowWidth += Spacing; } if (!layoutInput) { var h = CalculateRowVerticalOffset(groupHeight, yOffset, currentRowHeight); // Layout the final row LayoutRow(_rowList, currentRowWidth, currentRowHeight, workingWidth, padding.left, h, axis); } _rowList.Clear(); // Add the last rows height to the height accumulator yOffset += currentRowHeight; yOffset += IsLowerAlign ? padding.top : padding.bottom; if (layoutInput) { if (axis == 1) { SetLayoutInputForAxis(yOffset, yOffset, -1, axis); } } return(yOffset); }
public static Rect CalcSizeFromText(XdObjectJson xdObject, float?width) { var rawText = xdObject.Text.RawText; var font = xdObject.Style.Font; var fontAsset = AssetDatabase.FindAssets($"{font.PostscriptName}") .Select(guid => AssetDatabase.GUIDToAssetPath(guid)) .Select(path => AssetDatabase.LoadAssetAtPath <Object>(path)) .OfType <TMP_FontAsset>() .Select(x => { x.HasCharacters(rawText, out var missingCharacters); return(missingCharacters.Count, x); }) .OrderBy(x => x.Count) .FirstOrDefault() .x; if (fontAsset == null) { Debug.LogWarning($"TextMeshPro Asset {font.PostscriptName} is not found"); var textParser = new TextObjectParser(); return(textParser.CalcSize(xdObject)); } var position = Vector2.zero; var fontSize = font.Size; position.y -= fontAsset.faceInfo.ascentLine * (fontSize / fontAsset.faceInfo.pointSize); var dummyObject = new GameObject("Dummy"); var dummyRectTransform = dummyObject.AddComponent <RectTransform>(); dummyRectTransform.sizeDelta = new Vector2(width ?? 0f, 0f); var textMeshPro = dummyObject.AddComponent <TextMeshProUGUI>(); textMeshPro.font = fontAsset; textMeshPro.fontSize = fontSize; textMeshPro.text = rawText; if (width != null) { textMeshPro.enableWordWrapping = true; } var size = new Vector2(LayoutUtility.GetPreferredSize(dummyRectTransform, 0), LayoutUtility.GetPreferredSize(dummyRectTransform, 1)); DestroyImmediate(dummyObject); var lineJson = xdObject.Text.Paragraphs[0].Lines[0][0]; position.x += lineJson.X; position.y += lineJson.Y; return(new Rect(position, size)); }
protected void LayoutRow(IList <RectTransform> contents, float rowWidth, float rowHeight, float maxWidth, float xOffset, float yOffset, int axis) { var xPos = xOffset; if (!ChildForceExpandWidth && IsCenterAlign) { xPos += (maxWidth - rowWidth) * 0.5f; } else if (!ChildForceExpandWidth && IsRightAlign) { xPos += (maxWidth - rowWidth); } var extraWidth = 0f; if (ChildForceExpandWidth) { extraWidth = (maxWidth - rowWidth) / _rowList.Count; } for (var j = 0; j < _rowList.Count; j++) { var index = IsLowerAlign ? _rowList.Count - 1 - j : j; var rowChild = _rowList[index]; var rowChildWidth = LayoutUtility.GetPreferredSize(rowChild, 0) + extraWidth; var rowChildHeight = LayoutUtility.GetPreferredSize(rowChild, 1); var childFlexibleWidth = LayoutUtility.GetFlexibleSize(rowChild, 0); if (childFlexibleWidth > 0f) { rowChildWidth = rowWidth; } if (ChildForceExpandHeight) { rowChildHeight = rowHeight; } rowChildWidth = Mathf.Min(rowChildWidth, maxWidth); var yPos = yOffset; if (IsMiddleAlign) { yPos += (rowHeight - rowChildHeight) * 0.5f; } else if (IsLowerAlign) { yPos += (rowHeight - rowChildHeight); } if (axis == 0) { SetChildAlongAxis(rowChild, 0, xPos, rowChildWidth); } else { SetChildAlongAxis(rowChild, 1, yPos, rowChildHeight); } xPos += rowChildWidth + Spacing; } }
protected void LayoutCol(IList <RectTransform> contents, float colWidth, float colHeight, float maxHeight, float xOffset, float yOffset, int axis) { var yPos = yOffset; if (!ChildForceExpandHeight && IsMiddleAlign) { yPos += (maxHeight - colHeight) * 0.5f; } else if (!ChildForceExpandHeight && IsLowerAlign) { yPos += (maxHeight - colHeight); } var extraHeight = 0f; var extraSpacing = 0f; if (ChildForceExpandHeight) { extraHeight = (maxHeight - colHeight) / _itemList.Count; } else if (ExpandHorizontalSpacing) { extraSpacing = (maxHeight - colHeight) / (_itemList.Count - 1); if (_itemList.Count > 1) { if (IsMiddleAlign) { yPos -= extraSpacing * 0.5f * (_itemList.Count - 1); } else if (IsLowerAlign) { yPos -= extraSpacing * (_itemList.Count - 1); } } } for (var j = 0; j < _itemList.Count; j++) { var index = IsRightAlign ? _itemList.Count - 1 - j : j; var rowChild = _itemList[index]; var rowChildWidth = LayoutUtility.GetPreferredSize(rowChild, 0); var rowChildHeight = LayoutUtility.GetPreferredSize(rowChild, 1) + extraHeight; if (ChildForceExpandWidth) { rowChildWidth = colWidth; } rowChildHeight = Mathf.Min(rowChildHeight, maxHeight); var xPos = xOffset; if (IsCenterAlign) { xPos += (colWidth - rowChildWidth) * 0.5f; } else if (IsRightAlign) { xPos += (colWidth - rowChildWidth); } // if (ExpandHorizontalSpacing && j > 0) { yPos += extraSpacing; } if (axis == 0) { SetChildAlongAxis(rowChild, 0, xPos, rowChildWidth); } else { SetChildAlongAxis(rowChild, 1, yPos, rowChildHeight); } // Don't do vertical spacing for the last one if (j < _itemList.Count - 1) { yPos += rowChildHeight + SpacingY; } } }
public override void OnPreviewGUI(Rect r, GUIStyle background) { if (Event.current.type != EventType.Repaint) { return; } if (m_Styles == null) { m_Styles = new Styles(); } GameObject go = target as GameObject; RectTransform rect = go.transform as RectTransform; if (rect == null) { return; } // Apply padding RectOffset previewPadding = new RectOffset(-5, -5, -5, -5); r = previewPadding.Add(r); // Prepare rects for columns r.height = EditorGUIUtility.singleLineHeight; Rect labelRect = r; Rect valueRect = r; Rect sourceRect = r; labelRect.width = kLabelWidth; valueRect.xMin += kLabelWidth; valueRect.width = kValueWidth; sourceRect.xMin += kLabelWidth + kValueWidth; // Headers GUI.Label(labelRect, "Property", m_Styles.headerStyle); GUI.Label(valueRect, "Value", m_Styles.headerStyle); GUI.Label(sourceRect, "Source", m_Styles.headerStyle); labelRect.y += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing; valueRect.y += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing; sourceRect.y += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing; // Prepare reusable variable for out argument ILayoutElement source = null; // Show properties ShowProp(ref labelRect, ref valueRect, ref sourceRect, "Min Width", LayoutUtility.GetLayoutProperty(rect, e => e.minWidth, 0, out source).ToString(), source); ShowProp(ref labelRect, ref valueRect, ref sourceRect, "Min Height", LayoutUtility.GetLayoutProperty(rect, e => e.minHeight, 0, out source).ToString(), source); ShowProp(ref labelRect, ref valueRect, ref sourceRect, "Preferred Width", LayoutUtility.GetLayoutProperty(rect, e => e.preferredWidth, 0, out source).ToString(), source); ShowProp(ref labelRect, ref valueRect, ref sourceRect, "Preferred Height", LayoutUtility.GetLayoutProperty(rect, e => e.preferredHeight, 0, out source).ToString(), source); float flexible = 0; flexible = LayoutUtility.GetLayoutProperty(rect, e => e.flexibleWidth, 0, out source); ShowProp(ref labelRect, ref valueRect, ref sourceRect, "Flexible Width", flexible > 0 ? ("enabled (" + flexible.ToString() + ")") : "disabled", source); flexible = LayoutUtility.GetLayoutProperty(rect, e => e.flexibleHeight, 0, out source); ShowProp(ref labelRect, ref valueRect, ref sourceRect, "Flexible Height", flexible > 0 ? ("enabled (" + flexible.ToString() + ")") : "disabled", source); if (!rect.GetComponent <LayoutElement>()) { Rect noteRect = new Rect(labelRect.x, labelRect.y + 10, r.width, EditorGUIUtility.singleLineHeight); GUI.Label(noteRect, "Add a LayoutElement to override values.", m_Styles.labelStyle); } }
/// <summary> /// Main layout method /// </summary> /// <param name="width">Width to calculate the layout with</param> /// <param name="axis">0 for horizontal axis, 1 for vertical</param> /// <param name="layoutInput">If true, sets the layout input for the axis. If false, sets child position for axis</param> public float SetLayout(int axis, bool layoutInput) { //container height and width var groupHeight = rectTransform.rect.height; var groupWidth = rectTransform.rect.width; float spacingBetweenBars = 0; float spacingBetweenElements = 0; float offset = 0; float counterOffset = 0; float groupSize = 0; float workingSize = 0; if (startAxis == Axis.Horizontal) { groupSize = groupHeight; workingSize = groupWidth - padding.left - padding.right; if (IsLowerAlign) { offset = (float)padding.bottom; counterOffset = (float)padding.top; } else { offset = (float)padding.top; counterOffset = (float)padding.bottom; } spacingBetweenBars = SpacingY; spacingBetweenElements = SpacingX; } else if (startAxis == Axis.Vertical) { groupSize = groupWidth; workingSize = groupHeight - padding.top - padding.bottom; if (IsRightAlign) { offset = (float)padding.right; counterOffset = (float)padding.left; } else { offset = (float)padding.left; counterOffset = (float)padding.right; } spacingBetweenBars = SpacingX; spacingBetweenElements = SpacingY; } var currentBarSize = 0f; var currentBarSpace = 0f; for (var i = 0; i < rectChildren.Count; i++) { int index = i; var child = rectChildren [index]; float childSize = 0; float childOtherSize = 0; //get height and width of elements. if (startAxis == Axis.Horizontal) { if (invertOrder) { index = IsLowerAlign ? rectChildren.Count - 1 - i : i; } child = rectChildren [index]; childSize = LayoutUtility.GetPreferredSize(child, 0); childSize = Mathf.Min(childSize, workingSize); childOtherSize = LayoutUtility.GetPreferredSize(child, 1); childOtherSize = Mathf.Min(childOtherSize, workingSize); } else if (startAxis == Axis.Vertical) { if (invertOrder) { index = IsRightAlign ? rectChildren.Count - 1 - i : i; } child = rectChildren [index]; childSize = LayoutUtility.GetPreferredSize(child, 1); childSize = Mathf.Min(childSize, workingSize); childOtherSize = LayoutUtility.GetPreferredSize(child, 0); childOtherSize = Mathf.Min(childOtherSize, workingSize); } // If adding this element would exceed the bounds of the container, // go to a new bar after processing the current bar if (currentBarSize + childSize > workingSize) { currentBarSize -= spacingBetweenElements; // Process current bar elements positioning if (!layoutInput) { if (startAxis == Axis.Horizontal) { float newOffset = CalculateRowVerticalOffset(groupSize, offset, currentBarSpace); LayoutRow(_itemList, currentBarSize, currentBarSpace, workingSize, padding.left, newOffset, axis); } else if (startAxis == Axis.Vertical) { float newOffset = CalculateColHorizontalOffset(groupSize, offset, currentBarSpace); LayoutCol(_itemList, currentBarSpace, currentBarSize, workingSize, newOffset, padding.top, axis); } } // Clear existing bar _itemList.Clear(); // Add the current bar space to total barSpace accumulator, and reset to 0 for the next row offset += currentBarSpace; offset += spacingBetweenBars; currentBarSpace = 0; currentBarSize = 0; } currentBarSize += childSize; _itemList.Add(child); // We need the largest element height to determine the starting position of the next line if (childOtherSize > currentBarSpace) { currentBarSpace = childOtherSize; } // Don't do this for the last one if (i < rectChildren.Count - 1) { currentBarSize += spacingBetweenElements; } } // Layout the final bar if (!layoutInput) { if (startAxis == Axis.Horizontal) { float newOffset = CalculateRowVerticalOffset(groupHeight, offset, currentBarSpace); currentBarSize -= spacingBetweenElements; LayoutRow(_itemList, currentBarSize, currentBarSpace, workingSize - (ChildForceExpandWidth ? 0 : spacingBetweenElements), padding.left, newOffset, axis); } else if (startAxis == Axis.Vertical) { float newOffset = CalculateColHorizontalOffset(groupWidth, offset, currentBarSpace); currentBarSize -= spacingBetweenElements; LayoutCol(_itemList, currentBarSpace, currentBarSize, workingSize - (ChildForceExpandHeight ? 0 : spacingBetweenElements), newOffset, padding.top, axis); } } _itemList.Clear(); // Add the last bar space to the barSpace accumulator offset += currentBarSpace; offset += counterOffset; if (layoutInput) { SetLayoutInputForAxis(offset, offset, -1, axis); } return(offset); }
public void ShowBlockCategory(string categoryName) { Debug.Log("ShowBlockCategory"); Game.sound.play("CLICK"); if (string.Equals(categoryName, mActiveCategory)) { return; } if (!m_BlockScrollList.activeInHierarchy) { m_BlockScrollList.SetActive(true); } if (!string.IsNullOrEmpty(mActiveCategory)) { mRootList[mActiveCategory].SetActive(false); } mActiveCategory = categoryName; GameObject contentObj; RectTransform contentTrans; if (mRootList.TryGetValue(categoryName, out contentObj)) { contentObj.SetActive(true); contentTrans = contentObj.transform as RectTransform; } else { contentObj = GameObject.Instantiate(m_BlockContentPrefab, m_BlockContentPrefab.transform.parent); contentObj.name = "Content_" + categoryName; contentObj.SetActive(true); mRootList[categoryName] = contentObj; contentTrans = contentObj.GetComponent <RectTransform>(); //build new blocks if (categoryName.Equals(Define.VARIABLE_CATEGORY_NAME)) { BuildVariableBlocks(); } else if (categoryName.Equals(Define.PROCEDURE_CATEGORY_NAME)) { BuildProcedureBlocks(); } else { BuildBlockViewsForActiveCategory(); } } //resize the background LayoutRebuilder.ForceRebuildLayoutImmediate(contentTrans); m_BlockScrollList.GetComponent <RectTransform>().SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, LayoutUtility.GetPreferredWidth(contentTrans)); m_BlockScrollList.GetComponent <ScrollRect>().content = contentTrans; }
/// <summary> /// Creates a string recursively describing the specified GameObject. /// </summary> /// <param name="root">The root GameObject hierarchy.</param> /// <param name="indent">The indentation to use.</param> /// <returns>A string describing this game object.</returns> private static string GetObjectTree(GameObject root, int indent) { var result = new StringBuilder(1024); // Calculate indent to make nested reading easier var solBuilder = new StringBuilder(indent); for (int i = 0; i < indent; i++) { solBuilder.Append(' '); } string sol = solBuilder.ToString(); var transform = root.transform; int n = transform.childCount; // Basic information result.Append(sol).AppendFormat("GameObject[{0}, {1:D} child(ren), Layer {2:D}, " + "Active={3}]", root.name, n, root.layer, root.activeInHierarchy).AppendLine(); // Transformation result.Append(sol).AppendFormat(" Translation={0} [{3}] Rotation={1} [{4}] " + "Scale={2}", transform.position, transform.rotation, transform. localScale, transform.localPosition, transform.localRotation).AppendLine(); // Components foreach (var component in root.GetComponents <Component>()) { if (component is RectTransform rt) { // UI rectangle Vector2 size = rt.sizeDelta; result.Append(sol).AppendFormat(" Rect[Size=({0:F2},{1:F2}) Min=" + "({2:F2},{3:F2}) ", size.x, size.y, LayoutUtility.GetMinWidth(rt), LayoutUtility.GetMinHeight(rt)); result.AppendFormat("Preferred=({0:F2},{1:F2}) Flexible=({2:F2}," + "{3:F2})]", LayoutUtility.GetPreferredWidth(rt), LayoutUtility. GetPreferredHeight(rt), LayoutUtility.GetFlexibleWidth(rt), LayoutUtility.GetFlexibleHeight(rt)).AppendLine(); } else if (component != null && !(component is Transform)) { // Exclude destroyed components and Transform objects result.Append(sol).Append(" Component[").Append(component.GetType(). FullName); AddComponentText(result, component); result.AppendLine("]"); } } // Children if (n > 0) { result.Append(sol).AppendLine(" Children:"); } for (int i = 0; i < n; i++) { var child = transform.GetChild(i).gameObject; if (child != null) { // Exclude destroyed objects result.AppendLine(GetObjectTree(child, indent + 2)); } } return(result.ToString().TrimEnd()); }
public static Vector2 GetPreferredSize(this RectTransform rectTransform) { return(new Vector2( LayoutUtility.GetPreferredSize(rectTransform, 0), LayoutUtility.GetPreferredSize(rectTransform, 1))); }
public GameObject Build() { var textField = PUIElements.CreateUI(null, Name); var style = TextStyle ?? PUITuning.Fonts.TextLightStyle; // Background var border = textField.AddComponent <Image>(); border.sprite = PUITuning.Images.BoxBorderWhite; border.type = Image.Type.Sliced; border.color = style.textColor; // Text box with rectangular clipping area var textArea = PUIElements.CreateUI(textField, "Text Area", false); textArea.AddComponent <Image>().color = BackColor; var mask = textArea.AddComponent <RectMask2D>(); // Scrollable text var textBox = PUIElements.CreateUI(textArea, "Text"); // Text to display var textDisplay = ConfigureField(textBox.AddComponent <TextMeshProUGUI>(), style, TextAlignment); textDisplay.enableWordWrapping = false; textDisplay.maxVisibleLines = 1; textDisplay.raycastTarget = true; // Text field itself textField.SetActive(false); var textEntry = textField.AddComponent <TMP_InputField>(); textEntry.textComponent = textDisplay; textEntry.textViewport = textArea.rectTransform(); textEntry.text = Text ?? ""; textDisplay.text = Text ?? ""; // Placeholder if (PlaceholderText != null) { var placeholder = PUIElements.CreateUI(textArea, "Placeholder Text"); var textPlace = ConfigureField(placeholder.AddComponent <TextMeshProUGUI>(), PlaceholderStyle ?? style, TextAlignment); textPlace.maxVisibleLines = 1; textPlace.text = PlaceholderText; textEntry.placeholder = textPlace; } // Events! ConfigureTextEntry(textEntry); var events = textField.AddComponent <PTextFieldEvents>(); events.OnTextChanged = OnTextChanged; events.OnValidate = OnValidate; events.TextObject = textBox; // Add tooltip PUIElements.SetToolTip(textField, ToolTip); mask.enabled = true; PUIElements.SetAnchorOffsets(textBox, new RectOffset()); textField.SetActive(true); // Lay out var rt = textBox.rectTransform(); LayoutRebuilder.ForceRebuildLayoutImmediate(rt); var layout = PUIUtils.InsetChild(textField, textArea, Vector2.one, new Vector2( MinWidth, LayoutUtility.GetPreferredHeight(rt))).AddOrGet <LayoutElement>(); layout.flexibleWidth = FlexSize.x; layout.flexibleHeight = FlexSize.y; OnRealize?.Invoke(textField); return(textField); }