Jelajahi Sumber

Merged jpcgt/flatcam into master

Marius Stanciu 7 tahun lalu
induk
melakukan
e7a468c72a
15 mengubah file dengan 275 tambahan dan 64 penghapusan
  1. 58 27
      FlatCAMApp.py
  2. 22 11
      FlatCAMDraw.py
  3. 47 20
      FlatCAMGUI.py
  4. 28 0
      FlatCAMObj.py
  5. 7 2
      FlatCAMTool.py
  6. 2 2
      MeasurementTool.py
  7. 48 1
      ObjectUI.py
  8. TEMPAT SAMPAH
      share/buffer16.png
  9. TEMPAT SAMPAH
      share/doubleside16.png
  10. TEMPAT SAMPAH
      share/doubleside32.png
  11. TEMPAT SAMPAH
      share/floppy32.png
  12. TEMPAT SAMPAH
      share/paint16.png
  13. 62 0
      tclCommands/TclCommandFollow.py
  14. 1 0
      tclCommands/__init__.py
  15. 0 1
      termwidget.py

+ 58 - 27
FlatCAMApp.py

@@ -541,6 +541,10 @@ class App(QtCore.QObject):
         self.ui.menuhelp_home.triggered.connect(lambda: webbrowser.open(self.app_url))
         self.ui.menuhelp_manual.triggered.connect(lambda: webbrowser.open(self.manual_url))
         # Toolbar
+        self.ui.open_gerber_btn.triggered.connect(self.on_fileopengerber)
+        self.ui.open_exc_btn.triggered.connect(self.on_fileopenexcellon)
+        self.ui.open_gcode_btn.triggered.connect(self.on_fileopengcode)
+        self.ui.save_btn.triggered.connect(self.on_file_saveprojectas)
         self.ui.zoom_fit_btn.triggered.connect(self.on_zoom_fit)
         self.ui.zoom_in_btn.triggered.connect(lambda: self.plotcanvas.zoom(1.5))
         self.ui.zoom_out_btn.triggered.connect(lambda: self.plotcanvas.zoom(1 / 1.5))
@@ -571,10 +575,12 @@ class App(QtCore.QObject):
         ### Tools and Plugins ###
         #########################
         self.dblsidedtool = DblSidedTool(self)
-        self.dblsidedtool.install()
+        self.dblsidedtool.install(icon=QtGui.QIcon('share/doubleside16.png'), separator=True)
 
         self.measeurement_tool = Measurement(self)
-        self.measeurement_tool.install()
+        self.measeurement_tool.install(icon=QtGui.QIcon('share/measure16.png'))
+
+        self.ui.measure_btn.triggered.connect(self.measeurement_tool.run)
 
         self.draw = FlatCAMDraw(self, disabled=True)
 
@@ -603,6 +609,7 @@ class App(QtCore.QObject):
                              QtGui.QDockWidget.DockWidgetFloatable | QtGui.QDockWidget.DockWidgetClosable)
         self.ui.addDockWidget(QtCore.Qt.BottomDockWidgetArea, self.ui.shell_dock)
 
+
         if self.defaults["shell_at_startup"]:
             self.ui.shell_dock.show()
         else:
@@ -3634,27 +3641,51 @@ class App(QtCore.QObject):
 
             return output
 
-        def follow(obj_name, *args):
-            a, kwa = h(*args)
-
-            types = {'outname': str}
 
-            for key in kwa:
-                if key not in types:
-                    return 'Unknown parameter: %s' % key
-                kwa[key] = types[key](kwa[key])
+        # def follow(obj_name, *args):
+        #     a, kwa = h(*args)
+        #
+        #     types = {'outname': str}
+        #
+        #     for key in kwa:
+        #         if key not in types:
+        #             return 'Unknown parameter: %s' % key
+        #         kwa[key] = types[key](kwa[key])
+        #
+        #     try:
+        #         obj = self.collection.get_by_name(str(obj_name))
+        #     except:
+        #         return "Could not retrieve object: %s" % obj_name
+        #     if obj is None:
+        #         return "Object not found: %s" % obj_name
+        #
+        #     try:
+        #         obj.follow(**kwa)
+        #     except Exception, e:
+        #         return "ERROR: %s" % str(e)
 
-            try:
-                obj = self.collection.get_by_name(str(obj_name))
-            except:
-                return "Could not retrieve object: %s" % obj_name
-            if obj is None:
-                return "Object not found: %s" % obj_name
+        # def follow(obj_name, *args):
+        #     a, kwa = h(*args)
+        #
+        #     types = {'outname': str}
+        #
+        #     for key in kwa:
+        #         if key not in types:
+        #             return 'Unknown parameter: %s' % key
+        #         kwa[key] = types[key](kwa[key])
+        #
+        #     try:
+        #         obj = self.collection.get_by_name(str(obj_name))
+        #     except:
+        #         return "Could not retrieve object: %s" % obj_name
+        #     if obj is None:
+        #         return "Object not found: %s" % obj_name
+        #
+        #     try:
+        #         obj.follow(**kwa)
+        #     except Exception as e:
+        #         return "ERROR: %s" % str(e)
 
-            try:
-                obj.follow(**kwa)
-            except Exception as e:
-                return "ERROR: %s" % str(e)
 
         # def get_sys(param):
         #     if param in self.defaults:
@@ -4098,13 +4129,13 @@ class App(QtCore.QObject):
                 'fcn': make_docs,
                 'help': 'Prints command rererence in reStructuredText format.'
             },
-            'follow': {
-                'fcn': follow,
-                'help': 'Creates a geometry object following gerber paths.\n' +
-                        '> follow <name> [-outname <oname>]\n' +
-                        '   name: Name of the gerber object.\n' +
-                        '   outname: Name of the output geometry object.'
-            },
+            # 'follow': {
+            #     'fcn': follow,
+            #     'help': 'Creates a geometry object following gerber paths.\n' +
+            #             '> follow <name> [-outname <oname>]\n' +
+            #             '   name: Name of the gerber object.\n' +
+            #             '   outname: Name of the output geometry object.'
+            # },
 
             # 'get_sys': {
             #     'fcn': get_sys,

+ 22 - 11
FlatCAMDraw.py

@@ -690,25 +690,34 @@ class FlatCAMDraw(QtCore.QObject):
         self.axes = self.canvas.new_axes("draw")
 
         ### Drawing Toolbar ###
-        self.drawing_toolbar = QtGui.QToolBar()
+        self.drawing_toolbar = QtGui.QToolBar("Draw Toolbar")
         self.drawing_toolbar.setDisabled(disabled)
         self.app.ui.addToolBar(self.drawing_toolbar)
+
         self.select_btn = self.drawing_toolbar.addAction(QtGui.QIcon('share/pointer32.png'), "Select 'Esc'")
+        # Separator
+        self.drawing_toolbar.addSeparator()
         self.add_circle_btn = self.drawing_toolbar.addAction(QtGui.QIcon('share/circle32.png'), 'Add Circle')
         self.add_arc_btn = self.drawing_toolbar.addAction(QtGui.QIcon('share/arc32.png'), 'Add Arc')
         self.add_rectangle_btn = self.drawing_toolbar.addAction(QtGui.QIcon('share/rectangle32.png'), 'Add Rectangle')
         self.add_polygon_btn = self.drawing_toolbar.addAction(QtGui.QIcon('share/polygon32.png'), 'Add Polygon')
         self.add_path_btn = self.drawing_toolbar.addAction(QtGui.QIcon('share/path32.png'), 'Add Path')
+
+        # Separator
+        self.drawing_toolbar.addSeparator()
         self.union_btn = self.drawing_toolbar.addAction(QtGui.QIcon('share/union32.png'), 'Polygon Union')
         self.intersection_btn = self.drawing_toolbar.addAction(QtGui.QIcon('share/intersection32.png'), 'Polygon Intersection')
         self.subtract_btn = self.drawing_toolbar.addAction(QtGui.QIcon('share/subtract32.png'), 'Polygon Subtraction')
         self.cutpath_btn = self.drawing_toolbar.addAction(QtGui.QIcon('share/cutpath32.png'), 'Cut Path')
+
+        # Separator
+        self.drawing_toolbar.addSeparator()
         self.move_btn = self.drawing_toolbar.addAction(QtGui.QIcon('share/move32.png'), "Move Objects 'm'")
         self.copy_btn = self.drawing_toolbar.addAction(QtGui.QIcon('share/copy32.png'), "Copy Objects 'c'")
         self.delete_btn = self.drawing_toolbar.addAction(QtGui.QIcon('share/deleteshape32.png'), "Delete Shape '-'")
 
         ### Snap Toolbar ###
-        self.snap_toolbar = QtGui.QToolBar()
+        self.snap_toolbar = QtGui.QToolBar("Grid Toolbar")
         self.grid_snap_btn = self.snap_toolbar.addAction(QtGui.QIcon('share/grid32.png'), 'Snap to grid')
         self.grid_gap_x_entry = QtGui.QLineEdit()
         self.grid_gap_x_entry.setMaximumWidth(70)
@@ -731,18 +740,20 @@ class FlatCAMDraw(QtCore.QObject):
         ### Application menu ###
         self.menu = QtGui.QMenu("Drawing")
         self.app.ui.menu.insertMenu(self.app.ui.menutoolaction, self.menu)
-        # self.select_menuitem = self.menu.addAction(QtGui.QIcon('share/pointer16.png'), "Select 'Esc'")
-        # self.add_circle_menuitem = self.menu.addAction(QtGui.QIcon('share/circle16.png'), 'Add Circle')
-        # self.add_arc_menuitem = self.menu.addAction(QtGui.QIcon('share/arc16.png'), 'Add Arc')
-        # self.add_rectangle_menuitem = self.menu.addAction(QtGui.QIcon('share/rectangle16.png'), 'Add Rectangle')
-        # self.add_polygon_menuitem = self.menu.addAction(QtGui.QIcon('share/polygon16.png'), 'Add Polygon')
-        # self.add_path_menuitem = self.menu.addAction(QtGui.QIcon('share/path16.png'), 'Add Path')
+        # self.select_menuitem = self.menu.addAction(QtGui.QIcon('share:pointer16.png'), "Select 'Esc'")
+        # self.add_circle_menuitem = self.menu.addAction(QtGui.QIcon('share:circle16.png'), 'Add Circle')
+        # self.add_arc_menuitem = self.menu.addAction(QtGui.QIcon('share:arc16.png'), 'Add Arc')
+        # self.add_rectangle_menuitem = self.menu.addAction(QtGui.QIcon('share:rectangle16.png'), 'Add Rectangle')
+        # self.add_polygon_menuitem = self.menu.addAction(QtGui.QIcon('share:polygon16.png'), 'Add Polygon')
+        # self.add_path_menuitem = self.menu.addAction(QtGui.QIcon('share:path16.png'), 'Add Path')
         self.union_menuitem = self.menu.addAction(QtGui.QIcon('share/union16.png'), 'Polygon Union')
         self.intersection_menuitem = self.menu.addAction(QtGui.QIcon('share/intersection16.png'), 'Polygon Intersection')
-        # self.subtract_menuitem = self.menu.addAction(QtGui.QIcon('share/subtract16.png'), 'Polygon Subtraction')
+        # self.subtract_menuitem = self.menu.addAction(QtGui.QIcon('share:subtract16.png'), 'Polygon Subtraction')
         self.cutpath_menuitem = self.menu.addAction(QtGui.QIcon('share/cutpath16.png'), 'Cut Path')
-        # self.move_menuitem = self.menu.addAction(QtGui.QIcon('share/move16.png'), "Move Objects 'm'")
-        # self.copy_menuitem = self.menu.addAction(QtGui.QIcon('share/copy16.png'), "Copy Objects 'c'")
+        # Add Separator
+        self.menu.addSeparator()
+        # self.move_menuitem = self.menu.addAction(QtGui.QIcon('share:move16.png'), "Move Objects 'm'")
+        # self.copy_menuitem = self.menu.addAction(QtGui.QIcon('share:copy16.png'), "Copy Objects 'c'")
         self.delete_menuitem = self.menu.addAction(QtGui.QIcon('share/deleteshape16.png'), "Delete Shape '-'")
         self.buffer_menuitem = self.menu.addAction(QtGui.QIcon('share/buffer16.png'), "Buffer selection 'b'")
         self.paint_menuitem = self.menu.addAction(QtGui.QIcon('share/paint16.png'), "Paint selection")

+ 47 - 20
FlatCAMGUI.py

@@ -28,13 +28,15 @@ class FlatCAMGUI(QtGui.QMainWindow):
         self.menufile = self.menu.addMenu('&File')
 
         # New
-        self.menufilenew = QtGui.QAction(QtGui.QIcon('share/file16.png'), '&New', self)
+        self.menufilenew = QtGui.QAction(QtGui.QIcon('share/file16.png'), '&New project', self)
         self.menufile.addAction(self.menufilenew)
-        # Open recent
 
         # Recent
         self.recent = self.menufile.addMenu(QtGui.QIcon('share/folder16.png'), "Open recent ...")
 
+        # Separator
+        self.menufile.addSeparator()
+
         # Open gerber ...
         self.menufileopengerber = QtGui.QAction(QtGui.QIcon('share/folder16.png'), 'Open &Gerber ...', self)
         self.menufile.addAction(self.menufileopengerber)
@@ -51,6 +53,9 @@ class FlatCAMGUI(QtGui.QMainWindow):
         self.menufileopenproject = QtGui.QAction(QtGui.QIcon('share/folder16.png'), 'Open &Project ...', self)
         self.menufile.addAction(self.menufileopenproject)
 
+        # Separator
+        self.menufile.addSeparator()
+
         # Import SVG ...
         self.menufileimportsvg = QtGui.QAction(QtGui.QIcon('share/folder16.png'), 'Import &SVG ...', self)
         self.menufile.addAction(self.menufileimportsvg)
@@ -59,6 +64,9 @@ class FlatCAMGUI(QtGui.QMainWindow):
         self.menufileexportsvg = QtGui.QAction(QtGui.QIcon('share/folder16.png'), 'Export &SVG ...', self)
         self.menufile.addAction(self.menufileexportsvg)
 
+        # Separator
+        self.menufile.addSeparator()
+
         # Save Project
         self.menufilesaveproject = QtGui.QAction(QtGui.QIcon('share/floppy16.png'), '&Save Project', self)
         self.menufile.addAction(self.menufilesaveproject)
@@ -75,14 +83,16 @@ class FlatCAMGUI(QtGui.QMainWindow):
         self.menufilesavedefaults = QtGui.QAction(QtGui.QIcon('share/floppy16.png'), 'Save &Defaults', self)
         self.menufile.addAction(self.menufilesavedefaults)
 
+        # Separator
+        self.menufile.addSeparator()
+
         # Quit
         self.exit_action = QtGui.QAction(QtGui.QIcon('share/power16.png'), '&Exit', self)
+        self.menufile.addAction(self.exit_action)
         # exitAction.setShortcut('Ctrl+Q')
         # exitAction.setStatusTip('Exit application')
         #self.exit_action.triggered.connect(QtGui.qApp.quit)
 
-        self.menufile.addAction(self.exit_action)
-
         ### Edit ###
         self.menuedit = self.menu.addMenu('&Edit')
         self.menueditnew = self.menuedit.addAction(QtGui.QIcon('share/new_geo16.png'), 'New Geometry')
@@ -111,7 +121,7 @@ class FlatCAMGUI(QtGui.QMainWindow):
         self.menuviewenable = self.menuview.addAction(QtGui.QIcon('share/replot16.png'), 'Enable all plots')
 
         ### Tool ###
-        #self.menutool = self.menu.addMenu('&Tool')
+
         self.menutool = QtGui.QMenu('&Tool')
         self.menutoolaction = self.menu.addMenu(self.menutool)
         self.menutoolshell = self.menutool.addAction(QtGui.QIcon('share/shell16.png'), '&Command Line')
@@ -125,21 +135,38 @@ class FlatCAMGUI(QtGui.QMainWindow):
         ###############
         ### Toolbar ###
         ###############
-        self.toolbar = QtGui.QToolBar()
-        self.addToolBar(self.toolbar)
-
-        self.zoom_fit_btn = self.toolbar.addAction(QtGui.QIcon('share/zoom_fit32.png'), "&Zoom Fit")
-        self.zoom_out_btn = self.toolbar.addAction(QtGui.QIcon('share/zoom_out32.png'), "&Zoom Out")
-        self.zoom_in_btn = self.toolbar.addAction(QtGui.QIcon('share/zoom_in32.png'), "&Zoom In")
-        self.clear_plot_btn = self.toolbar.addAction(QtGui.QIcon('share/clear_plot32.png'), "&Clear Plot")
-        self.replot_btn = self.toolbar.addAction(QtGui.QIcon('share/replot32.png'), "&Replot")
-        self.newgeo_btn = self.toolbar.addAction(QtGui.QIcon('share/new_geo32.png'), "New Blank Geometry")
-        self.editgeo_btn = self.toolbar.addAction(QtGui.QIcon('share/edit32.png'), "Edit Geometry")
-        self.updategeo_btn = self.toolbar.addAction(QtGui.QIcon('share/edit_ok32.png'), "Update Geometry")
+        self.toolbarfile = QtGui.QToolBar('File Toolbar')
+        self.addToolBar(self.toolbarfile)
+        self.open_gerber_btn = self.toolbarfile.addAction(QtGui.QIcon('share/flatcam_icon32.png'), "Open &Gerber")
+        self.open_exc_btn = self.toolbarfile.addAction(QtGui.QIcon('share/drill32.png'), "Open &Excellon")
+        self.open_gcode_btn = self.toolbarfile.addAction(QtGui.QIcon('share/cnc32.png'), "Open Gco&de")
+        self.save_btn = self.toolbarfile.addAction(QtGui.QIcon('share/floppy32.png'), 'Save Project &As ...')
+
+        self.toolbarview= QtGui.QToolBar('View Toolbar')
+        self.addToolBar(self.toolbarview)
+        self.zoom_fit_btn = self.toolbarview.addAction(QtGui.QIcon('share/zoom_fit32.png'), "&Zoom Fit")
+        self.zoom_out_btn = self.toolbarview.addAction(QtGui.QIcon('share/zoom_out32.png'), "&Zoom Out")
+        self.zoom_in_btn = self.toolbarview.addAction(QtGui.QIcon('share/zoom_in32.png'), "&Zoom In")
+        # Separator
+        self.toolbarview.addSeparator()
+        self.clear_plot_btn = self.toolbarview.addAction(QtGui.QIcon('share/clear_plot32.png'), "&Clear Plot")
+        self.replot_btn = self.toolbarview.addAction(QtGui.QIcon('share/replot32.png'), "&Replot")
+
+        self.toolbareditobj = QtGui.QToolBar('Obj.Editor Toolbar')
+        self.addToolBar(self.toolbareditobj)
+        self.newgeo_btn = self.toolbareditobj.addAction(QtGui.QIcon('share/new_geo32.png'), "New Blank Geometry")
+        self.editgeo_btn = self.toolbareditobj.addAction(QtGui.QIcon('share/edit32.png'), "Edit Geometry")
+        self.updategeo_btn = self.toolbareditobj.addAction(QtGui.QIcon('share/edit_ok32.png'), "Update Geometry")
         self.updategeo_btn.setEnabled(False)
-        #self.canceledit_btn = self.toolbar.addAction(QtGui.QIcon('share/cancel_edit32.png'), "Cancel Edit")
-        self.delete_btn = self.toolbar.addAction(QtGui.QIcon('share/delete32.png'), "&Delete")
-        self.shell_btn = self.toolbar.addAction(QtGui.QIcon('share/shell32.png'), "&Command Line")
+
+        self.toolbaredit = QtGui.QToolBar('Edit Toolbar')
+        self.addToolBar(self.toolbaredit)
+        self.delete_btn = self.toolbaredit.addAction(QtGui.QIcon('share/delete32.png'), "&Delete")
+
+        self.toolbartools = QtGui.QToolBar('Tools Toolbar')
+        self.addToolBar(self.toolbartools)
+        self.shell_btn = self.toolbartools.addAction(QtGui.QIcon('share/shell32.png'), "&Command Line")
+        self.measure_btn = self.toolbartools.addAction(QtGui.QIcon('share/measure32.png'), "&Measurement Tool")
 
         ################
         ### Splitter ###
@@ -154,7 +181,7 @@ class FlatCAMGUI(QtGui.QMainWindow):
         
         # self.notebook.setMinimumWidth(250)
 
-        ### Projet ###
+        ### Project ###
         project_tab = QtGui.QWidget()
         project_tab.setMinimumWidth(250)  # Hack
         self.project_tab_layout = QtGui.QVBoxLayout(project_tab)

+ 28 - 0
FlatCAMObj.py

@@ -92,7 +92,9 @@ class FlatCAMObj(QtCore.QObject):
         assert isinstance(self.ui, ObjectUI)
         self.ui.name_entry.returnPressed.connect(self.on_name_activate)
         self.ui.offset_button.clicked.connect(self.on_offset_button_click)
+        self.ui.auto_offset_button.clicked.connect(self.on_auto_offset_button_click)
         self.ui.scale_button.clicked.connect(self.on_scale_button_click)
+        self.ui.mirror_button.clicked.connect(self.on_mirror_button_click)
 
     def __str__(self):
         return "<FlatCAMObj({:12s}): {:20s}>".format(self.kind, self.options["name"])
@@ -110,6 +112,15 @@ class FlatCAMObj(QtCore.QObject):
         vect = self.ui.offsetvector_entry.get_value()
         self.offset(vect)
         self.plot()
+    
+    def on_auto_offset_button_click(self):
+        self.app.report_usage("obj_on_auto_offset_button")
+        self.read_form()
+        minx, miny, maxx, maxy = self.bounds()
+        vect = (-minx, -miny)
+        self.ui.offsetvector_entry.set_value(vect)
+        self.offset(vect)
+        self.plot()
 
     def on_scale_button_click(self):
         self.app.report_usage("obj_on_scale_button")
@@ -118,6 +129,23 @@ class FlatCAMObj(QtCore.QObject):
         self.scale(factor)
         self.plot()
 
+    def on_mirror_button_click(self):
+        self.app.report_usage("obj_on_mirror_button")
+        self.read_form()
+        minx, miny, maxx, maxy = self.bounds()
+        
+        axis = self.ui.mirror_axis_radio.get_value()
+        
+        if not self.ui.mirror_auto_center_cb.get_value():
+          vect = (0, 0)
+        elif axis == 'X':
+          vect = (0, (maxy + miny)/2)
+        else:
+          vect = ((maxx + minx)/2, 0)
+        
+        self.mirror(axis, vect)
+        self.plot()
+
     def setup_axes(self, figure):
         """
         1) Creates axes if they don't exist. 2) Clears axes. 3) Attaches

+ 7 - 2
FlatCAMTool.py

@@ -32,8 +32,13 @@ class FlatCAMTool(QtGui.QWidget):
 
         self.menuAction = None
 
-    def install(self):
-        self.menuAction = self.app.ui.menutool.addAction(self.toolName)
+    def install(self, icon=None, separator=None):
+        if icon is None:
+            self.menuAction = self.app.ui.menutool.addAction(self.toolName)
+        else:
+            self.menuAction = self.app.ui.menutool.addAction(icon, self.toolName)
+        if separator is True:
+            self.app.ui.menutool.addSeparator()
         self.menuAction.triggered.connect(self.run)
 
     def run(self):

+ 2 - 2
MeasurementTool.py

@@ -29,8 +29,8 @@ class Measurement(FlatCAMTool):
         self.click_subscription = None
         self.move_subscription = None
 
-    def install(self):
-        FlatCAMTool.install(self)
+    def install(self, icon=None, separator=None):
+        FlatCAMTool.install(self, icon, separator)
         self.app.ui.right_layout.addWidget(self)
         self.app.plotcanvas.mpl_connect('key_press_event', self.on_key_press)
 

+ 48 - 1
ObjectUI.py

@@ -103,6 +103,46 @@ class ObjectUI(QtGui.QWidget):
         )
         layout.addWidget(self.offset_button)
 
+        self.auto_offset_button = QtGui.QPushButton('Offset auto')
+        self.auto_offset_button.setToolTip(
+            "Align the object with the x and y axes."
+        )
+        layout.addWidget(self.auto_offset_button)
+        
+        #### Mirror ####
+        self.mirror_label = QtGui.QLabel('<b>Mirror:</b>')
+        self.mirror_label.setToolTip(
+            "Flip the object along an axis."
+        )
+        layout.addWidget(self.mirror_label)
+        
+        self.mirror_axis_grid = QtGui.QGridLayout()
+        layout.addLayout(self.mirror_axis_grid)
+        
+        axislabel = QtGui.QLabel('Axis:')
+        axislabel.setToolTip(
+            "Mirror axis parallel to the x or y axis."
+        )
+        self.mirror_axis_grid.addWidget(axislabel, 0, 0)
+        
+        self.mirror_axis_radio = RadioSet([{'label': 'X', 'value': 'X'},
+                                           {'label': 'Y', 'value': 'Y'}])
+        self.mirror_axis_radio.set_value('Y')
+        self.mirror_axis_grid.addWidget(self.mirror_axis_radio, 0, 1)
+        
+        self.mirror_auto_center_cb = FCCheckBox(label='Center axis automatically')
+        self.mirror_auto_center_cb.setToolTip(
+            "Place the mirror axis on the middle of the object."
+        )
+        self.mirror_auto_center_cb.set_value(True)
+        layout.addWidget(self.mirror_auto_center_cb)
+
+        self.mirror_button = QtGui.QPushButton('Mirror')
+        self.mirror_button.setToolTip(
+            "Perform the mirror operation."
+        )
+        layout.addWidget(self.mirror_button)
+
         layout.addStretch()
 
 
@@ -130,6 +170,13 @@ class CNCObjectUI(ObjectUI):
             self.offset_grid.itemAt(i).widget().hide()
         self.offset_label.hide()
         self.offset_button.hide()
+        self.auto_offset_button.hide()
+        
+        self.mirror_label.hide()
+        for i in range(0, self.mirror_axis_grid.count()):
+            self.mirror_axis_grid.itemAt(i).widget().hide()
+        self.mirror_auto_center_cb.hide()
+        self.mirror_button.hide()
 
         ## Plot options
         self.plot_options_label = QtGui.QLabel("<b>Plot Options:</b>")
@@ -812,7 +859,7 @@ class GerberObjectUI(ObjectUI):
 
         self.generate_bb_button = QtGui.QPushButton('Generate Geometry')
         self.generate_bb_button.setToolTip(
-            "Genrate the Geometry object."
+            "Generate the Geometry object."
         )
         self.custom_box.addWidget(self.generate_bb_button)
 

TEMPAT SAMPAH
share/buffer16.png


TEMPAT SAMPAH
share/doubleside16.png


TEMPAT SAMPAH
share/doubleside32.png


TEMPAT SAMPAH
share/floppy32.png


TEMPAT SAMPAH
share/paint16.png


+ 62 - 0
tclCommands/TclCommandFollow.py

@@ -0,0 +1,62 @@
+from ObjectCollection import *
+import TclCommand
+
+
+class TclCommandFollow(TclCommand.TclCommandSignaled):
+    """
+    Tcl shell command to follow a Gerber file
+    """
+
+    # array of all command aliases, to be able use  old names for backward compatibility (add_poly, add_polygon)
+    aliases = ['follow']
+
+    # dictionary of types from Tcl command, needs to be ordered
+    arg_names = collections.OrderedDict([
+        ('name', str)
+    ])
+
+    # dictionary of types from Tcl command, needs to be ordered , this  is  for options  like -optionname value
+    option_types = collections.OrderedDict([
+        ('outname', str)
+    ])
+
+    # array of mandatory options for current Tcl command: required = {'name','outname'}
+    required = ['name']
+
+    # structured help for current command, args needs to be ordered
+    help = {
+        'main': "Creates a geometry object following gerber paths.",
+        'args': collections.OrderedDict([
+            ('name', 'Object name to follow.'),
+            ('outname', 'Name of the resulting Geometry object.')
+        ]),
+        'examples': ['follow name -outname name_follow']
+    }
+
+    def execute(self, args, unnamed_args):
+        """
+        execute current TCL shell command
+
+        :param args: array of known named arguments and options
+        :param unnamed_args: array of other values which were passed into command
+            without -somename and  we do not have them in known arg_names
+        :return: None or exception
+        """
+
+        name = args['name']
+
+        if 'outname' not in args:
+            follow_name = name + "_follow"
+
+        obj = self.app.collection.get_by_name(name)
+
+        if obj is None:
+            self.raise_tcl_error("Object not found: %s" % name)
+
+        if not isinstance(obj, FlatCAMGerber):
+            self.raise_tcl_error('Expected FlatCAMGerber, got %s %s.' % (name, type(obj)))
+
+        del args['name']
+        obj.follow(**args)
+
+

+ 1 - 0
tclCommands/__init__.py

@@ -16,6 +16,7 @@ import tclCommands.TclCommandDrillcncjob
 import tclCommands.TclCommandExportGcode
 import tclCommands.TclCommandExportSVG
 import tclCommands.TclCommandExteriors
+import tclCommands.TclCommandFollow
 import tclCommands.TclCommandGeoCutout
 import tclCommands.TclCommandGeoUnion
 import tclCommands.TclCommandGetNames

+ 0 - 1
termwidget.py

@@ -132,7 +132,6 @@ class TermWidget(QWidget):
             self._edit.setPlainText("...proccessing... [%s]" % detail)
 
         self._edit.setDisabled(True)
-        self._edit.setFocus()
 
     def close_proccessing(self):
         """