1
0
Fork 0
mirror of https://github.com/hawkeye-stan/msfs-popout-panel-manager.git synced 2024-11-22 05:40:11 +00:00

Clean up and reformat code

This commit is contained in:
Stanley 2022-06-30 19:53:08 -04:00
parent 4bd472f1d9
commit 93442a0150
52 changed files with 469 additions and 462 deletions

View file

@ -1,5 +1,4 @@
 namespace MSFSPopoutPanelManager.FsConnector
namespace MSFSPopoutPanelManager.FsConnector
{ {
public enum SimConnectDefinition public enum SimConnectDefinition
{ {
@ -8,7 +7,7 @@ namespace MSFSPopoutPanelManager.FsConnector
public enum NotificationGroup public enum NotificationGroup
{ {
GROUP0, GROUP0
} }
public enum DataRequest public enum DataRequest
@ -23,7 +22,7 @@ namespace MSFSPopoutPanelManager.FsConnector
SIMSTOP, SIMSTOP,
FLIGHTLOADED, FLIGHTLOADED,
VIEW, VIEW,
PAUSED, PAUSED,
NONE NONE
}; };
} }

View file

@ -11,7 +11,7 @@
<Copyright>Stanley Kwok 2021</Copyright> <Copyright>Stanley Kwok 2021</Copyright>
<PackageProjectUrl>https://github.com/hawkeye-stan/msfs-popout-panel-manager</PackageProjectUrl> <PackageProjectUrl>https://github.com/hawkeye-stan/msfs-popout-panel-manager</PackageProjectUrl>
<RootNamespace>MSFSPopoutPanelManager.FsConnector</RootNamespace> <RootNamespace>MSFSPopoutPanelManager.FsConnector</RootNamespace>
<Platforms>x64;AnyCPU</Platforms> <Platforms>x64</Platforms>
<AssemblyVersion>3.3.4.0</AssemblyVersion> <AssemblyVersion>3.3.4.0</AssemblyVersion>
<FileVersion>3.3.4.0</FileVersion> <FileVersion>3.3.4.0</FileVersion>
</PropertyGroup> </PropertyGroup>

View file

@ -1,5 +1,4 @@
 using System.Runtime.InteropServices;
using System.Runtime.InteropServices;
namespace MSFSPopoutPanelManager.FsConnector namespace MSFSPopoutPanelManager.FsConnector
{ {

View file

@ -6,7 +6,6 @@ using System.Diagnostics;
using System.Dynamic; using System.Dynamic;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
namespace MSFSPopoutPanelManager.FsConnector namespace MSFSPopoutPanelManager.FsConnector
{ {
public class SimConnector public class SimConnector
@ -34,7 +33,7 @@ namespace MSFSPopoutPanelManager.FsConnector
{ {
if (_simConnect == null) if (_simConnect == null)
{ {
_simConnect = new SimConnect("MSFS Pop Out Panel Manager", Process.GetCurrentProcess().MainWindowHandle, WM_USER_SIMCONNECT, null, 0); _simConnect = new SimConnect("MSFS Pop Out Panel Manager", Process.GetCurrentProcess().MainWindowHandle, WM_USER_SIMCONNECT, null, 0);
_simConnect.OnRecvQuit += HandleOnRecvQuit; _simConnect.OnRecvQuit += HandleOnRecvQuit;
_simConnect.OnRecvException += HandleOnRecvException; _simConnect.OnRecvException += HandleOnRecvException;
@ -162,7 +161,7 @@ namespace MSFSPopoutPanelManager.FsConnector
{ {
var exception = (SIMCONNECT_EXCEPTION)data.dwException; var exception = (SIMCONNECT_EXCEPTION)data.dwException;
switch(exception) switch (exception)
{ {
case SIMCONNECT_EXCEPTION.DATA_ERROR: case SIMCONNECT_EXCEPTION.DATA_ERROR:
case SIMCONNECT_EXCEPTION.NAME_UNRECOGNIZED: case SIMCONNECT_EXCEPTION.NAME_UNRECOGNIZED:

View file

@ -23,23 +23,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
VERSION.md = VERSION.md VERSION.md = VERSION.md
EndProjectSection EndProjectSection
EndProject EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "images", "images", "{D8938324-934B-4602-B30E-66B60365B426}"
ProjectSection(SolutionItems) = preProject
images\logo.png = images\logo.png
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "doc", "doc", "{E2AF3E4D-F5B6-44C0-8E15-528206E9F3C7}"
ProjectSection(SolutionItems) = preProject
images\doc\frameworkdownload.png = images\doc\frameworkdownload.png
images\doc\screenshot_1.png = images\doc\screenshot_1.png
images\doc\screenshot_2.png = images\doc\screenshot_2.png
images\doc\screenshot_3.png = images\doc\screenshot_3.png
images\doc\screenshot_4.png = images\doc\screenshot_4.png
images\doc\screenshot_5.png = images\doc\screenshot_5.png
images\doc\screenshot_6.png = images\doc\screenshot_6.png
images\doc\screenshot_7.png = images\doc\screenshot_7.png
EndProjectSection
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64 Debug|x64 = Debug|x64

View file

@ -25,7 +25,7 @@ namespace MSFSPopoutPanelManager.Model
} }
SimBaseDocument data; SimBaseDocument data;
using (Stream stream = new FileStream(filePath, FileMode.Open)) using (Stream stream = new FileStream(filePath, FileMode.Open))
{ {
data = (SimBaseDocument)serializer.Deserialize(stream); data = (SimBaseDocument)serializer.Deserialize(stream);

View file

@ -1,20 +1,16 @@
using MSFSPopoutPanelManager.Shared; using CommunityToolkit.Mvvm.ComponentModel;
using MSFSPopoutPanelManager.Shared;
using Newtonsoft.Json; using Newtonsoft.Json;
using System; using System;
using System.ComponentModel;
using System.IO; using System.IO;
namespace MSFSPopoutPanelManager.Model namespace MSFSPopoutPanelManager.Model
{ {
public class AppSetting : INotifyPropertyChanged public class AppSetting : ObservableObject
{ {
private const string APP_SETTING_DATA_FILENAME = "appsettingdata.json"; private const string APP_SETTING_DATA_FILENAME = "appsettingdata.json";
private bool _saveEnabled; private bool _saveEnabled;
// Using PropertyChanged.Fody
public event PropertyChangedEventHandler PropertyChanged;
public event EventHandler<EventArgs<bool>> AlwaysOnTopChanged; public event EventHandler<EventArgs<bool>> AlwaysOnTopChanged;
public event EventHandler<EventArgs<bool>> AutoPopOutPanelsChanged; public event EventHandler<EventArgs<bool>> AutoPopOutPanelsChanged;
@ -100,7 +96,7 @@ namespace MSFSPopoutPanelManager.Model
{ {
return AppAutoStart.CheckIsAutoStart(); return AppAutoStart.CheckIsAutoStart();
} }
set set
{ {
if (value) if (value)
AppAutoStart.Activate(); AppAutoStart.Activate();
@ -148,12 +144,9 @@ namespace MSFSPopoutPanelManager.Model
} }
} }
public class AutoPopOutPanelsWaitDelay : INotifyPropertyChanged public class AutoPopOutPanelsWaitDelay : ObservableObject
{ {
// Using PropertyChanged.Fody public event EventHandler<EventArgs<string>> DataChanged;
public event PropertyChangedEventHandler PropertyChanged;
public event EventHandler DataChanged;
public AutoPopOutPanelsWaitDelay() public AutoPopOutPanelsWaitDelay()
{ {
@ -170,7 +163,7 @@ namespace MSFSPopoutPanelManager.Model
public void OnPropertyChanged(string propertyName, object before, object after) public void OnPropertyChanged(string propertyName, object before, object after)
{ {
DataChanged?.Invoke(this, null); DataChanged?.Invoke(this, new EventArgs<string>(propertyName));
} }
} }
} }

View file

@ -11,18 +11,15 @@
<Copyright>Stanley Kwok 2021</Copyright> <Copyright>Stanley Kwok 2021</Copyright>
<Product>MSFS 2020 Popout Panel Manager Model</Product> <Product>MSFS 2020 Popout Panel Manager Model</Product>
<PackageProjectUrl>https://github.com/hawkeye-stan/msfs-popout-panel-manager</PackageProjectUrl> <PackageProjectUrl>https://github.com/hawkeye-stan/msfs-popout-panel-manager</PackageProjectUrl>
<Platforms>x64;AnyCPU</Platforms> <Platforms>x64</Platforms>
<AssemblyVersion>3.3.4.0</AssemblyVersion> <AssemblyVersion>3.3.4.0</AssemblyVersion>
<FileVersion>3.3.4.0</FileVersion> <FileVersion>3.3.4.0</FileVersion>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Fody" Version="6.6.0"> <PackageReference Include="CommunityToolkit.Mvvm" Version="7.1.2" />
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" /> <PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="PropertyChanged.Fody" Version="3.4.0" /> <PackageReference Include="PropertyChanged.Fody" Version="3.4.1" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View file

@ -1,13 +1,11 @@
using Newtonsoft.Json; using CommunityToolkit.Mvvm.ComponentModel;
using Newtonsoft.Json;
using System; using System;
using System.ComponentModel;
namespace MSFSPopoutPanelManager.Model namespace MSFSPopoutPanelManager.Model
{ {
public class PanelConfig : INotifyPropertyChanged public class PanelConfig : ObservableObject
{ {
public event PropertyChangedEventHandler PropertyChanged;
public int PanelIndex { get; set; } public int PanelIndex { get; set; }
public string PanelName { get; set; } public string PanelName { get; set; }

View file

@ -1,6 +1,4 @@
using System; namespace MSFSPopoutPanelManager.Model
namespace MSFSPopoutPanelManager.Model
{ {
public enum PanelConfigPropertyName public enum PanelConfigPropertyName
{ {

View file

@ -1,13 +1,11 @@
using Newtonsoft.Json; using CommunityToolkit.Mvvm.ComponentModel;
using Newtonsoft.Json;
using System; using System;
using System.ComponentModel;
namespace MSFSPopoutPanelManager.Model namespace MSFSPopoutPanelManager.Model
{ {
public class PanelSourceCoordinate : INotifyPropertyChanged public class PanelSourceCoordinate : ObservableObject
{ {
public event PropertyChangedEventHandler PropertyChanged;
public int PanelIndex { get; set; } public int PanelIndex { get; set; }
public int X { get; set; } public int X { get; set; }

View file

@ -5,6 +5,7 @@
FlightSimMainWindow, FlightSimMainWindow,
BuiltInPopout, BuiltInPopout,
CustomPopout, CustomPopout,
MSFSTouchPanel MSFSTouchPanel,
WPFWindow
} }
} }

View file

@ -1,14 +1,12 @@
using Newtonsoft.Json; using CommunityToolkit.Mvvm.ComponentModel;
using Newtonsoft.Json;
using System; using System;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.ComponentModel;
namespace MSFSPopoutPanelManager.Model namespace MSFSPopoutPanelManager.Model
{ {
public class UserProfile : INotifyPropertyChanged public class UserProfile : ObservableObject
{ {
public event PropertyChangedEventHandler PropertyChanged;
public UserProfile() public UserProfile()
{ {
PanelSourceCoordinates = new ObservableCollection<PanelSourceCoordinate>(); PanelSourceCoordinates = new ObservableCollection<PanelSourceCoordinate>();
@ -71,16 +69,16 @@ namespace MSFSPopoutPanelManager.Model
{ {
object val = new object(); object val = new object();
if(reader.TokenType == JsonToken.String) if (reader.TokenType == JsonToken.String)
{ {
var instance = (string)serializer.Deserialize(reader, typeof(string)); var instance = (string)serializer.Deserialize(reader, typeof(string));
val = new ObservableCollection<string>() { instance }; val = new ObservableCollection<string>() { instance };
} }
else if(reader.TokenType == JsonToken.StartArray) else if (reader.TokenType == JsonToken.StartArray)
{ {
val = serializer.Deserialize(reader, objectType); val = serializer.Deserialize(reader, objectType);
} }
else if(reader.TokenType == JsonToken.Null) else if (reader.TokenType == JsonToken.Null)
{ {
val = new ObservableCollection<string>(); val = new ObservableCollection<string>();
} }

View file

@ -26,7 +26,7 @@ namespace MSFSPopoutPanelManager.Provider
// Take a screen shot by removing the titlebar of the window // Take a screen shot by removing the titlebar of the window
var left = rectangle.Left; var left = rectangle.Left;
var top = rectangle.Top + (rectangle.Height - clientRectangle.Height) - 8; // 8 pixels adjustments var top = rectangle.Top + (rectangle.Height - clientRectangle.Height) - 8; // 8 pixels adjustments
var bmp = new Bitmap(clientRectangle.Width, clientRectangle.Height, PixelFormat.Format24bppRgb); var bmp = new Bitmap(clientRectangle.Width, clientRectangle.Height, PixelFormat.Format24bppRgb);
using (Graphics g = Graphics.FromImage(bmp)) using (Graphics g = Graphics.FromImage(bmp))
@ -37,10 +37,12 @@ namespace MSFSPopoutPanelManager.Provider
// Place the above image in the same canvas size as before // Place the above image in the same canvas size as before
Bitmap backingImage = new Bitmap(rectangle.Width, rectangle.Height); Bitmap backingImage = new Bitmap(rectangle.Width, rectangle.Height);
using (Graphics gfx = Graphics.FromImage(backingImage)) using (Graphics gfx = Graphics.FromImage(backingImage))
using (SolidBrush brush = new SolidBrush(Color.FromArgb(255, 0, 0)))
{ {
gfx.FillRectangle(brush, 0, 0, rectangle.Width, rectangle.Height); using (SolidBrush brush = new SolidBrush(Color.FromArgb(255, 0, 0)))
gfx.DrawImage(bmp, new Point(0, top)); {
gfx.FillRectangle(brush, 0, 0, rectangle.Width, rectangle.Height);
gfx.DrawImage(bmp, new Point(0, top));
}
} }
return backingImage; return backingImage;

View file

@ -58,7 +58,7 @@ namespace MSFSPopoutPanelManager.Provider
Rectangle clientRectangle; Rectangle clientRectangle;
PInvoke.GetClientRect(hwnd, out clientRectangle); PInvoke.GetClientRect(hwnd, out clientRectangle);
var x = Convert.ToInt32(rectangle.X + (clientRectangle.Width) * 0.5); var x = Convert.ToInt32(rectangle.X + (clientRectangle.Width) * 0.5);
var y = Convert.ToInt32(rectangle.Y + (clientRectangle.Height) * 0.5); var y = Convert.ToInt32(rectangle.Y + (clientRectangle.Height) * 0.5);
PInvoke.SetForegroundWindow(hwnd); PInvoke.SetForegroundWindow(hwnd);
@ -75,7 +75,7 @@ namespace MSFSPopoutPanelManager.Provider
public static void SaveCustomView(IntPtr hwnd, string keybinding) public static void SaveCustomView(IntPtr hwnd, string keybinding)
{ {
uint customViewKey = (uint) (Convert.ToInt32(keybinding) + KEY_0); uint customViewKey = (uint)(Convert.ToInt32(keybinding) + KEY_0);
PInvoke.SetForegroundWindow(hwnd); PInvoke.SetForegroundWindow(hwnd);
Thread.Sleep(500); Thread.Sleep(500);
@ -117,7 +117,6 @@ namespace MSFSPopoutPanelManager.Provider
Thread.Sleep(200); Thread.Sleep(200);
PInvoke.keybd_event(Convert.ToByte(customViewKey), 0, KEYEVENTF_KEYUP, 0); PInvoke.keybd_event(Convert.ToByte(customViewKey), 0, KEYEVENTF_KEYUP, 0);
PInvoke.keybd_event(Convert.ToByte(VK_LMENU), 0, KEYEVENTF_KEYUP, 0); PInvoke.keybd_event(Convert.ToByte(VK_LMENU), 0, KEYEVENTF_KEYUP, 0);
} }
public static void ToggleFullScreenPanel(IntPtr hwnd) public static void ToggleFullScreenPanel(IntPtr hwnd)
@ -157,11 +156,11 @@ namespace MSFSPopoutPanelManager.Provider
// set focus to game app // set focus to game app
var x = Convert.ToInt32(rectangle.X + (clientRectangle.Width) * 0.947); var x = Convert.ToInt32(rectangle.X + (clientRectangle.Width) * 0.947);
var y = Convert.ToInt32(rectangle.Y + (clientRectangle.Height) * 0.9); var y = Convert.ToInt32(rectangle.Y + (clientRectangle.Height) * 0.9);
LeftClick(x, y); LeftClick(x, y);
Thread.Sleep(250); Thread.Sleep(250);
LeftClick(x, y); LeftClick(x, y);
Thread.Sleep(250); Thread.Sleep(250);
for (var top = y; top < y + 100; top = top + 20) for (var top = y; top < y + 100; top = top + 20)
{ {
LeftClick(x, Convert.ToInt32(top)); LeftClick(x, Convert.ToInt32(top));

View file

@ -38,6 +38,8 @@ namespace MSFSPopoutPanelManager.Provider
public const uint WS_POPUP = 0x80000000; public const uint WS_POPUP = 0x80000000;
public const uint WS_EX_DLGMODALFRAME = 0x00000001; public const uint WS_EX_DLGMODALFRAME = 0x00000001;
public const uint WS_THICKFRAME = 0x00040000; public const uint WS_THICKFRAME = 0x00040000;
public const uint WS_MAXIMIZEBOX = 0x10000;
public const uint WS_MINIMIZEBOX = 0x20000;
public const int HWND_TOPMOST = -1; public const int HWND_TOPMOST = -1;
public const int HWND_NOTOPMOST = -2; public const int HWND_NOTOPMOST = -2;
@ -57,6 +59,8 @@ namespace MSFSPopoutPanelManager.Provider
[DllImport("user32.dll", SetLastError = true)] [DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName); public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll", EntryPoint = "FindWindow", SetLastError = true)]
public static extern IntPtr FindWindowByCaption(IntPtr ZeroOnly, string lpWindowName);
[DllImport("user32.dll", CharSet = CharSet.Auto)] [DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern int GetClassName(IntPtr hWnd, StringBuilder strPtrClassName, Int32 nMaxCount); private static extern int GetClassName(IntPtr hWnd, StringBuilder strPtrClassName, Int32 nMaxCount);

View file

@ -1,6 +1,5 @@
using MSFSPopoutPanelManager.Model; using MSFSPopoutPanelManager.Model;
using System; using System;
using System.Diagnostics;
using System.Drawing; using System.Drawing;
using System.Linq; using System.Linq;
using System.Threading; using System.Threading;
@ -30,7 +29,7 @@ namespace MSFSPopoutPanelManager.Provider
public void HookWinEvent() public void HookWinEvent()
{ {
// Setup panel config event hooks // Setup panel config event hooks
_winEventHook = PInvoke.SetWinEventHook(PInvokeConstant.EVENT_SYSTEM_CAPTURESTART, PInvokeConstant.EVENT_OBJECT_LOCATIONCHANGE, DiagnosticManager.GetApplicationProcess().Handle, _winEvent, 0, 0, PInvokeConstant.WINEVENT_OUTOFCONTEXT); _winEventHook = PInvoke.SetWinEventHook(PInvokeConstant.EVENT_SYSTEM_CAPTURESTART, PInvokeConstant.EVENT_OBJECT_LOCATIONCHANGE, DiagnosticManager.GetApplicationProcess().Handle, _winEvent, 0, 0, PInvokeConstant.WINEVENT_OUTOFCONTEXT);
} }
@ -68,29 +67,27 @@ namespace MSFSPopoutPanelManager.Provider
name = name + " (Custom)"; name = name + " (Custom)";
PInvoke.SetWindowText(panelConfig.PanelHandle, name); PInvoke.SetWindowText(panelConfig.PanelHandle, name);
} }
else if(!panelConfig.FullScreen) else if (!panelConfig.FullScreen)
{ {
switch (panelConfigItem.PanelConfigProperty) switch (panelConfigItem.PanelConfigProperty)
{ {
case PanelConfigPropertyName.Left: case PanelConfigPropertyName.Left:
case PanelConfigPropertyName.Top: case PanelConfigPropertyName.Top:
PInvoke.MoveWindow(panelConfig.PanelHandle, panelConfig.Left, panelConfig.Top, panelConfig.Width, panelConfig.Height, true); WindowManager.MoveWindow(panelConfig.PanelHandle, panelConfig.PanelType, panelConfig.Left, panelConfig.Top, panelConfig.Width, panelConfig.Height);
break; break;
case PanelConfigPropertyName.Width: case PanelConfigPropertyName.Width:
case PanelConfigPropertyName.Height: case PanelConfigPropertyName.Height:
if (panelConfig.HideTitlebar) if (panelConfig.HideTitlebar)
WindowManager.ApplyHidePanelTitleBar(panelConfig.PanelHandle, false); WindowManager.ApplyHidePanelTitleBar(panelConfig.PanelHandle, false);
int orignalLeft = panelConfig.Left; WindowManager.MoveWindowWithMsfsBugOverrirde(panelConfig.PanelHandle, panelConfig.PanelType, panelConfig.Left, panelConfig.Top, panelConfig.Width, panelConfig.Height);
PInvoke.MoveWindow(panelConfig.PanelHandle, panelConfig.Left, panelConfig.Top, panelConfig.Width, panelConfig.Height, true);
MSFSBugPanelShiftWorkaround(panelConfig.PanelHandle, orignalLeft, panelConfig.Top, panelConfig.Width, panelConfig.Height);
if (panelConfig.HideTitlebar) if (panelConfig.HideTitlebar)
WindowManager.ApplyHidePanelTitleBar(panelConfig.PanelHandle, true); WindowManager.ApplyHidePanelTitleBar(panelConfig.PanelHandle, true);
break; break;
case PanelConfigPropertyName.AlwaysOnTop: case PanelConfigPropertyName.AlwaysOnTop:
WindowManager.ApplyAlwaysOnTop(panelConfig.PanelHandle, panelConfig.AlwaysOnTop, new Rectangle(panelConfig.Left, panelConfig.Top, panelConfig.Width, panelConfig.Height)); WindowManager.ApplyAlwaysOnTop(panelConfig.PanelHandle, panelConfig.PanelType, panelConfig.AlwaysOnTop, new Rectangle(panelConfig.Left, panelConfig.Top, panelConfig.Width, panelConfig.Height));
break; break;
case PanelConfigPropertyName.HideTitlebar: case PanelConfigPropertyName.HideTitlebar:
WindowManager.ApplyHidePanelTitleBar(panelConfig.PanelHandle, panelConfig.HideTitlebar); WindowManager.ApplyHidePanelTitleBar(panelConfig.PanelHandle, panelConfig.HideTitlebar);
@ -123,11 +120,11 @@ namespace MSFSPopoutPanelManager.Provider
{ {
case PanelConfigPropertyName.Left: case PanelConfigPropertyName.Left:
panelConfig.Left += changeAmount; panelConfig.Left += changeAmount;
PInvoke.MoveWindow(panelConfig.PanelHandle, panelConfig.Left, panelConfig.Top, panelConfig.Width, panelConfig.Height, false); WindowManager.MoveWindow(panelConfig.PanelHandle, panelConfig.PanelType, panelConfig.Left, panelConfig.Top, panelConfig.Width, panelConfig.Height);
break; break;
case PanelConfigPropertyName.Top: case PanelConfigPropertyName.Top:
panelConfig.Top += changeAmount; panelConfig.Top += changeAmount;
PInvoke.MoveWindow(panelConfig.PanelHandle, panelConfig.Left, panelConfig.Top, panelConfig.Width, panelConfig.Height, false); WindowManager.MoveWindow(panelConfig.PanelHandle, panelConfig.PanelType, panelConfig.Left, panelConfig.Top, panelConfig.Width, panelConfig.Height);
break; break;
case PanelConfigPropertyName.Width: case PanelConfigPropertyName.Width:
panelConfig.Width += changeAmount; panelConfig.Width += changeAmount;
@ -135,8 +132,7 @@ namespace MSFSPopoutPanelManager.Provider
if (panelConfig.HideTitlebar) if (panelConfig.HideTitlebar)
WindowManager.ApplyHidePanelTitleBar(panelConfig.PanelHandle, false); WindowManager.ApplyHidePanelTitleBar(panelConfig.PanelHandle, false);
PInvoke.MoveWindow(panelConfig.PanelHandle, panelConfig.Left, panelConfig.Top, panelConfig.Width, panelConfig.Height, false); WindowManager.MoveWindowWithMsfsBugOverrirde(panelConfig.PanelHandle, panelConfig.PanelType, panelConfig.Left, panelConfig.Top, panelConfig.Width, panelConfig.Height);
MSFSBugPanelShiftWorkaround(panelConfig.PanelHandle, orignalLeft, panelConfig.Top, panelConfig.Width, panelConfig.Height);
if (panelConfig.HideTitlebar) if (panelConfig.HideTitlebar)
WindowManager.ApplyHidePanelTitleBar(panelConfig.PanelHandle, true); WindowManager.ApplyHidePanelTitleBar(panelConfig.PanelHandle, true);
@ -148,8 +144,7 @@ namespace MSFSPopoutPanelManager.Provider
if (panelConfig.HideTitlebar) if (panelConfig.HideTitlebar)
WindowManager.ApplyHidePanelTitleBar(panelConfig.PanelHandle, false); WindowManager.ApplyHidePanelTitleBar(panelConfig.PanelHandle, false);
PInvoke.MoveWindow(panelConfig.PanelHandle, panelConfig.Left, panelConfig.Top, panelConfig.Width, panelConfig.Height, false); WindowManager.MoveWindowWithMsfsBugOverrirde(panelConfig.PanelHandle, panelConfig.PanelType, panelConfig.Left, panelConfig.Top, panelConfig.Width, panelConfig.Height);
MSFSBugPanelShiftWorkaround(panelConfig.PanelHandle, orignalLeft, panelConfig.Top, panelConfig.Width, panelConfig.Height);
if (panelConfig.HideTitlebar) if (panelConfig.HideTitlebar)
WindowManager.ApplyHidePanelTitleBar(panelConfig.PanelHandle, true); WindowManager.ApplyHidePanelTitleBar(panelConfig.PanelHandle, true);
@ -163,22 +158,9 @@ namespace MSFSPopoutPanelManager.Provider
} }
} }
private void MSFSBugPanelShiftWorkaround(IntPtr handle, int originalLeft, int top, int width, int height)
{
// Fixed MSFS bug, create workaround where on 2nd or later instance of width adjustment, the panel shift to the left by itself
// Wait for system to catch up on panel coordinate that were just applied
System.Threading.Thread.Sleep(200);
Rectangle rectangle;
PInvoke.GetWindowRect(handle, out rectangle);
if (rectangle.Left != originalLeft)
PInvoke.MoveWindow(handle, originalLeft, top, width, height, false);
}
private void EventCallback(IntPtr hWinEventHook, uint iEvent, IntPtr hWnd, int idObject, int idChild, int dwEventThread, int dwmsEventTime) private void EventCallback(IntPtr hWinEventHook, uint iEvent, IntPtr hWnd, int idObject, int idChild, int dwEventThread, int dwmsEventTime)
{ {
switch(iEvent) switch (iEvent)
{ {
case PInvokeConstant.EVENT_OBJECT_LOCATIONCHANGE: case PInvokeConstant.EVENT_OBJECT_LOCATIONCHANGE:
case PInvokeConstant.EVENT_SYSTEM_MOVESIZEEND: case PInvokeConstant.EVENT_SYSTEM_MOVESIZEEND:
@ -316,7 +298,7 @@ namespace MSFSPopoutPanelManager.Provider
} }
} }
private async Task RefocusMsfs(int prevWinEventClickLock) private void RefocusMsfs(int prevWinEventClickLock)
{ {
Thread.Sleep(1000); Thread.Sleep(1000);

View file

@ -38,13 +38,13 @@ namespace MSFSPopoutPanelManager.Provider
{ {
var simulatorProcess = DiagnosticManager.GetSimulatorProcess(); var simulatorProcess = DiagnosticManager.GetSimulatorProcess();
if(simulatorProcess != null) if (simulatorProcess != null)
_simulatorHandle = simulatorProcess.Handle; _simulatorHandle = simulatorProcess.Handle;
_panels = new List<PanelConfig>(); _panels = new List<PanelConfig>();
OnPopOutStarted?.Invoke(this, null); OnPopOutStarted?.Invoke(this, null);
// If enable, load the current viewport into custom view by Ctrl-Alt-0 // If enable, load the current viewport into custom view by Ctrl-Alt-0
if (AppSetting.UseAutoPanning) if (AppSetting.UseAutoPanning)
{ {
@ -82,7 +82,7 @@ namespace MSFSPopoutPanelManager.Provider
// Recenter the view port by Ctrl-Space, needs to click on game window // Recenter the view port by Ctrl-Space, needs to click on game window
var simualatorProcess = DiagnosticManager.GetSimulatorProcess(); var simualatorProcess = DiagnosticManager.GetSimulatorProcess();
if (simualatorProcess != null && UserProfile.PanelSourceCoordinates.Count > 0) if (simualatorProcess != null)
{ {
InputEmulationManager.CenterView(simualatorProcess.Handle); InputEmulationManager.CenterView(simualatorProcess.Handle);
} }
@ -91,7 +91,7 @@ namespace MSFSPopoutPanelManager.Provider
OnPopOutCompleted?.Invoke(this, new EventArgs<bool>(true)); OnPopOutCompleted?.Invoke(this, new EventArgs<bool>(true));
} }
else else
{ {
OnPopOutCompleted?.Invoke(this, new EventArgs<bool>(false)); OnPopOutCompleted?.Invoke(this, new EventArgs<bool>(false));
} }
@ -143,7 +143,7 @@ namespace MSFSPopoutPanelManager.Provider
PInvoke.SetWindowText(panelInfo.PanelHandle, panelInfo.PanelName + " (Custom)"); PInvoke.SetWindowText(panelInfo.PanelHandle, panelInfo.PanelName + " (Custom)");
if (i > 1) if (i > 1)
PInvoke.MoveWindow(panelInfo.PanelHandle, 0, 0, 800, 600, true); WindowManager.MoveWindow(panelInfo.PanelHandle, panelInfo.PanelType, 0, 0, 800, 600);
} }
_currentPanelIndex = _panels.Count; _currentPanelIndex = _panels.Count;
@ -173,7 +173,7 @@ namespace MSFSPopoutPanelManager.Provider
_panels[i].Width = 800; _panels[i].Width = 800;
_panels[i].Height = 600; _panels[i].Height = 600;
PInvoke.MoveWindow(_panels[i].PanelHandle, _panels[i].Top, _panels[i].Left, _panels[i].Width, _panels[i].Height, true); WindowManager.MoveWindow(_panels[i].PanelHandle, _panels[i].PanelType, _panels[i].Top, _panels[i].Left, _panels[i].Width, _panels[i].Height);
PInvoke.SetForegroundWindow(_panels[i].PanelHandle); PInvoke.SetForegroundWindow(_panels[i].PanelHandle);
Thread.Sleep(200); Thread.Sleep(200);
} }
@ -238,7 +238,7 @@ namespace MSFSPopoutPanelManager.Provider
Thread.Sleep(500); Thread.Sleep(500);
} }
// Apply full screen (cannot combine with always on top or hide title bar // Apply full screen (cannot combine with always on top or hide title bar)
if (panel.FullScreen) if (panel.FullScreen)
{ {
WindowManager.MoveWindow(panel.PanelHandle, panel.Left, panel.Top); WindowManager.MoveWindow(panel.PanelHandle, panel.Left, panel.Top);
@ -246,17 +246,17 @@ namespace MSFSPopoutPanelManager.Provider
InputEmulationManager.ToggleFullScreenPanel(panel.PanelHandle); InputEmulationManager.ToggleFullScreenPanel(panel.PanelHandle);
Thread.Sleep(1000); Thread.Sleep(1000);
} }
else else
{ {
// Apply locations // Apply locations
PInvoke.ShowWindow(panel.PanelHandle, PInvokeConstant.SW_RESTORE); PInvoke.ShowWindow(panel.PanelHandle, PInvokeConstant.SW_RESTORE);
Thread.Sleep(250); Thread.Sleep(250);
PInvoke.MoveWindow(panel.PanelHandle, panel.Left, panel.Top, panel.Width, panel.Height, false); WindowManager.MoveWindow(panel.PanelHandle, panel.PanelType, panel.Left, panel.Top, panel.Width, panel.Height);
Thread.Sleep(1000); Thread.Sleep(1000);
// Built-in panels (ie. Checklist, ATC) needs another window resize since there is a bug where when move between // Built-in panels (ie. Checklist, ATC) needs another window resize since there is a bug where when move between
// monitors, it changes its size // monitors, it changes its size
if(panel.PanelType == PanelType.BuiltInPopout) if (panel.PanelType == PanelType.BuiltInPopout)
{ {
PInvoke.MoveWindow(panel.PanelHandle, panel.Left, panel.Top, panel.Width, panel.Height, false); PInvoke.MoveWindow(panel.PanelHandle, panel.Left, panel.Top, panel.Width, panel.Height, false);
Thread.Sleep(1000); Thread.Sleep(1000);
@ -265,7 +265,7 @@ namespace MSFSPopoutPanelManager.Provider
// Apply always on top // Apply always on top
if (panel.AlwaysOnTop) if (panel.AlwaysOnTop)
{ {
WindowManager.ApplyAlwaysOnTop(panel.PanelHandle, true, new Rectangle(panel.Left, panel.Top, panel.Width, panel.Height)); WindowManager.ApplyAlwaysOnTop(panel.PanelHandle, panel.PanelType, true, new Rectangle(panel.Left, panel.Top, panel.Width, panel.Height));
Thread.Sleep(1000); Thread.Sleep(1000);
} }
@ -300,7 +300,7 @@ namespace MSFSPopoutPanelManager.Provider
{ {
// Resize all windows to 800x600 when separating and shimmy the panel // Resize all windows to 800x600 when separating and shimmy the panel
// MSFS draws popout panel differently at different time for same panel // MSFS draws popout panel differently at different time for same panel
PInvoke.MoveWindow(hwnd, -8, 0, 800, 600, true); WindowManager.MoveWindow(hwnd, PanelType.CustomPopout, -8, 0, 800, 600);
PInvoke.SetForegroundWindow(hwnd); PInvoke.SetForegroundWindow(hwnd);
Thread.Sleep(500); Thread.Sleep(500);
@ -319,7 +319,7 @@ namespace MSFSPopoutPanelManager.Provider
if (!_panels.Exists(x => x.PanelHandle == hwnd)) if (!_panels.Exists(x => x.PanelHandle == hwnd))
{ {
Interlocked.Increment(ref _currentPanelIndex); Interlocked.Increment(ref _currentPanelIndex);
panelInfo.PanelIndex = _currentPanelIndex; panelInfo.PanelIndex = _currentPanelIndex;
_panels.Add(panelInfo); _panels.Add(panelInfo);
} }
} }
@ -357,7 +357,7 @@ namespace MSFSPopoutPanelManager.Provider
_panels.Add(panelInfo); _panels.Add(panelInfo);
// Apply always on top to these panels // Apply always on top to these panels
WindowManager.ApplyAlwaysOnTop(panelInfo.PanelHandle, true); //WindowManager.ApplyAlwaysOnTop(panelInfo.PanelHandle, true);
} }
} }
@ -400,7 +400,7 @@ namespace MSFSPopoutPanelManager.Provider
panelInfo.PanelHandle = hwnd; panelInfo.PanelHandle = hwnd;
panelInfo.PanelName = caption; panelInfo.PanelName = caption;
if (caption.IndexOf("MSFS Touch Panel |") > -1) if (caption.IndexOf("Touch Panel |") > -1)
{ {
panelInfo.PanelType = PanelType.MSFSTouchPanel; panelInfo.PanelType = PanelType.MSFSTouchPanel;
return panelInfo; return panelInfo;
@ -408,8 +408,6 @@ namespace MSFSPopoutPanelManager.Provider
else else
return null; return null;
} }
return null;
} }
private Point AnalyzeMergedWindows(IntPtr hwnd) private Point AnalyzeMergedWindows(IntPtr hwnd)
@ -432,7 +430,7 @@ namespace MSFSPopoutPanelManager.Provider
var panelsStartingLeft = GetPanelMenubarStartingLeft(sourceImage, rectangle, panelMenubarTop + 5); var panelsStartingLeft = GetPanelMenubarStartingLeft(sourceImage, rectangle, panelMenubarTop + 5);
// The center of magnifying glass icon is around (2.7 x height of menubar) to the right of the panel menubar starting left // The center of magnifying glass icon is around (3.2 x height of menubar) to the right of the panel menubar starting left
// But need to use higher number here to click the left side of magnifying glass icon because on some panel, the ratio is smaller // But need to use higher number here to click the left side of magnifying glass icon because on some panel, the ratio is smaller
var menubarHeight = panelMenubarBottom - panelMenubarTop; var menubarHeight = panelMenubarBottom - panelMenubarTop;
var magnifyingIconXCoor = panelsStartingLeft - Convert.ToInt32(menubarHeight * 3.2); // ToDo: play around with this multiplier to find the best for all resolutions var magnifyingIconXCoor = panelsStartingLeft - Convert.ToInt32(menubarHeight * 3.2); // ToDo: play around with this multiplier to find the best for all resolutions

View file

@ -69,7 +69,7 @@ namespace MSFSPopoutPanelManager.Provider
private void HandleOnPanelSelectionRemoved(object sender, EventArgs e) private void HandleOnPanelSelectionRemoved(object sender, EventArgs e)
{ {
if(_panelCoordinates.Count > 0) if (_panelCoordinates.Count > 0)
{ {
_panelCoordinates.RemoveAt(_panelCoordinates.Count - 1); _panelCoordinates.RemoveAt(_panelCoordinates.Count - 1);
_panelIndex--; _panelIndex--;

View file

@ -14,14 +14,11 @@
<UseWindowsForms>true</UseWindowsForms> <UseWindowsForms>true</UseWindowsForms>
<ApplicationIcon /> <ApplicationIcon />
<StartupObject /> <StartupObject />
<Platforms>AnyCPU;x64</Platforms> <Platforms>x64</Platforms>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup> </PropertyGroup>
@ -29,9 +26,7 @@
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="MouseKeyHook" Version="5.6.0" /> <PackageReference Include="MouseKeyHook" Version="5.6.0" />

View file

@ -9,15 +9,14 @@ using System.Timers;
namespace MSFSPopoutPanelManager.Provider namespace MSFSPopoutPanelManager.Provider
{ {
public class SimConnectManager public class SimConnectManager
{ {
private const int MSFS_DATA_REFRESH_TIMEOUT = 1000; private const int MSFS_DATA_REFRESH_TIMEOUT = 1000;
private SimConnector _simConnector; private SimConnector _simConnector;
private dynamic _simData; private dynamic _simData;
private System.Timers.Timer _requestDataTimer; private System.Timers.Timer _requestDataTimer;
private SimConnectSystemEvent _lastSystemEvent;
private bool _isPowerOnForPopOut; private bool _isPowerOnForPopOut;
private bool _isTrackIRManaged; private bool _isTrackIRManaged;
@ -75,7 +74,7 @@ namespace MSFSPopoutPanelManager.Provider
public void TurnOffpower() public void TurnOffpower()
{ {
if(_isPowerOnForPopOut) if (_isPowerOnForPopOut)
{ {
_simConnector.TransmitActionEvent(ActionEvent.KEY_AVIONICS_MASTER_2_SET, 0); _simConnector.TransmitActionEvent(ActionEvent.KEY_AVIONICS_MASTER_2_SET, 0);
Thread.Sleep(100); Thread.Sleep(100);
@ -91,7 +90,7 @@ namespace MSFSPopoutPanelManager.Provider
public void TurnOffTrackIR() public void TurnOffTrackIR()
{ {
if(_simData != null && _simData.TrackIREnable) if (_simData != null && _simData.TrackIREnable)
{ {
SetTrackIREnable(false); SetTrackIREnable(false);
_isTrackIRManaged = true; _isTrackIRManaged = true;
@ -114,10 +113,10 @@ namespace MSFSPopoutPanelManager.Provider
// It is prop3 in SimConnectStruct (by DataDefinitions.cs) // It is prop3 in SimConnectStruct (by DataDefinitions.cs)
SimConnectStruct simConnectStruct = new SimConnectStruct(); SimConnectStruct simConnectStruct = new SimConnectStruct();
simConnectStruct.Prop01 = _simData.Title; // must set "Title" for TrackIR variable to write correctly simConnectStruct.Prop01 = _simData.Title; // must set "Title" for TrackIR variable to write correctly
simConnectStruct.Prop02 = _simData.ElectricalMasterBattery ? Convert.ToDouble(1) : Convert.ToDouble(0); // must set "ElectricalMasterBattery" for TrackIR variable to write correctly simConnectStruct.Prop02 = _simData.ElectricalMasterBattery ? Convert.ToDouble(1) : Convert.ToDouble(0); // must set "ElectricalMasterBattery" for TrackIR variable to write correctly
simConnectStruct.Prop03 = enable ? Convert.ToDouble(1): Convert.ToDouble(0); // this is the TrackIR variable simConnectStruct.Prop03 = enable ? Convert.ToDouble(1) : Convert.ToDouble(0); // this is the TrackIR variable
_simConnector.SetDataObject(simConnectStruct); _simConnector.SetDataObject(simConnectStruct);
} }

View file

@ -4,7 +4,6 @@ using Newtonsoft.Json;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.Diagnostics;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
@ -90,8 +89,6 @@ namespace MSFSPopoutPanelManager.Provider
public void WriteUserProfiles() public void WriteUserProfiles()
{ {
Debug.WriteLine("saving profile....");
if (UserProfiles == null) if (UserProfiles == null)
throw new Exception("User Profiles is null."); throw new Exception("User Profiles is null.");

View file

@ -1,4 +1,5 @@
using System; using MSFSPopoutPanelManager.Model;
using System;
using System.Drawing; using System.Drawing;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
@ -16,12 +17,16 @@ namespace MSFSPopoutPanelManager.Provider
PInvoke.SetWindowLong(handle, PInvokeConstant.GWL_STYLE, (uint)(currentStyle | (PInvokeConstant.WS_CAPTION | PInvokeConstant.WS_SIZEBOX))); PInvoke.SetWindowLong(handle, PInvokeConstant.GWL_STYLE, (uint)(currentStyle | (PInvokeConstant.WS_CAPTION | PInvokeConstant.WS_SIZEBOX)));
} }
public static void ApplyAlwaysOnTop(IntPtr handle, bool alwaysOnTop, Rectangle panelRectangle) public static void ApplyAlwaysOnTop(IntPtr handle, PanelType panelType, bool alwaysOnTop, Rectangle panelRectangle)
{ {
// Override weird size adjustment for Touch Panel WPF window
int newWidth = panelType == PanelType.MSFSTouchPanel ? panelRectangle.Width - 16 : panelRectangle.Width;
int newHeight = panelType == PanelType.MSFSTouchPanel ? panelRectangle.Height - 39 : panelRectangle.Height;
if (alwaysOnTop) if (alwaysOnTop)
PInvoke.SetWindowPos(handle, new IntPtr(PInvokeConstant.HWND_TOPMOST), panelRectangle.Left, panelRectangle.Top, panelRectangle.Width, panelRectangle.Height, PInvokeConstant.SWP_ALWAYS_ON_TOP); PInvoke.SetWindowPos(handle, new IntPtr(PInvokeConstant.HWND_TOPMOST), panelRectangle.Left, panelRectangle.Top, newWidth, newHeight, PInvokeConstant.SWP_ALWAYS_ON_TOP);
else else
PInvoke.SetWindowPos(handle, new IntPtr(PInvokeConstant.HWND_NOTOPMOST), panelRectangle.Left, panelRectangle.Top, panelRectangle.Width, panelRectangle.Height, 0); PInvoke.SetWindowPos(handle, new IntPtr(PInvokeConstant.HWND_NOTOPMOST), panelRectangle.Left, panelRectangle.Top, newWidth, newHeight, 0);
} }
public static void ApplyAlwaysOnTop(IntPtr handle, bool alwaysOnTop) public static void ApplyAlwaysOnTop(IntPtr handle, bool alwaysOnTop)
@ -32,7 +37,7 @@ namespace MSFSPopoutPanelManager.Provider
Rectangle clientRectangle; Rectangle clientRectangle;
PInvoke.GetClientRect(handle, out clientRectangle); PInvoke.GetClientRect(handle, out clientRectangle);
ApplyAlwaysOnTop(handle, alwaysOnTop, new Rectangle(rect.X, rect.Y, clientRectangle.Width, clientRectangle.Height)); ApplyAlwaysOnTop(handle, PanelType.WPFWindow, alwaysOnTop, new Rectangle(rect.X, rect.Y, clientRectangle.Width, clientRectangle.Height));
} }
public static void CloseWindow(IntPtr handle) public static void CloseWindow(IntPtr handle)
@ -47,6 +52,36 @@ namespace MSFSPopoutPanelManager.Provider
PInvoke.MoveWindow(handle, x, y, rectangle.Width, rectangle.Height, true); PInvoke.MoveWindow(handle, x, y, rectangle.Width, rectangle.Height, true);
} }
public static void MoveWindow(IntPtr handle, PanelType panelType, int x, int y, int width, int height)
{
// Override weird size adjustment for Touch Panel WPF window
int newWidth = panelType == PanelType.MSFSTouchPanel ? width - 16 : width;
int newHeight = panelType == PanelType.MSFSTouchPanel ? height - 39 : height;
PInvoke.MoveWindow(handle, x, y, newWidth, newHeight, true);
}
public static void MoveWindowWithMsfsBugOverrirde(IntPtr handle, PanelType panelType, int x, int y, int width, int height)
{
int originalX = x;
// Override weird size adjustment for Touch Panel WPF window
int newWidth = panelType == PanelType.MSFSTouchPanel ? width - 16 : width;
int newHeight = panelType == PanelType.MSFSTouchPanel ? height - 39 : height;
PInvoke.MoveWindow(handle, x, y, newWidth, newHeight, true);
// Fixed MSFS bug, create workaround where on 2nd or later instance of width adjustment, the panel shift to the left by itself
// Wait for system to catch up on panel coordinate that were just applied
System.Threading.Thread.Sleep(200);
Rectangle rectangle;
PInvoke.GetWindowRect(handle, out rectangle);
if (rectangle.Left != originalX)
PInvoke.MoveWindow(handle, originalX, y, newWidth, newHeight, false);
}
public static void MinimizeWindow(IntPtr handle) public static void MinimizeWindow(IntPtr handle)
{ {
PInvoke.ShowWindow(handle, PInvokeConstant.SW_MINIMIZE); PInvoke.ShowWindow(handle, PInvokeConstant.SW_MINIMIZE);
@ -75,6 +110,11 @@ namespace MSFSPopoutPanelManager.Provider
} }
} }
public static IntPtr FindWindowByCaption(string caption)
{
return PInvoke.FindWindowByCaption(IntPtr.Zero, caption);
}
private static bool EnumToMinimizePopoutPanels(IntPtr hwnd, int index) private static bool EnumToMinimizePopoutPanels(IntPtr hwnd, int index)
{ {
var className = PInvoke.GetClassName(hwnd); var className = PInvoke.GetClassName(hwnd);

View file

@ -4,7 +4,7 @@
<img src="images/doc/panel_selection.png" width="600" hspace="10"/> <img src="images/doc/panel_selection.png" width="600" hspace="10"/>
</p> </p>
MSFS Pop Out Panel Manager is an application for MSFS 2020 which helps pop out, save and re-position pop out panels to be used by utilities such as Sim Innovations Air Manager or to place pop out panels onto your screen or another monitor at predetermined locations automatically. MSFS Pop Out Panel Manager is an application for MSFS 2020 which helps pop out, save and position pop out panels to be used by utilities such as Sim Innovations Air Manager or to place pop out panels onto your screen or another monitor at predetermined locations automatically.
Please follow [FlightSimulator.com](https://forums.flightsimulator.com/t/msfs-pop-out-panel-manager-automatically-pop-out-and-save-panel-position/460613) forum thread regarding this project Please follow [FlightSimulator.com](https://forums.flightsimulator.com/t/msfs-pop-out-panel-manager-automatically-pop-out-and-save-panel-position/460613) forum thread regarding this project
@ -15,18 +15,19 @@ Please follow [FlightSimulator.com](https://forums.flightsimulator.com/t/msfs-po
<hr> <hr>
## Application Features ## Application Features
* Display resolution independent. Supports 1080p/1440p/4k display. * Display resolution independent. Supports 1080p/1440p/4k display and ultrawide displays.
* Support multiple user defined aircraft profiles to save panel locations to be recalled later. * Support multiple user defined aircraft profiles to save panel locations to be recalled later.
* Intuitive user interface to defined location of panels to be popped out. * Intuitive user interface to defined location of panels to be popped out.
* [Auto Pop Out](#auto-pop-out-feature) feature. The application will detect active aircraft by livery and activate the corresponding profile on start of new flight session. * [Auto Pop Out](#auto-pop-out-feature) feature. The application will detect active aircraft by livery and activate the corresponding profile on start of new flight session.
* [Cold Start feature](#auto-pop-out-feature). Instrumentation panels can be popped out even when they're not powered on (for G1000 planes only). * [Cold Start feature](#auto-pop-out-feature). Instrumentation panels can be popped out even when they're not powered on (for G1000 / / G1000 NXi planes only).
* Auto Panning feature remembers the cockpit camera angle when you first define the pop out panels. You can now pan, zoom in, and zoom out to identify offscreen panels and the camera angle will be saved and reused. This feature requires the use of Ctrl-Alt-0 keyboard binding to save custom camera view per plane configuration. (Can be configured to use 0 through 9). If the keyboard binding is currently being used. The auto-panning feature will overwrite the saved camera view if enabled. * Auto Panning feature remembers the cockpit camera angle when you first define the pop out panels. You can now pan, zoom in, and zoom out to identify offscreen panels and the camera angle will be saved and reused. This feature requires the use of Ctrl-Alt-0 keyboard binding to save custom camera view per plane configuration. (Can be configured to use 0 through 9). If the keyboard binding is currently being used. The auto-panning feature will overwrite the saved camera view if enabled.
* Fine-grain control in positioning of panels down to pixel level. * Fine-grain control in positioning of panels down to pixel level.
* Panels can also be configured to be always on top, with title bar hidden, or stretch to full screen mode. * Panels can be configured to appear always on top, with title bar hidden, or stretch to full screen mode.
* Auto disable Track IR when pop out starts. * Auto disable Track IR when pop out starts.
* User-friendly features such as application always on top, auto start, minimized to tray with keyboard shortcuts. * User-friendly features such as application always on top, auto start, minimized to tray with keyboard shortcuts.
* Auto save feature. All profile and panel changes are saved automatically. * Auto save feature. All profile and panel changes are saved automatically.
* **Experimental Feature**: Enable touch support for pop outs on touch enable display. Please see [Touch Enable Pop Out Feature](#touch-enable-pop-out-feature) for more information. * Auto update feature. Application can auto-update itself when new version becomes available.
* **Experimental Feature**: Enable touch support for pop outs on touch capable display. Please see [Touch Enable Pop Out Feature](#touch-enable-pop-out-feature) for more information.
<hr> <hr>

View file

@ -19,13 +19,22 @@ namespace MSFSPopoutPanelManager.Shared
{ {
return InternalCopy(originalObject, new Dictionary<Object, Object>(new ReferenceEqualityComparer())); return InternalCopy(originalObject, new Dictionary<Object, Object>(new ReferenceEqualityComparer()));
} }
private static Object InternalCopy(Object originalObject, IDictionary<Object, Object> visited) private static Object InternalCopy(Object originalObject, IDictionary<Object, Object> visited)
{ {
if (originalObject == null) return null; if (originalObject == null)
return null;
var typeToReflect = originalObject.GetType(); var typeToReflect = originalObject.GetType();
if (IsPrimitive(typeToReflect)) return originalObject; if (IsPrimitive(typeToReflect))
if (visited.ContainsKey(originalObject)) return visited[originalObject]; return originalObject;
if (typeof(Delegate).IsAssignableFrom(typeToReflect)) return null;
if (visited.ContainsKey(originalObject))
return visited[originalObject];
if (typeof(Delegate).IsAssignableFrom(typeToReflect))
return null;
var cloneObject = CloneMethod.Invoke(originalObject, null); var cloneObject = CloneMethod.Invoke(originalObject, null);
if (typeToReflect.IsArray) if (typeToReflect.IsArray)
{ {
@ -35,7 +44,6 @@ namespace MSFSPopoutPanelManager.Shared
Array clonedArray = (Array)cloneObject; Array clonedArray = (Array)cloneObject;
clonedArray.ForEach((array, indices) => array.SetValue(InternalCopy(clonedArray.GetValue(indices), visited), indices)); clonedArray.ForEach((array, indices) => array.SetValue(InternalCopy(clonedArray.GetValue(indices), visited), indices));
} }
} }
visited.Add(originalObject, cloneObject); visited.Add(originalObject, cloneObject);
CopyFields(originalObject, visited, cloneObject, typeToReflect); CopyFields(originalObject, visited, cloneObject, typeToReflect);
@ -63,6 +71,7 @@ namespace MSFSPopoutPanelManager.Shared
fieldInfo.SetValue(cloneObject, clonedFieldValue); fieldInfo.SetValue(cloneObject, clonedFieldValue);
} }
} }
public static T Copy<T>(this T original) public static T Copy<T>(this T original)
{ {
return (T)Copy((Object)original); return (T)Copy((Object)original);
@ -75,6 +84,7 @@ namespace MSFSPopoutPanelManager.Shared
{ {
return ReferenceEquals(x, y); return ReferenceEquals(x, y);
} }
public override int GetHashCode(object obj) public override int GetHashCode(object obj)
{ {
if (obj == null) return 0; if (obj == null) return 0;

View file

@ -10,7 +10,7 @@
<Copyright>Stanley Kwok 2021</Copyright> <Copyright>Stanley Kwok 2021</Copyright>
<PackageProjectUrl>https://github.com/hawkeye-stan/msfs-popout-panel-manager</PackageProjectUrl> <PackageProjectUrl>https://github.com/hawkeye-stan/msfs-popout-panel-manager</PackageProjectUrl>
<Version>3.3.4.0</Version> <Version>3.3.4.0</Version>
<Platforms>AnyCPU;x64</Platforms> <Platforms>x64</Platforms>
<UseWPF>true</UseWPF> <UseWPF>true</UseWPF>
<AssemblyVersion>3.3.4.0</AssemblyVersion> <AssemblyVersion>3.3.4.0</AssemblyVersion>
</PropertyGroup> </PropertyGroup>

View file

@ -1,12 +1,11 @@
<mah:MetroWindow x:Class="MSFSPopoutPanelManager.WpfApp.AddProfileDialog" <mah:MetroWindow x:Class="MSFSPopoutPanelManager.WpfApp.AddProfileDialog"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 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:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:mah="clr-namespace:MahApps.Metro.Controls;assembly=MahApps.Metro" xmlns:mah="clr-namespace:MahApps.Metro.Controls;assembly=MahApps.Metro"
xmlns:scm="clr-namespace:System.ComponentModel;assembly=WindowsBase" xmlns:scm="clr-namespace:System.ComponentModel;assembly=WindowsBase"
xmlns:local="clr-namespace:MSFSPopoutPanelManager.WpfApp" mc:Ignorable="d"
mc:Ignorable="d"
Title="Add Profile" Title="Add Profile"
Height="220" Height="220"
Width="600" Width="600"

View file

@ -9,9 +9,6 @@ using System.Windows.Input;
namespace MSFSPopoutPanelManager.WpfApp namespace MSFSPopoutPanelManager.WpfApp
{ {
/// <summary>
/// Interaction logic for AddProfileDialog.xaml
/// </summary>
public partial class AddProfileDialog : MetroWindow public partial class AddProfileDialog : MetroWindow
{ {
public List<UserProfile> UserProfiles { get; set; } public List<UserProfile> UserProfiles { get; set; }
@ -66,4 +63,4 @@ namespace MSFSPopoutPanelManager.WpfApp
btnDialogOk.IsEnabled = txtProfileName.Text.Length > 0; btnDialogOk.IsEnabled = txtProfileName.Text.Length > 0;
} }
} }
} }

View file

@ -1,9 +1,7 @@
<Application x:Class="MSFSPopoutPanelManager.WpfApp.App" <Application x:Class="MSFSPopoutPanelManager.WpfApp.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="http://metro.mahapps.com/winfx/xaml/controls" xmlns:controls="http://metro.mahapps.com/winfx/xaml/controls"
xmlns:mah="clr-namespace:MahApps.Metro.Controls;assembly=MahApps.Metro" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:MSFSPopoutPanelManager.WpfApp"
StartupUri="ApplicationWindow.xaml"> StartupUri="ApplicationWindow.xaml">
<Application.Resources> <Application.Resources>
<ResourceDictionary> <ResourceDictionary>

View file

@ -11,9 +11,6 @@ using System.Windows;
namespace MSFSPopoutPanelManager.WpfApp namespace MSFSPopoutPanelManager.WpfApp
{ {
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application public partial class App : Application
{ {
private static Mutex _mutex = null; private static Mutex _mutex = null;
@ -59,8 +56,11 @@ namespace MSFSPopoutPanelManager.WpfApp
private void HandleDispatcherException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e) private void HandleDispatcherException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
{ {
e.Handled = true; e.Handled = true;
Log.Error(e.Exception.Message, e.Exception); if (e.Exception.Message != "E_INVALIDARG") // Ignore this error
ShowExceptionDialog(); {
Log.Error(e.Exception.Message, e.Exception);
ShowExceptionDialog();
}
} }
private void HandledDomainException(object sender, UnhandledExceptionEventArgs e) private void HandledDomainException(object sender, UnhandledExceptionEventArgs e)
@ -78,7 +78,11 @@ namespace MSFSPopoutPanelManager.WpfApp
if (MessageBox.Show(messageBoxMessage, messageBoxTitle, messageBoxButtons) == MessageBoxResult.OK) if (MessageBox.Show(messageBoxMessage, messageBoxTitle, messageBoxButtons) == MessageBoxResult.OK)
{ {
Application.Current.Shutdown(); try
{
Application.Current.Shutdown();
}
catch { }
} }
} }
} }
@ -138,4 +142,4 @@ namespace MSFSPopoutPanelManager.WpfApp
[DllImport("SHCore.dll", SetLastError = true)] [DllImport("SHCore.dll", SetLastError = true)]
internal static extern void GetProcessDpiAwareness(IntPtr hprocess, out PROCESS_DPI_AWARENESS awareness); internal static extern void GetProcessDpiAwareness(IntPtr hprocess, out PROCESS_DPI_AWARENESS awareness);
} }
} }

View file

@ -1,14 +1,13 @@
<mah:MetroWindow x:Class="MSFSPopoutPanelManager.WpfApp.ApplicationWindow" <mah:MetroWindow x:Class="MSFSPopoutPanelManager.WpfApp.ApplicationWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 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:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:mah="clr-namespace:MahApps.Metro.Controls;assembly=MahApps.Metro" xmlns:tb="http://www.hardcodet.net/taskbar"
xmlns:tb="http://www.hardcodet.net/taskbar" xmlns:c="clr-namespace:CalcBinding;assembly=CalcBinding"
xmlns:c="clr-namespace:CalcBinding;assembly=CalcBinding" xmlns:mah="clr-namespace:MahApps.Metro.Controls;assembly=MahApps.Metro"
xmlns:local="clr-namespace:MSFSPopoutPanelManager.WpfApp" xmlns:shared="clr-namespace:MSFSPopoutPanelManager.Shared;assembly=Shared"
xmlns:shared="clr-namespace:MSFSPopoutPanelManager.Shared;assembly=Shared" mc:Ignorable="d"
mc:Ignorable="d"
Title="MSFS Pop Out Panel Manager" Title="MSFS Pop Out Panel Manager"
Height="670" Height="670"
Width="920" Width="920"
@ -19,14 +18,14 @@
WindowState="{Binding InitialWindowState, Mode=OneWay}" WindowState="{Binding InitialWindowState, Mode=OneWay}"
Loaded="Window_Loaded" Loaded="Window_Loaded"
Closing="Window_Closing"> Closing="Window_Closing">
<Window.InputBindings> <Window.InputBindings>
<KeyBinding Command="{Binding Path=MinimizeAllPanelsCommand}" Modifiers="Ctrl" Key="M" /> <KeyBinding Command="{Binding Path=MinimizeAllPanelsCommand}" Modifiers="Ctrl+Alt" Key="M" />
</Window.InputBindings> </Window.InputBindings>
<Grid> <Grid>
<tb:TaskbarIcon Name="notifyIcon" <tb:TaskbarIcon Name="notifyIcon"
ToolTipText="MSFS Pop Out Panel Manager" ToolTipText="MSFS Pop Out Panel Manager"
IconSource="logo.ico" IconSource="logo.ico"
MenuActivation="RightClick" MenuActivation="LeftOrRightClick"
Visibility="Visible"> Visibility="Visible">
<tb:TaskbarIcon.ContextMenu> <tb:TaskbarIcon.ContextMenu>
<ContextMenu> <ContextMenu>
@ -58,7 +57,7 @@
<MenuItem Name="menuItem_Exit" Header="Exit" Command="{Binding Path=ExitCommand}"/> <MenuItem Name="menuItem_Exit" Header="Exit" Command="{Binding Path=ExitCommand}"/>
</MenuItem> </MenuItem>
<MenuItem Header="View"> <MenuItem Header="View">
<MenuItem Name="menuItem_MinimizeAllPanels" Header="Minimize All Panels " InputGestureText="Ctrl+M" Command="{Binding Path=MinimizeAllPanelsCommand}" IsChecked="{Binding Path=IsMinimizedAllPanels, Mode=TwoWay}" IsEnabled="{c:Binding Path='IsShownPanelConfigurationScreen'}"/> <MenuItem Name="menuItem_MinimizeAllPanels" Header="Minimize All Panels " InputGestureText="Ctrl+Alt+M" Command="{Binding Path=MinimizeAllPanelsCommand}" IsChecked="{Binding Path=IsMinimizedAllPanels, Mode=TwoWay}" IsEnabled="{c:Binding Path='IsShownPanelConfigurationScreen'}"/>
</MenuItem> </MenuItem>
<MenuItem Header="Help"> <MenuItem Header="Help">
<MenuItem Name="menuItem_UserGuide" Header="User Guide" Command="{Binding Path=UserGuideCommand}"/> <MenuItem Name="menuItem_UserGuide" Header="User Guide" Command="{Binding Path=UserGuideCommand}"/>
@ -102,7 +101,6 @@
<Label Name="lblVersion" Margin="0, 0, 0, 5" FontSize="14" Content="{Binding Path = ApplicationVersion, Mode=OneWay}" /> <Label Name="lblVersion" Margin="0, 0, 0, 5" FontSize="14" Content="{Binding Path = ApplicationVersion, Mode=OneWay}" />
</WrapPanel> </WrapPanel>
</DockPanel> </DockPanel>
</DockPanel> </DockPanel>
</Grid> </Grid>
</mah:MetroWindow> </mah:MetroWindow>

View file

@ -10,9 +10,6 @@ using System.Windows.Interop;
namespace MSFSPopoutPanelManager.WpfApp namespace MSFSPopoutPanelManager.WpfApp
{ {
/// <summary>
/// Interaction logic for ApplicationWindow.xaml
/// </summary>
public partial class ApplicationWindow : MetroWindow public partial class ApplicationWindow : MetroWindow
{ {
private ApplicationViewModel _viewModel; private ApplicationViewModel _viewModel;
@ -97,12 +94,12 @@ namespace MSFSPopoutPanelManager.WpfApp
private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e) private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{ {
_viewModel.ExitCommand.Execute(null); _viewModel.Exit();
} }
private void EditPreferences_Click(object sender, RoutedEventArgs e) private void EditPreferences_Click(object sender, RoutedEventArgs e)
{ {
PreferencesDialog dialog = new PreferencesDialog(_viewModel.DataStore.AppSetting); PreferencesDialog dialog = new PreferencesDialog(_viewModel.PreferencesViewModel);
dialog.Owner = Application.Current.MainWindow; dialog.Owner = Application.Current.MainWindow;
dialog.Topmost = true; dialog.Topmost = true;
dialog.WindowStartupLocation = WindowStartupLocation.CenterOwner; dialog.WindowStartupLocation = WindowStartupLocation.CenterOwner;

View file

@ -1,11 +1,10 @@
<mah:MetroWindow x:Class="MSFSPopoutPanelManager.WpfApp.ConfirmationDialog" <mah:MetroWindow x:Class="MSFSPopoutPanelManager.WpfApp.ConfirmationDialog"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 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:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:mah="clr-namespace:MahApps.Metro.Controls;assembly=MahApps.Metro" xmlns:mah="clr-namespace:MahApps.Metro.Controls;assembly=MahApps.Metro"
xmlns:local="clr-namespace:MSFSPopoutPanelManager.WpfApp" mc:Ignorable="d"
mc:Ignorable="d"
Title="Confirmation" Title="Confirmation"
ResizeMode="NoResize" ResizeMode="NoResize"
Height="180" Height="180"

View file

@ -1,23 +1,8 @@
using MahApps.Metro.Controls; using MahApps.Metro.Controls;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows; 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.Shapes;
namespace MSFSPopoutPanelManager.WpfApp namespace MSFSPopoutPanelManager.WpfApp
{ {
/// <summary>
/// Interaction logic for ConfirmationDialog.xaml
/// </summary>
public partial class ConfirmationDialog : MetroWindow public partial class ConfirmationDialog : MetroWindow
{ {
public ConfirmationDialog(string title, string message) public ConfirmationDialog(string title, string message)

View file

@ -1,11 +1,11 @@
<mah:MetroWindow x:Class="MSFSPopoutPanelManager.WpfApp.OnScreenMessageDialog" <mah:MetroWindow x:Class="MSFSPopoutPanelManager.WpfApp.OnScreenMessageDialog"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 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:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:mah="clr-namespace:MahApps.Metro.Controls;assembly=MahApps.Metro" xmlns:mah="clr-namespace:MahApps.Metro.Controls;assembly=MahApps.Metro"
xmlns:local="clr-namespace:MSFSPopoutPanelManager.WpfApp" xmlns:local="clr-namespace:MSFSPopoutPanelManager.WpfApp"
mc:Ignorable="d" mc:Ignorable="d"
Height="Auto" Height="Auto"
Width="Auto" Width="Auto"
SizeToContent="WidthAndHeight" SizeToContent="WidthAndHeight"

View file

@ -1,16 +1,13 @@
using MahApps.Metro.Controls; using MahApps.Metro.Controls;
using MSFSPopoutPanelManager.Model;
using MSFSPopoutPanelManager.Provider; using MSFSPopoutPanelManager.Provider;
using System; using System;
using System.Diagnostics;
using System.Drawing; using System.Drawing;
using System.Windows; using System.Windows;
using System.Windows.Interop; using System.Windows.Interop;
namespace MSFSPopoutPanelManager.WpfApp namespace MSFSPopoutPanelManager.WpfApp
{ {
/// <summary>
/// Interaction logic for OnScreenMessageDialog.xaml
/// </summary>
public partial class OnScreenMessageDialog : MetroWindow public partial class OnScreenMessageDialog : MetroWindow
{ {
public MessageIcon MessageIcon { get; set; } public MessageIcon MessageIcon { get; set; }
@ -40,17 +37,20 @@ namespace MSFSPopoutPanelManager.WpfApp
if (window != null) if (window != null)
{ {
var dialogHandle = window.Handle; var dialogHandle = window.Handle;
var simulatorProcessHandle = DiagnosticManager.GetSimulatorProcess().Handle; var simulatorProcess = DiagnosticManager.GetSimulatorProcess();
Rectangle rectangle; if (simulatorProcess != null)
PInvoke.GetWindowRect(DiagnosticManager.GetSimulatorProcess().Handle, out rectangle); {
Rectangle clientRectangle; Rectangle rectangle;
PInvoke.GetClientRect(DiagnosticManager.GetSimulatorProcess().Handle, out clientRectangle); PInvoke.GetWindowRect(simulatorProcess.Handle, out rectangle);
Rectangle clientRectangle;
PInvoke.GetClientRect(simulatorProcess.Handle, out clientRectangle);
var x = Convert.ToInt32(rectangle.X + clientRectangle.Width / 2 - this.Width / 2); var x = Convert.ToInt32(rectangle.X + clientRectangle.Width / 2 - this.Width / 2);
var y = Convert.ToInt32(rectangle.Y + clientRectangle.Height / 2 - this.Height / 2); var y = Convert.ToInt32(rectangle.Y + clientRectangle.Height / 2 - this.Height / 2);
PInvoke.MoveWindow(dialogHandle, x, y, Convert.ToInt32(this.Width), Convert.ToInt32(this.Height), false); WindowManager.MoveWindow(dialogHandle, PanelType.WPFWindow, x, y, Convert.ToInt32(this.Width), Convert.ToInt32(this.Height));
}
} }
} }
}; };
@ -63,7 +63,7 @@ namespace MSFSPopoutPanelManager.WpfApp
this.Close(); timer.Enabled = false; this.Close(); timer.Enabled = false;
}); });
}; };
timer.Interval = duration * 1000; timer.Interval = duration * 1000;
timer.Enabled = true; timer.Enabled = true;
} }
} }

View file

@ -1,9 +1,8 @@
<Window x:Class="MSFSPopoutPanelManager.WpfApp.PanelCoorOverlay" <Window x:Class="MSFSPopoutPanelManager.WpfApp.PanelCoorOverlay"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 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:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:MSFSPopoutPanelManager.WpfApp"
mc:Ignorable="d" mc:Ignorable="d"
Title="PanelCoorOverlay" Title="PanelCoorOverlay"
ResizeMode="NoResize" ResizeMode="NoResize"

View file

@ -1,12 +1,8 @@
using System; using System;
using System.Windows; using System.Windows;
using System.Windows.Interop;
namespace MSFSPopoutPanelManager.WpfApp namespace MSFSPopoutPanelManager.WpfApp
{ {
/// <summary>
/// Interaction logic for PanelCoorOverlay.xaml
/// </summary>
public partial class PanelCoorOverlay : Window public partial class PanelCoorOverlay : Window
{ {
public bool IsEditingPanelLocation { get; set; } public bool IsEditingPanelLocation { get; set; }
@ -23,9 +19,7 @@ namespace MSFSPopoutPanelManager.WpfApp
private void Window_MouseMove(object sender, System.Windows.Input.MouseEventArgs e) private void Window_MouseMove(object sender, System.Windows.Input.MouseEventArgs e)
{ {
if (IsEditingPanelLocation && e.LeftButton == System.Windows.Input.MouseButtonState.Pressed) if (IsEditingPanelLocation && e.LeftButton == System.Windows.Input.MouseButtonState.Pressed)
{
this.DragMove(); this.DragMove();
}
} }
} }
} }

View file

@ -1,13 +1,10 @@
<mah:MetroWindow x:Class="MSFSPopoutPanelManager.WpfApp.PreferencesDialog" <mah:MetroWindow x:Class="MSFSPopoutPanelManager.WpfApp.PreferencesDialog"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 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:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:mah="clr-namespace:MahApps.Metro.Controls;assembly=MahApps.Metro" xmlns:mah="clr-namespace:MahApps.Metro.Controls;assembly=MahApps.Metro"
xmlns:scm="clr-namespace:System.ComponentModel;assembly=WindowsBase" mc:Ignorable="d"
xmlns:c="clr-namespace:CalcBinding;assembly=CalcBinding"
xmlns:local="clr-namespace:MSFSPopoutPanelManager.WpfApp"
mc:Ignorable="d"
Title="Preferences" Title="Preferences"
Height="580" Height="580"
Width="800" Width="800"
@ -25,6 +22,7 @@
<Setter Property="Width" Value="Auto"/> <Setter Property="Width" Value="Auto"/>
<Setter Property="Margin" Value="24,5,0,10"/> <Setter Property="Margin" Value="24,5,0,10"/>
</Style> </Style>
<BooleanToVisibilityConverter x:Key="VisibleIfTrueConverter" />
</Window.Resources> </Window.Resources>
<Grid> <Grid>
<DockPanel> <DockPanel>
@ -48,26 +46,26 @@
<TreeViewItem Header="Track IR Settings" Selected="TreeViewItem_Selected" Margin="0,0,0,10"></TreeViewItem> <TreeViewItem Header="Track IR Settings" Selected="TreeViewItem_Selected" Margin="0,0,0,10"></TreeViewItem>
</TreeView> </TreeView>
<WrapPanel DockPanel.Dock="Right" Margin="20,15,20,0" Width="Auto" > <WrapPanel DockPanel.Dock="Right" Margin="20,15,20,0" Width="Auto" >
<WrapPanel Orientation="Vertical" Width="Auto" Visibility="{Binding Path=ApplicationSettingsVisibility, Mode=TwoWay}"> <WrapPanel Orientation="Vertical" Width="Auto" Visibility="{Binding Path=ApplicationSettingsVisible, Converter={StaticResource VisibleIfTrueConverter}, Mode=OneWay}">
<CheckBox IsChecked="{Binding Path=AppSetting.AlwaysOnTop, Mode=TwoWay}" Content="Always on Top"></CheckBox> <CheckBox IsChecked="{Binding Path=DataStore.AppSetting.AlwaysOnTop, Mode=TwoWay}" Content="Always on Top"></CheckBox>
<TextBlock Style="{StaticResource TextBlockDescription}"> <TextBlock Style="{StaticResource TextBlockDescription}">
Pin the application on top of all open windows. Pin the application on top of all open windows.
</TextBlock> </TextBlock>
<CheckBox IsChecked="{Binding Path=AppSetting.AutoStart, Mode=TwoWay}" Content="Auto Start"></CheckBox> <CheckBox IsChecked="{Binding Path=DataStore.AppSetting.AutoStart, Mode=TwoWay}" Content="Auto Start"></CheckBox>
<TextBlock Style="{StaticResource TextBlockDescription}"> <TextBlock Style="{StaticResource TextBlockDescription}">
Enable auto start the application when MSFS starts. This adds a XML config entry in EXE.xml file. Enable auto start the application when MSFS starts. This adds a XML config entry in EXE.xml file.
</TextBlock> </TextBlock>
<CheckBox IsChecked="{Binding Path=AppSetting.MinimizeToTray, Mode=TwoWay}" Content="Minimize to Tray"></CheckBox> <CheckBox IsChecked="{Binding Path=DataStore.AppSetting.MinimizeToTray, Mode=TwoWay}" Content="Minimize to Tray"></CheckBox>
<TextBlock Style="{StaticResource TextBlockDescription}"> <TextBlock Style="{StaticResource TextBlockDescription}">
Minimize the application to system tray. Minimize the application to system tray.
</TextBlock> </TextBlock>
<CheckBox IsChecked="{Binding Path=AppSetting.StartMinimized, Mode=TwoWay}" Content="Start Minimized"></CheckBox> <CheckBox IsChecked="{Binding Path=DataStore.AppSetting.StartMinimized, Mode=TwoWay}" Content="Start Minimized"></CheckBox>
<TextBlock Style="{StaticResource TextBlockDescription}"> <TextBlock Style="{StaticResource TextBlockDescription}">
Start the application in minimized mode in system tray. Start the application in minimized mode in system tray.
</TextBlock> </TextBlock>
</WrapPanel> </WrapPanel>
<WrapPanel Orientation="Vertical" Width="Auto" Visibility="{Binding Path=PopOutSettingsVisibility, Mode=TwoWay}"> <WrapPanel Orientation="Vertical" Width="Auto" Visibility="{Binding Path=PopOutSettingsVisible, Converter={StaticResource VisibleIfTrueConverter}, Mode=OneWay}">
<CheckBox IsChecked="{Binding Path=AppSetting.UseAutoPanning, Mode=TwoWay}" Content="Enable Auto Panning"></CheckBox> <CheckBox IsChecked="{Binding Path=DataStore.AppSetting.UseAutoPanning, Mode=TwoWay}" Content="Enable Auto Panning"></CheckBox>
<TextBlock Style="{StaticResource TextBlockDescription}"> <TextBlock Style="{StaticResource TextBlockDescription}">
Enable automatic panning of cockpit view when popping out panels. Auto Panning remembers the custom cockpit camera angle you used when defining the locations of pop out panel. Enable automatic panning of cockpit view when popping out panels. Auto Panning remembers the custom cockpit camera angle you used when defining the locations of pop out panel.
</TextBlock> </TextBlock>
@ -83,7 +81,7 @@
VerticalAlignment="Center" VerticalAlignment="Center"
Width="60" Width="60"
SelectedValuePath="Tag" SelectedValuePath="Tag"
SelectedValue="{Binding Path=AppSetting.AutoPanningKeyBinding, Mode=TwoWay}" > SelectedValue="{Binding Path=DataStore.AppSetting.AutoPanningKeyBinding, Mode=TwoWay}" >
<ComboBoxItem Content="0" Tag="0"></ComboBoxItem> <ComboBoxItem Content="0" Tag="0"></ComboBoxItem>
<ComboBoxItem Content="1" Tag="1"></ComboBoxItem> <ComboBoxItem Content="1" Tag="1"></ComboBoxItem>
<ComboBoxItem Content="2" Tag="2"></ComboBoxItem> <ComboBoxItem Content="2" Tag="2"></ComboBoxItem>
@ -96,11 +94,11 @@
<ComboBoxItem Content="9" Tag="9"></ComboBoxItem> <ComboBoxItem Content="9" Tag="9"></ComboBoxItem>
</ComboBox> </ComboBox>
</WrapPanel> </WrapPanel>
<CheckBox IsChecked="{Binding Path=AppSetting.IncludeBuiltInPanel, Mode=TwoWay}" Content="Include Built-in Panels"></CheckBox> <CheckBox IsChecked="{Binding Path=DataStore.AppSetting.IncludeBuiltInPanel, Mode=TwoWay}" Content="Include Built-in Panels"></CheckBox>
<TextBlock Style="{StaticResource TextBlockDescription}">Enable saving and recalling of MSFS built-in panels (ie. ATC, VFR Map, Checklist, etc) as part of profile definition.</TextBlock> <TextBlock Style="{StaticResource TextBlockDescription}">Enable saving and recalling of MSFS built-in panels (ie. ATC, VFR Map, Checklist, etc) as part of profile definition.</TextBlock>
</WrapPanel> </WrapPanel>
<WrapPanel Orientation="Vertical" Width="Auto" Visibility="{Binding Path=AutoPopOutSettingsVisibility, Mode=TwoWay}"> <WrapPanel Orientation="Vertical" Width="Auto" Visibility="{Binding Path=AutoPopOutSettingsVisible, Converter={StaticResource VisibleIfTrueConverter}, Mode=OneWay}">
<CheckBox IsChecked="{Binding Path=AppSetting.AutoPopOutPanels, Mode=TwoWay}" Content="Enable Auto Pop Out Panels"></CheckBox> <CheckBox IsChecked="{Binding Path=DataStore.AppSetting.AutoPopOutPanels, Mode=TwoWay}" Content="Enable Auto Pop Out Panels"></CheckBox>
<TextBlock Style="{StaticResource TextBlockDescription}"> <TextBlock Style="{StaticResource TextBlockDescription}">
Automatic pop out panels when an aircraft livery is bound to a profile. The following steps will be performed. Automatic pop out panels when an aircraft livery is bound to a profile. The following steps will be performed.
</TextBlock> </TextBlock>
@ -116,33 +114,35 @@
<TextBlock Style="{StaticResource TextBlockDescription}"> <TextBlock Style="{StaticResource TextBlockDescription}">
4. If configured for a profile on cold start, wait for instrumentation power on before executing pop out panel sequence. 4. If configured for a profile on cold start, wait for instrumentation power on before executing pop out panel sequence.
</TextBlock> </TextBlock>
<TextBlock Style="{StaticResource TextBlockHeading}">Wait delay for each step during auto pop out process (in seconds)</TextBlock> <WrapPanel Visibility="{Binding Path=DataStore.IsEnableAutoPopOutPanel, Converter={StaticResource VisibleIfTrueConverter}, Mode=OneWay}">
<WrapPanel Orientation="Horizontal" Margin="24,0,0,0" > <TextBlock Style="{StaticResource TextBlockHeading}">Wait delay for each step during auto pop out process (in seconds)</TextBlock>
<mah:NumericUpDown Width="80" Minimum="1" Maximum="30" FontSize="16" Value="{Binding Path=AppSetting.AutoPopOutPanelsWaitDelay.ReadyToFlyButton, Mode=TwoWay}"></mah:NumericUpDown> <WrapPanel Orientation="Horizontal" Margin="24,0,0,0" >
<Label Margin="10,0,0,0">Ready to Fly</Label> <mah:NumericUpDown Width="80" Minimum="1" Maximum="30" FontSize="16" Value="{Binding Path=DataStore.AppSetting.AutoPopOutPanelsWaitDelay.ReadyToFlyButton, Mode=TwoWay}"></mah:NumericUpDown>
<Label Margin="10,0,0,0">Ready to Fly</Label>
</WrapPanel>
<TextBlock Margin="119,0,10,10" Style="{StaticResource TextBlockDescription}">Amount of time to wait for 'Ready to Fly' button to appear.<LineBreak/>(Default: 6 seconds)</TextBlock>
<WrapPanel Orientation="Horizontal" Margin="24,0,0,0" >
<mah:NumericUpDown Width="80" Minimum="1" Maximum="30" FontSize="16" Value="{Binding Path=DataStore.AppSetting.AutoPopOutPanelsWaitDelay.InitialCockpitView, Mode=TwoWay}"></mah:NumericUpDown>
<Label Margin="10,0,0,0">Initial Cockpit View</Label>
</WrapPanel>
<TextBlock Margin="119,0,10,10" Style="{StaticResource TextBlockDescription}">Amount of time to wait for the cockpit to appear.<LineBreak/>(Default: 2 seconds)</TextBlock>
<WrapPanel Orientation="Horizontal" Margin="24,0,0,0" >
<mah:NumericUpDown Width="80" Minimum="1" Maximum="30" FontSize="16" Value="{Binding Path=DataStore.AppSetting.AutoPopOutPanelsWaitDelay.InstrumentationPowerOn, Mode=TwoWay}"></mah:NumericUpDown>
<Label Margin="10,0,0,0">Instrumentation Power On</Label>
</WrapPanel>
<TextBlock Margin="119,0,10,10" Style="{StaticResource TextBlockDescription}">Amount of time to wait for cold start instrumentation power on to complete.<LineBreak/>(Default: 2 seconds)</TextBlock>
<WrapPanel Orientation="Horizontal"></WrapPanel>
</WrapPanel> </WrapPanel>
<TextBlock Margin="119,0,10,10" Style="{StaticResource TextBlockDescription}">Amount of time to wait for 'Ready to Fly' button to appear.<LineBreak/>(Default: 6 seconds)</TextBlock>
<WrapPanel Orientation="Horizontal" Margin="24,0,0,0" >
<mah:NumericUpDown Width="80" Minimum="1" Maximum="30" FontSize="16" Value="{Binding Path=AppSetting.AutoPopOutPanelsWaitDelay.InitialCockpitView, Mode=TwoWay}"></mah:NumericUpDown>
<Label Margin="10,0,0,0">Initial Cockpit View</Label>
</WrapPanel>
<TextBlock Margin="119,0,10,10" Style="{StaticResource TextBlockDescription}">Amount of time to wait for the cockpit to appear.<LineBreak/>(Default: 2 seconds)</TextBlock>
<WrapPanel Orientation="Horizontal" Margin="24,0,0,00" >
<mah:NumericUpDown Width="80" Minimum="1" Maximum="30" FontSize="16" Value="{Binding Path=AppSetting.AutoPopOutPanelsWaitDelay.InstrumentationPowerOn, Mode=TwoWay}"></mah:NumericUpDown>
<Label Margin="10,0,0,0">Instrumentation Power On</Label>
</WrapPanel>
<TextBlock Margin="119,0,10,10" Style="{StaticResource TextBlockDescription}">Amount of time to wait for cold start instrumentation power on to complete.<LineBreak/>(Default: 2 seconds)</TextBlock>
<WrapPanel Orientation="Horizontal"></WrapPanel>
</WrapPanel> </WrapPanel>
<WrapPanel Orientation="Vertical" Visibility="Visible"> <WrapPanel Orientation="Vertical" Width="Auto" Visibility="{Binding Path=TrackIRSettingsVisible, Converter={StaticResource VisibleIfTrueConverter}, Mode=OneWay}">
</WrapPanel> <CheckBox IsChecked="{Binding Path=DataStore.AppSetting.AutoDisableTrackIR, Mode=TwoWay}" Content="Auto Disable Track IR"></CheckBox>
<WrapPanel Orientation="Vertical" Width="Auto" Visibility="{Binding Path=TrackIRSettingsVisibility, Mode=TwoWay}">
<CheckBox IsChecked="{Binding Path=AppSetting.AutoDisableTrackIR, Mode=TwoWay}" Content="Auto Disable Track IR"></CheckBox>
<TextBlock Style="{StaticResource TextBlockDescription}"> <TextBlock Style="{StaticResource TextBlockDescription}">
Automactically disable Track IR during panel selections and pop out process. Track IR will be re-enable once these processes are completed. Automactically disable Track IR during panel selections and pop out process. Track IR will be re-enable once these processes are completed.
</TextBlock> </TextBlock>
</WrapPanel> </WrapPanel>
<WrapPanel Orientation="Vertical" Visibility="Visible">
</WrapPanel>
</WrapPanel> </WrapPanel>
</DockPanel> </DockPanel>
</Grid> </Grid>
</mah:MetroWindow> </mah:MetroWindow>

View file

@ -1,66 +1,37 @@
using MahApps.Metro.Controls; using MahApps.Metro.Controls;
using MSFSPopoutPanelManager.Model; using MSFSPopoutPanelManager.Model;
using System.ComponentModel; using MSFSPopoutPanelManager.WpfApp.ViewModel;
using System.Windows; using System.Windows;
using System.Windows.Controls; using System.Windows.Controls;
namespace MSFSPopoutPanelManager.WpfApp namespace MSFSPopoutPanelManager.WpfApp
{ {
/// <summary> public partial class PreferencesDialog : MetroWindow
/// Interaction logic for AddProfileDialog.xaml
/// </summary>
public partial class PreferencesDialog : MetroWindow, INotifyPropertyChanged
{ {
public event PropertyChangedEventHandler PropertyChanged; private PreferencesViewModel _preferencesViewModel;
public PreferencesDialog(AppSetting appSetting) public PreferencesDialog(PreferencesViewModel preferencesViewModel)
{ {
_preferencesViewModel = preferencesViewModel;
InitializeComponent(); InitializeComponent();
AppSetting = appSetting; this.DataContext = preferencesViewModel;
this.DataContext = this;
ApplicationSettingsVisibility = Visibility.Visible;
PopOutSettingsVisibility = Visibility.Collapsed;
AutoPopOutSettingsVisibility = Visibility.Collapsed;
TrackIRSettingsVisibility = Visibility.Collapsed;
} }
public AppSetting AppSetting { get; set; } public AppSetting AppSetting { get; set; }
public Visibility ApplicationSettingsVisibility { get; set; } public bool ApplicationSettingsVisible { get; set; }
public Visibility PopOutSettingsVisibility { get; set; } public bool PopOutSettingsVisible { get; set; }
public Visibility AutoPopOutSettingsVisibility { get; set; } public bool AutoPopOutSettingsVisible { get; set; }
public Visibility TrackIRSettingsVisibility { get; set; } public bool TrackIRSettingsVisible { get; set; }
private void TreeViewItem_Selected(object sender, RoutedEventArgs e) private void TreeViewItem_Selected(object sender, RoutedEventArgs e)
{ {
var treeViewItem = (TreeViewItem)e.Source; var treeViewItem = (TreeViewItem)e.Source;
_preferencesViewModel.SectionSelectCommand.Execute(treeViewItem.Header.ToString());
ApplicationSettingsVisibility = Visibility.Collapsed;
PopOutSettingsVisibility = Visibility.Collapsed;
AutoPopOutSettingsVisibility = Visibility.Collapsed;
TrackIRSettingsVisibility = Visibility.Collapsed;
if (treeViewItem.Header.ToString() == "Application Settings")
{
ApplicationSettingsVisibility = Visibility.Visible;
}
else if(treeViewItem.Header.ToString() == "Pop Out Settings")
{
PopOutSettingsVisibility = Visibility.Visible;
}
else if (treeViewItem.Header.ToString() == "Auto Pop Out Panel Settings")
{
AutoPopOutSettingsVisibility = Visibility.Visible;
}
else if (treeViewItem.Header.ToString() == "Track IR Settings")
{
TrackIRSettingsVisibility = Visibility.Visible;
}
} }
} }
} }

View file

@ -1,10 +1,9 @@
<UserControl x:Class="MSFSPopoutPanelManager.WpfApp.UserControlPanelConfiguration" <UserControl x:Class="MSFSPopoutPanelManager.WpfApp.UserControlPanelConfiguration"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 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"
xmlns:local="clr-namespace:MSFSPopoutPanelManager.WpfApp"
xmlns:controls="http://metro.mahapps.com/winfx/xaml/controls" xmlns:controls="http://metro.mahapps.com/winfx/xaml/controls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:c="clr-namespace:CalcBinding;assembly=CalcBinding" xmlns:c="clr-namespace:CalcBinding;assembly=CalcBinding"
mc:Ignorable="d" mc:Ignorable="d"
Height="505" Height="505"
@ -125,7 +124,8 @@
SourceUpdated="GridData_SourceUpdated" SourceUpdated="GridData_SourceUpdated"
Style="{StaticResource TextBoxColumnFocus}" Style="{StaticResource TextBoxColumnFocus}"
IsReadOnly="{c:Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=DataGrid, AncestorLevel=1}, Path='DataContext.DataStore.ActiveUserProfile.IsLocked or !DataContext.DataStore.AllowEdit'}" IsReadOnly="{c:Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=DataGrid, AncestorLevel=1}, Path='DataContext.DataStore.ActiveUserProfile.IsLocked or !DataContext.DataStore.AllowEdit'}"
IsHitTestVisible="{c:Binding Path='!FullScreen'}"/> </DataTemplate> IsHitTestVisible="{c:Binding Path='!FullScreen'}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate> </DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn> </DataGridTemplateColumn>
<DataGridTemplateColumn Header="Y-Pos" Width="80"> <DataGridTemplateColumn Header="Y-Pos" Width="80">
@ -228,7 +228,6 @@
</Button.Style> </Button.Style>
</Button> </Button>
</WrapPanel> </WrapPanel>
</DockPanel> </DockPanel>
</Grid> </Grid>
</UserControl> </UserControl>

View file

@ -9,9 +9,6 @@ using System.Windows.Media;
namespace MSFSPopoutPanelManager.WpfApp namespace MSFSPopoutPanelManager.WpfApp
{ {
/// <summary>
/// Interaction logic for UserControlPanelConfiguration.xaml
/// </summary>
public partial class UserControlPanelConfiguration : UserControl public partial class UserControlPanelConfiguration : UserControl
{ {
private PanelConfigurationViewModel _panelConfigurationViewModel; private PanelConfigurationViewModel _panelConfigurationViewModel;
@ -25,9 +22,9 @@ namespace MSFSPopoutPanelManager.WpfApp
private void GridData_SourceUpdated(object sender, DataTransferEventArgs e) private void GridData_SourceUpdated(object sender, DataTransferEventArgs e)
{ {
var container = VisualTreeHelper.GetParent((Control) sender) as ContentPresenter; var container = VisualTreeHelper.GetParent((Control)sender) as ContentPresenter;
var panelConfig = container.Content as PanelConfig; var panelConfig = container.Content as PanelConfig;
var propertyName = (PanelConfigPropertyName) Enum.Parse(typeof(PanelConfigPropertyName), ((Control)sender).Name); var propertyName = (PanelConfigPropertyName)Enum.Parse(typeof(PanelConfigPropertyName), ((Control)sender).Name);
var panelConfigItem = new PanelConfigItem() { PanelIndex = panelConfig.PanelIndex, PanelConfigProperty = propertyName }; var panelConfigItem = new PanelConfigItem() { PanelIndex = panelConfig.PanelIndex, PanelConfigProperty = propertyName };
_panelConfigurationViewModel.PanelConfigUpdatedCommand.Execute(panelConfigItem); _panelConfigurationViewModel.PanelConfigUpdatedCommand.Execute(panelConfigItem);
@ -42,7 +39,7 @@ namespace MSFSPopoutPanelManager.WpfApp
PanelConfigPropertyName selectedProperty = PanelConfigPropertyName.Invalid; PanelConfigPropertyName selectedProperty = PanelConfigPropertyName.Invalid;
switch(cell.Column.Header) switch (cell.Column.Header)
{ {
case "Panel Name": case "Panel Name":
selectedProperty = PanelConfigPropertyName.PanelName; selectedProperty = PanelConfigPropertyName.PanelName;
@ -73,13 +70,13 @@ namespace MSFSPopoutPanelManager.WpfApp
break; break;
} }
_panelConfigurationViewModel.SelectedPanelConfigItem = new PanelConfigItem() { PanelIndex = panelConfig.PanelIndex, PanelConfigProperty = selectedProperty }; _panelConfigurationViewModel.SelectedPanelConfigItem = new PanelConfigItem() { PanelIndex = panelConfig.PanelIndex, PanelConfigProperty = selectedProperty };
} }
} }
private void LockPanels_Click(object sender, RoutedEventArgs e) private void LockPanels_Click(object sender, RoutedEventArgs e)
{ {
if(_panelConfigurationViewModel.DataStore.ActiveUserProfile.IsLocked) if (_panelConfigurationViewModel.DataStore.ActiveUserProfile.IsLocked)
{ {
ConfirmationDialog dialog = new ConfirmationDialog("Confirm Unlock Panels", "Are you sure you want to unlock all panels to make changes?"); ConfirmationDialog dialog = new ConfirmationDialog("Confirm Unlock Panels", "Are you sure you want to unlock all panels to make changes?");
dialog.Owner = Application.Current.MainWindow; dialog.Owner = Application.Current.MainWindow;

View file

@ -1,12 +1,11 @@
<UserControl x:Class="MSFSPopoutPanelManager.WpfApp.UserControlPanelSelection" <UserControl x:Class="MSFSPopoutPanelManager.WpfApp.UserControlPanelSelection"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 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"
xmlns:c="clr-namespace:CalcBinding;assembly=CalcBinding"
xmlns:local="clr-namespace:MSFSPopoutPanelManager.WpfApp"
xmlns:scm="clr-namespace:System.ComponentModel;assembly=WindowsBase"
xmlns:controls="http://metro.mahapps.com/winfx/xaml/controls" xmlns:controls="http://metro.mahapps.com/winfx/xaml/controls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:c="clr-namespace:CalcBinding;assembly=CalcBinding"
xmlns:scm="clr-namespace:System.ComponentModel;assembly=WindowsBase"
mc:Ignorable="d" mc:Ignorable="d"
Height="505" Height="505"
Width="920" Width="920"
@ -43,6 +42,7 @@
</DataTrigger> </DataTrigger>
</Style.Triggers> </Style.Triggers>
</Style> </Style>
<BooleanToVisibilityConverter x:Key="VisibleIfTrueConverter" />
</UserControl.Resources> </UserControl.Resources>
<Grid> <Grid>
<DockPanel> <DockPanel>
@ -95,30 +95,34 @@
<TextBlock Text="Power on required to pop out panels on cold start (G1000 / NXi Only)" TextWrapping="Wrap" Margin="5,0,0,3"/> <TextBlock Text="Power on required to pop out panels on cold start (G1000 / NXi Only)" TextWrapping="Wrap" Margin="5,0,0,3"/>
</CheckBox> </CheckBox>
</WrapPanel> </WrapPanel>
<Separator Margin="5,10,5,5"/> <WrapPanel Orientation="Vertical">
<Label Content="3. Identify pop out panel locations in the game by clicking on them." Margin="0,0,0,0" /> <Label Content="3. Identify pop out panel locations in the game by clicking on them." Margin="0,0,0,0" />
<WrapPanel Orientation="Vertical" Margin="20,0,0,0" HorizontalAlignment="Left"> <WrapPanel Orientation="Vertical" Margin="20,0,0,0" HorizontalAlignment="Left">
<WrapPanel Orientation="Horizontal"> <WrapPanel Orientation="Horizontal">
<Label Content="LEFT CLICK" Foreground="AntiqueWhite"/> <Label Content="LEFT CLICK" Foreground="AntiqueWhite"/>
<Label Content="to add a new panel."/> <Label Content="to add a new panel."/>
</WrapPanel> </WrapPanel>
<WrapPanel Orientation="Horizontal">
<WrapPanel Orientation="Horizontal"> <Label Content="CTRL + LEFT CLICK" Foreground="AntiqueWhite" />
<Label Content="CTRL + LEFT CLICK" Foreground="AntiqueWhite" /> <Label Content="when all panels have been selected or to cancel selections." />
<Label Content="when all panels have been selected or to cancel selections." /> </WrapPanel>
</WrapPanel> <WrapPanel Orientation="Horizontal">
<WrapPanel Orientation="Horizontal"> <Label Content="SHIFT + LEFT CLICK" Foreground="AntiqueWhite" />
<Label Content="SHIFT + LEFT CLICK" Foreground="AntiqueWhite" /> <Label Content="to remove the most recently added panel."/>
<Label Content="to remove the most recently added panel."/> </WrapPanel>
</WrapPanel> <WrapPanel Orientation="Horizontal" Margin="0,5,0,0" HorizontalAlignment="Left">
<WrapPanel Orientation="Horizontal" Margin="0,5,0,0" HorizontalAlignment="Left"> <Button Content="Start Panel Selection" HorizontalAlignment="Left" Margin="0,0,0,0" Width="165" Click="StartPanelSelection_Click" Style="{StaticResource ProfileSelectedDependency}"/>
<Button Content="Start Panel Selection" HorizontalAlignment="Left" Margin="0,0,0,0" Width="165" Click="StartPanelSelection_Click" Style="{StaticResource ProfileSelectedDependency}"/> <Button Content="Save Auto Panning Camera" HorizontalAlignment="Left" Margin="20,0,0,0" IsEnabled="{c:Binding Path='DataStore.HasActiveUserProfileId and DataStore.IsFlightActive'}" Width="215" Click="SaveAutoPanningCamera_Click" Style="{StaticResource ProfileSelectedDependency}"/>
<Button Content="Save Auto Panning Camera" HorizontalAlignment="Left" Margin="20,0,0,0" IsEnabled="{c:Binding Path='DataStore.HasActiveUserProfileId and DataStore.IsFlightActive'}" Width="215" Click="SaveAutoPanningCamera_Click" Style="{StaticResource ProfileSelectedDependency}"/> </WrapPanel>
</WrapPanel> </WrapPanel>
<Separator Margin="5,10,5,5"/>
</WrapPanel>
<WrapPanel Orientation="Vertical" >
<Label Content="4. Start the pop out process for selected panels." Margin="0,0,0,0" />
<Button Content="Start Pop Out" HorizontalAlignment="Left" Margin="20,5,0,0" Width="130" IsEnabled="{c:Binding Path='DataStore.HasActiveUserProfileId and DataStore.IsFlightActive'}" Command="{Binding Path=StartPopOutCommand}" Style="{StaticResource ProfileSelectedDependency}"/>
</WrapPanel>
<WrapPanel Orientation="Vertical" Visibility="Visible">
</WrapPanel> </WrapPanel>
<Separator Margin="5,10,5,5"/>
<Label Content="4. Start the pop out process for selected panels." Margin="0,0,0,0" />
<Button Content="Start Pop Out" HorizontalAlignment="Left" Margin="20,5,0,0" Width="130" IsEnabled="{c:Binding Path='DataStore.HasActiveUserProfileId and DataStore.IsFlightActive'}" Command="{Binding Path=StartPopOutCommand}" Style="{StaticResource ProfileSelectedDependency}"/>
</WrapPanel> </WrapPanel>
<DockPanel DockPanel.Dock="Right" Width="325" HorizontalAlignment="Center"> <DockPanel DockPanel.Dock="Right" Width="325" HorizontalAlignment="Center">
<Label DockPanel.Dock="Top" Content="Panel Locations" HorizontalAlignment="Center" Margin="0,10,0,0"/> <Label DockPanel.Dock="Top" Content="Panel Locations" HorizontalAlignment="Center" Margin="0,10,0,0"/>

View file

@ -4,9 +4,6 @@ using System.Windows.Controls;
namespace MSFSPopoutPanelManager.WpfApp namespace MSFSPopoutPanelManager.WpfApp
{ {
/// <summary>
/// Interaction logic for UserControlPanelSelection.xaml
/// </summary>
public partial class UserControlPanelSelection : UserControl public partial class UserControlPanelSelection : UserControl
{ {
private PanelSelectionViewModel _panelSelectionViewModel; private PanelSelectionViewModel _panelSelectionViewModel;
@ -94,16 +91,6 @@ namespace MSFSPopoutPanelManager.WpfApp
private void AddBinding_Click(object sender, RoutedEventArgs e) private void AddBinding_Click(object sender, RoutedEventArgs e)
{ {
//ConfirmationDialog dialog = new ConfirmationDialog("Confirm Add Binding", $"Are you sure you want to bind the aircraft livery below to the active profile? \n{_panelSelectionViewModel.DataStore.CurrentMsfsPlaneTitle}");
//dialog.Owner = Application.Current.MainWindow;
//dialog.Topmost = true;
//dialog.WindowStartupLocation = WindowStartupLocation.CenterOwner;
//if ((bool)dialog.ShowDialog())
//{
// _panelSelectionViewModel.AddProfileBindingCommand.Execute(null);
//}
_panelSelectionViewModel.AddProfileBindingCommand.Execute(null); _panelSelectionViewModel.AddProfileBindingCommand.Execute(null);
} }

View file

@ -1,10 +1,9 @@
using AutoUpdaterDotNET; using AutoUpdaterDotNET;
using CommunityToolkit.Mvvm.ComponentModel;
using MSFSPopoutPanelManager.Model; using MSFSPopoutPanelManager.Model;
using MSFSPopoutPanelManager.Provider; using MSFSPopoutPanelManager.Provider;
using MSFSPopoutPanelManager.Shared; using MSFSPopoutPanelManager.Shared;
using System; using System;
using System.ComponentModel;
using System.Diagnostics;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Threading; using System.Threading;
@ -12,21 +11,20 @@ using System.Windows;
namespace MSFSPopoutPanelManager.WpfApp.ViewModel namespace MSFSPopoutPanelManager.WpfApp.ViewModel
{ {
public class ApplicationViewModel : INotifyPropertyChanged public class ApplicationViewModel : ObservableObject
{ {
private UserProfileManager _userProfileManager; private UserProfileManager _userProfileManager;
private PanelPopOutManager _panelPopoutManager; private PanelPopOutManager _panelPopoutManager;
private SimConnectManager _simConnectManager; private SimConnectManager _simConnectManager;
// Using PropertyChanged.Fody
public event PropertyChangedEventHandler PropertyChanged;
public event EventHandler<EventArgs<StatusMessage>> ShowContextMenuBalloonTip; public event EventHandler<EventArgs<StatusMessage>> ShowContextMenuBalloonTip;
public PanelSelectionViewModel PanelSelectionViewModel { get; private set; } public PanelSelectionViewModel PanelSelectionViewModel { get; private set; }
public PanelConfigurationViewModel PanelConfigurationViewModel { get; private set; } public PanelConfigurationViewModel PanelConfigurationViewModel { get; private set; }
public PreferencesViewModel PreferencesViewModel { get; private set; }
public DataStore DataStore { get; set; } public DataStore DataStore { get; set; }
public int ActiveUserProfileId { get; set; } public int ActiveUserProfileId { get; set; }
@ -43,6 +41,8 @@ namespace MSFSPopoutPanelManager.WpfApp.ViewModel
public bool IsMinimizedAllPanels { get; set; } public bool IsMinimizedAllPanels { get; set; }
public IntPtr WindowHandle { get; set; }
public DelegateCommand RestartCommand => new DelegateCommand(OnRestart, CanExecute); public DelegateCommand RestartCommand => new DelegateCommand(OnRestart, CanExecute);
public DelegateCommand MinimizeAllPanelsCommand => new DelegateCommand(OnMinimizeAllPanels, CanExecute); public DelegateCommand MinimizeAllPanelsCommand => new DelegateCommand(OnMinimizeAllPanels, CanExecute);
public DelegateCommand ExitCommand => new DelegateCommand(OnExit, CanExecute); public DelegateCommand ExitCommand => new DelegateCommand(OnExit, CanExecute);
@ -61,15 +61,15 @@ namespace MSFSPopoutPanelManager.WpfApp.ViewModel
_userProfileManager = new UserProfileManager(); _userProfileManager = new UserProfileManager();
_simConnectManager = new SimConnectManager(); _simConnectManager = new SimConnectManager();
_simConnectManager.OnSimConnectDataRefreshed += (sender, e) => _simConnectManager.OnSimConnectDataRefreshed += (sender, e) =>
{ {
// Automatic switching of active profile when SimConnect active aircraft livery changes // Automatic switching of active profile when SimConnect active aircraft livery changes
if(DataStore.CurrentMsfsPlaneTitle != e.Value.Title) if (DataStore.CurrentMsfsPlaneTitle != e.Value.Title)
{ {
DataStore.CurrentMsfsPlaneTitle = e.Value.Title; DataStore.CurrentMsfsPlaneTitle = e.Value.Title;
AutoSwitchProfile(e.Value.Title); AutoSwitchProfile(e.Value.Title);
} }
DataStore.ElectricalMasterBatteryStatus = e.Value.ElectricalMasterBattery; DataStore.ElectricalMasterBatteryStatus = e.Value.ElectricalMasterBattery;
}; };
_simConnectManager.OnConnected += (sender, e) => { DataStore.IsSimulatorStarted = true; }; _simConnectManager.OnConnected += (sender, e) => { DataStore.IsSimulatorStarted = true; };
@ -95,9 +95,9 @@ namespace MSFSPopoutPanelManager.WpfApp.ViewModel
PanelSelectionViewModel = new PanelSelectionViewModel(DataStore, _userProfileManager, _panelPopoutManager, _simConnectManager); PanelSelectionViewModel = new PanelSelectionViewModel(DataStore, _userProfileManager, _panelPopoutManager, _simConnectManager);
PanelSelectionViewModel.OnPopOutCompleted += (sender, e) => { ShowPanelSelection(false); PanelConfigurationViewModel.Initialize(); }; PanelSelectionViewModel.OnPopOutCompleted += (sender, e) => { ShowPanelSelection(false); PanelConfigurationViewModel.Initialize(); };
PanelConfigurationViewModel = new PanelConfigurationViewModel(DataStore, _userProfileManager); PanelConfigurationViewModel = new PanelConfigurationViewModel(DataStore, _userProfileManager);
PreferencesViewModel = new PreferencesViewModel(DataStore);
InputHookManager.OnStartPopout += (source, e) => { OnStartPopOut(null); }; InputHookManager.OnStartPopout += (source, e) => { OnStartPopOut(null); };
} }
@ -141,10 +141,17 @@ namespace MSFSPopoutPanelManager.WpfApp.ViewModel
InputHookManager.StartHook(); InputHookManager.StartHook();
} }
public void Exit()
{
// This method gets call on Windows_Closing
InputHookManager.EndHook();
_simConnectManager.Stop();
}
private void OnRestart(object commandParameter) private void OnRestart(object commandParameter)
{ {
// Un-minimize all panels if applicable // Un-minimize all panels if applicable
if(IsMinimizedAllPanels) if (IsMinimizedAllPanels)
{ {
DataStore.AllowEdit = true; DataStore.AllowEdit = true;
IsMinimizedAllPanels = false; IsMinimizedAllPanels = false;
@ -167,10 +174,14 @@ namespace MSFSPopoutPanelManager.WpfApp.ViewModel
private void OnExit(object commandParameter) private void OnExit(object commandParameter)
{ {
InputHookManager.EndHook(); if (Application.Current != null)
_simConnectManager.Stop(); Application.Current.Dispatcher.Invoke(() => Application.Current.Shutdown());
}
Application.Current.Shutdown(); private void ShutDownApplication()
{
if (Application.Current != null)
Application.Current.Shutdown();
} }
private void OnMinimizeAllPanels(object commandParameter) private void OnMinimizeAllPanels(object commandParameter)
@ -306,4 +317,4 @@ namespace MSFSPopoutPanelManager.WpfApp.ViewModel
} }
} }
} }
} }

View file

@ -1,17 +1,16 @@
using MSFSPopoutPanelManager.Model; using CommunityToolkit.Mvvm.ComponentModel;
using MSFSPopoutPanelManager.Model;
using System; using System;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq; using System.Linq;
using System.Windows; using System.Windows;
namespace MSFSPopoutPanelManager.WpfApp.ViewModel namespace MSFSPopoutPanelManager.WpfApp.ViewModel
{ {
public class DataStore : INotifyPropertyChanged public class DataStore : ObservableObject
{ {
private int _activeProfileId; private int _activeProfileId;
private AppSetting _appSetting;
public event PropertyChangedEventHandler PropertyChanged;
public event EventHandler OnActiveUserProfileChanged; public event EventHandler OnActiveUserProfileChanged;
public event EventHandler OnAllowEditChanged; public event EventHandler OnAllowEditChanged;
@ -23,21 +22,45 @@ namespace MSFSPopoutPanelManager.WpfApp.ViewModel
IsFlightActive = true; // ToDo: temporary for testing IsFlightActive = true; // ToDo: temporary for testing
} }
public AppSetting AppSetting { get; set; } public AppSetting AppSetting
{
get
{
return _appSetting;
}
set
{
_appSetting = value;
if (_appSetting != null)
{
IsEnableAutoPopOutPanel = _appSetting.AutoPopOutPanels;
}
// bubble event up to this 'DataStore' level
_appSetting.AutoPopOutPanelsChanged += (sender, e) =>
{
IsEnableAutoPopOutPanel = e.Value;
};
}
}
public ObservableCollection<UserProfile> UserProfiles { get; set; } public ObservableCollection<UserProfile> UserProfiles { get; set; }
public ObservableCollection<PanelSourceCoordinate> ActiveProfilePanelCoordinates public ObservableCollection<PanelSourceCoordinate> ActiveProfilePanelCoordinates
{ {
get get
{ {
if (ActiveUserProfile == null) if (ActiveUserProfile == null)
return new ObservableCollection<PanelSourceCoordinate>(); return new ObservableCollection<PanelSourceCoordinate>();
else else
return ActiveUserProfile.PanelSourceCoordinates; return ActiveUserProfile.PanelSourceCoordinates;
} }
} }
public ObservableCollection<PanelConfig> ActiveProfilePanelConfigs public ObservableCollection<PanelConfig> ActiveProfilePanelConfigs
{ {
get get
@ -69,14 +92,10 @@ namespace MSFSPopoutPanelManager.WpfApp.ViewModel
} }
set set
{ {
if(value != _allowEdit) if (value != _allowEdit)
{ {
_allowEdit = value; _allowEdit = value;
if (PropertyChanged != null) OnAllowEditChanged?.Invoke(this, null);
{
PropertyChanged(this, new PropertyChangedEventArgs("AllowEdit"));
OnAllowEditChanged?.Invoke(this, null);
}
} }
} }
} }
@ -98,7 +117,7 @@ namespace MSFSPopoutPanelManager.WpfApp.ViewModel
// Set active profile flag // Set active profile flag
UserProfiles.ToList().ForEach(p => p.IsActive = false); UserProfiles.ToList().ForEach(p => p.IsActive = false);
var profile = UserProfiles.ToList().Find(p => p.ProfileId == value); var profile = UserProfiles.ToList().Find(p => p.ProfileId == value);
if(profile != null) if (profile != null)
profile.IsActive = true; profile.IsActive = true;
OnActiveUserProfileChanged?.Invoke(this, null); OnActiveUserProfileChanged?.Invoke(this, null);
@ -112,7 +131,7 @@ namespace MSFSPopoutPanelManager.WpfApp.ViewModel
public string CurrentMsfsPlaneTitle { get; set; } public string CurrentMsfsPlaneTitle { get; set; }
public bool HasCurrentMsfsPlaneTitle public bool HasCurrentMsfsPlaneTitle
{ {
get { return !String.IsNullOrEmpty(CurrentMsfsPlaneTitle); } get { return !String.IsNullOrEmpty(CurrentMsfsPlaneTitle); }
} }
@ -123,7 +142,7 @@ namespace MSFSPopoutPanelManager.WpfApp.ViewModel
{ {
if (ActiveUserProfile == null) if (ActiveUserProfile == null)
return false; return false;
return ActiveUserProfile.BindingAircraftLiveries.ToList().Exists(p => p == CurrentMsfsPlaneTitle); return ActiveUserProfile.BindingAircraftLiveries.ToList().Exists(p => p == CurrentMsfsPlaneTitle);
} }
} }
@ -165,5 +184,6 @@ namespace MSFSPopoutPanelManager.WpfApp.ViewModel
public bool IsEnteredFlight { get; set; } public bool IsEnteredFlight { get; set; }
public bool IsFlightActive { get; set; } public bool IsFlightActive { get; set; }
public bool IsEnableAutoPopOutPanel { get; set; }
} }
} }

View file

@ -22,4 +22,4 @@ namespace MSFSPopoutPanelManager.WpfApp.ViewModel
public void InvokeCanExecuteChanged() => CanExecuteChanged?.Invoke(this, EventArgs.Empty); public void InvokeCanExecuteChanged() => CanExecuteChanged?.Invoke(this, EventArgs.Empty);
} }
} }

View file

@ -1,20 +1,15 @@
using MSFSPopoutPanelManager.Model; using CommunityToolkit.Mvvm.ComponentModel;
using MSFSPopoutPanelManager.Model;
using MSFSPopoutPanelManager.Provider; using MSFSPopoutPanelManager.Provider;
using System; using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
namespace MSFSPopoutPanelManager.WpfApp.ViewModel namespace MSFSPopoutPanelManager.WpfApp.ViewModel
{ {
public class PanelConfigurationViewModel public class PanelConfigurationViewModel : ObservableObject
{ {
private UserProfileManager _userProfileManager; private UserProfileManager _userProfileManager;
private PanelConfigurationManager _panelConfigurationManager; private PanelConfigurationManager _panelConfigurationManager;
// Using PropertyChanged.Fody
public event PropertyChangedEventHandler PropertyChanged;
public DataStore DataStore { get; set; } public DataStore DataStore { get; set; }
public PanelConfigItem SelectedPanelConfigItem { get; set; } public PanelConfigItem SelectedPanelConfigItem { get; set; }
@ -39,9 +34,9 @@ namespace MSFSPopoutPanelManager.WpfApp.ViewModel
_panelConfigurationManager.UserProfile = DataStore.ActiveUserProfile; _panelConfigurationManager.UserProfile = DataStore.ActiveUserProfile;
_panelConfigurationManager.AllowEdit = DataStore.AllowEdit; _panelConfigurationManager.AllowEdit = DataStore.AllowEdit;
_panelConfigurationManager.HookWinEvent(); _panelConfigurationManager.HookWinEvent();
DataStore.OnAllowEditChanged += (sender, e) => DataStore.OnAllowEditChanged += (sender, e) =>
{ {
_panelConfigurationManager.AllowEdit = DataStore.AllowEdit; _panelConfigurationManager.AllowEdit = DataStore.AllowEdit;
}; };
} }
@ -57,7 +52,7 @@ namespace MSFSPopoutPanelManager.WpfApp.ViewModel
private void OnPanelConfigUpdated(object panelConfigItem) private void OnPanelConfigUpdated(object panelConfigItem)
{ {
if(DataStore.AllowEdit) if (DataStore.AllowEdit)
_panelConfigurationManager.PanelConfigPropertyUpdated(panelConfigItem as PanelConfigItem); _panelConfigurationManager.PanelConfigPropertyUpdated(panelConfigItem as PanelConfigItem);
} }
@ -71,5 +66,5 @@ namespace MSFSPopoutPanelManager.WpfApp.ViewModel
{ {
return true; return true;
} }
} }
} }

View file

@ -1,8 +1,8 @@
using MSFSPopoutPanelManager.Model; using CommunityToolkit.Mvvm.ComponentModel;
using MSFSPopoutPanelManager.Model;
using MSFSPopoutPanelManager.Provider; using MSFSPopoutPanelManager.Provider;
using MSFSPopoutPanelManager.Shared; using MSFSPopoutPanelManager.Shared;
using System; using System;
using System.ComponentModel;
using System.Linq; using System.Linq;
using System.Threading; using System.Threading;
using System.Windows; using System.Windows;
@ -10,7 +10,7 @@ using System.Windows.Interop;
namespace MSFSPopoutPanelManager.WpfApp.ViewModel namespace MSFSPopoutPanelManager.WpfApp.ViewModel
{ {
public class PanelSelectionViewModel : INotifyPropertyChanged public class PanelSelectionViewModel : ObservableObject
{ {
private UserProfileManager _userProfileManager; private UserProfileManager _userProfileManager;
private PanelSelectionManager _panelSelectionManager; private PanelSelectionManager _panelSelectionManager;
@ -18,14 +18,11 @@ namespace MSFSPopoutPanelManager.WpfApp.ViewModel
private SimConnectManager _simConnectManager; private SimConnectManager _simConnectManager;
private bool _minimizeForPopOut; private bool _minimizeForPopOut;
// Using PropertyChanged.Fody
public event PropertyChangedEventHandler PropertyChanged;
public event EventHandler OnPopOutStarted; public event EventHandler OnPopOutStarted;
public event EventHandler OnPopOutCompleted; public event EventHandler OnPopOutCompleted;
public event EventHandler OnShowPrePopOutMessage; public event EventHandler OnUserProfileChanged;
public DataStore DataStore { get; set; } public DataStore DataStore { get; private set; }
public bool IsEditingPanelCoorOverlay { get; set; } public bool IsEditingPanelCoorOverlay { get; set; }
@ -43,8 +40,9 @@ namespace MSFSPopoutPanelManager.WpfApp.ViewModel
public PanelSelectionViewModel(DataStore dataStore, UserProfileManager userProfileManager, PanelPopOutManager panelPopoutManager, SimConnectManager simConnectManager) public PanelSelectionViewModel(DataStore dataStore, UserProfileManager userProfileManager, PanelPopOutManager panelPopoutManager, SimConnectManager simConnectManager)
{ {
DataStore = dataStore; DataStore = dataStore;
DataStore.OnActiveUserProfileChanged += (sender, e) => { DataStore.OnActiveUserProfileChanged += (sender, e) =>
IsEditingPanelCoorOverlay = false; {
IsEditingPanelCoorOverlay = false;
RemoveAllPanelCoorOverlay(); RemoveAllPanelCoorOverlay();
}; };
@ -95,6 +93,7 @@ namespace MSFSPopoutPanelManager.WpfApp.ViewModel
private void OnChangeProfile(object commandParameter) private void OnChangeProfile(object commandParameter)
{ {
DataStore.AppSetting.LastUsedProfileId = DataStore.ActiveUserProfileId; DataStore.AppSetting.LastUsedProfileId = DataStore.ActiveUserProfileId;
OnUserProfileChanged?.Invoke(this, null);
} }
private void OnAddProfileBinding(object commandParameter) private void OnAddProfileBinding(object commandParameter)
@ -178,7 +177,7 @@ namespace MSFSPopoutPanelManager.WpfApp.ViewModel
// Turn off TrackIR if TrackIR is started // Turn off TrackIR if TrackIR is started
if (commandParameter == null && DataStore.AppSetting.AutoDisableTrackIR) if (commandParameter == null && DataStore.AppSetting.AutoDisableTrackIR)
{ {
if(IsEditingPanelCoorOverlay) if (IsEditingPanelCoorOverlay)
_simConnectManager.TurnOffTrackIR(); _simConnectManager.TurnOffTrackIR();
else else
_simConnectManager.TurnOnTrackIR(); _simConnectManager.TurnOnTrackIR();
@ -209,7 +208,7 @@ namespace MSFSPopoutPanelManager.WpfApp.ViewModel
var overlay = (Window)sender; var overlay = (Window)sender;
var handle = new WindowInteropHelper(Window.GetWindow(overlay)).Handle; var handle = new WindowInteropHelper(Window.GetWindow(overlay)).Handle;
panelSourceCoordinate.PanelHandle = handle; panelSourceCoordinate.PanelHandle = handle;
PInvoke.MoveWindow(handle, (int)overlay.Left, (int)overlay.Top, (int)overlay.Width, (int)overlay.Height, false); WindowManager.MoveWindow(handle, PanelType.WPFWindow, (int)overlay.Left, (int)overlay.Top, (int)overlay.Width, (int)overlay.Height);
}; };
overlay.WindowStartupLocation = System.Windows.WindowStartupLocation.Manual; overlay.WindowStartupLocation = System.Windows.WindowStartupLocation.Manual;
overlay.Left = panelSourceCoordinate.X - overlay.Width / 2; overlay.Left = panelSourceCoordinate.X - overlay.Width / 2;
@ -276,7 +275,7 @@ namespace MSFSPopoutPanelManager.WpfApp.ViewModel
OnPopOutCompleted?.Invoke(this, null); OnPopOutCompleted?.Invoke(this, null);
} }
// Turn off TrackIR if TrackIR is started
if (DataStore.AppSetting.AutoDisableTrackIR) if (DataStore.AppSetting.AutoDisableTrackIR)
_simConnectManager.TurnOnTrackIR(); _simConnectManager.TurnOnTrackIR();
} }
@ -294,7 +293,7 @@ namespace MSFSPopoutPanelManager.WpfApp.ViewModel
else else
Logger.LogStatus("Panels selection is completed. No panel has been selected.", StatusMessageType.Info); Logger.LogStatus("Panels selection is completed. No panel has been selected.", StatusMessageType.Info);
// Turn off TrackIR if TrackIR is started
if (DataStore.AppSetting.AutoDisableTrackIR) if (DataStore.AppSetting.AutoDisableTrackIR)
_simConnectManager.TurnOnTrackIR(); _simConnectManager.TurnOnTrackIR();
} }

View file

@ -0,0 +1,58 @@
using CommunityToolkit.Mvvm.ComponentModel;
namespace MSFSPopoutPanelManager.WpfApp.ViewModel
{
public class PreferencesViewModel : ObservableObject
{
public PreferencesViewModel(DataStore dataStore)
{
DataStore = dataStore;
ApplicationSettingsVisible = true;
PopOutSettingsVisible = false;
AutoPopOutSettingsVisible = false;
TrackIRSettingsVisible = false;
}
public DelegateCommand SectionSelectCommand => new DelegateCommand(OnSectionSelected, CanExecute);
public DataStore DataStore { get; private set; }
public bool ApplicationSettingsVisible { get; private set; }
public bool PopOutSettingsVisible { get; private set; }
public bool AutoPopOutSettingsVisible { get; private set; }
public bool TrackIRSettingsVisible { get; private set; }
private bool CanExecute(object commandParameter)
{
return true;
}
private void OnSectionSelected(object commandParameter)
{
ApplicationSettingsVisible = false;
PopOutSettingsVisible = false;
AutoPopOutSettingsVisible = false;
TrackIRSettingsVisible = false;
switch (commandParameter.ToString())
{
case "Application Settings":
ApplicationSettingsVisible = true;
break;
case "Pop Out Settings":
PopOutSettingsVisible = true;
break;
case "Auto Pop Out Panel Settings":
AutoPopOutSettingsVisible = true;
break;
case "Track IR Settings":
TrackIRSettingsVisible = true;
break;
}
}
}
}

View file

@ -17,6 +17,10 @@
<SatelliteResourceLanguages>en</SatelliteResourceLanguages> <SatelliteResourceLanguages>en</SatelliteResourceLanguages>
</PropertyGroup> </PropertyGroup>
<ItemGroup>
<None Remove="resources\logo.png" />
</ItemGroup>
<ItemGroup> <ItemGroup>
<Content Include="log4net.config"> <Content Include="log4net.config">
<CopyToOutputDirectory>Always</CopyToOutputDirectory> <CopyToOutputDirectory>Always</CopyToOutputDirectory>
@ -30,6 +34,9 @@
<Content Include="Resources\info.png"> <Content Include="Resources\info.png">
<CopyToOutputDirectory>Always</CopyToOutputDirectory> <CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content> </Content>
<Content Include="resources\logo.png">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Include="Resources\msfsconnected.png"> <Content Include="Resources\msfsconnected.png">
<CopyToOutputDirectory>Always</CopyToOutputDirectory> <CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content> </Content>
@ -42,18 +49,15 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Autoupdater.NET.Official" Version="1.7.0" /> <PackageReference Include="Autoupdater.NET.Official" Version="1.7.3" />
<PackageReference Include="CalcBinding" Version="2.5.2" /> <PackageReference Include="CalcBinding" Version="2.5.2" />
<PackageReference Include="Fody" Version="6.6.0"> <PackageReference Include="CommunityToolkit.Mvvm" Version="7.1.2" />
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Hardcodet.NotifyIcon.Wpf" Version="1.1.0" /> <PackageReference Include="Hardcodet.NotifyIcon.Wpf" Version="1.1.0" />
<PackageReference Include="log4net" Version="2.0.14" /> <PackageReference Include="log4net" Version="2.0.14" />
<PackageReference Include="MahApps.Metro" Version="2.4.9" /> <PackageReference Include="MahApps.Metro" Version="2.4.9" />
<PackageReference Include="MouseKeyHook" Version="5.6.0" /> <PackageReference Include="MouseKeyHook" Version="5.6.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" /> <PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="PropertyChanged.Fody" Version="3.4.0" /> <PackageReference Include="PropertyChanged.Fody" Version="3.4.1" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

BIN
WpfApp/resources/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB