Skip to content
This repository has been archived by the owner on May 1, 2024. It is now read-only.

Commit

Permalink
Stylesheets wip
Browse files Browse the repository at this point in the history
  • Loading branch information
StephaneDelcroix committed Oct 18, 2017
1 parent 347c340 commit b8e5e98
Show file tree
Hide file tree
Showing 35 changed files with 1,287 additions and 88 deletions.
2 changes: 1 addition & 1 deletion .nuspec/Xamarin.Forms.Debug.targets
Expand Up @@ -24,4 +24,4 @@
DebugSymbols = "$(DebugSymbols)"
DebugType = "$(DebugType)"/>
</Target>
</Project>
</Project>
15 changes: 15 additions & 0 deletions .nuspec/Xamarin.Forms.targets
Expand Up @@ -109,4 +109,19 @@
DebugType = "$(DebugType)"
KeepXamlResources = "$(XFKeepXamlResources)" />
</Target>

<PropertyGroup>
<PrepareResourcesDependsOn>
RenameCss;
$(PrepareResourcesDependsOn)
</PrepareResourcesDependsOn>
</PropertyGroup>

<Target Name="RenameCss">
<ItemGroup>
<EmbeddedResource Condition="'%(Extension)' == '.css'" >
<LogicalName>%(EmbeddedResource.RelativeDir)%(EmbeddedResource.Filename)%(EmbeddedResource.Extension)</LogicalName>
</EmbeddedResource>
</ItemGroup>
</Target>
</Project>
13 changes: 13 additions & 0 deletions Xamarin.Forms.Build.Tasks/NodeILExtensions.cs
Expand Up @@ -457,6 +457,19 @@ public static IEnumerable<Instruction> PushServiceProvider(this INode node, ILCo

yield return Instruction.Create(OpCodes.Newobj, ctor);

//Add a CurrentAssemblyProvider
{
yield return Instruction.Create(OpCodes.Dup); //Dupicate the serviceProvider
yield return Instruction.Create(OpCodes.Ldtoken, module.ImportReference(typeof(ICurrentAssemblyProvider)));
yield return Instruction.Create(OpCodes.Call, module.ImportReference(getTypeFromHandle));
var currentAssemblyproviderCtor = module.ImportReference(typeof(CurrentAssemblyProvider).GetConstructor(new []{ typeof(System.Reflection.Assembly) }));
//call class [mscorlib]System.Reflection.Assembly class [mscorlib]System.Reflection.Assembly::GetExecutingAssembly()
var getExecutingAssembly = module.ImportReference(typeof(System.Reflection.Assembly).GetMethod("GetExecutingAssembly"));
yield return Instruction.Create(OpCodes.Call, getExecutingAssembly);
yield return Instruction.Create(OpCodes.Newobj, currentAssemblyproviderCtor);
yield return Instruction.Create(OpCodes.Callvirt, addService);
}

//Add a SimpleValueTargetProvider
var pushParentIl = node.PushParentObjectsArray(context).ToList();
if (pushParentIl[pushParentIl.Count - 1].OpCode != OpCodes.Ldnull)
Expand Down
16 changes: 14 additions & 2 deletions Xamarin.Forms.Core.UnitTests/LabelTests.cs
Expand Up @@ -189,8 +189,7 @@ public void FontSizeCanBeSetFromStyle ()
public void ManuallySetFontSizeNotOverridenByStyle ()
{
var label = new Label ();

Assert.AreEqual (10.0, label.FontSize);
Assume.That (label.FontSize, Is.EqualTo(10.0));

label.SetValue (Label.FontSizeProperty, 2.0, false);
Assert.AreEqual (2.0, label.FontSize);
Expand All @@ -199,6 +198,19 @@ public void ManuallySetFontSizeNotOverridenByStyle ()
Assert.AreEqual (2.0, label.FontSize);
}

[Test]
public void ManuallySetFontSizeNotOverridenByFontSetInStyle()
{
var label = new Label();
Assume.That(label.FontSize, Is.EqualTo(10.0));

label.SetValue(Label.FontSizeProperty, 2.0);
Assert.AreEqual(2.0, label.FontSize);

label.SetValue(Label.FontProperty, Font.SystemFontOfSize(1.0), fromStyle: true);
Assert.AreEqual(2.0, label.FontSize);
}

[Test]
public void ChangingHorizontalTextAlignmentFiresXAlignChanged ()
{
Expand Down
51 changes: 51 additions & 0 deletions Xamarin.Forms.Core.UnitTests/StyleSheets/IStylableTest.cs
@@ -0,0 +1,51 @@
using System;

using NUnit.Framework;

using Xamarin.Forms.Core.UnitTests;

namespace Xamarin.Forms.StyleSheets.UnitTests
{
[TestFixture]
public class IStylableTest
{
[SetUp]
public void SetUp()
{
Device.PlatformServices = new MockPlatformServices();
Internals.Registrar.RegisterAll(new Type[0]);
}

[TestCase]
public void GetBackgroundColor()
{
var label = new Label();
var bp = ((IStylable)label).GetProperty("background-color");
Assert.AreSame(VisualElement.BackgroundColorProperty, bp);
}

[TestCase]
public void GetLabelColor()
{
var label = new Label();
var bp = ((IStylable)label).GetProperty("color");
Assert.AreSame(Label.TextColorProperty, bp);
}

[TestCase]
public void GetEntryColor()
{
var entry = new Entry();
var bp = ((IStylable)entry).GetProperty("color");
Assert.AreSame(Entry.TextColorProperty, bp);
}

[TestCase]
public void GetGridColor()
{
var grid = new Grid();
var bp = ((IStylable)grid).GetProperty("color");
Assert.Null(bp);
}
}
}
14 changes: 14 additions & 0 deletions Xamarin.Forms.Core.UnitTests/StyleSheets/MockStylable.cs
@@ -0,0 +1,14 @@
using System.Collections.Generic;
using NUnit.Framework;

namespace Xamarin.Forms.StyleSheets.UnitTests
{
class MockStylable : IStyleSelectable
{
public IEnumerable<IStyleSelectable> Children { get; set; }
public IList<string> Classes { get; set; }
public string Id { get; set; }
public string Name { get; set; }
public IStyleSelectable Parent { get; set; }
}
}
110 changes: 110 additions & 0 deletions Xamarin.Forms.Core.UnitTests/StyleSheets/SelectorTests.cs
@@ -0,0 +1,110 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using NUnit.Framework;

namespace Xamarin.Forms.StyleSheets.UnitTests
{
[TestFixture]
public class SelectorTests
{
IStyleSelectable Page;
IStyleSelectable StackLayout => Page.Children.First();
IStyleSelectable Label0 => StackLayout.Children.Skip(0).First();
IStyleSelectable Label1 => StackLayout.Children.Skip(1).First();
IStyleSelectable Label2 => ContentView0.Children.First();
IStyleSelectable Label3 => StackLayout.Children.Skip(3).First();
IStyleSelectable Label4 => StackLayout.Children.Skip(4).First();
IStyleSelectable ContentView0 => StackLayout.Children.Skip(2).First();

[SetUp]
public void SetUp()
{
Page = new MockStylable {
Name = "Page",
Children = new List<IStyleSelectable> {
new MockStylable {
Name = "StackLayout",
Children = new List<IStyleSelectable> {
new MockStylable {Name = "Label", Classes = new[]{"test"}}, //Label0
new MockStylable {Name = "Label"}, //Label1
new MockStylable { //ContentView0
Name = "ContentView",
Classes = new[]{"test"},
Children = new List<IStyleSelectable> {
new MockStylable {Name = "Label", Classes = new[]{"test"}}, //Label2
}
},
new MockStylable {Name = "Label", Id="foo"}, //Label3
new MockStylable {Name = "Label"}, //Label4
}
}
}
};
SetParents(Page);
}

void SetParents(IStyleSelectable stylable, IStyleSelectable parent = null)
{
((MockStylable)stylable).Parent = parent;
if (stylable.Children == null)
return;
foreach (var s in stylable.Children)
SetParents(s, stylable);
}

[TestCase("label", true, true, true, true, true, false)]
[TestCase(" label", true, true, true, true, true, false)]
[TestCase("label ", true, true, true, true, true, false)]
[TestCase(".test", true, false, true, false, false, true)]
[TestCase("label.test", true, false, true, false, false, false)]
[TestCase("stacklayout>label.test", true, false, false, false, false, false)]
[TestCase("stacklayout >label.test", true, false, false, false, false, false)]
[TestCase("stacklayout> label.test", true, false, false, false, false, false)]
[TestCase("stacklayout label.test", true, false, true, false, false, false)]
[TestCase("stacklayout label.test", true, false, true, false, false, false)]
[TestCase("stacklayout .test", true, false, true, false, false, true)]
[TestCase("*", true, true, true, true, true, true)]
[TestCase("#foo", false, false, false, true, false, false)]
[TestCase("label#foo", false, false, false, true, false, false)]
[TestCase("div#foo", false, false, false, false, false, false)]
[TestCase(".test,#foo", true, false, true, true, false, true)]
[TestCase(".test ,#foo", true, false, true, true, false, true)]
[TestCase(".test, #foo", true, false, true, true, false, true)]
[TestCase("#foo,.test", true, false, true, true, false, true)]
[TestCase("#foo ,.test", true, false, true, true, false, true)]
[TestCase("#foo, .test", true, false, true, true, false, true)]
[TestCase("contentview+label", false, false, false, true, false, false)]
[TestCase("contentview +label", false, false, false, true, false, false)]
[TestCase("contentview+ label", false, false, false, true, false, false)]
[TestCase("contentview~label", false, false, false, true, true, false)]
[TestCase("contentview ~label", false, false, false, true, true, false)]
[TestCase("contentview\r\n~label", false, false, false, true, true, false)]
[TestCase("contentview~ label", false, false, false, true, true, false)]
[TestCase("label~*", false, true, false, true, true, true)]
[TestCase("label~.test", false, false, false, false, false, true)]
[TestCase("label~#foo", false, false, false, true, false, false)]
[TestCase("page contentview stacklayout label", false, false, false, false, false, false)]
[TestCase("page stacklayout contentview label", false, false, true, false, false, false)]
[TestCase("page contentview label", false, false, true, false, false, false)]
[TestCase("page contentview>label", false, false, true, false, false, false)]
[TestCase("page>stacklayout contentview label", false, false, true, false, false, false)]
[TestCase("page stacklayout>contentview label", false, false, true, false, false, false)]
[TestCase("page stacklayout contentview>label", false, false, true, false, false, false)]
[TestCase("page>stacklayout>contentview label", false, false, true, false, false, false)]
[TestCase("page>stack/* comment * */layout>contentview label", false, false, true, false, false, false)]
[TestCase("page>stacklayout contentview>label", false, false, true, false, false, false)]
[TestCase("page stacklayout>contentview>label", false, false, true, false, false, false)]
[TestCase("page>stacklayout>contentview>label", false, false, true, false, false, false)]
public void TestCase(string selectorString, bool label0match, bool label1match, bool label2match, bool label3match, bool label4match, bool content0match)
{
var selector = Selector.Parse(new CssReader(new StringReader(selectorString)));
Assert.AreEqual(label0match, selector.Matches(Label0));
Assert.AreEqual(label1match, selector.Matches(Label1));
Assert.AreEqual(label2match, selector.Matches(Label2));
Assert.AreEqual(label3match, selector.Matches(Label3));
Assert.AreEqual(label4match, selector.Matches(Label4));
Assert.AreEqual(content0match, selector.Matches(ContentView0));
}
}
}
82 changes: 82 additions & 0 deletions Xamarin.Forms.Core.UnitTests/StyleSheets/StyleTests.cs
@@ -0,0 +1,82 @@
using System;
using System.IO;

using NUnit.Framework;

using Xamarin.Forms.Core.UnitTests;

namespace Xamarin.Forms.StyleSheets.UnitTests
{
[TestFixture]
public class StyleTests
{
[SetUp]
public void SetUp()
{
Device.PlatformServices = new MockPlatformServices();
Internals.Registrar.RegisterAll(new Type[0]);
}

[Test]
public void PropertiesAreApplied()
{
var styleString = @"background-color: #ff0000;";
var style = Style.Parse(new CssReader(new StringReader(styleString)), '}');
Assume.That(style, Is.Not.Null);

var ve = new VisualElement();
Assume.That(ve.BackgroundColor, Is.EqualTo(Color.Default));
style.Apply(ve);
Assert.That(ve.BackgroundColor, Is.EqualTo(Color.Red));
}

[Test]
public void PropertiesSetByStyleDoesNotOverrideManualOne()
{
var styleString = @"background-color: #ff0000;";
var style = Style.Parse(new CssReader(new StringReader(styleString)), '}');
Assume.That(style, Is.Not.Null);

var ve = new VisualElement() { BackgroundColor = Color.Pink };
Assume.That(ve.BackgroundColor, Is.EqualTo(Color.Pink));

style.Apply(ve);
Assert.That(ve.BackgroundColor, Is.EqualTo(Color.Pink));
}

[Test]
public void StylesAreCascading()
{
var styleString = @"background-color: #ff0000; color: #00ff00;";
var style = Style.Parse(new CssReader(new StringReader(styleString)), '}');
Assume.That(style, Is.Not.Null);

var label = new Label();
var layout = new StackLayout {
Children = {
label,
}
};

Assume.That(layout.BackgroundColor, Is.EqualTo(Color.Default));
Assume.That(label.BackgroundColor, Is.EqualTo(Color.Default));
Assume.That(label.TextColor, Is.EqualTo(Color.Default));

style.Apply(layout);
Assert.That(layout.BackgroundColor, Is.EqualTo(Color.Red));
Assert.That(label.BackgroundColor, Is.EqualTo(Color.Red));
Assert.That(label.TextColor, Is.EqualTo(Color.Lime));
}

[Test]
public void PropertiesAreOnlySetOnMatchingElements()
{
var styleString = @"background-color: #ff0000; color: #00ff00;";
var style = Style.Parse(new CssReader(new StringReader(styleString)), '}');
Assume.That(style, Is.Not.Null);

var layout = new StackLayout();
Assert.That(layout.GetValue(TextElement.TextColorProperty), Is.EqualTo(Color.Default));
}
}
}
Expand Up @@ -187,6 +187,10 @@
<Compile Include="NativeBindingTests.cs" />
<Compile Include="TypedBindingUnitTests.cs" />
<Compile Include="AnimationTests.cs" />
<Compile Include="StyleSheets\MockStylable.cs" />
<Compile Include="StyleSheets\SelectorTests.cs" />
<Compile Include="StyleSheets\IStylableTest.cs" />
<Compile Include="StyleSheets\StyleTests.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Xamarin.Forms.Core\Xamarin.Forms.Core.csproj">
Expand Down Expand Up @@ -219,4 +223,7 @@
<LogicalName>Images/crimson.jpg</LogicalName>
</EmbeddedResource>
</ItemGroup>
</Project>
<ItemGroup>
<Folder Include="StyleSheets\" />
</ItemGroup>
</Project>
2 changes: 1 addition & 1 deletion Xamarin.Forms.Core/Element.cs
Expand Up @@ -9,7 +9,7 @@

namespace Xamarin.Forms
{
public abstract class Element : BindableObject, IElement, INameScope, IElementController
public abstract partial class Element : BindableObject, IElement, INameScope, IElementController
{

public static readonly BindableProperty MenuProperty = BindableProperty.CreateAttached(nameof(Menu), typeof(Menu), typeof(Element), null);
Expand Down
2 changes: 1 addition & 1 deletion Xamarin.Forms.Core/Entry.cs
Expand Up @@ -129,4 +129,4 @@ void ITextElement.OnTextColorPropertyChanged(Color oldValue, Color newValue)
{
}
}
}
}
7 changes: 0 additions & 7 deletions Xamarin.Forms.Core/IRootObjectProvider.cs

This file was deleted.

2 changes: 1 addition & 1 deletion Xamarin.Forms.Core/Label.cs
Expand Up @@ -191,4 +191,4 @@ void ITextElement.OnTextColorPropertyChanged(Color oldValue, Color newValue)
{
}
}
}
}

0 comments on commit b8e5e98

Please sign in to comment.