@ -172,12 +172,29 @@ namespace Fungus.EditorUtils
}
}
}
}
public const float GridLineSpacingSize = 1 2 0 ;
public const float GridObjectSnap = 2 0 ;
public const float DefaultBlockHeight = 4 0 ;
public const float BlockMinWidth = 6 0 ;
public const float BlockMaxWidth = 2 4 0 ;
public const float MinZoomValue = 0.25f ;
public const float MaxZoomValue = 1f ;
public const int HorizontalPad = 2 0 ;
public const int VerticalPad = 5 ;
//defines the distance between a down and up for a right click to be a click rather than a drag
public const float RightClickTolerance = 5f ;
public const string SearchFieldName = "search" ;
protected readonly Color connectionColor = new Color ( 0.65f , 0.65f , 0.65f , 1.0f ) ;
protected List < BlockCopy > copyList = new List < BlockCopy > ( ) ;
protected List < BlockCopy > copyList = new List < BlockCopy > ( ) ;
public static List < Block > deleteList = new List < Block > ( ) ;
public static List < Block > deleteList = new List < Block > ( ) ;
protected Vector2 startDragPosition ;
protected Vector2 startDragPosition ;
public const float minZoomValue = 0.25f ;
protected GUIStyle nodeStyle , descriptionStyle , handlerStyle ;
public const float maxZoomValue = 1f ;
protected GUIStyle nodeStyle = new GUIStyle ( ) ;
protected static BlockInspector blockInspector ;
protected static BlockInspector blockInspector ;
protected int forceRepaintCount ;
protected int forceRepaintCount ;
protected Texture2D addTexture ;
protected Texture2D addTexture ;
@ -187,12 +204,9 @@ namespace Fungus.EditorUtils
protected Vector2 startSelectionBoxPosition = - Vector2 . one ;
protected Vector2 startSelectionBoxPosition = - Vector2 . one ;
protected List < Block > mouseDownSelectionState = new List < Block > ( ) ;
protected List < Block > mouseDownSelectionState = new List < Block > ( ) ;
protected Color gridLineColor = Color . black ;
protected Color gridLineColor = Color . black ;
protected readonly Color connectionColor = new Color ( 0.65f , 0.65f , 0.65f , 1.0f ) ;
// Context Click occurs on MouseDown which interferes with panning
// Context Click occurs on MouseDown which interferes with panning
// Track right click positions manually to show menus on MouseUp
// Track right click positions manually to show menus on MouseUp
protected Vector2 rightClickDown = - Vector2 . one ;
protected Vector2 rightClickDown = - Vector2 . one ;
protected const float rightClickTolerance = 5f ;
protected const string searchFieldName = "search" ;
private string searchString = string . Empty ;
private string searchString = string . Empty ;
protected Rect searchRect ;
protected Rect searchRect ;
protected Rect popupRect ;
protected Rect popupRect ;
@ -245,13 +259,6 @@ namespace Fungus.EditorUtils
protected virtual void OnEnable ( )
protected virtual void OnEnable ( )
{
{
// All block nodes use the same GUIStyle, but with a different background
nodeStyle . border = new RectOffset ( 2 0 , 2 0 , 5 , 5 ) ;
nodeStyle . padding = nodeStyle . border ;
nodeStyle . contentOffset = Vector2 . zero ;
nodeStyle . alignment = TextAnchor . MiddleCenter ;
nodeStyle . wordWrap = true ;
addTexture = FungusEditorResources . AddSmall ;
addTexture = FungusEditorResources . AddSmall ;
addButtonContent = new GUIContent ( addTexture , "Add a new block" ) ;
addButtonContent = new GUIContent ( addTexture , "Add a new block" ) ;
connectionPointTexture = FungusEditorResources . ConnectionPoint ;
connectionPointTexture = FungusEditorResources . ConnectionPoint ;
@ -272,6 +279,37 @@ namespace Fungus.EditorUtils
# endif
# endif
}
}
//cache styles here, rather than duping them for every block we may ever draw,
// does mean any modifications made to the style when drawing must be undone as you go
protected void InitStyles ( )
{
if ( nodeStyle = = null )
{
nodeStyle = new GUIStyle ( ) ;
// All block nodes use the same GUIStyle, but with a different background
nodeStyle . border = new RectOffset ( HorizontalPad , HorizontalPad , VerticalPad , VerticalPad ) ;
nodeStyle . padding = nodeStyle . border ;
nodeStyle . contentOffset = Vector2 . zero ;
nodeStyle . alignment = TextAnchor . MiddleCenter ;
nodeStyle . wordWrap = true ;
}
if ( EditorStyles . helpBox ! = null & & descriptionStyle = = null )
{
descriptionStyle = new GUIStyle ( EditorStyles . helpBox ) ;
descriptionStyle . wordWrap = true ;
}
if ( EditorStyles . whiteLabel ! = null & & handlerStyle = = null )
{
handlerStyle = new GUIStyle ( EditorStyles . whiteLabel ) ;
handlerStyle . wordWrap = true ;
handlerStyle . margin . top = 0 ;
handlerStyle . margin . bottom = 0 ;
handlerStyle . alignment = TextAnchor . MiddleCenter ;
}
}
protected virtual void OnDisable ( )
protected virtual void OnDisable ( )
{
{
EditorApplication . update - = OnEditorUpdate ;
EditorApplication . update - = OnEditorUpdate ;
@ -530,7 +568,7 @@ namespace Fungus.EditorUtils
break ;
break ;
case EventType . KeyDown :
case EventType . KeyDown :
if ( GUI . GetNameOfFocusedControl ( ) = = s earchFieldName)
if ( GUI . GetNameOfFocusedControl ( ) = = S earchFieldName)
{
{
var centerBlock = false ;
var centerBlock = false ;
var selectBlock = false ;
var selectBlock = false ;
@ -715,6 +753,8 @@ namespace Fungus.EditorUtils
return ;
return ;
}
}
InitStyles ( ) ;
DeleteBlocks ( ) ;
DeleteBlocks ( ) ;
UpdateFilteredBlocks ( ) ;
UpdateFilteredBlocks ( ) ;
@ -787,7 +827,7 @@ namespace Fungus.EditorUtils
// Draw scale bar and labels
// Draw scale bar and labels
GUILayout . Label ( "Scale" , EditorStyles . miniLabel ) ;
GUILayout . Label ( "Scale" , EditorStyles . miniLabel ) ;
var newZoom = GUILayout . HorizontalSlider (
var newZoom = GUILayout . HorizontalSlider (
flowchart . Zoom , minZoomValue , m axZoomValue, GUILayout . MinWidth ( 4 0 ) , GUILayout . MaxWidth ( 1 0 0 )
flowchart . Zoom , MinZoomValue , M axZoomValue, GUILayout . MinWidth ( 4 0 ) , GUILayout . MaxWidth ( 1 0 0 )
) ;
) ;
GUILayout . Label ( flowchart . Zoom . ToString ( "0.0#x" ) , EditorStyles . miniLabel , GUILayout . Width ( 3 0 ) ) ;
GUILayout . Label ( flowchart . Zoom . ToString ( "0.0#x" ) , EditorStyles . miniLabel , GUILayout . Width ( 3 0 ) ) ;
@ -805,7 +845,7 @@ namespace Fungus.EditorUtils
GUILayout . FlexibleSpace ( ) ;
GUILayout . FlexibleSpace ( ) ;
// Draw search bar
// Draw search bar
GUI . SetNextControlName ( s earchFieldName) ;
GUI . SetNextControlName ( S earchFieldName) ;
var newString = EditorGUILayout . TextField ( searchString , ToolbarSeachTextFieldStyle , GUILayout . Width ( 1 5 0 ) ) ;
var newString = EditorGUILayout . TextField ( searchString , ToolbarSeachTextFieldStyle , GUILayout . Width ( 1 5 0 ) ) ;
if ( newString ! = searchString )
if ( newString ! = searchString )
{
{
@ -861,7 +901,7 @@ namespace Fungus.EditorUtils
// Draw block search popup on top of other controls
// Draw block search popup on top of other controls
if ( GUI . GetNameOfFocusedControl ( ) = = s earchFieldName & & filteredBlocks . Length > 0 )
if ( GUI . GetNameOfFocusedControl ( ) = = S earchFieldName & & filteredBlocks . Length > 0 )
{
{
DrawBlockPopup ( e ) ;
DrawBlockPopup ( e ) ;
}
}
@ -1152,7 +1192,7 @@ namespace Fungus.EditorUtils
break ;
break ;
case MouseButton . Right :
case MouseButton . Right :
if ( Vector2 . Distance ( rightClickDown , e . mousePosition ) > r ightClickTolerance)
if ( Vector2 . Distance ( rightClickDown , e . mousePosition ) > R ightClickTolerance)
{
{
rightClickDown = - Vector2 . one ;
rightClickDown = - Vector2 . one ;
}
}
@ -1207,6 +1247,11 @@ namespace Fungus.EditorUtils
Undo . RecordObject ( block , "Block Position" ) ;
Undo . RecordObject ( block , "Block Position" ) ;
tempRect . position + = distance ;
tempRect . position + = distance ;
block . _ NodeRect = tempRect ;
block . _ NodeRect = tempRect ;
if ( FungusEditorPreferences . useGridSnap )
{
block . _ NodeRect = block . _ NodeRect . SnapPosition ( GridObjectSnap ) ;
}
Repaint ( ) ;
}
}
dragBlock = null ;
dragBlock = null ;
@ -1345,12 +1390,6 @@ namespace Fungus.EditorUtils
{
{
DrawGrid ( ) ;
DrawGrid ( ) ;
// Draw connections
foreach ( var block in blocks )
{
DrawConnections ( block ) ;
}
//draw all non selected
//draw all non selected
for ( int i = 0 ; i < blocks . Length ; + + i )
for ( int i = 0 ; i < blocks . Length ; + + i )
{
{
@ -1469,13 +1508,14 @@ namespace Fungus.EditorUtils
{
{
var prevZoom = flowchart . Zoom ;
var prevZoom = flowchart . Zoom ;
flowchart . Zoom + = delta ;
flowchart . Zoom + = delta ;
flowchart . Zoom = Mathf . Clamp ( flowchart . Zoom , minZoomValue , m axZoomValue) ;
flowchart . Zoom = Mathf . Clamp ( flowchart . Zoom , MinZoomValue , M axZoomValue) ;
var deltaSize = position . size / prevZoom - position . size / flowchart . Zoom ;
var deltaSize = position . size / prevZoom - position . size / flowchart . Zoom ;
var offset = - Vector2 . Scale ( deltaSize , center ) ;
var offset = - Vector2 . Scale ( deltaSize , center ) ;
flowchart . ScrollPos + = offset ;
flowchart . ScrollPos + = offset ;
forceRepaintCount = 1 ;
forceRepaintCount = 1 ;
}
}
//Potentially could be faster using https://forum.unity.com/threads/how-do-i-access-the-background-image-used-for-the-animator.501876/
protected virtual void DrawGrid ( )
protected virtual void DrawGrid ( )
{
{
float width = this . position . width / flowchart . Zoom ;
float width = this . position . width / flowchart . Zoom ;
@ -1483,23 +1523,22 @@ namespace Fungus.EditorUtils
Handles . color = gridLineColor ;
Handles . color = gridLineColor ;
float gridSize = 1 2 8f ;
float x = flowchart . ScrollPos . x % grid Size;
float x = flowchart . ScrollPos . x % GridLineSpacing Size;
while ( x < width )
while ( x < width )
{
{
Handles . DrawLine ( new Vector2 ( x , 0 ) , new Vector2 ( x , height ) ) ;
Handles . DrawLine ( new Vector2 ( x , 0 ) , new Vector2 ( x , height ) ) ;
x + = grid Size;
x + = GridLineSpacing Size;
}
}
float y = ( flowchart . ScrollPos . y % grid Size) ;
float y = ( flowchart . ScrollPos . y % GridLineSpacing Size) ;
while ( y < height )
while ( y < height )
{
{
if ( y > = 0 )
if ( y > = 0 )
{
{
Handles . DrawLine ( new Vector2 ( 0 , y ) , new Vector2 ( width , y ) ) ;
Handles . DrawLine ( new Vector2 ( 0 , y ) , new Vector2 ( width , y ) ) ;
}
}
y + = grid Size;
y + = GridLineSpacing Size;
}
}
Handles . color = Color . white ;
Handles . color = Color . white ;
@ -1543,6 +1582,9 @@ namespace Fungus.EditorUtils
return newBlock ;
return newBlock ;
}
}
//prevent every DrawConnections from allocating a new list for all of its connections
protected List < Block > connectedBlocksWorkSpace = new List < Block > ( ) ;
protected virtual void DrawConnections ( Block block )
protected virtual void DrawConnections ( Block block )
{
{
if ( block = = null )
if ( block = = null )
@ -1550,7 +1592,6 @@ namespace Fungus.EditorUtils
return ;
return ;
}
}
var connectedBlocks = new List < Block > ( ) ;
bool blockIsSelected = flowchart . SelectedBlock = = block ;
bool blockIsSelected = flowchart . SelectedBlock = = block ;
@ -1578,10 +1619,10 @@ namespace Fungus.EditorUtils
bool highlight = command . IsExecuting | | ( blockIsSelected & & commandIsSelected ) ;
bool highlight = command . IsExecuting | | ( blockIsSelected & & commandIsSelected ) ;
connectedBlocks . Clear ( ) ;
connectedBlocksWorkSpace . Clear ( ) ;
command . GetConnectedBlocks ( ref connectedBlocks ) ;
command . GetConnectedBlocks ( ref connectedBlocksWorkSpace ) ;
foreach ( var blockB in connectedBlocks )
foreach ( var blockB in connectedBlocksWorkSpace )
{
{
if ( blockB = = null | |
if ( blockB = = null | |
block = = blockB | |
block = = blockB | |
@ -1945,7 +1986,7 @@ namespace Fungus.EditorUtils
case "Find" :
case "Find" :
blockPopupSelection = 0 ;
blockPopupSelection = 0 ;
popupScroll = Vector2 . zero ;
popupScroll = Vector2 . zero ;
EditorGUI . FocusTextInControl ( s earchFieldName) ;
EditorGUI . FocusTextInControl ( S earchFieldName) ;
e . Use ( ) ;
e . Use ( ) ;
break ;
break ;
}
}
@ -1967,10 +2008,14 @@ namespace Fungus.EditorUtils
searchString = string . Empty ;
searchString = string . Empty ;
}
}
static protected List < Block > blockGraphicsUniqueListWorkSpace = new List < Block > ( ) ;
static protected List < Block > blockGraphicsConnectedWorkSpace = new List < Block > ( ) ;
protected virtual BlockGraphics GetBlockGraphics ( Block block )
protected virtual BlockGraphics GetBlockGraphics ( Block block )
{
{
var graphics = new BlockGraphics ( ) ;
var graphics = new BlockGraphics ( ) ;
blockGraphicsUniqueListWorkSpace . Clear ( ) ;
blockGraphicsConnectedWorkSpace . Clear ( ) ;
Color defaultTint ;
Color defaultTint ;
if ( block . _ EventHandler ! = null )
if ( block . _ EventHandler ! = null )
{
{
@ -1981,19 +2026,18 @@ namespace Fungus.EditorUtils
else
else
{
{
// Count the number of unique connections (excluding self references)
// Count the number of unique connections (excluding self references)
var uniqueList = new List < Block > ( ) ;
block . GetConnectedBlocks ( ref blockGraphicsConnectedWorkSpace ) ;
var connectedBlocks = block . GetConnectedBlocks ( ) ;
foreach ( var connectedBlock in blockGraphicsConnectedWorkSpace )
foreach ( var connectedBlock in connectedBlocks )
{
{
if ( connectedBlock = = block | |
if ( connectedBlock = = block | |
uniqueList . Contains ( connectedBlock ) )
blockGraphicsUniqueListWorkSpace . Contains ( connectedBlock ) )
{
{
continue ;
continue ;
}
}
uniqueList . Add ( connectedBlock ) ;
blockGraphicsUniqueListWorkSpace . Add ( connectedBlock ) ;
}
}
if ( uniqueList . Count > 1 )
if ( blockGraphicsUniqueListWorkSpace . Count > 1 )
{
{
graphics . offTexture = FungusEditorResources . ChoiceNodeOff ;
graphics . offTexture = FungusEditorResources . ChoiceNodeOff ;
graphics . onTexture = FungusEditorResources . ChoiceNodeOn ;
graphics . onTexture = FungusEditorResources . ChoiceNodeOn ;
@ -2015,79 +2059,81 @@ namespace Fungus.EditorUtils
private void DrawBlock ( Block block , Rect scriptViewRect )
private void DrawBlock ( Block block , Rect scriptViewRect )
{
{
float nodeWidthA = nodeStyle . CalcSize ( new GUIContent ( block . BlockName ) ) . x + 1 0 ;
float nodeWidthA = nodeStyle . CalcSize ( new GUIContent ( block . BlockName ) ) . x + 1 0 ;
float nodeWidthB = 0f ;
if ( block . _ EventHandler ! = null )
{
nodeWidthB = nodeStyle . CalcSize ( new GUIContent ( block . _ EventHandler . GetSummary ( ) ) ) . x + 1 0 ;
}
Rect tempRect = block . _ NodeRect ;
Rect tempRect = block . _ NodeRect ;
tempRect . width = Mathf . Max ( Mathf . Max ( nodeWidthA , nodeWidthB ) , 1 2 0 ) ;
tempRect . width = Mathf . Clamp ( nodeWidthA , BlockMinWidth , BlockMaxWidth ) ;
tempRect . height = 4 0 ;
tempRect . height = DefaultBlockHeight ;
if ( FungusEditorPreferences . useGridSnap )
{
tempRect = tempRect . SnapWidth ( GridObjectSnap ) ;
}
block . _ NodeRect = tempRect ;
block . _ NodeRect = tempRect ;
Rect windowRect = new Rect ( block . _ NodeRect ) ;
// Draw blocks
windowRect . position + = flowchart . ScrollPos ;
var graphics = GetBlockGraphics ( block ) ;
Rect windowRelativeRect = new Rect ( block . _ NodeRect ) ;
if ( FungusEditorPreferences . useGridSnap )
{
windowRelativeRect = windowRelativeRect . SnapPosition ( GridObjectSnap ) ;
}
windowRelativeRect . position + = flowchart . ScrollPos ;
//skip if outside of view
//skip if outside of view
if ( ! scriptViewRect . Overlaps ( windowRect ) )
if ( ! scriptViewRect . Overlaps ( windowRelativeRe ct ) )
return ;
return ;
// Draw blocks
var tmpNormBg = nodeStyle . normal . background ;
GUIStyle nodeStyleCopy = new GUIStyle ( nodeStyle ) ;
var graphics = GetBlockGraphics ( block ) ;
// Make sure node is wide enough to fit the node name text
float width = nodeStyleCopy . CalcSize ( new GUIContent ( block . BlockName ) ) . x ;
tempRect = block . _ NodeRect ;
tempRect . width = Mathf . Max ( block . _ NodeRect . width , width ) ;
block . _ NodeRect = tempRect ;
// Draw untinted highlight
// Draw untinted highlight
if ( block . IsSelected & & ! block . IsControlSelected )
if ( block . IsSelected & & ! block . IsControlSelected )
{
{
GUI . backgroundColor = Color . white ;
GUI . backgroundColor = Color . white ;
nodeStyleCopy . normal . background = graphics . onTexture ;
nodeStyle . normal . background = graphics . onTexture ;
GUI . Box ( windowRect , "" , nodeStyleCopy ) ;
GUI . Box ( windowRelativeRect , "" , nodeStyle ) ;
nodeStyle . normal . background = tmpNormBg ;
}
}
if ( block . IsControlSelected & & ! block . IsSelected )
if ( block . IsControlSelected & & ! block . IsSelected )
{
{
GUI . backgroundColor = Color . white ;
GUI . backgroundColor = Color . white ;
nodeStyleCopy . normal . background = graphics . onTexture ;
nodeStyle . normal . background = graphics . onTexture ;
var c = GUI . backgroundColor ;
var c = GUI . backgroundColor ;
c . a = 0.5f ;
c . a = 0.5f ;
GUI . backgroundColor = c ;
GUI . backgroundColor = c ;
GUI . Box ( windowRect , "" , nodeStyleCopy ) ;
GUI . Box ( windowRelativeRect , "" , nodeStyle ) ;
nodeStyle . normal . background = tmpNormBg ;
}
}
// Draw tinted block; ensure text is readable
// Draw tinted block; ensure text is readable
var brightness = graphics . tint . r * 0.3 + graphics . tint . g * 0.59 + graphics . tint . b * 0.11 ;
var brightness = graphics . tint . r * 0.3 + graphics . tint . g * 0.59 + graphics . tint . b * 0.11 ;
nodeStyleCopy . normal . textColor = brightness > = 0.5 ? Color . black : Color . white ;
var tmpNormTxtCol = nodeStyle . normal . textColor ;
nodeStyle . normal . textColor = brightness > = 0.5 ? Color . black : Color . white ;
if ( GUI . GetNameOfFocusedControl ( ) = = s earchFieldName & & ! block . IsFiltered )
if ( GUI . GetNameOfFocusedControl ( ) = = S earchFieldName & & ! block . IsFiltered )
{
{
graphics . tint . a * = 0.2f ;
graphics . tint . a * = 0.2f ;
}
}
nodeStyleCopy . normal . background = graphics . offTexture ;
nodeStyle . normal . background = graphics . offTexture ;
GUI . backgroundColor = graphics . tint ;
GUI . backgroundColor = graphics . tint ;
GUI . Box ( windowRect , block . BlockName , nodeStyleCopy ) ;
GUI . Box ( windowRelativeRe ct , block . BlockName , nodeStyle ) ;
GUI . backgroundColor = Color . white ;
GUI . backgroundColor = Color . white ;
if ( block . Description . Length > 0 )
if ( block . Description . Length > 0 )
{
{
GUIStyle descriptionStyle = new GUIStyle ( EditorStyles . helpBox ) ;
descriptionStyle . wordWrap = true ;
var content = new GUIContent ( block . Description ) ;
var content = new GUIContent ( block . Description ) ;
windowRect . y + = windowRect . height ;
windowRelativeRect . y + = windowRelativeRect . height ;
windowRect . height = descriptionStyle . CalcHeight ( content , windowRect . width ) ;
windowRelativeRe ct . height = descriptionStyle . CalcHeight ( content , windowRelative Rect . width ) ;
GUI . Label ( windowRect , content , descriptionStyle ) ;
GUI . Label ( windowRelativeRe ct , content , descriptionStyle ) ;
}
}
GUI . backgroundColor = Color . white ;
GUI . backgroundColor = Color . white ;
nodeStyle . normal . textColor = tmpNormTxtCol ;
nodeStyle . normal . background = tmpNormBg ;
// Draw Event Handler labels
// Draw Event Handler labels
if ( block . _ EventHandler ! = null )
if ( block . _ EventHandler ! = null )
{
{
@ -2098,12 +2144,6 @@ namespace Fungus.EditorUtils
handlerLabel = "<" + info . EventHandlerName + "> " ;
handlerLabel = "<" + info . EventHandlerName + "> " ;
}
}
GUIStyle handlerStyle = new GUIStyle ( EditorStyles . whiteLabel ) ;
handlerStyle . wordWrap = true ;
handlerStyle . margin . top = 0 ;
handlerStyle . margin . bottom = 0 ;
handlerStyle . alignment = TextAnchor . MiddleCenter ;
Rect rect = new Rect ( block . _ NodeRect ) ;
Rect rect = new Rect ( block . _ NodeRect ) ;
rect . height = handlerStyle . CalcHeight ( new GUIContent ( handlerLabel ) , block . _ NodeRect . width ) ;
rect . height = handlerStyle . CalcHeight ( new GUIContent ( handlerLabel ) , block . _ NodeRect . width ) ;
rect . x + = flowchart . ScrollPos . x ;
rect . x + = flowchart . ScrollPos . x ;
@ -2111,6 +2151,9 @@ namespace Fungus.EditorUtils
GUI . Label ( rect , handlerLabel , handlerStyle ) ;
GUI . Label ( rect , handlerLabel , handlerStyle ) ;
}
}
DrawConnections ( block ) ;
}
}
}
}
}
}