diff options
48 files changed, 2751 insertions, 95 deletions
@@ -53,8 +53,7 @@ node_modules cluster-geo/cluster-geo/config.js cluster-geo/cluster-geo/cache.* tests/http/zerotier-one -tests/http/result_* -tests/http/big-test-out +tests/http/big-test-hosts # MacGap wrapper build files /ext/mac-ui-macgap1-wrapper/src/MacGap.xcodeproj/project.xcworkspace/xcuserdata/* @@ -70,4 +69,6 @@ java/doc/ java/build_win64/ java/build_win32/ /java/mac32_64/ +windows/WinUI/obj/ +windows/WinUI/bin/ windows/ZeroTierOne/Debug/ diff --git a/controller/SqliteNetworkController.cpp b/controller/SqliteNetworkController.cpp index 52b47665..049db04e 100644 --- a/controller/SqliteNetworkController.cpp +++ b/controller/SqliteNetworkController.cpp @@ -71,6 +71,9 @@ // than this (ms). #define ZT_NETCONF_MIN_REQUEST_PERIOD 1000 +// Delay between backups in milliseconds +#define ZT_NETCONF_BACKUP_PERIOD 60000 + namespace ZeroTier { namespace { @@ -122,6 +125,7 @@ struct NetworkRecord { SqliteNetworkController::SqliteNetworkController(Node *node,const char *dbPath,const char *circuitTestPath) : _node(node), + _backupThreadRun(true), _dbPath(dbPath), _circuitTestPath(circuitTestPath), _db((sqlite3 *)0) @@ -247,10 +251,15 @@ SqliteNetworkController::SqliteNetworkController(Node *node,const char *dbPath,c throw std::runtime_error("SqliteNetworkController unable to read instanceId (it's NULL)"); _instanceId = iid; } + + _backupThread = Thread::start(this); } SqliteNetworkController::~SqliteNetworkController() { + _backupThreadRun = false; + Thread::join(_backupThread); + Mutex::Lock _l(_lock); if (_db) { sqlite3_finalize(_sGetNetworkById); @@ -991,6 +1000,59 @@ unsigned int SqliteNetworkController::handleControlPlaneHttpDELETE( return 404; } +void SqliteNetworkController::threadMain() + throw() +{ + uint64_t lastBackupTime = 0; + while (_backupThreadRun) { + if ((OSUtils::now() - lastBackupTime) >= ZT_NETCONF_BACKUP_PERIOD) { + lastBackupTime = OSUtils::now(); + + char backupPath[4096],backupPath2[4096]; + Utils::snprintf(backupPath,sizeof(backupPath),"%s.backupInProgress",_dbPath.c_str()); + Utils::snprintf(backupPath2,sizeof(backupPath),"%s.backup",_dbPath.c_str()); + OSUtils::rm(backupPath); // delete any unfinished backups + + sqlite3 *bakdb = (sqlite3 *)0; + sqlite3_backup *bak = (sqlite3_backup *)0; + if (sqlite3_open_v2(backupPath,&bakdb,SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE,(const char *)0) != SQLITE_OK) { + fprintf(stderr,"SqliteNetworkController: CRITICAL: backup failed on sqlite3_open_v2()"ZT_EOL_S); + continue; + } + bak = sqlite3_backup_init(bakdb,"main",_db,"main"); + if (!bak) { + sqlite3_close(bakdb); + OSUtils::rm(backupPath); // delete any unfinished backups + fprintf(stderr,"SqliteNetworkController: CRITICAL: backup failed on sqlite3_backup_init()"ZT_EOL_S); + continue; + } + + int rc = SQLITE_OK; + for(;;) { + if (!_backupThreadRun) { + sqlite3_backup_finish(bak); + sqlite3_close(bakdb); + OSUtils::rm(backupPath); + return; + } + _lock.lock(); + rc = sqlite3_backup_step(bak,64); + _lock.unlock(); + if ((rc == SQLITE_OK)||(rc == SQLITE_LOCKED)||(rc == SQLITE_BUSY)) + Thread::sleep(50); + else break; + } + + sqlite3_backup_finish(bak); + sqlite3_close(bakdb); + + OSUtils::rm(backupPath2); + ::rename(backupPath,backupPath2); + } + Thread::sleep(250); + } +} + unsigned int SqliteNetworkController::_doCPGet( const std::vector<std::string> &path, const std::map<std::string,std::string> &urlArgs, diff --git a/controller/SqliteNetworkController.hpp b/controller/SqliteNetworkController.hpp index a3d5dfc7..0e2bb63e 100644 --- a/controller/SqliteNetworkController.hpp +++ b/controller/SqliteNetworkController.hpp @@ -39,6 +39,7 @@ #include "../node/Constants.hpp" #include "../node/NetworkController.hpp" #include "../node/Mutex.hpp" +#include "../osdep/Thread.hpp" // Number of in-memory last log entries to maintain per user #define ZT_SQLITENETWORKCONTROLLER_IN_MEMORY_LOG_SIZE 32 @@ -86,6 +87,10 @@ public: std::string &responseBody, std::string &responseContentType); + // threadMain() for backup thread -- do not call directly + void threadMain() + throw(); + private: enum IpAssignmentType { // IP assignment is a static IP address @@ -112,6 +117,8 @@ private: static void _circuitTestCallback(ZT_Node *node,ZT_CircuitTest *test,const ZT_CircuitTestReport *report); Node *_node; + Thread _backupThread; + volatile bool _backupThreadRun; std::string _dbPath; std::string _circuitTestPath; std::string _instanceId; diff --git a/make-linux.mk b/make-linux.mk index 5e0a2072..eddef7fc 100644 --- a/make-linux.mk +++ b/make-linux.mk @@ -88,6 +88,9 @@ else LDFLAGS=-pie -Wl,-z,relro,-z,now STRIP=strip --strip-all endif +ifeq ($(ZT_TRACE),1) + DEFS+=-DZT_TRACE +endif # Uncomment for gprof profile build #CFLAGS=-Wall -g -pg -pthread $(INCLUDES) $(DEFS) diff --git a/node/InetAddress.hpp b/node/InetAddress.hpp index c4d5cfda..74efc943 100644 --- a/node/InetAddress.hpp +++ b/node/InetAddress.hpp @@ -411,7 +411,7 @@ struct InetAddress : public sockaddr_storage // TODO: Ethernet address (but accept for forward compatibility) return 7; case 0x02: - // TODO: Bluetooth address (but accept for forward compatibility) + // TODO: Bluetooth address (but accept for forward compatibility) return 7; case 0x03: // TODO: Other address types (but accept for forward compatibility) diff --git a/node/Peer.cpp b/node/Peer.cpp index 9d0d78e5..0b981c8e 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -83,10 +83,10 @@ void Peer::received( Packet::Verb inReVerb) { #ifdef ZT_ENABLE_CLUSTER - InetAddress redirectTo; if ((RR->cluster)&&(hops == 0)) { // Note: findBetterEndpoint() is first since we still want to check // for a better endpoint even if we don't actually send a redirect. + InetAddress redirectTo; if ( (RR->cluster->findBetterEndpoint(redirectTo,_id.address(),remoteAddr,false)) && (verb != Packet::VERB_OK)&&(verb != Packet::VERB_ERROR)&&(verb != Packet::VERB_RENDEZVOUS)&&(verb != Packet::VERB_PUSH_DIRECT_PATHS) ) { if (_vProto >= 5) { // For newer peers we can send a more idiomatic verb: PUSH_DIRECT_PATHS. @@ -141,13 +141,6 @@ void Peer::received( else if (verb == Packet::VERB_MULTICAST_FRAME) _lastMulticastFrame = now; -#ifdef ZT_ENABLE_CLUSTER - // If we think this peer belongs elsewhere, don't learn this path or - // do other connection init stuff. - if (redirectTo) - return; -#endif - if ((now - _lastAnnouncedTo) >= ((ZT_MULTICAST_LIKE_EXPIRE / 2) - 1000)) { _lastAnnouncedTo = now; needMulticastGroupAnnounce = true; diff --git a/node/Switch.cpp b/node/Switch.cpp index b7a9c522..97befbc6 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -154,25 +154,84 @@ void Switch::onLocalEthernet(const SharedPtr<Network> &network,const MAC &from,c MulticastGroup mg(to,0); if (to.isBroadcast()) { - if ( - (etherType == ZT_ETHERTYPE_ARP)&& - (len >= 28)&& - ( - (((const unsigned char *)data)[2] == 0x08)&& - (((const unsigned char *)data)[3] == 0x00)&& - (((const unsigned char *)data)[4] == 6)&& - (((const unsigned char *)data)[5] == 4)&& - (((const unsigned char *)data)[7] == 0x01) - ) - ) { - // Cram IPv4 IP into ADI field to make IPv4 ARP broadcast channel specific and scalable - // Also: enableBroadcast() does not apply to ARP since it's required for IPv4 + if ( (etherType == ZT_ETHERTYPE_ARP) && (len >= 28) && ((((const uint8_t *)data)[2] == 0x08)&&(((const uint8_t *)data)[3] == 0x00)&&(((const uint8_t *)data)[4] == 6)&&(((const uint8_t *)data)[5] == 4)&&(((const uint8_t *)data)[7] == 0x01)) ) { + /* IPv4 ARP is one of the few special cases that we impose upon what is + * otherwise a straightforward Ethernet switch emulation. Vanilla ARP + * is dumb old broadcast and simply doesn't scale. ZeroTier multicast + * groups have an additional field called ADI (additional distinguishing + * information) which was added specifically for ARP though it could + * be used for other things too. We then take ARP broadcasts and turn + * them into multicasts by stuffing the IP address being queried into + * the 32-bit ADI field. In practice this uses our multicast pub/sub + * system to implement a kind of extended/distributed ARP table. */ mg = MulticastGroup::deriveMulticastGroupForAddressResolution(InetAddress(((const unsigned char *)data) + 24,4,0)); } else if (!nconf->enableBroadcast()) { // Don't transmit broadcasts if this network doesn't want them TRACE("%.16llx: dropped broadcast since ff:ff:ff:ff:ff:ff is not enabled",network->id()); return; } + } else if ((etherType == ZT_ETHERTYPE_IPV6)&&(len >= (40 + 8 + 16))) { + /* IPv6 NDP emulation on ZeroTier-RFC4193 addressed networks! This allows + * for multicast-free operation in IPv6 networks, which both improves + * performance and is friendlier to mobile and (especially) IoT devices. + * In the future there may be a no-multicast build option for embedded + * and IoT use and this will be the preferred addressing mode. Note that + * it plays nice with our L2 emulation philosophy and even with bridging. + * While "real" devices behind the bridge can't have ZT-RFC4193 addresses + * themselves, they can look these addresses up with NDP and it will + * work just fine. */ + if ((reinterpret_cast<const uint8_t *>(data)[6] == 0x3a)&&(reinterpret_cast<const uint8_t *>(data)[40] == 0x87)) { // ICMPv6 neighbor solicitation + for(std::vector<InetAddress>::const_iterator sip(nconf->staticIps().begin()),sipend(nconf->staticIps().end());sip!=sipend;++sip) { + if ((sip->ss_family == AF_INET6)&&(Utils::ntoh((uint16_t)reinterpret_cast<const struct sockaddr_in6 *>(&(*sip))->sin6_port) == 88)) { + const uint8_t *my6 = reinterpret_cast<const uint8_t *>(reinterpret_cast<const struct sockaddr_in6 *>(&(*sip))->sin6_addr.s6_addr); + if ((my6[0] == 0xfd)&&(my6[9] == 0x99)&&(my6[10] == 0x93)) { // ZT-RFC4193 == fd__:____:____:____:__99:93__:____:____ / 88 + const uint8_t *pkt6 = reinterpret_cast<const uint8_t *>(data) + 40 + 8; + unsigned int ptr = 0; + while (ptr != 11) { + if (pkt6[ptr] != my6[ptr]) + break; + ++ptr; + } + if (ptr == 11) { // /88 matches an assigned address on this network + const Address atPeer(pkt6 + ptr,5); + if (atPeer != RR->identity.address()) { + const MAC atPeerMac(atPeer,network->id()); + TRACE("ZT-RFC4193 NDP emulation: %.16llx: forging response for %s/%s",network->id(),atPeer.toString().c_str(),atPeerMac.toString().c_str()); + + uint8_t adv[72]; + adv[0] = 0x60; adv[1] = 0x00; adv[2] = 0x00; adv[3] = 0x00; + adv[4] = 0x00; adv[5] = 0x20; + adv[6] = 0x3a; adv[7] = 0xff; + for(int i=0;i<16;++i) adv[8 + i] = pkt6[i]; + for(int i=0;i<16;++i) adv[24 + i] = my6[i]; + adv[40] = 0x88; adv[41] = 0x00; + adv[42] = 0x00; adv[43] = 0x00; // future home of checksum + adv[44] = 0x60; adv[45] = 0x00; adv[46] = 0x00; adv[47] = 0x00; + for(int i=0;i<16;++i) adv[48 + i] = pkt6[i]; + adv[64] = 0x02; adv[65] = 0x01; + adv[66] = atPeerMac[0]; adv[67] = atPeerMac[1]; adv[68] = atPeerMac[2]; adv[69] = atPeerMac[3]; adv[70] = atPeerMac[4]; adv[71] = atPeerMac[5]; + + uint16_t pseudo_[36]; + uint8_t *const pseudo = reinterpret_cast<uint8_t *>(pseudo_); + for(int i=0;i<32;++i) pseudo[i] = adv[8 + i]; + pseudo[32] = 0x00; pseudo[33] = 0x00; pseudo[34] = 0x00; pseudo[35] = 0x20; + pseudo[36] = 0x00; pseudo[37] = 0x00; pseudo[38] = 0x00; pseudo[39] = 0x3a; + for(int i=0;i<32;++i) pseudo[40 + i] = adv[40 + i]; + uint32_t checksum = 0; + for(int i=0;i<36;++i) checksum += Utils::hton(pseudo_[i]); + while ((checksum >> 16)) checksum = (checksum & 0xffff) + (checksum >> 16); + checksum = ~checksum; + adv[42] = (checksum >> 8) & 0xff; + adv[43] = checksum & 0xff; + + RR->node->putFrame(network->id(),atPeerMac,from,ZT_ETHERTYPE_IPV6,0,adv,72); + return; // stop processing: we have handled this frame with a spoofed local reply so no need to send it anywhere + } + } + } + } + } + } } /* Learn multicast groups for bridged-in hosts. diff --git a/osdep/OSUtils.hpp b/osdep/OSUtils.hpp index 5de35eba..43fd2813 100644 --- a/osdep/OSUtils.hpp +++ b/osdep/OSUtils.hpp @@ -95,7 +95,6 @@ public: static inline bool rm(const std::string &path) throw() { return rm(path.c_str()); } static inline bool mkdir(const char *path) - throw() { #ifdef __WINDOWS__ if (::PathIsDirectoryA(path)) diff --git a/selftest.cpp b/selftest.cpp index 0787925f..fa8df48b 100644 --- a/selftest.cpp +++ b/selftest.cpp @@ -41,6 +41,7 @@ #include "node/InetAddress.hpp" #include "node/Utils.hpp" #include "node/Identity.hpp" +#include "node/Buffer.hpp" #include "node/Packet.hpp" #include "node/Salsa20.hpp" #include "node/MAC.hpp" diff --git a/tests/http/agent.js b/tests/http/agent.js index bc7c475e..e90ee482 100644 --- a/tests/http/agent.js +++ b/tests/http/agent.js @@ -4,20 +4,20 @@ // Customizable parameters: // Maximum interval between test attempts -var TEST_INTERVAL_MAX = 60000; +var TEST_INTERVAL_MAX = (60000 * 5); // Test timeout in ms -var TEST_TIMEOUT = 30000; +var TEST_TIMEOUT = 60000; // Where should I contact to register and query a list of other test agents? -var SERVER_HOST = '104.238.141.145'; +var SERVER_HOST = '174.136.102.178'; var SERVER_PORT = 18080; // Which port should agents use for their HTTP? var AGENT_PORT = 18888; // Payload size in bytes -var PAYLOAD_SIZE = 10000; +var PAYLOAD_SIZE = 5000; // --------------------------------------------------------------------------- diff --git a/tests/http/big-test-hosts b/tests/http/big-test-hosts deleted file mode 100644 index 93b6f23f..00000000 --- a/tests/http/big-test-hosts +++ /dev/null @@ -1,2 +0,0 @@ -root@104.156.246.48 -root@104.156.252.136 diff --git a/tests/http/big-test-kill.sh b/tests/http/big-test-kill.sh index 59f36788..29dbd638 100755 --- a/tests/http/big-test-kill.sh +++ b/tests/http/big-test-kill.sh @@ -1,18 +1,9 @@ #!/bin/bash -# Edit as needed -- note that >1000 per host is likely problematic due to Linux kernel limits -NUM_CONTAINERS=100 -CONTAINER_IMAGE=zerotier/http-test - -# -# This script is designed to be run on Docker hosts to run NUM_CONTAINERS -# -# It can then be run on each Docker host via pssh or similar to run very -# large scale tests. -# +# Kills all running Docker containers on all big-test-hosts export PATH=/bin:/usr/bin:/usr/local/bin:/usr/sbin:/sbin -pssh -h big-test-hosts -i -t 0 -p 256 "docker ps -aq | xargs -r docker rm -f" +pssh -h big-test-hosts -i -t 0 -p 256 "sudo docker ps -aq | xargs -r sudo docker rm -f" exit 0 diff --git a/tests/http/big-test-ready.sh b/tests/http/big-test-ready.sh deleted file mode 100755 index aa540bba..00000000 --- a/tests/http/big-test-ready.sh +++ /dev/null @@ -1,30 +0,0 @@ -#!/bin/bash - -# Edit as needed -- note that >1000 per host is likely problematic due to Linux kernel limits -NUM_CONTAINERS=100 -CONTAINER_IMAGE=zerotier/http-test - -# -# This script is designed to be run on Docker hosts to run NUM_CONTAINERS -# -# It can then be run on each Docker host via pssh or similar to run very -# large scale tests. -# - -export PATH=/bin:/usr/bin:/usr/local/bin:/usr/sbin:/sbin - -# Kill and clean up old test containers if any -- note that this kills all containers on the system! -#docker ps -q | xargs -n 1 docker kill -#docker ps -aq | xargs -n 1 docker rm - -# Pull latest if needed -- change this to your image name and/or where to pull it from -#docker pull $CONTAINER_IMAGE - -# Run NUM_CONTAINERS -#for ((n=0;n<$NUM_CONTAINERS;n++)); do -# docker run --device=/dev/net/tun --privileged -d $CONTAINER_IMAGE -#done - -pssh -h big-test-hosts -i -t 0 -p 256 "docker pull $CONTAINER_IMAGE" - -exit 0 diff --git a/tests/http/big-test-start.sh b/tests/http/big-test-start.sh index f300ac61..3ef4a316 100755 --- a/tests/http/big-test-start.sh +++ b/tests/http/big-test-start.sh @@ -1,30 +1,12 @@ #!/bin/bash -# Edit as needed -- note that >1000 per host is likely problematic due to Linux kernel limits -NUM_CONTAINERS=50 +# More than 500 container seems to result in a lot of sporadic failures, probably due to Linux kernel scaling issues with virtual network ports +# 250 with a 16GB RAM VM like Amazon m4.xlarge seems good +NUM_CONTAINERS=250 CONTAINER_IMAGE=zerotier/http-test -# -# This script is designed to be run on Docker hosts to run NUM_CONTAINERS -# -# It can then be run on each Docker host via pssh or similar to run very -# large scale tests. -# - export PATH=/bin:/usr/bin:/usr/local/bin:/usr/sbin:/sbin -# Kill and clean up old test containers if any -- note that this kills all containers on the system! -#docker ps -q | xargs -n 1 docker kill -#docker ps -aq | xargs -n 1 docker rm - -# Pull latest if needed -- change this to your image name and/or where to pull it from -#docker pull $CONTAINER_IMAGE - -# Run NUM_CONTAINERS -#for ((n=0;n<$NUM_CONTAINERS;n++)); do -# docker run --device=/dev/net/tun --privileged -d $CONTAINER_IMAGE -#done - -pssh -h big-test-hosts -o big-test-out -t 0 -p 256 "for ((n=0;n<$NUM_CONTAINERS;n++)); do docker run --device=/dev/net/tun --privileged -d $CONTAINER_IMAGE; sleep 0.25; done" +pssh -h big-test-hosts -o big-test-out -t 0 -p 256 "for ((n=0;n<$NUM_CONTAINERS;n++)); do sudo docker run --device=/dev/net/tun --privileged -d $CONTAINER_IMAGE; sleep 0.1; done" exit 0 diff --git a/tests/http/docker-main.sh b/tests/http/docker-main.sh index f9e11de5..29cdced9 100755 --- a/tests/http/docker-main.sh +++ b/tests/http/docker-main.sh @@ -4,11 +4,13 @@ export PATH=/bin:/usr/bin:/usr/local/bin:/sbin:/usr/sbin /zerotier-one -d >>zerotier-one.out 2>&1 +# Wait for ZeroTier to start and join the network while [ ! -d "/proc/sys/net/ipv6/conf/zt0" ]; do sleep 0.25 done -sleep 2 +# Wait just a bit longer for stuff to settle +sleep 5 exec node --harmony /agent.js >>agent.out 2>&1 #exec node --harmony /agent.js diff --git a/windows/WinUI/APIHandler.cs b/windows/WinUI/APIHandler.cs new file mode 100644 index 00000000..8e7408a5 --- /dev/null +++ b/windows/WinUI/APIHandler.cs @@ -0,0 +1,151 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Net; +using System.IO; +using Newtonsoft.Json; + +namespace WinUI +{ + + + public class APIHandler + { + static string authtoken = "p3ptrzds5jkr2hbx5ipbyf04"; // delete me! + + private string url = null; + + public APIHandler() + { + url = "http://127.0.0.1:9993"; + } + + public APIHandler(string host, int port) + { + url = "http://" + host + ":" + port; + } + + public ZeroTierStatus GetStatus() + { + var request = WebRequest.Create(url + "/status" + "?auth=" + authtoken) as HttpWebRequest; + if (request != null) + { + request.Method = "GET"; + request.ContentType = "application/json"; + } + + 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; + } + } + + 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"; + + 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; + } + } + + public void JoinNetwork(string nwid) + { + var request = WebRequest.Create(url + "/network/" + nwid + "?auth=" + authtoken) as HttpWebRequest; + if (request == null) + { + return; + } + + request.Method = "POST"; + + var httpResponse = (HttpWebResponse)request.GetResponse(); + + if (httpResponse.StatusCode != HttpStatusCode.OK) + { + Console.WriteLine("Error sending join network message"); + } + } + + public void LeaveNetwork(string nwid) + { + var request = WebRequest.Create(url + "/network/" + nwid + "?auth=" + authtoken) as HttpWebRequest; + if (request == null) + { + return; + } + + request.Method = "DELETE"; + + var httpResponse = (HttpWebResponse)request.GetResponse(); + + if (httpResponse.StatusCode != HttpStatusCode.OK) + { + Console.WriteLine("Error sending leave network message"); + } + } + + 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"; + + var httpResponse = (HttpWebResponse)request.GetResponse(); + using (var streamReader = new StreamReader(httpResponse.GetResponseStream())) + { + var responseText = streamReader.ReadToEnd(); + + List<ZeroTierPeer> peerList = null; + try + { + peerList = JsonConvert.DeserializeObject<List<ZeroTierPeer>>(responseText); + } + catch (JsonReaderException e) + { + Console.WriteLine(e.ToString()); + } + return peerList; + } + } + } +} diff --git a/windows/WinUI/App.config b/windows/WinUI/App.config new file mode 100644 index 00000000..8e156463 --- /dev/null +++ b/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/windows/WinUI/App.xaml b/windows/WinUI/App.xaml new file mode 100644 index 00000000..08b9b792 --- /dev/null +++ b/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/windows/WinUI/App.xaml.cs b/windows/WinUI/App.xaml.cs new file mode 100644 index 00000000..a97edde7 --- /dev/null +++ b/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/windows/WinUI/Fonts/segoeui.ttf b/windows/WinUI/Fonts/segoeui.ttf Binary files differnew file mode 100644 index 00000000..fc18ebd0 --- /dev/null +++ b/windows/WinUI/Fonts/segoeui.ttf diff --git a/windows/WinUI/Fonts/segoeuib.ttf b/windows/WinUI/Fonts/segoeuib.ttf Binary files differnew file mode 100644 index 00000000..5f31e0ca --- /dev/null +++ b/windows/WinUI/Fonts/segoeuib.ttf diff --git a/windows/WinUI/Fonts/segoeuii.ttf b/windows/WinUI/Fonts/segoeuii.ttf Binary files differnew file mode 100644 index 00000000..7efb70d6 --- /dev/null +++ b/windows/WinUI/Fonts/segoeuii.ttf diff --git a/windows/WinUI/Fonts/segoeuiz.ttf b/windows/WinUI/Fonts/segoeuiz.ttf Binary files differnew file mode 100644 index 00000000..d7bb186b --- /dev/null +++ b/windows/WinUI/Fonts/segoeuiz.ttf diff --git a/windows/WinUI/MainWindow.xaml b/windows/WinUI/MainWindow.xaml new file mode 100644 index 00000000..553d44fe --- /dev/null +++ b/windows/WinUI/MainWindow.xaml @@ -0,0 +1,114 @@ +<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="700" Icon="ZeroTierIcon.ico"> + + <Window.Resources> + <ResourceDictionary> + <Style TargetType="{x:Type TabItem}"> + <Setter Property="BorderThickness" + Value="3" /> + <Setter Property="BorderBrush" + Value="Blue" /> + <Setter Property="VerticalContentAlignment" + Value="Center" /> + <Setter Property="HorizontalContentAlignment" + Value="Center" /> + <Setter Property="Template"> + <Setter.Value> + <ControlTemplate TargetType="{x:Type TabItem}"> + <Border> + <Grid> + <Grid> + <Border x:Name="border" + CornerRadius="3,3,0,0" + Background="{TemplateBinding Background}" + BorderBrush="{TemplateBinding BorderBrush}" + BorderThickness="1,1,1,0" /> + </Grid> + <Border BorderThickness="{TemplateBinding BorderThickness}" + Padding="{TemplateBinding Padding}"> + <ContentPresenter ContentSource="Header" + HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" + VerticalAlignment="{TemplateBinding VerticalContentAlignment}" /> + </Border> + </Grid> + </Border> + <ControlTemplate.Triggers> + <Trigger Property="IsSelected" + Value="True"> + <Setter TargetName="border" + Property="BorderBrush" + Value="#ff91a2a3" /> + <Setter TargetName="border" + Property="BorderThickness" + Value="0,3,0,0" /> + </Trigger> + </ControlTemplate.Triggers> + </ControlTemplate> + </Setter.Value> + </Setter> + </Style> + </ResourceDictionary> + </Window.Resources> + + <DockPanel> + <StatusBar DockPanel.Dock="Bottom" Height="34" 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="Network ID" Foreground="White"/> + <StatusBarItem Grid.Column="1" x:Name="onlineStatus" Content="ONLINE" Foreground="White"/> + <StatusBarItem Grid.Column="2" x:Name="versionString" Content="1.0.5" Foreground="White" Margin="0"/> + <StatusBarItem Grid.Column="3" x:Name="blank" Content="" Height="43" Foreground="White" Margin="6,0,-6,-9"/> + <StatusBarItem Grid.Column="4"> + <TextBox x:Name="joinNetworkID" Height="23" TextWrapping="Wrap" Width="120" HorizontalAlignment="Right" RenderTransformOrigin="1.168,0.478" ToolTip="Enter Network ID" PreviewTextInput="OnNetworkEntered" MaxLength="16"/> + </StatusBarItem> + <StatusBarItem Grid.Column="5" x:Name="statusBarButton" Foreground="White" RenderTransformOrigin="0.789,0.442"> + <Button x:Name="joinButton" Content="Join" Background="#FFFFB354" Width="77.423" Click="joinButton_Click"/> + </StatusBarItem> + </StatusBar> + <TabControl> + <TabItem x:Name="Networks" Header="Networks" Background="#FF234447" Foreground="White" IsSelected="True" IsManipulationEnabled="True"> + <Grid 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" Background="#FF234447" 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/windows/WinUI/MainWindow.xaml.cs b/windows/WinUI/MainWindow.xaml.cs new file mode 100644 index 00000000..f6cb4f44 --- /dev/null +++ b/windows/WinUI/MainWindow.xaml.cs @@ -0,0 +1,124 @@ +using System; +using System.Collections.Generic; +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 = new APIHandler(); + Regex charRegex = new Regex("[0-9a-fxA-FX]"); + Regex wholeStringRegex = new Regex("^[0-9a-fxA-FX]+$"); + + Timer timer = new Timer(); + + public MainWindow() + { + InitializeComponent(); + + networksPage.SetAPIHandler(handler); + + updateStatus(); + updateNetworks(); + updatePeers(); + + DataObject.AddPastingHandler(joinNetworkID, OnPaste); + + timer.Elapsed += new ElapsedEventHandler(OnUpdateTimer); + timer.Interval = 2000; + timer.Enabled = true; + } + + private void updateStatus() + { + var status = handler.GetStatus(); + + 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"); + })); + } + + 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/windows/WinUI/NetworkInfoView.xaml b/windows/WinUI/NetworkInfoView.xaml new file mode 100644 index 00000000..86f2b98c --- /dev/null +++ b/windows/WinUI/NetworkInfoView.xaml @@ -0,0 +1,63 @@ +<UserControl 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" + > + <Grid Background="#FFFFFFFF" Margin="5,0,5,1"> + <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"/> + </Grid.RowDefinitions> + + <Grid Grid.Column="0" Grid.Row="0" Grid.ColumnSpan="3"> + <Grid.ColumnDefinitions> + <ColumnDefinition Width="auto"/> + <ColumnDefinition Width="*"/> + </Grid.ColumnDefinitions> + + <TextBlock x:Name="networkId" Text="8056c2e21c000001" HorizontalAlignment="Left" Grid.Column="0" Foreground="#FF91A2A3"/> + <TextBlock x:Name="networkName" Text="earth.zerotier.net" HorizontalAlignment="Right" Grid.Column="1" Foreground="#FF000000"/> + </Grid> + + <TextBlock TextWrapping="Wrap" Text="Status" HorizontalAlignment="Right" Grid.Column="0" Grid.Row="1" Foreground="#FF000000"/> + <TextBlock TextWrapping="Wrap" Text="Type" HorizontalAlignment="Right" Grid.Column="0" Grid.Row="2" Foreground="#FF000000"/> + <TextBlock TextWrapping="Wrap" Text="MAC" HorizontalAlignment="Right" Grid.Column="0" Grid.Row="3" Foreground="#FF000000"/> + <TextBlock TextWrapping="Wrap" Text="MTU" HorizontalAlignment="Right" Grid.Column="0" Grid.Row="4" Foreground="#FF000000"/> + <TextBlock TextWrapping="Wrap" Text="Broadcast" HorizontalAlignment="Right" Grid.Column="0" Grid.Row="5" Foreground="#FF000000"/> + <TextBlock TextWrapping="Wrap" Text="Bridging" HorizontalAlignment="Right" Grid.Column="0" Grid.Row="6" Foreground="#FF000000"/> + <TextBlock TextWrapping="Wrap" Text="Device" HorizontalAlignment="Right" Grid.Column="0" Grid.Row="7" Foreground="#FF000000"/> + <TextBlock TextWrapping="Wrap" Text="Managed IPs" HorizontalAlignment="Right" Grid.Column="0" Grid.Row="8" Foreground="#FF000000"/> + + <TextBlock x:Name="networkStatus" TextWrapping="Wrap" HorizontalAlignment="Right" Text="OK" TextAlignment="Right" Grid.Column="2" Grid.Row="1" Foreground="#FF000000"/> + <TextBlock x:Name="networkType" TextWrapping="Wrap" Text="PUBLIC" HorizontalAlignment="Right" Grid.Column="2" Grid.Row="2" Foreground="#FF000000"/> + <TextBlock x:Name="macAddress" TextWrapping="Wrap" HorizontalAlignment="Right" Grid.Column="2" Grid.Row="3" Foreground="#FF000000"><Span><Run Text="02:83:4a:1e:4b:3a"/></Span></TextBlock> + <TextBlock x:Name="mtu" TextWrapping="Wrap" Text="2800" HorizontalAlignment="Right" Grid.Column="2" Grid.Row="4" Foreground="#FF000000"/> + <TextBlock x:Name="broadcastEnabled" TextWrapping="Wrap" Text="ENABLED" HorizontalAlignment="Right" Grid.Column="2" Grid.Row="5" Foreground="#FF000000"/> + <TextBlock x:Name="bridgingEnabled" TextWrapping="Wrap" Text="DISABLED" HorizontalAlignment="Right" Grid.Column="2" Grid.Row="6" Foreground="#FF000000"/> + <TextBlock x:Name="deviceName" TextWrapping="Wrap" HorizontalAlignment="Right" Grid.Column="2" Grid.Row="7" Foreground="#FF000000"><Span><Run Text="ethernet_32771"/></Span></TextBlock> + <TextBlock x:Name="managedIps" TextWrapping="Wrap" HorizontalAlignment="Right" TextAlignment="Right" Grid.Column="2" Grid.Row="8" 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> + + <Grid Grid.Column="0" Grid.Row="9" Grid.ColumnSpan="3" Background="#FFFFFFFF"> + <Grid.ColumnDefinitions> + <ColumnDefinition Width="*"/> + </Grid.ColumnDefinitions> + <Button /> + <Button x:Name="leaveButton" Content="Leave" HorizontalAlignment="Right" VerticalAlignment="Bottom" Width="75" Background="#FFFFB354" Click="leaveButton_Click"/> + </Grid> + </Grid> +</UserControl> diff --git a/windows/WinUI/NetworkInfoView.xaml.cs b/windows/WinUI/NetworkInfoView.xaml.cs new file mode 100644 index 00000000..ccdec288 --- /dev/null +++ b/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/windows/WinUI/NetworksPage.xaml b/windows/WinUI/NetworksPage.xaml new file mode 100644 index 00000000..f8aec61b --- /dev/null +++ b/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" Width="{Binding RelativeSource={RelativeSource AncestorType={x:Type Window}}, Path=ActualWidth}" Height="{Binding RelativeSource={RelativeSource AncestorType={x:Type Window}}, Path=ActualHeight}"> + <WrapPanel x:Name="wrapPanel" Background="#FF555555" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"> + + </WrapPanel> + </ScrollViewer> +</UserControl> diff --git a/windows/WinUI/NetworksPage.xaml.cs b/windows/WinUI/NetworksPage.xaml.cs new file mode 100644 index 00000000..9ded9970 --- /dev/null +++ b/windows/WinUI/NetworksPage.xaml.cs @@ -0,0 +1,48 @@ +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(); + + for (int i = 0; i < networks.Count; ++i) + { + this.wrapPanel.Children.Add( + new NetworkInfoView( + handler, + networks.ElementAt<ZeroTierNetwork>(i))); + } + } + } +} diff --git a/windows/WinUI/PeersPage.xaml b/windows/WinUI/PeersPage.xaml new file mode 100644 index 00000000..bf96f5ef --- /dev/null +++ b/windows/WinUI/PeersPage.xaml @@ -0,0 +1,19 @@ +<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" AutoGenerateColumns="False" CanUserResizeColumns="True" Margin="0,0,0,0" CanUserReorderColumns="False" Width="{Binding RelativeSource={RelativeSource AncestorType={x:Type Window}}, Path=ActualWidth}" Height="{Binding RelativeSource={RelativeSource AncestorType={x:Type Window}}, Path=ActualHeight}" CanUserSortColumns="False"> + <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 Header="Role" Binding="{Binding Role}"/> + </DataGrid.Columns> + </DataGrid> +</UserControl> diff --git a/windows/WinUI/PeersPage.xaml.cs b/windows/WinUI/PeersPage.xaml.cs new file mode 100644 index 00000000..b1dd8adf --- /dev/null +++ b/windows/WinUI/PeersPage.xaml.cs @@ -0,0 +1,39 @@ +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> peerList) + { + this.peersList = peerList; + dataGrid.ItemsSource = this.peersList; + dataGrid.Items.Refresh(); + } + } +} diff --git a/windows/WinUI/Properties/AssemblyInfo.cs b/windows/WinUI/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..9c7cd133 --- /dev/null +++ b/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/windows/WinUI/Properties/Resources.Designer.cs b/windows/WinUI/Properties/Resources.Designer.cs new file mode 100644 index 00000000..57a56f7d --- /dev/null +++ b/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/windows/WinUI/Properties/Resources.resx b/windows/WinUI/Properties/Resources.resx new file mode 100644 index 00000000..af7dbebb --- /dev/null +++ b/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/windows/WinUI/Properties/Settings.Designer.cs b/windows/WinUI/Properties/Settings.Designer.cs new file mode 100644 index 00000000..6812cccd --- /dev/null +++ b/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/windows/WinUI/Properties/Settings.settings b/windows/WinUI/Properties/Settings.settings new file mode 100644 index 00000000..033d7a5e --- /dev/null +++ b/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/windows/WinUI/Simple Styles.xaml b/windows/WinUI/Simple Styles.xaml new file mode 100644 index 00000000..f2ddedf9 --- /dev/null +++ b/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/windows/WinUI/Themes/Generic.xaml b/windows/WinUI/Themes/Generic.xaml new file mode 100644 index 00000000..2b47588d --- /dev/null +++ b/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/windows/WinUI/WinUI.csproj b/windows/WinUI/WinUI.csproj new file mode 100644 index 00000000..5ebfedcf --- /dev/null +++ b/windows/WinUI/WinUI.csproj @@ -0,0 +1,223 @@ +<?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> + <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="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/windows/WinUI/ZeroTierIcon.ico b/windows/WinUI/ZeroTierIcon.ico Binary files differnew file mode 100644 index 00000000..2d190c47 --- /dev/null +++ b/windows/WinUI/ZeroTierIcon.ico diff --git a/windows/WinUI/ZeroTierNetwork.cs b/windows/WinUI/ZeroTierNetwork.cs new file mode 100644 index 00000000..cce65441 --- /dev/null +++ b/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/windows/WinUI/ZeroTierPeer.cs b/windows/WinUI/ZeroTierPeer.cs new file mode 100644 index 00000000..3153f7e2 --- /dev/null +++ b/windows/WinUI/ZeroTierPeer.cs @@ -0,0 +1,66 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Newtonsoft.Json; + +namespace WinUI +{ + public class ZeroTierPeer + { + [JsonProperty("address")] + public string Address { get; set; } + + [JsonProperty("lastUnicastFrame")] + public UInt64 LastUnicastFrame { get; set; } + + [JsonProperty("lastMulticastFrame")] + public UInt64 LastMulticastFrame { 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; } + + 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; + } + } + } +} diff --git a/windows/WinUI/ZeroTierPeerPhysicalPath.cs b/windows/WinUI/ZeroTierPeerPhysicalPath.cs new file mode 100644 index 00000000..3eaa8026 --- /dev/null +++ b/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/windows/WinUI/ZeroTierStatus.cs b/windows/WinUI/ZeroTierStatus.cs new file mode 100644 index 00000000..2851d017 --- /dev/null +++ b/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/windows/WinUI/packages.config b/windows/WinUI/packages.config new file mode 100644 index 00000000..505e5883 --- /dev/null +++ b/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 diff --git a/windows/ZeroTierOne.sln b/windows/ZeroTierOne.sln index 1c6e58ed..d86c212a 100644 --- a/windows/ZeroTierOne.sln +++ b/windows/ZeroTierOne.sln @@ -9,6 +9,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TapDriver6", "TapDriver6\Ta EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WebUIWrapper", "WebUIWrapper\WebUIWrapper.csproj", "{04832129-0F0C-438B-ACDF-8BB7F99AE241}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WinUI", "WinUI\WinUI.csproj", "{4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution CD_ROM|Any CPU = CD_ROM|Any CPU @@ -519,6 +521,83 @@ Global {04832129-0F0C-438B-ACDF-8BB7F99AE241}.Win8 Release|Win32.ActiveCfg = Release|Any CPU {04832129-0F0C-438B-ACDF-8BB7F99AE241}.Win8 Release|x64.ActiveCfg = Release|Any CPU {04832129-0F0C-438B-ACDF-8BB7F99AE241}.Win8 Release|x86.ActiveCfg = Release|Any CPU + {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.CD_ROM|Any CPU.ActiveCfg = Release|Any CPU + {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.CD_ROM|Any CPU.Build.0 = Release|Any CPU + {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.CD_ROM|Mixed Platforms.ActiveCfg = Release|Any CPU + {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.CD_ROM|Mixed Platforms.Build.0 = Release|Any CPU + {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.CD_ROM|Win32.ActiveCfg = Release|Any CPU + {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.CD_ROM|x64.ActiveCfg = Release|Any CPU + {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.CD_ROM|x86.ActiveCfg = Release|Any CPU + {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.Debug|Win32.ActiveCfg = Debug|Any CPU + {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.Debug|x64.ActiveCfg = Debug|Any CPU + {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.Debug|x86.ActiveCfg = Debug|Any CPU + {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.DVD-5|Any CPU.ActiveCfg = Debug|Any CPU + {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.DVD-5|Any CPU.Build.0 = Debug|Any CPU + {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.DVD-5|Mixed Platforms.ActiveCfg = Debug|Any CPU + {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.DVD-5|Mixed Platforms.Build.0 = Debug|Any CPU + {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.DVD-5|Win32.ActiveCfg = Debug|Any CPU + {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.DVD-5|x64.ActiveCfg = Debug|Any CPU + {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.DVD-5|x86.ActiveCfg = Debug|Any CPU + {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.Release|Any CPU.Build.0 = Release|Any CPU + {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.Release|Win32.ActiveCfg = Release|Any CPU + {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.Release|x64.ActiveCfg = Release|Any CPU + {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.Release|x86.ActiveCfg = Release|Any CPU + {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.SingleImage|Any CPU.ActiveCfg = Release|Any CPU + {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.SingleImage|Any CPU.Build.0 = Release|Any CPU + {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.SingleImage|Mixed Platforms.ActiveCfg = Release|Any CPU + {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.SingleImage|Mixed Platforms.Build.0 = Release|Any CPU + {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.SingleImage|Win32.ActiveCfg = Release|Any CPU + {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.SingleImage|x64.ActiveCfg = Release|Any CPU + {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.SingleImage|x86.ActiveCfg = Release|Any CPU + {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.Vista Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.Vista Debug|Any CPU.Build.0 = Debug|Any CPU + {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.Vista Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.Vista Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.Vista Debug|Win32.ActiveCfg = Debug|Any CPU + {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.Vista Debug|x64.ActiveCfg = Debug|Any CPU + {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.Vista Debug|x86.ActiveCfg = Debug|Any CPU + {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.Vista Release|Any CPU.ActiveCfg = Release|Any CPU + {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.Vista Release|Any CPU.Build.0 = Release|Any CPU + {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.Vista Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.Vista Release|Mixed Platforms.Build.0 = Release|Any CPU + {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.Vista Release|Win32.ActiveCfg = Release|Any CPU + {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.Vista Release|x64.ActiveCfg = Release|Any CPU + {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.Vista Release|x86.ActiveCfg = Release|Any CPU + {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.Win7 Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.Win7 Debug|Any CPU.Build.0 = Debug|Any CPU + {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.Win7 Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.Win7 Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.Win7 Debug|Win32.ActiveCfg = Debug|Any CPU + {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.Win7 Debug|x64.ActiveCfg = Debug|Any CPU + {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.Win7 Debug|x86.ActiveCfg = Debug|Any CPU + {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.Win7 Release|Any CPU.ActiveCfg = Release|Any CPU + {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.Win7 Release|Any CPU.Build.0 = Release|Any CPU + {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.Win7 Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.Win7 Release|Mixed Platforms.Build.0 = Release|Any CPU + {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.Win7 Release|Win32.ActiveCfg = Release|Any CPU + {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.Win7 Release|x64.ActiveCfg = Release|Any CPU + {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.Win7 Release|x86.ActiveCfg = Release|Any CPU + {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.Win8 Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.Win8 Debug|Any CPU.Build.0 = Debug|Any CPU + {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.Win8 Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.Win8 Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.Win8 Debug|Win32.ActiveCfg = Debug|Any CPU + {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.Win8 Debug|x64.ActiveCfg = Debug|Any CPU + {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.Win8 Debug|x86.ActiveCfg = Debug|Any CPU + {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.Win8 Release|Any CPU.ActiveCfg = Release|Any CPU + {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.Win8 Release|Any CPU.Build.0 = Release|Any CPU + {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.Win8 Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.Win8 Release|Mixed Platforms.Build.0 = Release|Any CPU + {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.Win8 Release|Win32.ActiveCfg = Release|Any CPU + {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.Win8 Release|x64.ActiveCfg = Release|Any CPU + {4CCA6B98-5E64-45BF-AC34-19B3E2570DB1}.Win8 Release|x86.ActiveCfg = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/windows/packages/.gitignore b/windows/packages/.gitignore new file mode 100644 index 00000000..0acda714 --- /dev/null +++ b/windows/packages/.gitignore @@ -0,0 +1,3 @@ +* +!repositories.config +!.gitignore
\ No newline at end of file diff --git a/windows/packages/repositories.config b/windows/packages/repositories.config new file mode 100644 index 00000000..f8197655 --- /dev/null +++ b/windows/packages/repositories.config @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="utf-8"?> +<repositories> + <repository path="..\WinUI\packages.config" /> +</repositories>
\ No newline at end of file |