| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484 | using System;using System.Collections.Generic;using System.ComponentModel;using System.Drawing;using System.IO;using System.Linq;using System.Threading.Tasks;using System.Windows;using System.Windows.Controls;using System.Windows.Input;using System.Windows.Threading;using ICSharpCode.AvalonEdit.Highlighting;using InABox.Core;using InABox.Scripting;using InABox.WPF;using InABox.Wpf;using Microsoft.CodeAnalysis;using RoslynPad.Editor;using RoslynPad.Roslyn;using Syncfusion.Data.Extensions;using Image = System.Windows.Controls.Image;namespace InABox.DynamicGrid{    /// <summary>    ///     Interaction logic for ScriptEditor.xaml    /// </summary>    public partial class ScriptEditor : ThemableWindow    {        public static RoutedCommand SaveCommand = new();        private bool _bChanged;        private string _editorTitle = "ScriptEditor";        public string EditorTitle        {            get => _editorTitle;            set {                _editorTitle = value;                UpdateTitle();            }        }        private RoslynHost _host;        private readonly SyntaxLanguage _language = SyntaxLanguage.CSharp;        private readonly string _script = "";        private Dictionary<string, string[]> _snippets = new();        private bool bCompiled;        private readonly Dictionary<bool, Image> compile = SetupImage(Properties.Resources.tick);        private readonly Dictionary<bool, Image> copy = SetupImage(Properties.Resources.copy);        private readonly Dictionary<bool, Image> cut = SetupImage(Properties.Resources.cut);        private readonly Dictionary<bool, Image> paste = SetupImage(Properties.Resources.paste);        private readonly Dictionary<bool, Image> print = SetupImage(Properties.Resources.print);        private readonly Dictionary<bool, Image> redo = SetupImage(Properties.Resources.redo);        private readonly Dictionary<bool, Image> run = SetupImage(Properties.Resources.run);        private readonly Dictionary<bool, Image> save = SetupImage(Properties.Resources.disk);        private readonly Dictionary<bool, Image> undo = SetupImage(Properties.Resources.undo);        static ScriptEditor()        {            SaveCommand.InputGestures.Add(new KeyGesture(Key.S, ModifierKeys.Control));        }        public ScriptEditor(string script, SyntaxLanguage language = SyntaxLanguage.CSharp, string scriptTitle = "ScriptEditor")        {            _language = language;            _script = script;            EditorTitle = scriptTitle;            InitializeComponent();            // Not Sure if we need Roslyn for XAML - need to research this            if (language == SyntaxLanguage.CSharp || language == SyntaxLanguage.XAML)                try                {                    if (ScriptDocument.Host == null)                        ScriptDocument.Initialize();                }                catch (Exception e)                {                    MessageBox.Show("Unable to initialize Script Editor!\nPlease try again.\n\n" + e.Message);                }            Roslyn.SyntaxHighlighting = HighlightingManager.Instance.GetDefinition(                language == SyntaxLanguage.HTML                    ? "HTML"                    : language == SyntaxLanguage.XAML                        ? "XML"                        : language == SyntaxLanguage.CSS                            ? "CSS"                            : "C#"            );            Roslyn.TextArea.TextEntering += TextArea_TextEntering;            CheckButton(SaveButton, true, save);            CheckButton(CopyButton, false, copy);            CheckButton(CutButton, false, cut);            CheckButton(PasteButton, false, paste);            CheckButton(UndoButton, false, undo);            CheckButton(RedoButton, false, redo);            CheckButton(PrintButton, true, print);            CheckButton(CompileButton, language == SyntaxLanguage.CSharp || language == SyntaxLanguage.XAML, compile);            CheckButton(RunButton, false, run);            var timer = new DispatcherTimer();            timer.Interval = TimeSpan.FromMilliseconds(500);            timer.Tick += Timer_Tick;            timer.Start();            bChanged = false;        }        public string Script => Roslyn.Text;        public Dictionary<string, string[]> Snippets        {            get => _snippets;            set            {                _snippets = value;                if (_snippets != null && _snippets.Any())                {                    SnippetPanel.Visibility = Visibility.Visible;                    SnippetSection.ItemsSource = _snippets.Keys;                    SnippetSection.SelectedValue = _snippets.Keys.First();                }                else                {                    SnippetPanel.Visibility = Visibility.Collapsed;                }            }        }        private bool bChanged        {            get => _bChanged;            set            {                _bChanged = value;                UpdateTitle();            }        }        private static Dictionary<bool, Image> SetupImage(Bitmap bitmap)        {            return new Dictionary<bool, Image>            {                { true, new Image { Source = bitmap.AsBitmapImage(), MaxHeight = 32, MaxWidth = 32 } },                { false, new Image { Source = bitmap.AsGrayScale().AsBitmapImage(), MaxHeight = 32, MaxWidth = 32 } }            };        }        private event EventHandler _onSave;        public event EventHandler OnSave        {            add            {                _onSave += value;                SaveButton.ToolTip = "Save";            }            remove            {                _onSave -= value;                if (_onSave == null) SaveButton.ToolTip = "Save & Close";            }        }        private event EventHandler _onCompile;        public event EventHandler OnCompile        {            add            {                _onCompile += value;                CheckButton(CompileButton, true, compile);            }            remove => _onCompile -= value;        }        private void CheckButton(Button button, bool condition, Dictionary<bool, Image> images)        {            if (button.Visibility != Visibility.Visible)                button.Visibility = Visibility.Visible;            if (condition != button.IsEnabled)            {                button.IsEnabled = condition;                button.Content = images[condition];            }        }        private void UpdateTitle()        {            if (bChanged)            {                Title = _editorTitle + "*";            }            else            {                Title = _editorTitle;            }        }        #region Public Interface        public ScriptEditor ClearErrors()        {            Errors.Items.Clear();            return this;        }        public ScriptEditor AddError(string error)        {            Errors.Items.Add(error);            return this;        }        public void Save()        {            bChanged = false;            if (_onSave != null)            {                _onSave?.Invoke(this, EventArgs.Empty);            }            else            {                DialogResult = true;                Close();            }        }        #endregion        #region Event Handlers        private void TextArea_TextEntering(object sender, TextCompositionEventArgs e)        {            if (string.Equals(e.Text, "\r"))                e.Handled = true;        }        private void OnLoaded(object sender, RoutedEventArgs e)        {            if (_language == SyntaxLanguage.CSharp || _language == SyntaxLanguage.XAML)            {                Roslyn.DataContext = new ScriptDocument(_script);            }            else            {                Roslyn.Text = _script;                bChanged = false;            }            //Roslyn.Text = _script;            //Changed = DateTime.MinValue;        }        private void Roslyn_Loaded(object sender, RoutedEventArgs e)        {            var editor = (RoslynCodeEditor)sender;            editor.Focus();            if (_language == SyntaxLanguage.CSharp || _language == SyntaxLanguage.XAML)            {                var changed = bChanged;                var script = (ScriptDocument)editor.DataContext;                script.Id = editor.Initialize(                    ScriptDocument.Host,                    new ClassificationHighlightColors(),                    Directory.GetCurrentDirectory(),                    _script,                    SourceCodeKind.Regular                );                bChanged = changed;            }        }        private void Roslyn_PreviewKeyDown(object sender, KeyEventArgs e)        {            if (bCompiled)            {                bCompiled = false;                CheckButton(RunButton, false, run);            }        }        private void Roslyn_TextChanged(object sender, EventArgs e)        {            bChanged = true;            if (bCompiled)            {                bCompiled = false;                CheckButton(RunButton, false, run);            }        }        private void Timer_Tick(object sender, EventArgs e)        {            CheckButton(CopyButton, !string.IsNullOrEmpty(Roslyn.SelectedText), copy);            CheckButton(CutButton, !string.IsNullOrEmpty(Roslyn.SelectedText), cut);            CheckButton(PasteButton, Clipboard.ContainsText(), paste);            CheckButton(UndoButton, Roslyn.CanUndo, undo);            CheckButton(RedoButton, Roslyn.CanRedo, redo);        }        private void OKButton_Click(object sender, RoutedEventArgs e)        {            DialogResult = true;            Close();        }        private void CancelButton_Click(object sender, RoutedEventArgs e)        {            DialogResult = false;            Close();        }        private void CompileButton_Click(object sender, RoutedEventArgs e)        {            CheckButton(RunButton, false, run);            if (_onCompile != null)            {                _onCompile.Invoke(this, EventArgs.Empty);            }            else            {                var viewModel = (ScriptDocument)Roslyn.DataContext;                viewModel.Text = Roslyn.Text;                Errors.Items.Clear();                Errors.Items.Add("Compiling Script... ");                Task.Run(() =>                {                    bCompiled = viewModel.Compile();                    Dispatcher.Invoke(() =>                    {                        Errors.Items.Clear();                        if (bCompiled)                        {                            Errors.Items.Add("Script Compiled Successfully!");                        }                        else                        {                            var errors = viewModel.Result.Split(new[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries);                            errors.ForEach(x => Errors.Items.Add(x));                        }                        CheckButton(RunButton, bCompiled, run);                    });                });            }        }        private void RunButton_Click(object sender, RoutedEventArgs e)        {            var viewModel = (ScriptDocument)Roslyn.DataContext;            try            {                var result = viewModel.Execute();            }            catch (Exception err)            {                MessageBox.Show(CoreUtils.FormatException(err));            }        }        private void GotoLine(string line)        {            if (line.StartsWith("("))            {                var sLine = line.Substring(1).Split(',')[0];                var iLine = int.Parse(sLine);                Roslyn.ScrollToLine(iLine);            }        }        private void Errors_SelectionChanged(object sender, SelectionChangedEventArgs e)        {            if (e.AddedItems.Count == 1) GotoLine(e.AddedItems[0].ToString());        }        private void Errors_PreviewMouseDown(object sender, MouseButtonEventArgs e)        {            if (Errors.SelectedItems.Count == 1) GotoLine(Errors.SelectedItems[0].ToString());        }        private void Window_Closing(object sender, CancelEventArgs e)        {            if (bChanged)            {                var bRes = MessageBox.Show("Script has changed.  Do you wish to save this script before closing?", "Save Changes",                    MessageBoxButton.YesNoCancel);                if (bRes == MessageBoxResult.Cancel)                {                    e.Cancel = true;                    return;                }                if (bRes == MessageBoxResult.Yes) _onSave?.Invoke(this, EventArgs.Empty);                try                {                    DialogResult = bRes == MessageBoxResult.Yes;                }                catch (InvalidOperationException)                {                    // Do nothing, just avoids a crash when closing a script editor which was opened by Show();                }            }        }        private void SaveButton_Click(object sender, RoutedEventArgs e)        {            Save();        }        private void CopyButton_Click(object sender, RoutedEventArgs e)        {            Roslyn.Copy();        }        private void CutButton_Click(object sender, RoutedEventArgs e)        {            Roslyn.Cut();        }        private void PasteButton_Click(object sender, RoutedEventArgs e)        {            Roslyn.Paste();        }        private void UndoButton_Click(object sender, RoutedEventArgs e)        {            Roslyn.Undo();        }        private void RedoButton_Click(object sender, RoutedEventArgs e)        {            Roslyn.Redo();        }        private void PrintButton_Click(object sender, RoutedEventArgs e)        {            //Syncfusion.Windows.Edit.EditCommands.PrintPreview.Execute(null, Edit1);        }        private void Snippets_MouseDoubleClick(object sender, MouseButtonEventArgs e)        {            Roslyn.SelectedText = SnippetList.SelectedValue.ToString();        }        private void SnippetSection_SelectionChanged(object sender, SelectionChangedEventArgs e)        {            if (e.AddedItems.Count == 1)                SnippetList.ItemsSource = _snippets[e.AddedItems[0].ToString()];            else                SnippetList.ItemsSource = null;        }        private void SaveCommandBinding_Executed(object sender, ExecutedRoutedEventArgs e)        {            if (_onSave != null)            {                bChanged = false;                _onSave?.Invoke(this, EventArgs.Empty);            }        }        private void SaveCommandBinding_CanExecute(object sender, CanExecuteRoutedEventArgs e)        {            e.CanExecute = _onSave != null;        }        #endregion    }}
 |