diff --git a/Editor/Build/BuildCLI/AppBuildHelper.cs b/Editor/Build/BuildCLI/AppBuildHelper.cs index b40e506..c57b21e 100644 --- a/Editor/Build/BuildCLI/AppBuildHelper.cs +++ b/Editor/Build/BuildCLI/AppBuildHelper.cs @@ -22,6 +22,16 @@ public static class AppBuildHelper Debug.Log("Generate AppBuilderSetting.bytes"); + PlayerSettings.fullScreenMode = appBuildParameter.FullScreenMode; + if (appBuildParameter.FullScreenMode == FullScreenMode.Windowed) + { + PlayerSettings.defaultScreenWidth = appBuildParameter.WindowedScreenSize.x; + PlayerSettings.defaultScreenHeight = appBuildParameter.WindowedScreenSize.y; + } + + if (!string.IsNullOrEmpty(appBuildParameter.Version)) + { + } try { diff --git a/Editor/Build/BuildCLI/BuildParameter.cs b/Editor/Build/BuildCLI/BuildParameter.cs index cfee7cb..ee26ef8 100644 --- a/Editor/Build/BuildCLI/BuildParameter.cs +++ b/Editor/Build/BuildCLI/BuildParameter.cs @@ -1,6 +1,7 @@ using System; using AlicizaX; using UnityEditor; +using UnityEngine; using UnityEngine.Serialization; using YooAsset; using YooAsset.Editor; @@ -15,7 +16,22 @@ public class AppBuildParameter public int ResMode; public string FileName; public Language Language; - public string [] Scenes; + public string[] Scenes; + + /// + /// 版本 + /// + public string Version; + + /// + /// 是否全屏 + /// + public FullScreenMode FullScreenMode; + + /// + /// 窗口化大小 + /// + public Vector2Int WindowedScreenSize; } diff --git a/Editor/EditorIcons.cs b/Editor/EditorIcons.cs index ca544a6..2be3d60 100644 --- a/Editor/EditorIcons.cs +++ b/Editor/EditorIcons.cs @@ -9,7 +9,7 @@ using System.IO; public class EditorIcons : EditorWindow { - [MenuItem("Tools/Editor Icons %e", priority = -1001)] + [MenuItem("Tools/EditorExtension/Editor Icons %e", priority = -1001)] public static void EditorIconsOpen() { #if UNITY_2018 @@ -43,9 +43,9 @@ public class EditorIcons : EditorWindow search = EditorGUILayout.TextField(search, EditorStyles.toolbarSearchField); #endif if (GUILayout.Button(EditorGUIUtility.IconContent("winbtn_mac_close_h"), //SVN_DeletedLocal - EditorStyles.toolbarButton, - GUILayout.Width(22)) - ) search = ""; + EditorStyles.toolbarButton, + GUILayout.Width(22)) + ) search = ""; } } @@ -157,7 +157,7 @@ public class EditorIcons : EditorWindow //List found = new List(); List unique = new List(); //var skip_flag = HideFlags.HideInInspector | HideFlags.HideAndDontSave; - //int unique_to_resources = 0, skipped_empty_str = 0, skipped_flags = 0, + //int unique_to_resources = 0, skipped_empty_str = 0, skipped_flags = 0, // skipped_not_persistent = 0, skipped_nulls = 0, unique_to_list = 0; foreach (Texture2D x in Resources.FindObjectsOfTypeAll()) @@ -167,10 +167,10 @@ public class EditorIcons : EditorWindow //if (x.hideFlags != HideFlags.HideAndDontSave && x.hideFlags != skip_flag) skipped_flags++; // skipped 27 icons GUIContent icoContent = GetIcon(x.name); - if (icoContent == null) continue; // skipped 14 icons - //{ - // skipped_nulls++; - // continue; + if (icoContent == null) continue; // skipped 14 icons + //{ + // skipped_nulls++; + // continue; //} if (!all_icons.Contains(x.name)) @@ -211,8 +211,8 @@ public class EditorIcons : EditorWindow if (GUILayout.Button("Save all icons to folder...", EditorStyles.miniButton)) SaveAllIcons(); GUILayout.Label("Select what icons to show", GUILayout.Width(160)); viewBigIcons = GUILayout.SelectionGrid( - viewBigIcons ? 1 : 0, new string[] { "Small", "Big" }, - 2, EditorStyles.toolbarButton) == 1; + viewBigIcons ? 1 : 0, new string[] { "Small", "Big" }, + 2, EditorStyles.toolbarButton) == 1; if (isWide) SearchGUI(); } @@ -236,8 +236,9 @@ public class EditorIcons : EditorWindow List iconList; - if (doSearch) iconList = iconContentListAll.Where(x => x.tooltip.ToLower() - .Contains(search.ToLower())).ToList(); + if (doSearch) + iconList = iconContentListAll.Where(x => x.tooltip.ToLower() + .Contains(search.ToLower())).ToList(); else iconList = viewBigIcons ? iconContentListBig : iconContentListSmall; while (index < iconList.Count) @@ -253,9 +254,9 @@ public class EditorIcons : EditorWindow var icon = iconList[k]; if (GUILayout.Button(icon, - iconButtonStyle, - GUILayout.Width(buttonSize), - GUILayout.Height(buttonSize))) + iconButtonStyle, + GUILayout.Width(buttonSize), + GUILayout.Height(buttonSize))) { EditorGUI.FocusTextInControl(""); iconSelected = icon; @@ -291,8 +292,8 @@ public class EditorIcons : EditorWindow GUILayout.Space(5); darkPreview = GUILayout.SelectionGrid( - darkPreview ? 1 : 0, new string[] { "Light", "Dark" }, - 2, EditorStyles.miniButton) == 1; + darkPreview ? 1 : 0, new string[] { "Light", "Dark" }, + 2, EditorStyles.miniButton) == 1; GUILayout.FlexibleSpace(); } @@ -321,7 +322,6 @@ public class EditorIcons : EditorWindow { iconSelected = null; } - } } @@ -394,353 +394,353 @@ public class EditorIcons : EditorWindow public static string[] ico_list = { - "_Help","_Popup","aboutwindow.mainheader","ageialogo","AlphabeticalSorting","Animation.AddEvent", - "Animation.AddKeyframe","Animation.EventMarker","Animation.FirstKey","Animation.LastKey", - "Animation.NextKey","Animation.Play","Animation.PrevKey","Animation.Record","Animation.SequencerLink", - "animationanimated","animationdopesheetkeyframe","animationkeyframe","animationnocurve", - "animationvisibilitytoggleoff","animationvisibilitytoggleon","AnimationWrapModeMenu","AssemblyLock", - "Asset Store","Audio Mixer","AvatarCompass","AvatarController.Layer","AvatarController.LayerHover", - "AvatarController.LayerSelected","BodyPartPicker","BodySilhouette","DotFill","DotFrame","DotFrameDotted", - "DotSelection","Head","HeadIk","HeadZoom","HeadZoomSilhouette","LeftArm","LeftFeetIk","LeftFingers", - "LeftFingersIk","LeftHandZoom","LeftHandZoomSilhouette","LeftLeg","MaskEditor_Root","RightArm","RightFeetIk", - "RightFingers","RightFingersIk","RightHandZoom","RightHandZoomSilhouette","RightLeg","Torso","AvatarPivot", - "back","back@2x","beginButton-On","beginButton","blendKey","blendKeyOverlay","blendKeySelected", - "blendSampler","blueGroove","BuildSettings.Android","BuildSettings.Android.Small","BuildSettings.Broadcom", - "BuildSettings.Editor","BuildSettings.Editor.Small","BuildSettings.Facebook", - "BuildSettings.Facebook.Small","BuildSettings.FlashPlayer","BuildSettings.FlashPlayer.Small", - "BuildSettings.iPhone","BuildSettings.iPhone.Small","BuildSettings.Lumin","BuildSettings.Lumin.small", - "BuildSettings.Metro","BuildSettings.Metro.Small","BuildSettings.N3DS","BuildSettings.N3DS.Small", - "BuildSettings.PS4","BuildSettings.PS4.Small","BuildSettings.PSM","BuildSettings.PSM.Small", - "BuildSettings.PSP2","BuildSettings.PSP2.Small","BuildSettings.SelectedIcon","BuildSettings.Standalone", - "BuildSettings.Standalone.Small","BuildSettings.StandaloneBroadcom.Small", - "BuildSettings.StandaloneGLES20Emu.Small","BuildSettings.StandaloneGLESEmu", - "BuildSettings.StandaloneGLESEmu.Small","BuildSettings.Switch","BuildSettings.Switch.Small", - "BuildSettings.tvOS","BuildSettings.tvOS.Small","BuildSettings.Web","BuildSettings.Web.Small", - "BuildSettings.WebGL","BuildSettings.WebGL.Small","BuildSettings.WP8","BuildSettings.WP8.Small", - "BuildSettings.Xbox360","BuildSettings.Xbox360.Small","BuildSettings.XboxOne", - "BuildSettings.XboxOne.Small","BuildSettings.Xiaomi","Camera Gizmo","CheckerFloor","Clipboard", - "ClothInspector.PaintTool","ClothInspector.PaintValue","ClothInspector.SelectTool", - "ClothInspector.SettingsTool","ClothInspector.ViewValue","CloudConnect","Collab.Build", - "Collab.BuildFailed","Collab.BuildSucceeded","Collab.FileAdded","Collab.FileConflict","Collab.FileDeleted", - "Collab.FileIgnored","Collab.FileMoved","Collab.FileUpdated","Collab.FolderAdded","Collab.FolderConflict", - "Collab.FolderDeleted","Collab.FolderIgnored","Collab.FolderMoved","Collab.FolderUpdated", - "Collab.NoInternet","Collab","Collab.Warning","CollabConflict","CollabError","CollabNew","CollabOffline", - "CollabProgress","CollabPull","CollabPush","ColorPicker.ColorCycle","ColorPicker.CycleColor", - "ColorPicker.CycleSlider","ColorPicker.SliderCycle","console.erroricon.inactive.sml","console.erroricon", - "console.erroricon.sml","console.infoicon","console.infoicon.sml","console.warnicon.inactive.sml", - "console.warnicon","console.warnicon.sml","curvekeyframe","curvekeyframeselected", - "curvekeyframeselectedoverlay","curvekeyframesemiselectedoverlay","curvekeyframeweighted","CustomSorting", - "d__Popup","d_aboutwindow.mainheader","d_ageialogo","d_AlphabeticalSorting","d_Animation.AddEvent", - "d_Animation.AddKeyframe","d_Animation.EventMarker","d_Animation.FirstKey","d_Animation.LastKey", - "d_Animation.NextKey","d_Animation.Play","d_Animation.PrevKey","d_Animation.Record", - "d_Animation.SequencerLink","d_animationanimated","d_animationkeyframe","d_animationnocurve", - "d_animationvisibilitytoggleoff","d_animationvisibilitytoggleon","d_AnimationWrapModeMenu", - "d_AS Badge Delete","d_AS Badge New","d_AssemblyLock","d_Asset Store","d_Audio Mixer", - "d_AvatarBlendBackground","d_AvatarBlendLeft","d_AvatarBlendLeftA","d_AvatarBlendRight", - "d_AvatarBlendRightA","d_AvatarCompass","d_AvatarPivot","d_back","d_back@2x","d_beginButton-On", - "d_beginButton","d_blueGroove","d_BuildSettings.Android","d_BuildSettings.Android.Small", - "d_BuildSettings.Broadcom","d_BuildSettings.FlashPlayer","d_BuildSettings.FlashPlayer.Small", - "d_BuildSettings.iPhone","d_BuildSettings.iPhone.Small","d_BuildSettings.Lumin", - "d_BuildSettings.Lumin.small","d_BuildSettings.PS4","d_BuildSettings.PS4.Small","d_BuildSettings.PSP2", - "d_BuildSettings.PSP2.Small","d_BuildSettings.SelectedIcon","d_BuildSettings.Standalone", - "d_BuildSettings.Standalone.Small","d_BuildSettings.tvOS","d_BuildSettings.tvOS.Small", - "d_BuildSettings.Web","d_BuildSettings.Web.Small","d_BuildSettings.WebGL","d_BuildSettings.WebGL.Small", - "d_BuildSettings.Xbox360","d_BuildSettings.Xbox360.Small","d_BuildSettings.XboxOne", - "d_BuildSettings.XboxOne.Small","d_CheckerFloor","d_CloudConnect","d_Collab.FileAdded", - "d_Collab.FileConflict","d_Collab.FileDeleted","d_Collab.FileIgnored","d_Collab.FileMoved", - "d_Collab.FileUpdated","d_Collab.FolderAdded","d_Collab.FolderConflict","d_Collab.FolderDeleted", - "d_Collab.FolderIgnored","d_Collab.FolderMoved","d_Collab.FolderUpdated","d_ColorPicker.CycleColor", - "d_ColorPicker.CycleSlider","d_console.erroricon","d_console.erroricon.sml","d_console.infoicon", - "d_console.infoicon.sml","d_console.warnicon","d_console.warnicon.sml","d_curvekeyframe", - "d_curvekeyframeselected","d_curvekeyframeselectedoverlay","d_curvekeyframesemiselectedoverlay", - "d_curvekeyframeweighted","d_CustomSorting","d_DefaultSorting","d_EditCollider","d_editcollision_16", - "d_editconstraints_16","d_editicon.sml","d_endButton-On","d_endButton","d_eyeDropper.Large", - "d_eyeDropper.sml","d_Favorite","d_FilterByLabel","d_FilterByType","d_FilterSelectedOnly", - "d_FilterSelectedOnly@2x","d_forward","d_forward@2x","d_GEAR","d_Groove","d_HorizontalSplit", - "d_icon dropdown","d_InspectorLock","d_JointAngularLimits","d_leftBracket","d_Lighting", - "d_LightmapEditor.WindowTitle","d_LookDevCenterLight","d_LookDevCenterLight@2x","d_LookDevClose", - "d_LookDevClose@2x","d_LookDevEnvRotation","d_LookDevEnvRotation@2x","d_LookDevMirrorViews", - "d_LookDevMirrorViews@2x","d_LookDevMirrorViewsActive","d_LookDevMirrorViewsActive@2x", - "d_LookDevMirrorViewsInactive","d_LookDevMirrorViewsInactive@2x","d_LookDevObjRotation", - "d_LookDevObjRotation@2x","d_LookDevPaneOption","d_LookDevPaneOption@2x","d_LookDevResetEnv", - "d_LookDevResetEnv@2x","d_LookDevShadow","d_LookDevShadow@2x","d_LookDevSideBySide", - "d_LookDevSideBySide@2x","d_LookDevSingle1","d_LookDevSingle1@2x","d_LookDevSingle2", - "d_LookDevSingle2@2x","d_LookDevSplit","d_LookDevSplit@2x","d_LookDevZone","d_LookDevZone@2x", - "d_Mirror","d_model large","d_monologo","d_MoveTool on","d_MoveTool","d_Navigation","d_Occlusion", - "d_P4_AddedLocal","d_P4_AddedRemote","d_P4_CheckOutLocal","d_P4_CheckOutRemote","d_P4_Conflicted", - "d_P4_DeletedLocal","d_P4_DeletedRemote","d_P4_Local","d_P4_LockedLocal","d_P4_LockedRemote", - "d_P4_OutOfSync","d_Particle Effect","d_PauseButton On","d_PauseButton","d_PlayButton On","d_PlayButton", - "d_PlayButtonProfile On","d_PlayButtonProfile","d_playLoopOff","d_playLoopOn","d_preAudioAutoPlayOff", - "d_preAudioAutoPlayOn","d_preAudioLoopOff","d_preAudioLoopOn","d_preAudioPlayOff","d_preAudioPlayOn", - "d_PreMatCube","d_PreMatCylinder","d_PreMatLight0","d_PreMatLight1","d_PreMatSphere","d_PreMatTorus", - "d_Preset.Context","d_PreTextureAlpha","d_PreTextureMipMapHigh","d_PreTextureMipMapLow","d_PreTextureRGB", - "d_Profiler.Audio","d_Profiler.CPU","d_Profiler.FirstFrame","d_Profiler.GPU","d_Profiler.LastFrame", - "d_Profiler.Memory","d_Profiler.Network","d_Profiler.NextFrame","d_Profiler.Physics","d_Profiler.PrevFrame", - "d_Profiler.Record","d_Profiler.Rendering","d_Profiler.Video","d_ProfilerColumn.WarningCount","d_Project", - "d_RectTool On","d_RectTool","d_RectTransformBlueprint","d_RectTransformRaw","d_redGroove","d_Refresh", - "d_renderdoc","d_rightBracket","d_RotateTool On","d_RotateTool","d_ScaleTool On","d_ScaleTool", - "d_SceneViewAlpha","d_SceneViewAudio","d_SceneViewFx","d_SceneViewLighting","d_SceneViewOrtho", - "d_SceneViewRGB","d_ScrollShadow","d_Settings","d_SettingsIcon","d_SocialNetworks.FacebookShare", - "d_SocialNetworks.LinkedInShare","d_SocialNetworks.Tweet","d_SocialNetworks.UDNOpen","d_SpeedScale", - "d_StepButton On","d_StepButton","d_StepLeftButton-On","d_StepLeftButton","d_SVN_AddedLocal", - "d_SVN_Conflicted","d_SVN_DeletedLocal","d_SVN_Local","d_SVN_LockedLocal","d_SVN_OutOfSync","d_tab_next", - "d_tab_next@2x","d_tab_prev","d_tab_prev@2x","d_TerrainInspector.TerrainToolLower On", - "d_TerrainInspector.TerrainToolLowerAlt","d_TerrainInspector.TerrainToolPlants On", - "d_TerrainInspector.TerrainToolPlants","d_TerrainInspector.TerrainToolPlantsAlt On", - "d_TerrainInspector.TerrainToolPlantsAlt","d_TerrainInspector.TerrainToolRaise On", - "d_TerrainInspector.TerrainToolRaise","d_TerrainInspector.TerrainToolSetheight On", - "d_TerrainInspector.TerrainToolSetheight","d_TerrainInspector.TerrainToolSetheightAlt On", - "d_TerrainInspector.TerrainToolSetheightAlt","d_TerrainInspector.TerrainToolSettings On", - "d_TerrainInspector.TerrainToolSettings","d_TerrainInspector.TerrainToolSmoothHeight On", - "d_TerrainInspector.TerrainToolSmoothHeight","d_TerrainInspector.TerrainToolSplat On", - "d_TerrainInspector.TerrainToolSplat","d_TerrainInspector.TerrainToolSplatAlt On", - "d_TerrainInspector.TerrainToolSplatAlt","d_TerrainInspector.TerrainToolTrees On", - "d_TerrainInspector.TerrainToolTrees","d_TerrainInspector.TerrainToolTreesAlt On", - "d_TerrainInspector.TerrainToolTreesAlt","d_TimelineDigIn","d_TimelineEditModeMixOFF", - "d_TimelineEditModeMixON","d_TimelineEditModeReplaceOFF","d_TimelineEditModeReplaceON", - "d_TimelineEditModeRippleOFF","d_TimelineEditModeRippleON","d_TimelineSelector","d_Toolbar Minus", - "d_Toolbar Plus More","d_Toolbar Plus","d_ToolHandleCenter","d_ToolHandleGlobal","d_ToolHandleLocal", - "d_ToolHandlePivot","d_tranp","d_TransformTool On","d_TransformTool","d_tree_icon","d_tree_icon_branch", - "d_tree_icon_branch_frond","d_tree_icon_frond","d_tree_icon_leaf","d_TreeEditor.AddBranches", - "d_TreeEditor.AddLeaves","d_TreeEditor.Branch On","d_TreeEditor.Branch","d_TreeEditor.BranchFreeHand On", - "d_TreeEditor.BranchFreeHand","d_TreeEditor.BranchRotate On","d_TreeEditor.BranchRotate", - "d_TreeEditor.BranchScale On","d_TreeEditor.BranchScale","d_TreeEditor.BranchTranslate On", - "d_TreeEditor.BranchTranslate","d_TreeEditor.Distribution On","d_TreeEditor.Distribution", - "d_TreeEditor.Duplicate","d_TreeEditor.Geometry On","d_TreeEditor.Geometry","d_TreeEditor.Leaf On", - "d_TreeEditor.Leaf","d_TreeEditor.LeafFreeHand On","d_TreeEditor.LeafFreeHand","d_TreeEditor.LeafRotate On", - "d_TreeEditor.LeafRotate","d_TreeEditor.LeafScale On","d_TreeEditor.LeafScale", - "d_TreeEditor.LeafTranslate On","d_TreeEditor.LeafTranslate","d_TreeEditor.Material On", - "d_TreeEditor.Material","d_TreeEditor.Refresh","d_TreeEditor.Trash","d_TreeEditor.Wind On", - "d_TreeEditor.Wind","d_UnityEditor.AnimationWindow","d_UnityEditor.ConsoleWindow", - "d_UnityEditor.DebugInspectorWindow","d_UnityEditor.FindDependencies","d_UnityEditor.GameView", - "d_UnityEditor.HierarchyWindow","d_UnityEditor.InspectorWindow","d_UnityEditor.LookDevView", - "d_UnityEditor.ProfilerWindow","d_UnityEditor.SceneHierarchyWindow","d_UnityEditor.SceneView", - "d_UnityEditor.Timeline.TimelineWindow","d_UnityEditor.VersionControl","d_UnityLogo","d_VerticalSplit", - "d_ViewToolMove On","d_ViewToolMove","d_ViewToolOrbit On","d_ViewToolOrbit","d_ViewToolZoom On", - "d_ViewToolZoom","d_VisibilityOff","d_VisibilityOn","d_VUMeterTextureHorizontal","d_VUMeterTextureVertical", - "d_WaitSpin00","d_WaitSpin01","d_WaitSpin02","d_WaitSpin03","d_WaitSpin04","d_WaitSpin05","d_WaitSpin06", - "d_WaitSpin07","d_WaitSpin08","d_WaitSpin09","d_WaitSpin10","d_WaitSpin11","d_WelcomeScreen.AssetStoreLogo", - "d_winbtn_graph","d_winbtn_graph_close_h","d_winbtn_graph_max_h","d_winbtn_graph_min_h", - "d_winbtn_mac_close","d_winbtn_mac_close_a","d_winbtn_mac_close_h","d_winbtn_mac_inact","d_winbtn_mac_max", - "d_winbtn_mac_max_a","d_winbtn_mac_max_h","d_winbtn_mac_min","d_winbtn_mac_min_a","d_winbtn_mac_min_h", - "d_winbtn_win_close","d_winbtn_win_close_a","d_winbtn_win_close_h","d_winbtn_win_max","d_winbtn_win_max_a", - "d_winbtn_win_max_h","d_winbtn_win_min","d_winbtn_win_min_a","d_winbtn_win_min_h","d_winbtn_win_rest", - "d_winbtn_win_rest_a","d_winbtn_win_rest_h","DefaultSorting","EditCollider","editcollision_16", - "editconstraints_16","editicon.sml","endButton-On","endButton","eyeDropper.Large","eyeDropper.sml", - "Favorite","FilterByLabel","FilterByType","FilterSelectedOnly","FilterSelectedOnly@2x","forward", - "forward@2x","GEAR","Grid.BoxTool","Grid.Default","Grid.EraserTool","Grid.FillTool","Grid.MoveTool", - "Grid.PaintTool","Grid.PickingTool","Grid.SelectTool","Groove","align_horizontally", - "align_horizontally_center","align_horizontally_center_active","align_horizontally_left", - "align_horizontally_left_active","align_horizontally_right","align_horizontally_right_active", - "align_vertically","align_vertically_bottom","align_vertically_bottom_active","align_vertically_center", - "align_vertically_center_active","align_vertically_top","align_vertically_top_active", - "d_align_horizontally","d_align_horizontally_center","d_align_horizontally_center_active", - "d_align_horizontally_left","d_align_horizontally_left_active","d_align_horizontally_right", - "d_align_horizontally_right_active","d_align_vertically","d_align_vertically_bottom", - "d_align_vertically_bottom_active","d_align_vertically_center","d_align_vertically_center_active", - "d_align_vertically_top","d_align_vertically_top_active","HorizontalSplit","icon dropdown", - "InspectorLock","JointAngularLimits","KnobCShape","KnobCShapeMini","leftBracket","Lighting", - "LightmapEditor.WindowTitle","Lightmapping","d_greenLight","d_lightOff","d_lightRim","d_orangeLight", - "d_redLight","greenLight","lightOff","lightRim","orangeLight","redLight","LockIcon-On","LockIcon", - "LookDevCenterLight","LookDevCenterLightl@2x","LookDevClose","LookDevClose@2x","LookDevEnvRotation", - "LookDevEnvRotation@2x","LookDevEyedrop","LookDevLight","LookDevLight@2x","LookDevMirrorViewsActive", - "LookDevMirrorViewsActive@2x","LookDevMirrorViewsInactive","LookDevMirrorViewsInactive@2x", - "LookDevObjRotation","LookDevObjRotation@2x","LookDevPaneOption","LookDevPaneOption@2x","LookDevResetEnv", - "LookDevResetEnv@2x","LookDevShadow","LookDevShadow@2x","LookDevShadowFrame","LookDevShadowFrame@2x", - "LookDevSideBySide","LookDevSideBySide@2x","LookDevSingle1","LookDevSingle1@2x","LookDevSingle2", - "LookDevSingle2@2x","LookDevSplit","LookDevSplit@2x","LookDevZone","LookDevZone@2x","loop","Mirror", - "monologo","MoveTool on","MoveTool","Navigation","Occlusion","P4_AddedLocal","P4_AddedRemote", - "P4_BlueLeftParenthesis","P4_BlueRightParenthesis","P4_CheckOutLocal","P4_CheckOutRemote","P4_Conflicted", - "P4_DeletedLocal","P4_DeletedRemote","P4_Local","P4_LockedLocal","P4_LockedRemote","P4_OutOfSync", - "P4_RedLeftParenthesis","P4_RedRightParenthesis","P4_Updating","PackageBadgeDelete","PackageBadgeNew", - "Particle Effect","PauseButton On","PauseButton","PlayButton On","PlayButton","PlayButtonProfile On", - "PlayButtonProfile","playLoopOff","playLoopOn","playSpeed","preAudioAutoPlayOff","preAudioAutoPlayOn", - "preAudioLoopOff","preAudioLoopOn","preAudioPlayOff","preAudioPlayOn","PreMatCube","PreMatCylinder", - "PreMatLight0","PreMatLight1","PreMatQuad","PreMatSphere","PreMatTorus","Preset.Context","PreTextureAlpha", - "PreTextureArrayFirstSlice","PreTextureArrayLastSlice","PreTextureMipMapHigh","PreTextureMipMapLow", - "PreTextureRGB","AreaLight Gizmo","AreaLight Icon","Assembly Icon","AssetStore Icon","AudioMixerView Icon", - "AudioSource Gizmo","Camera Gizmo","CGProgram Icon","ChorusFilter Icon","CollabChanges Icon", - "CollabChangesConflict Icon","CollabChangesDeleted Icon","CollabConflict Icon","CollabCreate Icon", - "CollabDeleted Icon","CollabEdit Icon","CollabExclude Icon","CollabMoved Icon","cs Script Icon", - "d_AudioMixerView Icon","d_CollabChanges Icon","d_CollabChangesConflict Icon","d_CollabChangesDeleted Icon", - "d_CollabConflict Icon","d_CollabCreate Icon","d_CollabDeleted Icon","d_CollabEdit Icon", - "d_CollabExclude Icon","d_CollabMoved Icon","d_GridLayoutGroup Icon","d_HorizontalLayoutGroup Icon", - "d_Prefab Icon","d_PrefabModel Icon","d_PrefabVariant Icon","d_VerticalLayoutGroup Icon", - "DefaultSlate Icon","DirectionalLight Gizmo","DirectionalLight Icon","DiscLight Gizmo","DiscLight Icon", - "dll Script Icon","EchoFilter Icon","Favorite Icon","Folder Icon","FolderEmpty Icon", - "FolderFavorite Icon","GameManager Icon","GridBrush Icon","HighPassFilter Icon", - "HorizontalLayoutGroup Icon","LensFlare Gizmo","LightingDataAssetParent Icon","LightProbeGroup Gizmo", - "LightProbeProxyVolume Gizmo","LowPassFilter Icon","Main Light Gizmo","MetaFile Icon", - "Microphone Icon","MuscleClip Icon","ParticleSystem Gizmo","PointLight Gizmo","Prefab Icon", - "PrefabModel Icon","PrefabOverlayAdded Icon","PrefabOverlayModified Icon","PrefabOverlayRemoved Icon", - "PrefabVariant Icon","Projector Gizmo","RaycastCollider Icon","ReflectionProbe Gizmo", - "ReverbFilter Icon","SceneSet Icon","Search Icon","SoftlockProjectBrowser Icon","SpeedTreeModel Icon", - "SpotLight Gizmo","Spotlight Icon","SpriteCollider Icon","sv_icon_dot0_pix16_gizmo", - "sv_icon_dot10_pix16_gizmo","sv_icon_dot11_pix16_gizmo","sv_icon_dot12_pix16_gizmo", - "sv_icon_dot13_pix16_gizmo","sv_icon_dot14_pix16_gizmo","sv_icon_dot15_pix16_gizmo", - "sv_icon_dot1_pix16_gizmo","sv_icon_dot2_pix16_gizmo","sv_icon_dot3_pix16_gizmo", - "sv_icon_dot4_pix16_gizmo","sv_icon_dot5_pix16_gizmo","sv_icon_dot6_pix16_gizmo", - "sv_icon_dot7_pix16_gizmo","sv_icon_dot8_pix16_gizmo","sv_icon_dot9_pix16_gizmo", - "AnimatorController Icon","AnimatorState Icon","AnimatorStateMachine Icon", - "AnimatorStateTransition Icon","BlendTree Icon","AnimationWindowEvent Icon","AudioMixerController Icon", - "DefaultAsset Icon","EditorSettings Icon","AnyStateNode Icon","HumanTemplate Icon", - "LightingDataAsset Icon","LightmapParameters Icon","Preset Icon","SceneAsset Icon", - "SubstanceArchive Icon","AssemblyDefinitionAsset Icon","NavMeshAgent Icon","NavMeshData Icon", - "NavMeshObstacle Icon","OffMeshLink Icon","AnalyticsTracker Icon","Animation Icon", - "AnimationClip Icon","AimConstraint Icon","d_AimConstraint Icon","d_LookAtConstraint Icon", - "d_ParentConstraint Icon","d_PositionConstraint Icon","d_RotationConstraint Icon", - "d_ScaleConstraint Icon","LookAtConstraint Icon","ParentConstraint Icon","PositionConstraint Icon", - "RotationConstraint Icon","ScaleConstraint Icon","Animator Icon","AnimatorOverrideController Icon", - "AreaEffector2D Icon","AudioMixerGroup Icon","AudioMixerSnapshot Icon","AudioSpatializerMicrosoft Icon", - "AudioChorusFilter Icon","AudioClip Icon","AudioDistortionFilter Icon","AudioEchoFilter Icon", - "AudioHighPassFilter Icon","AudioListener Icon","AudioLowPassFilter Icon","AudioReverbFilter Icon", - "AudioReverbZone Icon","AudioSource Icon","Avatar Icon","AvatarMask Icon","BillboardAsset Icon", - "BillboardRenderer Icon","BoxCollider Icon","BoxCollider2D Icon","BuoyancyEffector2D Icon","Camera Icon", - "Canvas Icon","CanvasGroup Icon","CanvasRenderer Icon","CapsuleCollider Icon","CapsuleCollider2D Icon", - "CharacterController Icon","CharacterJoint Icon","CircleCollider2D Icon","Cloth Icon", - "CompositeCollider2D Icon","ComputeShader Icon","ConfigurableJoint Icon","ConstantForce Icon", - "ConstantForce2D Icon","Cubemap Icon","d_Canvas Icon","d_CanvasGroup Icon","d_CanvasRenderer Icon", - "d_GameObject Icon","d_LightProbeProxyVolume Icon","d_ParticleSystem Icon","d_ParticleSystemForceField Icon", - "d_RectTransform Icon","d_StreamingController Icon","DistanceJoint2D Icon","EdgeCollider2D Icon", - "d_EventSystem Icon","d_EventTrigger Icon","d_Physics2DRaycaster Icon","d_PhysicsRaycaster Icon", - "d_StandaloneInputModule Icon","d_TouchInputModule Icon","EventSystem Icon","EventTrigger Icon", - "HoloLensInputModule Icon","Physics2DRaycaster Icon","PhysicsRaycaster Icon","StandaloneInputModule Icon", - "TouchInputModule Icon","SpriteShapeRenderer Icon","VisualTreeAsset Icon","d_VisualEffect Icon", - "d_VisualEffectAsset Icon","VisualEffect Icon","VisualEffectAsset Icon","FixedJoint Icon", - "FixedJoint2D Icon","Flare Icon","FlareLayer Icon","Font Icon","FrictionJoint2D Icon", - "GameObject Icon","Grid Icon","GUILayer Icon","GUISkin Icon","GUIText Icon","GUITexture Icon", - "Halo Icon","HingeJoint Icon","HingeJoint2D Icon","LensFlare Icon","Light Icon","LightProbeGroup Icon", - "LightProbeProxyVolume Icon","LightProbes Icon","LineRenderer Icon","LODGroup Icon","Material Icon", - "Mesh Icon","MeshCollider Icon","MeshFilter Icon","MeshRenderer Icon","Motion Icon","MovieTexture Icon", - "NetworkAnimator Icon","NetworkDiscovery Icon","NetworkIdentity Icon","NetworkLobbyManager Icon", - "NetworkLobbyPlayer Icon","NetworkManager Icon","NetworkManagerHUD Icon","NetworkMigrationManager Icon", - "NetworkProximityChecker Icon","NetworkStartPosition Icon","NetworkTransform Icon", - "NetworkTransformChild Icon","NetworkTransformVisualizer Icon","NetworkView Icon","OcclusionArea Icon", - "OcclusionPortal Icon","ParticleSystem Icon","ParticleSystemForceField Icon","PhysicMaterial Icon", - "PhysicsMaterial2D Icon","PlatformEffector2D Icon","d_PlayableDirector Icon","PlayableDirector Icon", - "PointEffector2D Icon","PolygonCollider2D Icon","ProceduralMaterial Icon","Projector Icon", - "RectTransform Icon","ReflectionProbe Icon","RelativeJoint2D Icon","d_SortingGroup Icon", - "SortingGroup Icon","RenderTexture Icon","Rigidbody Icon","Rigidbody2D Icon","ScriptableObject Icon", - "Shader Icon","ShaderVariantCollection Icon","SkinnedMeshRenderer Icon","Skybox Icon","SliderJoint2D Icon", - "TrackedPoseDriver Icon","SphereCollider Icon","SpringJoint Icon","SpringJoint2D Icon","Sprite Icon", - "SpriteMask Icon","SpriteRenderer Icon","StreamingController Icon","StyleSheet Icon","SurfaceEffector2D Icon", - "TargetJoint2D Icon","Terrain Icon","TerrainCollider Icon","TerrainData Icon","TextAsset Icon", - "TextMesh Icon","Texture Icon","Texture2D Icon","Tile Icon","Tilemap Icon","TilemapCollider2D Icon", - "TilemapRenderer Icon","d_TimelineAsset Icon","TimelineAsset Icon","TrailRenderer Icon","Transform Icon", - "SpriteAtlas Icon","AspectRatioFitter Icon","Button Icon","CanvasScaler Icon","ContentSizeFitter Icon", - "d_AspectRatioFitter Icon","d_CanvasScaler Icon","d_ContentSizeFitter Icon","d_FreeformLayoutGroup Icon", - "d_GraphicRaycaster Icon","d_GridLayoutGroup Icon","d_HorizontalLayoutGroup Icon","d_LayoutElement Icon", - "d_PhysicalResolution Icon","d_ScrollViewArea Icon","d_SelectionList Icon","d_SelectionListItem Icon", - "d_SelectionListTemplate Icon","d_VerticalLayoutGroup Icon","Dropdown Icon","FreeformLayoutGroup Icon", - "GraphicRaycaster Icon","GridLayoutGroup Icon","HorizontalLayoutGroup Icon","Image Icon","InputField Icon", - "LayoutElement Icon","Mask Icon","Outline Icon","PositionAsUV1 Icon","RawImage Icon","RectMask2D Icon", - "Scrollbar Icon","ScrollRect Icon","Selectable Icon","Shadow Icon","Slider Icon","Text Icon","Toggle Icon", - "ToggleGroup Icon","VerticalLayoutGroup Icon","VideoClip Icon","VideoPlayer Icon","VisualEffect Icon", - "VisualEffectAsset Icon","WheelCollider Icon","WheelJoint2D Icon","WindZone Icon", - "SpatialMappingCollider Icon","SpatialMappingRenderer Icon","WorldAnchor Icon","UssScript Icon", - "UxmlScript Icon","VerticalLayoutGroup Icon","VideoEffect Icon","VisualEffect Gizmo", - "VisualEffectAsset Icon","AnchorBehaviour Icon","AnchorInputListenerBehaviour Icon", - "AnchorStageBehaviour Icon","CloudRecoBehaviour Icon","ContentPlacementBehaviour Icon", - "ContentPositioningBehaviour Icon","CylinderTargetBehaviour Icon","d_AnchorBehaviour Icon", - "d_AnchorInputListenerBehaviour Icon","d_AnchorStageBehaviour Icon","d_CloudRecoBehaviour Icon", - "d_ContentPlacementBehaviour Icon","d_ContentPositioningBehaviour Icon","d_CylinderTargetBehaviour Icon", - "d_ImageTargetBehaviour Icon","d_MidAirPositionerBehaviour Icon","d_ModelTargetBehaviour Icon", - "d_MultiTargetBehaviour Icon","d_ObjectTargetBehaviour Icon","d_PlaneFinderBehaviour Icon", - "d_UserDefinedTargetBuildingBehaviour Icon","d_VirtualButtonBehaviour Icon","d_VuforiaBehaviour Icon", - "d_VuMarkBehaviour Icon","d_WireframeBehaviour Icon","ImageTargetBehaviour Icon", - "MidAirPositionerBehaviour Icon","ModelTargetBehaviour Icon","MultiTargetBehaviour Icon", - "ObjectTargetBehaviour Icon","PlaneFinderBehaviour Icon","UserDefinedTargetBuildingBehaviour Icon", - "VirtualButtonBehaviour Icon","VuforiaBehaviour Icon","VuMarkBehaviour Icon","WireframeBehaviour Icon", - "WindZone Gizmo","Profiler.Audio","Profiler.CPU","Profiler.FirstFrame","Profiler.GlobalIllumination", - "Profiler.GPU","Profiler.Instrumentation","Profiler.LastFrame","Profiler.Memory","Profiler.NetworkMessages", - "Profiler.NetworkOperations","Profiler.NextFrame","Profiler.Physics","Profiler.Physics2D", - "Profiler.PrevFrame","Profiler.Record","Profiler.Rendering","Profiler.UI","Profiler.UIDetails", - "Profiler.Video","ProfilerColumn.WarningCount","Project","RectTool On","RectTool","RectTransformBlueprint", - "RectTransformRaw","redGroove","Refresh","renderdoc","rightBracket","RotateTool On","RotateTool", - "SaveActive","SaveFromPlay","SavePassive","ScaleTool On","ScaleTool","SceneLoadIn","SceneLoadOut", - "SceneSave","SceneSaveGrey","SceneViewAlpha","SceneViewAudio","SceneViewFx","SceneViewLighting", - "SceneViewOrtho","SceneViewRGB","ScrollShadow","Settings","SettingsIcon","SocialNetworks.FacebookShare", - "SocialNetworks.LinkedInShare","SocialNetworks.Tweet","SocialNetworks.UDNLogo","SocialNetworks.UDNOpen", - "SoftlockInline","SpeedScale","StateMachineEditor.ArrowTip","StateMachineEditor.ArrowTipSelected", - "StateMachineEditor.Background","StateMachineEditor.State","StateMachineEditor.StateHover", - "StateMachineEditor.StateSelected","StateMachineEditor.StateSub","StateMachineEditor.StateSubHover", - "StateMachineEditor.StateSubSelected","StateMachineEditor.UpButton","StateMachineEditor.UpButtonHover", - "StepButton On","StepButton","StepLeftButton-On","StepLeftButton","sticky_arrow","sticky_p4","sticky_skin", - "sv_icon_dot0_sml","sv_icon_dot10_sml","sv_icon_dot11_sml","sv_icon_dot12_sml","sv_icon_dot13_sml", - "sv_icon_dot14_sml","sv_icon_dot15_sml","sv_icon_dot1_sml","sv_icon_dot2_sml","sv_icon_dot3_sml", - "sv_icon_dot4_sml","sv_icon_dot5_sml","sv_icon_dot6_sml","sv_icon_dot7_sml","sv_icon_dot8_sml", - "sv_icon_dot9_sml","sv_icon_name0","sv_icon_name1","sv_icon_name2","sv_icon_name3","sv_icon_name4", - "sv_icon_name5","sv_icon_name6","sv_icon_name7","sv_icon_none","sv_label_0","sv_label_1","sv_label_2", - "sv_label_3","sv_label_4","sv_label_5","sv_label_6","sv_label_7","SVN_AddedLocal","SVN_Conflicted", - "SVN_DeletedLocal","SVN_Local","SVN_LockedLocal","SVN_OutOfSync","tab_next","tab_next@2x","tab_prev", - "tab_prev@2x","TerrainInspector.TerrainToolLower On","TerrainInspector.TerrainToolLower", - "TerrainInspector.TerrainToolLowerAlt","TerrainInspector.TerrainToolPlants On", - "TerrainInspector.TerrainToolPlants","TerrainInspector.TerrainToolPlantsAlt On", - "TerrainInspector.TerrainToolPlantsAlt","TerrainInspector.TerrainToolRaise On", - "TerrainInspector.TerrainToolRaise","TerrainInspector.TerrainToolSculpt On", - "TerrainInspector.TerrainToolSculpt","TerrainInspector.TerrainToolSetheight On", - "TerrainInspector.TerrainToolSetheight","TerrainInspector.TerrainToolSetheightAlt On", - "TerrainInspector.TerrainToolSetheightAlt","TerrainInspector.TerrainToolSettings On", - "TerrainInspector.TerrainToolSettings","TerrainInspector.TerrainToolSmoothHeight On", - "TerrainInspector.TerrainToolSmoothHeight","TerrainInspector.TerrainToolSplat On", - "TerrainInspector.TerrainToolSplat","TerrainInspector.TerrainToolSplatAlt On", - "TerrainInspector.TerrainToolSplatAlt","TerrainInspector.TerrainToolTrees On", - "TerrainInspector.TerrainToolTrees","TerrainInspector.TerrainToolTreesAlt On", - "TerrainInspector.TerrainToolTreesAlt","TestFailed","TestIgnored","TestInconclusive","TestNormal", - "TestPassed","TestStopwatch","TimelineClipBG","TimelineClipFG","TimelineDigIn","TimelineEditModeMixOFF", - "TimelineEditModeMixON","TimelineEditModeReplaceOFF","TimelineEditModeReplaceON","TimelineEditModeRippleOFF", - "TimelineEditModeRippleON","TimelineSelector","Toolbar Minus","Toolbar Plus More","Toolbar Plus", - "ToolHandleCenter","ToolHandleGlobal","ToolHandleLocal","ToolHandlePivot","tranp","TransformTool On", - "TransformTool","tree_icon","tree_icon_branch","tree_icon_branch_frond","tree_icon_frond","tree_icon_leaf", - "TreeEditor.AddBranches","TreeEditor.AddLeaves","TreeEditor.Branch On","TreeEditor.Branch", - "TreeEditor.BranchFreeHand On","TreeEditor.BranchFreeHand","TreeEditor.BranchRotate On", - "TreeEditor.BranchRotate","TreeEditor.BranchScale On","TreeEditor.BranchScale", - "TreeEditor.BranchTranslate On","TreeEditor.BranchTranslate","TreeEditor.Distribution On", - "TreeEditor.Distribution","TreeEditor.Duplicate","TreeEditor.Geometry On","TreeEditor.Geometry", - "TreeEditor.Leaf On","TreeEditor.Leaf","TreeEditor.LeafFreeHand On","TreeEditor.LeafFreeHand", - "TreeEditor.LeafRotate On","TreeEditor.LeafRotate","TreeEditor.LeafScale On","TreeEditor.LeafScale", - "TreeEditor.LeafTranslate On","TreeEditor.LeafTranslate","TreeEditor.Material On","TreeEditor.Material", - "TreeEditor.Refresh","TreeEditor.Trash","TreeEditor.Wind On","TreeEditor.Wind","UnityEditor.AnimationWindow", - "UnityEditor.ConsoleWindow","UnityEditor.DebugInspectorWindow","UnityEditor.FindDependencies", - "UnityEditor.GameView","UnityEditor.Graphs.AnimatorControllerTool","UnityEditor.HierarchyWindow", - "UnityEditor.InspectorWindow","UnityEditor.LookDevView","UnityEditor.ProfilerWindow", - "UnityEditor.SceneHierarchyWindow","UnityEditor.SceneView","UnityEditor.Timeline.TimelineWindow", - "UnityEditor.VersionControl","UnityLogo","UnityLogoLarge","UpArrow","vcs_add","vcs_branch","vcs_change", - "vcs_check","vcs_delete","vcs_document","vcs_edit","vcs_incoming","vcs_integrate","vcs_local","vcs_lock", - "vcs_refresh","vcs_sync","vcs_unresolved","vcs_update","VerticalSplit","ViewToolMove On","ViewToolMove", - "ViewToolOrbit On","ViewToolOrbit","ViewToolZoom On","ViewToolZoom","VisibilityOff","VisibilityOn", - "VisualEffect Gizmo","VUMeterTextureHorizontal","VUMeterTextureVertical","WaitSpin00","WaitSpin01", - "WaitSpin02","WaitSpin03","WaitSpin04","WaitSpin05","WaitSpin06","WaitSpin07","WaitSpin08","WaitSpin09", - "WaitSpin10","WaitSpin11","WelcomeScreen.AssetStoreLogo","winbtn_graph","winbtn_graph_close_h", - "winbtn_graph_max_h","winbtn_graph_min_h","winbtn_mac_close","winbtn_mac_close_a","winbtn_mac_close_h", - "winbtn_mac_inact","winbtn_mac_max","winbtn_mac_max_a","winbtn_mac_max_h","winbtn_mac_min", - "winbtn_mac_min_a","winbtn_mac_min_h","winbtn_win_close","winbtn_win_close_a","winbtn_win_close_h", - "winbtn_win_max","winbtn_win_max_a","winbtn_win_max_h","winbtn_win_min","winbtn_win_min_a", - "winbtn_win_min_h","winbtn_win_rest","winbtn_win_rest_a","winbtn_win_rest_h", - "AvatarInspector/RightFingersIk","AvatarInspector/LeftFingersIk","AvatarInspector/RightFeetIk", - "AvatarInspector/LeftFeetIk","AvatarInspector/RightFingers","AvatarInspector/LeftFingers", - "AvatarInspector/RightArm","AvatarInspector/LeftArm","AvatarInspector/RightLeg","AvatarInspector/LeftLeg", - "AvatarInspector/Head","AvatarInspector/Torso","AvatarInspector/MaskEditor_Root", - "AvatarInspector/BodyPartPicker","AvatarInspector/BodySIlhouette","boo Script Icon","js Script Icon", - "EyeDropper.Large","AboutWindow.MainHeader","AgeiaLogo","MonoLogo","PlayButtonProfile Anim", - "StepButton Anim","PauseButton Anim","PlayButton Anim","MoveTool On","Icon Dropdown", - "AvatarInspector/DotSelection","AvatarInspector/DotFrameDotted","AvatarInspector/DotFrame", - "AvatarInspector/DotFill","AvatarInspector/RightHandZoom","AvatarInspector/LeftHandZoom", - "AvatarInspector/HeadZoom","AvatarInspector/RightLeg","AvatarInspector/LeftLeg", - "AvatarInspector/RightFingers","AvatarInspector/RightArm","AvatarInspector/LeftFingers", - "AvatarInspector/LeftArm","AvatarInspector/Head","AvatarInspector/Torso", - "AvatarInspector/RightHandZoomSilhouette","AvatarInspector/LeftHandZoomSilhouette", - "AvatarInspector/HeadZoomSilhouette","AvatarInspector/BodySilhouette","lightMeter/redLight", - "lightMeter/orangeLight","lightMeter/lightRim","lightMeter/greenLight","SceneviewAudio", - "SceneviewLighting","TerrainInspector.TerrainToolSetHeight","AS Badge New","AS Badge Move", - "AS Badge Delete","WelcomeScreen.UnityAnswersLogo","WelcomeScreen.UnityForumLogo", - "WelcomeScreen.UnityBasicsLogo","WelcomeScreen.VideoTutLogo","WelcomeScreen.MainHeader","Icon Dropdown", - "PrefabNormal Icon","PrefabNormal Icon","BuildSettings.BlackBerry.Small","BuildSettings.Tizen.Small", - "BuildSettings.XBox360.Small","BuildSettings.PS3.Small","BuildSettings.SamsungTV.Small", - "BuildSettings.BlackBerry","BuildSettings.Tizen","BuildSettings.XBox360","BuildSettings.PS3", + "_Help", "_Popup", "aboutwindow.mainheader", "ageialogo", "AlphabeticalSorting", "Animation.AddEvent", + "Animation.AddKeyframe", "Animation.EventMarker", "Animation.FirstKey", "Animation.LastKey", + "Animation.NextKey", "Animation.Play", "Animation.PrevKey", "Animation.Record", "Animation.SequencerLink", + "animationanimated", "animationdopesheetkeyframe", "animationkeyframe", "animationnocurve", + "animationvisibilitytoggleoff", "animationvisibilitytoggleon", "AnimationWrapModeMenu", "AssemblyLock", + "Asset Store", "Audio Mixer", "AvatarCompass", "AvatarController.Layer", "AvatarController.LayerHover", + "AvatarController.LayerSelected", "BodyPartPicker", "BodySilhouette", "DotFill", "DotFrame", "DotFrameDotted", + "DotSelection", "Head", "HeadIk", "HeadZoom", "HeadZoomSilhouette", "LeftArm", "LeftFeetIk", "LeftFingers", + "LeftFingersIk", "LeftHandZoom", "LeftHandZoomSilhouette", "LeftLeg", "MaskEditor_Root", "RightArm", "RightFeetIk", + "RightFingers", "RightFingersIk", "RightHandZoom", "RightHandZoomSilhouette", "RightLeg", "Torso", "AvatarPivot", + "back", "back@2x", "beginButton-On", "beginButton", "blendKey", "blendKeyOverlay", "blendKeySelected", + "blendSampler", "blueGroove", "BuildSettings.Android", "BuildSettings.Android.Small", "BuildSettings.Broadcom", + "BuildSettings.Editor", "BuildSettings.Editor.Small", "BuildSettings.Facebook", + "BuildSettings.Facebook.Small", "BuildSettings.FlashPlayer", "BuildSettings.FlashPlayer.Small", + "BuildSettings.iPhone", "BuildSettings.iPhone.Small", "BuildSettings.Lumin", "BuildSettings.Lumin.small", + "BuildSettings.Metro", "BuildSettings.Metro.Small", "BuildSettings.N3DS", "BuildSettings.N3DS.Small", + "BuildSettings.PS4", "BuildSettings.PS4.Small", "BuildSettings.PSM", "BuildSettings.PSM.Small", + "BuildSettings.PSP2", "BuildSettings.PSP2.Small", "BuildSettings.SelectedIcon", "BuildSettings.Standalone", + "BuildSettings.Standalone.Small", "BuildSettings.StandaloneBroadcom.Small", + "BuildSettings.StandaloneGLES20Emu.Small", "BuildSettings.StandaloneGLESEmu", + "BuildSettings.StandaloneGLESEmu.Small", "BuildSettings.Switch", "BuildSettings.Switch.Small", + "BuildSettings.tvOS", "BuildSettings.tvOS.Small", "BuildSettings.Web", "BuildSettings.Web.Small", + "BuildSettings.WebGL", "BuildSettings.WebGL.Small", "BuildSettings.WP8", "BuildSettings.WP8.Small", + "BuildSettings.Xbox360", "BuildSettings.Xbox360.Small", "BuildSettings.XboxOne", + "BuildSettings.XboxOne.Small", "BuildSettings.Xiaomi", "Camera Gizmo", "CheckerFloor", "Clipboard", + "ClothInspector.PaintTool", "ClothInspector.PaintValue", "ClothInspector.SelectTool", + "ClothInspector.SettingsTool", "ClothInspector.ViewValue", "CloudConnect", "Collab.Build", + "Collab.BuildFailed", "Collab.BuildSucceeded", "Collab.FileAdded", "Collab.FileConflict", "Collab.FileDeleted", + "Collab.FileIgnored", "Collab.FileMoved", "Collab.FileUpdated", "Collab.FolderAdded", "Collab.FolderConflict", + "Collab.FolderDeleted", "Collab.FolderIgnored", "Collab.FolderMoved", "Collab.FolderUpdated", + "Collab.NoInternet", "Collab", "Collab.Warning", "CollabConflict", "CollabError", "CollabNew", "CollabOffline", + "CollabProgress", "CollabPull", "CollabPush", "ColorPicker.ColorCycle", "ColorPicker.CycleColor", + "ColorPicker.CycleSlider", "ColorPicker.SliderCycle", "console.erroricon.inactive.sml", "console.erroricon", + "console.erroricon.sml", "console.infoicon", "console.infoicon.sml", "console.warnicon.inactive.sml", + "console.warnicon", "console.warnicon.sml", "curvekeyframe", "curvekeyframeselected", + "curvekeyframeselectedoverlay", "curvekeyframesemiselectedoverlay", "curvekeyframeweighted", "CustomSorting", + "d__Popup", "d_aboutwindow.mainheader", "d_ageialogo", "d_AlphabeticalSorting", "d_Animation.AddEvent", + "d_Animation.AddKeyframe", "d_Animation.EventMarker", "d_Animation.FirstKey", "d_Animation.LastKey", + "d_Animation.NextKey", "d_Animation.Play", "d_Animation.PrevKey", "d_Animation.Record", + "d_Animation.SequencerLink", "d_animationanimated", "d_animationkeyframe", "d_animationnocurve", + "d_animationvisibilitytoggleoff", "d_animationvisibilitytoggleon", "d_AnimationWrapModeMenu", + "d_AS Badge Delete", "d_AS Badge New", "d_AssemblyLock", "d_Asset Store", "d_Audio Mixer", + "d_AvatarBlendBackground", "d_AvatarBlendLeft", "d_AvatarBlendLeftA", "d_AvatarBlendRight", + "d_AvatarBlendRightA", "d_AvatarCompass", "d_AvatarPivot", "d_back", "d_back@2x", "d_beginButton-On", + "d_beginButton", "d_blueGroove", "d_BuildSettings.Android", "d_BuildSettings.Android.Small", + "d_BuildSettings.Broadcom", "d_BuildSettings.FlashPlayer", "d_BuildSettings.FlashPlayer.Small", + "d_BuildSettings.iPhone", "d_BuildSettings.iPhone.Small", "d_BuildSettings.Lumin", + "d_BuildSettings.Lumin.small", "d_BuildSettings.PS4", "d_BuildSettings.PS4.Small", "d_BuildSettings.PSP2", + "d_BuildSettings.PSP2.Small", "d_BuildSettings.SelectedIcon", "d_BuildSettings.Standalone", + "d_BuildSettings.Standalone.Small", "d_BuildSettings.tvOS", "d_BuildSettings.tvOS.Small", + "d_BuildSettings.Web", "d_BuildSettings.Web.Small", "d_BuildSettings.WebGL", "d_BuildSettings.WebGL.Small", + "d_BuildSettings.Xbox360", "d_BuildSettings.Xbox360.Small", "d_BuildSettings.XboxOne", + "d_BuildSettings.XboxOne.Small", "d_CheckerFloor", "d_CloudConnect", "d_Collab.FileAdded", + "d_Collab.FileConflict", "d_Collab.FileDeleted", "d_Collab.FileIgnored", "d_Collab.FileMoved", + "d_Collab.FileUpdated", "d_Collab.FolderAdded", "d_Collab.FolderConflict", "d_Collab.FolderDeleted", + "d_Collab.FolderIgnored", "d_Collab.FolderMoved", "d_Collab.FolderUpdated", "d_ColorPicker.CycleColor", + "d_ColorPicker.CycleSlider", "d_console.erroricon", "d_console.erroricon.sml", "d_console.infoicon", + "d_console.infoicon.sml", "d_console.warnicon", "d_console.warnicon.sml", "d_curvekeyframe", + "d_curvekeyframeselected", "d_curvekeyframeselectedoverlay", "d_curvekeyframesemiselectedoverlay", + "d_curvekeyframeweighted", "d_CustomSorting", "d_DefaultSorting", "d_EditCollider", "d_editcollision_16", + "d_editconstraints_16", "d_editicon.sml", "d_endButton-On", "d_endButton", "d_eyeDropper.Large", + "d_eyeDropper.sml", "d_Favorite", "d_FilterByLabel", "d_FilterByType", "d_FilterSelectedOnly", + "d_FilterSelectedOnly@2x", "d_forward", "d_forward@2x", "d_GEAR", "d_Groove", "d_HorizontalSplit", + "d_icon dropdown", "d_InspectorLock", "d_JointAngularLimits", "d_leftBracket", "d_Lighting", + "d_LightmapEditor.WindowTitle", "d_LookDevCenterLight", "d_LookDevCenterLight@2x", "d_LookDevClose", + "d_LookDevClose@2x", "d_LookDevEnvRotation", "d_LookDevEnvRotation@2x", "d_LookDevMirrorViews", + "d_LookDevMirrorViews@2x", "d_LookDevMirrorViewsActive", "d_LookDevMirrorViewsActive@2x", + "d_LookDevMirrorViewsInactive", "d_LookDevMirrorViewsInactive@2x", "d_LookDevObjRotation", + "d_LookDevObjRotation@2x", "d_LookDevPaneOption", "d_LookDevPaneOption@2x", "d_LookDevResetEnv", + "d_LookDevResetEnv@2x", "d_LookDevShadow", "d_LookDevShadow@2x", "d_LookDevSideBySide", + "d_LookDevSideBySide@2x", "d_LookDevSingle1", "d_LookDevSingle1@2x", "d_LookDevSingle2", + "d_LookDevSingle2@2x", "d_LookDevSplit", "d_LookDevSplit@2x", "d_LookDevZone", "d_LookDevZone@2x", + "d_Mirror", "d_model large", "d_monologo", "d_MoveTool on", "d_MoveTool", "d_Navigation", "d_Occlusion", + "d_P4_AddedLocal", "d_P4_AddedRemote", "d_P4_CheckOutLocal", "d_P4_CheckOutRemote", "d_P4_Conflicted", + "d_P4_DeletedLocal", "d_P4_DeletedRemote", "d_P4_Local", "d_P4_LockedLocal", "d_P4_LockedRemote", + "d_P4_OutOfSync", "d_Particle Effect", "d_PauseButton On", "d_PauseButton", "d_PlayButton On", "d_PlayButton", + "d_PlayButtonProfile On", "d_PlayButtonProfile", "d_playLoopOff", "d_playLoopOn", "d_preAudioAutoPlayOff", + "d_preAudioAutoPlayOn", "d_preAudioLoopOff", "d_preAudioLoopOn", "d_preAudioPlayOff", "d_preAudioPlayOn", + "d_PreMatCube", "d_PreMatCylinder", "d_PreMatLight0", "d_PreMatLight1", "d_PreMatSphere", "d_PreMatTorus", + "d_Preset.Context", "d_PreTextureAlpha", "d_PreTextureMipMapHigh", "d_PreTextureMipMapLow", "d_PreTextureRGB", + "d_Profiler.Audio", "d_Profiler.CPU", "d_Profiler.FirstFrame", "d_Profiler.GPU", "d_Profiler.LastFrame", + "d_Profiler.Memory", "d_Profiler.Network", "d_Profiler.NextFrame", "d_Profiler.Physics", "d_Profiler.PrevFrame", + "d_Profiler.Record", "d_Profiler.Rendering", "d_Profiler.Video", "d_ProfilerColumn.WarningCount", "d_Project", + "d_RectTool On", "d_RectTool", "d_RectTransformBlueprint", "d_RectTransformRaw", "d_redGroove", "d_Refresh", + "d_renderdoc", "d_rightBracket", "d_RotateTool On", "d_RotateTool", "d_ScaleTool On", "d_ScaleTool", + "d_SceneViewAlpha", "d_SceneViewAudio", "d_SceneViewFx", "d_SceneViewLighting", "d_SceneViewOrtho", + "d_SceneViewRGB", "d_ScrollShadow", "d_Settings", "d_SettingsIcon", "d_SocialNetworks.FacebookShare", + "d_SocialNetworks.LinkedInShare", "d_SocialNetworks.Tweet", "d_SocialNetworks.UDNOpen", "d_SpeedScale", + "d_StepButton On", "d_StepButton", "d_StepLeftButton-On", "d_StepLeftButton", "d_SVN_AddedLocal", + "d_SVN_Conflicted", "d_SVN_DeletedLocal", "d_SVN_Local", "d_SVN_LockedLocal", "d_SVN_OutOfSync", "d_tab_next", + "d_tab_next@2x", "d_tab_prev", "d_tab_prev@2x", "d_TerrainInspector.TerrainToolLower On", + "d_TerrainInspector.TerrainToolLowerAlt", "d_TerrainInspector.TerrainToolPlants On", + "d_TerrainInspector.TerrainToolPlants", "d_TerrainInspector.TerrainToolPlantsAlt On", + "d_TerrainInspector.TerrainToolPlantsAlt", "d_TerrainInspector.TerrainToolRaise On", + "d_TerrainInspector.TerrainToolRaise", "d_TerrainInspector.TerrainToolSetheight On", + "d_TerrainInspector.TerrainToolSetheight", "d_TerrainInspector.TerrainToolSetheightAlt On", + "d_TerrainInspector.TerrainToolSetheightAlt", "d_TerrainInspector.TerrainToolSettings On", + "d_TerrainInspector.TerrainToolSettings", "d_TerrainInspector.TerrainToolSmoothHeight On", + "d_TerrainInspector.TerrainToolSmoothHeight", "d_TerrainInspector.TerrainToolSplat On", + "d_TerrainInspector.TerrainToolSplat", "d_TerrainInspector.TerrainToolSplatAlt On", + "d_TerrainInspector.TerrainToolSplatAlt", "d_TerrainInspector.TerrainToolTrees On", + "d_TerrainInspector.TerrainToolTrees", "d_TerrainInspector.TerrainToolTreesAlt On", + "d_TerrainInspector.TerrainToolTreesAlt", "d_TimelineDigIn", "d_TimelineEditModeMixOFF", + "d_TimelineEditModeMixON", "d_TimelineEditModeReplaceOFF", "d_TimelineEditModeReplaceON", + "d_TimelineEditModeRippleOFF", "d_TimelineEditModeRippleON", "d_TimelineSelector", "d_Toolbar Minus", + "d_Toolbar Plus More", "d_Toolbar Plus", "d_ToolHandleCenter", "d_ToolHandleGlobal", "d_ToolHandleLocal", + "d_ToolHandlePivot", "d_tranp", "d_TransformTool On", "d_TransformTool", "d_tree_icon", "d_tree_icon_branch", + "d_tree_icon_branch_frond", "d_tree_icon_frond", "d_tree_icon_leaf", "d_TreeEditor.AddBranches", + "d_TreeEditor.AddLeaves", "d_TreeEditor.Branch On", "d_TreeEditor.Branch", "d_TreeEditor.BranchFreeHand On", + "d_TreeEditor.BranchFreeHand", "d_TreeEditor.BranchRotate On", "d_TreeEditor.BranchRotate", + "d_TreeEditor.BranchScale On", "d_TreeEditor.BranchScale", "d_TreeEditor.BranchTranslate On", + "d_TreeEditor.BranchTranslate", "d_TreeEditor.Distribution On", "d_TreeEditor.Distribution", + "d_TreeEditor.Duplicate", "d_TreeEditor.Geometry On", "d_TreeEditor.Geometry", "d_TreeEditor.Leaf On", + "d_TreeEditor.Leaf", "d_TreeEditor.LeafFreeHand On", "d_TreeEditor.LeafFreeHand", "d_TreeEditor.LeafRotate On", + "d_TreeEditor.LeafRotate", "d_TreeEditor.LeafScale On", "d_TreeEditor.LeafScale", + "d_TreeEditor.LeafTranslate On", "d_TreeEditor.LeafTranslate", "d_TreeEditor.Material On", + "d_TreeEditor.Material", "d_TreeEditor.Refresh", "d_TreeEditor.Trash", "d_TreeEditor.Wind On", + "d_TreeEditor.Wind", "d_UnityEditor.AnimationWindow", "d_UnityEditor.ConsoleWindow", + "d_UnityEditor.DebugInspectorWindow", "d_UnityEditor.FindDependencies", "d_UnityEditor.GameView", + "d_UnityEditor.HierarchyWindow", "d_UnityEditor.InspectorWindow", "d_UnityEditor.LookDevView", + "d_UnityEditor.ProfilerWindow", "d_UnityEditor.SceneHierarchyWindow", "d_UnityEditor.SceneView", + "d_UnityEditor.Timeline.TimelineWindow", "d_UnityEditor.VersionControl", "d_UnityLogo", "d_VerticalSplit", + "d_ViewToolMove On", "d_ViewToolMove", "d_ViewToolOrbit On", "d_ViewToolOrbit", "d_ViewToolZoom On", + "d_ViewToolZoom", "d_VisibilityOff", "d_VisibilityOn", "d_VUMeterTextureHorizontal", "d_VUMeterTextureVertical", + "d_WaitSpin00", "d_WaitSpin01", "d_WaitSpin02", "d_WaitSpin03", "d_WaitSpin04", "d_WaitSpin05", "d_WaitSpin06", + "d_WaitSpin07", "d_WaitSpin08", "d_WaitSpin09", "d_WaitSpin10", "d_WaitSpin11", "d_WelcomeScreen.AssetStoreLogo", + "d_winbtn_graph", "d_winbtn_graph_close_h", "d_winbtn_graph_max_h", "d_winbtn_graph_min_h", + "d_winbtn_mac_close", "d_winbtn_mac_close_a", "d_winbtn_mac_close_h", "d_winbtn_mac_inact", "d_winbtn_mac_max", + "d_winbtn_mac_max_a", "d_winbtn_mac_max_h", "d_winbtn_mac_min", "d_winbtn_mac_min_a", "d_winbtn_mac_min_h", + "d_winbtn_win_close", "d_winbtn_win_close_a", "d_winbtn_win_close_h", "d_winbtn_win_max", "d_winbtn_win_max_a", + "d_winbtn_win_max_h", "d_winbtn_win_min", "d_winbtn_win_min_a", "d_winbtn_win_min_h", "d_winbtn_win_rest", + "d_winbtn_win_rest_a", "d_winbtn_win_rest_h", "DefaultSorting", "EditCollider", "editcollision_16", + "editconstraints_16", "editicon.sml", "endButton-On", "endButton", "eyeDropper.Large", "eyeDropper.sml", + "Favorite", "FilterByLabel", "FilterByType", "FilterSelectedOnly", "FilterSelectedOnly@2x", "forward", + "forward@2x", "GEAR", "Grid.BoxTool", "Grid.Default", "Grid.EraserTool", "Grid.FillTool", "Grid.MoveTool", + "Grid.PaintTool", "Grid.PickingTool", "Grid.SelectTool", "Groove", "align_horizontally", + "align_horizontally_center", "align_horizontally_center_active", "align_horizontally_left", + "align_horizontally_left_active", "align_horizontally_right", "align_horizontally_right_active", + "align_vertically", "align_vertically_bottom", "align_vertically_bottom_active", "align_vertically_center", + "align_vertically_center_active", "align_vertically_top", "align_vertically_top_active", + "d_align_horizontally", "d_align_horizontally_center", "d_align_horizontally_center_active", + "d_align_horizontally_left", "d_align_horizontally_left_active", "d_align_horizontally_right", + "d_align_horizontally_right_active", "d_align_vertically", "d_align_vertically_bottom", + "d_align_vertically_bottom_active", "d_align_vertically_center", "d_align_vertically_center_active", + "d_align_vertically_top", "d_align_vertically_top_active", "HorizontalSplit", "icon dropdown", + "InspectorLock", "JointAngularLimits", "KnobCShape", "KnobCShapeMini", "leftBracket", "Lighting", + "LightmapEditor.WindowTitle", "Lightmapping", "d_greenLight", "d_lightOff", "d_lightRim", "d_orangeLight", + "d_redLight", "greenLight", "lightOff", "lightRim", "orangeLight", "redLight", "LockIcon-On", "LockIcon", + "LookDevCenterLight", "LookDevCenterLightl@2x", "LookDevClose", "LookDevClose@2x", "LookDevEnvRotation", + "LookDevEnvRotation@2x", "LookDevEyedrop", "LookDevLight", "LookDevLight@2x", "LookDevMirrorViewsActive", + "LookDevMirrorViewsActive@2x", "LookDevMirrorViewsInactive", "LookDevMirrorViewsInactive@2x", + "LookDevObjRotation", "LookDevObjRotation@2x", "LookDevPaneOption", "LookDevPaneOption@2x", "LookDevResetEnv", + "LookDevResetEnv@2x", "LookDevShadow", "LookDevShadow@2x", "LookDevShadowFrame", "LookDevShadowFrame@2x", + "LookDevSideBySide", "LookDevSideBySide@2x", "LookDevSingle1", "LookDevSingle1@2x", "LookDevSingle2", + "LookDevSingle2@2x", "LookDevSplit", "LookDevSplit@2x", "LookDevZone", "LookDevZone@2x", "loop", "Mirror", + "monologo", "MoveTool on", "MoveTool", "Navigation", "Occlusion", "P4_AddedLocal", "P4_AddedRemote", + "P4_BlueLeftParenthesis", "P4_BlueRightParenthesis", "P4_CheckOutLocal", "P4_CheckOutRemote", "P4_Conflicted", + "P4_DeletedLocal", "P4_DeletedRemote", "P4_Local", "P4_LockedLocal", "P4_LockedRemote", "P4_OutOfSync", + "P4_RedLeftParenthesis", "P4_RedRightParenthesis", "P4_Updating", "PackageBadgeDelete", "PackageBadgeNew", + "Particle Effect", "PauseButton On", "PauseButton", "PlayButton On", "PlayButton", "PlayButtonProfile On", + "PlayButtonProfile", "playLoopOff", "playLoopOn", "playSpeed", "preAudioAutoPlayOff", "preAudioAutoPlayOn", + "preAudioLoopOff", "preAudioLoopOn", "preAudioPlayOff", "preAudioPlayOn", "PreMatCube", "PreMatCylinder", + "PreMatLight0", "PreMatLight1", "PreMatQuad", "PreMatSphere", "PreMatTorus", "Preset.Context", "PreTextureAlpha", + "PreTextureArrayFirstSlice", "PreTextureArrayLastSlice", "PreTextureMipMapHigh", "PreTextureMipMapLow", + "PreTextureRGB", "AreaLight Gizmo", "AreaLight Icon", "Assembly Icon", "AssetStore Icon", "AudioMixerView Icon", + "AudioSource Gizmo", "Camera Gizmo", "CGProgram Icon", "ChorusFilter Icon", "CollabChanges Icon", + "CollabChangesConflict Icon", "CollabChangesDeleted Icon", "CollabConflict Icon", "CollabCreate Icon", + "CollabDeleted Icon", "CollabEdit Icon", "CollabExclude Icon", "CollabMoved Icon", "cs Script Icon", + "d_AudioMixerView Icon", "d_CollabChanges Icon", "d_CollabChangesConflict Icon", "d_CollabChangesDeleted Icon", + "d_CollabConflict Icon", "d_CollabCreate Icon", "d_CollabDeleted Icon", "d_CollabEdit Icon", + "d_CollabExclude Icon", "d_CollabMoved Icon", "d_GridLayoutGroup Icon", "d_HorizontalLayoutGroup Icon", + "d_Prefab Icon", "d_PrefabModel Icon", "d_PrefabVariant Icon", "d_VerticalLayoutGroup Icon", + "DefaultSlate Icon", "DirectionalLight Gizmo", "DirectionalLight Icon", "DiscLight Gizmo", "DiscLight Icon", + "dll Script Icon", "EchoFilter Icon", "Favorite Icon", "Folder Icon", "FolderEmpty Icon", + "FolderFavorite Icon", "GameManager Icon", "GridBrush Icon", "HighPassFilter Icon", + "HorizontalLayoutGroup Icon", "LensFlare Gizmo", "LightingDataAssetParent Icon", "LightProbeGroup Gizmo", + "LightProbeProxyVolume Gizmo", "LowPassFilter Icon", "Main Light Gizmo", "MetaFile Icon", + "Microphone Icon", "MuscleClip Icon", "ParticleSystem Gizmo", "PointLight Gizmo", "Prefab Icon", + "PrefabModel Icon", "PrefabOverlayAdded Icon", "PrefabOverlayModified Icon", "PrefabOverlayRemoved Icon", + "PrefabVariant Icon", "Projector Gizmo", "RaycastCollider Icon", "ReflectionProbe Gizmo", + "ReverbFilter Icon", "SceneSet Icon", "Search Icon", "SoftlockProjectBrowser Icon", "SpeedTreeModel Icon", + "SpotLight Gizmo", "Spotlight Icon", "SpriteCollider Icon", "sv_icon_dot0_pix16_gizmo", + "sv_icon_dot10_pix16_gizmo", "sv_icon_dot11_pix16_gizmo", "sv_icon_dot12_pix16_gizmo", + "sv_icon_dot13_pix16_gizmo", "sv_icon_dot14_pix16_gizmo", "sv_icon_dot15_pix16_gizmo", + "sv_icon_dot1_pix16_gizmo", "sv_icon_dot2_pix16_gizmo", "sv_icon_dot3_pix16_gizmo", + "sv_icon_dot4_pix16_gizmo", "sv_icon_dot5_pix16_gizmo", "sv_icon_dot6_pix16_gizmo", + "sv_icon_dot7_pix16_gizmo", "sv_icon_dot8_pix16_gizmo", "sv_icon_dot9_pix16_gizmo", + "AnimatorController Icon", "AnimatorState Icon", "AnimatorStateMachine Icon", + "AnimatorStateTransition Icon", "BlendTree Icon", "AnimationWindowEvent Icon", "AudioMixerController Icon", + "DefaultAsset Icon", "EditorSettings Icon", "AnyStateNode Icon", "HumanTemplate Icon", + "LightingDataAsset Icon", "LightmapParameters Icon", "Preset Icon", "SceneAsset Icon", + "SubstanceArchive Icon", "AssemblyDefinitionAsset Icon", "NavMeshAgent Icon", "NavMeshData Icon", + "NavMeshObstacle Icon", "OffMeshLink Icon", "AnalyticsTracker Icon", "Animation Icon", + "AnimationClip Icon", "AimConstraint Icon", "d_AimConstraint Icon", "d_LookAtConstraint Icon", + "d_ParentConstraint Icon", "d_PositionConstraint Icon", "d_RotationConstraint Icon", + "d_ScaleConstraint Icon", "LookAtConstraint Icon", "ParentConstraint Icon", "PositionConstraint Icon", + "RotationConstraint Icon", "ScaleConstraint Icon", "Animator Icon", "AnimatorOverrideController Icon", + "AreaEffector2D Icon", "AudioMixerGroup Icon", "AudioMixerSnapshot Icon", "AudioSpatializerMicrosoft Icon", + "AudioChorusFilter Icon", "AudioClip Icon", "AudioDistortionFilter Icon", "AudioEchoFilter Icon", + "AudioHighPassFilter Icon", "AudioListener Icon", "AudioLowPassFilter Icon", "AudioReverbFilter Icon", + "AudioReverbZone Icon", "AudioSource Icon", "Avatar Icon", "AvatarMask Icon", "BillboardAsset Icon", + "BillboardRenderer Icon", "BoxCollider Icon", "BoxCollider2D Icon", "BuoyancyEffector2D Icon", "Camera Icon", + "Canvas Icon", "CanvasGroup Icon", "CanvasRenderer Icon", "CapsuleCollider Icon", "CapsuleCollider2D Icon", + "CharacterController Icon", "CharacterJoint Icon", "CircleCollider2D Icon", "Cloth Icon", + "CompositeCollider2D Icon", "ComputeShader Icon", "ConfigurableJoint Icon", "ConstantForce Icon", + "ConstantForce2D Icon", "Cubemap Icon", "d_Canvas Icon", "d_CanvasGroup Icon", "d_CanvasRenderer Icon", + "d_GameObject Icon", "d_LightProbeProxyVolume Icon", "d_ParticleSystem Icon", "d_ParticleSystemForceField Icon", + "d_RectTransform Icon", "d_StreamingController Icon", "DistanceJoint2D Icon", "EdgeCollider2D Icon", + "d_EventSystem Icon", "d_EventTrigger Icon", "d_Physics2DRaycaster Icon", "d_PhysicsRaycaster Icon", + "d_StandaloneInputModule Icon", "d_TouchInputModule Icon", "EventSystem Icon", "EventTrigger Icon", + "HoloLensInputModule Icon", "Physics2DRaycaster Icon", "PhysicsRaycaster Icon", "StandaloneInputModule Icon", + "TouchInputModule Icon", "SpriteShapeRenderer Icon", "VisualTreeAsset Icon", "d_VisualEffect Icon", + "d_VisualEffectAsset Icon", "VisualEffect Icon", "VisualEffectAsset Icon", "FixedJoint Icon", + "FixedJoint2D Icon", "Flare Icon", "FlareLayer Icon", "Font Icon", "FrictionJoint2D Icon", + "GameObject Icon", "Grid Icon", "GUILayer Icon", "GUISkin Icon", "GUIText Icon", "GUITexture Icon", + "Halo Icon", "HingeJoint Icon", "HingeJoint2D Icon", "LensFlare Icon", "Light Icon", "LightProbeGroup Icon", + "LightProbeProxyVolume Icon", "LightProbes Icon", "LineRenderer Icon", "LODGroup Icon", "Material Icon", + "Mesh Icon", "MeshCollider Icon", "MeshFilter Icon", "MeshRenderer Icon", "Motion Icon", "MovieTexture Icon", + "NetworkAnimator Icon", "NetworkDiscovery Icon", "NetworkIdentity Icon", "NetworkLobbyManager Icon", + "NetworkLobbyPlayer Icon", "NetworkManager Icon", "NetworkManagerHUD Icon", "NetworkMigrationManager Icon", + "NetworkProximityChecker Icon", "NetworkStartPosition Icon", "NetworkTransform Icon", + "NetworkTransformChild Icon", "NetworkTransformVisualizer Icon", "NetworkView Icon", "OcclusionArea Icon", + "OcclusionPortal Icon", "ParticleSystem Icon", "ParticleSystemForceField Icon", "PhysicMaterial Icon", + "PhysicsMaterial2D Icon", "PlatformEffector2D Icon", "d_PlayableDirector Icon", "PlayableDirector Icon", + "PointEffector2D Icon", "PolygonCollider2D Icon", "ProceduralMaterial Icon", "Projector Icon", + "RectTransform Icon", "ReflectionProbe Icon", "RelativeJoint2D Icon", "d_SortingGroup Icon", + "SortingGroup Icon", "RenderTexture Icon", "Rigidbody Icon", "Rigidbody2D Icon", "ScriptableObject Icon", + "Shader Icon", "ShaderVariantCollection Icon", "SkinnedMeshRenderer Icon", "Skybox Icon", "SliderJoint2D Icon", + "TrackedPoseDriver Icon", "SphereCollider Icon", "SpringJoint Icon", "SpringJoint2D Icon", "Sprite Icon", + "SpriteMask Icon", "SpriteRenderer Icon", "StreamingController Icon", "StyleSheet Icon", "SurfaceEffector2D Icon", + "TargetJoint2D Icon", "Terrain Icon", "TerrainCollider Icon", "TerrainData Icon", "TextAsset Icon", + "TextMesh Icon", "Texture Icon", "Texture2D Icon", "Tile Icon", "Tilemap Icon", "TilemapCollider2D Icon", + "TilemapRenderer Icon", "d_TimelineAsset Icon", "TimelineAsset Icon", "TrailRenderer Icon", "Transform Icon", + "SpriteAtlas Icon", "AspectRatioFitter Icon", "Button Icon", "CanvasScaler Icon", "ContentSizeFitter Icon", + "d_AspectRatioFitter Icon", "d_CanvasScaler Icon", "d_ContentSizeFitter Icon", "d_FreeformLayoutGroup Icon", + "d_GraphicRaycaster Icon", "d_GridLayoutGroup Icon", "d_HorizontalLayoutGroup Icon", "d_LayoutElement Icon", + "d_PhysicalResolution Icon", "d_ScrollViewArea Icon", "d_SelectionList Icon", "d_SelectionListItem Icon", + "d_SelectionListTemplate Icon", "d_VerticalLayoutGroup Icon", "Dropdown Icon", "FreeformLayoutGroup Icon", + "GraphicRaycaster Icon", "GridLayoutGroup Icon", "HorizontalLayoutGroup Icon", "Image Icon", "InputField Icon", + "LayoutElement Icon", "Mask Icon", "Outline Icon", "PositionAsUV1 Icon", "RawImage Icon", "RectMask2D Icon", + "Scrollbar Icon", "ScrollRect Icon", "Selectable Icon", "Shadow Icon", "Slider Icon", "Text Icon", "Toggle Icon", + "ToggleGroup Icon", "VerticalLayoutGroup Icon", "VideoClip Icon", "VideoPlayer Icon", "VisualEffect Icon", + "VisualEffectAsset Icon", "WheelCollider Icon", "WheelJoint2D Icon", "WindZone Icon", + "SpatialMappingCollider Icon", "SpatialMappingRenderer Icon", "WorldAnchor Icon", "UssScript Icon", + "UxmlScript Icon", "VerticalLayoutGroup Icon", "VideoEffect Icon", "VisualEffect Gizmo", + "VisualEffectAsset Icon", "AnchorBehaviour Icon", "AnchorInputListenerBehaviour Icon", + "AnchorStageBehaviour Icon", "CloudRecoBehaviour Icon", "ContentPlacementBehaviour Icon", + "ContentPositioningBehaviour Icon", "CylinderTargetBehaviour Icon", "d_AnchorBehaviour Icon", + "d_AnchorInputListenerBehaviour Icon", "d_AnchorStageBehaviour Icon", "d_CloudRecoBehaviour Icon", + "d_ContentPlacementBehaviour Icon", "d_ContentPositioningBehaviour Icon", "d_CylinderTargetBehaviour Icon", + "d_ImageTargetBehaviour Icon", "d_MidAirPositionerBehaviour Icon", "d_ModelTargetBehaviour Icon", + "d_MultiTargetBehaviour Icon", "d_ObjectTargetBehaviour Icon", "d_PlaneFinderBehaviour Icon", + "d_UserDefinedTargetBuildingBehaviour Icon", "d_VirtualButtonBehaviour Icon", "d_VuforiaBehaviour Icon", + "d_VuMarkBehaviour Icon", "d_WireframeBehaviour Icon", "ImageTargetBehaviour Icon", + "MidAirPositionerBehaviour Icon", "ModelTargetBehaviour Icon", "MultiTargetBehaviour Icon", + "ObjectTargetBehaviour Icon", "PlaneFinderBehaviour Icon", "UserDefinedTargetBuildingBehaviour Icon", + "VirtualButtonBehaviour Icon", "VuforiaBehaviour Icon", "VuMarkBehaviour Icon", "WireframeBehaviour Icon", + "WindZone Gizmo", "Profiler.Audio", "Profiler.CPU", "Profiler.FirstFrame", "Profiler.GlobalIllumination", + "Profiler.GPU", "Profiler.Instrumentation", "Profiler.LastFrame", "Profiler.Memory", "Profiler.NetworkMessages", + "Profiler.NetworkOperations", "Profiler.NextFrame", "Profiler.Physics", "Profiler.Physics2D", + "Profiler.PrevFrame", "Profiler.Record", "Profiler.Rendering", "Profiler.UI", "Profiler.UIDetails", + "Profiler.Video", "ProfilerColumn.WarningCount", "Project", "RectTool On", "RectTool", "RectTransformBlueprint", + "RectTransformRaw", "redGroove", "Refresh", "renderdoc", "rightBracket", "RotateTool On", "RotateTool", + "SaveActive", "SaveFromPlay", "SavePassive", "ScaleTool On", "ScaleTool", "SceneLoadIn", "SceneLoadOut", + "SceneSave", "SceneSaveGrey", "SceneViewAlpha", "SceneViewAudio", "SceneViewFx", "SceneViewLighting", + "SceneViewOrtho", "SceneViewRGB", "ScrollShadow", "Settings", "SettingsIcon", "SocialNetworks.FacebookShare", + "SocialNetworks.LinkedInShare", "SocialNetworks.Tweet", "SocialNetworks.UDNLogo", "SocialNetworks.UDNOpen", + "SoftlockInline", "SpeedScale", "StateMachineEditor.ArrowTip", "StateMachineEditor.ArrowTipSelected", + "StateMachineEditor.Background", "StateMachineEditor.State", "StateMachineEditor.StateHover", + "StateMachineEditor.StateSelected", "StateMachineEditor.StateSub", "StateMachineEditor.StateSubHover", + "StateMachineEditor.StateSubSelected", "StateMachineEditor.UpButton", "StateMachineEditor.UpButtonHover", + "StepButton On", "StepButton", "StepLeftButton-On", "StepLeftButton", "sticky_arrow", "sticky_p4", "sticky_skin", + "sv_icon_dot0_sml", "sv_icon_dot10_sml", "sv_icon_dot11_sml", "sv_icon_dot12_sml", "sv_icon_dot13_sml", + "sv_icon_dot14_sml", "sv_icon_dot15_sml", "sv_icon_dot1_sml", "sv_icon_dot2_sml", "sv_icon_dot3_sml", + "sv_icon_dot4_sml", "sv_icon_dot5_sml", "sv_icon_dot6_sml", "sv_icon_dot7_sml", "sv_icon_dot8_sml", + "sv_icon_dot9_sml", "sv_icon_name0", "sv_icon_name1", "sv_icon_name2", "sv_icon_name3", "sv_icon_name4", + "sv_icon_name5", "sv_icon_name6", "sv_icon_name7", "sv_icon_none", "sv_label_0", "sv_label_1", "sv_label_2", + "sv_label_3", "sv_label_4", "sv_label_5", "sv_label_6", "sv_label_7", "SVN_AddedLocal", "SVN_Conflicted", + "SVN_DeletedLocal", "SVN_Local", "SVN_LockedLocal", "SVN_OutOfSync", "tab_next", "tab_next@2x", "tab_prev", + "tab_prev@2x", "TerrainInspector.TerrainToolLower On", "TerrainInspector.TerrainToolLower", + "TerrainInspector.TerrainToolLowerAlt", "TerrainInspector.TerrainToolPlants On", + "TerrainInspector.TerrainToolPlants", "TerrainInspector.TerrainToolPlantsAlt On", + "TerrainInspector.TerrainToolPlantsAlt", "TerrainInspector.TerrainToolRaise On", + "TerrainInspector.TerrainToolRaise", "TerrainInspector.TerrainToolSculpt On", + "TerrainInspector.TerrainToolSculpt", "TerrainInspector.TerrainToolSetheight On", + "TerrainInspector.TerrainToolSetheight", "TerrainInspector.TerrainToolSetheightAlt On", + "TerrainInspector.TerrainToolSetheightAlt", "TerrainInspector.TerrainToolSettings On", + "TerrainInspector.TerrainToolSettings", "TerrainInspector.TerrainToolSmoothHeight On", + "TerrainInspector.TerrainToolSmoothHeight", "TerrainInspector.TerrainToolSplat On", + "TerrainInspector.TerrainToolSplat", "TerrainInspector.TerrainToolSplatAlt On", + "TerrainInspector.TerrainToolSplatAlt", "TerrainInspector.TerrainToolTrees On", + "TerrainInspector.TerrainToolTrees", "TerrainInspector.TerrainToolTreesAlt On", + "TerrainInspector.TerrainToolTreesAlt", "TestFailed", "TestIgnored", "TestInconclusive", "TestNormal", + "TestPassed", "TestStopwatch", "TimelineClipBG", "TimelineClipFG", "TimelineDigIn", "TimelineEditModeMixOFF", + "TimelineEditModeMixON", "TimelineEditModeReplaceOFF", "TimelineEditModeReplaceON", "TimelineEditModeRippleOFF", + "TimelineEditModeRippleON", "TimelineSelector", "Toolbar Minus", "Toolbar Plus More", "Toolbar Plus", + "ToolHandleCenter", "ToolHandleGlobal", "ToolHandleLocal", "ToolHandlePivot", "tranp", "TransformTool On", + "TransformTool", "tree_icon", "tree_icon_branch", "tree_icon_branch_frond", "tree_icon_frond", "tree_icon_leaf", + "TreeEditor.AddBranches", "TreeEditor.AddLeaves", "TreeEditor.Branch On", "TreeEditor.Branch", + "TreeEditor.BranchFreeHand On", "TreeEditor.BranchFreeHand", "TreeEditor.BranchRotate On", + "TreeEditor.BranchRotate", "TreeEditor.BranchScale On", "TreeEditor.BranchScale", + "TreeEditor.BranchTranslate On", "TreeEditor.BranchTranslate", "TreeEditor.Distribution On", + "TreeEditor.Distribution", "TreeEditor.Duplicate", "TreeEditor.Geometry On", "TreeEditor.Geometry", + "TreeEditor.Leaf On", "TreeEditor.Leaf", "TreeEditor.LeafFreeHand On", "TreeEditor.LeafFreeHand", + "TreeEditor.LeafRotate On", "TreeEditor.LeafRotate", "TreeEditor.LeafScale On", "TreeEditor.LeafScale", + "TreeEditor.LeafTranslate On", "TreeEditor.LeafTranslate", "TreeEditor.Material On", "TreeEditor.Material", + "TreeEditor.Refresh", "TreeEditor.Trash", "TreeEditor.Wind On", "TreeEditor.Wind", "UnityEditor.AnimationWindow", + "UnityEditor.ConsoleWindow", "UnityEditor.DebugInspectorWindow", "UnityEditor.FindDependencies", + "UnityEditor.GameView", "UnityEditor.Graphs.AnimatorControllerTool", "UnityEditor.HierarchyWindow", + "UnityEditor.InspectorWindow", "UnityEditor.LookDevView", "UnityEditor.ProfilerWindow", + "UnityEditor.SceneHierarchyWindow", "UnityEditor.SceneView", "UnityEditor.Timeline.TimelineWindow", + "UnityEditor.VersionControl", "UnityLogo", "UnityLogoLarge", "UpArrow", "vcs_add", "vcs_branch", "vcs_change", + "vcs_check", "vcs_delete", "vcs_document", "vcs_edit", "vcs_incoming", "vcs_integrate", "vcs_local", "vcs_lock", + "vcs_refresh", "vcs_sync", "vcs_unresolved", "vcs_update", "VerticalSplit", "ViewToolMove On", "ViewToolMove", + "ViewToolOrbit On", "ViewToolOrbit", "ViewToolZoom On", "ViewToolZoom", "VisibilityOff", "VisibilityOn", + "VisualEffect Gizmo", "VUMeterTextureHorizontal", "VUMeterTextureVertical", "WaitSpin00", "WaitSpin01", + "WaitSpin02", "WaitSpin03", "WaitSpin04", "WaitSpin05", "WaitSpin06", "WaitSpin07", "WaitSpin08", "WaitSpin09", + "WaitSpin10", "WaitSpin11", "WelcomeScreen.AssetStoreLogo", "winbtn_graph", "winbtn_graph_close_h", + "winbtn_graph_max_h", "winbtn_graph_min_h", "winbtn_mac_close", "winbtn_mac_close_a", "winbtn_mac_close_h", + "winbtn_mac_inact", "winbtn_mac_max", "winbtn_mac_max_a", "winbtn_mac_max_h", "winbtn_mac_min", + "winbtn_mac_min_a", "winbtn_mac_min_h", "winbtn_win_close", "winbtn_win_close_a", "winbtn_win_close_h", + "winbtn_win_max", "winbtn_win_max_a", "winbtn_win_max_h", "winbtn_win_min", "winbtn_win_min_a", + "winbtn_win_min_h", "winbtn_win_rest", "winbtn_win_rest_a", "winbtn_win_rest_h", + "AvatarInspector/RightFingersIk", "AvatarInspector/LeftFingersIk", "AvatarInspector/RightFeetIk", + "AvatarInspector/LeftFeetIk", "AvatarInspector/RightFingers", "AvatarInspector/LeftFingers", + "AvatarInspector/RightArm", "AvatarInspector/LeftArm", "AvatarInspector/RightLeg", "AvatarInspector/LeftLeg", + "AvatarInspector/Head", "AvatarInspector/Torso", "AvatarInspector/MaskEditor_Root", + "AvatarInspector/BodyPartPicker", "AvatarInspector/BodySIlhouette", "boo Script Icon", "js Script Icon", + "EyeDropper.Large", "AboutWindow.MainHeader", "AgeiaLogo", "MonoLogo", "PlayButtonProfile Anim", + "StepButton Anim", "PauseButton Anim", "PlayButton Anim", "MoveTool On", "Icon Dropdown", + "AvatarInspector/DotSelection", "AvatarInspector/DotFrameDotted", "AvatarInspector/DotFrame", + "AvatarInspector/DotFill", "AvatarInspector/RightHandZoom", "AvatarInspector/LeftHandZoom", + "AvatarInspector/HeadZoom", "AvatarInspector/RightLeg", "AvatarInspector/LeftLeg", + "AvatarInspector/RightFingers", "AvatarInspector/RightArm", "AvatarInspector/LeftFingers", + "AvatarInspector/LeftArm", "AvatarInspector/Head", "AvatarInspector/Torso", + "AvatarInspector/RightHandZoomSilhouette", "AvatarInspector/LeftHandZoomSilhouette", + "AvatarInspector/HeadZoomSilhouette", "AvatarInspector/BodySilhouette", "lightMeter/redLight", + "lightMeter/orangeLight", "lightMeter/lightRim", "lightMeter/greenLight", "SceneviewAudio", + "SceneviewLighting", "TerrainInspector.TerrainToolSetHeight", "AS Badge New", "AS Badge Move", + "AS Badge Delete", "WelcomeScreen.UnityAnswersLogo", "WelcomeScreen.UnityForumLogo", + "WelcomeScreen.UnityBasicsLogo", "WelcomeScreen.VideoTutLogo", "WelcomeScreen.MainHeader", "Icon Dropdown", + "PrefabNormal Icon", "PrefabNormal Icon", "BuildSettings.BlackBerry.Small", "BuildSettings.Tizen.Small", + "BuildSettings.XBox360.Small", "BuildSettings.PS3.Small", "BuildSettings.SamsungTV.Small", + "BuildSettings.BlackBerry", "BuildSettings.Tizen", "BuildSettings.XBox360", "BuildSettings.PS3", "BuildSettings.SamsungTV" }; #endregion } -#endif \ No newline at end of file +#endif diff --git a/Editor/ToolBar.meta b/Editor/ToolBar.meta index 728d15b..ab63f9b 100644 --- a/Editor/ToolBar.meta +++ b/Editor/ToolBar.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 93fb9d2834752b649891dba19cba5169 +guid: fb7e9c820d4ba2b4d836ffc849b55067 folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/Editor/ToolBarExtension.meta b/Editor/ToolBarExtension.meta new file mode 100644 index 0000000..728d15b --- /dev/null +++ b/Editor/ToolBarExtension.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 93fb9d2834752b649891dba19cba5169 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/ToolBar/BuildSettingWindow.cs b/Editor/ToolBarExtension/BuildSettingWindow.cs similarity index 100% rename from Editor/ToolBar/BuildSettingWindow.cs rename to Editor/ToolBarExtension/BuildSettingWindow.cs diff --git a/Editor/ToolBar/BuildSettingWindow.cs.meta b/Editor/ToolBarExtension/BuildSettingWindow.cs.meta similarity index 100% rename from Editor/ToolBar/BuildSettingWindow.cs.meta rename to Editor/ToolBarExtension/BuildSettingWindow.cs.meta diff --git a/Editor/ToolBar/EditorQuickToolBar.cs b/Editor/ToolBarExtension/EditorQuickToolBar.cs similarity index 100% rename from Editor/ToolBar/EditorQuickToolBar.cs rename to Editor/ToolBarExtension/EditorQuickToolBar.cs diff --git a/Editor/ToolBar/EditorQuickToolBar.cs.meta b/Editor/ToolBarExtension/EditorQuickToolBar.cs.meta similarity index 100% rename from Editor/ToolBar/EditorQuickToolBar.cs.meta rename to Editor/ToolBarExtension/EditorQuickToolBar.cs.meta diff --git a/Editor/ToolBarExtension/LocalizationDropdownField.cs b/Editor/ToolBarExtension/LocalizationDropdownField.cs new file mode 100644 index 0000000..f2c6550 --- /dev/null +++ b/Editor/ToolBarExtension/LocalizationDropdownField.cs @@ -0,0 +1,69 @@ +using System; +using AlicizaX.Localization.Runtime; +using AlicizaX; +using Paps.UnityToolbarExtenderUIToolkit; +using UnityEditor; +using UnityEngine; +using UnityEngine.UIElements; + +[MainToolbarElement("LocalizationDropdownField", alignment: ToolbarAlign.Right, order: 0)] +public class LocalizationDropdownField : IMGUIContainer +{ + private static GUIContent appConfigBtContent; + + private static string[] _languageTypeNames; + + public void InitializeElement() + { + var nameArray = Enum.GetNames(typeof(Language)); + _languageTypeNames = new string[nameArray.Length - 1]; + for (int i = 1; i < nameArray.Length; i++) + { + var name = nameArray[i]; + _languageTypeNames[i - 1] = name; + } + + appConfigBtContent = + EditorGUIUtility.TrTextContentWithIcon("", "", + "Settings"); + onGUIHandler = MyGUIMethod; + } + + private void MyGUIMethod() + { + GUILayout.BeginHorizontal(); + string title = _languageTypeNames[GetPrefsIndex()]; + appConfigBtContent.text = title; + if (EditorGUILayout.DropdownButton(appConfigBtContent, FocusType.Passive, EditorStyles.toolbarPopup, GUILayout.MaxWidth(120))) + { + DrawEditorToolDropdownMenus(); + } + + GUILayout.Space(5); + GUILayout.EndHorizontal(); + } + + static void DrawEditorToolDropdownMenus() + { + int index = GetPrefsIndex(); + GenericMenu popMenu = new GenericMenu(); + for (int i = 0; i < _languageTypeNames.Length; i++) + { + var selected = index == i; + var toolAttr = _languageTypeNames[i]; + popMenu.AddItem(new GUIContent(toolAttr), selected, menuIdx => { ClickToolsSubmenu((int)menuIdx); }, i); + } + + popMenu.ShowAsContext(); + } + + static void ClickToolsSubmenu(int menuIdx) + { + EditorPrefs.SetInt(LocalizationComponent.PrefsKey, menuIdx + 1); + } + + static int GetPrefsIndex() + { + return EditorPrefs.GetInt(LocalizationComponent.PrefsKey, 1) - 1; + } +} diff --git a/Editor/ToolBarExtension/LocalizationDropdownField.cs.meta b/Editor/ToolBarExtension/LocalizationDropdownField.cs.meta new file mode 100644 index 0000000..84b1b0b --- /dev/null +++ b/Editor/ToolBarExtension/LocalizationDropdownField.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 2295b86f78274a84a63dc65ab4a69cb1 +timeCreated: 1742364662 \ No newline at end of file diff --git a/Editor/ToolBar/ResourceModeDropdownField.cs b/Editor/ToolBarExtension/ResourceModeDropdownField.cs similarity index 91% rename from Editor/ToolBar/ResourceModeDropdownField.cs rename to Editor/ToolBarExtension/ResourceModeDropdownField.cs index 3324846..313dd81 100644 --- a/Editor/ToolBar/ResourceModeDropdownField.cs +++ b/Editor/ToolBarExtension/ResourceModeDropdownField.cs @@ -23,9 +23,7 @@ namespace AlicizaX.Editor.Extension public void InitializeElement() { - appConfigBtContent = - EditorGUIUtility.TrTextContentWithIcon("Res:", "配置App运行时所需DataTable/Config/Procedure", - "Settings"); + appConfigBtContent = EditorGUIUtility.TrTextContentWithIcon("Res:", "配置App运行时资源模式", "Settings"); onGUIHandler = MyGUIMethod; } diff --git a/Editor/ToolBar/ResourceModeDropdownField.cs.meta b/Editor/ToolBarExtension/ResourceModeDropdownField.cs.meta similarity index 100% rename from Editor/ToolBar/ResourceModeDropdownField.cs.meta rename to Editor/ToolBarExtension/ResourceModeDropdownField.cs.meta diff --git a/Editor/ToolBar/SwitchSceneToolBar.cs b/Editor/ToolBarExtension/SwitchSceneToolBar.cs similarity index 100% rename from Editor/ToolBar/SwitchSceneToolBar.cs rename to Editor/ToolBarExtension/SwitchSceneToolBar.cs diff --git a/Editor/ToolBar/SwitchSceneToolBar.cs.meta b/Editor/ToolBarExtension/SwitchSceneToolBar.cs.meta similarity index 100% rename from Editor/ToolBar/SwitchSceneToolBar.cs.meta rename to Editor/ToolBarExtension/SwitchSceneToolBar.cs.meta diff --git a/Editor/Toolbar/ByAttributeMainToolbarElementRepository.cs b/Editor/Toolbar/ByAttributeMainToolbarElementRepository.cs new file mode 100644 index 0000000..a87db80 --- /dev/null +++ b/Editor/Toolbar/ByAttributeMainToolbarElementRepository.cs @@ -0,0 +1,40 @@ +using System; +using System.Linq; +using System.Reflection; +using UnityEditor; +using UnityEngine.UIElements; + +namespace Paps.UnityToolbarExtenderUIToolkit +{ + internal class ByAttributeMainToolbarElementRepository : IMainToolbarElementRepository + { + public MainToolbarElement[] GetAll() + { + return TypeCache.GetTypesWithAttribute() + .Where(type => IsValidVisualElementType(type)) + .Select(type => GetMainToolbarElementFromType(type)) + .ToArray(); + } + + private MainToolbarElement GetMainToolbarElementFromType(Type type) + { + var elementInstance = (VisualElement)Activator.CreateInstance(type); + var attribute = type.GetCustomAttribute(); + + if (string.IsNullOrEmpty(elementInstance.name)) + elementInstance.name = elementInstance.GetType().Name; + + return new MainToolbarElement(attribute.Id, elementInstance, attribute.Alignment, + attribute.Order, attribute.UseRecommendedStyles); + } + + private bool IsValidVisualElementType(Type type) + { + var visualElementType = typeof(VisualElement); + + return visualElementType != type && + visualElementType.IsAssignableFrom(type) && + !type.IsAbstract; + } + } +} \ No newline at end of file diff --git a/Editor/Toolbar/ByAttributeMainToolbarElementRepository.cs.meta b/Editor/Toolbar/ByAttributeMainToolbarElementRepository.cs.meta new file mode 100644 index 0000000..e03e5a9 --- /dev/null +++ b/Editor/Toolbar/ByAttributeMainToolbarElementRepository.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9e664729ffc0507499365cb1b3393b91 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Toolbar/ControlPanelWindow.meta b/Editor/Toolbar/ControlPanelWindow.meta new file mode 100644 index 0000000..795b449 --- /dev/null +++ b/Editor/Toolbar/ControlPanelWindow.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e5d6770a557fcef47bfab9c1562f972c +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Toolbar/ControlPanelWindow/MainToolbarControlPanelWindow.cs b/Editor/Toolbar/ControlPanelWindow/MainToolbarControlPanelWindow.cs new file mode 100644 index 0000000..349d753 --- /dev/null +++ b/Editor/Toolbar/ControlPanelWindow/MainToolbarControlPanelWindow.cs @@ -0,0 +1,207 @@ +using System.Collections.Generic; +using System.Linq; +using UnityEditor; +using UnityEngine; +using UnityEngine.UIElements; + +namespace Paps.UnityToolbarExtenderUIToolkit +{ + public class MainToolbarControlPanelWindow : EditorWindow + { + private const string NATIVE_ELEMENTS_CONTAINER_NAME = "UnityNativeElementsContainer"; + private const string NATIVE_ELEMENTS_FOLDOUT_TEXT = "Unity Native Elements"; + + private const string SINGLE_ELEMENTS_CONTAINER_NAME = "SingleElementsContainer"; + private const string SINGLE_ELEMENTS_FOLDOUT_TEXT = "Single Elements"; + + private const string GROUP_ELEMENTS_CONTAINER_NAME = "GroupElementsContainer"; + private const string GROUP_ELEMENTS_FOLDOUT_TEXT = "Groups"; + + private const float MAIN_CONTAINER_PADDING_TOP = 5; + + private OrganizationalFoldableContainer _nativeElementsContainer; + private OrganizationalFoldableContainer _singleElementsContainer; + private OrganizationalFoldableContainer _groupElementsContainer; + private MainToolbarElementController[] _controllers; + + private Button _resetOverridesButton; + + private VisualElement _noElementsMessageElement; + private VisualElement _windowContainer; + + public static void OpenWindow() + { + var window = GetWindow(); + + window.titleContent = new GUIContent("Main Toolbar Control Panel"); + } + + private void CreateGUI() + { + MainToolbarAutomaticExtender.OnAddedCustomContainersToToolbar += Refresh; + MainToolbarAutomaticExtender.OnRefresh += Refresh; + + BuildFixedGUI(); + SetDefaultView(); + + if (MainToolbar.IsAvailable) + Refresh(); + } + + private void OnDestroy() + { + MainToolbarAutomaticExtender.OnAddedCustomContainersToToolbar -= Refresh; + MainToolbarAutomaticExtender.OnRefresh -= Refresh; + } + + private void Refresh() + { + BuildDynamicGUI(); + SetCorrespondingView(); + } + + private void BuildFixedGUI() + { + _windowContainer = GetContainer(); + + _resetOverridesButton = new Button(GlobalActions.ResetOverridesIfUserAccepts); + _resetOverridesButton.text = "Reset Overrides"; + + _singleElementsContainer = new OrganizationalFoldableContainer( + SINGLE_ELEMENTS_CONTAINER_NAME, SINGLE_ELEMENTS_FOLDOUT_TEXT); + _groupElementsContainer = new OrganizationalFoldableContainer( + GROUP_ELEMENTS_CONTAINER_NAME, GROUP_ELEMENTS_FOLDOUT_TEXT); + _nativeElementsContainer = new OrganizationalFoldableContainer( + NATIVE_ELEMENTS_CONTAINER_NAME, NATIVE_ELEMENTS_FOLDOUT_TEXT); + + _noElementsMessageElement = CreateNoElementsMessageElement(); + + rootVisualElement.Add(_resetOverridesButton); + rootVisualElement.Add(_windowContainer); + } + + private void SetDefaultView() + { + _windowContainer.Add(_noElementsMessageElement); + } + + private void SetCorrespondingView() + { + if(_controllers.Length > 0) + { + if(_windowContainer.Contains(_noElementsMessageElement)) + _windowContainer.Remove(_noElementsMessageElement); + + if (!_windowContainer.Contains(_singleElementsContainer)) + { + _windowContainer.Add(_singleElementsContainer); + _windowContainer.Add(_groupElementsContainer); + _windowContainer.Add(_nativeElementsContainer); + } + } + else + { + if (_windowContainer.Contains(_singleElementsContainer)) + { + _windowContainer.Remove(_singleElementsContainer); + _windowContainer.Remove(_groupElementsContainer); + _windowContainer.Remove(_nativeElementsContainer); + } + + if (!_windowContainer.Contains(_noElementsMessageElement)) + _windowContainer.Add(_noElementsMessageElement); + } + } + + private void BuildDynamicGUI() + { + _controllers = CreateControllers(); + + var controllersOfNativeElements = _controllers + .Where(controller => controller.HoldsANativeElement); + var controllersOfGroups = _controllers + .Where(controller => controller.HoldsAGroup); + var controllersOfSingleElements = _controllers + .Where(controller => !controller.HoldsAGroup && !controller.HoldsANativeElement) + .Where(controller => SingleControllerIsNotInsideAGroupController(controller, controllersOfGroups)); + + _singleElementsContainer.SetControllers(controllersOfSingleElements); + _groupElementsContainer.SetControllers(controllersOfGroups); + _nativeElementsContainer.SetControllers(controllersOfNativeElements); + } + + private static bool SingleControllerIsNotInsideAGroupController(MainToolbarElementController controller, IEnumerable controllersOfGroups) + { + foreach (var groupController in controllersOfGroups) + if (groupController.ContainsSubController(controller.Id)) + return false; + + return true; + } + + private VisualElement GetContainer() + { + var scrollView = new ScrollView(ScrollViewMode.Vertical); + + scrollView.style.paddingTop = MAIN_CONTAINER_PADDING_TOP; + + return scrollView; + } + + private MainToolbarElementController[] CreateControllers() + { + return GetOverridableElements() + .OrderBy(overridableElement => overridableElement.Id) + .Select(overridableElement => new MainToolbarElementController( + overridableElement, + ServicesAndRepositories.MainToolbarElementOverridesRepository, + GetSubElementsIfAny(overridableElement)) + ) + .ToArray(); + } + + private OverridableElement[] GetSubElementsIfAny(OverridableElement overridableElement) + { + if(overridableElement.VisualElement is GroupElement) + { + return MainToolbarAutomaticExtender.GetElementsOfGroup(overridableElement.Id) + .Select(el => new OverridableElement( + el.Id, + el.VisualElement, + false) + ) + .ToArray(); + } + + return new OverridableElement[0]; + } + + private OverridableElement[] GetOverridableElements() + { + var nativeElements = MainToolbarAutomaticExtender.NativeElements + .Select(nativeElement => new OverridableElement( + nativeElement.Id, + nativeElement.VisualElement, + true + ) + ); + + var customElements = MainToolbarAutomaticExtender.CustomMainToolbarElements + .Concat(MainToolbarAutomaticExtender.GroupElements) + .Select(mainToolbarElement => new OverridableElement( + mainToolbarElement.Id, + mainToolbarElement.VisualElement, + false + ) + ); + + return nativeElements.Concat(customElements) + .ToArray(); + } + + private VisualElement CreateNoElementsMessageElement() + { + return new HelpBox("No main toolbar elements were found. To use the automatic toolbar extender define a main toolbar element. See the docs.", HelpBoxMessageType.Warning); + } + } +} \ No newline at end of file diff --git a/Editor/Toolbar/ControlPanelWindow/MainToolbarControlPanelWindow.cs.meta b/Editor/Toolbar/ControlPanelWindow/MainToolbarControlPanelWindow.cs.meta new file mode 100644 index 0000000..ca70fb2 --- /dev/null +++ b/Editor/Toolbar/ControlPanelWindow/MainToolbarControlPanelWindow.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: fef14479cdf8f5a41bb3b7f4b442484e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Toolbar/ControlPanelWindow/MainToolbarElementController.cs b/Editor/Toolbar/ControlPanelWindow/MainToolbarElementController.cs new file mode 100644 index 0000000..59fb561 --- /dev/null +++ b/Editor/Toolbar/ControlPanelWindow/MainToolbarElementController.cs @@ -0,0 +1,187 @@ +using System.Collections.Generic; +using System.Linq; +using UnityEngine; +using UnityEngine.UIElements; + +namespace Paps.UnityToolbarExtenderUIToolkit +{ + internal class MainToolbarElementController : VisualElement + { + private const string FOLDOUT_STATE_SAVE_KEY_BASE = "main-toolbar-element-controller:foldout-state:"; + private const float LEFT_PADDING_SINGLE = 19; + private const float RIGHT_PADDING = 10; + + private readonly IMainToolbarElementOverrideRepository _overridesRepository; + private Label _label; + private Button _button; + private Image _buttonIconImage; + private Foldout _foldout; + + private StyleColor _defaultButtonColor; + private List _subControllers = new List(); + + public string Id { get; } + public VisualElement ControlledVisualElement { get; } + public bool HoldsAGroup => _foldout != null; + public bool HoldsANativeElement { get; private set; } + + public MainToolbarElementController(OverridableElement overridableElement, + IMainToolbarElementOverrideRepository overridesRepository, params OverridableElement[] subElements) + { + Id = overridableElement.Id; + ControlledVisualElement = overridableElement.VisualElement; + HoldsANativeElement = overridableElement.IsNative; + name = Id + "-Controller"; + _overridesRepository = overridesRepository; + + _buttonIconImage = new Image(); + + style.flexDirection = FlexDirection.Row; + style.justifyContent = Justify.SpaceBetween; + style.paddingRight = RIGHT_PADDING; + + _label = CreateLabel(); + _button = CreateButton(); + + _defaultButtonColor = _button.style.backgroundColor; + + UpdateButtonStatus(VisibleValueOrDefault()); + BuildAsGroupOrSingle(subElements); + } + + private string GetFullFoldoutStateSaveKey() => FOLDOUT_STATE_SAVE_KEY_BASE + Id; + + private void SaveFoldoutState(ChangeEvent eventArgs) + { + UserSettingsPrefs.SetBool(GetFullFoldoutStateSaveKey(), eventArgs.newValue); + } + + private bool GetSavedFoldoutState() + { + return UserSettingsPrefs.GetBool(GetFullFoldoutStateSaveKey(), false); + } + + public bool ContainsSubController(string id) + { + return _subControllers.Any(controller => controller.Id == id); + } + + private void BuildAsGroupOrSingle(OverridableElement[] subElements) + { + if (subElements.Length > 0) + BuildFoldout(subElements); + else + BuildSingleElement(); + } + + private void BuildSingleElement() + { + style.paddingLeft = LEFT_PADDING_SINGLE; + + Add(_label); + Add(_button); + } + + private void BuildFoldout(OverridableElement[] subElements) + { + _foldout = new Foldout() { text = _label.text }; + + foreach (var overridable in subElements) + { + var subController = new MainToolbarElementController(overridable, _overridesRepository); + + _subControllers.Add(subController); + + _foldout.Add(subController); + } + + _foldout.value = GetSavedFoldoutState(); + _foldout.RegisterCallback>(SaveFoldoutState); + _foldout.style.flexGrow = 1; + + Add(_foldout); + Add(_button); + } + + private bool VisibleValueOrDefault() + { + var possibleOverride = _overridesRepository.Get(Id); + + if (possibleOverride == null) + return CurrentDisplayValueAsBool(); + + var overrideValue = possibleOverride.Value; + + return overrideValue.Visible; + } + + private Label CreateLabel() + { + var label = new Label(Id); + + label.style.alignSelf = Align.Center; + + return label; + } + + private Button CreateButton() + { + var button = new Button(ChangeVisibilityValue); + + button.Add(_buttonIconImage); + + button.tooltip = "Change the visibility of element with id " + Id; + + button.style.alignSelf = Align.FlexStart; + + return button; + } + + private Texture IconByVisibilityValue(bool visible) + { + if (visible) + return Icons.VisibilityOnOverrideIcon; + + return Icons.VisibilityOffOverrideIcon; + } + + private void ChangeVisibilityValue() + { + var currentOverrideValue = _overridesRepository.Get(Id); + + bool newValue; + + if (currentOverrideValue == null) + newValue = !CurrentDisplayValueAsBool(); + else + newValue = !currentOverrideValue.Value.Visible; + + _overridesRepository.Save(new MainToolbarElementOverride(Id, newValue)); + UpdateButtonStatus(newValue); + + MainToolbarAutomaticExtender.Refresh(); + } + + private bool CurrentDisplayValueAsBool() + { + if (ControlledVisualElement.style.display == DisplayStyle.None) + return false; + else + return true; + } + + private void UpdateButtonStatus(bool visible) + { + _buttonIconImage.image = IconByVisibilityValue(visible); + _button.style.backgroundColor = GetButtonColor(visible); + } + + private StyleColor GetButtonColor(bool visible) + { + if (visible) + return _defaultButtonColor; + else + return new StyleColor(Color.black); + } + } +} \ No newline at end of file diff --git a/Editor/Toolbar/ControlPanelWindow/MainToolbarElementController.cs.meta b/Editor/Toolbar/ControlPanelWindow/MainToolbarElementController.cs.meta new file mode 100644 index 0000000..63b2445 --- /dev/null +++ b/Editor/Toolbar/ControlPanelWindow/MainToolbarElementController.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ae80166256b03484a9bfc1ad9c4cc0dc +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Toolbar/ControlPanelWindow/OrganizationalFoldableContainer.cs b/Editor/Toolbar/ControlPanelWindow/OrganizationalFoldableContainer.cs new file mode 100644 index 0000000..5178fea --- /dev/null +++ b/Editor/Toolbar/ControlPanelWindow/OrganizationalFoldableContainer.cs @@ -0,0 +1,51 @@ +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.UIElements; + +namespace Paps.UnityToolbarExtenderUIToolkit +{ + internal class OrganizationalFoldableContainer : Box + { + private static readonly Color ORGANIZATIONAL_FOLDABLE_CONTAINER_BORDER_COLOR = new Color(153f / 255f, 153f / 255f, 153f / 255f); + private const string FOLDOUT_STATE_SAVE_KEY_BASE = "organizational-foldable-container:foldout-state:"; + + private Foldout _foldout; + private string _id; + + public OrganizationalFoldableContainer(string containerId, string foldoutText) + { + _id = containerId; + name = containerId; + style.borderTopColor = ORGANIZATIONAL_FOLDABLE_CONTAINER_BORDER_COLOR; + style.borderTopWidth = 1; + + _foldout = new Foldout() { text = foldoutText }; + _foldout.value = GetSavedFoldoutState(); + _foldout.RegisterCallback>(SaveFoldoutState); + + Add(_foldout); + } + + private string GetFullFoldoutStateSaveKey() => FOLDOUT_STATE_SAVE_KEY_BASE + _id; + + private void SaveFoldoutState(ChangeEvent eventArgs) + { + UserSettingsPrefs.SetBool(GetFullFoldoutStateSaveKey(), eventArgs.newValue); + } + + private bool GetSavedFoldoutState() + { + return UserSettingsPrefs.GetBool(GetFullFoldoutStateSaveKey(), false); + } + + public void SetControllers(IEnumerable controllers) + { + _foldout.Clear(); + + foreach (var controller in controllers) + { + _foldout.Add(controller); + } + } + } +} \ No newline at end of file diff --git a/Editor/Toolbar/ControlPanelWindow/OrganizationalFoldableContainer.cs.meta b/Editor/Toolbar/ControlPanelWindow/OrganizationalFoldableContainer.cs.meta new file mode 100644 index 0000000..82d0a8c --- /dev/null +++ b/Editor/Toolbar/ControlPanelWindow/OrganizationalFoldableContainer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9ac00cb9059df7e43b1c2ed433ce61cc +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Toolbar/ControlPanelWindow/OverridableElement.cs b/Editor/Toolbar/ControlPanelWindow/OverridableElement.cs new file mode 100644 index 0000000..be33db5 --- /dev/null +++ b/Editor/Toolbar/ControlPanelWindow/OverridableElement.cs @@ -0,0 +1,18 @@ +using UnityEngine.UIElements; + +namespace Paps.UnityToolbarExtenderUIToolkit +{ + internal readonly struct OverridableElement + { + public string Id { get; } + public VisualElement VisualElement { get; } + public bool IsNative { get; } + + public OverridableElement(string id, VisualElement visualElement, bool isNative) + { + Id = id; + VisualElement = visualElement; + IsNative = isNative; + } + } +} \ No newline at end of file diff --git a/Editor/Toolbar/ControlPanelWindow/OverridableElement.cs.meta b/Editor/Toolbar/ControlPanelWindow/OverridableElement.cs.meta new file mode 100644 index 0000000..79c9790 --- /dev/null +++ b/Editor/Toolbar/ControlPanelWindow/OverridableElement.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 542f1fb68120090489ba1613162eb17b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Toolbar/Extensions.meta b/Editor/Toolbar/Extensions.meta new file mode 100644 index 0000000..005d707 --- /dev/null +++ b/Editor/Toolbar/Extensions.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f0a074f24b9c98d488341e6258c0c0b0 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Toolbar/Extensions/EditorWindowExtensions.cs b/Editor/Toolbar/Extensions/EditorWindowExtensions.cs new file mode 100644 index 0000000..ceb227c --- /dev/null +++ b/Editor/Toolbar/Extensions/EditorWindowExtensions.cs @@ -0,0 +1,17 @@ +using UnityEditor; +using UnityEngine; + +namespace Paps.UnityToolbarExtenderUIToolkit +{ + public static class EditorWindowExtensions + { + public static void ShowAsDropdownForMainToolbar(this EditorWindow window, Rect activatorRect, Vector2 size) + { + window.ShowAsDropDown(activatorRect, size); + + var rect = GUIUtility.GUIToScreenRect(activatorRect); + rect.y += activatorRect.size.y; + window.position = new Rect(rect.position, window.position.size); + } + } +} diff --git a/Editor/Toolbar/Extensions/EditorWindowExtensions.cs.meta b/Editor/Toolbar/Extensions/EditorWindowExtensions.cs.meta new file mode 100644 index 0000000..b8b3fbf --- /dev/null +++ b/Editor/Toolbar/Extensions/EditorWindowExtensions.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3333a000c60ebce4aa038ee0945d0072 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Toolbar/GroupDefinitions.meta b/Editor/Toolbar/GroupDefinitions.meta new file mode 100644 index 0000000..89f1e7a --- /dev/null +++ b/Editor/Toolbar/GroupDefinitions.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 1a83afb20ef0f5f40b22a93ff124fe1f +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Toolbar/GroupDefinitions/GroupDefinition.cs b/Editor/Toolbar/GroupDefinitions/GroupDefinition.cs new file mode 100644 index 0000000..579e6a2 --- /dev/null +++ b/Editor/Toolbar/GroupDefinitions/GroupDefinition.cs @@ -0,0 +1,39 @@ +using System.Linq; + +namespace Paps.UnityToolbarExtenderUIToolkit +{ + internal readonly struct GroupDefinition + { + public string GroupId { get; } + public string GroupName { get; } + public ToolbarAlign Alignment { get; } + public int Order { get; } + public string[] ToolbarElementsIds { get; } + + public GroupDefinition(string groupId, string groupName, ToolbarAlign alignment, int order, string[] toolbarElementsIds) + { + GroupId = groupId; + GroupName = string.IsNullOrEmpty(groupName) ? groupId : groupName; + Alignment = alignment; + Order = order; + ToolbarElementsIds = toolbarElementsIds; + } + + public bool AreEquals(GroupDefinition other) + { + return GroupId == other.GroupId && + GroupName == other.GroupName && + Alignment == other.Alignment && + Order == other.Order && + AreEquals(ToolbarElementsIds, other.ToolbarElementsIds); + } + + private bool AreEquals(string[] types, string[] types2) + { + if(types.Length != types2.Length) + return false; + + return types.All(typeName => types2.Contains(typeName)); + } + } +} \ No newline at end of file diff --git a/Editor/Toolbar/GroupDefinitions/GroupDefinition.cs.meta b/Editor/Toolbar/GroupDefinitions/GroupDefinition.cs.meta new file mode 100644 index 0000000..821335d --- /dev/null +++ b/Editor/Toolbar/GroupDefinitions/GroupDefinition.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8e3f2e82a96ef3246860b2861fa19b15 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Toolbar/GroupDefinitions/GroupDropdownWindowPopup.cs b/Editor/Toolbar/GroupDefinitions/GroupDropdownWindowPopup.cs new file mode 100644 index 0000000..f0c85c0 --- /dev/null +++ b/Editor/Toolbar/GroupDefinitions/GroupDropdownWindowPopup.cs @@ -0,0 +1,92 @@ +using UnityEditor; +using UnityEngine; +using UnityEngine.UIElements; + +namespace Paps.UnityToolbarExtenderUIToolkit +{ + internal class GroupDropdownWindowPopup : EditorWindow + { + private VisualElement[] _groupElements; + private ScrollView _scrollView; + + public void Initialize(VisualElement[] groupElements) + { + _groupElements = groupElements; + hideFlags = HideFlags.DontSave; + } + + private void OnEnable() + { + AssemblyReloadEvents.beforeAssemblyReload += Close; + } + + private void OnDisable() + { + AssemblyReloadEvents.beforeAssemblyReload -= Close; + } + + private void CreateGUI() + { + _scrollView = new ScrollView(ScrollViewMode.Vertical); + _scrollView.contentContainer.style.alignContent = Align.Center; + _scrollView.contentContainer.style.alignItems = Align.Center; + _scrollView.horizontalScrollerVisibility = ScrollerVisibility.Hidden; + + foreach (var groupElement in _groupElements) + { + var container = CreateGroupElementContainer(); + container.Add(groupElement); + groupElement.style.flexWrap = Wrap.Wrap; + container.style.display = groupElement.style.display; + _scrollView.Add(container); + } + + var baseContainer = CreateBaseContainer(); + baseContainer.Add(_scrollView); + + rootVisualElement.Add(baseContainer); + } + + private VisualElement CreateBaseContainer() + { + return new VisualElement() + { + style = + { + flexGrow = 1, + borderBottomColor = Color.black, + borderTopColor = Color.black, + borderLeftColor = Color.black, + borderRightColor = Color.black, + borderBottomWidth = 2, + borderTopWidth = 2, + borderLeftWidth = 2, + borderRightWidth = 2, + } + }; + } + + private VisualElement CreateGroupElementContainer() + { + return new Box() + { + style = + { + alignContent = Align.Center, + alignItems = Align.Center, + flexDirection = FlexDirection.Row, + flexGrow = 1, + width = Length.Percent(100), + height = Length.Auto(), + justifyContent = Justify.Center, + borderTopColor = Color.black, + borderTopWidth = 1, + paddingTop = 3f, + paddingBottom = 3f, + paddingLeft = 8, + paddingRight = 8, + } + }; + } + } +} diff --git a/Editor/Toolbar/GroupDefinitions/GroupDropdownWindowPopup.cs.meta b/Editor/Toolbar/GroupDefinitions/GroupDropdownWindowPopup.cs.meta new file mode 100644 index 0000000..7b134df --- /dev/null +++ b/Editor/Toolbar/GroupDefinitions/GroupDropdownWindowPopup.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8509c9dbf1627b74c9e521402a3de28b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Toolbar/GroupDefinitions/GroupDropdownWindowPopupManager.cs b/Editor/Toolbar/GroupDefinitions/GroupDropdownWindowPopupManager.cs new file mode 100644 index 0000000..bb21d42 --- /dev/null +++ b/Editor/Toolbar/GroupDefinitions/GroupDropdownWindowPopupManager.cs @@ -0,0 +1,144 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using UnityEditor; +using UnityEngine; +using UnityEngine.UIElements; +using PopupWindow = UnityEditor.PopupWindow; + +namespace Paps.UnityToolbarExtenderUIToolkit +{ + internal static class GroupDropdownWindowPopupManager + { + private const string POPUP_WINDOW_CONTENT_FIELD_NAME = "m_WindowContent"; + private static readonly string[] SPECIAL_EDITOR_WINDOW_TYPE_NAMES = + { + "UnityEditor.UIElements.Debugger.UIElementsDebugger", + "UnityEditor.UIElements.EditorMenuExtensions+ContextMenu", + "UnityEditor.ObjectSelector", + "UnityEditor.Search.SearchPickerWindow" + }; + private static readonly string[] SPECIAL_POPUP_WINDOW_CONTENT_TYPE_NAMES = + { + "UnityEditor.UIElements.EditorGenericDropdownMenuWindowContent" + }; + + private static FieldInfo _popupWindowContentField; + private static Type[] _subWindowTypes = new Type[0]; + private static Type[] _specialWindowTypes = new Type[0]; + private static List _windows = new List(); + + static GroupDropdownWindowPopupManager() + { + _popupWindowContentField = typeof(PopupWindow) + .GetField(POPUP_WINDOW_CONTENT_FIELD_NAME, + BindingFlags.NonPublic | BindingFlags.Instance); + + InitializeSpecialWindowTypes(); + LoadSubWindowTypes(); + EditorApplication.update += Update; + } + + private static void LoadSubWindowTypes() + { + _subWindowTypes = TypeCache.GetTypesWithAttribute() + .Where(type => IsValidSubWindowType(type)) + .ToArray(); + } + + private static void InitializeSpecialWindowTypes() + { + var typeList = new List(); + + typeList.AddRange(TypeCache.GetTypesDerivedFrom() + .Where(type => SPECIAL_EDITOR_WINDOW_TYPE_NAMES.Contains(type.Name) || SPECIAL_EDITOR_WINDOW_TYPE_NAMES.Contains(type.FullName))); + + typeList.AddRange(TypeCache.GetTypesDerivedFrom() + .Where(type => SPECIAL_POPUP_WINDOW_CONTENT_TYPE_NAMES.Contains(type.Name) || SPECIAL_POPUP_WINDOW_CONTENT_TYPE_NAMES.Contains(type.FullName))); + + _specialWindowTypes = typeList.Where(t => t != null).ToArray(); + } + + private static bool IsValidSubWindowType(Type type) + { + return typeof(EditorWindow).IsAssignableFrom(type) || + typeof(PopupWindowContent).IsAssignableFrom(type); + } + + private static bool ContainsValidPopupWindowContent(EditorWindow window) + { + if(window is PopupWindow popupWindow) + { + var popupContent = _popupWindowContentField.GetValue(popupWindow) as PopupWindowContent; + + var popupContentSpecificType = popupContent.GetType(); + + return _subWindowTypes.Contains(popupContentSpecificType) || _specialWindowTypes.Contains(popupContentSpecificType); + } + + return false; + } + + private static void Update() + { + if (_windows.Count == 0) + return; + + if (EditorWindow.focusedWindow == null || !FocusedWindowIsValid()) + CloseAll(); + else if(_windows.Contains(EditorWindow.focusedWindow)) + { + var focusedWindow = EditorWindow.focusedWindow; + + var downMostWindow = _windows.Last(); + + while(downMostWindow != focusedWindow) + { + _windows.Remove(downMostWindow); + downMostWindow.Close(); + downMostWindow = _windows.Last(); + } + } + } + + private static void CloseAll() + { + foreach(var window in _windows) + { + if(window != null) + window.Close(); + } + + _windows.Clear(); + } + + private static bool FocusedWindowIsValid() + { + return _windows.Contains(EditorWindow.focusedWindow) || + _subWindowTypes.Contains(EditorWindow.focusedWindow.GetType()) || + _specialWindowTypes.Contains(EditorWindow.focusedWindow.GetType()) || + ContainsValidPopupWindowContent(EditorWindow.focusedWindow); + } + + public static void Show(Rect activatorRect, VisualElement[] elements) + { + var window = ScriptableObject.CreateInstance(); + + var rect = GUIUtility.GUIToScreenRect(activatorRect); + rect.y += activatorRect.size.y; + window.position = new Rect(rect.position, window.position.size); + + _windows.Add(window); + + window.Initialize(elements); + +#if UNITY_EDITOR_WIN + window.ShowPopup(); +#elif UNITY_EDITOR_OSX + window.ShowAsDropdownForMainToolbar(activatorRect, window.position.size); +#endif + + } + } +} diff --git a/Editor/Toolbar/GroupDefinitions/GroupDropdownWindowPopupManager.cs.meta b/Editor/Toolbar/GroupDefinitions/GroupDropdownWindowPopupManager.cs.meta new file mode 100644 index 0000000..4bd2b9b --- /dev/null +++ b/Editor/Toolbar/GroupDefinitions/GroupDropdownWindowPopupManager.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 88333c3cc209cb143bc93891e1664b41 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Toolbar/GroupDefinitions/GroupElement.cs b/Editor/Toolbar/GroupDefinitions/GroupElement.cs new file mode 100644 index 0000000..00ee23a --- /dev/null +++ b/Editor/Toolbar/GroupDefinitions/GroupElement.cs @@ -0,0 +1,29 @@ +using System.Linq; +using UnityEditor.Toolbars; +using UnityEngine.UIElements; + +namespace Paps.UnityToolbarExtenderUIToolkit +{ + internal class GroupElement : EditorToolbarDropdown + { + private VisualElement[] _groupedElements; + public VisualElement[] GroupedElements => _groupedElements.ToArray(); + + public GroupElement(string name) + { + this.name = name; + text = name; + clicked += ShowDropdown; + } + + public void Initialize(VisualElement[] groupedElements) + { + _groupedElements = groupedElements; + } + + private void ShowDropdown() + { + GroupDropdownWindowPopupManager.Show(worldBound, _groupedElements); + } + } +} \ No newline at end of file diff --git a/Editor/Toolbar/GroupDefinitions/GroupElement.cs.meta b/Editor/Toolbar/GroupDefinitions/GroupElement.cs.meta new file mode 100644 index 0000000..4eee5d1 --- /dev/null +++ b/Editor/Toolbar/GroupDefinitions/GroupElement.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c782e5c3d1d2bd7499b358c6aa5703cd +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Toolbar/GroupDefinitions/GroupPopupSubWindowAttribute.cs b/Editor/Toolbar/GroupDefinitions/GroupPopupSubWindowAttribute.cs new file mode 100644 index 0000000..b074d05 --- /dev/null +++ b/Editor/Toolbar/GroupDefinitions/GroupPopupSubWindowAttribute.cs @@ -0,0 +1,10 @@ +using System; + +namespace Paps.UnityToolbarExtenderUIToolkit +{ + [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)] + public class GroupPopupSubWindowAttribute : Attribute + { + + } +} diff --git a/Editor/Toolbar/GroupDefinitions/GroupPopupSubWindowAttribute.cs.meta b/Editor/Toolbar/GroupDefinitions/GroupPopupSubWindowAttribute.cs.meta new file mode 100644 index 0000000..0f83646 --- /dev/null +++ b/Editor/Toolbar/GroupDefinitions/GroupPopupSubWindowAttribute.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f6e542ea23caed94c92fab5ac0d0f1c8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Toolbar/GroupDefinitions/IGroupDefinitionRepository.cs b/Editor/Toolbar/GroupDefinitions/IGroupDefinitionRepository.cs new file mode 100644 index 0000000..84c8e7f --- /dev/null +++ b/Editor/Toolbar/GroupDefinitions/IGroupDefinitionRepository.cs @@ -0,0 +1,7 @@ +namespace Paps.UnityToolbarExtenderUIToolkit +{ + internal interface IGroupDefinitionRepository + { + public GroupDefinition[] GetAll(); + } +} \ No newline at end of file diff --git a/Editor/Toolbar/GroupDefinitions/IGroupDefinitionRepository.cs.meta b/Editor/Toolbar/GroupDefinitions/IGroupDefinitionRepository.cs.meta new file mode 100644 index 0000000..fcd92f1 --- /dev/null +++ b/Editor/Toolbar/GroupDefinitions/IGroupDefinitionRepository.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 15164a1a1815ea04c9ae72e65e0a9fe9 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Toolbar/GroupDefinitions/MainToolbarElementDropdownAttribute.cs b/Editor/Toolbar/GroupDefinitions/MainToolbarElementDropdownAttribute.cs new file mode 100644 index 0000000..abab388 --- /dev/null +++ b/Editor/Toolbar/GroupDefinitions/MainToolbarElementDropdownAttribute.cs @@ -0,0 +1,11 @@ +using System; +using UnityEngine; + +namespace Paps.UnityToolbarExtenderUIToolkit +{ + [AttributeUsage(AttributeTargets.Field, AllowMultiple = false, Inherited = false)] + internal class MainToolbarElementDropdownAttribute : PropertyAttribute + { + + } +} diff --git a/Editor/Toolbar/GroupDefinitions/MainToolbarElementDropdownAttribute.cs.meta b/Editor/Toolbar/GroupDefinitions/MainToolbarElementDropdownAttribute.cs.meta new file mode 100644 index 0000000..4a5d1f8 --- /dev/null +++ b/Editor/Toolbar/GroupDefinitions/MainToolbarElementDropdownAttribute.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ffb57bb326f1c1247b6e1341c5caecf3 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Toolbar/GroupDefinitions/MainToolbarElementDropdownDrawer.cs b/Editor/Toolbar/GroupDefinitions/MainToolbarElementDropdownDrawer.cs new file mode 100644 index 0000000..f070eea --- /dev/null +++ b/Editor/Toolbar/GroupDefinitions/MainToolbarElementDropdownDrawer.cs @@ -0,0 +1,84 @@ +using System.Collections.Generic; +using System.Linq; +using UnityEditor; +using UnityEngine.UIElements; + +namespace Paps.UnityToolbarExtenderUIToolkit +{ + [CustomPropertyDrawer(typeof(MainToolbarElementDropdownAttribute))] + internal class MainToolbarElementDropdownDrawer : PropertyDrawer + { + private string _groupId; + private IEnumerable _mainToolbarElementsIds; + private IEnumerable _groupIds; + private IEnumerable _allIds; + + public override VisualElement CreatePropertyGUI(SerializedProperty property) + { + _groupId = property.serializedObject.FindProperty("_groupId").stringValue; + + CacheAllIds(); + + var availableIds = GetAvailableIds(); + + var popupField = new PopupField( + choices: availableIds, + 0); + + Restore(property, availableIds, popupField); + + popupField.RegisterCallback>(ev => + { + property.stringValue = ev.newValue; + property.serializedObject.ApplyModifiedProperties(); + ScriptableGroupDefinitionHelper.Refresh(); + CacheAllIds(); + var newAvailableIds = GetAvailableIds(); + newAvailableIds.Add(property.stringValue); + popupField.choices = newAvailableIds.OrderBy(id => id).ToList(); + }); + + return popupField; + } + + private void Restore(SerializedProperty property, List availableIds, PopupField popupField) + { + if (string.IsNullOrEmpty(property.stringValue)) + { + property.stringValue = popupField.value; + property.serializedObject.ApplyModifiedProperties(); + } + else + { + if (_allIds.Contains(property.stringValue)) + { + availableIds.Add(property.stringValue); + popupField.choices = availableIds.OrderBy(id => id).ToList(); + popupField.SetValueWithoutNotify(property.stringValue); + } + else + popupField.SetValueWithoutNotify(""); + } + } + + private void CacheAllIds() + { + _mainToolbarElementsIds = MainToolbarAutomaticExtender.CustomMainToolbarElements.Select(el => el.Id); + _groupIds = ScriptableGroupDefinitionHelper.GetGroupIds(); + + _allIds = _mainToolbarElementsIds + .Concat(_groupIds); + } + + private List GetAvailableIds() + { + var unusedMainToolbarElementIds = ScriptableGroupDefinitionHelper.GetUnusedMainToolbarElementIds(_mainToolbarElementsIds); + var unusedGroupIds = ScriptableGroupDefinitionHelper.GetEligibleGroupChildsFor(_groupId); + + return unusedMainToolbarElementIds + .Concat(unusedGroupIds) + .OrderBy(id => id) + .ToList(); + } + } +} diff --git a/Editor/Toolbar/GroupDefinitions/MainToolbarElementDropdownDrawer.cs.meta b/Editor/Toolbar/GroupDefinitions/MainToolbarElementDropdownDrawer.cs.meta new file mode 100644 index 0000000..072f1fe --- /dev/null +++ b/Editor/Toolbar/GroupDefinitions/MainToolbarElementDropdownDrawer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: cb51db686d5e79d4295bc1a510395e2c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Toolbar/GroupDefinitions/ScriptableGroupDefinition.cs b/Editor/Toolbar/GroupDefinitions/ScriptableGroupDefinition.cs new file mode 100644 index 0000000..332e199 --- /dev/null +++ b/Editor/Toolbar/GroupDefinitions/ScriptableGroupDefinition.cs @@ -0,0 +1,52 @@ +using UnityEngine; + +namespace Paps.UnityToolbarExtenderUIToolkit +{ + [CreateAssetMenu(menuName = ToolInfo.EDITOR_MENU_BASE + "/Group Definition")] + public sealed class ScriptableGroupDefinition : ScriptableObject + { + [SerializeField] + [Tooltip("Id of group. It must be unique")] + private string _groupId; + [SerializeField] + [Tooltip("Text to display in group element dropdown")] + private string _groupName; + [SerializeField] + [Tooltip("Alignment when used as root element. Ignored inside other groups")] + private ToolbarAlign _alignment; + [Tooltip("Order when used as root element. Ignored inside other groups. Order of elements inside a group is determined by ToolbarElementsIds array elements order.")] + [SerializeField] private int _order; + [SerializeField] + [Tooltip("Elements ids of this group. Order of elements in array determines the order in which the elements will be displayed")] + [MainToolbarElementDropdown] private string[] _toolbarElementsIds; + + public string GroupId => _groupId; + public string GroupName => _groupName; + public ToolbarAlign Alignment => _alignment; + public int Order => _order; + public string[] ToolbarElementsIds => _toolbarElementsIds == null ? new string[0] : _toolbarElementsIds; + + private void OnValidate() + { + SetEqualValuesToEmptyInOrder(); + } + + private void SetEqualValuesToEmptyInOrder() + { + for (int i = 0; i < _toolbarElementsIds.Length; i++) + { + var value = _toolbarElementsIds[i]; + for (int j = 0; j < _toolbarElementsIds.Length; j++) + { + if (i == j) + continue; + + if (_toolbarElementsIds[j] == value) + { + _toolbarElementsIds[j] = ""; + } + } + } + } + } +} \ No newline at end of file diff --git a/Editor/Toolbar/GroupDefinitions/ScriptableGroupDefinition.cs.meta b/Editor/Toolbar/GroupDefinitions/ScriptableGroupDefinition.cs.meta new file mode 100644 index 0000000..062cded --- /dev/null +++ b/Editor/Toolbar/GroupDefinitions/ScriptableGroupDefinition.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6df7c06c2de586e41bb0c33bfd80766f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Toolbar/GroupDefinitions/ScriptableGroupDefinitionHelper.cs b/Editor/Toolbar/GroupDefinitions/ScriptableGroupDefinitionHelper.cs new file mode 100644 index 0000000..6f95126 --- /dev/null +++ b/Editor/Toolbar/GroupDefinitions/ScriptableGroupDefinitionHelper.cs @@ -0,0 +1,63 @@ +using System.Collections.Generic; +using System.Linq; +using UnityEditor; + +namespace Paps.UnityToolbarExtenderUIToolkit +{ + internal static class ScriptableGroupDefinitionHelper + { + private static ScriptableGroupDefinition[] _projectGroupDefinitions; + + static ScriptableGroupDefinitionHelper() + { + LoadProjectGroupDefinitions(); + + EditorApplication.projectChanged += OnProjectChange; + } + + public static void Refresh() + { + LoadProjectGroupDefinitions(); + } + + private static void LoadProjectGroupDefinitions() + { + var paths = AssetDatabase.FindAssets("t:" + nameof(ScriptableGroupDefinition)) + .Select(guid => AssetDatabase.GUIDToAssetPath(guid)); + + _projectGroupDefinitions = paths + .Select(path => AssetDatabase.LoadAssetAtPath(path)) + .ToArray(); + } + + public static IEnumerable GetUnusedMainToolbarElementIds(IEnumerable allIds) + { + return allIds.Except(GetUsedMainToolbarElementIds()); + } + + private static IEnumerable GetUsedMainToolbarElementIds() + { + return _projectGroupDefinitions + .SelectMany(groupDefinition => groupDefinition.ToolbarElementsIds); + } + + public static IEnumerable GetGroupIds() + { + return _projectGroupDefinitions.Select(g => g.GroupId); + } + + public static IEnumerable GetEligibleGroupChildsFor(string groupId) + { + var allUsedIds = _projectGroupDefinitions.SelectMany(g => g.ToolbarElementsIds); + + return _projectGroupDefinitions.Select(g => g.GroupId) + .Where(id => !allUsedIds.Contains(id)) + .Where(id => id != groupId); + } + + private static void OnProjectChange() + { + Refresh(); + } + } +} diff --git a/Editor/Toolbar/GroupDefinitions/ScriptableGroupDefinitionHelper.cs.meta b/Editor/Toolbar/GroupDefinitions/ScriptableGroupDefinitionHelper.cs.meta new file mode 100644 index 0000000..83b04a8 --- /dev/null +++ b/Editor/Toolbar/GroupDefinitions/ScriptableGroupDefinitionHelper.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 12a0d38180307184e87497e8fbb28985 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Toolbar/GroupDefinitions/ScriptableObjectGroupDefinitionRepository.cs b/Editor/Toolbar/GroupDefinitions/ScriptableObjectGroupDefinitionRepository.cs new file mode 100644 index 0000000..f8c5d95 --- /dev/null +++ b/Editor/Toolbar/GroupDefinitions/ScriptableObjectGroupDefinitionRepository.cs @@ -0,0 +1,38 @@ +using System.Linq; +using UnityEditor; + +namespace Paps.UnityToolbarExtenderUIToolkit +{ + internal class ScriptableObjectGroupDefinitionRepository : IGroupDefinitionRepository + { + public GroupDefinition[] GetAll() + { + var paths = AssetDatabase.FindAssets("t:" + nameof(ScriptableGroupDefinition)) + .Select(guid => AssetDatabase.GUIDToAssetPath(guid)); + + return paths + .Select(path => AssetDatabase.LoadAssetAtPath(path)) + .Where(scriptableGroupDefinition => !string.IsNullOrEmpty(scriptableGroupDefinition.GroupId)) + .GroupBy(scriptableGroupDefinition => scriptableGroupDefinition.GroupId) + .Select(scriptableGroupDefinition => scriptableGroupDefinition.First()) + .Select(scriptableGroupDefinition => new GroupDefinition( + scriptableGroupDefinition.GroupId, + scriptableGroupDefinition.GroupName, + scriptableGroupDefinition.Alignment, + scriptableGroupDefinition.Order, + FilterIds(scriptableGroupDefinition) + ) + ) + .Where(m => m.ToolbarElementsIds.Length > 0) + .ToArray(); + } + + private string[] FilterIds(ScriptableGroupDefinition scriptableGroupDefinition) + { + return scriptableGroupDefinition.ToolbarElementsIds + .Where(id => !string.IsNullOrEmpty(id)) + .Distinct() + .ToArray(); + } + } +} \ No newline at end of file diff --git a/Editor/Toolbar/GroupDefinitions/ScriptableObjectGroupDefinitionRepository.cs.meta b/Editor/Toolbar/GroupDefinitions/ScriptableObjectGroupDefinitionRepository.cs.meta new file mode 100644 index 0000000..297cac0 --- /dev/null +++ b/Editor/Toolbar/GroupDefinitions/ScriptableObjectGroupDefinitionRepository.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 225393fc4d1ad744c972f3a876dce3df +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Toolbar/Helpers.meta b/Editor/Toolbar/Helpers.meta new file mode 100644 index 0000000..0714222 --- /dev/null +++ b/Editor/Toolbar/Helpers.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: efeeca875749f6d46905cc399ed76bae +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Toolbar/Helpers/GlobalActions.cs b/Editor/Toolbar/Helpers/GlobalActions.cs new file mode 100644 index 0000000..28f11d7 --- /dev/null +++ b/Editor/Toolbar/Helpers/GlobalActions.cs @@ -0,0 +1,34 @@ +using System; +using UnityEditor; + +namespace Paps.UnityToolbarExtenderUIToolkit +{ + internal static class GlobalActions + { + public static void ResetOverrides() + { + ServicesAndRepositories.MainToolbarElementOverridesRepository.Clear(); + MainToolbarAutomaticExtender.Refresh(); + } + + public static void ResetOverridesIfUserAccepts() + { + ShowDialog( + "Reset Overrides", + "You are about to reset all toolbar elements overrides.\nAre you sure you want to continue?", + "Reset", + "Cancel", + ResetOverrides + ); + } + + public static void ShowDialog(string title, string message, string okMessage, + string cancelMessage, Action onOk = null, Action onCancel = null) + { + if (EditorUtility.DisplayDialog(title, message, okMessage, cancelMessage)) + onOk?.Invoke(); + else + onCancel?.Invoke(); + } + } +} \ No newline at end of file diff --git a/Editor/Toolbar/Helpers/GlobalActions.cs.meta b/Editor/Toolbar/Helpers/GlobalActions.cs.meta new file mode 100644 index 0000000..3a3c774 --- /dev/null +++ b/Editor/Toolbar/Helpers/GlobalActions.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: bfe995773a109214db8292f8ce74d342 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Toolbar/Helpers/Icons.cs b/Editor/Toolbar/Helpers/Icons.cs new file mode 100644 index 0000000..24d5b8a --- /dev/null +++ b/Editor/Toolbar/Helpers/Icons.cs @@ -0,0 +1,18 @@ +using System; +using UnityEditor; +using UnityEngine; + +namespace Paps.UnityToolbarExtenderUIToolkit +{ + internal static class Icons + { + private static readonly Lazy VISIBILITY_ON_OVERRIDE_ICON_LAZY = + new Lazy(() => EditorGUIUtility.IconContent("animationvisibilitytoggleon").image); + + private static readonly Lazy VISIBILITY_OFF_OVERRIDE_ICON_LAZY = + new Lazy(() => EditorGUIUtility.IconContent("animationvisibilitytoggleoff").image); + + public static Texture VisibilityOnOverrideIcon => VISIBILITY_ON_OVERRIDE_ICON_LAZY.Value; + public static Texture VisibilityOffOverrideIcon => VISIBILITY_OFF_OVERRIDE_ICON_LAZY.Value; + } +} \ No newline at end of file diff --git a/Editor/Toolbar/Helpers/Icons.cs.meta b/Editor/Toolbar/Helpers/Icons.cs.meta new file mode 100644 index 0000000..64a811e --- /dev/null +++ b/Editor/Toolbar/Helpers/Icons.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 51ede7e0c6a32a74faa6298082ed29cc +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Toolbar/Helpers/MenuItems.cs b/Editor/Toolbar/Helpers/MenuItems.cs new file mode 100644 index 0000000..ca1c4f0 --- /dev/null +++ b/Editor/Toolbar/Helpers/MenuItems.cs @@ -0,0 +1,19 @@ +using UnityEditor; + +namespace Paps.UnityToolbarExtenderUIToolkit +{ + internal static class MenuItems + { + [MenuItem(ToolInfo.EDITOR_MENU_BASE + "/Refresh Toolbar Extender", priority = 1)] + public static void Refresh() + { + MainToolbarAutomaticExtender.Refresh(); + } + + [MenuItem(ToolInfo.EDITOR_MENU_BASE + "/Main Toolbar Control Panel", priority = 12)] + public static void OpenControlPanel() + { + MainToolbarControlPanelWindow.OpenWindow(); + } + } +} diff --git a/Editor/Toolbar/Helpers/MenuItems.cs.meta b/Editor/Toolbar/Helpers/MenuItems.cs.meta new file mode 100644 index 0000000..beaf989 --- /dev/null +++ b/Editor/Toolbar/Helpers/MenuItems.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a74255adbb601344cb6b565d617de6f1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Toolbar/Helpers/RefreshToolbarAutomaticExtenderOnSave.cs b/Editor/Toolbar/Helpers/RefreshToolbarAutomaticExtenderOnSave.cs new file mode 100644 index 0000000..658a389 --- /dev/null +++ b/Editor/Toolbar/Helpers/RefreshToolbarAutomaticExtenderOnSave.cs @@ -0,0 +1,39 @@ +using System; +using System.Linq; +using UnityEditor; + +namespace Paps.UnityToolbarExtenderUIToolkit +{ + internal class RefreshToolbarAutomaticExtenderOnSave : AssetModificationProcessor + { + private static string[] OnWillSaveAssets(string[] paths) + { + var groupDefinitionsAssetsPaths = AssetDatabase.FindAssets("t:" + nameof(ScriptableGroupDefinition)) + .Select(guid => AssetDatabase.GUIDToAssetPath(guid)) + .ToArray(); + + if (GroupDefinitionAssetIsBeingSaved(paths, groupDefinitionsAssetsPaths)) + { + EditorApplication.update += RefreshOneTime; + } + + return paths; + } + + private static bool GroupDefinitionAssetIsBeingSaved(string[] savingAssetsPaths, string[] groupDefinitionsAssetsPaths) + { + return savingAssetsPaths.Any(path => groupDefinitionsAssetsPaths.Contains(path)); + } + + private static void RefreshOneTime() + { + EditorApplication.update -= RefreshOneTime; + Refresh(); + } + + private static void Refresh() + { + MainToolbarAutomaticExtender.Refresh(); + } + } +} \ No newline at end of file diff --git a/Editor/Toolbar/Helpers/RefreshToolbarAutomaticExtenderOnSave.cs.meta b/Editor/Toolbar/Helpers/RefreshToolbarAutomaticExtenderOnSave.cs.meta new file mode 100644 index 0000000..966e2b3 --- /dev/null +++ b/Editor/Toolbar/Helpers/RefreshToolbarAutomaticExtenderOnSave.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e74405729947e434fb3760be36ad262e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Toolbar/Helpers/ServicesAndRepositories.cs b/Editor/Toolbar/Helpers/ServicesAndRepositories.cs new file mode 100644 index 0000000..4f8e465 --- /dev/null +++ b/Editor/Toolbar/Helpers/ServicesAndRepositories.cs @@ -0,0 +1,23 @@ +namespace Paps.UnityToolbarExtenderUIToolkit +{ + internal static class ServicesAndRepositories + { + public static IMainToolbarElementOverrideRepository MainToolbarElementOverridesRepository = + new UserSettingsFileMainToolbarElementOverrideRepository(); + + public static IGroupDefinitionRepository GroupDefinitionRepository = + new ScriptableObjectGroupDefinitionRepository(); + + public static IMainToolbarElementRepository MainToolbarElementRepository = + new ByAttributeMainToolbarElementRepository(); + + public static IValueSerializer ValueSerializer = + new UnitySerializationValueSerializer(); + + public static IMainToolbarElementVariableSerializer MainToolbarElementVariableSerializer = + new UnitySerializationMainToolbarElementVariableSerializer(ValueSerializer); + + public static IMainToolbarElementVariableRepository MainToolbarElementVariableRepository = + new UserSettingsFileMainToolbarElementVariableRepository(MainToolbarElementVariableSerializer); + } +} \ No newline at end of file diff --git a/Editor/Toolbar/Helpers/ServicesAndRepositories.cs.meta b/Editor/Toolbar/Helpers/ServicesAndRepositories.cs.meta new file mode 100644 index 0000000..0fd74ad --- /dev/null +++ b/Editor/Toolbar/Helpers/ServicesAndRepositories.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4f95a2c4cbecd4f419ae142074dbb03f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Toolbar/Helpers/ToolInfo.cs b/Editor/Toolbar/Helpers/ToolInfo.cs new file mode 100644 index 0000000..2b14392 --- /dev/null +++ b/Editor/Toolbar/Helpers/ToolInfo.cs @@ -0,0 +1,8 @@ +namespace Paps.UnityToolbarExtenderUIToolkit +{ + internal static class ToolInfo + { + public const string COMPANY_NAME = "Tools/EditorExtension/Toolbar"; + public const string EDITOR_MENU_BASE = COMPANY_NAME + "/" ; + } +} diff --git a/Editor/Toolbar/Helpers/ToolInfo.cs.meta b/Editor/Toolbar/Helpers/ToolInfo.cs.meta new file mode 100644 index 0000000..04e7a23 --- /dev/null +++ b/Editor/Toolbar/Helpers/ToolInfo.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c363bf3b832d93c45b14669aa6ae573c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Toolbar/Helpers/UnityNativeElementsIds.cs b/Editor/Toolbar/Helpers/UnityNativeElementsIds.cs new file mode 100644 index 0000000..a6ec37b --- /dev/null +++ b/Editor/Toolbar/Helpers/UnityNativeElementsIds.cs @@ -0,0 +1,120 @@ +using System.Collections.Generic; +using UnityEngine.UIElements; + +namespace Paps.UnityToolbarExtenderUIToolkit +{ + internal static class UnityNativeElementsIds + { + // ------------------- ELEMENTS TYPES --------------------- + + // LEFT + private const string ACCOUNT_DROPDOWN_TYPE_NAME = "AccountDropdown"; + private const string CLOUD_BUTTON_TYPE_NAME = "CloudButton"; + private const string VERSION_CONTROL_BUTTON_TYPE_NAME = "MainToolbarImguiContainer"; + private const string STORE_BUTTON_TYPE_NAME = "StoreButton"; + + // RIGHT + private const string LAYOUT_DROPDOWN_TYPE_NAME = "LayoutDropdown"; + private const string LAYERS_DROPDOWN_TYPE_NAME = "LayersDropdown"; + private const string SEARCH_BUTTON_TYPE_NAME = "SearchButton"; + private const string MODES_DROPDOWN_TYPE_NAME = "ModesDropdown"; + private const string PREVIEW_PACKAGES_IN_USE_DROPDOWN_TYPE_NAME = "PreviewPackagesInUseDropdown"; + private const string UNDO_BUTTON_TYPE_NAME = "UndoButton"; + private const string MULTIPLAYER_ROLE_DROPDOWN_TYPE_NAME = "MultiplayerRoleDropdown"; + + // ------------------- ELEMENTS NAMES --------------------- + + // LEFT + private const string TOOLBAR_PRODUCT_CAPTION_NAME = "ToolbarProductCaption"; + private const string ACCOUNT_DROPDOWN_ELEMENT_NAME = "AccountDropdown"; + private const string CLOUD_BUTTON_ELEMENT_NAME = "Cloud"; + + // CENTER + private const string PLAY_BUTTON_ELEMENT_NAME = "Play"; + private const string PAUSE_BUTTON_ELEMENT_NAME = "Pause"; + private const string FRAME_STEP_BUTTON_ELEMENT_NAME = "Step"; + + // RIGHT + private const string LAYOUT_DROPDOWN_ELEMENT_NAME = "LayoutDropdown"; + private const string LAYERS_DROPDOWN_ELEMENT_NAME = "LayersDropdown"; + private const string MODES_DROPDOWN_ELEMENT_NAME = "ModesDropdown"; + private const string PREVIEW_PACKAGES_IN_USE_DROPDOWN_ELEMENT_NAME = "PreviewPackagesInUseDropdown"; + private const string UNDO_BUTTON_ELEMENT_NAME = "History"; + + // ------------------- FIXED IDS --------------------- + + // LEFT + public const string TOOLBAR_PRODUCT_CAPTION = "ToolbarProductCaption"; + public const string ACCOUNT_DROPDOWN_ID = "AccountDropdown"; + public const string CLOUD_BUTTON_ID = "CloudButton"; + public const string VERSION_CONTROL_ID = "VersionControlButton"; + public const string STORE_BUTTON_ID = "StoreButton"; + + // CENTER + public const string PLAY_BUTTON_ID = "PlayButton"; + public const string PAUSE_BUTTON_ID = "PauseButton"; + public const string FRAME_STEP_BUTTON_ID = "FrameStepButton"; + + // RIGHT + public const string LAYOUT_DROPDOWN_ID = "LayoutDropdown"; + public const string LAYERS_DROPDOWN_ID = "LayersDropdown"; + public const string SEARCH_BUTTON_ID = "SearchButton"; + public const string MODES_DROPDOWN_ID = "ModesDropdown"; + public const string PREVIEW_PACKAGES_IN_USE_DROPDOWN_ID = "PreviewPackagesInUseDropdown"; + public const string UNDO_BUTTON_ID = "UndoButton"; + public const string MULTIPLAYER_ROLE_DROPDOWN = "MultiplayerRoleDropdown"; + + private static readonly Dictionary IDS_BY_TYPE = new Dictionary() + { + // LEFT + { ACCOUNT_DROPDOWN_TYPE_NAME, ACCOUNT_DROPDOWN_ID }, + { CLOUD_BUTTON_TYPE_NAME, CLOUD_BUTTON_ID }, + { VERSION_CONTROL_BUTTON_TYPE_NAME, VERSION_CONTROL_ID }, + { STORE_BUTTON_TYPE_NAME, STORE_BUTTON_ID }, + + // RIGHT + { LAYOUT_DROPDOWN_TYPE_NAME, LAYOUT_DROPDOWN_ID }, + { LAYERS_DROPDOWN_TYPE_NAME, LAYERS_DROPDOWN_ID }, + { SEARCH_BUTTON_TYPE_NAME, SEARCH_BUTTON_ID }, + { MODES_DROPDOWN_TYPE_NAME, MODES_DROPDOWN_ID }, + { PREVIEW_PACKAGES_IN_USE_DROPDOWN_TYPE_NAME, PREVIEW_PACKAGES_IN_USE_DROPDOWN_ID }, + { UNDO_BUTTON_TYPE_NAME, UNDO_BUTTON_ID }, + { MULTIPLAYER_ROLE_DROPDOWN_TYPE_NAME, MULTIPLAYER_ROLE_DROPDOWN } + }; + + private static readonly Dictionary IDS_BY_NAME = new Dictionary() + { + // LEFT + { TOOLBAR_PRODUCT_CAPTION_NAME, TOOLBAR_PRODUCT_CAPTION }, + { ACCOUNT_DROPDOWN_ELEMENT_NAME, ACCOUNT_DROPDOWN_ID }, + { CLOUD_BUTTON_ELEMENT_NAME, CLOUD_BUTTON_ID }, + + // CENTER + { PLAY_BUTTON_ELEMENT_NAME, PLAY_BUTTON_ID }, + { PAUSE_BUTTON_ELEMENT_NAME, PAUSE_BUTTON_ID }, + { FRAME_STEP_BUTTON_ELEMENT_NAME, FRAME_STEP_BUTTON_ID }, + + // RIGHT + { LAYOUT_DROPDOWN_ELEMENT_NAME, LAYOUT_DROPDOWN_ID }, + { LAYERS_DROPDOWN_ELEMENT_NAME, LAYERS_DROPDOWN_ID }, + { MODES_DROPDOWN_ELEMENT_NAME, MODES_DROPDOWN_ID }, + { PREVIEW_PACKAGES_IN_USE_DROPDOWN_ELEMENT_NAME, PREVIEW_PACKAGES_IN_USE_DROPDOWN_ID }, + { UNDO_BUTTON_ELEMENT_NAME, UNDO_BUTTON_ID }, + }; + + public static string IdOf(VisualElement visualElement) + { + var typeName = visualElement.GetType().Name; + + if(IDS_BY_TYPE.ContainsKey(typeName)) + return IDS_BY_TYPE[typeName]; + + var elementName = visualElement.name; + + if(IDS_BY_NAME.ContainsKey(elementName)) + return IDS_BY_NAME[elementName]; + + return null; + } + } +} \ No newline at end of file diff --git a/Editor/Toolbar/Helpers/UnityNativeElementsIds.cs.meta b/Editor/Toolbar/Helpers/UnityNativeElementsIds.cs.meta new file mode 100644 index 0000000..61ae332 --- /dev/null +++ b/Editor/Toolbar/Helpers/UnityNativeElementsIds.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 62370caf7a9d1274ba18d9556d83fd07 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Toolbar/Helpers/UserSettingsPrefs.cs b/Editor/Toolbar/Helpers/UserSettingsPrefs.cs new file mode 100644 index 0000000..9b8c024 --- /dev/null +++ b/Editor/Toolbar/Helpers/UserSettingsPrefs.cs @@ -0,0 +1,118 @@ +using System; +using System.Collections.Generic; +using System.IO; +using Unity.Serialization.Json; +using UnityEngine; + +namespace Paps.UnityToolbarExtenderUIToolkit +{ + public static class UserSettingsPrefs + { + private static readonly string DIRECTORY = Path.Combine(Directory.GetParent(Application.dataPath).FullName, "UserSettings/", "unity-toolbar-extender-ui-toolkit", "user-settings-prefs"); + private static readonly string FILE = Path.Combine(DIRECTORY, "user-settings-prefs.json"); + + private static Dictionary _prefs; + private static Dictionary Prefs + { + get + { + if (_prefs == null) + _prefs = Load(); + + return _prefs; + } + } + + public static void SetInt(string key, int value) + { + Prefs[key] = value; + Save(); + } + + public static void SetFloat(string key, float value) + { + Prefs[key] = value; + Save(); + } + + public static void SetDouble(string key, double value) + { + Prefs[key] = value; + Save(); + } + + public static void SetBool(string key, bool value) + { + Prefs[key] = value; + Save(); + } + + public static void SetString(string key, string value) + { + Prefs[key] = value; + Save(); + } + + public static string GetString(string key, string defaultValue = null) + { + if (Prefs.ContainsKey(key)) + return (string)Prefs[key]; + + return defaultValue; + } + + public static bool GetBool(string key, bool defaultValue = false) + { + if (Prefs.ContainsKey(key)) + return (bool)Prefs[key]; + + return defaultValue; + } + + public static int GetInt(string key, int defaultValue = 0) + { + if (Prefs.ContainsKey(key)) + return Convert.ToInt32(Prefs[key]); + + return defaultValue; + } + + public static float GetFloat(string key, float defaultValue = 0.0f) + { + if (Prefs.ContainsKey(key)) + return Convert.ToSingle(Prefs[key]); + + return defaultValue; + } + + public static double GetDouble(string key, double defaultValue = 0.0) + { + if (Prefs.ContainsKey(key)) + return Convert.ToDouble(Prefs[key]); + + return defaultValue; + } + + private static Dictionary Load() + { + if (!Directory.Exists(DIRECTORY)) + Directory.CreateDirectory(DIRECTORY); + + if (!File.Exists(FILE)) + return JsonSerialization.FromJson>("{}"); + + var json = File.ReadAllText(FILE); + + var serializedDictionary = JsonSerialization.FromJson>(json); + + return serializedDictionary; + } + + private static void Save() + { + var json = JsonSerialization.ToJson(Prefs); + + File.WriteAllText(FILE, json); + } + } +} diff --git a/Editor/Toolbar/Helpers/UserSettingsPrefs.cs.meta b/Editor/Toolbar/Helpers/UserSettingsPrefs.cs.meta new file mode 100644 index 0000000..0593120 --- /dev/null +++ b/Editor/Toolbar/Helpers/UserSettingsPrefs.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: fad7572312c85da4e80e115c63b2d164 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Toolbar/IMainToolbarElementRepository.cs b/Editor/Toolbar/IMainToolbarElementRepository.cs new file mode 100644 index 0000000..df3d199 --- /dev/null +++ b/Editor/Toolbar/IMainToolbarElementRepository.cs @@ -0,0 +1,7 @@ +namespace Paps.UnityToolbarExtenderUIToolkit +{ + internal interface IMainToolbarElementRepository + { + public MainToolbarElement[] GetAll(); + } +} \ No newline at end of file diff --git a/Editor/Toolbar/IMainToolbarElementRepository.cs.meta b/Editor/Toolbar/IMainToolbarElementRepository.cs.meta new file mode 100644 index 0000000..b120dfa --- /dev/null +++ b/Editor/Toolbar/IMainToolbarElementRepository.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b6fdece3308162d4994b872bcb838c72 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Toolbar/MainToolbar.cs b/Editor/Toolbar/MainToolbar.cs new file mode 100644 index 0000000..ff2a5dc --- /dev/null +++ b/Editor/Toolbar/MainToolbar.cs @@ -0,0 +1,88 @@ +using System; +using System.Reflection; +using UnityEditor; +using UnityEngine; +using UnityEngine.UIElements; + +namespace Paps.UnityToolbarExtenderUIToolkit +{ + [InitializeOnLoad] + public static class MainToolbar + { + private const string TOOLBAR_ROOT_ELEMENT_FIELD_NAME = "m_Root"; + private const string TOOLBAR_CENTER_CONTAINER_NAME = "ToolbarZonePlayMode"; + private const string TOOLBAR_LEFT_CONTAINER_NAME = "ToolbarZoneLeftAlign"; + private const string TOOLBAR_RIGHT_CONTAINER_NAME = "ToolbarZoneRightAlign"; + private const string TOOLBAR_PLAY_BUTTON_NAME = "Play"; + + private static Type _toolbarType = typeof(Editor).Assembly.GetType("UnityEditor.Toolbar"); + private static ScriptableObject _innerToolbarObject; + + public static event Action OnInitialized; + public static event Action OnRefresh; + + public static VisualElement UnityToolbarRoot { get; private set; } + + public static VisualElement LeftContainer { get; private set; } + public static VisualElement CenterContainer { get; private set; } + public static VisualElement RightContainer { get; private set; } + public static VisualElement PlayModeButtonsContainer { get; private set; } + + public static bool IsAvailable => _innerToolbarObject != null; + + private static bool _initialized; + + static MainToolbar() + { + EditorApplication.update -= OnUpdate; + EditorApplication.update += OnUpdate; + } + + private static void WrapNativeToolbar() + { + FindUnityToolbar(); + if (_innerToolbarObject == null) + return; + CacheNativeToolbarContainers(); + + if(!_initialized) + { + _initialized = true; + OnInitialized?.Invoke(); + } + else + OnRefresh?.Invoke(); + } + + private static void FindUnityToolbar() + { + var toolbars = Resources.FindObjectsOfTypeAll(_toolbarType); + _innerToolbarObject = toolbars.Length > 0 ? (ScriptableObject)toolbars[0] : null; + } + + private static void CacheNativeToolbarContainers() + { + var unityToolbarRootFieldInfo = _innerToolbarObject.GetType() + .GetField(TOOLBAR_ROOT_ELEMENT_FIELD_NAME, BindingFlags.NonPublic | BindingFlags.Instance); + UnityToolbarRoot = unityToolbarRootFieldInfo.GetValue(_innerToolbarObject) as VisualElement; + + LeftContainer = UnityToolbarRoot.Q(TOOLBAR_LEFT_CONTAINER_NAME); + CenterContainer = UnityToolbarRoot.Q(TOOLBAR_CENTER_CONTAINER_NAME); + RightContainer = UnityToolbarRoot.Q(TOOLBAR_RIGHT_CONTAINER_NAME); + PlayModeButtonsContainer = CenterContainer.Q(TOOLBAR_PLAY_BUTTON_NAME).parent; + } + + private static void OnUpdate() + { + if (NeedsWrap()) + { + WrapNativeToolbar(); + } + } + + private static bool NeedsWrap() + { + return _innerToolbarObject == null; + } + } +} \ No newline at end of file diff --git a/Editor/Toolbar/MainToolbar.cs.meta b/Editor/Toolbar/MainToolbar.cs.meta new file mode 100644 index 0000000..912245e --- /dev/null +++ b/Editor/Toolbar/MainToolbar.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ce77a44ce866ce34d9ce10f93b19c256 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Toolbar/MainToolbarAutomaticExtender.cs b/Editor/Toolbar/MainToolbarAutomaticExtender.cs new file mode 100644 index 0000000..2decf20 --- /dev/null +++ b/Editor/Toolbar/MainToolbarAutomaticExtender.cs @@ -0,0 +1,330 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using UnityEditor; +using UnityEngine.UIElements; +using System.Reflection; +using UnityEngine; +using UnityEditor.SceneManagement; +using UnityEngine.SceneManagement; + +namespace Paps.UnityToolbarExtenderUIToolkit +{ + [InitializeOnLoad] + public static class MainToolbarAutomaticExtender + { + private static MainToolbarElement[] _mainToolbarElements = new MainToolbarElement[0]; + private static MainToolbarElement[] _groupElements = new MainToolbarElement[0]; + private static GroupDefinition[] _groupDefinitions = new GroupDefinition[0]; + private static MainToolbarElement[] _rootElements = new MainToolbarElement[0]; + private static NativeToolbarElement[] _nativeElements = new NativeToolbarElement[0]; + private static MainToolbarElement[] _singleElements = new MainToolbarElement[0]; + private static MainToolbarElementOverrideApplier _overrideApplier = new MainToolbarElementOverrideApplier(ServicesAndRepositories.MainToolbarElementOverridesRepository); + private static Dictionary _elementsByGroup = new Dictionary(); + private static MainToolbarElementVariableWatcher _variableWatcher = new MainToolbarElementVariableWatcher(ServicesAndRepositories.MainToolbarElementVariableRepository, ServicesAndRepositories.ValueSerializer); + + internal static MainToolbarCustomContainer LeftCustomContainer { get; private set; } = new MainToolbarCustomContainer("ToolbarAutomaticExtenderLeftContainer", FlexDirection.RowReverse); + internal static MainToolbarCustomContainer RightCustomContainer { get; private set; } = new MainToolbarCustomContainer("ToolbarAutomaticExtenderRightContainer", FlexDirection.Row); + + internal static MainToolbarElement[] CustomMainToolbarElements => _mainToolbarElements.ToArray(); + internal static MainToolbarElement[] GroupElements => _groupElements.ToArray(); + internal static NativeToolbarElement[] NativeElements => _nativeElements.ToArray(); + + public static event Action OnRefresh; + public static event Action OnAddedCustomContainersToToolbar; + + static MainToolbarAutomaticExtender() + { + MainToolbar.OnInitialized += Initialize; + } + + private static void Initialize() + { + BuildCustomToolbarContainers(); + + if (_mainToolbarElements.Length == 0) + return; + + EditorApplication.projectChanged += OnProjectChange; + MainToolbar.OnRefresh += ApplyFixedChangesToToolbar; + + CacheNativeElements(); + ApplyFixedChangesToToolbar(); + } + + private static void CacheNativeElements() + { + var nativeElements = GetNativeElements(); + if (nativeElements.Length != 0) + { + _nativeElements = nativeElements; + _overrideApplier.SetNativeElements(_nativeElements); + } + } + + internal static void Refresh() + { + if (!MainToolbar.IsAvailable) + return; + + ResetCustomContainers(); + BuildCustomToolbarContainers(); + _overrideApplier.ApplyOverrides(); + OnRefresh?.Invoke(); + } + + internal static MainToolbarElement[] GetElementsOfGroup(string id) + { + return _elementsByGroup[id].ToArray(); + } + + private static void ResetCustomContainers() + { + LeftCustomContainer.ClearContainer(); + RightCustomContainer.ClearContainer(); + } + + private static void BuildCustomToolbarContainers() + { + _mainToolbarElements = ServicesAndRepositories.MainToolbarElementRepository.GetAll(); + + if (_mainToolbarElements.Count() == 0) + return; + + _groupDefinitions = LoadGroupDefinitions(); + _groupElements = GetGroups(); + _elementsByGroup = GetElementsByGroup(); + InitializeGroups(); + _singleElements = GetSingles(); + _rootElements = GetRootElements(); + _overrideApplier.SetCustomElements(_mainToolbarElements.Concat(_groupElements).ToArray()); + _variableWatcher.RestoreValues(CustomMainToolbarElements); + + InitializeCustomElements(); + RegisterElementsForRecommendedStyles(); + + AddRootElementsToContainers(); + + EditorApplication.update += Update; + } + + private static void InitializeCustomElements() + { + foreach(var customElement in CustomMainToolbarElements) + { + var typeOfElement = customElement.VisualElement.GetType(); + + var initializeMethod = typeOfElement.GetMethod("InitializeElement", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); + initializeMethod?.Invoke(customElement.VisualElement, null); + } + } + + private static void Update() + { + _variableWatcher.Update(); + } + + private static void InitializeGroups() + { + foreach (var group in _groupElements) + { + var groupElement = group.VisualElement as GroupElement; + var elementsOfThisGroup = _elementsByGroup[group.Id] + .Select(e => e.VisualElement) + .ToArray(); + + groupElement.Initialize(elementsOfThisGroup); + } + } + + private static void RegisterElementsForRecommendedStyles() + { + var eligibleElements = _mainToolbarElements + .Concat(_groupElements) + .Where(element => element.UseRecommendedStyles) + .Select(element => new RecommendedStyleVisualElement(element.VisualElement, IsInGroup(element))) + .ToArray(); + + RecommendedStyles.SetElements(eligibleElements); + } + + private static bool IsInGroup(MainToolbarElement mainToolbarElement) + { + return !_rootElements.Contains(mainToolbarElement); + } + + private static MainToolbarElement[] GetRootElements() + { + return GetRootGroups() + .Concat(_singleElements) + .ToArray(); + } + + private static MainToolbarElement[] GetRootGroups() + { + var rootGroups = new List(); + + var allGroupElements = _groupElements.Select(group => group.VisualElement as GroupElement); + + foreach (var group in _groupElements) + { + var groupElement = group.VisualElement as GroupElement; + + if (!allGroupElements.Any(g => g.GroupedElements.Contains(groupElement))) + rootGroups.Add(group); + } + + return rootGroups.ToArray(); + } + + private static NativeToolbarElement[] GetNativeElements() + { + return MainToolbar.LeftContainer.Children() + .Concat(MainToolbar.RightContainer.Children()) + .Concat(MainToolbar.PlayModeButtonsContainer.Children()) + .Where(visualElement => UnityNativeElementsIds.IdOf(visualElement) != null) + .Select(visualElement => new NativeToolbarElement(UnityNativeElementsIds.IdOf(visualElement), visualElement)) + .ToArray(); + } + + private static void ApplyFixedChangesToToolbar() + { + ConfigureStyleOfContainers(); + AddCustomContainers(); + _overrideApplier.ApplyOverrides(); + OnAddedCustomContainersToToolbar?.Invoke(); + } + + private static void AddCustomContainers() + { + MainToolbar.CenterContainer.Insert(0, LeftCustomContainer); + MainToolbar.CenterContainer.Add(RightCustomContainer); + } + + private static void AddRootElementsToContainers() + { + var leftElements = _rootElements.Where(el => el.Alignment == ToolbarAlign.Left) + .OrderBy(el => el.Order); + + var rightElements = _rootElements.Where(el => el.Alignment == ToolbarAlign.Right) + .OrderBy(el => el.Order); + + foreach (var orderedAlignedElement in leftElements) + LeftCustomContainer.AddToContainer(orderedAlignedElement.VisualElement); + + foreach (var orderedAlignedElement in rightElements) + RightCustomContainer.AddToContainer(orderedAlignedElement.VisualElement); + } + + private static MainToolbarElement[] GetGroups() + { + var groups = new List(); + + foreach (var groupDefinition in _groupDefinitions) + { + if (groupDefinition.ToolbarElementsIds.Length == 0) + continue; + + var groupToolbarElement = new MainToolbarElement( + groupDefinition.GroupId, + new GroupElement(groupDefinition.GroupName), + groupDefinition.Alignment, + groupDefinition.Order, + true + ); + + groups.Add(groupToolbarElement); + } + + return groups.ToArray(); + } + + private static MainToolbarElement[] GetSingles() + { + var elementsInGroups = _elementsByGroup.Values.SelectMany(list => list); + + return _mainToolbarElements + .Where(mainToolbarElement => !elementsInGroups.Contains(mainToolbarElement)) + .ToArray(); + } + + private static Dictionary GetElementsByGroup() + { + var elementsByGroup = new Dictionary(); + + foreach (var groupDefinition in _groupDefinitions) + { + var elementsOfThisGroup = groupDefinition.ToolbarElementsIds + .Select(id => + { + var element = _mainToolbarElements.FirstOrDefault(e => e.Id == id); + + if (element != null) + return element; + + element = _groupElements.FirstOrDefault(e => e.Id == id); + + return element; + }) + .Where(mainToolbarElement => mainToolbarElement != null) + .ToList(); + + elementsByGroup.Add(groupDefinition.GroupId, elementsOfThisGroup.ToArray()); + } + + return elementsByGroup; + } + + private static GroupDefinition[] LoadGroupDefinitions() + { + return ServicesAndRepositories.GroupDefinitionRepository.GetAll(); + } + + private static void ConfigureStyleOfContainers() + { + MainToolbar.LeftContainer.style.flexGrow = 0; + MainToolbar.LeftContainer.style.width = Length.Auto(); + + MainToolbar.RightContainer.style.flexGrow = 0; + MainToolbar.RightContainer.style.width = Length.Auto(); + + MainToolbar.CenterContainer.style.flexGrow = 1; + + MainToolbar.CenterContainer.parent.style.paddingTop = 0; + MainToolbar.CenterContainer.parent.style.paddingBottom = 0; + } + + private static void OnProjectChange() + { + if(ShouldRefresh()) + Refresh(); + } + + private static bool ShouldRefresh() + { + return GroupsChanged(); + } + + private static bool GroupsChanged() + { + var groups = ServicesAndRepositories.GroupDefinitionRepository.GetAll(); + + if (_groupDefinitions.Length != groups.Length) + return true; + + if (_groupDefinitions.Length == 0 && groups.Length == 0) + return false; + + for(int i = 0; i < _groupDefinitions.Length; i++) + { + var savedGroupDefinition = _groupDefinitions[i]; + var retrievedGroupDefinition = groups[i]; + + if (!savedGroupDefinition.AreEquals(retrievedGroupDefinition)) + return true; + } + + return false; + } + } +} \ No newline at end of file diff --git a/Editor/Toolbar/MainToolbarAutomaticExtender.cs.meta b/Editor/Toolbar/MainToolbarAutomaticExtender.cs.meta new file mode 100644 index 0000000..ec98cfa --- /dev/null +++ b/Editor/Toolbar/MainToolbarAutomaticExtender.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6fd1abb4edafb6a4793209e0f154d8a8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Toolbar/MainToolbarCustomContainer.cs b/Editor/Toolbar/MainToolbarCustomContainer.cs new file mode 100644 index 0000000..aa060bb --- /dev/null +++ b/Editor/Toolbar/MainToolbarCustomContainer.cs @@ -0,0 +1,95 @@ +using System.Linq; +using UnityEngine.UIElements; + +namespace Paps.UnityToolbarExtenderUIToolkit +{ + internal class MainToolbarCustomContainer : VisualElement + { + private const string LAST_SCROLLER_POSITION_SAVE_KEY_BASE = "main-toolbar-custom-container:last-scroller-position:"; + + private const float SCROLL_VIEW_SCROLLER_HEIGHT = 1; + private const float SCROLLER_HEIGHT = 5; + private const float SCROLL_VIEW_HORIZONTAL_PADDING = 5; + private const float SCROLL_VIEW_SCROLLER_BORDER_TOP_WIDTH = 0; + + private string _id; + private ScrollView _scrollView; + private Scroller _scroller; + private VisualElement _container; + + public MainToolbarCustomContainer(string id, FlexDirection flexDirection) + { + _id = id; + name = id; + + style.flexDirection = flexDirection; + style.flexGrow = 1; + style.width = 0; + + _container = CreateAndAddContainer(flexDirection); + } + + private VisualElement CreateAndAddContainer(FlexDirection flexDirection) + { + _scrollView = new ScrollView(ScrollViewMode.Horizontal); + + _scrollView.style.paddingLeft = SCROLL_VIEW_HORIZONTAL_PADDING; + _scrollView.style.paddingRight = SCROLL_VIEW_HORIZONTAL_PADDING; + + _scrollView.verticalScrollerVisibility = ScrollerVisibility.Hidden; + _scrollView.contentContainer.style.flexDirection = flexDirection; + + _scroller = _scrollView.horizontalScroller; + + var leftButton = _scroller.lowButton; + var rightButton = _scroller.highButton; + var slider = _scroller.slider; + + _scroller.style.height = SCROLL_VIEW_SCROLLER_HEIGHT; + _scroller.style.borderTopWidth = SCROLL_VIEW_SCROLLER_BORDER_TOP_WIDTH; + leftButton.style.height = SCROLLER_HEIGHT; + rightButton.style.height = SCROLLER_HEIGHT; + slider.style.height = SCROLLER_HEIGHT; + + Add(_scrollView); + _scrollView.RegisterCallback(LoadLastScrollerPosition); + + return _scrollView; + } + + private void LoadLastScrollerPosition(GeometryChangedEvent eventArgs) + { + _scroller.value = (float)LastScrollerPosition(); + _scroller.valueChanged += SaveScrollerPosition; + + _scrollView.UnregisterCallback(LoadLastScrollerPosition); + } + + private double LastScrollerPosition() + { + return UserSettingsPrefs.GetDouble(GetFullKey(), 0d); + } + + private void SaveScrollerPosition(float newPosition) + { + UserSettingsPrefs.SetDouble(GetFullKey(), newPosition); + } + + private string GetFullKey() => LAST_SCROLLER_POSITION_SAVE_KEY_BASE + _id; + + public void AddToContainer(VisualElement child) + { + _container.Add(child); + } + + public void ClearContainer() + { + _container.Clear(); + } + + public VisualElement[] GetContainerChilds() + { + return _container.Children().ToArray(); + } + } +} \ No newline at end of file diff --git a/Editor/Toolbar/MainToolbarCustomContainer.cs.meta b/Editor/Toolbar/MainToolbarCustomContainer.cs.meta new file mode 100644 index 0000000..94de1cc --- /dev/null +++ b/Editor/Toolbar/MainToolbarCustomContainer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3a0122c91e132b8478c5d18c85d0df6f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Toolbar/MainToolbarElement.cs b/Editor/Toolbar/MainToolbarElement.cs new file mode 100644 index 0000000..fb8d76b --- /dev/null +++ b/Editor/Toolbar/MainToolbarElement.cs @@ -0,0 +1,23 @@ +using UnityEngine.UIElements; + +namespace Paps.UnityToolbarExtenderUIToolkit +{ + internal class MainToolbarElement + { + public string Id { get; } + public VisualElement VisualElement { get; } + public ToolbarAlign Alignment { get; } + public int Order { get; } + public bool UseRecommendedStyles { get; } + + public MainToolbarElement(string id, VisualElement visualElement, + ToolbarAlign alignment, int order, bool useRecommendedStyles) + { + Id = id; + VisualElement = visualElement; + Alignment = alignment; + Order = order; + UseRecommendedStyles = useRecommendedStyles; + } + } +} \ No newline at end of file diff --git a/Editor/Toolbar/MainToolbarElement.cs.meta b/Editor/Toolbar/MainToolbarElement.cs.meta new file mode 100644 index 0000000..7da1baa --- /dev/null +++ b/Editor/Toolbar/MainToolbarElement.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f67ca04efaf7f044fa5a17a7627aca0b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Toolbar/MainToolbarElementAttribute.cs b/Editor/Toolbar/MainToolbarElementAttribute.cs new file mode 100644 index 0000000..35271bf --- /dev/null +++ b/Editor/Toolbar/MainToolbarElementAttribute.cs @@ -0,0 +1,31 @@ +using System; + +namespace Paps.UnityToolbarExtenderUIToolkit +{ + [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)] + public class MainToolbarElementAttribute : Attribute + { + public string Id { get; } + public ToolbarAlign Alignment { get; } + public int Order { get; } + public bool UseRecommendedStyles { get; } + + /// + /// Mark a class derived from VisualElement to be found by toolbar extender + /// + /// Id of element. Must be unique. In case of collision, first found is used + /// Left or right to play buttons. Ignored if inside a group + /// Order in which this element will be displayed in toolbar. Ignored if inside a group + /// True if this element should use recommended styles. Set it to false if you want to style the visual element yourself. + /// + public MainToolbarElementAttribute(string id, ToolbarAlign alignment = ToolbarAlign.Left, + int order = 0, + bool useRecommendedStyles = true) + { + Id = id; + Alignment = alignment; + Order = order; + UseRecommendedStyles = useRecommendedStyles; + } + } +} \ No newline at end of file diff --git a/Editor/Toolbar/MainToolbarElementAttribute.cs.meta b/Editor/Toolbar/MainToolbarElementAttribute.cs.meta new file mode 100644 index 0000000..952db19 --- /dev/null +++ b/Editor/Toolbar/MainToolbarElementAttribute.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d4059a4ac36791549810df04f72dcc75 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Toolbar/MainToolbarElementOverrideApplier.cs b/Editor/Toolbar/MainToolbarElementOverrideApplier.cs new file mode 100644 index 0000000..cb13938 --- /dev/null +++ b/Editor/Toolbar/MainToolbarElementOverrideApplier.cs @@ -0,0 +1,179 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using UnityEngine.UIElements; + +namespace Paps.UnityToolbarExtenderUIToolkit +{ + internal class MainToolbarElementOverrideApplier + { + private class HiddenRemovedElement + { + public VisualElement RemovedVisualElement; + public VisualElement Parent; + public int Index; + } + + private static readonly string[] EXCEPTIONAL_ELEMENTS_FOR_VISIBILITY = + { + UnityNativeElementsIds.ACCOUNT_DROPDOWN_ID, + UnityNativeElementsIds.CLOUD_BUTTON_ID + }; + private readonly IMainToolbarElementOverrideRepository _mainToolbarElementOverrideRepository; + private MainToolbarElement[] _mainToolbarElements = new MainToolbarElement[0]; + private NativeToolbarElement[] _nativeElements = new NativeToolbarElement[0]; + private readonly Dictionary _nativeElementsInitialState = new Dictionary(); + private readonly Dictionary _hiddenElementsByRemotion = new Dictionary(); + + public MainToolbarElementOverrideApplier(IMainToolbarElementOverrideRepository mainToolbarElementOverrideRepository) + { + _mainToolbarElementOverrideRepository = mainToolbarElementOverrideRepository; + } + + public void SetNativeElements(NativeToolbarElement[] nativeElements) + { + _nativeElements = nativeElements.ToArray(); + + SaveNativeElementsInitialState(); + SetNativeElementsDefaultState(); // necesito hacer esto? + } + + public void SetCustomElements(MainToolbarElement[] mainToolbarElements) + { + _mainToolbarElements = mainToolbarElements.ToArray(); + } + + public void ApplyOverrides() + { + SetNativeElementsDefaultState(); + + ApplyOverridesOnCustomElements(); + ApplyOverridesOnNativeElements(); + } + + private void ApplyOverridesOnCustomElements() + { + foreach (var mainToolbarElement in _mainToolbarElements) + { + ApplyOverride(mainToolbarElement.Id, mainToolbarElement.VisualElement); + } + } + + private void ApplyOverridesOnNativeElements() + { + foreach (var nativeElement in _nativeElements) + { + ApplyOverride(nativeElement.Id, nativeElement.VisualElement); + } + } + + private void SaveNativeElementsInitialState() + { + if (_nativeElementsInitialState.Count > 0) + return; + + foreach (var nativeElement in _nativeElements) + { + _nativeElementsInitialState[nativeElement.Id] = + new MainToolbarElementOverride( + nativeElement.Id, + nativeElement.VisualElement.resolvedStyle.display == DisplayStyle.Flex + ); + } + } + + private void SetNativeElementsDefaultState() + { + foreach (var nativeElement in _nativeElements) + { + var defaultStateOverride = _nativeElementsInitialState[nativeElement.Id]; + + ApplyOverride(nativeElement, defaultStateOverride); + } + } + + private void ApplyOverride(NativeToolbarElement nativeElement, MainToolbarElementOverride overrideData) + { + ApplyVisibilityOverride(nativeElement.Id, nativeElement.VisualElement, overrideData.Visible); + } + + private void ApplyOverride(string id, VisualElement visualElement) + { + var userOverride = _mainToolbarElementOverrideRepository + .Get(id); + + if (userOverride == null) + return; + + ApplyVisibilityOverride(id, visualElement, userOverride.Value.Visible); + } + + private void ApplyVisibilityOverride(string elementId, VisualElement visualElement, bool visible) + { + if (IsExceptionElementForVisibility(elementId)) + HandleVisibilityApplicationOnExceptions(elementId, visualElement, visible); + else + visualElement.style.display = visible ? DisplayStyle.Flex : DisplayStyle.None; + } + + private bool IsExceptionElementForVisibility(string elementId) + { + return EXCEPTIONAL_ELEMENTS_FOR_VISIBILITY.Contains(elementId); + } + + private void HandleVisibilityApplicationOnExceptions(string elementId, VisualElement visualElement, bool visible) + { + if (visible) + HandleExceptionalElementVisibleCase(elementId, visualElement); + else + HandleExceptionalElementInvisibleCase(elementId, visualElement); + } + + private void HandleExceptionalElementInvisibleCase(string elementId, VisualElement visualElement) + { + var parent = visualElement.parent; + var index = parent.IndexOf(visualElement); + + if (parent.Contains(visualElement)) + parent.Remove(visualElement); + + if (!_hiddenElementsByRemotion.ContainsKey(elementId)) + _hiddenElementsByRemotion.Add(elementId, new HiddenRemovedElement() + { + RemovedVisualElement = visualElement, + Parent = parent, + Index = index + }); + } + + private void HandleExceptionalElementVisibleCase(string elementId, VisualElement visualElement) + { + if (_hiddenElementsByRemotion.ContainsKey(elementId)) + { + var removedElement = _hiddenElementsByRemotion[elementId]; + + var parent = removedElement.Parent; + + if (!parent.Contains(visualElement)) + { + var bestIndex = GetIndexEqualOrLessThan(removedElement.Index, parent); + + parent.Insert(bestIndex, visualElement); + } + + _hiddenElementsByRemotion.Remove(elementId); + } + } + + private int GetIndexEqualOrLessThan(int removedElementIndex, VisualElement parent) + { + for (int i = parent.childCount - 1; i >= 0; i--) + { + if (removedElementIndex <= i) + return i; + } + + return 0; + } + } +} \ No newline at end of file diff --git a/Editor/Toolbar/MainToolbarElementOverrideApplier.cs.meta b/Editor/Toolbar/MainToolbarElementOverrideApplier.cs.meta new file mode 100644 index 0000000..ffd8952 --- /dev/null +++ b/Editor/Toolbar/MainToolbarElementOverrideApplier.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 24d310911f14d4d45a02bd5586c371bb +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Toolbar/NativeToolbarElement.cs b/Editor/Toolbar/NativeToolbarElement.cs new file mode 100644 index 0000000..b95a5d1 --- /dev/null +++ b/Editor/Toolbar/NativeToolbarElement.cs @@ -0,0 +1,16 @@ +using UnityEngine.UIElements; + +namespace Paps.UnityToolbarExtenderUIToolkit +{ + internal class NativeToolbarElement + { + public string Id { get; } + public VisualElement VisualElement { get; } + + public NativeToolbarElement(string id, VisualElement visualElement) + { + Id = id; + VisualElement = visualElement; + } + } +} \ No newline at end of file diff --git a/Editor/Toolbar/NativeToolbarElement.cs.meta b/Editor/Toolbar/NativeToolbarElement.cs.meta new file mode 100644 index 0000000..65bf7ba --- /dev/null +++ b/Editor/Toolbar/NativeToolbarElement.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4b9dec15dbb8eea42b0c2254ce4b7177 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Toolbar/Override.meta b/Editor/Toolbar/Override.meta new file mode 100644 index 0000000..0c09781 --- /dev/null +++ b/Editor/Toolbar/Override.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 6f722a3e209ed5649a219e2282177125 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Toolbar/Override/IMainToolbarElementOverrideRepository.cs b/Editor/Toolbar/Override/IMainToolbarElementOverrideRepository.cs new file mode 100644 index 0000000..b5e5377 --- /dev/null +++ b/Editor/Toolbar/Override/IMainToolbarElementOverrideRepository.cs @@ -0,0 +1,10 @@ +namespace Paps.UnityToolbarExtenderUIToolkit +{ + internal interface IMainToolbarElementOverrideRepository + { + public MainToolbarElementOverride? Get(string elementId); + public MainToolbarElementOverride[] GetAll(); + public void Save(MainToolbarElementOverride elementOverride); + public void Clear(); + } +} \ No newline at end of file diff --git a/Editor/Toolbar/Override/IMainToolbarElementOverrideRepository.cs.meta b/Editor/Toolbar/Override/IMainToolbarElementOverrideRepository.cs.meta new file mode 100644 index 0000000..66c1634 --- /dev/null +++ b/Editor/Toolbar/Override/IMainToolbarElementOverrideRepository.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 280c883dcd1944448a1b93cecc8877f7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Toolbar/Override/MainToolbarElementOverride.cs b/Editor/Toolbar/Override/MainToolbarElementOverride.cs new file mode 100644 index 0000000..4d16d6c --- /dev/null +++ b/Editor/Toolbar/Override/MainToolbarElementOverride.cs @@ -0,0 +1,14 @@ +namespace Paps.UnityToolbarExtenderUIToolkit +{ + internal readonly struct MainToolbarElementOverride + { + public string ElementId { get; } + public bool Visible { get; } + + public MainToolbarElementOverride(string elementId, bool visible) + { + ElementId = elementId; + Visible = visible; + } + } +} \ No newline at end of file diff --git a/Editor/Toolbar/Override/MainToolbarElementOverride.cs.meta b/Editor/Toolbar/Override/MainToolbarElementOverride.cs.meta new file mode 100644 index 0000000..d6beecb --- /dev/null +++ b/Editor/Toolbar/Override/MainToolbarElementOverride.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e51009f5c83b62f419eee2089fd6e63f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Toolbar/Override/UserSettingsFileMainToolbarElementOverrideRepository.cs b/Editor/Toolbar/Override/UserSettingsFileMainToolbarElementOverrideRepository.cs new file mode 100644 index 0000000..3429a9d --- /dev/null +++ b/Editor/Toolbar/Override/UserSettingsFileMainToolbarElementOverrideRepository.cs @@ -0,0 +1,99 @@ +using System.Collections.Generic; +using System.IO; +using System.Linq; +using Unity.Serialization.Json; +using UnityEngine; + +namespace Paps.UnityToolbarExtenderUIToolkit +{ + internal class UserSettingsFileMainToolbarElementOverrideRepository : IMainToolbarElementOverrideRepository + { + private static readonly string DIRECTORY = Path.Combine(Directory.GetParent(Application.dataPath).FullName, "UserSettings/", "unity-toolbar-extender-ui-toolkit", "overrides"); + private static readonly string FILE = Path.Combine(DIRECTORY, "overrides.json"); + + private struct SerializableOverride + { + public string ElementId; + public bool Visible; + } + + private Dictionary _overrides = new Dictionary(); + + public UserSettingsFileMainToolbarElementOverrideRepository() + { + _overrides = LoadOverrides(); + } + + public void Clear() + { + _overrides.Clear(); + DeleteSave(); + } + + public MainToolbarElementOverride? Get(string elementId) + { + if(_overrides.ContainsKey(elementId)) + return _overrides[elementId]; + + return null; + } + + public MainToolbarElementOverride[] GetAll() + { + return _overrides.Values.ToArray(); + } + + public void Save(MainToolbarElementOverride elementOverride) + { + _overrides[elementOverride.ElementId] = elementOverride; + SaveOverrides(); + } + + private MainToolbarElementOverride FromSerialized(SerializableOverride serializableOverride) + { + return new MainToolbarElementOverride(serializableOverride.ElementId, serializableOverride.Visible); + } + + private SerializableOverride ToSerialized(MainToolbarElementOverride mainToolbarElementOverride) + { + return new SerializableOverride() { + ElementId = mainToolbarElementOverride.ElementId, + Visible = mainToolbarElementOverride.Visible + }; + } + + private void DeleteSave() + { + File.Delete(FILE); + } + + private Dictionary LoadOverrides() + { + if (!Directory.Exists(DIRECTORY)) + Directory.CreateDirectory(DIRECTORY); + + if (!File.Exists(FILE)) + return JsonSerialization.FromJson>("{}"); + + var json = File.ReadAllText(FILE); + + var serializedDictionary = JsonSerialization.FromJson>(json); + + return serializedDictionary.Values + .ToDictionary(serializedOverride => serializedOverride.ElementId, + serializedOverride => FromSerialized(serializedOverride)); + } + + private void SaveOverrides() + { + var serializableDictionary = _overrides.Values.ToDictionary( + mainToolbarElementOverride => mainToolbarElementOverride.ElementId, + mainToolbarElementOverride => ToSerialized(mainToolbarElementOverride) + ); + + var json = JsonSerialization.ToJson(serializableDictionary); + + File.WriteAllText(FILE, json); + } + } +} \ No newline at end of file diff --git a/Editor/Toolbar/Override/UserSettingsFileMainToolbarElementOverrideRepository.cs.meta b/Editor/Toolbar/Override/UserSettingsFileMainToolbarElementOverrideRepository.cs.meta new file mode 100644 index 0000000..bb15f60 --- /dev/null +++ b/Editor/Toolbar/Override/UserSettingsFileMainToolbarElementOverrideRepository.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 267c04a3d47600c488137859ea7af2a9 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Toolbar/Paps.UnityToolbarExtenderUIToolkit.asmdef b/Editor/Toolbar/Paps.UnityToolbarExtenderUIToolkit.asmdef new file mode 100644 index 0000000..0217154 --- /dev/null +++ b/Editor/Toolbar/Paps.UnityToolbarExtenderUIToolkit.asmdef @@ -0,0 +1,18 @@ +{ + "name": "Paps.UnityToolbarExtenderUIToolkit", + "rootNamespace": "Paps.UnityToolbarExtenderUIToolkit", + "references": [ + "Unity.Serialization" + ], + "includePlatforms": [ + "Editor" + ], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": false, + "defineConstraints": [], + "versionDefines": [], + "noEngineReferences": false +} \ No newline at end of file diff --git a/Editor/Toolbar/Paps.UnityToolbarExtenderUIToolkit.asmdef.meta b/Editor/Toolbar/Paps.UnityToolbarExtenderUIToolkit.asmdef.meta new file mode 100644 index 0000000..e244337 --- /dev/null +++ b/Editor/Toolbar/Paps.UnityToolbarExtenderUIToolkit.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 8d62da4aabd2a19419c7378d23ea5849 +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Toolbar/RecommendedStyles.meta b/Editor/Toolbar/RecommendedStyles.meta new file mode 100644 index 0000000..07aa3a2 --- /dev/null +++ b/Editor/Toolbar/RecommendedStyles.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 21a21acb2ce38fb46bd178a11e0cc483 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Toolbar/RecommendedStyles/ButtonRecommendedStyle.cs b/Editor/Toolbar/RecommendedStyles/ButtonRecommendedStyle.cs new file mode 100644 index 0000000..d4b905d --- /dev/null +++ b/Editor/Toolbar/RecommendedStyles/ButtonRecommendedStyle.cs @@ -0,0 +1,19 @@ +using UnityEngine.UIElements; + +namespace Paps.UnityToolbarExtenderUIToolkit +{ + internal class ButtonRecommendedStyle : RecommendedStyle + { + private Button _button; + + public ButtonRecommendedStyle(Button button) + { + _button = button; + } + + protected override void ApplyRootElementStyle() + { + _button.style.overflow = Overflow.Visible; + } + } +} \ No newline at end of file diff --git a/Editor/Toolbar/RecommendedStyles/ButtonRecommendedStyle.cs.meta b/Editor/Toolbar/RecommendedStyles/ButtonRecommendedStyle.cs.meta new file mode 100644 index 0000000..b9f4863 --- /dev/null +++ b/Editor/Toolbar/RecommendedStyles/ButtonRecommendedStyle.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: dcaec52f220ee13458fa862e8f9f31b6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Toolbar/RecommendedStyles/ColorFieldRecommendedStyle.cs b/Editor/Toolbar/RecommendedStyles/ColorFieldRecommendedStyle.cs new file mode 100644 index 0000000..8732a9c --- /dev/null +++ b/Editor/Toolbar/RecommendedStyles/ColorFieldRecommendedStyle.cs @@ -0,0 +1,20 @@ +using UnityEditor.UIElements; +using UnityEngine.UIElements; + +namespace Paps.UnityToolbarExtenderUIToolkit +{ + internal class ColorFieldRecommendedStyle : RecommendedStyle + { + private readonly ColorField _colorField; + + public ColorFieldRecommendedStyle(ColorField colorField) + { + _colorField = colorField; + } + + protected override void ApplyRootElementStyle() + { + _colorField.labelElement.style.minWidth = Length.Auto(); + } + } +} \ No newline at end of file diff --git a/Editor/Toolbar/RecommendedStyles/ColorFieldRecommendedStyle.cs.meta b/Editor/Toolbar/RecommendedStyles/ColorFieldRecommendedStyle.cs.meta new file mode 100644 index 0000000..4243822 --- /dev/null +++ b/Editor/Toolbar/RecommendedStyles/ColorFieldRecommendedStyle.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ee22b5ac49a830e4a8e35f5e98b656d1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Toolbar/RecommendedStyles/DropdownFieldRecommendedStyle.cs b/Editor/Toolbar/RecommendedStyles/DropdownFieldRecommendedStyle.cs new file mode 100644 index 0000000..824d6ec --- /dev/null +++ b/Editor/Toolbar/RecommendedStyles/DropdownFieldRecommendedStyle.cs @@ -0,0 +1,27 @@ +using UnityEngine.UIElements; + +namespace Paps.UnityToolbarExtenderUIToolkit +{ + internal class DropdownFieldRecommendedStyle : RecommendedStyle + { + private DropdownField _dropdownField; + + public DropdownFieldRecommendedStyle(DropdownField dropdownField) + { + _dropdownField = dropdownField; + } + + protected override void ApplyRootElementStyle() + { + _dropdownField.labelElement.style.minWidth = Length.Auto(); + + var inputFieldIndex = 1; + + if (string.IsNullOrEmpty(_dropdownField.label)) + inputFieldIndex = 0; + + var inputElement = _dropdownField[inputFieldIndex]; + inputElement.style.overflow = Overflow.Visible; + } + } +} \ No newline at end of file diff --git a/Editor/Toolbar/RecommendedStyles/DropdownFieldRecommendedStyle.cs.meta b/Editor/Toolbar/RecommendedStyles/DropdownFieldRecommendedStyle.cs.meta new file mode 100644 index 0000000..4194266 --- /dev/null +++ b/Editor/Toolbar/RecommendedStyles/DropdownFieldRecommendedStyle.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 494f883ee1470b044a6a7dbdc7218c66 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Toolbar/RecommendedStyles/EditorToolbarDropdownRecommendedStyle.cs b/Editor/Toolbar/RecommendedStyles/EditorToolbarDropdownRecommendedStyle.cs new file mode 100644 index 0000000..7ab7d0a --- /dev/null +++ b/Editor/Toolbar/RecommendedStyles/EditorToolbarDropdownRecommendedStyle.cs @@ -0,0 +1,49 @@ +using UnityEditor.Toolbars; +using UnityEngine.UIElements; + +namespace Paps.UnityToolbarExtenderUIToolkit +{ + internal class EditorToolbarDropdownRecommendedStyle : RecommendedStyle + { + private EditorToolbarDropdown _dropdown; + + public EditorToolbarDropdownRecommendedStyle(EditorToolbarDropdown dropdown) + { + _dropdown = dropdown; + } + + protected override void ApplyInsideGroupStyle() + { + var arrowIndex = 2; + + if (string.IsNullOrEmpty(_dropdown.text)) + arrowIndex = 1; + + var arrow = _dropdown[arrowIndex]; + + _dropdown.style.flexDirection = FlexDirection.Row; + _dropdown.style.flexWrap = Wrap.NoWrap; + _dropdown.style.overflow = Overflow.Visible; + _dropdown.RemoveFromClassList("unity-toolbar-button"); + _dropdown.AddToClassList("unity-button"); + arrow.AddToClassList("unity-base-popup-field__arrow"); + } + + protected override void ApplyRootElementStyle() + { + var arrowIndex = 2; + + if (string.IsNullOrEmpty(_dropdown.text)) + arrowIndex = 1; + + var arrow = _dropdown[arrowIndex]; + + _dropdown.style.flexDirection = FlexDirection.Row; + _dropdown.style.flexWrap = Wrap.NoWrap; + _dropdown.style.overflow = StyleKeyword.Null; + _dropdown.RemoveFromClassList("unity-button"); + _dropdown.AddToClassList("unity-toolbar-button"); + arrow.RemoveFromClassList("unity-base-popup-field__arrow"); + } + } +} \ No newline at end of file diff --git a/Editor/Toolbar/RecommendedStyles/EditorToolbarDropdownRecommendedStyle.cs.meta b/Editor/Toolbar/RecommendedStyles/EditorToolbarDropdownRecommendedStyle.cs.meta new file mode 100644 index 0000000..c1e2aaa --- /dev/null +++ b/Editor/Toolbar/RecommendedStyles/EditorToolbarDropdownRecommendedStyle.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ceacb8187593d1345ac7101feedd059c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Toolbar/RecommendedStyles/EditorToolbarToggleRecommendedStyle.cs b/Editor/Toolbar/RecommendedStyles/EditorToolbarToggleRecommendedStyle.cs new file mode 100644 index 0000000..f2361e8 --- /dev/null +++ b/Editor/Toolbar/RecommendedStyles/EditorToolbarToggleRecommendedStyle.cs @@ -0,0 +1,35 @@ +using UnityEditor.Toolbars; +using UnityEngine.UIElements; +using System.Reflection; +using UnityEngine; + +namespace Paps.UnityToolbarExtenderUIToolkit +{ + internal class EditorToolbarToggleRecommendedStyle : RecommendedStyle + { + private readonly EditorToolbarToggle _toolbarToggle; + private Image _iconImageElement; + private VisualElement _checkmark; + + public EditorToolbarToggleRecommendedStyle(EditorToolbarToggle toolbarToggle) + { + _toolbarToggle = toolbarToggle; + _iconImageElement = _toolbarToggle.Q(); + _checkmark = _toolbarToggle.Query(className: "unity-toggle__checkmark"); + } + + protected override void ApplyRootElementStyle() + { + _iconImageElement.style.width = Length.Auto(); + _toolbarToggle.style.paddingLeft = 3; + } + + protected override void ApplyInsideGroupStyle() + { + _toolbarToggle.AddToClassList("unity-button"); + _toolbarToggle.RemoveFromClassList("unity-toolbar-toggle"); + _toolbarToggle.RemoveFromClassList("unity-editor-toolbar-toggle"); + _checkmark.style.display = DisplayStyle.None; + } + } +} \ No newline at end of file diff --git a/Editor/Toolbar/RecommendedStyles/EditorToolbarToggleRecommendedStyle.cs.meta b/Editor/Toolbar/RecommendedStyles/EditorToolbarToggleRecommendedStyle.cs.meta new file mode 100644 index 0000000..2f64b7f --- /dev/null +++ b/Editor/Toolbar/RecommendedStyles/EditorToolbarToggleRecommendedStyle.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1397116b676f4994c8458c8ca852d7dc +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Toolbar/RecommendedStyles/EnumFieldRecommendedStyle.cs b/Editor/Toolbar/RecommendedStyles/EnumFieldRecommendedStyle.cs new file mode 100644 index 0000000..9fd80c2 --- /dev/null +++ b/Editor/Toolbar/RecommendedStyles/EnumFieldRecommendedStyle.cs @@ -0,0 +1,27 @@ +using UnityEngine.UIElements; + +namespace Paps.UnityToolbarExtenderUIToolkit +{ + internal class EnumFieldRecommendedStyle : RecommendedStyle + { + private EnumField _enumField; + + public EnumFieldRecommendedStyle(EnumField enumField) + { + _enumField = enumField; + } + + protected override void ApplyRootElementStyle() + { + _enumField.labelElement.style.minWidth = Length.Auto(); + + var inputFieldIndex = 1; + + if (string.IsNullOrEmpty(_enumField.label)) + inputFieldIndex = 0; + + var inputElement = _enumField[inputFieldIndex]; + inputElement.style.overflow = Overflow.Visible; + } + } +} \ No newline at end of file diff --git a/Editor/Toolbar/RecommendedStyles/EnumFieldRecommendedStyle.cs.meta b/Editor/Toolbar/RecommendedStyles/EnumFieldRecommendedStyle.cs.meta new file mode 100644 index 0000000..8a3069f --- /dev/null +++ b/Editor/Toolbar/RecommendedStyles/EnumFieldRecommendedStyle.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d96e8ee8678283341916b37ef64659a9 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Toolbar/RecommendedStyles/EnumFlagsFieldRecommendedStyle.cs b/Editor/Toolbar/RecommendedStyles/EnumFlagsFieldRecommendedStyle.cs new file mode 100644 index 0000000..20c7663 --- /dev/null +++ b/Editor/Toolbar/RecommendedStyles/EnumFlagsFieldRecommendedStyle.cs @@ -0,0 +1,34 @@ +using UnityEditor.UIElements; +using UnityEngine.UIElements; + +namespace Paps.UnityToolbarExtenderUIToolkit +{ + internal class EnumFlagsFieldRecommendedStyle : RecommendedStyle + { + private EnumFlagsField _enumField; + + public EnumFlagsFieldRecommendedStyle(EnumFlagsField enumField) + { + _enumField = enumField; + } + + protected override void ApplyRootElementStyle() + { + _enumField.labelElement.style.minWidth = Length.Auto(); + + var inputFieldIndex = 1; + + if (string.IsNullOrEmpty(_enumField.label)) + inputFieldIndex = 0; + + var inputElement = _enumField[inputFieldIndex]; + inputElement.style.overflow = Overflow.Visible; + inputElement.style.minWidth = 120; + } + + protected override void ApplyInsideGroupStyle() + { + _enumField.style.flexGrow = 1; + } + } +} \ No newline at end of file diff --git a/Editor/Toolbar/RecommendedStyles/EnumFlagsFieldRecommendedStyle.cs.meta b/Editor/Toolbar/RecommendedStyles/EnumFlagsFieldRecommendedStyle.cs.meta new file mode 100644 index 0000000..0a98d2a --- /dev/null +++ b/Editor/Toolbar/RecommendedStyles/EnumFlagsFieldRecommendedStyle.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: bb3b70fed4d19e84394fb93b4e4417aa +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Toolbar/RecommendedStyles/FloatFieldRecommendedStyle.cs b/Editor/Toolbar/RecommendedStyles/FloatFieldRecommendedStyle.cs new file mode 100644 index 0000000..37fe638 --- /dev/null +++ b/Editor/Toolbar/RecommendedStyles/FloatFieldRecommendedStyle.cs @@ -0,0 +1,30 @@ +using UnityEngine.UIElements; + +namespace Paps.UnityToolbarExtenderUIToolkit +{ + internal class FloatFieldRecommendedStyle : RecommendedStyle + { + private const int MIN_WIDTH = 80; + + private FloatField _floatField; + + public FloatFieldRecommendedStyle(FloatField floatField) + { + _floatField = floatField; + } + + protected override void ApplyRootElementStyle() + { + var inputFieldIndex = 1; + + if (string.IsNullOrEmpty(_floatField.label)) + inputFieldIndex = 0; + + var inputElement = _floatField[inputFieldIndex]; + + _floatField.labelElement.style.minWidth = Length.Auto(); + inputElement.style.minWidth = MIN_WIDTH; + inputElement.style.overflow = Overflow.Visible; + } + } +} \ No newline at end of file diff --git a/Editor/Toolbar/RecommendedStyles/FloatFieldRecommendedStyle.cs.meta b/Editor/Toolbar/RecommendedStyles/FloatFieldRecommendedStyle.cs.meta new file mode 100644 index 0000000..7915d36 --- /dev/null +++ b/Editor/Toolbar/RecommendedStyles/FloatFieldRecommendedStyle.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1886e6235603764499ce2f621b0104e1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Toolbar/RecommendedStyles/IntegerFieldRecommendedStyle.cs b/Editor/Toolbar/RecommendedStyles/IntegerFieldRecommendedStyle.cs new file mode 100644 index 0000000..b497596 --- /dev/null +++ b/Editor/Toolbar/RecommendedStyles/IntegerFieldRecommendedStyle.cs @@ -0,0 +1,31 @@ +using UnityEngine; +using UnityEngine.UIElements; + +namespace Paps.UnityToolbarExtenderUIToolkit +{ + internal class IntegerFieldRecommendedStyle : RecommendedStyle + { + private const int MIN_WIDTH = 80; + + private IntegerField _integerField; + + public IntegerFieldRecommendedStyle(IntegerField integerField) + { + _integerField = integerField; + } + + protected override void ApplyRootElementStyle() + { + var inputFieldIndex = 1; + + if(string.IsNullOrEmpty(_integerField.label)) + inputFieldIndex = 0; + + var inputElement = _integerField[inputFieldIndex]; + + _integerField.labelElement.style.minWidth = Length.Auto(); + inputElement.style.minWidth = MIN_WIDTH; + inputElement.style.overflow = Overflow.Visible; + } + } +} \ No newline at end of file diff --git a/Editor/Toolbar/RecommendedStyles/IntegerFieldRecommendedStyle.cs.meta b/Editor/Toolbar/RecommendedStyles/IntegerFieldRecommendedStyle.cs.meta new file mode 100644 index 0000000..42a928b --- /dev/null +++ b/Editor/Toolbar/RecommendedStyles/IntegerFieldRecommendedStyle.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e985a178fb9e7144997ea894be45f69c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Toolbar/RecommendedStyles/LayerFieldRecommendedStyle.cs b/Editor/Toolbar/RecommendedStyles/LayerFieldRecommendedStyle.cs new file mode 100644 index 0000000..1ef3532 --- /dev/null +++ b/Editor/Toolbar/RecommendedStyles/LayerFieldRecommendedStyle.cs @@ -0,0 +1,28 @@ +using UnityEditor.UIElements; +using UnityEngine.UIElements; + +namespace Paps.UnityToolbarExtenderUIToolkit +{ + internal class LayerFieldRecommendedStyle : RecommendedStyle + { + private readonly LayerField _layerField; + + public LayerFieldRecommendedStyle(LayerField layerField) + { + _layerField = layerField; + } + + protected override void ApplyRootElementStyle() + { + _layerField.labelElement.style.minWidth = Length.Auto(); + + var inputFieldIndex = 1; + + if (string.IsNullOrEmpty(_layerField.label)) + inputFieldIndex = 0; + + var inputElement = _layerField[inputFieldIndex]; + inputElement.style.overflow = Overflow.Visible; + } + } +} \ No newline at end of file diff --git a/Editor/Toolbar/RecommendedStyles/LayerFieldRecommendedStyle.cs.meta b/Editor/Toolbar/RecommendedStyles/LayerFieldRecommendedStyle.cs.meta new file mode 100644 index 0000000..d04d1bf --- /dev/null +++ b/Editor/Toolbar/RecommendedStyles/LayerFieldRecommendedStyle.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2d1af6dea50217644b547fb52bf5c06d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Toolbar/RecommendedStyles/ObjectFieldRecommendedStyle.cs b/Editor/Toolbar/RecommendedStyles/ObjectFieldRecommendedStyle.cs new file mode 100644 index 0000000..92420ae --- /dev/null +++ b/Editor/Toolbar/RecommendedStyles/ObjectFieldRecommendedStyle.cs @@ -0,0 +1,28 @@ +using UnityEditor.UIElements; +using UnityEngine.UIElements; + +namespace Paps.UnityToolbarExtenderUIToolkit +{ + internal class ObjectFieldRecommendedStyle : RecommendedStyle + { + private ObjectField _objectField; + + public ObjectFieldRecommendedStyle(ObjectField objectField) + { + _objectField = objectField; + } + + protected override void ApplyRootElementStyle() + { + _objectField.labelElement.style.minWidth = Length.Auto(); + + var inputFieldIndex = 1; + + if (string.IsNullOrEmpty(_objectField.label)) + inputFieldIndex = 0; + + var inputElement = _objectField[inputFieldIndex]; + inputElement.style.overflow = Overflow.Visible; + } + } +} \ No newline at end of file diff --git a/Editor/Toolbar/RecommendedStyles/ObjectFieldRecommendedStyle.cs.meta b/Editor/Toolbar/RecommendedStyles/ObjectFieldRecommendedStyle.cs.meta new file mode 100644 index 0000000..6a35420 --- /dev/null +++ b/Editor/Toolbar/RecommendedStyles/ObjectFieldRecommendedStyle.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4867ef570d5dc0d4aa440c808aa8b8cb +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Toolbar/RecommendedStyles/RecommendedStyle.cs b/Editor/Toolbar/RecommendedStyles/RecommendedStyle.cs new file mode 100644 index 0000000..1a5fe01 --- /dev/null +++ b/Editor/Toolbar/RecommendedStyles/RecommendedStyle.cs @@ -0,0 +1,16 @@ +namespace Paps.UnityToolbarExtenderUIToolkit +{ + internal abstract class RecommendedStyle + { + public void Apply(bool isInsideGroup) + { + if (isInsideGroup) + ApplyInsideGroupStyle(); + else + ApplyRootElementStyle(); + } + + protected virtual void ApplyRootElementStyle() { } + protected virtual void ApplyInsideGroupStyle() { } + } +} \ No newline at end of file diff --git a/Editor/Toolbar/RecommendedStyles/RecommendedStyle.cs.meta b/Editor/Toolbar/RecommendedStyles/RecommendedStyle.cs.meta new file mode 100644 index 0000000..305daf7 --- /dev/null +++ b/Editor/Toolbar/RecommendedStyles/RecommendedStyle.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5f26f22147430fd489504b39ee8b4701 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Toolbar/RecommendedStyles/RecommendedStyleVisualElement.cs b/Editor/Toolbar/RecommendedStyles/RecommendedStyleVisualElement.cs new file mode 100644 index 0000000..0cc16fa --- /dev/null +++ b/Editor/Toolbar/RecommendedStyles/RecommendedStyleVisualElement.cs @@ -0,0 +1,16 @@ +using UnityEngine.UIElements; + +namespace Paps.UnityToolbarExtenderUIToolkit +{ + internal class RecommendedStyleVisualElement + { + public VisualElement VisualElement { get; } + public bool IsInsideGroup { get; } + + public RecommendedStyleVisualElement(VisualElement visualElement, bool isInsideGroup) + { + VisualElement = visualElement; + IsInsideGroup = isInsideGroup; + } + } +} \ No newline at end of file diff --git a/Editor/Toolbar/RecommendedStyles/RecommendedStyleVisualElement.cs.meta b/Editor/Toolbar/RecommendedStyles/RecommendedStyleVisualElement.cs.meta new file mode 100644 index 0000000..88b25e3 --- /dev/null +++ b/Editor/Toolbar/RecommendedStyles/RecommendedStyleVisualElement.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c7fa52a9eb868af459e137032102136d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Toolbar/RecommendedStyles/RecommendedStyles.cs b/Editor/Toolbar/RecommendedStyles/RecommendedStyles.cs new file mode 100644 index 0000000..bdbef7c --- /dev/null +++ b/Editor/Toolbar/RecommendedStyles/RecommendedStyles.cs @@ -0,0 +1,93 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using UnityEditor.Toolbars; +using UnityEditor.UIElements; +using UnityEngine; +using UnityEngine.UIElements; + +namespace Paps.UnityToolbarExtenderUIToolkit +{ + internal static class RecommendedStyles + { + private static Dictionary _recommendedStyles = new Dictionary(); + + public static void SetElements(RecommendedStyleVisualElement[] elements) + { + _recommendedStyles.Clear(); + + foreach(var element in elements) + { + var recommendedStyle = GetRecommendedStyleFor(element.VisualElement); + + if (recommendedStyle == null) + continue; + + element.VisualElement.RegisterCallback(ApplyRecommendedStyle); + _recommendedStyles.Add(element, recommendedStyle); + } + } + + private static void ApplyRecommendedStyle(AttachToPanelEvent eventArgs) + { + var visualElement = eventArgs.target as VisualElement; + + var key = _recommendedStyles.Keys.FirstOrDefault(key => key.VisualElement == visualElement); + + ApplySafely(key); + } + + private static void ApplySafely(RecommendedStyleVisualElement key) + { + try + { + _recommendedStyles[key].Apply(key.IsInsideGroup); + } + catch(Exception e) + { + Debug.LogWarning("An exception ocurred when trying to apply recommended styles"); + Debug.LogException(e); + } + } + + private static RecommendedStyle GetRecommendedStyleFor(VisualElement visualElement) + { + if (visualElement is not EditorToolbarToggle && visualElement is Toggle toggle) + return new ToggleRecommendedStyle(toggle); + else if (visualElement is not EditorToolbarButton && visualElement is Button button) + return new ButtonRecommendedStyle(button); + else if (visualElement is Slider slider) + return new SliderRecommendedStyle(slider); + else if (visualElement is DropdownField dropdownField) + return new DropdownFieldRecommendedStyle(dropdownField); + else if (visualElement is EditorToolbarDropdown dropdown) + return new EditorToolbarDropdownRecommendedStyle(dropdown); + else if (visualElement is IntegerField integerField) + return new IntegerFieldRecommendedStyle(integerField); + else if (visualElement is FloatField floatField) + return new FloatFieldRecommendedStyle(floatField); + else if (visualElement is TextField textField) + return new TextFieldRecommendedStyle(textField); + else if (visualElement is EditorToolbarToggle toolbarToggle) + return new EditorToolbarToggleRecommendedStyle(toolbarToggle); + else if (visualElement is Vector3Field vector3Field) + return new Vector3FieldRecommendedStyle(vector3Field); + else if (visualElement is Vector2Field vector2Field) + return new Vector2FieldRecommendedStyle(vector2Field); + else if (visualElement is ColorField colorField) + return new ColorFieldRecommendedStyle(colorField); + else if (visualElement is LayerField layerField) + return new LayerFieldRecommendedStyle(layerField); + else if (visualElement is EnumField enumField) + return new EnumFieldRecommendedStyle(enumField); + else if (visualElement is TagField tagField) + return new TagFieldRecommendedStyle(tagField); + else if (visualElement is ObjectField objectField) + return new ObjectFieldRecommendedStyle(objectField); + else if (visualElement is EnumFlagsField enumFlagsField) + return new EnumFlagsFieldRecommendedStyle(enumFlagsField); + + return null; + } + } +} \ No newline at end of file diff --git a/Editor/Toolbar/RecommendedStyles/RecommendedStyles.cs.meta b/Editor/Toolbar/RecommendedStyles/RecommendedStyles.cs.meta new file mode 100644 index 0000000..35ec40c --- /dev/null +++ b/Editor/Toolbar/RecommendedStyles/RecommendedStyles.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 716c417d45185ed49880601a82aa7ce3 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Toolbar/RecommendedStyles/SliderRecommendedStyle.cs b/Editor/Toolbar/RecommendedStyles/SliderRecommendedStyle.cs new file mode 100644 index 0000000..ac8eddc --- /dev/null +++ b/Editor/Toolbar/RecommendedStyles/SliderRecommendedStyle.cs @@ -0,0 +1,29 @@ +using UnityEngine.UIElements; + +namespace Paps.UnityToolbarExtenderUIToolkit +{ + internal class SliderRecommendedStyle : RecommendedStyle + { + private const float MIN_WIDTH = 200; + + private readonly Slider _slider; + + public SliderRecommendedStyle(Slider slider) + { + _slider = slider; + } + + protected override void ApplyInsideGroupStyle() + { + _slider.style.flexWrap = Wrap.NoWrap; + _slider.style.flexShrink = 1; + } + + protected override void ApplyRootElementStyle() + { + _slider.labelElement.style.minWidth = 0; + _slider.style.minWidth = MIN_WIDTH; + _slider.style.flexShrink = 0; + } + } +} \ No newline at end of file diff --git a/Editor/Toolbar/RecommendedStyles/SliderRecommendedStyle.cs.meta b/Editor/Toolbar/RecommendedStyles/SliderRecommendedStyle.cs.meta new file mode 100644 index 0000000..bb1da62 --- /dev/null +++ b/Editor/Toolbar/RecommendedStyles/SliderRecommendedStyle.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5d17fd66cf40a264298b8233ece34e5d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Toolbar/RecommendedStyles/TagFieldRecommendedStyle.cs b/Editor/Toolbar/RecommendedStyles/TagFieldRecommendedStyle.cs new file mode 100644 index 0000000..0574cc6 --- /dev/null +++ b/Editor/Toolbar/RecommendedStyles/TagFieldRecommendedStyle.cs @@ -0,0 +1,28 @@ +using UnityEditor.UIElements; +using UnityEngine.UIElements; + +namespace Paps.UnityToolbarExtenderUIToolkit +{ + internal class TagFieldRecommendedStyle : RecommendedStyle + { + private TagField _tagField; + + public TagFieldRecommendedStyle(TagField tagField) + { + _tagField = tagField; + } + + protected override void ApplyRootElementStyle() + { + _tagField.labelElement.style.minWidth = Length.Auto(); + + var inputFieldIndex = 1; + + if (string.IsNullOrEmpty(_tagField.label)) + inputFieldIndex = 0; + + var inputElement = _tagField[inputFieldIndex]; + inputElement.style.overflow = Overflow.Visible; + } + } +} \ No newline at end of file diff --git a/Editor/Toolbar/RecommendedStyles/TagFieldRecommendedStyle.cs.meta b/Editor/Toolbar/RecommendedStyles/TagFieldRecommendedStyle.cs.meta new file mode 100644 index 0000000..9dd6bd8 --- /dev/null +++ b/Editor/Toolbar/RecommendedStyles/TagFieldRecommendedStyle.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0bb992cea63cc3b4a8bb869531fa8d11 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Toolbar/RecommendedStyles/TextFieldRecommendedStyle.cs b/Editor/Toolbar/RecommendedStyles/TextFieldRecommendedStyle.cs new file mode 100644 index 0000000..bef7b24 --- /dev/null +++ b/Editor/Toolbar/RecommendedStyles/TextFieldRecommendedStyle.cs @@ -0,0 +1,30 @@ +using UnityEngine.UIElements; + +namespace Paps.UnityToolbarExtenderUIToolkit +{ + internal class TextFieldRecommendedStyle : RecommendedStyle + { + private const int MIN_WIDTH = 120; + + private TextField _textField; + + public TextFieldRecommendedStyle(TextField textField) + { + _textField = textField; + } + + protected override void ApplyRootElementStyle() + { + var inputFieldIndex = 1; + + if (string.IsNullOrEmpty(_textField.label)) + inputFieldIndex = 0; + + var inputElement = _textField[inputFieldIndex]; + + _textField.labelElement.style.minWidth = Length.Auto(); + inputElement.style.minWidth = MIN_WIDTH; + inputElement.style.overflow = Overflow.Visible; + } + } +} \ No newline at end of file diff --git a/Editor/Toolbar/RecommendedStyles/TextFieldRecommendedStyle.cs.meta b/Editor/Toolbar/RecommendedStyles/TextFieldRecommendedStyle.cs.meta new file mode 100644 index 0000000..0c63798 --- /dev/null +++ b/Editor/Toolbar/RecommendedStyles/TextFieldRecommendedStyle.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 34fd75b876b07474eb077487a678ff0e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Toolbar/RecommendedStyles/ToggleRecommendedStyle.cs b/Editor/Toolbar/RecommendedStyles/ToggleRecommendedStyle.cs new file mode 100644 index 0000000..86caeb6 --- /dev/null +++ b/Editor/Toolbar/RecommendedStyles/ToggleRecommendedStyle.cs @@ -0,0 +1,19 @@ +using UnityEngine.UIElements; + +namespace Paps.UnityToolbarExtenderUIToolkit +{ + internal class ToggleRecommendedStyle : RecommendedStyle + { + private Toggle _toggle; + + public ToggleRecommendedStyle(Toggle toggle) + { + _toggle = toggle; + } + + protected override void ApplyRootElementStyle() + { + _toggle.labelElement.style.minWidth = 0; + } + } +} \ No newline at end of file diff --git a/Editor/Toolbar/RecommendedStyles/ToggleRecommendedStyle.cs.meta b/Editor/Toolbar/RecommendedStyles/ToggleRecommendedStyle.cs.meta new file mode 100644 index 0000000..b003c10 --- /dev/null +++ b/Editor/Toolbar/RecommendedStyles/ToggleRecommendedStyle.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d7af66ce1efeb9645835121aad8c63d4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Toolbar/RecommendedStyles/Vector2FieldRecommendedStyle.cs b/Editor/Toolbar/RecommendedStyles/Vector2FieldRecommendedStyle.cs new file mode 100644 index 0000000..2bd3442 --- /dev/null +++ b/Editor/Toolbar/RecommendedStyles/Vector2FieldRecommendedStyle.cs @@ -0,0 +1,59 @@ +using System.Linq; +using UnityEngine.UIElements; + +namespace Paps.UnityToolbarExtenderUIToolkit +{ + internal class Vector2FieldRecommendedStyle : RecommendedStyle + { + private const int SINGLE_FIELD_MIN_WIDTH = 80; + + private readonly Vector2Field _vector2Field; + + public Vector2FieldRecommendedStyle(Vector2Field vector2Field) + { + _vector2Field = vector2Field; + } + + protected override void ApplyRootElementStyle() + { + _vector2Field.labelElement.style.minWidth = Length.Auto(); + + var inputFieldsParentElement = GetInputFieldsParentElement(); + + foreach (var child in inputFieldsParentElement.Children().Where(childElement => childElement is FloatField)) + { + var inputFieldElementIndex = 1; + + var inputFieldElement = child[inputFieldElementIndex]; + + inputFieldElement.style.overflow = Overflow.Visible; + inputFieldElement.style.minWidth = SINGLE_FIELD_MIN_WIDTH; + } + + var spacerElement = inputFieldsParentElement.Children().Last(); + + spacerElement.style.flexGrow = 0; + } + + protected override void ApplyInsideGroupStyle() + { + var inputFieldsParentElement = GetInputFieldsParentElement(); + + inputFieldsParentElement.style.flexWrap = Wrap.Wrap; + + var spacerElement = inputFieldsParentElement.Children().Last(); + + spacerElement.style.flexGrow = 0; + } + + private VisualElement GetInputFieldsParentElement() + { + var inputFieldsParentIndex = 1; + + if (string.IsNullOrEmpty(_vector2Field.label)) + inputFieldsParentIndex = 0; + + return _vector2Field[inputFieldsParentIndex]; + } + } +} \ No newline at end of file diff --git a/Editor/Toolbar/RecommendedStyles/Vector2FieldRecommendedStyle.cs.meta b/Editor/Toolbar/RecommendedStyles/Vector2FieldRecommendedStyle.cs.meta new file mode 100644 index 0000000..f662b73 --- /dev/null +++ b/Editor/Toolbar/RecommendedStyles/Vector2FieldRecommendedStyle.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d74598c0b3338b540a340e16719351b2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Toolbar/RecommendedStyles/Vector3FieldRecommendedStyle.cs b/Editor/Toolbar/RecommendedStyles/Vector3FieldRecommendedStyle.cs new file mode 100644 index 0000000..613a4c3 --- /dev/null +++ b/Editor/Toolbar/RecommendedStyles/Vector3FieldRecommendedStyle.cs @@ -0,0 +1,50 @@ +using UnityEngine.UIElements; + +namespace Paps.UnityToolbarExtenderUIToolkit +{ + internal class Vector3FieldRecommendedStyle : RecommendedStyle + { + private const int SINGLE_FIELD_MIN_WIDTH = 80; + + private readonly Vector3Field _vector3Field; + + public Vector3FieldRecommendedStyle(Vector3Field vector3Field) + { + _vector3Field = vector3Field; + } + + protected override void ApplyRootElementStyle() + { + _vector3Field.labelElement.style.minWidth = Length.Auto(); + + var inputFieldsParentElement = GetInputFieldsParentElement(); + + foreach(var floatField in inputFieldsParentElement.Children()) + { + var inputFieldElementIndex = 1; + + var inputFieldElement = floatField[inputFieldElementIndex]; + + inputFieldElement.style.overflow = Overflow.Visible; + inputFieldElement.style.minWidth = SINGLE_FIELD_MIN_WIDTH; + } + } + + protected override void ApplyInsideGroupStyle() + { + var inputFieldsParentElement = GetInputFieldsParentElement(); + + inputFieldsParentElement.style.flexWrap = Wrap.Wrap; + } + + private VisualElement GetInputFieldsParentElement() + { + var inputFieldsParentIndex = 1; + + if (string.IsNullOrEmpty(_vector3Field.label)) + inputFieldsParentIndex = 0; + + return _vector3Field[inputFieldsParentIndex]; + } + } +} \ No newline at end of file diff --git a/Editor/Toolbar/RecommendedStyles/Vector3FieldRecommendedStyle.cs.meta b/Editor/Toolbar/RecommendedStyles/Vector3FieldRecommendedStyle.cs.meta new file mode 100644 index 0000000..b96db90 --- /dev/null +++ b/Editor/Toolbar/RecommendedStyles/Vector3FieldRecommendedStyle.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ca6000716cd684f44ac44154a65f9653 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Toolbar/SerializableValues.meta b/Editor/Toolbar/SerializableValues.meta new file mode 100644 index 0000000..eae14c6 --- /dev/null +++ b/Editor/Toolbar/SerializableValues.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: da7391b8db06da04394d88ad292f12d1 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Toolbar/SerializableValues/ElementVariables.cs b/Editor/Toolbar/SerializableValues/ElementVariables.cs new file mode 100644 index 0000000..6d5d166 --- /dev/null +++ b/Editor/Toolbar/SerializableValues/ElementVariables.cs @@ -0,0 +1,33 @@ +using UnityEngine; + +namespace Paps.UnityToolbarExtenderUIToolkit +{ + internal class ElementVariables + { + public MainToolbarElement MainToolbarElement; + public FieldVariable[] Fields; + public PropertyVariable[] Properties; + + public bool DidChange() + { + foreach (var field in Fields) + if (field.DidChange()) + return true; + + foreach (var property in Properties) + if (property.DidChange()) + return true; + + return false; + } + + public void UpdateValues() + { + foreach (var field in Fields) + field.UpdateValue(); + + foreach (var property in Properties) + property.UpdateValue(); + } + } +} diff --git a/Editor/Toolbar/SerializableValues/ElementVariables.cs.meta b/Editor/Toolbar/SerializableValues/ElementVariables.cs.meta new file mode 100644 index 0000000..2f4c421 --- /dev/null +++ b/Editor/Toolbar/SerializableValues/ElementVariables.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1fd7c94aebc6703448efe6f6e8e899aa +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Toolbar/SerializableValues/FieldVariable.cs b/Editor/Toolbar/SerializableValues/FieldVariable.cs new file mode 100644 index 0000000..fadfd14 --- /dev/null +++ b/Editor/Toolbar/SerializableValues/FieldVariable.cs @@ -0,0 +1,25 @@ +using System.Reflection; + +namespace Paps.UnityToolbarExtenderUIToolkit +{ + internal class FieldVariable : Variable + { + public readonly FieldInfo Field; + + public FieldVariable(MainToolbarElement element, FieldInfo field, IValueSerializer valueSerializer, SerializeAttribute attribute) + : base(element, field.FieldType, field.GetValue(element.VisualElement), valueSerializer, attribute) + { + Field = field; + } + + public override object Get() + { + return Field.GetValue(Element.VisualElement); + } + + public override void Set(object value) + { + Field.SetValue(Element.VisualElement, value); + } + } +} diff --git a/Editor/Toolbar/SerializableValues/FieldVariable.cs.meta b/Editor/Toolbar/SerializableValues/FieldVariable.cs.meta new file mode 100644 index 0000000..685b510 --- /dev/null +++ b/Editor/Toolbar/SerializableValues/FieldVariable.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 52b93a1d12abcdd43ad8862697bad9ef +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Toolbar/SerializableValues/IMainToolbarElementVariableRepository.cs b/Editor/Toolbar/SerializableValues/IMainToolbarElementVariableRepository.cs new file mode 100644 index 0000000..43b739b --- /dev/null +++ b/Editor/Toolbar/SerializableValues/IMainToolbarElementVariableRepository.cs @@ -0,0 +1,10 @@ +namespace Paps.UnityToolbarExtenderUIToolkit +{ + internal interface IMainToolbarElementVariableRepository + { + public void Set(SerializableElement serializableElement); + public void SetAll(SerializableElement[] serializableElements); + public SerializableElement[] GetAll(); + public void Save(); + } +} diff --git a/Editor/Toolbar/SerializableValues/IMainToolbarElementVariableRepository.cs.meta b/Editor/Toolbar/SerializableValues/IMainToolbarElementVariableRepository.cs.meta new file mode 100644 index 0000000..d83d5a1 --- /dev/null +++ b/Editor/Toolbar/SerializableValues/IMainToolbarElementVariableRepository.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: cc3941d2eca2d2f4ea42787117a4bd40 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Toolbar/SerializableValues/IMainToolbarElementVariableSerializer.cs b/Editor/Toolbar/SerializableValues/IMainToolbarElementVariableSerializer.cs new file mode 100644 index 0000000..b18de2e --- /dev/null +++ b/Editor/Toolbar/SerializableValues/IMainToolbarElementVariableSerializer.cs @@ -0,0 +1,8 @@ +namespace Paps.UnityToolbarExtenderUIToolkit +{ + internal interface IMainToolbarElementVariableSerializer + { + public string Serialize(SerializableElementGroup serializableElementGroup); + public SerializableElementGroup Deserialize(string serializedElementGroup); + } +} diff --git a/Editor/Toolbar/SerializableValues/IMainToolbarElementVariableSerializer.cs.meta b/Editor/Toolbar/SerializableValues/IMainToolbarElementVariableSerializer.cs.meta new file mode 100644 index 0000000..150bed4 --- /dev/null +++ b/Editor/Toolbar/SerializableValues/IMainToolbarElementVariableSerializer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d142e847e3be4574e9d1689324b5720c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Toolbar/SerializableValues/IValueSerializer.cs b/Editor/Toolbar/SerializableValues/IValueSerializer.cs new file mode 100644 index 0000000..a581761 --- /dev/null +++ b/Editor/Toolbar/SerializableValues/IValueSerializer.cs @@ -0,0 +1,8 @@ +namespace Paps.UnityToolbarExtenderUIToolkit +{ + internal interface IValueSerializer + { + string Serialize(T value); + T Deserialize(string serializedValue); + } +} diff --git a/Editor/Toolbar/SerializableValues/IValueSerializer.cs.meta b/Editor/Toolbar/SerializableValues/IValueSerializer.cs.meta new file mode 100644 index 0000000..580311f --- /dev/null +++ b/Editor/Toolbar/SerializableValues/IValueSerializer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d5c4ccea207b25d4098b94a25cd4eb5e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Toolbar/SerializableValues/MainToolbarElementVariableWatcher.cs b/Editor/Toolbar/SerializableValues/MainToolbarElementVariableWatcher.cs new file mode 100644 index 0000000..33b3e37 --- /dev/null +++ b/Editor/Toolbar/SerializableValues/MainToolbarElementVariableWatcher.cs @@ -0,0 +1,160 @@ +using System.Linq; +using System.Reflection; +using UnityEditor; + +namespace Paps.UnityToolbarExtenderUIToolkit +{ + internal class MainToolbarElementVariableWatcher + { + private const BindingFlags BINDING_FLAGS = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance; + + private const double SERIALIZE_EVERY_SECONDS = 0.5f; + private static double _nextSerializeTime = SERIALIZE_EVERY_SECONDS; + + private ElementVariables[] _elementsWithVariables; + private readonly IMainToolbarElementVariableRepository _repository; + private readonly IValueSerializer _valueSerializer; + + public MainToolbarElementVariableWatcher(IMainToolbarElementVariableRepository repository, IValueSerializer valueSerializer) + { + _repository = repository; + _valueSerializer = valueSerializer; + } + + public void RestoreValues(MainToolbarElement[] elements) + { + _elementsWithVariables = GetElementsWithVariables(elements); + + var serializedElements = _repository.GetAll(); + + foreach(var element in _elementsWithVariables) + { + var matchingSerialized = serializedElements.FirstOrDefault(serialized => serialized.ElementFullTypeName == + element.MainToolbarElement.VisualElement.GetType().FullName); + + if(matchingSerialized != null) + { + RestoreFields(element, matchingSerialized); + RestoreProperties(element, matchingSerialized); + } + } + + SaveCurrentState(); + } + + private void RestoreFields(ElementVariables element, SerializableElement matchingSerialized) + { + foreach (var field in element.Fields) + { + var matchingField = matchingSerialized.Variables.FirstOrDefault(v => + (v.Key == field.Attribute.SerializationKey || v.Key == field.Field.Name) && + v.Type == ValueHolderType.Field && + v.ValueType == field.Field.FieldType); + + if (matchingField.Key != null) + { + field.Set(matchingField.Value); + } + } + } + + private void RestoreProperties(ElementVariables element, SerializableElement matchingSerialized) + { + foreach (var property in element.Properties) + { + var matchingField = matchingSerialized.Variables.FirstOrDefault(v => + (v.Key == property.Attribute.SerializationKey || v.Key == property.Property.Name) && + v.Type == ValueHolderType.Property && + v.ValueType == property.Property.PropertyType); + + if (matchingField.Key != null) + { + property.Set(matchingField.Value); + } + } + } + + public void Update() + { + if (EditorApplication.timeSinceStartup > _nextSerializeTime) + { + _nextSerializeTime = EditorApplication.timeSinceStartup + SERIALIZE_EVERY_SECONDS; + WatchChanges(); + } + } + + private void WatchChanges() + { + var anyChange = false; + + foreach(var element in _elementsWithVariables) + { + if (element.DidChange()) + { + anyChange = true; + element.UpdateValues(); + _repository.Set(ToSerializable(element)); + } + } + + if(anyChange) + _repository.Save(); + } + + private void SaveCurrentState() + { + _repository.SetAll(_elementsWithVariables.Select(e => ToSerializable(e)).ToArray()); + + _repository.Save(); + } + + private ElementVariables[] GetElementsWithVariables(MainToolbarElement[] elements) + { + return elements.Select(element => new ElementVariables + { + MainToolbarElement = element, + Fields = GetSerializableFields(element), + Properties = GetSerializableProperties(element) + }) + .Where(serializableElement => serializableElement.Fields.Any() || serializableElement.Properties.Any()) + .ToArray(); + } + + private FieldVariable[] GetSerializableFields(MainToolbarElement element) + { + return element.VisualElement.GetType().GetFields(BINDING_FLAGS) + .Where(field => field.GetCustomAttribute() != null) + .Select(field => new FieldVariable(element, field, _valueSerializer, field.GetCustomAttribute())) + .ToArray(); + } + + private PropertyVariable[] GetSerializableProperties(MainToolbarElement element) + { + return element.VisualElement.GetType().GetProperties(BINDING_FLAGS) + .Where(property => property.GetCustomAttribute() != null) + .Select(property => new PropertyVariable(element, property, _valueSerializer, property.GetCustomAttribute())) + .ToArray(); + } + + private SerializableElement ToSerializable(ElementVariables elementWithVariables) + { + return new SerializableElement() + { + ElementFullTypeName = elementWithVariables.MainToolbarElement.VisualElement.GetType().FullName, + Variables = elementWithVariables.Fields.Select(f => new SerializableVariable() + { + Type = ValueHolderType.Field, + Key = string.IsNullOrEmpty(f.Attribute.SerializationKey) ? f.Field.Name : f.Attribute.SerializationKey, + ValueType = f.Field.FieldType, + Value = f.Get() + }).Concat(elementWithVariables.Properties.Select(p => new SerializableVariable() + { + Type = ValueHolderType.Property, + Key = string.IsNullOrEmpty(p.Attribute.SerializationKey) ? p.Property.Name : p.Attribute.SerializationKey, + ValueType = p.Property.PropertyType, + Value = p.Get() + })).ToArray() + }; + } + } +} diff --git a/Editor/Toolbar/SerializableValues/MainToolbarElementVariableWatcher.cs.meta b/Editor/Toolbar/SerializableValues/MainToolbarElementVariableWatcher.cs.meta new file mode 100644 index 0000000..79554e0 --- /dev/null +++ b/Editor/Toolbar/SerializableValues/MainToolbarElementVariableWatcher.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 62abfdfdd04775b409e83c230d7ddc4c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Toolbar/SerializableValues/PropertyVariable.cs b/Editor/Toolbar/SerializableValues/PropertyVariable.cs new file mode 100644 index 0000000..58dc6f6 --- /dev/null +++ b/Editor/Toolbar/SerializableValues/PropertyVariable.cs @@ -0,0 +1,26 @@ +using System.Collections; +using System.Reflection; + +namespace Paps.UnityToolbarExtenderUIToolkit +{ + internal class PropertyVariable : Variable + { + public readonly PropertyInfo Property; + + public PropertyVariable(MainToolbarElement element, PropertyInfo property, IValueSerializer valueSerializer, SerializeAttribute attribute) + : base(element, property.PropertyType, property.GetValue(element.VisualElement), valueSerializer, attribute) + { + Property = property; + } + + public override object Get() + { + return Property.GetValue(Element.VisualElement); + } + + public override void Set(object value) + { + Property.SetValue(Element.VisualElement, value); + } + } +} diff --git a/Editor/Toolbar/SerializableValues/PropertyVariable.cs.meta b/Editor/Toolbar/SerializableValues/PropertyVariable.cs.meta new file mode 100644 index 0000000..b77e154 --- /dev/null +++ b/Editor/Toolbar/SerializableValues/PropertyVariable.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e18acef36457df44da9432e05a0c38a1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Toolbar/SerializableValues/SerializableElement.cs b/Editor/Toolbar/SerializableValues/SerializableElement.cs new file mode 100644 index 0000000..e1c9def --- /dev/null +++ b/Editor/Toolbar/SerializableValues/SerializableElement.cs @@ -0,0 +1,8 @@ +namespace Paps.UnityToolbarExtenderUIToolkit +{ + internal class SerializableElement + { + public string ElementFullTypeName; + public SerializableVariable[] Variables = new SerializableVariable[0]; + } +} diff --git a/Editor/Toolbar/SerializableValues/SerializableElement.cs.meta b/Editor/Toolbar/SerializableValues/SerializableElement.cs.meta new file mode 100644 index 0000000..a87418c --- /dev/null +++ b/Editor/Toolbar/SerializableValues/SerializableElement.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7edf7215b75471c4f83e4affd1852a6f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Toolbar/SerializableValues/SerializableElementGroup.cs b/Editor/Toolbar/SerializableValues/SerializableElementGroup.cs new file mode 100644 index 0000000..313b389 --- /dev/null +++ b/Editor/Toolbar/SerializableValues/SerializableElementGroup.cs @@ -0,0 +1,9 @@ +using System.Collections.Generic; + +namespace Paps.UnityToolbarExtenderUIToolkit +{ + internal class SerializableElementGroup + { + public Dictionary SerializableElements = new Dictionary(); + } +} diff --git a/Editor/Toolbar/SerializableValues/SerializableElementGroup.cs.meta b/Editor/Toolbar/SerializableValues/SerializableElementGroup.cs.meta new file mode 100644 index 0000000..22d7157 --- /dev/null +++ b/Editor/Toolbar/SerializableValues/SerializableElementGroup.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 657001aa20153804f8d8e39515494221 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Toolbar/SerializableValues/SerializableVariable.cs b/Editor/Toolbar/SerializableValues/SerializableVariable.cs new file mode 100644 index 0000000..d77a5f8 --- /dev/null +++ b/Editor/Toolbar/SerializableValues/SerializableVariable.cs @@ -0,0 +1,12 @@ +using System; + +namespace Paps.UnityToolbarExtenderUIToolkit +{ + internal struct SerializableVariable + { + public ValueHolderType Type; + public string Key; + public Type ValueType; + public object Value; + } +} diff --git a/Editor/Toolbar/SerializableValues/SerializableVariable.cs.meta b/Editor/Toolbar/SerializableValues/SerializableVariable.cs.meta new file mode 100644 index 0000000..98178ad --- /dev/null +++ b/Editor/Toolbar/SerializableValues/SerializableVariable.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: fbe233d1da6590648bd836f9184b28c7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Toolbar/SerializableValues/SerializeAttribute.cs b/Editor/Toolbar/SerializableValues/SerializeAttribute.cs new file mode 100644 index 0000000..f516366 --- /dev/null +++ b/Editor/Toolbar/SerializableValues/SerializeAttribute.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections; + +namespace Paps.UnityToolbarExtenderUIToolkit +{ + public class SerializeAttribute : Attribute + { + public string SerializationKey { get; } + + public SerializeAttribute(string serializationKey = null) + { + SerializationKey = serializationKey; + } + } +} diff --git a/Editor/Toolbar/SerializableValues/SerializeAttribute.cs.meta b/Editor/Toolbar/SerializableValues/SerializeAttribute.cs.meta new file mode 100644 index 0000000..00cd790 --- /dev/null +++ b/Editor/Toolbar/SerializableValues/SerializeAttribute.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 13ca109f93dfdcd49bb7e38c834a6679 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Toolbar/SerializableValues/UnitySerializationMainToolbarElementVariableSerializer.cs b/Editor/Toolbar/SerializableValues/UnitySerializationMainToolbarElementVariableSerializer.cs new file mode 100644 index 0000000..9149683 --- /dev/null +++ b/Editor/Toolbar/SerializableValues/UnitySerializationMainToolbarElementVariableSerializer.cs @@ -0,0 +1,133 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using Unity.Serialization.Json; +using UnityEditor; + +namespace Paps.UnityToolbarExtenderUIToolkit +{ + internal class UnitySerializationMainToolbarElementVariableSerializer : IMainToolbarElementVariableSerializer + { + private struct SerializableElementGroupDTO + { + public Dictionary SerializableElements; + } + + private struct SerializableElementDTO + { + public string ElementFullTypeName; + public SerializableVariableDTO[] Variables; + } + + private struct SerializableVariableDTO + { + public ValueHolderType Type; + public string Key; + public string SerializedValue; + public string SerializedValueTypeFullyQualifiedName; + } + + private IValueSerializer _valuesSerializer; + private MethodInfo _serializeValueMethod, _deserializeValueMethod; + + public UnitySerializationMainToolbarElementVariableSerializer(IValueSerializer valuesSerializer) + { + _valuesSerializer = valuesSerializer; + + _serializeValueMethod = _valuesSerializer.GetType().GetMethod("Serialize", BindingFlags.Instance | BindingFlags.Public); + _deserializeValueMethod = _valuesSerializer.GetType().GetMethod("Deserialize", BindingFlags.Instance | BindingFlags.Public); + } + + public string Serialize(SerializableElementGroup serializableElementGroup) + { + var dto = ToDTO(serializableElementGroup); + + return JsonSerialization.ToJson(dto, new JsonSerializationParameters() { Minified = true }); + } + + public SerializableElementGroup Deserialize(string serializedElementGroup) + { + var dto = JsonSerialization.FromJson(serializedElementGroup); + + return FromDTO(dto); + } + + private SerializableElementGroupDTO ToDTO(SerializableElementGroup group) + { + return new SerializableElementGroupDTO() + { + SerializableElements = group.SerializableElements.ToDictionary(e => e.Key, e => ToDTO(e.Value)) + }; + } + + + private SerializableElementGroup FromDTO(SerializableElementGroupDTO dto) + { + return new SerializableElementGroup() + { + SerializableElements = dto.SerializableElements == null ? + new Dictionary() : + dto.SerializableElements.ToDictionary(e => e.Key, e => FromDTO(e.Value)) + }; + } + + private SerializableElementDTO ToDTO(SerializableElement serializableElement) + { + return new SerializableElementDTO() + { + ElementFullTypeName = serializableElement.ElementFullTypeName, + Variables = serializableElement.Variables.Select(v => new SerializableVariableDTO() + { + Key = v.Key, + Type = v.Type, + SerializedValue = SerializeValue(v.ValueType, v.Value), + SerializedValueTypeFullyQualifiedName = v.ValueType.AssemblyQualifiedName + }).ToArray() + }; + } + + private SerializableElement FromDTO(SerializableElementDTO dto) + { + return new SerializableElement() + { + ElementFullTypeName = dto.ElementFullTypeName, + Variables = dto.Variables.Select(v => + { + try + { + var valueType = Type.GetType(v.SerializedValueTypeFullyQualifiedName); + + return new SerializableVariable() + { + Key = v.Key, + Type = v.Type, + ValueType = valueType, + Value = DeserializeValue(valueType, v.SerializedValue) + }; + } + catch + { + return default; + } + }) + .Where(v => !string.IsNullOrEmpty(v.Key)) + .ToArray() + }; + } + + private string SerializeValue(Type type, object value) + { + var genericMethod = _serializeValueMethod.MakeGenericMethod(type); + + return (string)genericMethod.Invoke(_valuesSerializer, new object[] { value }); + } + + private object DeserializeValue(Type type, string serializedValue) + { + var genericMethod = _deserializeValueMethod.MakeGenericMethod(type); + + return genericMethod.Invoke(_valuesSerializer, new object[] { serializedValue }); + } + } +} diff --git a/Editor/Toolbar/SerializableValues/UnitySerializationMainToolbarElementVariableSerializer.cs.meta b/Editor/Toolbar/SerializableValues/UnitySerializationMainToolbarElementVariableSerializer.cs.meta new file mode 100644 index 0000000..e7b0b77 --- /dev/null +++ b/Editor/Toolbar/SerializableValues/UnitySerializationMainToolbarElementVariableSerializer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: eb8fdee7bd4d00a489619573c341c510 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Toolbar/SerializableValues/UnitySerializationValueSerializer.cs b/Editor/Toolbar/SerializableValues/UnitySerializationValueSerializer.cs new file mode 100644 index 0000000..3bafa22 --- /dev/null +++ b/Editor/Toolbar/SerializableValues/UnitySerializationValueSerializer.cs @@ -0,0 +1,17 @@ +using Unity.Serialization.Json; + +namespace Paps.UnityToolbarExtenderUIToolkit +{ + internal class UnitySerializationValueSerializer : IValueSerializer + { + public T Deserialize(string serializedValue) + { + return JsonSerialization.FromJson(serializedValue); + } + + public string Serialize(T value) + { + return JsonSerialization.ToJson(value, new JsonSerializationParameters() { Minified = true } ); + } + } +} diff --git a/Editor/Toolbar/SerializableValues/UnitySerializationValueSerializer.cs.meta b/Editor/Toolbar/SerializableValues/UnitySerializationValueSerializer.cs.meta new file mode 100644 index 0000000..4db3f29 --- /dev/null +++ b/Editor/Toolbar/SerializableValues/UnitySerializationValueSerializer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 71e02839f1a8c5240af3b944fc2daa38 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Toolbar/SerializableValues/UserSettingsFileMainToolbarElementVariableRepository.cs b/Editor/Toolbar/SerializableValues/UserSettingsFileMainToolbarElementVariableRepository.cs new file mode 100644 index 0000000..9b841d7 --- /dev/null +++ b/Editor/Toolbar/SerializableValues/UserSettingsFileMainToolbarElementVariableRepository.cs @@ -0,0 +1,63 @@ +using System.IO; +using System.Linq; +using UnityEditor; +using UnityEngine; + +namespace Paps.UnityToolbarExtenderUIToolkit +{ + internal class UserSettingsFileMainToolbarElementVariableRepository : IMainToolbarElementVariableRepository + { + private static readonly string DIRECTORY = Path.Combine(Directory.GetParent(Application.dataPath).FullName, "UserSettings/", "unity-toolbar-extender-ui-toolkit", "serialized-user-values"); + private static readonly string FILE = Path.Combine(DIRECTORY, "serialized_values.json"); + private readonly IMainToolbarElementVariableSerializer _serializer; + private SerializableElementGroup _elementGroup; + private SerializableElementGroup ElementGroup + { + get + { + if (_elementGroup == null) + _elementGroup = Load(); + + return _elementGroup; + } + set => _elementGroup = value; + } + + public UserSettingsFileMainToolbarElementVariableRepository(IMainToolbarElementVariableSerializer serializer) + { + _serializer = serializer; + } + + public SerializableElement[] GetAll() + { + return ElementGroup.SerializableElements.Values.ToArray(); + } + + public void Set(SerializableElement serializableElement) + { + ElementGroup.SerializableElements[serializableElement.ElementFullTypeName] = serializableElement; + } + + public void SetAll(SerializableElement[] serializableElements) + { + ElementGroup.SerializableElements = serializableElements.ToDictionary(s => s.ElementFullTypeName, s => s); + } + + private SerializableElementGroup Load() + { + if(!Directory.Exists(DIRECTORY)) + Directory.CreateDirectory(DIRECTORY); + + if (!File.Exists(FILE)) + return _serializer.Deserialize("{}"); + else + return _serializer.Deserialize(File.ReadAllText(FILE)); + } + + public void Save() + { + var serializedString = _serializer.Serialize(ElementGroup); + File.WriteAllText(FILE, serializedString); + } + } +} diff --git a/Editor/Toolbar/SerializableValues/UserSettingsFileMainToolbarElementVariableRepository.cs.meta b/Editor/Toolbar/SerializableValues/UserSettingsFileMainToolbarElementVariableRepository.cs.meta new file mode 100644 index 0000000..7e2e197 --- /dev/null +++ b/Editor/Toolbar/SerializableValues/UserSettingsFileMainToolbarElementVariableRepository.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8063852f8dc46d74a9fa8cd1d5401716 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Toolbar/SerializableValues/ValueHolderType.cs b/Editor/Toolbar/SerializableValues/ValueHolderType.cs new file mode 100644 index 0000000..f2bd9ec --- /dev/null +++ b/Editor/Toolbar/SerializableValues/ValueHolderType.cs @@ -0,0 +1,8 @@ +namespace Paps.UnityToolbarExtenderUIToolkit +{ + internal enum ValueHolderType + { + Field, + Property + } +} diff --git a/Editor/Toolbar/SerializableValues/ValueHolderType.cs.meta b/Editor/Toolbar/SerializableValues/ValueHolderType.cs.meta new file mode 100644 index 0000000..01a509d --- /dev/null +++ b/Editor/Toolbar/SerializableValues/ValueHolderType.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1dd09907e73e4a84ab82d32c04378911 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Toolbar/SerializableValues/Variable.cs b/Editor/Toolbar/SerializableValues/Variable.cs new file mode 100644 index 0000000..664d483 --- /dev/null +++ b/Editor/Toolbar/SerializableValues/Variable.cs @@ -0,0 +1,68 @@ +using System; +using System.Reflection; + +namespace Paps.UnityToolbarExtenderUIToolkit +{ + internal abstract class Variable + { + private string _lastValueSerialized; + private string LastValueSerialized + { + get + { + if (_lastValueSerialized == null) + _lastValueSerialized = Serialize(Get()); + + return _lastValueSerialized; + } + + set => _lastValueSerialized = value; + } + private IValueSerializer _valueSerializer; + private MethodInfo _serializeValueMethod, _deserializeValueMethod; + + public MainToolbarElement Element { get; } + public Type ValueType { get; } + public SerializeAttribute Attribute { get; } + + public Variable(MainToolbarElement element, Type valueType, object initialValue, IValueSerializer valueSerializer, SerializeAttribute attribute) + { + Element = element; + ValueType = valueType; + _valueSerializer = valueSerializer; + Attribute = attribute; + _serializeValueMethod = _valueSerializer.GetType().GetMethod("Serialize", BindingFlags.Instance | BindingFlags.Public); + _deserializeValueMethod = _valueSerializer.GetType().GetMethod("Deserialize", BindingFlags.Instance | BindingFlags.Public); + } + + public abstract object Get(); + + public abstract void Set(object value); + + public bool DidChange() + { + var currentValue = Get(); + + var currentValueSerialized = Serialize(currentValue); + + return currentValueSerialized != LastValueSerialized; + } + + private string Serialize(object value) + { + var genericMethod = _serializeValueMethod.MakeGenericMethod(ValueType); + return (string)genericMethod.Invoke(_valueSerializer, new object[] { Get() }); + } + + private object Deserialize(string serialized) + { + var genericMethod = _deserializeValueMethod.MakeGenericMethod(ValueType); + return genericMethod.Invoke(_valueSerializer, new object[] { serialized }); + } + + public void UpdateValue() + { + LastValueSerialized = Serialize(Get()); + } + } +} diff --git a/Editor/Toolbar/SerializableValues/Variable.cs.meta b/Editor/Toolbar/SerializableValues/Variable.cs.meta new file mode 100644 index 0000000..b8586a3 --- /dev/null +++ b/Editor/Toolbar/SerializableValues/Variable.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 219c1bb61dbca8e4d966b029961aed81 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Toolbar/ToolbarAlign.cs b/Editor/Toolbar/ToolbarAlign.cs new file mode 100644 index 0000000..aa8632f --- /dev/null +++ b/Editor/Toolbar/ToolbarAlign.cs @@ -0,0 +1,8 @@ +namespace Paps.UnityToolbarExtenderUIToolkit +{ + public enum ToolbarAlign + { + Left, + Right + } +} \ No newline at end of file diff --git a/Editor/Toolbar/ToolbarAlign.cs.meta b/Editor/Toolbar/ToolbarAlign.cs.meta new file mode 100644 index 0000000..041e815 --- /dev/null +++ b/Editor/Toolbar/ToolbarAlign.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3ea30c0e2b125014f8d433ee5360acb4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: