Explorar o código

View, delete, re-plot items

Juan Pablo Caram %!s(int64=12) %!d(string=hai) anos
pai
achega
0b16365ba2
Modificáronse 5 ficheiros con 938 adicións e 63 borrados
  1. 32 31
      camlib.py
  2. BIN=BIN
      camlib.pyc
  3. 263 32
      cirkuix.py
  4. BIN=BIN
      cirkuix.pyc
  5. 643 0
      cirkuix.ui

+ 32 - 31
camlib.py

@@ -1,4 +1,4 @@
-import cairo
+#import cairo
 
 #from string import *
 #from math import *
@@ -11,7 +11,7 @@ from numpy import arctan2, Inf, array, sqrt, pi, ceil, sin, cos
 from matplotlib.figure import Figure
 
 # See: http://toblerity.org/shapely/manual.html
-from shapely.geometry import Polygon, LineString, Point
+from shapely.geometry import Polygon, LineString, Point, LinearRing
 from shapely.geometry import MultiPoint, MultiPolygon
 from shapely.geometry import box as shply_box
 from shapely.ops import cascaded_union
@@ -41,7 +41,11 @@ class Geometry:
         if self.solid_geometry == None:
             print "Warning: solid_geometry not computed yet."
             return (0,0,0,0)
-        return self.solid_geometry.bounds
+            
+        if type(self.solid_geometry) == list:
+            return cascaded_union(self.solid_geometry).bounds
+        else:
+            return self.solid_geometry.bounds
         
     def size(self):
         '''
@@ -62,7 +66,7 @@ class Geometry:
         '''
         if boundary == None:
             boundary = self.solid_geometry.envelope
-        return boundary.difference(g.solid_geometry)
+        return boundary.difference(self.solid_geometry)
         
     def clear_polygon(self, polygon, tooldia, overlap = 0.15):
         '''
@@ -340,9 +344,10 @@ class Excellon(Geometry):
             self.solid_geometry.append(poly)
         self.solid_geometry = cascaded_union(self.solid_geometry)
 
-class CNCjob:
+class CNCjob(Geometry):
     def __init__(self, units="in", kind="generic", z_move = 0.1,
                  feedrate = 3.0, z_cut = -0.002):
+        
         # Options
         self.kind = kind
         self.units = units
@@ -366,7 +371,8 @@ class CNCjob:
         self.tooldia = 0
         
         # Output generated by CNCjob.create_gcode_geometry()
-        self.G_geometry = None
+        #self.G_geometry = None
+        self.gcode_parsed = None
         
     def generate_from_excellon(self, exobj):
         '''
@@ -447,7 +453,7 @@ class CNCjob:
                     self.gcode += "G00 Z%.4f\n"%self.z_move # Stop cutting
                 continue
             
-            if type(geo) == LineString or type(geo) == LineRing:
+            if type(geo) == LineString or type(geo) == LinearRing:
                 path = list(geo.coords)
                 self.gcode += t%(0, path[0][0], path[0][1]) # Move to first point
                 self.gcode += "G01 Z%.4f\n"%self.z_cut      # Start cutting
@@ -469,7 +475,7 @@ class CNCjob:
         self.gcode += "G00 X0Y0\n"
         self.gcode += "M05\n" # Spindle stop
     
-    def create_gcode_geometry(self):
+    def gcode_parse(self):
         steps_per_circ = 20
         '''
         G-Code parser (from self.gcode). Generates dictionary with 
@@ -534,7 +540,8 @@ class CNCjob:
             for code in gobj:
                 current[code] = gobj[code]
                 
-        self.G_geometry = geometry
+        #self.G_geometry = geometry
+        self.gcode_parsed = geometry
         return geometry
         
     def plot(self, tooldia=None, dpi=75, margin=0.1,
@@ -555,7 +562,7 @@ class CNCjob:
         ax.set_ylim(ymin-margin, ymax+margin)
         
         if tooldia == 0:
-            for geo in self.G_geometry:
+            for geo in self.gcode_parsed:
                 linespec = '--'
                 linecolor = color[geo['kind'][0]][1]
                 if geo['kind'][0] == 'C':
@@ -563,7 +570,7 @@ class CNCjob:
                 x, y = geo['geom'].coords.xy
                 ax.plot(x, y, linespec, color=linecolor)
         else:
-            for geo in self.G_geometry:
+            for geo in self.gcode_parsed:
                 poly = geo['geom'].buffer(tooldia/2.0)
                 patch = PolygonPatch(poly, facecolor=color[geo['kind'][0]][0],
                                      edgecolor=color[geo['kind'][0]][1],
@@ -576,20 +583,13 @@ class CNCjob:
              color={"T":["#F0E24D", "#B5AB3A"], "C":["#5E6CFF", "#4650BD"]},
              alpha={"T":0.3, "C":1.0}):
         '''
-        Plots the G-code job onto the given axes
+        Plots the G-code job onto the given axes.
         '''
         if tooldia == None:
             tooldia = self.tooldia
-            
-        #fig = Figure(dpi=dpi)
-        #ax = fig.add_subplot(111)
-        #ax.set_aspect(1)
-        #xmin, ymin, xmax, ymax = self.input_geometry_bounds
-        #ax.set_xlim(xmin-margin, xmax+margin)
-        #ax.set_ylim(ymin-margin, ymax+margin)
         
         if tooldia == 0:
-            for geo in self.G_geometry:
+            for geo in self.gcode_parsed:
                 linespec = '--'
                 linecolor = color[geo['kind'][0]][1]
                 if geo['kind'][0] == 'C':
@@ -597,13 +597,17 @@ class CNCjob:
                 x, y = geo['geom'].coords.xy
                 axes.plot(x, y, linespec, color=linecolor)
         else:
-            for geo in self.G_geometry:
+            for geo in self.gcode_parsed:
                 poly = geo['geom'].buffer(tooldia/2.0)
                 patch = PolygonPatch(poly, facecolor=color[geo['kind'][0]][0],
                                      edgecolor=color[geo['kind'][0]][1],
                                      alpha=alpha[geo['kind'][0]], zorder=2)
                 axes.add_patch(patch)
         
+    def create_geometry(self):
+        self.solid_geometry = cascaded_union([geo['geom'] for geo in self.gcode_parsed])
+
+                
 
 def gparse1b(gtext):
     '''
@@ -650,21 +654,18 @@ def gparse1b(gtext):
         gcmds.append(cmds)
     return gcmds
 
-def get_bounds(geometry_sets):
+def get_bounds(geometry_set):
     xmin = Inf
     ymin = Inf
     xmax = -Inf
     ymax = -Inf
     
-    #geometry_sets = [self.gerbers, self.excellons]
-    
-    for gs in geometry_sets:
-        for g in gs:
-            gxmin, gymin, gxmax, gymax = g.solid_geometry.bounds
-            xmin = min([xmin, gxmin])
-            ymin = min([ymin, gymin])
-            xmax = max([xmax, gxmax])
-            ymax = max([ymax, gymax])
+    for gs in geometry_set:
+        gxmin, gymin, gxmax, gymax = geometry_set[gs].bounds()
+        xmin = min([xmin, gxmin])
+        ymin = min([ymin, gymin])
+        xmax = max([xmax, gxmax])
+        ymax = max([ymax, gymax])
             
     return [xmin, ymin, xmax, ymax]
 

BIN=BIN
camlib.pyc


+ 263 - 32
cirkuix.py

@@ -13,18 +13,92 @@ from matplotlib.backends.backend_gtk3agg import FigureCanvasGTK3Agg as FigureCan
 
 from camlib import *
 
+class CirkuixObj:
+    def __init__(self, name, kind):
+        self.name = name
+        self.kind = kind
+        
+class CirkuixGerber(CirkuixObj, Gerber):
+    def __init__(self, name):
+        Gerber.__init__(self)
+        CirkuixObj.__init__(self, name, "gerber")
+        self.fields = [{"name":"plot", 
+                        "type":bool, 
+                        "value":True, 
+                        "get":None, 
+                        "set":None, 
+                        "onchange":None},
+                       {}]
+        
+class CirkuixExcellon(CirkuixObj, Excellon):
+    def __init__(self, name):
+        Excellon.__init__(self)
+        CirkuixObj.__init__(self, name, "excellon")
+        self.options = {"plot": True,
+                        "solid": False,
+                        "multicolored": False}
+        
+class CirkuixCNCjob(CirkuixObj, CNCjob):
+    def __init__(self, name):
+        CNCjob.__init__(self)
+        CirkuixObj.__init__(self, name, "cncjob")
+        self.options = {"plot": True}
+
+class CirkuixGeometry(CirkuixObj, Geometry):
+    def __init__(self, name):
+        CirkuixObj.__init__(self, name, "geometry")
+        self.options = {"plot": True,
+                        "solid": False,
+                        "multicolored": False}
+
+class CirkuixObjForm:
+    def __init__(self, container, Cobj):
+        self.Cobj = Cobj
+        self.container = container
+        self.fields = {}
+    
+    def populate(self):
+        return
+        
+    def save(self):
+        return
+
+#class CirkuixGerberForm(CirkuixObjForm)
+    
+
+def get_entry_text(entry):
+    return entry.get_text()
+    
+def get_entry_int(entry):
+    return int(entry.get_text())
+    
+def get_entry_float(entry):
+    return float(entry.get_text())
+    
+def get_entry_eval(entry):
+    return eval(entry.get_text)
+
+getters = {"entry_text":get_entry_text,
+           "entry_int":get_entry_int,
+           "entry_float":get_entry_float,
+           "entry_eval":get_entry_eval}
+
+setters = {"entry"}
+
 class App:
     def __init__(self):
         
         ########################################
         ##                GUI                 ##
-        ########################################
+        ########################################       
         self.gladefile = "cirkuix.ui"
         self.builder = Gtk.Builder()
         self.builder.add_from_file(self.gladefile)
         self.window = self.builder.get_object("window1")
+        self.window.set_title("Cirkuix")
         self.positionLabel = self.builder.get_object("label3")      
         self.grid = self.builder.get_object("grid1")
+        self.notebook = self.builder.get_object("notebook1")
         
         ## Event handling ##
         self.builder.connect_signals(self)
@@ -33,34 +107,36 @@ class App:
         self.figure = None
         self.axes = None
         self.canvas = None
-        self.mplpaint()
+        self.plot_setup()
         
+        self.setup_component_viewer()
+        self.setup_component_editor()
         
         ########################################
         ##               DATA                 ##
         ########################################
-        self.gerbers = []
-        self.excellons = []
-        self.cncjobs = []
+        self.stuff = {} # CirkuixObj's by name
         
         self.mouse = None
         
+        # What is selected by the user. It is
+        # a key if self.stuff
+        self.selected_item_name = None
+        
         ########################################
         ##              START                 ##
         ########################################
         self.window.show_all()
         Gtk.main()
         
-    def mplpaint(self):
+    def plot_setup(self):
         self.figure = Figure(dpi=50)
-        #self.axes = self.figure.add_subplot(111)
         self.axes = self.figure.add_axes([0.05,0.05,0.9,0.9])
         self.axes.set_aspect(1)
         #t = arange(0.0,5.0,0.01)
         #s = sin(2*pi*t)
         #self.axes.plot(t,s)
         self.axes.grid()
-        #a.patch.set_visible(False) Background of the axes
         self.figure.patch.set_visible(False)
         
         self.canvas = FigureCanvas(self.figure)  # a Gtk.DrawingArea
@@ -76,11 +152,13 @@ class App:
         self.canvas.mpl_connect('key_press_event', self.on_key_over_plot)
         self.canvas.mpl_connect('scroll_event', self.on_scroll_over_plot)
         
-        #self.builder.get_object("viewport2").add(self.canvas)
         self.grid.attach(self.canvas,0,0,600,400)
-        #self.builder.get_object("scrolledwindow1").add(self.canvas)
     
     def zoom(self, factor, center=None):
+        '''
+        Zooms the plot by factor around a given
+        center point. Takes care of re-drawing.
+        '''
         xmin, xmax = self.axes.get_xlim()
         ymin, ymax = self.axes.get_ylim()
         width = xmax-xmin
@@ -129,6 +207,8 @@ class App:
             for ints in poly.interiors:
                 x, y = ints.coords.xy
                 self.axes.plot(x, y, linespec)
+                
+        self.canvas.queue_draw()
         
     def plot_excellon(self, excellon):
         excellon.create_geometry()
@@ -140,31 +220,152 @@ class App:
             for ints in geo.interiors:
                 x, y = ints.coords.xy
                 self.axes.plot(x, y, 'g-')
+                
+        self.canvas.queue_draw()
 
     def plot_cncjob(self, job):
-        job.create_gcode_geometry()
+        #job.gcode_parse()
         tooldia_text = self.builder.get_object("entry_tooldia").get_text()
         tooldia_val = eval(tooldia_text)
         job.plot2(self.axes, tooldia=tooldia_val)
-        return
-    
-    def file_chooser_action(self, on_success):
-        dialog = Gtk.FileChooserDialog("Please choose a file", self.window,
-            Gtk.FileChooserAction.OPEN,
-            (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
-             Gtk.STOCK_OPEN, Gtk.ResponseType.OK))
-        response = dialog.run()
-        if response == Gtk.ResponseType.OK:
-            on_success(self, dialog.get_filename())
-        elif response == Gtk.ResponseType.CANCEL:
-            print("Cancel clicked")
-        dialog.destroy()
         
+        self.canvas.queue_draw()
+        
+    def setup_component_viewer(self):
+        '''
+        List or Tree where whatever has been loaded or created is
+        displayed.
+        '''
+        self.store = Gtk.ListStore(str)
+        self.tree = Gtk.TreeView(self.store)
+        select = self.tree.get_selection()
+        self.signal_id = select.connect("changed", self.on_tree_selection_changed)
+        renderer = Gtk.CellRendererText()
+        column = Gtk.TreeViewColumn("Title", renderer, text=0)
+        self.tree.append_column(column)
+        self.builder.get_object("notebook1").append_page(self.tree, Gtk.Label("Project"))
         
+    def setup_component_editor(self):
+        box1 = Gtk.Box(Gtk.Orientation.VERTICAL)
+        label1 = Gtk.Label("Choose an item from Project")
+        box1.pack_start(label1, False, False, 1)
+        self.builder.get_object("notebook1").append_page(box1, Gtk.Label("Selection"))
+        
+    def build_list(self):
+        self.store.clear()
+        for key in self.stuff:
+            self.store.append([key])
+        
+    def build_gerber_ui(self):
+        print "build_gerber_ui()"
+        osw = self.builder.get_object("offscrwindow_gerber")
+        box1 = self.builder.get_object("box_gerber")
+        osw.remove(box1)
+        self.notebook.append_page(box1, Gtk.Label("Selection"))
+        gerber = self.stuff[self.selected_item_name]
+        entry_name = self.builder.get_object("entry_gerbername")
+        entry_name.set_text(self.selected_item_name)
+        entry_name.connect("activate", self.on_activate_name)
+        box1.show()
+        
+    def build_excellon_ui(self):
+        print "build_excellon_ui()"
+        osw = self.builder.get_object("offscrwindow_excellon")
+        box1 = self.builder.get_object("box_excellon")
+        osw.remove(box1)
+        self.notebook.append_page(box1, Gtk.Label("Selection"))
+        entry_name = self.builder.get_object("entry_excellonname")
+        entry_name.set_text(self.selected_item_name)
+        entry_name.connect("activate", self.on_activate_name)
+        box1.show()
+        
+    def build_cncjob_ui(self):
+        print "build_cncjob_ui()"
+        osw = self.builder.get_object("offscrwindow_cncjob")
+        box1 = self.builder.get_object("box_cncjob")
+        osw.remove(box1)
+        self.notebook.append_page(box1, Gtk.Label("Selection"))
+        entry_name = self.builder.get_object("entry_cncjobname")
+        entry_name.set_text(self.selected_item_name)
+        entry_name.connect("activate", self.on_activate_name)
+        box1.show()
+        
+    def plot_all(self):
+        self.clear_plots()
+        plotter = {"gerber":self.plot_gerber,
+                   "excellon":self.plot_excellon,
+                   "cncjob":self.plot_cncjob}
+        
+        for i in self.stuff:
+            kind = self.stuff[i].kind
+            plotter[kind](self.stuff[i])
+        
+        self.on_zoom_fit(None)
+        self.axes.grid()
+        self.canvas.queue_draw()
+        
+    def clear_plots(self):
+        self.axes.cla()
+        self.canvas.queue_draw()
+
     ########################################
     ##         EVENT HANDLERS             ##
     ########################################
-            
+    def on_delete(self, widget):
+        self.stuff.pop(self.selected_item_name)
+        
+        #self.tree.get_selection().disconnect(self.signal_id)
+        self.build_list() # Update the items list
+        #self.signal_id = self.tree.get_selection().connect(
+        #                     "changed", self.on_tree_selection_changed)
+                             
+        self.plot_all()
+        #self.notebook.set_current_page(1)
+                             
+    def on_replot(self, widget):
+        self.plot_all()
+    
+    def on_clear_plots(self, widget):
+        self.clear_plots()
+        
+    def on_activate_name(self, entry):
+        '''
+        Hitting 'Enter' after changing the name of an item
+        updates the item dictionary and re-builds the item list.
+        '''
+        print "Changing name"
+        self.tree.get_selection().disconnect(self.signal_id)
+        new_name = entry.get_text() # Get from form
+        self.stuff[new_name] = self.stuff.pop(self.selected_item_name) # Update dictionary
+        self.selected_item_name = new_name # Update selection name
+        self.build_list() # Update the items list
+        self.signal_id = self.tree.get_selection().connect(
+                             "changed", self.on_tree_selection_changed)
+                             
+    def on_tree_selection_changed(self, selection):
+        model, treeiter = selection.get_selected()
+        
+                
+        if treeiter != None:
+            print "You selected", model[treeiter][0]
+        else:
+            return # TODO: Clear "Selected" page
+        
+        self.selected_item_name = model[treeiter][0]
+        # Remove the current selection page
+        # from the notebook
+        # TODO: Assuming it was last page or #2. Find the right page
+        self.builder.get_object("notebook1").remove_page(2)
+        
+        # Determine the kind of item selected
+        kind = self.stuff[model[treeiter][0]].kind
+        
+        # Build the UI
+        builder = {"gerber": self.build_gerber_ui,
+                   "excellon": self.build_excellon_ui,
+                   "cncjob": self.build_cncjob_ui}
+        builder[kind]()
+    
     def on_filequit(self, param):
         print "quit from menu"
         self.window.destroy()
@@ -175,31 +376,61 @@ class App:
         self.window.destroy()
         Gtk.main_quit()
     
+    def file_chooser_action(self, on_success):
+        '''
+        Opens the file chooser and runs on_success
+        upon completion of valid file choice.
+        '''
+        dialog = Gtk.FileChooserDialog("Please choose a file", self.window,
+            Gtk.FileChooserAction.OPEN,
+            (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
+             Gtk.STOCK_OPEN, Gtk.ResponseType.OK))
+        response = dialog.run()
+        if response == Gtk.ResponseType.OK:
+            on_success(self, dialog.get_filename())
+        elif response == Gtk.ResponseType.CANCEL:
+            print("Cancel clicked")
+        dialog.destroy()    
+    
     def on_fileopengerber(self, param):
         def on_success(self, filename):
-            gerber = Gerber()
+            name = filename.split('/')[-1].split('\\')[-1]
+            gerber = CirkuixGerber(name)
             gerber.parse_file(filename)
-            self.gerbers.append(gerber)
+            self.store.append([name])
+            #self.gerbers.append(gerber)
+            self.stuff[name] = gerber
             self.plot_gerber(gerber)
+            self.on_zoom_fit(None)
         self.file_chooser_action(on_success)
     
     def on_fileopenexcellon(self, param):
         def on_success(self, filename):
-            excellon = Excellon()
+            name = filename.split('/')[-1].split('\\')[-1]
+            excellon = CirkuixExcellon(name)
             excellon.parse_file(filename)
-            self.excellons.append(excellon)
+            self.store.append([name])
+            #self.excellons.append(excellon)
+            self.stuff[name] = excellon
             self.plot_excellon(excellon)
+            self.on_zoom_fit(None)
         self.file_chooser_action(on_success)
     
     def on_fileopengcode(self, param):
         def on_success(self, filename):
+            name = filename.split('/')[-1].split('\\')[-1]
             f = open(filename)
             gcode = f.read()
             f.close()
-            job = CNCjob()
+            job = CirkuixCNCjob(name)
             job.gcode = gcode
-            self.cncjobs.append(job)
+            job.gcode_parse()
+            job.create_geometry()
+            self.store.append([name])
+            #self.cncjobs.append(job)
+            self.stuff[name] = job
             self.plot_cncjob(job)
+            self.on_zoom_fit(None)
         self.file_chooser_action(on_success)
         
     def on_mouse_move_over_plot(self, event):
@@ -226,7 +457,7 @@ class App:
         self.zoom(1/1.5)
          
     def on_zoom_fit(self, event):
-        xmin, ymin, xmax, ymax = get_bounds([self.gerbers, self.excellons])
+        xmin, ymin, xmax, ymax = get_bounds(self.stuff)
         width = xmax-xmin
         height = ymax-ymin
         self.axes.set_xlim((xmin-0.05*width, xmax+0.05*width))

BIN=BIN
cirkuix.pyc


+ 643 - 0
cirkuix.ui

@@ -16,6 +16,607 @@
     <property name="can_focus">False</property>
     <property name="stock">gtk-open</property>
   </object>
+  <object class="GtkOffscreenWindow" id="offscrwindow_cncjob">
+    <property name="can_focus">False</property>
+    <child>
+      <object class="GtkBox" id="box_cncjob">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="margin_left">5</property>
+        <property name="margin_right">5</property>
+        <property name="margin_top">5</property>
+        <property name="margin_bottom">5</property>
+        <property name="orientation">vertical</property>
+        <child>
+          <object class="GtkLabel" id="label17">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="ypad">3</property>
+            <property name="label" translatable="yes">CNC Job Object</property>
+            <attributes>
+              <attribute name="weight" value="semibold"/>
+            </attributes>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkBox" id="box7">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <child>
+              <object class="GtkLabel" id="label18">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="xpad">3</property>
+                <property name="label" translatable="yes">Name: </property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">True</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkEntry" id="entry_cncjobname">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="invisible_char">●</property>
+                <property name="invisible_char_set">True</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">True</property>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkLabel" id="label19">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="xalign">0</property>
+            <property name="ypad">3</property>
+            <property name="label" translatable="yes">Plot Options:</property>
+            <attributes>
+              <attribute name="weight" value="semibold"/>
+            </attributes>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">2</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkCheckButton" id="cb_cncjobplot">
+            <property name="label" translatable="yes">Plot</property>
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="receives_default">False</property>
+            <property name="xalign">0</property>
+            <property name="active">True</property>
+            <property name="draw_indicator">True</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">3</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkCheckButton" id="checkbutton4">
+            <property name="label" translatable="yes">Solid</property>
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="receives_default">False</property>
+            <property name="xalign">0</property>
+            <property name="draw_indicator">True</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">4</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkCheckButton" id="cb_multicolored3">
+            <property name="label" translatable="yes">Multi-colored</property>
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="receives_default">False</property>
+            <property name="xalign">0</property>
+            <property name="draw_indicator">True</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">5</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkButton" id="button4">
+            <property name="label" translatable="yes">Refresh Plot</property>
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="receives_default">True</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">6</property>
+          </packing>
+        </child>
+        <child>
+          <placeholder/>
+        </child>
+        <child>
+          <placeholder/>
+        </child>
+        <child>
+          <placeholder/>
+        </child>
+      </object>
+    </child>
+  </object>
+  <object class="GtkOffscreenWindow" id="offscrwindow_excellon">
+    <property name="can_focus">False</property>
+    <child>
+      <object class="GtkBox" id="box_excellon">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="margin_left">5</property>
+        <property name="margin_right">5</property>
+        <property name="margin_top">5</property>
+        <property name="margin_bottom">5</property>
+        <property name="orientation">vertical</property>
+        <child>
+          <object class="GtkLabel" id="label10">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="ypad">3</property>
+            <property name="label" translatable="yes">Excellon Object</property>
+            <attributes>
+              <attribute name="weight" value="semibold"/>
+            </attributes>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkBox" id="box5">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <child>
+              <object class="GtkLabel" id="label11">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="xpad">3</property>
+                <property name="label" translatable="yes">Name: </property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">True</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkEntry" id="entry_excellonname">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="invisible_char">●</property>
+                <property name="invisible_char_set">True</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">True</property>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkLabel" id="label12">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="xalign">0</property>
+            <property name="ypad">3</property>
+            <property name="label" translatable="yes">Plot Options:</property>
+            <attributes>
+              <attribute name="weight" value="semibold"/>
+            </attributes>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">2</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkCheckButton" id="cb_excellonplot">
+            <property name="label" translatable="yes">Plot</property>
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="receives_default">False</property>
+            <property name="xalign">0</property>
+            <property name="active">True</property>
+            <property name="draw_indicator">True</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">3</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkCheckButton" id="checkbutton3">
+            <property name="label" translatable="yes">Solid</property>
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="receives_default">False</property>
+            <property name="xalign">0</property>
+            <property name="draw_indicator">True</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">4</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkCheckButton" id="cb_multicolored2">
+            <property name="label" translatable="yes">Multi-colored</property>
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="receives_default">False</property>
+            <property name="xalign">0</property>
+            <property name="draw_indicator">True</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">5</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkButton" id="button3">
+            <property name="label" translatable="yes">Refresh Plot</property>
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="receives_default">True</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">6</property>
+          </packing>
+        </child>
+        <child>
+          <placeholder/>
+        </child>
+        <child>
+          <placeholder/>
+        </child>
+        <child>
+          <placeholder/>
+        </child>
+      </object>
+    </child>
+  </object>
+  <object class="GtkOffscreenWindow" id="offscrwindow_gerber">
+    <property name="can_focus">False</property>
+    <child>
+      <object class="GtkBox" id="box_gerber">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="margin_left">5</property>
+        <property name="margin_right">5</property>
+        <property name="margin_top">5</property>
+        <property name="margin_bottom">5</property>
+        <property name="orientation">vertical</property>
+        <child>
+          <object class="GtkLabel" id="label7">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="ypad">3</property>
+            <property name="label" translatable="yes">Gerber Object</property>
+            <attributes>
+              <attribute name="weight" value="semibold"/>
+            </attributes>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkBox" id="box6">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <child>
+              <object class="GtkLabel" id="label8">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="xpad">3</property>
+                <property name="label" translatable="yes">Name: </property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">True</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkEntry" id="entry_gerbername">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="invisible_char">●</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">True</property>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkLabel" id="label9">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="xalign">0</property>
+            <property name="ypad">3</property>
+            <property name="label" translatable="yes">Plot Options:</property>
+            <attributes>
+              <attribute name="weight" value="semibold"/>
+            </attributes>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">2</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkCheckButton" id="cb_gerberplot">
+            <property name="label" translatable="yes">Plot</property>
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="receives_default">False</property>
+            <property name="xalign">0</property>
+            <property name="active">True</property>
+            <property name="draw_indicator">True</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">3</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkCheckButton" id="cb_mergepolys1">
+            <property name="label" translatable="yes">Merge Polygons</property>
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="receives_default">False</property>
+            <property name="xalign">0</property>
+            <property name="active">True</property>
+            <property name="draw_indicator">True</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">4</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkCheckButton" id="checkbutton2">
+            <property name="label" translatable="yes">Solid</property>
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="receives_default">False</property>
+            <property name="xalign">0</property>
+            <property name="draw_indicator">True</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">5</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkCheckButton" id="cb_multicolored1">
+            <property name="label" translatable="yes">Multi-colored</property>
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="receives_default">False</property>
+            <property name="xalign">0</property>
+            <property name="draw_indicator">True</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">6</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkButton" id="button2">
+            <property name="label" translatable="yes">Refresh Plot</property>
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="receives_default">True</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">7</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkLabel" id="label13">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="xalign">0</property>
+            <property name="ypad">3</property>
+            <property name="label" translatable="yes">Isolation Routing:</property>
+            <attributes>
+              <attribute name="weight" value="semibold"/>
+            </attributes>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">8</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkGrid" id="grid2">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="row_spacing">2</property>
+            <property name="column_spacing">2</property>
+            <child>
+              <object class="GtkLabel" id="label14">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="xalign">1</property>
+                <property name="xpad">3</property>
+                <property name="label" translatable="yes">Tool diam:</property>
+              </object>
+              <packing>
+                <property name="left_attach">0</property>
+                <property name="top_attach">0</property>
+                <property name="width">1</property>
+                <property name="height">1</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkEntry" id="entry4">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="invisible_char">●</property>
+                <property name="invisible_char_set">True</property>
+              </object>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="top_attach">0</property>
+                <property name="width">1</property>
+                <property name="height">1</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLabel" id="label15">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="xalign">1</property>
+                <property name="xpad">3</property>
+                <property name="label" translatable="yes">Cut X:</property>
+              </object>
+              <packing>
+                <property name="left_attach">0</property>
+                <property name="top_attach">1</property>
+                <property name="width">1</property>
+                <property name="height">1</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkEntry" id="entry5">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="invisible_char">●</property>
+                <property name="invisible_char_set">True</property>
+              </object>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="top_attach">1</property>
+                <property name="width">1</property>
+                <property name="height">1</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLabel" id="label16">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="xalign">1</property>
+                <property name="xpad">3</property>
+                <property name="label" translatable="yes">Travel X:</property>
+              </object>
+              <packing>
+                <property name="left_attach">0</property>
+                <property name="top_attach">2</property>
+                <property name="width">1</property>
+                <property name="height">1</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkEntry" id="entry6">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="invisible_char">●</property>
+                <property name="invisible_char_set">True</property>
+              </object>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="top_attach">2</property>
+                <property name="width">1</property>
+                <property name="height">1</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">9</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkButton" id="button1">
+            <property name="label" translatable="yes">Generate Geometry</property>
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="receives_default">True</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">10</property>
+          </packing>
+        </child>
+        <child>
+          <placeholder/>
+        </child>
+        <child>
+          <placeholder/>
+        </child>
+        <child>
+          <placeholder/>
+        </child>
+      </object>
+    </child>
+  </object>
   <object class="GtkWindow" id="window1">
     <property name="width_request">600</property>
     <property name="height_request">400</property>
@@ -237,6 +838,48 @@
                 <property name="homogeneous">True</property>
               </packing>
             </child>
+            <child>
+              <object class="GtkToolButton" id="Clear">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="label" translatable="yes">Clear Plots</property>
+                <property name="use_underline">True</property>
+                <property name="stock_id">gtk-stop</property>
+                <signal name="clicked" handler="on_clear_plots" swapped="no"/>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="homogeneous">True</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkToolButton" id="toolbutton1">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="label" translatable="yes">Re-plot</property>
+                <property name="use_underline">True</property>
+                <property name="stock_id">gtk-redo</property>
+                <signal name="clicked" handler="on_replot" swapped="no"/>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="homogeneous">True</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkToolButton" id="toolbutton2">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="label" translatable="yes">Delete Object</property>
+                <property name="use_underline">True</property>
+                <property name="stock_id">gtk-delete</property>
+                <signal name="clicked" handler="on_delete" swapped="no"/>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="homogeneous">True</property>
+              </packing>
+            </child>
           </object>
           <packing>
             <property name="expand">False</property>