public override void Apply(ComputedStyle style,Value value){
			
			// Is it lit?
			bool lit=(value!=null && value.Boolean);
			
			if(!lit && style.Shading==null){
				// Essentially ignore it anyway.
				return;
			}
			
			if(style.Shading==null){
				// It's lit:
				style.RequireShading().Lit=true;
			}else{
				// It's not lit:
				style.Shading.Lit=false;
				
				// Optimise - might no longer need the shading info:
				style.Shading.Optimise();
			}
			
			// Request a layout now:
			style.RequestLayout();
			
		}
		public override void Apply(ComputedStyle style,Value value){
			
			// Got text at all?:
			if(GetText(style)==null){
				return;
			}
			
			// Apply the property:
			if(value==null || value.Text=="none"){
				
				// Clear the shadow:
				style.TextShadow=null;
				
			}else{
			
				// The glow properties:
				int blur=0;
				Color colour=Color.black;
				
				ShadowData data=style.TextShadow;
				
				if(data==null){
					data=new ShadowData();
					style.TextShadow=data;
				}
				
				data.HOffset=value[0].PX;
				data.VOffset=value[1].PX;
				
				// Grab the blur:
				Value innerValue=value[2];
				
				if(innerValue.Type==ValueType.Color){
					colour=innerValue.ToColor();
				}else{
					blur=innerValue.PX;
					
					// Grab the colour:
					innerValue=value[3];
					
					if(innerValue.Type==ValueType.Color){
						colour=innerValue.ToColor();
					}
					
				}
			
				if(colour.a==1f){
					// Default transparency:
					colour.a=0.8f;
				}
				
				data.Colour=colour;
				data.Blur=blur;
				
			}
			
			// Apply the changes - doesn't change anything about the actual text, so we just want a layout:
			style.RequestLayout();
			
		}
Beispiel #3
0
        /// <summary>Animates this property now.</summary>
        /// <param name="animation">The animation that this property is a part of.</param>
        /// <param name="targetValue">The value that this property will be when the animation is over.</param>
        /// <param name="constantSpeedTime">How long the animation will change the value at a constant speed for.</param>
        /// <param name="timeToAccelerateFor">How long the animation will accelerate for. This produces a smoother animation.</param>
        /// <param name="timeToDecelerateFor">How long the animation will decelerate for. This produces a smoother animation.</param>
        /// <param name="updateCss">True if this particular property should flush its changes to css/the screen.</param>
        public void Animate(UIAnimation animation, string targetValue, float constantSpeedTime, float timeToAccelerateFor, float timeToDecelerateFor, bool updateCss)
        {
            // Get the target float value for calculating our transition speeds as an object:
            Css.Value targetValueObject = new Css.Value();
            targetValueObject.Set(targetValue);

            Animate(animation, targetValueObject, constantSpeedTime, timeToAccelerateFor, timeToDecelerateFor, updateCss);
        }
Beispiel #4
0
        /// <summary>Creates a new animated property.</summary>
        /// <param name="animation">The animation that this property is a part of.</param>
        /// <param name="property">The property being animated.</param>
        /// <param name="targetValue">The value that this property will be when the animation is over.</param>
        /// <param name="constantSpeedTime">How long the animation will change the value at a constant speed for.</param>
        /// <param name="timeToAccelerateFor">How long the animation will accelerate for. This produces a smoother animation.</param>
        /// <param name="timeToDecelerateFor">How long the animation will decelerate for. This produces a smoother animation.</param>
        /// <param name="updateCss">True if this particular property should flush its changes to css/the screen.</param>
        public AnimatedProperty(UIAnimation animation, CssProperty property, int innerIndex, Css.Value targetValue, float constantSpeedTime, float timeToAccelerateFor, float timeToDecelerateFor, bool updateCss)
        {
            Animation    = animation;
            PropertyInfo = property;
            InnerIndex   = innerIndex;
            Css.ValueType type = targetValue.Type;

            if (!Animation.ElementStyle.Properties.TryGetValue(property, out ValueObject))
            {
                ComputedStyle computed = Animation.ElementStyle.Computed;

                if (computed != null && computed.Properties.TryGetValue(property, out ValueObject))
                {
                    // Let's derive from the computed form.
                    ValueObject = ValueObject.Copy();
                }
                else
                {
                    ValueObject = new Css.Value();

                    if (innerIndex != -1 || type == Css.ValueType.Null)
                    {
                        type = Css.ValueType.Rectangle;
                    }

                    property.SetDefault(ValueObject, type);
                }

                Animation.ElementStyle.Properties[property] = ValueObject;
            }

            if (ValueObject.Type == Css.ValueType.Inherit)
            {
                // Special case - we need to duplicate it.
                Animation.ElementStyle.Properties[property] = ValueObject = ValueObject.Copy();
                ValueObject.Type = type;
            }

            PropertyValueObject = ValueObject;

            if (innerIndex != -1)
            {
                Css.Value innerValue = ValueObject[innerIndex];

                if (innerValue == null)
                {
                    ValueObject[innerIndex] = innerValue = new Css.Value();
                }

                ValueObject = innerValue;
            }

            // Set our starting value:
            ActiveValue = ValueObject.ToFloat();
            Animate(Animation, targetValue, constantSpeedTime, timeToAccelerateFor, timeToDecelerateFor, updateCss);
        }
Beispiel #5
0
        private void AnimateComposite(CssProperty property, Css.Value value)
        {
            bool isPoint = (value.Type == Css.ValueType.Point);

            Animate(property, 0, value[0], false);
            Animate(property, 1, value[1], isPoint);

            if (!isPoint)
            {
                Animate(property, 2, value[2], false);
                Animate(property, 3, value[3], true);
            }
        }
		/// <summary>Creates a new animated property.</summary>
		/// <param name="animation">The animation that this property is a part of.</param>
		/// <param name="property">The property being animated.</param>
		/// <param name="targetValue">The value that this property will be when the animation is over.</param>
		/// <param name="constantSpeedTime">How long the animation will change the value at a constant speed for.</param>
		/// <param name="timeToAccelerateFor">How long the animation will accelerate for. This produces a smoother animation.</param>
		/// <param name="timeToDecelerateFor">How long the animation will decelerate for. This produces a smoother animation.</param>
		/// <param name="updateCss">True if this particular property should flush its changes to css/the screen.</param>
		public AnimatedProperty(UIAnimation animation,CssProperty property,int innerIndex,Css.Value targetValue,float constantSpeedTime,float timeToAccelerateFor,float timeToDecelerateFor,bool updateCss){
			Animation=animation;
			PropertyInfo=property;
			InnerIndex=innerIndex;
			Css.ValueType type=targetValue.Type;
			
			if(!Animation.ElementStyle.Properties.TryGetValue(property,out ValueObject)){
				ComputedStyle computed=Animation.ElementStyle.Computed;
				
				if(computed!=null && computed.Properties.TryGetValue(property,out ValueObject)){
					// Let's derive from the computed form.
					ValueObject=ValueObject.Copy();
				}else{
					ValueObject=new Css.Value();
					
					if(innerIndex!=-1 || type==Css.ValueType.Null){
						type=Css.ValueType.Rectangle;
					}
					
					property.SetDefault(ValueObject,type);
					
				}
				
				Animation.ElementStyle.Properties[property]=ValueObject;
				
			}
			
			if(ValueObject.Type==Css.ValueType.Inherit){
				// Special case - we need to duplicate it.
				Animation.ElementStyle.Properties[property]=ValueObject=ValueObject.Copy();
				ValueObject.Type=type;
			}
			
			PropertyValueObject=ValueObject;
			
			if(innerIndex!=-1){
				Css.Value innerValue=ValueObject[innerIndex];
				
				if(innerValue==null){
					ValueObject[innerIndex]=innerValue=new Css.Value();
				}
				
				ValueObject=innerValue;
			}
			
			// Set our starting value:
			ActiveValue=ValueObject.ToFloat();
			Animate(Animation,targetValue,constantSpeedTime,timeToAccelerateFor,timeToDecelerateFor,updateCss);
		}
Beispiel #7
0
        /// <summary>Starts animating the named property and target value. Must not be composite properties.
        /// (e.g. color-overlay-r instead of color-overlay)</summary>
        /// <param name="property">The property to update.</param>
        /// <param name="innerIndex">The inner index of the property to update.</param>
        /// <param name="value">The target value of the property.</param>
        /// <param name="updateCss">True if this property should update CSS/ the screen when it's progressed.</param>
        private void Animate(CssProperty property, int innerIndex, Css.Value value, bool updateCss)
        {
            // Check if this property is already animated - if so, interrupt it and override with our new values.
            // There won't be many actively animated properties, so looping through the update queue is fast anyway.
            AnimatedProperty animProperty = GetAnimatedProperty(Animating, property, innerIndex);

            if (animProperty != null)
            {
                animProperty.Animate(this, value, ConstantSpeedTime, TimeToAccelerateFor, TimeToDecelerateFor, updateCss);
            }
            else
            {
                // Otherwise we want to create a new AnimatedProperty and stick it into the queue:
                animProperty = new AnimatedProperty(this, property, innerIndex, value, ConstantSpeedTime, TimeToAccelerateFor, TimeToDecelerateFor, updateCss);
                animProperty.AddToQueue();
            }
        }
Beispiel #8
0
        public override void OnLoaded(string type)
        {
            ComputedStyle computed = Element.Style.Computed;

            if (computed.BGImage == null)
            {
                return;
            }

            Image = computed.BGImage.Image;

            if (Image == null)
            {
                return;
            }

            float width  = (float)Image.Width();
            float height = (float)Image.Height();

            // Figure out the aspect ratios:
            AspectRatio        = width / height;
            InverseAspectRatio = height / width;

            if (Image.PixelPerfect)
            {
                width  *= ScreenInfo.ResolutionScale;
                height *= ScreenInfo.ResolutionScale;
            }

            // Compute the tag width:
            TagWidth = new Css.Value((int)width + "fpx", Css.ValueType.Pixels);

            // Compute the tag height:
            TagHeight = new Css.Value((int)height + "fpx", Css.ValueType.Pixels);

            // Act like we're setting tag properties:
            // This is so that class/ID/Style can override any of them.
            computed.ChangeTagProperty("height", TagHeight);
            computed.ChangeTagProperty("width", TagWidth);
            computed.ChangeTagProperty("background-repeat", new Css.Value("no-repeat", Css.ValueType.Text));
            computed.ChangeTagProperty("background-size", new Css.Value("100% 100%", Css.ValueType.Point));
        }
		public override void Apply(ComputedStyle style,Value value){
			
			ShaderSet family=null;
			
			// Apply:
			if(value!=null){
				
				// Lowercase so we can have the best chance at spotting the standard set (which is optimised for).
				string familyLC=value.Text.ToLower();
				
				if(familyLC!="standardui" && familyLC!="standard" && familyLC!="" && familyLC!="none"){
					
					// Get the family:
					family=ShaderSet.Get(value.Text);
					
				}
				
			}
			
			// Apply it here:
			if(style.Shading!=null){
				
				// Update it:
				style.Shading.Shaders=family;
				
				if(family==null){
					// Check if the shading data is no longer in use:
					style.Shading.Optimise();
				}
				
			}else if(family!=null){
				
				style.RequireShading().Shaders=family;
				
			}
			
			// Request a layout now:
			style.RequestLayout();
			
		}
Beispiel #10
0
        /// <summary>Animates this property now.</summary>
        /// <param name="animation">The animation that this property is a part of.</param>
        /// <param name="targetValue">The parsed value that this property will be when the animation is over.</param>
        /// <param name="constantSpeedTime">How long the animation will change the value at a constant speed for.</param>
        /// <param name="timeToAccelerateFor">How long the animation will accelerate for. This produces a smoother animation.</param>
        /// <param name="timeToDecelerateFor">How long the animation will decelerate for. This produces a smoother animation.</param>
        /// <param name="updateCss">True if this particular property should flush its changes to css/the screen.</param>
        public void Animate(UIAnimation animation, Css.Value targetValue, float constantSpeedTime, float timeToAccelerateFor, float timeToDecelerateFor, bool updateCss)
        {
            Animation        = animation;
            ValueObject.Type = targetValue.Type;

            Stage       = 0;
            Speed       = 0f;
            CurrentTime = 0f;
            UpdateCss   = updateCss;

            PropertyAfter = PropertyBefore = null;
            // Find the max speed. This is what we accelerate to.
            // Speed (y) / time (x) graph:
            //  /| |-| |\
            //	A   B   C. A = accelerate, b=constant, c=decelerate.
            // Max speed = top y value.
            // Distance travelled = area of the graph. This should match target - current value.

            TargetValue = targetValue.ToFloat();

            float unitsDelta = TargetValue - ActiveValue;

            MaxSpeed = (unitsDelta * UI.RedrawRate) / ((0.5f * timeToAccelerateFor) + constantSpeedTime + (0.5f * timeToDecelerateFor));

            if (timeToAccelerateFor == 0f)
            {
                // Skip acceleration stage.
                Stage = 1;
                Speed = MaxSpeed;
            }
            else
            {
                Acceleration = MaxSpeed * UI.RedrawRate / timeToAccelerateFor;
            }

            if (timeToDecelerateFor != 0f)
            {
                Deceleration = MaxSpeed * UI.RedrawRate / timeToDecelerateFor;
            }
        }
//--------------------------------------
		/// <summary>Sets the named property on this style to the given value. An inner value may be set; For example,
		/// setting the red component of color-overlay (color-overlay-r) becomes color-overlay and an innerIndex of 0.</summary>
		/// <param name="property">The property to set or overwrite. e.g. "display".</param>
		/// <param name="value">The value to set the property to, e.g. "none".</param>
		/// <param name="innerIndex">The index of the inner value to set, if any. -1 to set the whole property.</param>
		private void Set(string cssProperty,string value,int innerIndex,bool important){
			
			if(Element!=null && Element.Document.AotDocument){
				return;
			}
			
			// Get the property:
			CssProperty property=CssProperties.Get(cssProperty);
			
			if(property==null){
				// It doesn't exist!
				return;
			}
			
			if(value==""){
				value=null;
			}
			
			if(value==null){
				
				Properties.Remove(property);
				// Was in there (and not blank) - change it.
				OnChanged(property,null);
				
				return;
			}
			
			// Get the type of the property:
			ValueType type=Css.Value.TypeOf(property,ref value);
			
			// Read or create the raw property value:
			Value propertyValue=GetRawValue(property,type);
			
			if(innerIndex!=-1){
				
				// Writing to an inner value, e.g. border-left. Grab it:
				Value innerValue=propertyValue[innerIndex];
				
				if(innerValue==null){
					innerValue=propertyValue[innerIndex]=new Value();
				}
				
				innerValue.Set(value);
				
				// Apply its importance:
				innerValue.Important=important;
				
			}else{
				
				if(type==ValueType.Null){
					propertyValue.Set(value);
					
				}else{
					propertyValue.Set(value,type);
				}
				
				// Apply its importance:
				propertyValue.Important=important;
				
			}
			
			// Let the sheet know the value changed:
			if(type==ValueType.Null){
				OnChanged(property,null);
			}else{
				OnChanged(property,propertyValue);
			}
		}
		public override void OnChanged(CssProperty property,Value newValue){
			// Update the computed object:
			Computed.ChangeProperty(property,newValue);
		}
Beispiel #14
0
		public override void OnLoaded(string type){
			ComputedStyle computed=Element.Style.Computed;
			
			if(computed.BGImage==null){
				return;
			}
			
			Image=computed.BGImage.Image;
			
			if(Image==null){
				return;
			}
			
			float width=(float)Image.Width();
			float height=(float)Image.Height();
			
			// Figure out the aspect ratios:
			AspectRatio=width/height;
			InverseAspectRatio=height/width;
			
			if(Image.PixelPerfect){
				width*=ScreenInfo.ResolutionScale;
				height*=ScreenInfo.ResolutionScale;
			}
			
			// Compute the tag width:
			TagWidth=new Css.Value((int)width+"fpx",Css.ValueType.Pixels);
			
			// Compute the tag height:
			TagHeight=new Css.Value((int)height+"fpx",Css.ValueType.Pixels);
			
			// Act like we're setting tag properties:
			// This is so that class/ID/Style can override any of them.
			computed.ChangeTagProperty("height",TagHeight);
			computed.ChangeTagProperty("width",TagWidth);
			computed.ChangeTagProperty("background-repeat",new Css.Value("no-repeat",Css.ValueType.Text));
			computed.ChangeTagProperty("background-size",new Css.Value("100% 100%",Css.ValueType.Point));
			
		}
		/// <summary>Inherits from the given parent value by copying them.</summary>
		/// <param name="parent">The value to inherit from.</param>
		public void InheritFrom(Value parent){
			// e.g. font-size:inherit;
			// Simply copies the parent objects properties exactly.
			if(parent==null){
				PX=0;
				Text=null;
				Boolean=false;
				InnerValues=null;
				Single=0f;
			}else{
				PX=parent.PX;
				Text=parent.Text;
				Single=parent.Single;
				Boolean=parent.Boolean;
				InnerValues=parent.InnerValues;	
			}
			
		}
		/// <summary>Animates this property now.</summary>
		/// <param name="animation">The animation that this property is a part of.</param>
		/// <param name="targetValue">The value that this property will be when the animation is over.</param>
		/// <param name="constantSpeedTime">How long the animation will change the value at a constant speed for.</param>
		/// <param name="timeToAccelerateFor">How long the animation will accelerate for. This produces a smoother animation.</param>
		/// <param name="timeToDecelerateFor">How long the animation will decelerate for. This produces a smoother animation.</param>
		/// <param name="updateCss">True if this particular property should flush its changes to css/the screen.</param>
		public void Animate(UIAnimation animation,string targetValue,float constantSpeedTime,float timeToAccelerateFor,float timeToDecelerateFor,bool updateCss){
			// Get the target float value for calculating our transition speeds as an object:
			Css.Value targetValueObject=new Css.Value();
			targetValueObject.Set(targetValue);
			
			Animate(animation,targetValueObject,constantSpeedTime,timeToAccelerateFor,timeToDecelerateFor,updateCss);
		}
Beispiel #17
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);
                }
            }
        }
		/// <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);
				}
			}
		}
		/// <summary>Gets or creates the base value for the given property.
		/// The base value is essentially the value held directly in this style sheet.
		/// E.g. if the value you're setting is the R channel of color-overlay, this sets up the color-overlay value for you.</summary>
		/// <returns>The raw value (which may have just been created).</returns>
		public Css.Value GetRawValue(CssProperty property,ValueType type){
			
			Css.Value propertyValue;
			
			// Does it exist already?
			if(!Properties.TryGetValue(property,out propertyValue)){
				
				// Nope! Create it now. Does the computed style hold a value instead?
				ComputedStyle computed=GetComputed();
				
				if(computed!=null && computed.Properties.TryGetValue(property,out propertyValue) && propertyValue!=null){
					// Let's derive from the computed form.
					propertyValue=propertyValue.Copy();
					Properties[property]=propertyValue;
				}else{
					// Needs to be created.
					Properties[property]=propertyValue=new Value();
					
					if(type==ValueType.Null){
						type=ValueType.Rectangle;
					}
					
					// Set the default value:
					property.SetDefault(propertyValue,type);
					
					if(type==ValueType.Inherit){
						
						// Set inherit:
						propertyValue.Type=ValueType.Inherit;
						
					}
					
					
				}
				
			}
			
			if(propertyValue.Type==ValueType.Inherit && type!=ValueType.Inherit){
				// Special case - we need to duplicate it.
				
				Properties[property]=propertyValue=propertyValue.Copy();
				propertyValue.Type=type;
				
			}
			
			return propertyValue;
			
		}
//--------------------------------------
		/// <summary>Duplicates this value.</summary>
		/// <returns>A duplicated copy of this value. Note that if this value has inner values, they are copied too.</returns>
		public Value Copy(){
			Value result=new Value();
			result.Type=Type;
			
			result.PX=PX;
			result.Text=Text;
			result.Single=Single;
			result.Boolean=Boolean;
			
			if(InnerValues!=null){
				result.InnerValues=new Value[InnerValues.Length];
				
				for(int i=0;i<InnerValues.Length;i++){
					Value value=InnerValues[i];
					
					if(value==null){
						continue;
					}
					
					result[i]=value.Copy();
				}
				
			}
			
			return result;
		}
		/// <summary>called when the named property changes.</summary>
		/// <param name="property">The property that changed.</param>
		/// <param name="newValue">It's new fully parsed value. May be null.</param>
		public virtual void OnChanged(CssProperty property,Value newValue){
		}
		/// <summary>Checks if two values are equal.</summary>
		/// <param name="value">The value to check for equality with this. Always returns false if null.</param>
		/// <returns>True if this and the given value are equal; false otherwise.</returns>
		public bool Equals(Value value){
			if(value==null || value.Type!=Type){
				return false;
			}
			
			switch(Type){
				case ValueType.Null:
					return true;
				case ValueType.Boolean:
					return (value.Boolean==Boolean);
				case ValueType.Pixels:
					return (value.PX==PX);
				case ValueType.Percentage:
					return (value.Single==Single);
				case ValueType.Em:
					return (value.Single==Single);
				case ValueType.Radians:
					return (value.Single==Single);
				case ValueType.Degrees:
					return (value.Single==Single);
				case ValueType.Single:
					return (value.Single==Single);
				case ValueType.Text:
					return (value.Text==Text);
				case ValueType.Calc:
					return (value.Single==Single);
				default:
				
				if(InnerValues==null){
					return (value.InnerValues==null);
				}else if(value.InnerValues==null){
					return (InnerValues==null);
				}
				
				for(int i=InnerValues.Length-1;i>=0;i--){
					if(InnerValues[i]==null){
						if(value.InnerValues[i]!=null){
							return false;
						}
					}else if(!InnerValues[i].Equals(value.InnerValues[i])){
						return false;
					}
				}
				
				return true;
			}
			
		}
		/// <summary>Apply this CSS style to the given computed style.
		/// Note that you can grab the element from the computed style if you need that.</summary>
		/// <param name="style">The computed style to apply the property to.</param>
		/// <param name="value">The new value being applied.</param>
		public virtual void Apply(ComputedStyle style,Value value){}
		/// <summary>Offsets this percentage value by a given percentage or pixel value.</summary>
		public void Offset(Value by){
			
			if(Single==1f){
				
				// Take from it.
				if(by.PX!=0){
					// Set:
					PX=-by.PX;
				}else{
					// Decrease:
					Single-=by.Single;
				}
				
			}else{
				
				// Add to it.
				if(by.PX!=0){
					// Set:
					PX=by.PX;
				}else{
					// Increase:
					Single+=by.Single;
				}
				
			}
			
			// It's a mixed unit type:
			Type=ValueType.Mixed;
			
		}
		public override void Apply(ComputedStyle style,Value value){
			
			// Got any text at all?:
			if(GetText(style)==null){
				return;
			}
			
			// Apply the property:
			if(value==null || value.Text=="none"){
				
				// Clear the stroke:
				style.TextStroke=null;
				
			}else{
			
				// The stroke properties:
				int blur=0;
				Color colour=Color.black;
				
				int thickness=value[0].PX;
				
				if(thickness==0){
					
					style.TextStroke=null;
					
				}else{
					
					StrokeData data=style.TextStroke;
					
					if(data==null){
						data=new StrokeData();
						style.TextStroke=data;
					}
					
					data.Thickness=thickness;
				
					// Grab the blur:
					Value innerValue=value[1];
					
					if(innerValue.Type==ValueType.Color){
						colour=innerValue.ToColor();
					}else{
						blur=innerValue.PX;
						
						// Grab the colour:
						innerValue=value[2];
						
						if(innerValue.Type==ValueType.Color){
							colour=innerValue.ToColor();
						}
						
					}
					
					data.Colour=colour;
					data.Blur=blur;
				
				}
				
			}
			
			// Apply the changes - doesn't change anything about the actual text, so we just want a layout:
			style.RequestLayout();
		}
		/// <summary>Sets defaults for the given number of inner values.</summary>
		/// <param name="count">The number of inner values to setup.</param>
		public void SetInnerValues(int count){
			if(InnerValues==null||InnerValues.Length!=count){
				InnerValues=new Value[count];
				
				for(int i=0;i<count;i++){
					InnerValues[i]=new Value();
				}
			}
		}