📄 ui/src/Views/MainWindow.axaml
<Window
  xmlns="https://github.com/avaloniaui"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:nodify="https://miroiu.github.io/nodify"
  xmlns:vm="using:Cfa.Ui.ViewModels"
  xmlns:graph="using:Cfa.Ui.Graph"
  xmlns:views="using:Cfa.Ui.Views"
  x:Class="Cfa.Ui.Views.MainWindow"
  x:DataType="vm:MainViewModel"
  Title="Code Flow Analysis"
  Width="1400"
  Height="900"
  MinWidth="800"
  MinHeight="500"
>
  <Grid RowDefinitions="Auto,Auto,*,Auto">
    <Menu>
      <MenuItem Header="_File">
        <MenuItem
          Header="_Open Solution..."
          Name="OpenSolutionMenu"
          Command="{Binding OpenSolutionCommand}"
          InputGesture="Ctrl+O"
        />
      </MenuItem>
    </Menu>
    <Grid Grid.Row="1" ColumnDefinitions="*,Auto,Auto" Margin="16,8,16,12">
      <TextBox
        Name="AddressBar"
        Text="{Binding Address}"
        IsEnabled="{Binding CanAnalyze}"
        Watermark="Source file:line (relative to solution)"
        VerticalContentAlignment="Center"
      >
        <TextBox.KeyBindings>
          <KeyBinding Gesture="Enter" Command="{Binding AnalyzeCommand}" />
        </TextBox.KeyBindings>
      </TextBox>
      <Button
        Grid.Column="1"
        Name="AnalyzeButton"
        Margin="8,0,0,0"
        Content="Explore"
        Command="{Binding AnalyzeCommand}"
      />
      <Button
        Grid.Column="2"
        Margin="8,0,0,0"
        Content="Fit graph"
        Click="FitGraph"
        IsEnabled="{Binding HasScene}"
      />
    </Grid>
    <Grid Grid.Row="2" ClipToBounds="True">
      <nodify:NodifyEditor
        Name="Editor"
        ItemsSource="{Binding Scene.Nodes}"
        Connections="{Binding Scene.Edges}"
        CanSelectMultipleItems="False"
        CanSelectMultipleConnections="False"
        DisableAutoPanning="True"
      >
        <nodify:NodifyEditor.Background>
          <VisualBrush
            TileMode="Tile"
            DestinationRect="0,0,32,32"
            SourceRect="0,0,32,32"
            Transform="{Binding ViewportTransform, ElementName=Editor}"
          >
            <VisualBrush.Visual>
              <Canvas Width="32" Height="32" Background="#111827">
                <Ellipse Width="2" Height="2" Fill="#334155" Canvas.Left="15" Canvas.Top="15" />
              </Canvas>
            </VisualBrush.Visual>
          </VisualBrush>
        </nodify:NodifyEditor.Background>
        <nodify:NodifyEditor.Styles>
          <Style Selector="nodify|ItemContainer" x:DataType="graph:GraphNode">
            <Setter Property="Location" Value="{Binding Location, Mode=OneWay}" />
            <Setter Property="IsDraggable" Value="False" />
            <Setter Property="IsSelectable" Value="False" />
            <Setter Property="Focusable" Value="False" />
            <Setter Property="BorderThickness" Value="0" />
            <Setter Property="BorderBrush" Value="Transparent" />
          </Style>
        </nodify:NodifyEditor.Styles>
        <nodify:NodifyEditor.ItemTemplate>
          <DataTemplate x:DataType="graph:GraphNode">
            <Button
              Classes="member"
              Classes.origin="{Binding IsOrigin}"
              Classes.cycle="{Binding IsCycleReference}"
              Width="{Binding Width}"
              Height="{Binding Height}"
              Content="{Binding Label}"
              CommandParameter="{Binding}"
              Command="{Binding $parent[Window].((vm:MainViewModel)DataContext).OpenSourceCommand}"
              ToolTip.Tip="{Binding SourceLink}"
              AutomationProperties.Name="{Binding Label}"
            >
              <Button.Styles>
                <Style Selector="Button.member">
                  <Setter Property="Background" Value="#1E293B" />
                  <Setter Property="BorderBrush" Value="#38BDF8" />
                  <Setter Property="BorderThickness" Value="2" />
                  <Setter Property="CornerRadius" Value="18" />
                  <Setter Property="Padding" Value="12,8" />
                  <Setter Property="HorizontalContentAlignment" Value="Center" />
                  <Setter Property="VerticalContentAlignment" Value="Center" />
                </Style>
                <Style Selector="Button.member.origin">
                  <Setter Property="Background" Value="#164E63" />
                  <Setter Property="BorderBrush" Value="#67E8F9" />
                </Style>
                <Style Selector="Button.member.cycle">
                  <Setter Property="BorderBrush" Value="#FBBF24" />
                </Style>
              </Button.Styles>
              <Button.ContentTemplate>
                <DataTemplate>
                  <TextBlock
                    Text="{Binding}"
                    TextWrapping="Wrap"
                    TextAlignment="Center"
                    FontSize="13"
                  />
                </DataTemplate>
              </Button.ContentTemplate>
            </Button>
          </DataTemplate>
        </nodify:NodifyEditor.ItemTemplate>
        <nodify:NodifyEditor.ConnectionTemplate>
          <DataTemplate x:DataType="graph:GraphEdge">
            <views:GraphConnection Edge="{Binding}" IsHitTestVisible="False" />
          </DataTemplate>
        </nodify:NodifyEditor.ConnectionTemplate>
      </nodify:NodifyEditor>
      <TextBlock
        Text="Open a solution, then enter a source file:line to explore."
        IsVisible="{Binding !HasScene}"
        IsHitTestVisible="False"
        HorizontalAlignment="Center"
        VerticalAlignment="Center"
        Foreground="#94A3B8"
      />
      <Border IsVisible="{Binding IsBusy}" Background="#B3111827">
        <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center" Spacing="12">
          <ProgressBar Name="BusySpinner" IsIndeterminate="True" Width="220" Height="5" />
          <TextBlock Text="{Binding Status}" HorizontalAlignment="Center" />
        </StackPanel>
      </Border>
    </Grid>
    <TextBlock Grid.Row="3" Margin="16,8" Text="{Binding Status}" Foreground="#94A3B8" />
  </Grid>
  <Window.KeyBindings>
    <KeyBinding Gesture="Ctrl+O" Command="{Binding OpenSolutionCommand}" />
  </Window.KeyBindings>
</Window>