Skip to content

Commit

Permalink
Add Hatch
Browse files Browse the repository at this point in the history
  • Loading branch information
ghost1372 committed Dec 29, 2024
1 parent 57abc6a commit 51ec4ed
Show file tree
Hide file tree
Showing 11 changed files with 354 additions and 0 deletions.
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,7 @@ Install-Package DevWinUI
- ✨ Border Style
- ✨ Subtle Button Style
#### 🔥 Win2D 🔥
- ✨ Hatch
- ✨ TiledImageBrush
- ✨ OutlineTextControl
- ✨ WaveCircle
Expand Down Expand Up @@ -256,6 +257,9 @@ Install-Package DevWinUI.ContextMenu

## 🕰️ History 🕰️

### Hatch
![DevWinUI](https://raw.githubusercontent.com/ghost1372/DevWinUI-Resources/refs/heads/main/DevWinUI-Docs/Hatch.gif)

### CompareSlider
![DevWinUI](https://raw.githubusercontent.com/ghost1372/DevWinUI-Resources/refs/heads/main/DevWinUI-Docs/CompareSlider.gif)
![DevWinUI](https://raw.githubusercontent.com/ghost1372/DevWinUI-Resources/refs/heads/main/DevWinUI-Docs/CompareSlider2.gif)
Expand Down
18 changes: 18 additions & 0 deletions dev/DevWinUI.Controls/Themes/Generic.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ Themes\Styles\Win2D\GooeyButton.xaml
Themes\Styles\Win2D\GooeyButtonItem.xaml
Themes\Styles\Win2D\GooeyEffect.xaml
Themes\Styles\Win2D\GooeyFooterEffect.xaml
Themes\Styles\Win2D\Hatch.xaml
Themes\Styles\Win2D\Particle.xaml
Themes\Styles\Win2D\TextBlockStrokeView.xaml
Themes\Styles\Win2D\TextGlitchEffect.xaml
Expand Down Expand Up @@ -1726,6 +1727,23 @@ Themes\Styles\Win2D\Watermark.xaml
</Setter.Value>
</Setter>
</Style>
<Style TargetType="local:Hatch">
<Setter Property="Foreground" Value="{ThemeResource SystemAccentColor}" />
<Setter Property="Background" Value="{ThemeResource ControlFillColorDefaultBrush}" />
<Setter Property="BorderBrush" Value="{ThemeResource ControlElevationBorderBrush}" />
<Setter Property="CornerRadius" Value="{ThemeResource ControlCornerRadius}" />
<Setter Property="BorderThickness" Value="1" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:Hatch">
<Grid BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" CornerRadius="{TemplateBinding CornerRadius}">
<win2d:CanvasControl x:Name="PART_Canvas" />
<ContentPresenter Padding="{TemplateBinding Padding}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" Content="{TemplateBinding Content}" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="local:Particle">
<Setter Property="LineColor" Value="{ThemeResource SystemBaseMediumLowColor}" />
<Setter Property="ParticleColor" Value="{ThemeResource SystemBaseLowColor}" />
Expand Down
29 changes: 29 additions & 0 deletions dev/DevWinUI.Controls/Themes/Styles/Win2D/Hatch.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="utf-8" ?>
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:DevWinUI"
xmlns:win2d="using:Microsoft.Graphics.Canvas.UI.Xaml">

<Style TargetType="local:Hatch">
<Setter Property="Foreground" Value="{ThemeResource SystemAccentColor}" />
<Setter Property="Background" Value="{ThemeResource ControlFillColorDefaultBrush}" />
<Setter Property="BorderBrush" Value="{ThemeResource ControlElevationBorderBrush}" />
<Setter Property="CornerRadius" Value="{ThemeResource ControlCornerRadius}" />
<Setter Property="BorderThickness" Value="1" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:Hatch">
<Grid BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="{TemplateBinding CornerRadius}">
<win2d:CanvasControl x:Name="PART_Canvas" />
<ContentPresenter Padding="{TemplateBinding Padding}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
Content="{TemplateBinding Content}" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
115 changes: 115 additions & 0 deletions dev/DevWinUI.Controls/Win2D/Controls/Hatch/Hatch.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
using Microsoft.UI.Xaml.Markup;

namespace DevWinUI;

[TemplatePart(Name = CanvasElement, Type = typeof(CanvasControl))]
[ContentProperty(Name = nameof(Content))]
public partial class Hatch : Control
{
public HatchStyle HatchStyle
{
get => (HatchStyle)GetValue(HatchStyleProperty);
set => SetValue(HatchStyleProperty, value);
}
public static readonly DependencyProperty HatchStyleProperty =
DependencyProperty.Register(nameof(HatchStyle), typeof(HatchStyle), typeof(Hatch), new PropertyMetadata(HatchStyle.Horizontal, OnHatchStyleChanged));
private static void OnHatchStyleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is Hatch control)
{
control.InvalidateCanvas();
}
}
public object Content
{
get { return (object)GetValue(ContentProperty); }
set { SetValue(ContentProperty, value); }
}

public static readonly DependencyProperty ContentProperty =
DependencyProperty.Register(nameof(Content), typeof(object), typeof(Hatch), new PropertyMetadata(null));

private const string CanvasElement = "PART_Canvas";
private CanvasControl canvas;
protected override void OnApplyTemplate()
{
base.OnApplyTemplate();

canvas = GetTemplateChild(CanvasElement) as CanvasControl;

canvas.Draw -= OnCanvasDraw;
canvas.Draw += OnCanvasDraw;

RegisterPropertyChangedCallback(ForegroundProperty, (s, dp) => InvalidateCanvas());
RegisterPropertyChangedCallback(BackgroundProperty, (s, dp) => InvalidateCanvas());
}
private void InvalidateCanvas()
{
if (canvas != null)
{
canvas.Invalidate();
}
}
private void OnCanvasDraw(CanvasControl sender, CanvasDrawEventArgs args)
{
var hatchStyle = HatchStyle;
var foreground = (Foreground as SolidColorBrush)?.Color ?? Colors.Transparent;
var background = (Background as SolidColorBrush)?.Color ?? Colors.Transparent;

DrawHatchPattern(args.DrawingSession, hatchStyle, foreground, background);
}
public float GetAdjustedDpi()
{
var baseDpi = 96.0f;

if (canvas == null)
{
return baseDpi;
}

var rasterizationScale = GeneralHelper.GetElementRasterizationScale(canvas);
var adjustedDpi = baseDpi * rasterizationScale;

return (float)adjustedDpi;
}
private void DrawHatchPattern(CanvasDrawingSession session, HatchStyle hatchStyle, Color foreColor, Color backColor)
{
// Fill the background
session.FillRectangle(0, 0, (float)ActualWidth, (float)ActualHeight, backColor);

// Get the hatch pattern
var hatchData = HatchGenerator.GetHatchData(hatchStyle);

// Define the size of the pattern
const int patternSize = 8;

// Create a pixel grid using the hatch data
using (var offscreen = new CanvasRenderTarget(session.Device, patternSize, patternSize, GetAdjustedDpi()))
{
using (var offscreenSession = offscreen.CreateDrawingSession())
{
offscreenSession.Clear(Colors.Transparent);
for (int y = 0; y < patternSize; y++)
{
byte row = hatchData[y];
for (int x = 0; x < patternSize; x++)
{
if ((row & (1 << (7 - x))) != 0) // Check if the bit is set
{
offscreenSession.FillRectangle(x, y, 1, 1, foreColor);
}
}
}
}

// Use the generated pattern as a tiled brush
var tiledBrush = new CanvasImageBrush(session.Device, offscreen)
{
ExtendX = CanvasEdgeBehavior.Wrap,
ExtendY = CanvasEdgeBehavior.Wrap
};

session.FillRectangle(0, 0, (float)ActualWidth, (float)ActualHeight, tiledBrush);
}
}
}
64 changes: 64 additions & 0 deletions dev/DevWinUI.Controls/Win2D/Controls/Hatch/HatchGenerator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
namespace DevWinUI;
public class HatchGenerator
{
private static readonly byte[][] HatchBrushes =
{
new byte[] {0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00}, // Horizontal
new byte[] {0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08}, // Vertical
new byte[] {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80}, // ForwardDiagonal
new byte[] {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01}, // BackwardDiagonal
new byte[] {0x08, 0x08, 0x08, 0xff, 0x08, 0x08, 0x08, 0x08}, // Cross
new byte[] {0x81, 0x42, 0x24, 0x18, 0x18, 0x24, 0x42, 0x81}, // DiagonalCross
new byte[] {0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x80}, // Percent05
new byte[] {0x00, 0x02, 0x00, 0x88, 0x00, 0x20, 0x00, 0x88}, // Percent10
new byte[] {0x00, 0x22, 0x00, 0xcc, 0x00, 0x22, 0x00, 0xcc}, // Percent20
new byte[] {0x00, 0xcc, 0x00, 0xcc, 0x00, 0xcc, 0x00, 0xcc}, // Percent25
new byte[] {0x00, 0xcc, 0x04, 0xcc, 0x00, 0xcc, 0x40, 0xcc}, // Percent30
new byte[] {0x44, 0xcc, 0x22, 0xcc, 0x44, 0xcc, 0x22, 0xcc}, // Percent40
new byte[] {0x55, 0xcc, 0x55, 0xcc, 0x55, 0xcc, 0x55, 0xcc}, // Percent50
new byte[] {0x55, 0xcd, 0x55, 0xee, 0x55, 0xdc, 0x55, 0xee}, // Percent60
new byte[] {0x55, 0xdd, 0x55, 0xff, 0x55, 0xdd, 0x55, 0xff}, // Percent70
new byte[] {0x55, 0xff, 0x55, 0xff, 0x55, 0xff, 0x55, 0xff}, // Percent75
new byte[] {0x55, 0xff, 0x59, 0xff, 0x55, 0xff, 0x99, 0xff}, // Percent80
new byte[] {0x77, 0xff, 0xdd, 0xff, 0x77, 0xff, 0xfd, 0xff}, // Percent90
new byte[] {0x11, 0x22, 0x44, 0x88, 0x11, 0x22, 0x44, 0x88}, // LightDownwardDiagonal
new byte[] {0x88, 0x44, 0x22, 0x11, 0x88, 0x44, 0x22, 0x11}, // LightUpwardDiagonal
new byte[] {0x99, 0x33, 0x66, 0xcc, 0x99, 0x33, 0x66, 0xcc}, // DarkDownwardDiagonal
new byte[] {0xcc, 0x66, 0x33, 0x99, 0xcc, 0x66, 0x33, 0x99}, // DarkUpwardDiagonal
new byte[] {0xc1, 0x83, 0x07, 0x0e, 0x1c, 0x38, 0x70, 0xe0}, // WideDownwardDiagonal
new byte[] {0xe0, 0x70, 0x38, 0x1c, 0x0e, 0x07, 0x83, 0xc1}, // WideUpwardDiagonal
new byte[] {0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88}, // LightVertical
new byte[] {0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff}, // LightHorizontal
new byte[] {0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa}, // NarrowVertical
new byte[] {0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff}, // NarrowHorizontal
new byte[] {0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc}, // DarkVertical
new byte[] {0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff}, // DarkHorizontal
new byte[] {0x11, 0x22, 0x44, 0x88, 0x00, 0x00, 0x00, 0x00}, // DashedDownwardDiagonal
new byte[] {0x88, 0x44, 0x22, 0x11, 0x00, 0x00, 0x00, 0x00}, // DashedUpwardDiagonal
new byte[] {0x0f, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00}, // DashedHorizontal
new byte[] {0x01, 0x01, 0x01, 0x01, 0x10, 0x10, 0x10, 0x10}, // DashedVertical
new byte[] {0x01, 0x08, 0x80, 0x10, 0x02, 0x40, 0x04, 0x20}, // SmallConfetti
new byte[] {0x03, 0x63, 0x6c, 0x0c, 0xc0, 0xc6, 0x36, 0x30}, // LargeConfetti
new byte[] {0x03, 0x84, 0x48, 0x30, 0x03, 0x84, 0x48, 0x30}, // ZigZag
new byte[] {0x30, 0x49, 0x06, 0x00, 0x30, 0x49, 0x06, 0x00}, // Wave
new byte[] {0x81, 0x42, 0x24, 0x18, 0x08, 0x04, 0x02, 0x01}, // DiagonalBrick
new byte[] {0xff, 0x01, 0x01, 0x01, 0xff, 0x10, 0x10, 0x10}, // HorizontalBrick
new byte[] {0x11, 0x82, 0x44, 0xa8, 0x11, 0xa2, 0x44, 0x2a}, // Weave
new byte[] {0x55, 0xaa, 0x55, 0xaa, 0x0f, 0x0f, 0x0f, 0x0f}, // Plaid
new byte[] {0x02, 0x01, 0x02, 0x00, 0x10, 0x20, 0x10, 0x00}, // Divot
new byte[] {0x55, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00}, // DottedGrid
new byte[] {0x11, 0x00, 0x04, 0x00, 0x11, 0x00, 0x40, 0x00}, // DottedDiamond
new byte[] {0x03, 0x0c, 0x10, 0x20, 0x20, 0x30, 0x48, 0x84}, // Shingle
new byte[] {0xff, 0x33, 0xff, 0xcc, 0xff, 0x33, 0xff, 0xcc}, // Trellis
new byte[] {0xee, 0x19, 0x1f, 0x1f, 0xee, 0x91, 0xf1, 0xf1}, // Sphere
new byte[] {0xff, 0x11, 0x11, 0x11, 0xff, 0x11, 0x11, 0x11}, // SmallGrid
new byte[] {0x33, 0x33, 0xcc, 0xcc, 0x33, 0x33, 0xcc, 0xcc}, // SmallCheckerBoard
new byte[] {0x0f, 0x0f, 0x0f, 0x0f, 0xf0, 0xf0, 0xf0, 0xf0}, // LargeCheckerBoard
new byte[] {0x01, 0x82, 0x44, 0x28, 0x10, 0x28, 0x44, 0x82}, // OutlinedDiamond
new byte[] {0x08, 0x1c, 0x3e, 0x7f, 0x3e, 0x1c, 0x08, 0x00} // SolidDiamond
};
public static byte[] GetHatchData(HatchStyle hatchStyle) =>
hatchStyle < HatchStyle.Horizontal || hatchStyle > HatchStyle.SolidDiamond
? throw new ArgumentOutOfRangeException(nameof(hatchStyle))
: HatchBrushes[(int)hatchStyle];
}
57 changes: 57 additions & 0 deletions dev/DevWinUI.Controls/Win2D/Controls/Hatch/HatchStyle.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
namespace DevWinUI;
public enum HatchStyle
{
Horizontal,
Vertical,
ForwardDiagonal,
BackwardDiagonal,
Cross,
DiagonalCross,
Percent05,
Percent10,
Percent20,
Percent25,
Percent30,
Percent40,
Percent50,
Percent60,
Percent70,
Percent75,
Percent80,
Percent90,
LightDownwardDiagonal,
LightUpwardDiagonal,
DarkDownwardDiagonal,
DarkUpwardDiagonal,
WideDownwardDiagonal,
WideUpwardDiagonal,
LightVertical,
LightHorizontal,
NarrowVertical,
NarrowHorizontal,
DarkVertical,
DarkHorizontal,
DashedDownwardDiagonal,
DashedUpwardDiagonal,
DashedHorizontal,
DashedVertical,
SmallConfetti,
LargeConfetti,
ZigZag,
Wave,
DiagonalBrick,
HorizontalBrick,
Weave,
Plaid,
Divot,
DottedGrid,
DottedDiamond,
Shingle,
Trellis,
Sphere,
SmallGrid,
SmallCheckerBoard,
LargeCheckerBoard,
OutlinedDiamond,
SolidDiamond
}
Binary file added dev/DevWinUI.Gallery/Assets/Fluent/Grid.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
7 changes: 7 additions & 0 deletions dev/DevWinUI.Gallery/Assets/NavViewMenu/AppData.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,13 @@
"Title": "Features (Win2D)",
"ImagePath": "ms-appx:///Assets/Fluent/Canvas.png",
"Items": [
{
"UniqueId": "DevWinUIGallery.Views.HatchPage",
"Title": "Hatch",
"Subtitle": "Hatch",
"IsNew": true,
"ImagePath": "ms-appx:///Assets/Fluent/Grid.png"
},
{
"UniqueId": "DevWinUIGallery.Views.TiledImageBrushPage",
"Title": "TiledImageBrush",
Expand Down
1 change: 1 addition & 0 deletions dev/DevWinUI.Gallery/T4Templates/NavigationPageMappings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ public partial class NavigationPageMappings
public static Dictionary<string, Type> PageDictionary { get; } = new Dictionary<string, Type>
{
{"DevWinUIGallery.Views.HomeLandingPage", typeof(DevWinUIGallery.Views.HomeLandingPage)},
{"DevWinUIGallery.Views.HatchPage", typeof(DevWinUIGallery.Views.HatchPage)},
{"DevWinUIGallery.Views.TiledImageBrushPage", typeof(DevWinUIGallery.Views.TiledImageBrushPage)},
{"DevWinUIGallery.Views.OutlineTextControlPage", typeof(DevWinUIGallery.Views.OutlineTextControlPage)},
{"DevWinUIGallery.Views.WatermarkPage", typeof(DevWinUIGallery.Views.WatermarkPage)},
Expand Down
35 changes: 35 additions & 0 deletions dev/DevWinUI.Gallery/Views/Pages/Win2d/HatchPage.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?xml version="1.0" encoding="utf-8" ?>
<Page x:Class="DevWinUIGallery.Views.HatchPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:dev="using:DevWinUI"
xmlns:local="using:DevWinUIGallery"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">

<ScrollViewer>
<StackPanel Margin="10"
dev:PanelAttach.ChildrenTransitions="Default"
Spacing="10">
<local:ControlExample DocPage="controls/hatch"
DocType="Controls">
<local:ControlExample.Pane>
<ComboBox x:Name="HatchPicker"
Header="Pick a Hatch"
ItemsSource="{x:Bind Items, Mode=OneWay}"
SelectedIndex="0"
SelectionChanged="HatchPicker_SelectionChanged" />
</local:ControlExample.Pane>
<local:ControlExample.Xaml>
<x:String>
&lt;dev:Hatch /&gt;
</x:String>
</local:ControlExample.Xaml>
<dev:Hatch x:Name="HatchSample"
Height="400" />
</local:ControlExample>
</StackPanel>
</ScrollViewer>

</Page>
Loading

0 comments on commit 51ec4ed

Please sign in to comment.