Added undo button to spline UI

Signed-off-by: Ryan Yin <100028731@mvla.net>
Change-Id: I39a2f1ea9695206fba78cbe1c0c4dbbe525c469f
diff --git a/frc971/control_loops/python/path_edit.py b/frc971/control_loops/python/path_edit.py
index bf54f60..414245e 100755
--- a/frc971/control_loops/python/path_edit.py
+++ b/frc971/control_loops/python/path_edit.py
@@ -40,7 +40,8 @@
         self.graph = Graph()
         self.set_vexpand(True)
         self.set_hexpand(True)
-
+        # list of multisplines
+        self.multispline_stack = []
         # init field drawing
         # add default spline for testing purposes
         # init editing / viewing modes and pointer location
@@ -331,7 +332,14 @@
         self.queue_draw()
         self.graph.schedule_recalculate(self.points)
 
-    def clear_graph(self):
+    def attempt_append_multispline(self):
+        if (len(self.multispline_stack) == 0 or
+        self.points.toMultiSpline() != self.multispline_stack[-1]):
+            self.multispline_stack.append(self.points.toMultiSpline())
+
+    def clear_graph(self, should_attempt_append=True):
+        if should_attempt_append:
+            self.attempt_append_multispline()
         self.points = Points()
         #recalulate graph using new points
         self.graph.axis.clear()
@@ -340,11 +348,31 @@
         self.mode = Mode.kPlacing
         #redraw entire graph
         self.queue_draw()
-        #TODO: Make a way to undo clear
+
+
+    def undo(self):
+        try:
+            self.multispline_stack.pop()
+        except IndexError:
+            return
+        if len(self.multispline_stack) == 0:
+            self.clear_graph(should_attempt_append=False) #clear, don't do anything
+            return
+        multispline = self.multispline_stack[-1]
+        if multispline['spline_count'] > 0:
+            self.points.fromMultiSpline(multispline)
+            self.mode= Mode.kEditing
+        else:
+            self.mode = Mode.kPlacing
+            self.clear_graph(should_attempt_append=False)
+        self.queue_draw()
+
+
 
     def do_key_press_event(self, event):
         keyval = Gdk.keyval_to_lower(event.keyval)
-
+        if keyval == Gdk.KEY_z and event.state & Gdk.ModifierType.CONTROL_MASK:
+            self.undo()
         # TODO: This should be a button
         if keyval == Gdk.KEY_p:
             self.mode = Mode.kPlacing
@@ -360,6 +388,7 @@
             self.queue_draw()
 
     def do_button_release_event(self, event):
+        self.attempt_append_multispline()
         self.mousex, self.mousey = self.input_transform.transform_point(
             event.x, event.y)
         if self.mode == Mode.kEditing:
diff --git a/frc971/control_loops/python/spline_graph.py b/frc971/control_loops/python/spline_graph.py
index e07bc80..2e67480 100755
--- a/frc971/control_loops/python/spline_graph.py
+++ b/frc971/control_loops/python/spline_graph.py
@@ -34,6 +34,8 @@
             self.field.points.getConstraint("LATERAL_ACCELERATION"))
         self.vol_input.set_value(self.field.points.getConstraint("VOLTAGE"))
 
+    def undo_func(self, *args):
+        self.field.undo()
     def long_changed(self, button):
         value = self.long_input.get_value()
         self.field.points.setConstraint("LONGITUDINAL_ACCELERATION", value)
@@ -135,6 +137,10 @@
         self.clear = Gtk.Button.new_with_label("Clear")
         self.clear.set_size_request(100, 40)
         self.clear.connect("clicked", self.clear_clicked)
+
+        self.undo = Gtk.Button.new_with_label("Undo (Ctrl + Z)")
+        self.undo.set_size_request(100, 40)
+        self.undo.connect("clicked", self.undo_func)
         #Dropdown feature
         self.label = Gtk.Label()
         self.label.set_text("Change Field:")
@@ -171,11 +177,12 @@
         container.attach(limitControls, 5, 1, 1, 1)
 
         jsonControls = Gtk.FlowBox()
-        jsonControls.set_min_children_per_line(3)
+        jsonControls.set_min_children_per_line(5)
         jsonControls.add(self.file_name_box)
         jsonControls.add(self.output_json)
         jsonControls.add(self.input_json)
         jsonControls.add(self.clear)
+        jsonControls.add(self.undo)
         container.attach(jsonControls, 1, 0, 1, 1)
 
         container.attach(self.label, 4, 0, 1, 1)