public void TestCustomCode() { var visualScript = new VisualScriptAsset(); // Build blocks var functionStart = new FunctionStartBlock(); var writeTrue = new CustomCodeBlock { Code = "System.Console.Write(true);" }; var method = new Method { Name = "Test" }; method.Blocks.Add(functionStart); method.Blocks.Add(writeTrue); // Generate slots foreach (var block in method.Blocks) { block.Value.GenerateSlots(block.Value.Slots, new SlotGeneratorContext()); } // Build links method.Links.Add(new Link(functionStart, writeTrue)); visualScript.Methods.Add(method); // Test TestAndCompareOutput(visualScript, "True", testInstance => testInstance.Test()); }
public void TestVariableGet() { var visualScript = new VisualScriptAsset(); var condition = new Property("bool", "Condition"); visualScript.Properties.Add(condition); // Build blocks // TODO: Switch to a simple Write(variable) later, so that we don't depend on ConditionalBranchBlock for this test? var functionStart = new FunctionStartBlock(); var conditionGet = new VariableGet { Name = condition.Name }; var conditionalBranch = new ConditionalBranchBlock(); var writeTrue = new CustomCodeBlock { Code = "System.Console.Write(true);" }; var writeFalse = new CustomCodeBlock { Code = "System.Console.Write(false);" }; var method = new Method { Name = "Test" }; method.Blocks.Add(functionStart); method.Blocks.Add(conditionGet); method.Blocks.Add(conditionalBranch); method.Blocks.Add(writeTrue); method.Blocks.Add(writeFalse); // Generate slots foreach (var block in method.Blocks) { block.Value.GenerateSlots(block.Value.Slots, new SlotGeneratorContext()); } // Build links method.Links.Add(new Link(functionStart, conditionalBranch)); method.Links.Add(new Link(conditionGet.ValueSlot, conditionalBranch.ConditionSlot)); method.Links.Add(new Link(conditionalBranch.TrueSlot, writeTrue)); method.Links.Add(new Link(conditionalBranch.FalseSlot, writeFalse)); visualScript.Methods.Add(method); // Test TestAndCompareOutput(visualScript, "True", testInstance => { testInstance.Condition = true; testInstance.Test(); }); TestAndCompareOutput(visualScript, "False", testInstance => { testInstance.Condition = false; testInstance.Test(); }); }
/// <summary> /// Adds extra adornments to Code Block, if it contains a Language. /// </summary> /// <param name="element">CodeBlock Element</param> /// <param name="context">Render Context</param> protected override void RenderCode(CodeBlock element, IRenderContext context) { // Renders the Code Block in the standard fashion. base.RenderCode(element, context); // Don't do any manipulations if the CodeLanguage isn't specified. if (string.IsNullOrWhiteSpace(element.CodeLanguage)) { return; } // Unify all Code Language headers for C#. var language = element.CodeLanguage.ToUpper(); switch (language) { case "CSHARP": case "CS": language = "C#"; break; } // Grab the Local context and cast it. var localContext = context as UIElementCollectionRenderContext; var collection = localContext?.BlockUIElementCollection; // Don't go through with it, if there is an issue with the context or collection. if (localContext == null || collection?.Any() != true) { return; } var lastIndex = collection.Count() - 1; var prevIndex = lastIndex - 1; // Removes the current Code Block UI from the UI Collection, and wraps it in additional UI. if (collection[lastIndex] is ScrollViewer viewer) { collection.RemoveAt(lastIndex); // Combine Code Blocks if a Different Language. if (language != "XAML" && prevIndex >= 0 && collection[prevIndex] is StackPanel prevPanel && prevPanel.Tag is CustomCodeBlock block && !block.Languages.ContainsKey("XAML") && // Prevent combining of XAML Code Blocks. !block.Languages.ContainsKey(language)) { // Add New Lang to Existing Block #pragma warning disable SA1008 // Opening parenthesis must be spaced correctly block.Languages.Add(language, (viewer, element.Text)); #pragma warning restore SA1008 // Opening parenthesis must be spaced correctly if (prevPanel.Children.FirstOrDefault() is Grid headerGrid) { var langHead = headerGrid.Children.FirstOrDefault(); if (langHead is TextBlock textLangHead) { // Replace TextBlock with ComboBox headerGrid.Children.Remove(textLangHead); var combLangHead = new ComboBox { Items = { textLangHead.Text, language }, SelectedIndex = 0, MinWidth = 80 }; headerGrid.Children.Add(combLangHead); combLangHead.SelectionChanged += (s, e) => { var newLang = combLangHead.SelectedItem as string; block.CurrentLanguage = newLang; LanguageRequested?.Invoke(combLangHead, newLang); var newViewer = block.Languages[newLang].viewer; // Remove old Viewer. var lastItem = prevPanel.Children.Count - 1; if (lastItem >= 0) { prevPanel.Children.RemoveAt(lastItem); } prevPanel.Children.Add(newViewer); }; LanguageRequested += (s, e) => { if (s != combLangHead) { if (combLangHead.Items.Contains(e)) { combLangHead.SelectedItem = e; block.CurrentLanguage = e; } } }; if (DesiredLang == language) { combLangHead.SelectedItem = language; block.CurrentLanguage = language; } } else if (langHead is ComboBox combLangHead) { // Add Lang to ComboBox #pragma warning disable SA1008 // Opening parenthesis must be spaced correctly block.Languages.Add(language, (viewer, element.Text)); #pragma warning restore SA1008 // Opening parenthesis must be spaced correctly combLangHead.Items.Add(language); if (DesiredLang == language) { combLangHead.SelectedItem = language; block.CurrentLanguage = language; } } } } else { block = new CustomCodeBlock(); #pragma warning disable SA1008 // Opening parenthesis must be spaced correctly block.Languages.Add(language, (viewer, element.Text)); #pragma warning restore SA1008 // Opening parenthesis must be spaced correctly block.CurrentLanguage = language; // Creates a Header to specify Language and provide a copy button. var headerGrid = new Grid { Background = new SolidColorBrush(Color.FromArgb(50, 0, 0, 0)) }; headerGrid.ColumnDefinitions.Add(new ColumnDefinition()); headerGrid.ColumnDefinitions.Add(new ColumnDefinition { Width = GridLength.Auto }); var languageBlock = new TextBlock { Text = language, VerticalAlignment = VerticalAlignment.Center, Margin = new Thickness(10, 0, 0, 0) }; headerGrid.Children.Add(languageBlock); var copyButton = new Button { Content = "Copy", HorizontalAlignment = HorizontalAlignment.Stretch, VerticalAlignment = VerticalAlignment.Stretch }; copyButton.Click += (s, e) => { var text = block.Languages[block.CurrentLanguage].text; var content = new DataPackage(); content.SetText(text); Clipboard.SetContent(content); }; headerGrid.Children.Add(copyButton); Grid.SetColumn(copyButton, 1); // Collection the adornment and the standard UI, add them to a StackPanel, and add it back to the collection. var panel = new StackPanel { Background = viewer.Background, Margin = viewer.Margin, Tag = block }; panel.Children.Add(headerGrid); panel.Children.Add(viewer); collection.Add(panel); } }