예제 #1
0
    private static void AssertStyleNodesEqual(StyleNodeTestDef expected, StyleASTNode actual)
    {
        Assert.AreEqual(expected.type, actual.GetType());
        if (expected.identifier != null)
        {
            if (actual is StyleNodeContainer n)
            {
                Assert.AreEqual(expected.identifier, n.identifier);
            }
            else if (actual is StyleIdentifierNode id)
            {
                Assert.AreEqual(expected.identifier, id.name);
            }
            else
            {
                Assert.IsTrue(false, $"Expected node to have an identifier {expected.identifier} but {actual} did not");
            }
        }

        if (expected.nodeType != 0)
        {
            Assert.AreEqual(expected.nodeType, actual.type);
        }

        if (expected.type == typeof(MeasurementNode))
        {
            AssertMeasurementNode(expected, actual as MeasurementNode);
        }


        if (expected.rawValue != null)
        {
            FieldInfo fieldInfo = null;
            if (ReflectionUtil.IsField(actual.GetType(), "rawValue", out fieldInfo) || ReflectionUtil.IsField(actual.GetType(), "value", out fieldInfo))
            {
                Assert.AreEqual(expected.rawValue, fieldInfo.GetValue(actual));
            }
            else
            {
                Assert.IsTrue(false, $"Expected {actual} to have a value or rawValue field, it did not");
            }
        }

        if (expected.children != null)
        {
            if (actual is StyleNodeContainer c)
            {
                Assert.AreEqual(expected.children.Length, c.children.Count);

                for (int i = 0; i < expected.children.Length; i++)
                {
                    AssertStyleNodesEqual(expected.children[i], c.children[i]);
                }
            }
            else
            {
                Assert.IsTrue(false, $"Expected node to have children but {actual} is not a StyleContainer");
            }
        }
    }
예제 #2
0
        private UISoundData CompileSoundProperties(SoundRootNode soundRootNode)
        {
            UISoundData soundData = new UISoundData();

            // set defaults
            soundData.duration   = new UITimeMeasurement(1, UITimeMeasurementUnit.Percentage);
            soundData.pitch      = 1;
            soundData.iterations = 1;
            soundData.tempo      = 1;

            for (int i = 0; i < soundRootNode.children.Count; i++)
            {
                StyleASTNode property = soundRootNode.children[i];
                if (property is SoundPropertyNode soundPropertyNode)
                {
                    StyleASTNode value = soundPropertyNode.value;
                    switch (soundPropertyNode.name.ToLower())
                    {
                    case "asset":
                        soundData.asset = StylePropertyMappers.MapString(value, context);
                        break;

                    case "duration":
                        soundData.duration = StylePropertyMappers.MapUITimeMeasurement(value, context);
                        break;

                    case "iterations":
                        soundData.iterations = (int)StylePropertyMappers.MapNumberOrInfinite(value, context);
                        break;

                    case "pitch":
                        soundData.pitch = StylePropertyMappers.MapNumber(value, context);
                        break;

                    case "pitchrange":
                        soundData.pitchRange = StylePropertyMappers.MapFloatRange(value, context);
                        break;

                    case "tempo":
                        soundData.tempo = StylePropertyMappers.MapNumber(value, context);
                        break;

                    case "volume":
                        soundData.volume = StylePropertyMappers.MapNumber(value, context);
                        break;

                    case "mixergroup":
                        soundData.mixerGroup = StylePropertyMappers.MapString(value, context);
                        break;
                    }
                }
                else
                {
                    throw new CompileException(property, "Expected a sound property.");
                }
            }

            return(soundData);
        }
예제 #3
0
        private StyleASTNode ParseRgb()
        {
            AssertTokenTypeAndAdvance(StyleTokenType.Rgb);
            AssertTokenTypeAndAdvance(StyleTokenType.ParenOpen);

            StyleASTNode red = ParseLiteralOrReference(StyleTokenType.Number);

            AssertTokenTypeAndAdvance(StyleTokenType.Comma);

            StyleASTNode green = ParseLiteralOrReference(StyleTokenType.Number);

            AssertTokenTypeAndAdvance(StyleTokenType.Comma);

            StyleASTNode blue = ParseLiteralOrReference(StyleTokenType.Number);

            AssertTokenTypeAndAdvance(StyleTokenType.ParenClose);

            return(StyleASTNodeFactory.RgbNode(red, green, blue));
        }
예제 #4
0
        /// <summary>
        /// Returns a referenced StyleASTNode if the passed in node is a ReferenceNode.
        /// Only called once all references have been resolved in the constants list.
        /// </summary>
        /// <param name="node">A node that can be a ReferenceNode or something else.</param>
        /// <returns>The referenced node or the node itself if it's a regular one.</returns>
        /// <exception cref="CompileException">thrown in case a reference cannot be resolved.</exception>
        public StyleASTNode GetValueForReference(StyleASTNode node)
        {
            if (node is ConstReferenceNode referenceNode)
            {
                for (int index = 0; index < constants.Count; index++)
                {
                    StyleConstant c = constants[index];
                    if (c.name == referenceNode.identifier)
                    {
                        return(c.value);
                    }
                }

                if (referenceNode.children.Count > 0)
                {
                    if (importedStyleConstants.ContainsKey(referenceNode.identifier))
                    {
                        DotAccessNode importedConstant = (DotAccessNode)referenceNode.children[0];

                        StyleConstant importedStyleConstant = importedStyleConstants[referenceNode.identifier]
                                                              .Find(importedConstant.propertyName, s_FindStyleConstant);

                        if (importedStyleConstant.name == null)
                        {
                            throw new CompileException(importedConstant, $"Could not find referenced property '{importedConstant.propertyName}' in imported scope '{referenceNode.identifier}'.");
                        }

                        return(importedStyleConstant.value);
                    }

                    throw new CompileException(referenceNode, "Constants cannot reference members of other constants.");
                }


                throw new CompileException(referenceNode, $"Couldn't resolve reference {referenceNode}. Known references are: {PrintConstants()}");
            }

            return(node);
        }
예제 #5
0
        private StyleASTNode ParsePropertyValue()
        {
            StyleToken   propertyToken = tokenStream.Current;
            StyleASTNode propertyValue;

            switch (tokenStream.Current.styleTokenType)
            {
            case StyleTokenType.Number:
                StyleLiteralNode value = StyleASTNodeFactory.NumericLiteralNode(tokenStream.Current.value).WithLocation(propertyToken) as StyleLiteralNode;
                tokenStream.Advance();
                if (!IsAnyTokenType(StyleTokenType.EndStatement, StyleTokenType.Number, StyleTokenType.Comma, StyleTokenType.ParenClose))
                {
                    UnitNode unit = ParseUnit().WithLocation(tokenStream.Previous) as UnitNode;
                    propertyValue = StyleASTNodeFactory.MeasurementNode(value, unit);
                }
                else
                {
                    propertyValue = value;
                }

                break;

            case StyleTokenType.String:

                propertyValue = StyleASTNodeFactory.StringLiteralNode(tokenStream.Current.value);
                tokenStream.Advance();

                if (tokenStream.Current == StyleTokenType.BracesOpen)
                {
                    TextUtil.StringBuilder.Clear();
                    StyleLiteralNode n = (StyleLiteralNode)propertyValue;

                    TextUtil.StringBuilder.Append("\"");
                    TextUtil.StringBuilder.Append(n.rawValue);
                    TextUtil.StringBuilder.Append("\" ");

                    while (tokenStream.HasMoreTokens && tokenStream.Current != StyleTokenType.BracesClose)
                    {
                        TextUtil.StringBuilder.Append(tokenStream.Current.value);
                        tokenStream.Advance();
                    }

                    TextUtil.StringBuilder.Append(tokenStream.Current.value);

                    tokenStream.Advance();
                    n.rawValue = TextUtil.StringBuilder.ToString();
                    TextUtil.StringBuilder.Clear();
                }

                break;

            case StyleTokenType.Identifier:
                string identifier = tokenStream.Current.value;
                tokenStream.Advance();
                if (tokenStream.Current.styleTokenType == StyleTokenType.ParenOpen)
                {
                    tokenStream.Advance();
                    propertyValue = ParsePropertyFunction(identifier);
                }
                else
                {
                    propertyValue = StyleASTNodeFactory.IdentifierNode(identifier);
                }

                break;

            case StyleTokenType.Rgba:
                propertyValue = ParseRgba();
                break;

            case StyleTokenType.Rgb:
                propertyValue = ParseRgb();
                break;

            case StyleTokenType.HashColor:
                propertyValue = StyleASTNodeFactory.ColorNode(tokenStream.Current.value);
                tokenStream.Advance();
                break;

            case StyleTokenType.Url:
                tokenStream.Advance();
                AssertTokenTypeAndAdvance(StyleTokenType.ParenOpen);

                StyleASTNode url;
                StyleASTNode spriteName = null;
                if (tokenStream.Current.styleTokenType == StyleTokenType.String)
                {
                    url = ParseLiteralOrReference(StyleTokenType.String);
                }
                else
                {
                    url = ParseLiteralOrReference(StyleTokenType.Identifier);
                }

                if (url is StyleIdentifierNode urlIdentifier)
                {
                    // todo -- this doesn't handle spaces!
                    while (tokenStream.HasMoreTokens && !AdvanceIfTokenType(StyleTokenType.ParenClose))
                    {
                        // advancing tokens no matter the type. We want to concatenate all identifiers and slashes of a path again.
                        urlIdentifier.name += tokenStream.Current.value;
                        spriteName          = ParseSpriteName();
                        tokenStream.Advance();
                    }
                }
                else if (url is StyleLiteralNode || url is ConstReferenceNode)
                {
                    spriteName = ParseSpriteName();
                    AssertTokenTypeAndAdvance(StyleTokenType.ParenClose);
                }
                else
                {
                    throw new CompileException(url, "URL could not be parsed.");
                }

                propertyValue = StyleASTNodeFactory.UrlNode(url, spriteName);
                break;

            case StyleTokenType.At:
                propertyValue = ParseConstReference();
                break;

            case StyleTokenType.Dollar:
                propertyValue = ParseVariableReference();
                break;

            default:
                throw new ParseException(propertyToken, "Expected a property value but found no valid token.");
            }

            return(propertyValue.WithLocation(propertyToken));
        }
예제 #6
0
 public CompileException(string fileName, StyleASTNode node, string message = null) :
     base($"Compile error for style token at line {node.line}, column {node.column}, node type '{node.type}'\n{message}")
 {
     this.fileName = fileName;
 }
예제 #7
0
        private void CompileStyleGroups(StyleNodeContainer root, StyleType styleType, LightList <UIStyleGroup> groups, UIStyleGroup targetGroup, AnimationData[] styleSheetAnimations, UISoundData[] uiSoundData)
        {
            for (int index = 0; index < root.children.Count; index++)
            {
                StyleASTNode node = root.children[index];
                switch (node)
                {
                case SelectNode selectNode:
                    break;

                case PropertyNode propertyNode:
                    // add to normal ui style set
                    StylePropertyMappers.MapProperty(targetGroup.normal.style, propertyNode, context);
                    break;

                case AttributeNodeContainer attribute:
                    if (root is AttributeNodeContainer)
                    {
                        throw new CompileException(attribute, "You cannot nest attribute group definitions.");
                    }

                    UIStyleGroup attributeGroup = new UIStyleGroup();
                    attributeGroup.normal    = UIStyleRunCommand.CreateInstance();
                    attributeGroup.name      = root.identifier;
                    attributeGroup.rule      = MapAttributeContainerToRule(attribute);
                    attributeGroup.styleType = styleType;
                    groups.Add(attributeGroup);
                    CompileStyleGroups(attribute, styleType, groups, attributeGroup, styleSheetAnimations, uiSoundData);

                    break;

                case RunNode runNode:
                    UIStyleRunCommand cmd = new UIStyleRunCommand()
                    {
                        style       = targetGroup.normal.style,
                        runCommands = targetGroup.normal.runCommands ?? new LightList <IRunCommand>(4)
                    };

                    if (runNode.command is AnimationCommandNode animationCommandNode)
                    {
                        MapAnimationCommand(styleSheetAnimations, cmd, animationCommandNode);
                    }
                    else if (runNode.command is SoundCommandNode soundCommandNode)
                    {
                        MapSoundCommand(uiSoundData, cmd, soundCommandNode);
                    }

                    targetGroup.normal = cmd;
                    break;

                case StyleStateContainer styleContainer:
                    if (styleContainer.identifier == "hover")
                    {
                        UIStyleRunCommand uiStyleRunCommand = targetGroup.hover;
                        uiStyleRunCommand.style = uiStyleRunCommand.style ?? new UIStyle();
                        MapProperties(styleSheetAnimations, uiSoundData, ref uiStyleRunCommand, styleContainer.children);
                        targetGroup.hover = uiStyleRunCommand;
                    }
                    else if (styleContainer.identifier == "focus")
                    {
                        UIStyleRunCommand uiStyleRunCommand = targetGroup.focused;
                        uiStyleRunCommand.style = uiStyleRunCommand.style ?? new UIStyle();
                        MapProperties(styleSheetAnimations, uiSoundData, ref uiStyleRunCommand, styleContainer.children);
                        targetGroup.focused = uiStyleRunCommand;
                    }
                    else if (styleContainer.identifier == "active")
                    {
                        UIStyleRunCommand uiStyleRunCommand = targetGroup.active;
                        uiStyleRunCommand.style = uiStyleRunCommand.style ?? new UIStyle();
                        MapProperties(styleSheetAnimations, uiSoundData, ref uiStyleRunCommand, styleContainer.children);
                        targetGroup.active = uiStyleRunCommand;
                    }
                    else
                    {
                        throw new CompileException(styleContainer, $"Unknown style state '{styleContainer.identifier}'. Please use [hover], [focus] or [active] instead.");
                    }

                    break;

                default:
                    throw new CompileException(node, $"You cannot have a {node} at this level.");
                }
            }
        }
예제 #8
0
        private AnimationOptions CompileSpriteSheetOptions(SpriteSheetNode node)
        {
            AnimationOptions options = new AnimationOptions();

            LightList <StyleASTNode> spriteSheetProperties = node.children;

            if (spriteSheetProperties == null)
            {
                return(options);
            }

            for (int i = 0; i < spriteSheetProperties.Count; i++)
            {
                if (spriteSheetProperties[i] is PropertyNode property)
                {
                    string       optionName = property.identifier.ToLower();
                    StyleASTNode value      = property.children[0];

                    switch (optionName)
                    {
                    case "iterations":
                        options.iterations = (int)StylePropertyMappers.MapNumberOrInfinite(value, context);
                        break;

                    case "delay":
                        options.delay = StylePropertyMappers.MapUITimeMeasurement(value, context);
                        break;

                    case "duration":
                        options.duration = StylePropertyMappers.MapUITimeMeasurement(value, context);
                        break;

                    case "looptype":
                        options.loopType = StylePropertyMappers.MapEnum <AnimationLoopType>(value, context);
                        break;

                    case "direction":
                        options.direction = StylePropertyMappers.MapEnum <AnimationDirection>(value, context);
                        break;

                    case "forwardstartdelay":
                        options.forwardStartDelay = (int)StylePropertyMappers.MapNumber(value, context);
                        break;

                    case "reversestartdelay":
                        options.reverseStartDelay = (int)StylePropertyMappers.MapNumber(value, context);
                        break;

                    case "fps":
                        options.fps = (int)StylePropertyMappers.MapNumber(value, context);
                        break;

                    case "startframe":
                        options.startFrame = (int)StylePropertyMappers.MapNumber(value, context);
                        break;

                    case "endframe":
                        options.endFrame = (int)StylePropertyMappers.MapNumber(value, context);
                        break;

                    case "pathprefix":
                        options.pathPrefix = StylePropertyMappers.MapString(value, context);
                        break;

                    default:
                        throw new CompileException(property, "Invalid option argument for animation");
                    }
                }
                else
                {
                    throw new CompileException(spriteSheetProperties[i], "Invalid option argument for animation");
                }
            }

            return(options);
        }
예제 #9
0
        private AnimationOptions CompileAnimationOptions(AnimationRootNode animNode)
        {
            AnimationOptions options = new AnimationOptions();

            if (animNode.optionNodes == null)
            {
                return(options);
            }

            LightList <AnimationOptionNode> optionNodes = animNode.optionNodes;

            if (optionNodes == null)
            {
                return(options);
            }

            for (int i = 0; i < optionNodes.Count; i++)
            {
                string       optionName = optionNodes[i].optionName.ToLower();
                StyleASTNode value      = optionNodes[i].value;

                switch (optionName)
                {
                case "duration":
                    options.duration = StylePropertyMappers.MapUITimeMeasurement(value, context);
                    break;

                case "iterations":
                    options.iterations = (int)StylePropertyMappers.MapNumberOrInfinite(value, context);
                    break;

                case "looptime":
                    options.loopTime = StylePropertyMappers.MapNumber(value, context);
                    break;

                case "delay":
                    options.delay = StylePropertyMappers.MapUITimeMeasurement(value, context);
                    break;

                case "direction":
                    options.direction = StylePropertyMappers.MapEnum <AnimationDirection>(value, context);
                    break;

                case "looptype":
                    options.loopType = StylePropertyMappers.MapEnum <AnimationLoopType>(value, context);
                    break;

                case "forwardstartdelay":
                    options.forwardStartDelay = (int)StylePropertyMappers.MapNumber(value, context);
                    break;

                case "reversestartdelay":
                    options.reverseStartDelay = (int)StylePropertyMappers.MapNumber(value, context);
                    break;

                case "timingfunction":
                    options.timingFunction = StylePropertyMappers.MapEnum <EasingFunction>(value, context);
                    break;

                default:
                    throw new CompileException(optionNodes[i], "Invalid option argument for animation");
                }
            }

            return(options);
        }
예제 #10
0
        private unsafe StyleAnimationKeyFrame[] CompileKeyFrames(AnimationRootNode animNode, AnimationData[] styleSheetAnimations, UISoundData[] uiSoundData)
        {
            if (animNode.keyframeNodes == null)
            {
                // todo throw error or log warning?
                return(new StyleAnimationKeyFrame[0]);
            }

            int keyframeCount = 0;

            for (int i = 0; i < animNode.keyframeNodes.Count; i++)
            {
                keyframeCount += animNode.keyframeNodes[i].keyframes.Count;
            }

            StyleAnimationKeyFrame[] frames = new StyleAnimationKeyFrame[keyframeCount];

            int nextKeyframeIndex = 0;

            for (int i = 0; i < animNode.keyframeNodes.Count; i++)
            {
                KeyFrameNode keyFrameNode = animNode.keyframeNodes[i];

                // todo -- this is madness and not working, fix it!!!!!!!
                for (int j = 0; j < keyFrameNode.children.Count; j++)
                {
                    StyleASTNode keyFrameProperty = keyFrameNode.children[j];
                    if (keyFrameProperty is PropertyNode propertyNode)
                    {
                        StylePropertyMappers.MapProperty(s_ScratchStyle, propertyNode, context);
                    }
                    else if (keyFrameProperty is MaterialPropertyNode materialPropertyNode)
                    {
                        string materialName = materialPropertyNode.materialName;

                        if (context.materialDatabase.TryGetBaseMaterialId(materialName, out MaterialId materialId))
                        {
                            if (context.materialDatabase.TryGetMaterialProperty(materialId, materialPropertyNode.identifier, out MaterialPropertyInfo propertyInfo))
                            {
                                fixed(char *charptr = materialPropertyNode.value)
                                {
                                    CharStream            stream = new CharStream(charptr, 0, (uint)materialPropertyNode.value.Length);
                                    MaterialKeyFrameValue kfv    = default;

                                    switch (propertyInfo.propertyType)
                                    {
                                    case MaterialPropertyType.Color:

                                        if (stream.TryParseColorProperty(out Color32 color))
                                        {
                                            kfv = new MaterialKeyFrameValue(materialId, propertyInfo.propertyId, new MaterialPropertyValue2()
                                            {
                                                colorValue = color
                                            });
                                        }

                                        break;

                                    case MaterialPropertyType.Float:
                                        if (stream.TryParseFloat(out float floatVal))
                                        {
                                            kfv = new MaterialKeyFrameValue(materialId, propertyInfo.propertyId, new MaterialPropertyValue2()
                                            {
                                                floatValue = floatVal
                                            });
                                        }
                                        break;

                                    case MaterialPropertyType.Vector:
                                        break;

                                    case MaterialPropertyType.Range:
                                        break;

                                    case MaterialPropertyType.Texture:
                                        break;

                                    default:
                                        throw new ArgumentOutOfRangeException();
                                    }
                                }
                            }
                        }
                    }
                }

                StructList <StyleKeyFrameValue> styleKeyValues = new StructList <StyleKeyFrameValue>(s_ScratchStyle.PropertyCount);

                for (int j = 0; j < s_ScratchStyle.PropertyCount; j++)
                {
                    styleKeyValues[j] = new StyleKeyFrameValue(s_ScratchStyle[j]);
                }

                styleKeyValues.size = s_ScratchStyle.PropertyCount;

                for (int keyframeIndex = 0; keyframeIndex < keyFrameNode.keyframes.Count; keyframeIndex++)
                {
                    float time = keyFrameNode.keyframes[keyframeIndex] / 100f;

                    frames[nextKeyframeIndex] = new StyleAnimationKeyFrame(time)
                    {
                        properties = styleKeyValues
                    };

                    nextKeyframeIndex++;
                }

                s_ScratchStyle.PropertyCount = 0;
            }

            return(frames);
        }