diff --git a/src/SheetMe.Designer/Controls/LucideIcons.cs b/src/SheetMe.Designer/Controls/LucideIcons.cs index 77e548c..521ac4d 100644 --- a/src/SheetMe.Designer/Controls/LucideIcons.cs +++ b/src/SheetMe.Designer/Controls/LucideIcons.cs @@ -116,20 +116,58 @@ public static class LucideIcons } public static FrameworkElement Icon(string name, double size = 16, Brush? color = null) + => Build(name, size, color, brushKey: null); + + /// + /// 아이콘 — 색을 리소스 키로 지정한다(테마 전환 추종). + /// + /// Brush 인스턴스를 대입하면 그 시점 값으로 굳어, ThemeManager 가 토큰 사전을 통째로 갈아끼워도 + /// 이미 만들어진 아이콘은 옛 색을 유지한다(실측: 라이트 전환 후 플로팅 바 도구 아이콘이 다크의 + /// B.Ink #EDEDED 를 유지해 흰 배경에서 사라졌다). SetResourceReference 는 XAML 의 + /// DynamicResource 와 동등해 교체를 따라간다. + /// + public static FrameworkElement Icon(string name, double size, string brushKey) + => Build(name, size, color: null, brushKey: brushKey); + + private static FrameworkElement Build(string name, double size, Brush? color, string? brushKey) { - color ??= Brushes.Black; var canvas = new Canvas { Width = 24, Height = 24 }; if (Data.TryGetValue(name, out var markup)) { var (stroke, fill) = Parse(markup); if (stroke.Children.Count > 0) - canvas.Children.Add(new Path { Data = stroke, Stroke = color, StrokeThickness = 2, StrokeStartLineCap = PenLineCap.Round, StrokeEndLineCap = PenLineCap.Round, StrokeLineJoin = PenLineJoin.Round }); + { + var path = new Path + { + Data = stroke, + StrokeThickness = 2, + StrokeStartLineCap = PenLineCap.Round, + StrokeEndLineCap = PenLineCap.Round, + StrokeLineJoin = PenLineJoin.Round, + }; + Paint(path, Path.StrokeProperty, color, brushKey); + canvas.Children.Add(path); + } if (fill.Children.Count > 0) - canvas.Children.Add(new Path { Data = fill, Fill = color }); + { + var path = new Path { Data = fill }; + Paint(path, Path.FillProperty, color, brushKey); + canvas.Children.Add(path); + } } return new Viewbox { Width = size, Height = size, Child = canvas, Stretch = Stretch.Uniform, SnapsToDevicePixels = true }; } + private static void Paint(Path path, DependencyProperty property, Brush? color, string? brushKey) + { + if (brushKey is not null) + { + path.SetResourceReference(property, brushKey); + return; + } + path.SetValue(property, color ?? Brushes.Black); + } + private static (GeometryGroup Stroke, GeometryGroup Fill) Parse(string markup) { var stroke = new GeometryGroup(); diff --git a/src/SheetMe.Designer/Controls/PaletteIconCatalog.cs b/src/SheetMe.Designer/Controls/PaletteIconCatalog.cs index 8714946..f0c3073 100644 --- a/src/SheetMe.Designer/Controls/PaletteIconCatalog.cs +++ b/src/SheetMe.Designer/Controls/PaletteIconCatalog.cs @@ -45,12 +45,15 @@ public static class PaletteIconCatalog /// /// 아이콘 컨버터 공용 파라미터 해석 — "크기" 또는 "크기|브러시키". /// -/// 브러시 키를 생략하면 종전처럼 B.Muted 를 쓴다(하위호환). 색을 인자로 받을 수 있어야 -/// 활성 문서 탭 아이콘을 강조색으로, 레이어 타입 아이콘을 본문색으로 굽는 것이 가능해진다. +/// 브러시 키를 생략하면 B.Muted 를 쓴다(하위호환). 색을 인자로 받을 수 있어야 +/// 활성 문서 탭 아이콘을 강조색으로, 레이어 타입 아이콘을 본문색으로 칠할 수 있다. +/// +/// Brush 인스턴스가 아니라 키를 그대로 돌려준다 — 여기서 TryFindResource 로 브러시를 꺼내 +/// 대입하면 그 시점 값으로 굳어 테마 전환을 따라가지 못한다. /// internal static class IconParam { - public static (double Size, Brush Brush) Parse(object? parameter, double defaultSize) + public static (double Size, string BrushKey) Parse(object? parameter, double defaultSize) { var size = defaultSize; var key = "B.Muted"; @@ -69,8 +72,7 @@ internal static class IconParam } } - var brush = System.Windows.Application.Current?.TryFindResource(key) as Brush ?? Brushes.Gray; - return (size, brush); + return (size, key); } } @@ -83,8 +85,8 @@ public sealed class TypeToIconConverter : IValueConverter { return null; } - var (size, brush) = IconParam.Parse(parameter, 18); - return LucideIcons.Icon(PaletteIconCatalog.IconOf(type), size, brush); + var (size, brushKey) = IconParam.Parse(parameter, 18); + return LucideIcons.Icon(PaletteIconCatalog.IconOf(type), size, brushKey); } public object ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture) @@ -124,8 +126,8 @@ public sealed class IconNameToVisualConverter : IValueConverter { return null; } - var (size, brush) = IconParam.Parse(parameter, 14); - return LucideIcons.Icon(name, size, brush); + var (size, brushKey) = IconParam.Parse(parameter, 14); + return LucideIcons.Icon(name, size, brushKey); } public object ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture) diff --git a/src/SheetMe.Designer/Themes/DesignerTheme.xaml b/src/SheetMe.Designer/Themes/DesignerTheme.xaml index 3b3f695..0d6c9d5 100644 --- a/src/SheetMe.Designer/Themes/DesignerTheme.xaml +++ b/src/SheetMe.Designer/Themes/DesignerTheme.xaml @@ -69,9 +69,10 @@ @@ -106,8 +107,10 @@ + - + @@ -193,6 +196,106 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -777,10 +895,10 @@ 막대 최소 길이는 MinThumbTrack 이 보장한다. 기본 WPF Track 은 Thumb.MinHeight 를 무시해 항목이 많은 목록에서 막대가 실처럼 가늘어진다. --> - - - - + + + +