Skip to content
This repository has been archived by the owner on Dec 24, 2023. It is now read-only.

Commit

Permalink
init
Browse files Browse the repository at this point in the history
  • Loading branch information
oneo-me committed Jul 11, 2020
0 parents commit 46b65be
Show file tree
Hide file tree
Showing 31 changed files with 11,469 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*.png filter=lfs diff=lfs merge=lfs -text
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.idea
.vs
bin
obj
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[submodule "Assets"]
path = Assets
url = git@github.com:microsoft/fluentui-system-icons.git
1 change: 1 addition & 0 deletions Assets
Submodule Assets added at 0cf1b6
42 changes: 42 additions & 0 deletions FluentSystemIcons.sln
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.29613.14
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FluentSystemIconsDemo", "FluentSystemIconsDemo\FluentSystemIconsDemo.csproj", "{DCF06249-138E-4382-BABF-0981FBBF441A}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FluentSystemIcons", "FluentSystemIcons\FluentSystemIcons.csproj", "{5E793AFD-1CD3-4CDB-BF96-D27F38885CCB}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FluentSystemIconsGenerator", "FluentSystemIconsGenerator\FluentSystemIconsGenerator.csproj", "{9EF99322-7675-4BCA-93FC-1530F7C53AAD}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "_", "_", "{692CE698-16C0-4B84-9643-02845B5C579D}"
ProjectSection(SolutionItems) = preProject
README.md = README.md
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{DCF06249-138E-4382-BABF-0981FBBF441A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{DCF06249-138E-4382-BABF-0981FBBF441A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DCF06249-138E-4382-BABF-0981FBBF441A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DCF06249-138E-4382-BABF-0981FBBF441A}.Release|Any CPU.Build.0 = Release|Any CPU
{5E793AFD-1CD3-4CDB-BF96-D27F38885CCB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5E793AFD-1CD3-4CDB-BF96-D27F38885CCB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5E793AFD-1CD3-4CDB-BF96-D27F38885CCB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5E793AFD-1CD3-4CDB-BF96-D27F38885CCB}.Release|Any CPU.Build.0 = Release|Any CPU
{9EF99322-7675-4BCA-93FC-1530F7C53AAD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9EF99322-7675-4BCA-93FC-1530F7C53AAD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9EF99322-7675-4BCA-93FC-1530F7C53AAD}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9EF99322-7675-4BCA-93FC-1530F7C53AAD}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {9AD3DD87-4FFF-46E4-BF2E-3F72DBB7EBCB}
EndGlobalSection
EndGlobal
28 changes: 28 additions & 0 deletions FluentSystemIcons/FluentIcon.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
using System.Windows;
using System.Windows.Media;
using System.Windows.Shapes;

namespace FluentSystemIcons
{
public class FluentIcon : Shape
{
static FluentIcon()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(FluentIcon), new FrameworkPropertyMetadata(typeof(FluentIcon)));
}

public static readonly DependencyProperty IconProperty =
DependencyProperty.Register(nameof(Key), typeof(FluentIconKey), typeof(FluentIcon), new FrameworkPropertyMetadata(FluentIconKey.None, FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender));

public FluentIconKey Key
{
get => (FluentIconKey)GetValue(IconProperty);
set => SetValue(IconProperty, value);
}

protected override Geometry DefiningGeometry
{
get => FluentIconInfoAttribute.GetPathData(Key) ?? Geometry.Empty;
}
}
}
132 changes: 132 additions & 0 deletions FluentSystemIcons/FluentIconAnimation.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
using System;
using System.Linq;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace FluentSystemIcons
{
public class FluentIconAnimation : Shape
{
static FluentIconAnimation()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(FluentIconAnimation), new FrameworkPropertyMetadata(typeof(FluentIconAnimation)));
}

public static readonly DependencyProperty IconProperty =
DependencyProperty.Register(nameof(Key), typeof(FluentIconKey), typeof(FluentIconAnimation), new FrameworkPropertyMetadata(FluentIconKey.None, FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender, OnIconChanged));

public FluentIconKey Key
{
get => (FluentIconKey)GetValue(IconProperty);
set => SetValue(IconProperty, value);
}

static void OnIconChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var animationPath = (FluentIconAnimation)d;
animationPath.data = FluentIconInfoAttribute.GetPathData(animationPath.Key) ?? Geometry.Empty;
animationPath.UpdatePath();
}

public static readonly DependencyProperty DurationProperty =
DependencyProperty.Register(nameof(Duration), typeof(int), typeof(FluentIconAnimation), new FrameworkPropertyMetadata(1000));

public int Duration
{
get => (int)GetValue(DurationProperty);
set => SetValue(DurationProperty, value);
}

protected override Geometry DefiningGeometry
{
get => data;
}

Geometry data = Geometry.Empty;
Storyboard storyboard;

public FluentIconAnimation()
{
Loaded += OnLoaded;
}

void OnLoaded(object sender, RoutedEventArgs e)
{
Loaded -= OnLoaded;
UpdatePath();
}

void UpdatePath()
{
if (!IsLoaded)
return;

storyboard?.Stop();

if (data == Geometry.Empty)
return;

var pathLength = GetGeometryLength(data, ActualWidth, ActualHeight, StrokeThickness);

StrokeDashOffset = pathLength;
StrokeDashArray = new DoubleCollection { pathLength };

var duration = Duration / 360d * pathLength;

storyboard = new Storyboard();
var doubleAnimation = new DoubleAnimation(pathLength, 0, new Duration(TimeSpan.FromMilliseconds(duration)));
Storyboard.SetTarget(doubleAnimation, this);
Storyboard.SetTargetProperty(doubleAnimation, new PropertyPath(StrokeDashOffsetProperty));
storyboard.Children.Add(doubleAnimation);
storyboard.Begin();
}

static double GetGeometryLength(Geometry geometry, double width, double height, double strokeThickness)
{
var flattenedPathGeometry = geometry.GetFlattenedPathGeometry();
if (flattenedPathGeometry.Figures.Count == 0)
return 0;
var maxFiguresLength = flattenedPathGeometry.Figures.Max(GetFigureLength);
var sw = geometry.Bounds.Width / width;
var sh = geometry.Bounds.Height / height;
var min = Math.Min(sw, sh);
return maxFiguresLength / min / strokeThickness;
}

static double GetFigureLength(PathFigure pathFigure)
{
var length = 0.0;
var start = pathFigure.StartPoint;

foreach (var pathSegment in pathFigure.Segments)
switch (pathSegment)
{
case LineSegment lineSegment:
length += GetPointDistance(start, lineSegment.Point);
start = lineSegment.Point;
break;

case PolyLineSegment polyLineSegment:
foreach (var point in polyLineSegment.Points)
{
length += GetPointDistance(start, point);
start = point;
}

break;

default:
throw new Exception();
}

return length;
}

static double GetPointDistance(Point point1, Point point2)
{
return Math.Sqrt(Math.Pow(point1.X - point2.X, 2) + Math.Pow(point1.Y - point2.Y, 2));
}
}
}
59 changes: 59 additions & 0 deletions FluentSystemIcons/FluentIconInfoAttribute.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Windows.Media;

namespace FluentSystemIcons
{
public class FluentIconInfoAttribute : Attribute
{
static readonly Type type = typeof(FluentIconInfoAttribute);
static readonly Type infoType = typeof(FluentIconKey);
static readonly Dictionary<FluentIconKey, FieldInfo> infos = new Dictionary<FluentIconKey, FieldInfo>();

static FieldInfo GetField(FluentIconKey iconKey)
{
if (!infos.ContainsKey(iconKey))
infos[iconKey] = infoType.GetField($"{iconKey}");
return infos[iconKey];
}

readonly string path;
readonly string name;

public FluentIconInfoAttribute(string name, string path)
{
this.name = name;
this.path = path;
}

static readonly Dictionary<FluentIconKey, Geometry> geometries = new Dictionary<FluentIconKey, Geometry>();

public static string GetCategory(FluentIconKey iconKey)
{
if (iconKey == FluentIconKey.None)
return null;

if (!(GetCustomAttribute(GetField(iconKey), type) is FluentIconInfoAttribute pathAttribute))
return null;

return pathAttribute.name;
}

public static Geometry GetPathData(FluentIconKey iconKey)
{
if (iconKey == FluentIconKey.None)
return null;

if (geometries.ContainsKey(iconKey))
return geometries[iconKey];

if (!(GetCustomAttribute(GetField(iconKey), type) is FluentIconInfoAttribute pathAttribute))
return null;

geometries[iconKey] = Geometry.Parse(pathAttribute.path);

return geometries[iconKey];
}
}
}
Loading

0 comments on commit 46b65be

Please sign in to comment.