/// <summary> /// Generates and displays a list 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 override void Display(object data, bool isRowOdd) { // Perform initial setup for new rows. if (nameLabel == null) { isVisible = true; canFocus = true; isInteractive = true; width = parent.width; height = RowHeight; // Add object name label. nameLabel = AddUIComponent <UILabel>(); nameLabel.width = this.width - 10f; nameLabel.textScale = TextScale; labelX = LeftMargin; } // Set label position and default white colour. nameLabel.relativePosition = new Vector2(LeftMargin, PaddingY); nameLabel.textColor = Color.white; // Set data record and calculate name - depends if 'pure' prefab or BOB random prefab. if (data is BOBRandomPrefab randomPrefab) { // BOB random prefab. if (randomPrefab.prop != null) { thisPrefab = randomPrefab.prop; } else { thisPrefab = randomPrefab.tree; } // Grey colour for random props with missing variants. if (randomPrefab.missingVariant) { nameLabel.textColor = Color.grey; } } else if (data is LoadedListItem loadedItem) { // Loaded list item. thisListItem = loadedItem; thisPrefab = loadedItem.thisPrefab; } else { // Standard PropInfo/TreeInfo prefab. thisPrefab = data as PrefabInfo; } displayName = PrefabLists.GetDisplayName(thisPrefab); nameLabel.text = displayName; // Set initial background as deselected state. Deselect(isRowOdd); }
/// <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 (nameLabel == null) { isVisible = true; canFocus = true; isInteractive = true; width = parent.width; height = RowHeight; // Add object name label. nameLabel = AddUIComponent <UILabel>(); nameLabel.width = this.width - 10f; nameLabel.textScale = TextScale; // Add index text label. indexLabel = AddUIComponent <UILabel>(); indexLabel.width = IndexWidth; indexLabel.textScale = TextScale; indexLabel.relativePosition = new Vector2(IndexLabelX, PaddingY); } // Add line sprite if we need to (initially hidden). if (lineSprite == null) { lineSprite = AddUIComponent <UISprite>(); lineSprite.size = new Vector2(17f, 17f); lineSprite.relativePosition = new Vector2(3f, 3f); lineSprite.Hide(); } // Set initial label position. labelX = LeftMargin; // See if our attached data is a raw PropInfo (e.g an available prop item as opposed to a PropListItem replacment record). thisPrefab = data as PrefabInfo; if (thisPrefab == null) { // Hide any existing line sprites; it will be re-shown as necessary. if (lineSprite != null) { lineSprite.Hide(); // Adjust name label position to accomodate. labelX += PackageMargin; } // Text to display - StringBuilder due to the amount of manipulation we're doing. StringBuilder displayText = new StringBuilder(); // Not a raw PropInfo, so it should be a PropListItem replacement record. // Set local references. thisItem = data as PropListItem; index = thisItem.index; // See if this is a network prop. NetPropListItem thisNetItem = data as NetPropListItem; // Display index number if this is an individual reference. if (thisItem.index >= 0) { indexLabel.text = thisItem.index.ToString(); // Adjust name label position to accomodate. labelX += IndexWidth; } else { indexLabel.text = ""; } bool hasReplacement = false; // Check to see if there's a currently active individual replacement. if (thisItem.individualPrefab != null) { // A replacement is currently active - include it in the text. displayText.Append(PrefabLists.GetDisplayName(thisItem.individualPrefab.name)); // Append probability to the label, if we're showing it. if (thisItem.showProbs) { displayText.Append(" "); displayText.Append(thisItem.individualProb); displayText.Append("%"); } // Set flag. hasReplacement = true; } // If no current individual replacement, check to see if there's a currently active building/network replacement. else if (thisItem.replacementPrefab != null) { // A replacement is currently active - include it in the text. displayText.Append(PrefabLists.GetDisplayName(thisItem.replacementPrefab.name)); // Append probability to the label, if we're showing it. if (thisItem.showProbs) { displayText.Append(" "); displayText.Append(thisItem.replacementProb); displayText.Append("%"); } // Set flag. hasReplacement = true; // Show building replacement sprite. lineSprite.atlas = TextureUtils.LoadSpriteAtlas(thisNetItem == null ? "bob_single_building_small" : "bob_road_small"); lineSprite.spriteName = "normal"; lineSprite.tooltip = Translations.Translate(thisNetItem == null ? "BOB_SPR_SBL" : "BOB_SPR_SNT"); lineSprite.Show(); } // If no current building/network replacement, check to see if any all- replacement is currently active. else if (thisItem.allPrefab != null) { // An all- replacement is currently active; append name to the label. displayText.Append(PrefabLists.GetDisplayName(thisItem.allPrefab.name)); // Append probability if this is not a network item and we're showing probs. if (thisNetItem == null && thisItem.showProbs) { displayText.Append(" "); displayText.Append(thisItem.allProb); displayText.Append("%"); } // Set flag. hasReplacement = true; // Show all- replacement sprite. lineSprite.atlas = TextureUtils.LoadSpriteAtlas(thisNetItem == null ? "bob_buildings_small" : "bob_all_roads_small"); lineSprite.spriteName = "normal"; lineSprite.tooltip = Translations.Translate(thisNetItem == null ? "BOB_SPR_ABL" : "BOB_SPR_ANT"); lineSprite.Show(); } // If no other replacements, chek to see if any pack replacement is currently active else if (thisItem.packagePrefab != null) { // Yes; append name to the label. displayText.Append(PrefabLists.GetDisplayName(thisItem.packagePrefab.name)); // Set flag. hasReplacement = true; // Show package replacement sprite. lineSprite.atlas = TextureUtils.LoadSpriteAtlas("bob_prop_pack_small"); lineSprite.spriteName = "normal"; lineSprite.tooltip = Translations.Translate("BOB_SPR_PCK"); lineSprite.Show(); } // Do we have a replacement? if (hasReplacement) { // Yes; append "was" to the display name. displayText.Append("; "); displayText.Append(Translations.Translate("BOB_ROW_WAS")); displayText.Append(" "); } // Original prefab display name. displayText.Append(PrefabLists.GetDisplayName(thisItem.originalPrefab.name)); // Show original probability in brackets immediately afterwards. if (thisItem.showProbs) { displayText.Append(" ("); displayText.Append(thisItem.originalProb); displayText.Append("%)"); } // Set display text. nameLabel.text = displayText.ToString(); } else { // Attached data is a raw PropInfo; just display its (cleaned-up) name. nameLabel.text = PrefabLists.GetDisplayName(thisPrefab.name); } // Set label position nameLabel.relativePosition = new Vector2(labelX, PaddingY); // Set initial background as deselected state. Deselect(isRowOdd); }
/// <summary> /// Populates a fastlist with a filtered list of loaded trees or props. /// </summary> protected override void LoadedList() { // List of prefabs that have passed filtering. List <LoadedListItem> list = new List <LoadedListItem>(); bool nameFilterActive = !nameFilter.text.IsNullOrWhiteSpace(); if (IsTree) { // Tree - iterate through each prop in our list of loaded prefabs. foreach (TreeInfo loadedTree in PrefabLists.LoadedTrees) { // Set display name. string displayName = PrefabLists.GetDisplayName(loadedTree); // Apply vanilla filtering if selected. if (!hideVanilla.isChecked || !displayName.StartsWith("[v]")) { // Apply name filter. if (!nameFilterActive || displayName.ToLower().Contains(nameFilter.text.Trim().ToLower())) { // Filtering passed - add this prefab to our list. list.Add(new LoadedListItem(loadedTree)); } } } } else { // Prop - iterate through each prop in our list of loaded prefabs. foreach (PropInfo loadedProp in PrefabLists.LoadedProps) { // Set display name. string displayName = PrefabLists.GetDisplayName(loadedProp); // Apply vanilla filtering if selected. if (!hideVanilla.isChecked || !displayName.StartsWith("[v]")) { // Apply name filter. if (!nameFilterActive || displayName.ToLower().Contains(nameFilter.text.Trim().ToLower())) { // Filtering passed - add this prefab to our list. list.Add(new LoadedListItem(loadedProp)); } } } } // Create new object list for fastlist, ordering as approprite. object[] objectArray; switch (loadedSearchStatus) { case (int)OrderBy.NameDescending: objectArray = list.OrderByDescending(item => item.displayName).ToArray(); break; case (int)OrderBy.CreatorAscending: objectArray = list.OrderBy(item => item.creatorName).ToArray(); break; case (int)OrderBy.CreatorDescending: objectArray = list.OrderByDescending(item => item.creatorName).ToArray(); break; default: objectArray = list.OrderBy(item => item.displayName).ToArray(); break; } // Create return fastlist from our filtered list. loadedList.rowsData = new FastList <object> { m_buffer = objectArray, m_size = list.Count }; // Select currently selected prefab, if any. if (selectedLoadedPrefab != null) { loadedList.FindPrefabInItem(selectedLoadedPrefab); } else { // No current selection. loadedList.selectedIndex = -1; } }
/// <summary> /// Performs initial setup /// </summary> /// <param name="parentTransform">Parent transform</param> /// <param name="targetPrefabInfo">Currently selected target prefab</param> internal override void Setup(Transform parentTransform, PrefabInfo targetPrefabInfo) { System.Diagnostics.Stopwatch stopwatch = new System.Diagnostics.Stopwatch(); stopwatch.Start(); // Set target reference. currentBuilding = targetPrefabInfo as BuildingInfo; // Base setup. base.Setup(parentTransform, targetPrefabInfo); Logging.Message("base setup time ", stopwatch.ElapsedMilliseconds.ToString()); // Add group checkbox. indCheck = UIControls.LabelledCheckBox(this, 155f, TitleHeight + Margin, Translations.Translate("BOB_PNL_IND"), 12f, 0.7f); // Does this building have sub-buildings? if (currentBuilding.m_subBuildings != null && currentBuilding.m_subBuildings.Length > 0) { // Yes - create lists of sub-buildings (names and infos). int numSubs = currentBuilding.m_subBuildings.Length; int numChoices = numSubs + 1; string[] subBuildingNames = new string[numChoices]; subBuildings = new BuildingInfo[numChoices]; subBuildingNames[0] = PrefabLists.GetDisplayName(currentBuilding.name); subBuildings[0] = currentBuilding; for (int i = 0; i < numSubs; ++i) { subBuildingNames[i + 1] = PrefabLists.GetDisplayName(currentBuilding.m_subBuildings[i].m_buildingInfo.name); subBuildings[i + 1] = currentBuilding.m_subBuildings[i].m_buildingInfo; } // Add sub-building menu. subBuildingMenu = UIControls.AddLabelledDropDown(this, 155f, indCheck.relativePosition.y + indCheck.height + (Margin / 2f), Translations.Translate("BOB_PNL_SUB"), 250f, 20f, 0.7f, 15, 4); subBuildingMenu.listBackground = "GenericPanelDark"; subBuildingMenu.items = subBuildingNames; subBuildingMenu.selectedIndex = 0; // Sub-building menu event handler. subBuildingMenu.eventSelectedIndexChanged += (control, index) => { // Set current building. currentBuilding = subBuildings[index]; // Reset current items. CurrentTargetItem = null; replacementPrefab = null; // Reset loaded lists. LoadedList(); TargetList(); }; } // Event handler for group checkbox. indCheck.eventCheckChanged += (control, isChecked) => { // Rebuild target list. TargetList(); // Clear selection. targetList.selectedIndex = -1; CurrentTargetItem = null; // Store current group state as most recent state. ModSettings.lastInd = isChecked; // Toggle replace all button visibility. if (isChecked) { replaceAllButton.Hide(); } else { replaceAllButton.Show(); } }; // Set grouped checkbox initial state according to preferences. switch (ModSettings.indDefault) { case 0: // Most recent state. indCheck.isChecked = ModSettings.lastInd; break; case 1: // Grouping off by default. indCheck.isChecked = false; break; case 2: // Grouping on by default. indCheck.isChecked = true; break; } // Populate target list and select target item. TargetList(); Logging.Message("building setup time ", stopwatch.ElapsedMilliseconds.ToString()); // Apply Harmony rendering patches. RenderOverlays.CurrentBuilding = selectedPrefab as BuildingInfo; Patcher.PatchBuildingOverlays(true); stopwatch.Stop(); Logging.Message("Harmony patching time ", stopwatch.ElapsedMilliseconds.ToString()); }
/// <summary> /// Sets the target prefab. /// </summary> /// <param name="targetPrefabInfo">Target prefab to set</param> internal override void SetTarget(PrefabInfo targetPrefabInfo) { // Don't do anything if invalid target, or target hasn't changed. if (!(targetPrefabInfo is BuildingInfo) || selectedPrefab == targetPrefabInfo) { return; } // Base setup. base.SetTarget(targetPrefabInfo); // Set target reference. currentBuilding = SelectedBuilding; // Does this building have sub-buildings? if (currentBuilding.m_subBuildings != null && currentBuilding.m_subBuildings.Length > 0) { // Yes - create lists of sub-buildings (names and infos). int numSubs = currentBuilding.m_subBuildings.Length; int numChoices = numSubs + 1; SubBuildingNames = new string[numChoices]; subBuildings = new BuildingInfo[numChoices]; SubBuildingNames[0] = PrefabLists.GetDisplayName(currentBuilding); subBuildings[0] = currentBuilding; object[] subBuildingIndexes = new object[numChoices]; subBuildingIndexes[0] = 0; for (int i = 0; i < numSubs; ++i) { SubBuildingNames[i + 1] = PrefabLists.GetDisplayName(currentBuilding.m_subBuildings[i].m_buildingInfo); subBuildings[i + 1] = currentBuilding.m_subBuildings[i].m_buildingInfo; subBuildingIndexes[i + 1] = i + 1; } // Add sub-building menu, if it doesn't already exist. if (subBuildingPanel == null) { subBuildingPanel = this.AddUIComponent <UIPanel>(); // Basic behaviour. subBuildingPanel.autoLayout = false; subBuildingPanel.canFocus = true; subBuildingPanel.isInteractive = true; // Appearance. subBuildingPanel.backgroundSprite = "MenuPanel2"; subBuildingPanel.opacity = PanelOpacity; // Size and position. subBuildingPanel.size = new Vector2(200f, PanelHeight - TitleHeight); subBuildingPanel.relativePosition = new Vector2(-205f, TitleHeight); // Heading. UILabel subTitleLabel = UIControls.AddLabel(subBuildingPanel, 5f, 5f, Translations.Translate("BOB_PNL_SUB"), 190f); subTitleLabel.textAlignment = UIHorizontalAlignment.Center; subTitleLabel.relativePosition = new Vector2(5f, (TitleHeight - subTitleLabel.height) / 2f); // List panel. UIPanel subBuildingListPanel = subBuildingPanel.AddUIComponent <UIPanel>(); subBuildingListPanel.relativePosition = new Vector2(Margin, TitleHeight); subBuildingListPanel.width = subBuildingPanel.width - (Margin * 2f); subBuildingListPanel.height = subBuildingPanel.height - TitleHeight - (Margin * 2f); subBuildingList = UIFastList.Create <UISubBuildingRow>(subBuildingListPanel); ListSetup(subBuildingList); // Create return fastlist from our filtered list. subBuildingList.rowsData = new FastList <object> { m_buffer = subBuildingIndexes, m_size = subBuildingIndexes.Length }; } else { // If the sub-building panel has already been created. just make sure it's visible. subBuildingPanel.Show(); } } else { // Otherwise, hide the sub-building panel (if it exists). subBuildingPanel?.Hide(); } // Populate target list and select target item. TargetList(); // Apply Harmony rendering patches. RenderOverlays.CurrentBuilding = selectedPrefab as BuildingInfo; Patcher.PatchBuildingOverlays(true); }