Viewing is open to everyone. Downloading and starring need a GitHub sign-in.
Sign in with GitHub
CKeyStyle.cs
v0.1.0-build.85
Latest
Commit ede38f5
Sign in with GitHub to download. Each download is recorded with your GitHub username.
| 1 | using System; |
| 2 | using OpenCKey.Interop; |
| 3 | |
| 4 | namespace OpenCKey |
| 5 | { |
| 6 | /// <summary> |
| 7 | /// How a Profile 0 symbol is painted (<c>ckey_style</c>). Styling never |
| 8 | /// moves where a reader samples: site geometry, the frame, finders, keys |
| 9 | /// and the quiet margin are fixed. The core checks every style |
| 10 | /// (<see cref="CKeySymbol.CheckStyle"/>) and, under the default |
| 11 | /// <see cref="StylePolicy.Strict"/> policy, renderers refuse one that fails. |
| 12 | /// </summary> |
| 13 | public sealed class CKeyStyle |
| 14 | { |
| 15 | private CKeyColor[] _accents = Array.Empty<CKeyColor>(); |
| 16 | |
| 17 | /// <summary>A default style: black ink on white (the same as <see cref="Plain"/>).</summary> |
| 18 | public CKeyStyle() |
| 19 | { |
| 20 | unsafe |
| 21 | { |
| 22 | NativeStyle s; |
| 23 | Native.EnsureAbi(); |
| 24 | NativeMethods.ckey_style_default(&s); |
| 25 | Load(in s); |
| 26 | } |
| 27 | } |
| 28 | |
| 29 | /// <summary>A new copy of the <see cref="CKeyStylePreset.Plain"/> preset.</summary> |
| 30 | public static CKeyStyle Plain => FromPreset(CKeyStylePreset.Plain); |
| 31 | |
| 32 | /// <summary>A new copy of the <see cref="CKeyStylePreset.Concept"/> preset.</summary> |
| 33 | public static CKeyStyle Concept => FromPreset(CKeyStylePreset.Concept); |
| 34 | |
| 35 | /// <summary>A new style filled from a named preset.</summary> |
| 36 | public static unsafe CKeyStyle FromPreset(CKeyStylePreset preset) |
| 37 | { |
| 38 | Native.EnsureAbi(); |
| 39 | NativeStyle s; |
| 40 | Native.Check(NativeMethods.ckey_style_preset_fill(&s, (int)preset), "ckey_style_preset_fill"); |
| 41 | var style = new CKeyStyle(skipDefault: true); |
| 42 | style.Load(in s); |
| 43 | return style; |
| 44 | } |
| 45 | |
| 46 | private CKeyStyle(bool skipDefault) |
| 47 | { |
| 48 | _ = skipDefault; |
| 49 | } |
| 50 | |
| 51 | /// <summary>Background colour at the centre.</summary> |
| 52 | public CKeyColor Background { get; set; } |
| 53 | /// <summary>Background colour at the edge (radial vignette); equal to <see cref="Background"/> for a solid fill.</summary> |
| 54 | public CKeyColor BackgroundEdge { get; set; } |
| 55 | /// <summary>Mark colour; the light side of a metallic sheen.</summary> |
| 56 | public CKeyColor Ink { get; set; } |
| 57 | /// <summary>Sheen shade across the symbol; equal to <see cref="Ink"/> for flat ink.</summary> |
| 58 | public CKeyColor InkShade { get; set; } |
| 59 | |
| 60 | /// <summary>Up to four accent colours for payload marks.</summary> |
| 61 | public CKeyColor[] Accents |
| 62 | { |
| 63 | get => (CKeyColor[])_accents.Clone(); |
| 64 | set |
| 65 | { |
| 66 | if (value == null) throw new ArgumentNullException(nameof(value)); |
| 67 | if (value.Length > 4) throw new ArgumentOutOfRangeException(nameof(value), "A style has at most four accents."); |
| 68 | _accents = (CKeyColor[])value.Clone(); |
| 69 | } |
| 70 | } |
| 71 | |
| 72 | /// <summary>0..100: share of payload marks drawn in accent colours.</summary> |
| 73 | public int AccentPercent { get; set; } |
| 74 | /// <summary>Payload module shape.</summary> |
| 75 | public ModuleShape Modules { get; set; } |
| 76 | /// <summary>Ring mark style.</summary> |
| 77 | public RingStyle Rings { get; set; } |
| 78 | /// <summary>Ray caps.</summary> |
| 79 | public RayCap Rays { get; set; } |
| 80 | /// <summary>0..1 embossed highlight.</summary> |
| 81 | public double Bevel { get; set; } |
| 82 | /// <summary>0..1 drop-shadow depth.</summary> |
| 83 | public double Shadow { get; set; } |
| 84 | /// <summary>0..1 background grain.</summary> |
| 85 | public double Texture { get; set; } |
| 86 | /// <summary>Logo image URL or data: URI (SVG export); null or empty for none.</summary> |
| 87 | public string? LogoHref { get; set; } |
| 88 | /// <summary>Logo radius in canonical units; 0 = the empty centre's size.</summary> |
| 89 | public double LogoRadius { get; set; } |
| 90 | /// <summary>Draw a background disc behind the logo.</summary> |
| 91 | public bool LogoPlate { get; set; } |
| 92 | /// <summary>Optical-safety policy (default <see cref="StylePolicy.Strict"/>).</summary> |
| 93 | public StylePolicy Policy { get; set; } |
| 94 | |
| 95 | /// <summary>A deep copy.</summary> |
| 96 | public CKeyStyle Clone() |
| 97 | { |
| 98 | var c = (CKeyStyle)MemberwiseClone(); |
| 99 | c._accents = (CKeyColor[])_accents.Clone(); |
| 100 | return c; |
| 101 | } |
| 102 | |
| 103 | internal unsafe void Load(in NativeStyle s) |
| 104 | { |
| 105 | Background = CKeyColor.FromNative(s.Background); |
| 106 | BackgroundEdge = CKeyColor.FromNative(s.BackgroundEdge); |
| 107 | Ink = CKeyColor.FromNative(s.Ink); |
| 108 | InkShade = CKeyColor.FromNative(s.InkShade); |
| 109 | int count = (int)Math.Min(s.AccentCount, 4u); |
| 110 | var all = new[] { s.Accent0, s.Accent1, s.Accent2, s.Accent3 }; |
| 111 | _accents = new CKeyColor[count]; |
| 112 | for (int i = 0; i < count; i++) _accents[i] = CKeyColor.FromNative(all[i]); |
| 113 | AccentPercent = (int)s.AccentPercent; |
| 114 | Modules = (ModuleShape)s.Modules; |
| 115 | Rings = (RingStyle)s.Rings; |
| 116 | Rays = (RayCap)s.Rays; |
| 117 | Bevel = s.Bevel; |
| 118 | Shadow = s.Shadow; |
| 119 | Texture = s.Texture; |
| 120 | LogoHref = Native.FromUtf8Z((byte*)s.LogoHref); |
| 121 | LogoRadius = s.LogoRadius; |
| 122 | LogoPlate = s.LogoPlate != 0; |
| 123 | Policy = (StylePolicy)s.Policy; |
| 124 | } |
| 125 | |
| 126 | /// <summary>UTF-8, NUL-terminated logo href to pin for the duration of a native call.</summary> |
| 127 | internal byte[]? LogoHrefUtf8Z() => string.IsNullOrEmpty(LogoHref) ? null : Native.ToUtf8Z(LogoHref); |
| 128 | |
| 129 | /// <summary>Fills a native style. logoHref must stay pinned while the native style is in use.</summary> |
| 130 | internal NativeStyle ToNative(IntPtr logoHref) |
| 131 | { |
| 132 | if (AccentPercent < 0) throw new ArgumentOutOfRangeException(nameof(AccentPercent)); |
| 133 | var a = new NativeRgb[4]; |
| 134 | for (int i = 0; i < _accents.Length; i++) a[i] = _accents[i].ToNative(); |
| 135 | return new NativeStyle |
| 136 | { |
| 137 | Background = Background.ToNative(), |
| 138 | BackgroundEdge = BackgroundEdge.ToNative(), |
| 139 | Ink = Ink.ToNative(), |
| 140 | InkShade = InkShade.ToNative(), |
| 141 | Accent0 = a[0], |
| 142 | Accent1 = a[1], |
| 143 | Accent2 = a[2], |
| 144 | Accent3 = a[3], |
| 145 | AccentCount = (uint)_accents.Length, |
| 146 | AccentPercent = (uint)AccentPercent, |
| 147 | Modules = (int)Modules, |
| 148 | Rings = (int)Rings, |
| 149 | Rays = (int)Rays, |
| 150 | Bevel = Bevel, |
| 151 | Shadow = Shadow, |
| 152 | Texture = Texture, |
| 153 | LogoHref = logoHref, |
| 154 | LogoRadius = LogoRadius, |
| 155 | LogoPlate = LogoPlate ? 1u : 0u, |
| 156 | Policy = (uint)Policy, |
| 157 | }; |
| 158 | } |
| 159 | } |
| 160 | } |