/// <summary> /// Updates button states (enabled/disabled) according to current control states. /// </summary> protected override void UpdateButtonStates() { // Disable by default (selectively (re)-enable if eligible). replaceButton.Disable(); revertButton.Disable(); // Buttons are only enabled if a current target item is selected. if (CurrentTargetItem != null) { // Replacement requires a valid replacement selection. if (ReplacementPrefab != null) { replaceButton.Enable(); } // Reversion requires a currently active replacement. if (CurrentTargetItem.replacementPrefab != null) { revertButton.Enable(); revertButton.tooltip = Translations.Translate("BOB_PNL_REV_UND"); } else { revertButton.tooltip = Translations.Translate("BOB_PNL_REV_TIP"); } } }
/// <summary> /// Adds an icon toggle checkbox. /// </summary> /// <param name="parent">Parent component</param> /// <param name="xPos">Relative X position</param> /// <param name="yPos">Relative Y position</param> /// <param name="atlasName">Atlas name (for loading from file)</param> /// <param name="tooltipKey">Tooltip translation key</param> /// <returns>New checkbox</returns> protected UICheckBox IconToggleCheck(UIComponent parent, float xPos, float yPos, string atlasName, string tooltipKey) { // Size and position. UICheckBox checkBox = parent.AddUIComponent <UICheckBox>(); checkBox.width = ToggleSize; checkBox.height = ToggleSize; checkBox.clipChildren = true; checkBox.relativePosition = new Vector2(xPos, yPos); // Checkbox sprites. UISprite sprite = checkBox.AddUIComponent <UISprite>(); sprite.name = "UncheckedSprite"; sprite.atlas = TextureUtils.LoadSpriteAtlas(atlasName); sprite.spriteName = "disabled"; sprite.size = new Vector2(ToggleSize, ToggleSize); sprite.relativePosition = Vector3.zero; checkBox.checkedBoxObject = sprite.AddUIComponent <UISprite>(); ((UISprite)checkBox.checkedBoxObject).atlas = TextureUtils.LoadSpriteAtlas(atlasName); ((UISprite)checkBox.checkedBoxObject).spriteName = "pressed"; checkBox.checkedBoxObject.size = new Vector2(ToggleSize, ToggleSize); checkBox.checkedBoxObject.relativePosition = Vector3.zero; checkBox.tooltip = Translations.Translate(tooltipKey); return(checkBox); }
/// <summary> /// Adds mod options tab to tabstrip. /// </summary> /// <param name="tabStrip">Tab strip to add to</param> /// <param name="tabIndex">Index number of tab</param> internal GeneralOptionsPanel(UITabstrip tabStrip, int tabIndex) { // Add tab and helper. UIPanel panel = PanelUtils.AddTab(tabStrip, Translations.Translate("BOB_OPT_GEN"), tabIndex); UIHelper helper = new UIHelper(panel); panel.autoLayout = true; // Language dropdown. UIDropDown languageDrop = UIControls.AddPlainDropDown(panel, Translations.Translate("TRN_CHOICE"), Translations.LanguageList, Translations.Index); languageDrop.eventSelectedIndexChanged += (control, index) => Translations.Index = index; // Hotkey control. panel.gameObject.AddComponent <OptionsKeymapping>(); // Default grouping behaviour. string[] groupItems = new string[] { Translations.Translate("BOB_PER_LST"), Translations.Translate("BOB_PER_SIN"), Translations.Translate("BOB_PER_GRP") }; UIDropDown groupDropDown = UIControls.AddPlainDropDown(panel, Translations.Translate("BOB_PER_IND"), groupItems, ModSettings.indDefault, 350f); groupDropDown.eventSelectedIndexChanged += (control, index) => ModSettings.indDefault = index; // Rember last position. UICheckBox rememberPosCheck = UIControls.AddPlainCheckBox(panel, Translations.Translate("BOB_OPT_POS")); rememberPosCheck.isChecked = ModSettings.rememberPosition; rememberPosCheck.eventCheckChanged += (control, isChecked) => ModSettings.rememberPosition = isChecked; }
/// <summary> /// Sets the target prefab. /// </summary> /// <param name="targetPrefabInfo">Target prefab to set</param> internal override void SetTarget(PrefabInfo targetPrefabInfo) { // Base setup. base.SetTarget(targetPrefabInfo); // Title label. SetTitle(Translations.Translate("BOB_NAM")); // Replace text label. UILabel replaceLabel = AddUIComponent <UILabel>(); replaceLabel.text = Translations.Translate("BOB_PNL_REP"); replaceLabel.relativePosition = new Vector2(MidControlX, ReplaceLabelY); // Set trees/props. propCheck.isChecked = !InitialTreeCheckedState; treeCheck.isChecked = InitialTreeCheckedState; // Populate target list and select target item. TargetList(); targetList.FindTargetItem(targetPrefabInfo); // Update button states. UpdateButtonStates(); // Apply Harmony rendering patches. Patcher.PatchMapOverlays(true); }
/// <summary> /// Adds a BOB slider to the specified component. /// </summary> /// <param name="parent">Parent component</param> /// <param name="xPos">Relative X position</param /// <param name="yPos">Relative Y position</param /// <param name="width">Slider width</param> /// <param name="labelKey">Text label translation key</param> /// <param name="minValue">Minimum displayed value</param /// <param name="maxValue">Maximum displayed value</param> /// <param name="stepSize">Minimum slider step size</param> /// <param name="name">Slider name</param> /// <returns>New BOBSlider</returns> protected BOBSlider AddBOBSlider(UIComponent parent, float xPos, float yPos, float width, string labelKey, float minValue, float maxValue, float stepSize, string name) { const float SliderY = 18f; const float ValueY = 3f; const float LabelY = -13f; const float SliderHeight = 18f; const float FloatTextFieldWidth = 45f; const float IntTextFieldWidth = 38f; // Slider control. BOBSlider newSlider = parent.AddUIComponent <BOBSlider>(); newSlider.size = new Vector2(width, SliderHeight); newSlider.relativePosition = new Vector2(xPos, yPos + SliderY); newSlider.name = name; // Value field - added to parent, not to slider, otherwise slider catches all input attempts. Integer textfields (stepsize == 1) have shorter widths. float textFieldWidth = stepSize == 1 ? IntTextFieldWidth : FloatTextFieldWidth; UITextField valueField = UIControls.TinyTextField(parent, xPos + Margin + newSlider.width - textFieldWidth, yPos + ValueY, textFieldWidth); // Title label. UILabel titleLabel = UIControls.AddLabel(newSlider, 0f, LabelY, Translations.Translate(labelKey), textScale: 0.7f); // Autoscale tile label text, with minimum size 0.35. while (titleLabel.width > newSlider.width - textFieldWidth && titleLabel.textScale > 0.35f) { titleLabel.textScale -= 0.05f; } // Slider track. UISlicedSprite sliderSprite = newSlider.AddUIComponent <UISlicedSprite>(); sliderSprite.atlas = TextureUtils.InGameAtlas; sliderSprite.spriteName = "BudgetSlider"; sliderSprite.size = new Vector2(newSlider.width, 9f); sliderSprite.relativePosition = new Vector2(0f, 4f); // Slider thumb. UISlicedSprite sliderThumb = newSlider.AddUIComponent <UISlicedSprite>(); sliderThumb.atlas = TextureUtils.InGameAtlas; sliderThumb.spriteName = "SliderBudget"; newSlider.thumbObject = sliderThumb; // Set references. newSlider.ValueField = valueField; // Event handler for textfield. newSlider.ValueField.eventTextSubmitted += newSlider.OnTextSubmitted; // Set initial values. newSlider.StepSize = stepSize; newSlider.maxValue = maxValue; newSlider.minValue = minValue; newSlider.TrueValue = 0f; return(newSlider); }
/// <summary> /// Prop check event handler. /// </summary> /// <param name="control">Calling component (unused)</param> /// <param name="isChecked">New checked state</param> protected override void PropCheckChanged(UIComponent control, bool isChecked) { base.PropCheckChanged(control, isChecked); // Toggle replace button atlas. replaceButton.atlas = isChecked ? TextureUtils.LoadSpriteAtlas("BOB-Props") : TextureUtils.LoadSpriteAtlas("BOB-Trees"); replaceButton.tooltip = Translations.Translate(ReplaceTooltipKey); }
/// <summary> /// Constructor. /// </summary> internal BOBPanelBase() { // Basic behaviour. autoLayout = false; canFocus = true; isInteractive = true; // Appearance. backgroundSprite = "MenuPanel2"; opacity = PanelOpacity; // Size. size = new Vector2(PanelWidth, PanelHeight); // Drag bar. UIDragHandle dragHandle = AddUIComponent <UIDragHandle>(); dragHandle.width = this.width - 50f; dragHandle.height = this.height; dragHandle.relativePosition = Vector3.zero; dragHandle.target = this; // Close button. UIButton closeButton = AddUIComponent <UIButton>(); closeButton.relativePosition = new Vector2(width - 35, 2); closeButton.normalBgSprite = "buttonclose"; closeButton.hoveredBgSprite = "buttonclosehover"; closeButton.pressedBgSprite = "buttonclosepressed"; closeButton.eventClick += (component, clickEvent) => CloseEvent(); // Name filter. nameFilter = UIControls.SmallLabelledTextField(this, width - 200f - Margin, TitleHeight + Margin, Translations.Translate("BOB_FIL_NAME")); // Event handlers for name filter textbox. nameFilter.eventTextChanged += (control, text) => LoadedList(); nameFilter.eventTextSubmitted += (control, text) => LoadedList(); // Vanilla filter. hideVanilla = UIControls.LabelledCheckBox((UIComponent)(object)this, nameFilter.relativePosition.x, nameFilter.relativePosition.y + nameFilter.height + (Margin / 2f), Translations.Translate("BOB_PNL_HDV"), 12f, 0.7f); hideVanilla.isChecked = ModSettings.hideVanilla; hideVanilla.eventCheckChanged += VanillaCheckChanged; // Mode label. modeLabel = UIControls.AddLabel(this, Margin, ToggleHeaderY, Translations.Translate("BOB_PNL_MOD"), textScale: 0.8f); // Tree/Prop checkboxes. propCheck = IconToggleCheck(this, Margin, ToggleY, "BOB-PropsSmall", "BOB_PNL_PRP"); treeCheck = IconToggleCheck(this, Margin + ToggleSize, ToggleY, "BOB-TreesSmall", "BOB_PNL_TRE"); propCheck.isChecked = !InitialTreeCheckedState; treeCheck.isChecked = InitialTreeCheckedState; propCheck.eventCheckChanged += PropCheckChanged; treeCheck.eventCheckChanged += TreeCheckChanged; }
/// <summary> /// Adds mod options tab to tabstrip. /// </summary> /// <param name="tabStrip">Tab strip to add to</param> /// <param name="tabIndex">Index number of tab</param> internal RuiningOptionsPanel(UITabstrip tabStrip, int tabIndex) { // Add tab and helper. UIPanel panel = PanelUtils.AddTab(tabStrip, Translations.Translate("BOB_OPT_RUI"), tabIndex); UIHelper helper = new UIHelper(panel); panel.autoLayout = true; UIHelperBase ruinGroup = helper.AddGroup(Translations.Translate("BOB_OPT_RGL")); // Checkboxes. ruinGroup.AddCheckbox(Translations.Translate("BOB_OPT_RRT"), ModSettings.StopTreeRuining, (value) => ModSettings.StopTreeRuining = value); ruinGroup.AddCheckbox(Translations.Translate("BOB_OPT_RRP"), ModSettings.StopPropRuining, (value) => ModSettings.StopPropRuining = value); }
/// <summary> /// Setup this control /// Called by Unity immediately before the first update. /// </summary> public void Start() { // Get the template from the game and attach it here. UIPanel uIPanel = component.AttachUIComponent(UITemplateManager.GetAsGameObject("KeyBindingTemplate")) as UIPanel; // Find our sub-components. label = uIPanel.Find <UILabel>("Name"); button = uIPanel.Find <UIButton>("Binding"); // Attach our event handlers. button.eventKeyDown += (control, keyEvent) => OnKeyDown(keyEvent); button.eventMouseDown += (control, mouseEvent) => OnMouseDown(mouseEvent); // Set label and button text. label.text = Translations.Translate("BOB_OPT_KEY"); button.text = SavedInputKey.ToLocalizedString("KEYNAME", ModSettings.CurrentHotkey); }
/// <summary> /// Constructor - creates panel. /// </summary> internal BOBScalePanel() { // Default position - centre in screen. relativePosition = new Vector2(Mathf.Floor((GetUIView().fixedWidth - width) / 2), Mathf.Floor((GetUIView().fixedHeight - height) / 2)); // Title label. SetTitle(Translations.Translate("BOB_NAM") + " : " + Translations.Translate("BOB_SCA_TIT")); // Minimum scale slider. minScaleSlider = AddBOBSlider(this, ControlX, MinOffsetY, ControlWidth - (Margin * 2f), "BOB_SCA_MIN", 0.5f, 2f, 0.5f, "MinScale"); minScaleSlider.eventValueChanged += MinScaleValue; minScaleSlider.value = 1f; maxScaleSlider = AddBOBSlider(this, ControlX, MaxOffsetY + 40f, ControlWidth - (Margin * 2f), "BOB_SCA_MAX", 0.5f, 2f, 0.5f, "MaxScale"); maxScaleSlider.eventValueChanged += MaxScaleValue; maxScaleSlider.value = 1f; // Revert button. revertButton = UIControls.AddSmallerButton(this, ControlX, RevertY, Translations.Translate("BOB_PNL_REV"), ControlWidth); revertButton.eventClicked += Revert; revertButton.Disable(); // Loaded prop list. UIPanel loadedPanel = AddUIComponent <UIPanel>(); loadedPanel.width = LoadedWidth; loadedPanel.height = ListHeight; loadedPanel.relativePosition = new Vector2(LoadedX, ListY); loadedList = UIFastList.Create <UILoadedScalingPropRow>(loadedPanel); ListSetup(loadedList); // Order button. loadedNameButton = ArrowButton(this, LoadedX + 10f, ListY - 20f); loadedNameButton.eventClicked += SortLoaded; loadedCreatorButton = ArrowButton(this, LoadedX + UILoadedScalingPropRow.CreatorX + 10f, ListY - 20f); loadedCreatorButton.eventClicked += SortLoaded; // Default is name ascending. SetFgSprites(loadedNameButton, "IconUpArrow2"); // Populate loaded list. LoadedList(); // Bring to front. BringToFront(); }
/// <summary> /// Adds mod options tab to tabstrip. /// </summary> /// <param name="tabStrip">Tab strip to add to</param> /// <param name="tabIndex">Index number of tab</param> internal VisualOptionsPanel(UITabstrip tabStrip, int tabIndex) { // Add tab and helper. UIPanel panel = PanelUtils.AddTab(tabStrip, Translations.Translate("BOB_OPT_VIS"), tabIndex); UIHelper helper = new UIHelper(panel); panel.autoLayout = true; // Ruining. UIHelperBase ruinGroup = helper.AddGroup(Translations.Translate("BOB_OPT_RUI") + " - " + Translations.Translate("BOB_OPT_RGL")); ruinGroup.AddCheckbox(Translations.Translate("BOB_OPT_RRT"), ModSettings.StopTreeRuining, (value) => ModSettings.StopTreeRuining = value); ruinGroup.AddCheckbox(Translations.Translate("BOB_OPT_RRP"), ModSettings.StopPropRuining, (value) => ModSettings.StopPropRuining = value); // Electrical wire thickness. UIHelperBase wiresGroup = helper.AddGroup(Translations.Translate("BOB_OPT_WIR")); wiresGroup.AddCheckbox(Translations.Translate("BOB_OPT_WTH"), ModSettings.ThinnerWires, (value) => ModSettings.ThinnerWires = value); }
/// <summary> /// Initialise the tool. /// Called by unity when the tool is created. /// </summary> protected override void Awake() { base.Awake(); // Initializae PropAPI. PropAPI.Initialize(); // Load cursors. lightCursor = TextureUtils.LoadCursor("BOB-CursorLight.png"); darkCursor = TextureUtils.LoadCursor("BOB-CursorDark.png"); m_cursor = darkCursor; // Create new UUI button. UIComponent uuiButton = UUIHelpers.RegisterToolButton( name: nameof(BOBTool), groupName: null, // default group tooltip: Translations.Translate("BOB_NAM"), tool: this, icon: UUIHelpers.LoadTexture(UUIHelpers.GetFullPath <BOBMod>("Resources", "BOB-UUI.png")) //hotkeys: new UUIHotKeys { ActivationKey = ModSettings.PanelSavedKey } ); }
/// <summary> /// Adds an icon-style button to the specified component at the specified coordinates. /// </summary> /// <param name="parent">Parent UIComponent</param> /// <param name="xPos">Relative X position</param> /// <param name="yPos">Relative Y position</param> /// <param name="size">Button size (square)</param> /// <param name="tooltipKey">Tooltip translation key</param> /// <param name="atlas">Icon atlas</param> /// <returns>New UIButton</returns> protected UIButton AddIconButton(UIComponent parent, float xPos, float yPos, float size, string tooltipKey, UITextureAtlas atlas) { UIButton newButton = parent.AddUIComponent <UIButton>(); // Size and position. newButton.relativePosition = new Vector2(xPos, yPos); newButton.height = size; newButton.width = size; // Appearance. newButton.atlas = atlas; newButton.normalFgSprite = "normal"; newButton.focusedFgSprite = "normal"; newButton.hoveredFgSprite = "hovered"; newButton.disabledFgSprite = "disabled"; newButton.pressedFgSprite = "pressed"; // Tooltip. newButton.tooltip = Translations.Translate(tooltipKey); return(newButton); }
/// <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) { try { // Perform basic panel setup. base.Setup(parentTransform, targetPrefabInfo); Logging.Message("commencing InfoPanel setup"); // Replace all button. replaceAllButton = AddIconButton(this, MidControlX + replaceButton.width, ReplaceY, BigIconSize, ReplaceAllTooltipKey, ReplaceAllAtlas); replaceAllButton.eventClicked += ReplaceAll; // Probability. UIPanel probabilityPanel = Sliderpanel(this, MidControlX, ProbabilityY, SliderHeight); probabilitySlider = AddBOBSlider(probabilityPanel, 0f, "BOB_PNL_PRB", 0, 100, 1); probabilitySlider.TrueValue = 100f; probabilitySlider.LimitToVisible = true; // Angle. UIPanel anglePanel = Sliderpanel(this, MidControlX, AngleY, SliderHeight); angleSlider = AddBOBSlider(anglePanel, 0f, "BOB_PNL_ANG", -180, 180, 1); Logging.Message("Creating offset panel"); // Offset panel. UIPanel offsetPanel = Sliderpanel(this, MidControlX, OffsetPanelY, OffsetPanelHeight); UILabel offsetLabel = UIControls.AddLabel(offsetPanel, 0f, OffsetLabelY, Translations.Translate("BOB_PNL_OFF")); offsetLabel.textAlignment = UIHorizontalAlignment.Center; while (offsetLabel.width > MidControlWidth) { offsetLabel.textScale -= 0.05f; offsetLabel.PerformLayout(); } offsetLabel.relativePosition = new Vector2((offsetPanel.width - offsetLabel.width) / 2f, OffsetLabelY); // Offset sliders. xSlider = AddBOBSlider(offsetPanel, XOffsetY, "BOB_PNL_XOF", -8f, 8f, 0.01f); ySlider = AddBOBSlider(offsetPanel, YOffsetY, "BOB_PNL_YOF", -8f, 8f, 0.01f); zSlider = AddBOBSlider(offsetPanel, ZOffsetY, "BOB_PNL_ZOF", -8f, 8f, 0.01f); // Set initial button states. UpdateButtonStates(); // Normal/random toggle. randomCheck = UIControls.LabelledCheckBox((UIComponent)(object)this, hideVanilla.relativePosition.x, hideVanilla.relativePosition.y + hideVanilla.height + (Margin / 2f), Translations.Translate("BOB_PNL_RSW"), 12f, 0.7f); randomCheck.eventCheckChanged += RandomCheckChanged; // Random settings button. UIButton randomButton = UIControls.EvenSmallerButton(this, RightX - 200f, TitleHeight + Margin + 20f, Translations.Translate("BOB_PNL_RST")); randomButton.eventClicked += (control, clickEvent) => BOBRandomPanel.Create(); Logging.Message("InfoPanel setup completed"); } catch (Exception e) { Logging.LogException(e, "exception setting up InfoPanel"); } }
/// <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> /// 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) { // Set target reference. currentNet = targetPrefabInfo as NetInfo; // Base setup. base.Setup(parentTransform, targetPrefabInfo); // Add pack button. UIButton packButton = UIControls.EvenSmallerButton(this, RightX - 200f, TitleHeight + (Margin / 2f), Translations.Translate("BOB_PNL_PKB")); packButton.eventClicked += (component, clickEvent) => PackPanelManager.Create(); // Populate target list and select target item. TargetList(); // Apply Harmony rendering patches. Patcher.PatchNetworkOverlays(true); }
/// <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); }
/// <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> /// Called by the game when level loading is complete. /// </summary> /// <param name="mode">Loading mode (e.g. game, editor, scenario, etc.)</param> public override void OnLevelLoaded(LoadMode mode) { Logging.Message("commencing loading checks"); base.OnLevelLoaded(mode); // Don't do anything further if we're not operating. if (!isModEnabled) { Logging.Message("exiting"); return; } // Check to see that Harmony 2 was properly loaded. if (!Patcher.Patched) { // Harmony 2 wasn't loaded; abort. Logging.Error("Harmony patches not applied; aborting"); isModEnabled = false; // Display warning message. ListMessageBox harmonyBox = MessageBoxBase.ShowModal <ListMessageBox>(); // Key text items. harmonyBox.AddParas(Translations.Translate("ERR_HAR0"), Translations.Translate("BOB_ERR_HAR"), Translations.Translate("BOB_ERR_FAT"), Translations.Translate("ERR_HAR1")); // List of dot points. harmonyBox.AddList(Translations.Translate("ERR_HAR2"), Translations.Translate("ERR_HAR3")); // Closing para. harmonyBox.AddParas(Translations.Translate("MES_PAGE")); // Don't do anything further. return; } Logging.Message("loading checks passed"); // Build lists of loaded prefabs. PrefabLists.BuildLists(); // Load prop packs. new NetworkPackReplacement(); // Load configuration file. ConfigurationUtils.LoadConfig(); // Set up BOB tool. ToolsModifierControl.toolController.gameObject.AddComponent <BOBTool>(); // Display update notification. WhatsNew.ShowWhatsNew(); // Set up Network Skins 2 reflection. ModUtils.NS2Reflection(); // Enable thin wires, if applicable. if (ModSettings.ThinnerWires) { ElectricalWires.Instance.ApplyThinnerWires(); } // Force update of any dirty net or building prefabs from replacement process. Logging.Message("updating dirty prefabs"); BuildingData.Update(); NetData.Update(); // Set up options panel event handler. OptionsPanel.OptionsEventHook(); // Display any exception message that occured during load. InfoPanelManager.CheckException(); // Activate tool hotkey. UIThreading.Operating = true; Logging.Message("loading complete"); }
/// <summary> /// Adds configurations panel tab to tabstrip. /// </summary> /// <param name="tabStrip">Tab strip to add to</param> /// <param name="tabIndex">Index number of tab</param> internal ConfigurationsPanel(UITabstrip tabStrip, int tabIndex) { // Set reference. instance = this; // Determine if we're in-game or not; use status of replacer managers to determine. inGame = BuildingReplacement.Instance != null && NetworkReplacement.Instance != null; // Add tab and helper. UIPanel panel = PanelUtils.AddTab(tabStrip, Translations.Translate("BOB_OPT_CFG"), tabIndex); UIHelper helper = new UIHelper(panel); panel.autoLayout = false; // Config list panel. UIPanel configListPanel = panel.AddUIComponent <UIPanel>(); configListPanel.width = ListWidth; configListPanel.height = ListHeight; configListPanel.relativePosition = new Vector2(Margin, ListY); // Config selection list. configList = UIFastList.Create <UIConfigRow>(configListPanel); configList.backgroundSprite = "UnlockingPanel"; configList.width = configListPanel.width; configList.height = configListPanel.height; configList.canSelect = true; configList.rowHeight = RowHeight; configList.autoHideScrollbar = true; configList.relativePosition = Vector2.zero; configList.rowsData = new FastList <object>(); // File name textfield. UILabel fileTextLabel = UIControls.AddLabel(panel, ControlPanelX, ListY, "New configuration name:"); fileNameField = UIControls.AddTextField(panel, ControlPanelX, ListY + fileTextLabel.height); fileNameField.eventTextChanged += (control, text) => UpdateButtonStates(); // Buttons. activeCopyButton = UIControls.AddButton(panel, ControlPanelX, ListY + 70f, Translations.Translate("BOB_CFG_SAC"), 300f, scale: 0.8f); activeCopyButton.eventClicked += NewCurrent; selectedCopyButton = UIControls.AddButton(panel, ControlPanelX, ListY + 105f, Translations.Translate("BOB_CFG_SSC"), 300f, scale: 0.8f); selectedCopyButton.eventClicked += CopySelected; newCleanButton = UIControls.AddButton(panel, ControlPanelX, ListY + 140f, Translations.Translate("BOB_CFG_SEC"), 300f, scale: 0.8f); newCleanButton.eventClicked += NewClean; deleteButton = UIControls.AddButton(panel, ControlPanelX, ListY + 210f, Translations.Translate("BOB_CFG_DEL"), 300f, scale: 0.8f); deleteButton.eventClicked += Delete; // Ingame buttons - 'use custom' check and apply and nuke buttons. if (inGame) { // Use custom check box. customCheck = UIControls.LabelledCheckBox(panel, Margin, ToolBarY, Translations.Translate("BOB_CFG_UCS")); customCheck.eventCheckChanged += (control, isChecked) => { // If we've got a valid selection, set the current config name to this. if (isChecked && !string.IsNullOrEmpty(selectedConfig)) { ConfigurationUtils.CurrentSavedConfigName = selectedConfig; } }; // Apply button. UIButton applyButton = UIControls.AddButton(panel, Margin, FooterY, Translations.Translate("BOB_CFG_LAA"), 400f, scale: 0.8f); applyButton.eventClicked += Apply; // Use global configuration button. UIButton globalButton = UIControls.AddButton(panel, Margin, FooterY + 50f, Translations.Translate("BOB_CFG_LGL"), 400f, scale: 0.8f); globalButton.eventClicked += UseGlobal; // Clean up config button. UIButton cleanUpButton = UIControls.AddButton(panel, Margin + 50f, FooterY + 150f, Translations.Translate("BOB_CFG_CLE"), 300f); cleanUpButton.tooltip = Translations.Translate("BOB_CFG_CLE_TIP"); cleanUpButton.eventClicked += (control, clickEvent) => ConfigurationUtils.Cleanup(); // Nuke all settings button. UIButton nukeButton = UIControls.AddButton(panel, Margin + 50f, FooterY + 200f, Translations.Translate("BOB_NUKE"), 300f); nukeButton.eventClicked += (control, clickEvent) => { // Revert all-building and building settings. ReplacementUtils.NukeSettings(); // Save clean configuration. //ConfigurationUtils.SaveConfig(ConfigurationUtils.CurrentSavedConfigName, true); }; } // Populate selection list and set initial button states. RefreshList(); // Select current pack if we've got one. if (customCheck != null && customCheck.isChecked) { // Try to select current config name. selectedConfig = configList.FindItem(ConfigurationUtils.CurrentSavedConfigName); // Did we find it? if (selectedConfig == null) { // Not found; uncheck the use custom check. customCheck.isChecked = false; } } // Set initial button states. UpdateButtonStates(); }
/// <summary> /// MouseDown event handler to handle mouse clicks; primarily used to prime hotkey entry. /// </summary> /// <param name="mouseEvent">Mouse button event parameter</param> public void OnMouseDown(UIMouseEventParameter mouseEvent) { // Use the event. mouseEvent.Use(); // Check to see if we're already primed for hotkey entry. if (isPrimed) { // We were already primed; is this a bindable mouse button? if (mouseEvent.buttons == UIMouseButton.Left || mouseEvent.buttons == UIMouseButton.Right) { // Not a bindable mouse button - set the button text and cancel priming. button.text = SavedInputKey.ToLocalizedString("KEYNAME", ModSettings.CurrentHotkey); UIView.PopModal(); isPrimed = false; } else { // Bindable mouse button - do keybinding as if this was a keystroke. KeyCode mouseCode; switch (mouseEvent.buttons) { // Convert buttons to keycodes (we don't bother with left and right buttons as they're non-bindable). case UIMouseButton.Middle: mouseCode = KeyCode.Mouse2; break; case UIMouseButton.Special0: mouseCode = KeyCode.Mouse3; break; case UIMouseButton.Special1: mouseCode = KeyCode.Mouse4; break; case UIMouseButton.Special2: mouseCode = KeyCode.Mouse5; break; case UIMouseButton.Special3: mouseCode = KeyCode.Mouse6; break; default: // No valid button pressed: exit without doing anything. return; } // We got a valid mouse button key - apply settings and save. ApplyKey(SavedInputKey.Encode(mouseCode, IsControlDown(), IsShiftDown(), IsAltDown())); } } else { // We weren't already primed - set our text and focus the button. button.buttonsMask = (UIMouseButton.Left | UIMouseButton.Right | UIMouseButton.Middle | UIMouseButton.Special0 | UIMouseButton.Special1 | UIMouseButton.Special2 | UIMouseButton.Special3); button.text = Translations.Translate("BOB_OPT_PRS"); button.Focus(); // Prime for new keybinding entry. isPrimed = true; UIView.PushModal(button); } }