public void AttributeDictionary_Remove_KeyValuePair_Success() { // Arrange var attributes = new AttributeDictionary(); attributes.Add(new KeyValuePair <string, string>("zero", "0")); attributes.Add(new KeyValuePair <string, string>("one", "1")); attributes.Add(new KeyValuePair <string, string>("two", "2")); // Act var result = attributes.Remove(new KeyValuePair <string, string>("one", "1")); // Assert Assert.True(result); Assert.Equal(2, attributes.Count); Assert.Collection( attributes, kvp => Assert.Equal(new KeyValuePair <string, string>("two", "2"), kvp), kvp => Assert.Equal(new KeyValuePair <string, string>("zero", "0"), kvp)); }
public override void ApplyAttributes(AttributeDictionary attributesToApply) { if (currentInstanceTransform == null) { return; } if (currentXmlElement.name == "GameObject" || currentXmlElement.name == "Xml Element") { currentXmlElement.name = "TextMesh Pro"; } var go = currentInstanceTransform.gameObject; //var mt = new MethodTimer("TMP::Get/Add Component"); var tmp = go.GetComponent <TextMeshProUGUI>() ?? go.AddComponent <TextMeshProUGUI>(); //mt.Dispose(); // If we don't add a LayoutElement component, TextMeshPro will use up any layout parameters (as it uses the ILayoutElement interface) // and it doesn't use them in the same way as a LayoutElement so things like, for example, 'flexibleWidth' will not work as expected // by adding a LayoutElement, we ensure that the TMP element responds to layout attributes in the same way as other elements var layoutElement = tmp.GetComponent <LayoutElement>(); if (layoutElement == null) { tmp.gameObject.AddComponent <LayoutElement>(); } if (!attributesToApply.ContainsKey("dontMatchParentDimensions") && !currentXmlElement.HasAttribute("delayedProcessingScheduled")) { MatchParentDimensions(); } // default alignment, as per standard UI text if (!attributesToApply.ContainsKey("alignment") && !currentXmlElement.attributes.ContainsKey("alignment")) { tmp.alignment = TextAlignmentOptions.Center; } // default font size, as per standard UI text if (!attributesToApply.ContainsKey("fontSize") && !currentXmlElement.attributes.ContainsKey("fontSize")) { tmp.fontSize = 14f; } Material fontMaterial = null; if (attributesToApply.ContainsKey("fontMaterial")) { if (currentXmlLayoutInstance.textMeshProMaterials.ContainsKey(attributesToApply["fontMaterial"])) { fontMaterial = currentXmlLayoutInstance.textMeshProMaterials[attributesToApply["fontMaterial"]]; attributesToApply.Remove("fontMaterial"); } } //using (new MethodTimer("TMP::Base::ApplyAttributes")) { base.ApplyAttributes(attributesToApply); } if (fontMaterial != null) { tmp.fontMaterial = fontMaterial; } if (attributesToApply.ContainsKey("colorGradient")) { tmp.enableVertexGradient = true; } if (attributesToApply.ContainsKey("text")) { tmp.text = StringExtensions.DecodeEncodedNonAsciiCharacters(attributesToApply["text"]); } // For some reason, some TMP properties (such as text) // will not accept changes until after some internal TMP setup // has been completed. As such, it is necessary to delay our processing briefly // and then attempt to apply attributes again. // This only needs to be done once, as further ApplyAttributes() calls // will happen after TMP has already completed its setup. if (!currentXmlElement.HasAttribute("delayedProcessingScheduled")) { var attributeDictionaryCopy = attributesToApply; var _currentElement = currentXmlElement; XmlLayoutTimer.AtEndOfFrame(() => { if (_currentElement != null) { if (_currentElement.gameObject.activeInHierarchy) { _currentElement.ApplyAttributes(); } else { _currentElement.m_onEnableEventsOnceOff.Enqueue(() => { _currentElement.ApplyAttributes(attributeDictionaryCopy); }); } } }, _currentElement, true); currentXmlElement.attributes.AddIfKeyNotExists("delayedProcessingScheduled", "true"); } else { // TextMeshPro seems to sometimes ignore changes to the color property; // calling it again sorts this out if (attributesToApply.ContainsKey("color") && !attributesToApply.ContainsKey("delayedColorSet")) { var _currentElement = currentXmlElement; XmlLayoutTimer.AtEndOfFrame(() => { _currentElement.ApplyAttributes(new Dictionary <string, string>() { { "color", attributesToApply["color"] }, { "delayedColorSet", "1" } }); _currentElement.RemoveAttribute("delayedColorSet"); }, _currentElement, true); } } }
public override void ApplyAttributes(AttributeDictionary attributes) { var pagedRectTagHandler = PagedRectTagHandler.CurrentPagedRectTagHandler; if (pagedRectTagHandler == null) { Debug.Log("[XmlLayout] Error: PaginationButtonTemplate: Unable to locate PagedRect instance."); } else { var pagedRectInstance = pagedRectTagHandler.currentInstanceTransform.GetComponent <PagedRect>(); var type = attributes.GetValue("type"); Button buttonInstance = null; switch (type.ToLower()) { case "currentpage": if (pagedRectInstance.ButtonTemplate_CurrentPage != null) { buttonInstance = pagedRectInstance.ButtonTemplate_CurrentPage.Button; } break; case "otherpages": if (pagedRectInstance.ButtonTemplate_OtherPages != null) { buttonInstance = pagedRectInstance.ButtonTemplate_OtherPages.Button; } break; case "disabledpages": if (pagedRectInstance.ButtonTemplate_DisabledPage != null) { buttonInstance = pagedRectInstance.ButtonTemplate_DisabledPage.Button; } break; case "next": if (pagedRectInstance.Button_NextPage != null) { buttonInstance = pagedRectInstance.Button_NextPage.Button; } break; case "previous": if (pagedRectInstance.Button_PreviousPage != null) { buttonInstance = pagedRectInstance.Button_PreviousPage.Button; } break; case "first": if (pagedRectInstance.Button_FirstPage != null) { buttonInstance = pagedRectInstance.Button_FirstPage.Button; } break; case "last": if (pagedRectInstance.Button_LastPage != null) { buttonInstance = pagedRectInstance.Button_LastPage.Button; } break; } if (buttonInstance == null) { Debug.Log("[XmlLayout][PaginationButtonTemplate] Unable to locate button template for '" + type + "'"); } else { var tagHandler = XmlLayoutUtilities.GetXmlTagHandler("PaginationButton"); tagHandler.SetInstance(buttonInstance.transform as RectTransform, this.currentXmlLayoutInstance); attributes.Remove("type"); tagHandler.ApplyAttributes(attributes); } } }
public override void ApplyAttributes(AttributeDictionary attributesToApply) { base.ApplyAttributes(attributesToApply); var inputField = primaryComponent as InputField; var textComponents = new List <Text> { inputField.textComponent }; if (inputField.placeholder != null) { var placeholderText = inputField.placeholder.GetComponent <Text>(); if (placeholderText != null) { textComponents.Add(placeholderText); } if (attributesToApply.ContainsKey("placeholdertext")) { placeholderText.text = StringExtensions.DecodeEncodedNonAsciiCharacters(attributesToApply["placeholdertext"]); } } foreach (var textComponent in textComponents) { var tagHandler = XmlLayoutUtilities.GetXmlTagHandler("Text"); tagHandler.SetInstance(textComponent.rectTransform, this.currentXmlLayoutInstance); var textAttributes = new AttributeDictionary( attributesToApply.Where(a => TextTagHandler.TextAttributes.Contains(a.Key, StringComparer.OrdinalIgnoreCase)) .ToDictionary(a => a.Key, b => b.Value)); if (attributesToApply.ContainsKey("textshadow")) { textAttributes.Add("shadow", attributesToApply["textshadow"]); } if (attributesToApply.ContainsKey("textoutline")) { textAttributes.Add("outline", attributesToApply["textoutline"]); } if (attributesToApply.ContainsKey("textcolor")) { textAttributes.Add("color", attributesToApply["textcolor"]); } if (attributesToApply.ContainsKey("textalignment")) { textAttributes.Add("alignment", attributesToApply["textalignment"]); } textAttributes.Remove("text"); if (attributesToApply.ContainsKey("textoffset")) { var offset = attributesToApply["textoffset"].ToRectOffset(); textAttributes.Add("offsetMin", String.Format("{0} {1}", offset.left, offset.bottom)); textAttributes.Add("offsetMax", String.Format("-{0} -{1}", offset.right, offset.top)); } tagHandler.ApplyAttributes(textAttributes); } }
public override void ApplyAttributes(AttributeDictionary attributesToApply) { // necessary for elements which don't use a prefab MatchParentDimensions(); // If multiple child layouts are nested, then ApplyAttributes() will be called for each before this method has finished executing // This becomes an issue, because tag handlers are singletons intended to deal with a single element in one go, // which means that the 'currentXmlElement' reference will be replaced with the child, which causes several issues // this is also true of all other references, although in this case only 'currentXmlElement' causes any trouble // It may be necessary in future to modify the way tag handlers work such that each XmlLayout reference has its own collection of tag handlers, // although that will require a small amount of additional memory and processing var _currentXmlElement = currentXmlElement; _currentXmlElement.name = "ChildXmlLayout"; base.ApplyAttributes(attributesToApply); // Don't pass 'id' on attributesToApply.Remove("id"); attributesToApply.Remove("internalId"); // if we've already been initialized, don't repeat the process if (_currentXmlElement.GetAttribute("initialized") != null) { // attempt to apply the attributes to the child // I've removed this for the time being; as there are potential issues with properties e.g. width="50%" would make // the container use width="50%" and then the child would be 50% width of that // // var _childXmlLayout = _currentXmlElement.childElements.FirstOrDefault(t => t.tagType == "XmlLayout"); // if(_childXmlLayout != null) _childXmlLayout.ApplyAttributes(attributesToApply); return; } var viewPath = attributesToApply.GetValue <string>("viewPath"); if (String.IsNullOrEmpty(viewPath)) { Debug.LogWarning("[XmlLayout][Warning][ChildXmlLayout]:: The 'viewPath' attribute is required."); return; } // validate viewPath var xmlFile = XmlLayoutResourceDatabase.instance.GetResource <TextAsset>(viewPath); if (xmlFile == null) { Debug.LogWarning("[XmlLayout][Warning][ChildXmlLayout]:: View '" + viewPath + "' not found. Please ensure that the view is accessible via an XmlLayout Resource Database (or is in a Resources folder)."); return; } Type controllerType = null; var controllerTypeName = attributesToApply.GetValue <string>("controller"); if (!String.IsNullOrEmpty(controllerTypeName)) { // controllerType = Type.GetType(controllerTypeName, false, true); controllerType = GetTypeFromStringName(controllerTypeName); if (controllerType == null) { Debug.LogWarning("[XmlLayout][Warning][ChildXmlLayout]:: Controller Type '" + controllerTypeName + "' not found. Please ensure that the full class name (including the namespace, if the class is located within one). For example: MyNamespace.MyLayoutControllerType"); } } bool passEventsToParentController = false; if (controllerType == null) { controllerType = typeof(XmlLayoutController); passEventsToParentController = true; } var childXmlLayout = XmlLayoutFactory.Instantiate(currentInstanceTransform, viewPath, controllerType); childXmlLayout.ParentLayout = _currentXmlElement.xmlLayoutInstance; childXmlLayout.ForceRebuildOnAwake = false; if (passEventsToParentController) { childXmlLayout.XmlLayoutController.EventTarget = currentXmlLayoutInstance.XmlLayoutController; } // Adding a sub-canvas may (slightly) improve performance if (_currentXmlElement.gameObject.GetComponent <Canvas>() == null) { _currentXmlElement.gameObject.AddComponent <Canvas>(); } if (_currentXmlElement.gameObject.GetComponent <GraphicRaycaster>() == null) { _currentXmlElement.gameObject.AddComponent <GraphicRaycaster>(); } childXmlLayout.XmlElement.tagType = "XmlLayout"; _currentXmlElement.AddChildElement(childXmlLayout.XmlElement, false); _currentXmlElement.SetAttribute("initialized", "true"); childXmlLayout.XmlElement.ApplyAttributes(attributesToApply); // For some reason, the child XmlLayout offset Min/Max values are incorrect, so we need to force them to be zero if (!attributesToApply.ContainsKey("offsetMax")) { childXmlLayout.XmlElement.rectTransform.offsetMax = Vector2.zero; } if (!attributesToApply.ContainsKey("offsetMin")) { childXmlLayout.XmlElement.rectTransform.offsetMin = Vector2.zero; } }
public void AttributeDictionary_Remove_KeyValuePair_Failure() { // Arrange var attributes = new AttributeDictionary(); attributes.Add(new KeyValuePair<string, string>("zero", "0")); attributes.Add(new KeyValuePair<string, string>("one", "1")); attributes.Add(new KeyValuePair<string, string>("two", "2")); // Act var result = attributes.Remove(new KeyValuePair<string, string>("one", "0")); // Assert Assert.False(result); Assert.Equal(3, attributes.Count); Assert.Collection( attributes, kvp => Assert.Equal(new KeyValuePair<string, string>("one", "1"), kvp), kvp => Assert.Equal(new KeyValuePair<string, string>("two", "2"), kvp), kvp => Assert.Equal(new KeyValuePair<string, string>("zero", "0"), kvp)); }