2017-12-20 12:47:50 +03:00
|
|
|
using System;
|
|
|
|
using System.Collections.Generic;
|
|
|
|
using System.ComponentModel;
|
|
|
|
using System.IO;
|
|
|
|
using System.Reflection;
|
|
|
|
using System.Runtime.CompilerServices;
|
|
|
|
using System.Xml;
|
|
|
|
using Xamarin.Forms.Xaml;
|
|
|
|
|
|
|
|
namespace Xamarin.Forms.StyleSheets
|
|
|
|
{
|
|
|
|
public sealed class StyleSheet : IStyle
|
|
|
|
{
|
|
|
|
StyleSheet()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
internal IDictionary<Selector, Style> Styles { get; set; } = new Dictionary<Selector, Style>();
|
|
|
|
|
|
|
|
public static StyleSheet FromAssemblyResource(Assembly assembly, string resourceId, IXmlLineInfo lineInfo = null)
|
|
|
|
{
|
|
|
|
using (var stream = assembly.GetManifestResourceStream(resourceId)) {
|
|
|
|
if (stream == null)
|
|
|
|
throw new XamlParseException($"No resource found for '{resourceId}'.", lineInfo);
|
|
|
|
using (var reader = new StreamReader(stream)) {
|
|
|
|
return FromReader(reader);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//used by code generated by XamlC. Has to stay public
|
|
|
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
|
|
|
public static StyleSheet FromString(string stylesheet)
|
|
|
|
{
|
|
|
|
if (stylesheet == null)
|
|
|
|
throw new ArgumentNullException(nameof(stylesheet));
|
|
|
|
using (var reader = new StringReader(stylesheet))
|
|
|
|
return FromReader(reader);
|
|
|
|
}
|
|
|
|
|
|
|
|
public static StyleSheet FromReader(TextReader reader)
|
|
|
|
{
|
|
|
|
if (reader == null)
|
|
|
|
throw new ArgumentNullException(nameof(reader));
|
|
|
|
|
|
|
|
return Parse(new CssReader(reader));
|
|
|
|
}
|
|
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
|
static StyleSheet Parse(CssReader reader)
|
|
|
|
{
|
|
|
|
var sheet = new StyleSheet();
|
|
|
|
|
|
|
|
Style style = null;
|
|
|
|
var selector = Selector.All;
|
|
|
|
|
|
|
|
int p;
|
|
|
|
bool inStyle = false;
|
|
|
|
reader.SkipWhiteSpaces();
|
|
|
|
while ((p = reader.Peek()) > 0) {
|
|
|
|
switch ((char)p) {
|
|
|
|
case '@':
|
|
|
|
throw new NotSupportedException("AT-rules not supported");
|
|
|
|
case '{':
|
|
|
|
reader.Read();
|
|
|
|
style = Style.Parse(reader, '}');
|
|
|
|
inStyle = true;
|
|
|
|
break;
|
|
|
|
case '}':
|
|
|
|
reader.Read();
|
|
|
|
if (!inStyle)
|
|
|
|
throw new Exception();
|
|
|
|
inStyle = false;
|
|
|
|
sheet.Styles.Add(selector, style);
|
|
|
|
style = null;
|
|
|
|
selector = Selector.All;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
selector = Selector.Parse(reader, '{');
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return sheet;
|
|
|
|
}
|
|
|
|
|
|
|
|
Type IStyle.TargetType
|
|
|
|
=> typeof(VisualElement);
|
|
|
|
|
|
|
|
void IStyle.Apply(BindableObject bindable)
|
|
|
|
{
|
2018-01-10 18:35:44 +03:00
|
|
|
var styleable = bindable as Element;
|
2017-12-20 12:47:50 +03:00
|
|
|
if (styleable == null)
|
|
|
|
return;
|
|
|
|
Apply(styleable);
|
|
|
|
}
|
|
|
|
|
2018-01-10 18:35:44 +03:00
|
|
|
void Apply(Element styleable)
|
2017-12-20 12:47:50 +03:00
|
|
|
{
|
|
|
|
ApplyCore(styleable);
|
|
|
|
foreach (var child in styleable.LogicalChildrenInternal)
|
|
|
|
((IStyle)this).Apply(child);
|
|
|
|
}
|
|
|
|
|
2018-01-10 18:35:44 +03:00
|
|
|
void ApplyCore(Element styleable)
|
2017-12-20 12:47:50 +03:00
|
|
|
{
|
2018-01-10 18:35:44 +03:00
|
|
|
var visualStylable = styleable as VisualElement;
|
|
|
|
if (visualStylable == null)
|
|
|
|
return;
|
2017-12-20 12:47:50 +03:00
|
|
|
foreach (var kvp in Styles) {
|
|
|
|
var selector = kvp.Key;
|
|
|
|
var style = kvp.Value;
|
|
|
|
if (!selector.Matches(styleable))
|
|
|
|
continue;
|
2018-01-10 18:35:44 +03:00
|
|
|
style.Apply(visualStylable);
|
2017-12-20 12:47:50 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void IStyle.UnApply(BindableObject bindable)
|
|
|
|
{
|
|
|
|
throw new NotImplementedException();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|