diff --git a/ClientApp/App.xaml b/ClientApp/App.xaml index 1400927..61cadcc 100644 --- a/ClientApp/App.xaml +++ b/ClientApp/App.xaml @@ -6,13 +6,25 @@ xmlns:views="clr-namespace:ClientApp.Views" StartupUri="Views/MainWindow.xaml"> - - - - - - - - + + + + + + + + + + + + + + + + + + + + diff --git a/ClientApp/ClientApp.csproj b/ClientApp/ClientApp.csproj index 7b0bcaf..d8da9bf 100644 --- a/ClientApp/ClientApp.csproj +++ b/ClientApp/ClientApp.csproj @@ -7,6 +7,28 @@ Images\Logo\icon1.ico + + + + + + + + + + Always + + + Always + + + Always + + + Always + + + @@ -19,6 +41,10 @@ + + + + \ No newline at end of file diff --git a/ClientApp/Images/gradient-geometric-shape-background_78532-374.jpg b/ClientApp/Images/CoolBackground.jpg similarity index 100% rename from ClientApp/Images/gradient-geometric-shape-background_78532-374.jpg rename to ClientApp/Images/CoolBackground.jpg diff --git a/ClientApp/Images/Logo/icon1.ico b/ClientApp/Images/Logo/icon1.ico index 95760d6..faa56b4 100644 Binary files a/ClientApp/Images/Logo/icon1.ico and b/ClientApp/Images/Logo/icon1.ico differ diff --git a/ClientApp/Images/Logo/icon1_small.ico b/ClientApp/Images/Logo/icon1_small.ico new file mode 100644 index 0000000..95760d6 Binary files /dev/null and b/ClientApp/Images/Logo/icon1_small.ico differ diff --git a/ClientApp/MagicCode/WindowResizer.cs b/ClientApp/MagicCode/WindowResizer.cs new file mode 100644 index 0000000..c997d89 --- /dev/null +++ b/ClientApp/MagicCode/WindowResizer.cs @@ -0,0 +1,212 @@ +using System; +using System.Runtime.InteropServices; +using System.Windows; +using System.Windows.Interop; + +namespace ClientApp.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 diff --git a/ClientApp/Styles/Buttons.xaml b/ClientApp/Styles/Buttons.xaml new file mode 100644 index 0000000..c951dd8 --- /dev/null +++ b/ClientApp/Styles/Buttons.xaml @@ -0,0 +1,65 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ClientApp/Styles/Colors.xaml b/ClientApp/Styles/Colors.xaml new file mode 100644 index 0000000..8e4f8ef --- /dev/null +++ b/ClientApp/Styles/Colors.xaml @@ -0,0 +1,25 @@ + + + #efefef + + + + #fafafa + + + #d7d7d7 + + + #686868 + + + #000 + + + #fff + + + + \ No newline at end of file diff --git a/ClientApp/Styles/Fonts.xaml b/ClientApp/Styles/Fonts.xaml new file mode 100644 index 0000000..b0e7544 --- /dev/null +++ b/ClientApp/Styles/Fonts.xaml @@ -0,0 +1,5 @@ + + + \ No newline at end of file diff --git a/ClientApp/Styles/Texts.xaml b/ClientApp/Styles/Texts.xaml new file mode 100644 index 0000000..4fdba93 --- /dev/null +++ b/ClientApp/Styles/Texts.xaml @@ -0,0 +1,11 @@ + + + + \ No newline at end of file diff --git a/ClientApp/Styles/Windows.xaml b/ClientApp/Styles/Windows.xaml new file mode 100644 index 0000000..b0e7544 --- /dev/null +++ b/ClientApp/Styles/Windows.xaml @@ -0,0 +1,5 @@ + + + \ No newline at end of file diff --git a/ClientApp/ViewModels/MainWindowViewModel.cs b/ClientApp/ViewModels/MainWindowViewModel.cs index 2061ccf..56b98c1 100644 --- a/ClientApp/ViewModels/MainWindowViewModel.cs +++ b/ClientApp/ViewModels/MainWindowViewModel.cs @@ -1,27 +1,135 @@ -using ClientApp.Models; +using ClientApp.MagicCode; +using ClientApp.Models; using ClientApp.Utils; +using GalaSoft.MvvmLight.Command; using System; using System.Collections.Generic; +using System.Diagnostics; using System.Text; using Util; +using System.Windows; +using System.Windows.Input; namespace ClientApp.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 TitleHeightGridLegth { 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); } + + #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/ClientApp/Views/LoginView.xaml b/ClientApp/Views/LoginView.xaml index 472674d..9266c85 100644 --- a/ClientApp/Views/LoginView.xaml +++ b/ClientApp/Views/LoginView.xaml @@ -6,11 +6,12 @@ xmlns:local="clr-namespace:ClientApp.Views" xmlns:viewModels="clr-namespace:ClientApp.ViewModels" mc:Ignorable="d" + ShowsNavigationUI="False" d:DesignHeight="450" d:DesignWidth="800"> - - + + + +