// Copyright (c) Wojciech Figat. All rights reserved. using System; using FlaxEditor.Scripting; using FlaxEngine; using FlaxEngine.Utilities; namespace FlaxEditor.Surface { /// /// Describes GUI style used by the surface. /// [HideInEditor] public class SurfaceStyle { /// /// Description with the colors used by the surface. /// public struct ColorsData { /// /// The connecting nodes color. /// public Color Connecting; /// /// The connecting nodes color (for valid connection). /// public Color ConnectingValid; /// /// The connecting nodes color (for invalid connection). /// public Color ConnectingInvalid; /// /// The impulse boxes color. /// public Color Impulse; /// /// The boolean boxes color. /// public Color Bool; /// /// The integer boxes color. /// public Color Integer; /// /// The floating point boxes color. /// public Color Float; /// /// The vector boxes color. /// public Color Vector; /// /// The string boxes color. /// public Color String; /// /// The object boxes color. /// public Color Object; /// /// The rotation boxes color. /// public Color Rotation; /// /// The transform boxes color. /// public Color Transform; /// /// The enum boxes color. /// public Color Enum; /// /// The bounding box color. /// public Color Bounds; /// /// The structures color. /// public Color Structures; /// /// The default boxes color. /// public Color Default; } /// /// Descriptions for icons used by the surface. /// public struct IconsData { /// /// Icon for boxes without connections. /// public SpriteHandle BoxOpen; /// /// Icon for boxes with connections. /// public SpriteHandle BoxClose; /// /// Icon for impulse boxes without connections. /// public SpriteHandle ArrowOpen; /// /// Icon for impulse boxes with connections. /// public SpriteHandle ArrowClose; } /// /// The colors. /// public ColorsData Colors; /// /// The icons. /// public IconsData Icons; /// /// The background image (tiled). /// public Texture Background; /// /// Boxes drawing callback. /// public Action DrawBox = DefaultDrawBox; /// /// Custom box connection drawing callback (null by default). /// public Action DrawConnection = null; /// /// Gets the color for the connection. /// /// The connection type. /// The connection hint. /// The color. public void GetConnectionColor(ScriptType type, ConnectionsHint hint, out Color color) { if (type == ScriptType.Null) { if (hint == ConnectionsHint.Vector) color = Colors.Vector; else if (hint == ConnectionsHint.Scalar) color = Colors.Float; else if (hint == ConnectionsHint.Enum) color = Colors.Enum; else color = Colors.Default; } else if (type.IsPointer || type.IsReference) { // Find underlying type without `*` or `&` var typeName = type.TypeName; type = TypeUtils.GetType(typeName.Substring(0, typeName.Length - 1)); GetConnectionColor(type, hint, out color); } else if (type.IsArray) GetConnectionColor(type.GetElementType(), hint, out color); else if (type.Type == typeof(void)) color = Colors.Impulse; else if (type.Type == typeof(bool)) color = Colors.Bool; else if (type.Type == typeof(byte) || type.Type == typeof(sbyte) || type.Type == typeof(char) || type.Type == typeof(short) || type.Type == typeof(ushort) || type.Type == typeof(int) || type.Type == typeof(uint) || type.Type == typeof(long) || type.Type == typeof(ulong)) color = Colors.Integer; else if (type.Type == typeof(float) || type.Type == typeof(double) || hint == ConnectionsHint.Scalar) color = Colors.Float; else if (type.Type == typeof(Vector2) || type.Type == typeof(Vector3) || type.Type == typeof(Vector4) || type.Type == typeof(Color)) color = Colors.Vector; else if (type.Type == typeof(Float2) || type.Type == typeof(Float3) || type.Type == typeof(Float4)) color = Colors.Vector; else if (type.Type == typeof(Double2) || type.Type == typeof(Double3) || type.Type == typeof(Double4)) color = Colors.Vector; else if (type.Type == typeof(Int2) || type.Type == typeof(Int3) || type.Type == typeof(Int4)) color = Colors.Vector; else if (type.Type == typeof(string)) color = Colors.String; else if (type.Type == typeof(Quaternion)) color = Colors.Rotation; else if (type.Type == typeof(Transform)) color = Colors.Transform; else if (type.Type == typeof(BoundingBox) || type.Type == typeof(BoundingSphere) || type.Type == typeof(BoundingFrustum)) color = Colors.Bounds; else if (type.IsEnum || hint == ConnectionsHint.Enum) color = Colors.Enum; else if (type.IsValueType) color = Colors.Structures; else if (ScriptType.FlaxObject.IsAssignableFrom(type) || type.IsInterface) color = Colors.Object; else if (hint == ConnectionsHint.Vector) color = Colors.Vector; else color = Colors.Default; } private static void DefaultDrawBox(Elements.Box box) { var rect = new Rectangle(Float2.Zero, box.Size); // Size culling const float minBoxSize = 5.0f; if (rect.Size.LengthSquared < minBoxSize * minBoxSize) return; // Debugging boxes size //Render2D.DrawRectangle(rect, Color.Orange); return; // Draw icon bool hasConnections = box.HasAnyConnection; float alpha = box.Enabled && box.IsActive ? 1.0f : 0.6f; Color color = box.CurrentTypeColor * alpha; var style = box.Surface.Style; SpriteHandle icon; if (box.CurrentType.Type == typeof(void)) icon = hasConnections ? style.Icons.ArrowClose : style.Icons.ArrowOpen; else icon = hasConnections ? style.Icons.BoxClose : style.Icons.BoxOpen; color *= box.ConnectionsHighlightIntensity + 1; Render2D.DrawSprite(icon, rect, color); // Draw selection hint if (box.IsSelected) { float outlineAlpha = Mathf.Sin(Time.TimeSinceStartup * 4.0f) * 0.5f + 0.5f; float outlineWidth = Mathf.Lerp(1.5f, 4.0f, outlineAlpha); var outlineRect = new Rectangle(rect.X - outlineWidth, rect.Y - outlineWidth, rect.Width + outlineWidth * 2, rect.Height + outlineWidth * 2); Render2D.DrawSprite(icon, outlineRect, FlaxEngine.GUI.Style.Current.BorderSelected.RGBMultiplied(1.0f + outlineAlpha * 0.4f)); } } /// /// Function used to create style for the given surface type. Can be overriden to provide some customization via user plugin. /// public static Func CreateStyleHandler = CreateDefault; /// /// Creates the default style. /// /// The editor. /// Created style. public static SurfaceStyle CreateDefault(Editor editor) { return new SurfaceStyle { Colors = { // Connecting nodes Connecting = Color.White, ConnectingValid = new Color(11, 252, 11), ConnectingInvalid = new Color(252, 12, 11), // Boxes Impulse = new Color(252, 255, 255), Bool = new Color(237, 28, 36), Integer = new Color(181, 230, 29), Float = new Color(146, 208, 80), Vector = new Color(255, 251, 1), String = new Color(163, 73, 164), Object = new Color(0, 162, 232), Rotation = new Color(153, 217, 234), Transform = new Color(255, 127, 39), Enum = new Color(20, 151, 20), Bounds = new Color(34, 117, 76), Structures = new Color(228, 138, 185), Default = new Color(200, 200, 200), }, Icons = { BoxOpen = editor.Icons.VisjectBoxOpen32, BoxClose = editor.Icons.VisjectBoxClosed32, ArrowOpen = editor.Icons.VisjectArrowOpen32, ArrowClose = editor.Icons.VisjectArrowClosed32, }, Background = editor.UI.VisjectSurfaceBackground, }; } /// /// Draws a simple straight connection between two locations. /// /// The start position. /// The end position. /// The line color. /// The line thickness. public static void DrawStraightConnection(Float2 startPos, Float2 endPos, Color color, float thickness = 1.0f) { var sub = endPos - startPos; var length = sub.Length; if (length > Mathf.Epsilon) { var dir = sub / length; var arrowRect = new Rectangle(0, 0, 16.0f, 16.0f); float rotation = Float2.Dot(dir, Float2.UnitY); if (endPos.X < startPos.X) rotation = 2 - rotation; var sprite = Editor.Instance.Icons.VisjectArrowClosed32; var arrowTransform = Matrix3x3.Translation2D(-6.5f, -8) * Matrix3x3.RotationZ(rotation * Mathf.PiOverTwo) * Matrix3x3.Translation2D(endPos - dir * 8); Render2D.PushTransform(ref arrowTransform); Render2D.DrawSprite(sprite, arrowRect, color); Render2D.PopTransform(); endPos -= dir * 4.0f; } Render2D.DrawLine(startPos, endPos, color); } } }