A game about forced loneliness, made by TACStudios
1using System.Collections.Generic; 2using UnityEditor.Experimental.GraphView; 3using UnityEditor.ShaderGraph.Drawing.Interfaces; 4using UnityEngine; 5using UnityEngine.UIElements; 6 7namespace UnityEditor.ShaderGraph.Drawing.Views 8{ 9 interface ISelectionProvider 10 { 11 List<ISelectable> GetSelection { get; } 12 } 13 14 class GraphSubWindow : GraphElement, ISGResizable 15 { 16 ISGViewModel m_ViewModel; 17 18 ISGViewModel ViewModel 19 { 20 get => m_ViewModel; 21 set => m_ViewModel = value; 22 } 23 24 Dragger m_Dragger; 25 26 // This needs to be something that each subclass defines for itself at creation time 27 // if they all use the same they'll be stacked on top of each other at SG window creation 28 protected WindowDockingLayout windowDockingLayout { get; private set; } = new WindowDockingLayout 29 { 30 dockingTop = true, 31 dockingLeft = false, 32 verticalOffset = 8, 33 horizontalOffset = 8, 34 }; 35 36 // Used to cache the window docking layout between resizing operations as it interferes with window resizing operations 37 private IStyle cachedWindowDockingStyle; 38 39 protected VisualElement m_MainContainer; 40 protected VisualElement m_Root; 41 protected Label m_TitleLabel; 42 protected Label m_SubTitleLabel; 43 protected ScrollView m_ScrollView; 44 protected VisualElement m_ContentContainer; 45 protected VisualElement m_HeaderItem; 46 protected VisualElement m_ParentView; 47 48 // Added for test assembly access 49 internal ScrollView scrollView => m_ScrollView; 50 51 // These are used as default values for styling and layout purposes 52 // They can be overriden if a child class wants to roll its own style and layout behavior 53 public virtual string layoutKey => "UnityEditor.ShaderGraph.SubWindow"; 54 public virtual string styleName => "GraphSubWindow"; 55 public virtual string UxmlName => "GraphSubWindow"; 56 57 // Each sub-window will override these if they need to 58 public virtual string elementName => ""; 59 public virtual string windowTitle => ""; 60 61 public VisualElement ParentView 62 { 63 get 64 { 65 if (!isWindowed && m_ParentView == null) 66 m_ParentView = GetFirstAncestorOfType<GraphView>(); 67 return m_ParentView; 68 } 69 70 set 71 { 72 if (!isWindowed) 73 return; 74 m_ParentView = value; 75 } 76 } 77 78 public List<ISelectable> selection 79 { 80 get 81 { 82 if (ParentView is ISelectionProvider selectionProvider) 83 return selectionProvider.GetSelection; 84 85 AssertHelpers.Fail("GraphSubWindow was unable to find a selection provider. Please check if parent view of: " + name + " implements ISelectionProvider::GetSelection"); 86 return new List<ISelectable>(); 87 } 88 } 89 90 public override string title 91 { 92 get { return m_TitleLabel.text; } 93 set { m_TitleLabel.text = value; } 94 } 95 96 public string subTitle 97 { 98 get { return m_SubTitleLabel.text; } 99 set { m_SubTitleLabel.text = value; } 100 } 101 102 // Intended for future handling of docking to sides of the shader graph window 103 bool m_IsWindowed; 104 public bool isWindowed 105 { 106 get { return m_IsWindowed; } 107 set 108 { 109 if (m_IsWindowed == value) return; 110 111 if (value) 112 { 113 capabilities &= ~Capabilities.Movable; 114 AddToClassList("windowed"); 115 this.RemoveManipulator(m_Dragger); 116 } 117 else 118 { 119 capabilities |= Capabilities.Movable; 120 RemoveFromClassList("windowed"); 121 this.AddManipulator(m_Dragger); 122 } 123 m_IsWindowed = value; 124 } 125 } 126 127 public override VisualElement contentContainer => m_ContentContainer; 128 129 private bool m_IsResizable = false; 130 131 // Can be set by child classes as needed 132 protected bool isWindowResizable 133 { 134 get => m_IsResizable; 135 set 136 { 137 if (m_IsResizable != value) 138 { 139 m_IsResizable = value; 140 HandleResizingBehavior(m_IsResizable); 141 } 142 } 143 } 144 145 void HandleResizingBehavior(bool isResizable) 146 { 147 if (isResizable) 148 { 149 var resizeElement = this.Q<ResizableElement>(); 150 resizeElement.BindOnResizeCallback(OnWindowResize); 151 hierarchy.Add(resizeElement); 152 } 153 else 154 { 155 var resizeElement = this.Q<ResizableElement>(); 156 resizeElement.SetResizeRules(ResizableElement.Resizer.None); 157 hierarchy.Remove(resizeElement); 158 } 159 } 160 161 protected void SetResizingRules(ResizableElement.Resizer resizeDirections) 162 { 163 var resizeElement = this.Q<ResizableElement>(); 164 resizeElement.SetResizeRules(resizeDirections); 165 } 166 167 private bool m_IsScrollable = false; 168 169 // Can be set by child classes as needed 170 protected bool isWindowScrollable 171 { 172 get => m_IsScrollable; 173 set 174 { 175 if (m_IsScrollable != value) 176 { 177 m_IsScrollable = value; 178 HandleScrollingBehavior(m_IsScrollable); 179 } 180 } 181 } 182 183 protected float scrollableWidth 184 { 185 get { return m_ScrollView.contentContainer.layout.width - m_ScrollView.contentViewport.layout.width; } 186 } 187 188 protected float scrollableHeight 189 { 190 get { return contentContainer.layout.height - m_ScrollView.contentViewport.layout.height; } 191 } 192 193 void HandleScrollingBehavior(bool scrollable) 194 { 195 if (scrollable) 196 { 197 // Remove the categories container from the content item and add it to the scrollview 198 m_ContentContainer.RemoveFromHierarchy(); 199 m_ScrollView.Add(m_ContentContainer); 200 AddToClassList("scrollable"); 201 } 202 else 203 { 204 // Remove the categories container from the scrollview and add it to the content item 205 m_ContentContainer.RemoveFromHierarchy(); 206 m_Root.Add(m_ContentContainer); 207 208 RemoveFromClassList("scrollable"); 209 } 210 } 211 212 protected GraphSubWindow(ISGViewModel viewModel) 213 { 214 ViewModel = viewModel; 215 m_ParentView = ViewModel.parentView; 216 ParentView.Add(this); 217 218 var styleSheet = Resources.Load<StyleSheet>($"Styles/{styleName}"); 219 // Setup VisualElement from Stylesheet and UXML file 220 styleSheets.Add(styleSheet); 221 var uxml = Resources.Load<VisualTreeAsset>($"UXML/{UxmlName}"); 222 m_MainContainer = uxml.Instantiate(); 223 m_MainContainer.AddToClassList("mainContainer"); 224 225 m_Root = m_MainContainer.Q("content"); 226 m_HeaderItem = m_MainContainer.Q("header"); 227 m_HeaderItem.AddToClassList("subWindowHeader"); 228 m_ScrollView = m_MainContainer.Q<ScrollView>("scrollView"); 229 m_TitleLabel = m_MainContainer.Q<Label>(name: "titleLabel"); 230 m_SubTitleLabel = m_MainContainer.Q<Label>(name: "subTitleLabel"); 231 m_ContentContainer = m_MainContainer.Q(name: "contentContainer"); 232 233 hierarchy.Add(m_MainContainer); 234 235 capabilities |= Capabilities.Movable | Capabilities.Resizable; 236 style.overflow = Overflow.Hidden; 237 focusable = false; 238 239 name = elementName; 240 title = windowTitle; 241 242 ClearClassList(); 243 AddToClassList(name); 244 245 BuildManipulators(); 246 247 /* Event interception to prevent GraphView manipulators from being triggered */ 248 //RegisterCallback<DragUpdatedEvent>(e => 249 //{ 250 // e.StopPropagation(); 251 //}); 252 253 // prevent Zoomer manipulator 254 RegisterCallback<WheelEvent>(e => 255 { 256 e.StopPropagation(); 257 }); 258 259 //RegisterCallback<MouseDownEvent>(e => 260 //{ 261 // // prevent ContentDragger manipulator 262 // e.StopPropagation(); 263 //}); 264 } 265 266 public void ShowWindow() 267 { 268 this.style.visibility = Visibility.Visible; 269 this.m_ScrollView.style.display = DisplayStyle.Flex; 270 this.MarkDirtyRepaint(); 271 } 272 273 public void HideWindow() 274 { 275 this.style.visibility = Visibility.Hidden; 276 this.m_ScrollView.style.display = DisplayStyle.None; 277 this.MarkDirtyRepaint(); 278 } 279 280 void BuildManipulators() 281 { 282 m_Dragger = new Dragger { clampToParentEdges = true }; 283 RegisterCallback<MouseUpEvent>(OnMoveEnd); 284 this.AddManipulator(m_Dragger); 285 } 286 287 #region Layout 288 public void ClampToParentLayout(Rect parentLayout) 289 { 290 windowDockingLayout.CalculateDockingCornerAndOffset(layout, parentLayout); 291 windowDockingLayout.ClampToParentWindow(); 292 293 // If the parent shader graph window is being resized smaller than this window on either axis 294 if (parentLayout.width < this.layout.width || parentLayout.height < this.layout.height) 295 { 296 // Don't adjust the sub window in this case as it causes flickering errors and looks broken 297 } 298 else 299 { 300 windowDockingLayout.ApplyPosition(this); 301 } 302 303 SerializeLayout(); 304 } 305 306 public void OnStartResize() 307 { 308 cachedWindowDockingStyle = this.style; 309 } 310 311 public void OnResized() 312 { 313 if (cachedWindowDockingStyle != null) 314 { 315 this.style.left = cachedWindowDockingStyle.left; 316 this.style.right = cachedWindowDockingStyle.right; 317 this.style.bottom = cachedWindowDockingStyle.bottom; 318 this.style.top = cachedWindowDockingStyle.top; 319 } 320 windowDockingLayout.size = layout.size; 321 SerializeLayout(); 322 } 323 324 public void DeserializeLayout() 325 { 326 var serializedLayout = EditorUserSettings.GetConfigValue(layoutKey); 327 if (!string.IsNullOrEmpty(serializedLayout)) 328 windowDockingLayout = JsonUtility.FromJson<WindowDockingLayout>(serializedLayout); 329 else 330 { 331 // The window size needs to come from the stylesheet or UXML as opposed to being defined in code 332 windowDockingLayout.size = layout.size; 333 } 334 335 windowDockingLayout.ApplySize(this); 336 windowDockingLayout.ApplyPosition(this); 337 } 338 339 protected void AddStyleSheetFromPath(string styleSheetPath) 340 { 341 StyleSheet sheetAsset = Resources.Load<StyleSheet>(styleSheetPath); ; 342 343 if (sheetAsset == null) 344 { 345 Debug.LogWarning(string.Format("Style sheet not found for path \"{0}\"", styleSheetPath)); 346 return; 347 } 348 styleSheets.Add(sheetAsset); 349 } 350 351 void SerializeLayout() 352 { 353 windowDockingLayout.size = layout.size; 354 var serializedLayout = JsonUtility.ToJson(windowDockingLayout); 355 EditorUserSettings.SetConfigValue(layoutKey, serializedLayout); 356 } 357 358 void OnMoveEnd(MouseUpEvent upEvent) 359 { 360 windowDockingLayout.CalculateDockingCornerAndOffset(layout, ParentView.layout); 361 windowDockingLayout.ClampToParentWindow(); 362 363 SerializeLayout(); 364 } 365 366 public bool CanResizePastParentBounds() 367 { 368 return false; 369 } 370 371 void OnWindowResize(MouseUpEvent upEvent) 372 { 373 } 374 375 public virtual void Dispose() 376 { 377 m_MainContainer = null; 378 m_Root = null; 379 m_TitleLabel = null; 380 m_SubTitleLabel = null; 381 m_ScrollView = null; 382 m_ContentContainer = null; 383 m_HeaderItem = null; 384 m_ParentView = null; 385 cachedWindowDockingStyle = null; 386 styleSheets.Clear(); 387 } 388 } 389 #endregion 390}