Quellcode durchsuchen

Develop (#12)

* Userstory 13 & 17 (#8)

Finished Userstory 13 & 17

* Userstory19 (#9)
- Cleaned up code
- Split up Program into Model, View and Presenter
- Created MVP_View interface
- Removed unneccessary code

* Userstory16 (#11)

- Added Icons
- All previous features now work in WPF
- Added working UI-Tests
- Added debug mode
- Removed travis support
- Added AppVeyor support

* Hotfix + Cleaned up Project Folder
m-edlund vor 5 Jahren
Ursprung
Commit
60b2843da4
46 geänderte Dateien mit 2677 neuen und 2025 gelöschten Zeilen
  1. 8 0
      .appveyor.yml
  2. 0 6
      .travis.yml
  3. 13 0
      Finished Userstories/userstory12.md
  4. 13 0
      Finished Userstories/userstory13.md
  5. 13 0
      Finished Userstories/userstory17.md
  6. 13 0
      Finished Userstories/userstory19.md
  7. 0 373
      SketchAssistant/SketchAssistant.Tests/UnitTest1.cs
  8. 10 10
      SketchAssistant/SketchAssistant.sln
  9. 0 14
      SketchAssistant/SketchAssistant/App.config
  10. 0 299
      SketchAssistant/SketchAssistant/Form1.Designer.cs
  11. 0 623
      SketchAssistant/SketchAssistant/Form1.cs
  12. 0 217
      SketchAssistant/SketchAssistant/Form1.resx
  13. 0 266
      SketchAssistant/SketchAssistant/Line.cs
  14. 0 22
      SketchAssistant/SketchAssistant/Program.cs
  15. 0 36
      SketchAssistant/SketchAssistant/Properties/AssemblyInfo.cs
  16. 0 7
      SketchAssistant/SketchAssistant/Properties/Settings.settings
  17. 0 6
      SketchAssistant/SketchAssistant/packages.config
  18. 24 17
      SketchAssistant/SketchAssistantWPF/ActionHistory.cs
  19. 6 0
      SketchAssistant/SketchAssistantWPF/App.config
  20. 9 0
      SketchAssistant/SketchAssistantWPF/App.xaml
  21. 17 0
      SketchAssistant/SketchAssistantWPF/App.xaml.cs
  22. 18 0
      SketchAssistant/SketchAssistantWPF/CustomCanvas.cs
  23. 11 0
      SketchAssistant/SketchAssistantWPF/DebugData.cs
  24. 17 28
      SketchAssistant/SketchAssistantWPF/FileImporter.cs
  25. 3 3
      SketchAssistant/SketchAssistantWPF/FileImporterException.cs
  26. 209 0
      SketchAssistant/SketchAssistantWPF/GeometryCalculator.cs
  27. 27 0
      SketchAssistant/SketchAssistantWPF/ImageDimension.cs
  28. 172 0
      SketchAssistant/SketchAssistantWPF/InternalLine.cs
  29. 456 0
      SketchAssistant/SketchAssistantWPF/MVP_Model.cs
  30. 423 0
      SketchAssistant/SketchAssistantWPF/MVP_Presenter.cs
  31. 123 0
      SketchAssistant/SketchAssistantWPF/MVP_View.cs
  32. 193 0
      SketchAssistant/SketchAssistantWPF/MainWindow.xaml
  33. 570 0
      SketchAssistant/SketchAssistantWPF/MainWindow.xaml.cs
  34. 55 0
      SketchAssistant/SketchAssistantWPF/Properties/AssemblyInfo.cs
  35. 20 28
      SketchAssistant/SketchAssistantWPF/Properties/Resources.Designer.cs
  36. 10 7
      SketchAssistant/SketchAssistantWPF/Properties/Resources.resx
  37. 2 2
      SketchAssistant/SketchAssistantWPF/Properties/Settings.Designer.cs
  38. 7 0
      SketchAssistant/SketchAssistantWPF/Properties/Settings.settings
  39. 1 1
      SketchAssistant/SketchAssistantWPF/SketchAction.cs
  40. 56 42
      SketchAssistant/SketchAssistantWPF/SketchAssistantWPF.csproj
  41. 4 4
      SketchAssistant/WhiteTests/Properties/AssemblyInfo.cs
  42. 143 0
      SketchAssistant/WhiteTests/UITest.cs
  43. 14 11
      SketchAssistant/WhiteTests/WhiteTests.csproj
  44. 2 2
      SketchAssistant/WhiteTests/app.config
  45. 2 1
      SketchAssistant/WhiteTests/packages.config
  46. 13 0
      userstory16.md

+ 8 - 0
.appveyor.yml

@@ -0,0 +1,8 @@
+image:
+ - Visual Studio 2017
+ 
+install:
+ - "nuget install TestStack.White"
+ - "nuget install MSTest.TestAdapter"
+ - "nuget install MSTest.TestFramework"
+ - "nuget restore SketchAssistant/SketchAssistant.sln"

+ 0 - 6
.travis.yml

@@ -1,6 +0,0 @@
-language: csharp
-solution: "./SketchAssistant/SketchAssistant.sln"
-
-install:
-  - nuget restore "./SketchAssistant/SketchAssistant.sln"
-  - nuget install NUnit.ConsoleRunner -Version 3.9.0 -OutputDirectory testrunner

+ 13 - 0
Finished Userstories/userstory12.md

@@ -0,0 +1,13 @@
+# Userstory 12  
+ 
+|**ID**|12|  
+|-|-|
+|**Name**|Darstellen einer Zeichnung in der linken Picture Box|
+|**Beschreibung**|In der Linken picture box kann ein Bild angezeigt werden, was Line Elemente des Programms verwendet.|
+|**Akzeptanzkriterium**|Die Userstory ist akzeptiert, wenn das Programm ein Bild in bestehend aus den internen Line Elementen in der linken picture box darstellen kann.|
+|Geschätzter Aufwand (Story Points)|6|
+|Entwickler|Vincenz|
+|Umgesetzt in Iteration|3|
+|Tatsächlicher Aufwand (Std.)|8|
+|Velocity (Std./Story Point)|1.333|
+|Bemerkungen|Keine|

+ 13 - 0
Finished Userstories/userstory13.md

@@ -0,0 +1,13 @@
+# Userstory 13 
+ 
+|**ID**|13|  
+|-|-|
+|**Name**|Start und Endpunkt anzeigen|
+|**Beschreibung**|Beim Nachzeichnen kann der Start- & Endpunkt einer nachzuzeichnenden Linie angzeigt werden.|
+|**Akzeptanzkriterium**|Sofern auf der linken Seite eine nachzeichenbare Grafik dargestellt wird, kann der Start- und Endpunkt der ersten Linie der linken Grafik an der richtigen Stelle auf der rechten Seite angezeigt werden.|
+|Geschätzter Aufwand (Story Points)|2|
+|Entwickler|Martin|
+|Umgesetzt in Iteration|4|
+|Tatsächlicher Aufwand (Std.)|1|
+|Velocity (Std./Story Point)|0.5|
+|Bemerkungen|Keine|

+ 13 - 0
Finished Userstories/userstory17.md

@@ -0,0 +1,13 @@
+# Userstory 17  
+ 
+|**ID**|17|  
+|-|-|
+|**Name**|Nachzeichenmodus|
+|**Beschreibung**|Es gibt einen speziellen Modus zum Nachzeichnen von Bildern.|
+|**Akzeptanzkriterium**|Sobald ein Bild geladen wird, welches sich nachzeichenen lässt, wird der Nachzeichenmodus aktiviert. Ist der Nachzeichen Modus aktiviert, so werden Startpunkte für alle Linien auf der rechten Seite angezeigt. Fängt der Nutzer an einem Startpunkt an zu zeichnen, werden die anderen Startpunkte ausgeblendet und der Endpunkt der aktuellen Linie angezeigt. Zeichnet der Nutzer die Linie bis zum Endpunkt fertig, werden die verbleibenden Startpunkte angezeigt und der Nutzer kann eine neue Linie nachzeichnen. Wenn der Nutzer die Linie nicht zuende Zeichnet, muss sie von vorne begonnen werden.|
+|Geschätzter Aufwand (Story Points)|10|
+|Entwickler|Martin|
+|Umgesetzt in Iteration|4|
+|Tatsächlicher Aufwand (Std.)|11|
+|Velocity (Std./Story Point)|1.1|
+|Bemerkungen|Keine|

+ 13 - 0
Finished Userstories/userstory19.md

@@ -0,0 +1,13 @@
+# Userstory 19  
+ 
+|**ID**|19|  
+|-|-|
+|**Name**|Verbesserung der Struktur des Programms|
+|**Beschreibung**|Strukturierung des Programms zu einem Model-View-Controller Modell.|
+|**Akzeptanzkriterium**|Aufteilung der Form Datei in drei Klassen: Eine View Klasse, welche Aufgaben bezüglich Anzeigen im Form übernimmt. Eine Controller Klasse, welche Eingaben vom Form empfängt und verarbeitet. Sowie eine Model Klasse, welche den Status des Programms darstellt, und vom Controller manipuliert wird und selbst den View anpasst.|
+|Geschätzter Aufwand (Story Points)|20|
+|Entwickler|Martin Edlund|
+|Umgesetzt in Iteration|6|
+|Tatsächlicher Aufwand (Std.)|8,5|
+|Velocity (Std./Story Point)|0,425|
+|Bemerkungen|Keine|

+ 0 - 373
SketchAssistant/SketchAssistant.Tests/UnitTest1.cs

@@ -1,373 +0,0 @@
-using System;
-using Microsoft.VisualStudio.TestTools.UnitTesting;
-using System.Drawing;
-using System.Collections.Generic;
-using SketchAssistant;
-using System.Windows.Forms;
-
-namespace Tests
-{
-    [TestClass]
-    public class LineTests
-    {
-        //========================//
-        //= Bresenham Line Tests =//
-        //========================//
-
-        [TestMethod]
-        public void BresenhamLineTest1()
-        {
-            //Test point
-            List<Point> expectedResult = new List<Point>();
-            expectedResult.Add(new Point(1, 2));
-            List<Point> actualResult = SketchAssistant.Line.BresenhamLineAlgorithm(new Point(1, 2), new Point(1, 2));
-            Assert.AreEqual(1, actualResult.Count);
-            for (int i = 0; i < actualResult.Count; i++)
-            {
-                Assert.AreEqual(expectedResult[i], actualResult[i]);
-            }
-        }
-
-        [TestMethod]
-        public void BresenhamLineTest2()
-        {
-            //Test line going from left to right
-            List<Point> expectedResult = new List<Point>();
-            for (int i = 1; i <= 6; i++) { expectedResult.Add(new Point(i, 2)); }
-            List<Point> actualResult = SketchAssistant.Line.BresenhamLineAlgorithm(new Point(1, 2), new Point(6, 2));
-            Assert.AreEqual(expectedResult.Count, actualResult.Count);
-            for (int i = 0; i < actualResult.Count; i++)
-            {
-                Assert.AreEqual(expectedResult[i], actualResult[i]);
-            }
-        }
-
-        [TestMethod]
-        public void BresenhamLineTest3()
-        {
-            //Test line going from right to left
-            List<Point> expectedResult = new List<Point>();
-            for (int i = 6; i >= 1; i--) { expectedResult.Add(new Point(i, 2)); }
-            List<Point> actualResult = SketchAssistant.Line.BresenhamLineAlgorithm(new Point(6, 2), new Point(1, 2));
-            Assert.AreEqual(expectedResult.Count, actualResult.Count);
-            for (int i = 0; i < actualResult.Count; i++)
-            {
-                Assert.AreEqual(expectedResult[i], actualResult[i]);
-            }
-        }
-
-        [TestMethod]
-        public void BresenhamLineTest4()
-        {
-            //Test line going from top to bottom
-            List<Point> expectedResult = new List<Point>();
-            for (int i = 5; i <= 25; i++) { expectedResult.Add(new Point(7, i)); }
-            List<Point> actualResult = SketchAssistant.Line.BresenhamLineAlgorithm(new Point(7, 5), new Point(7, 25));
-            Assert.AreEqual(expectedResult.Count, actualResult.Count);
-            for (int i = 0; i < actualResult.Count; i++)
-            {
-                Assert.AreEqual(expectedResult[i], actualResult[i]);
-            }
-        }
-
-        [TestMethod]
-        public void BresenhamLineTest5()
-        {
-            //Test line going from bottom to top
-            List<Point> expectedResult = new List<Point>();
-            for (int i = 25; i >= 5; i--) { expectedResult.Add(new Point(7, i)); }
-            List<Point> actualResult = SketchAssistant.Line.BresenhamLineAlgorithm(new Point(7, 25), new Point(7, 5));
-            Assert.AreEqual(expectedResult.Count, actualResult.Count);
-            for (int i = 0; i < actualResult.Count; i++)
-            {
-                Assert.AreEqual(expectedResult[i], actualResult[i]);
-            }
-        }
-
-        [TestMethod]
-        public void BresenhamLineTest6()
-        {
-            //Test exactly diagonal line from top left to bottom right
-            List<Point> expectedResult = new List<Point>();
-            for (int i = 5; i <= 25; i++) { expectedResult.Add(new Point(i + 2, i)); }
-            List<Point> actualResult = SketchAssistant.Line.BresenhamLineAlgorithm(new Point(7, 5), new Point(27, 25));
-            Assert.AreEqual(expectedResult.Count, actualResult.Count);
-            for (int i = 0; i < actualResult.Count; i++)
-            {
-                Assert.AreEqual(expectedResult[i], actualResult[i]);
-            }
-        }
-
-        [TestMethod]
-        public void BresenhamLineTest7()
-        {
-            //Test exactly diagonal line from bottom right to top left
-            List<Point> expectedResult = new List<Point>();
-            for (int i = 25; i >= 5; i--) { expectedResult.Add(new Point(i + 2, i)); }
-            List<Point> actualResult = SketchAssistant.Line.BresenhamLineAlgorithm(new Point(27, 25), new Point(7, 5));
-            Assert.AreEqual(expectedResult.Count, actualResult.Count);
-            for (int i = 0; i < actualResult.Count; i++)
-            {
-                Assert.AreEqual(expectedResult[i], actualResult[i]);
-            }
-        }
-
-        //===========================//
-        //= Matrix Population Tests =//
-        //===========================//
-
-        [TestMethod]
-        public void MatrixTest1()
-        {
-            //Populate Matrix for temporary Line
-            List<Point> thePoints = new List<Point>();
-            thePoints.Add(new Point(1, 1));
-            thePoints.Add(new Point(1, 2));
-            bool[,] testBoolMatrix = new bool[5, 5];
-            List<int>[,] testLineMatrix = new List<int>[5, 5];
-            bool[,] resultBoolMatrix = new bool[5, 5];
-            HashSet<int>[,] resultLineMatrix = new HashSet<int>[5, 5];
-            Line testLine = new Line(thePoints);
-            testLine.PopulateMatrixes(resultBoolMatrix, resultLineMatrix);
-            for (int i = 0; i < 5; i++)
-            {
-                for (int j = 0; j < 5; j++)
-                {
-                    Assert.AreEqual(testBoolMatrix[i, j], resultBoolMatrix[i, j]);
-                    Assert.AreEqual(testLineMatrix[i, j], resultLineMatrix[i, j]);
-                }
-            }
-        }
-
-        [TestMethod]
-        public void MatrixTest2()
-        {
-            //Populate Matrix for non-temporary Line
-            List<Point> thePoints = new List<Point>();
-            thePoints.Add(new Point(1, 1));
-            thePoints.Add(new Point(3, 3));
-            bool[,] testBoolMatrix = new bool[5, 5];
-            HashSet<int>[,] testLineMatrix = new HashSet<int>[5, 5];
-            for (int i = 1; i <= 3; i++)
-            {
-                testBoolMatrix[i, i] = true;
-                HashSet<int> temp = new HashSet<int>();
-                temp.Add(5);
-                testLineMatrix[i, i] = temp;
-            }
-            bool[,] resultBoolMatrix = new bool[5, 5];
-            HashSet<int>[,] resultLineMatrix = new HashSet<int>[5, 5];
-            Line testLine = new Line(thePoints, 5);
-            testLine.PopulateMatrixes(resultBoolMatrix, resultLineMatrix);
-            for (int i = 0; i < 5; i++)
-            {
-                for (int j = 0; j < 5; j++)
-                {
-                    Assert.AreEqual(testBoolMatrix[i, j], resultBoolMatrix[i, j]);
-                    if (testLineMatrix[i, j] != null && resultLineMatrix[i, j] != null)
-                    {
-                        for (int k = 0; k < resultLineMatrix[i, j].Count; k++)
-                        {
-                            Assert.AreEqual(true, testLineMatrix[i, j].SetEquals(resultLineMatrix[i, j]));
-                        }
-                    }
-                }
-            }
-        }
-
-        //=========================//
-        //= Line Constructor Test =//
-        //=========================//
-
-        [TestMethod]
-        public void ConstructorTest()
-        {
-            //Create non-temporary Line and check points
-            //reference Points
-            List<Point> comparisonPoints = new List<Point> {new Point(2,2), new Point(3, 1), new Point(4, 1), new Point(5, 1), new Point(6, 2),
-                new Point(7, 3), new Point(8, 4), new Point(9, 5), new Point(10, 6), new Point(11, 5), new Point(11, 4), new Point(11, 3),
-                new Point(10, 2), new Point(9, 1), new Point(8, 2), new Point(7, 3), new Point(6, 4), new Point(5, 5), new Point(4, 5),
-                new Point(3, 5), new Point(2, 5), new Point(1, 4)};
-            //test Points, with intermediate points missing & duplicate points
-            List<Point> testPoints = new List<Point> {new Point(2,2), new Point(3, 1), new Point(5, 1), new Point(5, 1), new Point(5, 1),
-                new Point(8, 4), new Point(10, 6), new Point(11, 5), new Point(11, 3), new Point(9, 1), new Point(9, 1), new Point(9, 1),
-                new Point(5, 5), new Point(2, 5), new Point(2, 5), new Point(1, 4) };
-            Line testLine = new Line(testPoints, 0);
-            List<Point> returnedPoints = testLine.GetPoints();
-            Assert.AreEqual(comparisonPoints.Count, returnedPoints.Count);
-            for (int i = 0; i < returnedPoints.Count; i++)
-            {
-                Assert.AreEqual(comparisonPoints[i], returnedPoints[i]);
-            }
-        }
-    }
-
-    [TestClass]
-    public class ActionHistoryTests
-    {
-        ToolStripStatusLabel testLabel = new ToolStripStatusLabel();
-
-        private ActionHistory GetActionHistory()
-        {
-            return new ActionHistory(testLabel);
-        }
-
-        [DataTestMethod]
-        [DataRow(SketchAction.ActionType.Start, 5, -1, "A new canvas was created.")]
-        [DataRow(SketchAction.ActionType.Draw, 5, 5, "Line number 5 was drawn.")]
-        [DataRow(SketchAction.ActionType.Delete, 10, 10, "Line number 10 was deleted.")]
-        public void ScetchActionTest1(SketchAction.ActionType type, int id, int exit, String response)
-        {
-            HashSet<int> actualResult = new HashSet<int>();
-            if (!type.Equals(SketchAction.ActionType.Start)) { actualResult.Add(id); }
-            SketchAction testAction = new SketchAction(type, id);
-            Assert.AreEqual(type, testAction.GetActionType());
-            Assert.AreEqual(true, actualResult.SetEquals(testAction.GetLineIDs()));
-            Assert.AreEqual(response, testAction.GetActionInformation());
-        }
-
-        [DataTestMethod]
-        [DataRow(SketchAction.ActionType.Start, 1, 2, 3, "A new canvas was created.")]
-        [DataRow(SketchAction.ActionType.Draw, 3, 3, 3, "Line number 3 was drawn.")]
-        [DataRow(SketchAction.ActionType.Delete, 20, 30, 40, "Several Lines were deleted.")]
-        public void ScetchActionTest2(SketchAction.ActionType type, int id1, int id2, int id3, String response)
-        {
-            HashSet<int> actualResult = new HashSet<int>();
-            if (!type.Equals(SketchAction.ActionType.Start))
-            {
-                actualResult.Add(id1);
-                actualResult.Add(id2);
-                actualResult.Add(id3);
-            }
-            SketchAction testAction = new SketchAction(type, actualResult);
-            Assert.AreEqual(type, testAction.GetActionType());
-            Assert.AreEqual(true, actualResult.SetEquals(testAction.GetLineIDs()));
-            Assert.AreEqual(response, testAction.GetActionInformation());
-        }
-
-        [DataTestMethod]
-        [DataRow(SketchAction.ActionType.Start, SketchAction.ActionType.Start, true)]
-        [DataRow(SketchAction.ActionType.Draw, SketchAction.ActionType.Delete, false)]
-        public void ActionHistoryTest1(SketchAction.ActionType action1, SketchAction.ActionType action2, bool isEmpty)
-        {
-            ActionHistory testHistory = GetActionHistory();
-            if (!action1.Equals(SketchAction.ActionType.Start)) { testHistory.AddNewAction(new SketchAction(action1, 5)); }
-            if (!action2.Equals(SketchAction.ActionType.Start)) { testHistory.AddNewAction(new SketchAction(action2, 5)); }
-            Assert.AreEqual(isEmpty, testHistory.IsEmpty());
-        }
-
-        [DataTestMethod]
-        [DataRow(SketchAction.ActionType.Draw, "Last Action: Line number 0 was drawn.")]
-        [DataRow(SketchAction.ActionType.Delete, "Last Action: Line number 0 was deleted.")]
-        public void ActionHistoryUndoRedoTest(SketchAction.ActionType actionType, String message)
-        {
-            ActionHistory testHistory = GetActionHistory();
-            SketchAction testAction = new SketchAction(actionType, 0);
-            testHistory.AddNewAction(testAction);
-            Assert.AreEqual(true, testHistory.CanUndo());
-            testHistory.MoveAction(true);
-            Assert.AreEqual(true, testHistory.CanRedo());
-            testHistory.MoveAction(false);
-            Assert.AreEqual(actionType, testHistory.GetCurrentAction().GetActionType());
-            String currLabel = testLabel.Text;
-            Assert.AreEqual(currLabel, message);
-        }
-    }
-
-    [TestClass]
-    public class FileImporterTests
-    {
-        [DataTestMethod]
-        [DataRow(new int[] { 54, 43, 57, 11, 145, 34, 113, 299, 0 }, new int[] { 33, 42, 140, 30, 30, 30, 32, 145, 2 })]
-        [DataRow(new int[] { 33, 42, 140, 30, 30, 30, 32, 145, 2 }, new int[] { 33, 42, 140, 30, 30, 30, 32, 145, 2 })]
-        [DataRow(new int[] { 33, 42, 140, 30, 30, 30, 32, 145, 2 }, new int[] { 54, 43, 57, 11, 145, 34, 113, 199, 0 })]
-        public void ParseISADInputSuccessfulTest(int[] xCoordinates, int[] yCoordinates)
-        {
-            Form1 program = new Form1();
-            FileImporter uut = new SketchAssistant.FileImporter(program);
-
-            List<String> file = new List<string>();
-            file.Add("drawing");
-            file.Add("300x200");
-            for (int i = 0; i < xCoordinates.Length - 2; i += 3)
-            {
-                file.Add("line");
-                file.Add(xCoordinates[i] + ";" + yCoordinates[i]);
-                file.Add(xCoordinates[i + 1] + ";" + yCoordinates[i + 1]);
-                file.Add(xCoordinates[i + 2] + ";" + yCoordinates[i + 2]);
-                file.Add("endline");
-            }
-            file.Add("enddrawing");
-
-            (int, int, List<Line>) values = uut.ParseISADInputForTesting(file.ToArray());
-            program.CreateCanvasAndSetPictureForTesting(values.Item1, values.Item2, values.Item3);
-
-            Line[] drawing = GetLeftImage(program).ToArray();
-
-            Assert.AreEqual(xCoordinates.Length / 3, drawing.Length);
-            for (int i = 0; i < xCoordinates.Length - 2; i += 3)
-            {
-                Point[] currentLine = drawing[i / 3].GetPoints().ToArray();
-                Assert.AreEqual(3, currentLine.Length);
-                for (int j = 0; j < 3; j++)
-                {
-                    Assert.IsTrue(currentLine[j].X == xCoordinates[i + j] && currentLine[j].Y == yCoordinates[i + j]);
-                }
-            }
-        }
-
-        [DataTestMethod]
-        [DataRow(new String[] {})]
-        [DataRow(new String[] { "begindrawing", "300x300", "line", "50;50", "100;50", "endline", "enddrawing" })]
-        [DataRow(new String[] { "drawing", "300;300", "line", "50;50", "100;50", "endline", "enddrawing" })]
-        [DataRow(new String[] { "drawing", "30.5x300", "line", "50;50", "100;50", "endline", "enddrawing" })]
-        [DataRow(new String[] { "drawing", "line", "50;50", "100;50", "endline", "enddrawing" })]
-        [DataRow(new String[] { "drawing", "300x300", "beginline", "50;50", "100;50", "endline", "enddrawing" })]
-        [DataRow(new String[] { "drawing", "300x300", "line", "500;50", "100;50", "endline", "enddrawing" })]
-        [DataRow(new String[] { "drawing", "300x300", "line", "50x50", "100;50", "endline", "enddrawing" })]
-        [DataRow(new String[] { "drawing", "300x300", "line", "50", "100", "endline", "enddrawing" })]
-        [DataRow(new String[] { "drawing", "300x300", "line", "50;50", "line", "endline", "enddrawing" })]
-        [DataRow(new String[] { "drawing", "300x300", "line", "50;50", "100;50", "stopline", "enddrawing" })]
-        [DataRow(new String[] { "drawing", "300x300", "line", "50;50", "100;50", "enddrawing" })]
-        [DataRow(new String[] { "drawing", "300x300", "line", "50;50", "100;50", "endline", "endrawing" })]
-        [DataRow(new String[] { "drawing", "300x300", "line", "50;50", "100;50", "endline" })]
-        public void ParseISADInputExceptionTest(String[] file)
-        {
-            bool exceptionThrown = false;
-            Form1 program = new Form1();
-            FileImporter uut = new SketchAssistant.FileImporter(program);
-            //check that left image initially is uninitialized
-            Assert.IsNull(GetLeftImage(program));
-            //initialize left image with a valid isad drawing
-            (int, int, List<Line>) values = uut.ParseISADInputForTesting(new string[] { "drawing", "300x205", "line", "40;40", "140;140", "endline", "enddrawing" });
-            program.CreateCanvasAndSetPictureForTesting(values.Item1, values.Item2, values.Item3);
-            //save left image for later comparison
-            List<Line> oldLeftImage = GetLeftImage(program);
-            try
-            {
-                //try to initialize the left image with an invalid isad drawing
-                (int, int, List<Line>) values1 = uut.ParseISADInputForTesting(file);
-                program.CreateCanvasAndSetPictureForTesting(values1.Item1, values1.Item2, values1.Item3);
-            }
-            catch(FileImporterException)
-            {
-                //save the occurence of an exception
-                exceptionThrown = true;
-            }
-            //check that an exception has been thrown
-            Assert.IsTrue(exceptionThrown);
-            //check that the left image has not been changed by the failed image import
-            Assert.AreEqual(oldLeftImage, GetLeftImage(program));
-        }
-
-        /// <summary>
-        /// local helper method retrieving the left image from a Form1 instance
-        /// </summary>
-        /// <returns>the left image of the given Form1 instance</returns>
-        private List<Line> GetLeftImage(Form1 program)
-        {
-            //cast is save as long as Form1#GetAllVariables() is conform to its contract
-            return (List<Line>) program.GetAllVariables()[4];
-        }
-    }
-}

+ 10 - 10
SketchAssistant/SketchAssistant.sln

@@ -3,9 +3,9 @@ Microsoft Visual Studio Solution File, Format Version 12.00
 # Visual Studio 15
 VisualStudioVersion = 15.0.28010.2050
 MinimumVisualStudioVersion = 10.0.40219.1
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SketchAssistant", "SketchAssistant\SketchAssistant.csproj", "{0336F628-A2F7-4170-8B2E-9277C23118D4}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SketchAssistantWPF", "SketchAssistantWPF\SketchAssistantWPF.csproj", "{EE53AE79-2AA0-4F43-9638-1789B189D5C3}"
 EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SketchAssistant.Tests", "SketchAssistant.Tests\SketchAssistant.Tests.csproj", "{7DCDC31A-8291-4B05-93D6-DCC5DE27A4A0}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WhiteTests", "WhiteTests\WhiteTests.csproj", "{EB09C624-91F2-465F-825B-559BF7A7D5CB}"
 EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -13,14 +13,14 @@ Global
 		Release|Any CPU = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(ProjectConfigurationPlatforms) = postSolution
-		{0336F628-A2F7-4170-8B2E-9277C23118D4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{0336F628-A2F7-4170-8B2E-9277C23118D4}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{0336F628-A2F7-4170-8B2E-9277C23118D4}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{0336F628-A2F7-4170-8B2E-9277C23118D4}.Release|Any CPU.Build.0 = Release|Any CPU
-		{7DCDC31A-8291-4B05-93D6-DCC5DE27A4A0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{7DCDC31A-8291-4B05-93D6-DCC5DE27A4A0}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{7DCDC31A-8291-4B05-93D6-DCC5DE27A4A0}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{7DCDC31A-8291-4B05-93D6-DCC5DE27A4A0}.Release|Any CPU.Build.0 = Release|Any CPU
+		{EE53AE79-2AA0-4F43-9638-1789B189D5C3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{EE53AE79-2AA0-4F43-9638-1789B189D5C3}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{EE53AE79-2AA0-4F43-9638-1789B189D5C3}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{EE53AE79-2AA0-4F43-9638-1789B189D5C3}.Release|Any CPU.Build.0 = Release|Any CPU
+		{EB09C624-91F2-465F-825B-559BF7A7D5CB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{EB09C624-91F2-465F-825B-559BF7A7D5CB}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{EB09C624-91F2-465F-825B-559BF7A7D5CB}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{EB09C624-91F2-465F-825B-559BF7A7D5CB}.Release|Any CPU.Build.0 = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE

+ 0 - 14
SketchAssistant/SketchAssistant/App.config

@@ -1,14 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<configuration>
-    <startup> 
-        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" />
-    </startup>
-  <runtime>
-    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
-      <dependentAssembly>
-        <assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
-        <bindingRedirect oldVersion="0.0.0.0-4.0.4.1" newVersion="4.0.4.1" />
-      </dependentAssembly>
-    </assemblyBinding>
-  </runtime>
-</configuration>

+ 0 - 299
SketchAssistant/SketchAssistant/Form1.Designer.cs

@@ -1,299 +0,0 @@
-namespace SketchAssistant
-{
-    partial class Form1
-    {
-        /// <summary>
-        /// Required designer variable.
-        /// </summary>
-        private System.ComponentModel.IContainer components = null;
-
-        /// <summary>
-        /// Clean up any resources being used.
-        /// </summary>
-        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
-        protected override void Dispose(bool disposing)
-        {
-            if (disposing && (components != null))
-            {
-                components.Dispose();
-            }
-            base.Dispose(disposing);
-        }
-
-        #region Windows Form Designer generated code
-
-        /// <summary>
-        /// Required method for Designer support - do not modify
-        /// the contents of this method with the code editor.
-        /// </summary>
-        private void InitializeComponent()
-        {
-            this.components = new System.ComponentModel.Container();
-            System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(Form1));
-            this.backgroundWorker1 = new System.ComponentModel.BackgroundWorker();
-            this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel();
-            this.pictureBoxRight = new System.Windows.Forms.PictureBox();
-            this.pictureBoxLeft = new System.Windows.Forms.PictureBox();
-            this.menuStrip1 = new System.Windows.Forms.MenuStrip();
-            this.fileToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
-            this.loadToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
-            this.importToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
-            this.examplePictureToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
-            this.toolStrip1 = new System.Windows.Forms.ToolStrip();
-            this.canvasButton = new System.Windows.Forms.ToolStripButton();
-            this.drawButton = new System.Windows.Forms.ToolStripButton();
-            this.deleteButton = new System.Windows.Forms.ToolStripButton();
-            this.statusStrip1 = new System.Windows.Forms.StatusStrip();
-            this.toolStripLoadStatus = 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();
-            this.menuStrip1.SuspendLayout();
-            this.toolStrip1.SuspendLayout();
-            this.statusStrip1.SuspendLayout();
-            this.SuspendLayout();
-            // 
-            // tableLayoutPanel1
-            // 
-            this.tableLayoutPanel1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) 
-            | System.Windows.Forms.AnchorStyles.Left) 
-            | System.Windows.Forms.AnchorStyles.Right)));
-            this.tableLayoutPanel1.BackColor = System.Drawing.SystemColors.InactiveCaption;
-            this.tableLayoutPanel1.CellBorderStyle = System.Windows.Forms.TableLayoutPanelCellBorderStyle.OutsetDouble;
-            this.tableLayoutPanel1.ColumnCount = 2;
-            this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F));
-            this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F));
-            this.tableLayoutPanel1.Controls.Add(this.pictureBoxRight, 1, 0);
-            this.tableLayoutPanel1.Controls.Add(this.pictureBoxLeft, 0, 0);
-            this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 52);
-            this.tableLayoutPanel1.Name = "tableLayoutPanel1";
-            this.tableLayoutPanel1.RowCount = 1;
-            this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
-            this.tableLayoutPanel1.Size = new System.Drawing.Size(696, 440);
-            this.tableLayoutPanel1.TabIndex = 1;
-            // 
-            // pictureBoxRight
-            // 
-            this.pictureBoxRight.Dock = System.Windows.Forms.DockStyle.Fill;
-            this.pictureBoxRight.Location = new System.Drawing.Point(349, 3);
-            this.pictureBoxRight.Margin = new System.Windows.Forms.Padding(0);
-            this.pictureBoxRight.Name = "pictureBoxRight";
-            this.pictureBoxRight.Size = new System.Drawing.Size(344, 434);
-            this.pictureBoxRight.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom;
-            this.pictureBoxRight.TabIndex = 6;
-            this.pictureBoxRight.TabStop = false;
-            this.pictureBoxRight.MouseDown += new System.Windows.Forms.MouseEventHandler(this.pictureBoxRight_MouseDown);
-            this.pictureBoxRight.MouseMove += new System.Windows.Forms.MouseEventHandler(this.pictureBoxRight_MouseMove);
-            this.pictureBoxRight.MouseUp += new System.Windows.Forms.MouseEventHandler(this.pictureBoxRight_MouseUp);
-            // 
-            // pictureBoxLeft
-            // 
-            this.pictureBoxLeft.BackColor = System.Drawing.SystemColors.InactiveCaption;
-            this.pictureBoxLeft.Dock = System.Windows.Forms.DockStyle.Fill;
-            this.pictureBoxLeft.Location = new System.Drawing.Point(3, 3);
-            this.pictureBoxLeft.Margin = new System.Windows.Forms.Padding(0);
-            this.pictureBoxLeft.Name = "pictureBoxLeft";
-            this.pictureBoxLeft.Size = new System.Drawing.Size(343, 434);
-            this.pictureBoxLeft.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom;
-            this.pictureBoxLeft.TabIndex = 5;
-            this.pictureBoxLeft.TabStop = false;
-            // 
-            // menuStrip1
-            // 
-            this.menuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
-            this.fileToolStripMenuItem});
-            this.menuStrip1.Location = new System.Drawing.Point(0, 0);
-            this.menuStrip1.MaximumSize = new System.Drawing.Size(1000, 0);
-            this.menuStrip1.Name = "menuStrip1";
-            this.menuStrip1.Size = new System.Drawing.Size(696, 24);
-            this.menuStrip1.TabIndex = 2;
-            this.menuStrip1.Text = "menuStrip1";
-            // 
-            // fileToolStripMenuItem
-            // 
-            this.fileToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
-            this.loadToolStripMenuItem,
-            this.importToolStripMenuItem});
-            this.fileToolStripMenuItem.Name = "fileToolStripMenuItem";
-            this.fileToolStripMenuItem.Size = new System.Drawing.Size(37, 20);
-            this.fileToolStripMenuItem.Text = "File";
-            // 
-            // loadToolStripMenuItem
-            // 
-            this.loadToolStripMenuItem.Name = "loadToolStripMenuItem";
-            this.loadToolStripMenuItem.Size = new System.Drawing.Size(180, 22);
-            this.loadToolStripMenuItem.Text = "Load...";
-            this.loadToolStripMenuItem.Click += new System.EventHandler(this.loadToolStripMenuItem_Click);
-            // 
-            // importToolStripMenuItem
-            // 
-            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.Text = "Import...";
-            // 
-            // examplePictureToolStripMenuItem
-            // 
-            this.examplePictureToolStripMenuItem.Name = "examplePictureToolStripMenuItem";
-            this.examplePictureToolStripMenuItem.Size = new System.Drawing.Size(180, 22);
-            this.examplePictureToolStripMenuItem.Text = "Example picture";
-            this.examplePictureToolStripMenuItem.Click += new System.EventHandler(this.examplePictureToolStripMenuItem_Click);
-            // 
-            // toolStrip1
-            // 
-            this.toolStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
-            this.canvasButton,
-            this.drawButton,
-            this.deleteButton,
-            this.undoButton,
-            this.redoButton});
-            this.toolStrip1.Location = new System.Drawing.Point(0, 24);
-            this.toolStrip1.Name = "toolStrip1";
-            this.toolStrip1.Size = new System.Drawing.Size(696, 25);
-            this.toolStrip1.TabIndex = 3;
-            this.toolStrip1.Text = "toolStrip1";
-            // 
-            // canvasButton
-            // 
-            this.canvasButton.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Text;
-            this.canvasButton.Image = ((System.Drawing.Image)(resources.GetObject("canvasButton.Image")));
-            this.canvasButton.ImageTransparentColor = System.Drawing.Color.Magenta;
-            this.canvasButton.Name = "canvasButton";
-            this.canvasButton.Size = new System.Drawing.Size(76, 22);
-            this.canvasButton.Text = "New Canvas";
-            this.canvasButton.Click += new System.EventHandler(this.canvasButton_Click);
-            // 
-            // drawButton
-            // 
-            this.drawButton.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Text;
-            this.drawButton.Image = ((System.Drawing.Image)(resources.GetObject("drawButton.Image")));
-            this.drawButton.ImageTransparentColor = System.Drawing.Color.Magenta;
-            this.drawButton.Name = "drawButton";
-            this.drawButton.Size = new System.Drawing.Size(38, 22);
-            this.drawButton.Text = "Draw";
-            this.drawButton.Click += new System.EventHandler(this.drawButton_Click);
-            // 
-            // deleteButton
-            // 
-            this.deleteButton.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Text;
-            this.deleteButton.Image = ((System.Drawing.Image)(resources.GetObject("deleteButton.Image")));
-            this.deleteButton.ImageTransparentColor = System.Drawing.Color.Magenta;
-            this.deleteButton.Name = "deleteButton";
-            this.deleteButton.Size = new System.Drawing.Size(44, 22);
-            this.deleteButton.Text = "Delete";
-            this.deleteButton.Click += new System.EventHandler(this.deleteButton_Click);
-            // 
-            // statusStrip1
-            // 
-            this.statusStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
-            this.toolStripLoadStatus,
-            this.lastActionTakenLabel});
-            this.statusStrip1.Location = new System.Drawing.Point(0, 491);
-            this.statusStrip1.Name = "statusStrip1";
-            this.statusStrip1.Size = new System.Drawing.Size(696, 24);
-            this.statusStrip1.TabIndex = 4;
-            this.statusStrip1.Text = "statusStrip1";
-            // 
-            // toolStripLoadStatus
-            // 
-            this.toolStripLoadStatus.Name = "toolStripLoadStatus";
-            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;
-            this.lastActionTakenLabel.Name = "lastActionTakenLabel";
-            this.lastActionTakenLabel.Size = new System.Drawing.Size(38, 19);
-            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
-            // 
-            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);
-            // 
-            // Form1
-            // 
-            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
-            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
-            this.BackColor = System.Drawing.SystemColors.MenuBar;
-            this.ClientSize = new System.Drawing.Size(696, 515);
-            this.Controls.Add(this.statusStrip1);
-            this.Controls.Add(this.toolStrip1);
-            this.Controls.Add(this.tableLayoutPanel1);
-            this.Controls.Add(this.menuStrip1);
-            this.KeyPreview = true;
-            this.MainMenuStrip = this.menuStrip1;
-            this.Margin = new System.Windows.Forms.Padding(2);
-            this.Name = "Form1";
-            this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
-            this.Text = "Sketch Assistant";
-            this.WindowState = System.Windows.Forms.FormWindowState.Maximized;
-            this.Load += new System.EventHandler(this.Form1_Load);
-            this.SizeChanged += new System.EventHandler(this.Form1_Resize);
-            this.KeyDown += new System.Windows.Forms.KeyEventHandler(this.Form1_KeyDown);
-            this.tableLayoutPanel1.ResumeLayout(false);
-            ((System.ComponentModel.ISupportInitialize)(this.pictureBoxRight)).EndInit();
-            ((System.ComponentModel.ISupportInitialize)(this.pictureBoxLeft)).EndInit();
-            this.menuStrip1.ResumeLayout(false);
-            this.menuStrip1.PerformLayout();
-            this.toolStrip1.ResumeLayout(false);
-            this.toolStrip1.PerformLayout();
-            this.statusStrip1.ResumeLayout(false);
-            this.statusStrip1.PerformLayout();
-            this.ResumeLayout(false);
-            this.PerformLayout();
-
-        }
-
-        #endregion
-        private System.ComponentModel.BackgroundWorker backgroundWorker1;
-        private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1;
-        private System.Windows.Forms.MenuStrip menuStrip1;
-        private System.Windows.Forms.ToolStripMenuItem fileToolStripMenuItem;
-        private System.Windows.Forms.ToolStripMenuItem loadToolStripMenuItem;
-        private System.Windows.Forms.ToolStrip toolStrip1;
-        private System.Windows.Forms.StatusStrip statusStrip1;
-        private System.Windows.Forms.ToolStripStatusLabel toolStripLoadStatus;
-        private System.ComponentModel.BackgroundWorker backgroundWorker2;
-        private System.Windows.Forms.PictureBox pictureBoxRight;
-        private System.Windows.Forms.PictureBox pictureBoxLeft;
-        private System.Windows.Forms.Timer mouseTimer;
-        private System.Windows.Forms.ToolStripButton canvasButton;
-        private System.Windows.Forms.ToolStripButton drawButton;
-        private System.Windows.Forms.ToolStripButton deleteButton;
-        private System.Windows.Forms.ToolStripMenuItem importToolStripMenuItem;
-        private System.Windows.Forms.ToolStripMenuItem examplePictureToolStripMenuItem;
-        private System.Windows.Forms.ToolStripStatusLabel lastActionTakenLabel;
-        private System.Windows.Forms.ToolStripButton undoButton;
-        private System.Windows.Forms.ToolStripButton redoButton;
-    }
-}
-

+ 0 - 623
SketchAssistant/SketchAssistant/Form1.cs

@@ -1,623 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.ComponentModel;
-using System.Data;
-using System.Drawing;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using System.Windows.Forms;
-using System.Text.RegularExpressions;
-
-
-// This is the code for your desktop app.
-// Press Ctrl+F5 (or go to Debug > Start Without Debugging) to run your app.
-
-namespace SketchAssistant
-{
-    public partial class Form1 : Form
-    {
-        public Form1()
-        {
-            InitializeComponent();
-            fileImporter = new FileImporter(this);
-        }
-
-        /**********************************/
-        /*** CLASS VARIABLES START HERE ***/
-        /**********************************/
-
-        //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()
-
-        /// <summary>
-        /// Different Program States
-        /// </summary>
-        public enum ProgramState
-        {
-            Idle,
-            Draw,
-            Delete
-        }
-        /// <summary>
-        /// Current Program State
-        /// </summary>
-        private ProgramState currentState;
-        /// <summary>
-        /// instance of FileImporter to handle drawing imports
-        /// </summary>
-        private FileImporter fileImporter;
-        /// <summary>
-        /// Dialog to select a file.
-        /// </summary>
-        OpenFileDialog openFileDialog = new OpenFileDialog();
-        /// <summary>
-        /// Image loaded on the left
-        /// </summary>
-        private Image leftImage = null;
-        /// <summary>
-        /// the graphic shown in the left window, represented as a list of polylines
-        /// </summary>
-        private List<Line> leftLineList;
-        /// <summary>
-        /// Image on the right
-        /// </summary>
-        Image rightImage = null;
-        /// <summary>
-        /// Current Line being Drawn
-        /// </summary>
-        List<Point> currentLine;
-        /// <summary>
-        /// All Lines in the current session
-        /// </summary>
-        List<Tuple<bool,Line>> rightLineList = new List<Tuple<bool, Line>>();
-        /// <summary>
-        /// Whether the Mouse is currently pressed in the rightPictureBox
-        /// </summary>
-        bool mousePressed = false;
-        /// <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>
-        /// The graphic representation of the right image
-        /// </summary>
-        Graphics rightGraph = null;
-        /// <summary>
-        /// Deletion Matrixes for checking postions of lines in the image
-        /// </summary>
-        bool[,] isFilledMatrix;
-        HashSet<int>[,] linesMatrix;
-        /// <summary>
-        /// Size of deletion area
-        /// </summary>
-        uint deletionSize = 2;
-        /// <summary>
-        /// History of Actions
-        /// </summary>
-        ActionHistory historyOfActions;
-
-        /******************************************/
-        /*** FORM SPECIFIC FUNCTIONS START HERE ***/
-        /******************************************/
-
-        private void Form1_Load(object sender, EventArgs e)
-        {
-            currentState = ProgramState.Idle;
-            this.DoubleBuffered = true;
-            historyOfActions = new ActionHistory(null);
-            UpdateButtonStatus();
-        }
-
-        //Resize Function connected to the form resize event, will refresh the form when it is resized
-        private void Form1_Resize(object sender, System.EventArgs e)
-        {
-            this.Refresh();
-        }
-        
-        //Load button, will open an OpenFileDialog
-        private void loadToolStripMenuItem_Click(object sender, EventArgs e)
-        {
-            openFileDialog.Filter = "Image|*.jpg;*.png;*.jpeg";
-            if(openFileDialog.ShowDialog() == DialogResult.OK)
-            {
-                toolStripLoadStatus.Text = openFileDialog.SafeFileName;
-                leftImage = Image.FromFile(openFileDialog.FileName);
-                pictureBoxLeft.Image = leftImage;
-                //Refresh the left image box when the content is changed
-                this.Refresh();
-            }
-            UpdateButtonStatus();
-        }
-
-        /// <summary>
-        /// Import button, will open an OpenFileDialog
-        /// </summary>
-        private void examplePictureToolStripMenuItem_Click(object sender, EventArgs e)
-        {
-            openFileDialog.Filter = "Interactive Sketch-Assistant Drawing|*.isad";
-            if (openFileDialog.ShowDialog() == DialogResult.OK)
-            {
-                toolStripLoadStatus.Text = openFileDialog.SafeFileName;
-                try
-                {
-                    (int, int, List<Line>) values = fileImporter.ParseISADInputFile(openFileDialog.FileName);
-                    DrawEmptyCanvasLeft(values.Item1, values.Item2);
-                    BindAndDrawLeftImage(values.Item3);
-                    this.Refresh();
-                }
-                catch(FileImporterException ex)
-                {
-                    ShowInfoMessage(ex.ToString());
-                }
-            }
-        }
-
-        //Changes the state of the program to drawing
-        private void drawButton_Click(object sender, EventArgs e)
-        {
-            if(rightImage != null)
-            {
-                if (currentState.Equals(ProgramState.Draw))
-                {
-                    ChangeState(ProgramState.Idle);
-                }
-                else
-                {
-                    ChangeState(ProgramState.Draw);
-                }
-            }
-            UpdateButtonStatus();
-        }
-
-        //Changes the state of the program to deletion
-        private void deleteButton_Click(object sender, EventArgs e)
-        {
-            if (rightImage != null)
-            {
-                if (currentState.Equals(ProgramState.Delete))
-                {
-                    ChangeState(ProgramState.Idle);
-                }
-                else
-                {
-                    ChangeState(ProgramState.Delete);
-                }
-            }
-            UpdateButtonStatus();
-        }
-
-        //Undo an action
-        private void undoButton_Click(object sender, EventArgs e)
-        {
-            if (historyOfActions.CanUndo())
-            {
-                HashSet<int> affectedLines = historyOfActions.GetCurrentAction().GetLineIDs();
-                SketchAction.ActionType  undoAction = historyOfActions.GetCurrentAction().GetActionType();
-                switch (undoAction)
-                {
-                    case SketchAction.ActionType.Delete:
-                        //Deleted Lines need to be shown
-                        ChangeLines(affectedLines, true);
-                        break;
-                    case SketchAction.ActionType.Draw:
-                        //Drawn lines need to be hidden
-                        ChangeLines(affectedLines, false);
-                        break;
-                    default:
-                        break;
-                }
-            }
-            historyOfActions.MoveAction(true);
-            UpdateButtonStatus();
-        }
-
-        //Redo an action
-        private void redoButton_Click(object sender, EventArgs e)
-        {
-            if (historyOfActions.CanRedo())
-            {
-                historyOfActions.MoveAction(false);
-                HashSet<int> affectedLines = historyOfActions.GetCurrentAction().GetLineIDs();
-                SketchAction.ActionType redoAction = historyOfActions.GetCurrentAction().GetActionType();
-                switch (redoAction)
-                {
-                    case SketchAction.ActionType.Delete:
-                        //Deleted Lines need to be redeleted
-                        ChangeLines(affectedLines, false);
-                        break;
-                    case SketchAction.ActionType.Draw:
-                        //Drawn lines need to be redrawn
-                        ChangeLines(affectedLines, true);
-                        break;
-                    default:
-                        break;
-                }
-            }
-            UpdateButtonStatus();
-        }
-
-        //Detect Keyboard Shortcuts
-        private void Form1_KeyDown(object sender, KeyEventArgs e)
-        {
-            if (e.Modifiers == Keys.Control && e.KeyCode == Keys.Z)
-            {
-                undoButton_Click(sender, e);
-            }
-            if (e.Modifiers == Keys.Control && e.KeyCode == Keys.Y)
-            {
-                redoButton_Click(sender, e);
-            }
-        }
-
-        //get current Mouse positon within the right picture box
-        private void pictureBoxRight_MouseMove(object sender, MouseEventArgs e)
-        {
-            currentCursorPosition = ConvertCoordinates(new Point(e.X, e.Y));
-        }
-
-        //hold left mouse button to draw.
-        private void pictureBoxRight_MouseDown(object sender, MouseEventArgs e)
-        {
-            mousePressed = true;
-            if (currentState.Equals(ProgramState.Draw))
-            {
-                currentLine = new List<Point>();
-            }
-        }
-
-        //Lift left mouse button to stop drawing and add a new Line.
-        private void pictureBoxRight_MouseUp(object sender, MouseEventArgs e)
-        {
-            mousePressed = false;
-            if (currentState.Equals(ProgramState.Draw) && currentLine.Count > 0)
-            {
-                Line newLine = new Line(currentLine, rightLineList.Count);
-                rightLineList.Add(new Tuple<bool, Line>(true, newLine));
-                newLine.PopulateMatrixes(isFilledMatrix, linesMatrix);
-                historyOfActions.AddNewAction(new SketchAction(SketchAction.ActionType.Draw, newLine.GetID()));
-            }
-            UpdateButtonStatus();
-        }
-
-        //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
-        private void canvasButton_Click(object sender, EventArgs e)
-        {
-            if (!historyOfActions.IsEmpty())
-            {
-                if (MessageBox.Show("You have unsaved changes, creating a new canvas will discard these.", 
-                    "Attention", MessageBoxButtons.OKCancel, MessageBoxIcon.Warning) == DialogResult.OK)
-                {
-                    historyOfActions = new ActionHistory(lastActionTakenLabel);
-                    DrawEmptyCanvasRight();
-                    //The following lines cannot be in DrawEmptyCanvas()
-                    isFilledMatrix = new bool[rightImage.Width, rightImage.Height];
-                    linesMatrix = new HashSet<int>[rightImage.Width, rightImage.Height];
-                    rightLineList = new List<Tuple<bool, Line>>();
-                }
-            }
-            else
-            {
-                historyOfActions = new ActionHistory(lastActionTakenLabel);
-                DrawEmptyCanvasRight();
-                //The following lines cannot be in DrawEmptyCanvas()
-                isFilledMatrix = new bool[rightImage.Width, rightImage.Height];
-                linesMatrix = new HashSet<int>[rightImage.Width, rightImage.Height];
-                rightLineList = new List<Tuple<bool, Line>>();
-            }
-            UpdateButtonStatus();
-        }
-
-        //add a Point on every tick to the Drawpath
-        private void mouseTimer_Tick(object sender, EventArgs e)
-        {
-            cursorPositions.Enqueue(currentCursorPosition);
-            previousCursorPosition = cursorPositions.Dequeue();
-            if (currentState.Equals(ProgramState.Draw) && mousePressed)
-            {
-                currentLine.Add(currentCursorPosition);
-                Line drawline = new Line(currentLine);
-                drawline.DrawLine(rightGraph);
-                pictureBoxRight.Image = rightImage;
-            }
-            if (currentState.Equals(ProgramState.Delete) && mousePressed)
-            {
-                List<Point> uncheckedPoints = Line.BresenhamLineAlgorithm(previousCursorPosition, currentCursorPosition);
-                foreach (Point currPoint in uncheckedPoints)
-                {
-                    HashSet<int> linesToDelete = CheckDeletionMatrixesAroundPoint(currPoint, deletionSize);
-                    if (linesToDelete.Count > 0)
-                    {
-                        historyOfActions.AddNewAction(new SketchAction(SketchAction.ActionType.Delete, linesToDelete));
-                        foreach (int lineID in linesToDelete)
-                        {
-                            rightLineList[lineID] = new Tuple<bool, Line>(false, rightLineList[lineID].Item2);
-                        }
-                        RepopulateDeletionMatrixes();
-                        RedrawRightImage();
-                    }
-                }
-            }
-        }
-
-        /***********************************/
-        /*** HELPER FUNCTIONS START HERE ***/
-        /***********************************/
-
-        /// <summary>
-        /// Creates an empty Canvas
-        /// </summary>
-        private void DrawEmptyCanvasRight()
-        {
-            if (leftImage == null)
-            {
-                rightImage = new Bitmap(pictureBoxRight.Width, pictureBoxRight.Height);
-                rightGraph = Graphics.FromImage(rightImage);
-                rightGraph.FillRectangle(Brushes.White, 0, 0, pictureBoxRight.Width + 10, pictureBoxRight.Height + 10);
-                pictureBoxRight.Image = rightImage;
-            }
-            else
-            {
-                rightImage = new Bitmap(leftImage.Width, leftImage.Height);
-                rightGraph = Graphics.FromImage(rightImage);
-                rightGraph.FillRectangle(Brushes.White, 0, 0, leftImage.Width + 10, leftImage.Height + 10);
-                pictureBoxRight.Image = rightImage;
-            }
-            this.Refresh();
-            pictureBoxRight.Refresh();
-        }
-
-        /// <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 = new Bitmap(pictureBoxLeft.Width, pictureBoxLeft.Height);
-            }
-            else
-            {
-                leftImage = new Bitmap(width, height);
-            }
-            Graphics.FromImage(leftImage).FillRectangle(Brushes.White, 0, 0, pictureBoxLeft.Width + 10, pictureBoxLeft.Height + 10);
-            pictureBoxLeft.Image = leftImage;
-            
-            this.Refresh();
-            pictureBoxLeft.Refresh();
-        }
-
-        /// <summary>
-        /// Redraws all lines in lineList, for which their associated boolean value equals true.
-        /// </summary>
-        private void RedrawRightImage()
-        {
-            DrawEmptyCanvasRight();
-            foreach (Tuple<bool, Line> lineBoolTuple in rightLineList)
-            {
-                if (lineBoolTuple.Item1)
-                {
-                    lineBoolTuple.Item2.DrawLine(rightGraph);
-                }
-            }
-            pictureBoxRight.Refresh();
-        }
-
-        /// <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)
-        {
-            foreach (int lineId in lines)
-            {
-                if (lineId <= rightLineList.Count - 1 && lineId >= 0)
-                {
-                    rightLineList[lineId] = new Tuple<bool, Line>(shown, rightLineList[lineId].Item2);
-                }
-            }
-            RedrawRightImage();
-        }
-
-        /// <summary>
-        /// Updates the active status of buttons. Currently draw, delete, undo and redo button.
-        /// </summary>
-        private void UpdateButtonStatus()
-        {
-            undoButton.Enabled = historyOfActions.CanUndo();
-            redoButton.Enabled = historyOfActions.CanRedo();
-            drawButton.Enabled = (rightImage != null);
-            deleteButton.Enabled = (rightImage != null);
-        }
-
-        /// <summary>
-        /// A helper function which handles tasks associated witch changing states, 
-        /// such as checking and unchecking buttons and changing the state.
-        /// </summary>
-        /// <param name="newState">The new state of the program</param>
-        private void ChangeState(ProgramState newState)
-        {
-            switch (currentState)
-            {
-                case ProgramState.Draw:
-                    drawButton.CheckState = CheckState.Unchecked;
-                    mouseTimer.Enabled = false;
-                    break;
-                case ProgramState.Delete:
-                    deleteButton.CheckState = CheckState.Unchecked;
-                    mouseTimer.Enabled = false;
-                    break;
-                default:
-                    break;
-            }
-            switch (newState)
-            {
-                case ProgramState.Draw:
-                    drawButton.CheckState = CheckState.Checked;
-                    mouseTimer.Enabled = true;
-                    break;
-                case ProgramState.Delete:
-                    deleteButton.CheckState = CheckState.Checked;
-                    mouseTimer.Enabled = true;
-                    break;
-                default:
-                    break;
-            }
-            currentState = newState;
-            pictureBoxRight.Refresh();
-        }
-
-        /// <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)
-        {
-            Point realCoordinates = new Point(5,3);
-            if(pictureBoxRight.Image == null)
-            {
-                return cursorPosition;
-            }
-
-            int widthImage = pictureBoxRight.Image.Width;
-            int heightImage = pictureBoxRight.Image.Height;
-            int widthBox = pictureBoxRight.Width;
-            int heightBox = pictureBoxRight.Height;
-
-            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;
-        }
-
-        /// <summary>
-        /// A function that populates the matrixes needed for deletion detection with line data.
-        /// </summary>
-        private void RepopulateDeletionMatrixes()
-        {
-            if(rightImage != null)
-            {
-                isFilledMatrix = new bool[rightImage.Width,rightImage.Height];
-                linesMatrix = new HashSet<int>[rightImage.Width, rightImage.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, uint range)
-        {
-            HashSet<int> returnSet = new HashSet<int>();
-
-            if (p.X >= 0 && p.Y >= 0 && p.X < rightImage.Width && p.Y < rightImage.Height)
-            {
-                if (isFilledMatrix[p.X, p.Y])
-                {
-                    returnSet.UnionWith(linesMatrix[p.X, p.Y]);
-                }
-            }
-            for (int x_mod = (int)range*(-1); x_mod < range; x_mod++)
-            {
-                for (int y_mod = (int)range * (-1); y_mod < range; y_mod++)
-                {
-                    if (p.X + x_mod >= 0 && p.Y + y_mod >= 0 && p.X + x_mod < rightImage.Width && p.Y + y_mod < rightImage.Height)
-                    {
-                        if (isFilledMatrix[p.X + x_mod, p.Y + y_mod])
-                        {
-                            returnSet.UnionWith(linesMatrix[p.X + x_mod, p.Y + y_mod]);
-                        }
-                    }
-                }
-            }
-            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>
-        /// 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>
-        /// returns all instance variables in the order of their definition for testing
-        /// </summary>
-        /// <returns>all instance variables in the order of their definition</returns>
-        public Object[]/*(ProgramState, FileImporter, OpenFileDialog, Image, List<Line>, Image, List<Point>, List<Tuple<bool, Line>>, bool, Point, Point, Queue<Point>, Graphics, bool[,], HashSet<int>[,], uint, ActionHistory)*/ GetAllVariables()
-        {
-            return new Object[] { currentState, fileImporter, openFileDialog, leftImage, leftLineList, rightImage, currentLine, rightLineList, mousePressed, currentCursorPosition, previousCursorPosition, cursorPositions, rightGraph, isFilledMatrix, linesMatrix, deletionSize, historyOfActions };
-        }
-
-        /// <summary>
-        /// public method wrapper for testing purposes, invoking DrawEmptyCanvas(...) and BindAndDrawLeftImage(...)
-        /// </summary>
-        /// <param name="width">width of the parsed image</param>
-        /// <param name="height">height of the parsed image</param>
-        /// <param name="newImage">the parsed image</param>
-        public void CreateCanvasAndSetPictureForTesting(int width, int height, List<Line> newImage)
-        {
-            DrawEmptyCanvasLeft(width, height);
-            BindAndDrawLeftImage(newImage);
-        }
-
-
-    }
-}

+ 0 - 217
SketchAssistant/SketchAssistant/Form1.resx

@@ -1,217 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<root>
-  <!-- 
-    Microsoft ResX Schema 
-    
-    Version 2.0
-    
-    The primary goals of this format is to allow a simple XML format 
-    that is mostly human readable. The generation and parsing of the 
-    various data types are done through the TypeConverter classes 
-    associated with the data types.
-    
-    Example:
-    
-    ... ado.net/XML headers & schema ...
-    <resheader name="resmimetype">text/microsoft-resx</resheader>
-    <resheader name="version">2.0</resheader>
-    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
-    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
-    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
-    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
-    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
-        <value>[base64 mime encoded serialized .NET Framework object]</value>
-    </data>
-    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
-        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
-        <comment>This is a comment</comment>
-    </data>
-                
-    There are any number of "resheader" rows that contain simple 
-    name/value pairs.
-    
-    Each data row contains a name, and value. The row also contains a 
-    type or mimetype. Type corresponds to a .NET class that support 
-    text/value conversion through the TypeConverter architecture. 
-    Classes that don't support this are serialized and stored with the 
-    mimetype set.
-    
-    The mimetype is used for serialized objects, and tells the 
-    ResXResourceReader how to depersist the object. This is currently not 
-    extensible. For a given mimetype the value must be set accordingly:
-    
-    Note - application/x-microsoft.net.object.binary.base64 is the format 
-    that the ResXResourceWriter will generate, however the reader can 
-    read any of the formats listed below.
-    
-    mimetype: application/x-microsoft.net.object.binary.base64
-    value   : The object must be serialized with 
-            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
-            : and then encoded with base64 encoding.
-    
-    mimetype: application/x-microsoft.net.object.soap.base64
-    value   : The object must be serialized with 
-            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
-            : and then encoded with base64 encoding.
-
-    mimetype: application/x-microsoft.net.object.bytearray.base64
-    value   : The object must be serialized into a byte array 
-            : using a System.ComponentModel.TypeConverter
-            : and then encoded with base64 encoding.
-    -->
-  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
-    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
-    <xsd:element name="root" msdata:IsDataSet="true">
-      <xsd:complexType>
-        <xsd:choice maxOccurs="unbounded">
-          <xsd:element name="metadata">
-            <xsd:complexType>
-              <xsd:sequence>
-                <xsd:element name="value" type="xsd:string" minOccurs="0" />
-              </xsd:sequence>
-              <xsd:attribute name="name" use="required" type="xsd:string" />
-              <xsd:attribute name="type" type="xsd:string" />
-              <xsd:attribute name="mimetype" type="xsd:string" />
-              <xsd:attribute ref="xml:space" />
-            </xsd:complexType>
-          </xsd:element>
-          <xsd:element name="assembly">
-            <xsd:complexType>
-              <xsd:attribute name="alias" type="xsd:string" />
-              <xsd:attribute name="name" type="xsd:string" />
-            </xsd:complexType>
-          </xsd:element>
-          <xsd:element name="data">
-            <xsd:complexType>
-              <xsd:sequence>
-                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
-                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
-              </xsd:sequence>
-              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
-              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
-              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
-              <xsd:attribute ref="xml:space" />
-            </xsd:complexType>
-          </xsd:element>
-          <xsd:element name="resheader">
-            <xsd:complexType>
-              <xsd:sequence>
-                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
-              </xsd:sequence>
-              <xsd:attribute name="name" type="xsd:string" use="required" />
-            </xsd:complexType>
-          </xsd:element>
-        </xsd:choice>
-      </xsd:complexType>
-    </xsd:element>
-  </xsd:schema>
-  <resheader name="resmimetype">
-    <value>text/microsoft-resx</value>
-  </resheader>
-  <resheader name="version">
-    <value>2.0</value>
-  </resheader>
-  <resheader name="reader">
-    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
-  </resheader>
-  <resheader name="writer">
-    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
-  </resheader>
-  <metadata name="backgroundWorker1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
-    <value>122, 17</value>
-  </metadata>
-  <metadata name="menuStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
-    <value>286, 17</value>
-  </metadata>
-  <metadata name="toolStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
-    <value>401, 17</value>
-  </metadata>
-  <assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
-  <data name="canvasButton.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
-    <value>
-        iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
-        YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAIDSURBVDhPpZLrS5NhGMb3j4SWh0oRQVExD4gonkDpg4hG
-        YKxG6WBogkMZKgPNCEVJFBGdGETEvgwyO9DJE5syZw3PIlPEE9pgBCLZ5XvdMB8Ew8gXbl54nuf63dd9
-        0OGSnwCahxbPRNPAPMw9Xpg6ZmF46kZZ0xSKzJPIrhpDWsVnpBhGkKx3nAX8Pv7z1zg8OoY/cITdn4fw
-        bf/C0kYAN3Ma/w3gWfZL5kzTKBxjWyK2DftwI9tyMYCZKXbNHaD91bLYJrDXsYbrWfUKwJrPE9M2M1Oc
-        VzOOpHI7Jr376Hi9ogHqFIANO0/MmmmbmSmm9a8ze+I4MrNWAdjtoJgWcx+PSzg166yZZ8xM8XvXDix9
-        c4jIqFYAjoriBV9AhEPv1mH/sonogha0afbZMMZz+yreTGyhpusHwtNNCsA5U1zS4BLxzJIfg299qO32
-        Ir7UJtZfftyATqeT+8o2D8JSjQrAJblrncYL7ZJ2+bfaFnC/1S1NjL3diRat7qrO7wLRP3HjWsojBeCo
-        mDEo5mNjuweFGvjWg2EBhCbpkW78htSHHwRyNdmgAFzPEee2iFkzayy2OLXzT4gr6UdUnlXrullsxxQ+
-        kx0g8BTA3aZlButjSTyjODq/WcQcW/B/Je4OQhLvKQDnzN1mp0nnkvAhR8VuMzNrpm1mpjgkoVwB/v8D
-        TgDQASA1MVpwzwAAAABJRU5ErkJggg==
-</value>
-  </data>
-  <data name="drawButton.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
-    <value>
-        iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
-        YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAIDSURBVDhPpZLrS5NhGMb3j4SWh0oRQVExD4gonkDpg4hG
-        YKxG6WBogkMZKgPNCEVJFBGdGETEvgwyO9DJE5syZw3PIlPEE9pgBCLZ5XvdMB8Ew8gXbl54nuf63dd9
-        0OGSnwCahxbPRNPAPMw9Xpg6ZmF46kZZ0xSKzJPIrhpDWsVnpBhGkKx3nAX8Pv7z1zg8OoY/cITdn4fw
-        bf/C0kYAN3Ma/w3gWfZL5kzTKBxjWyK2DftwI9tyMYCZKXbNHaD91bLYJrDXsYbrWfUKwJrPE9M2M1Oc
-        VzOOpHI7Jr376Hi9ogHqFIANO0/MmmmbmSmm9a8ze+I4MrNWAdjtoJgWcx+PSzg166yZZ8xM8XvXDix9
-        c4jIqFYAjoriBV9AhEPv1mH/sonogha0afbZMMZz+yreTGyhpusHwtNNCsA5U1zS4BLxzJIfg299qO32
-        Ir7UJtZfftyATqeT+8o2D8JSjQrAJblrncYL7ZJ2+bfaFnC/1S1NjL3diRat7qrO7wLRP3HjWsojBeCo
-        mDEo5mNjuweFGvjWg2EBhCbpkW78htSHHwRyNdmgAFzPEee2iFkzayy2OLXzT4gr6UdUnlXrullsxxQ+
-        kx0g8BTA3aZlButjSTyjODq/WcQcW/B/Je4OQhLvKQDnzN1mp0nnkvAhR8VuMzNrpm1mpjgkoVwB/v8D
-        TgDQASA1MVpwzwAAAABJRU5ErkJggg==
-</value>
-  </data>
-  <data name="deleteButton.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
-    <value>
-        iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
-        YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAIDSURBVDhPpZLrS5NhGMb3j4SWh0oRQVExD4gonkDpg4hG
-        YKxG6WBogkMZKgPNCEVJFBGdGETEvgwyO9DJE5syZw3PIlPEE9pgBCLZ5XvdMB8Ew8gXbl54nuf63dd9
-        0OGSnwCahxbPRNPAPMw9Xpg6ZmF46kZZ0xSKzJPIrhpDWsVnpBhGkKx3nAX8Pv7z1zg8OoY/cITdn4fw
-        bf/C0kYAN3Ma/w3gWfZL5kzTKBxjWyK2DftwI9tyMYCZKXbNHaD91bLYJrDXsYbrWfUKwJrPE9M2M1Oc
-        VzOOpHI7Jr376Hi9ogHqFIANO0/MmmmbmSmm9a8ze+I4MrNWAdjtoJgWcx+PSzg166yZZ8xM8XvXDix9
-        c4jIqFYAjoriBV9AhEPv1mH/sonogha0afbZMMZz+yreTGyhpusHwtNNCsA5U1zS4BLxzJIfg299qO32
-        Ir7UJtZfftyATqeT+8o2D8JSjQrAJblrncYL7ZJ2+bfaFnC/1S1NjL3diRat7qrO7wLRP3HjWsojBeCo
-        mDEo5mNjuweFGvjWg2EBhCbpkW78htSHHwRyNdmgAFzPEee2iFkzayy2OLXzT4gr6UdUnlXrullsxxQ+
-        kx0g8BTA3aZlButjSTyjODq/WcQcW/B/Je4OQhLvKQDnzN1mp0nnkvAhR8VuMzNrpm1mpjgkoVwB/v8D
-        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
-        YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAIDSURBVDhPpZLrS5NhGMb3j4SWh0oRQVExD4gonkDpg4hG
-        YKxG6WBogkMZKgPNCEVJFBGdGETEvgwyO9DJE5syZw3PIlPEE9pgBCLZ5XvdMB8Ew8gXbl54nuf63dd9
-        0OGSnwCahxbPRNPAPMw9Xpg6ZmF46kZZ0xSKzJPIrhpDWsVnpBhGkKx3nAX8Pv7z1zg8OoY/cITdn4fw
-        bf/C0kYAN3Ma/w3gWfZL5kzTKBxjWyK2DftwI9tyMYCZKXbNHaD91bLYJrDXsYbrWfUKwJrPE9M2M1Oc
-        VzOOpHI7Jr376Hi9ogHqFIANO0/MmmmbmSmm9a8ze+I4MrNWAdjtoJgWcx+PSzg166yZZ8xM8XvXDix9
-        c4jIqFYAjoriBV9AhEPv1mH/sonogha0afbZMMZz+yreTGyhpusHwtNNCsA5U1zS4BLxzJIfg299qO32
-        Ir7UJtZfftyATqeT+8o2D8JSjQrAJblrncYL7ZJ2+bfaFnC/1S1NjL3diRat7qrO7wLRP3HjWsojBeCo
-        mDEo5mNjuweFGvjWg2EBhCbpkW78htSHHwRyNdmgAFzPEee2iFkzayy2OLXzT4gr6UdUnlXrullsxxQ+
-        kx0g8BTA3aZlButjSTyjODq/WcQcW/B/Je4OQhLvKQDnzN1mp0nnkvAhR8VuMzNrpm1mpjgkoVwB/v8D
-        TgDQASA1MVpwzwAAAABJRU5ErkJggg==
-</value>
-  </data>
-  <data name="redoButton.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
-    <value>
-        iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
-        YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAIDSURBVDhPpZLrS5NhGMb3j4SWh0oRQVExD4gonkDpg4hG
-        YKxG6WBogkMZKgPNCEVJFBGdGETEvgwyO9DJE5syZw3PIlPEE9pgBCLZ5XvdMB8Ew8gXbl54nuf63dd9
-        0OGSnwCahxbPRNPAPMw9Xpg6ZmF46kZZ0xSKzJPIrhpDWsVnpBhGkKx3nAX8Pv7z1zg8OoY/cITdn4fw
-        bf/C0kYAN3Ma/w3gWfZL5kzTKBxjWyK2DftwI9tyMYCZKXbNHaD91bLYJrDXsYbrWfUKwJrPE9M2M1Oc
-        VzOOpHI7Jr376Hi9ogHqFIANO0/MmmmbmSmm9a8ze+I4MrNWAdjtoJgWcx+PSzg166yZZ8xM8XvXDix9
-        c4jIqFYAjoriBV9AhEPv1mH/sonogha0afbZMMZz+yreTGyhpusHwtNNCsA5U1zS4BLxzJIfg299qO32
-        Ir7UJtZfftyATqeT+8o2D8JSjQrAJblrncYL7ZJ2+bfaFnC/1S1NjL3diRat7qrO7wLRP3HjWsojBeCo
-        mDEo5mNjuweFGvjWg2EBhCbpkW78htSHHwRyNdmgAFzPEee2iFkzayy2OLXzT4gr6UdUnlXrullsxxQ+
-        kx0g8BTA3aZlButjSTyjODq/WcQcW/B/Je4OQhLvKQDnzN1mp0nnkvAhR8VuMzNrpm1mpjgkoVwB/v8D
-        TgDQASA1MVpwzwAAAABJRU5ErkJggg==
-</value>
-  </data>
-  <metadata name="$this.TrayHeight" type="System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
-    <value>47</value>
-  </metadata>
-</root>

+ 0 - 266
SketchAssistant/SketchAssistant/Line.cs

@@ -1,266 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using System.Drawing;
-
-namespace SketchAssistant
-{
-    public class Line
-    {
-        /// <summary>
-        /// list saving all the points of the line in the order of the path from start to end point
-        /// </summary>
-        private List<Point> linePoints;
-        /// <summary>
-        /// unique identifier of this Line object
-        /// </summary>
-        private int identifier;
-        /// <summary>
-        /// flag showing if this is only a temporary line
-        /// </summary>
-        private bool isTemporary;
-
-        /// <summary>
-        /// The constructor for lines which are only temporary.
-        /// If you want nice lines use the other constructor.
-        /// </summary>
-        /// <param name="points">The points of the line</param>
-        public Line(List<Point> points)
-        {
-            linePoints = new List<Point>(points);
-            isTemporary = true;
-        }
-
-        /// <summary>
-        /// The constructor for lines, which will be more resource efficient 
-        /// and have the ability to populate deletion matrixes.
-        /// </summary>
-        /// <param name="points">The points of the line</param>
-        /// <param name="id">The identifier of the line</param>
-        public Line(List<Point> points, int id)
-        {
-            linePoints = new List<Point>(points);
-            identifier = id;
-            CleanPoints();
-            isTemporary = false;
-        }
-
-        public Point GetStartPoint()
-        {
-            return linePoints.First();
-        }
-
-        public Point GetEndPoint()
-        {
-            return linePoints.Last();
-        }
-
-        public List<Point> GetPoints()
-        {
-            return linePoints;
-        }
-
-        public int GetID()
-        {
-            return identifier;
-        }
-
-        /// <summary>
-        /// A function that takes a Graphics element and returns it with
-        /// the line drawn on it.
-        /// </summary>
-        /// <param name="canvas">The Graphics element on which the line shall be drawn</param>
-        /// <returns>The given Graphics element with the additional line</returns>
-        public Graphics DrawLine(Graphics canvas)
-        {
-            Pen thePen = new Pen(Color.Black);
-            for(int i = 0; i < linePoints.Count - 1 ; i++)
-            {
-                canvas.DrawLine(thePen, linePoints[i], linePoints[i + 1]);
-            }
-            //If there is only one point
-            if(linePoints.Count == 1){ canvas.FillRectangle(Brushes.Black, linePoints[0].X, linePoints[0].Y, 1, 1); }
-            return canvas;
-        }
-
-        /// <summary>
-        /// A function that will take to matrixes and populate the with the line data of this line object
-        /// </summary>
-        /// <param name="boolMatrix">The Matrix of booleans, in which is saved wether there is a line at this position.</param>
-        /// <param name="listMatrix">The Matrix of Lists of integers, in which is saved which lines are at this position</param>
-        public void PopulateMatrixes(bool[,] boolMatrix, HashSet<int>[,] listMatrix)
-        {
-            if(!isTemporary)
-            {
-                foreach (Point currPoint in linePoints)
-                {
-                    if (currPoint.X >= 0 && currPoint.Y >= 0 && 
-                        currPoint.X < boolMatrix.GetLength(0) && currPoint.Y < boolMatrix.GetLength(1))
-                    {
-                        boolMatrix[currPoint.X, currPoint.Y] = true;
-                        if (listMatrix[currPoint.X, currPoint.Y] == null)
-                        {
-                            listMatrix[currPoint.X, currPoint.Y] = new HashSet<int>();
-                        }
-                        listMatrix[currPoint.X, currPoint.Y].Add(identifier);
-                    }
-                }
-            }
-        }
-
-        /// <summary>
-        /// Removes duplicate points from the line object
-        /// </summary>
-        private void CleanPoints()
-        {
-            if (linePoints.Count > 1)
-            {
-                List<Point> newList = new List<Point>();
-                List<Point> tempList = new List<Point>();
-                //Since Point is non-nullable, we must ensure the nullPoints, 
-                //which we remove can not possibly be points of the original given line.
-                int nullValue = linePoints[0].X + 1;
-                //Fill the gaps between points
-                for (int i = 0; i < linePoints.Count - 1; i++)
-                {
-                    nullValue += linePoints[i + 1].X;
-                    List<Point> partialList = BresenhamLineAlgorithm(linePoints[i], linePoints[i + 1]);
-                    tempList.AddRange(partialList);
-                }
-                Point nullPoint = new Point(nullValue, 0);
-                //Set duplicate points to the null point
-                for (int i = 1; i < tempList.Count; i++)
-                {
-                    if ((tempList[i].X == tempList[i - 1].X) && (tempList[i].Y == tempList[i - 1].Y))
-                    {
-                        tempList[i - 1] = nullPoint;
-                    }
-                }
-                //remove the null points
-                foreach (Point tempPoint in tempList)
-                {
-                    if (tempPoint.X != nullValue)
-                    {
-                        newList.Add(tempPoint);
-                    }
-                }
-                linePoints = new List<Point>(newList);
-            }
-        }
-
-        /// <summary>
-        /// An implementation of the Bresenham Line Algorithm, 
-        /// which calculates all points between two points in a straight line.
-        /// Implemented using the pseudocode on Wikipedia.
-        /// </summary>
-        /// <param name="p0">The start point</param>
-        /// <param name="p1">The end point</param>
-        /// <returns>All points between p0 and p1 (including p0 and p1)</returns>
-        public static List<Point> BresenhamLineAlgorithm(Point p0, Point p1)
-        {
-            int deltaX = p1.X - p0.X;
-            int deltaY = p1.Y - p0.Y;
-            List<Point> returnList;
-
-            if (Math.Abs(deltaY) < Math.Abs(deltaX))
-            {
-                if(p0.X > p1.X)
-                {
-                    returnList = GetLineLow(p1.X, p1.Y, p0.X, p0.Y);
-                    returnList.Reverse();
-                }
-                else
-                {
-                    returnList = GetLineLow(p0.X, p0.Y, p1.X, p1.Y);
-                }
-            }
-            else
-            {
-                if (p0.Y > p1.Y)
-                {
-                    returnList = GetLineHigh(p1.X, p1.Y, p0.X, p0.Y);
-                    returnList.Reverse();
-                }
-                else
-                {
-                    returnList = GetLineHigh(p0.X, p0.Y, p1.X, p1.Y);
-                }
-            }
-            return returnList;
-        }
-
-        /// <summary>
-        /// Helping function of the Bresenham Line algorithm,
-        /// under the assumption that abs(deltaY) is smaller than abs(deltX)
-        /// and x0 is smaller than x1
-        /// </summary>
-        /// <param name="x0">x value of point 0</param>
-        /// <param name="y0">y value of point 0</param>
-        /// <param name="x1">x value of point 1</param>
-        /// <param name="y1">y value of point 1</param>
-        /// <returns>All points on the line between the two points</returns>
-        private static List<Point> GetLineLow(int x0, int y0, int x1, int y1)
-        {
-            List<Point> returnList = new List<Point>();
-            int dx = x1 - x0;
-            int dy = y1 - y0;
-            int yi = 1;
-            if(dy < 0)
-            {
-                yi = -1;
-                dy = -dy;
-            }
-            int D = 2 * dy - dx;
-            int y = y0;
-            for (int x = x0; x <= x1; x++)
-            {
-                returnList.Add(new Point(x, y));
-                if (D > 0)
-                {
-                    y = y + yi;
-                    D = D - 2 * dx;
-                }
-                D = D + 2 * dy;
-            }
-            return returnList;
-        }
-
-        /// <summary>
-        /// Helping function of the Bresenham Line algorithm,
-        /// under the assumption that abs(deltaY) is larger or equal than abs(deltX)
-        /// and y0 is smaller than y1
-        /// </summary>
-        /// <param name="x0">x value of point 0</param>
-        /// <param name="y0">y value of point 0</param>
-        /// <param name="x1">x value of point 1</param>
-        /// <param name="y1">y value of point 1</param>
-        /// <returns>All points on the line between the two points</returns>
-        private static List<Point> GetLineHigh(int x0, int y0, int x1, int y1)
-        {
-            List<Point> returnList = new List<Point>();
-            int dx = x1 - x0;
-            int dy = y1 - y0;
-            int xi = 1;
-            if (dx < 0)
-            {
-                xi = -1;
-                dx = -dx;
-            }
-            int D = 2 * dx - dy;
-            int x = x0;
-            for (int y = y0; y <= y1; y++)
-            {
-                returnList.Add(new Point(x, y));
-                if (D > 0)
-                {
-                    x = x + xi;
-                    D = D - 2 * dy;
-                }
-                D = D + 2 * dx;
-            }
-            return returnList;
-        }
-    }
-}

+ 0 - 22
SketchAssistant/SketchAssistant/Program.cs

@@ -1,22 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading.Tasks;
-using System.Windows.Forms;
-
-namespace SketchAssistant
-{
-    static class Program
-    {
-        /// <summary>
-        /// The main entry point for the application.
-        /// </summary>
-        [STAThread]
-        static void Main()
-        {
-            Application.EnableVisualStyles();
-            Application.SetCompatibleTextRenderingDefault(false);
-            Application.Run(new Form1());
-        }
-    }
-}

+ 0 - 36
SketchAssistant/SketchAssistant/Properties/AssemblyInfo.cs

@@ -1,36 +0,0 @@
-using System.Reflection;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-
-// General Information about an assembly is controlled through the following
-// set of attributes. Change these attribute values to modify the information
-// associated with an assembly.
-[assembly: AssemblyTitle("SketchAssistant")]
-[assembly: AssemblyDescription("")]
-[assembly: AssemblyConfiguration("")]
-[assembly: AssemblyCompany("")]
-[assembly: AssemblyProduct("SketchAssistant")]
-[assembly: AssemblyCopyright("Copyright ©  2018")]
-[assembly: AssemblyTrademark("")]
-[assembly: AssemblyCulture("")]
-
-// Setting ComVisible to false makes the types in this assembly not visible
-// to COM components.  If you need to access a type in this assembly from
-// COM, set the ComVisible attribute to true on that type.
-[assembly: ComVisible(false)]
-
-// The following GUID is for the ID of the typelib if this project is exposed to COM
-[assembly: Guid("0336f628-a2f7-4170-8b2e-9277c23118d4")]
-
-// Version information for an assembly consists of the following four values:
-//
-//      Major Version
-//      Minor Version
-//      Build Number
-//      Revision
-//
-// You can specify all the values or you can default the Build and Revision Numbers
-// by using the '*' as shown below:
-// [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion("1.0.0.0")]
-[assembly: AssemblyFileVersion("1.0.0.0")]

+ 0 - 7
SketchAssistant/SketchAssistant/Properties/Settings.settings

@@ -1,7 +0,0 @@
-<?xml version='1.0' encoding='utf-8'?>
-<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)">
-  <Profiles>
-    <Profile Name="(Default)" />
-  </Profiles>
-  <Settings />
-</SettingsFile>

+ 0 - 6
SketchAssistant/SketchAssistant/packages.config

@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<packages>
-  <package id="OpenCover" version="4.6.519" targetFramework="net461" />
-  <package id="System.Runtime.CompilerServices.Unsafe" version="4.5.2" targetFramework="net461" />
-  <package id="System.Threading.Tasks.Extensions" version="4.5.1" targetFramework="net461" />
-</packages>

+ 24 - 17
SketchAssistant/SketchAssistant/ActionHistory.cs → SketchAssistant/SketchAssistantWPF/ActionHistory.cs

@@ -3,9 +3,8 @@ using System.Collections.Generic;
 using System.Linq;
 using System.Text;
 using System.Threading.Tasks;
-using System.Windows.Forms;
 
-namespace SketchAssistant
+namespace SketchAssistantWPF
 {
     public class ActionHistory
     {
@@ -13,22 +12,31 @@ namespace SketchAssistant
         List<SketchAction> actionHistory;
         //The current position in the actionHistory
         Tuple<int, SketchAction> currentAction;
-        //The label in which the current action is displayed
-        ToolStripStatusLabel displayLabel;
 
-        public ActionHistory(ToolStripStatusLabel displayPosition)
+        public ActionHistory()
         {
-            displayLabel = displayPosition;
             actionHistory = new List<SketchAction>();
             currentAction = new Tuple<int, SketchAction>(-1, null);
             AddNewAction(new SketchAction(SketchAction.ActionType.Start, -1));
         }
 
+        /// <summary>
+        /// Resets the action history to its initial state.
+        /// </summary>
+        /// <returns>The new Last Action taken.</returns>
+        public String Reset()
+        {
+            actionHistory.Clear();
+            currentAction = new Tuple<int, SketchAction>(-1, null);
+            return AddNewAction(new SketchAction(SketchAction.ActionType.Start, -1));
+        }
+
         /// <summary>
         /// Adds a new action to the action history.
         /// </summary>
         /// <param name="newAction">The newly added action.</param>
-        public void AddNewAction(SketchAction newAction)
+        /// <returns>The message to be displayed</returns>
+        public String AddNewAction(SketchAction newAction)
         {
             //The current Action is before the last action taken, delete everything after the current action.
             if (currentAction.Item1 < actionHistory.Count - 1)
@@ -37,24 +45,25 @@ namespace SketchAssistant
             }
             actionHistory.Add(newAction);
             currentAction = new Tuple<int, SketchAction>(actionHistory.Count - 1, newAction);
-            UpdateStatusLabel();
+            return UpdateStatusLabel();
         }
 
         /// <summary>
         /// Changes the currentAction.
         /// </summary>
         /// <param name="moveBack">If True, moves the current action back one slot, if False, moves it forward.</param>
-        public void MoveAction(bool moveBack)
+        /// <returns>The message to be displayed</returns>
+        public String MoveAction(bool moveBack)
         {
-            if(moveBack && CanUndo())
+            if (moveBack && CanUndo())
             {
                 currentAction = new Tuple<int, SketchAction>(currentAction.Item1 - 1, actionHistory[currentAction.Item1 - 1]);
             }
-            if(!moveBack && CanRedo())
+            if (!moveBack && CanRedo())
             {
                 currentAction = new Tuple<int, SketchAction>(currentAction.Item1 + 1, actionHistory[currentAction.Item1 + 1]);
             }
-            UpdateStatusLabel();
+            return UpdateStatusLabel();
         }
 
         /// <summary>
@@ -99,12 +108,10 @@ namespace SketchAssistant
         /// <summary>
         /// Updates the status label if there is one given.
         /// </summary>
-        private void UpdateStatusLabel()
+        /// <returns>The message to be displayed</returns>
+        private String UpdateStatusLabel()
         {
-            if (displayLabel != null)
-            {
-                displayLabel.Text = "Last Action: " + currentAction.Item2.GetActionInformation();
-            }
+            return "Last Action: " + currentAction.Item2.GetActionInformation();
         }
     }
 }

+ 6 - 0
SketchAssistant/SketchAssistantWPF/App.config

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<configuration>
+    <startup> 
+        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" />
+    </startup>
+</configuration>

+ 9 - 0
SketchAssistant/SketchAssistantWPF/App.xaml

@@ -0,0 +1,9 @@
+<Application x:Class="SketchAssistantWPF.App"
+             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+             xmlns:local="clr-namespace:SketchAssistantWPF"
+             StartupUri="MainWindow.xaml">
+    <Application.Resources>
+         
+    </Application.Resources>
+</Application>

+ 17 - 0
SketchAssistant/SketchAssistantWPF/App.xaml.cs

@@ -0,0 +1,17 @@
+using System;
+using System.Collections.Generic;
+using System.Configuration;
+using System.Data;
+using System.Linq;
+using System.Threading.Tasks;
+using System.Windows;
+
+namespace SketchAssistantWPF
+{
+    /// <summary>
+    /// Interaction logic for App.xaml
+    /// </summary>
+    public partial class App : Application
+    {
+    }
+}

+ 18 - 0
SketchAssistant/SketchAssistantWPF/CustomCanvas.cs

@@ -0,0 +1,18 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Automation.Peers;
+using System.Windows.Controls;
+
+namespace SketchAssistantWPF
+{
+    public class CustomCanvas : Canvas
+    {
+        protected override AutomationPeer OnCreateAutomationPeer()
+        {
+            return new FrameworkElementAutomationPeer(this);
+        }
+    }
+}

Datei-Diff unterdrückt, da er zu groß ist
+ 11 - 0
SketchAssistant/SketchAssistantWPF/DebugData.cs


+ 17 - 28
SketchAssistant/SketchAssistant/FileImporter.cs → SketchAssistant/SketchAssistantWPF/FileImporter.cs

@@ -1,32 +1,21 @@
 using System;
 using System.Collections.Generic;
-using System.Drawing;
+using System.Windows;
 using System.Linq;
 using System.Text;
 using System.Text.RegularExpressions;
 using System.Threading.Tasks;
 
-namespace SketchAssistant
+namespace SketchAssistantWPF
 {
     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>
         /// <param name="fileName">the path of the input file</param>
         /// <returns>the width and height of the left canvas and the parsed picture as a list of lines</returns>
-        public (int, int, List<Line>) ParseISADInputFile(String fileName)
+        public Tuple<int, int, List<InternalLine>> ParseISADInputFile(String fileName)
         {
             return ParseISADInput(System.IO.File.ReadAllLines(fileName));
         }
@@ -36,7 +25,7 @@ namespace SketchAssistant
         /// </summary>
         /// <param name="allLines">an array holding all lines of the input file</param>
         /// <returns>the width and height of the left canvas and the parsed picture as a list of lines</returns>
-        private (int, int, List<Line>) ParseISADInput(String[] allLines)
+        private Tuple<int, int, List<InternalLine>> ParseISADInput(String[] allLines)
         {
 
             if (allLines.Length == 0)
@@ -52,10 +41,10 @@ namespace SketchAssistant
                 throw new FileImporterException("unterminated drawing definition", ".isad files have to end with the 'enddrawing' token", allLines.Length);
             }
 
-            (int, int) dimensions = ParseISADHeader(allLines);
-            List<Line> picture = ParseISADBody(allLines, dimensions.Item1, dimensions.Item2);
-
-            return (dimensions.Item1, dimensions.Item2, picture);
+            Tuple<int, int> dimensions = ParseISADHeader(allLines);
+            List<InternalLine> picture = ParseISADBody(allLines, dimensions.Item1, dimensions.Item2);
+            
+            return new Tuple<int, int, List<InternalLine>>(dimensions.Item1, dimensions.Item2, picture);
         }
 
 
@@ -65,7 +54,7 @@ namespace SketchAssistant
         /// </summary>
         /// <param name="allLines">the input file as an array of lines</param>
         /// <returns>the width and height of the left canvas</returns>
-        private (int, int) ParseISADHeader(String[] allLines)
+        private Tuple<int, int> ParseISADHeader(String[] allLines)
         {
             int width;
             int height;
@@ -76,7 +65,7 @@ namespace SketchAssistant
             String[] size = allLines[1].Split('x');
             width = Convert.ToInt32(size[0]);
             height = Convert.ToInt32(size[1]);
-            return (width, height);
+            return new Tuple<int, int>(width, height);
         }
 
         /// <summary>
@@ -84,13 +73,13 @@ namespace SketchAssistant
         /// </summary>
         /// <param name="allLines">the input file as an array of lines</param>
         /// <returns>the parsed picture as a list of lines</returns>
-        private List<Line> ParseISADBody(String[] allLines, int width, int height)
+        private List<InternalLine> ParseISADBody(String[] allLines, int width, int height)
         {
 
             String lineStartString = "line";
             String lineEndString = "endline";
 
-            List<Line> drawing = new List<Line>();
+            List<InternalLine> drawing = new List<InternalLine>();
 
             //number of the line currently being parsed, enumeration starting at 0, body starts at the third line, therefore lin number 2
             int i = 2;
@@ -111,7 +100,7 @@ namespace SketchAssistant
                     //parse single point definition
                     if (!Regex.Match(allLines[i], @"^\d+;\d+$", RegexOptions.None).Success)
                     {
-                        throw new FileImporterException("invalid Point definition: wrong format", "format: [xCoordinate];[yCoordinate]", (i + 1) );
+                        throw new FileImporterException("invalid Point definition: wrong format", "format: [xCoordinate];[yCoordinate]", (i + 1));
                     }
                     String[] coordinates = allLines[i].Split(';');
                     //no errors possible, convertability to int already checked above
@@ -119,7 +108,7 @@ namespace SketchAssistant
                     int yCoordinate = Convert.ToInt32(coordinates[1]);
                     if (xCoordinate < 0 || yCoordinate < 0 || xCoordinate > width - 1 || yCoordinate > height - 1)
                     {
-                        throw new FileImporterException("invalid Point definition: point out of bounds", null, (i + 1) );
+                        throw new FileImporterException("invalid Point definition: point out of bounds", null, (i + 1));
                     }
                     newLine.Add(new Point(xCoordinate, yCoordinate));
                     //start parsing next line
@@ -128,12 +117,12 @@ namespace SketchAssistant
                 //"parse" 'endline' token, syntax already checked at the beginning,  and start parsing next line
                 i++;
                 //add line to drawing
-                drawing.Add(new Line(newLine));
+                drawing.Add(new InternalLine(newLine));
                 //update lineStartPointer to the presumable start of the next line
                 lineStartPointer = i;
             }
             //check if end of body is reached after there are no more line definitions
-            if(i != allLines.Length - 1)
+            if (i != allLines.Length - 1)
             {
                 throw new FileImporterException("missing or invalid line definition token", "line definitions start with the 'line' token", (i + 1));
             }
@@ -146,7 +135,7 @@ namespace SketchAssistant
         /// </summary>
         /// <param name="allLines">an array holding all lines of the input file</param>
         /// <returns>the width and height of the left canvas and the parsed picture as a list of lines</returns>
-        public (int, int, List<Line>) ParseISADInputForTesting(String[] allLines)
+        public Tuple<int, int, List<InternalLine>> ParseISADInputForTesting(String[] allLines)
         {
             return ParseISADInput(allLines);
         }

+ 3 - 3
SketchAssistant/SketchAssistant/FileImporterException.cs → SketchAssistant/SketchAssistantWPF/FileImporterException.cs

@@ -4,7 +4,7 @@ using System.Linq;
 using System.Text;
 using System.Threading.Tasks;
 
-namespace SketchAssistant
+namespace SketchAssistantWPF
 {
     public class FileImporterException : Exception
     {
@@ -13,9 +13,9 @@ namespace SketchAssistant
         /// </summary>
         String showMessage;
 
-        public FileImporterException(String message, String hint, int lineNumber) : base (message)
+        public FileImporterException(String message, String hint, int lineNumber) : base(message)
         {
-            showMessage = "Could not import file:\n\n" + message + (hint == null ? "" : "\n(Hint: " + hint + ")") + (lineNumber == -1 ? "" : "\n\n-line: " + lineNumber );
+            showMessage = "Could not import file:\n\n" + message + (hint == null ? "" : "\n(Hint: " + hint + ")") + (lineNumber == -1 ? "" : "\n\n-line: " + lineNumber);
         }
 
         public override string ToString()

+ 209 - 0
SketchAssistant/SketchAssistantWPF/GeometryCalculator.cs

@@ -0,0 +1,209 @@
+using System;
+using System.Collections.Generic;
+using System.Windows;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace SketchAssistantWPF
+{
+    /// <summary>
+    /// A class that contains all algorithms related to geometry.
+    /// </summary>
+    public static class GeometryCalculator
+    {
+        /// <summary>
+        /// An implementation of the Bresenham Line Algorithm,
+        /// which calculates the points of a circle in a radius around a center point.
+        /// Implemented with the help of code examples on Wikipedia.
+        /// </summary>
+        /// <param name="center">The center of the circle.</param>
+        /// <param name="radius">The radius of the circle, 
+        /// when it is zero or less, only the midpoint is returned</param>
+        /// <returns>The HashSet containing all Points on the circle.</returns>
+        public static HashSet<Point> BresenhamCircleAlgorithm(Point center, int radius)
+        {
+            if (radius <= 0) { return new HashSet<Point> { center }; }
+
+            int x = radius - 1;
+            int y = 0;
+            int dx = 1;
+            int dy = 1;
+            int err = dx - (radius * 2);
+            HashSet<Point> returnSet = new HashSet<Point>();
+
+            while (x >= y)
+            {
+                returnSet.Add(new Point(center.X + x, center.Y + y));
+                returnSet.Add(new Point(center.X + y, center.Y + x));
+                returnSet.Add(new Point(center.X - y, center.Y + x));
+                returnSet.Add(new Point(center.X - x, center.Y + y));
+                returnSet.Add(new Point(center.X - x, center.Y - y));
+                returnSet.Add(new Point(center.X - y, center.Y - x));
+                returnSet.Add(new Point(center.X + y, center.Y - x));
+                returnSet.Add(new Point(center.X + x, center.Y - y));
+
+                if (err <= 0)
+                {
+                    y++;
+                    err += dy;
+                    dy += 2;
+                }
+
+                if (err > 0)
+                {
+                    x--;
+                    dx += 2;
+                    err += dx - (radius * 2);
+                }
+            }
+            return returnSet;
+        }
+
+        /// <summary>
+        /// A simple algorithm that returns a filled circle with a radius and a center point.
+        /// </summary>
+        /// <param name="center">The center point of the alorithm </param>
+        /// <param name="radius">The radius of the circle, if its less or equal to 1 
+        /// only the center point is returned. </param>
+        /// <returns>All the points in or on the circle.</returns>
+        public static HashSet<Point> FilledCircleAlgorithm(Point center, int radius)
+        {
+            HashSet<Point> returnSet = new HashSet<Point> { center };
+            //Fill the circle
+            for (int x = 0; x < radius; x++)
+            {
+                for (int y = 0; y < radius; y++)
+                {
+                    //Check if point is on or in the circle
+                    if ((x * x + y * y - radius * radius) <= 0)
+                    {
+                        returnSet.Add(new Point(center.X + x, center.Y + y));
+                        returnSet.Add(new Point(center.X - x, center.Y + y));
+                        returnSet.Add(new Point(center.X + x, center.Y - y));
+                        returnSet.Add(new Point(center.X - x, center.Y - y));
+                    }
+                }
+            }
+            return returnSet;
+        }
+
+        /// <summary>
+        /// An implementation of the Bresenham Line Algorithm, 
+        /// which calculates all points between two points in a straight line.
+        /// Implemented using the pseudocode on Wikipedia.
+        /// </summary>
+        /// <param name="p0">The start point</param>
+        /// <param name="p1">The end point</param>
+        /// <returns>All points between p0 and p1 (including p0 and p1)</returns>
+        public static List<Point> BresenhamLineAlgorithm(Point p0, Point p1)
+        {
+            int p1x = (int)p1.X;
+            int p1y = (int)p1.Y;
+            int p0x = (int)p0.X;
+            int p0y = (int)p0.Y;
+
+            int deltaX = p1x - p0x;
+            int deltaY = p1y - p0y;
+            List<Point> returnList;
+
+            if (Math.Abs(deltaY) < Math.Abs(deltaX))
+            {
+                if (p0.X > p1.X)
+                {
+                    returnList = GetLineLow(p1x, p1y, p0x, p0y);
+                    returnList.Reverse();
+                }
+                else
+                {
+                    returnList = GetLineLow(p0x, p0y, p1x, p1y);
+                }
+            }
+            else
+            {
+                if (p0.Y > p1.Y)
+                {
+                    returnList = GetLineHigh(p1x, p1y, p0x, p0y);
+                    returnList.Reverse();
+                }
+                else
+                {
+                    returnList = GetLineHigh(p0x, p0y, p1x, p1y);
+                }
+            }
+            return returnList;
+        }
+
+        /// <summary>
+        /// Helping function of the Bresenham Line algorithm,
+        /// under the assumption that abs(deltaY) is smaller than abs(deltX)
+        /// and x0 is smaller than x1
+        /// </summary>
+        /// <param name="x0">x value of point 0</param>
+        /// <param name="y0">y value of point 0</param>
+        /// <param name="x1">x value of point 1</param>
+        /// <param name="y1">y value of point 1</param>
+        /// <returns>All points on the line between the two points</returns>
+        private static List<Point> GetLineLow(int x0, int y0, int x1, int y1)
+        {
+            List<Point> returnList = new List<Point>();
+            int dx = x1 - x0;
+            int dy = y1 - y0;
+            int yi = 1;
+            if (dy < 0)
+            {
+                yi = -1;
+                dy = -dy;
+            }
+            int D = 2 * dy - dx;
+            int y = y0;
+            for (int x = x0; x <= x1; x++)
+            {
+                returnList.Add(new Point(x, y));
+                if (D > 0)
+                {
+                    y = y + yi;
+                    D = D - 2 * dx;
+                }
+                D = D + 2 * dy;
+            }
+            return returnList;
+        }
+
+        /// <summary>
+        /// Helping function of the Bresenham Line algorithm,
+        /// under the assumption that abs(deltaY) is larger or equal than abs(deltX)
+        /// and y0 is smaller than y1
+        /// </summary>
+        /// <param name="x0">x value of point 0</param>
+        /// <param name="y0">y value of point 0</param>
+        /// <param name="x1">x value of point 1</param>
+        /// <param name="y1">y value of point 1</param>
+        /// <returns>All points on the line between the two points</returns>
+        private static List<Point> GetLineHigh(int x0, int y0, int x1, int y1)
+        {
+            List<Point> returnList = new List<Point>();
+            int dx = x1 - x0;
+            int dy = y1 - y0;
+            int xi = 1;
+            if (dx < 0)
+            {
+                xi = -1;
+                dx = -dx;
+            }
+            int D = 2 * dx - dy;
+            int x = x0;
+            for (int y = y0; y <= y1; y++)
+            {
+                returnList.Add(new Point(x, y));
+                if (D > 0)
+                {
+                    x = x + xi;
+                    D = D - 2 * dy;
+                }
+                D = D + 2 * dx;
+            }
+            return returnList;
+        }
+    }
+}

+ 27 - 0
SketchAssistant/SketchAssistantWPF/ImageDimension.cs

@@ -0,0 +1,27 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace SketchAssistantWPF
+{
+    public class ImageDimension
+    {
+        public int Width { get; set; }
+
+        public int Height { get; set; }
+
+        public ImageDimension(int width, int height)
+        {
+            Width = width;
+            Height = height;
+        }
+
+        public void ChangeDimension(int width, int height)
+        {
+            Width = width;
+            Height = height;
+        }
+    }
+}

+ 172 - 0
SketchAssistant/SketchAssistantWPF/InternalLine.cs

@@ -0,0 +1,172 @@
+using System;
+using System.Collections.Generic;
+using System.Windows;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Media;
+
+namespace SketchAssistantWPF
+{
+    public class InternalLine
+    {
+        /// <summary>
+        /// list saving all the points of the line in the order of the path from start to end point
+        /// </summary>
+        private List<Point> linePoints;
+        /// <summary>
+        /// unique identifier of this Line object
+        /// </summary>
+        private int identifier;
+        /// <summary>
+        /// flag showing if this is only a temporary line
+        /// </summary>
+        private bool isTemporary;
+        /// <summary>
+        /// A collection of the original Points defining the line.
+        /// </summary>
+        private PointCollection pointColl;
+        /// <summary>
+        /// Indicates if this is a single point.
+        /// </summary>
+        public bool isPoint { get; private set; }
+        /// <summary>
+        /// The location of the point, if this is a point
+        /// </summary>
+        public Point point { get; private set; }
+
+        /// <summary>
+        /// The constructor for lines which are only temporary.
+        /// If you want nice lines use the other constructor.
+        /// </summary>
+        /// <param name="points">The points of the line</param>
+        public InternalLine(List<Point> points)
+        {
+            linePoints = new List<Point>(points);
+            pointColl = new PointCollection(linePoints);
+            isTemporary = true;
+        }
+
+        /// <summary>
+        /// The constructor for lines, which will be more resource efficient 
+        /// and have the ability to populate deletion matrixes.
+        /// </summary>
+        /// <param name="points">The points of the line</param>
+        /// <param name="id">The identifier of the line</param>
+        public InternalLine(List<Point> points, int id)
+        {
+            linePoints = new List<Point>(points);
+            pointColl = new PointCollection(linePoints);
+            identifier = id;
+            CleanPoints();
+            isTemporary = false;
+        }
+
+        public Point GetStartPoint()
+        {
+            return linePoints.First();
+        }
+
+        public Point GetEndPoint()
+        {
+            return linePoints.Last();
+        }
+
+        public List<Point> GetPoints()
+        {
+            return linePoints;
+        }
+
+        public int GetID()
+        {
+            return identifier;
+        }
+
+        public PointCollection GetPointCollection()
+        {
+            return pointColl;
+        }
+
+        /// <summary>
+        /// A function that will take two matrixes and populate them with the line data of this line object
+        /// </summary>
+        /// <param name="boolMatrix">The Matrix of booleans, in which is saved wether there is a line at this position.</param>
+        /// <param name="listMatrix">The Matrix of Lists of integers, in which is saved which lines are at this position</param>
+        public void PopulateMatrixes(bool[,] boolMatrix, HashSet<int>[,] listMatrix)
+        {
+            if (!isTemporary)
+            {
+                foreach (Point currPoint in linePoints)
+                {
+                    if (currPoint.X >= 0 && currPoint.Y >= 0 &&
+                        currPoint.X < boolMatrix.GetLength(0) && currPoint.Y < boolMatrix.GetLength(1))
+                    {
+                        boolMatrix[(int) currPoint.X, (int) currPoint.Y] = true;
+                        if (listMatrix[(int) currPoint.X, (int) currPoint.Y] == null)
+                        {
+                            listMatrix[(int) currPoint.X, (int) currPoint.Y] = new HashSet<int>();
+                        }
+                        listMatrix[(int) currPoint.X, (int) currPoint.Y].Add(identifier);
+                    }
+                }
+            }
+        }
+
+        /// <summary>
+        /// Removes duplicate points from the line object
+        /// </summary>
+        private void CleanPoints()
+        {
+            if (linePoints.Count > 1)
+            {
+                //if this is a point or not
+                var localIsPoint = true;
+                //check if its a point
+                foreach(Point p in linePoints)
+                {
+                    if (p.X != linePoints[0].X || p.Y != linePoints[0].Y)
+                        localIsPoint = false;
+                }
+                if (!localIsPoint) {
+                    List<Point> newList = new List<Point>();
+                    List<Point> tempList = new List<Point>();
+                    //Since Point is non-nullable, we must ensure the nullPoints, 
+                    //which we remove can not possibly be points of the original given line.
+                    int nullValue = (int) linePoints[0].X + 1;
+                    //Fill the gaps between points
+                    for (int i = 0; i < linePoints.Count - 1; i++)
+                    {
+                        nullValue += (int) linePoints[i + 1].X;
+                        List<Point> partialList = GeometryCalculator.BresenhamLineAlgorithm(linePoints[i], linePoints[i + 1]);
+                        tempList.AddRange(partialList);
+                    }
+                    Point nullPoint = new Point(nullValue, 0);
+                    //Set duplicate points to the null point
+                    for (int i = 1; i < tempList.Count; i++)
+                    {
+                        if ((tempList[i].X == tempList[i - 1].X) && (tempList[i].Y == tempList[i - 1].Y))
+                        {
+                            tempList[i - 1] = nullPoint;
+                        }
+                    }
+                    //remove the null points
+                    foreach (Point tempPoint in tempList)
+                    {
+                        if (tempPoint.X != nullValue)
+                        {
+                            newList.Add(tempPoint);
+                        }
+                    }
+                    linePoints = new List<Point>(newList);
+                }
+                else
+                {
+                    isPoint = true;
+                    point = linePoints[0];
+                    linePoints = new List<Point>();
+                    linePoints.Add(point);
+                }
+            }
+        }
+    }
+}

+ 456 - 0
SketchAssistant/SketchAssistantWPF/MVP_Model.cs

@@ -0,0 +1,456 @@
+using System;
+using System.Collections.Generic;
+using System.Windows;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Controls;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+
+namespace SketchAssistantWPF
+{
+    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;
+
+
+        /***********************/
+        /*** CLASS VARIABLES ***/
+        /***********************/
+
+        /// <summary>
+        /// If the program is in drawing mode.
+        /// </summary>
+        bool inDrawingMode;
+        /// <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;
+
+        public ImageDimension leftImageSize { get; private set; }
+
+        public ImageDimension rightImageSize { get; private set; }
+        /// <summary>
+        /// Indicates whether or not the canvas on the right side is active.
+        /// </summary>
+        public bool canvasActive {get; set;}
+        /// <summary>
+        /// Indicates if there is a graphic loaded in the left canvas.
+        /// </summary>
+        public bool graphicLoaded { get; set; }
+        /// <summary>
+        /// Whether or not the mouse is pressed.
+        /// </summary>
+        private bool mouseDown;
+
+        Image rightImageWithoutOverlay;
+
+        List<InternalLine> leftLineList;
+        
+        List<Tuple<bool, InternalLine>> rightLineList;
+
+        List<Point> currentLine = new List<Point>();
+
+
+
+        public MVP_Model(MVP_Presenter presenter)
+        {
+            programPresenter = presenter;
+            historyOfActions = new ActionHistory();
+            //redrawAss = new RedrawAssistant();
+            //overlayItems = new List<Tuple<bool, HashSet<Point>>>();
+            rightLineList = new List<Tuple<bool, InternalLine>>();
+            canvasActive = false;
+            UpdateUI();
+            rightImageSize = new ImageDimension(0, 0);
+            leftImageSize = new ImageDimension(0, 0);
+        }
+
+        /**************************/
+        /*** INTERNAL FUNCTIONS ***/
+        /**************************/
+
+
+        /// <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)
+        {
+            foreach (int lineId in lines)
+            {
+                if (lineId <= rightLineList.Count - 1 && lineId >= 0)
+                {
+                    rightLineList[lineId] = new Tuple<bool, InternalLine>(shown, rightLineList[lineId].Item2);
+                }
+            }
+        }
+
+        /// <summary>
+        /// A function that populates the matrixes needed for deletion detection with line data.
+        /// </summary>
+        private void RepopulateDeletionMatrixes()
+        {
+            if (canvasActive)
+            {
+                isFilledMatrix = new bool[rightImageSize.Width, rightImageSize.Height];
+                linesMatrix = new HashSet<int>[rightImageSize.Width, rightImageSize.Height];
+                foreach (Tuple<bool, InternalLine> lineTuple in rightLineList)
+                {
+                    if (lineTuple.Item1)
+                    {
+                        lineTuple.Item2.PopulateMatrixes(isFilledMatrix, linesMatrix);
+                    }
+                }
+            }
+        }
+
+        /// <summary>
+        /// Tells the Presenter to Update the UI
+        /// </summary>
+        private void UpdateUI()
+        {
+            programPresenter.UpdateUIState(inDrawingMode, historyOfActions.CanUndo(), historyOfActions.CanRedo(), canvasActive, graphicLoaded);
+        }
+
+        /// <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 < rightImageSize.Width && pnt.Y < rightImageSize.Height)
+                {
+                    if (isFilledMatrix[(int)pnt.X, (int)pnt.Y])
+                    {
+                        returnSet.UnionWith(linesMatrix[(int)pnt.X, (int)pnt.Y]);
+                    }
+                }
+            }
+            return returnSet;
+        }
+
+        /********************************************/
+        /*** FUNCTIONS TO INTERACT WITH PRESENTER ***/
+        /********************************************/
+
+        /// <summary>
+        /// A function to update the dimensions of the left and right canvas when the window is resized.
+        /// </summary>
+        /// <param name="LeftCanvas">The size of the left canvas.</param>
+        /// <param name="RightCanvas">The size of the right canvas.</param>
+        public void ResizeEvent(ImageDimension LeftCanvas, ImageDimension RightCanvas)
+        {
+            if(LeftCanvas.Height >= 0 && LeftCanvas.Width>= 0) { leftImageSize = LeftCanvas; }
+            if(RightCanvas.Height >= 0 && RightCanvas.Width >= 0) { rightImageSize = RightCanvas; }
+          
+            RepopulateDeletionMatrixes();
+        }
+
+        /// <summary>
+        /// A function to reset the right image.
+        /// </summary>
+        public void ResetRightImage()
+        {
+            rightLineList.Clear();
+            programPresenter.PassLastActionTaken(historyOfActions.Reset());
+            programPresenter.ClearRightLines();
+        }
+
+        /// <summary>
+        /// The function to set the left image.
+        /// </summary>
+        /// <param name="width">The width of the left image.</param>
+        /// <param name="height">The height of the left image.</param>
+        /// <param name="listOfLines">The List of Lines to be displayed in the left image.</param>
+        public void SetLeftLineList(int width, int height, List<InternalLine> listOfLines)
+        {
+            leftImageSize = new ImageDimension(width, height);
+            rightImageSize = new ImageDimension(width, height);
+            leftLineList = listOfLines;
+            graphicLoaded = true;
+            programPresenter.UpdateLeftLines(leftLineList);
+            CanvasActivated();
+            /*
+            var workingCanvas = GetEmptyCanvas(width, height);
+            var workingGraph = Graphics.FromImage(workingCanvas);
+            leftLineList = listOfLines;
+            //redrawAss = new RedrawAssistant(leftLineList);
+            //overlayItems = redrawAss.Initialize(markerRadius);
+            //Lines
+            foreach (InternalLine line in leftLineList)
+            {
+                line.DrawLine(workingGraph);
+            }
+            leftImage = workingCanvas;
+            programPresenter.UpdateLeftImage(leftImage);
+            //Set right image to same size as left image and delete linelist
+            DrawEmptyCanvasRight();
+            rightLineList = new List<Tuple<bool, InternalLine>>();
+            */
+        }
+
+        /// <summary>
+        /// A function to tell the model a new canvas was activated.
+        /// </summary>
+        public void CanvasActivated()
+        {
+            canvasActive = true;
+            RepopulateDeletionMatrixes();
+            UpdateUI();
+        }
+
+        /// <summary>
+        /// Will undo the last action taken, if the action history allows it.
+        /// </summary>
+        public void Undo()
+        {
+            if (historyOfActions.CanUndo())
+            {
+                HashSet<int> affectedLines = historyOfActions.GetCurrentAction().GetLineIDs();
+                SketchAction.ActionType undoAction = historyOfActions.GetCurrentAction().GetActionType();
+                switch (undoAction)
+                {
+                    case SketchAction.ActionType.Delete:
+                        //Deleted Lines need to be shown
+                        ChangeLines(affectedLines, true);
+                        break;
+                    case SketchAction.ActionType.Draw:
+                        //Drawn lines need to be hidden
+                        ChangeLines(affectedLines, false);
+                        break;
+                    default:
+                        break;
+                }
+                //TODO: For the person implementing overlay: Add check if overlay needs to be added
+                programPresenter.UpdateRightLines(rightLineList);
+            }
+            RepopulateDeletionMatrixes();
+            programPresenter.PassLastActionTaken(historyOfActions.MoveAction(true));
+            UpdateUI();
+        }
+
+        /// <summary>
+        /// Will redo the last action undone, if the action history allows it.
+        /// </summary>
+        public void Redo()
+        {
+            if (historyOfActions.CanRedo())
+            {
+                programPresenter.PassLastActionTaken(historyOfActions.MoveAction(false));
+                HashSet<int> affectedLines = historyOfActions.GetCurrentAction().GetLineIDs();
+                SketchAction.ActionType redoAction = historyOfActions.GetCurrentAction().GetActionType();
+                switch (redoAction)
+                {
+                    case SketchAction.ActionType.Delete:
+                        //Deleted Lines need to be redeleted
+                        ChangeLines(affectedLines, false);
+                        break;
+                    case SketchAction.ActionType.Draw:
+                        //Drawn lines need to be redrawn
+                        ChangeLines(affectedLines, true);
+                        break;
+                    default:
+                        break;
+                }
+                //TODO: For the person implementing overlay: Add check if overlay needs to be added
+                programPresenter.UpdateRightLines(rightLineList);
+                RepopulateDeletionMatrixes();
+            }
+            UpdateUI();
+        }
+
+        /// <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>
+        /// Updates the current cursor position of the model.
+        /// </summary>
+        /// <param name="p">The new cursor position</param>
+        public void SetCurrentCursorPosition(Point p)
+        {
+            currentCursorPosition = p;
+            mouseDown = programPresenter.IsMousePressed();
+        }
+
+        /// <summary>
+        /// Start a new Line, when the Mouse is pressed down.
+        /// </summary>
+        public void MouseDown()
+        {
+            mouseDown = true;
+            if (inDrawingMode && mouseDown)
+            {
+                currentLine.Clear();
+                currentLine.Add(currentCursorPosition);
+            }
+        }
+
+        /// <summary>
+        /// Finish the current Line, when the pressed Mouse is released.
+        /// </summary>
+        public void MouseUp()
+        {
+            mouseDown = false;
+            if (inDrawingMode && currentLine.Count > 0)
+            {
+                InternalLine newLine = new InternalLine(currentLine, rightLineList.Count);
+                rightLineList.Add(new Tuple<bool, InternalLine>(true, newLine));
+                newLine.PopulateMatrixes(isFilledMatrix, linesMatrix);
+                programPresenter.PassLastActionTaken(historyOfActions.AddNewAction(new SketchAction(SketchAction.ActionType.Draw, newLine.GetID())));
+                //TODO: For the person implementing overlay: Add check if overlay needs to be added
+                programPresenter.UpdateRightLines(rightLineList);
+                currentLine.Clear();
+                programPresenter.UpdateCurrentLine(currentLine);
+            }
+            UpdateUI();
+        }
+
+        /// <summary>
+        /// Method to be called every tick. Updates the current Line, or checks for Lines to delete, depending on the drawing mode.
+        /// </summary>
+        public void Tick()
+        {
+            if (cursorPositions.Count > 0) { previousCursorPosition = cursorPositions.Dequeue(); }
+            else { previousCursorPosition = currentCursorPosition; }
+            cursorPositions.Enqueue(currentCursorPosition);
+            //Drawing
+            if (inDrawingMode && programPresenter.IsMousePressed())
+            {
+                currentLine.Add(currentCursorPosition);
+                programPresenter.UpdateCurrentLine(currentLine);
+            }
+            //Deleting
+            if (!inDrawingMode && programPresenter.IsMousePressed())
+            {
+                List<Point> uncheckedPoints = GeometryCalculator.BresenhamLineAlgorithm(previousCursorPosition, currentCursorPosition);
+                foreach (Point currPoint in uncheckedPoints)
+                {
+                    HashSet<int> linesToDelete = CheckDeletionMatrixesAroundPoint(currPoint, deletionRadius);
+                    if (linesToDelete.Count > 0)
+                    {
+                        programPresenter.PassLastActionTaken(historyOfActions.AddNewAction(new SketchAction(SketchAction.ActionType.Delete, linesToDelete)));
+                        foreach (int lineID in linesToDelete)
+                        {
+                            rightLineList[lineID] = new Tuple<bool, InternalLine>(false, rightLineList[lineID].Item2);
+                        }
+                        RepopulateDeletionMatrixes();
+                        //TODO: For the person implementing overlay: Add check if overlay needs to be added
+                        programPresenter.UpdateRightLines(rightLineList);
+                    }
+                }
+            }
+        }
+
+        /// <summary>
+        /// A helper Function that updates the markerRadius & deletionRadius, considering the size of the canvas.
+        /// </summary>
+        /// <param name="CanvasSize">The size of the canvas</param>
+        public void UpdateSizes(ImageDimension CanvasSize)
+        {
+            if (rightImageWithoutOverlay != null)
+            {
+                int widthImage = rightImageSize.Width;
+                int heightImage = rightImageSize.Height;
+                int widthBox = CanvasSize.Width;
+                int heightBox = CanvasSize.Height;
+
+                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);
+                deletionRadius = (int)(5 * zoomFactor);
+            }
+        }
+
+        /// <summary>
+        /// If there is unsaved progress.
+        /// </summary>
+        /// <returns>True if there is progress that has not been saved.</returns>
+        public bool HasUnsavedProgress()
+        {
+            return !historyOfActions.IsEmpty();
+        }
+    }
+}

+ 423 - 0
SketchAssistant/SketchAssistantWPF/MVP_Presenter.cs

@@ -0,0 +1,423 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Shapes;
+
+namespace SketchAssistantWPF
+{
+    public class MVP_Presenter
+    {
+        /// <summary>
+        /// The View of the MVP-Model, in this case Form1.
+        /// </summary>
+        MVP_View programView;
+        /// <summary>
+        /// The Model of the MVP-Model.
+        /// </summary>
+        MVP_Model programModel;
+        /// <summary>
+        /// A dictionary connecting the id of an InternalLine with the respective Polyline in the right canvas.
+        /// </summary>
+        Dictionary<int, Shape> rightPolyLines;
+
+        ImageDimension CanvasSizeLeft = new ImageDimension(0,0);
+
+        ImageDimension CanvasSizeRight = new ImageDimension(0, 0);
+
+        ImageDimension ImageSizeLeft = new ImageDimension(0, 0);
+
+        ImageDimension ImageSizeRight = new ImageDimension(0, 0);
+
+        /*******************/
+        /*** ENUMERATORS ***/
+        /*******************/
+
+        public enum MouseAction
+        {
+            Click,
+            Down,
+            Up,
+            Move
+        }
+
+        /***********************/
+        /*** CLASS VARIABLES ***/
+        /***********************/
+
+        /// <summary>
+        /// Instance of FileImporter to handle drawing imports.
+        /// </summary>
+        private FileImporter fileImporter;
+
+
+        public MVP_Presenter(MVP_View form)
+        {
+            programView = form;
+            programModel = new MVP_Model(this);
+            //Initialize Class Variables
+            fileImporter = new FileImporter();
+        }
+
+        /***********************************/
+        /*** FUNCTIONS VIEW -> PRESENTER ***/
+        /***********************************/
+
+        /// <summary>
+        /// Pass-trough function to update the appropriate information of the model, when the window is resized.
+        /// </summary>
+        /// <param name="leftPBS">The new size of the left picture box.</param>
+        /// <param name="rightPBS">The new size of the left picture box.</param>
+        public void Resize(Tuple<int, int> leftPBS, Tuple<int, int> rightPBS)
+        {
+            CanvasSizeLeft.ChangeDimension(leftPBS.Item1, leftPBS.Item2);
+            CanvasSizeRight.ChangeDimension(rightPBS.Item1, rightPBS.Item2);
+            programModel.UpdateSizes(CanvasSizeRight);
+            programModel.ResizeEvent(CanvasSizeLeft, CanvasSizeRight);
+        }
+
+        /// <summary>
+        /// Display a new FileDialog to load a collection of lines.
+        /// </summary>
+        public void ExamplePictureToolStripMenuItemClick()
+        {
+            var okToContinue = true;
+            if (programModel.HasUnsavedProgress())
+            {
+                okToContinue = programView.ShowWarning("You have unsaved progress. Continue?");
+            }
+            if (okToContinue)
+            {
+                var fileNameTup = programView.openNewDialog("Interactive Sketch-Assistant Drawing|*.isad");
+                if (!fileNameTup.Item1.Equals("") && !fileNameTup.Item2.Equals(""))
+                {
+                    programView.SetToolStripLoadStatus(fileNameTup.Item2);
+                    Tuple<int, int, List<InternalLine>> values = fileImporter.ParseISADInputFile(fileNameTup.Item1);
+                    programModel.SetLeftLineList(values.Item1, values.Item2, values.Item3);
+
+                    programModel.ResetRightImage();
+                    programModel.CanvasActivated();
+                    programModel.ChangeState(true);
+                    programView.EnableTimer();
+                    ClearRightLines();
+                }
+            }
+        }
+
+        /// <summary>
+        /// Pass-trough function to change the drawing state of the model.
+        /// </summary>
+        /// <param name="NowDrawing">Indicates if the program is in drawing (true) or deletion (false) mode.</param>
+        public void ChangeState(bool NowDrawing)
+        {
+            programModel.ChangeState(NowDrawing);
+        }
+
+        /// <summary>
+        /// Pass-trough function to undo an action.
+        /// </summary>
+        public void Undo()
+        {
+            programModel.Undo();
+        }
+
+        /// <summary>
+        /// Pass-trough function to redo an action.
+        /// </summary>
+        public void Redo()
+        {
+            programModel.Redo();
+        }
+
+        /// <summary>
+        /// Pass-trough function for ticking the model.
+        /// </summary>
+        public void Tick()
+        {
+            programModel.Tick();
+        }
+
+        /// <summary>
+        /// Checks if there is unsaved progress, and promts the model to generate a new canvas if not.
+        /// </summary>
+        public void NewCanvas()
+        {
+            var okToContinue = true;
+            if (programModel.HasUnsavedProgress())
+            {
+                okToContinue = programView.ShowWarning("You have unsaved progress. Continue?");
+            }
+            if (okToContinue)
+            {
+                programModel.ResizeEvent(CanvasSizeLeft, CanvasSizeRight);
+                programModel.ResetRightImage();
+                programModel.CanvasActivated();
+                programModel.ChangeState(true);
+                programView.EnableTimer();
+                ClearRightLines();
+            }
+        }
+
+        /// <summary>
+        /// Pass-trough when the mouse is moved.
+        /// </summary>
+        /// <param name="mouseAction">The action which is sent by the View.</param>
+        /// <param name="e">The Mouse event arguments.</param>
+        public void MouseEvent(MouseAction mouseAction, Point position)
+        {
+            switch (mouseAction)
+            {
+                case MouseAction.Move:
+                    programModel.SetCurrentCursorPosition(position);
+                    break;
+                default:
+                    break;
+            }
+        }
+
+        /// <summary>
+        /// Pass-trough function that calls the correct Mouse event of the model, when the mouse is clicked.
+        /// </summary>
+        /// <param name="mouseAction">The action which is sent by the View.</param>
+        /// <param name="e">The Mouse event arguments.</param>
+        public void MouseEvent(MouseAction mouseAction)
+        {
+            switch (mouseAction)
+            {
+                case MouseAction.Click:
+                    programModel.MouseDown();
+                    programModel.Tick();
+                    programModel.MouseUp();
+                    break;
+                case MouseAction.Down:
+                    programModel.MouseDown();
+                    break;
+                case MouseAction.Up:
+                    programModel.MouseUp();
+                    break;
+                default:
+                    break;
+            }
+        }
+
+        /************************************/
+        /*** FUNCTIONS MODEL -> PRESENTER ***/
+        /************************************/
+
+        /// <summary>
+        /// Return the position of the cursor
+        /// </summary>
+        /// <returns>The position of the cursor</returns>
+        public Point GetCursorPosition()
+        {
+            return programView.GetCursorPosition();
+        }
+
+        /// <summary>
+        /// Updates the currentline
+        /// </summary>
+        /// <param name="linepoints">The points of the current line.</param>
+        public void UpdateCurrentLine(List<Point> linepoints)
+        {
+            Polyline currentLine = new Polyline();
+            currentLine.Stroke = Brushes.Black;
+            currentLine.Points = new PointCollection(linepoints);
+            programView.DisplayCurrLine(currentLine);
+        }
+
+        /// <summary>
+        /// Clears all Lines in the right canvas.
+        /// </summary>
+        public void ClearRightLines()
+        {
+            programView.RemoveAllRightLines();
+            rightPolyLines = new Dictionary<int, Shape>();
+        }
+
+        /// <summary>
+        /// A function to update the displayed lines in the right canvas.
+        /// </summary>
+        public void UpdateRightLines(List<Tuple<bool, InternalLine>> lines)
+        {
+            foreach(Tuple<bool, InternalLine> tup in lines)
+            {
+                var status = tup.Item1;
+                var line = tup.Item2;
+                if (!rightPolyLines.ContainsKey(line.GetID()))
+                {
+                    if (!line.isPoint)
+                    {
+                        Polyline newLine = new Polyline();
+                        newLine.Points = line.GetPointCollection();
+                        rightPolyLines.Add(line.GetID(), newLine);
+                        programView.AddNewLineRight(newLine);
+                    }
+                    else
+                    {
+                        Ellipse newPoint = new Ellipse();
+                        newPoint.SetValue(Canvas.LeftProperty, line.point.X);
+                        newPoint.SetValue(Canvas.TopProperty, line.point.Y);
+                        rightPolyLines.Add(line.GetID(), newPoint);
+                        programView.AddNewPointRight(newPoint);
+                    }
+                }
+                SetVisibility(rightPolyLines[line.GetID()], status);
+            }
+        }
+
+        /// <summary>
+        /// A function to update the displayed lines in the left canvas.
+        /// </summary>
+        public void UpdateLeftLines(List<InternalLine> lines)
+        {
+            programView.RemoveAllLeftLines();
+            foreach (InternalLine line in lines)
+            {
+                Polyline newLine = new Polyline();
+                newLine.Stroke = Brushes.Black;
+                newLine.Points = line.GetPointCollection();
+                programView.AddNewLineLeft(newLine);
+            }
+            programView.SetCanvasState("LeftCanvas", true);
+            programView.SetCanvasState("RightCanvas", true);
+        }
+
+        /// <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="canvasActive">If the right canvas is active</param>
+        /// <param name="graphicLoaded">If an image is loaded in the model</param>
+        public void UpdateUIState(bool inDrawingMode, bool canUndo, bool canRedo, bool canvasActive, bool graphicLoaded)
+        {
+            Dictionary<String, MainWindow.ButtonState> dict = new Dictionary<String, MainWindow.ButtonState> {
+                {"canvasButton", MainWindow.ButtonState.Enabled }, {"drawButton", MainWindow.ButtonState.Disabled}, {"deleteButton",MainWindow.ButtonState.Disabled },
+                {"undoButton", MainWindow.ButtonState.Disabled },{"redoButton",  MainWindow.ButtonState.Disabled}};
+
+            if (canvasActive)
+            {
+                if (inDrawingMode)
+                {
+                    dict["drawButton"] = MainWindow.ButtonState.Active;
+                    dict["deleteButton"] = MainWindow.ButtonState.Enabled;
+                }
+                else
+                {
+                    dict["drawButton"] = MainWindow.ButtonState.Enabled;
+                    dict["deleteButton"] = MainWindow.ButtonState.Active;
+                }
+                if (canUndo) { dict["undoButton"] = MainWindow.ButtonState.Enabled; }
+                if (canRedo) { dict["redoButton"] = MainWindow.ButtonState.Enabled; }
+            }
+            foreach (KeyValuePair<String, MainWindow.ButtonState> entry in dict)
+            {
+                programView.SetToolStripButtonStatus(entry.Key, entry.Value);
+            }
+            programView.SetCanvasState("RightCanvas", canvasActive);
+            programView.SetCanvasState("LeftCanvas", graphicLoaded);
+        }
+
+
+        /// <summary>
+        /// Pass-trough function to display an info message in the view.
+        /// </summary>
+        /// <param name="msg">The message.</param>
+        public void PassMessageToView(String msg)
+        {
+            programView.ShowInfoMessage(msg);
+        }
+
+        /// <summary>
+        /// Pass-trough function to update the display of the last action taken.
+        /// </summary>
+        /// <param name="msg">The new last action taken.</param>
+        public void PassLastActionTaken(String msg)
+        {
+            programView.SetLastActionTakenText(msg);
+        }
+
+        /// <summary>
+        /// Passes whether or not the mouse is pressed.
+        /// </summary>
+        /// <returns>Whether or not the mouse is pressed</returns>
+        public bool IsMousePressed()
+        {
+            return programView.IsMousePressed();
+        }
+
+        /*************************/
+        /*** HELPING FUNCTIONS ***/
+        /*************************/
+
+        /// <summary>
+        /// Sets the visibility of a polyline.
+        /// </summary>
+        /// <param name="line">The polyline</param>
+        /// <param name="visible">Whether or not it should be visible.</param>
+        private void SetVisibility(Shape line, bool visible)
+        {
+            if (!visible)
+            {
+                line.Opacity = 0.00001;
+            }
+            else
+            {
+                line.Opacity = 1;
+            }
+        }
+
+        /// <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)
+        {
+            if (!programModel.canvasActive) { return cursorPosition; }
+            if (programModel.canvasActive && !programModel.graphicLoaded) { return cursorPosition; }
+            ImageDimension rightImageDimensions = programModel.rightImageSize;
+            Point realCoordinates = new Point(0, 0);
+
+            int widthImage = rightImageDimensions.Width;
+            int heightImage = rightImageDimensions.Height;
+            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;
+        }
+    }
+}

+ 123 - 0
SketchAssistant/SketchAssistantWPF/MVP_View.cs

@@ -0,0 +1,123 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Shapes;
+
+namespace SketchAssistantWPF
+{
+    public interface MVP_View
+    {
+        /// <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>
+        void SetCanvasState(string canvasName, bool active);
+
+        /// <summary>
+        /// Remove the current line.
+        /// </summary>
+        void RemoveCurrLine();
+
+        /// <summary>
+        /// Display the current line.
+        /// </summary>
+        /// <param name="line">The current line to display</param>
+        void DisplayCurrLine(Polyline line);
+
+        /// <summary>
+        /// Removes all Lines from the left canvas.
+        /// </summary>
+        void RemoveAllLeftLines();
+
+        /// <summary>
+        /// Removes all lines in the right canvas.
+        /// </summary>
+        void RemoveAllRightLines();
+
+        /// <summary>
+        /// Adds another Line that will be displayed in the left display.
+        /// </summary>
+        /// <param name="newLine">The new Polyline to be added displayed.</param>
+        void AddNewLineLeft(Polyline 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>
+        void AddNewLineRight(Polyline newLine);
+
+        /// <summary>
+        /// Enables the timer of the View, which will tick the Presenter.
+        /// </summary>
+        void EnableTimer();
+
+        /// <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>
+        Tuple<String, String> openNewDialog(String Filter);
+
+        /// <summary>
+        /// Sets the contents of the load status indicator label.
+        /// </summary>
+        /// <param name="message">The new contents</param>
+        void SetToolStripLoadStatus(String message);
+
+        /// <summary>
+        /// Sets the contents of the last action taken indicator label.
+        /// </summary>
+        /// <param name="message">The new contents</param>
+        void SetLastActionTakenText(String 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>
+        void SetToolStripButtonStatus(String buttonName, MainWindow.ButtonState state);
+
+        /// <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>
+        void ShowInfoMessage(String 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>
+        bool ShowWarning(String message);
+
+        /// <summary>
+        /// If the mouse is pressed or not.
+        /// </summary>
+        /// <returns>Whether or not the mouse is pressed.</returns>
+        bool IsMousePressed();
+
+        /// <summary>
+        /// Adds a point to the right canvas
+        /// </summary>
+        /// <param name="newPoint">The point</param>
+        void AddNewPointRight(Ellipse newPoint);
+
+        /// <summary>
+        /// Adds a point to the left canvas
+        /// </summary>
+        /// <param name="newPoint">The point</param>
+        void AddNewPointLeft(Ellipse newPoint);
+
+        /// <summary>
+        /// Returns the cursor position.
+        /// </summary>
+        /// <returns>The cursor Position</returns>
+        Point GetCursorPosition();
+    }
+}

+ 193 - 0
SketchAssistant/SketchAssistantWPF/MainWindow.xaml

@@ -0,0 +1,193 @@
+<Window x:Class="SketchAssistantWPF.MainWindow"
+        xmlns:local="clr-namespace:SketchAssistantWPF"
+        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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+        mc:Ignorable="d"
+        Title="Sketch Assistant" Height="612" Width="914" SizeChanged="Window_SizeChanged">
+    <Grid>
+        <Grid.ColumnDefinitions>
+            <ColumnDefinition Width="auto"/>
+            <ColumnDefinition Width="auto"/>
+            <ColumnDefinition Width="170*"/>
+            <ColumnDefinition Width="55*"/>
+            <ColumnDefinition Width="225*"/>
+            <ColumnDefinition Width="5"/>
+            <ColumnDefinition Width="226*"/>
+            <ColumnDefinition Width="225*"/>
+            <ColumnDefinition Width="auto"/>
+            <ColumnDefinition Width="auto"/>
+        </Grid.ColumnDefinitions>
+        <Grid.RowDefinitions>
+            <RowDefinition Height="auto"/>
+            <RowDefinition Height="*"/>
+            <RowDefinition Height="auto"/>
+        </Grid.RowDefinitions>
+        <ToolBar x:Name="MenuToolbar" Grid.Column="0" Grid.ColumnSpan="5" Grid.Row="0" Background="LightGray">
+            <Menu Background="LightGray">
+                <MenuItem x:Name="LoadMenuButton" Header="Load">
+                    <MenuItem x:Name="SVGMenuButton" Header="Load SVG File" Click="MenuItem_Click"/>
+                </MenuItem>
+                <MenuItem x:Name="EditMenuButton" Header="Edit">
+                    <MenuItem x:Name="CanvasMenuButton" Header="New Canvas" Click="CanvasButton_Click"/>
+                    <MenuItem x:Name="UndoMenuButton" Header="Undo" Click="UndoButton_Click"/>
+                    <MenuItem x:Name="RedoMenuButton" Header="Redo" Click="RedoButton_Click"/>
+                    <MenuItem x:Name="DebugMode" Header="Debug Input">
+                        <MenuItem x:Name="DebugOne" Header="Debug 1" Click="DebugOne_Click"/>
+                        <MenuItem x:Name="DebugTwo" Header="Debug 2" Click="DebugTwo_Click"/>
+                        <MenuItem x:Name="DebugThree" Header="Debug 3" Click="DebugThree_Click"/>
+                    </MenuItem>
+                </MenuItem>
+            </Menu>
+        </ToolBar>
+        <!-- All Icons in the Toolbar taken from openclipart.org -->
+        <ToolBar x:Name="DrawingToolBar" Grid.Column="6" Grid.Row="0" Grid.ColumnSpan="2" Background="LightGray">
+            <Button x:Name="CanvasButton" ToolTip="Create a new Canvas" Click="CanvasButton_Click">
+                <Rectangle Width="30" Height="30">
+                    <Rectangle.Fill>
+                        <DrawingBrush>
+                            <DrawingBrush.Drawing>
+                                <DrawingGroup ClipGeometry="M0,0 V60 H60 V0 H0 Z">
+                                    <DrawingGroup Transform="1.0513,0,0,1.0513,-1.5376,-1.5376">
+                                        <GeometryDrawing Geometry="F1 M60,60z M0,0z M11.75,54.375L11.75,5.625 39.438,5.625 48.25,14.438 48.25,54.375 11.75,54.375z">
+                                            <GeometryDrawing.Pen>
+                                                <Pen Brush="#FFFFFFFF" Thickness="7.1343" StartLineCap="Round" EndLineCap="Round" LineJoin="Round" />
+                                            </GeometryDrawing.Pen>
+                                        </GeometryDrawing>
+                                        <GeometryDrawing Brush="#FFFFFFFF" Geometry="F1 M60,60z M0,0z M11.75,54.375L11.75,5.625 39.438,5.625 48.25,14.438 48.25,54.375 11.75,54.375z">
+                                            <GeometryDrawing.Pen>
+                                                <Pen Brush="#FF000000" Thickness="2.3781" StartLineCap="Round" EndLineCap="Round" LineJoin="Round" />
+                                            </GeometryDrawing.Pen>
+                                        </GeometryDrawing>
+                                        <GeometryDrawing Brush="#FF000000" Geometry="F1 M60,60z M0,0z M39.437,14.438L39.437,5.625 48.25,14.438 39.437,14.438z">
+                                            <GeometryDrawing.Pen>
+                                                <Pen Brush="#FF000000" Thickness="2.3781" StartLineCap="Round" EndLineCap="Round" LineJoin="Round" />
+                                            </GeometryDrawing.Pen>
+                                        </GeometryDrawing>
+                                    </DrawingGroup>
+                                </DrawingGroup>
+                            </DrawingBrush.Drawing>
+                        </DrawingBrush>
+                    </Rectangle.Fill>
+                </Rectangle>
+            </Button>
+            <ToggleButton x:Name="DrawButton" ToolTip="Enter Drawing Mode" Click="DrawButton_Click">
+                <Rectangle Width="30" Height="30">
+                    <Rectangle.Fill>
+                        <DrawingBrush>
+                            <DrawingBrush.Drawing>
+                                <DrawingGroup ClipGeometry="M0,0 V100 H100 V0 H0 Z">
+                                    <GeometryDrawing Brush="#FF000000" Geometry="F1 M100,100z M0,0z M69.172,11.265C68.981,11.073,68.67,11.073,68.477,11.265L11.639,68.029C11.447,68.22,11.447,68.53,11.639,68.721L30.846,87.905C30.942,88 31.068,88.048 31.194,88.048 31.319,88.048 31.445,88 31.541,87.905L88.38,31.14C88.473,31.048 88.525,30.924 88.525,30.793 88.525,30.662 88.473,30.538 88.38,30.446L69.172,11.265z" />
+                                    <GeometryDrawing Brush="#FF000000" Geometry="F1 M100,100z M0,0z M96.846,9.12L90.527,2.809C88.713,0.997999999999999 86.301,-8.88178419700125E-16 83.735,-8.88178419700125E-16 81.171,-8.88178419700125E-16 78.758,0.997999999999999 76.945,2.809L70.626,9.12C70.533,9.212 70.481,9.336 70.481,9.467 70.481,9.597 70.533,9.721 70.626,9.813L89.833,28.995C89.925,29.087 90.051,29.139 90.181,29.139 90.312,29.139 90.436,29.087 90.527,28.995L96.846,22.684C98.66,20.872 99.659,18.464 99.659,15.901 99.659,13.34 98.66,10.932 96.846,9.12z" />
+                                    <GeometryDrawing Brush="#FF000000" Geometry="F1 M100,100z M0,0z M10.358,69.967C10.236,69.846 10.062,69.795 9.894,69.838 9.727,69.878 9.594,70.003 9.543,70.168L0.363,99.363C0.308,99.541 0.357,99.732 0.49,99.861 0.584,99.952 0.707,100 0.832,100 0.886,100 0.942,99.989 0.996,99.971L29.383,89.959C29.542,89.903 29.661,89.771 29.698,89.605 29.735,89.441 29.686,89.268 29.566,89.15L10.358,69.967z" />
+                                </DrawingGroup>
+                            </DrawingBrush.Drawing>
+                        </DrawingBrush>
+                    </Rectangle.Fill>
+                </Rectangle>
+            </ToggleButton>
+            <ToggleButton x:Name="DeleteButton" ToolTip="Enter Deletion Mode" Click="DeleteButton_Click">
+                <Rectangle Width="30" Height="30">
+                    <Rectangle.Fill>
+                        <DrawingBrush>
+                            <DrawingBrush.Drawing>
+                                <DrawingGroup ClipGeometry="M0,0 V60 H60 V0 H0 Z">
+                                    <DrawingGroup>
+                                        <GeometryDrawing Geometry="F1 M60,60z M0,0z M41.312,11.031L6.438,32.5C5.407,33.151,4.6875,34.249,4.6875,35.562L4.6875,45.281C4.6875,47.32,6.3367,48.969,8.375,48.969L24.656,48.969C25.444,48.969,26.121,48.669,26.719,48.25L54.312,26.719 55.312,11.094 41.312,11.031z">
+                                            <GeometryDrawing.Pen>
+                                                <Pen Brush="#FFFFFFFF" Thickness="8.125" StartLineCap="Round" EndLineCap="Round" LineJoin="Round" />
+                                            </GeometryDrawing.Pen>
+                                        </GeometryDrawing>
+                                        <DrawingGroup Transform="0.99664,0,0,0.99664,-0.3563,-0.39594">
+                                            <GeometryDrawing Brush="#FF000000" Geometry="F0 M60,60z M0,0z M27.173,48.89L54.852,27.221 55.857,11.533 27.522,33.19 27.173,48.89z">
+                                                <GeometryDrawing.Pen>
+                                                    <Pen Brush="#FF000000" Thickness="3.1356" StartLineCap="Round" EndLineCap="Round" LineJoin="Round" />
+                                                </GeometryDrawing.Pen>
+                                            </GeometryDrawing>
+                                            <GeometryDrawing Brush="#FFFFFFFF" Geometry="F0 M60,60z M0,0z M6.6373,32.995L41.8073,11.464 55.8573,11.533 27.5223,33.19 6.63729999999999,32.995z">
+                                                <GeometryDrawing.Pen>
+                                                    <Pen Brush="#FF000000" Thickness="3.1356" StartLineCap="Round" EndLineCap="Round" LineJoin="Round" />
+                                                </GeometryDrawing.Pen>
+                                            </GeometryDrawing>
+                                            <GeometryDrawing>
+                                                <GeometryDrawing.Brush>
+                                                    <SolidColorBrush Color="#FFFFFFFF" Opacity="1" Transform="1.8458,0,0,1.8458,-121.06,-6.2579" />
+                                                </GeometryDrawing.Brush>
+                                                <GeometryDrawing.Pen>
+                                                    <Pen Brush="#FF000000" Thickness="1.6987" StartLineCap="Flat" EndLineCap="Flat" LineJoin="Round" />
+                                                </GeometryDrawing.Pen>
+                                                <GeometryDrawing.Geometry>
+                                                    <PathGeometry FillRule="EvenOdd" Transform="1.8458,0,0,1.8458,-121.06,-6.2579" Figures="M60,60z M0,0z M70.328,20.937C69.22,20.937,68.328,21.829,68.328,22.937L68.328,28.226C68.328,29.334,69.22,30.226,70.328,30.226L79.18,30.226C80.288,30.226,81.18,29.334,81.18,28.226L81.18,22.937C81.18,21.829,80.288,20.937,79.18,20.937L70.328,20.937z" />
+                                                </GeometryDrawing.Geometry>
+                                            </GeometryDrawing>
+                                        </DrawingGroup>
+                                    </DrawingGroup>
+                                </DrawingGroup>
+                            </DrawingBrush.Drawing>
+                        </DrawingBrush>
+                    </Rectangle.Fill>
+                </Rectangle>
+            </ToggleButton>
+            <Button x:Name="UndoButton" ToolTip="Undo the last action" Click="UndoButton_Click">
+                <Rectangle Width="30" Height="30">
+                    <Rectangle.Fill>
+                        <DrawingBrush>
+                            <DrawingBrush.Drawing>
+                                <DrawingGroup ClipGeometry="M0,0 V60 H60 V0 H0 Z">
+                                    <GeometryDrawing Geometry="F1 M60,60z M0,0z M25.063,4.6882L9.445,20.1632 25.063,35.6012 25.063,25.9792C25.442,25.9292 25.778,25.7632 26.176,25.7632 33.176,25.7632 38.85,31.4742 38.85,38.4732 38.85,41.7872 37.521,44.7602 35.439,47.0182L43.733,55.3122C47.934,50.9322 50.555,45.0212 50.555,38.4732 50.555,25.0092 39.64,14.0592 26.176,14.0592 25.797,14.0592 25.437,14.1452 25.063,14.1672L25.063,4.68840000000001z">
+                                        <GeometryDrawing.Pen>
+                                            <Pen Brush="#FFFFFFFF" Thickness="8.125" StartLineCap="Round" EndLineCap="Round" LineJoin="Round" />
+                                        </GeometryDrawing.Pen>
+                                    </GeometryDrawing>
+                                    <GeometryDrawing Brush="#FF000000" Geometry="F0 M60,60z M0,0z M25.063,4.6882L9.445,20.1632 25.063,35.6012 25.063,25.9792C25.442,25.9292 25.778,25.7632 26.176,25.7632 33.176,25.7632 38.85,31.4742 38.85,38.4732 38.85,41.7872 37.521,44.7602 35.439,47.0182L43.733,55.3122C47.934,50.9322 50.555,45.0212 50.555,38.4732 50.555,25.0092 39.64,14.0592 26.176,14.0592 25.797,14.0592 25.437,14.1452 25.063,14.1672L25.063,4.68840000000001z">
+                                        <GeometryDrawing.Pen>
+                                            <Pen Brush="#FF000000" Thickness="3.125" StartLineCap="Round" EndLineCap="Round" LineJoin="Round" />
+                                        </GeometryDrawing.Pen>
+                                    </GeometryDrawing>
+                                </DrawingGroup>
+                            </DrawingBrush.Drawing>
+                        </DrawingBrush>
+                    </Rectangle.Fill>
+                </Rectangle>
+            </Button>
+            <Button x:Name="RedoButton" ToolTip="Redo the last undone action" Click="RedoButton_Click">
+                <Rectangle Width="30" Height="30">
+                    <Rectangle.Fill>
+                        <DrawingBrush>
+                            <DrawingBrush.Drawing>
+                                <DrawingGroup ClipGeometry="M0,0 V60 H60 V0 H0 Z">
+                                    <DrawingGroup Transform="-1,0,0,1,60,0">
+                                        <GeometryDrawing Geometry="F1 M60,60z M0,0z M25.063,4.6882L9.445,20.1632 25.063,35.6012 25.063,25.9792C25.442,25.9292 25.778,25.7632 26.176,25.7632 33.176,25.7632 38.85,31.4742 38.85,38.4732 38.85,41.7872 37.521,44.7602 35.439,47.0182L43.733,55.3122C47.934,50.9322 50.555,45.0212 50.555,38.4732 50.555,25.0092 39.64,14.0592 26.176,14.0592 25.797,14.0592 25.437,14.1452 25.063,14.1672L25.063,4.68840000000001z">
+                                            <GeometryDrawing.Pen>
+                                                <Pen Brush="#FFFFFFFF" Thickness="8.125" StartLineCap="Round" EndLineCap="Round" LineJoin="Round" />
+                                            </GeometryDrawing.Pen>
+                                        </GeometryDrawing>
+                                        <GeometryDrawing Brush="#FF000000" Geometry="F0 M60,60z M0,0z M25.063,4.6882L9.445,20.1632 25.063,35.6012 25.063,25.9792C25.442,25.9292 25.778,25.7632 26.176,25.7632 33.176,25.7632 38.85,31.4742 38.85,38.4732 38.85,41.7872 37.521,44.7602 35.439,47.0182L43.733,55.3122C47.934,50.9322 50.555,45.0212 50.555,38.4732 50.555,25.0092 39.64,14.0592 26.176,14.0592 25.797,14.0592 25.437,14.1452 25.063,14.1672L25.063,4.68840000000001z">
+                                            <GeometryDrawing.Pen>
+                                                <Pen Brush="#FF000000" Thickness="3.125" StartLineCap="Round" EndLineCap="Round" LineJoin="Round" />
+                                            </GeometryDrawing.Pen>
+                                        </GeometryDrawing>
+                                    </DrawingGroup>
+                                </DrawingGroup>
+                            </DrawingBrush.Drawing>
+                        </DrawingBrush>
+                    </Rectangle.Fill>
+                </Rectangle>
+            </Button>
+        </ToolBar>
+        <local:CustomCanvas x:Name="LeftCanvas" Background="SlateGray" Grid.Column="2" Grid.Row="1" Height="auto" Grid.ColumnSpan="3"/>
+        <Canvas Name="CanvasSeperator" Grid.Column="5" Grid.Row="1" Background="LightGray"/>
+        <local:CustomCanvas x:Name="RightCanvas" Background="SlateGray" Grid.Column="6" Grid.Row="1" Height="auto"
+            MouseDown="RightCanvas_MouseDown" MouseUp="RightCanvas_MouseUp" MouseMove="RightCanvas_MouseMove" Grid.ColumnSpan="2" MouseLeave="RightCanvas_MouseLeave" MouseEnter="RightCanvas_MouseEnter" TouchEnter="RightCanvas_TouchEnter" TouchLeave="RightCanvas_TouchLeave"/>
+
+
+        <DockPanel Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="8">
+            <StatusBar DockPanel.Dock="Bottom" Name="StatusBar"  Background="LightGray">
+                <TextBox Name="LoadStatusBox" Text="nothing loaded" Background="LightGray"/>
+                <Separator/>
+                <TextBox Name="LastActionBox" Text="none" Background="LightGray"/>
+            </StatusBar>
+        </DockPanel>
+    </Grid>
+</Window>

+ 570 - 0
SketchAssistant/SketchAssistantWPF/MainWindow.xaml.cs

@@ -0,0 +1,570 @@
+using Microsoft.Win32;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using System.Text;
+using System.Threading;
+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()
+        {
+            bool InDebugMode = false;
+            String[] commArgs = Environment.GetCommandLineArgs();
+            InitializeComponent();
+            if (commArgs.Length > 1)
+            {
+                if (commArgs[1].Equals("-debug"))
+                {
+                    InDebugMode = true;
+                }
+            }
+            if(!InDebugMode)
+            {
+                DebugMode.Visibility = Visibility.Collapsed;
+            }
+            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, 10);
+            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;
+        /// <summary>
+        /// If the debug function is running.
+        /// </summary>
+        bool debugRunning = false;
+        /// <summary>
+        /// Point collections for debugging.
+        /// </summary>
+        DebugData debugDat = new DebugData();
+
+        /********************************************/
+        /*** 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);
+            //System.Diagnostics.Debug.WriteLine("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);
+            //System.Diagnostics.Debug.WriteLine("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>
+        /// If the cursor enters the canvas, it is treated as if the cursor was just pressed if the cursor is pressed.
+        /// </summary>
+        private void RightCanvas_MouseEnter(object sender, MouseEventArgs e)
+        {
+            if (IsMousePressed())
+            {
+                ProgramPresenter.MouseEvent(MVP_Presenter.MouseAction.Move, Mouse.GetPosition(RightCanvas));
+                ProgramPresenter.MouseEvent(MVP_Presenter.MouseAction.Down);
+            }
+        }
+
+        /// <summary>
+        /// If the finger enters the canvas, it is treated as if the finger was just pressed if the finger is pressed.
+        /// </summary>
+        private void RightCanvas_TouchEnter(object sender, TouchEventArgs e)
+        {
+            if (IsMousePressed())
+            {
+                ProgramPresenter.MouseEvent(MVP_Presenter.MouseAction.Move, Mouse.GetPosition(RightCanvas));
+                ProgramPresenter.MouseEvent(MVP_Presenter.MouseAction.Down);
+            }
+        }
+
+        /// <summary>
+        /// If the finger leaves the canvas, it is treated as if the finger was released.
+        /// </summary>
+        private void RightCanvas_TouchLeave(object sender, TouchEventArgs 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));
+            //System.Diagnostics.Debug.WriteLine("new Point(" + ((int)e.GetPosition(RightCanvas).X).ToString() + "," + ((int)e.GetPosition(RightCanvas).Y).ToString() + "), ");
+        }
+
+        /// <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>
+        /// Sends inputs to the presenter simulating drawing, used for testing and debugging.
+        /// Takes 7000ms
+        /// </summary>
+        private void DebugOne_Click(object sender, RoutedEventArgs e)
+        {
+            Debug(1);
+        }
+
+        /// <summary>
+        /// Sends inputs to the presenter simulating drawing, used for testing and debugging.
+        /// Takes 24000ms
+        /// </summary>
+        private void DebugTwo_Click(object sender, RoutedEventArgs e)
+        {
+            Debug(2);
+        }
+
+        /// <summary>
+        /// Sends inputs to the presenter simulating drawing, used for testing and debugging.
+        /// Takes 7000ms
+        /// </summary>
+        private void DebugThree_Click(object sender, RoutedEventArgs e)
+        {
+            Debug(3);
+        }
+
+        /// <summary>
+        /// Ticks the Presenter.
+        /// </summary>
+        private void dispatcherTimer_Tick(object sender, EventArgs e)
+        {
+            ProgramPresenter.Tick();
+            //System.Diagnostics.Debug.WriteLine("ProgramPresenter.Tick();");
+        }
+
+        /// <summary>
+        /// Import button, will open an OpenFileDialog
+        /// </summary>
+        private void MenuItem_Click(object sender, RoutedEventArgs e)
+        {
+            ProgramPresenter.ExamplePictureToolStripMenuItemClick();
+        }
+
+        /*************************/
+        /*** PRESENTER -> VIEW ***/
+        /*************************/
+
+        /// <summary>
+        /// Returns the cursor position.
+        /// </summary>
+        /// <returns>The cursor Position</returns>
+        public Point GetCursorPosition()
+        {
+            return Mouse.GetPosition(RightCanvas);
+        }
+
+        /// <summary>
+        /// If the mouse is pressed or not.
+        /// </summary>
+        /// <returns>Whether or not the mouse is pressed.</returns>
+        public bool IsMousePressed()
+        {
+            if (!debugRunning) {
+                return (Mouse.LeftButton.Equals(MouseButtonState.Pressed) || Mouse.RightButton.Equals(MouseButtonState.Pressed)); }
+            else return true;
+        }
+
+        /// <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>
+        /// Adds a point to the right canvas
+        /// </summary>
+        /// <param name="newPoint">The point</param>
+        public void AddNewPointRight(Ellipse newPoint)
+        {
+            newPoint.Height = 3; newPoint.Width = 3;
+            newPoint.Fill = Brushes.Black;
+            RightCanvas.Children.Add(newPoint);
+        }
+
+        /// <summary>
+        /// Adds a point to the left canvas
+        /// </summary>
+        /// <param name="newPoint">The point</param>
+        public void AddNewPointLeft(Ellipse newPoint)
+        {
+            newPoint.Height = 3; newPoint.Width = 3;
+            newPoint.Fill = Brushes.Black;
+            LeftCanvas.Children.Add(newPoint);
+        }
+
+        /// <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;
+            }
+        }
+
+        /************************/
+        /*** HELPING FUNCTION ***/
+        /************************/
+
+        /// <summary>
+        /// A function which simulates canvas input for debugging.
+        /// </summary>
+        /// <param name="option"></param>
+        private async void Debug(int option)
+        {
+            Point[] points;
+            switch (option)
+            {
+                case 1:
+                    points = debugDat.debugPoints1;
+                    break;
+                case 2:
+                    points = debugDat.debugPoints2;
+                    break;
+                default:
+                    return;
+            }
+            dispatcherTimer.Stop();
+            debugRunning = true;
+            ProgramPresenter.Tick(); await Task.Delay(10);
+            ProgramPresenter.MouseEvent(MVP_Presenter.MouseAction.Move, new Point(50, 50));
+            ProgramPresenter.MouseEvent(MVP_Presenter.MouseAction.Down); await Task.Delay(10);
+            for (int x = 0; x < points.Length; x++)
+            {
+                ProgramPresenter.MouseEvent(MVP_Presenter.MouseAction.Move, points[x]);
+                await Task.Delay(1);
+                if (x % 5 == 0)
+                {
+                    ProgramPresenter.Tick();
+                    await Task.Delay(1);
+                }
+            }
+            ProgramPresenter.MouseEvent(MVP_Presenter.MouseAction.Up); await Task.Delay(1);
+            debugRunning = false;
+            dispatcherTimer.Start();
+        }
+    }
+}

+ 55 - 0
SketchAssistant/SketchAssistantWPF/Properties/AssemblyInfo.cs

@@ -0,0 +1,55 @@
+using System.Reflection;
+using System.Resources;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Windows;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("SketchAssistantWPF")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("SketchAssistantWPF")]
+[assembly: AssemblyCopyright("Copyright ©  2019")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components.  If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+//In order to begin building localizable applications, set
+//<UICulture>CultureYouAreCodingWith</UICulture> in your .csproj file
+//inside a <PropertyGroup>.  For example, if you are using US english
+//in your source files, set the <UICulture> to en-US.  Then uncomment
+//the NeutralResourceLanguage attribute below.  Update the "en-US" in
+//the line below to match the UICulture setting in the project file.
+
+//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
+
+
+[assembly: ThemeInfo(
+    ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
+                                     //(used if a resource is not found in the page,
+                                     // or application resource dictionaries)
+    ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
+                                              //(used if a resource is not found in the page,
+                                              // app, or any theme specific resource dictionaries)
+)]
+
+
+// Version information for an assembly consists of the following four values:
+//
+//      Major Version
+//      Minor Version
+//      Build Number
+//      Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]

+ 20 - 28
SketchAssistant/SketchAssistant/Properties/Resources.Designer.cs → SketchAssistant/SketchAssistantWPF/Properties/Resources.Designer.cs

@@ -1,4 +1,4 @@
-//------------------------------------------------------------------------------
+//------------------------------------------------------------------------------
 // <auto-generated>
 //     This code was generated by a tool.
 //     Runtime Version:4.0.30319.42000
@@ -8,10 +8,10 @@
 // </auto-generated>
 //------------------------------------------------------------------------------
 
-namespace SketchAssistant.Properties
-{
-
-
+namespace SketchAssistantWPF.Properties {
+    using System;
+    
+    
     /// <summary>
     ///   A strongly-typed resource class, for looking up localized strings, etc.
     /// </summary>
@@ -19,51 +19,43 @@ namespace SketchAssistant.Properties
     // class via a tool like ResGen or Visual Studio.
     // To add or remove a member, edit your .ResX file then rerun ResGen
     // with the /str option, or rebuild your VS project.
-    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
+    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")]
     [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
     [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
-    internal class Resources
-    {
-
+    internal class Resources {
+        
         private static global::System.Resources.ResourceManager resourceMan;
-
+        
         private static global::System.Globalization.CultureInfo resourceCulture;
-
+        
         [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
-        internal Resources()
-        {
+        internal Resources() {
         }
-
+        
         /// <summary>
         ///   Returns the cached ResourceManager instance used by this class.
         /// </summary>
         [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
-        internal static global::System.Resources.ResourceManager ResourceManager
-        {
-            get
-            {
-                if ((resourceMan == null))
-                {
-                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("SketchAssistant.Properties.Resources", typeof(Resources).Assembly);
+        internal static global::System.Resources.ResourceManager ResourceManager {
+            get {
+                if (object.ReferenceEquals(resourceMan, null)) {
+                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("SketchAssistantWPF.Properties.Resources", typeof(Resources).Assembly);
                     resourceMan = temp;
                 }
                 return resourceMan;
             }
         }
-
+        
         /// <summary>
         ///   Overrides the current thread's CurrentUICulture property for all
         ///   resource lookups using this strongly typed resource class.
         /// </summary>
         [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
-        internal static global::System.Globalization.CultureInfo Culture
-        {
-            get
-            {
+        internal static global::System.Globalization.CultureInfo Culture {
+            get {
                 return resourceCulture;
             }
-            set
-            {
+            set {
                 resourceCulture = value;
             }
         }

+ 10 - 7
SketchAssistant/SketchAssistant/Properties/Resources.resx → SketchAssistant/SketchAssistantWPF/Properties/Resources.resx

@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="utf-8"?>
 <root>
   <!-- 
     Microsoft ResX Schema 
@@ -46,7 +46,7 @@
     
     mimetype: application/x-microsoft.net.object.binary.base64
     value   : The object must be serialized with 
-            : System.Serialization.Formatters.Binary.BinaryFormatter
+            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
             : and then encoded with base64 encoding.
     
     mimetype: application/x-microsoft.net.object.soap.base64
@@ -60,6 +60,7 @@
             : and then encoded with base64 encoding.
     -->
   <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
     <xsd:element name="root" msdata:IsDataSet="true">
       <xsd:complexType>
         <xsd:choice maxOccurs="unbounded">
@@ -68,9 +69,10 @@
               <xsd:sequence>
                 <xsd:element name="value" type="xsd:string" minOccurs="0" />
               </xsd:sequence>
-              <xsd:attribute name="name" type="xsd:string" />
+              <xsd:attribute name="name" use="required" type="xsd:string" />
               <xsd:attribute name="type" type="xsd:string" />
               <xsd:attribute name="mimetype" type="xsd:string" />
+              <xsd:attribute ref="xml:space" />
             </xsd:complexType>
           </xsd:element>
           <xsd:element name="assembly">
@@ -85,9 +87,10 @@
                 <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
                 <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
               </xsd:sequence>
-              <xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
+              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
               <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
               <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+              <xsd:attribute ref="xml:space" />
             </xsd:complexType>
           </xsd:element>
           <xsd:element name="resheader">
@@ -109,9 +112,9 @@
     <value>2.0</value>
   </resheader>
   <resheader name="reader">
-    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
   </resheader>
   <resheader name="writer">
-    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
   </resheader>
-</root>
+</root>

+ 2 - 2
SketchAssistant/SketchAssistant/Properties/Settings.Designer.cs → SketchAssistant/SketchAssistantWPF/Properties/Settings.Designer.cs

@@ -1,4 +1,4 @@
-//------------------------------------------------------------------------------
+//------------------------------------------------------------------------------
 // <auto-generated>
 //     This code was generated by a tool.
 //     Runtime Version:4.0.30319.42000
@@ -8,7 +8,7 @@
 // </auto-generated>
 //------------------------------------------------------------------------------
 
-namespace SketchAssistant.Properties
+namespace SketchAssistantWPF.Properties
 {
 
 

+ 7 - 0
SketchAssistant/SketchAssistantWPF/Properties/Settings.settings

@@ -0,0 +1,7 @@
+<?xml version='1.0' encoding='utf-8'?>
+<SettingsFile xmlns="uri:settings" CurrentProfile="(Default)">
+  <Profiles>
+    <Profile Name="(Default)" />
+  </Profiles>
+  <Settings />
+</SettingsFile>

+ 1 - 1
SketchAssistant/SketchAssistant/SketchAction.cs → SketchAssistant/SketchAssistantWPF/SketchAction.cs

@@ -4,7 +4,7 @@ using System.Linq;
 using System.Text;
 using System.Threading.Tasks;
 
-namespace SketchAssistant
+namespace SketchAssistantWPF
 {
     public class SketchAction
     {

+ 56 - 42
SketchAssistant/SketchAssistant/SketchAssistant.csproj → SketchAssistant/SketchAssistantWPF/SketchAssistantWPF.csproj

@@ -4,13 +4,18 @@
   <PropertyGroup>
     <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
     <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
-    <ProjectGuid>{0336F628-A2F7-4170-8B2E-9277C23118D4}</ProjectGuid>
+    <ProjectGuid>{EE53AE79-2AA0-4F43-9638-1789B189D5C3}</ProjectGuid>
     <OutputType>WinExe</OutputType>
-    <RootNamespace>SketchAssistant</RootNamespace>
-    <AssemblyName>SketchAssistant</AssemblyName>
+    <RootNamespace>SketchAssistantWPF</RootNamespace>
+    <AssemblyName>SketchAssistantWPF</AssemblyName>
     <TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
     <FileAlignment>512</FileAlignment>
+    <ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
+    <WarningLevel>4</WarningLevel>
     <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
+    <Deterministic>true</Deterministic>
+    <NuGetPackageImportStamp>
+    </NuGetPackageImportStamp>
     <PublishUrl>publish\</PublishUrl>
     <Install>true</Install>
     <InstallFrom>Disk</InstallFrom>
@@ -26,8 +31,6 @@
     <IsWebBootstrapper>false</IsWebBootstrapper>
     <UseApplicationTrust>false</UseApplicationTrust>
     <BootstrapperEnabled>true</BootstrapperEnabled>
-    <NuGetPackageImportStamp>
-    </NuGetPackageImportStamp>
   </PropertyGroup>
   <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
     <PlatformTarget>AnyCPU</PlatformTarget>
@@ -50,65 +53,76 @@
   </PropertyGroup>
   <ItemGroup>
     <Reference Include="System" />
-    <Reference Include="System.Configuration" />
+    <Reference Include="System.Data" />
+    <Reference Include="System.Drawing" />
+    <Reference Include="System.Xml" />
+    <Reference Include="Microsoft.CSharp" />
     <Reference Include="System.Core" />
-    <Reference Include="System.Runtime.CompilerServices.Unsafe, Version=4.0.4.1, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
-      <HintPath>..\packages\System.Runtime.CompilerServices.Unsafe.4.5.2\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll</HintPath>
-    </Reference>
-    <Reference Include="System.Threading.Tasks.Extensions, Version=4.2.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
-      <HintPath>..\packages\System.Threading.Tasks.Extensions.4.5.1\lib\netstandard2.0\System.Threading.Tasks.Extensions.dll</HintPath>
-    </Reference>
     <Reference Include="System.Xml.Linq" />
     <Reference Include="System.Data.DataSetExtensions" />
-    <Reference Include="Microsoft.CSharp" />
-    <Reference Include="System.Data" />
-    <Reference Include="System.Deployment" />
-    <Reference Include="System.Drawing" />
     <Reference Include="System.Net.Http" />
-    <Reference Include="System.Windows.Forms" />
-    <Reference Include="System.Xml" />
+    <Reference Include="System.Xaml">
+      <RequiredTargetFramework>4.0</RequiredTargetFramework>
+    </Reference>
+    <Reference Include="WindowsBase" />
+    <Reference Include="PresentationCore" />
+    <Reference Include="PresentationFramework" />
   </ItemGroup>
   <ItemGroup>
+    <ApplicationDefinition Include="App.xaml">
+      <Generator>MSBuild:Compile</Generator>
+      <SubType>Designer</SubType>
+    </ApplicationDefinition>
+    <Compile Include="ActionHistory.cs" />
+    <Compile Include="CustomCanvas.cs" />
+    <Compile Include="DebugData.cs" />
     <Compile Include="FileImporter.cs" />
     <Compile Include="FileImporterException.cs" />
+    <Compile Include="GeometryCalculator.cs" />
+    <Compile Include="ImageDimension.cs" />
     <Compile Include="SketchAction.cs" />
-    <Compile Include="ActionHistory.cs" />
-    <Compile Include="Line.cs" />
-    <Compile Include="Form1.cs">
-      <SubType>Form</SubType>
+    <Page Include="MainWindow.xaml">
+      <Generator>MSBuild:Compile</Generator>
+      <SubType>Designer</SubType>
+    </Page>
+    <Compile Include="App.xaml.cs">
+      <DependentUpon>App.xaml</DependentUpon>
+      <SubType>Code</SubType>
     </Compile>
-    <Compile Include="Form1.Designer.cs">
-      <DependentUpon>Form1.cs</DependentUpon>
+    <Compile Include="InternalLine.cs" />
+    <Compile Include="MainWindow.xaml.cs">
+      <DependentUpon>MainWindow.xaml</DependentUpon>
+      <SubType>Code</SubType>
+    </Compile>
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="MVP_Model.cs" />
+    <Compile Include="MVP_Presenter.cs" />
+    <Compile Include="MVP_View.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs">
+      <SubType>Code</SubType>
     </Compile>
-    <Compile Include="Program.cs" />
-    <Compile Include="Properties\AssemblyInfo.cs" />
-    <EmbeddedResource Include="Form1.resx">
-      <DependentUpon>Form1.cs</DependentUpon>
-    </EmbeddedResource>
-    <EmbeddedResource Include="Properties\Resources.resx">
-      <Generator>ResXFileCodeGenerator</Generator>
-      <LastGenOutput>Resources.Designer.cs</LastGenOutput>
-      <SubType>Designer</SubType>
-    </EmbeddedResource>
     <Compile Include="Properties\Resources.Designer.cs">
       <AutoGen>True</AutoGen>
+      <DesignTime>True</DesignTime>
       <DependentUpon>Resources.resx</DependentUpon>
     </Compile>
-    <None Include="packages.config" />
-    <None Include="Properties\Settings.settings">
-      <Generator>SettingsSingleFileGenerator</Generator>
-      <LastGenOutput>Settings.Designer.cs</LastGenOutput>
-    </None>
     <Compile Include="Properties\Settings.Designer.cs">
       <AutoGen>True</AutoGen>
       <DependentUpon>Settings.settings</DependentUpon>
       <DesignTimeSharedInput>True</DesignTimeSharedInput>
     </Compile>
+    <EmbeddedResource Include="Properties\Resources.resx">
+      <Generator>ResXFileCodeGenerator</Generator>
+      <LastGenOutput>Resources.Designer.cs</LastGenOutput>
+    </EmbeddedResource>
+    <None Include="Properties\Settings.settings">
+      <Generator>SettingsSingleFileGenerator</Generator>
+      <LastGenOutput>Settings.Designer.cs</LastGenOutput>
+    </None>
   </ItemGroup>
   <ItemGroup>
-    <None Include="App.config">
-      <SubType>Designer</SubType>
-    </None>
+    <None Include="App.config" />
   </ItemGroup>
   <ItemGroup>
     <BootstrapperPackage Include=".NETFramework,Version=v4.6.1">

+ 4 - 4
SketchAssistant/SketchAssistant.Tests/Properties/AssemblyInfo.cs → SketchAssistant/WhiteTests/Properties/AssemblyInfo.cs

@@ -2,18 +2,18 @@ using System.Reflection;
 using System.Runtime.CompilerServices;
 using System.Runtime.InteropServices;
 
-[assembly: AssemblyTitle("SketchAssistant.Tests")]
+[assembly: AssemblyTitle("WhiteTests")]
 [assembly: AssemblyDescription("")]
 [assembly: AssemblyConfiguration("")]
 [assembly: AssemblyCompany("")]
-[assembly: AssemblyProduct("SketchAssistant.Tests")]
-[assembly: AssemblyCopyright("Copyright ©  2018")]
+[assembly: AssemblyProduct("WhiteTests")]
+[assembly: AssemblyCopyright("Copyright ©  2019")]
 [assembly: AssemblyTrademark("")]
 [assembly: AssemblyCulture("")]
 
 [assembly: ComVisible(false)]
 
-[assembly: Guid("7dcdc31a-8291-4b05-93d6-dcc5de27a4a0")]
+[assembly: Guid("eb09c624-91f2-465f-825b-559bf7a7d5cb")]
 
 // [assembly: AssemblyVersion("1.0.*")]
 [assembly: AssemblyVersion("1.0.0.0")]

+ 143 - 0
SketchAssistant/WhiteTests/UITest.cs

@@ -0,0 +1,143 @@
+using System;
+using System.IO;
+using System.Reflection;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using TestStack.White;
+using TestStack.White.UIItems;
+using TestStack.White.UIItems.WindowItems;
+using TestStack.White.UIItems.Finders;
+using System.Threading;
+using SketchAssistantWPF;
+using System.Windows;
+using System.Diagnostics;
+using TestStack.White.UIItems.WindowStripControls;
+using TestStack.White.UIItems.MenuItems;
+
+namespace WhiteTests
+{
+    [TestClass]
+    public class UITest
+    {
+        private TestStack.White.Application application;
+
+        public Window setupapp()
+        {
+            string outputDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
+            string editedDir = outputDir.Replace("WhiteTests", "SketchAssistantWPF");
+            string app_path = editedDir + @"\SketchAssistantWPF.exe";
+            ProcessStartInfo processStart = new ProcessStartInfo(app_path, "-debug");
+            application = Application.Launch(processStart);
+            return application.GetWindow("Sketch Assistant");
+        }
+
+        [TestMethod]
+        public void CreateCanvasTest()
+        {
+            Window mainWindow = setupapp();
+            Thread.Sleep(20);
+            Assert.AreEqual("none", mainWindow.Get<TextBox>(SearchCriteria.ByAutomationId("LastActionBox")).Text.ToString());
+            mainWindow.Get<Button>(SearchCriteria.ByAutomationId("CanvasButton")).Click();
+            Thread.Sleep(20);
+            Assert.AreEqual("Last Action: A new canvas was created.", mainWindow.Get<TextBox>(SearchCriteria.ByAutomationId("LastActionBox")).Text.ToString());
+            mainWindow.Close();
+        }
+
+        [TestMethod]
+        public void DrawLineTest()
+        {
+            Window mainWindow = setupapp();
+            Thread.Sleep(20);
+            Assert.AreEqual("none", mainWindow.Get<TextBox>(SearchCriteria.ByAutomationId("LastActionBox")).Text.ToString());
+            mainWindow.Get<Button>(SearchCriteria.ByAutomationId("CanvasButton")).Click();
+            Thread.Sleep(20);
+            Assert.AreEqual("Last Action: A new canvas was created.", mainWindow.Get<TextBox>(SearchCriteria.ByAutomationId("LastActionBox")).Text.ToString());
+            mainWindow.Get<Menu>(SearchCriteria.ByAutomationId("EditMenuButton")).Click();
+            Thread.Sleep(20);
+            mainWindow.Get<Menu>(SearchCriteria.ByAutomationId("DebugMode")).Click();
+            Thread.Sleep(20);
+            mainWindow.Get<Menu>(SearchCriteria.ByAutomationId("DebugOne")).Click();
+            Thread.Sleep(7000);
+            Assert.AreEqual("Last Action: Line number 0 was drawn.", mainWindow.Get<TextBox>(SearchCriteria.ByAutomationId("LastActionBox")).Text.ToString());
+            mainWindow.Close();
+        }
+
+        /*[TestMethod]
+         public void DeleteLineTest()
+         {
+             Window mainWindow = setupapp();
+             Thread.Sleep(20);
+             Assert.AreEqual("none", mainWindow.Get<TextBox>(SearchCriteria.ByAutomationId("LastActionBox")).Text.ToString());
+             mainWindow.Get<Button>(SearchCriteria.ByAutomationId("CanvasButton")).Click();
+             Thread.Sleep(20);
+             Assert.AreEqual("Last Action: A new canvas was created.", mainWindow.Get<TextBox>(SearchCriteria.ByAutomationId("LastActionBox")).Text.ToString());
+             mainWindow.Get<Menu>(SearchCriteria.ByAutomationId("EditMenuButton")).Click();
+             Thread.Sleep(20);
+             mainWindow.Get<Menu>(SearchCriteria.ByAutomationId("DebugMode")).Click();
+             Thread.Sleep(20);
+             mainWindow.Get<Menu>(SearchCriteria.ByAutomationId("DebugOne")).Click();
+             Thread.Sleep(7000);
+             Assert.AreEqual("Last Action: Line number 0 was drawn.", mainWindow.Get<TextBox>(SearchCriteria.ByAutomationId("LastActionBox")).Text.ToString());
+             Thread.Sleep(20);
+             mainWindow.Get<Button>(SearchCriteria.ByAutomationId("DeleteButton")).Click();
+             Thread.Sleep(20);
+             mainWindow.Get<Menu>(SearchCriteria.ByAutomationId("EditMenuButton")).Click();
+             Thread.Sleep(20);
+             mainWindow.Get<Menu>(SearchCriteria.ByAutomationId("DebugMode")).Click();
+             Thread.Sleep(20);
+             mainWindow.Get<Menu>(SearchCriteria.ByAutomationId("DebugThree")).Click();
+             Thread.Sleep(24000);
+             Assert.AreEqual("Last Action: Line number 0 was deleted", mainWindow.Get<TextBox>(SearchCriteria.ByAutomationId("LastActionBox")).Text.ToString());
+             mainWindow.Close();
+         }*/
+
+        [TestMethod]
+        public void UndoTest()
+        {
+            Window mainWindow = setupapp();
+            Thread.Sleep(20);
+            Assert.AreEqual("none", mainWindow.Get<TextBox>(SearchCriteria.ByAutomationId("LastActionBox")).Text.ToString());
+            mainWindow.Get<Button>(SearchCriteria.ByAutomationId("CanvasButton")).Click();
+            Thread.Sleep(20);
+            Assert.AreEqual("Last Action: A new canvas was created.", mainWindow.Get<TextBox>(SearchCriteria.ByAutomationId("LastActionBox")).Text.ToString());
+            mainWindow.Get<Menu>(SearchCriteria.ByAutomationId("EditMenuButton")).Click();
+            Thread.Sleep(20);
+            mainWindow.Get<Menu>(SearchCriteria.ByAutomationId("DebugMode")).Click();
+            Thread.Sleep(20);
+            mainWindow.Get<Menu>(SearchCriteria.ByAutomationId("DebugOne")).Click();
+            Thread.Sleep(7000);
+            Assert.AreEqual("Last Action: Line number 0 was drawn.", mainWindow.Get<TextBox>(SearchCriteria.ByAutomationId("LastActionBox")).Text.ToString());
+            Thread.Sleep(20);
+            mainWindow.Get<Button>(SearchCriteria.ByAutomationId("UndoButton")).Click();
+            Thread.Sleep(20);
+            Assert.AreEqual("Last Action: A new canvas was created.", mainWindow.Get<TextBox>(SearchCriteria.ByAutomationId("LastActionBox")).Text.ToString());
+            mainWindow.Close();
+        }
+
+        [TestMethod]
+        public void RedoTest()
+        {
+            Window mainWindow = setupapp();
+            Thread.Sleep(20);
+            Assert.AreEqual("none", mainWindow.Get<TextBox>(SearchCriteria.ByAutomationId("LastActionBox")).Text.ToString());
+            mainWindow.Get<Button>(SearchCriteria.ByAutomationId("CanvasButton")).Click();
+            Thread.Sleep(20);
+            Assert.AreEqual("Last Action: A new canvas was created.", mainWindow.Get<TextBox>(SearchCriteria.ByAutomationId("LastActionBox")).Text.ToString());
+            mainWindow.Get<Menu>(SearchCriteria.ByAutomationId("EditMenuButton")).Click();
+            Thread.Sleep(20);
+            mainWindow.Get<Menu>(SearchCriteria.ByAutomationId("DebugMode")).Click();
+            Thread.Sleep(20);
+            mainWindow.Get<Menu>(SearchCriteria.ByAutomationId("DebugOne")).Click();
+            Thread.Sleep(7000);
+            Assert.AreEqual("Last Action: Line number 0 was drawn.", mainWindow.Get<TextBox>(SearchCriteria.ByAutomationId("LastActionBox")).Text.ToString());
+            Thread.Sleep(20);
+            mainWindow.Get<Button>(SearchCriteria.ByAutomationId("UndoButton")).Click();
+            Thread.Sleep(20);
+            Assert.AreEqual("Last Action: A new canvas was created.", mainWindow.Get<TextBox>(SearchCriteria.ByAutomationId("LastActionBox")).Text.ToString());
+            Thread.Sleep(20);
+            mainWindow.Get<Button>(SearchCriteria.ByAutomationId("RedoButton")).Click();
+            Thread.Sleep(20);
+            Assert.AreEqual("Last Action: Line number 0 was drawn.", mainWindow.Get<TextBox>(SearchCriteria.ByAutomationId("LastActionBox")).Text.ToString());
+            mainWindow.Close();
+        }
+    }
+}

+ 14 - 11
SketchAssistant/SketchAssistant.Tests/SketchAssistant.Tests.csproj → SketchAssistant/WhiteTests/WhiteTests.csproj

@@ -5,11 +5,11 @@
   <PropertyGroup>
     <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
     <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
-    <ProjectGuid>{7DCDC31A-8291-4B05-93D6-DCC5DE27A4A0}</ProjectGuid>
+    <ProjectGuid>{EB09C624-91F2-465F-825B-559BF7A7D5CB}</ProjectGuid>
     <OutputType>Library</OutputType>
     <AppDesignerFolder>Properties</AppDesignerFolder>
-    <RootNamespace>SketchAssistant.Tests</RootNamespace>
-    <AssemblyName>SketchAssistant.Tests</AssemblyName>
+    <RootNamespace>WhiteTests</RootNamespace>
+    <AssemblyName>WhiteTests</AssemblyName>
     <TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
     <FileAlignment>512</FileAlignment>
     <ProjectTypeGuids>{3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
@@ -39,6 +39,9 @@
     <WarningLevel>4</WarningLevel>
   </PropertyGroup>
   <ItemGroup>
+    <Reference Include="Castle.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=407dd0808d44fbdc, processorArchitecture=MSIL">
+      <HintPath>..\packages\Castle.Core.4.3.1\lib\net45\Castle.Core.dll</HintPath>
+    </Reference>
     <Reference Include="Microsoft.VisualStudio.TestPlatform.TestFramework, Version=14.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
       <HintPath>..\packages\MSTest.TestFramework.1.4.0\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.dll</HintPath>
     </Reference>
@@ -46,15 +49,15 @@
       <HintPath>..\packages\MSTest.TestFramework.1.4.0\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.Extensions.dll</HintPath>
     </Reference>
     <Reference Include="System" />
+    <Reference Include="System.Configuration" />
     <Reference Include="System.Core" />
-    <Reference Include="System.Drawing" />
-    <Reference Include="System.ValueTuple, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
-      <HintPath>..\packages\System.ValueTuple.4.5.0\lib\net461\System.ValueTuple.dll</HintPath>
+    <Reference Include="TestStack.White, Version=0.13.0.0, Culture=neutral, PublicKeyToken=2672efbf3e161801, processorArchitecture=MSIL">
+      <HintPath>..\packages\TestStack.White.0.13.3\lib\net40\TestStack.White.dll</HintPath>
     </Reference>
-    <Reference Include="System.Windows.Forms" />
+    <Reference Include="WindowsBase" />
   </ItemGroup>
   <ItemGroup>
-    <Compile Include="UnitTest1.cs" />
+    <Compile Include="UITest.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
   </ItemGroup>
   <ItemGroup>
@@ -62,9 +65,9 @@
     <None Include="packages.config" />
   </ItemGroup>
   <ItemGroup>
-    <ProjectReference Include="..\SketchAssistant\SketchAssistant.csproj">
-      <Project>{0336f628-a2f7-4170-8b2e-9277c23118d4}</Project>
-      <Name>SketchAssistant</Name>
+    <ProjectReference Include="..\SketchAssistantWPF\SketchAssistantWPF.csproj">
+      <Project>{ee53ae79-2aa0-4f43-9638-1789b189d5c3}</Project>
+      <Name>SketchAssistantWPF</Name>
     </ProjectReference>
   </ItemGroup>
   <Import Project="$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets" Condition="Exists('$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets')" />

+ 2 - 2
SketchAssistant/SketchAssistant.Tests/app.config → SketchAssistant/WhiteTests/app.config

@@ -3,8 +3,8 @@
   <runtime>
     <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
       <dependentAssembly>
-        <assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
-        <bindingRedirect oldVersion="0.0.0.0-4.0.4.1" newVersion="4.0.4.1" />
+        <assemblyIdentity name="Castle.Core" publicKeyToken="407dd0808d44fbdc" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-4.0.0.0" newVersion="4.0.0.0" />
       </dependentAssembly>
     </assemblyBinding>
   </runtime>

+ 2 - 1
SketchAssistant/SketchAssistant.Tests/packages.config → SketchAssistant/WhiteTests/packages.config

@@ -1,6 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <packages>
+  <package id="Castle.Core" version="4.3.1" targetFramework="net461" />
   <package id="MSTest.TestAdapter" version="1.4.0" targetFramework="net461" />
   <package id="MSTest.TestFramework" version="1.4.0" targetFramework="net461" />
-  <package id="System.ValueTuple" version="4.5.0" targetFramework="net461" />
+  <package id="TestStack.White" version="0.13.3" targetFramework="net461" />
 </packages>

+ 13 - 0
userstory16.md

@@ -0,0 +1,13 @@
+# Userstory 16  
+ 
+|**ID**|16|  
+|-|-|
+|**Name**|Änderung der Nutzeroberfläche & wpf|
+|**Beschreibung**|Die Nutzeroberfläche wird an die neuen Anforderungen des Auftraggebers angepasst.|
+|**Akzeptanzkriterium**|Die Userstory ist akzeptiert, wenn die UI eine Zeichenfläche enthält und eine Fläche zum Anzeigen von Grafiken, sowie alle vorherig verfügbare Knöpfe. Zusätzlich ist erforderlich, dass die UI statt auf WinForms auf WPF basiert. Auch sollen die Knöpfe in der Toolbar durch Symbole, statt durch Text markiert sein, und es einen Edit Button gibt in welchem zusätzlich die Funktionen vorhanden sind.|
+|Geschätzter Aufwand (Story Points)|10|
+|Entwickler|Martin Edlund|
+|Umgesetzt in Iteration|keine|
+|Tatsächlicher Aufwand (Std.)|keine|
+|Velocity (Std./Story Point)|keine|
+|Bemerkungen|Keine|

Einige Dateien werden nicht angezeigt, da zu viele Dateien in diesem Diff geändert wurden.