From ed71f970a485ded5f8e27703c637e714ef7811f2 Mon Sep 17 00:00:00 2001 From: ChebanovDD Date: Fri, 15 Jul 2022 20:28:34 +0700 Subject: [PATCH 1/2] Add source generator. --- .../Assets/Scenes/MainScene.unity | 56 +- .../Scripts/HelloFromSourceGenerator.cs | 14 - .../Assets/Scripts/ViewModels.meta | 3 + .../Scripts/ViewModels/MainMenuViewModel.cs | 15 + .../ViewModels/MainMenuViewModel.cs.meta | 3 + .../Assets/Scripts/Views.meta | 3 + .../Assets/Scripts/Views/MainMenuView.cs | 15 + .../Assets/Scripts/Views/MainMenuView.cs.meta | 3 + .../Assets/Scripts/Views/MainMenuView.g.cs | 86 ++ .../Scripts/Views/MainMenuView.g.cs.meta | 3 + .../Assets/UI Toolkit.meta | 8 + .../Assets/UI Toolkit/MainMenu.uxml | 4 + .../Assets/UI Toolkit/MainMenu.uxml.meta | 10 + .../Assets/UI Toolkit/PanelSettings.asset | 37 + .../UI Toolkit/PanelSettings.asset.meta | 8 + .../Assets/UI Toolkit/UnityThemes.meta | 8 + .../UnityDefaultRuntimeTheme.tss.meta | 11 + .../UIElementsSchema/UIElements.xsd | 19 + ...llaborate.Components.ChangeListEntries.xsd | 109 ++ .../Unity.Cloud.Collaborate.Components.xsd | 332 ++++++ .../Unity.Cloud.Collaborate.Views.xsd | 67 ++ .../Unity.Profiling.Editor.xsd | 104 ++ .../UIElementsSchema/Unity.UI.Builder.xsd | 953 ++++++++++++++++++ .../UnityEditor.Experimental.GraphView.xsd | 66 ++ .../UIElementsSchema/UnityEditor.Overlays.xsd | 50 + ...UnityEditor.PackageManager.UI.Internal.xsd | 584 +++++++++++ .../UIElementsSchema/UnityEditor.Search.xsd | 28 + .../UnityEditor.ShortcutManagement.xsd | 46 + .../UnityEditor.U2D.Animation.xsd | 340 +++++++ .../UnityEditor.U2D.Layout.xsd | 65 ++ .../UnityEditor.UIElements.Debugger.xsd | 25 + .../UnityEditor.UIElements.xsd | 896 ++++++++++++++++ .../UnityEngine.UIElements.xsd | 896 ++++++++++++++++ ...yMvvmToolkit.UI.BindableVisualElements.xsd | 59 ++ .../Attributes/VisualTreeAssetAttribute.cs | 15 + .../Interfaces/IView.cs | 6 + .../Interfaces/IVisualElementBindings.cs | 7 + src/UnityMvvmToolkit.Common/ViewModel.cs | 44 + .../Captures/BindableElementCapture.cs | 16 + .../Captures/ViewCapture.cs | 17 + .../ExampleSourceGenerator.cs | 42 - .../Extensions/SyntaxNodeExtensions.cs | 23 + .../Models/BindableElementInfo.cs | 15 + .../BindableElementsReceiver.cs | 68 ++ .../SyntaxReceivers/ViewBindingsReceiver.cs | 15 + .../SyntaxReceivers/ViewsReceiver.cs | 47 + .../UnityMvvmToolkit.SourceGenerators.csproj | 1 + .../ViewBindingsGenerator.cs | 585 +++++++++++ .../Attributes/VisualTreeAssetAttribute.cs | 15 + .../VisualTreeAssetAttribute.cs.meta | 3 + .../Interfaces/IView.cs | 6 + .../Interfaces/IView.cs.meta | 2 +- .../Interfaces/IVisualElementBindings.cs | 7 + .../Interfaces/IVisualElementBindings.cs.meta | 11 + .../UnityMvvmToolkit.Common/ViewModel.cs | 44 + .../UnityMvvmToolkit.Common/ViewModel.cs.meta | 11 + .../UnityMvvmToolkit.SourceGenerators.dll | Bin 5632 -> 23552 bytes .../BindableVisualElements/BindableLabel.cs | 29 + .../BindableLabel.cs.meta | 3 + .../Runtime/UnityMvvmToolkit.UI/View.cs | 127 +++ .../Runtime/UnityMvvmToolkit.UI/View.cs.meta | 3 + 61 files changed, 6027 insertions(+), 61 deletions(-) delete mode 100644 samples/Unity.Mvvm.MainMenu/Assets/Scripts/HelloFromSourceGenerator.cs create mode 100644 samples/Unity.Mvvm.MainMenu/Assets/Scripts/ViewModels.meta create mode 100644 samples/Unity.Mvvm.MainMenu/Assets/Scripts/ViewModels/MainMenuViewModel.cs create mode 100644 samples/Unity.Mvvm.MainMenu/Assets/Scripts/ViewModels/MainMenuViewModel.cs.meta create mode 100644 samples/Unity.Mvvm.MainMenu/Assets/Scripts/Views.meta create mode 100644 samples/Unity.Mvvm.MainMenu/Assets/Scripts/Views/MainMenuView.cs create mode 100644 samples/Unity.Mvvm.MainMenu/Assets/Scripts/Views/MainMenuView.cs.meta create mode 100644 samples/Unity.Mvvm.MainMenu/Assets/Scripts/Views/MainMenuView.g.cs create mode 100644 samples/Unity.Mvvm.MainMenu/Assets/Scripts/Views/MainMenuView.g.cs.meta create mode 100644 samples/Unity.Mvvm.MainMenu/Assets/UI Toolkit.meta create mode 100644 samples/Unity.Mvvm.MainMenu/Assets/UI Toolkit/MainMenu.uxml create mode 100644 samples/Unity.Mvvm.MainMenu/Assets/UI Toolkit/MainMenu.uxml.meta create mode 100644 samples/Unity.Mvvm.MainMenu/Assets/UI Toolkit/PanelSettings.asset create mode 100644 samples/Unity.Mvvm.MainMenu/Assets/UI Toolkit/PanelSettings.asset.meta create mode 100644 samples/Unity.Mvvm.MainMenu/Assets/UI Toolkit/UnityThemes.meta create mode 100644 samples/Unity.Mvvm.MainMenu/Assets/UI Toolkit/UnityThemes/UnityDefaultRuntimeTheme.tss.meta create mode 100644 samples/Unity.Mvvm.MainMenu/UIElementsSchema/UIElements.xsd create mode 100644 samples/Unity.Mvvm.MainMenu/UIElementsSchema/Unity.Cloud.Collaborate.Components.ChangeListEntries.xsd create mode 100644 samples/Unity.Mvvm.MainMenu/UIElementsSchema/Unity.Cloud.Collaborate.Components.xsd create mode 100644 samples/Unity.Mvvm.MainMenu/UIElementsSchema/Unity.Cloud.Collaborate.Views.xsd create mode 100644 samples/Unity.Mvvm.MainMenu/UIElementsSchema/Unity.Profiling.Editor.xsd create mode 100644 samples/Unity.Mvvm.MainMenu/UIElementsSchema/Unity.UI.Builder.xsd create mode 100644 samples/Unity.Mvvm.MainMenu/UIElementsSchema/UnityEditor.Experimental.GraphView.xsd create mode 100644 samples/Unity.Mvvm.MainMenu/UIElementsSchema/UnityEditor.Overlays.xsd create mode 100644 samples/Unity.Mvvm.MainMenu/UIElementsSchema/UnityEditor.PackageManager.UI.Internal.xsd create mode 100644 samples/Unity.Mvvm.MainMenu/UIElementsSchema/UnityEditor.Search.xsd create mode 100644 samples/Unity.Mvvm.MainMenu/UIElementsSchema/UnityEditor.ShortcutManagement.xsd create mode 100644 samples/Unity.Mvvm.MainMenu/UIElementsSchema/UnityEditor.U2D.Animation.xsd create mode 100644 samples/Unity.Mvvm.MainMenu/UIElementsSchema/UnityEditor.U2D.Layout.xsd create mode 100644 samples/Unity.Mvvm.MainMenu/UIElementsSchema/UnityEditor.UIElements.Debugger.xsd create mode 100644 samples/Unity.Mvvm.MainMenu/UIElementsSchema/UnityEditor.UIElements.xsd create mode 100644 samples/Unity.Mvvm.MainMenu/UIElementsSchema/UnityEngine.UIElements.xsd create mode 100644 samples/Unity.Mvvm.MainMenu/UIElementsSchema/UnityMvvmToolkit.UI.BindableVisualElements.xsd create mode 100644 src/UnityMvvmToolkit.Common/Attributes/VisualTreeAssetAttribute.cs create mode 100644 src/UnityMvvmToolkit.Common/Interfaces/IView.cs create mode 100644 src/UnityMvvmToolkit.Common/Interfaces/IVisualElementBindings.cs create mode 100644 src/UnityMvvmToolkit.Common/ViewModel.cs create mode 100644 src/UnityMvvmToolkit.SourceGenerators/Captures/BindableElementCapture.cs create mode 100644 src/UnityMvvmToolkit.SourceGenerators/Captures/ViewCapture.cs delete mode 100644 src/UnityMvvmToolkit.SourceGenerators/ExampleSourceGenerator.cs create mode 100644 src/UnityMvvmToolkit.SourceGenerators/Extensions/SyntaxNodeExtensions.cs create mode 100644 src/UnityMvvmToolkit.SourceGenerators/Models/BindableElementInfo.cs create mode 100644 src/UnityMvvmToolkit.SourceGenerators/SyntaxReceivers/BindableElementsReceiver.cs create mode 100644 src/UnityMvvmToolkit.SourceGenerators/SyntaxReceivers/ViewBindingsReceiver.cs create mode 100644 src/UnityMvvmToolkit.SourceGenerators/SyntaxReceivers/ViewsReceiver.cs create mode 100644 src/UnityMvvmToolkit.SourceGenerators/ViewBindingsGenerator.cs create mode 100644 src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UnityMvvmToolkit.Common/Attributes/VisualTreeAssetAttribute.cs create mode 100644 src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UnityMvvmToolkit.Common/Attributes/VisualTreeAssetAttribute.cs.meta create mode 100644 src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UnityMvvmToolkit.Common/Interfaces/IView.cs rename samples/Unity.Mvvm.MainMenu/Assets/Scripts/HelloFromSourceGenerator.cs.meta => src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UnityMvvmToolkit.Common/Interfaces/IView.cs.meta (83%) create mode 100644 src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UnityMvvmToolkit.Common/Interfaces/IVisualElementBindings.cs create mode 100644 src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UnityMvvmToolkit.Common/Interfaces/IVisualElementBindings.cs.meta create mode 100644 src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UnityMvvmToolkit.Common/ViewModel.cs create mode 100644 src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UnityMvvmToolkit.Common/ViewModel.cs.meta create mode 100644 src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UnityMvvmToolkit.UI/BindableVisualElements/BindableLabel.cs create mode 100644 src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UnityMvvmToolkit.UI/BindableVisualElements/BindableLabel.cs.meta create mode 100644 src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UnityMvvmToolkit.UI/View.cs create mode 100644 src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UnityMvvmToolkit.UI/View.cs.meta diff --git a/samples/Unity.Mvvm.MainMenu/Assets/Scenes/MainScene.unity b/samples/Unity.Mvvm.MainMenu/Assets/Scenes/MainScene.unity index 62bc3c6..912d13f 100644 --- a/samples/Unity.Mvvm.MainMenu/Assets/Scenes/MainScene.unity +++ b/samples/Unity.Mvvm.MainMenu/Assets/Scenes/MainScene.unity @@ -134,7 +134,6 @@ GameObject: - component: {fileID: 519420032} - component: {fileID: 519420031} - component: {fileID: 519420029} - - component: {fileID: 519420033} m_Layer: 0 m_Name: MainCamera m_TagString: MainCamera @@ -208,15 +207,64 @@ Transform: m_Father: {fileID: 0} m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!114 &519420033 +--- !u!1 &1044909860 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1044909862} + - component: {fileID: 1044909861} + - component: {fileID: 1044909863} + m_Layer: 5 + m_Name: UIDocument + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1044909861 MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 519420028} + m_GameObject: {fileID: 1044909860} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 19102, guid: 0000000000000000e000000000000000, type: 0} + m_Name: + m_EditorClassIdentifier: + m_PanelSettings: {fileID: 11400000, guid: 05a4f1b7e240fdf4da6d25c89caa99e3, type: 2} + m_ParentUI: {fileID: 0} + sourceAsset: {fileID: 9197481963319205126, guid: 3331342ac7198664a90d50dfe90030fa, type: 3} + m_SortingOrder: 0 +--- !u!4 &1044909862 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1044909860} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &1044909863 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1044909860} m_Enabled: 1 m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 0a9a6d990dc283e4d91d57e902903ec0, type: 3} + m_Script: {fileID: 11500000, guid: 9b62dba053e944deb41f3b81e40f1d1e, type: 3} m_Name: m_EditorClassIdentifier: diff --git a/samples/Unity.Mvvm.MainMenu/Assets/Scripts/HelloFromSourceGenerator.cs b/samples/Unity.Mvvm.MainMenu/Assets/Scripts/HelloFromSourceGenerator.cs deleted file mode 100644 index 6e6d3b7..0000000 --- a/samples/Unity.Mvvm.MainMenu/Assets/Scripts/HelloFromSourceGenerator.cs +++ /dev/null @@ -1,14 +0,0 @@ -using UnityEngine; - -public class HelloFromSourceGenerator : MonoBehaviour -{ - static string GetStringFromSourceGenerator() - { - return ExampleSourceGenerated.ExampleSourceGenerated.GetTestText(); - } - - private void Start() - { - print(GetStringFromSourceGenerator()); - } -} diff --git a/samples/Unity.Mvvm.MainMenu/Assets/Scripts/ViewModels.meta b/samples/Unity.Mvvm.MainMenu/Assets/Scripts/ViewModels.meta new file mode 100644 index 0000000..e9af18e --- /dev/null +++ b/samples/Unity.Mvvm.MainMenu/Assets/Scripts/ViewModels.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 6632b49d12934814a5933474cb73b160 +timeCreated: 1657791554 \ No newline at end of file diff --git a/samples/Unity.Mvvm.MainMenu/Assets/Scripts/ViewModels/MainMenuViewModel.cs b/samples/Unity.Mvvm.MainMenu/Assets/Scripts/ViewModels/MainMenuViewModel.cs new file mode 100644 index 0000000..4825d18 --- /dev/null +++ b/samples/Unity.Mvvm.MainMenu/Assets/Scripts/ViewModels/MainMenuViewModel.cs @@ -0,0 +1,15 @@ +using UnityMvvmToolkit.Common; + +namespace ViewModels +{ + public class MainMenuViewModel : ViewModel + { + private string _strValue; + + public string StrValue + { + get => _strValue; + set => Set(ref _strValue, value); + } + } +} \ No newline at end of file diff --git a/samples/Unity.Mvvm.MainMenu/Assets/Scripts/ViewModels/MainMenuViewModel.cs.meta b/samples/Unity.Mvvm.MainMenu/Assets/Scripts/ViewModels/MainMenuViewModel.cs.meta new file mode 100644 index 0000000..304b964 --- /dev/null +++ b/samples/Unity.Mvvm.MainMenu/Assets/Scripts/ViewModels/MainMenuViewModel.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: ab138b4ab29841abbb0555baea2141d9 +timeCreated: 1657791695 \ No newline at end of file diff --git a/samples/Unity.Mvvm.MainMenu/Assets/Scripts/Views.meta b/samples/Unity.Mvvm.MainMenu/Assets/Scripts/Views.meta new file mode 100644 index 0000000..6264b5e --- /dev/null +++ b/samples/Unity.Mvvm.MainMenu/Assets/Scripts/Views.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 331ce41a95784c068cca15a573cadf2c +timeCreated: 1657791547 \ No newline at end of file diff --git a/samples/Unity.Mvvm.MainMenu/Assets/Scripts/Views/MainMenuView.cs b/samples/Unity.Mvvm.MainMenu/Assets/Scripts/Views/MainMenuView.cs new file mode 100644 index 0000000..14b0c72 --- /dev/null +++ b/samples/Unity.Mvvm.MainMenu/Assets/Scripts/Views/MainMenuView.cs @@ -0,0 +1,15 @@ +using UnityMvvmToolkit.Common.Attributes; +using UnityMvvmToolkit.UI; +using ViewModels; + +namespace Views +{ + [VisualTreeAsset("UI Toolkit/MainMenu.uxml")] + public partial class MainMenuView : View + { + protected override MainMenuViewModel GetBindingContext() + { + return new MainMenuViewModel { StrValue = "Test String" }; + } + } +} \ No newline at end of file diff --git a/samples/Unity.Mvvm.MainMenu/Assets/Scripts/Views/MainMenuView.cs.meta b/samples/Unity.Mvvm.MainMenu/Assets/Scripts/Views/MainMenuView.cs.meta new file mode 100644 index 0000000..29d337d --- /dev/null +++ b/samples/Unity.Mvvm.MainMenu/Assets/Scripts/Views/MainMenuView.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 9b62dba053e944deb41f3b81e40f1d1e +timeCreated: 1657791685 \ No newline at end of file diff --git a/samples/Unity.Mvvm.MainMenu/Assets/Scripts/Views/MainMenuView.g.cs b/samples/Unity.Mvvm.MainMenu/Assets/Scripts/Views/MainMenuView.g.cs new file mode 100644 index 0000000..aaf129a --- /dev/null +++ b/samples/Unity.Mvvm.MainMenu/Assets/Scripts/Views/MainMenuView.g.cs @@ -0,0 +1,86 @@ +// using System; +// using System.Runtime.CompilerServices; +// using UnityEngine.UIElements; +// using UnityMvvmToolkit.Common.Interfaces; +// using UnityMvvmToolkit.UI.BindableVisualElements; + +namespace Views +{ + // public partial class MainMenuView + // { + // protected override IVisualElementBindings GetVisualElementsBindings(ViewModels.MainMenuViewModel bindingContext, + // IBindableVisualElement bindableElement) + // { + // return bindableElement switch + // { + // BindableLabel bindableLabel => new LabelBindings(bindingContext, bindableLabel), + // BindableTextField bindableTextField => new TextFieldBindings(bindingContext, bindableTextField), + // _ => default + // }; + // } + // + // private class LabelBindings : IVisualElementBindings + // { + // private readonly ViewModels.MainMenuViewModel _viewModel; + // private readonly BindableLabel _visualElement; + // + // public LabelBindings(ViewModels.MainMenuViewModel viewModel, BindableLabel visualElement) + // { + // _viewModel = viewModel; + // _visualElement = visualElement; + // } + // + // public void UpdateValues() + // { + // UpdateStrValue(); + // } + // + // [MethodImpl(MethodImplOptions.AggressiveInlining)] + // private void UpdateStrValue() + // { + // if (_visualElement.text != _viewModel.StrValue) + // { + // _visualElement.text = _viewModel.StrValue; + // } + // } + // } + // + // private class TextFieldBindings : IVisualElementBindings, IDisposable + // { + // private readonly ViewModels.MainMenuViewModel _viewModel; + // private readonly BindableTextField _visualElement; + // + // public TextFieldBindings(ViewModels.MainMenuViewModel viewModel, BindableTextField visualElement) + // { + // _viewModel = viewModel; + // + // _visualElement = visualElement; + // _visualElement.RegisterValueChangedCallback(OnVisualElementValueChanged); + // } + // + // public void Dispose() + // { + // _visualElement.UnregisterValueChangedCallback(OnVisualElementValueChanged); + // } + // + // public void UpdateValues() + // { + // UpdateStrValue(); + // } + // + // private void OnVisualElementValueChanged(ChangeEvent e) + // { + // _viewModel.StrValue = e.newValue; + // } + // + // [MethodImpl(MethodImplOptions.AggressiveInlining)] + // private void UpdateStrValue() + // { + // if (_visualElement.value != _viewModel.StrValue) + // { + // _visualElement.SetValueWithoutNotify(_viewModel.StrValue); + // } + // } + // } + // } +} \ No newline at end of file diff --git a/samples/Unity.Mvvm.MainMenu/Assets/Scripts/Views/MainMenuView.g.cs.meta b/samples/Unity.Mvvm.MainMenu/Assets/Scripts/Views/MainMenuView.g.cs.meta new file mode 100644 index 0000000..8a73036 --- /dev/null +++ b/samples/Unity.Mvvm.MainMenu/Assets/Scripts/Views/MainMenuView.g.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 333c653f4a914c3bb1ba30a86e8dd8a3 +timeCreated: 1657797313 \ No newline at end of file diff --git a/samples/Unity.Mvvm.MainMenu/Assets/UI Toolkit.meta b/samples/Unity.Mvvm.MainMenu/Assets/UI Toolkit.meta new file mode 100644 index 0000000..3964970 --- /dev/null +++ b/samples/Unity.Mvvm.MainMenu/Assets/UI Toolkit.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 52a48eb306f4912419b720b0ac4c59b8 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/samples/Unity.Mvvm.MainMenu/Assets/UI Toolkit/MainMenu.uxml b/samples/Unity.Mvvm.MainMenu/Assets/UI Toolkit/MainMenu.uxml new file mode 100644 index 0000000..90f98c7 --- /dev/null +++ b/samples/Unity.Mvvm.MainMenu/Assets/UI Toolkit/MainMenu.uxml @@ -0,0 +1,4 @@ + + + + diff --git a/samples/Unity.Mvvm.MainMenu/Assets/UI Toolkit/MainMenu.uxml.meta b/samples/Unity.Mvvm.MainMenu/Assets/UI Toolkit/MainMenu.uxml.meta new file mode 100644 index 0000000..4d9b5ab --- /dev/null +++ b/samples/Unity.Mvvm.MainMenu/Assets/UI Toolkit/MainMenu.uxml.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 3331342ac7198664a90d50dfe90030fa +ScriptedImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 2 + userData: + assetBundleName: + assetBundleVariant: + script: {fileID: 13804, guid: 0000000000000000e000000000000000, type: 0} diff --git a/samples/Unity.Mvvm.MainMenu/Assets/UI Toolkit/PanelSettings.asset b/samples/Unity.Mvvm.MainMenu/Assets/UI Toolkit/PanelSettings.asset new file mode 100644 index 0000000..ef378ba --- /dev/null +++ b/samples/Unity.Mvvm.MainMenu/Assets/UI Toolkit/PanelSettings.asset @@ -0,0 +1,37 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 19101, guid: 0000000000000000e000000000000000, type: 0} + m_Name: PanelSettings + m_EditorClassIdentifier: + themeUss: {fileID: -4733365628477956816, guid: 9a71bae960d624d44acdf8bbcb7d583d, type: 3} + m_TargetTexture: {fileID: 0} + m_ScaleMode: 1 + m_Scale: 1 + m_ReferenceDpi: 120 + m_FallbackDpi: 96 + m_ReferenceResolution: {x: 1200, y: 800} + m_ScreenMatchMode: 0 + m_Match: 0 + m_SortingOrder: 0 + m_TargetDisplay: 0 + m_ClearDepthStencil: 1 + m_ClearColor: 0 + m_ColorClearValue: {r: 0, g: 0, b: 0, a: 0} + m_DynamicAtlasSettings: + m_MinAtlasSize: 64 + m_MaxAtlasSize: 4096 + m_MaxSubTextureSize: 64 + m_ActiveFilters: 31 + m_AtlasBlitShader: {fileID: 9101, guid: 0000000000000000f000000000000000, type: 0} + m_RuntimeShader: {fileID: 9100, guid: 0000000000000000f000000000000000, type: 0} + m_RuntimeWorldShader: {fileID: 9102, guid: 0000000000000000f000000000000000, type: 0} + textSettings: {fileID: 0} diff --git a/samples/Unity.Mvvm.MainMenu/Assets/UI Toolkit/PanelSettings.asset.meta b/samples/Unity.Mvvm.MainMenu/Assets/UI Toolkit/PanelSettings.asset.meta new file mode 100644 index 0000000..ebe2a9e --- /dev/null +++ b/samples/Unity.Mvvm.MainMenu/Assets/UI Toolkit/PanelSettings.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 05a4f1b7e240fdf4da6d25c89caa99e3 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/samples/Unity.Mvvm.MainMenu/Assets/UI Toolkit/UnityThemes.meta b/samples/Unity.Mvvm.MainMenu/Assets/UI Toolkit/UnityThemes.meta new file mode 100644 index 0000000..6ce3519 --- /dev/null +++ b/samples/Unity.Mvvm.MainMenu/Assets/UI Toolkit/UnityThemes.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: edce8b7e8ea4b214e8975b19e4d3172c +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/samples/Unity.Mvvm.MainMenu/Assets/UI Toolkit/UnityThemes/UnityDefaultRuntimeTheme.tss.meta b/samples/Unity.Mvvm.MainMenu/Assets/UI Toolkit/UnityThemes/UnityDefaultRuntimeTheme.tss.meta new file mode 100644 index 0000000..820cd7a --- /dev/null +++ b/samples/Unity.Mvvm.MainMenu/Assets/UI Toolkit/UnityThemes/UnityDefaultRuntimeTheme.tss.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9a71bae960d624d44acdf8bbcb7d583d +ScriptedImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 2 + userData: + assetBundleName: + assetBundleVariant: + script: {fileID: 12388, guid: 0000000000000000e000000000000000, type: 0} + disableValidation: 0 diff --git a/samples/Unity.Mvvm.MainMenu/UIElementsSchema/UIElements.xsd b/samples/Unity.Mvvm.MainMenu/UIElementsSchema/UIElements.xsd new file mode 100644 index 0000000..a966e0f --- /dev/null +++ b/samples/Unity.Mvvm.MainMenu/UIElementsSchema/UIElements.xsd @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/Unity.Mvvm.MainMenu/UIElementsSchema/Unity.Cloud.Collaborate.Components.ChangeListEntries.xsd b/samples/Unity.Mvvm.MainMenu/UIElementsSchema/Unity.Cloud.Collaborate.Components.ChangeListEntries.xsd new file mode 100644 index 0000000..37db2cb --- /dev/null +++ b/samples/Unity.Mvvm.MainMenu/UIElementsSchema/Unity.Cloud.Collaborate.Components.ChangeListEntries.xsd @@ -0,0 +1,109 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/Unity.Mvvm.MainMenu/UIElementsSchema/Unity.Cloud.Collaborate.Components.xsd b/samples/Unity.Mvvm.MainMenu/UIElementsSchema/Unity.Cloud.Collaborate.Components.xsd new file mode 100644 index 0000000..06b7da5 --- /dev/null +++ b/samples/Unity.Mvvm.MainMenu/UIElementsSchema/Unity.Cloud.Collaborate.Components.xsd @@ -0,0 +1,332 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/Unity.Mvvm.MainMenu/UIElementsSchema/Unity.Cloud.Collaborate.Views.xsd b/samples/Unity.Mvvm.MainMenu/UIElementsSchema/Unity.Cloud.Collaborate.Views.xsd new file mode 100644 index 0000000..f6ec2fb --- /dev/null +++ b/samples/Unity.Mvvm.MainMenu/UIElementsSchema/Unity.Cloud.Collaborate.Views.xsd @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/Unity.Mvvm.MainMenu/UIElementsSchema/Unity.Profiling.Editor.xsd b/samples/Unity.Mvvm.MainMenu/UIElementsSchema/Unity.Profiling.Editor.xsd new file mode 100644 index 0000000..32d7ed8 --- /dev/null +++ b/samples/Unity.Mvvm.MainMenu/UIElementsSchema/Unity.Profiling.Editor.xsd @@ -0,0 +1,104 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/Unity.Mvvm.MainMenu/UIElementsSchema/Unity.UI.Builder.xsd b/samples/Unity.Mvvm.MainMenu/UIElementsSchema/Unity.UI.Builder.xsd new file mode 100644 index 0000000..0de8a5b --- /dev/null +++ b/samples/Unity.Mvvm.MainMenu/UIElementsSchema/Unity.UI.Builder.xsd @@ -0,0 +1,953 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/Unity.Mvvm.MainMenu/UIElementsSchema/UnityEditor.Experimental.GraphView.xsd b/samples/Unity.Mvvm.MainMenu/UIElementsSchema/UnityEditor.Experimental.GraphView.xsd new file mode 100644 index 0000000..f9b22e3 --- /dev/null +++ b/samples/Unity.Mvvm.MainMenu/UIElementsSchema/UnityEditor.Experimental.GraphView.xsd @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/Unity.Mvvm.MainMenu/UIElementsSchema/UnityEditor.Overlays.xsd b/samples/Unity.Mvvm.MainMenu/UIElementsSchema/UnityEditor.Overlays.xsd new file mode 100644 index 0000000..d60844f --- /dev/null +++ b/samples/Unity.Mvvm.MainMenu/UIElementsSchema/UnityEditor.Overlays.xsd @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/Unity.Mvvm.MainMenu/UIElementsSchema/UnityEditor.PackageManager.UI.Internal.xsd b/samples/Unity.Mvvm.MainMenu/UIElementsSchema/UnityEditor.PackageManager.UI.Internal.xsd new file mode 100644 index 0000000..665abd5 --- /dev/null +++ b/samples/Unity.Mvvm.MainMenu/UIElementsSchema/UnityEditor.PackageManager.UI.Internal.xsd @@ -0,0 +1,584 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/Unity.Mvvm.MainMenu/UIElementsSchema/UnityEditor.Search.xsd b/samples/Unity.Mvvm.MainMenu/UIElementsSchema/UnityEditor.Search.xsd new file mode 100644 index 0000000..216cd6d --- /dev/null +++ b/samples/Unity.Mvvm.MainMenu/UIElementsSchema/UnityEditor.Search.xsd @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/Unity.Mvvm.MainMenu/UIElementsSchema/UnityEditor.ShortcutManagement.xsd b/samples/Unity.Mvvm.MainMenu/UIElementsSchema/UnityEditor.ShortcutManagement.xsd new file mode 100644 index 0000000..400097b --- /dev/null +++ b/samples/Unity.Mvvm.MainMenu/UIElementsSchema/UnityEditor.ShortcutManagement.xsd @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/Unity.Mvvm.MainMenu/UIElementsSchema/UnityEditor.U2D.Animation.xsd b/samples/Unity.Mvvm.MainMenu/UIElementsSchema/UnityEditor.U2D.Animation.xsd new file mode 100644 index 0000000..0e7f361 --- /dev/null +++ b/samples/Unity.Mvvm.MainMenu/UIElementsSchema/UnityEditor.U2D.Animation.xsd @@ -0,0 +1,340 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/Unity.Mvvm.MainMenu/UIElementsSchema/UnityEditor.U2D.Layout.xsd b/samples/Unity.Mvvm.MainMenu/UIElementsSchema/UnityEditor.U2D.Layout.xsd new file mode 100644 index 0000000..b40a7ff --- /dev/null +++ b/samples/Unity.Mvvm.MainMenu/UIElementsSchema/UnityEditor.U2D.Layout.xsd @@ -0,0 +1,65 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/Unity.Mvvm.MainMenu/UIElementsSchema/UnityEditor.UIElements.Debugger.xsd b/samples/Unity.Mvvm.MainMenu/UIElementsSchema/UnityEditor.UIElements.Debugger.xsd new file mode 100644 index 0000000..a2be34b --- /dev/null +++ b/samples/Unity.Mvvm.MainMenu/UIElementsSchema/UnityEditor.UIElements.Debugger.xsd @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/Unity.Mvvm.MainMenu/UIElementsSchema/UnityEditor.UIElements.xsd b/samples/Unity.Mvvm.MainMenu/UIElementsSchema/UnityEditor.UIElements.xsd new file mode 100644 index 0000000..d16ef98 --- /dev/null +++ b/samples/Unity.Mvvm.MainMenu/UIElementsSchema/UnityEditor.UIElements.xsd @@ -0,0 +1,896 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/Unity.Mvvm.MainMenu/UIElementsSchema/UnityEngine.UIElements.xsd b/samples/Unity.Mvvm.MainMenu/UIElementsSchema/UnityEngine.UIElements.xsd new file mode 100644 index 0000000..60d663f --- /dev/null +++ b/samples/Unity.Mvvm.MainMenu/UIElementsSchema/UnityEngine.UIElements.xsd @@ -0,0 +1,896 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/Unity.Mvvm.MainMenu/UIElementsSchema/UnityMvvmToolkit.UI.BindableVisualElements.xsd b/samples/Unity.Mvvm.MainMenu/UIElementsSchema/UnityMvvmToolkit.UI.BindableVisualElements.xsd new file mode 100644 index 0000000..939654f --- /dev/null +++ b/samples/Unity.Mvvm.MainMenu/UIElementsSchema/UnityMvvmToolkit.UI.BindableVisualElements.xsd @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/UnityMvvmToolkit.Common/Attributes/VisualTreeAssetAttribute.cs b/src/UnityMvvmToolkit.Common/Attributes/VisualTreeAssetAttribute.cs new file mode 100644 index 0000000..0bf1098 --- /dev/null +++ b/src/UnityMvvmToolkit.Common/Attributes/VisualTreeAssetAttribute.cs @@ -0,0 +1,15 @@ +using System; + +namespace UnityMvvmToolkit.Common.Attributes +{ + [AttributeUsage(AttributeTargets.Class, Inherited = false)] + public class VisualTreeAssetAttribute : Attribute + { + public VisualTreeAssetAttribute(string assetPath) + { + AssetPath = assetPath; + } + + public string AssetPath { get; } + } +} \ No newline at end of file diff --git a/src/UnityMvvmToolkit.Common/Interfaces/IView.cs b/src/UnityMvvmToolkit.Common/Interfaces/IView.cs new file mode 100644 index 0000000..a5abded --- /dev/null +++ b/src/UnityMvvmToolkit.Common/Interfaces/IView.cs @@ -0,0 +1,6 @@ +namespace UnityMvvmToolkit.Common.Interfaces +{ + public interface IView + { + } +} \ No newline at end of file diff --git a/src/UnityMvvmToolkit.Common/Interfaces/IVisualElementBindings.cs b/src/UnityMvvmToolkit.Common/Interfaces/IVisualElementBindings.cs new file mode 100644 index 0000000..69abbf1 --- /dev/null +++ b/src/UnityMvvmToolkit.Common/Interfaces/IVisualElementBindings.cs @@ -0,0 +1,7 @@ +namespace UnityMvvmToolkit.Common.Interfaces +{ + public interface IVisualElementBindings + { + void UpdateValues(); + } +} \ No newline at end of file diff --git a/src/UnityMvvmToolkit.Common/ViewModel.cs b/src/UnityMvvmToolkit.Common/ViewModel.cs new file mode 100644 index 0000000..f875b65 --- /dev/null +++ b/src/UnityMvvmToolkit.Common/ViewModel.cs @@ -0,0 +1,44 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Runtime.CompilerServices; + +namespace UnityMvvmToolkit.Common +{ + public abstract class ViewModel : INotifyPropertyChanged + { + public event PropertyChangedEventHandler PropertyChanged; + + protected bool Set(ref T oldValue, T newValue, [CallerMemberName] string propertyName = default) + { + if (EqualityComparer.Default.Equals(oldValue, newValue)) + { + return false; + } + + oldValue = newValue; + OnPropertyChanged(propertyName); + + return true; + } + + protected bool Set(T oldValue, T newValue, TModel model, Action callback, + [CallerMemberName] string propertyName = default) where TModel : class + { + if (EqualityComparer.Default.Equals(oldValue, newValue)) + { + return false; + } + + callback(model, newValue); + OnPropertyChanged(propertyName); + + return true; + } + + protected void OnPropertyChanged(string propertyName) + { + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + } + } +} \ No newline at end of file diff --git a/src/UnityMvvmToolkit.SourceGenerators/Captures/BindableElementCapture.cs b/src/UnityMvvmToolkit.SourceGenerators/Captures/BindableElementCapture.cs new file mode 100644 index 0000000..78934fb --- /dev/null +++ b/src/UnityMvvmToolkit.SourceGenerators/Captures/BindableElementCapture.cs @@ -0,0 +1,16 @@ +using System.Collections.Generic; +using Microsoft.CodeAnalysis.CSharp.Syntax; + +namespace UnityMvvmToolkit.SourceGenerators.Captures; + +public class BindableElementCapture +{ + public BindableElementCapture(ClassDeclarationSyntax @class) + { + Class = @class; + Properties = new List>(); + } + + public ClassDeclarationSyntax Class { get; } + public List> Properties { get; } +} \ No newline at end of file diff --git a/src/UnityMvvmToolkit.SourceGenerators/Captures/ViewCapture.cs b/src/UnityMvvmToolkit.SourceGenerators/Captures/ViewCapture.cs new file mode 100644 index 0000000..cc1f824 --- /dev/null +++ b/src/UnityMvvmToolkit.SourceGenerators/Captures/ViewCapture.cs @@ -0,0 +1,17 @@ +using Microsoft.CodeAnalysis.CSharp.Syntax; + +namespace UnityMvvmToolkit.SourceGenerators.Captures; + +public class ViewCapture +{ + public ViewCapture(string assetPath, string viewModelIdentifier, ClassDeclarationSyntax @class) + { + AssetPath = assetPath; + ViewModelIdentifier = viewModelIdentifier; + Class = @class; + } + + public string AssetPath { get; } + public string ViewModelIdentifier { get; } + public ClassDeclarationSyntax Class { get; } +} \ No newline at end of file diff --git a/src/UnityMvvmToolkit.SourceGenerators/ExampleSourceGenerator.cs b/src/UnityMvvmToolkit.SourceGenerators/ExampleSourceGenerator.cs deleted file mode 100644 index 0a9e0d9..0000000 --- a/src/UnityMvvmToolkit.SourceGenerators/ExampleSourceGenerator.cs +++ /dev/null @@ -1,42 +0,0 @@ -using System.Globalization; -using System.Text; -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.Text; -using UnityMvvmToolkit.Common.Attributes; - -namespace UnityMvvmToolkit.SourceGenerators -{ - [Generator] - public class ExampleSourceGenerator : ISourceGenerator - { - public void Initialize(GeneratorInitializationContext context) - { - } - - public void Execute(GeneratorExecutionContext context) - { - - var stringBuilder = new StringBuilder( - @" - using System; - namespace ExampleSourceGenerated - { - public static class ExampleSourceGenerated - { - public static string GetTestText() - { - return ""This is from source generator "); - - stringBuilder.Append(nameof(BindToAttribute)); - - stringBuilder.Append( - @"""; - } - } -} -"); - - context.AddSource("exampleSourceGenerator", SourceText.From(stringBuilder.ToString(), Encoding.UTF8)); - } - } -} \ No newline at end of file diff --git a/src/UnityMvvmToolkit.SourceGenerators/Extensions/SyntaxNodeExtensions.cs b/src/UnityMvvmToolkit.SourceGenerators/Extensions/SyntaxNodeExtensions.cs new file mode 100644 index 0000000..65e3d7d --- /dev/null +++ b/src/UnityMvvmToolkit.SourceGenerators/Extensions/SyntaxNodeExtensions.cs @@ -0,0 +1,23 @@ +using Microsoft.CodeAnalysis; + +namespace UnityMvvmToolkit.SourceGenerators.Extensions; + +public static class SyntaxNodeExtensions +{ + public static T GetParent(this SyntaxNode syntaxNode) + { + var parent = syntaxNode.Parent; + + while (parent != null) + { + if (parent is T result) + { + return result; + } + + parent = parent.Parent; + } + + return default; + } +} \ No newline at end of file diff --git a/src/UnityMvvmToolkit.SourceGenerators/Models/BindableElementInfo.cs b/src/UnityMvvmToolkit.SourceGenerators/Models/BindableElementInfo.cs new file mode 100644 index 0000000..24db602 --- /dev/null +++ b/src/UnityMvvmToolkit.SourceGenerators/Models/BindableElementInfo.cs @@ -0,0 +1,15 @@ +using System.Collections.Generic; + +namespace UnityMvvmToolkit.SourceGenerators.Models; + +public class BindableElementInfo +{ + public BindableElementInfo(string classIdentifier) + { + ClassIdentifier = classIdentifier; + Attributes = new List>(); + } + + public string ClassIdentifier { get; } + public List> Attributes { get; } +} \ No newline at end of file diff --git a/src/UnityMvvmToolkit.SourceGenerators/SyntaxReceivers/BindableElementsReceiver.cs b/src/UnityMvvmToolkit.SourceGenerators/SyntaxReceivers/BindableElementsReceiver.cs new file mode 100644 index 0000000..91285e1 --- /dev/null +++ b/src/UnityMvvmToolkit.SourceGenerators/SyntaxReceivers/BindableElementsReceiver.cs @@ -0,0 +1,68 @@ +using System.Collections.Generic; +using System.Linq; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using UnityMvvmToolkit.Common.Interfaces; +using UnityMvvmToolkit.SourceGenerators.Captures; +using UnityMvvmToolkit.SourceGenerators.Extensions; + +namespace UnityMvvmToolkit.SourceGenerators.SyntaxReceivers; + +public class BindableElementsReceiver : ISyntaxReceiver +{ + private const string AttributeName = "BindTo"; + private const string InterfaceName = nameof(IBindableVisualElement); + + private readonly Dictionary _captures = new(); + + public IReadOnlyDictionary Captures => _captures; + + public void OnVisitSyntaxNode(SyntaxNode syntaxNode) + { + if (syntaxNode is not AttributeSyntax + { + Name: IdentifierNameSyntax { Identifier.Text: AttributeName } + } attribute) + { + return; + } + + var bindToPath = GetAttributeArgumentValue(attribute); + if (string.IsNullOrWhiteSpace(bindToPath)) + { + return; + } + + var property = attribute.GetParent(); + var @class = property.GetParent(); + + if (IsImplementInterface(@class, InterfaceName) == false) + { + return; + } + + if (_captures.TryGetValue(@class.Identifier.Text, out var bindableElement) == false) + { + bindableElement = new BindableElementCapture(@class); + _captures.Add(@class.Identifier.Text, bindableElement); + } + + bindableElement.Properties.Add(new KeyValuePair(bindToPath, property)); + } + + private string GetAttributeArgumentValue(AttributeSyntax attribute) + { + return attribute.ArgumentList?.Arguments.Single().Expression switch + { + LiteralExpressionSyntax literal => literal.Token.ValueText, + InvocationExpressionSyntax invocation => invocation.ArgumentList.Arguments.Single().Expression.GetText().ToString(), + _ => null + }; + } + + private bool IsImplementInterface(ClassDeclarationSyntax @class, string @interface) + { + return @class.BaseList == null || + @class.BaseList.Types.Select(typeSyntax => typeSyntax.Type.GetText().ToString() == @interface).Any(); + } +} \ No newline at end of file diff --git a/src/UnityMvvmToolkit.SourceGenerators/SyntaxReceivers/ViewBindingsReceiver.cs b/src/UnityMvvmToolkit.SourceGenerators/SyntaxReceivers/ViewBindingsReceiver.cs new file mode 100644 index 0000000..5a4d6da --- /dev/null +++ b/src/UnityMvvmToolkit.SourceGenerators/SyntaxReceivers/ViewBindingsReceiver.cs @@ -0,0 +1,15 @@ +using Microsoft.CodeAnalysis; + +namespace UnityMvvmToolkit.SourceGenerators.SyntaxReceivers; + +public class ViewBindingsReceiver : ISyntaxReceiver +{ + public ViewsReceiver Views { get; } = new(); + public BindableElementsReceiver BindableElements { get; } = new(); + + public void OnVisitSyntaxNode(SyntaxNode syntaxNode) + { + BindableElements.OnVisitSyntaxNode(syntaxNode); + Views.OnVisitSyntaxNode(syntaxNode); + } +} \ No newline at end of file diff --git a/src/UnityMvvmToolkit.SourceGenerators/SyntaxReceivers/ViewsReceiver.cs b/src/UnityMvvmToolkit.SourceGenerators/SyntaxReceivers/ViewsReceiver.cs new file mode 100644 index 0000000..f565f26 --- /dev/null +++ b/src/UnityMvvmToolkit.SourceGenerators/SyntaxReceivers/ViewsReceiver.cs @@ -0,0 +1,47 @@ +using System.Collections.Generic; +using System.Linq; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using UnityMvvmToolkit.SourceGenerators.Captures; +using UnityMvvmToolkit.SourceGenerators.Extensions; + +namespace UnityMvvmToolkit.SourceGenerators.SyntaxReceivers; + +public class ViewsReceiver : ISyntaxReceiver +{ + private const string AttributeName = "VisualTreeAsset"; + + private readonly List _captures = new(); + + public IEnumerable Captures => _captures; + + public void OnVisitSyntaxNode(SyntaxNode syntaxNode) + { + if (syntaxNode is not AttributeSyntax + { + Name: IdentifierNameSyntax { Identifier.Text: AttributeName } + } attribute) + { + return; + } + + if (attribute.ArgumentList?.Arguments.Single().Expression is not LiteralExpressionSyntax + literalExpressionSyntax) + { + return; + } + + var @class = attribute.GetParent(); + + var genericNameSyntax = @class.BaseList?.Types.Single(type => type is SimpleBaseTypeSyntax).Type as GenericNameSyntax; + if (genericNameSyntax?.TypeArgumentList.Arguments.Single() is not IdentifierNameSyntax identifierNameSyntax) + { + return; + } + + var assetPath = literalExpressionSyntax.Token.ValueText; + var viewModelIdentifier = identifierNameSyntax.Identifier.Text; + + _captures.Add(new ViewCapture(assetPath, viewModelIdentifier, @class)); + } +} \ No newline at end of file diff --git a/src/UnityMvvmToolkit.SourceGenerators/UnityMvvmToolkit.SourceGenerators.csproj b/src/UnityMvvmToolkit.SourceGenerators/UnityMvvmToolkit.SourceGenerators.csproj index c7cfa7c..aee915a 100644 --- a/src/UnityMvvmToolkit.SourceGenerators/UnityMvvmToolkit.SourceGenerators.csproj +++ b/src/UnityMvvmToolkit.SourceGenerators/UnityMvvmToolkit.SourceGenerators.csproj @@ -3,6 +3,7 @@ netstandard2.0 true + 10 diff --git a/src/UnityMvvmToolkit.SourceGenerators/ViewBindingsGenerator.cs b/src/UnityMvvmToolkit.SourceGenerators/ViewBindingsGenerator.cs new file mode 100644 index 0000000..437373a --- /dev/null +++ b/src/UnityMvvmToolkit.SourceGenerators/ViewBindingsGenerator.cs @@ -0,0 +1,585 @@ +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.IO; +using System.Linq; +using System.Text; +using System.Xml; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using UnityMvvmToolkit.SourceGenerators.Captures; +using UnityMvvmToolkit.SourceGenerators.Extensions; +using UnityMvvmToolkit.SourceGenerators.Models; +using UnityMvvmToolkit.SourceGenerators.SyntaxReceivers; + +using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; + +namespace UnityMvvmToolkit.SourceGenerators; + +[Generator] +public class ViewBindingsGenerator : ISourceGenerator +{ + private const string AssetsFolderName = "Assets"; + private const string BindableIdentifier = "Bindable"; + + public void Initialize(GeneratorInitializationContext context) + { + context.RegisterForSyntaxNotifications(() => new ViewBindingsReceiver()); + } + + public void Execute(GeneratorExecutionContext context) + { + if (context.SyntaxReceiver is not ViewBindingsReceiver receiver) + { + return; + } + + // var sb = new StringBuilder(); + // sb.Append(receiver.Views.Captures.Count()); + // sb.AppendLine(); + // sb.Append(receiver.BindableElements.Captures.Values.Count()); + // + // File.WriteAllText($@"D:\0.txt", sb.ToString()); + // return; + + // if (receiver.Views.Captures.Count() > 0) + // { + // File.WriteAllText($@"D:\0.txt", receiver.Views.Captures.First().Class.SyntaxTree.GetRoot().GetParent().Name.ToString()); + // } + // + // if (receiver.BindableElements.Captures.Values.Count() > 0) + // { + // File.WriteAllText($@"D:\1.txt", receiver.BindableElements.Captures.Values.First().Class.SyntaxTree.GetRoot().GetParent().Name.ToString()); + // } + // + // if ((receiver.Views.Captures.Count() > 0) + // && + // (receiver.BindableElements.Captures.Values.Count() > 0) + // ) + // { + // File.WriteAllText($@"D:\2.txt", "!!!"); + // } + // + // // File.WriteAllText($@"D:\0.txt", receiver.Views.Captures.Count().ToString()); + // // File.WriteAllText($@"D:\1.txt", receiver.BindableElements.Captures.Values.Count().ToString()); + // + // return; + + foreach (var bindableElement in receiver.BindableElements.Captures.Values) + { + File.WriteAllText($@"D:\{bindableElement.Class.Identifier.Text}.txt", bindableElement.Class.GetText(Encoding.UTF8).ToString()); + } + + var compilation = context.Compilation; + + foreach (var view in receiver.Views.Captures) + { + // foreach (var bindableElement in receiver.BindableElements.Captures.Values) + // { + // File.WriteAllText($@"D:\{bindableElement.Class.Identifier.Text}.txt", bindableElement.Class.GetText(Encoding.UTF8).ToString()); + // } + + File.WriteAllText($@"D:\{view.Class.Identifier.Text}.txt", view.Class.GetText(Encoding.UTF8).ToString()); + + var assetFullPath = GetVisualTreeAssetPath(view); + if (File.Exists(assetFullPath) == false) + { + context.ReportDiagnostic( + Diagnostic.Create( + "LG01", + "View bindings generator", + "Visual tree asset file is not found.", + defaultSeverity: DiagnosticSeverity.Error, + severity: DiagnosticSeverity.Error, + isEnabledByDefault: true, + warningLevel: 0)); + + return; + } + + var bindableElements = GetBindableElements(assetFullPath); + + foreach (var bindableElement in bindableElements) + { + if (receiver.BindableElements.Captures.TryGetValue(bindableElement.ClassIdentifier, + out var visualElement) == false) + { + continue; + } + + var elementBindingsClass = CreateElementBindingsClass(visualElement, view.ViewModelIdentifier); + File.WriteAllText($@"D:\{visualElement.Class.Identifier.Text}Bindings.txt", elementBindingsClass); + } + + // var sb = new StringBuilder(); + // foreach (var bindableElement in bindableElements) + // { + // sb.Append(bindableElement.ClassIdentifier); + // sb.AppendLine(); + // + // foreach (var attribute in bindableElement.Attributes) + // { + // sb.Append($"{attribute.Key} - {attribute.Value}"); + // sb.AppendLine(); + // } + // + // sb.AppendLine(); + // } + // + // File.WriteAllText($@"D:\BindableElements.txt", sb.ToString()); + + + + // var sb = new StringBuilder(); + // foreach (var visualElement in receiver.BindableElements.Captures) + // { + // sb.Append(visualElement.Key); + // sb.AppendLine(); + // } + + File.WriteAllText($@"D:\BindableElements.txt", receiver.BindableElements.Captures.Values.Count().ToString()); + + foreach (var bindableElement in receiver.BindableElements.Captures.Values) + { + File.WriteAllText($@"D:\{bindableElement.Class.Identifier.Text}.txt", bindableElement.Class.GetText(Encoding.UTF8).ToString()); + } + + var syntaxTree = view.Class.SyntaxTree; + + var semanticModel = compilation.GetSemanticModel(syntaxTree); + var immutableHashSet = syntaxTree.GetRoot() + .DescendantNodesAndSelf() + .OfType() + .Select(x => ModelExtensions.GetDeclaredSymbol(semanticModel, x)) + .OfType() + // .Where(x => x.Interfaces.Contains(viewInterface)) + .ToImmutableHashSet(); + + foreach (var typeSymbol in immutableHashSet) + { + context.AddSource($"{typeSymbol.Name}.g.cs", GenerateView(typeSymbol, context, view)); + } + + // var elementBindingsClass = CreateElementBindingsClass(); + // var output = elementBindingsClass.GetText(Encoding.UTF8).ToString(); + } + } + + private string CreateElementBindingsClass(BindableElementCapture bindableElementCapture, string viewViewModelIdentifier) + { + var classIdentifier = $"{bindableElementCapture.Class.Identifier.Text}Bindings"; + + return $@" +private class {classIdentifier} : IVisualElementBindings +{{ + private readonly {viewViewModelIdentifier} _viewModel; + private readonly BindableLabel _visualElement; + + public {classIdentifier}({viewViewModelIdentifier} viewModel, BindableLabel visualElement) + {{ + _viewModel = viewModel; + _visualElement = visualElement; + }} + + public void UpdateValues() + {{ + {Block(GetUpdateValueMethodBody(bindableElementCapture.Properties)).GetText(Encoding.UTF8)} + }} +}}"; + + // return ClassDeclaration(classIdentifier) + // .WithModifiers(TokenList(Token(SyntaxKind.PrivateKeyword))).WithBaseList( + // BaseList(SingletonSeparatedList( + // SimpleBaseType(IdentifierName("IVisualElementBindings"))))) + // .WithMembers(List(new MemberDeclarationSyntax[] + // { + // FieldDeclaration(VariableDeclaration(IdentifierName("MainMenuViewModel")) + // .WithVariables(SingletonSeparatedList(VariableDeclarator(Identifier("_viewModel"))))) + // .WithModifiers(TokenList(Token(SyntaxKind.PrivateKeyword), Token(SyntaxKind.ReadOnlyKeyword))), + // FieldDeclaration(VariableDeclaration(IdentifierName("BindableLabel")) + // .WithVariables(SingletonSeparatedList(VariableDeclarator(Identifier("_visualElement"))))) + // .WithModifiers(TokenList(Token(SyntaxKind.PrivateKeyword), Token(SyntaxKind.ReadOnlyKeyword))), + // ConstructorDeclaration(Identifier(classIdentifier)) + // .WithModifiers(TokenList(Token(SyntaxKind.PublicKeyword))) + // .WithParameterList( + // ParameterList( + // SeparatedList( + // new SyntaxNodeOrToken[] + // { + // Parameter( + // Identifier("viewModel")) + // .WithType( + // IdentifierName("MainMenuViewModel")), + // Token(SyntaxKind.CommaToken), + // Parameter( + // Identifier("visualElement")) + // .WithType( + // IdentifierName("BindableLabel")) + // }))) + // .WithBody( + // Block( + // ExpressionStatement( + // AssignmentExpression( + // SyntaxKind.SimpleAssignmentExpression, + // IdentifierName("_viewModel"), + // IdentifierName("viewModel"))), + // ExpressionStatement( + // AssignmentExpression( + // SyntaxKind.SimpleAssignmentExpression, + // IdentifierName("_visualElement"), + // IdentifierName("visualElement"))))), + // MethodDeclaration( + // PredefinedType( + // Token(SyntaxKind.VoidKeyword)), + // Identifier("UpdateValues")) + // .WithModifiers( + // TokenList( + // Token(SyntaxKind.PublicKeyword))) + // .WithBody( + // Block(GetUpdateValueMethodBody(bindableElementCapture.Properties))) + // })).NormalizeWhitespace(); + } + // return ClassDeclaration("LabelBindings") + // .WithModifiers(TokenList(Token(SyntaxKind.PrivateKeyword))) + // .WithBaseList(BaseList( + // SingletonSeparatedList(SimpleBaseType(IdentifierName("IVisualElementBindings"))))) + // .WithMembers(List(new MemberDeclarationSyntax[] + // { + // FieldDeclaration(VariableDeclaration(IdentifierName("MainMenuViewModel")) + // .WithVariables(SingletonSeparatedList(VariableDeclarator(Identifier("_viewModel"))))) + // .WithModifiers(TokenList(Token(SyntaxKind.PrivateKeyword), Token(SyntaxKind.ReadOnlyKeyword))), + // FieldDeclaration(VariableDeclaration(IdentifierName("BindableLabel")) + // .WithVariables(SingletonSeparatedList(VariableDeclarator(Identifier("_visualElement"))))) + // .WithModifiers(TokenList(Token(SyntaxKind.PrivateKeyword), Token(SyntaxKind.ReadOnlyKeyword))), + // ConstructorDeclaration(Identifier("LabelBindings")) + // .WithModifiers(TokenList(Token(SyntaxKind.PublicKeyword))) + // .WithParameterList(ParameterList(SeparatedList(new SyntaxNodeOrToken[] + // { + // Parameter(Identifier("viewModel")).WithType(IdentifierName("MainMenuViewModel")), + // Token(SyntaxKind.CommaToken), + // Parameter(Identifier("visualElement")).WithType(IdentifierName("BindableLabel")) + // }))) + // .WithBody(Block( + // ExpressionStatement( + // AssignmentExpression( + // SyntaxKind.SimpleAssignmentExpression, + // IdentifierName("_viewModel"), + // IdentifierName("viewModel"))), + // ExpressionStatement( + // AssignmentExpression( + // SyntaxKind.SimpleAssignmentExpression, + // IdentifierName("_visualElement"), + // IdentifierName("visualElement"))))), + // MethodDeclaration(PredefinedType(Token(SyntaxKind.VoidKeyword)), Identifier("UpdateValues")) + // .WithModifiers(TokenList(Token(SyntaxKind.PublicKeyword))) + // .WithBody(Block(SingletonList( + // ExpressionStatement( + // InvocationExpression(IdentifierName("UpdateStrValue")))))), + // MethodDeclaration(PredefinedType(Token(SyntaxKind.VoidKeyword)), Identifier("UpdateStrValue")) + // .WithAttributeLists(SingletonList( + // AttributeList(SingletonSeparatedList(Attribute(IdentifierName("MethodImpl")) + // .WithArgumentList( + // AttributeArgumentList(SingletonSeparatedList( + // AttributeArgument(MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, + // IdentifierName("MethodImplOptions"), + // IdentifierName("AggressiveInlining")))))))))) + // .WithModifiers(TokenList(Token(SyntaxKind.PrivateKeyword))) + // .WithBody(Block( + // SingletonList( + // IfStatement( + // BinaryExpression( + // SyntaxKind.NotEqualsExpression, + // MemberAccessExpression( + // SyntaxKind.SimpleMemberAccessExpression, + // IdentifierName("_visualElement"), + // IdentifierName("text")), + // MemberAccessExpression( + // SyntaxKind.SimpleMemberAccessExpression, + // IdentifierName("_viewModel"), + // IdentifierName("StrValue"))), + // Block( + // SingletonList( + // ExpressionStatement( + // AssignmentExpression( + // SyntaxKind + // .SimpleAssignmentExpression, + // MemberAccessExpression( + // SyntaxKind + // .SimpleMemberAccessExpression, + // IdentifierName( + // "_visualElement"), + // IdentifierName("text")), + // MemberAccessExpression( + // SyntaxKind + // .SimpleMemberAccessExpression, + // IdentifierName("_viewModel"), + // IdentifierName( + // "StrValue")))))))))) + // })).NormalizeWhitespace(); + //} + + private IEnumerable GetUpdateValueMethodBody(List> properties) + { + var updateValueExpressions = new List(); + + foreach (var property in properties) + { + var leftExpression = MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, + IdentifierName("_visualElement"), IdentifierName(property.Key)); + + var rightExpression = MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, + IdentifierName("_viewModel"), IdentifierName(property.Value.Identifier)); + + updateValueExpressions.Add(IfStatement( + BinaryExpression(SyntaxKind.NotEqualsExpression, leftExpression, rightExpression), + Block(SingletonList(ExpressionStatement( + AssignmentExpression(SyntaxKind.SimpleAssignmentExpression, leftExpression, rightExpression)))))); + } + + return updateValueExpressions; + + // + // return new StatementSyntax[] + // { + // IfStatement( + // BinaryExpression( + // SyntaxKind.NotEqualsExpression, + // MemberAccessExpression( + // SyntaxKind.SimpleMemberAccessExpression, + // IdentifierName("_visualElement"), + // IdentifierName("text")), + // MemberAccessExpression( + // SyntaxKind.SimpleMemberAccessExpression, + // IdentifierName("_viewModel"), + // IdentifierName("StrValue"))), + // Block( + // SingletonList( + // ExpressionStatement( + // AssignmentExpression( + // SyntaxKind.SimpleAssignmentExpression, + // MemberAccessExpression( + // SyntaxKind.SimpleMemberAccessExpression, + // IdentifierName("_visualElement"), + // IdentifierName("text")), + // MemberAccessExpression( + // SyntaxKind.SimpleMemberAccessExpression, + // IdentifierName("_viewModel"), + // IdentifierName("StrValue"))))))), + // IfStatement( + // BinaryExpression( + // SyntaxKind.NotEqualsExpression, + // MemberAccessExpression( + // SyntaxKind.SimpleMemberAccessExpression, + // IdentifierName("_visualElement"), + // IdentifierName("text")), + // MemberAccessExpression( + // SyntaxKind.SimpleMemberAccessExpression, + // IdentifierName("_viewModel"), + // IdentifierName("StrValue"))), + // Block( + // SingletonList( + // ExpressionStatement( + // AssignmentExpression( + // SyntaxKind.SimpleAssignmentExpression, + // MemberAccessExpression( + // SyntaxKind.SimpleMemberAccessExpression, + // IdentifierName("_visualElement"), + // IdentifierName("text")), + // MemberAccessExpression( + // SyntaxKind.SimpleMemberAccessExpression, + // IdentifierName("_viewModel"), + // IdentifierName("StrValue"))))))) + // }; + } + + // private MethodDeclarationSyntax CreateViewClass + + private string GenerateView(ITypeSymbol typeSymbol, GeneratorExecutionContext context, ViewCapture view) + { + var usingDirectives = view.Class.SyntaxTree.GetRoot().DescendantNodes() + .OfType(); + var usingDirectivesAsText = string.Join("\r\n", usingDirectives); + + return $@"using System; +using System.Runtime.CompilerServices; +using UnityEngine.UIElements; +using UnityMvvmToolkit.Common.Interfaces; +using UnityMvvmToolkit.UI.BindableVisualElements; + +{usingDirectivesAsText} + +namespace {typeSymbol.ContainingNamespace} +{{ + public partial class {typeSymbol.Name} + {{ +// {view.AssetPath} +// {view.Class.Identifier.Text} +// {view.ViewModelIdentifier} +// {view.Class.GetParent().Name} + {GenerateBody(typeSymbol)} + }} +}}"; + } + + private IEnumerable GetBindableElements(string assetFullPath) + { + var result = new List(); + + var xmlDocument = new XmlDocument(); + xmlDocument.Load(assetFullPath); + + if (xmlDocument.DocumentElement == null) + { + return result; + } + + foreach (XmlNode node in xmlDocument.DocumentElement.ChildNodes) + { + if (node.Name.Contains(BindableIdentifier) == false) + { + continue; + } + + if (node.Attributes == null) + { + continue; + } + + var bindableElementInfo = new BindableElementInfo(node.Name.Split('.').Last()); + + foreach (XmlAttribute attribute in node.Attributes) + { + bindableElementInfo.Attributes.Add(new KeyValuePair(attribute.Name, attribute.Value)); + } + + result.Add(bindableElementInfo); + } + + return result; + } + + private string GetVisualTreeAssetPath(ViewCapture view) + { + if (view.Class.SyntaxTree.HasCompilationUnitRoot == false) + { + return null; + } + + var viewDirectory = Path.GetDirectoryName(view.Class.SyntaxTree.FilePath); + var assetsFolderIndex = viewDirectory?.IndexOf(AssetsFolderName, StringComparison.Ordinal); + + return assetsFolderIndex is null or -1 + ? null + : Path.Combine(viewDirectory.Substring(0, assetsFolderIndex.Value + AssetsFolderName.Length), + view.AssetPath); + } + + private string GenerateBody(ITypeSymbol typeSymbol) + { + return + $@"protected override IVisualElementBindings GetVisualElementsBindings(MainMenuViewModel bindingContext, + IBindableVisualElement bindableElement) + {{ + return bindableElement switch + {{ + BindableLabel bindableLabel => new LabelBindings(bindingContext, bindableLabel), + BindableTextField bindableTextField => new TextFieldBindings(bindingContext, bindableTextField), + _ => default + }}; + }} + + private class LabelBindings : IVisualElementBindings + {{ + private readonly MainMenuViewModel _viewModel; + private readonly BindableLabel _visualElement; + + public LabelBindings(MainMenuViewModel viewModel, BindableLabel visualElement) + {{ + _viewModel = viewModel; + _visualElement = visualElement; + }} + + public void UpdateValues() + {{ + UpdateStrValue(); + }} + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void UpdateStrValue() + {{ + if (_visualElement.text != _viewModel.StrValue) + {{ + _visualElement.text = _viewModel.StrValue; + }} + }} + }} + + private class TextFieldBindings : IVisualElementBindings, IDisposable + {{ + private readonly MainMenuViewModel _viewModel; + private readonly BindableTextField _visualElement; + + public TextFieldBindings(MainMenuViewModel viewModel, BindableTextField visualElement) + {{ + _viewModel = viewModel; + + _visualElement = visualElement; + _visualElement.RegisterValueChangedCallback(OnVisualElementValueChanged); + }} + + public void Dispose() + {{ + _visualElement.UnregisterValueChangedCallback(OnVisualElementValueChanged); + }} + + public void UpdateValues() + {{ + UpdateStrValue(); + }} + + private void OnVisualElementValueChanged(ChangeEvent e) + {{ + _viewModel.StrValue = e.newValue; + }} + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void UpdateStrValue() + {{ + if (_visualElement.value != _viewModel.StrValue) + {{ + _visualElement.SetValueWithoutNotify(_viewModel.StrValue); + }} + }} + }}"; + } + + // private class SyntaxReceiver : ISyntaxContextReceiver + // { + // public List Classes { get; } = new List(); + // + // /// + // /// Called for every syntax node in the compilation, we can inspect the nodes and save any information useful for generation + // /// + // public void OnVisitSyntaxNode(GeneratorSyntaxContext context) + // { + // // any field with at least one attribute is a candidate for property generation + // if (context.Node is ClassDeclarationSyntax classDeclarationSyntax && + // classDeclarationSyntax.AttributeLists.Count > 0) + // { + // // Classes.Add(classDeclarationSyntax.dec.Select(x => semanticModel.GetDeclaredSymbol(x)) + // // .OfType()); + // // if (classDeclarationSyntax.AttributeLists.Any(ad => ad.)) + // // foreach (var variable in classDeclarationSyntax.Declaration.Variables) + // // { + // // // Get the symbol being declared by the field, and keep it if its annotated + // // ITypeSymbol fieldSymbol = context.SemanticModel.GetDeclaredSymbol(variable) as IFieldSymbol; + // // if (fieldSymbol.GetAttributes().Any(ad => ad.AttributeClass.ToDisplayString() == "AutoNotify.AutoNotifyAttribute")) + // // { + // // Fields.Add(fieldSymbol); + // // } + // // } + // } + // } + // } +} \ No newline at end of file diff --git a/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UnityMvvmToolkit.Common/Attributes/VisualTreeAssetAttribute.cs b/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UnityMvvmToolkit.Common/Attributes/VisualTreeAssetAttribute.cs new file mode 100644 index 0000000..0bf1098 --- /dev/null +++ b/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UnityMvvmToolkit.Common/Attributes/VisualTreeAssetAttribute.cs @@ -0,0 +1,15 @@ +using System; + +namespace UnityMvvmToolkit.Common.Attributes +{ + [AttributeUsage(AttributeTargets.Class, Inherited = false)] + public class VisualTreeAssetAttribute : Attribute + { + public VisualTreeAssetAttribute(string assetPath) + { + AssetPath = assetPath; + } + + public string AssetPath { get; } + } +} \ No newline at end of file diff --git a/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UnityMvvmToolkit.Common/Attributes/VisualTreeAssetAttribute.cs.meta b/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UnityMvvmToolkit.Common/Attributes/VisualTreeAssetAttribute.cs.meta new file mode 100644 index 0000000..b2e1125 --- /dev/null +++ b/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UnityMvvmToolkit.Common/Attributes/VisualTreeAssetAttribute.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: d4e3531fa92d4d629ad073fb07c9f224 +timeCreated: 1657809287 \ No newline at end of file diff --git a/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UnityMvvmToolkit.Common/Interfaces/IView.cs b/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UnityMvvmToolkit.Common/Interfaces/IView.cs new file mode 100644 index 0000000..a5abded --- /dev/null +++ b/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UnityMvvmToolkit.Common/Interfaces/IView.cs @@ -0,0 +1,6 @@ +namespace UnityMvvmToolkit.Common.Interfaces +{ + public interface IView + { + } +} \ No newline at end of file diff --git a/samples/Unity.Mvvm.MainMenu/Assets/Scripts/HelloFromSourceGenerator.cs.meta b/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UnityMvvmToolkit.Common/Interfaces/IView.cs.meta similarity index 83% rename from samples/Unity.Mvvm.MainMenu/Assets/Scripts/HelloFromSourceGenerator.cs.meta rename to src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UnityMvvmToolkit.Common/Interfaces/IView.cs.meta index 5fab6ea..30b6054 100644 --- a/samples/Unity.Mvvm.MainMenu/Assets/Scripts/HelloFromSourceGenerator.cs.meta +++ b/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UnityMvvmToolkit.Common/Interfaces/IView.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 0a9a6d990dc283e4d91d57e902903ec0 +guid: e5a9b259942b63e47ac312d34bfe9e1d MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UnityMvvmToolkit.Common/Interfaces/IVisualElementBindings.cs b/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UnityMvvmToolkit.Common/Interfaces/IVisualElementBindings.cs new file mode 100644 index 0000000..69abbf1 --- /dev/null +++ b/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UnityMvvmToolkit.Common/Interfaces/IVisualElementBindings.cs @@ -0,0 +1,7 @@ +namespace UnityMvvmToolkit.Common.Interfaces +{ + public interface IVisualElementBindings + { + void UpdateValues(); + } +} \ No newline at end of file diff --git a/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UnityMvvmToolkit.Common/Interfaces/IVisualElementBindings.cs.meta b/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UnityMvvmToolkit.Common/Interfaces/IVisualElementBindings.cs.meta new file mode 100644 index 0000000..fe8d7c1 --- /dev/null +++ b/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UnityMvvmToolkit.Common/Interfaces/IVisualElementBindings.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6084ace45cd4edd4e833e57d9758ab6d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UnityMvvmToolkit.Common/ViewModel.cs b/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UnityMvvmToolkit.Common/ViewModel.cs new file mode 100644 index 0000000..f875b65 --- /dev/null +++ b/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UnityMvvmToolkit.Common/ViewModel.cs @@ -0,0 +1,44 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Runtime.CompilerServices; + +namespace UnityMvvmToolkit.Common +{ + public abstract class ViewModel : INotifyPropertyChanged + { + public event PropertyChangedEventHandler PropertyChanged; + + protected bool Set(ref T oldValue, T newValue, [CallerMemberName] string propertyName = default) + { + if (EqualityComparer.Default.Equals(oldValue, newValue)) + { + return false; + } + + oldValue = newValue; + OnPropertyChanged(propertyName); + + return true; + } + + protected bool Set(T oldValue, T newValue, TModel model, Action callback, + [CallerMemberName] string propertyName = default) where TModel : class + { + if (EqualityComparer.Default.Equals(oldValue, newValue)) + { + return false; + } + + callback(model, newValue); + OnPropertyChanged(propertyName); + + return true; + } + + protected void OnPropertyChanged(string propertyName) + { + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + } + } +} \ No newline at end of file diff --git a/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UnityMvvmToolkit.Common/ViewModel.cs.meta b/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UnityMvvmToolkit.Common/ViewModel.cs.meta new file mode 100644 index 0000000..419b00e --- /dev/null +++ b/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UnityMvvmToolkit.Common/ViewModel.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9df4a38140ed43b4eb36e8bab44d7f27 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UnityMvvmToolkit.SourceGenerators.dll b/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UnityMvvmToolkit.SourceGenerators.dll index 347cef22afe7f10de54c2437115e5f55fce31542..e18edb90d579e4a24d2d3ea3eca619a5dc4a87c1 100644 GIT binary patch literal 23552 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 g4}STi4UD@W&wdcNqfz4;XzCHvj+t delta 1747 zcmZuyZERCj7=F%Ocj?O3wcQw>!d*MNu|ZR^Y%nXbF-94x0g!J4kEU8@r# z+lUzO&zvVqz!;7G(L^O7BtkF^;>nKO_T;_J15|>bPcds=HC+2b6*CW z^Nj9OEA1q)&DB>>?4?c_>BC1GWQOQ~)`<9e;Zqa^v{DQDeOIVo3u)dFhs`zMxqN_rYzBBVTXm?7Dg-_ zwlGH2anjOHq6%w}z^pJZNBTOP#y4UkX5dFN{VFoR#_lIpAx2z_X`+w$0W{$Xu^HbJ zL->_A)d?X2*k>&a5B7%~d*e8JQ}~ezt_N6%8YO>yNz^;pa?1%EHgh9G z(cRndU{5-pPnr**Ba<;xaiq-LL@t(!$FgyBEQ`kn)A{U}yld1*e{E1cU3*4u_ipuc zO`2o*oQdvKBA19I6Gu$B%vWcRrVHm&o^9~TpM1+@XWfe4-P!aw2A`eCnd5;0^H9

^_yE$ijgpiAy(wad}w>WVH*vg6~(APH0699mmqA};$w_sQ!a zznl#@>nC_tW1I<$!Qf2Nn&4yL|8sAI?zeJB+8mvEj55BE`EMR&Wx0~VVKRkb(vA|9 zU&%?z1|B#=D!#ssfV{rdB|mR*#=KmAf|;s<0v;k$ntL$lOCwKfj0^^uP4b(xRsCs7 z1K6tEQYvn@GM%<%!qY|D)8*uflh?GTy9_0s9;c_<9nlR< zI6Xb~h3BgN_+s<75&M?Q+a7tpwYSA$*luBmT@;V(di9M*wVFq>u}rVb^uO-4iQ@64 zxHL1e2+`B8PV`%x3%oQJ%H`2Wjh^DAovM(pM!c@zt=ZOf2NuIGJazk*J4@To%7w^$ zpy+(&)1s49k5?Z1cpjg8IBfIHv|K7)`s!t0H_6$7HQKc%`R+iUbVfs>{oLN@`O-3@ R@Xzvd=$w21l9&tXe*)?PRzUy& diff --git a/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UnityMvvmToolkit.UI/BindableVisualElements/BindableLabel.cs b/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UnityMvvmToolkit.UI/BindableVisualElements/BindableLabel.cs new file mode 100644 index 0000000..2aa7581 --- /dev/null +++ b/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UnityMvvmToolkit.UI/BindableVisualElements/BindableLabel.cs @@ -0,0 +1,29 @@ +using UnityEngine.UIElements; +using UnityMvvmToolkit.Common.Attributes; +using UnityMvvmToolkit.Common.Interfaces; + +namespace UnityMvvmToolkit.UI.BindableVisualElements +{ + public class BindableLabel : Label, IBindableVisualElement + { + [BindTo(nameof(text))] + public string BindingTextPath { get; set; } + + public new class UxmlFactory : UxmlFactory + { + } + + public new class UxmlTraits : Label.UxmlTraits + { + private readonly UxmlStringAttributeDescription _bindingTextAttribute = new() + { name = "binding-text-path", defaultValue = "binding-property-name" }; + + public override void Init(VisualElement visualElement, IUxmlAttributes bag, CreationContext context) + { + base.Init(visualElement, bag, context); + ((BindableLabel) visualElement).BindingTextPath = + _bindingTextAttribute.GetValueFromBag(bag, context); + } + } + } +} \ No newline at end of file diff --git a/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UnityMvvmToolkit.UI/BindableVisualElements/BindableLabel.cs.meta b/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UnityMvvmToolkit.UI/BindableVisualElements/BindableLabel.cs.meta new file mode 100644 index 0000000..036cc05 --- /dev/null +++ b/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UnityMvvmToolkit.UI/BindableVisualElements/BindableLabel.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: dd55009627c7475ba7f9a364c7292a5b +timeCreated: 1657789669 \ No newline at end of file diff --git a/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UnityMvvmToolkit.UI/View.cs b/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UnityMvvmToolkit.UI/View.cs new file mode 100644 index 0000000..63be022 --- /dev/null +++ b/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UnityMvvmToolkit.UI/View.cs @@ -0,0 +1,127 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Reflection; +using UnityEngine; +using UnityEngine.UIElements; +using UnityMvvmToolkit.Common.Interfaces; + +namespace UnityMvvmToolkit.UI +{ + [RequireComponent(typeof(UIDocument))] + public abstract class View : MonoBehaviour where TBindingContext : class, INotifyPropertyChanged, new() + { + private UIDocument _uiDocument; + private TBindingContext _bindingContext; + private List _disposables; + private Dictionary> _visualElementsBindings; + + private void Awake() + { + _uiDocument = GetComponent(); + _bindingContext = GetBindingContext(); + + _disposables = new List(); + _visualElementsBindings = new Dictionary>(); + + BindElements(_bindingContext, _uiDocument.rootVisualElement); + } + + private void OnEnable() + { + _bindingContext.PropertyChanged += OnBindingContextPropertyChanged; + } + + private void OnDisable() + { + _bindingContext.PropertyChanged -= OnBindingContextPropertyChanged; + } + + private void OnDestroy() + { + // TODO: Unregister bindable elements (like TextField). + + foreach (var disposable in _disposables) + { + disposable.Dispose(); + } + } + + protected virtual TBindingContext GetBindingContext() + { + return new TBindingContext(); // TODO: Change DataContext dynamically? + } + + protected virtual IVisualElementBindings GetVisualElementsBindings(TBindingContext bindingContext, + IBindableVisualElement bindableElement) + { + throw new NotImplementedException(); + } + + private void BindElements(TBindingContext bindingContext, VisualElement rootVisualElement) + { + // var bindingContextProperties = + // typeof(TBindingContext).GetProperties(BindingFlags.Public | BindingFlags.Instance | + // BindingFlags.DeclaredOnly); + + rootVisualElement.Query().ForEach(visualElement => + { + if (visualElement is IBindableVisualElement bindableElement) + { + RegisterBindableElement(bindableElement); + } + }); + } + + private void RegisterBindableElement(IBindableVisualElement bindableElement) + { + var bindingProperties = bindableElement.GetType() + .GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly); + + foreach (var bindingPropertyInfo in bindingProperties) + { + var sourcePropertyName = bindingPropertyInfo.GetValue(bindableElement).ToString(); + if (string.IsNullOrWhiteSpace(sourcePropertyName)) + { + continue; + } + + var sourcePropertyInfo = typeof(TBindingContext).GetProperty(sourcePropertyName); // TODO: Cache properties to dictionary. + if (sourcePropertyInfo == null) + { + throw new NullReferenceException(nameof(sourcePropertyInfo)); + } + + var visualElementBindings = GetVisualElementsBindings(_bindingContext, bindableElement); + if (visualElementBindings == null) + { + throw new NullReferenceException(nameof(visualElementBindings)); + } + + if (visualElementBindings is IDisposable disposable) + { + _disposables.Add(disposable); + } + + if (_visualElementsBindings.TryGetValue(sourcePropertyName, out var visualElements) == false) + { + visualElements = new HashSet(); + _visualElementsBindings.Add(sourcePropertyName, visualElements); + } + + visualElementBindings.UpdateValues(); + visualElements.Add(visualElementBindings); + } + } + private void OnBindingContextPropertyChanged(object sender, PropertyChangedEventArgs e) + { + if (_visualElementsBindings.TryGetValue(e.PropertyName, out var visualElements)) + { + foreach (var visualElement in visualElements) + { + visualElement.UpdateValues(); + } + } + } + } +} \ No newline at end of file diff --git a/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UnityMvvmToolkit.UI/View.cs.meta b/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UnityMvvmToolkit.UI/View.cs.meta new file mode 100644 index 0000000..0f5d939 --- /dev/null +++ b/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UnityMvvmToolkit.UI/View.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 0c23133e65c84117a6d710966201599b +timeCreated: 1657793186 \ No newline at end of file From b6b50cafab86a9003ee22042744fa3870b158273 Mon Sep 17 00:00:00 2001 From: ChebanovDD Date: Sat, 16 Jul 2022 10:45:38 +0700 Subject: [PATCH 2/2] Add simple source generator. --- .../Scripts/ViewModels/MainMenuViewModel.cs | 7 + .../Assets/Scripts/Views/MainMenuView.cs | 81 +++- .../Assets/Scripts/Views/MainMenuView.g.cs | 86 ---- .../Scripts/Views/MainMenuView.g.cs.meta | 3 - .../Assets/UI Toolkit/MainMenu.uxml | 5 +- .../Assets/UnityMvvmToolkit.meta | 8 + .../Assets/UnityMvvmToolkit/Common.meta | 8 + .../UnityMvvmToolkit/Common/Attributes.meta | 8 + .../Common/Attributes/BindToAttribute.cs | 15 + .../Common/Attributes/BindToAttribute.cs.meta | 11 + .../Attributes/VisualTreeAssetAttribute.cs | 15 + .../VisualTreeAssetAttribute.cs.meta | 11 + .../UnityMvvmToolkit/Common/Interfaces.meta | 8 + .../Interfaces/IBindableVisualElement.cs | 6 + .../Interfaces/IBindableVisualElement.cs.meta | 11 + .../Common/Interfaces/IView.cs | 6 + .../Common/Interfaces/IView.cs.meta | 11 + .../Interfaces/IVisualElementBindings.cs | 7 + .../Interfaces/IVisualElementBindings.cs.meta | 11 + .../UnityMvvmToolkit/Common/ViewModel.cs | 44 ++ .../UnityMvvmToolkit/Common/ViewModel.cs.meta | 11 + .../Assets/UnityMvvmToolkit/UI.meta | 8 + .../UI/BindableVisualElements.meta | 8 + .../BindableVisualElements/BindableLabel.cs | 29 ++ .../BindableLabel.cs.meta | 3 + .../BindableTextField.cs | 29 ++ .../BindableTextField.cs.meta | 3 + .../Assets/UnityMvvmToolkit/UI/View.cs | 130 +++++ .../Assets/UnityMvvmToolkit/UI/View.cs.meta | 3 + .../UnityMvvmToolkit.SourceGenerators.dll | Bin 0 -> 23552 bytes ...UnityMvvmToolkit.SourceGenerators.dll.meta | 71 +++ .../Packages/manifest.json | 1 - .../Packages/packages-lock.json | 6 - .../UnityMvvmToolkit.Common.csproj | 2 +- .../Captures/BindableElementCapture.cs | 5 +- ...lementInfo.cs => VisualTreeElementInfo.cs} | 4 +- .../BindableElementsReceiver.cs | 3 +- .../UnityMvvmToolkit.SourceGenerators.csproj | 2 +- .../ViewBindingsGenerator.cs | 459 ++++-------------- .../UnityMvvmToolkit.SourceGenerators.dll | Bin 23552 -> 23552 bytes 40 files changed, 666 insertions(+), 473 deletions(-) delete mode 100644 samples/Unity.Mvvm.MainMenu/Assets/Scripts/Views/MainMenuView.g.cs delete mode 100644 samples/Unity.Mvvm.MainMenu/Assets/Scripts/Views/MainMenuView.g.cs.meta create mode 100644 samples/Unity.Mvvm.MainMenu/Assets/UnityMvvmToolkit.meta create mode 100644 samples/Unity.Mvvm.MainMenu/Assets/UnityMvvmToolkit/Common.meta create mode 100644 samples/Unity.Mvvm.MainMenu/Assets/UnityMvvmToolkit/Common/Attributes.meta create mode 100644 samples/Unity.Mvvm.MainMenu/Assets/UnityMvvmToolkit/Common/Attributes/BindToAttribute.cs create mode 100644 samples/Unity.Mvvm.MainMenu/Assets/UnityMvvmToolkit/Common/Attributes/BindToAttribute.cs.meta create mode 100644 samples/Unity.Mvvm.MainMenu/Assets/UnityMvvmToolkit/Common/Attributes/VisualTreeAssetAttribute.cs create mode 100644 samples/Unity.Mvvm.MainMenu/Assets/UnityMvvmToolkit/Common/Attributes/VisualTreeAssetAttribute.cs.meta create mode 100644 samples/Unity.Mvvm.MainMenu/Assets/UnityMvvmToolkit/Common/Interfaces.meta create mode 100644 samples/Unity.Mvvm.MainMenu/Assets/UnityMvvmToolkit/Common/Interfaces/IBindableVisualElement.cs create mode 100644 samples/Unity.Mvvm.MainMenu/Assets/UnityMvvmToolkit/Common/Interfaces/IBindableVisualElement.cs.meta create mode 100644 samples/Unity.Mvvm.MainMenu/Assets/UnityMvvmToolkit/Common/Interfaces/IView.cs create mode 100644 samples/Unity.Mvvm.MainMenu/Assets/UnityMvvmToolkit/Common/Interfaces/IView.cs.meta create mode 100644 samples/Unity.Mvvm.MainMenu/Assets/UnityMvvmToolkit/Common/Interfaces/IVisualElementBindings.cs create mode 100644 samples/Unity.Mvvm.MainMenu/Assets/UnityMvvmToolkit/Common/Interfaces/IVisualElementBindings.cs.meta create mode 100644 samples/Unity.Mvvm.MainMenu/Assets/UnityMvvmToolkit/Common/ViewModel.cs create mode 100644 samples/Unity.Mvvm.MainMenu/Assets/UnityMvvmToolkit/Common/ViewModel.cs.meta create mode 100644 samples/Unity.Mvvm.MainMenu/Assets/UnityMvvmToolkit/UI.meta create mode 100644 samples/Unity.Mvvm.MainMenu/Assets/UnityMvvmToolkit/UI/BindableVisualElements.meta create mode 100644 samples/Unity.Mvvm.MainMenu/Assets/UnityMvvmToolkit/UI/BindableVisualElements/BindableLabel.cs create mode 100644 samples/Unity.Mvvm.MainMenu/Assets/UnityMvvmToolkit/UI/BindableVisualElements/BindableLabel.cs.meta create mode 100644 samples/Unity.Mvvm.MainMenu/Assets/UnityMvvmToolkit/UI/BindableVisualElements/BindableTextField.cs create mode 100644 samples/Unity.Mvvm.MainMenu/Assets/UnityMvvmToolkit/UI/BindableVisualElements/BindableTextField.cs.meta create mode 100644 samples/Unity.Mvvm.MainMenu/Assets/UnityMvvmToolkit/UI/View.cs create mode 100644 samples/Unity.Mvvm.MainMenu/Assets/UnityMvvmToolkit/UI/View.cs.meta create mode 100644 samples/Unity.Mvvm.MainMenu/Assets/UnityMvvmToolkit/UnityMvvmToolkit.SourceGenerators.dll create mode 100644 samples/Unity.Mvvm.MainMenu/Assets/UnityMvvmToolkit/UnityMvvmToolkit.SourceGenerators.dll.meta rename src/UnityMvvmToolkit.SourceGenerators/Models/{BindableElementInfo.cs => VisualTreeElementInfo.cs} (77%) diff --git a/samples/Unity.Mvvm.MainMenu/Assets/Scripts/ViewModels/MainMenuViewModel.cs b/samples/Unity.Mvvm.MainMenu/Assets/Scripts/ViewModels/MainMenuViewModel.cs index 4825d18..1c8c4c8 100644 --- a/samples/Unity.Mvvm.MainMenu/Assets/Scripts/ViewModels/MainMenuViewModel.cs +++ b/samples/Unity.Mvvm.MainMenu/Assets/Scripts/ViewModels/MainMenuViewModel.cs @@ -5,11 +5,18 @@ namespace ViewModels public class MainMenuViewModel : ViewModel { private string _strValue; + private string _strValue1; public string StrValue { get => _strValue; set => Set(ref _strValue, value); } + + public string StrValue1 + { + get => _strValue1; + set => Set(ref _strValue1, value); + } } } \ No newline at end of file diff --git a/samples/Unity.Mvvm.MainMenu/Assets/Scripts/Views/MainMenuView.cs b/samples/Unity.Mvvm.MainMenu/Assets/Scripts/Views/MainMenuView.cs index 14b0c72..affb908 100644 --- a/samples/Unity.Mvvm.MainMenu/Assets/Scripts/Views/MainMenuView.cs +++ b/samples/Unity.Mvvm.MainMenu/Assets/Scripts/Views/MainMenuView.cs @@ -1,15 +1,90 @@ -using UnityMvvmToolkit.Common.Attributes; +using System; +using System.ComponentModel; +using UnityMvvmToolkit.Common.Attributes; using UnityMvvmToolkit.UI; using ViewModels; +using UnityEngine.UIElements; +using System.Collections.Generic; +using UnityMvvmToolkit.UI.BindableVisualElements; + namespace Views { - [VisualTreeAsset("UI Toolkit/MainMenu.uxml")] + // [VisualTreeAsset("UI Toolkit/MainMenu.uxml")] public partial class MainMenuView : View { protected override MainMenuViewModel GetBindingContext() { - return new MainMenuViewModel { StrValue = "Test String" }; + return new MainMenuViewModel { StrValue = "Test String!!!", StrValue1 = "It works!!!" }; + } + } + + public partial class MainMenuView + { + private BindableLabel _label0; + private BindableTextField _textField0; + private BindableTextField _textField1; + + private Dictionary _updateValuesAction; + + protected override void BindElements(MainMenuViewModel bindingContext, VisualElement rootVisualElement) + { + _label0 = rootVisualElement.Q("label0"); + + _textField0 = rootVisualElement.Q("textField0"); + _textField0.RegisterValueChangedCallback(OnUpdateStrValue); + + _textField1 = rootVisualElement.Q("textField1"); + _textField1.RegisterValueChangedCallback(OnUpdateStrValue1); + + _updateValuesAction = new Dictionary + { + { "StrValue", UpdateStrValueSubscribers }, + { "StrValue1", UpdateStrValue1Subscribers } + }; + + UpdateStrValueSubscribers(); + UpdateStrValue1Subscribers(); + } + + private void OnUpdateStrValue(ChangeEvent e) + { + BindingContext.StrValue = e.newValue; + } + + private void OnUpdateStrValue1(ChangeEvent e) + { + BindingContext.StrValue1 = e.newValue; + } + + private void UpdateStrValueSubscribers() + { + var newValue = BindingContext.StrValue; + + if (_label0.text != newValue) + { + _label0.text = newValue; + } + + if (_textField0.value != newValue) + { + _textField0.SetValueWithoutNotify(newValue); + } + } + + private void UpdateStrValue1Subscribers() + { + var newValue = BindingContext.StrValue1; + + if (_textField1.value != newValue) + { + _textField1.SetValueWithoutNotify(newValue); + } + } + + protected override void OnBindingContextPropertyChanged(object sender, PropertyChangedEventArgs e) + { + _updateValuesAction[e.PropertyName](); } } } \ No newline at end of file diff --git a/samples/Unity.Mvvm.MainMenu/Assets/Scripts/Views/MainMenuView.g.cs b/samples/Unity.Mvvm.MainMenu/Assets/Scripts/Views/MainMenuView.g.cs deleted file mode 100644 index aaf129a..0000000 --- a/samples/Unity.Mvvm.MainMenu/Assets/Scripts/Views/MainMenuView.g.cs +++ /dev/null @@ -1,86 +0,0 @@ -// using System; -// using System.Runtime.CompilerServices; -// using UnityEngine.UIElements; -// using UnityMvvmToolkit.Common.Interfaces; -// using UnityMvvmToolkit.UI.BindableVisualElements; - -namespace Views -{ - // public partial class MainMenuView - // { - // protected override IVisualElementBindings GetVisualElementsBindings(ViewModels.MainMenuViewModel bindingContext, - // IBindableVisualElement bindableElement) - // { - // return bindableElement switch - // { - // BindableLabel bindableLabel => new LabelBindings(bindingContext, bindableLabel), - // BindableTextField bindableTextField => new TextFieldBindings(bindingContext, bindableTextField), - // _ => default - // }; - // } - // - // private class LabelBindings : IVisualElementBindings - // { - // private readonly ViewModels.MainMenuViewModel _viewModel; - // private readonly BindableLabel _visualElement; - // - // public LabelBindings(ViewModels.MainMenuViewModel viewModel, BindableLabel visualElement) - // { - // _viewModel = viewModel; - // _visualElement = visualElement; - // } - // - // public void UpdateValues() - // { - // UpdateStrValue(); - // } - // - // [MethodImpl(MethodImplOptions.AggressiveInlining)] - // private void UpdateStrValue() - // { - // if (_visualElement.text != _viewModel.StrValue) - // { - // _visualElement.text = _viewModel.StrValue; - // } - // } - // } - // - // private class TextFieldBindings : IVisualElementBindings, IDisposable - // { - // private readonly ViewModels.MainMenuViewModel _viewModel; - // private readonly BindableTextField _visualElement; - // - // public TextFieldBindings(ViewModels.MainMenuViewModel viewModel, BindableTextField visualElement) - // { - // _viewModel = viewModel; - // - // _visualElement = visualElement; - // _visualElement.RegisterValueChangedCallback(OnVisualElementValueChanged); - // } - // - // public void Dispose() - // { - // _visualElement.UnregisterValueChangedCallback(OnVisualElementValueChanged); - // } - // - // public void UpdateValues() - // { - // UpdateStrValue(); - // } - // - // private void OnVisualElementValueChanged(ChangeEvent e) - // { - // _viewModel.StrValue = e.newValue; - // } - // - // [MethodImpl(MethodImplOptions.AggressiveInlining)] - // private void UpdateStrValue() - // { - // if (_visualElement.value != _viewModel.StrValue) - // { - // _visualElement.SetValueWithoutNotify(_viewModel.StrValue); - // } - // } - // } - // } -} \ No newline at end of file diff --git a/samples/Unity.Mvvm.MainMenu/Assets/Scripts/Views/MainMenuView.g.cs.meta b/samples/Unity.Mvvm.MainMenu/Assets/Scripts/Views/MainMenuView.g.cs.meta deleted file mode 100644 index 8a73036..0000000 --- a/samples/Unity.Mvvm.MainMenu/Assets/Scripts/Views/MainMenuView.g.cs.meta +++ /dev/null @@ -1,3 +0,0 @@ -fileFormatVersion: 2 -guid: 333c653f4a914c3bb1ba30a86e8dd8a3 -timeCreated: 1657797313 \ No newline at end of file diff --git a/samples/Unity.Mvvm.MainMenu/Assets/UI Toolkit/MainMenu.uxml b/samples/Unity.Mvvm.MainMenu/Assets/UI Toolkit/MainMenu.uxml index 90f98c7..1f330db 100644 --- a/samples/Unity.Mvvm.MainMenu/Assets/UI Toolkit/MainMenu.uxml +++ b/samples/Unity.Mvvm.MainMenu/Assets/UI Toolkit/MainMenu.uxml @@ -1,4 +1,5 @@ - - + + + diff --git a/samples/Unity.Mvvm.MainMenu/Assets/UnityMvvmToolkit.meta b/samples/Unity.Mvvm.MainMenu/Assets/UnityMvvmToolkit.meta new file mode 100644 index 0000000..91ac310 --- /dev/null +++ b/samples/Unity.Mvvm.MainMenu/Assets/UnityMvvmToolkit.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 29b0e72167ffd92489591aa499884528 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/samples/Unity.Mvvm.MainMenu/Assets/UnityMvvmToolkit/Common.meta b/samples/Unity.Mvvm.MainMenu/Assets/UnityMvvmToolkit/Common.meta new file mode 100644 index 0000000..6f059a1 --- /dev/null +++ b/samples/Unity.Mvvm.MainMenu/Assets/UnityMvvmToolkit/Common.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 4942c783af6eef54faeb35b5f26d6525 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/samples/Unity.Mvvm.MainMenu/Assets/UnityMvvmToolkit/Common/Attributes.meta b/samples/Unity.Mvvm.MainMenu/Assets/UnityMvvmToolkit/Common/Attributes.meta new file mode 100644 index 0000000..03e17fd --- /dev/null +++ b/samples/Unity.Mvvm.MainMenu/Assets/UnityMvvmToolkit/Common/Attributes.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 02ac014099ac8b54784c32293a6e7234 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/samples/Unity.Mvvm.MainMenu/Assets/UnityMvvmToolkit/Common/Attributes/BindToAttribute.cs b/samples/Unity.Mvvm.MainMenu/Assets/UnityMvvmToolkit/Common/Attributes/BindToAttribute.cs new file mode 100644 index 0000000..b570517 --- /dev/null +++ b/samples/Unity.Mvvm.MainMenu/Assets/UnityMvvmToolkit/Common/Attributes/BindToAttribute.cs @@ -0,0 +1,15 @@ +using System; + +namespace UnityMvvmToolkit.Common.Attributes +{ + [AttributeUsage(AttributeTargets.Property)] + public sealed class BindToAttribute : Attribute + { + public BindToAttribute(string targetPropertyName) // TODO: One or two way (set from uxml). + { + TargetPropertyName = targetPropertyName; + } + + public string TargetPropertyName { get; } + } +} \ No newline at end of file diff --git a/samples/Unity.Mvvm.MainMenu/Assets/UnityMvvmToolkit/Common/Attributes/BindToAttribute.cs.meta b/samples/Unity.Mvvm.MainMenu/Assets/UnityMvvmToolkit/Common/Attributes/BindToAttribute.cs.meta new file mode 100644 index 0000000..6e58fd9 --- /dev/null +++ b/samples/Unity.Mvvm.MainMenu/Assets/UnityMvvmToolkit/Common/Attributes/BindToAttribute.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 55bd311c0f7d06e46bd9c8ea15060c60 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/samples/Unity.Mvvm.MainMenu/Assets/UnityMvvmToolkit/Common/Attributes/VisualTreeAssetAttribute.cs b/samples/Unity.Mvvm.MainMenu/Assets/UnityMvvmToolkit/Common/Attributes/VisualTreeAssetAttribute.cs new file mode 100644 index 0000000..0bf1098 --- /dev/null +++ b/samples/Unity.Mvvm.MainMenu/Assets/UnityMvvmToolkit/Common/Attributes/VisualTreeAssetAttribute.cs @@ -0,0 +1,15 @@ +using System; + +namespace UnityMvvmToolkit.Common.Attributes +{ + [AttributeUsage(AttributeTargets.Class, Inherited = false)] + public class VisualTreeAssetAttribute : Attribute + { + public VisualTreeAssetAttribute(string assetPath) + { + AssetPath = assetPath; + } + + public string AssetPath { get; } + } +} \ No newline at end of file diff --git a/samples/Unity.Mvvm.MainMenu/Assets/UnityMvvmToolkit/Common/Attributes/VisualTreeAssetAttribute.cs.meta b/samples/Unity.Mvvm.MainMenu/Assets/UnityMvvmToolkit/Common/Attributes/VisualTreeAssetAttribute.cs.meta new file mode 100644 index 0000000..c986c12 --- /dev/null +++ b/samples/Unity.Mvvm.MainMenu/Assets/UnityMvvmToolkit/Common/Attributes/VisualTreeAssetAttribute.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 17f4537bf3018094eac204f27cc6e5c6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/samples/Unity.Mvvm.MainMenu/Assets/UnityMvvmToolkit/Common/Interfaces.meta b/samples/Unity.Mvvm.MainMenu/Assets/UnityMvvmToolkit/Common/Interfaces.meta new file mode 100644 index 0000000..a69e110 --- /dev/null +++ b/samples/Unity.Mvvm.MainMenu/Assets/UnityMvvmToolkit/Common/Interfaces.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 11c353a1b6a71e544b238dd04fc80d53 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/samples/Unity.Mvvm.MainMenu/Assets/UnityMvvmToolkit/Common/Interfaces/IBindableVisualElement.cs b/samples/Unity.Mvvm.MainMenu/Assets/UnityMvvmToolkit/Common/Interfaces/IBindableVisualElement.cs new file mode 100644 index 0000000..594686e --- /dev/null +++ b/samples/Unity.Mvvm.MainMenu/Assets/UnityMvvmToolkit/Common/Interfaces/IBindableVisualElement.cs @@ -0,0 +1,6 @@ +namespace UnityMvvmToolkit.Common.Interfaces +{ + public interface IBindableVisualElement + { + } +} \ No newline at end of file diff --git a/samples/Unity.Mvvm.MainMenu/Assets/UnityMvvmToolkit/Common/Interfaces/IBindableVisualElement.cs.meta b/samples/Unity.Mvvm.MainMenu/Assets/UnityMvvmToolkit/Common/Interfaces/IBindableVisualElement.cs.meta new file mode 100644 index 0000000..27cc462 --- /dev/null +++ b/samples/Unity.Mvvm.MainMenu/Assets/UnityMvvmToolkit/Common/Interfaces/IBindableVisualElement.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3eb18b14cca137445bc1d90b3a0a0e03 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/samples/Unity.Mvvm.MainMenu/Assets/UnityMvvmToolkit/Common/Interfaces/IView.cs b/samples/Unity.Mvvm.MainMenu/Assets/UnityMvvmToolkit/Common/Interfaces/IView.cs new file mode 100644 index 0000000..a5abded --- /dev/null +++ b/samples/Unity.Mvvm.MainMenu/Assets/UnityMvvmToolkit/Common/Interfaces/IView.cs @@ -0,0 +1,6 @@ +namespace UnityMvvmToolkit.Common.Interfaces +{ + public interface IView + { + } +} \ No newline at end of file diff --git a/samples/Unity.Mvvm.MainMenu/Assets/UnityMvvmToolkit/Common/Interfaces/IView.cs.meta b/samples/Unity.Mvvm.MainMenu/Assets/UnityMvvmToolkit/Common/Interfaces/IView.cs.meta new file mode 100644 index 0000000..71c9e16 --- /dev/null +++ b/samples/Unity.Mvvm.MainMenu/Assets/UnityMvvmToolkit/Common/Interfaces/IView.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e49e94a2c1e3cc34498da10f68616df6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/samples/Unity.Mvvm.MainMenu/Assets/UnityMvvmToolkit/Common/Interfaces/IVisualElementBindings.cs b/samples/Unity.Mvvm.MainMenu/Assets/UnityMvvmToolkit/Common/Interfaces/IVisualElementBindings.cs new file mode 100644 index 0000000..69abbf1 --- /dev/null +++ b/samples/Unity.Mvvm.MainMenu/Assets/UnityMvvmToolkit/Common/Interfaces/IVisualElementBindings.cs @@ -0,0 +1,7 @@ +namespace UnityMvvmToolkit.Common.Interfaces +{ + public interface IVisualElementBindings + { + void UpdateValues(); + } +} \ No newline at end of file diff --git a/samples/Unity.Mvvm.MainMenu/Assets/UnityMvvmToolkit/Common/Interfaces/IVisualElementBindings.cs.meta b/samples/Unity.Mvvm.MainMenu/Assets/UnityMvvmToolkit/Common/Interfaces/IVisualElementBindings.cs.meta new file mode 100644 index 0000000..c19e26b --- /dev/null +++ b/samples/Unity.Mvvm.MainMenu/Assets/UnityMvvmToolkit/Common/Interfaces/IVisualElementBindings.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 28512b0d243524e498df18ba702abae3 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/samples/Unity.Mvvm.MainMenu/Assets/UnityMvvmToolkit/Common/ViewModel.cs b/samples/Unity.Mvvm.MainMenu/Assets/UnityMvvmToolkit/Common/ViewModel.cs new file mode 100644 index 0000000..f875b65 --- /dev/null +++ b/samples/Unity.Mvvm.MainMenu/Assets/UnityMvvmToolkit/Common/ViewModel.cs @@ -0,0 +1,44 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Runtime.CompilerServices; + +namespace UnityMvvmToolkit.Common +{ + public abstract class ViewModel : INotifyPropertyChanged + { + public event PropertyChangedEventHandler PropertyChanged; + + protected bool Set(ref T oldValue, T newValue, [CallerMemberName] string propertyName = default) + { + if (EqualityComparer.Default.Equals(oldValue, newValue)) + { + return false; + } + + oldValue = newValue; + OnPropertyChanged(propertyName); + + return true; + } + + protected bool Set(T oldValue, T newValue, TModel model, Action callback, + [CallerMemberName] string propertyName = default) where TModel : class + { + if (EqualityComparer.Default.Equals(oldValue, newValue)) + { + return false; + } + + callback(model, newValue); + OnPropertyChanged(propertyName); + + return true; + } + + protected void OnPropertyChanged(string propertyName) + { + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + } + } +} \ No newline at end of file diff --git a/samples/Unity.Mvvm.MainMenu/Assets/UnityMvvmToolkit/Common/ViewModel.cs.meta b/samples/Unity.Mvvm.MainMenu/Assets/UnityMvvmToolkit/Common/ViewModel.cs.meta new file mode 100644 index 0000000..66dfcb5 --- /dev/null +++ b/samples/Unity.Mvvm.MainMenu/Assets/UnityMvvmToolkit/Common/ViewModel.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: cf160a9f81dde94409454031687c7677 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/samples/Unity.Mvvm.MainMenu/Assets/UnityMvvmToolkit/UI.meta b/samples/Unity.Mvvm.MainMenu/Assets/UnityMvvmToolkit/UI.meta new file mode 100644 index 0000000..75c5e4a --- /dev/null +++ b/samples/Unity.Mvvm.MainMenu/Assets/UnityMvvmToolkit/UI.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 5deea0ee0d2964645b8f04407d1efc8b +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/samples/Unity.Mvvm.MainMenu/Assets/UnityMvvmToolkit/UI/BindableVisualElements.meta b/samples/Unity.Mvvm.MainMenu/Assets/UnityMvvmToolkit/UI/BindableVisualElements.meta new file mode 100644 index 0000000..51a6368 --- /dev/null +++ b/samples/Unity.Mvvm.MainMenu/Assets/UnityMvvmToolkit/UI/BindableVisualElements.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 9a6a365fc19c6e348b70814faf7ada1c +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/samples/Unity.Mvvm.MainMenu/Assets/UnityMvvmToolkit/UI/BindableVisualElements/BindableLabel.cs b/samples/Unity.Mvvm.MainMenu/Assets/UnityMvvmToolkit/UI/BindableVisualElements/BindableLabel.cs new file mode 100644 index 0000000..2aa7581 --- /dev/null +++ b/samples/Unity.Mvvm.MainMenu/Assets/UnityMvvmToolkit/UI/BindableVisualElements/BindableLabel.cs @@ -0,0 +1,29 @@ +using UnityEngine.UIElements; +using UnityMvvmToolkit.Common.Attributes; +using UnityMvvmToolkit.Common.Interfaces; + +namespace UnityMvvmToolkit.UI.BindableVisualElements +{ + public class BindableLabel : Label, IBindableVisualElement + { + [BindTo(nameof(text))] + public string BindingTextPath { get; set; } + + public new class UxmlFactory : UxmlFactory + { + } + + public new class UxmlTraits : Label.UxmlTraits + { + private readonly UxmlStringAttributeDescription _bindingTextAttribute = new() + { name = "binding-text-path", defaultValue = "binding-property-name" }; + + public override void Init(VisualElement visualElement, IUxmlAttributes bag, CreationContext context) + { + base.Init(visualElement, bag, context); + ((BindableLabel) visualElement).BindingTextPath = + _bindingTextAttribute.GetValueFromBag(bag, context); + } + } + } +} \ No newline at end of file diff --git a/samples/Unity.Mvvm.MainMenu/Assets/UnityMvvmToolkit/UI/BindableVisualElements/BindableLabel.cs.meta b/samples/Unity.Mvvm.MainMenu/Assets/UnityMvvmToolkit/UI/BindableVisualElements/BindableLabel.cs.meta new file mode 100644 index 0000000..036cc05 --- /dev/null +++ b/samples/Unity.Mvvm.MainMenu/Assets/UnityMvvmToolkit/UI/BindableVisualElements/BindableLabel.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: dd55009627c7475ba7f9a364c7292a5b +timeCreated: 1657789669 \ No newline at end of file diff --git a/samples/Unity.Mvvm.MainMenu/Assets/UnityMvvmToolkit/UI/BindableVisualElements/BindableTextField.cs b/samples/Unity.Mvvm.MainMenu/Assets/UnityMvvmToolkit/UI/BindableVisualElements/BindableTextField.cs new file mode 100644 index 0000000..9039d52 --- /dev/null +++ b/samples/Unity.Mvvm.MainMenu/Assets/UnityMvvmToolkit/UI/BindableVisualElements/BindableTextField.cs @@ -0,0 +1,29 @@ +using UnityEngine.UIElements; +using UnityMvvmToolkit.Common.Attributes; +using UnityMvvmToolkit.Common.Interfaces; + +namespace UnityMvvmToolkit.UI.BindableVisualElements +{ + public class BindableTextField : TextField, IBindableVisualElement + { + [BindTo(nameof(value))] + public string BindingValuePath { get; set; } + + public new class UxmlFactory : UxmlFactory + { + } + + public new class UxmlTraits : TextField.UxmlTraits + { + private readonly UxmlStringAttributeDescription _bindingValueAttribute = new() + { name = "binding-value-path", defaultValue = "binding-property-name" }; + + public override void Init(VisualElement visualElement, IUxmlAttributes bag, CreationContext context) + { + base.Init(visualElement, bag, context); + ((BindableTextField) visualElement).BindingValuePath = + _bindingValueAttribute.GetValueFromBag(bag, context); + } + } + } +} \ No newline at end of file diff --git a/samples/Unity.Mvvm.MainMenu/Assets/UnityMvvmToolkit/UI/BindableVisualElements/BindableTextField.cs.meta b/samples/Unity.Mvvm.MainMenu/Assets/UnityMvvmToolkit/UI/BindableVisualElements/BindableTextField.cs.meta new file mode 100644 index 0000000..ea235c6 --- /dev/null +++ b/samples/Unity.Mvvm.MainMenu/Assets/UnityMvvmToolkit/UI/BindableVisualElements/BindableTextField.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 028dbab7fa75404b94ae26cdedd4a170 +timeCreated: 1657779189 \ No newline at end of file diff --git a/samples/Unity.Mvvm.MainMenu/Assets/UnityMvvmToolkit/UI/View.cs b/samples/Unity.Mvvm.MainMenu/Assets/UnityMvvmToolkit/UI/View.cs new file mode 100644 index 0000000..b44c6d2 --- /dev/null +++ b/samples/Unity.Mvvm.MainMenu/Assets/UnityMvvmToolkit/UI/View.cs @@ -0,0 +1,130 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Reflection; +using UnityEngine; +using UnityEngine.UIElements; +using UnityMvvmToolkit.Common.Interfaces; + +namespace UnityMvvmToolkit.UI +{ + [RequireComponent(typeof(UIDocument))] + public abstract class View : MonoBehaviour where TBindingContext : class, INotifyPropertyChanged, new() + { + private UIDocument _uiDocument; + private TBindingContext _bindingContext; + private List _disposables; + private Dictionary> _visualElementsBindings; + + protected TBindingContext BindingContext => _bindingContext; + + private void Awake() + { + _uiDocument = GetComponent(); + _bindingContext = GetBindingContext(); + + _disposables = new List(); + _visualElementsBindings = new Dictionary>(); + + BindElements(_bindingContext, _uiDocument.rootVisualElement); + } + + private void OnEnable() + { + _bindingContext.PropertyChanged += OnBindingContextPropertyChanged; + } + + private void OnDisable() + { + _bindingContext.PropertyChanged -= OnBindingContextPropertyChanged; + } + + private void OnDestroy() + { + // TODO: Unregister bindable elements (like TextField). + + foreach (var disposable in _disposables) + { + disposable.Dispose(); + } + } + + protected virtual TBindingContext GetBindingContext() + { + return new TBindingContext(); // TODO: Change DataContext dynamically? + } + + protected virtual IVisualElementBindings GetVisualElementBindings(TBindingContext bindingContext, + IBindableVisualElement bindableElement) + { + throw new NotImplementedException(); + } + + protected virtual void BindElements(TBindingContext bindingContext, VisualElement rootVisualElement) + { + // var bindingContextProperties = + // typeof(TBindingContext).GetProperties(BindingFlags.Public | BindingFlags.Instance | + // BindingFlags.DeclaredOnly); + + rootVisualElement.Query().ForEach(visualElement => + { + if (visualElement is IBindableVisualElement bindableElement) + { + RegisterBindableElement(bindableElement); + } + }); + } + + private void RegisterBindableElement(IBindableVisualElement bindableElement) + { + var bindingProperties = bindableElement.GetType() + .GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly); + + foreach (var bindingPropertyInfo in bindingProperties) + { + var sourcePropertyName = bindingPropertyInfo.GetValue(bindableElement).ToString(); + if (string.IsNullOrWhiteSpace(sourcePropertyName)) + { + continue; + } + + var sourcePropertyInfo = typeof(TBindingContext).GetProperty(sourcePropertyName); // TODO: Cache properties to dictionary. + if (sourcePropertyInfo == null) + { + throw new NullReferenceException(nameof(sourcePropertyInfo)); + } + + var visualElementBindings = GetVisualElementBindings(_bindingContext, bindableElement); + if (visualElementBindings == null) + { + return; + throw new NullReferenceException(nameof(visualElementBindings)); + } + + if (visualElementBindings is IDisposable disposable) + { + _disposables.Add(disposable); + } + + if (_visualElementsBindings.TryGetValue(sourcePropertyName, out var visualElements) == false) + { + visualElements = new HashSet(); + _visualElementsBindings.Add(sourcePropertyName, visualElements); + } + + visualElementBindings.UpdateValues(); + visualElements.Add(visualElementBindings); + } + } + protected virtual void OnBindingContextPropertyChanged(object sender, PropertyChangedEventArgs e) + { + if (_visualElementsBindings.TryGetValue(e.PropertyName, out var visualElements)) + { + foreach (var visualElement in visualElements) + { + visualElement.UpdateValues(); + } + } + } + } +} \ No newline at end of file diff --git a/samples/Unity.Mvvm.MainMenu/Assets/UnityMvvmToolkit/UI/View.cs.meta b/samples/Unity.Mvvm.MainMenu/Assets/UnityMvvmToolkit/UI/View.cs.meta new file mode 100644 index 0000000..0f5d939 --- /dev/null +++ b/samples/Unity.Mvvm.MainMenu/Assets/UnityMvvmToolkit/UI/View.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 0c23133e65c84117a6d710966201599b +timeCreated: 1657793186 \ No newline at end of file diff --git a/samples/Unity.Mvvm.MainMenu/Assets/UnityMvvmToolkit/UnityMvvmToolkit.SourceGenerators.dll b/samples/Unity.Mvvm.MainMenu/Assets/UnityMvvmToolkit/UnityMvvmToolkit.SourceGenerators.dll new file mode 100644 index 0000000000000000000000000000000000000000..f653038b5ff3b3eb861c6abfad9ecb3bd1bed0f6 GIT binary patch literal 23552 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 a_C9RekB)z}8W?we!z=%h6a1@mf&U9xTxWd% literal 0 HcmV?d00001 diff --git a/samples/Unity.Mvvm.MainMenu/Assets/UnityMvvmToolkit/UnityMvvmToolkit.SourceGenerators.dll.meta b/samples/Unity.Mvvm.MainMenu/Assets/UnityMvvmToolkit/UnityMvvmToolkit.SourceGenerators.dll.meta new file mode 100644 index 0000000..7515c5d --- /dev/null +++ b/samples/Unity.Mvvm.MainMenu/Assets/UnityMvvmToolkit/UnityMvvmToolkit.SourceGenerators.dll.meta @@ -0,0 +1,71 @@ +fileFormatVersion: 2 +guid: 25457824e2a0edb4c97c257322a6b106 +labels: +- RoslynAnalyzer +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + : Any + second: + enabled: 0 + settings: + Exclude Editor: 1 + Exclude Linux64: 1 + Exclude OSXUniversal: 1 + Exclude Win: 1 + Exclude Win64: 1 + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + CPU: AnyCPU + DefaultValueInitialized: true + OS: AnyOS + - first: + Standalone: Linux64 + second: + enabled: 0 + settings: + CPU: None + - first: + Standalone: OSXUniversal + second: + enabled: 0 + settings: + CPU: None + - first: + Standalone: Win + second: + enabled: 0 + settings: + CPU: None + - first: + Standalone: Win64 + second: + enabled: 0 + settings: + CPU: None + - first: + Windows Store Apps: WindowsStoreApps + second: + enabled: 0 + settings: + CPU: AnyCPU + userData: + assetBundleName: + assetBundleVariant: diff --git a/samples/Unity.Mvvm.MainMenu/Packages/manifest.json b/samples/Unity.Mvvm.MainMenu/Packages/manifest.json index c148722..9e02b62 100644 --- a/samples/Unity.Mvvm.MainMenu/Packages/manifest.json +++ b/samples/Unity.Mvvm.MainMenu/Packages/manifest.json @@ -1,6 +1,5 @@ { "dependencies": { - "com.chebanovdd.unitymvvmtoolkit": "file:../../../src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit", "com.unity.collab-proxy": "1.15.18", "com.unity.feature.2d": "1.0.0", "com.unity.ide.rider": "3.0.15", diff --git a/samples/Unity.Mvvm.MainMenu/Packages/packages-lock.json b/samples/Unity.Mvvm.MainMenu/Packages/packages-lock.json index 6925dcd..c155a50 100644 --- a/samples/Unity.Mvvm.MainMenu/Packages/packages-lock.json +++ b/samples/Unity.Mvvm.MainMenu/Packages/packages-lock.json @@ -1,11 +1,5 @@ { "dependencies": { - "com.chebanovdd.unitymvvmtoolkit": { - "version": "file:../../../src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit", - "depth": 0, - "source": "local", - "dependencies": {} - }, "com.unity.2d.animation": { "version": "7.0.6", "depth": 1, diff --git a/src/UnityMvvmToolkit.Common/UnityMvvmToolkit.Common.csproj b/src/UnityMvvmToolkit.Common/UnityMvvmToolkit.Common.csproj index 3a5e23a..af1a574 100644 --- a/src/UnityMvvmToolkit.Common/UnityMvvmToolkit.Common.csproj +++ b/src/UnityMvvmToolkit.Common/UnityMvvmToolkit.Common.csproj @@ -7,7 +7,7 @@ - $(ProjectDir)..\UnityMvvmToolkit.UnityPackage\Assets\Plugins\UnityMvvmToolkit\Runtime\ + $(ProjectDir)..\..\samples\Unity.Mvvm.MainMenu\Assets\UnityMvvmToolkit\ diff --git a/src/UnityMvvmToolkit.SourceGenerators/Captures/BindableElementCapture.cs b/src/UnityMvvmToolkit.SourceGenerators/Captures/BindableElementCapture.cs index 78934fb..b2e17cc 100644 --- a/src/UnityMvvmToolkit.SourceGenerators/Captures/BindableElementCapture.cs +++ b/src/UnityMvvmToolkit.SourceGenerators/Captures/BindableElementCapture.cs @@ -8,9 +8,10 @@ public class BindableElementCapture public BindableElementCapture(ClassDeclarationSyntax @class) { Class = @class; - Properties = new List>(); + Properties = new Dictionary(); } + public string ClassIdentifier => Class.Identifier.Text; public ClassDeclarationSyntax Class { get; } - public List> Properties { get; } + public Dictionary Properties { get; } } \ No newline at end of file diff --git a/src/UnityMvvmToolkit.SourceGenerators/Models/BindableElementInfo.cs b/src/UnityMvvmToolkit.SourceGenerators/Models/VisualTreeElementInfo.cs similarity index 77% rename from src/UnityMvvmToolkit.SourceGenerators/Models/BindableElementInfo.cs rename to src/UnityMvvmToolkit.SourceGenerators/Models/VisualTreeElementInfo.cs index 24db602..93aa97e 100644 --- a/src/UnityMvvmToolkit.SourceGenerators/Models/BindableElementInfo.cs +++ b/src/UnityMvvmToolkit.SourceGenerators/Models/VisualTreeElementInfo.cs @@ -2,9 +2,9 @@ namespace UnityMvvmToolkit.SourceGenerators.Models; -public class BindableElementInfo +public class VisualTreeElementInfo { - public BindableElementInfo(string classIdentifier) + public VisualTreeElementInfo(string classIdentifier) { ClassIdentifier = classIdentifier; Attributes = new List>(); diff --git a/src/UnityMvvmToolkit.SourceGenerators/SyntaxReceivers/BindableElementsReceiver.cs b/src/UnityMvvmToolkit.SourceGenerators/SyntaxReceivers/BindableElementsReceiver.cs index 91285e1..96c7393 100644 --- a/src/UnityMvvmToolkit.SourceGenerators/SyntaxReceivers/BindableElementsReceiver.cs +++ b/src/UnityMvvmToolkit.SourceGenerators/SyntaxReceivers/BindableElementsReceiver.cs @@ -47,7 +47,8 @@ public void OnVisitSyntaxNode(SyntaxNode syntaxNode) _captures.Add(@class.Identifier.Text, bindableElement); } - bindableElement.Properties.Add(new KeyValuePair(bindToPath, property)); + // bindableElement.Properties.Add(new KeyValuePair(bindToPath, property)); + bindableElement.Properties.Add(property.Identifier.Text.ToLower(), bindToPath); } private string GetAttributeArgumentValue(AttributeSyntax attribute) diff --git a/src/UnityMvvmToolkit.SourceGenerators/UnityMvvmToolkit.SourceGenerators.csproj b/src/UnityMvvmToolkit.SourceGenerators/UnityMvvmToolkit.SourceGenerators.csproj index aee915a..6ab64e3 100644 --- a/src/UnityMvvmToolkit.SourceGenerators/UnityMvvmToolkit.SourceGenerators.csproj +++ b/src/UnityMvvmToolkit.SourceGenerators/UnityMvvmToolkit.SourceGenerators.csproj @@ -15,7 +15,7 @@ - $(ProjectDir)..\UnityMvvmToolkit.UnityPackage\Assets\Plugins\UnityMvvmToolkit\Runtime\ + $(ProjectDir)..\..\samples\Unity.Mvvm.MainMenu\Assets\UnityMvvmToolkit\ diff --git a/src/UnityMvvmToolkit.SourceGenerators/ViewBindingsGenerator.cs b/src/UnityMvvmToolkit.SourceGenerators/ViewBindingsGenerator.cs index 437373a..523b92f 100644 --- a/src/UnityMvvmToolkit.SourceGenerators/ViewBindingsGenerator.cs +++ b/src/UnityMvvmToolkit.SourceGenerators/ViewBindingsGenerator.cs @@ -1,20 +1,16 @@ using System; using System.Collections.Generic; -using System.Collections.Immutable; using System.IO; using System.Linq; using System.Text; using System.Xml; using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using UnityMvvmToolkit.SourceGenerators.Captures; using UnityMvvmToolkit.SourceGenerators.Extensions; using UnityMvvmToolkit.SourceGenerators.Models; using UnityMvvmToolkit.SourceGenerators.SyntaxReceivers; -using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; - namespace UnityMvvmToolkit.SourceGenerators; [Generator] @@ -35,53 +31,8 @@ public void Execute(GeneratorExecutionContext context) return; } - // var sb = new StringBuilder(); - // sb.Append(receiver.Views.Captures.Count()); - // sb.AppendLine(); - // sb.Append(receiver.BindableElements.Captures.Values.Count()); - // - // File.WriteAllText($@"D:\0.txt", sb.ToString()); - // return; - - // if (receiver.Views.Captures.Count() > 0) - // { - // File.WriteAllText($@"D:\0.txt", receiver.Views.Captures.First().Class.SyntaxTree.GetRoot().GetParent().Name.ToString()); - // } - // - // if (receiver.BindableElements.Captures.Values.Count() > 0) - // { - // File.WriteAllText($@"D:\1.txt", receiver.BindableElements.Captures.Values.First().Class.SyntaxTree.GetRoot().GetParent().Name.ToString()); - // } - // - // if ((receiver.Views.Captures.Count() > 0) - // && - // (receiver.BindableElements.Captures.Values.Count() > 0) - // ) - // { - // File.WriteAllText($@"D:\2.txt", "!!!"); - // } - // - // // File.WriteAllText($@"D:\0.txt", receiver.Views.Captures.Count().ToString()); - // // File.WriteAllText($@"D:\1.txt", receiver.BindableElements.Captures.Values.Count().ToString()); - // - // return; - - foreach (var bindableElement in receiver.BindableElements.Captures.Values) - { - File.WriteAllText($@"D:\{bindableElement.Class.Identifier.Text}.txt", bindableElement.Class.GetText(Encoding.UTF8).ToString()); - } - - var compilation = context.Compilation; - foreach (var view in receiver.Views.Captures) { - // foreach (var bindableElement in receiver.BindableElements.Captures.Values) - // { - // File.WriteAllText($@"D:\{bindableElement.Class.Identifier.Text}.txt", bindableElement.Class.GetText(Encoding.UTF8).ToString()); - // } - - File.WriteAllText($@"D:\{view.Class.Identifier.Text}.txt", view.Class.GetText(Encoding.UTF8).ToString()); - var assetFullPath = GetVisualTreeAssetPath(view); if (File.Exists(assetFullPath) == false) { @@ -90,317 +41,119 @@ public void Execute(GeneratorExecutionContext context) "LG01", "View bindings generator", "Visual tree asset file is not found.", - defaultSeverity: DiagnosticSeverity.Error, + defaultSeverity: DiagnosticSeverity.Error, severity: DiagnosticSeverity.Error, isEnabledByDefault: true, warningLevel: 0)); - + return; } - - var bindableElements = GetBindableElements(assetFullPath); - foreach (var bindableElement in bindableElements) + var bindingClasses = new Dictionary(); + var visualTreeElements = GetBindableElements(assetFullPath); + + var index = 0; + foreach (var visualTreeElement in visualTreeElements) { - if (receiver.BindableElements.Captures.TryGetValue(bindableElement.ClassIdentifier, + if (receiver.BindableElements.Captures.TryGetValue(visualTreeElement.ClassIdentifier, out var visualElement) == false) { continue; } - - var elementBindingsClass = CreateElementBindingsClass(visualElement, view.ViewModelIdentifier); - File.WriteAllText($@"D:\{visualElement.Class.Identifier.Text}Bindings.txt", elementBindingsClass); - } - - // var sb = new StringBuilder(); - // foreach (var bindableElement in bindableElements) - // { - // sb.Append(bindableElement.ClassIdentifier); - // sb.AppendLine(); - // - // foreach (var attribute in bindableElement.Attributes) - // { - // sb.Append($"{attribute.Key} - {attribute.Value}"); - // sb.AppendLine(); - // } - // - // sb.AppendLine(); - // } - // - // File.WriteAllText($@"D:\BindableElements.txt", sb.ToString()); - - - - // var sb = new StringBuilder(); - // foreach (var visualElement in receiver.BindableElements.Captures) - // { - // sb.Append(visualElement.Key); - // sb.AppendLine(); - // } - - File.WriteAllText($@"D:\BindableElements.txt", receiver.BindableElements.Captures.Values.Count().ToString()); - - foreach (var bindableElement in receiver.BindableElements.Captures.Values) - { - File.WriteAllText($@"D:\{bindableElement.Class.Identifier.Text}.txt", bindableElement.Class.GetText(Encoding.UTF8).ToString()); + + var classIdentifier = visualElement.ClassIdentifier; + var classIdentifierIndexed = $"{classIdentifier}{index}"; + var classBody = + CreateElementBindingsClass(classIdentifierIndexed, view.ViewModelIdentifier, visualElement, + visualTreeElement); + + if (classBody == null) + { + continue; + } + + index++; + bindingClasses.Add(classIdentifier, (classIdentifierIndexed, classBody)); } - - var syntaxTree = view.Class.SyntaxTree; - - var semanticModel = compilation.GetSemanticModel(syntaxTree); - var immutableHashSet = syntaxTree.GetRoot() - .DescendantNodesAndSelf() - .OfType() - .Select(x => ModelExtensions.GetDeclaredSymbol(semanticModel, x)) - .OfType() - // .Where(x => x.Interfaces.Contains(viewInterface)) - .ToImmutableHashSet(); - - foreach (var typeSymbol in immutableHashSet) + + if (bindingClasses.Count != 0) { - context.AddSource($"{typeSymbol.Name}.g.cs", GenerateView(typeSymbol, context, view)); + context.AddSource($"{view.Class.Identifier.Text}.g.cs", GenerateView(context, view, bindingClasses)); } - - // var elementBindingsClass = CreateElementBindingsClass(); - // var output = elementBindingsClass.GetText(Encoding.UTF8).ToString(); } } - private string CreateElementBindingsClass(BindableElementCapture bindableElementCapture, string viewViewModelIdentifier) + private string CreateElementBindingsClass(string classIdentifier, string viewModelIdentifier, + BindableElementCapture visualElement, VisualTreeElementInfo visualTreeElement) { - var classIdentifier = $"{bindableElementCapture.Class.Identifier.Text}Bindings"; + var valueAssignments = GetUpdateValueMethodBody(visualElement.Properties, visualTreeElement); + if (valueAssignments.Count == 0) + { + return null; + } return $@" -private class {classIdentifier} : IVisualElementBindings -{{ - private readonly {viewViewModelIdentifier} _viewModel; - private readonly BindableLabel _visualElement; - - public {classIdentifier}({viewViewModelIdentifier} viewModel, BindableLabel visualElement) - {{ - _viewModel = viewModel; - _visualElement = visualElement; - }} + private class {classIdentifier}Bindings : IVisualElementBindings + {{ + private readonly {viewModelIdentifier} _viewModel; + private readonly {visualElement.ClassIdentifier} _visualElement; - public void UpdateValues() - {{ - {Block(GetUpdateValueMethodBody(bindableElementCapture.Properties)).GetText(Encoding.UTF8)} - }} -}}"; + public {classIdentifier}Bindings({viewModelIdentifier} viewModel, {visualElement.ClassIdentifier} visualElement) + {{ + _viewModel = viewModel; + _visualElement = visualElement; + }} - // return ClassDeclaration(classIdentifier) - // .WithModifiers(TokenList(Token(SyntaxKind.PrivateKeyword))).WithBaseList( - // BaseList(SingletonSeparatedList( - // SimpleBaseType(IdentifierName("IVisualElementBindings"))))) - // .WithMembers(List(new MemberDeclarationSyntax[] - // { - // FieldDeclaration(VariableDeclaration(IdentifierName("MainMenuViewModel")) - // .WithVariables(SingletonSeparatedList(VariableDeclarator(Identifier("_viewModel"))))) - // .WithModifiers(TokenList(Token(SyntaxKind.PrivateKeyword), Token(SyntaxKind.ReadOnlyKeyword))), - // FieldDeclaration(VariableDeclaration(IdentifierName("BindableLabel")) - // .WithVariables(SingletonSeparatedList(VariableDeclarator(Identifier("_visualElement"))))) - // .WithModifiers(TokenList(Token(SyntaxKind.PrivateKeyword), Token(SyntaxKind.ReadOnlyKeyword))), - // ConstructorDeclaration(Identifier(classIdentifier)) - // .WithModifiers(TokenList(Token(SyntaxKind.PublicKeyword))) - // .WithParameterList( - // ParameterList( - // SeparatedList( - // new SyntaxNodeOrToken[] - // { - // Parameter( - // Identifier("viewModel")) - // .WithType( - // IdentifierName("MainMenuViewModel")), - // Token(SyntaxKind.CommaToken), - // Parameter( - // Identifier("visualElement")) - // .WithType( - // IdentifierName("BindableLabel")) - // }))) - // .WithBody( - // Block( - // ExpressionStatement( - // AssignmentExpression( - // SyntaxKind.SimpleAssignmentExpression, - // IdentifierName("_viewModel"), - // IdentifierName("viewModel"))), - // ExpressionStatement( - // AssignmentExpression( - // SyntaxKind.SimpleAssignmentExpression, - // IdentifierName("_visualElement"), - // IdentifierName("visualElement"))))), - // MethodDeclaration( - // PredefinedType( - // Token(SyntaxKind.VoidKeyword)), - // Identifier("UpdateValues")) - // .WithModifiers( - // TokenList( - // Token(SyntaxKind.PublicKeyword))) - // .WithBody( - // Block(GetUpdateValueMethodBody(bindableElementCapture.Properties))) - // })).NormalizeWhitespace(); + public void UpdateValues() + {{ + {string.Join(Environment.NewLine, valueAssignments)} + }} + }}"; } - // return ClassDeclaration("LabelBindings") - // .WithModifiers(TokenList(Token(SyntaxKind.PrivateKeyword))) - // .WithBaseList(BaseList( - // SingletonSeparatedList(SimpleBaseType(IdentifierName("IVisualElementBindings"))))) - // .WithMembers(List(new MemberDeclarationSyntax[] - // { - // FieldDeclaration(VariableDeclaration(IdentifierName("MainMenuViewModel")) - // .WithVariables(SingletonSeparatedList(VariableDeclarator(Identifier("_viewModel"))))) - // .WithModifiers(TokenList(Token(SyntaxKind.PrivateKeyword), Token(SyntaxKind.ReadOnlyKeyword))), - // FieldDeclaration(VariableDeclaration(IdentifierName("BindableLabel")) - // .WithVariables(SingletonSeparatedList(VariableDeclarator(Identifier("_visualElement"))))) - // .WithModifiers(TokenList(Token(SyntaxKind.PrivateKeyword), Token(SyntaxKind.ReadOnlyKeyword))), - // ConstructorDeclaration(Identifier("LabelBindings")) - // .WithModifiers(TokenList(Token(SyntaxKind.PublicKeyword))) - // .WithParameterList(ParameterList(SeparatedList(new SyntaxNodeOrToken[] - // { - // Parameter(Identifier("viewModel")).WithType(IdentifierName("MainMenuViewModel")), - // Token(SyntaxKind.CommaToken), - // Parameter(Identifier("visualElement")).WithType(IdentifierName("BindableLabel")) - // }))) - // .WithBody(Block( - // ExpressionStatement( - // AssignmentExpression( - // SyntaxKind.SimpleAssignmentExpression, - // IdentifierName("_viewModel"), - // IdentifierName("viewModel"))), - // ExpressionStatement( - // AssignmentExpression( - // SyntaxKind.SimpleAssignmentExpression, - // IdentifierName("_visualElement"), - // IdentifierName("visualElement"))))), - // MethodDeclaration(PredefinedType(Token(SyntaxKind.VoidKeyword)), Identifier("UpdateValues")) - // .WithModifiers(TokenList(Token(SyntaxKind.PublicKeyword))) - // .WithBody(Block(SingletonList( - // ExpressionStatement( - // InvocationExpression(IdentifierName("UpdateStrValue")))))), - // MethodDeclaration(PredefinedType(Token(SyntaxKind.VoidKeyword)), Identifier("UpdateStrValue")) - // .WithAttributeLists(SingletonList( - // AttributeList(SingletonSeparatedList(Attribute(IdentifierName("MethodImpl")) - // .WithArgumentList( - // AttributeArgumentList(SingletonSeparatedList( - // AttributeArgument(MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, - // IdentifierName("MethodImplOptions"), - // IdentifierName("AggressiveInlining")))))))))) - // .WithModifiers(TokenList(Token(SyntaxKind.PrivateKeyword))) - // .WithBody(Block( - // SingletonList( - // IfStatement( - // BinaryExpression( - // SyntaxKind.NotEqualsExpression, - // MemberAccessExpression( - // SyntaxKind.SimpleMemberAccessExpression, - // IdentifierName("_visualElement"), - // IdentifierName("text")), - // MemberAccessExpression( - // SyntaxKind.SimpleMemberAccessExpression, - // IdentifierName("_viewModel"), - // IdentifierName("StrValue"))), - // Block( - // SingletonList( - // ExpressionStatement( - // AssignmentExpression( - // SyntaxKind - // .SimpleAssignmentExpression, - // MemberAccessExpression( - // SyntaxKind - // .SimpleMemberAccessExpression, - // IdentifierName( - // "_visualElement"), - // IdentifierName("text")), - // MemberAccessExpression( - // SyntaxKind - // .SimpleMemberAccessExpression, - // IdentifierName("_viewModel"), - // IdentifierName( - // "StrValue")))))))))) - // })).NormalizeWhitespace(); - //} - - private IEnumerable GetUpdateValueMethodBody(List> properties) + + private List GetUpdateValueMethodBody(IReadOnlyDictionary visualElementProperties, + VisualTreeElementInfo visualTreeElement) { - var updateValueExpressions = new List(); + var valueAssignments = new List(); - foreach (var property in properties) + foreach (var visualTreeAttribute in visualTreeElement.Attributes) { - var leftExpression = MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, - IdentifierName("_visualElement"), IdentifierName(property.Key)); - - var rightExpression = MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, - IdentifierName("_viewModel"), IdentifierName(property.Value.Identifier)); + var attributeName = visualTreeAttribute.Key.Replace("-", ""); + if (visualElementProperties.TryGetValue(attributeName, out var targetPropertyName) == false) + { + continue; + } - updateValueExpressions.Add(IfStatement( - BinaryExpression(SyntaxKind.NotEqualsExpression, leftExpression, rightExpression), - Block(SingletonList(ExpressionStatement( - AssignmentExpression(SyntaxKind.SimpleAssignmentExpression, leftExpression, rightExpression)))))); + valueAssignments.Add($@"if (_visualElement.{targetPropertyName} != _viewModel.{visualTreeAttribute.Value}) + {{ + _visualElement.{targetPropertyName} = _viewModel.{visualTreeAttribute.Value}; + }}"); } - return updateValueExpressions; - - // - // return new StatementSyntax[] - // { - // IfStatement( - // BinaryExpression( - // SyntaxKind.NotEqualsExpression, - // MemberAccessExpression( - // SyntaxKind.SimpleMemberAccessExpression, - // IdentifierName("_visualElement"), - // IdentifierName("text")), - // MemberAccessExpression( - // SyntaxKind.SimpleMemberAccessExpression, - // IdentifierName("_viewModel"), - // IdentifierName("StrValue"))), - // Block( - // SingletonList( - // ExpressionStatement( - // AssignmentExpression( - // SyntaxKind.SimpleAssignmentExpression, - // MemberAccessExpression( - // SyntaxKind.SimpleMemberAccessExpression, - // IdentifierName("_visualElement"), - // IdentifierName("text")), - // MemberAccessExpression( - // SyntaxKind.SimpleMemberAccessExpression, - // IdentifierName("_viewModel"), - // IdentifierName("StrValue"))))))), - // IfStatement( - // BinaryExpression( - // SyntaxKind.NotEqualsExpression, - // MemberAccessExpression( - // SyntaxKind.SimpleMemberAccessExpression, - // IdentifierName("_visualElement"), - // IdentifierName("text")), - // MemberAccessExpression( - // SyntaxKind.SimpleMemberAccessExpression, - // IdentifierName("_viewModel"), - // IdentifierName("StrValue"))), - // Block( - // SingletonList( - // ExpressionStatement( - // AssignmentExpression( - // SyntaxKind.SimpleAssignmentExpression, - // MemberAccessExpression( - // SyntaxKind.SimpleMemberAccessExpression, - // IdentifierName("_visualElement"), - // IdentifierName("text")), - // MemberAccessExpression( - // SyntaxKind.SimpleMemberAccessExpression, - // IdentifierName("_viewModel"), - // IdentifierName("StrValue"))))))) - // }; + return valueAssignments; } - - // private MethodDeclarationSyntax CreateViewClass - private string GenerateView(ITypeSymbol typeSymbol, GeneratorExecutionContext context, ViewCapture view) + private string GenerateView(GeneratorExecutionContext context, ViewCapture view, + Dictionary bindingClasses) { var usingDirectives = view.Class.SyntaxTree.GetRoot().DescendantNodes() .OfType(); - var usingDirectivesAsText = string.Join("\r\n", usingDirectives); + var usingDirectivesAsText = string.Join(Environment.NewLine, usingDirectives); + // TODO: Filter using directives. + + var switchStringBuilder = new StringBuilder(); + var classesStringBuilder = new StringBuilder(); + + foreach (var @class in bindingClasses) + { + switchStringBuilder.Append($"{@class.Key} visualElement => new {@class.Value.Item1}Bindings(bindingContext, visualElement),"); + switchStringBuilder.Append($"{Environment.NewLine}\t\t\t\t"); + + classesStringBuilder.Append(@class.Value.Item2); + classesStringBuilder.Append($"{Environment.NewLine}"); + } + return $@"using System; using System.Runtime.CompilerServices; using UnityEngine.UIElements; @@ -409,22 +162,27 @@ private string GenerateView(ITypeSymbol typeSymbol, GeneratorExecutionContext co {usingDirectivesAsText} -namespace {typeSymbol.ContainingNamespace} +namespace {view.Class.GetParent().Name} {{ - public partial class {typeSymbol.Name} + public partial class {view.Class.Identifier.Text} {{ -// {view.AssetPath} -// {view.Class.Identifier.Text} -// {view.ViewModelIdentifier} -// {view.Class.GetParent().Name} - {GenerateBody(typeSymbol)} + protected override IVisualElementBindings GetVisualElementsBindings(MainMenuViewModel bindingContext, + IBindableVisualElement bindableElement) + {{ + return bindableElement switch + {{ + {switchStringBuilder.ToString().TrimEnd()} + _ => default + }}; + }} + {classesStringBuilder.ToString().TrimEnd()} }} }}"; } - private IEnumerable GetBindableElements(string assetFullPath) + private IEnumerable GetBindableElements(string assetFullPath) { - var result = new List(); + var result = new List(); var xmlDocument = new XmlDocument(); xmlDocument.Load(assetFullPath); @@ -446,7 +204,7 @@ private IEnumerable GetBindableElements(string assetFullPat continue; } - var bindableElementInfo = new BindableElementInfo(node.Name.Split('.').Last()); + var bindableElementInfo = new VisualTreeElementInfo(node.Name.Split('.').Last()); foreach (XmlAttribute attribute in node.Attributes) { @@ -475,7 +233,7 @@ private string GetVisualTreeAssetPath(ViewCapture view) view.AssetPath); } - private string GenerateBody(ITypeSymbol typeSymbol) + private string GenerateBody() { return $@"protected override IVisualElementBindings GetVisualElementsBindings(MainMenuViewModel bindingContext, @@ -553,33 +311,4 @@ private void UpdateStrValue() }} }}"; } - - // private class SyntaxReceiver : ISyntaxContextReceiver - // { - // public List Classes { get; } = new List(); - // - // ///

- // /// Called for every syntax node in the compilation, we can inspect the nodes and save any information useful for generation - // /// - // public void OnVisitSyntaxNode(GeneratorSyntaxContext context) - // { - // // any field with at least one attribute is a candidate for property generation - // if (context.Node is ClassDeclarationSyntax classDeclarationSyntax && - // classDeclarationSyntax.AttributeLists.Count > 0) - // { - // // Classes.Add(classDeclarationSyntax.dec.Select(x => semanticModel.GetDeclaredSymbol(x)) - // // .OfType()); - // // if (classDeclarationSyntax.AttributeLists.Any(ad => ad.)) - // // foreach (var variable in classDeclarationSyntax.Declaration.Variables) - // // { - // // // Get the symbol being declared by the field, and keep it if its annotated - // // ITypeSymbol fieldSymbol = context.SemanticModel.GetDeclaredSymbol(variable) as IFieldSymbol; - // // if (fieldSymbol.GetAttributes().Any(ad => ad.AttributeClass.ToDisplayString() == "AutoNotify.AutoNotifyAttribute")) - // // { - // // Fields.Add(fieldSymbol); - // // } - // // } - // } - // } - // } } \ No newline at end of file diff --git a/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UnityMvvmToolkit.SourceGenerators.dll b/src/UnityMvvmToolkit.UnityPackage/Assets/Plugins/UnityMvvmToolkit/Runtime/UnityMvvmToolkit.SourceGenerators.dll index e18edb90d579e4a24d2d3ea3eca619a5dc4a87c1..65219b9c74376722ee75d9b886a4bebc6e2e0a95 100644 GIT binary patch delta 4045 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 F@gH5!2VVdH delta 4148 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