Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
be358b1
First step in Toolbar UI/UX rework
julienamsellem Jul 26, 2021
1c33600
[WIP] Reorganize VFX graph toolbar with dropdowns
julienamsellem Aug 3, 2021
657da4e
Created a base class for the Dropdown toolbar button and added an icon
julienamsellem Aug 4, 2021
d3f71ab
Implemented behaviors for all submenu commands
julienamsellem Aug 4, 2021
c47b092
Better control dropdown popup position
julienamsellem Aug 5, 2021
3298f90
Moved dropdown button classes as separate files
julienamsellem Aug 5, 2021
465ac3f
Implemented a "responsiveness" behavior in the vfx toolbar
julienamsellem Aug 5, 2021
45d6fc8
Fixed compile menu commands
julienamsellem Aug 5, 2021
ceb838d
Added a new icon for compile button and better theme support implemen…
julienamsellem Aug 9, 2021
eb65d1b
Updated icons and removed labels. Also added missing resync materials…
julienamsellem Aug 11, 2021
108a1f3
Refined a few borders and added an icon for target game object panel
julienamsellem Aug 11, 2021
0739519
Updated changelog
julienamsellem Aug 11, 2021
72ea906
Fixed formatting issues
julienamsellem Aug 12, 2021
cd3ca14
Added missing 3 dots for command that open an popup
julienamsellem Aug 12, 2021
8a2a97e
Added support for arrow navigation in custom dropdown menus
julienamsellem Aug 13, 2021
4d796e6
Do not close and reopen the popup if the arrow button is pressed whil…
julienamsellem Aug 13, 2021
8c96576
Force popup position after call to show. This partially fix DPI place…
julienamsellem Aug 16, 2021
f3c03e6
Force expected popup size otherwise it can be overridden by the API
julienamsellem Aug 16, 2021
43ea1d6
Tweaked a little bit the popup sizes
julienamsellem Aug 16, 2021
5127a63
Implemented a working "save as" command
julienamsellem Aug 16, 2021
43e3122
Internet links are now represented as link instead of buttons
julienamsellem Aug 19, 2021
f5242fb
Removed unexpected debug log
julienamsellem Aug 19, 2021
af848d1
Make the main help button action more obvious (opens a web page)
julienamsellem Aug 19, 2021
af37f36
[Github] is nicer than Github:
julienamsellem Aug 19, 2021
4c03eba
In SaveAs, use the same file extension as the original file
julienamsellem Aug 19, 2021
3958aa3
Fixed ".." in file extension and avoid saving if "save as" is canceled
julienamsellem Aug 19, 2021
a84f53f
Added a back button when the graph is opened in a subgraph
julienamsellem Aug 19, 2021
bd0cd62
Allow to re-import a sample package that has already been imported
julienamsellem Aug 23, 2021
a7e70c5
Hide "Checkout" button if not available
julienamsellem Aug 23, 2021
4ebf9d0
Added tooltips on almost all dropdown menu entries
julienamsellem Aug 23, 2021
148352e
Updated tooltips and removed hand cursor on help button
julienamsellem Aug 26, 2021
6aeee5c
Darken blackboard icons for light theme
julienamsellem Aug 26, 2021
888c0c1
Hide "Checkout" button if no VCS and disable it if asset is already c…
julienamsellem Aug 26, 2021
645230d
Switch main help button link with the dropdown menu for manual
julienamsellem Aug 30, 2021
9fb44f2
Merge branch 'master' into vfx/feature/GVFXG-143-improve-toolbar-desi…
julienamsellem Aug 31, 2021
09dc442
Fixed merge issues and replaced toolbar text with icons
julienamsellem Aug 31, 2021
c070d07
Changed dropdown buttons style and fixed a typo
julienamsellem Aug 31, 2021
3f6233c
Prevent the component board subtitle from overflowing the bounds of t…
julienamsellem Aug 31, 2021
7008a0b
Fixed code formatting issues
julienamsellem Aug 31, 2021
c6f4e64
Removed commented out code
julienamsellem Aug 31, 2021
44c9d40
Removed unused code
julienamsellem Aug 31, 2021
39ce14d
Fixed VFXViewWindow.currentWindow could be null after unmaximizing
julienamsellem Sep 1, 2021
4ed6177
Show the red dot in the record button from the beginning
julienamsellem Sep 1, 2021
3f83b3b
Updated the "Resync material" tooltip
julienamsellem Sep 2, 2021
16e2e4f
Keep attached component when unmaximizing the scene view
julienamsellem Sep 2, 2021
294a443
Fixed wrong tooltip
julienamsellem Sep 3, 2021
799b47a
Fixed a small typo in a style
julienamsellem Sep 8, 2021
49a60e7
Merge branch 'master' into vfx/feature/GVFXG-143-improve-toolbar-desi…
julienamsellem Sep 10, 2021
353aeb0
Fixed help popup placement when on a screen edged.
julienamsellem Sep 10, 2021
2cdd218
Fixed sample could not be imported because of wrong package version
julienamsellem Sep 16, 2021
31d136d
Applied code review comments
julienamsellem Sep 21, 2021
32c2ff5
Merge remote-tracking branch 'origin/vfx/feature/GVFXG-143-improve-to…
julienamsellem Sep 21, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion com.unity.visualeffectgraph/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
- Added Is Inside subgraph into VFX Graph additions package
- The VFX editor automatically attach to the current selection if the selected gameobject uses the currently edited VFX asset
- Two new buttons are available in the editor's tool bar. One will display a popup panel to handle attachement and one to lock/unlock the current attachement

- Improved toolbar design: added icons, removed labels and grouped commands into dropdown menus

### Changed
- Allow remaking an existing link.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -194,10 +194,11 @@ public VFXComponentBoard(VFXView view)
m_DebugModes = this.Query<Button>("debug-modes");
m_DebugModes.clickable.clicked += OnDebugModes;

m_RecordIcon = VFXView.LoadImage("d_Record");
m_RecordBoundsButton = this.Query<Button>("record");
m_RecordBoundsImage = this.Query<Image>("record-icon");
m_RecordBoundsImage = m_RecordBoundsButton.Query<Image>("record-icon");
m_RecordBoundsImage.style.backgroundImage = m_RecordIcon;
m_RecordBoundsButton.clickable.clicked += OnRecordBoundsButton;
m_RecordIcon = VFXView.LoadImage("d_Record");
m_BoundsActionLabel = this.Query<Label>("bounds-label");
m_BoundsToolContainer = this.Query("bounds-tool-container");
m_BackgroundDefaultColor = m_BoundsToolContainer.style.backgroundColor;
Expand Down
39 changes: 18 additions & 21 deletions com.unity.visualeffectgraph/Editor/GraphView/VFXViewWindow.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,10 @@ namespace UnityEditor.VFX.UI
[Serializable]
class VFXViewWindow : EditorWindow
{
static VisualEffect s_LastAttachedComponent;

ShortcutHandler m_ShortcutHandler;

protected void SetupFramingShortcutHandler(VFXView view)
{
m_ShortcutHandler = new ShortcutHandler(
Expand All @@ -29,7 +32,7 @@ protected void SetupFramingShortcutHandler(VFXView view)
{Event.KeyboardEvent("o"), view.FrameOrigin },
{Event.KeyboardEvent("^#>"), view.FramePrev },
{Event.KeyboardEvent("^>"), view.FrameNext },
{Event.KeyboardEvent("F7"), view.Compile},
{Event.KeyboardEvent("F7"), view.OnCompile},
{Event.KeyboardEvent("#d"), view.OutputToDot},
{Event.KeyboardEvent("^&d"), view.DuplicateSelectionWithEdges},
{Event.KeyboardEvent("^#d"), view.OutputToDotReduced},
Expand All @@ -41,7 +44,7 @@ protected void SetupFramingShortcutHandler(VFXView view)
});
}

public static VFXViewWindow currentWindow;
public static VFXViewWindow currentWindow => WindowLayout.FindEditorWindowOfType(typeof(VFXViewWindow)) as VFXViewWindow;

[MenuItem("Window/Visual Effects/Visual Effect Graph", false, 3011)]
public static void ShowWindow()
Expand Down Expand Up @@ -80,8 +83,11 @@ public void LoadResource(VisualEffectResource resource, VisualEffect effectToAtt
{
InternalLoadResource(resource);
}
if (effectToAttach != null && graphView.controller != null && graphView.controller.model != null && effectToAttach.visualEffectAsset == graphView.controller.model.asset)
graphView.attachedComponent = effectToAttach;

if (!graphView.TryAttachTo(effectToAttach))
{
s_LastAttachedComponent = null;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The introduction of this static variable was done to fix a bug when "unmaximizing" the window. Because in that process the window is recreated and then losing the attachment.

}
}

List<VisualEffectResource> m_ResourceHistory = new List<VisualEffectResource>();
Expand All @@ -106,6 +112,12 @@ void InternalLoadResource(VisualEffectResource resource)
graphView.controller = VFXViewController.GetController(resource, true);
graphView.UpdateGlobalSelection();
graphView.FrameNewController();
graphView.UpdateIsSubgraph();
}

public bool CanPopResource()
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I introduced a "back" button when we entered a subgraph, this is to know if the button should be displayed or not

{
return m_ResourceHistory.Any();
}

public void PopResource()
Expand Down Expand Up @@ -174,7 +186,7 @@ protected void CreateGUI()
var currentAsset = GetCurrentResource();
if (currentAsset != null)
{
LoadResource(currentAsset);
LoadResource(currentAsset, s_LastAttachedComponent);
}
};

Expand All @@ -188,8 +200,6 @@ protected void CreateGUI()
rootVisualElement.AddManipulator(m_ShortcutHandler);
}

currentWindow = this;

#if USE_EXIT_WORKAROUND_FOGBUGZ_1062258
EditorApplication.wantsToQuit += Quitting_Workaround;
#endif
Expand All @@ -216,11 +226,11 @@ protected void OnDestroy()

if (graphView != null)
{
s_LastAttachedComponent = graphView.attachedComponent;
graphView.UnregisterCallback<AttachToPanelEvent>(OnEnterPanel);
graphView.UnregisterCallback<DetachFromPanelEvent>(OnLeavePanel);
graphView.controller = null;
}
currentWindow = null;
}

void OnEnterPanel(AttachToPanelEvent e)
Expand Down Expand Up @@ -309,19 +319,6 @@ void Update()
VFXViewModificationProcessor.assetMoved = false;
}
titleContent.text = filename;

if (graphView?.controller?.model?.visualEffectObject != null)
{
graphView.checkoutButton.visible = true;
if (!graphView.IsAssetEditable() && Provider.isActive && Provider.enabled)
{
graphView.checkoutButton.SetEnabled(true);
}
else
{
graphView.checkoutButton.SetEnabled(false);
}
}
}

[SerializeField]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
using System;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a reusable class to add dropdowns (a button and an arrow button to open a popup).
It's used three times in this PR

using System.Collections.Generic;
using System.Linq;

using UnityEngine;
using UnityEngine.UIElements;

namespace UnityEditor.VFX.UI
{
abstract class DropDownButtonBase : VisualElement
{
private class NotifyEditorWindow : EditorWindow
{
public event Action Destroyed;

private void OnDestroy()
{
Destroyed?.Invoke();
}
}

readonly bool m_HasLeftSeparator;
readonly Button m_MainButton;

NotifyEditorWindow m_CurrentPopup;
DateTime m_PopupClosedTimestamp;

protected readonly VisualElement m_PopupContent;
protected readonly VFXViewWindow m_ParentWindow;

protected DropDownButtonBase(
VFXViewWindow parentWindow,
string uxmlSource,
string mainButtonLabel,
string mainButtonName,
string iconPath,
bool hasSeparatorBefore = false,
bool hasSeparatorAfter = false)
{
m_ParentWindow = parentWindow;
style.flexDirection = new StyleEnum<FlexDirection>(FlexDirection.Row);

if (hasSeparatorBefore)
{
m_HasLeftSeparator = true;
var divider = new VisualElement();
divider.AddToClassList("separator");
Add(divider);
}

m_MainButton = new Button(OnMainButton) { name = mainButtonName };
m_MainButton.AddToClassList("dropdown-button");
m_MainButton.AddToClassList("unity-toolbar-toggle");
if (!string.IsNullOrEmpty(iconPath))
{
var icon = new Image { image = EditorGUIUtility.LoadIcon(iconPath) };
m_MainButton.Add(icon);
m_MainButton.tooltip = mainButtonLabel;
}
else
{
m_MainButton.text = mainButtonLabel;
}
Add(m_MainButton);

var separator = new VisualElement();
separator.AddToClassList("dropdown-separator");
Add(separator);

var dropDownButton = new Button(OnTogglePopup);
dropDownButton.AddToClassList("dropdown-arrow");
dropDownButton.AddToClassList("unity-toolbar-toggle");
dropDownButton.Add(new VisualElement());
Add(dropDownButton);

if (hasSeparatorAfter)
{
var divider = new VisualElement();
divider.AddToClassList("separator");
Add(divider);
}

m_PopupContent = new VisualElement();
var tpl = VFXView.LoadUXML(uxmlSource);
tpl.CloneTree(m_PopupContent);
contentContainer.AddStyleSheetPath("VFXToolbar");
}

protected virtual void OnOpenPopup() { }
protected virtual void OnMainButton() { }
protected abstract Vector2 GetPopupSize();

protected void ClosePopup()
{
m_CurrentPopup?.Close();
}

private Vector2 GetPopupPosition() => m_ParentWindow.graphView.ViewToScreenPosition(worldBound.position);

private void OnTogglePopup()
{
// If the user click on the arrow button while the popup is opened
// the popup is then closed (because clicked outside) and immediately reopened
// To prevent this behavior we allow the popup to reopen only after a very short period of time after being closed
var deltaTime = DateTime.UtcNow - m_PopupClosedTimestamp;
if (m_CurrentPopup == null && deltaTime.TotalMilliseconds > 500)
{
m_CurrentPopup = ScriptableObject.CreateInstance<NotifyEditorWindow>();
m_CurrentPopup.hideFlags = HideFlags.HideAndDontSave;
if (m_PopupContent.parent != null)
{
m_PopupContent.parent.Remove(m_PopupContent);
}

m_CurrentPopup.Destroyed += OnPopupClosed;
m_CurrentPopup.rootVisualElement.AddStyleSheetPath("VFXToolbar");
m_CurrentPopup.rootVisualElement.Add(m_PopupContent);
m_CurrentPopup.rootVisualElement.AddToClassList("popup");
m_CurrentPopup.rootVisualElement.RegisterCallback<KeyUpEvent>(OnKeyUp);

OnOpenPopup();
var bounds = new Rect(GetPopupPosition(), localBound.size);
// Offset the bounds to align the popup with the real dropdown left edge
if (m_HasLeftSeparator)
{
bounds.xMin += 6;
}

m_CurrentPopup.ShowAsDropDown(bounds, GetPopupSize(), new[] { PopupLocation.BelowAlignLeft, PopupLocation.AboveAlignLeft });
m_CurrentPopup.minSize = GetPopupSize();
m_CurrentPopup.maxSize = m_CurrentPopup.minSize;
GetNextFocusable(null, m_PopupContent.Children(), false)?.Focus();
}
else if (m_CurrentPopup != null)
{
ClosePopup();
}
}

private void OnPopupClosed()
{
m_CurrentPopup.Destroyed -= OnPopupClosed;
m_CurrentPopup.rootVisualElement.UnregisterCallback<KeyUpEvent>(OnKeyUp);
m_CurrentPopup = null;
m_PopupClosedTimestamp = DateTime.UtcNow;
}

private void OnKeyUp(KeyUpEvent evt)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These last three methods were added to handle keyboard navigation (either with Tab or arrow keys). This was requested by UX designers

{
var focused = m_PopupContent.focusController.focusedElement;
switch (evt.keyCode)
{
case KeyCode.DownArrow:
var next = GetNextFocusable(focused, m_PopupContent.Children(), false);
next?.Focus();
break;
case KeyCode.UpArrow:
var prev = GetNextFocusable(focused, m_PopupContent.Children(), true);
prev?.Focus();
break;
case KeyCode.Escape:
ClosePopup();
break;
}
}

private VisualElement GetNextFocusable(Focusable focused, IEnumerable<VisualElement> elements, bool reverse)
{
var found = focused == null;
return GetNextFocusableRecursive(focused, elements, reverse, ref found);
}

private VisualElement GetNextFocusableRecursive(Focusable focused, IEnumerable<VisualElement> elements, bool reverse, ref bool found)
{
var collection = reverse ? elements.Reverse() : elements;
foreach (var child in collection)
{
if (child == focused)
{
found = true;
continue;
}

if (found && child != focused && child.enabledSelf && child.focusable)
{
return child;
}

var next = GetNextFocusableRecursive(focused, child.Children(), reverse, ref found);
if (next != null)
{
return next;
}
}

return null;
}
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading