using Microsoft.Win32; using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Text; using System.Threading.Tasks; using System.Timers; using System.Windows; using System.Windows.Controls; using System.Windows.Controls.Primitives; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; using System.Windows.Threading; namespace SketchAssistantWPF { /// <summary> /// Interaction logic for MainWindow.xaml /// </summary> public partial class MainWindow : Window, MVP_View { public MainWindow() { InitializeComponent(); ProgramPresenter = new MVP_Presenter(this); // DispatcherTimer setup dispatcherTimer = new DispatcherTimer(DispatcherPriority.Render); dispatcherTimer.Tick += new EventHandler(dispatcherTimer_Tick); dispatcherTimer.Interval = new TimeSpan(0, 0, 0, 0, 5); ProgramPresenter.Resize(new Tuple<int, int>((int)LeftCanvas.Width, (int)LeftCanvas.Height), new Tuple<int, int>((int)RightCanvas.Width, (int)RightCanvas.Height)); } public enum ButtonState { Enabled, Disabled, Active } DispatcherTimer dispatcherTimer; /// <summary> /// Dialog to select a file. /// </summary> OpenFileDialog openFileDialog = new OpenFileDialog(); /// <summary> /// All Lines in the current session /// </summary> List<Tuple<bool, InternalLine>> rightLineList = new List<Tuple<bool, InternalLine>>(); /// <summary> /// Queue for the cursorPositions /// </summary> Queue<Point> cursorPositions = new Queue<Point>(); /// <summary> /// The Presenter Component of the MVP-Model /// </summary> MVP_Presenter ProgramPresenter; /// <summary> /// The line currently being drawn /// </summary> Polyline currentLine; /********************************************/ /*** WINDOW SPECIFIC FUNCTIONS START HERE ***/ /********************************************/ /// <summary> /// Resize Function connected to the form resize event, will refresh the form when it is resized /// </summary> private void Window_SizeChanged(object sender, SizeChangedEventArgs e) { ProgramPresenter.Resize(new Tuple<int, int>((int)LeftCanvas.ActualWidth, (int)LeftCanvas.ActualHeight), new Tuple<int, int>((int)RightCanvas.ActualWidth, (int)RightCanvas.ActualHeight)); } /// <summary> /// Redo an Action. /// </summary> private void RedoButton_Click(object sender, RoutedEventArgs e) { ProgramPresenter.Redo(); } /// <summary> /// Undo an Action. /// </summary> private void UndoButton_Click(object sender, RoutedEventArgs e) { ProgramPresenter.Undo(); } /// <summary> /// Changes the state of the program to deletion /// </summary> private void DeleteButton_Click(object sender, RoutedEventArgs e) { ProgramPresenter.ChangeState(false); } /// <summary> /// Changes the state of the program to drawing /// </summary> private void DrawButton_Click(object sender, RoutedEventArgs e) { ProgramPresenter.ChangeState(true); } /// <summary> /// Hold left mouse button to start drawing. /// </summary> private void RightCanvas_MouseDown(object sender, MouseButtonEventArgs e) { ProgramPresenter.MouseEvent(MVP_Presenter.MouseAction.Down); } /// <summary> /// Lift left mouse button to stop drawing and add a new Line. /// </summary> private void RightCanvas_MouseUp(object sender, MouseButtonEventArgs e) { ProgramPresenter.MouseEvent(MVP_Presenter.MouseAction.Up); } /// <summary> /// If the mouse leaves the canvas, it is treated as if the mouse was released. /// </summary> private void RightCanvas_MouseLeave(object sender, MouseEventArgs e) { ProgramPresenter.MouseEvent(MVP_Presenter.MouseAction.Up); } /// <summary> /// Get current Mouse positon within the right picture box. /// </summary> private void RightCanvas_MouseMove(object sender, MouseEventArgs e) { ProgramPresenter.MouseEvent(MVP_Presenter.MouseAction.Move, e.GetPosition(RightCanvas)); } /// <summary> /// Button to create a new Canvas. Will create an empty image /// which is the size of the left image, if there is one. /// If there is no image loaded the canvas will be the size of the right picture box /// </summary> private void CanvasButton_Click(object sender, RoutedEventArgs e) { ProgramPresenter.NewCanvas(); } /// <summary> /// Ticks the Presenter. /// </summary> private void dispatcherTimer_Tick(object sender, EventArgs e) { ProgramPresenter.Tick(); } /// <summary> /// Import button, will open an OpenFileDialog /// </summary> private void MenuItem_Click(object sender, RoutedEventArgs e) { ProgramPresenter.ExamplePictureToolStripMenuItemClick(); } /*************************/ /*** PRESENTER -> VIEW ***/ /*************************/ /// <summary> /// Remove the current line. /// </summary> public void RemoveCurrLine() { RightCanvas.Children.Remove(currentLine); } /// <summary> /// Display the current line. /// </summary> /// <param name="line">The current line to display</param> public void DisplayCurrLine(Polyline line) { if (RightCanvas.Children.Contains(currentLine)) { RemoveCurrLine(); } RightCanvas.Children.Add(line); currentLine = line; } /// <summary> /// Removes all Lines from the left canvas. /// </summary> public void RemoveAllLeftLines() { LeftCanvas.Children.Clear(); } /// <summary> /// Removes all lines in the right canvas. /// </summary> public void RemoveAllRightLines() { RightCanvas.Children.Clear(); } /// <summary> /// Adds another Line that will be displayed in the left display. /// </summary> /// <param name="newLine">The new Polyline to be added displayed.</param> public void AddNewLineLeft(Polyline newLine) { newLine.Stroke = Brushes.Black; newLine.StrokeThickness = 2; LeftCanvas.Children.Add(newLine); } /// <summary> /// Adds another Line that will be displayed in the right display. /// </summary> /// <param name="newLine">The new Polyline to be added displayed.</param> public void AddNewLineRight(Polyline newLine) { newLine.Stroke = Brushes.Black; newLine.StrokeThickness = 2; RightCanvas.Children.Add(newLine); } /// <summary> /// Enables the timer of the View, which will tick the Presenter. /// </summary> public void EnableTimer() { dispatcherTimer.Start(); } /// <summary> /// A function that opens a file dialog and returns the filename. /// </summary> /// <param name="Filter">The filter that should be applied to the new Dialog.</param> /// <returns>Returns the FileName and the SafeFileName if the user correctly selects a file, /// else returns a tuple with empty strigns</returns> public Tuple<string, string> openNewDialog(string Filter) { openFileDialog.Filter = Filter; if (openFileDialog.ShowDialog() == true) { return new Tuple<string, string>(openFileDialog.FileName, openFileDialog.SafeFileName); } else { return new Tuple<string, string>("", ""); } } /// <summary> /// Sets the contents of the last action taken indicator label. /// </summary> /// <param name="message">The new contents</param> public void SetLastActionTakenText(string message) { LastActionBox.Text = message; } /// <summary> /// Changes the states of a tool strip button. /// </summary> /// <param name="buttonName">The name of the button.</param> /// <param name="state">The new state of the button.</param> public void SetToolStripButtonStatus(string buttonName, MainWindow.ButtonState state) { ButtonBase buttonToChange; bool isToggleable = false; switch (buttonName) { case "canvasButton": buttonToChange = CanvasButton; break; case "drawButton": buttonToChange = DrawButton; isToggleable = true; break; case "deleteButton": buttonToChange = DeleteButton; isToggleable = true; break; case "undoButton": buttonToChange = UndoButton; break; case "redoButton": buttonToChange = RedoButton; break; default: Console.WriteLine("Invalid Button was given to SetToolStripButton. \nMaybe you forgot to add a case?"); return; } if (isToggleable) { switch (state) { case ButtonState.Active: ((ToggleButton)buttonToChange).IsEnabled = true; ((ToggleButton)buttonToChange).IsChecked = true; ((ToggleButton)buttonToChange).Opacity = 1; ((ToggleButton)buttonToChange).Background = Brushes.SkyBlue; break; case ButtonState.Disabled: ((ToggleButton)buttonToChange).IsEnabled = false; ((ToggleButton)buttonToChange).IsChecked = false; ((ToggleButton)buttonToChange).Opacity = 0.5; ((ToggleButton)buttonToChange).Background = Brushes.LightGray; break; case ButtonState.Enabled: ((ToggleButton)buttonToChange).IsEnabled = true; ((ToggleButton)buttonToChange).IsChecked = false; ((ToggleButton)buttonToChange).Opacity = 1; ((ToggleButton)buttonToChange).Background = Brushes.LightGray; break; } } else { switch (state) { case ButtonState.Disabled: ((Button)buttonToChange).IsEnabled = false; ((Button)buttonToChange).Opacity = 0.5; break; default: ((Button)buttonToChange).IsEnabled = true; ((Button)buttonToChange).Opacity = 1; break; } } } /// <summary> /// Sets the contents of the load status indicator label. /// </summary> /// <param name="message">The new contents</param> public void SetToolStripLoadStatus(string message) { LoadStatusBox.Text = message; } /// <summary> /// shows the given info message in a popup and asks the user to aknowledge it /// </summary> /// <param name="message">the message to show</param> public void ShowInfoMessage(string message) { MessageBox.Show(message); } /// <summary> /// Shows a warning box with the given message (Yes/No Buttons)and returns true if the user aknowledges it. /// </summary> /// <param name="message">The message of the warning.</param> /// <returns>True if the user confirms (Yes), negative if he doesn't (No)</returns> public bool ShowWarning(string message) { MessageBoxResult result = MessageBox.Show(message, "Warning", MessageBoxButton.YesNo, MessageBoxImage.Warning); return (result.Equals(MessageBoxResult.Yes)); } /// <summary> /// Updates the colour of a canvas. /// </summary> /// <param name="canvasName">The name of the canvas to be updated.</param> /// <param name="active">Whether or not the canvas is active.</param> public void SetCanvasState(string canvasName, bool active) { Canvas canvas; switch (canvasName){ case ("LeftCanvas"): canvas = LeftCanvas; break; case ("RightCanvas"): canvas = RightCanvas; break; default: throw new InvalidOperationException("Unknown canvas name, Check that the canvas passed is either LeftCanvas or RightCanvas"); } if (active) { canvas.Background = Brushes.White; } else { canvas.Background = Brushes.SlateGray; } } } }