<!-- Copyright © Northwoods Software Corporation, 2008-2026. All Rights Reserved. -->

<UserControl x:Class="FlowChart.FlowChart"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:go="http://schemas.nwoods.com/GoXam"
    xmlns:local="clr-namespace:FlowChart">

  <UserControl.Resources>
    <!-- this converter produces the stroke brush for ports -->
    <go:BooleanBrushConverter x:Key="theBooleanBrushConverter"
                              TrueBrush="DarkRed" FalseBrush="Transparent" />
    <local:LabelVisibilityConverter x:Key="theLabelVisibilityConverter" />

    <!-- The brushes for Start and End nodes -->
    <RadialGradientBrush x:Key="theGreenBrush" GradientOrigin="-0.2,-0.2">
      <GradientStop Color="White" Offset="0.35" />
      <GradientStop Color="Green" Offset="1" />
    </RadialGradientBrush>
    <RadialGradientBrush x:Key="theRedBrush" GradientOrigin="-0.2,-0.2">
      <GradientStop Color="White" Offset="0.35" />
      <GradientStop Color="Red" Offset="1" />
    </RadialGradientBrush>

    <!-- Because SpotPanel is used as the root of each node template,
         in order to hold all of the (sometimes visible) ports,
         this style applies to all nodes -->
    <Style TargetType="go:SpotPanel" x:Key="SpotPanelStyle">
      <Setter Property="go:Part.SelectionElementName" Value="Shape" />
      <Setter Property="go:Part.SelectionAdorned" Value="True" />
      <Setter Property="go:Node.LocationSpot" Value="Center" />
    </Style>

    <!-- For the primary shape of each node -->
    <Style TargetType="go:NodeShape" x:Key="NodeShapeStyle">
      <Setter Property="Stroke" Value="Black" />
      <Setter Property="StrokeThickness" Value="2" />
      <Setter Property="Fill">
        <Setter.Value>
          <RadialGradientBrush GradientOrigin="-0.2,-0.2">
            <GradientStop Color="White" Offset="0.35" />
            <GradientStop Color="SkyBlue" Offset="1" />
          </RadialGradientBrush>
        </Setter.Value>
      </Setter>
    </Style>

    <!-- For the text of each node -->
    <Style TargetType="TextBlock" x:Key="TextBlockStyle">
      <Setter Property="TextWrapping" Value="Wrap" />
      <Setter Property="VerticalAlignment" Value="Center" />
      <Setter Property="HorizontalAlignment" Value="Center" />
      <Setter Property="Margin" Value="5" />
      <Setter Property="go:Part.TextEditable" Value="True" />
    </Style>

    <!-- This style is used for all ellipses, which act as ports in this demo. -->
    <Style TargetType="Ellipse" x:Key="EllipseStyle">
      <Setter Property="Width" Value="7" />
      <Setter Property="Height" Value="7" />
      <Setter Property="Cursor" Value="Hand" />
      <Setter Property="Fill" Value="Transparent" />
      <Setter Property="go:Node.LinkableFrom" Value="True" />
      <Setter Property="go:Node.LinkableTo" Value="True" />
    </Style>

    <!-- The DataTemplateDictionary used to store all the
         DataTemplates for the Node categories. -->
    <go:DataTemplateDictionary x:Key="NodeTemplateDictionary">
      <!-- There is a separate DataTemplate for each Node category.
         This allows for large differences between categories.-->
      <DataTemplate x:Key="Comment">
        <go:SpotPanel Style="{StaticResource SpotPanelStyle}"
                    go:Node.Location="{Binding Path=Data.Location, Mode=TwoWay}">
          <go:NodePanel Sizing="Auto" go:SpotPanel.Main="True">
            <go:NodeShape x:Name="Shape" Style="{StaticResource NodeShapeStyle}"
                        Stroke="LightGray" Fill="LemonChiffon"
                        go:NodePanel.Figure="{Binding Path=Data.Figure}" />
            <TextBlock Style="{StaticResource TextBlockStyle}"
                     Text="{Binding Path=Data.Text, Mode=TwoWay}" />
          </go:NodePanel>
        </go:SpotPanel>
      </DataTemplate>

      <DataTemplate x:Key="Start">
        <go:SpotPanel Style="{StaticResource SpotPanelStyle}"
                    go:Node.Location="{Binding Path=Data.Location, Mode=TwoWay}" 
                    MouseEnter="Node_MouseEnter" MouseLeave="Node_MouseLeave">
          <go:NodePanel Sizing="Auto" go:SpotPanel.Main="True">
            <go:NodeShape x:Name="Shape" Style="{StaticResource NodeShapeStyle}"
                        go:NodePanel.Figure="{Binding Path=Data.Figure}"
                        Fill="{StaticResource theGreenBrush}" />
            <TextBlock Style="{StaticResource TextBlockStyle}"
                     Text="{Binding Path=Data.Text, Mode=TwoWay}" />
          </go:NodePanel>
          <!-- A Start node has only three ports, all outgoing only.
           Port appearance depends on the Node.Tag property.
           The FromSpot and ToSpot properties control where the link connects.
           The SpotPanel properties control where the port is positioned. -->
          <Ellipse Style="{StaticResource EllipseStyle}"
                 Stroke="{Binding Path=Node.Tag,
                          Converter={StaticResource theBooleanBrushConverter}}"
                 go:Node.PortId="0"
                 go:Node.LinkableTo="False"
                 go:Node.FromSpot="MiddleBottom"
                 go:SpotPanel.Spot="MiddleBottom"
                 go:SpotPanel.Alignment="MiddleBottom" />
          <Ellipse Style="{StaticResource EllipseStyle}"
                 Stroke="{Binding Path=Node.Tag,
                          Converter={StaticResource theBooleanBrushConverter}}"
                 go:Node.PortId="2"
                 go:Node.LinkableTo="False"
                 go:Node.FromSpot="MiddleLeft"
                 go:SpotPanel.Spot="MiddleLeft"
                 go:SpotPanel.Alignment="MiddleLeft" />
          <Ellipse Style="{StaticResource EllipseStyle}"
                 Stroke="{Binding Path=Node.Tag,
                          Converter={StaticResource theBooleanBrushConverter}}"
                 go:Node.PortId="3"
                 go:Node.LinkableTo="False"
                 go:Node.FromSpot="MiddleRight"
                 go:SpotPanel.Spot="MiddleRight"
                 go:SpotPanel.Alignment="MiddleRight" />
        </go:SpotPanel>
      </DataTemplate>

      <DataTemplate x:Key="Standard">
        <go:SpotPanel Style="{StaticResource SpotPanelStyle}"
                    go:Node.Location="{Binding Path=Data.Location, Mode=TwoWay}" 
                    MouseEnter="Node_MouseEnter" MouseLeave="Node_MouseLeave">
          <go:NodePanel Sizing="Auto" go:SpotPanel.Main="True">
            <go:NodeShape x:Name="Shape" Style="{StaticResource NodeShapeStyle}"
                        go:NodePanel.Figure="{Binding Path=Data.Figure}" />
            <TextBlock Style="{StaticResource TextBlockStyle}"
                     Text="{Binding Path=Data.Text, Mode=TwoWay}" />
          </go:NodePanel>
          <!-- A Standard node has four ports, the top incoming only, the
           bottom outgoing only, and the other two support both directions.
           Port appearance depends on the Node.Tag property.
           The FromSpot and ToSpot properties control where the link connects.
           The SpotPanel properties control where the port is positioned. -->
          <Ellipse Style="{StaticResource EllipseStyle}"
                 Stroke="{Binding Path=Node.Tag,
                          Converter={StaticResource theBooleanBrushConverter}}"
                 go:Node.PortId="0"
                 go:Node.LinkableTo="False"
                 go:Node.FromSpot="MiddleBottom"
                 go:SpotPanel.Spot="MiddleBottom"
                 go:SpotPanel.Alignment="MiddleBottom" />
          <Ellipse Style="{StaticResource EllipseStyle}"
                 Stroke="{Binding Path=Node.Tag,
                          Converter={StaticResource theBooleanBrushConverter}}"
                 go:Node.PortId="1"
                 go:Node.LinkableFrom="False"
                 go:Node.ToSpot="MiddleTop"
                 go:SpotPanel.Spot="MiddleTop"
                 go:SpotPanel.Alignment="MiddleTop" />
          <Ellipse Style="{StaticResource EllipseStyle}"
                 Stroke="{Binding Path=Node.Tag,
                          Converter={StaticResource theBooleanBrushConverter}}"
                 go:Node.PortId="2"
                 go:Node.FromSpot="MiddleLeft"
                 go:Node.ToSpot="MiddleLeft"
                 go:SpotPanel.Spot="MiddleLeft"
                 go:SpotPanel.Alignment="MiddleLeft" />
          <Ellipse Style="{StaticResource EllipseStyle}"
                 Stroke="{Binding Path=Node.Tag,
                          Converter={StaticResource theBooleanBrushConverter}}"
                 go:Node.PortId="3"
                 go:Node.FromSpot="MiddleRight"
                 go:Node.ToSpot="MiddleRight"
                 go:SpotPanel.Spot="MiddleRight"
                 go:SpotPanel.Alignment="MiddleRight" />
        </go:SpotPanel>
      </DataTemplate>

      <DataTemplate x:Key="End">
        <go:SpotPanel Style="{StaticResource SpotPanelStyle}"
                    go:Node.Location="{Binding Path=Data.Location, Mode=TwoWay}" 
                    MouseEnter="Node_MouseEnter" MouseLeave="Node_MouseLeave">
          <go:NodePanel Sizing="Auto" go:SpotPanel.Main="True">
            <go:NodeShape x:Name="Shape" Style="{StaticResource NodeShapeStyle}"
                        go:NodePanel.Figure="{Binding Path=Data.Figure}"
                        Fill="{StaticResource theRedBrush}" />
            <TextBlock Style="{StaticResource TextBlockStyle}"
                     Text="{Binding Path=Data.Text, Mode=TwoWay}" />
          </go:NodePanel>
          <!-- An End node has only three ports, all incoming only.
           Port appearance depends on the Node.Tag property.
           The FromSpot and ToSpot properties control where the link connects.
           The SpotPanel properties control where the port is positioned. -->
          <Ellipse Style="{StaticResource EllipseStyle}"
                 Stroke="{Binding Path=Node.Tag,
                          Converter={StaticResource theBooleanBrushConverter}}"
                 go:Node.PortId="1"
                 go:Node.LinkableFrom="False"
                 go:Node.ToSpot="MiddleTop"
                 go:SpotPanel.Spot="MiddleTop"
                 go:SpotPanel.Alignment="MiddleTop" />
          <Ellipse Style="{StaticResource EllipseStyle}"
                 Stroke="{Binding Path=Node.Tag,
                          Converter={StaticResource theBooleanBrushConverter}}"
                 go:Node.PortId="2"
                 go:Node.LinkableFrom="False"
                 go:Node.ToSpot="MiddleLeft"
                 go:SpotPanel.Spot="MiddleLeft"
                 go:SpotPanel.Alignment="MiddleLeft" />
          <Ellipse Style="{StaticResource EllipseStyle}"
                 Stroke="{Binding Path=Node.Tag,
                          Converter={StaticResource theBooleanBrushConverter}}"
                 go:Node.PortId="3"
                 go:Node.LinkableFrom="False"
                 go:Node.ToSpot="MiddleRight"
                 go:SpotPanel.Spot="MiddleRight"
                 go:SpotPanel.Alignment="MiddleRight" />
        </go:SpotPanel>
      </DataTemplate>
    </go:DataTemplateDictionary>

    <!-- A fairly standard LinkTemplate with AvoidsNodes routing,
         a JumpOver curve, and a slight curviness.
         The user can reconnect either end of the link.
         It has a polygon shaped like an arrowhead and a label. -->
    <DataTemplate x:Key="LinkTemplate">
      <go:LinkPanel go:Part.Reshapable="True">
        <go:Link.Route>
          <go:Route Routing="AvoidsNodes" Curve="JumpOver" Curviness="10"
                    RelinkableFrom="True" RelinkableTo="True" />
        </go:Link.Route>
        <Path Fill="Black" go:LinkPanel.ToArrow="Standard" />
        <go:LinkShape Stroke="Black" StrokeThickness="2" />
        <!-- this is the label that is only shown when connected to a Decision node -->
        <TextBlock Text="{Binding Path=Data.Text, Mode=TwoWay}"
                   TextWrapping="Wrap" MaxWidth="50" go:Part.TextEditable="True"
                   go:LinkPanel.Index="1" go:LinkPanel.Alignment="0 0 -2 0"
                   Visibility="{Binding Path=Link,
                                Converter={StaticResource theLabelVisibilityConverter}}" />
      </go:LinkPanel>
    </DataTemplate>
  </UserControl.Resources>
  
  <Grid>
    <Grid.ColumnDefinitions>
      <ColumnDefinition Width="110" />
      <ColumnDefinition Width="Auto" />
      <ColumnDefinition Width="*" />
    </Grid.ColumnDefinitions>
    <!-- Palettes and Diagrams have similar implementations. -->
    <go:Palette x:Name="myPalette" Padding="5"
                NodeTemplateDictionary="{StaticResource NodeTemplateDictionary}">
      <go:Palette.Layout>
        <!-- Setting the Sorting to "Forward" is necessary in order to arrange
             the Nodes in the order they are declared in the NodesSource. -->
        <go:GridLayout Sorting="Forward" CellSize="75 5" Spacing="5 5" />
      </go:Palette.Layout>
    </go:Palette>
    <GridSplitter Grid.Column="1" Width="5"
                  HorizontalAlignment="Center" VerticalAlignment="Stretch" /> 
    <!-- A Diagram that allows for linking between nodes.
         It also uses a DataTemplateDictionary for different Node categories. -->
    <go:Diagram x:Name="myDiagram" Grid.Column="2"
                Padding="10"
                VerticalContentAlignment="Stretch"
                HorizontalContentAlignment="Stretch"
                NodeTemplateDictionary="{StaticResource NodeTemplateDictionary}"
                LinkTemplate="{StaticResource LinkTemplate}" />
    <StackPanel Grid.Column="2" Orientation="Horizontal"
                HorizontalAlignment="Left" VerticalAlignment="Top">
      <Button Content="Save" Click="Save_Click" />
      <Button Content="Load" Click="Load_Click" x:Name="LoadButton" IsEnabled="False" />
    </StackPanel>
  </Grid>
</UserControl>
