MouseWithoutBordersPage.xaml.cs
1 // Copyright (c) Microsoft Corporation 2 // The Microsoft Corporation licenses this file to you under the MIT license. 3 // See the LICENSE file in the project root for more information. 4 5 using System; 6 using System.IO.Abstractions; 7 using System.Threading.Tasks; 8 using System.Windows.Input; 9 using Microsoft.PowerToys.Settings.UI.Helpers; 10 using Microsoft.PowerToys.Settings.UI.Library; 11 using Microsoft.PowerToys.Settings.UI.Library.Utilities; 12 using Microsoft.PowerToys.Settings.UI.ViewModels; 13 using Microsoft.UI.Xaml; 14 using Microsoft.UI.Xaml.Controls; 15 using Microsoft.UI.Xaml.Media; 16 using Microsoft.UI.Xaml.Navigation; 17 using Windows.ApplicationModel.DataTransfer; 18 using WinRT; 19 20 using static Microsoft.PowerToys.Settings.UI.ViewModels.MouseWithoutBordersViewModel; 21 22 namespace Microsoft.PowerToys.Settings.UI.Views 23 { 24 public sealed partial class MouseWithoutBordersPage : NavigablePage, IRefreshablePage 25 { 26 private const string MouseWithoutBordersDragDropCheckString = "MWB Device Drag Drop"; 27 28 private const string PowerToyName = "MouseWithoutBorders"; 29 30 private MouseWithoutBordersViewModel ViewModel { get; set; } 31 32 private readonly IFileSystemWatcher watcher; 33 34 public MouseWithoutBordersPage() 35 { 36 var settingsUtils = SettingsUtils.Default; 37 ViewModel = new MouseWithoutBordersViewModel( 38 settingsUtils, 39 SettingsRepository<GeneralSettings>.GetInstance(settingsUtils), 40 ShellPage.SendDefaultIPCMessage, 41 DispatcherQueue); 42 43 watcher = Helper.GetFileWatcher( 44 PowerToyName, 45 "settings.json", 46 OnConfigFileUpdate); 47 48 DataContext = ViewModel; 49 InitializeComponent(); 50 51 Loaded += (s, e) => ViewModel.OnPageLoaded(); 52 } 53 54 private void OnConfigFileUpdate() 55 { 56 // Note: FileSystemWatcher raise notification multiple times for single update operation. 57 // Todo: Handle duplicate events either by somehow suppress them or re-read the configuration every time since we will be updating the UI only if something is changed. 58 this.DispatcherQueue.TryEnqueue(() => 59 { 60 if (ViewModel.LoadUpdatedSettings()) 61 { 62 ViewModel.NotifyUpdatedSettings(); 63 } 64 }); 65 } 66 67 private static T GetChildOfType<T>(DependencyObject depObj, string tag) 68 where T : FrameworkElement 69 { 70 if (depObj == null) 71 { 72 return null; 73 } 74 75 for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++) 76 { 77 var child = VisualTreeHelper.GetChild(depObj, i); 78 79 var result = (child as T) ?? GetChildOfType<T>(child, tag); 80 if (result != null && (string)result.Tag == tag) 81 { 82 return result; 83 } 84 } 85 86 return null; 87 } 88 89 private int GetDeviceIndex(Border b) 90 { 91 return b.DataContext.As<IndexedItem<DeviceViewModel>>().Index; 92 } 93 94 private void Device_DragStarting(UIElement sender, DragStartingEventArgs args) 95 { 96 args.Data.RequestedOperation = DataPackageOperation.Move; 97 args.Data.Properties.Add("check-usage", MouseWithoutBordersDragDropCheckString); 98 args.Data.Properties.Add("index", GetDeviceIndex((Border)sender)); 99 } 100 101 private void Device_Drop(object sender, DragEventArgs e) 102 { 103 if (e.DataView.Properties.TryGetValue("check-usage", out object checkUsage)) 104 { 105 // Guard against values dragged from somewhere else 106 if (!((string)checkUsage).Equals(MouseWithoutBordersDragDropCheckString, StringComparison.Ordinal)) 107 { 108 return; 109 } 110 } 111 else 112 { 113 return; 114 } 115 116 if (!e.DataView.Properties.TryGetValue("index", out object boxIndex)) 117 { 118 return; 119 } 120 121 var draggedDeviceIndex = (int)boxIndex; 122 123 if (draggedDeviceIndex < 0 || draggedDeviceIndex >= ViewModel.MachineMatrixString.Count) 124 { 125 return; 126 } 127 128 var targetDeviceIndex = GetDeviceIndex((Border)e.OriginalSource); 129 130 ViewModel.MachineMatrixString.Swap(draggedDeviceIndex, targetDeviceIndex); 131 var itemsControl = (ItemsControl)FindName("DevicesItemsControl"); 132 var binding = itemsControl.GetBindingExpression(ItemsControl.ItemsSourceProperty); 133 binding.UpdateSource(); 134 } 135 136 private void Device_DragOver(object sender, DragEventArgs e) 137 { 138 e.AcceptedOperation = DataPackageOperation.Move; 139 } 140 141 public ICommand ShowConnectFieldsCommand => new RelayCommand(ShowConnectFields); 142 143 public ICommand ConnectCommand => new AsyncCommand(Connect); 144 145 public ICommand GenerateNewKeyCommand => new AsyncCommand(ViewModel.SubmitNewKeyRequestAsync); 146 147 public ICommand CopyPCNameCommand => new RelayCommand(ViewModel.CopyMachineNameToClipboard); 148 149 public ICommand ReconnectCommand => new AsyncCommand(ViewModel.SubmitReconnectRequestAsync); 150 151 private void ShowConnectFields() 152 { 153 ViewModel.ConnectFieldsVisible = true; 154 } 155 156 private async Task Connect() 157 { 158 if (ConnectPCNameTextBox.Text.Length != 0 && ConnectSecurityKeyTextBox.Text.Length != 0) 159 { 160 string pcName = ConnectPCNameTextBox.Text; 161 string securityKey = ConnectSecurityKeyTextBox.Text.Trim(); 162 163 await ViewModel.SubmitConnectionRequestAsync(pcName, securityKey); 164 165 ConnectPCNameTextBox.Text = string.Empty; 166 ConnectSecurityKeyTextBox.Text = string.Empty; 167 } 168 } 169 170 public void RefreshEnabledState() 171 { 172 ViewModel.RefreshEnabledState(); 173 } 174 } 175 }