diff options
| author | Roy Ben Shabat <Roy.mail.net@gmail.com> | 2020-04-23 17:55:12 +0300 |
|---|---|---|
| committer | Roy Ben Shabat <Roy.mail.net@gmail.com> | 2020-04-23 17:55:12 +0300 |
| commit | 4c0712fb9ac9ea65b0c66c16639f847307c84f98 (patch) | |
| tree | 9e847a9cf6b92fe53c01cffed83d75195b870eef /Software/Visual_Studio | |
| parent | a440c6477a12a263969a507c2178981642ffb457 (diff) | |
| download | Tango-4c0712fb9ac9ea65b0c66c16639f847307c84f98.tar.gz Tango-4c0712fb9ac9ea65b0c66c16639f847307c84f98.zip | |
Improvements on test designer.
Diffstat (limited to 'Software/Visual_Studio')
11 files changed, 486 insertions, 111 deletions
diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/Contracts/ITestDesignerView.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/Contracts/ITestDesignerView.cs index bba69bac1..ea87a4f19 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/Contracts/ITestDesignerView.cs +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/Contracts/ITestDesignerView.cs @@ -10,5 +10,6 @@ namespace Tango.FSE.Stubs.Contracts public interface ITestDesignerView : IFSEView { void FormatCode(); + void HighlightCode(int position, int length); } } diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/Dialogs/AddReferenceAssemblyViewVM.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/Dialogs/AddReferenceAssemblyViewVM.cs index aa32f6a03..cee06ed91 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/Dialogs/AddReferenceAssemblyViewVM.cs +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/Dialogs/AddReferenceAssemblyViewVM.cs @@ -17,6 +17,8 @@ namespace Tango.FSE.Stubs.Dialogs { public class AddReferenceAssemblyViewVM : FSEDialogViewVM { + private List<ReferenceAssembly> _existing; + [TangoInject] private IFSEApplicationManager ApplicationManager { get; set; } @@ -24,42 +26,53 @@ namespace Tango.FSE.Stubs.Dialogs public AddReferenceAssemblyViewVM(List<ReferenceAssembly> existing) { + _existing = existing; OKText = "DONE"; - TangoIOC.Default.Inject(this); + } - List<ReferenceAssembly> source = new List<ReferenceAssembly>(); - - var startPath = ApplicationManager.StartPath; + public override void OnShow() + { + base.OnShow(); - foreach (var file in Directory.GetFiles(startPath, "*.dll")) + Task.Factory.StartNew(() => { - if (Path.GetFileName(file).StartsWith("Tango")) + System.Threading.Thread.Sleep(200); + List<ReferenceAssembly> source = new List<ReferenceAssembly>(); + + var startPath = ApplicationManager.StartPath; + + foreach (var file in Directory.GetFiles(startPath, "*.dll")) { - source.Add(ReferenceAssembly.FromFile(Path.GetFileName(file))); + if (Path.GetFileName(file).StartsWith("Tango")) + { + source.Add(ReferenceAssembly.FromFile(Path.GetFileName(file))); + } } - } - String dotNetPath = AssemblyHelper.GetAssemblyTargetFrameworkFolder(Assembly.GetExecutingAssembly()); + String dotNetPath = AssemblyHelper.GetAssemblyTargetFrameworkFolder(Assembly.GetExecutingAssembly()); - foreach (var file in Directory.GetFiles(dotNetPath, "*.dll")) - { - source.Add(ReferenceAssembly.FromFile(Path.GetFileName(file))); - } + foreach (var file in Directory.GetFiles(dotNetPath, "*.dll")) + { + source.Add(ReferenceAssembly.FromFile(Path.GetFileName(file))); + } - source = source.DistinctBy(x => x.Name).ToList(); + source = source.DistinctBy(x => x.Name).ToList(); - List<ReferenceAssembly> existingReferences = new List<ReferenceAssembly>(); + List<ReferenceAssembly> existingReferences = new List<ReferenceAssembly>(); - foreach (var asm in source) - { - if (existing.Exists(x => x.Name == asm.Name)) + foreach (var asm in source) { - existingReferences.Add(asm); + if (_existing.Exists(x => x.Name == asm.Name)) + { + existingReferences.Add(asm); + } } - } - ReferenceAssemblies = new SelectedObjectCollection<ReferenceAssembly>(source.ToObservableCollection(), existingReferences.ToObservableCollection()); + ReferenceAssemblies = new SelectedObjectCollection<ReferenceAssembly>(source.ToObservableCollection(), existingReferences.ToObservableCollection()); + + RaisePropertyChanged(nameof(ReferenceAssemblies)); + }); } } } diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/TestProject.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/TestProject.cs index 1600c9752..0bb4783dd 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/TestProject.cs +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/TestProject.cs @@ -1,4 +1,5 @@ using Google.Protobuf; +using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Collections.ObjectModel; @@ -14,8 +15,19 @@ namespace Tango.FSE.Stubs { public class TestProject : Project<TestContext> { + private static JsonSerializerSettings _jsonSettings; + public ObservableCollection<TestInput> Inputs { get; set; } + static TestProject() + { + _jsonSettings = new JsonSerializerSettings() + { + TypeNameHandling = TypeNameHandling.Auto, + PreserveReferencesHandling = PreserveReferencesHandling.All, + }; + } + public TestProject() : base() { Inputs = new ObservableCollection<TestInput>(); @@ -41,5 +53,15 @@ namespace Tango.FSE.Stubs return project; } + + public String ToJson() + { + return JsonConvert.SerializeObject(this, _jsonSettings); + } + + public static TestProject FromJson(String json) + { + return JsonConvert.DeserializeObject<TestProject>(json, _jsonSettings); + } } } diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/ViewModels/TestDesignerViewVM.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/ViewModels/TestDesignerViewVM.cs index e1fc8c539..1550da2ed 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/ViewModels/TestDesignerViewVM.cs +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/ViewModels/TestDesignerViewVM.cs @@ -1,7 +1,9 @@ using Google.Protobuf; +using MaterialDesignThemes.Wpf; using System; using System.Collections.Generic; using System.Collections.ObjectModel; +using System.IO; using System.Linq; using System.Reflection; using System.Text; @@ -35,6 +37,10 @@ namespace Tango.FSE.Stubs.ViewModels } private DispatcherTimer _compileTimer; + private String _projectFile; + private String PROJECT_FILE_EXTENSION = ".tproj"; + private String PROJECT_DIALOG_FILTER = $"Test Project Files|*.tproj"; + private bool _isProjectChanged; #region Properties @@ -126,6 +132,14 @@ namespace Tango.FSE.Stubs.ViewModels public RelayCommand AddProjectInputCommand { get; set; } public RelayCommand<TestInput> RemoveProjectInputCommand { get; set; } public RelayCommand FormatCodeCommand { get; set; } + public RelayCommand<CompilationError> HighlightErrorCommand { get; set; } + public RelayCommand NewProjectCommand { get; set; } + public RelayCommand SaveProjectCommand { get; set; } + public RelayCommand SaveAsProjectCommand { get; set; } + public RelayCommand OpenProjectCommand { get; set; } + public RelayCommand AddLibraryCommand { get; set; } + public RelayCommand<Script> DeleteLibraryCommand { get; set; } + public RelayCommand ClearOutputCommand { get; set; } #endregion @@ -136,7 +150,7 @@ namespace Tango.FSE.Stubs.ViewModels Status = "Ready"; LoadedAssemblies = new ObservableCollection<Assembly>(); - + Results = new List<Result>(); CompilationErrors = new List<CompilationError>(); Logger = new TextController(); ScriptEditor.LoadingSymbolsProgress += ScriptEditor_LoadingSymbolsProgress; @@ -156,18 +170,52 @@ namespace Tango.FSE.Stubs.ViewModels AddProjectInputCommand = new RelayCommand(AddProjectInput); RemoveProjectInputCommand = new RelayCommand<TestInput>(RemoveProjectInput); FormatCodeCommand = new RelayCommand(FormatCode); + HighlightErrorCommand = new RelayCommand<CompilationError>(HighlightError); + NewProjectCommand = new RelayCommand(CreateNewProject, () => ProjectRunner == null || !ProjectRunner.IsRunning); + SaveProjectCommand = new RelayCommand(SaveProject); + SaveAsProjectCommand = new RelayCommand(SaveAsProject); + OpenProjectCommand = new RelayCommand(OpenProject); + AddLibraryCommand = new RelayCommand(AddNewLibrary); + ClearOutputCommand = new RelayCommand(ClearOutput); + DeleteLibraryCommand = new RelayCommand<Script>(DeleteLibrary); + } + + private void HighlightError(CompilationError error) + { + var errorScript = Project.Scripts.SingleOrDefault(x => x.Name == error.File); + + if (errorScript != null) + { + OpenScript(errorScript); + View.HighlightCode(error.Position, error.Length); + } + } + + private void FormatCode() + { + View.FormatCode(); + } + + #endregion + #region Override Methods + + public override void OnApplicationStarted() + { _compileTimer = new DispatcherTimer(DispatcherPriority.ApplicationIdle); _compileTimer.Interval = TimeSpan.FromSeconds(2); _compileTimer.Tick += _compileTimer_Tick; _compileTimer.Start(); - - CreateNewProject(); } - private void FormatCode() + public override void OnNavigatedTo() { - View.FormatCode(); + base.OnNavigatedTo(); + + if (Project == null) + { + CreateStartupProject(); + } } #endregion @@ -293,6 +341,12 @@ namespace Tango.FSE.Stubs.ViewModels SelectedScript = script; } + private void ClearOpenedScripts() + { + OpenScripts.Clear(); + SelectedScript = null; + } + #endregion #region Event Handlers @@ -337,22 +391,130 @@ namespace Tango.FSE.Stubs.ViewModels Project.ReferenceAssemblies.Add(asm); } + _isProjectChanged = true; + LoadReferenceAssemblies(); } } - private void CreateNewProject() + private async void CreateNewProject() { - Project = TestProject.New("test1"); - LoadReferenceAssemblies(); + if (await CheckDiscardProjectChanges()) + { + var result = await NotificationProvider.ShowInputBox("New Project", "Please specify the project name", PackIconKind.TestTube, "untitled", "Project Name", 100, "CREATE"); + if (result.Confirmed) + { + Project = TestProject.New(result.Input); + _projectFile = null; + } + } + } + + private void CreateStartupProject() + { + Project = TestProject.New("untitled"); + _projectFile = null; + } + + private void SaveProject() + { + if (Project != null) + { + if (_projectFile == null) + { + SaveAsProject(); + return; + } + + try + { + Status = "Saving project..."; + + File.WriteAllText(_projectFile, Project.ToJson()); + + Status = "Project saved."; + + Project.Scripts.ToList().ForEach(x => x.IsChanged = false); + } + catch (Exception ex) + { + NotificationProvider.ShowError($"Error saving project\n{ex.FlattenMessage()}"); + Status = "Ready"; + } + } + } + + private async void SaveAsProject() + { + if (Project != null) + { + var result = await StorageProvider.SaveFile("Save As Project", PROJECT_DIALOG_FILTER, Project.Name, PROJECT_FILE_EXTENSION); + + if (result) + { + try + { + Status = "Saving project..."; + + File.WriteAllText(result.SelectedItem, Project.ToJson()); + _projectFile = result.SelectedItem; + + Status = "Project saved."; + + Project.Scripts.ToList().ForEach(x => x.IsChanged = false); + } + catch (Exception ex) + { + await NotificationProvider.ShowError($"Error saving project\n{ex.FlattenMessage()}"); + Status = "Ready"; + } + } + } + } + + private async void AddNewLibrary() + { + var result = await NotificationProvider.ShowInputBox("New Library File", "Please specify the library name", PackIconKind.Script, "MyLibrary", "Library Name", 100, "ADD LIBRARY"); + + if (result.Confirmed) + { + if (Project.Scripts.Any(x => x.Name.ToLower() == result.Input.ToLower() + ".csx")) + { + await NotificationProvider.ShowError($"The project already contains a file named '{result.Input}'."); + return; + } + + try + { + var lib = Script.New(result.Input.ToTitleCase() + ".csx", Encoding.UTF8.GetString(Properties.Resources.lib_template)); + Project.Scripts.Add(lib); + _isProjectChanged = true; + OpenScript(lib); + } + catch (Exception ex) + { + LogManager.Log(ex, "Error adding new library to test project."); + await NotificationProvider.ShowError($"Could not add a new script to the project.\n{ex.FlattenMessage()}"); + } + } } private void OnProjectChanged() { if (Project != null) { + _isProjectChanged = false; + LoadReferenceAssemblies(); ProjectRunner = new ProjectRunner(Project); ProjectRunner.StateChanged += ProjectRunner_StateChanged; + ClearOpenedScripts(); + + var programScript = Project.Scripts.SingleOrDefault(x => x.IsEntryPoint); + + if (programScript != null) + { + OpenScript(programScript); + } } else { @@ -367,12 +529,74 @@ namespace Tango.FSE.Stubs.ViewModels LoadedAssemblies = Project.LoadReferenceAssemblies().ToObservableCollection(); } + private async void OpenProject() + { + if (await CheckDiscardProjectChanges()) + { + var result = await StorageProvider.OpenFile("Open Test Project", PROJECT_DIALOG_FILTER); + + if (result) + { + OpenProject(result.SelectedItem); + } + } + } + + private void OpenProject(String file) + { + try + { + Project = TestProject.FromJson(File.ReadAllText(file)); + _projectFile = file; + Status = "Project loaded."; + } + catch (Exception ex) + { + LogManager.Log(ex, "Error opening test project."); + NotificationProvider.ShowError($"Error occurred while trying to open the project.\n{ex.FlattenMessage()}"); + } + } + + private async Task<bool> CheckDiscardProjectChanges() + { + if (Project != null && (Project.Scripts.Any(x => x.IsChanged) || _isProjectChanged)) + { + return await NotificationProvider.ShowWarningQuestion("The current project contains unsaved changes. Discard the changes?"); + } + else + { + return true; + } + } + private void RemoveReferenceAssembly(ReferenceAssembly assembly) { Project.ReferenceAssemblies.Remove(assembly); + _isProjectChanged = true; LoadedAssemblies = Project.LoadReferenceAssemblies().ToObservableCollection(); } + private void ClearOutput() + { + Logger.Clear(); + } + + private async void DeleteLibrary(Script script) + { + if (script.IsEntryPoint) + { + await NotificationProvider.ShowWarning("Entry point file cannot be deleted."); + return; + } + + if (await NotificationProvider.ShowWarningQuestion($"Are you sure you want to delete '{script.Name}'?")) + { + CloseScript(script); + Project.Scripts.Remove(script); + _isProjectChanged = true; + } + } + #endregion #region ITestLogger diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/Views/TestDesignerView.xaml b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/Views/TestDesignerView.xaml index 4d31b9083..9af2b777b 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/Views/TestDesignerView.xaml +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/Views/TestDesignerView.xaml @@ -4,6 +4,7 @@ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:global="clr-namespace:Tango.FSE.Stubs" + xmlns:helpers="clr-namespace:Tango.SharedUI.Helpers;assembly=Tango.SharedUI" xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" xmlns:components="clr-namespace:Tango.SharedUI.Components;assembly=Tango.SharedUI" xmlns:vm="clr-namespace:Tango.FSE.Stubs.ViewModels" @@ -21,6 +22,10 @@ <UserControl.InputBindings> <KeyBinding Key="F5" Command="{Binding RunProjectCommand}" /> <KeyBinding Key="F6" Command="{Binding CompileProjectCommand}" /> + <KeyBinding Modifiers="Ctrl" Key="S" Command="{Binding SaveProjectCommand}" /> + <KeyBinding Modifiers="Ctrl+Shift" Key="S" Command="{Binding SaveProjectCommand}" /> + <KeyBinding Modifiers="Ctrl" Key="N" Command="{Binding NewProjectCommand}" /> + <KeyBinding Modifiers="Ctrl" Key="O" Command="{Binding OpenProjectCommand}" /> </UserControl.InputBindings> <Grid> @@ -28,16 +33,33 @@ <DockPanel> <Menu IsMainMenu="True" DockPanel.Dock="Top"> <MenuItem Header="_File"> - <MenuItem Header="_New" MinWidth="250" Command="{Binding NewProjectCommand}"> + <MenuItem Header="_New" MinWidth="250" Command="{Binding NewProjectCommand}" InputGestureText="Ctrl+N"> <MenuItem.Icon> <material:PackIcon Kind="FileDocument" /> </MenuItem.Icon> </MenuItem> - <MenuItem Header="_Open" Command="{Binding OpenProjectCommand}"> + <MenuItem Header="_Open" Command="{Binding OpenProjectCommand}" InputGestureText="Ctrl+O"> <MenuItem.Icon> <material:PackIcon Kind="FileEdit" /> </MenuItem.Icon> </MenuItem> + <Separator/> + <MenuItem Header="_Save" Command="{Binding SaveProjectCommand}" InputGestureText="Ctrl+S"> + <MenuItem.Icon> + <material:PackIcon Kind="ContentSave" /> + </MenuItem.Icon> + </MenuItem> + <MenuItem Header="_Save As" Command="{Binding SaveAsProjectCommand}" InputGestureText="Ctrl+Shift+S"> + <MenuItem.Icon> + <material:PackIcon Kind="ContentSaveAll" /> + </MenuItem.Icon> + </MenuItem> + <Separator/> + <MenuItem Header="Add Library" Command="{Binding AddLibraryCommand}"> + <MenuItem.Icon> + <material:PackIcon Kind="ScriptText" /> + </MenuItem.Icon> + </MenuItem> </MenuItem> <MenuItem Header="_Edit"> <MenuItem MinWidth="250" Header="_Undo" Command="Undo"> @@ -96,8 +118,8 @@ <Grid DockPanel.Dock="Top"> <!--Toolbar--> <ToolBar ClipToBounds="False" Background="Transparent" HorizontalAlignment="Center" ToolBarTray.IsLocked="True"> - <Button ToolTip="Save"> - <material:PackIcon Kind="ContentSave" /> + <Button ToolTip="Save" Command="{Binding SaveProjectCommand}"> + <material:PackIcon Kind="ContentSave" /> </Button> <Separator /> <Button Command="Undo" ToolTip="Undo" ToolBar.OverflowMode="AsNeeded"> @@ -287,9 +309,15 @@ <!--Output & Error Tabs--> <TabControl SelectedIndex="{Binding SelectedToolWindow,Mode=TwoWay,Converter={StaticResource EnumToIntConverter}}" ItemContainerStyle="{StaticResource FSE_TabItem_VisualStudio_Output}" TabStripPlacement="Bottom" Margin="0" Background="{StaticResource FSE_PrimaryBackgroundDarkBrush}" BorderThickness="0"> <TabItem Header="OUTPUT"> - <TextBox HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto" Padding="5" Style="{x:Null}" Foreground="{StaticResource FSE_PrimaryForegroundBrush}" FontFamily="Consolas" components:TextController.Controller="{Binding Logger}" FontSize="{StaticResource FSE_SmallFontSize}" Background="{StaticResource FSE_PrimaryBackgroundDarkBrush}" BorderThickness="0" AcceptsReturn="True" IsReadOnly="True"> + <DockPanel> + <Grid DockPanel.Dock="Top" Height="28" Background="{StaticResource FSE_PrimaryBackgroundBrush}"> + <TextBlock VerticalAlignment="Center" Margin="5 0 0 0" FontFamily="{StaticResource hand}">Output</TextBlock> + <controls:IconButton Height="32" Cursor="Hand" ToolTip="Clear" Width="32" Icon="DeleteEmpty" Foreground="{StaticResource FSE_GrayBrush}" HorizontalAlignment="Right" VerticalAlignment="Center" /> - </TextBox> + <Rectangle VerticalAlignment="Bottom" Stroke="Black" StrokeThickness="2" /> + </Grid> + <TextBox HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto" Padding="5" Style="{x:Null}" Foreground="{StaticResource FSE_PrimaryForegroundBrush}" FontFamily="Consolas" components:TextController.Controller="{Binding Logger}" FontSize="{StaticResource FSE_SmallFontSize}" Background="{StaticResource FSE_PrimaryBackgroundDarkBrush}" BorderThickness="0" AcceptsReturn="True" IsReadOnly="True" TextWrapping="Wrap" /> + </DockPanel> </TabItem> <TabItem> <TabItem.Header> @@ -298,21 +326,33 @@ <Run>(</Run><Run Text="{Binding CompilationErrors.Count,Mode=OneWay}"></Run><Run>)</Run> </TextBlock> </TabItem.Header> - <DataGrid ItemsSource="{Binding CompilationErrors}" Style="{StaticResource FSE_LogsGridStyle}" CellStyle="{StaticResource FSE_LogsGridCellStyle}" HorizontalGridLinesBrush="{StaticResource FSE_PrimaryBackgroundBrush}" AutoGenerateColumns="False"> - <DataGrid.Columns> - <DataGridTemplateColumn Width="40"> - <DataGridTemplateColumn.CellTemplate> - <DataTemplate> - <material:PackIcon HorizontalAlignment="Center" VerticalAlignment="Center" Kind="Alert" Foreground="{StaticResource FSE_ErrorBrush}" /> - </DataTemplate> - </DataGridTemplateColumn.CellTemplate> - </DataGridTemplateColumn> - <DataGridTextColumn Header="DESCRIPTION" Binding="{Binding Message}" Width="1*" /> - <DataGridTextColumn Header="FILE" Binding="{Binding File}" /> - <DataGridTextColumn Header="LINE" Binding="{Binding Line}" /> - <DataGridTextColumn Header="COL" Binding="{Binding Column}" /> - </DataGrid.Columns> - </DataGrid> + <DockPanel> + <Grid DockPanel.Dock="Top" Height="28" Background="{StaticResource FSE_PrimaryBackgroundBrush}"> + <TextBlock VerticalAlignment="Center" Margin="5 0 0 0" FontFamily="{StaticResource hand}">Errors</TextBlock> + + <Rectangle VerticalAlignment="Bottom" Stroke="Black" StrokeThickness="2" /> + </Grid> + <DataGrid ItemsSource="{Binding CompilationErrors}" + Style="{StaticResource FSE_LogsGridStyle}" + CellStyle="{StaticResource FSE_LogsGridCellStyle}" + HorizontalGridLinesBrush="{StaticResource FSE_PrimaryBackgroundBrush}" + helpers:DataGridHelper.DoubleClickCommand="{Binding HighlightErrorCommand}" + AutoGenerateColumns="False"> + <DataGrid.Columns> + <DataGridTemplateColumn Width="40"> + <DataGridTemplateColumn.CellTemplate> + <DataTemplate> + <material:PackIcon HorizontalAlignment="Center" VerticalAlignment="Center" Kind="Alert" Foreground="{StaticResource FSE_ErrorBrush}" /> + </DataTemplate> + </DataGridTemplateColumn.CellTemplate> + </DataGridTemplateColumn> + <DataGridTextColumn Header="DESCRIPTION" Binding="{Binding Message}" Width="1*" /> + <DataGridTextColumn Header="FILE" Binding="{Binding File}" /> + <DataGridTextColumn Header="LINE" Binding="{Binding Line}" /> + <DataGridTextColumn Header="COL" Binding="{Binding Column}" /> + </DataGrid.Columns> + </DataGrid> + </DockPanel> </TabItem> <TabItem> <TabItem.Header> @@ -322,30 +362,36 @@ </TextBlock> </TabItem.Header> - <ScrollViewer HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto"> - <StackPanel HorizontalAlignment="Left" TextElement.Foreground="{StaticResource FSE_PrimaryForegroundBrush}"> - <ItemsControl ItemsSource="{Binding Project.Inputs}"> - <ItemsControl.ItemTemplate> - <DataTemplate> - <DockPanel Margin="15"> - <material:PackIcon Kind="Key" VerticalAlignment="Bottom" Margin="0 0 0 5" /> - <controls:IconButton VerticalAlignment="Bottom" DockPanel.Dock="Right" Margin="40 0 0 0" Icon="Close" Foreground="{StaticResource FSE_RedBrush}" ToolTip="Delete input" Command="{Binding RelativeSource={RelativeSource AncestorType=UserControl},Path=DataContext.RemoveProjectInputCommand}" CommandParameter="{Binding}"></controls:IconButton> - <DockPanel Margin="10 0 0 0" Width="100"> - <TextBlock Margin="2 0 0 2" DockPanel.Dock="Top" FontSize="{StaticResource FSE_SmallerFontSize}">Key</TextBlock> - <TextBox Style="{StaticResource FSE_Rounded_Corners_TextBox}" Text="{Binding Key}"></TextBox> - </DockPanel> - <DockPanel Margin="40 0 0 0" Width="500"> - <TextBlock Margin="2 0 0 2" DockPanel.Dock="Top" FontSize="{StaticResource FSE_SmallerFontSize}">Value</TextBlock> - <TextBox Style="{StaticResource FSE_Rounded_Corners_TextBox}" Text="{Binding Value}"></TextBox> + <DockPanel> + <Grid DockPanel.Dock="Top" Height="28" Background="{StaticResource FSE_PrimaryBackgroundBrush}"> + <TextBlock VerticalAlignment="Center" Margin="5 0 0 0" FontFamily="{StaticResource hand}">Inputs</TextBlock> + <controls:IconButton VerticalAlignment="Center" HorizontalAlignment="Right" Command="{Binding AddProjectInputCommand}" Icon="Add" Foreground="{StaticResource FSE_GrayBrush}" Cursor="Hand" ToolTip="Add input">Add Input</controls:IconButton> + <Rectangle VerticalAlignment="Bottom" Stroke="Black" StrokeThickness="2" /> + </Grid> + <ScrollViewer HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto"> + <StackPanel HorizontalAlignment="Left" TextElement.Foreground="{StaticResource FSE_PrimaryForegroundBrush}"> + <ItemsControl ItemsSource="{Binding Project.Inputs}"> + <ItemsControl.ItemTemplate> + <DataTemplate> + <DockPanel Margin="15"> + <material:PackIcon Kind="Key" VerticalAlignment="Bottom" Margin="0 0 0 5" /> + <controls:IconButton VerticalAlignment="Bottom" DockPanel.Dock="Right" Margin="40 0 0 0" Icon="Close" Foreground="{StaticResource FSE_RedBrush}" ToolTip="Delete input" Command="{Binding RelativeSource={RelativeSource AncestorType=UserControl},Path=DataContext.RemoveProjectInputCommand}" CommandParameter="{Binding}"></controls:IconButton> + <DockPanel Margin="10 0 0 0" Width="100"> + <TextBlock Margin="2 0 0 2" DockPanel.Dock="Top" FontSize="{StaticResource FSE_SmallerFontSize}">Key</TextBlock> + <TextBox Style="{StaticResource FSE_Rounded_Corners_TextBox}" Text="{Binding Key}"></TextBox> + </DockPanel> + <material:PackIcon Kind="Equal" VerticalAlignment="Bottom" Margin="20 0 20 5" /> + <DockPanel Width="500"> + <TextBlock Margin="2 0 0 2" DockPanel.Dock="Top" FontSize="{StaticResource FSE_SmallerFontSize}">Value</TextBlock> + <TextBox Style="{StaticResource FSE_Rounded_Corners_TextBox}" Text="{Binding Value}"></TextBox> + </DockPanel> </DockPanel> - </DockPanel> - </DataTemplate> - </ItemsControl.ItemTemplate> - </ItemsControl> - - <controls:IconButton HorizontalAlignment="Left" Command="{Binding AddProjectInputCommand}" Icon="Add" Foreground="{StaticResource FSE_GreenBrush}" ToolTip="Add input">Add Input</controls:IconButton> - </StackPanel> - </ScrollViewer> + </DataTemplate> + </ItemsControl.ItemTemplate> + </ItemsControl> + </StackPanel> + </ScrollViewer> + </DockPanel> </TabItem> <TabItem> <TabItem.Header> @@ -354,39 +400,55 @@ <Run>(</Run><Run Text="{Binding Results.Count,Mode=OneWay}"></Run><Run>)</Run> </TextBlock> </TabItem.Header> - <DataGrid ItemsSource="{Binding Results}" Style="{StaticResource FSE_LogsGridStyle}" CellStyle="{StaticResource FSE_LogsGridCellStyle}" HorizontalGridLinesBrush="{StaticResource FSE_PrimaryBackgroundBrush}" AutoGenerateColumns="False"> - <DataGrid.Columns> - <DataGridTemplateColumn Width="40"> - <DataGridTemplateColumn.CellTemplate> - <DataTemplate> - <material:PackIcon HorizontalAlignment="Center" VerticalAlignment="Center"> - <material:PackIcon.Style> - <Style TargetType="material:PackIcon"> - <Setter Property="Kind" Value="Check"></Setter> - <Setter Property="Foreground" Value="{StaticResource FSE_SuccessBrush}"></Setter> - <Style.Triggers> - <DataTrigger Binding="{Binding Type}" Value="Warning"> - <Setter Property="Kind" Value="Alert"></Setter> - <Setter Property="Foreground" Value="{StaticResource FSE_WarningBrush}"></Setter> - </DataTrigger> - <DataTrigger Binding="{Binding Type}" Value="Failed"> - <Setter Property="Kind" Value="Alert"></Setter> - <Setter Property="Foreground" Value="{StaticResource FSE_ErrorBrush}"></Setter> - </DataTrigger> - </Style.Triggers> - </Style> - </material:PackIcon.Style> - </material:PackIcon> - </DataTemplate> - </DataGridTemplateColumn.CellTemplate> - </DataGridTemplateColumn> - <DataGridTextColumn Header="NAME" Binding="{Binding Name}" /> - <DataGridTextColumn Header="VALUE" Binding="{Binding Value}" Width="1*" /> - </DataGrid.Columns> - </DataGrid> + <DockPanel> + <Grid DockPanel.Dock="Top" Height="28" Background="{StaticResource FSE_PrimaryBackgroundBrush}"> + <TextBlock VerticalAlignment="Center" Margin="5 0 0 0" FontFamily="{StaticResource hand}">Results</TextBlock> + + <Rectangle VerticalAlignment="Bottom" Stroke="Black" StrokeThickness="2" /> + </Grid> + <DataGrid ItemsSource="{Binding Results}" Style="{StaticResource FSE_LogsGridStyle}" CellStyle="{StaticResource FSE_LogsGridCellStyle}" HorizontalGridLinesBrush="{StaticResource FSE_PrimaryBackgroundBrush}" AutoGenerateColumns="False"> + <DataGrid.Columns> + <DataGridTemplateColumn Width="40"> + <DataGridTemplateColumn.CellTemplate> + <DataTemplate> + <material:PackIcon HorizontalAlignment="Center" VerticalAlignment="Center"> + <material:PackIcon.Style> + <Style TargetType="material:PackIcon"> + <Setter Property="Kind" Value="Check"></Setter> + <Setter Property="Foreground" Value="{StaticResource FSE_SuccessBrush}"></Setter> + <Style.Triggers> + <DataTrigger Binding="{Binding Type}" Value="Warning"> + <Setter Property="Kind" Value="Alert"></Setter> + <Setter Property="Foreground" Value="{StaticResource FSE_WarningBrush}"></Setter> + </DataTrigger> + <DataTrigger Binding="{Binding Type}" Value="Failed"> + <Setter Property="Kind" Value="Alert"></Setter> + <Setter Property="Foreground" Value="{StaticResource FSE_ErrorBrush}"></Setter> + </DataTrigger> + </Style.Triggers> + </Style> + </material:PackIcon.Style> + </material:PackIcon> + </DataTemplate> + </DataGridTemplateColumn.CellTemplate> + </DataGridTemplateColumn> + <DataGridTextColumn Header="NAME" Binding="{Binding Name}" /> + <DataGridTextColumn Header="VALUE" Binding="{Binding Value}" Width="1*" /> + </DataGrid.Columns> + </DataGrid> + </DockPanel> </TabItem> <TabItem Header="PUBLISH"> + <DockPanel> + <Grid DockPanel.Dock="Top" Height="28" Background="{StaticResource FSE_PrimaryBackgroundBrush}"> + <TextBlock VerticalAlignment="Center" Margin="5 0 0 0" FontFamily="{StaticResource hand}">Publish</TextBlock> + <Rectangle VerticalAlignment="Bottom" Stroke="Black" StrokeThickness="2" /> + </Grid> + <Grid> + + </Grid> + </DockPanel> </TabItem> </TabControl> </Grid> @@ -420,7 +482,7 @@ <Setter Property="ContextMenu"> <Setter.Value> <ContextMenu> - <MenuItem Header="Remove" Command="{Binding Source={StaticResource proxy},Path=Data.RemoveReferenceAssemblyCommand}" CommandParameter="{Binding}"> + <MenuItem MinWidth="180" Header="Remove" Command="{Binding Source={StaticResource proxy},Path=Data.RemoveReferenceAssemblyCommand}" CommandParameter="{Binding}"> <MenuItem.Icon> <material:PackIcon Kind="Delete" Foreground="{StaticResource FSE_RedBrush}" /> </MenuItem.Icon> @@ -440,10 +502,22 @@ </ListBox.ItemTemplate> </ListBox> - <ListBox Margin="5 5 0 0" ItemsSource="{Binding Project.Scripts}" ScrollViewer.VerticalScrollBarVisibility="Disabled" ScrollViewer.HorizontalScrollBarVisibility="Disabled"> + <ListBox Margin="5 5 0 0" ItemsSource="{Binding Project.Scripts,Converter={StaticResource ObservableCollectionToViewSourceConverter},ConverterParameter='Name'}" ScrollViewer.VerticalScrollBarVisibility="Disabled" ScrollViewer.HorizontalScrollBarVisibility="Disabled"> <ListBox.ItemContainerStyle> <Style TargetType="ListBoxItem" BasedOn="{StaticResource {x:Type ListBoxItem}}"> <EventSetter Event="PreviewMouseDoubleClick" Handler="OnScriptItemDoubleClick"></EventSetter> + + <Setter Property="ContextMenu"> + <Setter.Value> + <ContextMenu> + <MenuItem MinWidth="180" IsEnabled="{Binding IsEntryPoint,Converter={StaticResource BooleanInverseConverter}}" Header="Delete" Command="{Binding Source={StaticResource proxy},Path=Data.DeleteLibraryCommand}" CommandParameter="{Binding}"> + <MenuItem.Icon> + <material:PackIcon Kind="Delete" Foreground="{StaticResource FSE_RedBrush}" /> + </MenuItem.Icon> + </MenuItem> + </ContextMenu> + </Setter.Value> + </Setter> </Style> </ListBox.ItemContainerStyle> <ListBox.ItemTemplate> diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/Views/TestDesignerView.xaml.cs b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/Views/TestDesignerView.xaml.cs index 5bd798cc0..3636f7d50 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/Views/TestDesignerView.xaml.cs +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.Stubs/Views/TestDesignerView.xaml.cs @@ -38,14 +38,20 @@ namespace Tango.FSE.Stubs.Views _vm.OpenScript((sender as FrameworkElement).DataContext as Script); } - public void FormatCode() + private ScriptEditor GetCurrentEditor() { var editor = tabControl.FindVisualChildren<ScriptEditor>().FirstOrDefault(x => x.IsVisible); + return editor; + } - if (editor != null) - { - editor.FormatCode(); - } + public void FormatCode() + { + GetCurrentEditor()?.FormatCode(); + } + + public void HighlightCode(int position, int length) + { + GetCurrentEditor()?.Highlight(position, length); } } } diff --git a/Software/Visual_Studio/FSE/Tango.FSE.Common/Resources/Converters.xaml b/Software/Visual_Studio/FSE/Tango.FSE.Common/Resources/Converters.xaml index 04d8dc416..4917f9426 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.Common/Resources/Converters.xaml +++ b/Software/Visual_Studio/FSE/Tango.FSE.Common/Resources/Converters.xaml @@ -36,4 +36,5 @@ <converters:StringToOneLineConverter x:Key="StringToOneLineConverter" /> <converters:FilePathToFileNameConverter x:Key="FilePathToFileNameConverter" /> <converters:EnumToIntConverter x:Key="EnumToIntConverter" /> + <converters:ObservableCollectionToViewSourceConverter x:Key="ObservableCollectionToViewSourceConverter" /> </ResourceDictionary>
\ No newline at end of file diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Basic/CompilationError.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Basic/CompilationError.cs index 27c710b2f..eda72fa6e 100644 --- a/Software/Visual_Studio/Scripting/Tango.Scripting.Basic/CompilationError.cs +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Basic/CompilationError.cs @@ -12,6 +12,7 @@ namespace Tango.Scripting.Basic public String File { get; set; } public String Message { get; set; } public DiagnosticSeverity Severity { get; set; } + public int Position { get; set; } public int Line { get; set; } public int Column { get; set; } public int Length { get; set; } diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Basic/Project.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Basic/Project.cs index 776c21e53..7abcbb42d 100644 --- a/Software/Visual_Studio/Scripting/Tango.Scripting.Basic/Project.cs +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Basic/Project.cs @@ -73,6 +73,7 @@ namespace Tango.Scripting.Basic foreach (var script in Scripts) { script.LoadCount = 0; + script.LoadCharCount = 0; String code = script.Code; String codeFile = Path.Combine(tempFolder, script.Name); @@ -82,6 +83,7 @@ namespace Tango.Scripting.Basic { loadingString = $"#load \"{file}\"\n"; script.LoadCount++; + script.LoadCharCount += loadingString.Length; } code = loadingString + code; @@ -132,6 +134,7 @@ namespace Tango.Scripting.Basic Script errorScript = Scripts.Single(x => x.Name == cError.File); cError.Message = error.GetMessage(); cError.Severity = error.Severity; + cError.Position = error.Location.SourceSpan.Start - (errorScript != null ? errorScript.LoadCharCount : 0); var line = error.Location.GetMappedLineSpan(); cError.Line = line.StartLinePosition.Line + 1 - (errorScript != null ? errorScript.LoadCount : 0); cError.Column = line.StartLinePosition.Character + 1; diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Basic/Script.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Basic/Script.cs index 753026149..69bc15468 100644 --- a/Software/Visual_Studio/Scripting/Tango.Scripting.Basic/Script.cs +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Basic/Script.cs @@ -13,9 +13,32 @@ namespace Tango.Scripting.Basic public class Script : ExtendedObject, IScriptSource { public String Name { get; set; } - public String Code { get; set; } public bool IsEntryPoint { get; set; } + private String _code; + public String Code + { + get { return _code; } + set + { + if (_code != null && _code != value) + { + IsChanged = true; + } + + _code = value; + RaisePropertyChangedAuto(); + } + } + + private bool _isChanged; + [JsonIgnore] + public bool IsChanged + { + get { return _isChanged; } + set { _isChanged = value; RaisePropertyChangedAuto(); } + } + private bool _isSelected; [JsonIgnore] public bool IsSelected @@ -26,6 +49,8 @@ namespace Tango.Scripting.Basic [JsonIgnore] public int LoadCount { get; internal set; } + [JsonIgnore] + public int LoadCharCount { get; set; } public static Script New(String file) { diff --git a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/ScriptEditor.cs b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/ScriptEditor.cs index 42103a1b1..d7d72ec0b 100644 --- a/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/ScriptEditor.cs +++ b/Software/Visual_Studio/Scripting/Tango.Scripting.Editors/ScriptEditor.cs @@ -2121,6 +2121,11 @@ namespace Tango.Scripting.Editors } } + public void Highlight(int position, int length) + { + Select(position, Math.Max(length, 1)); + } + #endregion } } |
