/// <summary> /// Adds panel footer controls (pack name textfield and buttons). /// </summary> /// <param name="yPos">Reference Y position</param> protected void PanelFooter(float yPos) { // Additional space before name textfield. float currentY = yPos + RowHeight; // Pack name textfield. PackNameField = UIControls.BigTextField(panel, 140f, currentY); PackNameField.isEnabled = false; UILabel packNameLabel = UIControls.AddLabel(PackNameField, -100f, (PackNameField.height - 18f) / 2, Translations.Translate("RPR_OPT_EDT_NAM")); // Space for buttons. currentY += 50f; // 'Add new' button. UIButton addNewButton = UIControls.AddButton(panel, 20f, currentY, Translations.Translate("RPR_OPT_NEW")); addNewButton.eventClicked += AddPack; // Save pack button. saveButton = UIControls.AddButton(panel, 250f, currentY, Translations.Translate("RPR_OPT_SAA")); saveButton.eventClicked += Save; // Delete pack button. deleteButton = UIControls.AddButton(panel, 480f, currentY, Translations.Translate("RPR_OPT_DEL")); deleteButton.eventClicked += DeletePack; }
/// <summary> /// Harmony Postfix patch to ZonedBuildingWorldInfoPanel.UpdateBindings to display visitor counts for commercial buildings. /// </summary> public static void Postfix() { // Currently selected building. ushort building = WorldInfoPanel.GetCurrentInstanceID().Building; // Create visit label if it isn't already set up. if (visitLabel == null) { // Get info panel. ZonedBuildingWorldInfoPanel infoPanel = UIView.library.Get <ZonedBuildingWorldInfoPanel>(typeof(ZonedBuildingWorldInfoPanel).Name); // Add current visitor count label. visitLabel = UIControls.AddLabel(infoPanel.component, 65f, 280f, Translations.Translate("RPR_INF_VIS"), textScale: 0.75f); visitLabel.textColor = new Color32(185, 221, 254, 255); visitLabel.font = Resources.FindObjectsOfTypeAll <UIFont>().FirstOrDefault((UIFont f) => f.name == "OpenSans-Regular"); // Position under existing Highly Educated workers count row in line with total workplace count label. UIComponent situationLabel = infoPanel.Find("WorkSituation"); UIComponent workerLabel = infoPanel.Find("HighlyEducatedWorkers"); if (situationLabel != null && workerLabel != null) { visitLabel.absolutePosition = new Vector2(situationLabel.absolutePosition.x, workerLabel.absolutePosition.y + 25f); } else { Logging.Error("couldn't find ZonedBuildingWorldInfoPanel components"); } } // Local references. Building[] buildingBuffer = Singleton <BuildingManager> .instance.m_buildings.m_buffer; BuildingInfo buildingInfo = buildingBuffer[building].Info; // Is this a commercial building? CommercialBuildingAI commercialAI = buildingInfo.GetAI() as CommercialBuildingAI; if (commercialAI == null) { // Not a commercial building - hide the label. visitLabel.Hide(); } else { // Commercial building - show the label. visitLabel.Show(); // Get current visitor count. int aliveCount = 0, totalCount = 0; Citizen.BehaviourData behaviour = new Citizen.BehaviourData(); GetVisitBehaviour(commercialAI, building, ref buildingBuffer[building], ref behaviour, ref aliveCount, ref totalCount); // Display visitor count. visitLabel.text = totalCount.ToString() + " / " + commercialAI.CalculateVisitplaceCount((ItemClass.Level)buildingBuffer[building].m_level, new ColossalFramework.Math.Randomizer(building), buildingBuffer[building].Width, buildingBuffer[building].Length).ToString() + " " + Translations.Translate("RPR_INF_VIS"); } }
/// <summary> /// Adds header controls to the panel. /// </summary> /// <param name="yPos">Relative Y position for buttons</param> /// <returns>Relative Y coordinate below the finished setup</returns> protected override float PanelHeader(float yPos) { // Y position reference. float currentY = yPos + Margin; // Add 'Use legacy by default' header. // Label. UILabel legacyLabel = UIControls.AddLabel(panel, Margin, currentY, Translations.Translate(LegacyCheckLabel), panel.width - Margin, textScale: 0.9f); currentY += legacyLabel.height + 5f; // Use legacy by default for this save check. UICheckBox legacyThisSaveCheck = UIControls.LabelledCheckBox(panel, Margin * 2, currentY, Translations.Translate("RPR_DEF_LTS")); legacyThisSaveCheck.label.wordWrap = true; legacyThisSaveCheck.label.autoSize = false; legacyThisSaveCheck.label.width = 710f; legacyThisSaveCheck.label.autoHeight = true; legacyThisSaveCheck.isChecked = ThisLegacyCategory; legacyThisSaveCheck.eventCheckChanged += (control, isChecked) => { ThisLegacyCategory = isChecked; UpdateControls(); SettingsUtils.SaveSettings(); }; // Use legacy by default for new saves check. currentY += 20f; UICheckBox legacyNewSaveCheck = UIControls.LabelledCheckBox(panel, Margin * 2, currentY, Translations.Translate("RPR_DEF_LAS")); legacyNewSaveCheck.label.wordWrap = true; legacyNewSaveCheck.label.autoSize = false; legacyNewSaveCheck.label.width = 710f; legacyNewSaveCheck.label.autoHeight = true; legacyNewSaveCheck.isChecked = NewLegacyCategory; legacyNewSaveCheck.eventCheckChanged += (control, isChecked) => { NewLegacyCategory = isChecked; UpdateControls(); SettingsUtils.SaveSettings(); }; // Spacer bar. currentY += 25f; UIControls.OptionsSpacer(panel, Margin, currentY, panel.width - (Margin * 2f)); return(currentY + 10f); }
/// <summary> /// Adds a title label across the top of the specified UIComponent. /// </summary> /// <param name="parent">Parent component</param> /// <param name="titleKey">Title translation key</param> /// <returns>Y position below title</returns> internal static float TitleLabel(UIComponent parent, string titleKey) { // Margin. const float Margin = 5f; // Add title. UILabel titleLabel = UIControls.AddLabel(parent, 0f, Margin, Translations.Translate(titleKey), parent.width, 1.5f); titleLabel.textAlignment = UIHorizontalAlignment.Center; titleLabel.font = Resources.FindObjectsOfTypeAll <UIFont>().FirstOrDefault((UIFont f) => f.name == "OpenSans-Semibold"); UIControls.OptionsSpacer(parent, Margin, titleLabel.height + (Margin * 2f), parent.width - (Margin * 2f)); return(Margin + titleLabel.height + Margin + 5f + Margin); }
/// <summary> /// Create the mod calcs panel; we no longer use Start() as that's not sufficiently reliable (race conditions), and is no longer needed, with the new create/destroy process. /// </summary> internal void Setup() { // Basic setup. clipChildren = true; // Title. title = this.AddUIComponent <UILabel>(); title.relativePosition = new Vector3(0, 0); title.textAlignment = UIHorizontalAlignment.Center; title.text = Translations.Translate("RPR_CAL_MOD"); title.textScale = 1.2f; title.autoSize = false; title.width = this.width; // Column titles. UILabel densityTitle = ColumnLabel(this, Translations.Translate("RPR_CAL_DEN"), Margin, ColumnLabelY); UILabel floorTitle = ColumnLabel(this, Translations.Translate("RPR_CAL_BFL"), RightColumnX, ColumnLabelY); // Volumetric calculations panel. volumetricPanel = this.AddUIComponent <UIVolumetricPanel>(); volumetricPanel.relativePosition = new Vector2(0f, BaseCalcY); volumetricPanel.height = this.height - title.height + 80f; volumetricPanel.width = this.width; volumetricPanel.Setup(); // Legacy calculations panel - copy volumetric calculations panel. legacyPanel = this.AddUIComponent <UILegacyCalcs>(); legacyPanel.relativePosition = volumetricPanel.relativePosition; legacyPanel.height = volumetricPanel.height; legacyPanel.width = volumetricPanel.width; legacyPanel.Setup(); legacyPanel.Hide(); // Floor dropdown panel - set size manually to avoid invisible overlap of calculations panel (preventing e.g. tooltips). floorPanel = this.AddUIComponent <UIPanel>(); floorPanel.relativePosition = new Vector2(RightColumnX, MenuY); floorPanel.autoSize = false; floorPanel.width = RightColumnX - this.width; floorPanel.height = BaseCalcY - MenuY; floorPanel.autoLayout = false; floorPanel.clipChildren = false; floorPanel.Show(); // Floor override label (for when floor dropdown menu is hidden). floorOverrideLabel = UIControls.AddLabel(this, RightColumnX, MenuY, Translations.Translate("RPR_CAL_FOV"), this.width - RightColumnX, 0.7f); floorOverrideLabel.Hide(); // Pack dropdowns. popMenu = UIControls.AddDropDown(this, Margin, MenuY, ComponentWidth); floorMenu = UIControls.AddDropDown(floorPanel, 0f, 0f, ComponentWidth); // School dropdown panel. schoolPanel = this.AddUIComponent <UIPanel>(); schoolPanel.relativePosition = new Vector2(Margin, Row2LabelY); schoolPanel.autoSize = false; schoolPanel.autoLayout = false; schoolPanel.clipChildren = false; schoolPanel.height = ApplyX - Row2LabelY; schoolPanel.width = this.width - (Margin * 2); // School panel title and dropdown menu. UILabel schoolTitle = ColumnLabel(schoolPanel, Translations.Translate("RPR_CAL_SCH_PRO"), 0, 0); schoolMenu = UIControls.AddDropDown(schoolPanel, 0f, LabelHeight, ComponentWidth); schoolPanel.Hide(); // Pack descriptions. popDescription = Description(this, Margin, DescriptionY); floorDescription = Description(floorPanel, 0f, DescriptionY - MenuY); schoolDescription = Description(schoolPanel, 0f, LabelHeight + DescriptionY - MenuY); // Apply button. applyButton = UIControls.AddButton(this, ApplyX, BaseSaveY, Translations.Translate("RPR_OPT_SAA"), ButtonWidth); applyButton.eventClicked += (control, clickEvent) => ApplySettings(); // Dropdown event handlers. popMenu.eventSelectedIndexChanged += (component, index) => UpdatePopSelection(index); floorMenu.eventSelectedIndexChanged += (component, index) => UpdateFloorSelection(index); schoolMenu.eventSelectedIndexChanged += (component, index) => UpdateSchoolSelection(index); // Add school multiplier slider (starts hidden). multSlider = AddSliderWithMultipler(schoolPanel, string.Empty, 1f, 5f, 0.5f, ModSettings.DefaultSchoolMult, (value) => UpdateMultiplier(value), ComponentWidth); multSlider.parent.relativePosition = new Vector2(RightColumnX, 10f); multSlider.parent.Hide(); // Muliplier checkbox. multCheck = UIControls.LabelledCheckBox(schoolPanel, RightColumnX, 18f, Translations.Translate("RPR_CAL_CAP_OVR")); // Multiplier default label. multDefaultLabel = UIControls.AddLabel(schoolPanel, RightColumnX + 21f, 40f, Translations.Translate("RPR_CAL_CAP_DEF") + " x" + ModSettings.DefaultSchoolMult, textScale: 0.8f); // Multplier checkbox event handler. multCheck.eventCheckChanged += (control, isChecked) => MultiplierCheckChanged(isChecked); }
/// <summary> /// Create the panel; we no longer use Start() as that's not sufficiently reliable (race conditions), and is no longer needed, with the new create/destroy process. /// </summary> internal void Setup() { // Generic setup. isVisible = true; canFocus = true; isInteractive = true; backgroundSprite = "UnlockingPanel"; autoLayout = false; autoSize = false; width = parent.width; height = 395f; builtinKeyNavigation = true; clipChildren = true; // Labels. floorHeightLabel = AddVolumetricLabel(this, "RPR_CAL_VOL_FLH", RightColumn, Row1, "RPR_CAL_VOL_FLH_TIP"); firstMinLabel = AddVolumetricLabel(this, "RPR_CAL_VOL_FMN", RightColumn, Row2, "RPR_CAL_VOL_FMN_TIP"); firstExtraLabel = AddVolumetricLabel(this, "RPR_CAL_VOL_FMX", RightColumn, Row3, "RPR_CAL_VOL_FMX_TIP"); numFloorsLabel = AddVolumetricLabel(this, "RPR_CAL_VOL_FLR", RightColumn, Row5, "RPR_CAL_VOL_FLR_TIP"); floorAreaLabel = AddVolumetricLabel(this, "RPR_CAL_VOL_TFA", RightColumn, Row6, "RPR_CAL_VOL_TFA_TIP"); totalHomesLabel = AddVolumetricLabel(this, "RPR_CAL_VOL_HOU", RightColumn, Row7, "RPR_CAL_VOL_UTS_TIP"); totalJobsLabel = AddVolumetricLabel(this, "RPR_CAL_VOL_WOR", RightColumn, Row7, "RPR_CAL_VOL_UTS_TIP"); totalStudentsLabel = AddVolumetricLabel(this, "RPR_CAL_VOL_STU", RightColumn, Row7, "RPR_CAL_VOL_UTS_TIP"); visitCountLabel = AddVolumetricLabel(this, "RPR_CAL_VOL_VIS", RightColumn, Row8, "RPR_CAL_VOL_VIS_TIP"); productionLabel = AddVolumetricLabel(this, "RPR_CAL_VOL_PRD", RightColumn, Row8, "RPR_CAL_VOL_PRD_TIP"); unitsLabel = AddVolumetricLabel(this, "RPR_CAL_VOL_UNI", LeftColumn, Row2, "RPR_CAL_VOL_UNI_TIP"); emptyPercentLabel = AddVolumetricLabel(this, "RPR_CAL_VOL_EPC", LeftColumn, Row2, "RPR_CAL_VOL_EPC_TIP"); emptyAreaLabel = AddVolumetricLabel(this, "RPR_CAL_VOL_EMP", LeftColumn, Row3, "RPR_CAL_VOL_EMP_TIP"); perLabel = AddVolumetricLabel(this, "RPR_CAL_VOL_APU", LeftColumn, Row4, "RPR_CAL_VOL_APU_TIP"); schoolWorkerLabel = AddVolumetricLabel(this, "RPR_CAL_SCH_WKR", LeftColumn, Row7, "RPR_CAL_SCH_WKR_TIP"); costLabel = AddVolumetricLabel(this, "RPR_CAL_SCH_CST", LeftColumn, Row8, "RPR_CAL_SCH_CST_TIP"); // Intially hidden (just to avoid ugliness if no building is selected). totalHomesLabel.Hide(); totalStudentsLabel.Hide(); // Fixed population checkbox. fixedPopCheckBox = CalcCheckBox(this, "RPR_CAL_VOL_FXP", LeftColumn, Row1, "RPR_CAL_VOL_FXP_TIP"); fixedPopCheckBox.isInteractive = false; fixedPopCheckBox.Disable(); // Multi-floor units checkbox. multiFloorCheckBox = CalcCheckBox(this, "RPR_CAL_VOL_MFU", LeftColumn, Row5, "RPR_CAL_VOL_MFU_TIP"); multiFloorCheckBox.isInteractive = false; multiFloorCheckBox.Disable(); // Ignore first floor checkbox. ignoreFirstCheckBox = CalcCheckBox(this, "RPR_CAL_VOL_IGF", RightColumn, Row4, "RPR_CAL_VOL_IGF_TIP"); ignoreFirstCheckBox.isInteractive = false; ignoreFirstCheckBox.Disable(); // Message label. messageLabel = UIControls.AddLabel(this, Margin, MessageY, string.Empty); // Floor list - attached to root panel as scrolling and interactivity can be unreliable otherwise. floorsList = UIFastList.Create <UIFloorRow>(BuildingDetailsPanel.Panel); // Size, appearance and behaviour. floorsList.backgroundSprite = "UnlockingPanel"; floorsList.width = this.width; floorsList.isInteractive = true; floorsList.canSelect = false; floorsList.rowHeight = 20; floorsList.autoHideScrollbar = true;; ResetFloorListPosition(); // Data. floorsList.rowsData = new FastList <object>(); floorsList.selectedIndex = -1; // Toggle floorsList visibility on this panel's visibility change (because floorsList is attached to root panel). this.eventVisibilityChanged += (control, isVisible) => floorsList.isVisible = isVisible; }