public void CalculateLayoutInputHorizontal() { results = new GridLayoutResults(rows, columns, children); var elements = ListPool <Component, PGridLayoutGroup> .Allocate(); foreach (var component in results.Components) { // Cache size of children var obj = component.HorizontalSize.source; var margin = component.Margin; elements.Clear(); obj.GetComponents(elements); var sz = PUIUtils.CalcSizes(obj, PanelDirection.Horizontal, elements); if (!sz.ignore) { // Add borders int border = (margin == null) ? 0 : margin.left + margin.right; sz.min += border; sz.preferred += border; } component.HorizontalSize = sz; } elements.Recycle(); // Calculate columns sizes and our size results.CalcBaseWidths(); float width = results.MinWidth; if (Margin != null) { width += Margin.left + Margin.right; } minWidth = preferredWidth = width; flexibleWidth = (results.TotalFlexWidth > 0.0f) ? 1.0f : 0.0f; }
/// <summary> /// Calculates the final width of this component and applies it to the component. /// </summary> /// <param name="component">The component to calculate.</param> /// <param name="colX">The column locations from GetColumnWidths.</param> /// <returns>true if the width was applied, or false if the component was not laid out /// due to being disposed or set to ignore layout.</returns> private static bool SetFinalWidth(SizedGridComponent component, float[] colX) { var margin = component.Margin; var sizes = component.HorizontalSize; var target = sizes.source; bool ok = !sizes.ignore && target != null; if (ok) { int columns = colX.Length - 1; // Clamp first and last column occupied by this object int first = component.Column, last = first + component.ColumnSpan; first = first.InRange(0, columns - 1); last = last.InRange(1, columns); // Align correctly in the cell box float x = colX[first], colWidth = colX[last] - x; if (margin != null) { float border = margin.left + margin.right; x += margin.left; colWidth -= border; sizes.min -= border; sizes.preferred -= border; } float actualWidth = PUIUtils.GetProperSize(sizes, colWidth); // Take alignment into account x += PUIUtils.GetOffset(component.Alignment, PanelDirection.Horizontal, colWidth - actualWidth); target.rectTransform().SetInsetAndSizeFromParentEdge(RectTransform.Edge. Left, x, actualWidth); } return(ok); }
/// <summary> /// Calculates the size of the box layout container. /// </summary> /// <param name="obj">The container to lay out.</param> /// <param name="args">The parameters to use for layout.</param> /// <param name="direction">The direction which is being calculated.</param> /// <returns>The minimum and preferred box layout size.</returns> private static BoxLayoutResults Calc(GameObject obj, BoxLayoutParams args, PanelDirection direction) { var transform = obj.AddOrGet <RectTransform>(); int n = transform.childCount; var result = new BoxLayoutResults(direction, n); var components = ListPool <Component, BoxLayoutGroup> .Allocate(); for (int i = 0; i < n; i++) { var child = transform.GetChild(i)?.gameObject; if (child != null && child.activeInHierarchy) { // Only on active game objects components.Clear(); child.GetComponents(components); var hc = PUIUtils.CalcSizes(child, direction, components); if (!hc.ignore) { if (args.Direction == direction) { result.Accum(hc, args.Spacing); } else { result.Expand(hc); } result.children.Add(hc); } } } components.Recycle(); return(result); }
/// <summary> /// Calculates the final height of this component and applies it to the component. /// </summary> /// <param name="component">The component to calculate.</param> /// <param name="rowY">The row locations from GetRowHeights.</param> /// <returns>true if the height was applied, or false if the component was not laid out /// due to being disposed or set to ignore layout.</returns> private static bool SetFinalHeight(SizedGridComponent component, float[] rowY) { var margin = component.Margin; var sizes = component.VerticalSize; var target = sizes.source; bool ok = !sizes.ignore && target != null; if (ok) { int rows = rowY.Length - 1; // Clamp first and last row occupied by this object int first = component.Row, last = first + component.RowSpan; first = first.InRange(0, rows - 1); last = last.InRange(1, rows); // Align correctly in the cell box float y = rowY[first], rowHeight = rowY[last] - y; if (margin != null) { float border = margin.top + margin.bottom; y += margin.top; rowHeight -= border; sizes.min -= border; sizes.preferred -= border; } float actualHeight = PUIUtils.GetProperSize(sizes, rowHeight); // Take alignment into account y += PUIUtils.GetOffset(component.Alignment, PanelDirection.Vertical, rowHeight - actualHeight); target.rectTransform().SetInsetAndSizeFromParentEdge(RectTransform.Edge. Top, y, actualHeight); } return(ok); }
/// <summary> /// Calculates the size of the card layout container. /// </summary> /// <param name="obj">The container to lay out.</param> /// <param name="args">The parameters to use for layout.</param> /// <param name="direction">The direction which is being calculated.</param> /// <returns>The minimum and preferred box layout size.</returns> private static CardLayoutResults Calc(GameObject obj, PanelDirection direction) { var transform = obj.AddOrGet <RectTransform>(); int n = transform.childCount; var result = new CardLayoutResults(direction, n); var components = ListPool <Component, BoxLayoutGroup> .Allocate(); for (int i = 0; i < n; i++) { var child = transform.GetChild(i)?.gameObject; if (child != null) { bool active = child.activeInHierarchy; // Not only on active game objects components.Clear(); child.GetComponents(components); child.SetActive(true); var hc = PUIUtils.CalcSizes(child, direction, components); if (!hc.ignore) { result.Expand(hc); result.children.Add(hc); } child.SetActive(active); } } components.Recycle(); return(result); }
public override void CalculateLayoutInputVertical() { if (results != null && !locked) { var elements = ListPool <Component, PGridLayoutGroup> .Allocate(); foreach (var component in results.Components) { // Cache size of children var obj = component.VerticalSize.source; var margin = component.Margin; elements.Clear(); obj.GetComponents(elements); var sz = PUIUtils.CalcSizes(obj, PanelDirection.Vertical, elements); if (!sz.ignore) { // Add borders int border = (margin == null) ? 0 : margin.top + margin.bottom; sz.min += border; sz.preferred += border; } component.VerticalSize = sz; } elements.Recycle(); // Calculate row sizes and our size results.CalcBaseHeights(); float height = results.MinHeight; if (Margin != null) { height += Margin.bottom + Margin.top; } minHeight = preferredHeight = height; flexibleHeight = (results.TotalFlexHeight > 0.0f) ? 1.0f : 0.0f; } }
/// <summary> /// Lays out components in the box layout container parallel to the layout axis. /// </summary> /// <param name="required">The calculated minimum and preferred sizes.</param> /// <param name="args">The parameters to use for layout.</param> /// <param name="status">The current status of layout.</param> private static void DoLayoutLinear(BoxLayoutResults required, BoxLayoutParams args, BoxLayoutStatus status) { var total = required.total; var components = ListPool <ILayoutController, BoxLayoutGroup> .Allocate(); var direction = args.Direction; // Determine flex size ratio float size = status.size, prefRatio = 0.0f, minSize = total.min, prefSize = total.preferred, excess = Math.Max(0.0f, size - prefSize), flexTotal = total. flexible, offset = status.offset, spacing = args.Spacing; if (size > minSize && prefSize > minSize) { // Do not divide by 0 prefRatio = Math.Min(1.0f, (size - minSize) / (prefSize - minSize)); } if (excess > 0.0f && flexTotal == 0.0f) { // If no components can be expanded, offset all offset += PUIUtils.GetOffset(args.Alignment, status.direction, excess); } foreach (var child in required.children) { var obj = child.source; // Active objects only if (obj != null && obj.activeInHierarchy) { float compSize = child.min; if (prefRatio > 0.0f) { compSize += (child.preferred - child.min) * prefRatio; } if (excess > 0.0f && flexTotal > 0.0f) { compSize += excess * child.flexible / flexTotal; } // Place and size component obj.AddOrGet <RectTransform>().SetInsetAndSizeFromParentEdge(status.edge, offset, compSize); offset += compSize + ((compSize > 0.0f) ? spacing : 0.0f); // Invoke SetLayout on dependents components.Clear(); obj.GetComponents(components); foreach (var component in components) { if (direction == PanelDirection.Horizontal) { component.SetLayoutHorizontal(); } else // if (direction == PanelDirection.Vertical) { component.SetLayoutVertical(); } } } } components.Recycle(); }
/// <summary> /// Called each frame by Unity, checks to see if the user clicks/scrolls outside of /// the dropdown while open, and closes it if so. /// </summary> internal void Update() { if (open && handler != null && !handler.IsOver && (PUIUtils.GetMouseButton(0) || PUIUtils.GetInputAxis("Mouse ScrollWheel") != 0.0f)) { Close(); } }
public GameObject Build() { var textField = PUIElements.CreateUI(null, Name); // Background var style = TextStyle ?? PUITuning.Fonts.TextLightStyle; textField.AddComponent <Image>().color = style.textColor; // Text box with rectangular clipping area; put pivot in upper left var textArea = PUIElements.CreateUI(textField, "Text Area", false); textArea.rectTransform().pivot = Vector2.up; textArea.AddComponent <Image>().color = BackColor; var mask = textArea.AddComponent <RectMask2D>(); // Scrollable text var textBox = PUIElements.CreateUI(textArea, "Text", true, PUIAnchoring.Beginning, PUIAnchoring.End); // Text to display var textDisplay = textBox.AddComponent <TextMeshProUGUI>(); textDisplay.alignment = TextAlignment; textDisplay.autoSizeTextContainer = false; textDisplay.enabled = true; textDisplay.color = style.textColor; textDisplay.font = style.sdfFont; textDisplay.fontSize = style.fontSize; textDisplay.fontStyle = style.style; // Text field itself textField.SetActive(false); var textEntry = textField.AddComponent <TMP_InputField>(); textEntry.textComponent = textDisplay; textEntry.textViewport = textArea.rectTransform(); textField.SetActive(true); textEntry.text = Text ?? ""; textDisplay.text = Text ?? ""; // Events! ConfigureTextEntry(textEntry); var events = textField.AddComponent <PTextFieldEvents>(); events.OnTextChanged = OnTextChanged; events.OnValidate = OnValidate; // Add tooltip if (!string.IsNullOrEmpty(ToolTip)) { textField.AddComponent <ToolTip>().toolTip = ToolTip; } mask.enabled = true; // Lay out, even better than before new RelativeLayout(textField).SetTopEdge(textArea, fraction: 1.0f).SetBottomEdge( textArea, fraction: 0.0f).SetMargin(textArea, new RectOffset(1, 1, 1, 1)). OverrideSize(textArea, new Vector2(MinWidth, Math.Max(LineCount, 1) * PUIUtils. GetLineHeight(style))).Execute(true); textField.SetFlexUISize(FlexSize); OnRealize?.Invoke(textField); return(textField); }
/// <summary> /// Sets the minimum (and preferred) width of this combo box in characters. /// /// The width is computed using the currently selected text style. /// </summary> /// <param name="chars">The number of characters to be displayed.</param> /// <returns>This combo box for call chaining.</returns> public PComboBox <T> SetMinWidthInCharacters(int chars) { int width = Mathf.RoundToInt(chars * PUIUtils.GetEmWidth(TextStyle)); if (width > 0) { MinWidth = width; } return(this); }
public override void SetLayoutHorizontal() { if (horizontal != null && !locked) { #if DEBUG_LAYOUT PUIUtils.LogUIDebug("SetLayoutHorizontal for {0} resolved width to {1:F2}".F( gameObject.name, rectTransform.rect.width)); #endif DoLayout(parameters, horizontal, rectTransform.rect.width); } }
/// <summary> /// Lays out components in the card layout container. /// </summary> /// <param name="margin">The margin to allow around the components.</param> /// <param name="required">The calculated minimum and preferred sizes.</param> /// <param name="size">The total available size in this dimension.</param> private static void DoLayout(RectOffset margin, CardLayoutResults required, float size) { if (required == null) { throw new ArgumentNullException("required"); } var direction = required.direction; var components = ListPool <ILayoutController, BoxLayoutGroup> .Allocate(); // Compensate for margins if (direction == PanelDirection.Horizontal) { size -= margin.left + margin.right; } else { size -= margin.top + margin.bottom; } foreach (var child in required.children) { var obj = child.source; if (obj != null) { float compSize = PUIUtils.GetProperSize(child, size); // Place and size component var transform = obj.AddOrGet <RectTransform>(); if (direction == PanelDirection.Horizontal) { transform.SetInsetAndSizeFromParentEdge(RectTransform.Edge.Left, margin.left, compSize); } else { transform.SetInsetAndSizeFromParentEdge(RectTransform.Edge.Top, margin.top, compSize); } // Invoke SetLayout on dependents components.Clear(); obj.GetComponents(components); foreach (var component in components) { if (direction == PanelDirection.Horizontal) { component.SetLayoutHorizontal(); } else // if (direction == PanelDirection.Vertical) { component.SetLayoutVertical(); } } } } components.Recycle(); }
public override void SetLayoutVertical() { if (vertical != null && !locked) { #if DEBUG_LAYOUT PUIUtils.LogUIDebug("SetLayoutVertical for {0} resolved height to {1:F2}".F( gameObject.name, rectTransform.rect.height)); #endif DoLayout(parameters, vertical, rectTransform.rect.height); } }
public override void CalculateLayoutInputVertical() { if (child != null && calcElements != null) { // Lay out children childVertical = PUIUtils.CalcSizes(child, PanelDirection.Vertical, calcElements); preferredHeight = childVertical.preferred; calcElements = null; } }
public void CalculateLayoutInputHorizontal() { #if DEBUG_LAYOUT PUIUtils.LogUIDebug("CalculateLayoutInputHorizontal for " + gameObject.name); #endif var margin = parameters.Margin; float gap = (margin == null) ? 0.0f : margin.left + margin.right; horizontal = Calc(gameObject, parameters, PanelDirection.Horizontal); var hTotal = horizontal.total; minWidth = hTotal.min + gap; preferredWidth = hTotal.preferred + gap; }
public void CalculateLayoutInputVertical() { #if DEBUG_LAYOUT PUIUtils.LogUIDebug("CalculateLayoutInputVertical for " + gameObject.name); #endif var margin = parameters.Margin; float gap = (margin == null) ? 0.0f : margin.top + margin.bottom; vertical = Calc(gameObject, parameters, PanelDirection.Vertical); var vTotal = vertical.total; minHeight = vTotal.min + gap; preferredHeight = vTotal.preferred + gap; }
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; put pivot in upper left 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 = PTextField.ConfigureField(textBox.AddComponent <TextMeshProUGUI>(), style, TextAlignment); textDisplay.enableWordWrapping = true; 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 ?? ""; // 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 layout = PUIUtils.InsetChild(textField, textArea, Vector2.one, new Vector2( MinWidth, Math.Max(LineCount, 1) * PUIUtils.GetLineHeight(style))). AddOrGet <LayoutElement>(); layout.flexibleWidth = FlexSize.x; layout.flexibleHeight = FlexSize.y; OnRealize?.Invoke(textField); return(textField); }
public override void CalculateLayoutInputHorizontal() { if (child != null) { calcElements = child.GetComponents <Component>(); // Lay out children childHorizontal = PUIUtils.CalcSizes(child, PanelDirection.Horizontal, calcElements); if (childHorizontal.ignore) { throw new InvalidOperationException("ScrollPane child ignores layout!"); } preferredWidth = childHorizontal.preferred; } }
public override void CalculateLayoutInputVertical() { if (!locked) { var margin = parameters.Margin; float gap = (margin == null) ? 0.0f : margin.top + margin.bottom; vertical = Calc(gameObject, parameters, PanelDirection.Vertical); var vTotal = vertical.total; minHeight = vTotal.min + gap; preferredHeight = vTotal.preferred + gap; #if DEBUG_LAYOUT PUIUtils.LogUIDebug("CalculateLayoutInputVertical for {0} preferred {1:F2}".F( gameObject.name, preferredHeight)); #endif } }
public override void CalculateLayoutInputHorizontal() { if (!locked) { var margin = parameters.Margin; float gap = (margin == null) ? 0.0f : margin.left + margin.right; horizontal = Calc(gameObject, parameters, PanelDirection.Horizontal); var hTotal = horizontal.total; minWidth = hTotal.min + gap; preferredWidth = hTotal.preferred + gap; #if DEBUG_LAYOUT PUIUtils.LogUIDebug("CalculateLayoutInputHorizontal for {0} preferred {1:F2}". F(gameObject.name, preferredWidth)); #endif } }
/// <summary> /// Lays out components in the box layout container against the layout axis. /// </summary> /// <param name="required">The calculated minimum and preferred sizes.</param> /// <param name="args">The parameters to use for layout.</param> /// <param name="status">The current status of layout.</param> private static void DoLayoutPerp(LayoutResults required, BoxLayoutParams args, LayoutStatus status) { var components = ListPool <ILayoutController, BoxLayoutGroup> .Allocate(); var direction = args.Direction; float size = status.size; foreach (var child in required.children) { var obj = child.source; // Active objects only if (obj != null && obj.activeInHierarchy) { float compSize = size; if (child.flexible <= 0.0f) { // Does not expand to all compSize = Math.Min(compSize, child.preferred); } float offset = (size > compSize) ? GetOffset(args, status.direction, size - compSize) : 0.0f; // Place and size component obj.AddOrGet <RectTransform>().SetInsetAndSizeFromParentEdge(status.edge, offset + status.offset, compSize); // Invoke SetLayout on dependents components.Clear(); obj.GetComponents(components); foreach (var component in components) { if (!PUIUtils.IgnoreLayout(component)) { if (direction == PanelDirection.Horizontal) { component.SetLayoutVertical(); } else // if (direction == PanelDirection.Vertical) { component.SetLayoutHorizontal(); } } } } } components.Recycle(); }
public void SetLayoutVertical() { #if DEBUG if (vertical == null) { throw new InvalidOperationException("SetLayoutVertical before CalculateLayoutInputVertical"); } #endif #if DEBUG_LAYOUT PUIUtils.LogUIDebug("SetLayoutVertical for " + gameObject.name); #endif if (vertical != null) { var rt = gameObject.rectTransform(); DoLayout(parameters, vertical, rt.rect.size.y); } }
public void SetLayoutHorizontal() { #if DEBUG if (horizontal == null) { throw new InvalidOperationException("SetLayoutHorizontal before CalculateLayoutInputHorizontal"); } #endif if (horizontal != null) { var rt = gameObject.rectTransform(); #if DEBUG_LAYOUT PUIUtils.LogUIDebug("SetLayoutHorizontal for {0} resolved width to {1:F2}".F( gameObject.name, rt.rect.width)); #endif DoLayout(parameters, horizontal, rt.rect.width); } }
public override void SetLayoutVertical() { #if DEBUG if (vertical == null) { throw new InvalidOperationException("SetLayoutVertical before CalculateLayoutInputVertical"); } #endif if (vertical != null) { var rt = gameObject.rectTransform(); #if DEBUG_LAYOUT PUIUtils.LogUIDebug("SetLayoutVertical for {0} resolved height to {1:F2}".F( gameObject.name, rt.rect.height)); #endif DoLayout(parameters, vertical, rt.rect.height); } }
static Fonts() { FONTS = new Dictionary <string, TMP_FontAsset>(16); // List out all fonts shipped with the game foreach (var newFont in Resources.FindObjectsOfTypeAll <TMP_FontAsset>()) { string name = newFont?.name; if (!string.IsNullOrEmpty(name) && !FONTS.ContainsKey(name)) { FONTS.Add(name, newFont); } } // Initialization: UI fonts if ((DefaultTextFont = GetFontByName(DEFAULT_FONT_TEXT)) == null) { PUIUtils.LogUIWarning("Unable to find font " + DEFAULT_FONT_TEXT); } if ((DefaultUIFont = GetFontByName(DEFAULT_FONT_UI)) == null) { PUIUtils.LogUIWarning("Unable to find font " + DEFAULT_FONT_UI); } // Initialization: Text style DefaultSize = 14; TextDarkStyle = ScriptableObject.CreateInstance <TextStyleSetting>(); TextDarkStyle.enableWordWrapping = false; TextDarkStyle.fontSize = DefaultSize; TextDarkStyle.sdfFont = Text; TextDarkStyle.style = FontStyles.Normal; TextDarkStyle.textColor = Colors.UITextDark; TextLightStyle = TextDarkStyle.DeriveStyle(newColor: Colors.UITextLight); UIDarkStyle = ScriptableObject.CreateInstance <TextStyleSetting>(); UIDarkStyle.enableWordWrapping = false; UIDarkStyle.fontSize = DefaultSize; UIDarkStyle.sdfFont = UI; UIDarkStyle.style = FontStyles.Normal; UIDarkStyle.textColor = Colors.UITextDark; UILightStyle = UIDarkStyle.DeriveStyle(newColor: Colors.UITextLight); }
/// <summary> /// Returns a suitable parent object for a dialog. /// </summary> /// <returns>A game object that can be used as a dialog parent depending on the game /// stage, or null if none is available.</returns> public static GameObject GetParentObject() { GameObject parent = null; var fi = FrontEndManager.Instance; if (fi != null) { parent = fi.gameObject; } else { // Grr unity var gi = GameScreenManager.Instance; if (gi != null) { parent = gi.ssOverlayCanvas; } else { PUIUtils.LogUIWarning("No dialog parent found!"); } } return(parent); }