Browse Source

Started Userstory 19

Martin Edlund 5 years ago
parent
commit
ad6d6fb350

+ 0 - 11
SketchAssistant/SketchAssistant/FileImporter.cs

@@ -10,17 +10,6 @@ namespace SketchAssistant
 {
     public class FileImporter
     {
-
-        /// <summary>
-        /// pointer to the running instance of main program
-        /// </summary>
-        Form1 program;
-
-        public FileImporter(Form1 newProgram)
-        {
-            program = newProgram;
-        }
-
         /// <summary>
         /// parses a drawing consisting of line objects, given as a file in the application specific .isad format
         /// </summary>

+ 29 - 29
SketchAssistant/SketchAssistant/Form1.Designer.cs

@@ -43,13 +43,13 @@ namespace SketchAssistant
             this.canvasButton = new System.Windows.Forms.ToolStripButton();
             this.drawButton = new System.Windows.Forms.ToolStripButton();
             this.deleteButton = new System.Windows.Forms.ToolStripButton();
+            this.undoButton = new System.Windows.Forms.ToolStripButton();
+            this.redoButton = new System.Windows.Forms.ToolStripButton();
             this.statusStrip1 = new System.Windows.Forms.StatusStrip();
             this.toolStripLoadStatus = new System.Windows.Forms.ToolStripStatusLabel();
+            this.lastActionTakenLabel = new System.Windows.Forms.ToolStripStatusLabel();
             this.backgroundWorker2 = new System.ComponentModel.BackgroundWorker();
             this.mouseTimer = new System.Windows.Forms.Timer(this.components);
-            this.lastActionTakenLabel = new System.Windows.Forms.ToolStripStatusLabel();
-            this.undoButton = new System.Windows.Forms.ToolStripButton();
-            this.redoButton = new System.Windows.Forms.ToolStripButton();
             this.tableLayoutPanel1.SuspendLayout();
             ((System.ComponentModel.ISupportInitialize)(this.pictureBoxRight)).BeginInit();
             ((System.ComponentModel.ISupportInitialize)(this.pictureBoxLeft)).BeginInit();
@@ -126,7 +126,7 @@ namespace SketchAssistant
             // loadToolStripMenuItem
             // 
             this.loadToolStripMenuItem.Name = "loadToolStripMenuItem";
-            this.loadToolStripMenuItem.Size = new System.Drawing.Size(180, 22);
+            this.loadToolStripMenuItem.Size = new System.Drawing.Size(119, 22);
             this.loadToolStripMenuItem.Text = "Load...";
             this.loadToolStripMenuItem.Click += new System.EventHandler(this.loadToolStripMenuItem_Click);
             // 
@@ -135,13 +135,13 @@ namespace SketchAssistant
             this.importToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
             this.examplePictureToolStripMenuItem});
             this.importToolStripMenuItem.Name = "importToolStripMenuItem";
-            this.importToolStripMenuItem.Size = new System.Drawing.Size(180, 22);
+            this.importToolStripMenuItem.Size = new System.Drawing.Size(119, 22);
             this.importToolStripMenuItem.Text = "Import...";
             // 
             // examplePictureToolStripMenuItem
             // 
             this.examplePictureToolStripMenuItem.Name = "examplePictureToolStripMenuItem";
-            this.examplePictureToolStripMenuItem.Size = new System.Drawing.Size(180, 22);
+            this.examplePictureToolStripMenuItem.Size = new System.Drawing.Size(158, 22);
             this.examplePictureToolStripMenuItem.Text = "Example picture";
             this.examplePictureToolStripMenuItem.Click += new System.EventHandler(this.examplePictureToolStripMenuItem_Click);
             // 
@@ -189,6 +189,26 @@ namespace SketchAssistant
             this.deleteButton.Text = "Delete";
             this.deleteButton.Click += new System.EventHandler(this.deleteButton_Click);
             // 
+            // undoButton
+            // 
+            this.undoButton.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Text;
+            this.undoButton.Image = ((System.Drawing.Image)(resources.GetObject("undoButton.Image")));
+            this.undoButton.ImageTransparentColor = System.Drawing.Color.Magenta;
+            this.undoButton.Name = "undoButton";
+            this.undoButton.Size = new System.Drawing.Size(40, 22);
+            this.undoButton.Text = "Undo";
+            this.undoButton.Click += new System.EventHandler(this.undoButton_Click);
+            // 
+            // redoButton
+            // 
+            this.redoButton.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Text;
+            this.redoButton.Image = ((System.Drawing.Image)(resources.GetObject("redoButton.Image")));
+            this.redoButton.ImageTransparentColor = System.Drawing.Color.Magenta;
+            this.redoButton.Name = "redoButton";
+            this.redoButton.Size = new System.Drawing.Size(38, 22);
+            this.redoButton.Text = "Redo";
+            this.redoButton.Click += new System.EventHandler(this.redoButton_Click);
+            // 
             // statusStrip1
             // 
             this.statusStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
@@ -206,11 +226,6 @@ namespace SketchAssistant
             this.toolStripLoadStatus.Size = new System.Drawing.Size(40, 19);
             this.toolStripLoadStatus.Text = "no file";
             // 
-            // mouseTimer
-            // 
-            this.mouseTimer.Interval = 1;
-            this.mouseTimer.Tick += new System.EventHandler(this.mouseTimer_Tick);
-            // 
             // lastActionTakenLabel
             // 
             this.lastActionTakenLabel.BorderSides = System.Windows.Forms.ToolStripStatusLabelBorderSides.Left;
@@ -219,25 +234,10 @@ namespace SketchAssistant
             this.lastActionTakenLabel.Text = "none";
             this.lastActionTakenLabel.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
             // 
-            // undoButton
-            // 
-            this.undoButton.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Text;
-            this.undoButton.Image = ((System.Drawing.Image)(resources.GetObject("undoButton.Image")));
-            this.undoButton.ImageTransparentColor = System.Drawing.Color.Magenta;
-            this.undoButton.Name = "undoButton";
-            this.undoButton.Size = new System.Drawing.Size(40, 22);
-            this.undoButton.Text = "Undo";
-            this.undoButton.Click += new System.EventHandler(this.undoButton_Click);
-            // 
-            // redoButton
+            // mouseTimer
             // 
-            this.redoButton.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Text;
-            this.redoButton.Image = ((System.Drawing.Image)(resources.GetObject("redoButton.Image")));
-            this.redoButton.ImageTransparentColor = System.Drawing.Color.Magenta;
-            this.redoButton.Name = "redoButton";
-            this.redoButton.Size = new System.Drawing.Size(38, 22);
-            this.redoButton.Text = "Redo";
-            this.redoButton.Click += new System.EventHandler(this.redoButton_Click);
+            this.mouseTimer.Interval = 1;
+            this.mouseTimer.Tick += new System.EventHandler(this.mouseTimer_Tick);
             // 
             // Form1
             // 

+ 109 - 11
SketchAssistant/SketchAssistant/Form1.cs

@@ -20,6 +20,7 @@ namespace SketchAssistant
         public Form1()
         {
             InitializeComponent();
+            ProgramPresenter = new MVP_Presenter(this);
             fileImporter = new FileImporter(this);
         }
 
@@ -29,6 +30,13 @@ namespace SketchAssistant
 
         //important: add new variables only at the end of the list to keep the order of definition consistent with the order in which they are returned by GetAllVariables()
 
+        public enum ButtonState
+        {
+            Enabled,
+            Disabled,
+            Active
+        }
+
         /// <summary>
         /// Different Program States
         /// </summary>
@@ -118,6 +126,10 @@ namespace SketchAssistant
         /// Size of areas marking endpoints of lines in the redraw mode.
         /// </summary>
         int markerRadius = 10;
+        /// <summary>
+        /// The Presenter Component of the MVP-Model
+        /// </summary>
+        MVP_Presenter ProgramPresenter;
 
         /******************************************/
         /*** FORM SPECIFIC FUNCTIONS START HERE ***/
@@ -137,6 +149,9 @@ namespace SketchAssistant
         /// </summary>
         private void Form1_Resize(object sender, System.EventArgs e)
         {
+            ProgramPresenter.Resize(new Tuple<int, int>(pictureBoxLeft.Width, pictureBoxLeft.Height), 
+                new Tuple<int, int>(pictureBoxRight.Width, pictureBoxRight.Height));
+            ///
             this.Refresh();
             UpdateSizes();
         }
@@ -144,6 +159,8 @@ namespace SketchAssistant
         //Load button, will open an OpenFileDialog
         private void loadToolStripMenuItem_Click(object sender, EventArgs e)
         {
+            ProgramPresenter.LoadToolStripMenuItemClick();
+            ///
             openFileDialog.Filter = "Image|*.jpg;*.png;*.jpeg";
             if(openFileDialog.ShowDialog() == DialogResult.OK)
             {
@@ -161,6 +178,8 @@ namespace SketchAssistant
         /// </summary>
         private void examplePictureToolStripMenuItem_Click(object sender, EventArgs e)
         {
+            ProgramPresenter.ExamplePictureToolStripMenuItemClick();
+            ///
             if (CheckSavedStatus())
             {
                 openFileDialog.Filter = "Interactive Sketch-Assistant Drawing|*.isad";
@@ -200,6 +219,8 @@ namespace SketchAssistant
         /// </summary>
         private void drawButton_Click(object sender, EventArgs e)
         {
+            ProgramPresenter.ChangeState(true);
+            ///
             if(rightImage != null)
             {
                 if (currentState.Equals(ProgramState.Draw))
@@ -219,6 +240,8 @@ namespace SketchAssistant
         /// </summary>
         private void deleteButton_Click(object sender, EventArgs e)
         {
+            ProgramPresenter.ChangeState(false);
+            ///
             if (rightImage != null)
             {
                 if (currentState.Equals(ProgramState.Delete))
@@ -238,6 +261,8 @@ namespace SketchAssistant
         /// </summary>
         private void undoButton_Click(object sender, EventArgs e)
         {
+            ProgramPresenter.Undo();
+            ///
             if (historyOfActions.CanUndo())
             {
                 HashSet<int> affectedLines = historyOfActions.GetCurrentAction().GetLineIDs();
@@ -267,6 +292,8 @@ namespace SketchAssistant
         /// </summary>
         private void redoButton_Click(object sender, EventArgs e)
         {
+            ProgramPresenter.Redo();
+            ///
             if (historyOfActions.CanRedo())
             {
                 historyOfActions.MoveAction(false);
@@ -298,11 +325,11 @@ namespace SketchAssistant
         {
             if (e.Modifiers == Keys.Control && e.KeyCode == Keys.Z)
             {
-                undoButton_Click(sender, e);
+                ProgramPresenter.Undo();
             }
             if (e.Modifiers == Keys.Control && e.KeyCode == Keys.Y)
             {
-                redoButton_Click(sender, e);
+                ProgramPresenter.Redo();
             }
         }
 
@@ -311,6 +338,8 @@ namespace SketchAssistant
         /// </summary>
         private void pictureBoxRight_MouseMove(object sender, MouseEventArgs e)
         {
+            ProgramPresenter.MouseEvent(MVP_Presenter.MouseAction.Move, e);
+            ///
             currentCursorPosition = ConvertCoordinates(new Point(e.X, e.Y));
         }
         
@@ -319,6 +348,8 @@ namespace SketchAssistant
         /// </summary>
         private void pictureBoxRight_MouseDown(object sender, MouseEventArgs e)
         {
+            ProgramPresenter.MouseEvent(MVP_Presenter.MouseAction.Down, e);
+            ///
             mousePressed = true;
             if (currentState.Equals(ProgramState.Draw))
             {
@@ -331,6 +362,8 @@ namespace SketchAssistant
         /// </summary>
         private void pictureBoxRight_MouseUp(object sender, MouseEventArgs e)
         {
+            ProgramPresenter.MouseEvent(MVP_Presenter.MouseAction.Up, e);
+            ///
             mousePressed = false;
             if (currentState.Equals(ProgramState.Draw) && currentLine.Count > 0)
             {
@@ -352,6 +385,8 @@ namespace SketchAssistant
         /// </summary>
         private void canvasButton_Click(object sender, EventArgs e)
         {
+            ProgramPresenter.NewCanvas();
+            ///
             if (CheckSavedStatus())
             {
                 historyOfActions = new ActionHistory(lastActionTakenLabel);
@@ -379,6 +414,8 @@ namespace SketchAssistant
         /// </summary>
         private void mouseTimer_Tick(object sender, EventArgs e)
         {
+            ProgramPresenter.Tick();
+            ///
             if(cursorPositions.Count > 0) { previousCursorPosition = cursorPositions.Dequeue(); }
             else { previousCursorPosition = currentCursorPosition; }
             cursorPositions.Enqueue(currentCursorPosition);
@@ -693,15 +730,6 @@ namespace SketchAssistant
                 l.DrawLine(Graphics.FromImage(leftImage));
             }
         }
-
-        /// <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>
-        private void ShowInfoMessage(String message)
-        {
-            MessageBox.Show(message);
-        }
         
         /// <summary>
         /// Will calculate the start and endpoints of the given line on the right canvas.
@@ -762,6 +790,76 @@ namespace SketchAssistant
             return true;
         }
 
+        /************************************************/
+        /*** FUNCTIONS FOR MANIPULATING THE FORM HERE ***/
+        /************************************************/
+
+        public void SetToolStripLoadStatus(String message)
+        {
+            toolStripLoadStatus.Text = message;
+        }
+
+        public void SetToolStripButtonStatus(String buttonName, ButtonState state)
+        {
+            ToolStripButton buttonToChange;
+            switch (buttonName)
+            {
+                case "canvasButton":
+                    buttonToChange = canvasButton;
+                    break;
+                case "drawButton":
+                    buttonToChange = drawButton;
+                    break;
+                case "deleteButton":
+                    buttonToChange = deleteButton;
+                    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;
+            }
+            switch (state)
+            {
+                case ButtonState.Active:
+                    buttonToChange.Checked = true;
+                    break;
+                case ButtonState.Disabled:
+                    buttonToChange.Checked = false;
+                    buttonToChange.Enabled = false;
+                    break;
+                case ButtonState.Enabled:
+                    buttonToChange.Checked = false;
+                    buttonToChange.Enabled = true;
+                    break;
+            }
+        }
+
+        public void DisplayInLeftPictureBox(Image img)
+        {
+            pictureBoxLeft.Image = img;
+            this.Refresh();
+        }
+
+        public void DisplayInRightPictureBox(Image img)
+        {
+            pictureBoxRight.Image = img;
+            this.Refresh();
+        }
+
+        /// <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);
+        }
+
         /********************************************/
         /*** TESTING RELATED FUNCTIONS START HERE ***/
         /********************************************/

+ 9 - 9
SketchAssistant/SketchAssistant/Form1.resx

@@ -172,15 +172,6 @@
         TgDQASA1MVpwzwAAAABJRU5ErkJggg==
 </value>
   </data>
-  <metadata name="statusStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
-    <value>506, 17</value>
-  </metadata>
-  <metadata name="backgroundWorker2.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
-    <value>622, 17</value>
-  </metadata>
-  <metadata name="mouseTimer.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
-    <value>786, 17</value>
-  </metadata>
   <data name="undoButton.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
     <value>
         iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
@@ -211,6 +202,15 @@
         TgDQASA1MVpwzwAAAABJRU5ErkJggg==
 </value>
   </data>
+  <metadata name="statusStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
+    <value>506, 17</value>
+  </metadata>
+  <metadata name="backgroundWorker2.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
+    <value>622, 17</value>
+  </metadata>
+  <metadata name="mouseTimer.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
+    <value>786, 17</value>
+  </metadata>
   <metadata name="$this.TrayHeight" type="System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
     <value>47</value>
   </metadata>

+ 412 - 0
SketchAssistant/SketchAssistant/MVP_Model.cs

@@ -0,0 +1,412 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Drawing;
+
+namespace SketchAssistant
+{
+    public class MVP_Model
+    {
+        /// <summary>
+        /// The Presenter of the MVP-Model.
+        /// </summary>
+        MVP_Presenter programPresenter;
+        /// <summary>
+        /// History of Actions
+        /// </summary>
+        ActionHistory historyOfActions;
+        /// <summary>
+        /// The assistant responsible for the redraw mode
+        /// </summary>
+        RedrawAssistant redrawAss;
+
+        /*******************/
+        /*** ENUMERATORS ***/
+        /*******************/
+
+        /***********************/
+        /*** CLASS VARIABLES ***/
+        /***********************/
+
+        bool inDrawingMode;
+
+        bool mousePressed;
+        /// <summary>
+        /// Size of deletion area
+        /// </summary>
+        int deletionRadius = 5;
+        /// <summary>
+        /// Size of areas marking endpoints of lines in the redraw mode.
+        /// </summary>
+        int markerRadius = 10;
+        /// <summary>
+        /// The Position of the Cursor in the right picture box
+        /// </summary>
+        Point currentCursorPosition;
+        /// <summary>
+        /// The Previous Cursor Position in the right picture box
+        /// </summary>
+        Point previousCursorPosition;
+        /// <summary>
+        /// Queue for the cursorPositions
+        /// </summary>
+        Queue<Point> cursorPositions = new Queue<Point>();
+        /// <summary>
+        /// Lookup Matrix for checking postions of lines in the image
+        /// </summary>
+        bool[,] isFilledMatrix;
+        /// <summary>
+        /// Lookup Matrix for getting line ids at a certain postions of the image
+        /// </summary>
+        HashSet<int>[,] linesMatrix;
+        /// <summary>
+        /// List of items which will be overlayed over the right canvas.
+        /// </summary>
+        List<Tuple<bool, HashSet<Point>>> overlayItems;
+        /// <summary>
+        /// Width of the LeftImageBox.
+        /// </summary>
+        public int leftImageBoxWidth;
+        /// <summary>
+        /// Height of the LeftImageBox.
+        /// </summary>
+        public int leftImageBoxHeight;
+        /// <summary>
+        /// Width of the RightImageBox.
+        /// </summary>
+        public int rightImageBoxWidth;
+        /// <summary>
+        /// Height of the RightImageBox.
+        /// </summary>
+        public int rightImageBoxHeight;
+
+        //Images
+        Image leftImage;
+
+        List<Line> leftLineList;
+
+        Image rightImageWithoutOverlay;
+
+        Image rightImageWithOverlay;
+
+        List<Tuple<bool, Line>> rightLineList;
+
+        List<Point> currentLine;
+
+
+
+        public MVP_Model(MVP_Presenter presenter)
+        {
+            programPresenter = presenter;
+            historyOfActions = new ActionHistory(null);
+            redrawAss = new RedrawAssistant();
+        }
+        
+        public void Undo()
+        {
+
+        }
+
+        /// <summary>
+        /// A function that returns a white canvas for a given width and height.
+        /// </summary>
+        /// <param name="width">The width of the canvas in pixels</param>
+        /// <param name="height">The height of the canvas in pixels</param>
+        /// <returns>The new canvas</returns>
+        private Image GetEmptyCanvas(int width, int height)
+        {
+            Image image;
+            try
+            {
+                image = new Bitmap(width, height);
+            }
+            catch (ArgumentException e)
+            {
+                programPresenter.PassMessageToView("The requested canvas size caused an error: \n" 
+                    + e.ToString() + "\n The Canvas will be set to match your window.");
+                image = new Bitmap(leftImageBoxWidth, leftImageBoxHeight);
+            }
+            Graphics graph = Graphics.FromImage(image);
+            graph.FillRectangle(Brushes.White, 0, 0, width + 10, height + 10);
+            return image;
+        }
+        
+        /// <summary>
+        /// Creates an empty Canvas
+        /// </summary>
+        private void DrawEmptyCanvasRight()
+        {
+            if (leftImage == null)
+            {
+                rightImageWithoutOverlay = GetEmptyCanvas(leftImageBoxWidth, leftImageBoxHeight);
+            }
+            else
+            {
+                rightImageWithoutOverlay = GetEmptyCanvas(leftImage.Width, leftImage.Height);
+            }
+            RefreshRightImage();
+        }
+
+        /// <summary>
+        /// Creates an empty Canvas on the left
+        /// </summary>
+        /// <param name="width"> width of the new canvas in pixels </param>
+        /// <param name="height"> height of the new canvas in pixels </param>
+        private void DrawEmptyCanvasLeft(int width, int height)
+        {
+            if (width == 0)
+            {
+                leftImage = GetEmptyCanvas(leftImageBoxWidth, leftImageBoxHeight);
+            }
+            else
+            {
+                leftImage = GetEmptyCanvas(width, height);
+            }
+            RefreshLeftImage();
+        }
+
+        /// <summary>
+        /// A function to refresh the image being displayed in the right picture box, with the current rightImageWithOverlay.
+        /// </summary>
+        /// <param name="image">The new Image</param>
+        private void RefreshRightImage()
+        {
+            programPresenter.UpdateRightImage(rightImageWithOverlay);
+        }
+
+        /// <summary>
+        /// A function to refresh the image being displayed in the left picture box, with the current leftImage.
+        /// </summary>
+        /// <param name="image">The new Image</param>
+        private void RefreshLeftImage()
+        {
+            programPresenter.UpdateLeftImage(leftImage);
+        }
+
+        /// <summary>
+        /// Redraws all lines in lineList, for which their associated boolean value equals true and calls RedrawRightOverlay.
+        /// </summary>
+        private void RedrawRightImage()
+        {
+            var workingCanvas = GetEmptyCanvas(rightImageWithoutOverlay.Width, rightImageWithoutOverlay.Height);
+            var workingGraph = Graphics.FromImage(workingCanvas);
+            //Lines
+            foreach (Tuple<bool, Line> lineBoolTuple in rightLineList)
+            {
+                if (lineBoolTuple.Item1)
+                {
+                    lineBoolTuple.Item2.DrawLine(workingGraph);
+                }
+            }
+            //The Line being currently drawn
+            if (currentLine != null && currentLine.Count > 0 && inDrawingMode && mousePressed)
+            {
+                var currLine = new Line(currentLine);
+                currLine.DrawLine(workingGraph);
+            }
+            rightImageWithoutOverlay = workingCanvas;
+            //Redraw the Overlay
+            RedrawRightOverlay();
+            RefreshRightImage();
+        }
+
+        /// <summary>
+        /// Redraws all elements in the overlay items for which the respective boolean value is true.
+        /// </summary>
+        private void RedrawRightOverlay()
+        {
+            var workingCanvas = rightImageWithoutOverlay;
+            var workingGraph = Graphics.FromImage(workingCanvas);
+            foreach (Tuple<bool, HashSet<Point>> tup in overlayItems)
+            {
+                if (tup.Item1)
+                {
+                    foreach (Point p in tup.Item2)
+                    {
+                        workingGraph.FillRectangle(Brushes.Green, p.X, p.Y, 1, 1);
+                    }
+                }
+            }
+            rightImageWithOverlay = workingCanvas;
+            RefreshRightImage();
+        }
+        
+        /// <summary>
+        /// The function called by the Presenter to change the drawing state of the program.
+        /// </summary>
+        /// <param name="nowDrawing">The new drawingstate of the program</param>
+        public void ChangeState(bool nowDrawing)
+        {
+            inDrawingMode = nowDrawing;
+            UpdateUI();
+        }
+        
+        /// <summary>
+        /// Change the status of whether or not the lines are shown.
+        /// </summary>
+        /// <param name="lines">The HashSet containing the affected Line IDs.</param>
+        /// <param name="shown">True if the lines should be shown, false if they should be hidden.</param>
+        private void ChangeLines(HashSet<int> lines, bool shown)
+        {
+            var changed = false;
+            foreach (int lineId in lines)
+            {
+                if (lineId <= rightLineList.Count - 1 && lineId >= 0)
+                {
+                    rightLineList[lineId] = new Tuple<bool, Line>(shown, rightLineList[lineId].Item2);
+                    changed = true;
+                }
+            }
+            if (changed) { RedrawRightImage(); }
+        }
+        
+        /// <summary>
+        /// A function that populates the matrixes needed for deletion detection with line data.
+        /// </summary>
+        private void RepopulateDeletionMatrixes()
+        {
+            if (rightImageWithoutOverlay != null)
+            {
+                isFilledMatrix = new bool[rightImageWithoutOverlay.Width, rightImageWithoutOverlay.Height];
+                linesMatrix = new HashSet<int>[rightImageWithoutOverlay.Width, rightImageWithoutOverlay.Height];
+                foreach (Tuple<bool, Line> lineTuple in rightLineList)
+                {
+                    if (lineTuple.Item1)
+                    {
+                        lineTuple.Item2.PopulateMatrixes(isFilledMatrix, linesMatrix);
+                    }
+                }
+            }
+        }
+        /*
+        /// <summary>
+        /// A function that checks the deletion matrixes at a certain point 
+        /// and returns all Line ids at that point and in a square around it in a certain range.
+        /// </summary>
+        /// <param name="p">The point around which to check.</param>
+        /// <param name="range">The range around the point. If range is 0, only the point is checked.</param>
+        /// <returns>A List of all lines.</returns>
+        private HashSet<int> CheckDeletionMatrixesAroundPoint(Point p, int range)
+        {
+            HashSet<int> returnSet = new HashSet<int>();
+
+            foreach (Point pnt in GeometryCalculator.FilledCircleAlgorithm(p, (int)range))
+            {
+                if (pnt.X >= 0 && pnt.Y >= 0 && pnt.X < rightImage.Width && pnt.Y < rightImage.Height)
+                {
+                    if (isFilledMatrix[pnt.X, pnt.Y])
+                    {
+                        returnSet.UnionWith(linesMatrix[pnt.X, pnt.Y]);
+                    }
+                }
+            }
+            return returnSet;
+        }
+
+        /// <summary>
+        /// binds the given picture to templatePicture and draws it
+        /// </summary>
+        /// <param name="newTemplatePicture"> the new template picture, represented as a list of polylines </param>
+        /// <returns></returns>
+        private void BindAndDrawLeftImage(List<Line> newTemplatePicture)
+        {
+            leftLineList = newTemplatePicture;
+            foreach (Line l in leftLineList)
+            {
+                l.DrawLine(Graphics.FromImage(leftImage));
+            }
+        }
+        
+        /// <summary>
+        /// Will calculate the start and endpoints of the given line on the right canvas.
+        /// </summary>
+        /// <param name="line">The line.</param>
+        /// <param name="size">The size of the circle with which the endpoints of the line are marked.</param>
+        private Tuple<HashSet<Point>, HashSet<Point>> CalculateStartAndEnd(Line line, int size)
+        {
+            var circle0 = GeometryCalculator.FilledCircleAlgorithm(line.GetStartPoint(), size);
+            var circle1 = GeometryCalculator.FilledCircleAlgorithm(line.GetEndPoint(), size);
+            var currentLineEndings = new Tuple<HashSet<Point>, HashSet<Point>>(circle0, circle1);
+            return currentLineEndings;
+        }
+        */
+        /// <summary>
+        /// A helper Function that updates the markerRadius & deletionRadius, considering the size of the canvas.
+        /// </summary>
+        public void UpdateSizes()
+        {
+            if (rightImageWithoutOverlay != null)
+            {
+                int widthImage = rightImageWithoutOverlay.Width;
+                int heightImage = rightImageWithoutOverlay.Height;
+                int widthBox = rightImageBoxWidth;
+                int heightBox = rightImageBoxHeight;
+
+                float imageRatio = (float)widthImage / (float)heightImage;
+                float containerRatio = (float)widthBox / (float)heightBox;
+                float zoomFactor = 0;
+                if (imageRatio >= containerRatio)
+                {
+                    //Image is wider than it is high
+                    zoomFactor = (float)widthImage / (float)widthBox;
+                }
+                else
+                {
+                    //Image is higher than it is wide
+                    zoomFactor = (float)heightImage / (float)heightBox;
+                }
+                markerRadius = (int)(10 * zoomFactor);
+                redrawAss.SetMarkerRadius(markerRadius);
+                deletionRadius = (int)(5 * zoomFactor);
+            }
+        }
+
+
+        /// <summary>
+        /// Tells the Presenter to Update the UI
+        /// </summary>
+        private void UpdateUI()
+        {
+            programPresenter.UpdateUIState(inDrawingMode, historyOfActions.CanUndo(), historyOfActions.CanRedo(), (rightImageWithoutOverlay != null));
+        }
+
+        /// <summary>
+        /// A method to get the dimensions of the right image.
+        /// </summary>
+        /// <returns>A tuple containing the width and height of the right image.</returns>
+        public Tuple<int, int> GetRightImageDimensions()
+        {
+            if(rightImageWithoutOverlay != null)
+            {
+                return new Tuple<int, int>(rightImageWithoutOverlay.Width, rightImageWithoutOverlay.Height);
+            }
+            else
+            {
+                return new Tuple<int, int>(0, 0);
+            }
+        }
+
+        public void SetCurrentCursorPosition(Point p)
+        {
+
+        }
+        /*
+        /// <summary>
+        /// Checks if there is unsaved progess, and warns the user. Returns True if it safe to continue.
+        /// </summary>
+        /// <returns>true if there is none, or the user wishes to continue without saving.
+        /// false if there is progress, and the user doesn't wish to continue.</returns>
+        private bool CheckSavedStatus()
+        {
+            if (!historyOfActions.IsEmpty())
+            {
+                return (MessageBox.Show("You have unsaved changes, do you wish to continue?",
+                    "Attention", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.Yes);
+            }
+            return true;
+        }
+        */
+    }
+}

+ 279 - 0
SketchAssistant/SketchAssistant/MVP_Presenter.cs

@@ -0,0 +1,279 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+using System.Drawing;
+
+namespace SketchAssistant
+{
+    public class MVP_Presenter
+    {
+        /// <summary>
+        /// The View of the MVP-Model, in this case Form1.
+        /// </summary>
+        Form1 programView;
+        /// <summary>
+        /// The Model of the MVP-Model.
+        /// </summary>
+        MVP_Model programModel;
+
+        /*******************/
+        /*** ENUMERATORS ***/
+        /*******************/
+
+        public enum MouseAction
+        {
+            Click,
+            Down,
+            Up,
+            Move
+        }
+
+        /***********************/
+        /*** CLASS VARIABLES ***/
+        /***********************/
+
+        /// <summary>
+        /// A dialog responsible for opening files.
+        /// </summary>
+        OpenFileDialog openFileDialog;
+        /// <summary>
+        /// Instance of FileImporter to handle drawing imports.
+        /// </summary>
+        private FileImporter fileImporter;
+
+
+        public MVP_Presenter(Form1 form)
+        {
+            programView = form;
+            programModel = new MVP_Model(this);
+            //Initialize Class Variables
+            openFileDialog = new OpenFileDialog();
+            fileImporter = new FileImporter();
+        }
+
+        /***********************************/
+        /*** FUNCTIONS VIEW -> PRESENTER ***/
+        /***********************************/
+
+        public void Resize(Tuple<int, int> leftPBS,Tuple<int, int> rightPBS)
+        {
+            programView.Refresh();
+            programModel.leftImageBoxWidth = leftPBS.Item1;
+            programModel.leftImageBoxHeight = leftPBS.Item2;
+            programModel.rightImageBoxWidth = rightPBS.Item1;
+            programModel.rightImageBoxHeight = rightPBS.Item2;
+            programModel.UpdateSizes();
+        }
+
+        /// <summary>
+        /// Display a new FileDialog to load an image.
+        /// </summary>
+        public void LoadToolStripMenuItemClick()
+        {
+            openFileDialog.Filter = "Image|*.jpg;*.png;*.jpeg";
+            if (openFileDialog.ShowDialog() == DialogResult.OK)
+            {
+                ProgramView.SetToolStripLoadStatus(openFileDialog.SafeFileName);
+                ProgramModel
+                leftImage = Image.FromFile(openFileDialog.FileName);
+                pictureBoxLeft.Image = leftImage;
+                //Refresh the left image box when the content is changed
+                this.Refresh();
+            }
+            UpdateButtonStatus();
+        }
+
+        /// <summary>
+        /// Display a new FileDialog to load a collection of lines.
+        /// </summary>
+        public void ExamplePictureToolStripMenuItemClick()
+        {
+            if (ProgramModel.CheckSavedStatus())
+            {
+                openFileDialog.Filter = "Interactive Sketch-Assistant Drawing|*.isad";
+                if (openFileDialog.ShowDialog() == DialogResult.OK)
+                {
+                    ProgramView.SetToolStripLoadStatus(openFileDialog.SafeFileName);
+                    try
+                    {
+                        (int, int, List<Line>) values = fileImporter.ParseISADInputFile(openFileDialog.FileName);
+                        DrawEmptyCanvasLeft(values.Item1, values.Item2);
+                        BindAndDrawLeftImage(values.Item3);
+
+                        //Match The right canvas to the left
+                        historyOfActions = new ActionHistory(lastActionTakenLabel);
+                        DrawEmptyCanvasRight();
+                        isFilledMatrix = new bool[rightImage.Width, rightImage.Height];
+                        linesMatrix = new HashSet<int>[rightImage.Width, rightImage.Height];
+                        rightLineList = new List<Tuple<bool, Line>>();
+                        //Start the redraw mode
+                        redrawAss = new RedrawAssistant(leftLineList);
+                        UpdateSizes();
+                        overlayItems = redrawAss.Tick(currentCursorPosition, rightLineList, -1, false);
+                        RedrawRightImage();
+                        this.Refresh();
+                    }
+                    catch (FileImporterException ex)
+                    {
+                        ShowInfoMessage(ex.ToString());
+                    }
+                }
+            }
+            UpdateButtonStatus();
+        }
+
+        public void ChangeState(bool NowDrawing)
+        {
+            programModel.ChangeState(NowDrawing);
+        }
+
+        public void Undo()
+        {
+
+        }
+
+        public void Redo()
+        {
+
+        }
+
+        public void NewCanvas()
+        {
+
+        }
+
+        public void Tick()
+        {
+
+        }
+
+        public void MouseEvent(MouseAction mouseAction, MouseEventArgs e)
+        {
+            switch (mouseAction)
+            {
+                case MouseAction.Click:
+                    break;
+                case MouseAction.Down:
+                    break;
+                case MouseAction.Up:
+                    break;
+                case MouseAction.Move:
+                    programModel.SetCurrentCursorPosition(ConvertCoordinates(new Point(e.X, e.Y)));
+                    break;
+            }
+        }
+
+        /************************************/
+        /*** FUNCTIONS MODEL -> PRESENTER ***/
+        /************************************/
+
+        /// <summary>
+        /// Called by the model when the state of the Program changes. 
+        /// Changes the look of the UI according to the current state of the model.
+        /// </summary>
+        /// <param name="inDrawingMode">If the model is in Drawing Mode</param>
+        /// <param name="canUndo">If actions in the model can be undone</param>
+        /// <param name="canRedo">If actions in the model can be redone</param>
+        /// <param name="imageLoaded">If an image is loaded in the model</param>
+        public void UpdateUIState(bool inDrawingMode, bool canUndo, bool canRedo, bool imageLoaded)
+        {
+            Dictionary<String, Form1.ButtonState> dict = new Dictionary<String, Form1.ButtonState> {
+                {"canvasButton", Form1.ButtonState.Disabled }, {"drawButton", Form1.ButtonState.Disabled}, {"deleteButton",Form1.ButtonState.Disabled }
+                {"undoButton", Form1.ButtonState.Disabled },{"redoButton",  Form1.ButtonState.Disabled}};
+
+            if (imageLoaded)
+            {
+                if (inDrawingMode)
+                {
+                    dict["drawButton"] = Form1.ButtonState.Active;
+                    dict["deleteButton"] = Form1.ButtonState.Enabled;
+                }
+                else
+                {
+                    dict["drawButton"] = Form1.ButtonState.Enabled;
+                    dict["deleteButton"] = Form1.ButtonState.Active;
+                }
+                if (canUndo){dict["undoButton"] = Form1.ButtonState.Enabled;}
+                if (canRedo){dict["redoButton"] = Form1.ButtonState.Enabled;}
+            }
+            foreach(KeyValuePair<String, Form1.ButtonState> entry in dict)
+            {
+                programView.SetToolStripButtonStatus(entry.Key, entry.Value);
+            }
+        }
+
+        /// <summary>
+        /// Is called by the model when the left image is changed.
+        /// </summary>
+        /// <param name="img">The new image.</param>
+        public void UpdateLeftImage(Image img)
+        {
+            programView.DisplayInLeftPictureBox(img);
+        }
+
+        /// <summary>
+        /// Is called by the model when the right image is changed.
+        /// </summary>
+        /// <param name="img">The new image.</param>
+        public void UpdateRightImage(Image img)
+        {
+            programView.DisplayInRightPictureBox(img);
+        }
+
+        public void PassMessageToView(String msg)
+        {
+            programView.ShowInfoMessage(msg);
+        }
+
+        /*************************/
+        /*** HELPING FUNCTIONS ***/
+        /*************************/
+
+        /// <summary>
+        /// A function that calculates the coordinates of a point on a zoomed in image.
+        /// </summary>
+        /// <param name="">The position of the mouse cursor</param>
+        /// <returns>The real coordinates of the mouse cursor on the image</returns>
+        private Point ConvertCoordinates(Point cursorPosition)
+        {
+            var rightImageDimensions = programModel.GetRightImageDimensions();
+            Point realCoordinates = new Point(0, 0);
+
+            int widthImage = rightImageDimensions.Item1;
+            int heightImage = rightImageDimensions.Item2;
+            int widthBox = programModel.rightImageBoxWidth;
+            int heightBox = programModel.rightImageBoxHeight;
+
+            if (heightImage == 0 && widthImage == 0)
+            {
+                return cursorPosition;
+            }
+
+            float imageRatio = (float)widthImage / (float)heightImage;
+            float containerRatio = (float)widthBox / (float)heightBox;
+
+            if (imageRatio >= containerRatio)
+            {
+                //Image is wider than it is high
+                float zoomFactor = (float)widthImage / (float)widthBox;
+                float scaledHeight = heightImage / zoomFactor;
+                float filler = (heightBox - scaledHeight) / 2;
+                realCoordinates.X = (int)(cursorPosition.X * zoomFactor);
+                realCoordinates.Y = (int)((cursorPosition.Y - filler) * zoomFactor);
+            }
+            else
+            {
+                //Image is higher than it is wide
+                float zoomFactor = (float)heightImage / (float)heightBox;
+                float scaledWidth = widthImage / zoomFactor;
+                float filler = (widthBox - scaledWidth) / 2;
+                realCoordinates.X = (int)((cursorPosition.X - filler) * zoomFactor);
+                realCoordinates.Y = (int)(cursorPosition.Y * zoomFactor);
+            }
+            return realCoordinates;
+        }
+    }
+}

+ 2 - 0
SketchAssistant/SketchAssistant/SketchAssistant.csproj

@@ -69,6 +69,8 @@
     <Reference Include="System.Xml" />
   </ItemGroup>
   <ItemGroup>
+    <Compile Include="MVP_Presenter.cs" />
+    <Compile Include="MVP_Model.cs" />
     <Compile Include="RedrawAssistant.cs" />
     <Compile Include="FileImporter.cs" />
     <Compile Include="FileImporterException.cs" />