예제 #1
0
        /// <summary>
        /// Creates the actual image that shows the checkbox graphically.
        /// </summary>
        /// <param name="checkbox">The parent object to add the image.</param>
        /// <param name="color">The color style for the box border.</param>
        /// <param name="actualSize">The actual check mark size, which will be updated if it
        /// is 0x0 to the default size.</param>
        /// <returns>The image reference to the checkmark image itself.</returns>
        private Image CreateCheckImage(GameObject checkbox, ColorStyleSetting color,
                                       ref Vector2 actualSize)
        {
            // Checkbox border (grr rule of only one Graphics per GO...)
            var checkBorder = PUIElements.CreateUI(checkbox, "CheckBorder");
            var borderImg   = checkBorder.AddComponent <Image>();

            borderImg.sprite = PUITuning.Images.CheckBorder;
            borderImg.color  = color.activeColor;
            borderImg.type   = Image.Type.Sliced;
            // Checkbox foreground
            var imageChild = PUIElements.CreateUI(checkbox, "CheckMark", true, PUIAnchoring.
                                                  Center, PUIAnchoring.Center);
            var checkImage = imageChild.AddComponent <Image>();

            checkImage.sprite         = PUITuning.Images.Checked;
            checkImage.preserveAspect = true;
            // Determine the checkbox size
            if (actualSize.x <= 0.0f || actualSize.y <= 0.0f)
            {
                var rt = imageChild.rectTransform();
                actualSize.x = LayoutUtility.GetPreferredWidth(rt);
                actualSize.y = LayoutUtility.GetPreferredHeight(rt);
            }
            imageChild.SetUISize(CheckSize, false);
            return(checkImage);
        }
예제 #2
0
        /// <summary>
        /// Creates a vertical scroll bar.
        /// </summary>
        /// <param name="parent">The parent component.</param>
        /// <returns>The scroll bar component.</returns>
        private Scrollbar CreateScrollVert(GameObject parent)
        {
            // Outer scrollbar
            var track = PUIElements.CreateUI(parent, "Scrollbar V", true, PUIAnchoring.End,
                                             PUIAnchoring.Stretch);

            track.AddComponent <Image>().sprite = PUITuning.Images.ScrollBorderVertical;
            // Scroll track
            var sb = track.AddComponent <Scrollbar>();

            sb.interactable = true;
            sb.transition   = Selectable.Transition.ColorTint;
            sb.colors       = PUITuning.Colors.ScrollbarColors;
            sb.SetDirection(Scrollbar.Direction.BottomToTop, true);
            // Sliding area
            var area = PUIElements.CreateUI(track, "Sliding Area", false);
            // Handle
            var handle = PUIElements.CreateUI(area, "Handle", true, PUIAnchoring.Stretch,
                                              PUIAnchoring.Beginning);

            sb.handleRect = handle.rectTransform();
            var hImg = handle.AddComponent <Image>();

            hImg.sprite      = PUITuning.Images.ScrollHandleVertical;
            sb.targetGraphic = hImg;
            track.SetActive(true);
            // Sizing
            track.SetUISize(new Vector2(TrackSize + 2.0f, TrackSize + 2.0f));
            area.SetUISize(new Vector2(TrackSize, TrackSize));
            return(sb);
        }
예제 #3
0
        /// <summary>
        /// Adds a hot pink rectangle over the target matching its size, to help identify it
        /// better.
        /// </summary>
        /// <param name="parent">The target UI component.</param>
        public static void AddPinkOverlay(GameObject parent)
        {
            var child = PUIElements.CreateUI(parent, "Overlay");
            var img   = child.AddComponent <Image>();

            img.color = new Color(1.0f, 0.0f, 1.0f, 0.2f);
        }
예제 #4
0
        /// <summary>
        /// Creates a vertical scroll bar.
        /// </summary>
        /// <param name="parent">The parent component.</param>
        /// <returns>The scroll bar component.</returns>
        private Scrollbar CreateScrollVert(GameObject parent)
        {
            // Outer scrollbar
            var track = PUIElements.CreateUI(parent, "Scrollbar V", true, PUIAnchoring.End,
                                             PUIAnchoring.Stretch);
            var bg = track.AddComponent <Image>();

            bg.sprite = PUITuning.Images.ScrollBorderVertical;
            bg.type   = Image.Type.Sliced;
            // Scroll track
            var sb = track.AddComponent <Scrollbar>();

            sb.interactable = true;
            sb.transition   = Selectable.Transition.ColorTint;
            sb.colors       = PUITuning.Colors.ScrollbarColors;
            sb.SetDirection(Scrollbar.Direction.BottomToTop, true);
            // Handle
            var handle = PUIElements.CreateUI(track, "Handle", true, PUIAnchoring.Stretch,
                                              PUIAnchoring.Beginning);

            PUIElements.SetAnchorOffsets(handle, 1.0f, 1.0f, 1.0f, 1.0f);
            sb.handleRect = handle.rectTransform();
            var hImg = handle.AddComponent <Image>();

            hImg.sprite      = PUITuning.Images.ScrollHandleVertical;
            hImg.type        = Image.Type.Sliced;
            sb.targetGraphic = hImg;
            track.SetActive(true);
            PUIElements.SetAnchorOffsets(track, -TrackSize, 0.0f, 2.0f, 2.0f);
            return(sb);
        }
예제 #5
0
        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
            var layout = textField.AddComponent <RelativeLayoutGroup>();

            layout.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))).
            LockLayout();
            layout.flexibleWidth  = FlexSize.x;
            layout.flexibleHeight = FlexSize.y;
            OnRealize?.Invoke(textField);
            return(textField);
        }
예제 #6
0
        public GameObject Build()
        {
            var toggle = PUIElements.CreateUI(null, Name);
            // Set on click event
            var kToggle = toggle.AddComponent <KToggle>();
            var evt     = OnStateChanged;

            if (evt != null)
            {
                kToggle.onValueChanged += (on) => {
                    evt?.Invoke(toggle, on);
                }
            }
            ;
            kToggle.artExtension = new KToggleArtExtensions();
            kToggle.soundPlayer  = PUITuning.ToggleSounds;
            // Background image
            var fgImage = toggle.AddComponent <KImage>();

            fgImage.color  = Color.activeColor;
            fgImage.sprite = InactiveSprite;
            toggle.SetActive(false);
            // Toggled images
            var toggleImage = toggle.AddComponent <ImageToggleState>();

            toggleImage.TargetImage    = fgImage;
            toggleImage.useSprites     = true;
            toggleImage.InactiveSprite = InactiveSprite;
            toggleImage.ActiveSprite   = ActiveSprite;
            toggleImage.startingState  = InitialState ? ImageToggleState.State.Active :
                                         ImageToggleState.State.Inactive;
            toggleImage.useStartingState     = true;
            toggleImage.ActiveColour         = Color.activeColor;
            toggleImage.DisabledActiveColour = Color.disabledActiveColor;
            toggleImage.InactiveColour       = Color.inactiveColor;
            toggleImage.DisabledColour       = Color.disabledColor;
            toggleImage.HoverColour          = Color.hoverColor;
            toggleImage.DisabledHoverColor   = Color.disabledhoverColor;
            kToggle.isOn = InitialState;
            toggle.SetActive(true);
            // Set size
            if (Size.x > 0.0f && Size.y > 0.0f)
            {
                toggle.SetUISize(Size, true);
            }
            else
            {
                PUIElements.AddSizeFitter(toggle, DynamicSize);
            }
            // Add tooltip
            if (!string.IsNullOrEmpty(ToolTip))
            {
                toggle.AddComponent <ToolTip>().toolTip = ToolTip;
            }
            toggle.SetFlexUISize(FlexSize).SetActive(true);
            OnRealize?.Invoke(toggle);
            return(toggle);
        }
예제 #7
0
        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
            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 = 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;
            textDisplay.maxVisibleLines = 1;
            // 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
            var tbTransform = textBox.rectTransform();

            LayoutRebuilder.ForceRebuildLayoutImmediate(tbTransform);
            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, LayoutUtility.GetPreferredHeight(
                                                   tbTransform))).Execute(true);
            textField.SetFlexUISize(FlexSize);
            OnRealize?.Invoke(textField);
            return(textField);
        }
예제 #8
0
        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
            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 = 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;
            textDisplay.maxVisibleLines = 1;
            // 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 - TMP_InputField does not support auto layout so we have to do a hack
            var   rt     = textBox.rectTransform();
            float height = LayoutUtility.GetPreferredHeight(rt);

            textField.SetUISize(new Vector2(MinWidth + 2.0f, height + 2.0f), true).
            SetFlexUISize(FlexSize);
            textArea.SetUISize(new Vector2(MinWidth, height));
            OnRealize?.Invoke(textField);
            return(textField);
        }
예제 #9
0
        public GameObject Build()
        {
            var toggle = PUIElements.CreateUI(null, Name);
            // Set on click event
            var kToggle = toggle.AddComponent <KToggle>();
            var evt     = OnStateChanged;

            if (evt != null)
            {
                kToggle.onValueChanged += (on) => {
                    evt?.Invoke(toggle, on);
                }
            }
            ;
            UIDetours.ART_EXTENSION.Set(kToggle, new KToggleArtExtensions());
            UIDetours.SOUND_PLAYER_TOGGLE.Set(kToggle, PUITuning.ToggleSounds);
            // Background image
            var fgImage = toggle.AddComponent <Image>();

            fgImage.color  = Color.activeColor;
            fgImage.sprite = InactiveSprite;
            toggle.SetActive(false);
            // Toggled images
            var toggleImage = toggle.AddComponent <ImageToggleState>();

            toggleImage.TargetImage    = fgImage;
            toggleImage.useSprites     = true;
            toggleImage.InactiveSprite = InactiveSprite;
            toggleImage.ActiveSprite   = ActiveSprite;
            toggleImage.startingState  = InitialState ? ImageToggleState.State.Active :
                                         ImageToggleState.State.Inactive;
            toggleImage.useStartingState     = true;
            toggleImage.ActiveColour         = Color.activeColor;
            toggleImage.DisabledActiveColour = Color.disabledActiveColor;
            toggleImage.InactiveColour       = Color.inactiveColor;
            toggleImage.DisabledColour       = Color.disabledColor;
            toggleImage.HoverColour          = Color.hoverColor;
            toggleImage.DisabledHoverColor   = Color.disabledhoverColor;
            UIDetours.IS_ON.Set(kToggle, InitialState);
            toggle.SetActive(true);
            // Set size
            if (Size.x > 0.0f && Size.y > 0.0f)
            {
                toggle.SetUISize(Size, true);
            }
            else
            {
                PUIElements.AddSizeFitter(toggle, DynamicSize);
            }
            // Add tooltip
            PUIElements.SetToolTip(toggle, ToolTip).SetFlexUISize(FlexSize).SetActive(true);
            OnRealize?.Invoke(toggle);
            return(toggle);
        }
예제 #10
0
        /// <summary>
        /// Shared routine to spawn UI text objects.
        /// </summary>
        /// <param name="parent">The parent object for the text.</param>
        /// <param name="style">The text style to use.</param>
        /// <param name="contents">The default text.</param>
        /// <returns>The child text object.</returns>
        protected static LocText TextChildHelper(GameObject parent, TextStyleSetting style,
                                                 string contents = "")
        {
            var textChild = PUIElements.CreateUI(parent, "Text");
            var locText   = PUIElements.AddLocText(textChild, style);

            // Font needs to be set before the text
            locText.alignment = TMPro.TextAlignmentOptions.Center;
            locText.text      = contents;
            return(locText);
        }
예제 #11
0
        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);
        }
예제 #12
0
        public override GameObject Build()
        {
            var        button = PUIElements.CreateUI(null, Name);
            GameObject sprite = null, text = null;
            // Background
            var bgImage = button.AddComponent <KImage>();

            bgImage.colorStyleSetting = Color ?? PUITuning.Colors.ButtonPinkStyle;
            SetupButtonBackground(bgImage);
            // Set on click event
            var kButton = button.AddComponent <KButton>();
            var evt     = OnClick;

            if (evt != null)
            {
                kButton.onClick += () => evt?.Invoke(button);
            }
            SetupButton(kButton, bgImage);
            // Add foreground image since the background already has one
            if (Sprite != null)
            {
                var fgImage = ImageChildHelper(button, this);
                kButton.fgImage = fgImage;
                sprite          = fgImage.gameObject;
            }
            // Add text
            if (!string.IsNullOrEmpty(Text))
            {
                text = TextChildHelper(button, TextStyle ?? PUITuning.Fonts.UILightStyle,
                                       Text).gameObject;
            }
            // Add tooltip
            if (!string.IsNullOrEmpty(ToolTip))
            {
                button.AddComponent <ToolTip>().toolTip = ToolTip;
            }
            button.SetActive(true);
            // Arrange the icon and text
            var layout = button.AddComponent <RelativeLayoutGroup>();

            layout.Margin = Margin;
            GameObject inner;

            ArrangeComponent(layout, inner = WrapTextAndSprite(text, sprite), TextAlignment);
            if (!DynamicSize)
            {
                layout.LockLayout();
            }
            layout.flexibleWidth  = FlexSize.x;
            layout.flexibleHeight = FlexSize.y;
            InvokeRealize(button);
            return(button);
        }
예제 #13
0
        public override GameObject Build()
        {
            var        button = PUIElements.CreateUI(null, Name);
            GameObject sprite = null, text = null;
            // Background
            var bgImage      = button.AddComponent <KImage>();
            var bgColorStyle = Color ?? PUITuning.Colors.ButtonPinkStyle;

            UIDetours.COLOR_STYLE_SETTING.Set(bgImage, bgColorStyle);
            SetupButtonBackground(bgImage);
            // Set on click event
            var kButton = button.AddComponent <KButton>();
            var evt     = OnClick;

            if (evt != null)
            {
                // Detouring an Event is not worth the effort
                kButton.onClick += () => evt?.Invoke(button);
            }
            SetupButton(kButton, bgImage);
            // Add foreground image since the background already has one
            if (Sprite != null)
            {
                var fgImage = ImageChildHelper(button, this);
                UIDetours.FG_IMAGE.Set(kButton, fgImage);
                sprite = fgImage.gameObject;
            }
            // Add text
            if (!string.IsNullOrEmpty(Text))
            {
                text = TextChildHelper(button, TextStyle ?? PUITuning.Fonts.UILightStyle,
                                       Text).gameObject;
            }
            // Add tooltip
            PUIElements.SetToolTip(button, ToolTip).SetActive(true);
            // Arrange the icon and text
            var layout = button.AddComponent <RelativeLayoutGroup>();

            layout.Margin = Margin;
            GameObject inner;

            ArrangeComponent(layout, inner = WrapTextAndSprite(text, sprite), TextAlignment);
            if (!DynamicSize)
            {
                layout.LockLayout();
            }
            layout.flexibleWidth  = FlexSize.x;
            layout.flexibleHeight = FlexSize.y;
            DestroyLayoutIfPossible(button);
            InvokeRealize(button);
            return(button);
        }
예제 #14
0
        public GameObject Build()
        {
            if (Child == null)
            {
                throw new InvalidOperationException("No child component");
            }
            var pane = PUIElements.CreateUI(null, Name);

            if (BackColor.a > 0.0f)
            {
                pane.AddComponent <Image>().color = BackColor;
            }
            // Scroll pane itself
            var scroll = pane.AddComponent <KScrollRect>();

            scroll.horizontal = ScrollHorizontal;
            scroll.vertical   = ScrollVertical;
            // Viewport
            var viewport = PUIElements.CreateUI(pane, "Viewport", true, PUIAnchoring.Stretch,
                                                PUIAnchoring.Stretch);

            viewport.AddComponent <RectMask2D>().enabled = true;
            // BoxLayoutGroup resizes the viewport which is undesired, we only want to pass
            // an auto-layout request on to the children
            viewport.AddComponent <VerticalLayoutGroup>().childAlignment = TextAnchor.UpperLeft;
            scroll.viewport = viewport.rectTransform();
            // Make the child; give it a separate Canvas to reduce layout rebuilds
            var child = Child.Build();

            child.AddOrGet <Canvas>().pixelPerfect = false;
            child.AddOrGet <GraphicRaycaster>();
            PUIElements.SetAnchors(PUIElements.SetParent(child, viewport), PUIAnchoring.
                                   Beginning, PUIAnchoring.End);
            scroll.content = child.rectTransform();
            pane.SetActive(true);
            // Vertical scrollbar
            if (ScrollVertical)
            {
                scroll.verticalScrollbar           = CreateScrollVert(pane);
                scroll.verticalScrollbarVisibility = AlwaysShowVertical ? ScrollRect.
                                                     ScrollbarVisibility.Permanent : ScrollRect.ScrollbarVisibility.AutoHide;
            }
            if (ScrollHorizontal)
            {
                scroll.horizontalScrollbar           = CreateScrollHoriz(pane);
                scroll.horizontalScrollbarVisibility = AlwaysShowHorizontal ? ScrollRect.
                                                       ScrollbarVisibility.Permanent : ScrollRect.ScrollbarVisibility.AutoHide;
            }
            pane.SetFlexUISize(FlexSize);
            OnRealize?.Invoke(pane);
            return(pane);
        }
예제 #15
0
        /// <summary>
        /// Builds the actual scroll pane object.
        /// </summary>
        /// <param name="parent">The parent of this scroll pane.</param>
        /// <param name="child">The child element of this scroll pane.</param>
        /// <returns>The realized scroll pane.</returns>
        internal GameObject BuildScrollPane(GameObject parent, GameObject child)
        {
            var pane = PUIElements.CreateUI(parent, Name);

            if (BackColor.a > 0.0f)
            {
                pane.AddComponent <Image>().color = BackColor;
            }
            pane.SetActive(false);
            // Scroll pane itself
            var scroll = pane.AddComponent <KScrollRect>();

            scroll.horizontal = ScrollHorizontal;
            scroll.vertical   = ScrollVertical;
            // Viewport
            var viewport = PUIElements.CreateUI(pane, "Viewport");

            viewport.rectTransform().pivot = Vector2.up;
            viewport.AddComponent <RectMask2D>().enabled = true;
            viewport.AddComponent <ViewportLayoutGroup>();
            scroll.viewport = viewport.rectTransform();
            // Give the Child a separate Canvas to reduce layout rebuilds
            child.AddOrGet <Canvas>().pixelPerfect = false;
            child.AddOrGet <GraphicRaycaster>();
            PUIElements.SetAnchors(child.SetParent(viewport), PUIAnchoring.Beginning,
                                   PUIAnchoring.End);
            scroll.content = child.rectTransform();
            // Vertical scrollbar
            if (ScrollVertical)
            {
                scroll.verticalScrollbar           = CreateScrollVert(pane);
                scroll.verticalScrollbarVisibility = AlwaysShowVertical ? ScrollRect.
                                                     ScrollbarVisibility.Permanent : ScrollRect.ScrollbarVisibility.
                                                     AutoHideAndExpandViewport;
            }
            if (ScrollHorizontal)
            {
                scroll.horizontalScrollbar           = CreateScrollHoriz(pane);
                scroll.horizontalScrollbarVisibility = AlwaysShowHorizontal ? ScrollRect.
                                                       ScrollbarVisibility.Permanent : ScrollRect.ScrollbarVisibility.
                                                       AutoHideAndExpandViewport;
            }
            pane.SetActive(true);
            // Custom layout to pass child sizes to the scroll pane
            var layout = pane.AddComponent <PScrollPaneLayout>();

            layout.flexibleHeight = FlexSize.y;
            layout.flexibleWidth  = FlexSize.x;
            return(pane);
        }
예제 #16
0
        /// <summary>
        /// Shared routine to spawn UI image objects.
        /// </summary>
        /// <param name="parent">The parent object for the image.</param>
        /// <param name="settings">The settings to use for displaying the image.</param>
        /// <returns>The child image object.</returns>
        protected static Image ImageChildHelper(GameObject parent, PTextComponent settings)
        {
            var imageChild = PUIElements.CreateUI(parent, "Image", true,
                                                  PUIAnchoring.Beginning, PUIAnchoring.Beginning);
            var rt = imageChild.rectTransform();

            // The pivot is important here
            rt.pivot = CENTER;
            var img = imageChild.AddComponent <Image>();

            img.color          = settings.SpriteTint;
            img.sprite         = settings.Sprite;
            img.type           = settings.SpriteMode;
            img.preserveAspect = settings.MaintainSpriteAspect;
            // Set up transform
            var   scale  = Vector3.one;
            float rot    = 0.0f;
            var   rotate = settings.SpriteTransform;

            if ((rotate & ImageTransform.FlipHorizontal) != ImageTransform.None)
            {
                scale.x = -1.0f;
            }
            if ((rotate & ImageTransform.FlipVertical) != ImageTransform.None)
            {
                scale.y = -1.0f;
            }
            if ((rotate & ImageTransform.Rotate90) != ImageTransform.None)
            {
                rot = 90.0f;
            }
            if ((rotate & ImageTransform.Rotate180) != ImageTransform.None)
            {
                rot += 180.0f;
            }
            // Update transform
            var transform = imageChild.rectTransform();

            transform.localScale = scale;
            transform.Rotate(new Vector3(0.0f, 0.0f, rot));
            // Limit size if needed
            var imageSize = settings.SpriteSize;

            if (imageSize.x > 0.0f && imageSize.y > 0.0f)
            {
                imageChild.SetUISize(imageSize, true);
            }
            return(img);
        }
예제 #17
0
        /// <summary>
        /// Adds the specified side screen content to the side screen list. The side screen
        /// behavior should be defined in a class inherited from SideScreenContent.
        ///
        /// This method should be used in a postfix on DetailsScreen.OnPrefabInit.
        /// </summary>
        /// <typeparam name="T">The type of the controller that will determine how the side
        /// screen works. A new instance will be created and added as a component to the new
        /// side screen.</typeparam>
        /// <param name="targetClassName">The full name of the type of side screen to based to ordering
        /// around. An example of how this method can be used is:
        /// `AddSideScreenContentWithOrdering&lt;MySideScreen&gt;(typeof(CapacityControlSideScreen).FullName);`
        /// `typeof(TargetedSideScreen).FullName` is the suggested value of this parameter.
        /// Side screens from other mods can be used with their qualified names, even if no
        /// no reference to their type is available, but the target mod must have added their
        /// custom side screen to the list first.</param>
        /// <param name="insertBefore">Whether to insert the new screen before or after the
        /// target side screen in the list. Defaults to before (true).
        /// When inserting before the screen, if both are valid for a building then the side
        /// screen of type "T" will show below the one of type "fullName". When inserting after
        /// the screen, the reverse is true.</param>
        /// <param name="uiPrefab">The UI prefab to use. If null is passed, the UI should
        /// be created and added to the GameObject hosting the controller object in its
        /// constructor.</param>
        public static void AddSideScreenContentWithOrdering <T>(string targetClassName,
                                                                bool insertBefore = true, GameObject uiPrefab = null)
            where T : SideScreenContent
        {
            var inst = DetailsScreen.Instance;

            if (inst == null)
            {
                LogUIWarning("DetailsScreen is not yet initialized, try a postfix on " +
                             "DetailsScreen.OnPrefabInit");
            }
            else
            {
                var trInst = Traverse.Create(inst);
                // These are private fields
                var    screens = trInst.GetField <List <SideScreenRef> >("sideScreens");
                var    body    = trInst.GetField <GameObject>("sideScreenContentBody");
                string name    = typeof(T).Name;
                if (body != null && screens != null)
                {
                    // The ref normally contains a prefab which is instantiated
                    var newScreen = new SideScreenRef();
                    // Mimic the basic screens
                    var rootObject = PUIElements.CreateUI(body, name);
                    // Preserve the border by fitting the child
                    rootObject.AddComponent <BoxLayoutGroup>().Params = new BoxLayoutParams()
                    {
                        Direction = PanelDirection.Vertical, Alignment = TextAnchor.
                                                                         UpperCenter, Margin = new RectOffset(1, 1, 0, 1)
                    };
                    var controller = rootObject.AddComponent <T>();
                    if (uiPrefab != null)
                    {
                        // Add prefab if supplied
                        controller.ContentContainer = uiPrefab;
                        uiPrefab.transform.parent   = rootObject.transform;
                    }
                    newScreen.name = name;
                    // Offset is never used
                    newScreen.offset         = Vector2.zero;
                    newScreen.screenPrefab   = controller;
                    newScreen.screenInstance = controller;
                    InsertSideScreenContent(screens, newScreen, targetClassName, insertBefore);
                }
            }
        }
예제 #18
0
        /// <summary>
        /// Adds the specified side screen content to the side screen list. The side screen
        /// behavior should be defined in a class inherited from SideScreenContent.
        ///
        /// This method should be used in a postfix on DetailsScreen.OnPrefabInit.
        /// </summary>
        /// <typeparam name="T">The type of the controller that will determine how the side
        /// screen works. A new instance will be created and added as a component to the new
        /// side screen.</typeparam>
        /// <param name="targetClassName">The full name of the type of side screen to based to ordering
        /// around. An example of how this method can be used is:
        /// `AddSideScreenContentWithOrdering&lt;MySideScreen&gt;(typeof(CapacityControlSideScreen).FullName);`
        /// `typeof(TargetedSideScreen).FullName` is the suggested value of this parameter.
        /// Side screens from other mods can be used with their qualified names, even if no
        /// no reference to their type is available, but the target mod must have added their
        /// custom side screen to the list first.</param>
        /// <param name="insertBefore">Whether to insert the new screen before or after the
        /// target side screen in the list. Defaults to before (true).
        /// When inserting before the screen, if both are valid for a building then the side
        /// screen of type "T" will show below the one of type "fullName". When inserting after
        /// the screen, the reverse is true.</param>
        /// <param name="uiPrefab">The UI prefab to use. If null is passed, the UI should
        /// be created and added to the GameObject hosting the controller object in its
        /// constructor.</param>
        public static void AddSideScreenContentWithOrdering <T>(string targetClassName,
                                                                bool insertBefore = true, GameObject uiPrefab = null)
            where T : SideScreenContent
        {
            var inst = DetailsScreen.Instance;

            if (inst == null)
            {
                LogUIWarning("DetailsScreen is not yet initialized, try a postfix on " +
                             "DetailsScreen.OnPrefabInit");
            }
            else
            {
                var    screens = UIDetours.SIDE_SCREENS.Get(inst);
                var    body    = UIDetours.SS_CONTENT_BODY.Get(inst);
                string name    = typeof(T).Name;
                if (body != null && screens != null)
                {
                    // The ref normally contains a prefab which is instantiated
                    var newScreen = new DetailsScreen.SideScreenRef();
                    // Mimic the basic screens
                    var rootObject = PUIElements.CreateUI(body, name);
                    // Preserve the border by fitting the child
                    rootObject.AddComponent <BoxLayoutGroup>().Params = new BoxLayoutParams()
                    {
                        Direction = PanelDirection.Vertical, Alignment = TextAnchor.
                                                                         UpperCenter, Margin = new RectOffset(1, 1, 0, 1)
                    };
                    var controller = rootObject.AddComponent <T>();
                    if (uiPrefab != null)
                    {
                        // Add prefab if supplied
                        UIDetours.SS_CONTENT_CONTAINER.Set(controller, uiPrefab);
                        uiPrefab.transform.parent = rootObject.transform;
                    }
                    newScreen.name = name;
                    // Offset is never used
                    UIDetours.SS_OFFSET.Set(newScreen, Vector2.zero);
                    UIDetours.SS_PREFAB.Set(newScreen, controller);
                    UIDetours.SS_INSTANCE.Set(newScreen, controller);
                    InsertSideScreenContent(screens, newScreen, targetClassName, insertBefore);
                }
            }
        }
예제 #19
0
        public override GameObject Build()
        {
            var panel   = PUIElements.CreateUI(null, Name);
            var mapping = DictionaryPool <IUIComponent, GameObject, PRelativePanel> .Allocate();

            SetImage(panel);
            // Realize each component and add them to the panel
            foreach (var pair in constraints)
            {
                var component = pair.Key;
                var realized  = component.Build();
                realized.SetParent(panel);
                // We were already guaranteed that there were no duplicate keys
                mapping[component] = realized;
            }
            // Add layout component
            var layout = panel.AddComponent <RelativeLayoutGroup>();

            layout.Margin = Margin;
            foreach (var pair in constraints)
            {
                var realized  = mapping[pair.Key];
                var rawParams = pair.Value;
                var newParams = new RelativeLayoutParams();
                // Copy all of the settings
                Resolve(newParams.TopEdge, rawParams.TopEdge, mapping);
                Resolve(newParams.BottomEdge, rawParams.BottomEdge, mapping);
                Resolve(newParams.LeftEdge, rawParams.LeftEdge, mapping);
                Resolve(newParams.RightEdge, rawParams.RightEdge, mapping);
                newParams.OverrideSize = rawParams.OverrideSize;
                newParams.Insets       = rawParams.Insets;
                layout.SetRaw(realized, newParams);
            }
            if (!DynamicSize)
            {
                layout.LockLayout();
            }
            mapping.Recycle();
            // Set flex size
            layout.flexibleWidth  = FlexSize.x;
            layout.flexibleHeight = FlexSize.y;
            InvokeRealize(panel);
            return(panel);
        }
예제 #20
0
        public override GameObject Build()
        {
            var label = PUIElements.CreateUI(null, Name);

            // Background
            if (BackColor.a > 0)
            {
                label.AddComponent <Image>().color = BackColor;
            }
            // Add foreground image
            if (Sprite != null)
            {
                ImageChildHelper(label, this);
            }
            // Add text
            if (!string.IsNullOrEmpty(Text))
            {
                TextChildHelper(label, TextStyle ?? PUITuning.Fonts.UILightStyle, Text);
            }
            // Add tooltip
            if (!string.IsNullOrEmpty(ToolTip))
            {
                label.AddComponent <ToolTip>().toolTip = ToolTip;
            }
            label.SetActive(true);
            // Icon and text are side by side
            var lp = new BoxLayoutParams()
            {
                Spacing   = IconSpacing, Direction = PanelDirection.Horizontal, Margin = Margin,
                Alignment = TextAlignment
            };

            if (DynamicSize)
            {
                label.AddComponent <BoxLayoutGroup>().Params = lp;
            }
            else
            {
                BoxLayoutGroup.LayoutNow(label, lp);
            }
            label.SetFlexUISize(FlexSize);
            InvokeRealize(label);
            return(label);
        }
예제 #21
0
        public override GameObject Build()
        {
            var        label = PUIElements.CreateUI(null, Name);
            GameObject sprite = null, text = null;

            // Background
            if (BackColor.a > 0)
            {
                label.AddComponent <Image>().color = BackColor;
            }
            // Add foreground image
            if (Sprite != null)
            {
                sprite = ImageChildHelper(label, this).gameObject;
            }
            // Add text
            if (!string.IsNullOrEmpty(Text))
            {
                text = TextChildHelper(label, TextStyle ?? PUITuning.Fonts.UILightStyle,
                                       Text).gameObject;
            }
            // Add tooltip
            if (!string.IsNullOrEmpty(ToolTip))
            {
                label.AddComponent <ToolTip>().toolTip = ToolTip;
            }
            label.SetActive(true);
            // Arrange the icon and text
            var layout = label.AddComponent <RelativeLayoutGroup>();

            layout.Margin = Margin;
            ArrangeComponent(layout, WrapTextAndSprite(text, sprite), TextAlignment);
            if (!DynamicSize)
            {
                layout.LockLayout();
            }
            layout.flexibleWidth  = FlexSize.x;
            layout.flexibleHeight = FlexSize.y;
            InvokeRealize(label);
            return(label);
        }
예제 #22
0
        /// <summary>
        /// Shared routine to spawn UI image objects.
        /// </summary>
        /// <param name="parent">The parent object for the image.</param>
        /// <param name="sprite">The sprite to display.</param>
        /// <param name="rotate">How to rotate or flip the sprite.</param>
        /// <param name="imageSize">The size to which to scale the sprite.</param>
        /// <returns>The child image object.</returns>
        protected static Image ImageChildHelper(GameObject parent, Sprite sprite,
                                                ImageTransform rotate = ImageTransform.None, Vector2 imageSize = default)
        {
            var imageChild = PUIElements.CreateUI("Image");
            var img        = imageChild.AddComponent <Image>();

            PUIElements.SetParent(imageChild, parent);
            img.sprite         = sprite;
            img.preserveAspect = true;
            // Set up transform
            var   scale = Vector3.one;
            float rot   = 0.0f;

            if ((rotate & ImageTransform.FlipHorizontal) != ImageTransform.None)
            {
                scale.x = -1.0f;
            }
            if ((rotate & ImageTransform.FlipVertical) != ImageTransform.None)
            {
                scale.y = -1.0f;
            }
            if ((rotate & ImageTransform.Rotate90) != ImageTransform.None)
            {
                rot = 90.0f;
            }
            if ((rotate & ImageTransform.Rotate180) != ImageTransform.None)
            {
                rot += 180.0f;
            }
            // Update transform
            var transform = imageChild.rectTransform();

            transform.localScale = scale;
            transform.Rotate(new Vector3(0.0f, 0.0f, rot));
            // Limit size if needed
            if (imageSize.x > 0.0f && imageSize.y > 0.0f)
            {
                PUIElements.SetSizeImmediate(imageChild, imageSize);
            }
            return(img);
        }
예제 #23
0
        public GameObject Build()
        {
            if (Parent == null)
            {
                throw new InvalidOperationException("Parent for dialog may not be null");
            }
            var dialog     = PUIElements.CreateUI(Parent, Name);
            var dComponent = dialog.AddComponent <PDialogComp>();

            // Background
            dialog.AddComponent <Canvas>();
            dialog.AddComponent <GraphicRaycaster>();
            var bg = dialog.AddComponent <Image>();

            bg.color  = DialogBackColor;
            bg.sprite = PUITuning.Images.BoxBorder;
            bg.type   = Image.Type.Sliced;
            // Add each component
            var layout = dialog.AddComponent <PGridLayoutGroup>();

            layout.AddRow(new GridRowSpec());
            layout.AddRow(new GridRowSpec(flex: 1.0f));
            layout.AddRow(new GridRowSpec());
            layout.AddColumn(new GridColumnSpec(flex: 1.0f));
            layout.AddColumn(new GridColumnSpec());
            LayoutTitle(layout, dComponent.DoButton);
            layout.AddComponent(Body.Build(), new GridComponentSpec(1, 0)
            {
                ColumnSpan = 2, Margin = new RectOffset(10, 10, 10, 10)
            });
            CreateUserButtons(layout, dComponent.DoButton);
            // Configure body position
            SetDialogSize(dialog);
            // Dialog is realized
            dComponent.dialog  = this;
            dComponent.sortKey = SortKey;
            OnRealize?.Invoke(dialog);
            return(dialog);
        }
예제 #24
0
        public override GameObject Build()
        {
            if (Columns < 1)
            {
                throw new InvalidOperationException("At least one column must be defined");
            }
            if (Rows < 1)
            {
                throw new InvalidOperationException("At least one row must be defined");
            }
            var panel = PUIElements.CreateUI(null, Name);

            SetImage(panel);
            // Add layout component
            var layout = panel.AddComponent <PGridLayoutGroup>();

            layout.Margin = Margin;
            foreach (var column in columns)
            {
                layout.AddColumn(column);
            }
            foreach (var row in rows)
            {
                layout.AddRow(row);
            }
            // Add children
            foreach (var child in children)
            {
                layout.AddComponent(child.Item.Build(), child);
            }
            if (!DynamicSize)
            {
                layout.LockLayout();
            }
            layout.flexibleWidth  = FlexSize.x;
            layout.flexibleHeight = FlexSize.y;
            InvokeRealize(panel);
            return(panel);
        }
예제 #25
0
        /// <summary>
        /// Builds a row selection prefab object for this combo box.
        /// </summary>
        /// <param name="style">The text style for the entries.</param>
        /// <param name="entryColor">The color for the entry backgrounds.</param>
        /// <returns>A template for each row in the dropdown.</returns>
        private GameObject BuildRowPrefab(TextStyleSetting style, ColorStyleSetting entryColor)
        {
            var im        = ItemMargin;
            var rowPrefab = PUIElements.CreateUI(null, "RowEntry");
            // Background of the entry
            var bgImage = rowPrefab.AddComponent <KImage>();

            UIDetours.COLOR_STYLE_SETTING.Set(bgImage, entryColor);
            UIDetours.APPLY_COLOR_STYLE.Invoke(bgImage);
            // Checkmark for the front of the entry
            var isSelected = PUIElements.CreateUI(rowPrefab, "Selected");
            var fgImage    = isSelected.AddComponent <Image>();

            fgImage.color          = style.textColor;
            fgImage.preserveAspect = true;
            fgImage.sprite         = PUITuning.Images.Checked;
            // Button for the entry to select it
            var entryButton = rowPrefab.AddComponent <KButton>();

            PButton.SetupButton(entryButton, bgImage);
            UIDetours.FG_IMAGE.Set(entryButton, fgImage);
            // Tooltip for the entry
            rowPrefab.AddComponent <ToolTip>();
            // Text for the entry
            var textContainer = PUIElements.CreateUI(rowPrefab, "Text");

            PUIElements.AddLocText(textContainer, style).SetText(" ");
            // Configure the entire layout in 1 statement! (jk this is awful)
            var group = rowPrefab.AddComponent <RelativeLayoutGroup>();

            group.AnchorYAxis(isSelected).OverrideSize(isSelected, CheckSize).SetLeftEdge(
                isSelected, fraction: 0.0f).SetMargin(isSelected, im).AnchorYAxis(
                textContainer).SetLeftEdge(textContainer, toRight: isSelected).SetRightEdge(
                textContainer, 1.0f).SetMargin(textContainer, new RectOffset(0, im.right,
                                                                             im.top, im.bottom)).LockLayout();
            rowPrefab.SetActive(false);
            return(rowPrefab);
        }
예제 #26
0
        public GameObject Build()
        {
            var panel = PUIElements.CreateUI(Name);

            if (BackColor.a > 0.0f)
            {
                panel.AddComponent <Image>().color = BackColor;
            }
            panel.layer = LayerMask.NameToLayer("UI");
            // Add children
            foreach (var child in children)
            {
                PUIElements.SetParent(child.Build(), panel);
            }
            // Add layout component
            var args = new BoxLayoutParams()
            {
                Direction = Direction, Alignment = Alignment, Spacing = Spacing,
                Margin    = Margin
            };

            // Gotta love freezable layouts
            if (DynamicSize)
            {
                var lg = panel.AddComponent <BoxLayoutGroup>();
                lg.Params         = args;
                lg.flexibleWidth  = FlexSize.x;
                lg.flexibleHeight = FlexSize.y;
            }
            else
            {
                BoxLayoutGroup.LayoutNow(panel, args).SetFlexUISize(FlexSize);
            }
            OnRealize?.Invoke(panel);
            return(panel);
        }
예제 #27
0
        /// <summary>
        /// Creates the handle component.
        /// </summary>
        /// <param name="slider">The parent component.</param>
        /// <returns>The sliding handle object.</returns>
        private GameObject CreateHandle(GameObject slider)
        {
            // Handle
            var handle = PUIElements.CreateUI(slider, "Handle", true, PUIAnchoring.Center,
                                              PUIAnchoring.Center);
            var handleImg = handle.AddComponent <Image>();

            handleImg.sprite         = PUITuning.Images.SliderHandle;
            handleImg.preserveAspect = true;
            handle.SetUISize(new Vector2(HandleSize, HandleSize));
            // Rotate the handle if needed (CCW)
            float rot = 0.0f;

            switch (Direction)
            {
            case Slider.Direction.TopToBottom:
                rot = 90.0f;
                break;

            case Slider.Direction.RightToLeft:
                rot = 180.0f;
                break;

            case Slider.Direction.BottomToTop:
                rot = 270.0f;
                break;

            default:
                break;
            }
            if (rot != 0.0f)
            {
                handle.transform.Rotate(new Vector3(0.0f, 0.0f, rot));
            }
            return(handle);
        }
예제 #28
0
        /// <summary>
        /// Builds a PLib UI object and adds it to an existing UI object.
        /// </summary>
        /// <param name="component">The UI object to add.</param>
        /// <param name="parent">The parent of the new object.</param>
        /// <param name="index">The sibling index to insert the element at, if provided.</param>
        /// <returns>The built version of the UI object.</returns>
        public static GameObject AddTo(this IUIComponent component, GameObject parent,
                                       int index = -2)
        {
            if (component == null)
            {
                throw new ArgumentNullException("component");
            }
            if (parent == null)
            {
                throw new ArgumentNullException("parent");
            }
            var child = component.Build();

            PUIElements.SetParent(child, parent);
            if (index == -1)
            {
                child.transform.SetAsLastSibling();
            }
            else if (index >= 0)
            {
                child.transform.SetSiblingIndex(index);
            }
            return(child);
        }
예제 #29
0
        public GameObject Build()
        {
            var        combo = PUIElements.CreateUI(null, Name);
            var        style = TextStyle ?? PUITuning.Fonts.UILightStyle;
            var        entryColor = EntryColor ?? PUITuning.Colors.ButtonBlueStyle;
            RectOffset margin = Margin, im = ItemMargin;
            // Background color
            var bgImage        = combo.AddComponent <KImage>();
            var backColorStyle = BackColor ?? PUITuning.Colors.ButtonBlueStyle;

            UIDetours.COLOR_STYLE_SETTING.Set(bgImage, backColorStyle);
            PButton.SetupButtonBackground(bgImage);
            // Need a LocText (selected item)
            var selection = PUIElements.CreateUI(combo, "SelectedItem");

            if (MinWidth > 0)
            {
                selection.SetMinUISize(new Vector2(MinWidth, 0.0f));
            }
            var selectedLabel = PUIElements.AddLocText(selection, style);
            // Vertical flow panel with the choices
            var contentContainer = PUIElements.CreateUI(null, "Content");

            contentContainer.AddComponent <VerticalLayoutGroup>().childForceExpandWidth = true;
            // Scroll pane with items is laid out below everything else
            var pullDown = new PScrollPane("PullDown")
            {
                ScrollHorizontal = false, ScrollVertical = true, AlwaysShowVertical = true,
                FlexSize         = Vector2.right, TrackSize = 8.0f, BackColor = entryColor.
                                                                                inactiveColor
            }.BuildScrollPane(combo, contentContainer);

            // Add a black border (Does not work, covered by the combo box buttons...)
#if false
            var pdImage = pullDown.GetComponent <Image>();
            pdImage.sprite = PUITuning.Images.BoxBorder;
            pdImage.type   = Image.Type.Sliced;
#endif
            pullDown.rectTransform().pivot = new Vector2(0.5f, 1.0f);
            // Initialize the drop down
            var comboBox = combo.AddComponent <PComboBoxComponent>();
            comboBox.CheckColor       = style.textColor;
            comboBox.ContentContainer = contentContainer.rectTransform();
            comboBox.EntryPrefab      = BuildRowPrefab(style, entryColor);
            comboBox.MaxRowsShown     = MaxRowsShown;
            comboBox.Pulldown         = pullDown;
            comboBox.SelectedLabel    = selectedLabel;
            comboBox.SetItems(Content);
            comboBox.SetSelectedItem(InitialItem);
            comboBox.OnSelectionChanged = (obj, item) => OnOptionSelected?.Invoke(obj.
                                                                                  gameObject, item as T);
            // Inner component with the pulldown image
            var image = PUIElements.CreateUI(combo, "OpenImage");
            var icon  = image.AddComponent <Image>();
            icon.sprite = PUITuning.Images.Contract;
            icon.color  = style.textColor;
            // Button component
            var dropButton = combo.AddComponent <KButton>();
            PButton.SetupButton(dropButton, bgImage);
            UIDetours.FG_IMAGE.Set(dropButton, icon);
            dropButton.onClick += comboBox.OnClick;
            // Add tooltip
            PUIElements.SetToolTip(selection, ToolTip);
            combo.SetActive(true);
            // Button gets laid out on the right, rest of space goes to the label
            // Scroll pane is laid out on the bottom
            var layout = combo.AddComponent <RelativeLayoutGroup>();
            layout.AnchorYAxis(selection).SetLeftEdge(selection, fraction:
                                                      0.0f).SetRightEdge(selection, toLeft: image).AnchorYAxis(image).SetRightEdge(
                image, fraction: 1.0f).SetMargin(selection, new RectOffset(margin.left,
                                                                           im.right, margin.top, margin.bottom)).SetMargin(image, new RectOffset(0,
                                                                                                                                                 margin.right, margin.top, margin.bottom)).OverrideSize(image, ArrowSize).
            AnchorYAxis(pullDown, 0.0f).OverrideSize(pullDown, Vector2.up);
            layout.LockLayout();
            if (DynamicSize)
            {
                layout.UnlockLayout();
            }
            // Disable sizing on the pulldown
            pullDown.AddOrGet <LayoutElement>().ignoreLayout = true;
            // Scroll pane is hidden right away
            pullDown.SetActive(false);
            layout.flexibleWidth  = FlexSize.x;
            layout.flexibleHeight = FlexSize.y;
            OnRealize?.Invoke(combo);
            return(combo);
        }
예제 #30
0
        public GameObject Build()
        {
            var textField = PUIElements.CreateUI(Name);
            // Background
            var style = TextStyle ?? PUITuning.Fonts.TextLightStyle;

            textField.AddComponent <Image>().color = style.textColor;
            // Text box with rectangular clipping area
            var textArea = PUIElements.CreateUI("Text Area", true, false);

            textArea.AddComponent <Image>().color = BackColor;
            PUIElements.SetParent(textArea, textField);
            var mask = textArea.AddComponent <RectMask2D>();
            // Scrollable text
            var textBox = PUIElements.CreateUI("Text");

            PUIElements.SetParent(textBox, textArea);
            // 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;
            textDisplay.maxVisibleLines = 1;
            // Text field itself
            var onChange = OnTextChanged;

            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 ?? "";
            ConfigureTextEntry(textEntry).onDeselect.AddListener((text) => {
                onChange?.Invoke(textField, (text ?? "").TrimEnd());
            });
            // Add tooltip
            if (!string.IsNullOrEmpty(ToolTip))
            {
                textField.AddComponent <ToolTip>().toolTip = ToolTip;
            }
            mask.enabled = true;
            // Lay out - TMP_InputField does not support auto layout so we have to do a hack
            var minSize = new Vector2(MinWidth, LayoutUtility.GetPreferredHeight(textBox.
                                                                                 rectTransform()));

            textArea.SetMinUISize(minSize).SetFlexUISize(Vector2.one);
            var lp = new BoxLayoutParams()
            {
                Direction = PanelDirection.Horizontal, Alignment = TextAnchor.MiddleLeft,
                Margin    = new RectOffset(1, 1, 1, 1)
            };

            if (DynamicSize)
            {
                var layout = textField.AddComponent <BoxLayoutGroup>();
                layout.Params         = lp;
                layout.flexibleWidth  = FlexSize.x;
                layout.flexibleHeight = FlexSize.y;
                textField.SetMinUISize(minSize);
            }
            else
            {
                BoxLayoutGroup.LayoutNow(textField, lp, new Vector2(MinWidth, 0.0f)).
                SetFlexUISize(FlexSize);
            }
            OnRealize?.Invoke(textField);
            return(textField);
        }