Skip to content

Commit 33fd45e

Browse files
committed
添加自动补全的图标和颜色
1 parent 0604a6d commit 33fd45e

3 files changed

Lines changed: 198 additions & 10 deletions

File tree

UndertaleModTool/Editors/GmlLanguageService.cs

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -535,19 +535,21 @@ private static List<GmlCompletionItem> GetBaseCompletionItems(UndertaleData data
535535
foreach (var kvp in builtins.Functions)
536536
AddItem(items, kvp.Key, "function", null);
537537

538-
// Instance / global / global-array variables
538+
// Instance variables (built into the engine, per-instance: x, y, speed, ...)
539539
if (builtins?.InstanceVars is not null)
540540
foreach (var kvp in builtins.InstanceVars)
541-
AddItem(items, kvp.Key, "variable", null);
541+
AddItem(items, kvp.Key, "instance_var", null);
542+
if (builtins?.InstanceLimitedVars is not null)
543+
foreach (var kvp in builtins.InstanceLimitedVars)
544+
AddItem(items, kvp.Key, "instance_var", null);
545+
546+
// Global variables (built into the engine, global scope: room, score, ...)
542547
if (builtins?.GlobalVars is not null)
543548
foreach (var kvp in builtins.GlobalVars)
544-
AddItem(items, kvp.Key, "variable", null);
549+
AddItem(items, kvp.Key, "global_var", null);
545550
if (builtins?.GlobalArrayVars is not null)
546551
foreach (var kvp in builtins.GlobalArrayVars)
547-
AddItem(items, kvp.Key, "variable", null);
548-
if (builtins?.InstanceLimitedVars is not null)
549-
foreach (var kvp in builtins.InstanceLimitedVars)
550-
AddItem(items, kvp.Key, "variable", null);
552+
AddItem(items, kvp.Key, "global_var", null);
551553

552554
// Constants
553555
if (builtins?.Constants is not null)
@@ -625,6 +627,8 @@ private static List<GmlCompletionItem> GetBaseCompletionItems(UndertaleData data
625627
"function" => 2,
626628
"script" => 3,
627629
"variable" => 4,
630+
"instance_var" => 4,
631+
"global_var" => 4,
628632
"constant" => 5,
629633
"object" => 6,
630634
"sprite" => 6,

UndertaleModTool/Editors/UndertaleCodeEditor.xaml.cs

Lines changed: 187 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3458,15 +3458,200 @@ public void Complete(TextArea textArea, ISegment completionSegment, EventArgs in
34583458
textArea.Document.Replace(completionSegment, _item.Text);
34593459
}
34603460

3461-
public ImageSource Image => null;
3461+
public ImageSource Image => CompletionItemStyle.GetIcon(_item.Kind);
34623462

34633463
public string Text => _item.Text;
34643464

3465-
public object Content => _item.Text;
3465+
public object Content => new TextBlock
3466+
{
3467+
Text = _item.Text,
3468+
Foreground = CompletionItemStyle.GetBrush(_item.Kind),
3469+
VerticalAlignment = VerticalAlignment.Center
3470+
};
34663471

34673472
public object Description => _item.Type;
34683473

34693474
public double Priority => 0;
34703475
}
3476+
3477+
/// <summary>
3478+
/// Small vector icons and colors used to visually distinguish completion item categories
3479+
/// (builtin functions/constants/variables, resources, locals, instance and global variables).
3480+
/// </summary>
3481+
private static class CompletionItemStyle
3482+
{
3483+
private static readonly Dictionary<string, ImageSource> _darkIcons = new();
3484+
private static readonly Dictionary<string, ImageSource> _lightIcons = new();
3485+
private static readonly Dictionary<string, Brush> _darkBrushes = new();
3486+
private static readonly Dictionary<string, Brush> _lightBrushes = new();
3487+
3488+
private static bool IsDark => Settings.Instance?.EnableDarkMode ?? true;
3489+
3490+
public static ImageSource GetIcon(string kind)
3491+
{
3492+
Dictionary<string, ImageSource> cache = IsDark ? _darkIcons : _lightIcons;
3493+
if (!cache.TryGetValue(kind, out ImageSource icon))
3494+
{
3495+
icon = CreateIcon(kind, IsDark);
3496+
cache[kind] = icon;
3497+
}
3498+
return icon;
3499+
}
3500+
3501+
public static Brush GetBrush(string kind)
3502+
{
3503+
Dictionary<string, Brush> cache = IsDark ? _darkBrushes : _lightBrushes;
3504+
if (!cache.TryGetValue(kind, out Brush brush))
3505+
{
3506+
Color color = GetColor(kind, IsDark);
3507+
brush = new SolidColorBrush(color);
3508+
brush.Freeze();
3509+
cache[kind] = brush;
3510+
}
3511+
return brush;
3512+
}
3513+
3514+
private static Color GetColor(string kind, bool dark)
3515+
{
3516+
(Color DarkColor, Color LightColor) = kind switch
3517+
{
3518+
"function" => (Color.FromRgb(0xA5, 0x73, 0xE8), Color.FromRgb(0x7A, 0x3D, 0xB8)),
3519+
"constant" => (Color.FromRgb(0xC9, 0xA6, 0xF2), Color.FromRgb(0x8A, 0x5C, 0xB8)),
3520+
"variable" => (Color.FromRgb(0xC9, 0xA6, 0xF2), Color.FromRgb(0x8A, 0x5C, 0xB8)),
3521+
"local" => (Color.FromRgb(0x8F, 0xC7, 0xFF), Color.FromRgb(0x1F, 0x6F, 0xB2)),
3522+
"instance_var" => (Color.FromRgb(0x4A, 0x7A, 0xDE), Color.FromRgb(0x12, 0x3C, 0x96)),
3523+
"global_var" => (Color.FromRgb(0x4D, 0xC9, 0xC9), Color.FromRgb(0x00, 0x8C, 0x8C)),
3524+
"keyword" => (Color.FromRgb(0xF9, 0xB4, 0x6F), Color.FromRgb(0xB0, 0x5A, 0x00)),
3525+
"user" => (Color.FromRgb(0x9D, 0xA5, 0xB4), Color.FromRgb(0x56, 0x59, 0x5E)),
3526+
_ => (Color.FromRgb(0xFF, 0x6B, 0x6B), Color.FromRgb(0xC0, 0x19, 0x19)) // scripts and all asset kinds
3527+
};
3528+
return dark ? DarkColor : LightColor;
3529+
}
3530+
3531+
private static ImageSource CreateIcon(string kind, bool dark)
3532+
{
3533+
Color color = GetColor(kind, dark);
3534+
SolidColorBrush brush = new(color);
3535+
brush.Freeze();
3536+
Pen pen = new(brush, 1.4);
3537+
pen.Freeze();
3538+
3539+
// All variable kinds (builtin, instance, global) use a cube icon
3540+
if (kind is "variable" or "instance_var" or "global_var")
3541+
return CreateCubeIcon(pen);
3542+
3543+
// Functions use a pair of curly braces
3544+
if (kind == "function")
3545+
return CreateTextIcon("{ }", 12, "Consolas", FontWeights.Normal, brush);
3546+
3547+
// Scripts and all asset kinds use a "RES" text badge
3548+
if (kind is not ("constant" or "local" or "keyword" or "user"))
3549+
return CreateTextIcon("RES", 9, "Segoe UI", FontWeights.Bold, brush);
3550+
3551+
// Remaining kinds keep simple geometric glyphs
3552+
Geometry outline = null;
3553+
Geometry filledShape = kind switch
3554+
{
3555+
"constant" => CreatePolygon(new Point(8, 3), new Point(13, 8), new Point(8, 13), new Point(3, 8)),
3556+
"local" => CreatePolygon(new Point(5, 4), new Point(12, 8), new Point(5, 12)),
3557+
"keyword" => new RectangleGeometry(new Rect(4.5, 5, 7, 6), 3, 3),
3558+
_ => null // user
3559+
};
3560+
if (kind == "user")
3561+
outline = new RectangleGeometry(new Rect(3.5, 3.5, 9, 9), 2, 2);
3562+
3563+
DrawingGroup drawings = new();
3564+
if (outline is not null)
3565+
drawings.Children.Add(new GeometryDrawing(null, pen, outline));
3566+
if (filledShape is not null)
3567+
drawings.Children.Add(new GeometryDrawing(brush, null, filledShape));
3568+
3569+
DrawingImage image = new(drawings);
3570+
image.Freeze();
3571+
return image;
3572+
}
3573+
3574+
private static ImageSource CreateCubeIcon(Pen pen)
3575+
{
3576+
PathGeometry cube = new();
3577+
cube.Figures.Add(new PathFigure(new Point(8, 2.5), new PathSegment[]
3578+
{
3579+
new LineSegment(new Point(3.5, 5.25), true),
3580+
new LineSegment(new Point(8, 8), true),
3581+
new LineSegment(new Point(12.5, 5.25), true),
3582+
new LineSegment(new Point(8, 2.5), true)
3583+
}, true));
3584+
cube.Figures.Add(new PathFigure(new Point(3.5, 5.25), new PathSegment[]
3585+
{
3586+
new LineSegment(new Point(3.5, 10.75), true),
3587+
new LineSegment(new Point(8, 13.5), true),
3588+
new LineSegment(new Point(8, 8), true),
3589+
new LineSegment(new Point(3.5, 5.25), true)
3590+
}, true));
3591+
cube.Figures.Add(new PathFigure(new Point(12.5, 5.25), new PathSegment[]
3592+
{
3593+
new LineSegment(new Point(12.5, 10.75), true),
3594+
new LineSegment(new Point(8, 13.5), true),
3595+
new LineSegment(new Point(8, 8), true),
3596+
new LineSegment(new Point(12.5, 5.25), true)
3597+
}, true));
3598+
cube.Freeze();
3599+
3600+
DrawingGroup drawings = new();
3601+
drawings.Children.Add(new GeometryDrawing(null, pen, cube));
3602+
3603+
DrawingImage image = new(drawings);
3604+
image.Freeze();
3605+
return image;
3606+
}
3607+
3608+
private static ImageSource CreateTextIcon(string text, double fontSize, string fontFamily, FontWeight weight, Brush brush)
3609+
{
3610+
FormattedText formatted = new(text, CultureInfo.InvariantCulture, FlowDirection.LeftToRight,
3611+
new Typeface(new FontFamily(fontFamily), FontStyles.Normal, weight, FontStretches.Normal),
3612+
fontSize, Brushes.Black, 1.0);
3613+
Geometry glyph = FitGeometry(formatted.BuildGeometry(new Point(0, 0)), 1.5);
3614+
3615+
DrawingGroup drawings = new();
3616+
drawings.Children.Add(new GeometryDrawing(brush, null, glyph));
3617+
3618+
DrawingImage image = new(drawings);
3619+
image.Freeze();
3620+
return image;
3621+
}
3622+
3623+
private static Geometry FitGeometry(Geometry source, double padding)
3624+
{
3625+
Rect bounds = source.Bounds;
3626+
if (bounds.IsEmpty)
3627+
return source;
3628+
3629+
double scale = Math.Min((16 - 2 * padding) / bounds.Width, (16 - 2 * padding) / bounds.Height);
3630+
double offsetX = (16 - bounds.Width * scale) / 2 - bounds.X * scale;
3631+
double offsetY = (16 - bounds.Height * scale) / 2 - bounds.Y * scale;
3632+
3633+
TransformGroup transform = new();
3634+
transform.Children.Add(new ScaleTransform(scale, scale));
3635+
transform.Children.Add(new TranslateTransform(offsetX, offsetY));
3636+
transform.Freeze();
3637+
3638+
Geometry result = source.Clone();
3639+
result.Transform = transform;
3640+
result.Freeze();
3641+
return result;
3642+
}
3643+
3644+
private static Geometry CreatePolygon(params Point[] points)
3645+
{
3646+
List<PathSegment> segments = new(points.Length - 1);
3647+
for (int i = 1; i < points.Length; i++)
3648+
segments.Add(new LineSegment(points[i], true));
3649+
3650+
PathGeometry geometry = new();
3651+
geometry.Figures.Add(new PathFigure(points[0], segments, true));
3652+
geometry.Freeze();
3653+
return geometry;
3654+
}
3655+
}
34713656
}
34723657
}

UndertaleModTool/MainWindow.xaml.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3016,7 +3016,6 @@ public async void UpdateApp(SettingsWindow window = null)
30163016
Regex invalidChars = new Regex(@"Git:|[ (),/:;<=>?@[\]{}]");
30173017
string version = invalidChars.Replace(Version, "");
30183018
httpClient.DefaultRequestHeaders.UserAgent.Add(new ProductInfoHeaderValue("UndertaleModTool", version));
3019-
30203019
double bytesToMB = 1024 * 1024;
30213020

30223021
if (!Environment.Is64BitOperatingSystem)

0 commit comments

Comments
 (0)