Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
50 changes: 47 additions & 3 deletions UnityFigmaBridge/Editor/FigmaApi/FigmaApiData.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using Newtonsoft.Json;

namespace UnityFigmaBridge.Editor.FigmaApi
{
Expand Down Expand Up @@ -74,7 +75,7 @@ public class FigmaFile
public string lastModified;
public string thumbnailUrl;
public string version;
public string owner;
public string role;
}

/// <summary>
Expand Down Expand Up @@ -263,7 +264,8 @@ public enum LayoutAlign
/// <summary>
/// The top two rows of a matrix that represents the 2D transform of this node relative to its parent. The bottom row of the matrix is implicitly always (0, 0, 1). Use to transform coordinates in geometry. Only present if geometry=paths is passed
/// </summary>
public float[,] relativeTransform;
[JsonConverter(typeof(CustomJsonConverter))]
public List<List<float>> relativeTransform;
// TO DO - Implement

/// <summary>
Expand Down Expand Up @@ -444,7 +446,49 @@ public enum OverflowDirection
public ArcData arcData;

}


public class CustomJsonConverter : JsonConverter<List<List<float>>>
{
public override void WriteJson(JsonWriter writer, List<List<float>> value, JsonSerializer serializer)
{
writer.WriteStartArray();
foreach (var innerList in value)
{
writer.WriteStartArray();
foreach (var item in innerList)
{
writer.WriteValue(item);
}
writer.WriteEndArray();
}
writer.WriteEndArray();
}

public override List<List<float>> ReadJson(JsonReader reader, Type objectType, List<List<float>> existingValue, bool hasExistingValue, JsonSerializer serializer)
{
List<List<float>> result = new List<List<float>>();
while (reader.Read())
{
if (reader.TokenType == JsonToken.EndArray)
break;

List<float> innerList = new List<float>();
while (reader.Read())
{
if (reader.TokenType == JsonToken.EndArray)
break;

if (reader.Value == null)
continue;

innerList.Add(float.Parse(reader.Value.ToString()));
}
result.Add(innerList);
}
return result;
}
}

public class Color
{
public float r;
Expand Down
5 changes: 5 additions & 0 deletions UnityFigmaBridge/Editor/Nodes/FigmaLayoutManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ node.overflowDirection is Node.OverflowDirection.VERTICAL_SCROLLING
case Node.LayoutMode.VERTICAL:
layoutGroup= UnityUiUtils.GetOrAddComponent<VerticalLayoutGroup>(targetLayoutObject);
layoutGroup.childForceExpandWidth= layoutGroup.childForceExpandHeight = false;

// Setup alignment according to Figma layout. Primary is Vertical
switch (node.primaryAxisAlignItems)
{
Expand Down Expand Up @@ -116,6 +117,9 @@ node.overflowDirection is Node.OverflowDirection.VERTICAL_SCROLLING
_ => layoutGroup.childAlignment
};
break;
case Node.PrimaryAxisAlignItems.SPACE_BETWEEN:
layoutGroup.childAlignment = TextAnchor.UpperLeft;
break;
default:
throw new ArgumentOutOfRangeException();
}
Expand Down Expand Up @@ -151,6 +155,7 @@ node.overflowDirection is Node.OverflowDirection.VERTICAL_SCROLLING
Node.CounterAxisAlignItems.MAX => TextAnchor.LowerRight,
_ => layoutGroup.childAlignment
},
Node.PrimaryAxisAlignItems.SPACE_BETWEEN => TextAnchor.UpperLeft,
_ => throw new ArgumentOutOfRangeException()
};
break;
Expand Down
82 changes: 42 additions & 40 deletions UnityFigmaBridge/Editor/Nodes/FigmaNodeManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -250,55 +250,57 @@ private static void SetupFill(FigmaImage figmaImage, Node node)
{
if (node.fills.Length > 0)
{
var firstFill = node.fills[0];
switch (firstFill.type)
foreach (var fill in node.fills)
{
case Paint.PaintType.IMAGE:
SetupImageFill(figmaImage, firstFill);
break;
case Paint.PaintType.GRADIENT_LINEAR:
case Paint.PaintType.GRADIENT_RADIAL:
figmaImage.FillGradient = FigmaDataUtils.ToUnityGradient(firstFill);
figmaImage.Fill = firstFill.type == Paint.PaintType.GRADIENT_RADIAL
? FigmaImage.FillStyle.RadialGradient
: FigmaImage.FillStyle.LinearGradient;
switch (fill.type)
{
case Paint.PaintType.IMAGE:
SetupImageFill(figmaImage, fill);
break;
case Paint.PaintType.GRADIENT_LINEAR:
case Paint.PaintType.GRADIENT_RADIAL:
figmaImage.FillGradient = FigmaDataUtils.ToUnityGradient(fill);
figmaImage.Fill = fill.type == Paint.PaintType.GRADIENT_RADIAL
? FigmaImage.FillStyle.RadialGradient
: FigmaImage.FillStyle.LinearGradient;

var gradientHandlePositions = firstFill.gradientHandlePositions;
if (gradientHandlePositions.Length == 3)
{
figmaImage.GradientHandlePositions = new[]
var gradientHandlePositions = fill.gradientHandlePositions;
if (gradientHandlePositions.Length == 3)
{
FigmaDataUtils.ToUnityVector(gradientHandlePositions[0]),
FigmaDataUtils.ToUnityVector(gradientHandlePositions[1]),
FigmaDataUtils.ToUnityVector(gradientHandlePositions[2])
};
}
figmaImage.GradientHandlePositions = new[]
{
FigmaDataUtils.ToUnityVector(gradientHandlePositions[0]),
FigmaDataUtils.ToUnityVector(gradientHandlePositions[1]),
FigmaDataUtils.ToUnityVector(gradientHandlePositions[2])
};
}

break;
case Paint.PaintType.SOLID:
// Default, fill colour set below
break;
case Paint.PaintType.GRADIENT_ANGULAR:
// Unsupported
break;
case Paint.PaintType.GRADIENT_DIAMOND:
// Unsupported
break;
case Paint.PaintType.EMOJI:
// Unsupported
break;
}
break;
case Paint.PaintType.SOLID:
// Default, fill colour set below
break;
case Paint.PaintType.GRADIENT_ANGULAR:
// Unsupported
break;
case Paint.PaintType.GRADIENT_DIAMOND:
// Unsupported
break;
case Paint.PaintType.EMOJI:
// Unsupported
break;
}

// for invisible fills, disable
if (!firstFill.visible) figmaImage.enabled = false;
// for invisible fills, disable
if (!fill.visible) figmaImage.enabled = false;

// We don't use the base "color" attribute - this is reserved for transparency groups etc
// So as not to apply to both stroke and fill
figmaImage.FillColor = FigmaDataUtils.GetUnityFillColor(firstFill);
// We don't use the base "color" attribute - this is reserved for transparency groups etc
// So as not to apply to both stroke and fill
figmaImage.FillColor = FigmaDataUtils.GetUnityFillColor(fill);
}
}
else
figmaImage.FillColor =
new Color(0, 0, 0, 0); // Transparent fill - TODO find neater solution
new Color(0, 0, 0, 0); // Transparent fill - TODO find neater solution
}


Expand Down
10 changes: 5 additions & 5 deletions UnityFigmaBridge/Editor/Nodes/NodeTransformManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,20 +24,20 @@ public static void ApplyFigmaTransform(RectTransform targetRectTransform, Node f
if (figmaNode.relativeTransform != null)
{
// Apply the "relativeTransform" from Figma Node for translation and rotation
targetRectTransform.anchoredPosition = new Vector2(figmaNode.relativeTransform[0, 2],
-figmaNode.relativeTransform[1, 2]);
targetRectTransform.anchoredPosition = new Vector2(figmaNode.relativeTransform[0][2],
-figmaNode.relativeTransform[1][2]);
var rotation = Mathf.Rad2Deg *
Mathf.Atan2(-figmaNode.relativeTransform[1, 0], figmaNode.relativeTransform[0, 0]);
Mathf.Atan2(-figmaNode.relativeTransform[1][0], figmaNode.relativeTransform[0][0]);
targetRectTransform.localRotation = Quaternion.Euler(0, 0, rotation);
}

if (figmaNode.relativeTransform[0,0] < 0)
if (figmaNode.relativeTransform[0][0] < 0)
{
//horizontal mirror
targetRectTransform.localScale = new Vector3(-targetRectTransform.localScale.x, targetRectTransform.localScale.y, targetRectTransform.localScale.z);
targetRectTransform.localRotation = Quaternion.Euler(targetRectTransform.transform.rotation.eulerAngles.x, targetRectTransform.transform.rotation.eulerAngles.y, targetRectTransform.transform.rotation.eulerAngles.z - 180);
}
if (figmaNode.relativeTransform[1,1] < 0)
if (figmaNode.relativeTransform[1][1] < 0)
{
//vertical mirror
targetRectTransform.localScale = new Vector3(targetRectTransform.localScale.x, -targetRectTransform.localScale.y, targetRectTransform.localScale.z);
Expand Down