diff options
Diffstat (limited to 'zerotierone/windows/WinUI')
27 files changed, 2793 insertions, 0 deletions
diff --git a/zerotierone/windows/WinUI/APIHandler.cs b/zerotierone/windows/WinUI/APIHandler.cs new file mode 100644 index 0000000..92b8302 --- /dev/null +++ b/zerotierone/windows/WinUI/APIHandler.cs @@ -0,0 +1,208 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Net; +using System.IO; +using System.Windows; +using Newtonsoft.Json; + +namespace WinUI +{ + + + public class APIHandler + { + private string authtoken; + + private string url = null; + + public APIHandler() + { + url = "http://127.0.0.1:9993"; + } + + public APIHandler(int port, string authtoken) + { + url = "http://localhost:" + port; + this.authtoken = authtoken; + } + + public ZeroTierStatus GetStatus() + { + var request = WebRequest.Create(url + "/status" + "?auth=" + authtoken) as HttpWebRequest; + if (request != null) + { + request.Method = "GET"; + request.ContentType = "application/json"; + } + + try + { + var httpResponse = (HttpWebResponse)request.GetResponse(); + using (var streamReader = new StreamReader(httpResponse.GetResponseStream())) + { + var responseText = streamReader.ReadToEnd(); + + ZeroTierStatus status = null; + try + { + status = JsonConvert.DeserializeObject<ZeroTierStatus>(responseText); + } + catch (JsonReaderException e) + { + Console.WriteLine(e.ToString()); + } + return status; + } + } + catch (System.Net.Sockets.SocketException) + { + return null; + } + catch (System.Net.WebException) + { + return null; + } + } + + public List<ZeroTierNetwork> GetNetworks() + { + var request = WebRequest.Create(url + "/network" + "?auth=" + authtoken) as HttpWebRequest; + if (request == null) + { + return null; + } + + request.Method = "GET"; + request.ContentType = "application/json"; + + try + { + var httpResponse = (HttpWebResponse)request.GetResponse(); + using (var streamReader = new StreamReader(httpResponse.GetResponseStream())) + { + var responseText = streamReader.ReadToEnd(); + + List<ZeroTierNetwork> networkList = null; + try + { + networkList = JsonConvert.DeserializeObject<List<ZeroTierNetwork>>(responseText); + } + catch (JsonReaderException e) + { + Console.WriteLine(e.ToString()); + } + return networkList; + } + } + catch (System.Net.Sockets.SocketException) + { + return null; + } + catch (System.Net.WebException) + { + return null; + } + } + + public void JoinNetwork(string nwid) + { + var request = WebRequest.Create(url + "/network/" + nwid + "?auth=" + authtoken) as HttpWebRequest; + if (request == null) + { + return; + } + + request.Method = "POST"; + + try + { + var httpResponse = (HttpWebResponse)request.GetResponse(); + + if (httpResponse.StatusCode != HttpStatusCode.OK) + { + Console.WriteLine("Error sending join network message"); + } + } + catch (System.Net.Sockets.SocketException) + { + MessageBox.Show("Error Joining Network: Cannot connect to ZeroTier service."); + } + catch (System.Net.WebException) + { + MessageBox.Show("Error Joining Network: Cannot connect to ZeroTier service."); + } + } + + public void LeaveNetwork(string nwid) + { + var request = WebRequest.Create(url + "/network/" + nwid + "?auth=" + authtoken) as HttpWebRequest; + if (request == null) + { + return; + } + + request.Method = "DELETE"; + + try + { + var httpResponse = (HttpWebResponse)request.GetResponse(); + + if (httpResponse.StatusCode != HttpStatusCode.OK) + { + Console.WriteLine("Error sending leave network message"); + } + } + catch (System.Net.Sockets.SocketException) + { + MessageBox.Show("Error Leaving Network: Cannot connect to ZeroTier service."); + } + catch (System.Net.WebException) + { + MessageBox.Show("Error Leaving Network: Cannot connect to ZeroTier service."); + } + } + + public List<ZeroTierPeer> GetPeers() + { + var request = WebRequest.Create(url + "/peer" + "?auth=" + authtoken) as HttpWebRequest; + if (request == null) + { + return null; + } + + request.Method = "GET"; + request.ContentType = "application/json"; + + try + { + var httpResponse = (HttpWebResponse)request.GetResponse(); + using (var streamReader = new StreamReader(httpResponse.GetResponseStream())) + { + var responseText = streamReader.ReadToEnd(); + //Console.WriteLine(responseText); + List<ZeroTierPeer> peerList = null; + try + { + peerList = JsonConvert.DeserializeObject<List<ZeroTierPeer>>(responseText); + } + catch (JsonReaderException e) + { + Console.WriteLine(e.ToString()); + } + return peerList; + } + } + catch (System.Net.Sockets.SocketException) + { + return null; + } + catch (System.Net.WebException) + { + return null; + } + } + } +} diff --git a/zerotierone/windows/WinUI/App.config b/zerotierone/windows/WinUI/App.config new file mode 100644 index 0000000..8e15646 --- /dev/null +++ b/zerotierone/windows/WinUI/App.config @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="utf-8" ?> +<configuration> + <startup> + <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" /> + </startup> +</configuration>
\ No newline at end of file diff --git a/zerotierone/windows/WinUI/App.xaml b/zerotierone/windows/WinUI/App.xaml new file mode 100644 index 0000000..08b9b79 --- /dev/null +++ b/zerotierone/windows/WinUI/App.xaml @@ -0,0 +1,14 @@ +<Application x:Class="WinUI.App" + xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" + xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" + StartupUri="MainWindow.xaml"> + <Application.Resources> + + <ResourceDictionary> + <ResourceDictionary.MergedDictionaries> + <ResourceDictionary Source="Simple Styles.xaml"/> + </ResourceDictionary.MergedDictionaries> + </ResourceDictionary> + + </Application.Resources> +</Application> diff --git a/zerotierone/windows/WinUI/App.xaml.cs b/zerotierone/windows/WinUI/App.xaml.cs new file mode 100644 index 0000000..a97edde --- /dev/null +++ b/zerotierone/windows/WinUI/App.xaml.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Configuration; +using System.Data; +using System.Linq; +using System.Threading.Tasks; +using System.Windows; + +namespace WinUI +{ + /// <summary> + /// Interaction logic for App.xaml + /// </summary> + public partial class App : Application + { + } +} diff --git a/zerotierone/windows/WinUI/MainWindow.xaml b/zerotierone/windows/WinUI/MainWindow.xaml new file mode 100644 index 0000000..d71a90d --- /dev/null +++ b/zerotierone/windows/WinUI/MainWindow.xaml @@ -0,0 +1,132 @@ +<Window + xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" + xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" + xmlns:d="http://schemas.microsoft.com/expression/blend/2008" + xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" + xmlns:local="clr-namespace:WinUI" + mc:Ignorable="d" x:Class="WinUI.MainWindow" + Title="ZeroTier One" Height="500" Width="425" Icon="ZeroTierIcon.ico"> + + <Window.Resources> + <SolidColorBrush x:Key="GreenBrush" Color="#ff91a2a3"/> + + <SolidColorBrush x:Key="SolidBorderBrush" Color="#888" /> + + <SolidColorBrush x:Key="GreenDisabledBrush" Color="#FF234447" /> + + <SolidColorBrush x:Key="DisabledBackgroundBrush" Color="#EEE" /> + + <SolidColorBrush x:Key="DisabledBorderBrush" Color="#AAA" /> + + <SolidColorBrush x:Key="DisabledForegroundBrush" Color="#888" /> + + <Style TargetType="{x:Type DataGrid}"> + <Setter Property="Background" Value="#FFF" /> + <Setter Property="AlternationCount" Value="2" /> + </Style> + + <Style TargetType="{x:Type DataGridRow}"> + <Style.Triggers> + <Trigger Property="ItemsControl.AlternationIndex" Value="0"> + <Setter Property="Background" Value="#EEE"></Setter> + </Trigger> + <Trigger Property="ItemsControl.AlternationIndex" Value="1"> + <Setter Property="Background" Value="#FFF"></Setter> + </Trigger> + </Style.Triggers> + </Style> + + <Style TargetType="{x:Type TabItem}"> + <Setter Property="Template"> + <Setter.Value> + <ControlTemplate TargetType="{x:Type TabItem}"> + <Grid> + <Border + Name="Border" + Margin="0,0,-4,0" + Background="{StaticResource GreenBrush}" + BorderBrush="{StaticResource SolidBorderBrush}" + BorderThickness="1,1,1,1" + CornerRadius="2,12,0,0" > + <ContentPresenter x:Name="ContentSite" + VerticalAlignment="Center" + HorizontalAlignment="Center" + ContentSource="Header" + Margin="12,2,12,2" + RecognizesAccessKey="True"/> + </Border> + </Grid> + <ControlTemplate.Triggers> + <Trigger Property="IsSelected" Value="True"> + <Setter Property="Panel.ZIndex" Value="100" /> + <Setter TargetName="Border" Property="Background" Value="{StaticResource GreenDisabledBrush}" /> + <Setter TargetName="Border" Property="BorderThickness" Value="1,1,1,0" /> + </Trigger> + <Trigger Property="IsEnabled" Value="False"> + <Setter TargetName="Border" Property="Background" Value="{StaticResource DisabledBackgroundBrush}" /> + <Setter TargetName="Border" Property="BorderBrush" Value="{StaticResource DisabledBorderBrush}" /> + <Setter Property="Foreground" Value="{StaticResource DisabledForegroundBrush}" /> + </Trigger> + </ControlTemplate.Triggers> + </ControlTemplate> + </Setter.Value> + </Setter> + </Style> + </Window.Resources> + + <DockPanel> + <StatusBar DockPanel.Dock="Bottom" Height="26" Background="#FF234447" Margin="0"> + <StatusBar.ItemsPanel> + <ItemsPanelTemplate> + <Grid> + <Grid.RowDefinitions> + <RowDefinition Height="*"/> + </Grid.RowDefinitions> + <Grid.ColumnDefinitions> + <ColumnDefinition Width="Auto"/> + <ColumnDefinition Width="Auto"/> + <ColumnDefinition Width="Auto"/> + <ColumnDefinition Width="*"/> + <ColumnDefinition Width="Auto"/> + <ColumnDefinition Width="Auto"/> + </Grid.ColumnDefinitions> + </Grid> + </ItemsPanelTemplate> + </StatusBar.ItemsPanel> + <StatusBarItem Grid.Column="0" x:Name="networkId" Content="deadbeef00" Foreground="White" FontFamily="Lucida Console"/> + <StatusBarItem Grid.Column="1" x:Name="onlineStatus" Content="ONLINE" Foreground="White" FontFamily="Lucida Console"/> + <StatusBarItem Grid.Column="2" x:Name="versionString" Content="1.0.5" Foreground="White" FontFamily="Lucida Console"/> + <StatusBarItem Grid.Column="3" x:Name="blank" Content="" Height="43" Foreground="White"/> + <StatusBarItem Grid.Column="4"> + <TextBox x:Name="joinNetworkID" TextWrapping="Wrap" Width="140" HorizontalAlignment="Right" ToolTip="Enter Network ID" PreviewTextInput="OnNetworkEntered" MaxLength="16" FontFamily="Lucida Console" FontSize="12" BorderThickness="1"/> + </StatusBarItem> + <StatusBarItem Grid.Column="5" x:Name="statusBarButton" Foreground="White" RenderTransformOrigin="0.789,0.442"> + <Button x:Name="joinButton" Content="Join" Background="#FFFFB354" Width="76" Click="joinButton_Click"/> + </StatusBarItem> + </StatusBar> + <!--<TabControl Margin="0,0,0,0"> + <TabItem x:Name="Networks" Header="Networks" Foreground="White" IsSelected="True" IsManipulationEnabled="True">--> + <Grid Background="LightGray" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"> + <Grid.ColumnDefinitions> + <ColumnDefinition Width="*"/> + </Grid.ColumnDefinitions> + <Grid.RowDefinitions> + <RowDefinition Height="*"/> + </Grid.RowDefinitions> + <local:NetworksPage x:Name="networksPage" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Grid.Column="0" Grid.Row="0" Margin="0,0,0,0"/> + </Grid> + <!--</TabItem>--> + <!--<TabItem x:Name="Peers" Header="Peers" Foreground="White"> + <Grid Background="#FFE5E5E5" HorizontalAlignment="Left" VerticalAlignment="Top"> + <Grid.ColumnDefinitions> + <ColumnDefinition Width="*"/> + </Grid.ColumnDefinitions> + <Grid.RowDefinitions> + <RowDefinition Height="*"/> + </Grid.RowDefinitions> + <local:PeersPage x:Name="peersPage" HorizontalAlignment="Left" VerticalAlignment="Top" Grid.Column="0" Grid.Row="0"/> + </Grid> + </TabItem>--> + <!--</TabControl>--> + </DockPanel> +</Window> diff --git a/zerotierone/windows/WinUI/MainWindow.xaml.cs b/zerotierone/windows/WinUI/MainWindow.xaml.cs new file mode 100644 index 0000000..47f00bf --- /dev/null +++ b/zerotierone/windows/WinUI/MainWindow.xaml.cs @@ -0,0 +1,195 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using System.Timers; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; +using System.Windows.Threading; + +namespace WinUI +{ + /// <summary> + /// Interaction logic for MainWindow.xaml + /// </summary> + public partial class MainWindow : Window + { + APIHandler handler; + Regex charRegex = new Regex("[0-9a-fxA-FX]"); + Regex wholeStringRegex = new Regex("^[0-9a-fxA-FX]+$"); + + Timer timer = new Timer(); + + bool connected = false; + + public MainWindow() + { + InitializeComponent(); + + if (InitAPIHandler()) + { + networksPage.SetAPIHandler(handler); + + updateStatus(); + if (!connected) + { + MessageBox.Show("Unable to connect to ZeroTier Service."); + } + + updateNetworks(); + //updatePeers(); + + DataObject.AddPastingHandler(joinNetworkID, OnPaste); + + timer.Elapsed += new ElapsedEventHandler(OnUpdateTimer); + timer.Interval = 2000; + timer.Enabled = true; + } + } + + private bool InitAPIHandler() + { + String ztDir = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData) + "\\ZeroTier\\One"; + String authToken = ""; + Int32 port = 9993; + try + { + byte[] tmp = File.ReadAllBytes(ztDir + "\\authtoken.secret"); + authToken = System.Text.Encoding.ASCII.GetString(tmp).Trim(); + } + catch + { + MessageBox.Show("Unable to read ZeroTier One authtoken.secret from:\r\n" + ztDir, "ZeroTier One"); + this.Close(); + return false; + } + + if ((authToken == null) || (authToken.Length <= 0)) + { + MessageBox.Show("Unable to read ZeroTier One authtoken.secret from:\r\n" + ztDir, "ZeroTier One"); + this.Close(); + return false; + } + try + { + byte[] tmp = File.ReadAllBytes(ztDir + "\\zerotier-one.port"); + port = Int32.Parse(System.Text.Encoding.ASCII.GetString(tmp).Trim()); + if ((port <= 0) || (port > 65535)) + port = 9993; + } + catch + { + } + + handler = new APIHandler(port, authToken); + return true; + } + + private void updateStatus() + { + var status = handler.GetStatus(); + + if (status != null) + { + connected = true; + + networkId.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() => + { + this.networkId.Content = status.Address; + })); + versionString.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() => + { + this.versionString.Content = status.Version; + })); + onlineStatus.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() => + { + this.onlineStatus.Content = (status.Online ? "ONLINE" : "OFFLINE"); + })); + } + else + { + connected = false; + + networkId.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() => + { + this.networkId.Content = ""; + })); + versionString.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() => + { + this.versionString.Content = "0"; + })); + onlineStatus.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() => + { + this.onlineStatus.Content = "OFFLINE"; + })); + } + } + + private void updateNetworks() + { + var networks = handler.GetNetworks(); + + networksPage.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() => + { + networksPage.setNetworks(networks); + })); + } + + private void updatePeers() + { + //var peers = handler.GetPeers(); + + //peersPage.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() => + //{ + // peersPage.SetPeers(peers); + //})); + } + + private void OnUpdateTimer(object source, ElapsedEventArgs e) + { + updateStatus(); + updateNetworks(); + //updatePeers(); + } + + private void joinButton_Click(object sender, RoutedEventArgs e) + { + if (joinNetworkID.Text.Length < 16) + { + MessageBox.Show("Invalid Network ID"); + } + else + { + handler.JoinNetwork(joinNetworkID.Text); + } + } + + private void OnNetworkEntered(object sender, TextCompositionEventArgs e) + { + e.Handled = !charRegex.IsMatch(e.Text); + } + + private void OnPaste(object sender, DataObjectPastingEventArgs e) + { + var isText = e.SourceDataObject.GetDataPresent(DataFormats.UnicodeText, true); + if (!isText) return; + + var text = e.SourceDataObject.GetData(DataFormats.UnicodeText) as string; + + if (!wholeStringRegex.IsMatch(text)) + { + e.CancelCommand(); + } + } + } +} diff --git a/zerotierone/windows/WinUI/NetworkInfoView.xaml b/zerotierone/windows/WinUI/NetworkInfoView.xaml new file mode 100644 index 0000000..54ff037 --- /dev/null +++ b/zerotierone/windows/WinUI/NetworkInfoView.xaml @@ -0,0 +1,73 @@ +<UserControl Background="LightGray" x:Class="WinUI.NetworkInfoView" + 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" + mc:Ignorable="d" + > + + <Border Background="GhostWhite" BorderBrush="Gainsboro" BorderThickness="1" CornerRadius="8,8,8,8"> + <Grid Background="GhostWhite" Margin="10,10,10,10"> + <Grid.ColumnDefinitions> + <ColumnDefinition Width="auto"/> + <ColumnDefinition Width="10"/> + <ColumnDefinition Width="*"/> + </Grid.ColumnDefinitions> + <Grid.RowDefinitions> + <RowDefinition Height="auto"/> + <RowDefinition Height="auto"/> + <RowDefinition Height="auto"/> + <RowDefinition Height="auto"/> + <RowDefinition Height="auto"/> + <RowDefinition Height="auto"/> + <RowDefinition Height="auto"/> + <RowDefinition Height="auto"/> + <RowDefinition Height="auto"/> + <RowDefinition Height="auto"/> + <RowDefinition Height="auto"/> + <RowDefinition Height="auto"/> + </Grid.RowDefinitions> + + <Grid Grid.Column="0" Grid.Row="0" Grid.ColumnSpan="3"> + <Grid.ColumnDefinitions> + <ColumnDefinition Width="auto"/> + <ColumnDefinition Width="*"/> + </Grid.ColumnDefinitions> + + <TextBox x:Name="networkId" Text="8056c2e21c000001" HorizontalAlignment="Left" Grid.Column="0" Foreground="#FF91A2A3" FontFamily="Lucida Console" BorderThickness="0" IsReadOnly="true" Background="Transparent"/> + <TextBox x:Name="networkName" Text="earth.zerotier.net" HorizontalAlignment="Right" Grid.Column="1" Foreground="#FF000000" BorderThickness="0" IsReadOnly="true" Background="Transparent"/> + </Grid> + + <Separator Grid.Column="0" Grid.Row="1" Grid.ColumnSpan="3"/> + + <TextBlock TextWrapping="Wrap" Text="Status" HorizontalAlignment="Right" Grid.Column="0" Grid.Row="2" Foreground="#FF000000"/> + <TextBlock TextWrapping="Wrap" Text="Type" HorizontalAlignment="Right" Grid.Column="0" Grid.Row="3" Foreground="#FF000000"/> + <TextBlock TextWrapping="Wrap" Text="MAC" HorizontalAlignment="Right" Grid.Column="0" Grid.Row="4" Foreground="#FF000000"/> + <TextBlock TextWrapping="Wrap" Text="MTU" HorizontalAlignment="Right" Grid.Column="0" Grid.Row="5" Foreground="#FF000000"/> + <TextBlock TextWrapping="Wrap" Text="Broadcast" HorizontalAlignment="Right" Grid.Column="0" Grid.Row="6" Foreground="#FF000000"/> + <TextBlock TextWrapping="Wrap" Text="Bridging" HorizontalAlignment="Right" Grid.Column="0" Grid.Row="7" Foreground="#FF000000"/> + <TextBlock TextWrapping="Wrap" Text="Device" HorizontalAlignment="Right" Grid.Column="0" Grid.Row="8" Foreground="#FF000000"/> + <TextBlock TextWrapping="Wrap" Text="Managed IPs" HorizontalAlignment="Right" Grid.Column="0" Grid.Row="9" Foreground="#FF000000"/> + + <Rectangle Grid.Column="2" Grid.Row="2" Grid.RowSpan="8" Fill="#FFEEEEEE"/> + + <TextBlock x:Name="networkStatus" FontFamily="Lucida Console" TextWrapping="Wrap" HorizontalAlignment="Right" Text="OK" TextAlignment="Right" Grid.Column="2" Grid.Row="2" Foreground="#FF000000"/> + <TextBlock x:Name="networkType" FontFamily="Lucida Console" TextWrapping="Wrap" Text="PUBLIC" HorizontalAlignment="Right" Grid.Column="2" Grid.Row="3" Foreground="#FF000000"/> + <TextBlock x:Name="macAddress" FontFamily="Lucida Console" TextWrapping="Wrap" HorizontalAlignment="Right" Grid.Column="2" Grid.Row="4" Foreground="#FF000000"><Span><Run Text="02:83:4a:1e:4b:3a"/></Span></TextBlock> + <TextBlock x:Name="mtu" FontFamily="Lucida Console" TextWrapping="Wrap" Text="2800" HorizontalAlignment="Right" Grid.Column="2" Grid.Row="5" Foreground="#FF000000"/> + <TextBlock x:Name="broadcastEnabled" FontFamily="Lucida Console" TextWrapping="Wrap" Text="ENABLED" HorizontalAlignment="Right" Grid.Column="2" Grid.Row="6" Foreground="#FF000000"/> + <TextBlock x:Name="bridgingEnabled" FontFamily="Lucida Console" TextWrapping="Wrap" Text="DISABLED" HorizontalAlignment="Right" Grid.Column="2" Grid.Row="7" Background="#FFEEEEEE" Foreground="#FF000000"/> + <TextBlock x:Name="deviceName" FontFamily="Lucida Console" TextWrapping="Wrap" HorizontalAlignment="Right" Grid.Column="2" Grid.Row="8" Foreground="#FF000000"><Span><Run Text="ethernet_32771"/></Span></TextBlock> + <TextBlock x:Name="managedIps" TextWrapping="Wrap" FontFamily="Lucida Console" HorizontalAlignment="Right" TextAlignment="Right" Grid.Column="2" Grid.Row="9" Foreground="#FF000000"><Span><Run Text="28.2.169.248/7 "/></Span><LineBreak/><Span><Run Text="fd80:56c2:e21c:0000:0199:9383:4a02:a9f8/88"/></Span></TextBlock> + + <Separator Grid.Column="0" Grid.Row="10" Grid.ColumnSpan="3"/> + + <Grid Grid.Column="0" Grid.Row="11" Grid.ColumnSpan="3" Background="GhostWhite"> + <Grid.ColumnDefinitions> + <ColumnDefinition Width="*"/> + </Grid.ColumnDefinitions> + <Button x:Name="leaveButton" Content="Leave" HorizontalAlignment="Right" VerticalAlignment="Bottom" Width="75" Background="#FFFFB354" Click="leaveButton_Click"/> + </Grid> + </Grid> + </Border> +</UserControl> diff --git a/zerotierone/windows/WinUI/NetworkInfoView.xaml.cs b/zerotierone/windows/WinUI/NetworkInfoView.xaml.cs new file mode 100644 index 0000000..ccdec28 --- /dev/null +++ b/zerotierone/windows/WinUI/NetworkInfoView.xaml.cs @@ -0,0 +1,72 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; + +namespace WinUI +{ + /// <summary> + /// Interaction logic for NetworkInfoView.xaml + /// </summary> + public partial class NetworkInfoView : UserControl + { + private APIHandler handler; + private ZeroTierNetwork network; + + public NetworkInfoView(APIHandler handler, ZeroTierNetwork network) + { + InitializeComponent(); + + this.handler = handler; + this.network = network; + + UpdateNetworkData(); + } + + private void UpdateNetworkData() + { + this.networkId.Text = network.NetworkId; + this.networkName.Text = network.NetworkName; + this.networkStatus.Text = network.NetworkStatus; + this.networkType.Text = network.NetworkType; + this.macAddress.Text = network.MacAddress; + this.mtu.Text = network.MTU.ToString(); + this.broadcastEnabled.Text = (network.BroadcastEnabled ? "ENABLED" : "DISABLED"); + this.bridgingEnabled.Text = (network.Bridge ? "ENABLED" : "DISABLED"); + this.deviceName.Text = network.DeviceName; + + string iplist = ""; + for (int i = 0; i < network.AssignedAddresses.Length; ++i) + { + iplist += network.AssignedAddresses[i]; + if (i < (network.AssignedAddresses.Length - 1)) + iplist += "\n"; + } + + this.managedIps.Text = iplist; + } + + public bool HasNetwork(ZeroTierNetwork network) + { + if (this.network.NetworkId.Equals(network.NetworkId)) + return true; + + return false; + } + + private void leaveButton_Click(object sender, RoutedEventArgs e) + { + handler.LeaveNetwork(network.NetworkId); + } + } +} diff --git a/zerotierone/windows/WinUI/NetworksPage.xaml b/zerotierone/windows/WinUI/NetworksPage.xaml new file mode 100644 index 0000000..6f95bc0 --- /dev/null +++ b/zerotierone/windows/WinUI/NetworksPage.xaml @@ -0,0 +1,13 @@ +<UserControl x:Class="WinUI.NetworksPage" + 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" + mc:Ignorable="d" + d:DesignHeight="300" d:DesignWidth="300"> + <ScrollViewer x:Name="MyScrollViewer" HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"> + <UniformGrid x:Name="wrapPanel" Background="#FFDDDDDD" HorizontalAlignment="Stretch" VerticalAlignment="Top" Columns="1"> + + </UniformGrid> + </ScrollViewer> +</UserControl> diff --git a/zerotierone/windows/WinUI/NetworksPage.xaml.cs b/zerotierone/windows/WinUI/NetworksPage.xaml.cs new file mode 100644 index 0000000..5a0dc19 --- /dev/null +++ b/zerotierone/windows/WinUI/NetworksPage.xaml.cs @@ -0,0 +1,52 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; + +namespace WinUI +{ + /// <summary> + /// Interaction logic for NetworksPage.xaml + /// </summary> + public partial class NetworksPage : UserControl + { + private APIHandler handler; + + public NetworksPage() + { + InitializeComponent(); + } + + public void SetAPIHandler(APIHandler handler) + { + this.handler = handler; + } + + public void setNetworks(List<ZeroTierNetwork> networks) + { + this.wrapPanel.Children.Clear(); + if (networks == null) + { + return; + } + + for (int i = 0; i < networks.Count; ++i) + { + this.wrapPanel.Children.Add( + new NetworkInfoView( + handler, + networks.ElementAt<ZeroTierNetwork>(i))); + } + } + } +} diff --git a/zerotierone/windows/WinUI/PeersPage.xaml b/zerotierone/windows/WinUI/PeersPage.xaml new file mode 100644 index 0000000..57b11ed --- /dev/null +++ b/zerotierone/windows/WinUI/PeersPage.xaml @@ -0,0 +1,26 @@ +<UserControl x:Class="WinUI.PeersPage" + 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" + mc:Ignorable="d" + d:DesignHeight="300" d:DesignWidth="300" Background="White" Foreground="Black"> + + <DataGrid x:Name="dataGrid" GridLinesVisibility="None" AutoGenerateColumns="False" CanUserResizeColumns="True" Margin="0,0,0,0" CanUserReorderColumns="False" HorizontalAlignment="Stretch" VerticalScrollBarVisibility="Auto" CanUserSortColumns="False"> + <DataGrid.CellStyle> + <Style TargetType="DataGridCell"> + <Setter Property="BorderThickness" Value="0"/> + <Setter Property="FocusVisualStyle" Value="{x:Null}"/> + </Style> + </DataGrid.CellStyle> + <DataGrid.Columns> + <DataGridTextColumn Header="Address" Binding="{Binding Address}"/> + <DataGridTextColumn Header="Version" Binding="{Binding VersionString}"/> + <DataGridTextColumn Header="Latency" Binding="{Binding Latency}"/> + <DataGridTextColumn Header="Data Paths" Binding="{Binding DataPaths}"/> + <DataGridTextColumn Header="Last Unicast" Binding="{Binding LastUnicastFrame}"/> + <DataGridTextColumn Header="Last Multicast" Binding="{Binding LastMulticastFrame}"/> + <DataGridTextColumn Width="*" Header="Role" Binding="{Binding Role}"/> + </DataGrid.Columns> + </DataGrid> +</UserControl> diff --git a/zerotierone/windows/WinUI/PeersPage.xaml.cs b/zerotierone/windows/WinUI/PeersPage.xaml.cs new file mode 100644 index 0000000..fac22a4 --- /dev/null +++ b/zerotierone/windows/WinUI/PeersPage.xaml.cs @@ -0,0 +1,54 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; + +namespace WinUI +{ + /// <summary> + /// Interaction logic for PeersPage.xaml + /// </summary> + public partial class PeersPage : UserControl + { + private List<ZeroTierPeer> peersList = new List<ZeroTierPeer>(); + + public PeersPage() + { + InitializeComponent(); + + dataGrid.ItemsSource = peersList; + } + + public void SetPeers(List<ZeroTierPeer> list) + { + if (list == null) + return; + + + foreach(ZeroTierPeer p in list) + { + ZeroTierPeer curPeer = peersList.Find(peer => peer.Equals(p)); + if (curPeer == null) + { + peersList.Add(p); + } + else + { + curPeer.Update(p); + } + } + + dataGrid.Items.Refresh(); + } + } +} diff --git a/zerotierone/windows/WinUI/Properties/AssemblyInfo.cs b/zerotierone/windows/WinUI/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..9c7cd13 --- /dev/null +++ b/zerotierone/windows/WinUI/Properties/AssemblyInfo.cs @@ -0,0 +1,56 @@ +using System.Reflection; +using System.Resources; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Windows; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("ZeroTier One")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("ZeroTier, Inc")] +[assembly: AssemblyProduct("ZeroTier One")] +[assembly: AssemblyCopyright("Copyright © 2015")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +//In order to begin building localizable applications, set +//<UICulture>CultureYouAreCodingWith</UICulture> in your .csproj file +//inside a <PropertyGroup>. For example, if you are using US english +//in your source files, set the <UICulture> to en-US. Then uncomment +//the NeutralResourceLanguage attribute below. Update the "en-US" in +//the line below to match the UICulture setting in the project file. + +//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)] + + +[assembly: ThemeInfo( + ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located + //(used if a resource is not found in the page, + // or application resource dictionaries) + ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located + //(used if a resource is not found in the page, + // app, or any theme specific resource dictionaries) +)] + + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] +[assembly: NeutralResourcesLanguageAttribute("en-US")] diff --git a/zerotierone/windows/WinUI/Properties/Resources.Designer.cs b/zerotierone/windows/WinUI/Properties/Resources.Designer.cs new file mode 100644 index 0000000..57a56f7 --- /dev/null +++ b/zerotierone/windows/WinUI/Properties/Resources.Designer.cs @@ -0,0 +1,71 @@ +//------------------------------------------------------------------------------ +// <auto-generated> +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// </auto-generated> +//------------------------------------------------------------------------------ + +namespace WinUI.Properties +{ + + + /// <summary> + /// A strongly-typed resource class, for looking up localized strings, etc. + /// </summary> + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources + { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() + { + } + + /// <summary> + /// Returns the cached ResourceManager instance used by this class. + /// </summary> + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager + { + get + { + if ((resourceMan == null)) + { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("WinUI.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// <summary> + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// </summary> + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture + { + get + { + return resourceCulture; + } + set + { + resourceCulture = value; + } + } + } +} diff --git a/zerotierone/windows/WinUI/Properties/Resources.resx b/zerotierone/windows/WinUI/Properties/Resources.resx new file mode 100644 index 0000000..af7dbeb --- /dev/null +++ b/zerotierone/windows/WinUI/Properties/Resources.resx @@ -0,0 +1,117 @@ +<?xml version="1.0" encoding="utf-8"?> +<root> + <!-- + Microsoft ResX Schema + + Version 2.0 + + The primary goals of this format is to allow a simple XML format + that is mostly human readable. The generation and parsing of the + various data types are done through the TypeConverter classes + associated with the data types. + + Example: + + ... ado.net/XML headers & schema ... + <resheader name="resmimetype">text/microsoft-resx</resheader> + <resheader name="version">2.0</resheader> + <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader> + <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader> + <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data> + <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data> + <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64"> + <value>[base64 mime encoded serialized .NET Framework object]</value> + </data> + <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64"> + <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value> + <comment>This is a comment</comment> + </data> + + There are any number of "resheader" rows that contain simple + name/value pairs. + + Each data row contains a name, and value. The row also contains a + type or mimetype. Type corresponds to a .NET class that support + text/value conversion through the TypeConverter architecture. + Classes that don't support this are serialized and stored with the + mimetype set. + + The mimetype is used for serialized objects, and tells the + ResXResourceReader how to depersist the object. This is currently not + extensible. For a given mimetype the value must be set accordingly: + + Note - application/x-microsoft.net.object.binary.base64 is the format + that the ResXResourceWriter will generate, however the reader can + read any of the formats listed below. + + mimetype: application/x-microsoft.net.object.binary.base64 + value : The object must be serialized with + : System.Serialization.Formatters.Binary.BinaryFormatter + : and then encoded with base64 encoding. + + mimetype: application/x-microsoft.net.object.soap.base64 + value : The object must be serialized with + : System.Runtime.Serialization.Formatters.Soap.SoapFormatter + : and then encoded with base64 encoding. + + mimetype: application/x-microsoft.net.object.bytearray.base64 + value : The object must be serialized into a byte array + : using a System.ComponentModel.TypeConverter + : and then encoded with base64 encoding. + --> + <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"> + <xsd:element name="root" msdata:IsDataSet="true"> + <xsd:complexType> + <xsd:choice maxOccurs="unbounded"> + <xsd:element name="metadata"> + <xsd:complexType> + <xsd:sequence> + <xsd:element name="value" type="xsd:string" minOccurs="0" /> + </xsd:sequence> + <xsd:attribute name="name" type="xsd:string" /> + <xsd:attribute name="type" type="xsd:string" /> + <xsd:attribute name="mimetype" type="xsd:string" /> + </xsd:complexType> + </xsd:element> + <xsd:element name="assembly"> + <xsd:complexType> + <xsd:attribute name="alias" type="xsd:string" /> + <xsd:attribute name="name" type="xsd:string" /> + </xsd:complexType> + </xsd:element> + <xsd:element name="data"> + <xsd:complexType> + <xsd:sequence> + <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> + <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" /> + </xsd:sequence> + <xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" /> + <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" /> + <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" /> + </xsd:complexType> + </xsd:element> + <xsd:element name="resheader"> + <xsd:complexType> + <xsd:sequence> + <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> + </xsd:sequence> + <xsd:attribute name="name" type="xsd:string" use="required" /> + </xsd:complexType> + </xsd:element> + </xsd:choice> + </xsd:complexType> + </xsd:element> + </xsd:schema> + <resheader name="resmimetype"> + <value>text/microsoft-resx</value> + </resheader> + <resheader name="version"> + <value>2.0</value> + </resheader> + <resheader name="reader"> + <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </resheader> + <resheader name="writer"> + <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </resheader> +</root>
\ No newline at end of file diff --git a/zerotierone/windows/WinUI/Properties/Settings.Designer.cs b/zerotierone/windows/WinUI/Properties/Settings.Designer.cs new file mode 100644 index 0000000..6812ccc --- /dev/null +++ b/zerotierone/windows/WinUI/Properties/Settings.Designer.cs @@ -0,0 +1,30 @@ +//------------------------------------------------------------------------------ +// <auto-generated> +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// </auto-generated> +//------------------------------------------------------------------------------ + +namespace WinUI.Properties +{ + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")] + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase + { + + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); + + public static Settings Default + { + get + { + return defaultInstance; + } + } + } +} diff --git a/zerotierone/windows/WinUI/Properties/Settings.settings b/zerotierone/windows/WinUI/Properties/Settings.settings new file mode 100644 index 0000000..033d7a5 --- /dev/null +++ b/zerotierone/windows/WinUI/Properties/Settings.settings @@ -0,0 +1,7 @@ +<?xml version='1.0' encoding='utf-8'?> +<SettingsFile xmlns="uri:settings" CurrentProfile="(Default)"> + <Profiles> + <Profile Name="(Default)" /> + </Profiles> + <Settings /> +</SettingsFile>
\ No newline at end of file diff --git a/zerotierone/windows/WinUI/Simple Styles.xaml b/zerotierone/windows/WinUI/Simple Styles.xaml new file mode 100644 index 0000000..f2ddedf --- /dev/null +++ b/zerotierone/windows/WinUI/Simple Styles.xaml @@ -0,0 +1,1121 @@ +<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/interactivedesigner/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d"> + + <!-- SimpleStyles.XAML defines a set of control styles which are simplified starting points for creating your own controls --> + + <!-- Brushes : These are used to define the color for background, foreground, selection, enabled etc of all controls + If you want to change the color of a control you can just chnage the brush; if you want to add a new shape or change arrangement then also edit the template --> + + <!-- NormalBrush is used as the Background for SimpleButton, SimpleRepeatButton --> + <LinearGradientBrush x:Key="NormalBrush" EndPoint="0,1" StartPoint="0,0"> + <GradientStop Color="#EEE" Offset="0.0"/> + <GradientStop Color="#CCC" Offset="1.0"/> + </LinearGradientBrush> + <LinearGradientBrush x:Key="NormalBorderBrush" EndPoint="0,1" StartPoint="0,0"> + <GradientStop Color="#CCC" Offset="0.0"/> + <GradientStop Color="#444" Offset="1.0"/> + </LinearGradientBrush> + + <!-- LightBrush is used for content areas such as Menu, Tab Control background --> + <LinearGradientBrush x:Key="LightBrush" EndPoint="0,1" StartPoint="0,0"> + <GradientStop Color="#FFF" Offset="0.0"/> + <GradientStop Color="#EEE" Offset="1.0"/> + </LinearGradientBrush> + + <!-- MouseOverBrush is used for MouseOver in Button, Radio Button, CheckBox --> + <LinearGradientBrush x:Key="MouseOverBrush" EndPoint="0,1" StartPoint="0,0"> + <GradientStop Color="#FFF" Offset="0.0"/> + <GradientStop Color="#AAA" Offset="1.0"/> + </LinearGradientBrush> + + <!-- PressedBrush is used for Pressed in Button, Radio Button, CheckBox --> + <LinearGradientBrush x:Key="PressedBrush" EndPoint="0,1" StartPoint="0,0"> + <GradientStop Color="#BBB" Offset="0.0"/> + <GradientStop Color="#EEE" Offset="0.1"/> + <GradientStop Color="#EEE" Offset="0.9"/> + <GradientStop Color="#FFF" Offset="1.0"/> + </LinearGradientBrush> + <LinearGradientBrush x:Key="PressedBorderBrush" EndPoint="0,1" StartPoint="0,0"> + <GradientStop Color="#444" Offset="0.0"/> + <GradientStop Color="#888" Offset="1.0"/> + </LinearGradientBrush> + + <!-- SelectedBackgroundBrush is used for the Selected item in ListBoxItem, ComboBoxItem--> + <SolidColorBrush x:Key="SelectedBackgroundBrush" Color="#DDD"/> + + <!-- Disabled Brushes are used for the Disabled look of each control --> + <SolidColorBrush x:Key="DisabledForegroundBrush" Color="#888"/> + <SolidColorBrush x:Key="DisabledBackgroundBrush" Color="#EEE"/> + <SolidColorBrush x:Key="DisabledBorderBrush" Color="#AAA"/> + + <!-- Used for background of ScrollViewer, TreeView, ListBox, Expander, TextBox, Tab Control --> + <SolidColorBrush x:Key="WindowBackgroundBrush" Color="#FFF"/> + + <!-- DefaultedBorderBrush is used to show KeyBoardFocus --> + <LinearGradientBrush x:Key="DefaultedBorderBrush" EndPoint="0,1" StartPoint="0,0"> + <GradientStop Color="#777" Offset="0.0"/> + <GradientStop Color="#000" Offset="1.0"/> + </LinearGradientBrush> + + <SolidColorBrush x:Key="SolidBorderBrush" Color="#888"/> + <SolidColorBrush x:Key="LightBorderBrush" Color="#AAA"/> + <SolidColorBrush x:Key="LightColorBrush" Color="#DDD"/> + + <!-- Used for Checkmark, Radio button, TreeViewItem, Expander ToggleButton glyphs --> + <SolidColorBrush x:Key="GlyphBrush" Color="#444"/> + + + <!-- Style and Template pairs are used to define each control Part --> + <!-- The Style provides default values on the control; the Template gives the elements for each control --> + + <!-- SimpleButtonFocusVisual is used to show keyboard focus around a SimpleButton control --> + <Style x:Key="SimpleButtonFocusVisual"> + <Setter Property="Control.Template"> + <Setter.Value> + <ControlTemplate> + <Border> + <Rectangle Margin="2" Stroke="#60000000" StrokeThickness="1" StrokeDashArray="1 2"/> + </Border> + </ControlTemplate> + </Setter.Value> + </Setter> + </Style> + + <!-- Simple Button - This control sets brushes on each state. Note that these brushes must be listed above since they are static resources --> + <Style x:Key="SimpleButton" TargetType="{x:Type Button}" BasedOn="{x:Null}"> + <Setter Property="FocusVisualStyle" Value="{DynamicResource SimpleButtonFocusVisual}"/> + <Setter Property="Background" Value="{DynamicResource NormalBrush}"/> + <Setter Property="BorderBrush" Value="{DynamicResource NormalBorderBrush}"/> + <Setter Property="Template"> + <Setter.Value> + <ControlTemplate TargetType="{x:Type Button}"> + + <!-- We use Grid as a root because it is easy to add more elements to customize the button --> + <Grid x:Name="Grid"> + <Border x:Name="Border" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Padding="{TemplateBinding Padding}"/> + + <!-- Content Presenter is where the text content etc is placed by the control --> + <!-- The bindings are useful so that the control can be parameterized without editing the template --> + <ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" RecognizesAccessKey="True"/> + </Grid> + + <!--Each state sets a brush on the Border in the template --> + <ControlTemplate.Triggers> + <Trigger Property="IsKeyboardFocused" Value="true"> + <Setter Property="BorderBrush" Value="{DynamicResource DefaultedBorderBrush}" TargetName="Border"/> + </Trigger> + <Trigger Property="IsMouseOver" Value="true"> + <Setter Property="Background" Value="{DynamicResource MouseOverBrush}" TargetName="Border"/> + </Trigger> + <Trigger Property="IsPressed" Value="true"> + <Setter Property="Background" Value="{DynamicResource PressedBrush}" TargetName="Border"/> + <Setter Property="BorderBrush" Value="{DynamicResource PressedBorderBrush}" TargetName="Border"/> + </Trigger> + <Trigger Property="IsEnabled" Value="true"/> + <Trigger Property="IsEnabled" Value="false"> + <Setter Property="Background" Value="{DynamicResource DisabledBackgroundBrush}" TargetName="Border"/> + <Setter Property="BorderBrush" Value="{DynamicResource DisabledBorderBrush}" TargetName="Border"/> + <Setter Property="Foreground" Value="{DynamicResource DisabledForegroundBrush}"/> + </Trigger> + </ControlTemplate.Triggers> + </ControlTemplate> + </Setter.Value> + </Setter> + </Style> + + <Style x:Key="RadioButtonFocusVisual"> + <Setter Property="Control.Template"> + <Setter.Value> + <ControlTemplate> + <Border> + <Rectangle Margin="15,0,0,0" Stroke="#60000000" StrokeThickness="1" StrokeDashArray="1 2"/> + </Border> + </ControlTemplate> + </Setter.Value> + </Setter> + </Style> + + <Style x:Key="CheckBoxFocusVisual"> + <Setter Property="Control.Template"> + <Setter.Value> + <ControlTemplate> + <Border> + <Rectangle Margin="15,0,0,0" Stroke="#60000000" StrokeThickness="1" StrokeDashArray="1 2"/> + </Border> + </ControlTemplate> + </Setter.Value> + </Setter> + </Style> + + <!-- Simple CheckBox --> + <Style x:Key="SimpleCheckBox" TargetType="{x:Type CheckBox}"> + <Setter Property="SnapsToDevicePixels" Value="true"/> + <Setter Property="FocusVisualStyle" Value="{DynamicResource CheckBoxFocusVisual}"/> + <Setter Property="Background" Value="{DynamicResource NormalBrush}"/> + <Setter Property="BorderBrush" Value="{DynamicResource NormalBorderBrush}"/> + <Setter Property="Template"> + <Setter.Value> + <ControlTemplate TargetType="{x:Type CheckBox}"> + + <!-- BulletDecorator is used to provide baseline alignment between the checkmark and the Content --> + <BulletDecorator Background="Transparent"> + <BulletDecorator.Bullet> + <Grid Width="13" Height="13"> + <Border x:Name="Border" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}"/> + <Path x:Name="CheckMark" Stroke="{DynamicResource GlyphBrush}" StrokeThickness="2" SnapsToDevicePixels="False" Data="M 0 0 L 13 13 M 0 13 L 13 0"/> + </Grid> + </BulletDecorator.Bullet> + <ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" RecognizesAccessKey="True"/> + </BulletDecorator> + + <!-- This uses Visibility to hide and show the CheckMark on IsChecked --> + <ControlTemplate.Triggers> + <Trigger Property="IsChecked" Value="false"> + <Setter Property="Visibility" Value="Collapsed" TargetName="CheckMark"/> + </Trigger> + <Trigger Property="IsMouseOver" Value="true"> + <Setter Property="Background" Value="{DynamicResource MouseOverBrush}" TargetName="Border"/> + </Trigger> + <Trigger Property="IsPressed" Value="true"> + <Setter Property="Background" Value="{DynamicResource PressedBrush}" TargetName="Border"/> + <Setter Property="BorderBrush" Value="{DynamicResource PressedBorderBrush}" TargetName="Border"/> + </Trigger> + <Trigger Property="IsEnabled" Value="false"> + <Setter Property="Background" Value="{DynamicResource DisabledBackgroundBrush}" TargetName="Border"/> + <Setter Property="BorderBrush" Value="{DynamicResource DisabledBorderBrush}" TargetName="Border"/> + </Trigger> + </ControlTemplate.Triggers> + + </ControlTemplate> + </Setter.Value> + </Setter> + </Style> + + <!-- Simple Radio Button --> + <Style x:Key="SimpleRadioButton" TargetType="{x:Type RadioButton}"> + <Setter Property="SnapsToDevicePixels" Value="true"/> + <Setter Property="FocusVisualStyle" Value="{DynamicResource RadioButtonFocusVisual}"/> + <Setter Property="Background" Value="{DynamicResource NormalBrush}"/> + <Setter Property="BorderBrush" Value="{DynamicResource NormalBorderBrush}"/> + <Setter Property="Template"> + <Setter.Value> + <ControlTemplate TargetType="{x:Type RadioButton}"> + + <!-- BulletDecorator is used to provide baseline alignment between the checkmark and the Content --> + <BulletDecorator Background="Transparent"> + <BulletDecorator.Bullet> + <Grid Width="13" Height="13"> + <Ellipse x:Name="Ellipse_Border" Fill="{TemplateBinding Background}" Stroke="{TemplateBinding BorderBrush}" StrokeThickness="1"/> + <Ellipse Margin="4" x:Name="CheckMark" Fill="{DynamicResource GlyphBrush}"/> + </Grid> + </BulletDecorator.Bullet> + <ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" RecognizesAccessKey="True"/> + </BulletDecorator> + + <ControlTemplate.Triggers> + <Trigger Property="IsChecked" Value="false"> + <Setter Property="Visibility" Value="Collapsed" TargetName="CheckMark"/> + </Trigger> + <Trigger Property="IsMouseOver" Value="true"> + <Setter Property="Fill" Value="{DynamicResource MouseOverBrush}" TargetName="Ellipse_Border"/> + </Trigger> + <Trigger Property="IsPressed" Value="true"> + <Setter Property="Fill" Value="{DynamicResource PressedBrush}" TargetName="Ellipse_Border"/> + <Setter Property="Stroke" Value="{DynamicResource GlyphBrush}" TargetName="Ellipse_Border"/> + </Trigger> + <Trigger Property="IsEnabled" Value="false"> + <Setter Property="Fill" Value="{DynamicResource DisabledBackgroundBrush}" TargetName="Ellipse_Border"/> + <Setter Property="Stroke" Value="#40000000" TargetName="Ellipse_Border"/> + <Setter Property="Foreground" Value="#80000000"/> + </Trigger> + + </ControlTemplate.Triggers> + </ControlTemplate> + </Setter.Value> + </Setter> + </Style> + + <!-- Simple Repeat Button - This is used by Simple ScrollBar for the up and down buttons --> + <Style x:Key="SimpleRepeatButton" d:IsControlPart="True" TargetType="{x:Type RepeatButton}" BasedOn="{x:Null}"> + <Setter Property="Background" Value="{DynamicResource NormalBrush}"/> + <Setter Property="BorderBrush" Value="{DynamicResource NormalBorderBrush}"/> + <Setter Property="Template"> + <Setter.Value> + <ControlTemplate TargetType="{x:Type RepeatButton}"> + <Grid> + <Border x:Name="Border" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}"/> + <ContentPresenter HorizontalAlignment="Center" x:Name="ContentPresenter" VerticalAlignment="Center" Content="{TemplateBinding Content}" ContentTemplate="{TemplateBinding ContentTemplate}" ContentTemplateSelector="{TemplateBinding ContentTemplateSelector}"/> + </Grid> + <ControlTemplate.Triggers> + <Trigger Property="IsKeyboardFocused" Value="true"> + <Setter Property="BorderBrush" Value="{DynamicResource DefaultedBorderBrush}" TargetName="Border"/> + </Trigger> + <Trigger Property="IsMouseOver" Value="true"> + <Setter Property="Background" Value="{DynamicResource MouseOverBrush}" TargetName="Border"/> + </Trigger> + <Trigger Property="IsPressed" Value="true"> + <Setter Property="Background" Value="{DynamicResource PressedBrush}" TargetName="Border"/> + <Setter Property="BorderBrush" Value="{DynamicResource PressedBorderBrush}" TargetName="Border"/> + </Trigger> + <Trigger Property="IsEnabled" Value="false"> + <Setter Property="Background" Value="{DynamicResource DisabledBackgroundBrush}" TargetName="Border"/> + <Setter Property="BorderBrush" Value="{DynamicResource DisabledBorderBrush}" TargetName="Border"/> + <Setter Property="Foreground" Value="{DynamicResource DisabledForegroundBrush}"/> + </Trigger> + </ControlTemplate.Triggers> + </ControlTemplate> + </Setter.Value> + </Setter> + </Style> + + <!-- Simple Thumb - The Thumb is the draggable part of the Scrollbar --> + <Style x:Key="SimpleThumbStyle" d:IsControlPart="True" TargetType="{x:Type Thumb}" BasedOn="{x:Null}"> + <Setter Property="Template"> + <Setter.Value> + <ControlTemplate TargetType="{x:Type Thumb}"> + <Grid Margin="0,0,0,0" x:Name="Grid"> + <Rectangle HorizontalAlignment="Stretch" x:Name="Rectangle" VerticalAlignment="Stretch" Width="Auto" Height="Auto" RadiusX="2" RadiusY="2" Fill="{DynamicResource NormalBrush}" Stroke="{DynamicResource NormalBorderBrush}"/> + </Grid> + <ControlTemplate.Triggers> + <Trigger Property="IsFocused" Value="True"/> + <Trigger Property="IsMouseOver" Value="True"/> + <Trigger Property="IsEnabled" Value="False"/> + <Trigger Property="IsDragging" Value="True"/> + </ControlTemplate.Triggers> + </ControlTemplate> + </Setter.Value> + </Setter> + </Style> + + <!-- Simple ScrollRepeatButton Style - This RepeatButton is used above and below the Thumb in the Scrollbar. They are set to transparent si that they do not show over the scrollbar --> + <Style x:Key="SimpleScrollRepeatButtonStyle" d:IsControlPart="True" TargetType="{x:Type RepeatButton}"> + <Setter Property="Background" Value="Transparent"/> + <Setter Property="BorderBrush" Value="Transparent"/> + <Setter Property="IsTabStop" Value="false"/> + <Setter Property="Focusable" Value="false"/> + <Setter Property="Template"> + <Setter.Value> + <ControlTemplate TargetType="{x:Type RepeatButton}"> + <Grid> + <Rectangle Fill="{TemplateBinding Background}" Stroke="{TemplateBinding BorderBrush}" StrokeThickness="{TemplateBinding BorderThickness}"/> + </Grid> + </ControlTemplate> + </Setter.Value> + </Setter> + </Style> + + <!-- Simple ScrollBar This makes use of SimpleThumb, SimpleRepeatButton and SimpleScrollRepeatButton --> + + <Style x:Key="SimpleScrollBar" TargetType="{x:Type ScrollBar}"> + <Setter Property="Stylus.IsFlicksEnabled" Value="false"/> + <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/> + <Setter Property="Template"> + <Setter.Value> + <ControlTemplate TargetType="{x:Type ScrollBar}"> + <Grid x:Name="GridRoot" Width="{DynamicResource {x:Static SystemParameters.VerticalScrollBarWidthKey}}" Background="{TemplateBinding Background}"> + <Grid.RowDefinitions> + <RowDefinition MaxHeight="18"/> + <RowDefinition Height="0.00001*"/> + <RowDefinition MaxHeight="18"/> + </Grid.RowDefinitions> + + <RepeatButton x:Name="DecreaseRepeat" Style="{DynamicResource SimpleRepeatButton}" Command="ScrollBar.LineUpCommand"> + <Grid> + <Path x:Name="DecreaseArrow" Stroke="{TemplateBinding Foreground}" StrokeThickness="1" Data="M 0 4 L 8 4 L 4 0 Z"/> + </Grid> + </RepeatButton> + + <!-- Track is a special layout container which sizes the thumb and the repeat button which do jump scrolling either side of it --> + <Track Grid.Row="1" x:Name="PART_Track" Orientation="Vertical" IsDirectionReversed="true"> + <Track.Thumb> + <Thumb Style="{DynamicResource SimpleThumbStyle}"/> + </Track.Thumb> + <Track.IncreaseRepeatButton> + <RepeatButton x:Name="PageUp" Style="{DynamicResource SimpleScrollRepeatButtonStyle}" Command="ScrollBar.PageDownCommand"/> + </Track.IncreaseRepeatButton> + <Track.DecreaseRepeatButton> + <RepeatButton x:Name="PageDown" Style="{DynamicResource SimpleScrollRepeatButtonStyle}" Command="ScrollBar.PageUpCommand"/> + </Track.DecreaseRepeatButton> + </Track> + + <RepeatButton Grid.Row="2" x:Name="IncreaseRepeat" Style="{DynamicResource SimpleRepeatButton}" Command="ScrollBar.LineDownCommand"> + <Grid> + <Path x:Name="IncreaseArrow" Stroke="{TemplateBinding Foreground}" StrokeThickness="1" Data="M 0 0 L 4 4 L 8 0 Z"/> + </Grid> + </RepeatButton> + </Grid> + + <!-- This uses a single template for ScrollBar and rotate it to be Horizontal + It also changes the commands so that the it does Left and Right instead of Up and Down Commands --> + <ControlTemplate.Triggers> + <Trigger Property="Orientation" Value="Horizontal"> + + <!-- Rotate the ScrollBar from Vertical to Horizontal --> + <Setter Property="LayoutTransform" TargetName="GridRoot"> + <Setter.Value> + <RotateTransform Angle="-90"/> + </Setter.Value> + </Setter> + + <!-- Track is bound to Orientation internally, so we need to rotate it back to Vertical --> + <Setter TargetName="PART_Track" Property="Orientation" Value="Vertical"/> + + <!-- Change the commands to do Horizontal commands --> + <Setter Property="Command" Value="ScrollBar.LineLeftCommand" TargetName="DecreaseRepeat"/> + <Setter Property="Command" Value="ScrollBar.LineRightCommand" TargetName="IncreaseRepeat"/> + <Setter Property="Command" Value="ScrollBar.PageLeftCommand" TargetName="PageDown"/> + <Setter Property="Command" Value="ScrollBar.PageRightCommand" TargetName="PageUp"/> + </Trigger> + </ControlTemplate.Triggers> + </ControlTemplate> + </Setter.Value> + </Setter> + </Style> + + <!-- Simple ScrollViewer + ScrollViewer is a Grid control which has a ContentPresenter and a Horizontal and Vertical ScrollBar + It is used by ListBox, MenuItem, ComboBox, and TreeView --> + <Style x:Key="SimpleScrollViewer" TargetType="{x:Type ScrollViewer}" BasedOn="{x:Null}"> + <Setter Property="Template"> + <Setter.Value> + <ControlTemplate TargetType="{x:Type ScrollViewer}"> + <Grid Background="{TemplateBinding Background}"> + <Grid.ColumnDefinitions> + <ColumnDefinition Width="*"/> + <ColumnDefinition Width="Auto"/> + </Grid.ColumnDefinitions> + <Grid.RowDefinitions> + <RowDefinition Height="*"/> + <RowDefinition Height="Auto"/> + </Grid.RowDefinitions> + <ScrollContentPresenter Grid.Column="0" Grid.Row="0" Margin="{TemplateBinding Padding}" Content="{TemplateBinding Content}" ContentTemplate="{TemplateBinding ContentTemplate}" CanContentScroll="{TemplateBinding CanContentScroll}"/> + + <!-- The visibility of the ScrollBars is controlled by the implementation fo the control --> + <ScrollBar Visibility="{TemplateBinding ComputedHorizontalScrollBarVisibility}" Grid.Column="0" Grid.Row="1" x:Name="PART_HorizontalScrollBar" Style="{DynamicResource SimpleScrollBar}" Orientation="Horizontal" Value="{Binding Path=HorizontalOffset, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}" ViewportSize="{TemplateBinding ViewportWidth}" Minimum="0" Maximum="{TemplateBinding ScrollableWidth}" /> + <ScrollBar Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}" Grid.Column="1" Grid.Row="0" x:Name="PART_VerticalScrollBar" Style="{DynamicResource SimpleScrollBar}" Orientation="Vertical" Value="{Binding Path=VerticalOffset, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}" ViewportSize="{TemplateBinding ViewportHeight}" Minimum="0" Maximum="{TemplateBinding ScrollableHeight}" /> + </Grid> + </ControlTemplate> + </Setter.Value> + </Setter> + </Style> + + <!-- Simple ListBox - This uses SimpleScrollViewer to allow items to be scrolled and SimpleListBoxItem to define the look of each item --> + <Style x:Key="SimpleListBox" TargetType="{x:Type ListBox}"> + <Setter Property="SnapsToDevicePixels" Value="true"/> + <Setter Property="Background" Value="{DynamicResource WindowBackgroundBrush}"/> + <Setter Property="BorderBrush" Value="{DynamicResource SolidBorderBrush}"/> + <Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Auto"/> + <Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto"/> + <Setter Property="ScrollViewer.CanContentScroll" Value="True"/> + <Setter Property="Template"> + <Setter.Value> + <ControlTemplate TargetType="{x:Type ListBox}"> + <Grid> + <Border x:Name="Border" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}"/> + <ScrollViewer Margin="1" Style="{DynamicResource SimpleScrollViewer}" Focusable="false" Background="{TemplateBinding Background}"> + + <!-- The StackPanel is used to display the children by setting IsItemsHost to be Trus --> + <StackPanel Margin="2" IsItemsHost="true"/> + + </ScrollViewer> + </Grid> + <ControlTemplate.Triggers> + <Trigger Property="IsEnabled" Value="false"> + <Setter Property="Background" Value="{DynamicResource DisabledBackgroundBrush}" TargetName="Border"/> + <Setter Property="BorderBrush" Value="{DynamicResource DisabledBorderBrush}" TargetName="Border"/> + </Trigger> + <Trigger Property="IsGrouping" Value="true"> + <Setter Property="ScrollViewer.CanContentScroll" Value="false"/> + </Trigger> + </ControlTemplate.Triggers> + </ControlTemplate> + </Setter.Value> + </Setter> + </Style> + + <!-- Simple ListBoxItem - This is used for each Item in a ListBox. The item's content is placed in the ContentPresenter --> + + <Style x:Key="SimpleListBoxItem" d:IsControlPart="True" TargetType="{x:Type ListBoxItem}"> + <Setter Property="SnapsToDevicePixels" Value="true"/> + <Setter Property="OverridesDefaultStyle" Value="true"/> + <Setter Property="Template"> + <Setter.Value> + <ControlTemplate TargetType="{x:Type ListBoxItem}"> + <Grid SnapsToDevicePixels="true"> + <Border x:Name="Border" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}"/> + <ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/> + </Grid> + <ControlTemplate.Triggers> + + <!-- Change IsSelected SelectedBackgroundBrush to set the selection color for the items --> + <Trigger Property="IsSelected" Value="true"> + <Setter Property="Background" Value="{DynamicResource SelectedBackgroundBrush}" TargetName="Border"/> + </Trigger> + + <Trigger Property="IsEnabled" Value="false"> + <Setter Property="Foreground" Value="{DynamicResource DisabledForegroundBrush}"/> + </Trigger> + </ControlTemplate.Triggers> + </ControlTemplate> + </Setter.Value> + </Setter> + </Style> + + <!-- Simple Expander ToggleButton - This Button is used by the Expander control. When it is toggled it switches visibility on the Up_Arrow and Down_Arrow --> + <ControlTemplate x:Key="ExpanderToggleButton" TargetType="{x:Type ToggleButton}"> + <Grid> + <Rectangle Margin="0,0,0,0" x:Name="Rectangle" Fill="Transparent" Stroke="{DynamicResource NormalBorderBrush}"/> + <Path HorizontalAlignment="Center" x:Name="Up_Arrow" VerticalAlignment="Center" Fill="{DynamicResource GlyphBrush}" Data="M 0 0 L 4 4 L 8 0 Z"/> + <Path Visibility="Collapsed" HorizontalAlignment="Center" x:Name="Down_Arrow" VerticalAlignment="Center" Fill="{DynamicResource GlyphBrush}" Data="M 0 4 L 4 0 L 8 4 Z"/> + </Grid> + <ControlTemplate.Triggers> + <Trigger Property="IsMouseOver" Value="true"> + <Setter Property="Fill" Value="{DynamicResource MouseOverBrush}" TargetName="Rectangle"/> + </Trigger> + <Trigger Property="IsPressed" Value="true"> + <Setter Property="Fill" Value="{DynamicResource PressedBrush}" TargetName="Rectangle"/> + </Trigger> + <Trigger Property="IsChecked" Value="true"> + <Setter Property="Visibility" Value="Visible" TargetName="Down_Arrow"/> + <Setter Property="Visibility" Value="Collapsed" TargetName="Up_Arrow"/> + </Trigger> + <Trigger Property="IsEnabled" Value="False"> + <Setter Property="Fill" Value="{DynamicResource DisabledBackgroundBrush}" TargetName="Rectangle"/> + <Setter Property="Stroke" Value="{DynamicResource DisabledBorderBrush}" TargetName="Rectangle"/> + <Setter Property="Foreground" Value="{DynamicResource DisabledForegroundBrush}"/> + <Setter Property="Fill" Value="{DynamicResource DisabledForegroundBrush}" TargetName="Up_Arrow"/> + </Trigger> + </ControlTemplate.Triggers> + </ControlTemplate> + + <!-- Simple Expander + This uses the Simpler ExpanderToggleButton. It sets Visibility on the ContentPresenter to expand + Limitations : The Simple Expander only expands down --> + <Style x:Key="SimpleExpander" TargetType="{x:Type Expander}"> + <Setter Property="Background" Value="{DynamicResource LightBrush}"/> + <Setter Property="BorderBrush" Value="{DynamicResource NormalBorderBrush}"/> + <Setter Property="Template"> + <Setter.Value> + <ControlTemplate TargetType="{x:Type Expander}"> + <Grid> + <Grid.RowDefinitions> + <RowDefinition Height="Auto"/> + <RowDefinition Height="*" x:Name="ContentRow"/> + </Grid.RowDefinitions> + <Border Grid.Row="0" x:Name="Border" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" CornerRadius="2,2,0,0"> + <Grid> + <Grid.ColumnDefinitions> + <ColumnDefinition Width="20"/> + <ColumnDefinition Width="*"/> + </Grid.ColumnDefinitions> + <ToggleButton Template="{DynamicResource ExpanderToggleButton}" Background="{DynamicResource NormalBrush}" IsChecked="{Binding Path=IsExpanded, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}" OverridesDefaultStyle="True"/> + <ContentPresenter Grid.Column="1" Margin="4" RecognizesAccessKey="True" ContentSource="Header"/> + </Grid> + </Border> + <Border Visibility="Collapsed" Grid.Row="1" x:Name="ExpandSite" Background="{DynamicResource WindowBackgroundBrush}" BorderBrush="{DynamicResource SolidBorderBrush}" BorderThickness="1,0,1,1" CornerRadius="0,0,2,2"> + <ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" Focusable="false"/> + </Border> + </Grid> + <ControlTemplate.Triggers> + <Trigger Property="IsExpanded" Value="True"> + <Setter Property="Visibility" Value="Visible" TargetName="ExpandSite"/> + </Trigger> + <Trigger Property="IsEnabled" Value="False"> + <Setter Property="Background" Value="{DynamicResource DisabledBackgroundBrush}" TargetName="Border"/> + <Setter Property="BorderBrush" Value="{DynamicResource DisabledBorderBrush}" TargetName="Border"/> + <Setter Property="Foreground" Value="{DynamicResource DisabledForegroundBrush}"/> + </Trigger> + </ControlTemplate.Triggers> + </ControlTemplate> + </Setter.Value> + </Setter> + </Style> + + <!-- Simple ComboBox Toggle Button - This is used in ComboBox to expand and collapse the ComboBox Popup--> + <ControlTemplate x:Key="ComboBoxToggleButton" TargetType="{x:Type ToggleButton}"> + <Grid> + <Grid.ColumnDefinitions> + <ColumnDefinition/> + <ColumnDefinition Width="20"/> + </Grid.ColumnDefinitions> + <Rectangle Grid.ColumnSpan="2" HorizontalAlignment="Stretch" x:Name="Rectangle" VerticalAlignment="Stretch" Width="Auto" Height="Auto" RadiusX="5" RadiusY="5" Fill="{DynamicResource NormalBrush}" Stroke="{DynamicResource NormalBorderBrush}"/> + <Rectangle Grid.Column="0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Width="Auto" Height="Auto" RadiusX="5" RadiusY="5" Fill="{DynamicResource WindowBackgroundBrush}" Stroke="{DynamicResource NormalBorderBrush}"/> + <Path Grid.Column="1" HorizontalAlignment="Center" x:Name="Arrow" VerticalAlignment="Center" Fill="{DynamicResource GlyphBrush}" Data="M 0 0 L 4 4 L 8 0 Z"/> + </Grid> + <ControlTemplate.Triggers> + <Trigger Property="IsMouseOver" Value="true"> + <Setter Property="Fill" Value="{DynamicResource MouseOverBrush}" TargetName="Rectangle"/> + </Trigger> + <Trigger Property="IsChecked" Value="true"> + <Setter Property="Fill" Value="{DynamicResource PressedBrush}" TargetName="Rectangle"/> + </Trigger> + <Trigger Property="IsEnabled" Value="False"> + <Setter Property="Fill" Value="{DynamicResource DisabledBackgroundBrush}" TargetName="Rectangle"/> + <Setter Property="Stroke" Value="{DynamicResource DisabledBorderBrush}" TargetName="Rectangle"/> + <Setter Property="Foreground" Value="{DynamicResource DisabledForegroundBrush}"/> + <Setter Property="Fill" Value="{DynamicResource DisabledForegroundBrush}" TargetName="Arrow"/> + </Trigger> + </ControlTemplate.Triggers> + </ControlTemplate> + + <!-- This is the area which contains the selected item in the ComboBox --> + + <ControlTemplate x:Key="ComboBoxTextBox" TargetType="{x:Type TextBox}"> + <!-- This must be named as PART_ContentHost --> + <Border x:Name="PART_ContentHost" Focusable="False" Background="{TemplateBinding Background}"/> + </ControlTemplate> + + <!-- Simple ComboBox + This uses the ComboBoxToggleButton to expand and collapse a Popup control + SimpleScrollViewer to allow items to be scrolled and SimpleComboBoxItem to define the look of each item + The Popup shows a list of items in a StackPanel--> + + <Style x:Key="SimpleComboBox" TargetType="{x:Type ComboBox}"> + <Setter Property="SnapsToDevicePixels" Value="true"/> + <Setter Property="Template"> + <Setter.Value> + <ControlTemplate TargetType="{x:Type ComboBox}"> + <Grid> + <!-- The ToggleButton is databound to the ComboBox itself to toggle IsDropDownOpen --> + <ToggleButton Grid.Column="2" Template="{DynamicResource ComboBoxToggleButton}" x:Name="ToggleButton" Focusable="false" IsChecked="{Binding Path=IsDropDownOpen, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}" ClickMode="Press"/> + <ContentPresenter HorizontalAlignment="Left" Margin="3,3,23,3" x:Name="ContentSite" VerticalAlignment="Center" Content="{TemplateBinding SelectionBoxItem}" ContentTemplate="{TemplateBinding SelectionBoxItemTemplate}" ContentTemplateSelector="{TemplateBinding ItemTemplateSelector}" IsHitTestVisible="False"/> + + <!-- The TextBox must be named PART_EditableTextBox or ComboBox will not recognize it --> + <TextBox Visibility="Hidden" Template="{DynamicResource ComboBoxTextBox}" HorizontalAlignment="Left" Margin="3,3,23,3" x:Name="PART_EditableTextBox" Style="{x:Null}" VerticalAlignment="Center" Focusable="True" Background="Transparent" IsReadOnly="{TemplateBinding IsReadOnly}"/> + + <!-- The Popup shows the list of items in the ComboBox. IsOpen is databound to IsDropDownOpen which is toggled via the ComboBoxToggleButton --> + <Popup IsOpen="{TemplateBinding IsDropDownOpen}" Placement="Bottom" x:Name="Popup" Focusable="False" AllowsTransparency="True" PopupAnimation="Slide"> + <Grid MaxHeight="{TemplateBinding MaxDropDownHeight}" MinWidth="{TemplateBinding ActualWidth}" x:Name="DropDown" SnapsToDevicePixels="True"> + <Border x:Name="DropDownBorder" Background="{DynamicResource WindowBackgroundBrush}" BorderBrush="{DynamicResource SolidBorderBrush}" BorderThickness="1"/> + <ScrollViewer Margin="4,6,4,6" Style="{DynamicResource SimpleScrollViewer}" SnapsToDevicePixels="True" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto" CanContentScroll="True"> + + <!-- The StackPanel is used to display the children by setting IsItemsHost to be True --> + <StackPanel IsItemsHost="True" KeyboardNavigation.DirectionalNavigation="Contained"/> + + </ScrollViewer> + </Grid> + </Popup> + </Grid> + <ControlTemplate.Triggers> + <!-- This forces the DropDown to have a minimum size if it is empty --> + <Trigger Property="HasItems" Value="false"> + <Setter Property="MinHeight" Value="95" TargetName="DropDownBorder"/> + </Trigger> + <Trigger Property="IsEnabled" Value="false"> + <Setter Property="Foreground" Value="{DynamicResource DisabledForegroundBrush}"/> + </Trigger> + <Trigger Property="IsGrouping" Value="true"> + <Setter Property="ScrollViewer.CanContentScroll" Value="false"/> + </Trigger> + <Trigger Property="AllowsTransparency" SourceName="Popup" Value="true"> + <Setter Property="CornerRadius" Value="4" TargetName="DropDownBorder"/> + <Setter Property="Margin" Value="0,2,0,0" TargetName="DropDownBorder"/> + </Trigger> + <Trigger Property="IsEditable" Value="true"> + <Setter Property="IsTabStop" Value="false"/> + <Setter Property="Visibility" Value="Visible" TargetName="PART_EditableTextBox"/> + <Setter Property="Visibility" Value="Hidden" TargetName="ContentSite"/> + </Trigger> + </ControlTemplate.Triggers> + </ControlTemplate> + </Setter.Value> + </Setter> + </Style> + + <!-- Simple ComboBoxItem - This is used for each item inside of the ComboBox. You can change the selected color of each item below--> + <Style x:Key="SimpleComboBoxItem" d:IsControlPart="True" TargetType="{x:Type ComboBoxItem}"> + <Setter Property="SnapsToDevicePixels" Value="true"/> + <Setter Property="Template"> + <Setter.Value> + <ControlTemplate TargetType="{x:Type ComboBoxItem}"> + <Grid SnapsToDevicePixels="true"> + <Border x:Name="Border" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}"/> + <ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/> + </Grid> + <ControlTemplate.Triggers> + + <!-- Change IsHighlighted SelectedBackgroundBrush to set the selection color for the items --> + <Trigger Property="IsHighlighted" Value="true"> + <Setter Property="Background" Value="{DynamicResource SelectedBackgroundBrush}" TargetName="Border"/> + </Trigger> + + <Trigger Property="IsEnabled" Value="false"> + <Setter Property="Foreground" Value="{DynamicResource DisabledForegroundBrush}"/> + </Trigger> + </ControlTemplate.Triggers> + </ControlTemplate> + </Setter.Value> + </Setter> + </Style> + + <!-- Simple SimpleProgressBar + The template uses two Border controls to show the Track and Progress + Limitations : It only supports a horizontal orientated ProgressBar --> + <Style x:Key="SimpleProgressBar" TargetType="{x:Type ProgressBar}"> + <Setter Property="Template"> + <Setter.Value> + <ControlTemplate TargetType="{x:Type ProgressBar}"> + <Grid> + + <!-- This Border is the track. It must be named PART_Track --> + <Border x:Name="PART_Track" Background="{DynamicResource PressedBrush}" BorderBrush="{DynamicResource SolidBorderBrush}" BorderThickness="1" CornerRadius="2"/> + + <!-- This Border shows progress. It must be named PART_Indicator for the control to function --> + <Border HorizontalAlignment="Left" x:Name="PART_Indicator" Background="{DynamicResource MouseOverBrush}" BorderBrush="{DynamicResource NormalBorderBrush}" BorderThickness="1" CornerRadius="2"/> + + </Grid> + </ControlTemplate> + </Setter.Value> + </Setter> + </Style> + + <!-- Simple TextBox --> + <Style x:Key="SimpleTextBox" TargetType="{x:Type TextBox}"> + <Setter Property="KeyboardNavigation.TabNavigation" Value="None"/> + <Setter Property="FocusVisualStyle" Value="{x:Null}"/> + <Setter Property="AllowDrop" Value="true"/> + <Setter Property="Template"> + <Setter.Value> + <ControlTemplate TargetType="{x:Type TextBox}"> + <Grid> + <Border x:Name="Border" Background="{DynamicResource WindowBackgroundBrush}" BorderBrush="{DynamicResource SolidBorderBrush}" BorderThickness="1" Padding="2" CornerRadius="2"> + + <!-- The implementation places the Content into the ScrollViewer. It must be named PART_ContentHost for the control to function --> + <ScrollViewer Margin="0" x:Name="PART_ContentHost" Style="{DynamicResource SimpleScrollViewer}" Background="{TemplateBinding Background}"/> + + </Border> + </Grid> + <ControlTemplate.Triggers> + <Trigger Property="IsEnabled" Value="False"> + <Setter Property="Background" Value="{DynamicResource DisabledBackgroundBrush}" TargetName="Border"/> + <Setter Property="BorderBrush" Value="{DynamicResource DisabledBackgroundBrush}" TargetName="Border"/> + <Setter Property="Foreground" Value="{DynamicResource DisabledForegroundBrush}"/> + </Trigger> + </ControlTemplate.Triggers> + </ControlTemplate> + </Setter.Value> + </Setter> + </Style> + + <!-- Simple Label - This template is just a ContentPresenter that shows the content of the Label --> + <Style x:Key="SimpleLabel" TargetType="{x:Type Label}"> + <Setter Property="HorizontalContentAlignment" Value="Left"/> + <Setter Property="VerticalContentAlignment" Value="Top"/> + <Setter Property="Template"> + <Setter.Value> + <ControlTemplate TargetType="{x:Type Label}"> + <Grid> + <ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" RecognizesAccessKey="True"/> + </Grid> + <ControlTemplate.Triggers> + <Trigger Property="IsEnabled" Value="false"/> + </ControlTemplate.Triggers> + </ControlTemplate> + </Setter.Value> + </Setter> + </Style> + + <!-- Simple Menu - This template uses a StackPanel to layout MenuItems --> + <Style x:Key="SimpleMenu" TargetType="{x:Type Menu}"> + <Setter Property="Background" Value="{DynamicResource LightBrush}"/> + <Setter Property="BorderBrush" Value="{DynamicResource NormalBorderBrush}"/> + <Setter Property="SnapsToDevicePixels" Value="True"/> + <Setter Property="Template"> + <Setter.Value> + <ControlTemplate TargetType="{x:Type Menu}"> + <Grid> + <Border Margin="1" x:Name="Border" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}"/> + <StackPanel Background="{TemplateBinding Background}" IsItemsHost="True" ClipToBounds="True" Orientation="Horizontal"/> + </Grid> + <ControlTemplate.Triggers> + <Trigger Property="IsEnabled" Value="False"> + <Setter Property="Background" Value="{DynamicResource DisabledBackgroundBrush}" TargetName="Border"/> + <Setter Property="BorderBrush" Value="{DynamicResource DisabledBorderBrush}" TargetName="Border"/> + </Trigger> + </ControlTemplate.Triggers> + </ControlTemplate> + </Setter.Value> + </Setter> + </Style> + + <!-- This BitmapEffect is used by the Simple MenuItem --> + <DropShadowBitmapEffect x:Key="PopupDropShadow" ShadowDepth="1.5" Softness="0.15"/> + + <!-- Simple MenuItem - The template uses triggers to provide four different arrangements of menu item which are set via the Role property --> + <Style x:Key="SimpleMenuItem" TargetType="{x:Type MenuItem}"> + <Setter Property="HorizontalContentAlignment" Value="{Binding Path=HorizontalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"/> + <Setter Property="VerticalContentAlignment" Value="{Binding Path=VerticalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"/> + <Setter Property="Background" Value="Transparent"/> + <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.MenuTextBrushKey}}"/> + <Setter Property="Template"> + <Setter.Value> + <ControlTemplate TargetType="{x:Type MenuItem}"> + <Border x:Name="Border" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}"> + <Grid> + + <!-- The Grid is used to hold together columns for an Icon, Content, Glyph checkmark and Arrow to show the next level + Size sharing is used in Grid so that the Icon, Content, Arrow for each MenuItem align together --> + <Grid.ColumnDefinitions> + <ColumnDefinition MinWidth="17" Width="Auto" SharedSizeGroup="MenuItemIconColumnGroup"/> + <ColumnDefinition Width="*"/> + <ColumnDefinition Width="Auto" SharedSizeGroup="MenuItemIGTColumnGroup"/> + <ColumnDefinition Width="14"/> + </Grid.ColumnDefinitions> + + <!-- ContentPresenter to show an Icon if needed --> + <ContentPresenter Margin="4,0,6,0" x:Name="Icon" VerticalAlignment="Center" ContentSource="Icon"/> + + <!-- Glyph is a checkmark if needed for a checkable menu --> + <Grid Visibility="Hidden" Margin="4,0,6,0" x:Name="GlyphPanel" VerticalAlignment="Center"> + <Path x:Name="GlyphPanelpath" VerticalAlignment="Center" Fill="{TemplateBinding Foreground}" Data="M0,2 L0,4.8 L2.5,7.4 L7.1,2.8 L7.1,0 L2.5,4.6 z" FlowDirection="LeftToRight"/> + </Grid> + + <!-- Content for the menu text etc --> + <ContentPresenter Grid.Column="1" Margin="{TemplateBinding Padding}" x:Name="HeaderHost" RecognizesAccessKey="True" ContentSource="Header"/> + + <!-- Arrow drawn path which points to the next level of the menu --> + <Grid Grid.Column="3" Margin="4,0,6,0" x:Name="ArrowPanel" VerticalAlignment="Center"> + <Path x:Name="ArrowPanelPath" VerticalAlignment="Center" Fill="{TemplateBinding Foreground}" Data="M0,0 L0,8 L4,4 z"/> + </Grid> + + <!-- The Popup is the body of the menu which expands down or across depending on the level of the item --> + <Popup IsOpen="{Binding Path=IsSubmenuOpen, RelativeSource={RelativeSource TemplatedParent}}" Placement="Right" x:Name="SubMenuPopup" Focusable="false" AllowsTransparency="true" PopupAnimation="{DynamicResource {x:Static SystemParameters.MenuPopupAnimationKey}}" VerticalOffset="-3"> + <Grid x:Name="SubMenu"> + <Border x:Name="SubMenuBorder" Background="{DynamicResource WindowBackgroundBrush}" BorderBrush="{DynamicResource SolidBorderBrush}" BorderThickness="1"/> + + <!-- StackPanel holds children of the menu. This is set bu IsItemsHost=True --> + <StackPanel IsItemsHost="True" KeyboardNavigation.DirectionalNavigation="Cycle"/> + </Grid> + </Popup> + + </Grid> + </Border> + + <!-- These triggers re-configure the four arrangements of MenuItem to show different levels of menu via Role --> + <ControlTemplate.Triggers> + + <!-- Role = TopLevelHeader : this is the root menu item in a menu; the Popup expands down --> + <Trigger Property="Role" Value="TopLevelHeader"> + <Setter Property="Margin" Value="0,1,0,1"/> + <Setter Property="Padding" Value="6,3,6,3"/> + <Setter Property="Grid.IsSharedSizeScope" Value="true"/> + <Setter Property="Placement" Value="Bottom" TargetName="SubMenuPopup"/> + <Setter Property="Visibility" Value="Collapsed" TargetName="ArrowPanel"/> + </Trigger> + + <!-- Role = TopLevelItem : this is a child menu item from the top level without any child items--> + <Trigger Property="Role" Value="TopLevelItem"> + <Setter Property="Margin" Value="0,1,0,1"/> + <Setter Property="Padding" Value="6,3,6,3"/> + <Setter Property="Visibility" Value="Collapsed" TargetName="ArrowPanel"/> + </Trigger> + + <!-- Role = SubMenuHeader : this is a child menu item which does not have children --> + <Trigger Property="Role" Value="SubmenuHeader"> + <Setter Property="DockPanel.Dock" Value="Top"/> + <Setter Property="Padding" Value="0,2,0,2"/> + <Setter Property="Grid.IsSharedSizeScope" Value="true"/> + </Trigger> + + <!-- Role = SubMenuItem : this is a child menu item which has children--> + <Trigger Property="Role" Value="SubmenuItem"> + <Setter Property="DockPanel.Dock" Value="Top"/> + <Setter Property="Padding" Value="0,2,0,2"/> + <Setter Property="Visibility" Value="Collapsed" TargetName="ArrowPanel"/> + </Trigger> + <Trigger Property="IsSuspendingPopupAnimation" Value="true"> + <Setter Property="PopupAnimation" Value="None" TargetName="SubMenuPopup"/> + </Trigger> + + <!-- If no Icon is present the we collapse the Icon Content --> + <Trigger Property="Icon" Value="{x:Null}"> + <Setter Property="Visibility" Value="Collapsed" TargetName="Icon"/> + </Trigger> + + <!-- The GlyphPanel contains the CheckMark --> + <Trigger Property="IsChecked" Value="true"> + <Setter Property="Visibility" Value="Visible" TargetName="GlyphPanel"/> + <Setter Property="Visibility" Value="Collapsed" TargetName="Icon"/> + </Trigger> + + <Trigger Property="AllowsTransparency" SourceName="SubMenuPopup" Value="true"> + <Setter Property="Margin" Value="0,0,3,3" TargetName="SubMenu"/> + <Setter Property="SnapsToDevicePixels" Value="true" TargetName="SubMenu"/> + <Setter Property="BitmapEffect" Value="{DynamicResource PopupDropShadow}" TargetName="SubMenuBorder"/> + </Trigger> + + <!-- Using the system colors for the Menu Highlight and IsEnabled--> + <Trigger Property="IsHighlighted" Value="true"> + <Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}" TargetName="Border"/> + <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.HighlightTextBrushKey}}"/> + </Trigger> + <Trigger Property="IsEnabled" Value="false"> + <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/> + </Trigger> + </ControlTemplate.Triggers> + </ControlTemplate> + </Setter.Value> + </Setter> + </Style> + + <!-- Simple Separator - This template is used for a Separator in a menu --> + <Style x:Key="SimpleSeparator" TargetType="{x:Type Separator}"> + <Setter Property="Height" Value="1"/> + <Setter Property="Margin" Value="0,2,0,2"/> + <Setter Property="Focusable" Value="false"/> + <Setter Property="Template"> + <Setter.Value> + <ControlTemplate TargetType="{x:Type Separator}"> + <Border BorderBrush="{DynamicResource SolidBorderBrush}" BorderThickness="1"/> + </ControlTemplate> + </Setter.Value> + </Setter> + </Style> + + <!-- Simple TabControl + This template uses Simple TabItem for each Tab. The TabItems are placed in the TabPanel + Limitations : The Simple TabControl only allow the Tabs to be shown at the top of the Tab control. You can re-position the TabPanel to change this--> + + <Style x:Key="SimpleTabControl" TargetType="{x:Type TabControl}"> + <Setter Property="Template"> + <Setter.Value> + <ControlTemplate TargetType="{x:Type TabControl}"> + <Grid KeyboardNavigation.TabNavigation="Local"> + <Grid.RowDefinitions> + <RowDefinition Height="Auto"/> + <RowDefinition Height="*"/> + </Grid.RowDefinitions> + + <!-- TabPanel is a layout container which allows the TabItems to wrap and re-order when selected + The implementation knows to use this control because it is marked IsItemsHost = True --> + <TabPanel Grid.Row="0" Margin="0,0,4,-1" x:Name="HeaderPanel" Background="Transparent" IsItemsHost="True" Panel.ZIndex="1" KeyboardNavigation.TabIndex="1"/> + + <Border Grid.Row="1" x:Name="Border" Background="{DynamicResource WindowBackgroundBrush}" BorderBrush="{DynamicResource SolidBorderBrush}" BorderThickness="1" CornerRadius="2" KeyboardNavigation.DirectionalNavigation="Contained" KeyboardNavigation.TabNavigation="Local" KeyboardNavigation.TabIndex="2"> + + <!-- The implementation switches the content. This control must be named PART_SelectedContentHost --> + <ContentPresenter Margin="4" x:Name="PART_SelectedContentHost" ContentSource="SelectedContent"/> + + </Border> + </Grid> + + <ControlTemplate.Triggers> + <Trigger Property="IsEnabled" Value="False"> + <Setter Property="Foreground" Value="{DynamicResource DisabledForegroundBrush}"/> + <Setter Property="BorderBrush" Value="{DynamicResource DisabledBorderBrush}" TargetName="Border"/> + </Trigger> + </ControlTemplate.Triggers> + + </ControlTemplate> + </Setter.Value> + </Setter> + </Style> + + <!--Simple TabItem --> + <Style x:Key="SimpleTabItem" d:IsControlPart="True" TargetType="{x:Type TabItem}"> + <Setter Property="Template"> + <Setter.Value> + <ControlTemplate TargetType="{x:Type TabItem}"> + <Grid> + <Border Margin="0,0,-4,0" x:Name="Border" Background="{DynamicResource LightBrush}" BorderBrush="{DynamicResource SolidBorderBrush}" BorderThickness="1,1,1,1" CornerRadius="2,12,0,0"> + <ContentPresenter HorizontalAlignment="Center" Margin="12,2,12,2" x:Name="ContentSite" VerticalAlignment="Center" RecognizesAccessKey="True" ContentSource="Header"/> + </Border> + </Grid> + <ControlTemplate.Triggers> + <Trigger Property="IsSelected" Value="True"> + <Setter Property="Panel.ZIndex" Value="100"/> + <Setter Property="Background" Value="{DynamicResource WindowBackgroundBrush}" TargetName="Border"/> + <Setter Property="BorderThickness" Value="1,1,1,0" TargetName="Border"/> + </Trigger> + <Trigger Property="IsEnabled" Value="False"> + <Setter Property="Background" Value="{DynamicResource DisabledBackgroundBrush}" TargetName="Border"/> + <Setter Property="BorderBrush" Value="{DynamicResource DisabledBorderBrush}" TargetName="Border"/> + <Setter Property="Foreground" Value="{DynamicResource DisabledForegroundBrush}"/> + </Trigger> + </ControlTemplate.Triggers> + </ControlTemplate> + </Setter.Value> + </Setter> + </Style> + + <!--Simple Simple SliderThumb - The Thumb is the draggable part of a Slider--> + <Style x:Key="SimpleSliderThumb" d:IsControlPart="True" TargetType="{x:Type Thumb}"> + <Setter Property="SnapsToDevicePixels" Value="true"/> + <Setter Property="Height" Value="14"/> + <Setter Property="Width" Value="14"/> + <Setter Property="Template"> + <Setter.Value> + <ControlTemplate TargetType="{x:Type Thumb}"> + <Grid> + <Ellipse x:Name="Ellipse" Fill="{DynamicResource NormalBrush}" Stroke="{DynamicResource NormalBorderBrush}" StrokeThickness="1"/> + </Grid> + <ControlTemplate.Triggers> + <Trigger Property="IsMouseOver" Value="True"> + <Setter Property="Fill" Value="{DynamicResource MouseOverBrush}" TargetName="Ellipse"/> + </Trigger> + <Trigger Property="IsEnabled" Value="false"> + <Setter Property="Fill" Value="{DynamicResource DisabledBackgroundBrush}" TargetName="Ellipse"/> + </Trigger> + </ControlTemplate.Triggers> + </ControlTemplate> + </Setter.Value> + </Setter> + </Style> + + <!--Simple Simple Slider + Similiar to ScrollBar this template uses Track to layout the draggable Thumb which has an up and down repeat button + It uses Simple SliderThumb and SimpleScrollRepeatButtonStyle for the page up and down repeat buttons --> + <Style x:Key="SimpleSlider" TargetType="{x:Type Slider}"> + <Setter Property="Background" Value="{DynamicResource LightBrush}"/> + <Setter Property="BorderBrush" Value="{DynamicResource NormalBorderBrush}"/> + <Setter Property="Template"> + <Setter.Value> + <ControlTemplate TargetType="{x:Type Slider}"> + <Grid x:Name="GridRoot"> + <Grid.RowDefinitions> + <RowDefinition Height="Auto"/> + <RowDefinition Height="Auto" MinHeight="{TemplateBinding MinHeight}"/> + <RowDefinition Height="Auto"/> + </Grid.RowDefinitions> + + <!-- TickBar shows the ticks for Slider --> + <TickBar Visibility="Collapsed" x:Name="TopTick" Height="4" SnapsToDevicePixels="True" Placement="Top" Fill="{DynamicResource GlyphBrush}"/> + <Border Grid.Row="1" Margin="0" x:Name="Border" Height="4" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" CornerRadius="2"/> + + <!-- The Track lays out the repeat buttons and thumb --> + <Track Grid.Row="1" x:Name="PART_Track"> + <Track.Thumb> + <Thumb Style="{DynamicResource SimpleSliderThumb}"/> + </Track.Thumb> + <Track.IncreaseRepeatButton> + <RepeatButton Style="{DynamicResource SimpleScrollRepeatButtonStyle}" Command="Slider.IncreaseLarge"/> + </Track.IncreaseRepeatButton> + <Track.DecreaseRepeatButton> + <RepeatButton Style="{DynamicResource SimpleScrollRepeatButtonStyle}" Command="Slider.DecreaseLarge"/> + </Track.DecreaseRepeatButton> + </Track> + + <TickBar Visibility="Collapsed" Grid.Row="2" x:Name="BottomTick" Height="4" SnapsToDevicePixels="True" Placement="Bottom" Fill="{TemplateBinding Foreground}"/> + </Grid> + <ControlTemplate.Triggers> + <Trigger Property="TickPlacement" Value="TopLeft"> + <Setter Property="Visibility" Value="Visible" TargetName="TopTick"/> + </Trigger> + <Trigger Property="TickPlacement" Value="BottomRight"> + <Setter Property="Visibility" Value="Visible" TargetName="BottomTick"/> + </Trigger> + <Trigger Property="TickPlacement" Value="Both"> + <Setter Property="Visibility" Value="Visible" TargetName="TopTick"/> + <Setter Property="Visibility" Value="Visible" TargetName="BottomTick"/> + </Trigger> + <Trigger Property="IsEnabled" Value="false"> + <Setter Property="Background" Value="{DynamicResource DisabledBackgroundBrush}" TargetName="Border"/> + <Setter Property="BorderBrush" Value="{DynamicResource DisabledBorderBrush}" TargetName="Border"/> + </Trigger> + + <!-- Use a rotation to create a Vertical Slider form the default Horizontal --> + <Trigger Property="Orientation" Value="Vertical"> + <Setter Property="LayoutTransform" TargetName="GridRoot"> + <Setter.Value> + <RotateTransform Angle="-90"/> + </Setter.Value> + </Setter> + <!-- Track rotates itself based on orientation so need to force it back --> + <Setter TargetName="PART_Track" Property="Orientation" Value="Horizontal"/> + </Trigger> + + </ControlTemplate.Triggers> + </ControlTemplate> + </Setter.Value> + </Setter> + </Style> + + <!--Simple Tree View - This lays out TreeViewItems within a ScrollViewer --> + <Style x:Key="SimpleTreeView" TargetType="{x:Type TreeView}"> + <Setter Property="Template"> + <Setter.Value> + <ControlTemplate TargetType="{x:Type TreeView}"> + <Grid> + <Border x:Name="Border" Background="{DynamicResource WindowBackgroundBrush}" BorderBrush="{DynamicResource SolidBorderBrush}" BorderThickness="1" CornerRadius="1"> + <ScrollViewer Style="{DynamicResource SimpleScrollViewer}" Focusable="False" Background="{TemplateBinding Background}" Padding="4" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto" CanContentScroll="False"> + <ItemsPresenter/> + </ScrollViewer> + </Border> + </Grid> + </ControlTemplate> + </Setter.Value> + </Setter> + </Style> + + <!--Simple TreeViewItem ToggleButton - + and - button to expand and collapse a TreeViewItem --> + <Style x:Key="SimpleTreeViewItemToggleButton" d:IsControlPart="True" TargetType="{x:Type ToggleButton}"> + <Setter Property="Focusable" Value="False"/> + <Setter Property="Template"> + <Setter.Value> + <ControlTemplate TargetType="{x:Type ToggleButton}"> + <Grid Width="15" Height="13" Background="Transparent"> + <Path Visibility="Collapsed" HorizontalAlignment="Left" Margin="1,1,1,1" x:Name="IsExpandedPath" VerticalAlignment="Center" Fill="{DynamicResource GlyphBrush}" Data="M 0 4 L 8 4 L 4 8 Z"/> + <Path HorizontalAlignment="Left" Margin="1,1,1,1" x:Name="ExpandPath" VerticalAlignment="Center" Fill="{DynamicResource GlyphBrush}" Data="M 4 0 L 8 4 L 4 8 Z"/> + </Grid> + <ControlTemplate.Triggers> + <Trigger Property="IsChecked" Value="True"> + <Setter Property="Visibility" Value="Visible" TargetName="IsExpandedPath"/> + <Setter Property="Visibility" Value="Collapsed" TargetName="ExpandPath"/> + </Trigger> + </ControlTemplate.Triggers> + </ControlTemplate> + </Setter.Value> + </Setter> + </Style> + + <!--Simple TreeViewItem - The TreeViewItem template has a header which shows the Item and a Body which is an ItemsHost control which expands to show child items--> + <Style x:Key="SimpleTreeViewItem" d:IsControlPart="True" TargetType="{x:Type TreeViewItem}"> + <Setter Property="Background" Value="Transparent"/> + <Setter Property="HorizontalContentAlignment" Value="{Binding Path=HorizontalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"/> + <Setter Property="VerticalContentAlignment" Value="{Binding Path=VerticalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"/> + <Setter Property="Padding" Value="1,0,0,0"/> + <Setter Property="Template"> + <Setter.Value> + <ControlTemplate TargetType="{x:Type TreeViewItem}"> + <Grid> + <Grid.ColumnDefinitions> + <ColumnDefinition MinWidth="19" Width="Auto"/> + <ColumnDefinition Width="Auto"/> + <ColumnDefinition Width="*"/> + </Grid.ColumnDefinitions> + <Grid.RowDefinitions> + <RowDefinition Height="Auto"/> + <RowDefinition/> + </Grid.RowDefinitions> + <ToggleButton x:Name="Expander" Style="{DynamicResource SimpleTreeViewItemToggleButton}" IsChecked="{Binding Path=IsExpanded, RelativeSource={RelativeSource TemplatedParent}}" ClickMode="Press"/> + <Border Grid.Column="1" x:Name="Selection_Border" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Padding="{TemplateBinding Padding}"> + <ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" x:Name="PART_Header" ContentSource="Header"/> + </Border> + <ItemsPresenter Grid.Column="1" Grid.ColumnSpan="2" Grid.Row="1" x:Name="ItemsHost"/> + </Grid> + <ControlTemplate.Triggers> + <Trigger Property="IsExpanded" Value="false"> + <Setter Property="Visibility" Value="Collapsed" TargetName="ItemsHost"/> + </Trigger> + <Trigger Property="HasItems" Value="false"> + <Setter Property="Visibility" Value="Hidden" TargetName="Expander"/> + </Trigger> + <Trigger Property="IsSelected" Value="true"> + <Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}" TargetName="Selection_Border"/> + <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.HighlightTextBrushKey}}"/> + </Trigger> + <MultiTrigger> + <MultiTrigger.Conditions> + <Condition Property="IsSelected" Value="true"/> + <Condition Property="IsSelectionActive" Value="false"/> + </MultiTrigger.Conditions> + <Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}" TargetName="Selection_Border"/> + <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/> + </MultiTrigger> + <Trigger Property="IsEnabled" Value="false"> + <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/> + </Trigger> + </ControlTemplate.Triggers> + </ControlTemplate> + </Setter.Value> + </Setter> + </Style> +</ResourceDictionary> diff --git a/zerotierone/windows/WinUI/Themes/Generic.xaml b/zerotierone/windows/WinUI/Themes/Generic.xaml new file mode 100644 index 0000000..2b47588 --- /dev/null +++ b/zerotierone/windows/WinUI/Themes/Generic.xaml @@ -0,0 +1,7 @@ +<ResourceDictionary + xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" + xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" + xmlns:local="clr-namespace:WinUI"> + + +</ResourceDictionary> diff --git a/zerotierone/windows/WinUI/WinUI.csproj b/zerotierone/windows/WinUI/WinUI.csproj new file mode 100644 index 0000000..c3eeaba --- /dev/null +++ b/zerotierone/windows/WinUI/WinUI.csproj @@ -0,0 +1,227 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" /> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> + <ProjectGuid>{4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}</ProjectGuid> + <OutputType>WinExe</OutputType> + <AppDesignerFolder>Properties</AppDesignerFolder> + <RootNamespace>WinUI</RootNamespace> + <AssemblyName>ZeroTier One</AssemblyName> + <TargetFrameworkVersion>v4.5</TargetFrameworkVersion> + <FileAlignment>512</FileAlignment> + <ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> + <WarningLevel>4</WarningLevel> + <ExpressionBlendVersion>5.0.40218.0</ExpressionBlendVersion> + <IsWebBootstrapper>false</IsWebBootstrapper> + <PublishUrl>publish\</PublishUrl> + <Install>true</Install> + <InstallFrom>Disk</InstallFrom> + <UpdateEnabled>false</UpdateEnabled> + <UpdateMode>Foreground</UpdateMode> + <UpdateInterval>7</UpdateInterval> + <UpdateIntervalUnits>Days</UpdateIntervalUnits> + <UpdatePeriodically>false</UpdatePeriodically> + <UpdateRequired>false</UpdateRequired> + <MapFileExtensions>true</MapFileExtensions> + <AutorunEnabled>true</AutorunEnabled> + <ApplicationRevision>0</ApplicationRevision> + <ApplicationVersion>1.0.0.0</ApplicationVersion> + <UseApplicationTrust>false</UseApplicationTrust> + <BootstrapperEnabled>true</BootstrapperEnabled> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> + <PlatformTarget>AnyCPU</PlatformTarget> + <DebugSymbols>true</DebugSymbols> + <DebugType>full</DebugType> + <Optimize>false</Optimize> + <OutputPath>bin\Debug\</OutputPath> + <DefineConstants>DEBUG;TRACE</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + <Prefer32Bit>true</Prefer32Bit> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> + <PlatformTarget>AnyCPU</PlatformTarget> + <DebugType>pdbonly</DebugType> + <Optimize>true</Optimize> + <OutputPath>bin\Release\</OutputPath> + <DefineConstants>TRACE</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + </PropertyGroup> + <PropertyGroup> + <StartupObject>WinUI.App</StartupObject> + </PropertyGroup> + <PropertyGroup> + <ApplicationIcon>ZeroTierIcon.ico</ApplicationIcon> + </PropertyGroup> + <PropertyGroup> + <SignAssembly>false</SignAssembly> + </PropertyGroup> + <PropertyGroup> + <SignManifests>false</SignManifests> + </PropertyGroup> + <PropertyGroup> + <ApplicationManifest>app.manifest</ApplicationManifest> + </PropertyGroup> + <ItemGroup> + <Reference Include="Accessibility" /> + <Reference Include="Newtonsoft.Json, Version=7.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL"> + <HintPath>..\packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll</HintPath> + <Private>True</Private> + </Reference> + <Reference Include="PresentationUI, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL" /> + <Reference Include="ReachFramework" /> + <Reference Include="System" /> + <Reference Include="System.Data" /> + <Reference Include="System.Deployment" /> + <Reference Include="System.Drawing" /> + <Reference Include="System.Printing" /> + <Reference Include="System.Windows.Forms" /> + <Reference Include="System.Xml" /> + <Reference Include="Microsoft.CSharp" /> + <Reference Include="System.Core" /> + <Reference Include="System.Xml.Linq" /> + <Reference Include="System.Data.DataSetExtensions" /> + <Reference Include="System.Xaml"> + <RequiredTargetFramework>4.0</RequiredTargetFramework> + </Reference> + <Reference Include="UIAutomationProvider" /> + <Reference Include="UIAutomationTypes" /> + <Reference Include="WindowsBase" /> + <Reference Include="PresentationCore" /> + <Reference Include="PresentationFramework" /> + </ItemGroup> + <ItemGroup> + <ApplicationDefinition Include="App.xaml"> + <Generator>MSBuild:Compile</Generator> + <SubType>Designer</SubType> + </ApplicationDefinition> + <Compile Include="NetworksPage.xaml.cs"> + <DependentUpon>NetworksPage.xaml</DependentUpon> + </Compile> + <Compile Include="PeersPage.xaml.cs"> + <DependentUpon>PeersPage.xaml</DependentUpon> + </Compile> + <Compile Include="ZeroTierPeerPhysicalPath.cs" /> + <Compile Include="ZeroTierPeer.cs" /> + <Compile Include="ZeroTierNetwork.cs" /> + <Compile Include="ZeroTierStatus.cs" /> + <Page Include="MainWindow.xaml"> + <Generator>MSBuild:Compile</Generator> + <SubType>Designer</SubType> + </Page> + <Compile Include="APIHandler.cs" /> + <Compile Include="App.xaml.cs"> + <DependentUpon>App.xaml</DependentUpon> + <SubType>Code</SubType> + </Compile> + <Compile Include="MainWindow.xaml.cs"> + <DependentUpon>MainWindow.xaml</DependentUpon> + <SubType>Code</SubType> + </Compile> + <Page Include="NetworkInfoView.xaml"> + <SubType>Designer</SubType> + <Generator>MSBuild:Compile</Generator> + </Page> + <Page Include="NetworksPage.xaml"> + <SubType>Designer</SubType> + <Generator>MSBuild:Compile</Generator> + </Page> + <Page Include="PeersPage.xaml"> + <SubType>Designer</SubType> + <Generator>MSBuild:Compile</Generator> + </Page> + <Page Include="Simple Styles.xaml"> + <Generator>MSBuild:Compile</Generator> + <SubType>Designer</SubType> + </Page> + <Page Include="Themes\Generic.xaml"> + <Generator>MSBuild:Compile</Generator> + <SubType>Designer</SubType> + </Page> + </ItemGroup> + <ItemGroup> + <Compile Include="NetworkInfoView.xaml.cs"> + <DependentUpon>NetworkInfoView.xaml</DependentUpon> + </Compile> + <Compile Include="Properties\AssemblyInfo.cs"> + <SubType>Code</SubType> + </Compile> + <Compile Include="Properties\Resources.Designer.cs"> + <AutoGen>True</AutoGen> + <DesignTime>True</DesignTime> + <DependentUpon>Resources.resx</DependentUpon> + </Compile> + <Compile Include="Properties\Settings.Designer.cs"> + <AutoGen>True</AutoGen> + <DependentUpon>Settings.settings</DependentUpon> + <DesignTimeSharedInput>True</DesignTimeSharedInput> + </Compile> + <EmbeddedResource Include="Properties\Resources.resx"> + <Generator>ResXFileCodeGenerator</Generator> + <LastGenOutput>Resources.Designer.cs</LastGenOutput> + </EmbeddedResource> + <None Include="app.manifest" /> + <None Include="packages.config" /> + <None Include="Properties\Settings.settings"> + <Generator>SettingsSingleFileGenerator</Generator> + <LastGenOutput>Settings.Designer.cs</LastGenOutput> + </None> + <AppDesigner Include="Properties\" /> + </ItemGroup> + <ItemGroup> + <None Include="App.config" /> + </ItemGroup> + <ItemGroup> + <BootstrapperPackage Include=".NETFramework,Version=v4.5"> + <Visible>False</Visible> + <ProductName>Microsoft .NET Framework 4.5 %28x86 and x64%29</ProductName> + <Install>true</Install> + </BootstrapperPackage> + <BootstrapperPackage Include="Microsoft.Net.Client.3.5"> + <Visible>False</Visible> + <ProductName>.NET Framework 3.5 SP1 Client Profile</ProductName> + <Install>false</Install> + </BootstrapperPackage> + <BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1"> + <Visible>False</Visible> + <ProductName>.NET Framework 3.5 SP1</ProductName> + <Install>false</Install> + </BootstrapperPackage> + </ItemGroup> + <ItemGroup> + <BlendEmbeddedFont Include="Fonts\segoeui.ttf"> + <IsSystemFont>True</IsSystemFont> + <All>True</All> + <AutoFill>True</AutoFill> + </BlendEmbeddedFont> + <BlendEmbeddedFont Include="Fonts\segoeuib.ttf"> + <IsSystemFont>True</IsSystemFont> + <All>True</All> + <AutoFill>True</AutoFill> + </BlendEmbeddedFont> + <BlendEmbeddedFont Include="Fonts\segoeuii.ttf"> + <IsSystemFont>True</IsSystemFont> + <All>True</All> + <AutoFill>True</AutoFill> + </BlendEmbeddedFont> + <BlendEmbeddedFont Include="Fonts\segoeuiz.ttf"> + <IsSystemFont>True</IsSystemFont> + <All>True</All> + <AutoFill>True</AutoFill> + </BlendEmbeddedFont> + <Resource Include="ZeroTierIcon.ico" /> + </ItemGroup> + <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> + <Import Project="$(MSBuildExtensionsPath)\Microsoft\Expression\Blend\.NETFramework\v4.5\Microsoft.Expression.Blend.WPF.targets" /> + <!-- To modify your build process, add your task inside one of the targets below and uncomment it. + Other similar extension points exist, see Microsoft.Common.targets. + <Target Name="BeforeBuild"> + </Target> + <Target Name="AfterBuild"> + </Target> + --> +</Project>
\ No newline at end of file diff --git a/zerotierone/windows/WinUI/ZeroTierIcon.ico b/zerotierone/windows/WinUI/ZeroTierIcon.ico Binary files differnew file mode 100644 index 0000000..2d190c4 --- /dev/null +++ b/zerotierone/windows/WinUI/ZeroTierIcon.ico diff --git a/zerotierone/windows/WinUI/ZeroTierNetwork.cs b/zerotierone/windows/WinUI/ZeroTierNetwork.cs new file mode 100644 index 0000000..cce6544 --- /dev/null +++ b/zerotierone/windows/WinUI/ZeroTierNetwork.cs @@ -0,0 +1,54 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Newtonsoft.Json; + +namespace WinUI +{ + public class ZeroTierNetwork + { + [JsonProperty("nwid")] + public string NetworkId { get; set; } + + [JsonProperty("mac")] + public string MacAddress { get; set; } + + [JsonProperty("name")] + public string NetworkName { get; set; } + + [JsonProperty("status")] + public string NetworkStatus { get; set; } + + [JsonProperty("type")] + public string NetworkType { get; set; } + + [JsonProperty("mtu")] + public int MTU { get; set; } + + [JsonProperty("dhcp")] + public bool DHCP { get; set; } + + [JsonProperty("bridge")] + public bool Bridge { get; set ; } + + [JsonProperty("broadcastEnabled")] + public bool BroadcastEnabled { get ; set; } + + [JsonProperty("portError")] + public int PortError { get; set; } + + [JsonProperty("netconfRevision")] + public int NetconfRevision { get; set; } + + [JsonProperty("multicastSubscriptions")] + public string[] MulticastSubscriptions { get; set; } + + [JsonProperty("assignedAddresses")] + public string[] AssignedAddresses { get; set; } + + [JsonProperty("portDeviceName")] + public string DeviceName { get; set; } + } +} diff --git a/zerotierone/windows/WinUI/ZeroTierPeer.cs b/zerotierone/windows/WinUI/ZeroTierPeer.cs new file mode 100644 index 0000000..1597cf2 --- /dev/null +++ b/zerotierone/windows/WinUI/ZeroTierPeer.cs @@ -0,0 +1,116 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Newtonsoft.Json; + +namespace WinUI +{ + public class ZeroTierPeer : IEquatable<ZeroTierPeer> + { + [JsonProperty("address")] + public string Address { get; set; } + + private Int64 _lastUnicast; + [JsonProperty("lastUnicastFrame")] + public Int64 LastUnicastFrame + { + get + { + if (_lastUnicast == 0) + return 0; + + TimeSpan t = DateTime.UtcNow - new DateTime(1970, 1, 1); + Int64 millisecondsSinceEpoch = (Int64)t.TotalMilliseconds; + return (millisecondsSinceEpoch - _lastUnicast) / 1000; + } + set + { + _lastUnicast = value; + } + } + + private Int64 _lastMulticast; + [JsonProperty("lastMulticastFrame")] + public Int64 LastMulticastFrame + { + get + { + if (_lastMulticast == 0) + return 0; + + TimeSpan t = DateTime.UtcNow - new DateTime(1970, 1, 1); + Int64 millisecondsSinceEpoch = (Int64)t.TotalMilliseconds; + return (millisecondsSinceEpoch - _lastMulticast) / 1000; + } + set + { + _lastMulticast = value; + } + } + + [JsonProperty("versionMajor")] + public int VersionMajor { get; set; } + + [JsonProperty("versionMinor")] + public int VersionMinor { get; set; } + + [JsonProperty("versionRev")] + public int VersionRev { get; set; } + + [JsonProperty("version")] + public string Version { get; set; } + + public string VersionString + { + get + { + if (Version == "-1.-1.-1") + return "-"; + else + return Version; + } + } + + [JsonProperty("latency")] + public string Latency { get; set; } + + [JsonProperty("role")] + public string Role { get; set; } + + [JsonProperty("paths")] + public List<ZeroTierPeerPhysicalPath> Paths { get; set; } + + public string DataPaths + { + get + { + string pathStr = ""; + foreach(ZeroTierPeerPhysicalPath path in Paths) + { + pathStr += path.Address + "\n"; + } + return pathStr; + } + } + + public bool Equals(ZeroTierPeer other) + { + return this.Address.Equals(other.Address, StringComparison.InvariantCultureIgnoreCase); + } + + public void Update(ZeroTierPeer other) + { + _lastUnicast = other._lastUnicast; + _lastMulticast = other._lastMulticast; + VersionMajor = other.VersionMajor; + VersionMinor = other.VersionMinor; + VersionRev = other.VersionRev; + Version = other.Version; + Latency = other.Latency; + Role = other.Role; + Paths = other.Paths; + } + } +} diff --git a/zerotierone/windows/WinUI/ZeroTierPeerPhysicalPath.cs b/zerotierone/windows/WinUI/ZeroTierPeerPhysicalPath.cs new file mode 100644 index 0000000..3eaa802 --- /dev/null +++ b/zerotierone/windows/WinUI/ZeroTierPeerPhysicalPath.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Newtonsoft.Json; + +namespace WinUI +{ + public class ZeroTierPeerPhysicalPath + { + [JsonProperty("address")] + public string Address { get; set; } + + [JsonProperty("lastSend")] + public UInt64 LastSend { get; set; } + + [JsonProperty("lastReceive")] + public UInt64 LastReceive { get; set; } + + [JsonProperty("fixed")] + public bool Fixed { get; set; } + + [JsonProperty("preferred")] + public bool Preferred { get; set; } + } +} diff --git a/zerotierone/windows/WinUI/ZeroTierStatus.cs b/zerotierone/windows/WinUI/ZeroTierStatus.cs new file mode 100644 index 0000000..2851d01 --- /dev/null +++ b/zerotierone/windows/WinUI/ZeroTierStatus.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Newtonsoft.Json; + +namespace WinUI +{ + public class ZeroTierStatus + { + [JsonProperty("address")] + public string Address { get; set; } + + [JsonProperty("publicIdentity")] + public string PublicIdentity { get; set; } + + [JsonProperty("online")] + public bool Online { get; set; } + + [JsonProperty("tcpFallbackActive")] + public bool TcpFallbackActive { get; set; } + + [JsonProperty("versionMajor")] + public int VersionMajor { get; set; } + + [JsonProperty("versionMinor")] + public int VersionMinor { get; set; } + + [JsonProperty("versionRev")] + public int VersionRev { get; set; } + + [JsonProperty("version")] + public string Version { get; set; } + + [JsonProperty("clock")] + public UInt64 Clock { get; set; } + } +} diff --git a/zerotierone/windows/WinUI/app.manifest b/zerotierone/windows/WinUI/app.manifest new file mode 100644 index 0000000..b537bf4 --- /dev/null +++ b/zerotierone/windows/WinUI/app.manifest @@ -0,0 +1,55 @@ +<?xml version="1.0" encoding="utf-8"?> +<asmv1:assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1" xmlns:asmv1="urn:schemas-microsoft-com:asm.v1" xmlns:asmv2="urn:schemas-microsoft-com:asm.v2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> + <assemblyIdentity version="1.0.0.0" name="MyApplication.app"/> + <trustInfo xmlns="urn:schemas-microsoft-com:asm.v2"> + <security> + <requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3"> + <!-- UAC Manifest Options + If you want to change the Windows User Account Control level replace the + requestedExecutionLevel node with one of the following. + + <requestedExecutionLevel level="asInvoker" uiAccess="false" /> + <requestedExecutionLevel level="requireAdministrator" uiAccess="false" /> + <requestedExecutionLevel level="highestAvailable" uiAccess="false" /> + + Specifying requestedExecutionLevel node will disable file and registry virtualization. + If you want to utilize File and Registry Virtualization for backward + compatibility then delete the requestedExecutionLevel node. + --> + <requestedExecutionLevel level="requireAdministrator" uiAccess="false" /> + </requestedPrivileges> + </security> + </trustInfo> + + <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1"> + <application> + <!-- A list of all Windows versions that this application is designed to work with. + Windows will automatically select the most compatible environment.--> + + <!-- If your application is designed to work with Windows Vista, uncomment the following supportedOS node--> + <!--<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"></supportedOS>--> + + <!-- If your application is designed to work with Windows 7, uncomment the following supportedOS node--> + <!--<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>--> + + <!-- If your application is designed to work with Windows 8, uncomment the following supportedOS node--> + <!--<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"></supportedOS>--> + + </application> + </compatibility> + + <!-- Enable themes for Windows common controls and dialogs (Windows XP and later) --> + <!-- <dependency> + <dependentAssembly> + <assemblyIdentity + type="win32" + name="Microsoft.Windows.Common-Controls" + version="6.0.0.0" + processorArchitecture="*" + publicKeyToken="6595b64144ccf1df" + language="*" + /> + </dependentAssembly> + </dependency>--> + +</asmv1:assembly> diff --git a/zerotierone/windows/WinUI/packages.config b/zerotierone/windows/WinUI/packages.config new file mode 100644 index 0000000..505e588 --- /dev/null +++ b/zerotierone/windows/WinUI/packages.config @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="utf-8"?> +<packages> + <package id="Newtonsoft.Json" version="7.0.1" targetFramework="net45" /> +</packages>
\ No newline at end of file |
