public void Init()
        {
            if (_isInitialized)
            {
                return;
            }

            var container = new GameObject("DifficultiesFilterContainer");

            Controls[0] = new FilterControl(container, new Vector2(0f, 0.05f), new Vector2(1f, 0.95f), new Vector2(0.5f, 0.5f), Vector2.zero, Vector2.zero,
                                            delegate()
            {
                for (int i = 0; i < 5; ++i)
                {
                    _toggles[i].isOn = _stagingValues[i];
                }
            });

            var unused = container.AddComponent <Image>();

            unused.color    = new Color(0f, 0f, 0f, 0f);
            unused.material = Utilities.NoGlowMaterial;

            var text = BeatSaberUI.CreateText(container.transform as RectTransform, "Keep Songs That Have These Difficulties", Vector2.zero, new Vector2(60f, 6f));

            text.fontSize = 5.5f;
            var rt = text.rectTransform;

            rt.anchorMin = new Vector2(0f, 1f);
            rt.anchorMax = new Vector2(0f, 1f);
            rt.pivot     = new Vector2(0f, 1f);

            var togglePrefab = Utilities.GetTogglePrefab();

            for (int i = 0; i < 4; ++i)
            {
                CreateToggleControl(container.transform as RectTransform, DifficultyStrings[i], i, togglePrefab.toggle);
            }
            CreateToggleControl(container.transform as RectTransform, "Expert+", 4, togglePrefab.toggle, false);

            Object.Destroy(togglePrefab.gameObject);

            _isInitialized = true;
        }
Example #2
0
        public void Init()
        {
            if (_isInitialized)
            {
                return;
            }

            // since we're using BeatSaverDownloader's votedSong.json file, we need the mod to be present
            if (!Tweaks.BeatSaverDownloaderTweaks.ModLoaded)
            {
                var noModMessage = BeatSaberUI.CreateText(null, "<color=#FFAAAA>Sorry!\n\n<size=80%>This filter requires the BeatSaverDownloader mod\n to be installed.</size></color>", Vector2.zero);
                noModMessage.alignment = TextAlignmentOptions.Center;
                noModMessage.fontSize  = 5.5f;

                Controls[0] = new FilterControl(noModMessage.gameObject, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(80f, 50f), new Vector2(0f, 10f));
            }
            else
            {
                var container = new GameObject("VotedFilterContainer");
                Controls[0] = new FilterControl(container, new Vector2(0f, 0.95f), new Vector2(1f, 0.95f), new Vector2(0.5f, 0.5f), Vector2.zero, Vector2.zero,
                                                delegate()
                {
                    _upvotedToggle.isOn   = _upvotedStagingValue;
                    _noVoteToggle.isOn    = _noVoteStagingValue;
                    _downvotedToggle.isOn = _downvotedStagingValue;
                });

                // blank image assigned to container so it'll have a RectTransform
                var unused = container.AddComponent <Image>();
                unused.color    = new Color(0f, 0f, 0f, 0f);
                unused.material = Utilities.NoGlowMaterial;

                var text = BeatSaberUI.CreateText(container.transform as RectTransform, "Keep Songs That You Voted", Vector2.zero);
                text.fontSize = 5.5f;
                var rt = text.rectTransform;
                rt.anchorMin = new Vector2(0f, 1f);
                rt.anchorMax = rt.anchorMin;
                rt.pivot     = rt.anchorMin;
                BeatSaberUI.AddHintText(text.rectTransform, "Keep songs depending on how you have voted (or not voted)");

                var togglePrefab = Utilities.GetTogglePrefab();

                _upvotedToggle = CreateToggleControl(container.transform as RectTransform, "Upvoted Songs", 0, togglePrefab.toggle);
                _upvotedToggle.onValueChanged.AddListener(delegate(bool value)
                {
                    _upvotedStagingValue = value;
                    SettingChanged?.Invoke();
                });

                _noVoteToggle = CreateToggleControl(container.transform as RectTransform, "Songs With No Vote", 1, togglePrefab.toggle);
                _noVoteToggle.onValueChanged.AddListener(delegate(bool value)
                {
                    _noVoteStagingValue = value;
                    SettingChanged?.Invoke();
                });

                _downvotedToggle = CreateToggleControl(container.transform as RectTransform, "Downvoted Songs", 2, togglePrefab.toggle, false);
                _downvotedToggle.onValueChanged.AddListener(delegate(bool value)
                {
                    _downvotedStagingValue = value;
                    SettingChanged?.Invoke();
                });

                Object.Destroy(togglePrefab.gameObject);
            }

            _isInitialized = true;
        }
        public void Init()
        {
            if (_isInitialized)
            {
                return;
            }

            // difficulties
            var difficultiesContainer = new GameObject("DifficultiesContainer");

            Controls[0] = new FilterControl(difficultiesContainer, new Vector2(0f, 0.95f), new Vector2(1f, 0.95f), new Vector2(0.5f, 1f), new Vector2(0f, 26f), Vector2.zero,
                                            delegate()
            {
                for (int i = 0; i < 5; ++i)
                {
                    _difficultyToggles[i].isOn = _difficultiesStagingValue[i];
                }
            });

            // the container needs some graphical component to have the Transform to RectTransform cast work
            var unused = difficultiesContainer.AddComponent <Image>();

            unused.color = new Color(0f, 0f, 0f, 0f);

            var divider = Utilities.CreateHorizontalDivider(difficultiesContainer.transform);

            divider.color = new Color(1f, 1f, 1f, 0.4f);
            divider.rectTransform.sizeDelta = new Vector2(0f, 0.2f);

            CreateDifficultyToggles(difficultiesContainer.transform);

            // minimum value setting
            float[] values = Enumerable.Range(MinValue, MaxValue).Select(x => (float)x).ToArray();
            _minViewController = Utilities.CreateListViewController("Minimum NJS", values, "Filter out songs that have a smaller NJS than this value");
            _minViewController.GetTextForValue += x => ((int)x).ToString();
            _minViewController.GetValue        += () => _minStagingValue;
            _minViewController.SetValue        += delegate(float value)
            {
                if (_maxEnabledStagingValue && value > _maxStagingValue)
                {
                    _minStagingValue = _maxStagingValue;
                    RefreshUI();
                    return;
                }

                _minStagingValue = (int)value;

                RefreshUI(false);

                SettingChanged?.Invoke();
            };
            _minViewController.Init();
            _minViewController.applyImmediately = true;

            var minToggle = CreateEnableToggle(_minViewController);

            minToggle.name = "MinValueToggle";
            minToggle.onValueChanged.AddListener(delegate(bool value)
            {
                _minEnabledStagingValue = value;

                if (value && _maxEnabledStagingValue && _minStagingValue > _maxStagingValue)
                {
                    _minStagingValue = _maxStagingValue;
                }

                RefreshUI(true, true);

                SettingChanged?.Invoke();
            });

            Utilities.MoveListViewControllerElements(_minViewController);
            Utilities.CreateHorizontalDivider(_minViewController.transform);

            Controls[1] = new FilterControl(_minViewController.gameObject, new Vector2(0f, 0.95f), new Vector2(1f, 0.95f), new Vector2(0.5f, 1f), new Vector2(0f, 12f), new Vector2(0f, -26f),
                                            delegate()
            {
                // disabling buttons needs to be done after the view controller is enabled to override the interactable assignments of ListSettingsController:OnEnable()
                _minViewController.GetComponentsInChildren <Button>().First(x => x.name == "DecButton").interactable = _minEnabledStagingValue && _minStagingValue > MinValue;
                _minViewController.GetComponentsInChildren <Button>().First(x => x.name == "IncButton").interactable = _minEnabledStagingValue && (!_maxEnabledStagingValue || _minStagingValue < _maxStagingValue) && _minStagingValue < MaxValue;

                minToggle.isOn = _minEnabledStagingValue;
            });

            // maximum value setting
            _maxViewController = Utilities.CreateListViewController("Maximum NJS", values, "Filter out songs that have a larger NJS than this value");
            _maxViewController.GetTextForValue += x => ((int)x).ToString();
            _maxViewController.GetValue        += () => _maxStagingValue;
            _maxViewController.SetValue        += delegate(float value)
            {
                if (_minEnabledStagingValue && value < _minStagingValue)
                {
                    _maxStagingValue = _minStagingValue;
                    RefreshUI();
                    return;
                }

                _maxStagingValue = (int)value;

                RefreshUI(false);

                SettingChanged?.Invoke();
            };
            _maxViewController.Init();
            _maxViewController.applyImmediately = true;

            var maxToggle = CreateEnableToggle(_maxViewController);

            maxToggle.name = "MaxValueToggle";
            maxToggle.onValueChanged.AddListener(delegate(bool value)
            {
                _maxEnabledStagingValue = value;

                if (value && _minEnabledStagingValue && _maxStagingValue < _minStagingValue)
                {
                    _maxStagingValue = _minStagingValue;
                }

                RefreshUI(true, true);

                SettingChanged?.Invoke();
            });

            Utilities.MoveListViewControllerElements(_maxViewController);

            Controls[2] = new FilterControl(_maxViewController.gameObject, new Vector2(0f, 0.95f), new Vector2(1f, 0.95f), new Vector2(0.5f, 1f), new Vector2(0f, 12f), new Vector2(0f, -38f),
                                            delegate()
            {
                _maxViewController.GetComponentsInChildren <Button>().First(x => x.name == "DecButton").interactable = _maxEnabledStagingValue && (!_minEnabledStagingValue || _maxStagingValue > _minStagingValue) && _maxStagingValue < MinValue;
                _maxViewController.GetComponentsInChildren <Button>().First(x => x.name == "IncButton").interactable = _maxEnabledStagingValue && _maxStagingValue < MaxValue;

                maxToggle.isOn = _maxEnabledStagingValue;
            });

            _isInitialized = true;
        }
        public void Init()
        {
            if (_isInitialized)
            {
                return;
            }

            // we're using SongDataCore's ScoreSaber data storage to find out the star rating
            if (!Tweaks.SongDataCoreTweaks.ModLoaded)
            {
                Controls = new FilterControl[1];

                var noModMessage = BeatSaberUI.CreateText(null, "<color=#FFAAAA>Sorry!\n\n<size=80%>This filter requires the SongDataCore mod to be\n installed.</size></color>", Vector2.zero);
                noModMessage.alignment = TextAlignmentOptions.Center;
                noModMessage.fontSize  = 5.5f;

                Controls[0] = new FilterControl(noModMessage.gameObject, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(80f, 50f), new Vector2(0f, 10f));

                _isInitialized = true;
                return;
            }

            var togglePrefab = Utilities.GetTogglePrefab();

            // title text
            var text = BeatSaberUI.CreateText(null, "Keep Songs Between Some Star Rating", Vector2.zero, Vector2.zero);

            text.fontSize = 5.5f;
            var rt = text.rectTransform;

            rt.anchorMin = new Vector2(0f, 1f);
            rt.anchorMax = new Vector2(0f, 1f);
            rt.pivot     = new Vector2(0f, 1f);

            Controls[0] = new FilterControl(text.gameObject, new Vector2(0f, 0.95f), new Vector2(0f, 0.95f), new Vector2(0f, 1f), new Vector2(50f, 6f), Vector2.zero);

            // min view controller
            float[] values = Enumerable.Range((int)MinValue, (int)((MaxValue - MinValue) / IncrementValue) + 1).Select(x => x * IncrementValue).ToArray();
            _minViewController = Utilities.CreateListViewController("Minimum Star Rating", values, "Filters out songs that have a lesser star difficulty rating than this value");
            _minViewController.GetTextForValue += x => x.ToString("0.00");
            _minViewController.GetValue        += () => _minStagingValue;
            _minViewController.SetValue        += delegate(float value)
            {
                if (_maxEnabledStagingValue && value > _maxStagingValue)
                {
                    _minStagingValue = _maxStagingValue;
                    RefreshUI();
                    return;
                }

                _minStagingValue = value;

                RefreshUI(false);

                SettingChanged?.Invoke();
            };
            _minViewController.Init();
            _minViewController.applyImmediately = true;

            var minToggle = Utilities.CreateToggleFromPrefab(togglePrefab.toggle, _minViewController.transform.Find("Value"));

            minToggle.name = "MinValueToggle";
            minToggle.onValueChanged.AddListener(delegate(bool value)
            {
                _minEnabledStagingValue = value;

                if (value && _maxEnabledStagingValue && _minStagingValue > _maxStagingValue)
                {
                    _minStagingValue = _maxStagingValue;
                }

                RefreshUI(true, true);

                SettingChanged?.Invoke();
            });

            Utilities.MoveListViewControllerElements(_minViewController);
            Utilities.CreateHorizontalDivider(_minViewController.transform);

            Controls[1] = new FilterControl(_minViewController.gameObject, new Vector2(0f, 0.95f), new Vector2(1f, 0.95f), new Vector2(0.5f, 1f), new Vector2(0f, 12f), new Vector2(0f, -8f),
                                            delegate()
            {
                // disabling buttons needs to be done after the view controller is enabled to override the interactable assignments of ListSettingsController:OnEnable()
                _minViewController.GetComponentsInChildren <Button>().First(x => x.name == "DecButton").interactable = _minEnabledStagingValue && _minStagingValue > MinValue;
                _maxViewController.GetComponentsInChildren <Button>().First(x => x.name == "IncButton").interactable = _minEnabledStagingValue && (!_maxEnabledStagingValue || _minStagingValue < _maxStagingValue) && _minStagingValue < MaxValue;
            });

            // max view controller
            _maxViewController = Utilities.CreateListViewController("Maximum Star Rating", values, "Filters out songs that have a greater star difficulty rating than this value");
            _maxViewController.GetTextForValue += x => x.ToString("0.00");
            _maxViewController.GetValue        += () => _maxStagingValue;
            _maxViewController.SetValue        += delegate(float value)
            {
                if (_minEnabledStagingValue && value < _minStagingValue)
                {
                    _maxStagingValue = _minStagingValue;
                    RefreshUI();
                    return;
                }

                _maxStagingValue = value;

                RefreshUI(false);

                SettingChanged?.Invoke();
            };
            _maxViewController.Init();
            _maxViewController.applyImmediately = true;

            var maxToggle = Utilities.CreateToggleFromPrefab(togglePrefab.toggle, _maxViewController.transform.Find("Value"));

            maxToggle.name = "MaxValueToggle";
            maxToggle.onValueChanged.AddListener(delegate(bool value)
            {
                _maxEnabledStagingValue = value;

                if (value && _minEnabledStagingValue && _maxStagingValue < _minStagingValue)
                {
                    _maxStagingValue = _minStagingValue;
                }

                RefreshUI(true, true);

                SettingChanged?.Invoke();
            });

            Utilities.MoveListViewControllerElements(_maxViewController);
            Utilities.CreateHorizontalDivider(_maxViewController.transform);

            Controls[2] = new FilterControl(_maxViewController.gameObject, new Vector2(0f, 0.95f), new Vector2(1f, 0.95f), new Vector2(0.5f, 1f), new Vector2(0f, 12f), new Vector2(0f, -20f),
                                            delegate()
            {
                // disabling buttons needs to be done after the view controller is enabled to override the interactable assignments of ListSettingsController:OnEnable()
                _maxViewController.GetComponentsInChildren <Button>().First(x => x.name == "DecButton").interactable = _maxEnabledStagingValue && (!_minEnabledStagingValue || _maxStagingValue > _minStagingValue) && _maxStagingValue > MinValue;
                _maxViewController.GetComponentsInChildren <Button>().First(x => x.name == "IncButton").interactable = _maxEnabledStagingValue && _maxStagingValue < MaxValue;
            });

            // include unrated songs toggle
            _includeUnratedViewController           = Utilities.CreateBoolViewController("Include Unrated Songs", "Do not filter out songs that do not have a star rating provided by ScoreSaber");
            _includeUnratedViewController.GetValue += () => _includeUnratedStagingValue;
            _includeUnratedViewController.SetValue += delegate(bool value)
            {
                _includeUnratedStagingValue = value;

                SettingChanged?.Invoke();
            };
            _includeUnratedViewController.Init();
            _includeUnratedViewController.applyImmediately = true;

            Utilities.MoveIncDecViewControllerElements(_includeUnratedViewController);

            Controls[3] = new FilterControl(_includeUnratedViewController.gameObject, new Vector2(0f, 0.95f), new Vector2(1f, 0.95f), new Vector2(0.5f, 1f), new Vector2(0f, 12f), new Vector2(0f, -32f));

            Object.Destroy(togglePrefab);

            _isInitialized = true;
        }
Example #5
0
        public void Init()
        {
            if (_isInitialized)
            {
                return;
            }

            // title text
            var text = BeatSaberUI.CreateText(null, "Other Filters", Vector2.zero, Vector2.zero);

            text.fontSize = 5.5f;
            var rt = text.rectTransform;

            rt.anchorMin = new Vector2(0f, 1f);
            rt.anchorMax = rt.anchorMin;
            rt.pivot     = rt.anchorMin;

            Controls[0] = new FilterControl(text.gameObject, new Vector2(0f, 0.95f), new Vector2(0f, 0.95f), new Vector2(0f, 1f), new Vector2(50f, 6f), Vector2.zero);

            // one saber view controller
            _oneSaberViewController           = Utilities.CreateBoolViewController("Has One Saber Mode", "Filters out songs that don't have at least one saber map");
            _oneSaberViewController.GetValue += () => _oneSaberStagingValue;
            _oneSaberViewController.SetValue += delegate(bool value)
            {
                _oneSaberStagingValue = value;
                SettingChanged?.Invoke();
            };
            _oneSaberViewController.Init();
            _oneSaberViewController.applyImmediately = true;

            Utilities.CreateHorizontalDivider(_oneSaberViewController.transform);
            Utilities.MoveIncDecViewControllerElements(_oneSaberViewController);

            Controls[1] = new FilterControl(_oneSaberViewController.gameObject, new Vector2(0f, 0.95f), new Vector2(1f, 0.95f), new Vector2(0.5f, 1f), new Vector2(0f, 12f), new Vector2(0f, -8f));

            // lightshow view controller
            _lightshowViewController           = Utilities.CreateBoolViewController("Has Lightshow Mode", "Filters out songs that don't have a lightshow map");
            _lightshowViewController.GetValue += () => _lightshowStagingValue;
            _lightshowViewController.SetValue += delegate(bool value)
            {
                _lightshowStagingValue = value;
                SettingChanged?.Invoke();
            };
            _lightshowViewController.Init();
            _lightshowViewController.applyImmediately = true;

            Utilities.CreateHorizontalDivider(_lightshowViewController.transform);
            Utilities.MoveIncDecViewControllerElements(_lightshowViewController);

            Controls[2] = new FilterControl(_lightshowViewController.gameObject, new Vector2(0f, 0.95f), new Vector2(1f, 0.95f), new Vector2(0.5f, 1f), new Vector2(0f, 12f), new Vector2(0f, -20f));

            // mapping extensions view controller
            var values = Enumerable.Range(0, 3).Select(x => (float)x).ToArray();

            _mappingExtensionsViewController = Utilities.CreateListViewController("Requires Mapping Extensions", values, "Filters out songs that don't require the 'Mapping Extensions' mod");
            _mappingExtensionsViewController.GetTextForValue += delegate(float value)
            {
                if (value == (float)SongRequirement.Required)
                {
                    return("<size=90%>Required</size>");
                }
                else if (value == (float)SongRequirement.NotRequired)
                {
                    return("<size=70%>Not Required</size>");
                }
                else
                {
                    return("OFF");
                }
            };
            _mappingExtensionsViewController.GetValue += () => (float)_mappingExtensionsStagingValue;
            _mappingExtensionsViewController.SetValue += delegate(float value)
            {
                _mappingExtensionsStagingValue = (SongRequirement)value;
                SettingChanged?.Invoke();
            };
            _mappingExtensionsViewController.Init();
            _mappingExtensionsViewController.applyImmediately = true;

            Utilities.MoveIncDecViewControllerElements(_mappingExtensionsViewController);

            Controls[3] = new FilterControl(_mappingExtensionsViewController.gameObject, new Vector2(0f, 0.95f), new Vector2(1f, 0.95f), new Vector2(0.5f, 1f), new Vector2(0f, 12f), new Vector2(0f, -32f));

            _isInitialized = true;
        }
        public void Init()
        {
            if (_isInitialized)
            {
                return;
            }

            var togglePrefab = Utilities.GetTogglePrefab();

            // title text
            var text = BeatSaberUI.CreateText(null, "Keep Songs Between Some Length", Vector2.zero, Vector2.zero);

            text.fontSize = 5.5f;
            var rt = text.rectTransform;

            rt.anchorMin = new Vector2(0f, 1f);
            rt.anchorMax = new Vector2(0f, 1f);
            rt.pivot     = new Vector2(0f, 1f);

            Controls[0] = new FilterControl(text.gameObject, new Vector2(0f, 0.95f), new Vector2(0f, 0.95f), new Vector2(0f, 1f), new Vector2(50f, 6f), Vector2.zero);

            // min view controller
            float[] values = Enumerable.Range((int)MinValue, (int)((MaxValue - MinValue) / IncrementValue) + 1).Select(x => x * IncrementValue).ToArray();
            _minViewController = Utilities.CreateListViewController("Minimum Duration", values, "Filters out songs that are shorter than this value");
            _minViewController.GetTextForValue += x => ConvertFloatToTimeString(x);
            _minViewController.GetValue        += () => _minStagingValue;
            _minViewController.SetValue        += delegate(float value)
            {
                if (_maxEnabledStagingValue && value > _maxStagingValue)
                {
                    _minStagingValue = _maxStagingValue;
                    RefreshUI();
                    return;
                }

                _minStagingValue = value;

                RefreshUI(false);

                SettingChanged?.Invoke();
            };
            _minViewController.Init();
            _minViewController.applyImmediately = true;

            var minToggle = Utilities.CreateToggleFromPrefab(togglePrefab.toggle, _minViewController.transform.Find("Value"));

            minToggle.name = "MinValueToggle";
            minToggle.onValueChanged.AddListener(delegate(bool value)
            {
                _minEnabledStagingValue = value;

                if (value && _maxEnabledStagingValue && _minStagingValue > _maxStagingValue)
                {
                    _minStagingValue = _maxStagingValue;
                }

                RefreshUI(true, true);

                SettingChanged?.Invoke();
            });

            Utilities.MoveListViewControllerElements(_minViewController);
            Utilities.CreateHorizontalDivider(_minViewController.transform);

            Controls[1] = new FilterControl(_minViewController.gameObject, new Vector2(0f, 0.95f), new Vector2(1f, 0.95f), new Vector2(0.5f, 1f), new Vector2(0f, 12f), new Vector2(0f, -8f),
                                            delegate()
            {
                // disabling buttons needs to be done after the view controller is enabled to override the interactable assignments of ListSettingsController:OnEnable()
                _minViewController.GetComponentsInChildren <Button>().First(x => x.name == "DecButton").interactable = _minEnabledStagingValue && _minStagingValue > MinValue;
                _maxViewController.GetComponentsInChildren <Button>().First(x => x.name == "IncButton").interactable = _minEnabledStagingValue && (!_maxEnabledStagingValue || _minStagingValue < _maxStagingValue) && _minStagingValue < MaxValue;
            });

            // max view controller
            _maxViewController = Utilities.CreateListViewController("Maximum Duration", values, "Filters out songs that are longer than this value");
            _maxViewController.GetTextForValue += x => ConvertFloatToTimeString(x);
            _maxViewController.GetValue        += () => _maxStagingValue;
            _maxViewController.SetValue        += delegate(float value)
            {
                if (_minEnabledStagingValue && value < _minStagingValue)
                {
                    _maxStagingValue = _minStagingValue;
                    RefreshUI();
                    return;
                }

                _maxStagingValue = value;

                RefreshUI(false);

                SettingChanged?.Invoke();
            };
            _maxViewController.Init();
            _maxViewController.applyImmediately = true;

            var maxToggle = Utilities.CreateToggleFromPrefab(togglePrefab.toggle, _maxViewController.transform.Find("Value"));

            maxToggle.name = "MaxValueToggle";
            maxToggle.onValueChanged.AddListener(delegate(bool value)
            {
                _maxEnabledStagingValue = value;

                if (value && _minEnabledStagingValue && _maxStagingValue < _minStagingValue)
                {
                    _maxStagingValue = _minStagingValue;
                }

                RefreshUI(true, true);

                SettingChanged?.Invoke();
            });

            Utilities.MoveListViewControllerElements(_maxViewController);

            Controls[2] = new FilterControl(_maxViewController.gameObject, new Vector2(0f, 0.95f), new Vector2(1f, 0.95f), new Vector2(0.5f, 1f), new Vector2(0f, 12f), new Vector2(0f, -20f),
                                            delegate()
            {
                // disabling buttons needs to be done after the view controller is enabled to override the interactable assignments of ListSettingsController:OnEnable()
                _maxViewController.GetComponentsInChildren <Button>().First(x => x.name == "DecButton").interactable = _maxEnabledStagingValue && (!_minEnabledStagingValue || _maxStagingValue > _minStagingValue) && _maxStagingValue > MinValue;
                _maxViewController.GetComponentsInChildren <Button>().First(x => x.name == "IncButton").interactable = _maxEnabledStagingValue && _maxStagingValue < MaxValue;
            });

            Object.Destroy(togglePrefab);

            _isInitialized = true;
        }
        public void Init()
        {
            if (_isInitialized)
            {
                return;
            }

            if (!Tweaks.SongDataCoreTweaks.ModLoaded)
            {
                Controls = new FilterControl[1];

                var noModMessage = BeatSaberUI.CreateText(null, "<color=#FFAAAA>Sorry!\n\n<size=80%>This filter requires the SongDataCore mod to be\n installed.</size></color>", Vector2.zero);
                noModMessage.alignment = TextAlignmentOptions.Center;
                noModMessage.fontSize  = 5.5f;

                Controls[0] = new FilterControl(noModMessage.gameObject, new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(0.5f, 0.5f), new Vector2(80f, 50f), new Vector2(0f, 10f));

                _isInitialized = true;
                return;
            }

            // title text
            var text = BeatSaberUI.CreateText(null, "Keep Songs That Award PP", Vector2.zero, Vector2.zero);

            text.fontSize = 5.5f;
            var rt = text.rectTransform;

            rt.anchorMin = new Vector2(0f, 1f);
            rt.anchorMax = new Vector2(0f, 1f);
            rt.pivot     = new Vector2(0f, 1f);

            Controls[0] = new FilterControl(text.gameObject, new Vector2(0f, 0.95f), new Vector2(0f, 0.95f), new Vector2(0f, 1f), new Vector2(50f, 6f), Vector2.zero);

            // ranked view controller
            float[] rankedValues = Enumerable.Range(0, Enum.GetValues(typeof(RankFilterOption)).Length).Select(x => (float)x).ToArray();
            _rankedViewController = Utilities.CreateListViewController("Is Ranked", rankedValues, "Filters out songs depending on whether they are ranked");
            _rankedViewController.GetTextForValue += delegate(float value)
            {
                RankFilterOption option = (RankFilterOption)value;
                if (option == RankFilterOption.Ranked)
                {
                    return("Ranked");
                }
                else if (option == RankFilterOption.NotRanked)
                {
                    return("<size=80%>Not Ranked</size>");
                }
                else
                {
                    return("Off");
                }
            };
            _rankedViewController.GetValue += () => (float)_rankedStagingValue;
            _rankedViewController.SetValue += delegate(float value)
            {
                _rankedStagingValue = (RankFilterOption)value;

                if (_rankedStagingValue == RankFilterOption.Ranked)
                {
                    _container.SetActive(true);

                    _minViewController.transform.Find("MinValueToggle").GetComponent <Toggle>().isOn = _minEnabledStagingValue;
                    _maxViewController.transform.Find("MaxValueToggle").GetComponent <Toggle>().isOn = _maxEnabledStagingValue;
                }
                else
                {
                    _container.SetActive(false);
                    _minEnabledStagingValue = false;
                    _maxEnabledStagingValue = false;
                }

                SettingChanged?.Invoke();
            };
            _rankedViewController.Init();
            _rankedViewController.applyImmediately = true;

            Utilities.MoveListViewControllerElements(_rankedViewController);

            Controls[1] = new FilterControl(_rankedViewController.gameObject, new Vector2(0f, 0.95f), new Vector2(1f, 0.95f), new Vector2(0.5f, 1f), new Vector2(0f, 12f), new Vector2(0f, -8f));

            // min-max view controller container
            _container = new GameObject("PPFilterContainer");
            var unused = _container.AddComponent <Image>();

            unused.color    = new Color(0f, 0f, 0f, 0f);
            unused.material = Utilities.NoGlowMaterial;

            var togglePrefab = Utilities.GetTogglePrefab();

            // min view controller
            float[] values = Enumerable.Range((int)MinValue, (int)((MaxValue - MinValue) / IncrementValue) + 1).Select(x => x * IncrementValue).ToArray();
            _minViewController = Utilities.CreateListViewController("Minimum PP", values, "Filters out ranked songs that award less PP that this value");
            _minViewController.GetTextForValue += x => x.ToString();
            _minViewController.GetValue        += () => _minStagingValue;
            _minViewController.SetValue        += delegate(float value)
            {
                if (_maxEnabledStagingValue && value > _maxStagingValue)
                {
                    _minStagingValue = _maxStagingValue;
                    RefreshUI();
                    return;
                }

                _minStagingValue = value;

                RefreshUI(false);

                SettingChanged?.Invoke();
            };
            _minViewController.Init();
            _minViewController.applyImmediately = true;

            rt = _minViewController.transform as RectTransform;
            rt.SetParent(_container.transform);
            rt.anchorMin        = new Vector2(0f, 1f);
            rt.anchorMax        = Vector2.one;
            rt.pivot            = new Vector2(0.5f, 1f);
            rt.anchoredPosition = Vector2.zero;
            rt.sizeDelta        = new Vector2(0f, 12f);

            var minToggle = Utilities.CreateToggleFromPrefab(togglePrefab.toggle, _minViewController.transform.Find("Value"));

            minToggle.name = "MinValueToggle";
            minToggle.onValueChanged.AddListener(delegate(bool value)
            {
                _minEnabledStagingValue = value;

                if (value && _maxEnabledStagingValue && _minStagingValue > _maxStagingValue)
                {
                    _minStagingValue = _maxStagingValue;
                }

                RefreshUI(true, true);

                SettingChanged?.Invoke();
            });

            Utilities.MoveListViewControllerElements(_minViewController);
            var divider = Utilities.CreateHorizontalDivider(_minViewController.transform, false);

            divider.color = new Color(1f, 1f, 1f, 0.4f);
            divider.rectTransform.sizeDelta = new Vector2(0f, 0.2f);
            Utilities.CreateHorizontalDivider(_minViewController.transform);

            // max view controller
            _maxViewController = Utilities.CreateListViewController("Maximum PP", values, "Filters out ranked songs that award more PP that this value");
            _maxViewController.GetTextForValue += x => x.ToString();
            _maxViewController.GetValue        += () => _maxStagingValue;
            _maxViewController.SetValue        += delegate(float value)
            {
                if (_minEnabledStagingValue && value < _minStagingValue)
                {
                    _maxStagingValue = _minStagingValue;
                    RefreshUI();
                    return;
                }

                _maxStagingValue = value;

                RefreshUI(false);

                SettingChanged?.Invoke();
            };
            _maxViewController.Init();
            _maxViewController.applyImmediately = true;

            rt = _maxViewController.transform as RectTransform;
            rt.SetParent(_container.transform);
            rt.anchorMin        = new Vector2(0f, 1f);
            rt.anchorMax        = Vector2.one;
            rt.pivot            = new Vector2(0.5f, 1f);
            rt.anchoredPosition = new Vector2(0f, -12f);
            rt.sizeDelta        = new Vector2(0f, 12f);

            var maxToggle = Utilities.CreateToggleFromPrefab(togglePrefab.toggle, _maxViewController.transform.Find("Value"));

            maxToggle.name = "MaxValueToggle";
            maxToggle.onValueChanged.AddListener(delegate(bool value)
            {
                _maxEnabledStagingValue = value;

                if (value && _minEnabledStagingValue && _maxStagingValue < _minStagingValue)
                {
                    _maxStagingValue = _minStagingValue;
                }

                RefreshUI(true, true);

                SettingChanged?.Invoke();
            });

            Utilities.MoveListViewControllerElements(_maxViewController);

            Object.Destroy(togglePrefab);

            Controls[2] = new FilterControl(_container, new Vector2(0f, 0.95f), new Vector2(1f, 0.95f), new Vector2(0.5f, 1f), new Vector2(0f, 24f), new Vector2(0f, -20f),
                                            delegate()
            {
                _container.SetActive(_rankedStagingValue == RankFilterOption.Ranked);

                minToggle.isOn = _minEnabledStagingValue;
                maxToggle.isOn = _maxEnabledStagingValue;
            });

            _isInitialized = true;
        }