public void BakeToModifiers()
        {
            // Does it have any modified selectors? If so, add these properties in there too
            // (as the modified form 'derives' from this) but weakly - don't override them.
            // This occurs if :aModified is defined before the unmodified selector.
            List <Css.SelectorStyle> modifiedForms = Sheet.GetModifiers(Selector);

            if (modifiedForms != null)
            {
                // Great, it's got some! Copy this style over now:
                for (int i = modifiedForms.Count - 1; i >= 0; i--)
                {
                    SelectorStyle modifiedForm = modifiedForms[i];
                    CopyTo(modifiedForm, false);
                }
            }

            if (Document != null && Document.html != null && Unmodified)
            {
                // Is this selector already in use?
                Css.SelectorType type = SelectorType;

                // Next, recurse through the DOM looking for it:
                Document.html.RefreshSelector(type, BaseSelector);
            }
        }
		public Selector(StyleSheet sheet,string selectorText,string modifier){
			SelectorText=selectorText;
			Modifier=modifier;
			
			// Start it off immediately:
			Style=sheet.StartSelector(selectorText,modifier);
		}
        public Selector(StyleSheet sheet, string selectorText, string modifier)
        {
            SelectorText = selectorText;
            Modifier     = modifier;

            // Start it off immediately:
            Style = sheet.StartSelector(selectorText, modifier);
        }
        /// <summary>Gets the CSS property value defined by the ID selector for the given property.</summary>
        /// <param name="property">The CSS property to get the value for.</param>
        public Css.Value GetIDStyle(string property)
        {
            if (!string.IsNullOrEmpty(IDSelector))
            {
                SelectorStyle idStyle = Element.Document.getStyleBySelector(IDSelector);

                if (idStyle != null)
                {
                    return(idStyle[property]);
                }
            }

            return(null);
        }
        /// <summary>Gets a style definition by css selector from the StyleSheet.
        /// If it's not found in the style sheet, the default stylesheet is checked.</summary>
        /// <param name="selector">The css selector to search for.</param>
        /// <returns>If found, a selector style definition; null otherwise.</returns>
        public Css.SelectorStyle getStyleBySelector(string selector)
        {
            if (Style == null || AotDocument)
            {
                return(null);
            }

            Css.SelectorStyle result = Style.GetStyleBySelector(selector);

            if (result == null)
            {
                result = DefaultStyleSheet.GetStyleBySelector(selector);
            }

            return(result);
        }
        /// <summary>Copies this objects properties to the other given style, overwriting existing properties if told to do so.</summary>
        /// <param name="otherStyle">The style to copy this objects properties into.</param>
        /// <param name="overwrite">True if existing properties should be overwriten.</param>
        public void CopyTo(SelectorStyle otherStyle, bool overwrite)
        {
            if (otherStyle == null)
            {
                return;
            }

            foreach (KeyValuePair <CssProperty, Value> kvp in Properties)
            {
                if (!overwrite && otherStyle.Properties.ContainsKey(kvp.Key))
                {
                    continue;
                }

                otherStyle[kvp.Key] = kvp.Value.Copy();
            }
        }
        /// <summary>Gets the CSS property value defined by the class selector for the given property.</summary>
        /// <param name="property">The CSS property to get the value for.</param>
        public Css.Value GetClassStyle(CssProperty property)
        {
            if (!string.IsNullOrEmpty(ClassSelector))
            {
                // Grab the main class style:
                SelectorStyle classStyle = Element.Document.getStyleBySelector(ClassSelector);

                Css.Value result;

                if (classStyle != null)
                {
                    result = classStyle[property];

                    if (result != null)
                    {
                        return(result);
                    }
                }

                if (ExtraClassSelectors != null)
                {
                    for (int i = ExtraClassSelectors.Length - 1; i >= 0; i--)
                    {
                        // Grab the style:
                        classStyle = Element.Document.getStyleBySelector(ExtraClassSelectors[i]);

                        if (classStyle == null)
                        {
                            continue;
                        }

                        // Get the property:
                        result = classStyle[property];

                        if (result != null)
                        {
                            // Got it!
                            return(result);
                        }
                    }
                }
            }

            return(null);
        }
        /// <summary>Keeps reading selectors and their properties until a &gt; or the end of the css is reached.</summary>
        /// <param name="css">The css text to parse.</param>
        public void ParseCss(string css)
        {
            MLLexer lexer            = new MLLexer(css);
            char    currentCharacter = lexer.Peek();

            while (currentCharacter != '<' && currentCharacter != StringReader.NULL)
            {
                if (TryReadBlockComment(lexer, currentCharacter))
                {
                    currentCharacter = lexer.Peek();
                    continue;
                }

                // Read a selector:
                string          selector            = "";
                string          modifier            = "";
                bool            inModifier          = false;
                List <Selector> additionalSelectors = null;

                while (currentCharacter != '{' && currentCharacter != '<' && currentCharacter != StringReader.NULL)
                {
                    // Read it off:
                    lexer.Read();

                    if (currentCharacter == ' ')
                    {
                        // Skip spaces here.
                    }
                    else if (currentCharacter == ',')
                    {
                        // We have a series of selectors.

                        if (selector != "")
                        {
                            // Store the current one in the additional list:
                            if (additionalSelectors == null)
                            {
                                additionalSelectors = new List <Selector>(1);
                            }

                            additionalSelectors.Add(new Selector(this, selector, modifier));

                            // Clear the current one:
                            selector   = "";
                            modifier   = "";
                            inModifier = false;
                        }
                    }
                    else if (currentCharacter == ':')
                    {
                        if (inModifier)
                        {
                            // Already in the modifier - they've been daisy chained.
                            // So, the modifier we've read so far is actually part of the selector:
                            selector += ":" + modifier.ToLower();
                            modifier  = "";
                        }

                        inModifier = true;
                    }
                    else if (inModifier)
                    {
                        // Add it to the modifier:
                        modifier += currentCharacter;
                    }
                    else
                    {
                        // Add it to the selector:
                        selector += currentCharacter;
                    }

                    // Peek the next one:
                    currentCharacter = lexer.Peek();
                }

                if (currentCharacter == '{')
                {
                    // Read it off:
                    lexer.Read();
                }
                else
                {
                    // It must have been a < or null. Halt.
                    break;
                }

                // Start the style block:
                SelectorStyle style = StartSelector(selector, modifier);

                // Read the properties inside a selectors block. Literal reading after : until ;
                bool   readPropertyName = true;
                string propertyName     = "";
                string propertyValue    = "";

                currentCharacter = lexer.Peek();

                while (currentCharacter != '}' && currentCharacter != '<' && currentCharacter != StringReader.NULL)
                {
                    if (readPropertyName)
                    {
                        if (TryReadBlockComment(lexer, currentCharacter))
                        {
                            currentCharacter = lexer.Peek();
                            continue;
                        }

                        if (currentCharacter == ':')
                        {
                            // Bump into literal mode.
                            lexer.Literal    = true;
                            readPropertyName = false;
                        }
                        else
                        {
                            propertyName += currentCharacter;
                        }
                    }
                    else
                    {
                        if (currentCharacter == ';')
                        {
                            // Pop out of literal mode, and go back to property names.
                            readPropertyName = true;
                            lexer.Literal    = false;

                            // And push our new propertyName/propertyValue set:
                            style.SetDirect(propertyName, propertyValue);

                            if (additionalSelectors != null)
                            {
                                // We have more,than,one selector.

                                // Set to them too:
                                for (int i = additionalSelectors.Count - 1; i >= 0; i--)
                                {
                                    additionalSelectors[i].Style.SetDirect(propertyName, propertyValue);
                                }
                            }

                            propertyName  = "";
                            propertyValue = "";
                        }
                        else
                        {
                            propertyValue += currentCharacter;
                        }
                    }

                    // Read it off:
                    lexer.Read();
                    // And take a look at what's next:
                    currentCharacter = lexer.Peek();
                }

                // Let the style know it's done loading:
                style.OnLoaded();

                // 'Bake' the new styles into their modified forms, if any have been loaded yet.
                style.BakeToModifiers();

                if (additionalSelectors != null)
                {
                    // We have more,than,one selector.

                    // Start their blocks too:
                    for (int i = additionalSelectors.Count - 1; i >= 0; i--)
                    {
                        additionalSelectors[i].Style.BakeToModifiers();
                    }
                }

                if (currentCharacter == '}')
                {
                    // Read it off:
                    lexer.Read();
                    // And setup the next character:
                    currentCharacter = lexer.Peek();
                }
                else
                {
                    // Halt - it was a null or <.
                    break;
                }

                // Ensure we're out of literal mode:
                lexer.Literal = false;
            }
        }
        /// <summary>Creates a new selector block for the given selector/modifier combo.</summary>
        public SelectorStyle StartSelector(string selector, string modifier)
        {
            string fullSelector = selector;
            bool   modified     = false;

            if (!string.IsNullOrEmpty(modifier))
            {
                // Make it lowercase:
                modifier = modifier.ToLower();

                // Append it to the selector:
                fullSelector += ":" + modifier;
                modified      = true;
            }

            // Generate a style object for this selector if it doesn't already have one:
            SelectorStyle style = null;

            if (fullSelector == "@font-face")
            {
                // Special case for the font-face selector style.
                // - Load the font and add it to the document's renderer,
                style = new SelectorStyle(this, selector, modifier);

                return(style);
            }

            if (!Selectors.TryGetValue(fullSelector, out style))
            {
                Selectors[fullSelector] = style = new SelectorStyle(this, selector, modifier);

                if (modified)
                {
                    // Add it as a modified form:
                    AddModified(selector, style);
                }

                // Does a default selector exist?
                if (Document.DefaultStyleSheet != null && Document.DefaultStyleSheet != this)
                {
                    SelectorStyle defaultStyle = Document.DefaultStyleSheet.GetStyleBySelector(fullSelector);

                    if (defaultStyle != null)
                    {
                        // This tag has a default style - we must copy the content from it into the new overriding tag.
                        defaultStyle.CopyTo(style, false);
                    }
                }

                // Does a * selector exist? Only apply if selector is not html and a tag. Note that this must be applied last.
                // Also note that it's not applied to modified styles as they are applied additively.
                if (!modified && Document.DefaultStyleSheet != null && selector != "html" && selector != "*" && style.SelectorType == Css.SelectorType.Tag)
                {
                    SelectorStyle defaultStyle = Document.DefaultStyleSheet.GetStyleBySelector("*");

                    if (defaultStyle != null)
                    {
                        // Got a * style - Copy the content from it into the new overriding tag.
                        defaultStyle.CopyTo(style, false);
                    }
                }
            }

            return(style);
        }
//--------------------------------------
//--------------------------------------
Example #12
0
        /// <summary>Creates a new UIAnimation for animating CSS and immediately animates it.
        /// See <see cref="PowerUI.Element.animate"/>.</summary>
        /// <param name="animating">The element being animated.</param>
        /// <param name="properties">The CSS property string. Each property should define the value it will be when the animation is done.</param>
        /// <param name="constantSpeedTime">How long this animation lasts for at a constant speed.</param>
        /// <param name="timeToAccelerateFor">How long this animation accelerates for. Creates smooth animations when used.</param>
        /// <param name="timeToDecelerateFor">How long this animation decelerates for. Creates smooth animations when used.</param>
        public UIAnimation(Element animating, string properties, float constantSpeedTime, float timeToAccelerateFor, float timeToDecelerateFor)
        {
            Animating    = animating;
            ElementStyle = Animating.Style;

            if (string.IsNullOrEmpty(properties))
            {
                Wrench.Log.Add("No properties given to animate!");
                return;
            }

            if (constantSpeedTime < 0f)
            {
                constantSpeedTime = 0f;
            }

            if (timeToAccelerateFor < 0f)
            {
                timeToAccelerateFor = 0f;
            }

            if (timeToDecelerateFor < 0f)
            {
                timeToDecelerateFor = 0f;
            }

            TotalTime = (timeToDecelerateFor + timeToAccelerateFor + constantSpeedTime);

            ConstantSpeedTime   = constantSpeedTime;
            TimeToAccelerateFor = timeToAccelerateFor;
            TimeToDecelerateFor = timeToDecelerateFor;

            if (TotalTime == 0f)
            {
                // Instant - probably a fault somewhere in the users request, so we won't do anything.
                Wrench.Log.Add("Instant css animation request ignored. Told to take no time to transition.");
                return;
            }

            if (timeToDecelerateFor == 0f)
            {
                Decelerate = false;
            }
            else
            {
                Decelerate   = true;
                DecelerateAt = timeToAccelerateFor + constantSpeedTime;
            }

            if (properties.StartsWith(".") || properties.StartsWith("#"))
            {
                // Targeting a selector, e.g. #fadedBox
                // First, get the selector style:
                Css.SelectorStyle selector = animating.Document.getStyleBySelector(properties);

                if (selector == null)
                {
                    return;
                }

                // Animate each property:
                foreach (KeyValuePair <CssProperty, Css.Value> kvp in selector.Properties)
                {
                    // Is it a composite property?
                    Css.Value value = kvp.Value;

                    // Grab the type:
                    Css.ValueType type = value.Type;

                    if (type == Css.ValueType.Null || type == Css.ValueType.Text)
                    {
                        // Can't deal with either of these.
                        continue;
                    }

                    if (type == Css.ValueType.Rectangle || type == Css.ValueType.Point || type == Css.ValueType.Color)
                    {
                        // Animate it (note that we don't need to copy it):
                        AnimateComposite(kvp.Key, value);
                    }
                    else
                    {
                        // Animate it (note that we don't need to copy it):
                        Animate(kvp.Key, -1, value, true);
                    }
                }

                return;
            }

            string[] propertySet = properties.Split(';');

            foreach (string currentProperty in propertySet)
            {
                if (currentProperty == "")
                {
                    continue;
                }

                string[] keyValue = currentProperty.Split(Css.Style.Delimiter, 2);

                if (keyValue.Length != 2)
                {
                    continue;
                }

                string key = keyValue[0].Trim();

                if (key == "opacity")
                {
                    key = "color-overlay-a";
                }

                // Grab the inner index:
                int innerIndex = Css.Value.GetInnerIndex(ref key);

                // Get the property:
                CssProperty property = CssProperties.Get(key);

                if (property == null)
                {
                    Wrench.Log.Add("Warning: CSS property '" + keyValue[0] + "' not found during animate.");
                    continue;
                }

                // Trim shouldn't be applied to inner-text's value, but we can't animate that anyway! This is all we need to do:
                string value = keyValue[1].Trim();

                // Key could be a composite property - for example padding, which needs to be broken down into it's individual inner elements (e.g. padding-left)

                Css.ValueType type;

                if (innerIndex == -1)
                {
                    type = Css.Value.TypeOf(property, ref value);
                }
                else
                {
                    type = Css.Value.TypeOf(value);
                }

                if (type == Css.ValueType.Null || type == Css.ValueType.Text)
                {
                    // Can't deal with either of these.
                    continue;
                }
                else if (type == Css.ValueType.Rectangle || type == Css.ValueType.Point || type == Css.ValueType.Color)
                {
                    // We have a composite property (and we're animating the whole thing).
                    Css.Value tempValue = new Css.Value();
                    tempValue.Set(value, type);

                    // Animate it:
                    AnimateComposite(property, tempValue);
                }
                else
                {
                    Animate(property, innerIndex, new Css.Value(value, type), true);
                }
            }
        }