280 lines
10 KiB
C#
280 lines
10 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Collections.ObjectModel;
|
|
using System.Globalization;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Text.RegularExpressions;
|
|
using System.Threading.Tasks;
|
|
using System.Windows;
|
|
using System.Windows.Controls;
|
|
using System.Windows.Data;
|
|
using System.Windows.Documents;
|
|
using System.Windows.Input;
|
|
using System.Windows.Media;
|
|
using System.Windows.Media.Imaging;
|
|
using System.Windows.Shapes;
|
|
|
|
using Microsoft.Win32;
|
|
|
|
namespace ShrlAlgoStudio
|
|
{
|
|
/// <summary>
|
|
/// Iconfont2CSharpView.xaml 的交互逻辑
|
|
/// </summary>
|
|
public partial class Iconfont2CSharpView
|
|
{
|
|
public ObservableCollection<IconItem> Icons { get; set; } = new ObservableCollection<IconItem>();
|
|
|
|
// 字体预览属性
|
|
public FontFamily PreviewFontFamily
|
|
{
|
|
get { return (FontFamily)GetValue(PreviewFontFamilyProperty); }
|
|
set { SetValue(PreviewFontFamilyProperty, value); }
|
|
}
|
|
public static readonly DependencyProperty PreviewFontFamilyProperty =
|
|
DependencyProperty.Register("PreviewFontFamily", typeof(FontFamily), typeof(MainWindow), new PropertyMetadata(null));
|
|
|
|
// 内部状态
|
|
private Dictionary<int, string> _cssNameMap = new Dictionary<int, string>(); // Unicode -> CSS Name
|
|
private string _loadedFontName = "MyIcons";
|
|
private GlyphTypeface _currentGlyphTypeface;
|
|
public Iconfont2CSharpView()
|
|
{
|
|
InitializeComponent();
|
|
GridIcons.DataContext = this;
|
|
GridIcons.ItemsSource = Icons;
|
|
}
|
|
// ---------------------------------------------------------
|
|
// 1. 加载字体逻辑
|
|
// ---------------------------------------------------------
|
|
private void OnLoadFontClick(object sender, RoutedEventArgs e)
|
|
{
|
|
var dlg = new OpenFileDialog { Filter = "Font Files|*.ttf;*.otf" };
|
|
if (dlg.ShowDialog() == true)
|
|
{
|
|
LoadFont(dlg.FileName);
|
|
}
|
|
}
|
|
|
|
private void LoadFont(string path)
|
|
{
|
|
try
|
|
{
|
|
var uri = new Uri(path);
|
|
_currentGlyphTypeface = new GlyphTypeface(uri);
|
|
|
|
// 获取字体名称 (优先取英文)
|
|
_loadedFontName = _currentGlyphTypeface.FamilyNames.ContainsKey(CultureInfo.GetCultureInfo("en-US"))
|
|
? _currentGlyphTypeface.FamilyNames[CultureInfo.GetCultureInfo("en-US")]
|
|
: _currentGlyphTypeface.FamilyNames.Values.FirstOrDefault();
|
|
|
|
// 设置预览字体 (WPF Hack: file:///path/#FontName)
|
|
this.PreviewFontFamily = new FontFamily(uri, "./#" + _loadedFontName);
|
|
|
|
TxtStatus.Text = $"已加载字体: {_loadedFontName} (含 {_currentGlyphTypeface.CharacterToGlyphMap.Count} 个字符)";
|
|
|
|
RefreshData();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
MessageBox.Show($"无法加载字体: {ex.Message}");
|
|
}
|
|
}
|
|
|
|
// ---------------------------------------------------------
|
|
// 2. 加载 CSS 映射逻辑 (核心增强)
|
|
// ---------------------------------------------------------
|
|
private void OnLoadCssClick(object sender, RoutedEventArgs e)
|
|
{
|
|
if (_currentGlyphTypeface == null)
|
|
{
|
|
MessageBox.Show("请先加载字体文件!");
|
|
return;
|
|
}
|
|
|
|
var dlg = new OpenFileDialog { Filter = "CSS Files|*.css", Title = "选择对应的 CSS 文件 (如 fontawesome.css)" };
|
|
if (dlg.ShowDialog() == true)
|
|
{
|
|
ParseCss(dlg.FileName);
|
|
RefreshData(); // 重新生成列表和代码
|
|
}
|
|
}
|
|
|
|
private void ParseCss(string path)
|
|
{
|
|
_cssNameMap.Clear();
|
|
string cssContent = File.ReadAllText(path);
|
|
|
|
// 正则表达式匹配: .class-name:before { content: "\f001"; }
|
|
// 兼容格式:单双引号,有无 content 文本
|
|
// 捕获组 1: class name (e.g. "fa-home")
|
|
// 捕获组 2: hex code (e.g. "f015")
|
|
var regex = new Regex(@"\.([a-zA-Z0-9_-]+)::?before\s*\{\s*content:\s*[""']\\([a-fA-F0-9]+)[""'];?\s*\}");
|
|
|
|
var matches = regex.Matches(cssContent);
|
|
foreach (Match match in matches)
|
|
{
|
|
string className = match.Groups[1].Value;
|
|
string hex = match.Groups[2].Value;
|
|
|
|
if (int.TryParse(hex, NumberStyles.HexNumber, null, out int unicode))
|
|
{
|
|
// 如果存在多个名字对应同一个 Unicode (alias),这里只取第一个,或者取最短的
|
|
if (!_cssNameMap.ContainsKey(unicode))
|
|
{
|
|
_cssNameMap[unicode] = className;
|
|
}
|
|
}
|
|
}
|
|
|
|
TxtStatus.Text += $" | 已解析 CSS 映射: {_cssNameMap.Count} 个名称";
|
|
}
|
|
|
|
// ---------------------------------------------------------
|
|
// 3. 数据处理与代码生成
|
|
// ---------------------------------------------------------
|
|
private void RefreshData()
|
|
{
|
|
if (_currentGlyphTypeface == null) return;
|
|
|
|
Icons.Clear();
|
|
var sortedList = new List<IconItem>();
|
|
|
|
foreach (var kvp in _currentGlyphTypeface.CharacterToGlyphMap)
|
|
{
|
|
int unicode = kvp.Key;
|
|
|
|
// 生成基础变量名
|
|
string varName;
|
|
if (_cssNameMap.ContainsKey(unicode))
|
|
{
|
|
// 将 css-kebab-case 转换为 PascalCase
|
|
// 比如 fa-arrow-circle-down -> ArrowCircleDown
|
|
varName = ConvertCssToPascal(_cssNameMap[unicode]);
|
|
}
|
|
else
|
|
{
|
|
// 只有 Unicode 时的默认回退
|
|
varName = $"Icon_{unicode:X4}";
|
|
}
|
|
|
|
sortedList.Add(new IconItem
|
|
{
|
|
Unicode = unicode,
|
|
HexDisplay = $"\\u{unicode:X4}",
|
|
Character = char.ConvertFromUtf32(unicode),
|
|
VarName = varName
|
|
});
|
|
}
|
|
|
|
// 按 Unicode 排序并添加到界面
|
|
foreach (var item in sortedList.OrderBy(i => i.Unicode))
|
|
{
|
|
Icons.Add(item);
|
|
}
|
|
|
|
GenerateCSharpCode(sortedList);
|
|
}
|
|
|
|
private void GenerateCSharpCode(List<IconItem> items)
|
|
{
|
|
bool isEnum = ChkGenerateEnum.IsChecked == true;
|
|
string cleanName = Regex.Replace(_loadedFontName, @"[^a-zA-Z0-9]", ""); // 清理类名
|
|
if (char.IsDigit(cleanName[0])) cleanName = "_" + cleanName;
|
|
|
|
StringBuilder sb = new StringBuilder();
|
|
sb.AppendLine("// -----------------------------------------------------------------------------");
|
|
sb.AppendLine($"// <auto-generated>");
|
|
sb.AppendLine($"// Font Name: {_loadedFontName}");
|
|
sb.AppendLine($"// Generated: {DateTime.Now}");
|
|
sb.AppendLine($"// </auto-generated>");
|
|
sb.AppendLine("// -----------------------------------------------------------------------------");
|
|
sb.AppendLine("using System;");
|
|
sb.AppendLine();
|
|
|
|
if (isEnum)
|
|
{
|
|
sb.AppendLine($"public enum {cleanName}Enum");
|
|
sb.AppendLine("{");
|
|
// 检查重复名称并处理
|
|
var usedNames = new HashSet<string>();
|
|
foreach (var item in items)
|
|
{
|
|
string finalName = item.VarName;
|
|
// 如果名字冲突,追加 Hex 后缀
|
|
if (usedNames.Contains(finalName)) finalName += $"_{item.Unicode:X4}";
|
|
usedNames.Add(finalName);
|
|
|
|
// 不能以数字开头
|
|
if (char.IsDigit(finalName[0])) finalName = "_" + finalName;
|
|
|
|
// 只能是 int
|
|
sb.AppendLine($" /// <summary>Hex: {item.Unicode:X4}</summary>");
|
|
sb.AppendLine($" {finalName} = 0x{item.Unicode:X4},");
|
|
}
|
|
sb.AppendLine("}");
|
|
}
|
|
else
|
|
{
|
|
sb.AppendLine($"public static class {cleanName}Icons");
|
|
sb.AppendLine("{");
|
|
|
|
var usedNames = new HashSet<string>();
|
|
foreach (var item in items)
|
|
{
|
|
string finalName = item.VarName;
|
|
if (usedNames.Contains(finalName)) finalName += $"_{item.Unicode:X4}";
|
|
usedNames.Add(finalName);
|
|
|
|
sb.AppendLine($" public const string {finalName} = \"{item.HexDisplay}\";");
|
|
}
|
|
sb.AppendLine("}");
|
|
}
|
|
|
|
TxtOutput.Text = sb.ToString();
|
|
}
|
|
|
|
// 辅助:将 css-name 转换为 PascalName
|
|
private string ConvertCssToPascal(string cssName)
|
|
{
|
|
// 移除常见的 icon 前缀 (可选)
|
|
if (cssName.StartsWith("fa-")) cssName = cssName.Substring(3);
|
|
if (cssName.StartsWith("mdi-")) cssName = cssName.Substring(4);
|
|
if (cssName.StartsWith("bi-")) cssName = cssName.Substring(3);
|
|
|
|
// 分割并首字母大写
|
|
var parts = cssName.Split(new[] { '-', '_' }, StringSplitOptions.RemoveEmptyEntries);
|
|
for (int i = 0; i < parts.Length; i++)
|
|
{
|
|
if (parts[i].Length > 0)
|
|
{
|
|
char[] a = parts[i].ToCharArray();
|
|
a[0] = char.ToUpper(a[0]);
|
|
parts[i] = new string(a);
|
|
}
|
|
}
|
|
string result = string.Join("", parts);
|
|
|
|
// 确保不是数字开头
|
|
if (char.IsDigit(result[0])) result = "_" + result;
|
|
|
|
return result;
|
|
}
|
|
|
|
private void OnCopyCodeClick(object sender, RoutedEventArgs e)
|
|
{
|
|
Clipboard.SetText(TxtOutput.Text);
|
|
MessageBox.Show("代码已复制到剪贴板");
|
|
}
|
|
}
|
|
public class IconItem
|
|
{
|
|
public int Unicode { get; set; }
|
|
public string HexDisplay { get; set; } // "\uF001"
|
|
public string Character { get; set; } // 实际字符
|
|
public string VarName { get; set; } // C# 变量名
|
|
}
|
|
}
|