From 693241f288c5f4c02aee8a7063046108e365ba4a Mon Sep 17 00:00:00 2001 From: Juan Segura Date: Sat, 1 Feb 2025 19:19:20 +0100 Subject: [PATCH 1/5] Autocomplete bug fixed --- Bufdio/Bufdio.csproj | 2 +- .../AttachadProperty/HyperLinkCommand.cs | 2 +- MsBox.Avalonia/MsBox.Avalonia.csproj | 4 +- .../ZXGraphics/log/ExportManager.cs | 1 - .../ZXBasicCompletionData.cs | 5 +- .../ZXTextEditor/Controls/ZXBasicEditor.cs | 7 +- .../Controls/ZXTextEditor.axaml.cs | 67 +++++++++++-------- ZXBStudio/MainWindow.axaml.cs | 3 + ZXBStudio/ZXBasicStudio.csproj | 16 ++--- ZXBasicStudioTest/ZXBasicStudioTest.csproj | 6 +- 10 files changed, 65 insertions(+), 48 deletions(-) diff --git a/Bufdio/Bufdio.csproj b/Bufdio/Bufdio.csproj index 0a8f092..16bd398 100644 --- a/Bufdio/Bufdio.csproj +++ b/Bufdio/Bufdio.csproj @@ -9,7 +9,7 @@ - + diff --git a/MsBox.Avalonia/AttachadProperty/HyperLinkCommand.cs b/MsBox.Avalonia/AttachadProperty/HyperLinkCommand.cs index ba94858..be3de4d 100644 --- a/MsBox.Avalonia/AttachadProperty/HyperLinkCommand.cs +++ b/MsBox.Avalonia/AttachadProperty/HyperLinkCommand.cs @@ -1,9 +1,9 @@ -using System.Reactive; using System.Windows.Input; using Avalonia; using Avalonia.Data; using Avalonia.Input; using Avalonia.Interactivity; +using Avalonia.Reactive; namespace MsBox.Avalonia.AttachadProperty; diff --git a/MsBox.Avalonia/MsBox.Avalonia.csproj b/MsBox.Avalonia/MsBox.Avalonia.csproj index e039201..1195e6c 100644 --- a/MsBox.Avalonia/MsBox.Avalonia.csproj +++ b/MsBox.Avalonia/MsBox.Avalonia.csproj @@ -26,9 +26,9 @@ - + - + diff --git a/ZXBStudio/DocumentEditors/ZXGraphics/log/ExportManager.cs b/ZXBStudio/DocumentEditors/ZXGraphics/log/ExportManager.cs index 19fccac..45aa1b0 100644 --- a/ZXBStudio/DocumentEditors/ZXGraphics/log/ExportManager.cs +++ b/ZXBStudio/DocumentEditors/ZXGraphics/log/ExportManager.cs @@ -4,7 +4,6 @@ using System.Collections.Generic; using System.IO; using System.Linq; -using System.Reactive.Joins; using System.Text; using System.Threading.Tasks; using ZXBasicStudio.BuildSystem; diff --git a/ZXBStudio/DocumentEditors/ZXTextEditor/Classes/LanguageDefinitions/ZXBasicCompletionData.cs b/ZXBStudio/DocumentEditors/ZXTextEditor/Classes/LanguageDefinitions/ZXBasicCompletionData.cs index 860671c..91479f8 100644 --- a/ZXBStudio/DocumentEditors/ZXTextEditor/Classes/LanguageDefinitions/ZXBasicCompletionData.cs +++ b/ZXBStudio/DocumentEditors/ZXTextEditor/Classes/LanguageDefinitions/ZXBasicCompletionData.cs @@ -55,7 +55,7 @@ public ZXBasicCompletionData(ZXBasicCompletionType DataType, string Text, string public string Text { get; } - public object Content => Text; + public object Content => this; // Text; public object Description { get; } @@ -66,8 +66,11 @@ public void Complete(TextArea textArea, ISegment completionSegment, { textArea.Document.Replace(completionSegment, Text); } + + public override string ToString() => Text; } + public enum ZXBasicCompletionType { Keyword, diff --git a/ZXBStudio/DocumentEditors/ZXTextEditor/Controls/ZXBasicEditor.cs b/ZXBStudio/DocumentEditors/ZXTextEditor/Controls/ZXBasicEditor.cs index c9d3f9a..5be6720 100644 --- a/ZXBStudio/DocumentEditors/ZXTextEditor/Controls/ZXBasicEditor.cs +++ b/ZXBStudio/DocumentEditors/ZXTextEditor/Controls/ZXBasicEditor.cs @@ -487,8 +487,10 @@ public ZXBasicEditor(string DocumentPath) : base(DocumentPath, ZXBasicDocument.I if (!ByRequest) { - if(ZXOptions.Current.DisableAuto) + if (ZXOptions.Current.DisableAuto) + { return null; + } } if (ByRequest) @@ -540,7 +542,8 @@ public ZXBasicEditor(string DocumentPath) : base(DocumentPath, ZXBasicDocument.I } - if (string.IsNullOrWhiteSpace(preText)) + //if (string.IsNullOrWhiteSpace(preText)) + if(trimmed.Length > 1) { if (RequestedChar == '#') return directives; diff --git a/ZXBStudio/DocumentEditors/ZXTextEditor/Controls/ZXTextEditor.axaml.cs b/ZXBStudio/DocumentEditors/ZXTextEditor/Controls/ZXTextEditor.axaml.cs index bcb123b..bc08cbb 100644 --- a/ZXBStudio/DocumentEditors/ZXTextEditor/Controls/ZXTextEditor.axaml.cs +++ b/ZXBStudio/DocumentEditors/ZXTextEditor/Controls/ZXTextEditor.axaml.cs @@ -35,6 +35,7 @@ using AvaloniaEdit.Utils; using static System.Runtime.InteropServices.JavaScript.JSType; using System.Diagnostics; +using SixLabors.ImageSharp.Formats.Webp; namespace ZXBasicStudio.DocumentEditors.ZXTextEditor.Controls { @@ -99,14 +100,14 @@ public partial class ZXTextEditor : ZXDocumentEditorBase, IObserver _docName; public override string DocumentPath => _docPath; public override bool Modified - { - get - { - if (_docPath == ZXConstants.DISASSEMBLY_DOC || _docPath == ZXConstants.ROM_DOC) - return false; - - return editor?.IsModified ?? false; - } + { + get + { + if (_docPath == ZXConstants.DISASSEMBLY_DOC || _docPath == ZXConstants.ROM_DOC) + return false; + + return editor?.IsModified ?? false; + } } #endregion @@ -139,7 +140,7 @@ public int? BreakLine #region Constructors public ZXTextEditor() : this("Untitled", ZXTextDocument.Id) { - + } public ZXTextEditor(string DocumentPath, Guid DocumentTypeId) { @@ -147,7 +148,7 @@ public ZXTextEditor(string DocumentPath, Guid DocumentTypeId) _docTypeId = DocumentTypeId; InitializeShortcuts(); - + editor.DataContext = editor; editor.FontSize = ZXOptions.Current.EditorFontSize; editor.WordWrap = ZXOptions.Current.WordWrap; @@ -208,7 +209,9 @@ private void TextArea_TextEntering(object? sender, TextInputEventArgs e) { if (e.Text == null || e.Text.Length == 0) + { return; + } if (completionWindow == null && !string.IsNullOrWhiteSpace(e.Text) && !char.IsNumber(e.Text[0])) { @@ -216,11 +219,15 @@ private void TextArea_TextEntering(object? sender, TextInputEventArgs e) var completionData = ShouldComplete(editor.Document, editor.TextArea.Caret.Line, editor.TextArea.Caret.Column - 1, e.Text[0], false); if (completionData != null) + { ShowCompletion(completionData, false); + } } else if (completionWindow != null && !char.IsLetterOrDigit(e.Text[0])) + { completionWindow.CompletionList.RequestInsertion(e); - + } + } private void TextArea_KeyDown(object? sender, KeyEventArgs e) @@ -231,7 +238,9 @@ private void TextArea_KeyDown(object? sender, KeyEventArgs e) var completionData = ShouldComplete(editor.Document, editor.TextArea.Caret.Line, editor.TextArea.Caret.Column - 1, null, true); if (completionData != null) + { ShowCompletion(completionData, true); + } } } @@ -240,10 +249,9 @@ private void ShowCompletion(IEnumerable completions, bool reque if (completionWindow == null) { completionWindow = new CompletionWindow(editor.TextArea); - ICompletionData? selectedItem = null; - if (requested) + //if (requested) { var line = editor.Document.GetLineByNumber(editor.TextArea.Caret.Line); var text = editor.Document.GetText(line); @@ -270,6 +278,7 @@ private void ShowCompletion(IEnumerable completions, bool reque data.AddRange(completions); completionWindow.Show(); completionWindow.CompletionList.SelectedItem = selectedItem; + completionWindow.KeyDown += (s, e) => { if (e.Key == Key.F1 && completionWindow.CompletionList.SelectedItem != null) @@ -512,7 +521,7 @@ public override bool SaveDocument(TextWriter OutputLog) return true; } - catch(Exception ex) + catch (Exception ex) { OutputLog.WriteLine($"Error saving file {_docPath}: {ex.Message}"); return false; @@ -520,12 +529,12 @@ public override bool SaveDocument(TextWriter OutputLog) } public override bool RenameDocument(string NewName, TextWriter OutputLog) { - try + try { UpdateFileName(_docPath, NewName); return true; } - catch(Exception ex) + catch (Exception ex) { OutputLog.WriteLine($"Error internally updating the document name: {ex.Message}"); return false; @@ -602,22 +611,22 @@ public void Expand() foreach (var fold in fManager.AllFoldings) fold.IsFolded = false; } - + public void FontIncrease() { editor.FontSize++; } - + public void FontDecrease() { editor.FontSize--; } - + public void CommentSelection() { if (editor.IsReadOnly || commentChar == null || editor.TextArea.Selection == null) return; - + TextDocument document = editor.TextArea.Document; if (editor.TextArea.Selection.Length == 0) @@ -629,7 +638,7 @@ public void CommentSelection() else { IEnumerable selectionSegments = editor.TextArea.Selection.Segments; - + foreach (SelectionSegment segment in selectionSegments) { int lineStart = document.GetLineByOffset(segment.StartOffset).LineNumber; @@ -741,17 +750,17 @@ private void Document_Changing(object? sender, DocumentChangeEventArgs e) if (e.RemovalLength > 0) { - + int end = start + e.RemovalLength; int linesRemoved = 0; int pos = start; - while(pos < end) + while (pos < end) { var line = editor.Document.GetLineByOffset(pos); if (pos >= line.EndOffset) firstLine++; - + string lineText = editor.Document.GetText(line.Offset, line.Length); int removalLength = Math.Min(line.EndOffset - pos, end - pos); string leftText = lineText.Remove(pos - line.Offset, removalLength); @@ -766,11 +775,11 @@ private void Document_Changing(object? sender, DocumentChangeEventArgs e) linesRemoved++; } - if(linesRemoved > 0) + if (linesRemoved > 0) changed |= MoveBreakpoints(firstLine, -linesRemoved); } - if(changed) + if (changed) bpMargin?.InvalidateVisual(); } private void Document_Changed(object? sender, DocumentChangeEventArgs e) @@ -801,7 +810,7 @@ private void Document_Changed(object? sender, DocumentChangeEventArgs e) var firstText = editor.Document.GetText(firstLine.Offset, firstLine.Length); - if(!string.IsNullOrWhiteSpace(firstText)) + if (!string.IsNullOrWhiteSpace(firstText)) changed = MoveBreakpoints(firstLine.LineNumber + 1, addedLines); else changed = MoveBreakpoints(firstLine.LineNumber, addedLines); @@ -873,12 +882,12 @@ public void UpdateFontSize(bool increase) #region IObserver implementation for modified document notifications public void OnCompleted() { - + } public void OnError(Exception error) { - + } public void OnNext(AvaloniaPropertyChangedEventArgs value) diff --git a/ZXBStudio/MainWindow.axaml.cs b/ZXBStudio/MainWindow.axaml.cs index 9894d5a..557e845 100644 --- a/ZXBStudio/MainWindow.axaml.cs +++ b/ZXBStudio/MainWindow.axaml.cs @@ -215,6 +215,9 @@ public MainWindow() regView.Registers = emu.Registers; memView.Initialize(emu.Memory); CreateRomBreakpoints(); +#if DEBUG + this.AttachDevTools(); +#endif #endregion #region Player intialization diff --git a/ZXBStudio/ZXBasicStudio.csproj b/ZXBStudio/ZXBasicStudio.csproj index d329d20..fdda5ba 100644 --- a/ZXBStudio/ZXBasicStudio.csproj +++ b/ZXBStudio/ZXBasicStudio.csproj @@ -536,17 +536,17 @@ - + - - - + + + - - - + + + - + diff --git a/ZXBasicStudioTest/ZXBasicStudioTest.csproj b/ZXBasicStudioTest/ZXBasicStudioTest.csproj index 7767c58..5e6593a 100644 --- a/ZXBasicStudioTest/ZXBasicStudioTest.csproj +++ b/ZXBasicStudioTest/ZXBasicStudioTest.csproj @@ -10,13 +10,13 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive - - + + all runtime; build; native; contentfiles; analyzers; buildtransitive From 8fb555030d26b1525ad10755efdfaae3a2bf1aa4 Mon Sep 17 00:00:00 2001 From: Juan Segura Date: Thu, 6 Feb 2025 22:13:40 +0100 Subject: [PATCH 2/5] Beta 1.4 --- ZXBStudio/Dialogs/ZXAboutDialog.axaml | 17 +++++++------ .../ZXTextEditor/Controls/ZXBasicEditor.cs | 25 ++++++++++++++++--- ZXBStudio/ZXBasicStudio.csproj | 2 +- 3 files changed, 31 insertions(+), 13 deletions(-) diff --git a/ZXBStudio/Dialogs/ZXAboutDialog.axaml b/ZXBStudio/Dialogs/ZXAboutDialog.axaml index 05ecf92..f0bff6b 100644 --- a/ZXBStudio/Dialogs/ZXAboutDialog.axaml +++ b/ZXBStudio/Dialogs/ZXAboutDialog.axaml @@ -10,16 +10,17 @@ Title="About..." CanResize="False" WindowStartupLocation="CenterScreen" Topmost="True"> - + ZX Basic Studio Beta release - Build 1.3.5.6 - 2023-10-29 - The ZX Basic Studio development team - El Dr. Gusman, Duefectu, AdolFITO, Hash6Iron, SirRickster - Many thanks to Boriel for the ZX Basic compiler and his support to this project. - (C) 2023, El Dr. Gusman - + Build 1.3.5.6 + 2023-10-29 + The ZX Basic Studio development team + El Dr. Gusman, Boriel, Duefectu, AdolFITO, Hash6Iron, SirRickster + Many thanks to Boriel for the ZX Basic compiler and his support to this project. + (C) 2023, El Dr. Gusman + (C) 2025, Boriel & DuefectuCorp + diff --git a/ZXBStudio/DocumentEditors/ZXTextEditor/Controls/ZXBasicEditor.cs b/ZXBStudio/DocumentEditors/ZXTextEditor/Controls/ZXBasicEditor.cs index 5be6720..3a130fb 100644 --- a/ZXBStudio/DocumentEditors/ZXTextEditor/Controls/ZXBasicEditor.cs +++ b/ZXBStudio/DocumentEditors/ZXTextEditor/Controls/ZXBasicEditor.cs @@ -475,6 +475,16 @@ static ZXBasicEditor() public ZXBasicEditor() : base() { } public ZXBasicEditor(string DocumentPath) : base(DocumentPath, ZXBasicDocument.Id) { } + + /// + /// Gestion de autocompletar + /// + /// + /// + /// + /// + /// + /// protected override IEnumerable? ShouldComplete(IDocument Document, int Line, int Column, char? RequestedChar, bool ByRequest) { var line = Document.GetLineByNumber(Line); @@ -524,26 +534,33 @@ public ZXBasicEditor(string DocumentPath) : base(DocumentPath, ZXBasicDocument.I } if (context == ContextType.Comment) + { return null; + } string trimmed = preText.Trim(); - if(context == ContextType.Assembler) + if (context == ContextType.Assembler) { if (!char.IsLetter(RequestedChar ?? ' ') || regCommentAsm.IsMatch(trimmed)) + { return null; + } if (string.IsNullOrWhiteSpace(trimmed)) + { PrioritizeAssemblerKeywords(); + } else + { PrioritizeAssemblerRegisters(); - + } return assembler; } - //if (string.IsNullOrWhiteSpace(preText)) - if(trimmed.Length > 1) + if (string.IsNullOrWhiteSpace(preText)) + //if(trimmed.Length > 1) { if (RequestedChar == '#') return directives; diff --git a/ZXBStudio/ZXBasicStudio.csproj b/ZXBStudio/ZXBasicStudio.csproj index fdda5ba..a5697fd 100644 --- a/ZXBStudio/ZXBasicStudio.csproj +++ b/ZXBStudio/ZXBasicStudio.csproj @@ -11,7 +11,7 @@ AnyCPU;x64 zxbs.ico ZX Basic Studio - 1.4.* + 1.5.* False From 09f278024a6aae468459d20ec4d5d4327e7adca8 Mon Sep 17 00:00:00 2001 From: Juan Segura Date: Sun, 23 Feb 2025 11:14:54 +0100 Subject: [PATCH 3/5] Mergin with master --- .../ZXGraphics/NextImageViewControl.cs | 203 ++++ .../ZXGraphics/PaletteBuilderDialog.axaml | 102 ++ .../ZXGraphics/PaletteBuilderDialog.axaml.cs | 897 ++++++++++++++++++ .../ZXGraphics/log/ServiceLayer.cs | 110 ++- .../ZXGraphics/neg/PaletteColor.cs | 4 + ZXBStudio/MainWindow.axaml | 3 + ZXBStudio/MainWindow.axaml.cs | 13 + ZXBStudio/Svg/White/ImageImport.svg | 9 + ZXBStudio/Svg/White/Next.svg | 11 + ZXBStudio/Svg/White/palette.svg | 11 + ZXBStudio/ZXBasicStudio.csproj | 10 +- 11 files changed, 1351 insertions(+), 22 deletions(-) create mode 100644 ZXBStudio/DocumentEditors/ZXGraphics/NextImageViewControl.cs create mode 100644 ZXBStudio/DocumentEditors/ZXGraphics/PaletteBuilderDialog.axaml create mode 100644 ZXBStudio/DocumentEditors/ZXGraphics/PaletteBuilderDialog.axaml.cs create mode 100644 ZXBStudio/Svg/White/ImageImport.svg create mode 100644 ZXBStudio/Svg/White/Next.svg create mode 100644 ZXBStudio/Svg/White/palette.svg diff --git a/ZXBStudio/DocumentEditors/ZXGraphics/NextImageViewControl.cs b/ZXBStudio/DocumentEditors/ZXGraphics/NextImageViewControl.cs new file mode 100644 index 0000000..d12e52d --- /dev/null +++ b/ZXBStudio/DocumentEditors/ZXGraphics/NextImageViewControl.cs @@ -0,0 +1,203 @@ +using Avalonia; +using Avalonia.Controls; +using Avalonia.Input; +using Avalonia.Media; +using Avalonia.Media.Imaging; +using Avalonia.Platform; +using Avalonia.Platform.Storage; +using Avalonia.Threading; +using SixLabors.ImageSharp.Formats.Png; +using SixLabors.ImageSharp; +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Processing.Processors.Quantization; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Net; +using System.Runtime.Intrinsics.X86; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using ZXBasicStudio.DocumentEditors.ZXGraphics.neg; +using ZXBasicStudio.Common; +using SixLabors.ImageSharp.Formats.Bmp; + +namespace ZXBasicStudio.DocumentEditors.ZXGraphics +{ + /// + /// Control to show and manipulate imported image + /// Fixed size to 400x400 + /// + public class NextImageViewControl : Control + { + /// + /// Zoom factor + /// + public int Zoom + { + get + { + return _Zoom; + } + set + { + _Zoom = value; + this.InvalidateVisual(); + } + } + private int _Zoom = 1; + + /// + /// Import image data + /// + public SixLabors.ImageSharp.Image imageData = null; + + public NextImageViewControl() + { + } + + + public async void LoadImage(IStorageFile file) + { + try + { + await using (var stream = await file.OpenReadAsync()) + { + imageData = SixLabors.ImageSharp.Image.Load(stream); + } + if (imageData.Width > 320) + { + this.Width = 320; + } + else + { + this.Width = imageData.Width; + } + if (this.imageData.Height > 256) + { + this.Height = 256; + } + else + { + this.Height = imageData.Height; + } + + } + catch (Exception ex) + { + } + } + + + public void Refresh() + { + this.InvalidateVisual(); + } + + + public override void Render(DrawingContext context) + { + try + { + base.Render(context); + + // Image + if (imageData == null) + { + return; + } + int iw = imageData.Size.Width; + int ih = imageData.Size.Height; + int cw = 0; + int ch = 0; + int z = _Zoom; + int maxWidth = (int)this.Width; + int maxHeight = (int)this.Height; + + int yd = 0; + for (int y = 0; y < ih; y += z) + { + int xd = 0; + for (int x = 0; x < iw; x += z) + { + if (xd >= 0 && xd < iw && + yd >= 0 && yd < ih) + { + try + { + int xx = x; + int yy = y; + + if ((xx + z) > iw) + { + cw = iw - xx; + } + else + { + cw = z; + } + if ((yy + z) > ih) + { + ch = ih - yy; + } + else + { + ch = z; + } + if (xx >= 0 && xx <= maxWidth && yy >= 0 && yy <= maxHeight) + { + Rect r = new Rect(xx, yy, cw, ch); + var pixel = imageData[xd, yd]; + var brush = new SolidColorBrush(Avalonia.Media.Color.FromArgb( + 255, pixel.R, pixel.G, pixel.B)); + context.FillRectangle(brush, r); + } + } + catch (Exception ex) + { + + } + } + xd++; + } + yd++; + } + + } + catch (Exception ex) + { + + } + } + + + public void SetImageData(int[,] pixels, PaletteColor[] palette, int w, int h) + { + imageData = new Image(w, h); + for (int x = 0; x < w; x++) + { + for (int y = 0; y < h; y++) + { + var p = palette[pixels[x, y]]; + imageData[x, y] = new Rgba32(p.Red, p.Green, p.Blue); + } + } + this.InvalidateArrange(); + } + + + public bool SaveImageAsPng(string filename) + { + try + { + imageData.SaveAsPng(filename); + return true; + } + catch (Exception ex) + { + return false; + } + } + } +} diff --git a/ZXBStudio/DocumentEditors/ZXGraphics/PaletteBuilderDialog.axaml b/ZXBStudio/DocumentEditors/ZXGraphics/PaletteBuilderDialog.axaml new file mode 100644 index 0000000..905fc94 --- /dev/null +++ b/ZXBStudio/DocumentEditors/ZXGraphics/PaletteBuilderDialog.axaml @@ -0,0 +1,102 @@ + + + + + Source image + Palette + Converted image + + + + + + + + + + + + + + + + + + + + + + OutFormat + + 256x192 256 colors with palette + 256x192 256 colors without palette + + + + + + Convert to current palette + + + Append new colors to current palette + + + Add ULA colors at start + + + Add Grayscale at start + + + + + Red + + + + + + Green + + + + + + Blue + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ZXBStudio/DocumentEditors/ZXGraphics/PaletteBuilderDialog.axaml.cs b/ZXBStudio/DocumentEditors/ZXGraphics/PaletteBuilderDialog.axaml.cs new file mode 100644 index 0000000..123c6ed --- /dev/null +++ b/ZXBStudio/DocumentEditors/ZXGraphics/PaletteBuilderDialog.axaml.cs @@ -0,0 +1,897 @@ +using Avalonia; +using Avalonia.Controls; +using Avalonia.Media; +using Avalonia.Media.Imaging; +using Avalonia.Metadata; +using Avalonia.Platform.Storage; +using Avalonia.Threading; +using MsBox.Avalonia.Dto; +using MsBox.Avalonia.Enums; +using MsBox.Avalonia; +using SixLabors.ImageSharp.PixelFormats; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Drawing.Imaging; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading; +using ZXBasicStudio.Classes; +using ZXBasicStudio.Common; +using ZXBasicStudio.DocumentEditors.ZXGraphics.log; +using ZXBasicStudio.DocumentEditors.ZXGraphics.neg; +using ZXBasicStudio.DocumentModel.Classes; +using ZXBasicStudio.DocumentModel.Interfaces; +using ZXBasicStudio.Extensions; +using ZXBasicStudio.IntegratedDocumentTypes.CodeDocuments.Basic; +using static System.Net.Mime.MediaTypeNames; +using Avalonia.Controls.Presenters; +using Avalonia.Input; +using System.Formats.Tar; +using Avalonia.Controls.Shapes; +using static CommunityToolkit.Mvvm.ComponentModel.__Internals.__TaskExtensions.TaskAwaitableWithoutEndValidation; +using FFmpeg.AutoGen; + +namespace ZXBasicStudio.DocumentEditors.ZXGraphics +{ + public partial class PaletteBuilderDialog : Window, IDisposable + { + private bool StandartPalette = true; + private bool ULAColors = false; + private bool GrayScale = false; + + private Rectangle[] rectangulos = new Rectangle[256]; + private PaletteColor[] palette = null; + private string sourceFile = null; + private string convertedFile = null; + private bool imgSourceLoaded = false; + + private int[,] pixels = null; + private int selectedColorIndex = 0; + private int transparentColor = 223; + + private Brush negro = new SolidColorBrush(Colors.Black); + private Brush blanco = new SolidColorBrush(Colors.White); + private Brush rojo = new SolidColorBrush(Colors.Red); + + + public PaletteBuilderDialog() + { + InitializeComponent(); + + if (!ServiceLayer.Initialized) + { + ServiceLayer.Initialize(); + } + + // Set the palette + palette = ServiceLayer.GetPalette(GraphicsModes.Next); + selectedColorIndex = 0; + DrawPalette(); + + btnFileSource.Tapped += BtnFileSource_Tapped; + btnResetPalette.Click += BtnResetPalette_Click; + btnLoadPalette.Click += BtnLoadPalette_Click; + btnSavePalette.Click += BtnSavePalette_Click; + ActivarEventosSlider(); + + chkUseCurrent.Click += ChkUseCurrent_Click; + chkAppend.Click += ChkAppend_Click; + chkULA.Click += ChkULA_Click; + chkGrayscale.Click += ChkGrayscale_Click; + + btnRefresh.Click += BtnRefresh_Click; + btnSaveImage.Click += BtnSaveImage_Click; + + btnClose.Click += BtnClose_Click; + } + + + private void BtnClose_Click(object? sender, Avalonia.Interactivity.RoutedEventArgs e) + { + this.Close(); + } + + + private void ActivarEventosSlider() + { + sldRed.ValueChanged += Sld_ValueChanged; + sldGreen.ValueChanged += Sld_ValueChanged; + sldBlue.ValueChanged += Sld_ValueChanged; + + txtRed.ValueChanged += Txt_ValueChanged; + txtGreen.ValueChanged += Txt_ValueChanged; + txtBlue.ValueChanged += Txt_ValueChanged; + } + + + private void DesactivarEventosSlider() + { + sldRed.ValueChanged -= Sld_ValueChanged; + sldGreen.ValueChanged -= Sld_ValueChanged; + sldBlue.ValueChanged -= Sld_ValueChanged; + + txtRed.ValueChanged -= Txt_ValueChanged; + txtGreen.ValueChanged -= Txt_ValueChanged; + txtBlue.ValueChanged -= Txt_ValueChanged; + } + + + public void Dispose() + { + } + + + public void DrawPalette() + { + int idx = 0; + int ancho = 16; + int alto = 16; + + cnvPalette.Children.Clear(); + rectangulos = new Rectangle[256]; + + for (int y = 0; y < 16; y++) + { + for (int x = 0; x < 16; x++) + { + var c = palette[idx]; + Rectangle rect = new Rectangle(); + rect.Width = ancho; + rect.Height = alto; + rect.Fill = new SolidColorBrush(Color.FromRgb(c.Red, c.Green, c.Blue)); + rect.Margin = new Thickness(0, 0, 0, 0); + rect.StrokeThickness = 1; + if (selectedColorIndex == idx) + { + rect.Stroke = blanco; + } + else if (idx == 227) + { + rect.Stroke = rojo; + } + else + { + rect.Stroke = negro; + } + rect.Tag = idx; + rect.Tapped += Rect_Tapped; + ToolTip.SetTip(rect, $"Index: {idx}, RGB: {c.Red}, {c.Green}, {c.Blue}"); + cnvPalette.Children.Add(rect); + Canvas.SetLeft(rect, x * ancho); + Canvas.SetTop(rect, y * alto); + rectangulos[idx] = rect; + idx++; + } + } + + UpdateColorTest(); + //UpdateSelectedColor(); + } + + private void UpdateSelectedColor() + { + var color = palette[selectedColorIndex]; + + txtSelectedColor.Text = $"Selected color index: {selectedColorIndex}"; + txtRed.Text = color.Red.ToString(); + sldRed.Value = color.Red; + txtGreen.Text = color.Green.ToString(); + sldGreen.Value = color.Green; + + //txtBlue.Text = color.Blue.ToString(); + //sldBlue.Value = color.Blue; + } + + + private void UpdateColorTest() + { + txtSelectedColor.Text = $"Selected color index: {selectedColorIndex}"; + var color = palette[selectedColorIndex]; + grdSelectedColor.Background = new SolidColorBrush(Color.FromRgb(color.Red, color.Green, color.Blue)); + txtRed.Text = color.Red.ToString(); + txtGreen.Text = color.Green.ToString(); + txtBlue.Text = color.Blue.ToString(); + sldRed.Value = color.Red; + sldGreen.Value = color.Green; + sldBlue.Value = color.Blue; + + rectangulos[selectedColorIndex].Fill = new SolidColorBrush(Color.FromRgb(color.Red, color.Green, color.Blue)); + } + + + private void Sld_ValueChanged(object? sender, Avalonia.Controls.Primitives.RangeBaseValueChangedEventArgs e) + { + DesactivarEventosSlider(); + var color = palette[selectedColorIndex]; + + color.Red = AjustarColor(sldRed.Value.ToInteger(), 36); + color.Green = AjustarColor(sldGreen.Value.ToInteger(), 36); + color.Blue = AjustarColor(sldBlue.Value.ToInteger(), 36); + + UpdateColorTest(); + ActivarEventosSlider(); + } + + + private void Txt_ValueChanged(object? sender, NumericUpDownValueChangedEventArgs e) + { + DesactivarEventosSlider(); + var color = palette[selectedColorIndex]; + + color.Red = AjustarColor(txtRed.Value.ToInteger(), 36); + color.Green = AjustarColor(txtGreen.Value.ToInteger(), 36); + color.Blue = AjustarColor(txtBlue.Value.ToInteger(), 36); + + UpdateColorTest(); + ActivarEventosSlider(); + } + + + private void Rect_Tapped(object? sender, TappedEventArgs e) + { + DesactivarEventosSlider(); + var rect = (Rectangle)sender; + var idx = rect.Tag; + rectangulos[selectedColorIndex].Stroke = negro; + selectedColorIndex = idx.ToInteger(); + rectangulos[selectedColorIndex].Stroke = blanco; + UpdateColorTest(); + ActivarEventosSlider(); + } + + private void BtnFileSource_Tapped(object? sender, TappedEventArgs e) + { + var fileTypes = new FilePickerFileType[4]; + fileTypes[0] = new FilePickerFileType("All files") { Patterns = new[] { "*", "*.*" } }; + fileTypes[1] = new FilePickerFileType("BMP files") { Patterns = new[] { "*.bmp" } }; + fileTypes[2] = new FilePickerFileType("JPG files") { Patterns = new[] { "*.jpg", "*.jpeg" } }; + fileTypes[3] = new FilePickerFileType("PNG files") { Patterns = new[] { "*.png" } }; + + var select = StorageProvider.OpenFilePickerAsync(new FilePickerOpenOptions + { + AllowMultiple = false, + FileTypeFilter = fileTypes, + Title = "Select source file to use as source...", + }).Result; + + if (select != null && select.Count > 0) + { + imgSourceLoaded = true; + imgSource.LoadImage(select[0]); + sourceFile = select[0].Path.ToString().Replace("file:///", ""); + grdSource.Width = imgSource.Width; + grdSource.Height = imgSource.Height; + Convertir(); + } + } + + + private void Convertir() + { + try + { + if (!imgSourceLoaded) + { + return; + } + + // Obtener la resolución y colores deseados + int w = 256; + int h = 192; + int c = 256; + + switch (cmbMode.SelectedIndex) + { + case 0: + w = 256; + h = 192; + c = 256; + break; + + case 1: + w = 320; + h = 256; + c = 256; + break; + } + imgConverted.Width = w; + imgConverted.Height = h; + grdConverted.Width = w; + grdConverted.Height = h; + + pixels = new int[w, h]; + + if (chkUseCurrent.IsChecked == true) + { + for (int x = 0; x < w; x++) + { + for (int y = 0; y < h; y++) + { + try + { + if (x < imgSource.Width && y < imgSource.Height) + { + var p = imgSource.imageData[x, y]; + if (p.A == 0) + { + pixels[x, y] = 227; + } + else + { + var idx = ServiceLayer.GetColor(p.R, p.G, p.B, palette, 5); + pixels[x, y] = idx; + } + } + else + { + pixels[x, y] = 0; + } + } + catch (Exception ex) + { + + } + } + } + imgConverted.SetImageData(pixels, palette, w, h); + } + else + { + int ini = 0; + // Si no añadimos a la paleta actual, la borramos + if (chkAppend.IsChecked != true) + { + palette = new PaletteColor[256]; + for (int n = 0; n < 256; n++) + { + palette[n] = new PaletteColor() + { + Blue = 0, + Green = 0, + Red = 0 + }; + } + } + // Incluir colores ULA + if (chkULA.IsChecked == true) + { + var ulaP = ServiceLayer.GetPalette(GraphicsModes.ZXSpectrum); + for (int n = 0; n < 16; n++) + { + palette[n] = ulaP[n]; + } + ini = 16; + } + // Incluir escala de grises + if (chkGrayscale.IsChecked == true) + { + var grayP = ServiceLayer.GetPalette(GraphicsModes.Monochrome); + int cl = 0; + for (int n = 0; n < 8; n++) + { + palette[ini++] = new PaletteColor() + { + Blue = (byte)cl, + Green = (byte)cl, + Red = (byte)cl + }; + cl = cl + 36; + if (cl > 255) + { + cl = 255; + } + } + } + + // Buscamos el primer color libre + for (int n = 255; n > 1; n--) + { + if (n != 227) + { + if (palette[n].Red != 0 || + palette[n].Green != 0 || + palette[n].Blue != 0) + { + ini = n + 1; + break; + } + } + } + + // Recorremos la imagen original + for (int x = 0; x < w; x++) + { + for (int y = 0; y < h; y++) + { + try + { + if (x < imgSource.Width && y < imgSource.Height) + { + // Redondeamos el color a multiplos de 36 + var p = imgSource.imageData[x, y]; + var pR = AjustarColor(p.R, 36); + var pG = AjustarColor(p.G, 36); + var pB = AjustarColor(p.B, 36); + + // Buscamos si ya existe el color + bool encontrado = false; + if (p.A == 0) + { + // Color transparente + pixels[x, y] = 227; + if (!encontrado) + { + palette[227] = new PaletteColor() + { + Blue = 255, + Green = 0, + Red = 255 + }; + encontrado = true; + } + } + else + { + // Buscar el color + for (int n = 0; n < 256; n++) + { + if (palette[n].Red == pR && palette[n].Green == pG && palette[n].Blue == pB) + { + pixels[x, y] = n; + encontrado = true; + break; + } + } + } + // Si no existe el color + if (!encontrado) + { + // Si ya hay más de 256 colore, buscamos el más parecido + if (ini > 255) + { + var idx = ServiceLayer.GetColor(p.R, p.G, p.B, palette, 5); + pixels[x, y] = idx; + } + // Creamos el nuevo color + else + { + palette[ini] = new PaletteColor() + { + Blue = pB, + Green = pG, + Red = pR + }; + pixels[x, y] = ini; + ini++; + } + } + } + else + { + pixels[x, y] = 0; + } + } + catch (Exception ex) + { + + } + } + } + imgConverted.SetImageData(pixels, palette, w, h); + DrawPalette(); + } + } + catch (Exception ex) + { + + } + } + + + private byte AjustarColor(decimal color8, decimal unidad) + { + if (color8 > 255) + { + color8 = 255; + } + decimal cd = (color8 / unidad) + 0.5M; + byte cb = (byte)cd; + cb = (byte)(cb * (byte)unidad); + return cb; + } + + #region Save and Load palette + + private void BtnSavePalette_Click(object? sender, Avalonia.Interactivity.RoutedEventArgs e) + { + var fileTypes = new FilePickerFileType[3]; + fileTypes[2] = new FilePickerFileType("All files (*.*)") { Patterns = new[] { "*", "*.*" } }; + fileTypes[1] = new FilePickerFileType("Gimp palette (*.gpl)") { Patterns = new[] { "*.gpl" } }; + fileTypes[0] = new FilePickerFileType("Next palette (*.pal)") { Patterns = new[] { "*.pal" } }; + + var select = StorageProvider.SaveFilePickerAsync(new FilePickerSaveOptions + { + Title = "Select file to save palette...", + ShowOverwritePrompt = true, + DefaultExtension = "*.pal", + FileTypeChoices = fileTypes + }).Result; + + if (select != null) + { + var fileName = select.Path.LocalPath; + var extension = System.IO.Path.GetExtension(fileName); + + bool error = true; + switch (extension) + { + case ".gpl": + error = !SavePalette_Gpl(fileName); + break; + case ".pal": + error = !SavePalette_Pal(fileName); + break; + } + if (error) + { + var box = MessageBoxManager.GetMessageBoxStandard(new MessageBoxStandardParams + { + ButtonDefinitions = ButtonEnum.Ok, + ContentTitle = "SAVE ERROR", + ContentMessage = "An error occurred while saving the file.", + Icon = MsBox.Avalonia.Enums.Icon.Warning, + WindowIcon = ((Window)this.VisualRoot).Icon, + WindowStartupLocation = WindowStartupLocation.CenterOwner + }); + box.ShowAsPopupAsync(this); + } + } + } + + + private bool SavePalette_Gpl(string fileName) + { + var sb = new StringBuilder(); + + sb.AppendLine("GIMP Palette"); + sb.AppendLine($"Name: {System.IO.Path.GetFileNameWithoutExtension(fileName)}"); + sb.AppendLine("#Generated with ZX Basic Studio"); + for (int i = 0; i < 256; i++) + { + var color = palette[i]; + sb.AppendLine($"{color.Red.ToString().PadLeft(3, ' ')} {color.Green.ToString().PadLeft(3, ' ')} {color.Blue.ToString().PadLeft(3, ' ')}\ti:{i},r:{color.Red},g:{color.Green},b:{color.Blue}"); + } + var data = Encoding.ASCII.GetBytes(sb.ToString()); + return ServiceLayer.Files_SaveFileData(fileName, data); + } + + + private bool SavePalette_Pal(string fileName) + { + var data = new List(); + foreach (var color in palette) + { + int r = color.Red / 36; + int g = color.Green / 36; + int b = color.Blue / 36; + byte d1 = (byte)(((r & 0x07) << 5) | ((g & 0x07) << 2) | ((b & 0x7) >> 1)); + byte d2 = (byte)(b & 0x1); + if (color.HasPriority) + { + d2 = (byte)(d2 | 0x80); + } + data.Add(d1); + data.Add(d2); + } + return ServiceLayer.Files_SaveFileData(fileName, data.ToArray()); + } + + + private void BtnLoadPalette_Click(object? sender, Avalonia.Interactivity.RoutedEventArgs e) + { + var fileTypes = new FilePickerFileType[3]; + fileTypes[2] = new FilePickerFileType("All files (*.*)") { Patterns = new[] { "*", "*.*" } }; + fileTypes[1] = new FilePickerFileType("Gimp palette (*.gpl)") { Patterns = new[] { "*.gpl" } }; + fileTypes[0] = new FilePickerFileType("Next palette (*.pal)") { Patterns = new[] { "*.pal" } }; + + var select = StorageProvider.OpenFilePickerAsync(new FilePickerOpenOptions + { + AllowMultiple = false, + Title = "Select file to load...", + FileTypeFilter = fileTypes, + }).Result; + + if (select != null && select.Count > 0) + { + var data = ServiceLayer.GetFileData(select[0].Path.LocalPath); + if (data == null) + { + var box = MessageBoxManager.GetMessageBoxStandard(new MessageBoxStandardParams + { + ButtonDefinitions = ButtonEnum.Ok, + ContentTitle = "LOAD ERROR", + ContentMessage = "An error occurred while loading the file.", + Icon = MsBox.Avalonia.Enums.Icon.Warning, + WindowIcon = ((Window)this.VisualRoot).Icon, + WindowStartupLocation = WindowStartupLocation.CenterOwner + }); + box.ShowAsPopupAsync(this); + } + + DesactivarEventosSlider(); + int idx = 0; + for (int dir = 0; dir < 512; dir += 2) + { + int d1 = data[dir]; + int d2 = data[dir + 1]; + + int r = (d1 >> 5) & 0x07; + int g = (d1 >> 2) & 0x07; + int b = (d1 & 0x03) << 1; + b = b | (d2 & 0x01); + var color = palette[idx]; + color.Red = (byte)(r * 36); + color.Green = (byte)(g * 36); + color.Blue = (byte)(b * 36); + color.HasPriority = d2 > 1; + idx++; + } + DrawPalette(); + UpdateColorTest(); + ActivarEventosSlider(); + Convertir(); + } + } + + + private void BtnResetPalette_Click(object? sender, Avalonia.Interactivity.RoutedEventArgs e) + { + DesactivarEventosSlider(); + palette = ServiceLayer.GetPalette(GraphicsModes.Next); + UpdateColorTest(); + ActivarEventosSlider(); + DrawPalette(); + chkUseCurrent.IsChecked = true; + chkAppend.IsChecked = false; + chkULA.IsChecked = false; + chkULA.IsEnabled = false; + chkGrayscale.IsChecked = false; + chkGrayscale.IsEnabled = false; + Convertir(); + } + + #endregion + + + #region Conversion options + + private void ChkUseCurrent_Click(object? sender, Avalonia.Interactivity.RoutedEventArgs e) + { + bool useCurrent = chkUseCurrent.IsChecked == true; + chkULA.IsEnabled = !useCurrent; + chkGrayscale.IsEnabled = !useCurrent; + Convertir(); + } + + + private void ChkAppend_Click(object? sender, Avalonia.Interactivity.RoutedEventArgs e) + { + bool append = chkAppend.IsChecked == true; + chkULA.IsEnabled = append; + chkGrayscale.IsEnabled = append; + Convertir(); + } + + + private void ChkGrayscale_Click(object? sender, Avalonia.Interactivity.RoutedEventArgs e) + { + Convertir(); + } + + private void ChkULA_Click(object? sender, Avalonia.Interactivity.RoutedEventArgs e) + { + Convertir(); + } + + + private void BtnRefresh_Click(object? sender, Avalonia.Interactivity.RoutedEventArgs e) + { + Convertir(); + } + + + private void BtnSaveImage_Click(object? sender, Avalonia.Interactivity.RoutedEventArgs e) + { + var fileTypes = new FilePickerFileType[3]; + fileTypes[2] = new FilePickerFileType("All files (*.*)") { Patterns = new[] { "*", "*.*" } }; + fileTypes[1] = new FilePickerFileType("Portable Nextwork Graphics (*.png)") { Patterns = new[] { "*.png" } }; + fileTypes[0] = new FilePickerFileType("Next image (*.nxi)") { Patterns = new[] { "*.nxi" } }; + + var select = StorageProvider.SaveFilePickerAsync(new FilePickerSaveOptions + { + Title = "Select file to save image...", + ShowOverwritePrompt = true, + DefaultExtension = "*.nxi", + FileTypeChoices = fileTypes + }).Result; + + if (select != null) + { + var fileName = select.Path.LocalPath; + var extension = System.IO.Path.GetExtension(fileName); + bool error = false; + + switch (extension) + { + case ".png": + if (!imgConverted.SaveImageAsPng(select.Path.LocalPath)) + { + error = true; + } + break; + case ".nxi": + if (!SaveAsNXI(fileName)) + { + error = true; + } + break; + default: + { + var box = MessageBoxManager.GetMessageBoxStandard(new MessageBoxStandardParams + { + ButtonDefinitions = ButtonEnum.Ok, + ContentTitle = "SAVE ERROR", + ContentMessage = "Format not supported.", + Icon = MsBox.Avalonia.Enums.Icon.Warning, + WindowIcon = ((Window)this.VisualRoot).Icon, + WindowStartupLocation = WindowStartupLocation.CenterOwner + }); + box.ShowAsPopupAsync(this); + } + return; + } + + if (error) + { + var box = MessageBoxManager.GetMessageBoxStandard(new MessageBoxStandardParams + { + ButtonDefinitions = ButtonEnum.Ok, + ContentTitle = "SAVE ERROR", + ContentMessage = "An error occurred while saving the file.", + Icon = MsBox.Avalonia.Enums.Icon.Warning, + WindowIcon = ((Window)this.VisualRoot).Icon, + WindowStartupLocation = WindowStartupLocation.CenterOwner + }); + box.ShowAsPopupAsync(this); + } + } + } + + + private bool SaveAsNXI(string fileName) + { + try + { + var data = new List(); + for (int y = 0; y < 192; y++) + { + for (int x = 0; x < 256; x++) + { + data.Add((byte)(pixels[x, y])); + } + } + if (cmbMode.SelectedIndex == 0) + { + foreach (var color in palette) + { + int r = color.Red / 36; + int g = color.Green / 36; + int b = color.Blue / 36; + byte d1 = (byte)(((r & 0x07) << 5) | ((g & 0x07) << 2) | ((b & 0x7) >> 1)); + byte d2 = (byte)(b & 0x1); + if (color.HasPriority) + { + d2 = (byte)(d2 | 0x80); + } + data.Add(d1); + data.Add(d2); + } + } + return ServiceLayer.Files_SaveFileData(fileName, data.ToArray()); + } + catch (Exception ex) + { + return false; + } + } + + #endregion + + + #region Crear paleta de 9 bits + + private static byte[] paletteDefRG = { 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff }; + + private void CrearPaletaGPL9bits() + { + var sw = new StreamWriter("c:\\Temp\\Duefectu_9bit_work.gpl", false); + int i = 0; + sw.WriteLine("GIMP Palette"); + sw.WriteLine("Name: 9 bit palette for Next"); + sw.WriteLine("#By Duefectu"); + // Escala de grises + for (int n = 0; n < 8; n++) + { + var s = paletteDefRG[n].ToString().PadLeft(3, ' '); + sw.WriteLine($"{s} {s} {s}\tGrayScale {n}"); + i++; + } + + // Colores ordenados por rojo + if (false) + { + for (int b = 0; b < 8; b++) + { + for (int g = 0; g < 8; g++) + { + for (int r = 0; r < 8; r++) + { + sw.WriteLine($"{paletteDefRG[r].ToString().PadLeft(3, ' ')} {paletteDefRG[g].ToString().PadLeft(3, ' ')} {paletteDefRG[b].ToString().PadLeft(3, ' ')}\ti:{i},r:{r},g:{g},b:{b}"); + i++; + } + } + } + } + + // Espacio en negro + for (int n = 0; n < 8; n++) + { + var s = " 0"; + sw.WriteLine($"{s} {s} {s}\tGrayScale {n}"); + i++; + } + + // Rojo 1 + for (int n = 0; n < 8; n++) + { + var s = paletteDefRG[n].ToString().PadLeft(3, ' '); + sw.WriteLine($"{s} 0 0\tGrayScale {n}"); + i++; + } + + // Rojo 2 + for (int n = 0; n < 8; n++) + { + var s = paletteDefRG[n].ToString().PadLeft(3, ' '); + sw.WriteLine($"255 {s} {s}\tGrayScale {n}"); + i++; + } + + // Rojo 3 + for (int n = 0; n < 8; n++) + { + string c1 = ""; + string c2 = ""; + string c3 = ""; + c1 = paletteDefRG[n].ToString().PadLeft(3, ' '); + if (n > 0) + { + c2 = paletteDefRG[n - 1].ToString().PadLeft(3, ' '); + } + if (n > 1) + { + c3 = paletteDefRG[n - 2].ToString().PadLeft(3, ' '); + } + sw.WriteLine($"255 {c1} {c2}\tGrayScale {n}"); + i++; + } + + sw.Close(); + } + + #endregion + } +} diff --git a/ZXBStudio/DocumentEditors/ZXGraphics/log/ServiceLayer.cs b/ZXBStudio/DocumentEditors/ZXGraphics/log/ServiceLayer.cs index 510ae01..2694d88 100644 --- a/ZXBStudio/DocumentEditors/ZXGraphics/log/ServiceLayer.cs +++ b/ZXBStudio/DocumentEditors/ZXGraphics/log/ServiceLayer.cs @@ -16,6 +16,7 @@ using Avalonia.Metadata; using Avalonia.Controls.Shapes; using AvaloniaEdit; +using System.Diagnostics; namespace ZXBasicStudio.DocumentEditors.ZXGraphics.log { @@ -555,6 +556,9 @@ public static ZXBuildSettings GetProjectSettings() }; + private static byte[] paletteDefRG = { 0x00, 0x24, 0x49, 0x6d, 0x92, 0xb6, 0xdb, 0xff }; + private static byte[] paletteDefB = { 0x00, 0x6d, 0xb6, 0xff }; + public static PaletteColor[] GetPalette(GraphicsModes mode) { switch (mode) @@ -575,30 +579,15 @@ public static PaletteColor[] GetPalette(GraphicsModes mode) int r = 0; int g = 0; int b = 0; + for (int i = 0; i < 256; i++) { r = (i >> 5); - r = r * 37; - if (r > 255) - { - r = 255; - } + r = paletteDefRG[r]; g = ((i >> 2) & 0x07); - g = g * 37; - if (g > 255) - { - g = 255; - } - b = (i & 0x07); - if (b != 0) - { - b++; - } - b = b * 37; - if (b > 255) - { - b = 255; - } + g = paletteDefRG[g]; + b = (i & 0x03); + b = paletteDefB[b]; pal[i] = new PaletteColor() { Blue = (byte)b, @@ -612,7 +601,7 @@ public static PaletteColor[] GetPalette(GraphicsModes mode) } - + #endregion @@ -697,5 +686,84 @@ public static bool SpriteData_ChangeFrames(ref Sprite sprite, byte oldFrames) } #endregion + + + + #region Tools + + public static int GetColor(byte r, byte g, byte b, PaletteColor[] palette, byte cutOff = 5) + { + if (r > 0) + { + + } + byte cr = GetColor_CutOff(r, cutOff); + byte cg = GetColor_CutOff(g, cutOff); + byte cb = GetColor_CutOff(b, cutOff); + PaletteColor targetColor = new PaletteColor() + { + Blue = cb, + Green = cg, + Red = cr + }; + + var palColor = palette.OrderBy(c => GetColorDistance(c, targetColor)).First(); + for (int n = 0; n < palette.Count(); n++) + { + var p = palette[n]; + if (palColor.Red == p.Red && + palColor.Green == p.Green && + palColor.Blue == p.Blue) + { + return n; + } + } + return 0; + } + + + private static byte GetColor_CutOff(byte c, byte cutOff) + { + if (cutOff == 5) + { + return c; + } + + if (cutOff < 5) + { + int ic = c - (25 * (5 - cutOff)); + if (ic < 0) + { + return 0; + } + else + { + return ic.ToByte(); + } + } + else + { + int ic = c + (25 * (cutOff - 5)); + if (ic > 255) + { + return 255; + } + else + { + return ic.ToByte(); + } + } + } + + + private static double GetColorDistance(PaletteColor c1, PaletteColor c2) + { + int rDiff = c1.Red - c2.Red; + int gDiff = c1.Green - c2.Green; + int bDiff = c1.Blue - c2.Blue; + return Math.Sqrt(rDiff * rDiff + gDiff * gDiff + bDiff * bDiff); + } + + #endregion } } \ No newline at end of file diff --git a/ZXBStudio/DocumentEditors/ZXGraphics/neg/PaletteColor.cs b/ZXBStudio/DocumentEditors/ZXGraphics/neg/PaletteColor.cs index 29bdc61..09cb833 100644 --- a/ZXBStudio/DocumentEditors/ZXGraphics/neg/PaletteColor.cs +++ b/ZXBStudio/DocumentEditors/ZXGraphics/neg/PaletteColor.cs @@ -23,5 +23,9 @@ public class PaletteColor /// Blue level /// public byte Blue { get; set; } + /// + /// When true, the color has Top Most + /// + public bool HasPriority { get; set; } } } diff --git a/ZXBStudio/MainWindow.axaml b/ZXBStudio/MainWindow.axaml index 997287f..c291296 100644 --- a/ZXBStudio/MainWindow.axaml +++ b/ZXBStudio/MainWindow.axaml @@ -72,6 +72,9 @@ + + + diff --git a/ZXBStudio/MainWindow.axaml.cs b/ZXBStudio/MainWindow.axaml.cs index 9894d5a..ac10070 100644 --- a/ZXBStudio/MainWindow.axaml.cs +++ b/ZXBStudio/MainWindow.axaml.cs @@ -45,6 +45,7 @@ using ZXBasicStudio.Controls.DockSystem; using ZXBasicStudio.Dialogs; using ZXBasicStudio.DocumentEditors; +using ZXBasicStudio.DocumentEditors.ZXGraphics; using ZXBasicStudio.DocumentEditors.ZXTextEditor.Controls; using ZXBasicStudio.DocumentModel.Classes; using ZXBasicStudio.DocumentModel.Interfaces; @@ -156,6 +157,7 @@ public MainWindow() mnuGlobalOptions.Click += ConfigureGlobalSettings; mnuDumpMem.Click += DumpMemory; mnuDumpRegs.Click += DumpRegisters; + mnuNext_PaletteBuilder.Click += Next_PaletteBuilder; mnuTurbo.Click += TurboModeEmulator; mnuRestoreLayout.Click += RestoreLayout; mnuCodeView.Click += FullLayout; @@ -2345,6 +2347,17 @@ private async void ExitApplication(object? sender, Avalonia.Interactivity.Routed } #endregion + + + #region Next Tools + + private async void Next_PaletteBuilder(object? sender, Avalonia.Interactivity.RoutedEventArgs e) + { + var dlg = new PaletteBuilderDialog(); + dlg.ShowDialog(this.VisualRoot as Window); + } + + #endregion } public enum PreferredSourceType diff --git a/ZXBStudio/Svg/White/ImageImport.svg b/ZXBStudio/Svg/White/ImageImport.svg new file mode 100644 index 0000000..07795c0 --- /dev/null +++ b/ZXBStudio/Svg/White/ImageImport.svg @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/ZXBStudio/Svg/White/Next.svg b/ZXBStudio/Svg/White/Next.svg new file mode 100644 index 0000000..c2cec58 --- /dev/null +++ b/ZXBStudio/Svg/White/Next.svg @@ -0,0 +1,11 @@ + + + + + Layer 1 + + + + + + \ No newline at end of file diff --git a/ZXBStudio/Svg/White/palette.svg b/ZXBStudio/Svg/White/palette.svg new file mode 100644 index 0000000..0d4d86f --- /dev/null +++ b/ZXBStudio/Svg/White/palette.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/ZXBStudio/ZXBasicStudio.csproj b/ZXBStudio/ZXBasicStudio.csproj index d329d20..d1fd9a6 100644 --- a/ZXBStudio/ZXBasicStudio.csproj +++ b/ZXBStudio/ZXBasicStudio.csproj @@ -11,7 +11,7 @@ AnyCPU;x64 zxbs.ico ZX Basic Studio - 1.4.* + 1.5.* False @@ -255,6 +255,8 @@ + + @@ -349,6 +351,7 @@ + @@ -476,6 +479,7 @@ + @@ -506,6 +510,7 @@ + @@ -576,6 +581,9 @@ SpriteExportDialog.axaml + + PaletteBuilderDialog.axaml + SpritePatternEditor.axaml From fdacf6ada3c82a89e3ea22f3bf43b97d5ccd8bb0 Mon Sep 17 00:00:00 2001 From: Juan Segura Date: Sun, 23 Feb 2025 11:22:10 +0100 Subject: [PATCH 4/5] Mixing with master --- Bufdio/Bufdio.csproj | 2 +- .../AttachadProperty/HyperLinkCommand.cs | 2 +- MsBox.Avalonia/MsBox.Avalonia.csproj | 4 +- ZXBStudio/Dialogs/ZXAboutDialog.axaml | 17 ++--- .../ZXGraphics/log/ExportManager.cs | 1 - .../ZXBasicCompletionData.cs | 5 +- .../ZXTextEditor/Controls/ZXBasicEditor.cs | 26 ++++++- .../Controls/ZXTextEditor.axaml.cs | 67 +++++++++++-------- ZXBStudio/MainWindow.axaml.cs | 3 + ZXBStudio/ZXBasicStudio.csproj | 16 ++--- ZXBasicStudioTest/ZXBasicStudioTest.csproj | 6 +- 11 files changed, 92 insertions(+), 57 deletions(-) diff --git a/Bufdio/Bufdio.csproj b/Bufdio/Bufdio.csproj index 0a8f092..16bd398 100644 --- a/Bufdio/Bufdio.csproj +++ b/Bufdio/Bufdio.csproj @@ -9,7 +9,7 @@ - + diff --git a/MsBox.Avalonia/AttachadProperty/HyperLinkCommand.cs b/MsBox.Avalonia/AttachadProperty/HyperLinkCommand.cs index ba94858..be3de4d 100644 --- a/MsBox.Avalonia/AttachadProperty/HyperLinkCommand.cs +++ b/MsBox.Avalonia/AttachadProperty/HyperLinkCommand.cs @@ -1,9 +1,9 @@ -using System.Reactive; using System.Windows.Input; using Avalonia; using Avalonia.Data; using Avalonia.Input; using Avalonia.Interactivity; +using Avalonia.Reactive; namespace MsBox.Avalonia.AttachadProperty; diff --git a/MsBox.Avalonia/MsBox.Avalonia.csproj b/MsBox.Avalonia/MsBox.Avalonia.csproj index e039201..1195e6c 100644 --- a/MsBox.Avalonia/MsBox.Avalonia.csproj +++ b/MsBox.Avalonia/MsBox.Avalonia.csproj @@ -26,9 +26,9 @@ - + - + diff --git a/ZXBStudio/Dialogs/ZXAboutDialog.axaml b/ZXBStudio/Dialogs/ZXAboutDialog.axaml index 05ecf92..f0bff6b 100644 --- a/ZXBStudio/Dialogs/ZXAboutDialog.axaml +++ b/ZXBStudio/Dialogs/ZXAboutDialog.axaml @@ -10,16 +10,17 @@ Title="About..." CanResize="False" WindowStartupLocation="CenterScreen" Topmost="True"> - + ZX Basic Studio Beta release - Build 1.3.5.6 - 2023-10-29 - The ZX Basic Studio development team - El Dr. Gusman, Duefectu, AdolFITO, Hash6Iron, SirRickster - Many thanks to Boriel for the ZX Basic compiler and his support to this project. - (C) 2023, El Dr. Gusman - + Build 1.3.5.6 + 2023-10-29 + The ZX Basic Studio development team + El Dr. Gusman, Boriel, Duefectu, AdolFITO, Hash6Iron, SirRickster + Many thanks to Boriel for the ZX Basic compiler and his support to this project. + (C) 2023, El Dr. Gusman + (C) 2025, Boriel & DuefectuCorp + diff --git a/ZXBStudio/DocumentEditors/ZXGraphics/log/ExportManager.cs b/ZXBStudio/DocumentEditors/ZXGraphics/log/ExportManager.cs index 19fccac..45aa1b0 100644 --- a/ZXBStudio/DocumentEditors/ZXGraphics/log/ExportManager.cs +++ b/ZXBStudio/DocumentEditors/ZXGraphics/log/ExportManager.cs @@ -4,7 +4,6 @@ using System.Collections.Generic; using System.IO; using System.Linq; -using System.Reactive.Joins; using System.Text; using System.Threading.Tasks; using ZXBasicStudio.BuildSystem; diff --git a/ZXBStudio/DocumentEditors/ZXTextEditor/Classes/LanguageDefinitions/ZXBasicCompletionData.cs b/ZXBStudio/DocumentEditors/ZXTextEditor/Classes/LanguageDefinitions/ZXBasicCompletionData.cs index 860671c..91479f8 100644 --- a/ZXBStudio/DocumentEditors/ZXTextEditor/Classes/LanguageDefinitions/ZXBasicCompletionData.cs +++ b/ZXBStudio/DocumentEditors/ZXTextEditor/Classes/LanguageDefinitions/ZXBasicCompletionData.cs @@ -55,7 +55,7 @@ public ZXBasicCompletionData(ZXBasicCompletionType DataType, string Text, string public string Text { get; } - public object Content => Text; + public object Content => this; // Text; public object Description { get; } @@ -66,8 +66,11 @@ public void Complete(TextArea textArea, ISegment completionSegment, { textArea.Document.Replace(completionSegment, Text); } + + public override string ToString() => Text; } + public enum ZXBasicCompletionType { Keyword, diff --git a/ZXBStudio/DocumentEditors/ZXTextEditor/Controls/ZXBasicEditor.cs b/ZXBStudio/DocumentEditors/ZXTextEditor/Controls/ZXBasicEditor.cs index c9d3f9a..3a130fb 100644 --- a/ZXBStudio/DocumentEditors/ZXTextEditor/Controls/ZXBasicEditor.cs +++ b/ZXBStudio/DocumentEditors/ZXTextEditor/Controls/ZXBasicEditor.cs @@ -475,6 +475,16 @@ static ZXBasicEditor() public ZXBasicEditor() : base() { } public ZXBasicEditor(string DocumentPath) : base(DocumentPath, ZXBasicDocument.Id) { } + + /// + /// Gestion de autocompletar + /// + /// + /// + /// + /// + /// + /// protected override IEnumerable? ShouldComplete(IDocument Document, int Line, int Column, char? RequestedChar, bool ByRequest) { var line = Document.GetLineByNumber(Line); @@ -487,8 +497,10 @@ public ZXBasicEditor(string DocumentPath) : base(DocumentPath, ZXBasicDocument.I if (!ByRequest) { - if(ZXOptions.Current.DisableAuto) + if (ZXOptions.Current.DisableAuto) + { return null; + } } if (ByRequest) @@ -522,25 +534,33 @@ public ZXBasicEditor(string DocumentPath) : base(DocumentPath, ZXBasicDocument.I } if (context == ContextType.Comment) + { return null; + } string trimmed = preText.Trim(); - if(context == ContextType.Assembler) + if (context == ContextType.Assembler) { if (!char.IsLetter(RequestedChar ?? ' ') || regCommentAsm.IsMatch(trimmed)) + { return null; + } if (string.IsNullOrWhiteSpace(trimmed)) + { PrioritizeAssemblerKeywords(); + } else + { PrioritizeAssemblerRegisters(); - + } return assembler; } if (string.IsNullOrWhiteSpace(preText)) + //if(trimmed.Length > 1) { if (RequestedChar == '#') return directives; diff --git a/ZXBStudio/DocumentEditors/ZXTextEditor/Controls/ZXTextEditor.axaml.cs b/ZXBStudio/DocumentEditors/ZXTextEditor/Controls/ZXTextEditor.axaml.cs index bcb123b..bc08cbb 100644 --- a/ZXBStudio/DocumentEditors/ZXTextEditor/Controls/ZXTextEditor.axaml.cs +++ b/ZXBStudio/DocumentEditors/ZXTextEditor/Controls/ZXTextEditor.axaml.cs @@ -35,6 +35,7 @@ using AvaloniaEdit.Utils; using static System.Runtime.InteropServices.JavaScript.JSType; using System.Diagnostics; +using SixLabors.ImageSharp.Formats.Webp; namespace ZXBasicStudio.DocumentEditors.ZXTextEditor.Controls { @@ -99,14 +100,14 @@ public partial class ZXTextEditor : ZXDocumentEditorBase, IObserver _docName; public override string DocumentPath => _docPath; public override bool Modified - { - get - { - if (_docPath == ZXConstants.DISASSEMBLY_DOC || _docPath == ZXConstants.ROM_DOC) - return false; - - return editor?.IsModified ?? false; - } + { + get + { + if (_docPath == ZXConstants.DISASSEMBLY_DOC || _docPath == ZXConstants.ROM_DOC) + return false; + + return editor?.IsModified ?? false; + } } #endregion @@ -139,7 +140,7 @@ public int? BreakLine #region Constructors public ZXTextEditor() : this("Untitled", ZXTextDocument.Id) { - + } public ZXTextEditor(string DocumentPath, Guid DocumentTypeId) { @@ -147,7 +148,7 @@ public ZXTextEditor(string DocumentPath, Guid DocumentTypeId) _docTypeId = DocumentTypeId; InitializeShortcuts(); - + editor.DataContext = editor; editor.FontSize = ZXOptions.Current.EditorFontSize; editor.WordWrap = ZXOptions.Current.WordWrap; @@ -208,7 +209,9 @@ private void TextArea_TextEntering(object? sender, TextInputEventArgs e) { if (e.Text == null || e.Text.Length == 0) + { return; + } if (completionWindow == null && !string.IsNullOrWhiteSpace(e.Text) && !char.IsNumber(e.Text[0])) { @@ -216,11 +219,15 @@ private void TextArea_TextEntering(object? sender, TextInputEventArgs e) var completionData = ShouldComplete(editor.Document, editor.TextArea.Caret.Line, editor.TextArea.Caret.Column - 1, e.Text[0], false); if (completionData != null) + { ShowCompletion(completionData, false); + } } else if (completionWindow != null && !char.IsLetterOrDigit(e.Text[0])) + { completionWindow.CompletionList.RequestInsertion(e); - + } + } private void TextArea_KeyDown(object? sender, KeyEventArgs e) @@ -231,7 +238,9 @@ private void TextArea_KeyDown(object? sender, KeyEventArgs e) var completionData = ShouldComplete(editor.Document, editor.TextArea.Caret.Line, editor.TextArea.Caret.Column - 1, null, true); if (completionData != null) + { ShowCompletion(completionData, true); + } } } @@ -240,10 +249,9 @@ private void ShowCompletion(IEnumerable completions, bool reque if (completionWindow == null) { completionWindow = new CompletionWindow(editor.TextArea); - ICompletionData? selectedItem = null; - if (requested) + //if (requested) { var line = editor.Document.GetLineByNumber(editor.TextArea.Caret.Line); var text = editor.Document.GetText(line); @@ -270,6 +278,7 @@ private void ShowCompletion(IEnumerable completions, bool reque data.AddRange(completions); completionWindow.Show(); completionWindow.CompletionList.SelectedItem = selectedItem; + completionWindow.KeyDown += (s, e) => { if (e.Key == Key.F1 && completionWindow.CompletionList.SelectedItem != null) @@ -512,7 +521,7 @@ public override bool SaveDocument(TextWriter OutputLog) return true; } - catch(Exception ex) + catch (Exception ex) { OutputLog.WriteLine($"Error saving file {_docPath}: {ex.Message}"); return false; @@ -520,12 +529,12 @@ public override bool SaveDocument(TextWriter OutputLog) } public override bool RenameDocument(string NewName, TextWriter OutputLog) { - try + try { UpdateFileName(_docPath, NewName); return true; } - catch(Exception ex) + catch (Exception ex) { OutputLog.WriteLine($"Error internally updating the document name: {ex.Message}"); return false; @@ -602,22 +611,22 @@ public void Expand() foreach (var fold in fManager.AllFoldings) fold.IsFolded = false; } - + public void FontIncrease() { editor.FontSize++; } - + public void FontDecrease() { editor.FontSize--; } - + public void CommentSelection() { if (editor.IsReadOnly || commentChar == null || editor.TextArea.Selection == null) return; - + TextDocument document = editor.TextArea.Document; if (editor.TextArea.Selection.Length == 0) @@ -629,7 +638,7 @@ public void CommentSelection() else { IEnumerable selectionSegments = editor.TextArea.Selection.Segments; - + foreach (SelectionSegment segment in selectionSegments) { int lineStart = document.GetLineByOffset(segment.StartOffset).LineNumber; @@ -741,17 +750,17 @@ private void Document_Changing(object? sender, DocumentChangeEventArgs e) if (e.RemovalLength > 0) { - + int end = start + e.RemovalLength; int linesRemoved = 0; int pos = start; - while(pos < end) + while (pos < end) { var line = editor.Document.GetLineByOffset(pos); if (pos >= line.EndOffset) firstLine++; - + string lineText = editor.Document.GetText(line.Offset, line.Length); int removalLength = Math.Min(line.EndOffset - pos, end - pos); string leftText = lineText.Remove(pos - line.Offset, removalLength); @@ -766,11 +775,11 @@ private void Document_Changing(object? sender, DocumentChangeEventArgs e) linesRemoved++; } - if(linesRemoved > 0) + if (linesRemoved > 0) changed |= MoveBreakpoints(firstLine, -linesRemoved); } - if(changed) + if (changed) bpMargin?.InvalidateVisual(); } private void Document_Changed(object? sender, DocumentChangeEventArgs e) @@ -801,7 +810,7 @@ private void Document_Changed(object? sender, DocumentChangeEventArgs e) var firstText = editor.Document.GetText(firstLine.Offset, firstLine.Length); - if(!string.IsNullOrWhiteSpace(firstText)) + if (!string.IsNullOrWhiteSpace(firstText)) changed = MoveBreakpoints(firstLine.LineNumber + 1, addedLines); else changed = MoveBreakpoints(firstLine.LineNumber, addedLines); @@ -873,12 +882,12 @@ public void UpdateFontSize(bool increase) #region IObserver implementation for modified document notifications public void OnCompleted() { - + } public void OnError(Exception error) { - + } public void OnNext(AvaloniaPropertyChangedEventArgs value) diff --git a/ZXBStudio/MainWindow.axaml.cs b/ZXBStudio/MainWindow.axaml.cs index ac10070..668fd82 100644 --- a/ZXBStudio/MainWindow.axaml.cs +++ b/ZXBStudio/MainWindow.axaml.cs @@ -217,6 +217,9 @@ public MainWindow() regView.Registers = emu.Registers; memView.Initialize(emu.Memory); CreateRomBreakpoints(); +#if DEBUG + this.AttachDevTools(); +#endif #endregion #region Player intialization diff --git a/ZXBStudio/ZXBasicStudio.csproj b/ZXBStudio/ZXBasicStudio.csproj index d1fd9a6..7ed9650 100644 --- a/ZXBStudio/ZXBasicStudio.csproj +++ b/ZXBStudio/ZXBasicStudio.csproj @@ -541,17 +541,17 @@ - + - - - + + + - - - + + + - + diff --git a/ZXBasicStudioTest/ZXBasicStudioTest.csproj b/ZXBasicStudioTest/ZXBasicStudioTest.csproj index 7767c58..5e6593a 100644 --- a/ZXBasicStudioTest/ZXBasicStudioTest.csproj +++ b/ZXBasicStudioTest/ZXBasicStudioTest.csproj @@ -10,13 +10,13 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive - - + + all runtime; build; native; contentfiles; analyzers; buildtransitive From ba10f64acf587bdac2e063fab58421c82207447d Mon Sep 17 00:00:00 2001 From: Jose Rodriguez Date: Sun, 9 Mar 2025 23:14:38 +0100 Subject: [PATCH 5/5] feat: put debug labels in separated lines --- ZXBStudio/BuildSystem/ZXCodeFile.cs | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/ZXBStudio/BuildSystem/ZXCodeFile.cs b/ZXBStudio/BuildSystem/ZXCodeFile.cs index 84cca94..1df182b 100644 --- a/ZXBStudio/BuildSystem/ZXCodeFile.cs +++ b/ZXBStudio/BuildSystem/ZXCodeFile.cs @@ -1,13 +1,9 @@ -using Avalonia.Svg.Skia; -using System; +using System; using System.Collections.Generic; using System.IO; using System.Linq; -using System.Reflection.Metadata; using System.Text; using System.Text.RegularExpressions; -using System.Threading.Tasks; -using ZXBasicStudio.Classes; using ZXBasicStudio.DocumentModel.Classes; using ZXBasicStudio.IntegratedDocumentTypes.CodeDocuments.Basic; @@ -99,6 +95,11 @@ void ContentCleanup() Content = regRemoveEmpty.Replace(Content, ""); } + private string GetSourceLine(int lineNum, string line) + { + return $"file__{FileGuid}__{lineNum}:\n{line}"; + } + public void CreateBuildFile(IEnumerable AllFiles) { string content = Content; @@ -155,7 +156,7 @@ public void CreateBuildFile(IEnumerable AllFiles) else { sbSource.AppendLine(line); - line = $"file__{FileGuid}__{lineIndex}: {line}"; + line = GetSourceLine(lineIndex, line); sb.AppendLine(line); } @@ -244,11 +245,11 @@ public void CreateBuildFile(IEnumerable AllFiles) } else if (inAsm && !regAsmExclude.IsMatch(line)) { - line = $"file__{FileGuid}__{buc}: {line}"; + line = GetSourceLine(buc, line); } else if (!inAsm && !string.IsNullOrWhiteSpace(line) && !regBasicExclude.IsMatch(line)) { - line = $"file__{FileGuid}__{buc}: {line}"; + line = GetSourceLine(buc, line); } }