diff --git a/DoctorApp/App.xaml b/DoctorApp/App.xaml index 1fcbd5c..aac18d8 100644 --- a/DoctorApp/App.xaml +++ b/DoctorApp/App.xaml @@ -6,17 +6,27 @@ xmlns:views="clr-namespace:DoctorApp.Views" StartupUri="Views/MainWindow.xaml"> - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + diff --git a/DoctorApp/Utils/Client.cs b/DoctorApp/Utils/Client.cs index da77925..26a87fb 100644 --- a/DoctorApp/Utils/Client.cs +++ b/DoctorApp/Utils/Client.cs @@ -57,6 +57,9 @@ namespace DoctorApp.Utils /// the result of the async read private void OnRead(IAsyncResult ar) { + if (ar == null || (!ar.IsCompleted) || (!this.stream.CanRead)) + return; + int receivedBytes = this.stream.EndRead(ar); if (totalBufferReceived + receivedBytes > 1024) @@ -91,7 +94,7 @@ namespace DoctorApp.Utils Debug.WriteLine("Username and password correct!"); this.LoginViewModel.setLoginStatus(true); this.connected = true; - + } else { @@ -192,7 +195,7 @@ namespace DoctorApp.Utils /// the message public void Bike(byte[] bytes) { - + if (!sessionRunning) { return; @@ -202,18 +205,18 @@ namespace DoctorApp.Utils throw new ArgumentNullException("no bytes"); } byte[] message = DataParser.GetRawDataMessage(bytes); - - /* switch (bytes[0]) - { - case 0x10: + /* switch (bytes[0]) + { - if (canSendToEngine) engineConnection.BikeSpeed = (bytes[4] | (bytes[5] << 8)) * 0.01f; - break; - case 0x19: - if (canSendToEngine) engineConnection.BikePower = (bytes[5]) | (bytes[6] & 0b00001111) << 8; - break; - }*/ + case 0x10: + + if (canSendToEngine) engineConnection.BikeSpeed = (bytes[4] | (bytes[5] << 8)) * 0.01f; + break; + case 0x19: + if (canSendToEngine) engineConnection.BikePower = (bytes[5]) | (bytes[6] & 0b00001111) << 8; + break; + }*/ this.stream.BeginWrite(message, 0, message.Length, new AsyncCallback(OnWrite), null); @@ -234,7 +237,7 @@ namespace DoctorApp.Utils /// public void tryLogin(string username, string password) { - + string hashPassword = Util.Hasher.HashString(password); byte[] message = DataParser.getJsonMessage(DataParser.LoginAsDoctor(username, hashPassword)); @@ -266,5 +269,13 @@ namespace DoctorApp.Utils { this.ClientInfoViewModel = clientInfoViewModel; } + + public void Dispose() + { + Debug.WriteLine("client dispose called"); + this.stream.Dispose(); + this.client.Dispose(); + this.handler?.stop(); + } } } diff --git a/DoctorApp/ViewModels/MainWindowViewModel.cs b/DoctorApp/ViewModels/MainWindowViewModel.cs index fa7a982..a15f026 100644 --- a/DoctorApp/ViewModels/MainWindowViewModel.cs +++ b/DoctorApp/ViewModels/MainWindowViewModel.cs @@ -1,26 +1,134 @@ -using DoctorApp.Models; -using DoctorApp.Utils; -using System; -using System.Collections.Generic; -using System.Text; +using GalaSoft.MvvmLight.Command; +using System.Diagnostics; using Util; +using System.Windows; +using System.Windows.Input; +using DoctorApp.Models; +using DoctorApp.Utils; +using Util.MagicCode; namespace DoctorApp.ViewModels { class MainWindowViewModel : ObservableObject { + #region private members + + private Window mWindow; + + private int mOuterMarginSize = 10; + private int mWindowRadius = 10; + + #endregion + + #region commands + + public ICommand MinimizeCommand { get; set; } + + public ICommand MaximizeCommand { get; set; } + + public ICommand CloseCommand { get; set; } + + public ICommand MenuCommand { get; set; } + + #endregion + + #region public properties public Info InfoModel { get; set; } public ObservableObject SelectedViewModel { get; set; } + public Client client { get; } - public MainWindowViewModel(Client client) + /// + /// size of the resize border around the window + /// + + public double MinimumWidth { get; set; } = 250; + + public double MinimumHeight { get; set; } = 250; + + + + public int ResizeBorder { get; set; } = 6; + + public Thickness ResizeBorderThickness { get { return new Thickness(ResizeBorder + OuterMarginSize); } } + + public Thickness InnerContentPadding { get { return new Thickness(ResizeBorder); } } + + + public Thickness OuterMarginThickness { get { return new Thickness(OuterMarginSize); } } + + public CornerRadius WindowCornerRadius { get { return new CornerRadius(WindowRadius); } } + + public int OuterMarginSize { + get + { + return mWindow.WindowState == WindowState.Maximized ? 0 : mOuterMarginSize; + } + set + { + mOuterMarginSize = value; + } + } + + public int WindowRadius + { + get + { + return mWindow.WindowState == WindowState.Maximized ? 0 : mWindowRadius; + } + set + { + mWindowRadius = value; + } + } + + public int TitleHeight { get; set; } = 42; + + public GridLength TitleHeightGridLength { get { return new GridLength(TitleHeight + ResizeBorder); } } + + #endregion + + public MainWindowViewModel(Window window, Client client) + { + this.mWindow = window; + + this.mWindow.StateChanged += (sender, e) => + { + OnPropertyChanged(nameof(ResizeBorderThickness)); + OnPropertyChanged(nameof(OuterMarginThickness)); + OnPropertyChanged(nameof(WindowCornerRadius)); + OnPropertyChanged(nameof(OuterMarginSize)); + OnPropertyChanged(nameof(WindowRadius)); + }; + this.InfoModel = new Info(); this.client = client; LoginViewModel loginViewModel = new LoginViewModel(this); SelectedViewModel = loginViewModel; this.client.SetLoginViewModel(loginViewModel); + + this.MinimizeCommand = new RelayCommand(() => this.mWindow.WindowState = WindowState.Minimized); + this.MaximizeCommand = new RelayCommand(() => this.mWindow.WindowState ^= WindowState.Maximized); + this.CloseCommand = new RelayCommand(() => this.mWindow.Close()); + this.MenuCommand = new RelayCommand(() => SystemCommands.ShowSystemMenu(this.mWindow, GetMousePosition())); + + var resizer = new WindowResizer(this.mWindow); + + this.mWindow.Closed += (sender, e) => this.client.Dispose(); } + + + #region helper + + private Point GetMousePosition() + { + Debug.WriteLine("getmousePosition called"); + var p = Mouse.GetPosition(this.mWindow); + return new Point(p.X + this.mWindow.Left, p.Y + this.mWindow.Top); + } + + #endregion } } diff --git a/DoctorApp/Views/MainWindow.xaml b/DoctorApp/Views/MainWindow.xaml index 5535982..024aa68 100644 --- a/DoctorApp/Views/MainWindow.xaml +++ b/DoctorApp/Views/MainWindow.xaml @@ -5,10 +5,113 @@ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:DoctorApp" mc:Ignorable="d" - Title="MainWindow" Height="450" Width="800" - WindowState="Maximized"> + Title="MainWindow" Height="450" Width="800"> + + + + + + + + - + diff --git a/DoctorApp/Views/MainWindow.xaml.cs b/DoctorApp/Views/MainWindow.xaml.cs index 19e287d..d38e5c1 100644 --- a/DoctorApp/Views/MainWindow.xaml.cs +++ b/DoctorApp/Views/MainWindow.xaml.cs @@ -26,7 +26,7 @@ namespace DoctorApp { Client client = new Client(); InitializeComponent(); - DataContext = new MainWindowViewModel(client); + DataContext = new MainWindowViewModel(this, client); } } } diff --git a/Hashing/Hashing.projitems b/Hashing/Hashing.projitems index 662f597..c169d90 100644 --- a/Hashing/Hashing.projitems +++ b/Hashing/Hashing.projitems @@ -11,6 +11,7 @@ + diff --git a/Hashing/MagicCode/WindowResizer.cs b/Hashing/MagicCode/WindowResizer.cs new file mode 100644 index 0000000..428ca40 --- /dev/null +++ b/Hashing/MagicCode/WindowResizer.cs @@ -0,0 +1,212 @@ +using System; +using System.Runtime.InteropServices; +using System.Windows; +using System.Windows.Interop; + +namespace Util.MagicCode +{ + /// + /// Fixes the issue with Windows of Style covering the taskbar + /// + public class WindowResizer + { + #region Private Members + + /// + /// The window to handle the resizing for + /// + private Window mWindow; + + #endregion + + #region Dll Imports + + [DllImport("user32.dll")] + [return: MarshalAs(UnmanagedType.Bool)] + static extern bool GetCursorPos(out POINT lpPoint); + + [DllImport("user32.dll")] + static extern bool GetMonitorInfo(IntPtr hMonitor, MONITORINFO lpmi); + + [DllImport("user32.dll", SetLastError = true)] + static extern IntPtr MonitorFromPoint(POINT pt, MonitorOptions dwFlags); + + #endregion + + #region Constructor + + /// + /// Default constructor + /// + /// The window to monitor and correctly maximize + /// The callback for the host to adjust the maximum available size if needed + public WindowResizer(Window window) + { + mWindow = window; + + // Listen out for source initialized to setup + mWindow.SourceInitialized += Window_SourceInitialized; + } + + #endregion + + #region Initialize + + /// + /// Initialize and hook into the windows message pump + /// + /// + /// + private void Window_SourceInitialized(object sender, System.EventArgs e) + { + // Get the handle of this window + var handle = (new WindowInteropHelper(mWindow)).Handle; + var handleSource = HwndSource.FromHwnd(handle); + + // If not found, end + if (handleSource == null) + return; + + // Hook into it's Windows messages + handleSource.AddHook(WindowProc); + } + + #endregion + + #region Windows Proc + + /// + /// Listens out for all windows messages for this window + /// + /// + /// + /// + /// + /// + /// + private IntPtr WindowProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) + { + switch (msg) + { + // Handle the GetMinMaxInfo of the Window + case 0x0024:/* WM_GETMINMAXINFO */ + WmGetMinMaxInfo(hwnd, lParam); + handled = true; + break; + } + + return (IntPtr)0; + } + + #endregion + + /// + /// Get the min/max window size for this window + /// Correctly accounting for the taskbar size and position + /// + /// + /// + private void WmGetMinMaxInfo(System.IntPtr hwnd, System.IntPtr lParam) + { + POINT lMousePosition; + GetCursorPos(out lMousePosition); + + IntPtr lPrimaryScreen = MonitorFromPoint(new POINT(0, 0), MonitorOptions.MONITOR_DEFAULTTOPRIMARY); + MONITORINFO lPrimaryScreenInfo = new MONITORINFO(); + if (GetMonitorInfo(lPrimaryScreen, lPrimaryScreenInfo) == false) + { + return; + } + + IntPtr lCurrentScreen = MonitorFromPoint(lMousePosition, MonitorOptions.MONITOR_DEFAULTTONEAREST); + + MINMAXINFO lMmi = (MINMAXINFO)Marshal.PtrToStructure(lParam, typeof(MINMAXINFO)); + + if (lPrimaryScreen.Equals(lCurrentScreen) == true) + { + lMmi.ptMaxPosition.X = lPrimaryScreenInfo.rcWork.Left; + lMmi.ptMaxPosition.Y = lPrimaryScreenInfo.rcWork.Top; + lMmi.ptMaxSize.X = lPrimaryScreenInfo.rcWork.Right - lPrimaryScreenInfo.rcWork.Left; + lMmi.ptMaxSize.Y = lPrimaryScreenInfo.rcWork.Bottom - lPrimaryScreenInfo.rcWork.Top; + } + else + { + lMmi.ptMaxPosition.X = lPrimaryScreenInfo.rcMonitor.Left; + lMmi.ptMaxPosition.Y = lPrimaryScreenInfo.rcMonitor.Top; + lMmi.ptMaxSize.X = lPrimaryScreenInfo.rcMonitor.Right - lPrimaryScreenInfo.rcMonitor.Left; + lMmi.ptMaxSize.Y = lPrimaryScreenInfo.rcMonitor.Bottom - lPrimaryScreenInfo.rcMonitor.Top; + } + + // Now we have the max size, allow the host to tweak as needed + Marshal.StructureToPtr(lMmi, lParam, true); + } + } + + #region Dll Helper Structures + + enum MonitorOptions : uint + { + MONITOR_DEFAULTTONULL = 0x00000000, + MONITOR_DEFAULTTOPRIMARY = 0x00000001, + MONITOR_DEFAULTTONEAREST = 0x00000002 + } + + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] + public class MONITORINFO + { + public int cbSize = Marshal.SizeOf(typeof(MONITORINFO)); + public Rectangle rcMonitor = new Rectangle(); + public Rectangle rcWork = new Rectangle(); + public int dwFlags = 0; + } + + + [StructLayout(LayoutKind.Sequential)] + public struct Rectangle + { + public int Left, Top, Right, Bottom; + + public Rectangle(int left, int top, int right, int bottom) + { + this.Left = left; + this.Top = top; + this.Right = right; + this.Bottom = bottom; + } + } + + [StructLayout(LayoutKind.Sequential)] + public struct MINMAXINFO + { + public POINT ptReserved; + public POINT ptMaxSize; + public POINT ptMaxPosition; + public POINT ptMinTrackSize; + public POINT ptMaxTrackSize; + }; + + [StructLayout(LayoutKind.Sequential)] + public struct POINT + { + /// + /// x coordinate of point. + /// + public int X; + /// + /// y coordinate of point. + /// + public int Y; + + /// + /// Construct a point of coordinates (x,y). + /// + public POINT(int x, int y) + { + this.X = x; + this.Y = y; + } + } + + #endregion +} \ No newline at end of file