/// <summary>
        /// Creates the panel object in-game and displays it.
        /// </summary>
        internal static void Open(BuildingInfo selected = null)
        {
            try
            {
                // If no instance already set, create one.
                if (uiGameObject == null)
                {
                    // Give it a unique name for easy finding with ModTools.
                    uiGameObject = new GameObject("RealPopBuildingDetails");
                    uiGameObject.transform.parent = UIView.GetAView().transform;

                    _panel = uiGameObject.AddComponent <UIBuildingDetails>();

                    // Set up panel.
                    Panel.Setup();
                }

                // Select appropriate building if there's a preselection.
                if (selected != null)
                {
                    Panel.SelectBuilding(selected);
                }

                Panel.Show();
            }
            catch (Exception e)
            {
                Debugging.LogException(e);
                return;
            }
        }
        /// <summary>
        /// Render and show a preview of a building.
        /// </summary>
        /// <param name="building">The building to render</param>
        public void Show(BuildingInfo building)
        {
            // If we're already showing this building, nothing further needs to be done.
            if (building == currentSelection)
            {
                return;
            }

            // Update current selection to the new building.
            currentSelection = building;

            // Generate render if there's a selection with a mesh.
            if (currentSelection != null && currentSelection.m_mesh != null)
            {
                // Set default values.
                previewRender.CameraRotation = 210f;
                previewRender.Zoom           = 4f;
                previewRender.Mesh           = currentSelection.m_mesh;
                previewRender.material       = currentSelection.m_material;

                RenderPreview();

                // Set background.
                previewSprite.texture     = previewRender.Texture;
                noPreviewSprite.isVisible = false;
            }
            else
            {
                // No valid current selection with a mesh; reset background.
                previewSprite.texture     = null;
                noPreviewSprite.isVisible = true;
            }

            // Hide any empty building names.
            if (building == null)
            {
                buildingName.isVisible = false;
            }
            else
            {
                // Set and show building name.
                buildingName.isVisible = true;
                buildingName.text      = UIBuildingDetails.GetDisplayName(currentSelection.name);
                UIUtils.TruncateLabel(buildingName, width - 45);
                buildingName.autoHeight = true;
            }
        }
        /// <summary>
        /// Generates and displays a building row.
        /// </summary>
        /// <param name="data">Object to list</param>
        /// <param name="isRowOdd">If the row is an odd-numbered row (for background banding)</param>
        public void Display(object data, bool isRowOdd)
        {
            // Perform initial setup for new rows.
            if (buildingName == null)
            {
                isVisible     = true;
                canFocus      = true;
                isInteractive = true;
                width         = parent.width;
                height        = 40;

                buildingName       = AddUIComponent <UILabel>();
                buildingName.width = 200;

                // Checkbox to indicate which items have custom settings.
                hasCustom                  = AddUIComponent <UISprite>();
                hasCustom.size             = new Vector2(20, 20);
                hasCustom.relativePosition = new Vector3(340, 10);
                hasCustom.tooltip          = Translations.Translate("RPR_CUS_HAS");
            }

            // Set selected building.
            thisBuilding      = data as BuildingInfo;
            buildingName.text = UIBuildingDetails.GetDisplayName(thisBuilding.name);

            // Update custom settings checkbox to correct state.
            if (ExternalCalls.GetResidential(thisBuilding) > 0 || ExternalCalls.GetWorker(thisBuilding) > 0)
            {
                // Custom value found.
                hasCustom.spriteName = "AchievementCheckedTrue";
            }
            else
            {
                // No custom value.
                hasCustom.spriteName = "AchievementCheckedFalse";
            }

            // Set initial background as deselected state.
            Deselect(isRowOdd);
        }
        /// <summary>
        /// Generates the list of buildings depending on current filter settings.
        /// </summary>
        /// <returns>List of buildings</returns>
        private FastList <object> GenerateFastList()
        {
            // List to store all building prefabs that pass the filter.
            List <BuildingInfo> filteredList = new List <BuildingInfo>();

            // Iterate through all loaded building prefabs and add them to the list if they meet the filter conditions.
            for (uint i = 0; i < PrefabCollection <BuildingInfo> .LoadedCount(); i++)
            {
                BuildingInfo item = PrefabCollection <BuildingInfo> .GetLoaded(i);

                // Skip any null or invalid prefabs.
                if (item?.name == null)
                {
                    continue;
                }

                // Apply zone type filters.
                ItemClass.Service    service    = item.GetService();
                ItemClass.SubService subService = item.GetSubService();

                // Laid out this way for clear visibility.
                if (subService == ItemClass.SubService.ResidentialLow && filterBar.categoryToggles[(int)BuildingCategories.ResidentialLow].isChecked)
                {
                }
                else if (subService == ItemClass.SubService.ResidentialHigh && filterBar.categoryToggles[(int)BuildingCategories.ResidentialHigh].isChecked)
                {
                }
                else if (subService == ItemClass.SubService.CommercialLow && filterBar.categoryToggles[(int)BuildingCategories.CommercialLow].isChecked)
                {
                }
                else if (subService == ItemClass.SubService.CommercialHigh && filterBar.categoryToggles[(int)BuildingCategories.CommercialHigh].isChecked)
                {
                }
                else if (service == ItemClass.Service.Office && filterBar.categoryToggles[(int)BuildingCategories.Office].isChecked)
                {
                }
                else if (service == ItemClass.Service.Industrial && filterBar.categoryToggles[(int)BuildingCategories.Industrial].isChecked)
                {
                }
                else if (subService == ItemClass.SubService.CommercialTourist && filterBar.categoryToggles[(int)BuildingCategories.Tourism].isChecked)
                {
                }
                else if (subService == ItemClass.SubService.CommercialLeisure && filterBar.categoryToggles[(int)BuildingCategories.Leisure].isChecked)
                {
                }
                else if (subService == ItemClass.SubService.CommercialEco && filterBar.categoryToggles[(int)BuildingCategories.Organic].isChecked)
                {
                }
                else if ((subService == ItemClass.SubService.ResidentialLowEco || subService == ItemClass.SubService.ResidentialHighEco) && filterBar.categoryToggles[(int)BuildingCategories.Selfsufficient].isChecked)
                {
                }
                else
                {
                    // If we've gotten here, then we've matched no categories; move on to next item.
                    continue;
                }

                // Filter by name.
                if (!filterBar.nameFilter.text.Trim().IsNullOrWhiteSpace() && !GetDisplayName(item.name).ToLower().Contains(filterBar.nameFilter.text.Trim().ToLower()))
                {
                    continue;
                }

                // Finally!  We've got an item that's passed all filters; add it to the list.
                filteredList.Add(item);
            }

            // Create return list with our filtered list, sorted alphabetically.
            FastList <object> fastList = new FastList <object>();

            fastList.m_buffer = filteredList.OrderBy(x => UIBuildingDetails.GetDisplayName(x.name)).ToArray();
            fastList.m_size   = filteredList.Count;
            return(fastList);
        }