Files
APIVisualExecutor/Examples/Nodify.Calculator/EditorView.xaml
Ankitkumar Satapara 99b8e2c24d
Some checks failed
Build / build (push) Has been cancelled
Implemented animations on the nodes while executing
2026-04-20 21:23:18 +05:30

997 lines
60 KiB
XML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<UserControl x:Class="Nodify.Calculator.EditorView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Nodify.Calculator"
xmlns:nodify="https://miroiu.github.io/nodify"
xmlns:shared="clr-namespace:Nodify;assembly=Nodify.Shared"
xmlns:sys="clr-namespace:System;assembly=System.Runtime"
d:DataContext="{d:DesignInstance Type=local:EditorViewModel}"
mc:Ignorable="d"
d:DesignHeight="450"
d:DesignWidth="800">
<UserControl.Resources>
<GeometryDrawing x:Key="SmallGridGeometry"
Geometry="M0,0 L0,1 0.03,1 0.03,0.03 1,0.03 1,0 Z"
Brush="{DynamicResource GridLinesBrush}" />
<GeometryDrawing x:Key="LargeGridGeometry"
Geometry="M0,0 L0,1 0.015,1 0.015,0.015 1,0.015 1,0 Z"
Brush="{DynamicResource GridLinesBrush}" />
<DrawingBrush x:Key="SmallGridLinesDrawingBrush"
TileMode="Tile"
ViewportUnits="Absolute"
Viewport="0 0 15 15"
Transform="{Binding ViewportTransform, ElementName=Editor}"
Drawing="{StaticResource SmallGridGeometry}" />
<DrawingBrush x:Key="LargeGridLinesDrawingBrush"
TileMode="Tile"
ViewportUnits="Absolute"
Opacity="0.5"
Viewport="0 0 150 150"
Transform="{Binding ViewportTransform, ElementName=Editor}"
Drawing="{StaticResource LargeGridGeometry}" />
<LinearGradientBrush x:Key="AnimatedBrush"
StartPoint="0 0"
EndPoint="1 0">
<GradientStop Color="#6366f1"
Offset="0" />
<GradientStop Color="#a855f7"
Offset="0.5" />
<GradientStop Color="#ec4899"
Offset="1" />
</LinearGradientBrush>
<Border x:Key="AnimatedBorderPlaceholder"
BorderBrush="{StaticResource AnimatedBrush}" />
<Storyboard x:Key="AnimateBorder"
RepeatBehavior="Forever">
<PointAnimation Storyboard.TargetProperty="BorderBrush.(LinearGradientBrush.StartPoint)"
Storyboard.Target="{StaticResource AnimatedBorderPlaceholder}"
Duration="0:0:2"
To="1 0" />
<PointAnimation Storyboard.TargetProperty="BorderBrush.(LinearGradientBrush.StartPoint)"
Storyboard.Target="{StaticResource AnimatedBorderPlaceholder}"
Duration="0:0:2"
To="1 1"
BeginTime="0:0:2" />
<PointAnimation Storyboard.TargetProperty="BorderBrush.(LinearGradientBrush.StartPoint)"
Storyboard.Target="{StaticResource AnimatedBorderPlaceholder}"
Duration="0:0:2"
To="0 1"
BeginTime="0:0:4" />
<PointAnimation Storyboard.TargetProperty="BorderBrush.(LinearGradientBrush.StartPoint)"
Storyboard.Target="{StaticResource AnimatedBorderPlaceholder}"
Duration="0:0:2"
To="0 0"
BeginTime="0:0:6" />
<PointAnimation Storyboard.TargetProperty="BorderBrush.(LinearGradientBrush.EndPoint)"
Storyboard.Target="{StaticResource AnimatedBorderPlaceholder}"
Duration="0:0:2"
To="1 1" />
<PointAnimation Storyboard.TargetProperty="BorderBrush.(LinearGradientBrush.EndPoint)"
Storyboard.Target="{StaticResource AnimatedBorderPlaceholder}"
Duration="0:0:2"
To="0 1"
BeginTime="0:0:2" />
<PointAnimation Storyboard.TargetProperty="BorderBrush.(LinearGradientBrush.EndPoint)"
Storyboard.Target="{StaticResource AnimatedBorderPlaceholder}"
Duration="0:0:2"
To="0 0"
BeginTime="0:0:4" />
<PointAnimation Storyboard.TargetProperty="BorderBrush.(LinearGradientBrush.EndPoint)"
Storyboard.Target="{StaticResource AnimatedBorderPlaceholder}"
Duration="0:0:2"
To="1 0"
BeginTime="0:0:6" />
</Storyboard>
<local:ItemToListConverter x:Key="ItemToListConverter" />
<local:UpperCaseConverter x:Key="UpperCaseConverter" />
<DataTemplate x:Key="ConnectionTemplate"
DataType="{x:Type local:ConnectionViewModel}">
<nodify:CircuitConnection Source="{Binding Output.Anchor}"
Target="{Binding Input.Anchor}"
Foreground="{Binding Input.Color}"
Stroke="{Binding Input.Color}"
StrokeThickness="2">
<nodify:CircuitConnection.Style>
<Style TargetType="{x:Type nodify:CircuitConnection}">
<Style.Triggers>
<DataTrigger Binding="{Binding IsActiveInExecution}" Value="True">
<Setter Property="Stroke" Value="#FFFFEB3B" />
<Setter Property="StrokeThickness" Value="5" />
<Setter Property="StrokeDashArray" Value="4 3" />
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard RepeatBehavior="Forever">
<DoubleAnimation Storyboard.TargetProperty="StrokeDashOffset"
From="20" To="0" Duration="0:0:0.6" />
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
</DataTrigger>
</Style.Triggers>
</Style>
</nodify:CircuitConnection.Style>
</nodify:CircuitConnection>
</DataTemplate>
<DataTemplate x:Key="PendingConnectionTemplate"
DataType="{x:Type local:PendingConnectionViewModel}">
<nodify:PendingConnection IsVisible="{Binding IsVisible}"
Source="{Binding Source, Mode=OneWayToSource}"
Target="{Binding Target, Mode=OneWayToSource}"
TargetAnchor="{Binding TargetLocation, Mode=OneWayToSource}"
StartedCommand="{Binding DataContext.StartConnectionCommand, RelativeSource={RelativeSource AncestorType={x:Type nodify:NodifyEditor}}}"
CompletedCommand="{Binding DataContext.CreateConnectionCommand, RelativeSource={RelativeSource AncestorType={x:Type nodify:NodifyEditor}}}" />
</DataTemplate>
<Style x:Key="ItemContainerStyle"
TargetType="{x:Type nodify:ItemContainer}"
BasedOn="{StaticResource {x:Type nodify:ItemContainer}}">
<Setter Property="Location"
Value="{Binding Location}" />
<Setter Property="IsSelected"
Value="{Binding IsSelected}" />
<Setter Property="ActualSize"
Value="{Binding Size, Mode=OneWayToSource}" />
<Setter Property="BorderBrush"
Value="{Binding BorderBrush, Source={StaticResource AnimatedBorderPlaceholder}}" />
<Setter Property="BorderThickness"
Value="2" />
<Style.Triggers>
<DataTrigger Binding="{Binding ExecutionState}" Value="Running">
<Setter Property="BorderBrush" Value="#FFFFC107" />
<Setter Property="BorderThickness" Value="3" />
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard RepeatBehavior="Forever" AutoReverse="True">
<DoubleAnimation Storyboard.TargetProperty="Opacity"
From="1.0" To="0.55" Duration="0:0:0.5" />
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="Opacity"
To="1.0" Duration="0:0:0.2" />
</Storyboard>
</BeginStoryboard>
</DataTrigger.ExitActions>
</DataTrigger>
<DataTrigger Binding="{Binding ExecutionState}" Value="Completed">
<Setter Property="BorderBrush" Value="#FF4CAF50" />
<Setter Property="BorderThickness" Value="3" />
</DataTrigger>
<DataTrigger Binding="{Binding ExecutionState}" Value="Error">
<Setter Property="BorderBrush" Value="#FFF44336" />
<Setter Property="BorderThickness" Value="3" />
</DataTrigger>
</Style.Triggers>
</Style>
<SolidColorBrush x:Key="SquareConnectorColor" Color="MediumSlateBlue"></SolidColorBrush>
<SolidColorBrush x:Key="TriangleConnectorColor" Color="White"></SolidColorBrush>
<SolidColorBrush x:Key="GridConnectorColor" Color="#4CAF50"></SolidColorBrush>
<ControlTemplate x:Key="GridConnector" TargetType="Control">
<Grid Width="14" Height="14">
<Ellipse Width="3" Height="3" Fill="{TemplateBinding BorderBrush}" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="1,1,0,0" />
<Ellipse Width="3" Height="3" Fill="{TemplateBinding BorderBrush}" HorizontalAlignment="Center" VerticalAlignment="Top" Margin="0,1,0,0" />
<Ellipse Width="3" Height="3" Fill="{TemplateBinding BorderBrush}" HorizontalAlignment="Right" VerticalAlignment="Top" Margin="0,1,1,0" />
<Ellipse Width="3" Height="3" Fill="{TemplateBinding BorderBrush}" HorizontalAlignment="Left" VerticalAlignment="Center" Margin="1,0,0,0" />
<Ellipse Width="3" Height="3" Fill="{TemplateBinding BorderBrush}" HorizontalAlignment="Center" VerticalAlignment="Center" />
<Ellipse Width="3" Height="3" Fill="{TemplateBinding BorderBrush}" HorizontalAlignment="Right" VerticalAlignment="Center" Margin="0,0,1,0" />
<Ellipse Width="3" Height="3" Fill="{TemplateBinding BorderBrush}" HorizontalAlignment="Left" VerticalAlignment="Bottom" Margin="1,0,0,1" />
<Ellipse Width="3" Height="3" Fill="{TemplateBinding BorderBrush}" HorizontalAlignment="Center" VerticalAlignment="Bottom" Margin="0,0,0,1" />
<Ellipse Width="3" Height="3" Fill="{TemplateBinding BorderBrush}" HorizontalAlignment="Right" VerticalAlignment="Bottom" Margin="0,0,1,1" />
</Grid>
</ControlTemplate>
<Style x:Key="ConnectionStyle" TargetType="{x:Type nodify:BaseConnection}">
<Style.Triggers>
<DataTrigger Binding="{Binding Input.Shape}"
Value="{x:Static local:ConnectorShape.Square}">
<Setter Property="Stroke" Value="{StaticResource SquareConnectorColor}"></Setter>
</DataTrigger>
<DataTrigger Binding="{Binding Input.Shape}"
Value="{x:Static local:ConnectorShape.Triangle}">
<Setter Property="Stroke" Value="{StaticResource TriangleConnectorColor}"></Setter>
</DataTrigger>
<DataTrigger Binding="{Binding Input.Shape}"
Value="{x:Static local:ConnectorShape.Grid}">
<Setter Property="Stroke" Value="{StaticResource GridConnectorColor}"></Setter>
</DataTrigger>
</Style.Triggers>
<Setter Property="Stroke" Value="{DynamicResource Connection.StrokeBrush}"></Setter>
<Setter Property="Cursor" Value="Hand"></Setter>
<Setter Property="ToolTip" Value="Double click to split"></Setter>
</Style>
<ControlTemplate x:Key="SquareConnector" TargetType="Control">
<Rectangle Width="14"
Height="14"
StrokeDashCap="Round"
StrokeLineJoin="Round"
StrokeStartLineCap="Round"
StrokeEndLineCap="Round"
Stroke="{TemplateBinding BorderBrush}"
Fill="{TemplateBinding Background}"
StrokeThickness="2" />
</ControlTemplate>
<ControlTemplate x:Key="TriangleConnector" TargetType="Control">
<Polygon Width="14"
Height="14"
Points="2,2 4,2 12,7 4,12 2,12"
StrokeDashCap="Round"
StrokeLineJoin="Round"
StrokeStartLineCap="Round"
StrokeEndLineCap="Round"
Stroke="{TemplateBinding BorderBrush}"
Fill="{TemplateBinding Background}"
/>
</ControlTemplate>
</UserControl.Resources>
<Grid>
<nodify:NodifyEditor DataContext="{Binding Calculator}"
ItemsSource="{Binding Operations}"
Connections="{Binding Connections}"
SelectedItems="{Binding SelectedOperations}"
DisconnectConnectorCommand="{Binding DisconnectConnectorCommand}"
PendingConnection="{Binding PendingConnection}"
PendingConnectionTemplate="{StaticResource PendingConnectionTemplate}"
ConnectionTemplate="{StaticResource ConnectionTemplate}"
Background="{StaticResource SmallGridLinesDrawingBrush}"
ItemContainerStyle="{StaticResource ItemContainerStyle}"
HasCustomContextMenu="True"
GridCellSize="15"
AllowDrop="True"
Drop="OnDropNode"
x:Name="Editor">
<nodify:NodifyEditor.Resources>
<Style TargetType="{x:Type nodify:NodeInput}"
BasedOn="{StaticResource OriginalNodeInputStyle}">
<Setter Property="Header"
Value="{Binding}" />
<Setter Property="IsConnected"
Value="{Binding IsConnected}" />
<Setter Property="Anchor"
Value="{Binding Anchor, Mode=OneWayToSource}" />
<Setter Property="ToolTip"
Value="{Binding Value}" />
<Setter Property="HeaderTemplate">
<Setter.Value>
<DataTemplate DataType="{x:Type local:ConnectorViewModel}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Title}"
Margin="0 0 5 0" />
<TextBox Text="{Binding Value}"
Visibility="{Binding IsConnected, Converter={shared:BooleanToVisibilityConverter Negate=True}}" />
</StackPanel>
</DataTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding Title}" Value="">
<Setter Property="HeaderTemplate">
<Setter.Value>
<DataTemplate/>
</Setter.Value>
</Setter>
</DataTrigger>
<DataTrigger Binding="{Binding Title}" Value="{x:Null}">
<Setter Property="HeaderTemplate">
<Setter.Value>
<DataTemplate/>
</Setter.Value>
</Setter>
</DataTrigger>
<DataTrigger Binding="{Binding Shape}"
Value="{x:Static local:ConnectorShape.Square}">
<Setter Property="ConnectorTemplate" Value="{StaticResource SquareConnector}" />
<Setter Property="BorderBrush" Value="{StaticResource SquareConnectorColor}"></Setter>
</DataTrigger>
<DataTrigger Binding="{Binding Shape}"
Value="{x:Static local:ConnectorShape.Triangle}">
<Setter Property="ConnectorTemplate" Value="{StaticResource TriangleConnector}" />
<Setter Property="BorderBrush" Value="{StaticResource TriangleConnectorColor}"></Setter>
</DataTrigger>
<DataTrigger Binding="{Binding Shape}"
Value="{x:Static local:ConnectorShape.Circle}">
<Setter Property="BorderBrush" Value="{Binding Color}"></Setter>
</DataTrigger>
<DataTrigger Binding="{Binding Shape}"
Value="{x:Static local:ConnectorShape.Grid}">
<Setter Property="ConnectorTemplate" Value="{StaticResource GridConnector}" />
<Setter Property="BorderBrush" Value="{StaticResource GridConnectorColor}"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
<Style TargetType="{x:Type nodify:NodeOutput}"
BasedOn="{StaticResource OriginalNodeOutputStyle}">
<Setter Property="Header"
Value="{Binding}" />
<Setter Property="IsConnected"
Value="{Binding IsConnected}" />
<Setter Property="Anchor"
Value="{Binding Anchor, Mode=OneWayToSource}" />
<Setter Property="HeaderTemplate">
<Setter.Value>
<DataTemplate DataType="{x:Type local:ConnectorViewModel}">
<TextBox Text="{Binding Title}"
IsEnabled="False" />
</DataTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding Title}" Value="">
<Setter Property="HeaderTemplate">
<Setter.Value>
<DataTemplate/>
</Setter.Value>
</Setter>
</DataTrigger>
<DataTrigger Binding="{Binding Title}" Value="{x:Null}">
<Setter Property="HeaderTemplate">
<Setter.Value>
<DataTemplate/>
</Setter.Value>
</Setter>
</DataTrigger>
<DataTrigger Binding="{Binding Shape}"
Value="{x:Static local:ConnectorShape.Square}">
<Setter Property="ConnectorTemplate" Value="{StaticResource SquareConnector}" />
<Setter Property="BorderBrush" Value="{StaticResource SquareConnectorColor}"></Setter>
</DataTrigger>
<DataTrigger Binding="{Binding Shape}"
Value="{x:Static local:ConnectorShape.Triangle}">
<Setter Property="ConnectorTemplate" Value="{StaticResource TriangleConnector}" />
<Setter Property="BorderBrush" Value="{StaticResource TriangleConnectorColor}"></Setter>
</DataTrigger>
<DataTrigger Binding="{Binding Shape}"
Value="{x:Static local:ConnectorShape.Circle}">
<Setter Property="BorderBrush" Value="{Binding Color}"></Setter>
</DataTrigger>
<DataTrigger Binding="{Binding Shape}"
Value="{x:Static local:ConnectorShape.Grid}">
<Setter Property="ConnectorTemplate" Value="{StaticResource GridConnector}" />
<Setter Property="BorderBrush" Value="{StaticResource GridConnectorColor}"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
<DataTemplate DataType="{x:Type local:OperationGraphViewModel}">
<nodify:GroupingNode Header="{Binding}"
CanResize="{Binding IsExpanded}"
ActualSize="{Binding DesiredSize, Mode=TwoWay}"
MovementMode="Self">
<nodify:GroupingNode.HeaderTemplate>
<DataTemplate DataType="{x:Type local:OperationGraphViewModel}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Title}" />
<StackPanel Orientation="Horizontal"
Margin="5 0 0 0"
Grid.Column="1">
<TextBlock Text="Expand?"
Visibility="{Binding IsExpanded, Converter={shared:BooleanToVisibilityConverter}}"
Margin="0 0 5 0" />
<CheckBox IsChecked="{Binding IsExpanded}" />
</StackPanel>
</Grid>
</DataTemplate>
</nodify:GroupingNode.HeaderTemplate>
<Grid>
<ScrollViewer CanContentScroll="True"
Visibility="{Binding IsExpanded, Converter={shared:BooleanToVisibilityConverter}}">
<nodify:NodifyEditor Tag="{Binding DataContext, RelativeSource={RelativeSource Self}}"
DataContext="{Binding InnerCalculator}"
ItemsSource="{Binding Operations}"
Connections="{Binding Connections}"
SelectedItems="{Binding SelectedOperations}"
DisconnectConnectorCommand="{Binding DisconnectConnectorCommand}"
PendingConnection="{Binding PendingConnection}"
PendingConnectionTemplate="{StaticResource PendingConnectionTemplate}"
ConnectionTemplate="{StaticResource ConnectionTemplate}"
ItemContainerStyle="{StaticResource ItemContainerStyle}"
HasCustomContextMenu="True"
Background="Transparent"
GridCellSize="15"
AllowDrop="True"
Drop="OnDropNode"
Visibility="{Binding DataContext.IsExpanded, RelativeSource={RelativeSource AncestorType=nodify:GroupingNode}, Converter={shared:BooleanToVisibilityConverter}}">
<nodify:NodifyEditor.InputBindings>
<KeyBinding Key="Delete"
Command="{Binding DeleteSelectionCommand}" />
<KeyBinding Key="G"
Modifiers="Ctrl"
Command="{Binding GroupSelectionCommand}" />
</nodify:NodifyEditor.InputBindings>
<nodify:NodifyEditor.CommandBindings>
<CommandBinding Command="{x:Static ApplicationCommands.ContextMenu}"
Executed="OpenContextMenu_Executed" />
</nodify:NodifyEditor.CommandBindings>
<CompositeCollection>
<nodify:DecoratorContainer DataContext="{Binding OperationsMenu}"
Location="{Binding Location}">
<local:OperationsMenuView />
</nodify:DecoratorContainer>
</CompositeCollection>
</nodify:NodifyEditor>
</ScrollViewer>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<ItemsControl ItemsSource="{Binding Input}"
Focusable="False">
<ItemsControl.ItemTemplate>
<DataTemplate>
<nodify:NodeInput />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<nodify:NodeOutput DataContext="{Binding Output}"
Grid.Column="1"
VerticalAlignment="Top"
HorizontalAlignment="Right" />
</Grid>
</Grid>
</nodify:GroupingNode>
</DataTemplate>
<DataTemplate DataType="{x:Type local:ExpandoOperationViewModel}">
<nodify:Node Header="{Binding Title}"
Content="{Binding}"
Input="{Binding Input}"
Output="{Binding Output}">
<nodify:Node.ContentTemplate>
<DataTemplate DataType="{x:Type local:ExpandoOperationViewModel}">
<StackPanel>
<Button Style="{StaticResource IconButton}"
Content="{StaticResource PlusIcon}"
FocusVisualStyle="{StaticResource {x:Static SystemParameters.FocusVisualStyleKey}}"
Command="{Binding AddInputCommand}" />
<Button Style="{StaticResource IconButton}"
Content="{StaticResource RemoveKeyIcon}"
FocusVisualStyle="{StaticResource {x:Static SystemParameters.FocusVisualStyleKey}}"
Command="{Binding RemoveInputCommand}" />
</StackPanel>
</DataTemplate>
</nodify:Node.ContentTemplate>
</nodify:Node>
</DataTemplate>
<DataTemplate DataType="{x:Type local:APIOperationViewModel}">
<nodify:Node Header="{Binding Title}"
Content="{Binding}"
Input="{Binding Input}"
Output="{Binding Output}">
<nodify:Node.ContentTemplate>
<DataTemplate DataType="{x:Type local:APIOperationViewModel}">
<StackPanel>
<TextBlock Text="{Binding OperationType}"></TextBlock>
</StackPanel>
</DataTemplate>
</nodify:Node.ContentTemplate>
</nodify:Node>
</DataTemplate>
<DataTemplate DataType="{x:Type local:ExpressionOperationViewModel}">
<nodify:Node Content="{Binding}"
Input="{Binding Input}"
Output="{Binding Output}">
<nodify:Node.ContentTemplate>
<DataTemplate DataType="{x:Type local:ExpressionOperationViewModel}">
<TextBox Text="{Binding Expression}"
MinWidth="100"
Margin="5 0 0 0" />
</DataTemplate>
</nodify:Node.ContentTemplate>
</nodify:Node>
</DataTemplate>
<DataTemplate DataType="{x:Type local:FunctionOperationViewModel}">
<nodify:Node Input="{Binding Input}"
Output="{Binding Output}"
ToolTip="Double click to edit function"
BorderBrush="#FF9800"
BorderThickness="2">
<nodify:Node.Header>
<StackPanel Orientation="Horizontal">
<TextBlock Text="ƒ"
FontSize="16"
FontWeight="Bold"
Foreground="#FF9800"
VerticalAlignment="Center"
Margin="0 0 6 0" />
<TextBlock Text="{Binding Title}"
VerticalAlignment="Center"
FontWeight="SemiBold" />
</StackPanel>
</nodify:Node.Header>
<TextBlock Text="⚡ Double-click to edit"
FontSize="10"
Foreground="#FF9800"
Opacity="0.8"
Margin="4 2" />
<nodify:Node.InputBindings>
<MouseBinding Gesture="LeftDoubleClick"
Command="{Binding DataContext.OpenCalculatorCommand, RelativeSource={RelativeSource AncestorType=UserControl}}"
CommandParameter="{Binding InnerCalculator}" />
</nodify:Node.InputBindings>
</nodify:Node>
</DataTemplate>
<DataTemplate DataType="{x:Type local:CalculatorOperationViewModel}">
<nodify:Node Header="{Binding Title}"
Input="{Binding Input}"
Output="{Binding Output}"
ToolTip="Double click to expand">
<nodify:Node.InputBindings>
<MouseBinding Gesture="LeftDoubleClick"
Command="{Binding DataContext.OpenCalculatorCommand, RelativeSource={RelativeSource AncestorType=UserControl}}"
CommandParameter="{Binding InnerCalculator}" />
</nodify:Node.InputBindings>
</nodify:Node>
</DataTemplate>
<DataTemplate DataType="{x:Type local:CalculatorInputOperationViewModel}">
<DataTemplate.Resources>
<Style TargetType="{x:Type nodify:NodeOutput}"
BasedOn="{StaticResource {x:Type nodify:NodeOutput}}">
<Setter Property="Header"
Value="{Binding}" />
<Setter Property="IsConnected"
Value="{Binding IsConnected}" />
<Setter Property="Anchor"
Value="{Binding Anchor, Mode=OneWayToSource}" />
<Setter Property="HeaderTemplate">
<Setter.Value>
<DataTemplate DataType="{x:Type local:ConnectorViewModel}">
<StackPanel Orientation="Horizontal">
<TextBox Text="{Binding Value}"
IsEnabled="False" />
<TextBlock Text="{Binding Title}"
Margin="5 0 0 0" />
</StackPanel>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</DataTemplate.Resources>
<nodify:Node Header="{Binding Title}"
Output="{Binding Output}">
<StackPanel>
<Button Style="{StaticResource IconButton}"
Content="{StaticResource PlusIcon}"
Command="{Binding AddOutputCommand}" />
<Button Style="{StaticResource IconButton}"
Content="{StaticResource RemoveKeyIcon}"
Command="{Binding RemoveOutputCommand}" />
</StackPanel>
</nodify:Node>
</DataTemplate>
<DataTemplate DataType="{x:Type local:OperationGroupViewModel}">
<nodify:GroupingNode ActualSize="{Binding GroupSize, Mode=TwoWay}">
<nodify:GroupingNode.Header>
<shared:EditableTextBlock Text="{Binding Title}"
FontWeight="SemiBold"
IsEditing="True" />
</nodify:GroupingNode.Header>
</nodify:GroupingNode>
</DataTemplate>
<DataTemplate DataType="{x:Type local:AuthOperationViewModel}">
<nodify:Node Header="🔐 Auth Configuration"
Content="{Binding}"
Input="{Binding Input}"
Output="{Binding Output}">
<nodify:Node.ContentTemplate>
<DataTemplate DataType="{x:Type local:AuthOperationViewModel}">
<StackPanel Margin="4">
<TextBlock Text="Base URL" FontWeight="SemiBold" Margin="0 0 0 2" />
<TextBox Text="{Binding BaseUrl, UpdateSourceTrigger=PropertyChanged}"
MinWidth="180" Margin="0 0 0 6" />
<TextBlock Text="Auth Type" FontWeight="SemiBold" Margin="0 0 0 2" />
<ComboBox SelectedItem="{Binding AuthType}"
MinWidth="180" Margin="0 0 0 6">
<sys:String>Bearer Token</sys:String>
<sys:String>Basic Auth</sys:String>
<sys:String>API Key</sys:String>
<sys:String>None</sys:String>
</ComboBox>
</StackPanel>
</DataTemplate>
</nodify:Node.ContentTemplate>
</nodify:Node>
</DataTemplate>
<DataTemplate DataType="{x:Type local:ForEachOperationViewModel}">
<nodify:Node Input="{Binding Input}"
Output="{Binding Output}"
BorderBrush="#4CAF50"
BorderThickness="2">
<nodify:Node.Header>
<StackPanel Orientation="Horizontal">
<TextBlock Text="🔁"
FontSize="14"
VerticalAlignment="Center"
Margin="0 0 6 0" />
<TextBlock Text="{Binding Title}"
VerticalAlignment="Center"
FontWeight="SemiBold" />
</StackPanel>
</nodify:Node.Header>
<TextBlock Text="Iterates over each item in a list"
FontSize="10"
Foreground="#4CAF50"
Opacity="0.8"
Margin="4 2" />
</nodify:Node>
</DataTemplate>
<DataTemplate DataType="{x:Type local:AssertOperationViewModel}">
<nodify:Node Input="{Binding Input}"
Output="{Binding Output}"
BorderBrush="#FF5722"
BorderThickness="2">
<nodify:Node.Header>
<StackPanel Orientation="Horizontal">
<TextBlock Text="✅"
FontSize="14"
VerticalAlignment="Center"
Margin="0 0 6 0" />
<TextBlock Text="{Binding Title}"
VerticalAlignment="Center"
FontWeight="SemiBold" />
</StackPanel>
</nodify:Node.Header>
<StackPanel Margin="4 2">
<TextBlock Text="Compares Actual vs Expected"
FontSize="10"
Foreground="#FF5722"
Opacity="0.8" />
</StackPanel>
</nodify:Node>
</DataTemplate>
<DataTemplate DataType="{x:Type local:TakeOperationViewModel}">
<nodify:Node Header="{Binding Title}"
Content="{Binding}"
Input="{Binding Input}"
Output="{Binding Output}">
<nodify:Node.ContentTemplate>
<DataTemplate DataType="{x:Type local:TakeOperationViewModel}">
<StackPanel Margin="4">
<CheckBox Content="Random"
IsChecked="{Binding IsRandom, UpdateSourceTrigger=PropertyChanged}"
Foreground="White" Margin="0 0 0 4" />
</StackPanel>
</DataTemplate>
</nodify:Node.ContentTemplate>
</nodify:Node>
</DataTemplate>
<DataTemplate DataType="{x:Type local:KnotOperationViewModel}">
<nodify:Node Input="{Binding Input}"
Output="{Binding Output}"
Background="#FF2A2A2A"
BorderBrush="#FF666666"
BorderThickness="1"
Padding="0"
ToolTip="Knot (Reroute) — Ctrl+Click to create">
<Ellipse Width="8" Height="8"
Fill="#FFAAAAAA"
Margin="2" />
</nodify:Node>
</DataTemplate>
<DataTemplate DataType="{x:Type local:OperationViewModel}">
<nodify:Node Content="{Binding Title}"
Input="{Binding Input}"
Output="{Binding Output}" />
</DataTemplate>
</nodify:NodifyEditor.Resources>
<nodify:NodifyEditor.InputBindings>
<KeyBinding Key="Delete"
Command="{Binding DeleteSelectionCommand}" />
<KeyBinding Key="G"
Modifiers="Ctrl"
Command="{Binding GroupSelectionCommand}" />
</nodify:NodifyEditor.InputBindings>
<nodify:NodifyEditor.CommandBindings>
<CommandBinding Command="{x:Static ApplicationCommands.ContextMenu}"
Executed="OpenContextMenu_Executed" />
</nodify:NodifyEditor.CommandBindings>
<nodify:NodifyEditor.Triggers>
<EventTrigger RoutedEvent="FrameworkElement.Loaded">
<BeginStoryboard Name="AnimateBorder"
Storyboard="{StaticResource AnimateBorder}" />
</EventTrigger>
</nodify:NodifyEditor.Triggers>
<CompositeCollection>
<nodify:DecoratorContainer DataContext="{Binding OperationsMenu}"
Location="{Binding Location}">
<local:OperationsMenuView />
</nodify:DecoratorContainer>
</CompositeCollection>
</nodify:NodifyEditor>
<Grid Background="{StaticResource LargeGridLinesDrawingBrush}"
Panel.ZIndex="-2" />
<Border HorizontalAlignment="Right"
MinWidth="200"
MaxWidth="350"
MaxHeight="600"
Padding="7"
Margin="10"
CornerRadius="3"
BorderThickness="2">
<Border.Background>
<SolidColorBrush Color="{DynamicResource BackgroundColor}"
Opacity="0.7" />
</Border.Background>
<DockPanel>
<Button Content="📥 Import Swagger"
Command="{Binding Calculator.OperationsMenu.ImportSwaggerCommand}"
Margin="5"
Padding="8 4"
Cursor="Hand"
HorizontalAlignment="Stretch"
Background="{DynamicResource NodeInput.BorderBrush}"
Foreground="{DynamicResource ForegroundBrush}"
FontWeight="Bold"
DockPanel.Dock="Top" />
<ScrollViewer VerticalScrollBarVisibility="Auto">
<StackPanel>
<!-- System nodes (non-API) -->
<ItemsControl ItemsSource="{Binding Calculator.OperationsMenu.SystemNodes}"
Focusable="False">
<ItemsControl.ItemContainerStyle>
<Style>
<Setter Property="FrameworkElement.Margin" Value="5" />
<Setter Property="FrameworkElement.HorizontalAlignment" Value="Left" />
<Setter Property="FrameworkElement.Cursor" Value="Hand" />
<Setter Property="FrameworkElement.ToolTip" Value="Drag and drop into the editor" />
</Style>
</ItemsControl.ItemContainerStyle>
<ItemsControl.ItemTemplate>
<DataTemplate DataType="{x:Type local:OperationViewModel}">
<nodify:Node Content="{Binding Title}"
Input="{Binding Input}"
Output="{Binding Output}"
BorderBrush="{StaticResource AnimatedBrush}"
BorderThickness="2"
MouseMove="OnNodeDrag"
Focusable="True"
KeyboardNavigation.TabNavigation="None">
</nodify:Node>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<!-- Grouped Swagger API operations -->
<ItemsControl ItemsSource="{Binding Calculator.OperationsMenu.GroupedSwaggerOperations}"
Focusable="False">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Expander IsExpanded="True" Margin="0 6 0 0">
<Expander.Header>
<TextBlock Text="{Binding GroupName}"
FontWeight="Bold"
FontSize="15"
Foreground="{DynamicResource ForegroundBrush}" />
</Expander.Header>
<ItemsControl ItemsSource="{Binding Operations}" Focusable="False" Margin="4 2 0 0">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border Margin="2 3" Padding="5 4" CornerRadius="4"
Cursor="Hand"
MouseMove="OnSwaggerItemDrag"
ToolTip="Drag and drop into the editor"
Tag="{Binding}">
<Border.Background>
<SolidColorBrush Color="{DynamicResource BackgroundColor}" Opacity="0.5" />
</Border.Background>
<StackPanel Orientation="Horizontal" VerticalAlignment="Center">
<Border CornerRadius="3" Padding="6 2" Margin="0 0 6 0" MinWidth="50"
HorizontalAlignment="Left">
<Border.Style>
<Style TargetType="Border">
<Setter Property="Background" Value="#61AFFE" />
<Style.Triggers>
<DataTrigger Binding="{Binding OPType}" Value="post">
<Setter Property="Background" Value="#49CC90" />
</DataTrigger>
<DataTrigger Binding="{Binding OPType}" Value="put">
<Setter Property="Background" Value="#FCA130" />
</DataTrigger>
<DataTrigger Binding="{Binding OPType}" Value="delete">
<Setter Property="Background" Value="#F93E3E" />
</DataTrigger>
<DataTrigger Binding="{Binding OPType}" Value="patch">
<Setter Property="Background" Value="#50E3C2" />
</DataTrigger>
</Style.Triggers>
</Style>
</Border.Style>
<TextBlock FontWeight="Bold" Foreground="White"
HorizontalAlignment="Center">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Setter Property="Text" Value="{Binding OPType, Converter={StaticResource UpperCaseConverter}}" />
</Style>
</TextBlock.Style>
</TextBlock>
</Border>
<TextBlock Text="{Binding Title}"
Foreground="{DynamicResource ForegroundBrush}"
VerticalAlignment="Center"
TextTrimming="CharacterEllipsis"
MaxWidth="220" />
</StackPanel>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Expander>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</ScrollViewer>
</DockPanel>
</Border>
<Border HorizontalAlignment="Left"
MinWidth="200"
MaxWidth="250"
MaxHeight="500"
MinHeight="200"
Padding="7"
Margin="10"
CornerRadius="3"
BorderThickness="2">
<Border.Background>
<SolidColorBrush Color="{DynamicResource BackgroundColor}"
Opacity="0.7" />
</Border.Background>
<DockPanel>
<TextBlock Text="Variables" FontWeight="Bold" Margin="0 0 0 4" DockPanel.Dock="Top" />
<Button Content=" Add New Variable"
Command="{Binding Calculator.OperationsMenu.AddVariableCommand}"
Margin="0 0 0 6"
Padding="6 3"
Cursor="Hand"
DockPanel.Dock="Top"
Background="{DynamicResource NodeInput.BorderBrush}"
Foreground="{DynamicResource ForegroundBrush}" />
<ScrollViewer VerticalScrollBarVisibility="Auto">
<StackPanel>
<!-- Simple Variables -->
<ItemsControl ItemsSource="{Binding Calculator.OperationsMenu.AvailableVariables}"
Focusable="False">
<ItemsControl.ItemContainerStyle>
<Style>
<Setter Property="FrameworkElement.Margin" Value="3" />
<Setter Property="FrameworkElement.HorizontalAlignment" Value="Left" />
<Setter Property="FrameworkElement.Cursor" Value="Hand" />
<Setter Property="FrameworkElement.ToolTip" Value="Drag and drop to GET or SET this variable" />
</Style>
</ItemsControl.ItemContainerStyle>
<ItemsControl.ItemTemplate>
<DataTemplate DataType="{x:Type local:OperationInfoViewModel}">
<Border Background="#3E3E42" CornerRadius="3" Padding="6 4"
MouseMove="OnNodeDrag" Cursor="Hand">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Title}" Foreground="LightGreen" FontWeight="SemiBold" />
<TextBlock Text=" : " Foreground="Gray" />
<TextBlock Text="{Binding VariableType}" Foreground="CornflowerBlue" />
</StackPanel>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<!-- Separator -->
<TextBlock Text="Models" FontWeight="Bold" Margin="0 8 0 4" />
<Button Content=" Create New Model"
Command="{Binding Calculator.OperationsMenu.CreateModelCommand}"
Margin="0 0 0 6"
Padding="6 3"
Cursor="Hand"
Background="{DynamicResource NodeInput.BorderBrush}"
Foreground="{DynamicResource ForegroundBrush}" />
<!-- Class Model Variables -->
<ItemsControl ItemsSource="{Binding Calculator.OperationsMenu.AvailableModels}"
Focusable="False">
<ItemsControl.ItemContainerStyle>
<Style>
<Setter Property="FrameworkElement.Margin" Value="5" />
<Setter Property="FrameworkElement.HorizontalAlignment" Value="Left" />
<Setter Property="FrameworkElement.Cursor" Value="Hand" />
<Setter Property="FrameworkElement.ToolTip" Value="Drag and drop into the editor" />
</Style>
</ItemsControl.ItemContainerStyle>
<ItemsControl.ItemTemplate>
<DataTemplate DataType="{x:Type local:OperationViewModel}">
<nodify:Node Content="{Binding Title}"
Input="{Binding Input}"
Output="{Binding Output}"
BorderBrush="{StaticResource AnimatedBrush}"
BorderThickness="2"
MouseMove="OnNodeDrag"
Focusable="True"
KeyboardNavigation.TabNavigation="None">
</nodify:Node>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<!-- Functions Section -->
<TextBlock Text="Functions" FontWeight="Bold" Margin="0 8 0 4" />
<Button Content=" Create New Function"
Command="{Binding Calculator.OperationsMenu.CreateFunctionCommand}"
Margin="0 0 0 6"
Padding="6 3"
Cursor="Hand"
Background="#FF9800"
Foreground="White" />
<ItemsControl ItemsSource="{Binding Calculator.OperationsMenu.AvailableFunctions}"
Focusable="False">
<ItemsControl.ItemContainerStyle>
<Style>
<Setter Property="FrameworkElement.Margin" Value="3" />
<Setter Property="FrameworkElement.HorizontalAlignment" Value="Left" />
<Setter Property="FrameworkElement.Cursor" Value="Hand" />
<Setter Property="FrameworkElement.ToolTip" Value="Drag and drop to add this function to the flow" />
</Style>
</ItemsControl.ItemContainerStyle>
<ItemsControl.ItemTemplate>
<DataTemplate DataType="{x:Type local:OperationInfoViewModel}">
<Border Background="#3E3E42" CornerRadius="3" Padding="6 4"
MouseMove="OnNodeDrag" Cursor="Hand">
<StackPanel Orientation="Horizontal">
<TextBlock Text="ƒ " Foreground="#FF9800" FontWeight="Bold" />
<TextBlock Text="{Binding Title}" Foreground="Orange" FontWeight="SemiBold" />
</StackPanel>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</ScrollViewer>
</DockPanel>
</Border>
</Grid>
</UserControl>