public virtual void MemberChanged(string propertyName, bool propogateToCalculatedProperties = true, bool ignoreMainProperty = false) { //Debug.Log("MemberChanged(" + propertyName + ")"); if (!ignoreMainProperty) { controller.ViewModelMemberChanged(path + "." + propertyName); } if (propogateToCalculatedProperties) { foreach (var property in calculatedProperties) { var _property = property; if (property.PropertyType.GetInterface("IObservableList") != null) { // this needs to be delayed to the end of the frame, as MemberChanged() // may be called before the update has been fully processed XmlLayoutTimer.AtEndOfFrame(() => { UpdateCalculatedListView(_property); }, controller); } else { MemberChanged(path + "." + property.Name, false); } } } }
internal void SectionDropped(XmlLayoutAccordionSection section) { if (!allowSectionReordering) { return; } var oldIndex = sections.IndexOf(section); sections.RemoveAt(oldIndex); int newIndex = sectionPlaceholder.rectTransform.GetSiblingIndex(); if (newIndex > oldIndex) { newIndex--; } sections.Insert(newIndex, section); XmlLayoutTimer.AtEndOfFrame(() => section.transform.SetSiblingIndex(newIndex), this, true); foreach (var s in sections) { s.content.xmlElement.childElements.First().CanvasGroup.blocksRaycasts = true; } if (expandSectionAfterReorder) { ExpandSection(section); } }
protected TableRow RenderDataRow(Dictionary <string, string> data) { var dataRow = Instantiate <TableRow>(templateDataRow, "Data Row"); table.AddRow(dataRow); // create the data cells foreach (var heading in headings) { var dataCell = Instantiate <TableCell>(templateDataCell, "Data Cell"); dataRow.AddCell(dataCell); var text = dataCell.GetComponentInChildren <Text>(); text.text = data.ContainsKey(heading) ? data[heading] : String.Empty; } dataRows.Add(dataRow); XmlLayoutTimer.AtEndOfFrame(() => { if (table != null) { table.CalculateLayoutInputHorizontal(); } }, this); return(dataRow); }
public void ChangeColorScheme(string newScheme) { colorScheme = newScheme; var colorSchemeFile = XmlLayoutUtilities.LoadResource <TextAsset>(string.Format("Xml/ColorSchemes/{0}", newScheme)); if (colorSchemeFile == null) { Debug.LogErrorFormat("[XmlLayout][Example][Color Scheme Manager] Warning: unable to locate color scheme definition '{0}'", newScheme); return; } List <XmlLayout> xmlLayouts = Root.gameObject .GetComponentsInChildren <XmlLayout>(true) .ToList(); foreach (var layout in xmlLayouts) { // skip this layout if (layout == this.xmlLayout) { continue; } if (layout.DefaultsFiles == null) { layout.DefaultsFiles = new List <TextAsset>(); } var inactive = !layout.gameObject.activeSelf; if (inactive) { layout.gameObject.SetActive(true); } layout.DefaultsFiles.Clear(); layout.DefaultsFiles.Add(colorSchemeFile); layout.RebuildLayout(true); if (inactive) { // copy the local variable (if we use 'layout' it will reference the foreach variable which changes through each iteration) var layoutTemp = layout; // hide the layout again at the end of the frame XmlLayoutTimer.AtEndOfFrame(() => { if (layoutTemp == null) { return; } //canvasGroup.alpha = alphaBefore; layoutTemp.gameObject.SetActive(false); }, layoutTemp, true); } } }
private void ObserveList(IObservableList list, string listName) { list.itemChanged += (index, item, changedField) => ListItemUpdated(list, index, item, listName, changedField); list.itemAdded += (item) => ListItemAdded(list, item, listName); list.itemRemoved += (item) => ListItemRemoved(list, item, listName); XmlLayoutTimer.AtEndOfFrame(() => MemberChanged(listName), controller); }
internal void SectionDragEnd() { dragInProgress = false; sectionBeingDragged.xmlElement.layoutElement.ignoreLayout = false; XmlLayoutTimer.AtEndOfFrame(() => sectionPlaceholder.gameObject.SetActive(false), this); SectionDropped(sectionBeingDragged); }
internal void RemoveRowMVVM(string guid) { var row = mvvmRows.FirstOrDefault(r => r.guid == guid); if (row != null) { _Destroy(row); } XmlLayoutTimer.AtEndOfFrame(table.CalculateLayoutInputHorizontal, this); }
void ILayoutController.SetLayoutVertical() { if (m_updateQueued) { return; } m_updateQueued = true; XmlLayoutTimer.AtEndOfFrame(MatchChildDimensions, this); }
void Awake() { m_awake = true; if (Application.isPlaying) { if (PreloadXmlLayoutCache) { HandlePreload(); } if (ForceRebuildOnAwake) { if (XmlFile != null && ForceReloadXmlFileOnAwake) { ReloadXmlFile(); } else { RebuildLayout(true); } } } #if UNITY_EDITOR if (!Application.isPlaying) { if (XmlFile != null) { if (Xml != XmlFile.text) { Debug.Log("[XmlLayout] : '" + XmlFile.name + "' has changed - reloading file and rebuilding layout."); ReloadXmlFile(); // Calling MarkSceneDirty here doesn't seem to work, but delaying the call to the end of the frame does XmlLayoutTimer.AtEndOfFrame(() => UnityEditor.SceneManagement.EditorSceneManager.MarkSceneDirty(this.gameObject.scene), this); } } } #endif if (Application.isPlaying && !ForceRebuildOnAwake) { SetupElementEventHandlers(); if (XmlLayoutController != null) { XmlLayoutTimer.DelayedCall(0.1f, () => XmlLayoutController.LayoutRebuilt(ParseXmlResult.Changed), this); } } IsReady = true; }
internal override void ViewModelUpdated(bool triggerLayoutRebuild = true) { if (!listenForViewModelChanges) { return; } if (_viewModelUpdatePending) { return; } _viewModelUpdatePending = true; // We wait until the end of the frame so as not to rebuild multiple times if multiple values change in one go XmlLayoutTimer.AtEndOfFrame(() => { if (triggerLayoutRebuild) { xmlLayout.RebuildLayout(true); } if (xmlLayout.ElementDataSources.Count > 0) { xmlLayout.ElementDataSources.Where(e => e is Tags.XmlLayoutDropdownDataSource) .Select(e => ((Tags.XmlLayoutDropdownDataSource)e).OptionsDataSource) .Distinct() .ToList() .ForEach(el => UpdateDataSourcePropertyValue(el)); xmlLayout.ElementDataSources.Select(e => e.DataSource) .Distinct() .ToList() .ForEach(ed => UpdateDataSourcePropertyValue(ed)); } _viewModelUpdatePending = false; XmlLayoutTimer.AtEndOfFrame(() => { UnityEngine.UI.LayoutRebuilder.ForceRebuildLayoutImmediate(xmlLayout.transform as RectTransform); }, this); }, this); }
/*void OnRectTransformDimensionsChange() * { * if (!gameObject.activeInHierarchy) return; * * if (!XmlElement.IsAnimating) * { * // RebuildLayoutDelayed will only execute once, even if OnRectTransformDimensionsChanged() is called multiple times in one frame * RebuildLayoutDelayed(); * } * }*/ void RebuildLayoutDelayed() { if (rebuildScheduled) { return; // don't rebuild more than once at a time } rebuildScheduled = true; XmlLayoutTimer.AtEndOfFrame(() => { try { RebuildLayout(true); } finally { rebuildScheduled = false; } }, this); }
public void ShowTooltip(XmlElement element, string tooltipContent) { m_CurrentTooltipElement = element; Tooltip.LoadAttributes(m_defaultTooltipAttributes); Tooltip.gameObject.SetActive(true); Tooltip.SetText(tooltipContent); Tooltip.SetStylesFromXmlElement(element); if (!Tooltip.followMouse) { Tooltip.SetPositionAdjacentTo(element); // the size/etc. of the tooltip may change as a result of text and styles, but it appears that the rectTransform values will not be updated until the the end of the current frame // as such, we need to call SetTooltipPositionAdjacentTo again in one frame, just in case. This is primarily so that the tooltip will be clamped within the canvas area. XmlLayoutTimer.AtEndOfFrame(() => { Tooltip.SetPositionAdjacentTo(element); }, this); } }
internal XmlLayoutDataTableRow AddRowMVVM(IObservableList list, object rowData, Type type) { TableRow row; if (type == typeof(Dictionary <string, string>)) { row = RenderDataRow(rowData as Dictionary <string, string>); } else { row = RenderDataRow(ExtractRowData(rowData, type)); } var tracker = row.gameObject.AddComponent <XmlLayoutDataTableRow>(); tracker.guid = list.GetGUID(rowData); mvvmRows.Add(tracker); XmlLayoutTimer.AtEndOfFrame(table.CalculateLayoutInputHorizontal, this); return(tracker); }
/// <summary> /// Set the selected value of this Dropdown to 'value'. /// </summary> /// <param name="dropdown"></param> /// <param name="value"></param> public static void SetSelectedValue(this Dropdown dropdown, string value, int attempt = 0) { var option = dropdown.options.FirstOrDefault(o => o.text.Equals(value, StringComparison.OrdinalIgnoreCase)); // If the user sets the options and the value in one frame, // the options property may not yet be populated correctly // so if this happens, we try wait a few frames if (option == null && attempt < 3) { XmlLayoutTimer.AtEndOfFrame(() => dropdown.SetSelectedValue(value, ++attempt), dropdown); return; } if (option != null) { dropdown.value = dropdown.options.IndexOf(option); dropdown.RefreshShownValue(); } else { Debug.Log("Dropdown.SetSelectedValue :: Value '" + value + "' was not found in dropdown '" + dropdown.name + "'."); } }
public override void OnInspectorGUI() { bool reloadXmlFile = false; bool update = false; bool saveChangesToFile = false; EditorGUILayout.Space(); EditorGUILayout.Space(); EditorGUILayout.BeginHorizontal(); EditorGUILayout.PrefixLabel("Force Rebuild On Awake"); ForceRebuildOnAwake.boolValue = EditorGUILayout.Toggle(ForceRebuildOnAwake.boolValue, GUILayout.Width(32)); if (GUILayout.Button("Force Rebuild Now", GUILayout.Width(128))) { XmlLayout.RebuildLayout(true); Repaint(); } EditorGUILayout.EndHorizontal(); EditorGUILayout.Space(); var previousValue = XmlFile.objectReferenceValue; EditorGUILayout.BeginHorizontal(); EditorGUI.BeginChangeCheck(); EditorGUILayout.PropertyField(XmlFile); if (EditorGUI.EndChangeCheck()) { var textAsset = XmlFile.objectReferenceValue as TextAsset; if (textAsset != null) { var text = textAsset.text.Trim(); if (text.IndexOf("<XmlLayout", StringComparison.OrdinalIgnoreCase) == -1) { Debug.LogWarning("Please select a valid XmlLayout Xml File."); // I'd use the Dialog here, but closing the dialog closes the "Select Asset" window as well :/ //UnityEditor.EditorUtility.DisplayDialog("Invalid XmlLayout File", "Please select a valid XmlLayout Xml File.", "Okay"); // revert the change XmlFile.objectReferenceValue = previousValue; } else { reloadXmlFile = true; } } } else { if (XmlFile.objectReferenceValue != null) { reloadXmlFile = GUILayout.Button("Reload File", GUILayout.Width(100)); } } EditorGUILayout.EndHorizontal(); if (XmlFile.objectReferenceValue != null) { EditorGUILayout.Space(); EditorGUILayout.BeginHorizontal(); EditorGUILayout.PrefixLabel(" "); EditorGUILayout.LabelField("Automatically Rebuild if Xml File Changes"); AutomaticallyReloadXmlFileIfItChanges.boolValue = EditorGUILayout.Toggle(AutomaticallyReloadXmlFileIfItChanges.boolValue); EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); EditorGUILayout.PrefixLabel(" "); if (!ForceRebuildOnAwake.boolValue) { EditorGUI.BeginDisabledGroup(true); ForceReloadXmlFileOnAwake.boolValue = false; } EditorGUILayout.LabelField("Force Reload Xml File On Awake"); ForceReloadXmlFileOnAwake.boolValue = EditorGUILayout.Toggle(ForceReloadXmlFileOnAwake.boolValue); if (!ForceRebuildOnAwake.boolValue) { EditorGUI.EndDisabledGroup(); } EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); EditorGUILayout.PrefixLabel(" "); if (GUILayout.Button("Open Xml File in External Editor")) { AssetDatabase.OpenAsset(XmlFile.objectReferenceValue); } EditorGUILayout.EndHorizontal(); } EditorGUILayout.BeginHorizontal(); EditorGUILayout.PrefixLabel("Use Unscaled Time for animation"); UseUnscaledTime.boolValue = EditorGUILayout.Toggle(UseUnscaledTime.boolValue, GUILayout.Width(32)); EditorGUILayout.EndHorizontal(); EditorGUI.BeginChangeCheck(); EditorGUILayout.PropertyField(DefaultsFiles, true); if (EditorGUI.EndChangeCheck()) { reloadXmlFile = true; } editor_showXml.boolValue = EditorGUI.Foldout(EditorGUILayout.GetControlRect(), editor_showXml.boolValue, "Xml", true); if (editor_showXml.boolValue) { EditorGUI.BeginChangeCheck(); editor_xmlScrollPosition.vector2Value = EditorGUILayout.BeginScrollView(editor_xmlScrollPosition.vector2Value, false, false, GUILayout.Height(400)); Xml.stringValue = EditorGUILayout.TextArea(Xml.stringValue, GUILayout.ExpandHeight(true)); EditorGUILayout.EndScrollView(); if (EditorGUI.EndChangeCheck()) { showUpdateMessage = true; } if (showUpdateMessage) { EditorGUILayout.HelpBox("Click the 'Update Element' button to apply any changes from editing the Xml.", MessageType.Info); } if (!showUpdateMessage) { EditorGUI.BeginDisabledGroup(true); } update = GUILayout.Button("Update Element"); if (!showUpdateMessage) { EditorGUI.EndDisabledGroup(); } if (XmlFile.objectReferenceValue as TextAsset != null) { saveChangesToFile = GUILayout.Button("Save Changes to Xml File"); } } editor_showLocalization.boolValue = EditorGUI.Foldout(EditorGUILayout.GetControlRect(), editor_showLocalization.boolValue, "Localization", true); if (editor_showLocalization.boolValue) { EditorGUI.BeginChangeCheck(); EditorGUILayout.PropertyField(LocalizationFile); if (EditorGUI.EndChangeCheck()) { XmlLayoutTimer.AtEndOfFrame(() => { XmlLayout.RebuildLayout(true, false); }, XmlLayout); } } if (GUI.changed) { SO_Target.ApplyModifiedProperties(); } if (reloadXmlFile) { showUpdateMessage = false; XmlLayout.ReloadXmlFile(); Xml.stringValue = XmlLayout.Xml; SO_Target.ApplyModifiedProperties(); } else { if (update) { showUpdateMessage = false; XmlLayout.RebuildLayout(); } if (saveChangesToFile) { showUpdateMessage = false; var path = AssetDatabase.GetAssetPath(XmlLayout.XmlFile); File.WriteAllText(path, Xml.stringValue); AssetDatabase.Refresh(); XmlLayoutEditorUtilities.XmlFileUpdated(path); } } EditorGUILayout.Space(); EditorGUILayout.Space(); showIntellisense = EditorGUILayout.Foldout(showIntellisense, "Intellisense"); if (showIntellisense) { EditorGUILayout.BeginHorizontal(); EditorGUILayout.PrefixLabel("Edit XSD File"); if (GUILayout.Button("In Visual Studio")) { AssetDatabase.OpenAsset(XmlLayoutUtilities.XmlLayoutConfiguration.XSDFile); } if (GUILayout.Button("In MonoDevelop")) { #if UNITY_2019_2_OR_NEWER Unity.CodeEditor.CodeEditor.CurrentEditor.OpenProject(AssetDatabase.GetAssetPath(XmlLayoutUtilities.XmlLayoutConfiguration.XSDFile), 0); #else UnityEditorInternal.InternalEditorUtility.OpenFileAtLineExternal(AssetDatabase.GetAssetPath(XmlLayoutUtilities.XmlLayoutConfiguration.XSDFile), 0); #endif } EditorGUILayout.EndHorizontal(); } }
void ILayoutController.SetLayoutVertical() { XmlLayoutTimer.AtEndOfFrame(MatchChildDimensions, this); }
/// <summary> /// Apply the specified attributes to the XmlElement (and its other relevant components) /// </summary> /// <param name="attributesToApply"></param> public virtual void ApplyAttributes(AttributeDictionary attributesToApply) { if (currentInstanceTransform == null || currentXmlLayoutInstance == null) { Debug.LogWarning("[XmlLayout][Warning] Please call ElementTagHandler.SetInstance() before using XmlElement.ApplyAttributes()"); return; } //var startTime = DateTime.Now; attributesToApply = HandleCustomAttributes(attributesToApply); var _primaryComponent = primaryComponent; // the vast majority of events require the element to block raycasts, so rather than expecting the users to set this value every time, // lets set it here if (attributesToApply.Any(a => !String.Equals("onValueChanged", a.Key, StringComparison.OrdinalIgnoreCase) && eventAttributeNames.Contains(a.Key, StringComparer.OrdinalIgnoreCase))) { attributesToApply.AddIfKeyNotExists("raycastTarget", "true"); } else if (!String.IsNullOrEmpty(attributesToApply.GetValue("tooltip"))) { attributesToApply.AddIfKeyNotExists("raycastTarget", "true"); } if (attributesToApply.ContainsKey("allowDragging") && attributesToApply["allowDragging"].ToBoolean()) { var dragEventHandler = currentXmlElement.GetComponent <XmlLayoutDragEventHandler>(); if (dragEventHandler == null) { currentXmlElement.gameObject.AddComponent <XmlLayoutDragEventHandler>(); } } foreach (var attribute in attributesToApply) { string name = attribute.Key.ToLower(); string value = attribute.Value; if (eventAttributeNames.Contains(name, StringComparer.OrdinalIgnoreCase)) { // As it happens, events don't work anyway unless they are processed at runtime (which is why we have 'ForceRebuildOnAwake') // so we may as well not process any event attributes at all in edit mode // (this also helps avoid triggering event handlers in edit mode) // Note: we set these at the end of the frame so that any internal event-handlers (such as for MVVM) will take precedence // and be executed first var _xmlLayoutInstance = currentXmlLayoutInstance; var _transform = currentInstanceTransform; if (Application.isPlaying) { XmlLayoutTimer.AtEndOfFrame(() => { if (_transform == null || _xmlLayoutInstance == null) { return; } SetInstance(_transform, _xmlLayoutInstance); HandleEventAttribute(name, value); }, null, true); } continue; } var propertySetOnComponent = _primaryComponent != null?SetPropertyValue(_primaryComponent, name, value) : false; // if we failed to set the property on the component, perhaps it is a transform value instead if (!propertySetOnComponent) { var propertySetOnTransform = SetPropertyValue(currentInstanceTransform, name, value); // perhaps it is a layout value if (!propertySetOnTransform) { var propertySetOnLayoutComponent = SetPropertyValue(layoutElement, name, value); // or, perhaps it is an image value if (!propertySetOnLayoutComponent) { // lastly, check the XmlElement var propertySetOnXmlElement = SetPropertyValue(currentXmlElement, name, value); if (!propertySetOnXmlElement) { var _imageComponent = imageComponent; if (_imageComponent != null) { SetPropertyValue(imageComponent, name, value); } } } } } } #if !ENABLE_IL2CPP && MVVM_ENABLED if (!dontCallHandleDataSourceAttributeAutomatically && attributesToApply.ContainsKey("vm-dataSource")) { HandleDataSourceAttribute(attributesToApply["vm-dataSource"]); } // If this element is associated with a data source, but has no vm-dataSource attribute // (perhaps it was removed) // then remove the association if (!currentXmlElement.attributes.ContainsKey("vm-dataSource")) { currentXmlLayoutInstance.ElementDataSources.RemoveAll(ed => ed.XmlElement == currentXmlElement); } #endif }