- renamed the theme to layout because it is really a layout change

- combined the geocutout and cutout_any TCL commands - work in progress
This commit is contained in:
Marius Stanciu 2019-02-06 16:59:17 +02:00 committed by Marius
parent 8bbb9ba534
commit 05ae92726c
7 changed files with 159 additions and 272 deletions

View File

@ -1212,7 +1212,7 @@ class App(QtCore.QObject):
self.general_defaults_form.general_gui_group.wk_cb.currentIndexChanged.connect(self.on_workspace_modified)
self.general_defaults_form.general_gui_group.workspace_cb.stateChanged.connect(self.on_workspace)
self.general_defaults_form.general_gui_group.theme_combo.activated.connect(self.on_theme)
self.general_defaults_form.general_gui_group.layout_combo.activated.connect(self.on_layout)
# Modify G-CODE Plot Area TAB
self.ui.code_editor.textChanged.connect(self.handleTextChanged)
@ -1257,7 +1257,7 @@ class App(QtCore.QObject):
# Auto-complete KEYWORDS
self.tcl_commands_list = ['add_circle', 'add_poly', 'add_polygon', 'add_polyline', 'add_rectangle',
'aligndrill', 'clear',
'aligndrillgrid', 'cncjob', 'cutout', 'cutout_any', 'delete', 'drillcncjob',
'aligndrillgrid', 'cncjob', 'cutout', 'delete', 'drillcncjob',
'export_gcode',
'export_svg', 'ext', 'exteriors', 'follow', 'geo_union', 'geocutout', 'get_names',
'get_sys', 'getsys', 'help', 'import_svg', 'interiors', 'isolate', 'join_excellon',
@ -3245,13 +3245,13 @@ class App(QtCore.QObject):
self.general_defaults_form.general_gui_group.workspace_cb.setChecked(True)
self.on_workspace()
def on_theme(self):
self.report_usage("on_theme()")
def on_layout(self):
self.report_usage("on_layout()")
current_theme= self.general_defaults_form.general_gui_group.theme_combo.get_value().lower()
current_layout= self.general_defaults_form.general_gui_group.layout_combo.get_value().lower()
settings = QSettings("Open Source", "FlatCAM")
settings.setValue('theme', current_theme)
settings.setValue('layout', current_layout)
# This will write the setting to the platform specific storage.
del settings
@ -3265,7 +3265,7 @@ class App(QtCore.QObject):
self.ui.removeToolBar(self.ui.geo_edit_toolbar)
self.ui.removeToolBar(self.ui.snap_toolbar)
if current_theme == 'standard':
if current_layout == 'standard':
### TOOLBAR INSTALLATION ###
self.ui.toolbarfile = QtWidgets.QToolBar('File Toolbar')
self.ui.toolbarfile.setObjectName('File_TB')
@ -3300,7 +3300,7 @@ class App(QtCore.QObject):
self.ui.corner_snap_btn.setVisible(False)
self.ui.snap_magnet.setVisible(False)
elif current_theme == 'compact':
elif current_layout == 'compact':
### TOOLBAR INSTALLATION ###
self.ui.toolbarfile = QtWidgets.QToolBar('File Toolbar')
self.ui.toolbarfile.setObjectName('File_TB')

View File

@ -2083,16 +2083,16 @@ class FlatCAMGeoEditor(QtCore.QObject):
self.app.ui.geo_edit_toolbar.setDisabled(True)
settings = QSettings("Open Source", "FlatCAM")
if settings.contains("theme"):
theme = settings.value('theme', type=str)
if theme == 'standard':
if settings.contains("layout"):
layout = settings.value('layout', type=str)
if layout == 'standard':
# self.app.ui.geo_edit_toolbar.setVisible(False)
self.app.ui.snap_max_dist_entry.setEnabled(False)
self.app.ui.corner_snap_btn.setEnabled(False)
self.app.ui.snap_magnet.setVisible(False)
self.app.ui.corner_snap_btn.setVisible(False)
elif theme == 'compact':
elif layout == 'compact':
# self.app.ui.geo_edit_toolbar.setVisible(True)
self.app.ui.snap_max_dist_entry.setEnabled(False)
@ -4224,16 +4224,16 @@ class FlatCAMExcEditor(QtCore.QObject):
self.app.ui.exc_edit_toolbar.setDisabled(True)
settings = QSettings("Open Source", "FlatCAM")
if settings.contains("theme"):
theme = settings.value('theme', type=str)
if theme == 'standard':
if settings.contains("layout"):
layout = settings.value('layout', type=str)
if layout == 'standard':
# self.app.ui.exc_edit_toolbar.setVisible(False)
self.app.ui.snap_max_dist_entry.setEnabled(False)
self.app.ui.corner_snap_btn.setEnabled(False)
self.app.ui.snap_magnet.setVisible(False)
self.app.ui.corner_snap_btn.setVisible(False)
elif theme == 'compact':
elif layout == 'compact':
# self.app.ui.exc_edit_toolbar.setVisible(True)
self.app.ui.snap_max_dist_entry.setEnabled(False)

View File

@ -435,11 +435,11 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
self.snap_toolbar.setObjectName('Snap_TB')
settings = QSettings("Open Source", "FlatCAM")
if settings.contains("theme"):
theme = settings.value('theme', type=str)
if theme == 'standard':
if settings.contains("layout"):
layout = settings.value('layout', type=str)
if layout == 'standard':
self.addToolBar(self.snap_toolbar)
elif theme == 'compact':
elif layout == 'compact':
self.snap_toolbar.setMaximumHeight(30)
self.splitter_left.addWidget(self.snap_toolbar)
else:
@ -1336,9 +1336,9 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
self.restoreState(saved_gui_state)
log.debug("FlatCAMGUI.__init__() --> UI state restored.")
if settings.contains("theme"):
theme = settings.value('theme', type=str)
if theme == 'standard':
if settings.contains("layout"):
layout = settings.value('layout', type=str)
if layout == 'standard':
self.exc_edit_toolbar.setVisible(False)
self.exc_edit_toolbar.setDisabled(True)
self.geo_edit_toolbar.setVisible(False)
@ -1346,7 +1346,7 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
self.corner_snap_btn.setVisible(False)
self.snap_magnet.setVisible(False)
elif theme == 'compact':
elif layout == 'compact':
self.exc_edit_toolbar.setDisabled(True)
self.geo_edit_toolbar.setDisabled(True)
self.snap_magnet.setVisible(True)
@ -1477,9 +1477,9 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
self.grid_snap_btn.trigger()
settings = QSettings("Open Source", "FlatCAM")
if settings.contains("theme"):
theme = settings.value('theme', type=str)
if theme == 'standard':
if settings.contains("layout"):
layout = settings.value('layout', type=str)
if layout == 'standard':
self.exc_edit_toolbar.setVisible(False)
self.exc_edit_toolbar.setDisabled(True)
self.geo_edit_toolbar.setVisible(False)
@ -1487,7 +1487,7 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
self.corner_snap_btn.setVisible(False)
self.snap_magnet.setVisible(False)
elif theme == 'compact':
elif layout == 'compact':
self.exc_edit_toolbar.setVisible(True)
self.exc_edit_toolbar.setDisabled(True)
self.geo_edit_toolbar.setVisible(True)
@ -2219,14 +2219,15 @@ class GeneralGUIPrefGroupUI(OptionsGroupUI):
self.form_box_child_11.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter)
# Theme selection
self.theme_label = QtWidgets.QLabel('Theme:')
self.layout_label = QtWidgets.QLabel('Layout:')
self.alt_sf_color_label.setToolTip(
"Select a theme for FlatCAM."
"Select an layout for FlatCAM."
)
self.theme_combo = FCComboBox()
self.theme_combo.addItem("Standard")
self.theme_combo.addItem("Compact")
self.theme_combo.setCurrentIndex(0)
self.layout_combo = FCComboBox()
self.layout_combo.addItem("Choose ...")
self.layout_combo.addItem("Standard")
self.layout_combo.addItem("Compact")
self.layout_combo.setCurrentIndex(0)
# Just to add empty rows
self.spacelabel = QtWidgets.QLabel('')
@ -2255,7 +2256,7 @@ class GeneralGUIPrefGroupUI(OptionsGroupUI):
self.form_box.addRow(self.sel_draw_color_label, self.form_box_child_11)
self.form_box.addRow(self.spacelabel, self.spacelabel)
self.form_box.addRow(self.theme_label, self.theme_combo)
self.form_box.addRow(self.layout_label, self.layout_combo)
# Add the QFormLayout that holds the Application general defaults
# to the main layout of this TAB
self.layout.addLayout(self.form_box)

View File

@ -20,6 +20,8 @@ CAD program, and create G-Code for Isolation routing.
- fixed FlatCAM crash when trying to make drills GCode out of a file that have only slots.
- changed the messages for Units Conversion
- all key shortcuts work across the entire application; moved all the shortcuts definitions in FlatCAMGUI.keyPressEvent()
- renamed the theme to layout because it is really a layout change
- combined the geocutout and cutout_any TCL commands - work in progress
5.02.3019

View File

@ -1,179 +0,0 @@
from ObjectCollection import *
from tclCommands.TclCommand import TclCommand
class TclCommandCutoutAny(TclCommand):
"""
Tcl shell command to create a board cutout geometry. Allow cutout for any shape.
example:
"""
# List of all command aliases, to be able use old
# names for backward compatibility (add_poly, add_polygon)
aliases = ['cutout_any', 'cut_any']
# 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([
('dia', float),
('margin', float),
('gapsize', float),
('gaps', 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 board cutout from an object (Gerber or Geometry) of any shape',
'args': collections.OrderedDict([
('name', 'Name of the object.'),
('dia', 'Tool diameter.'),
('margin', 'Margin over bounds.'),
('gapsize', 'size of gap.'),
('gaps', "type of gaps. Can be: 'tb' = top-bottom, 'lr' = left-right, '2tb' = 2top-2bottom, "
"'2lr' = 2left-2right, '4' = 4 cuts, '8' = 8 cuts")
]),
'examples': []
}
def execute(self, args, unnamed_args):
"""
:param args:
:param unnamed_args:
:return:
"""
def subtract_rectangle(obj_, x0, y0, x1, y1):
pts = [(x0, y0), (x1, y0), (x1, y1), (x0, y1)]
obj_.subtract_polygon(pts)
if 'name' in args:
name = args['name']
else:
self.app.inform.emit(
"[WARNING]The name of the object for which cutout is done is missing. Add it and retry.")
return
if 'margin' in args:
margin = args['margin']
else:
margin = 0.001
if 'dia' in args:
dia = args['dia']
else:
dia = 0.1
if 'gaps' in args:
gaps = args['gaps']
else:
gaps = 4
if 'gapsize' in args:
gapsize = args['gapsize']
else:
gapsize = 0.1
# Get source object.
try:
cutout_obj = self.app.collection.get_by_name(str(name))
except:
return "Could not retrieve object: %s" % name
if 0 in {dia}:
self.app.inform.emit("[WARNING]Tool Diameter is zero value. Change it to a positive integer.")
return "Tool Diameter is zero value. Change it to a positive integer."
if gaps not in ['lr', 'tb', '2lr', '2tb', 4, 8]:
self.app.inform.emit("[WARNING]Gaps value can be only one of: 'lr', 'tb', '2lr', '2tb', 4 or 8. "
"Fill in a correct value and retry. ")
return
# Get min and max data for each object as we just cut rectangles across X or Y
xmin, ymin, xmax, ymax = cutout_obj.bounds()
px = 0.5 * (xmin + xmax) + margin
py = 0.5 * (ymin + ymax) + margin
lenghtx = (xmax - xmin) + (margin * 2)
lenghty = (ymax - ymin) + (margin * 2)
gapsize = gapsize + (dia / 2)
if isinstance(cutout_obj, FlatCAMGeometry):
# rename the obj name so it can be identified as cutout
cutout_obj.options["name"] += "_cutout"
elif isinstance(cutout_obj, FlatCAMGerber):
cutout_obj.isolate(dia=dia, passes=1, overlap=1, combine=False, outname="_temp")
ext_obj = self.app.collection.get_by_name("_temp")
def geo_init(geo_obj, app_obj):
geo_obj.solid_geometry = obj_exteriors
outname = cutout_obj.options["name"] + "_cutout"
obj_exteriors = ext_obj.get_exteriors()
self.app.new_object('geometry', outname, geo_init)
self.app.collection.set_all_inactive()
self.app.collection.set_active("_temp")
self.app.on_delete()
cutout_obj = self.app.collection.get_by_name(outname)
else:
self.app.inform.emit("[ERROR]Cancelled. Object type is not supported.")
return
try:
gaps_u = int(gaps)
except ValueError:
gaps_u = gaps
if gaps_u == 8 or gaps_u == '2lr':
subtract_rectangle(cutout_obj,
xmin - gapsize, # botleft_x
py - gapsize + lenghty / 4, # botleft_y
xmax + gapsize, # topright_x
py + gapsize + lenghty / 4) # topright_y
subtract_rectangle(cutout_obj,
xmin - gapsize,
py - gapsize - lenghty / 4,
xmax + gapsize,
py + gapsize - lenghty / 4)
if gaps_u == 8 or gaps_u == '2tb':
subtract_rectangle(cutout_obj,
px - gapsize + lenghtx / 4,
ymin - gapsize,
px + gapsize + lenghtx / 4,
ymax + gapsize)
subtract_rectangle(cutout_obj,
px - gapsize - lenghtx / 4,
ymin - gapsize,
px + gapsize - lenghtx / 4,
ymax + gapsize)
if gaps_u == 4 or gaps_u == 'lr':
subtract_rectangle(cutout_obj,
xmin - gapsize,
py - gapsize,
xmax + gapsize,
py + gapsize)
if gaps_u == 4 or gaps_u == 'tb':
subtract_rectangle(cutout_obj,
px - gapsize,
ymin - gapsize,
px + gapsize,
ymax + gapsize)
cutout_obj.plot()
self.app.inform.emit("[success]Any-form Cutout operation finished.")

View File

@ -4,20 +4,23 @@ from tclCommands.TclCommand import TclCommandSignaled
class TclCommandGeoCutout(TclCommandSignaled):
"""
Tcl shell command to cut holding gaps from geometry.
"""
Tcl shell command to create a board cutout geometry. Allow cutout for any shape. Cuts holding gaps from geometry.
# array of all command aliases, to be able use old names for backward compatibility (add_poly, add_polygon)
aliases = ['geocutout']
example:
# Dictionary of types from Tcl command, needs to be ordered.
# For positional arguments
"""
# List of all command aliases, to be able use old
# names for backward compatibility (add_poly, add_polygon)
aliases = ['geocutout', 'geoc']
# Dictionary of types from Tcl command, needs to be ordered
arg_names = collections.OrderedDict([
('name', str)
('name', str),
])
# Dictionary of types from Tcl command, needs to be ordered.
# For options like -optionname value
# Dictionary of types from Tcl command, needs to be ordered,
# this is for options like -optionname value
option_types = collections.OrderedDict([
('dia', float),
('margin', float),
@ -30,99 +33,160 @@ class TclCommandGeoCutout(TclCommandSignaled):
# structured help for current command, args needs to be ordered
help = {
'main': "Cut holding gaps from geometry.",
'main': 'Creates board cutout from an object (Gerber or Geometry) of any shape',
'args': collections.OrderedDict([
('name', 'Name of the geometry object.'),
('name', 'Name of the object.'),
('dia', 'Tool diameter.'),
('margin', 'Margin over bounds.'),
('gapsize', 'Size of gap.'),
('gaps', 'Type of gaps.'),
('gapsize', 'size of gap.'),
('gaps', "type of gaps. Can be: 'tb' = top-bottom, 'lr' = left-right, '2tb' = 2top-2bottom, "
"'2lr' = 2left-2right, '4' = 4 cuts, '8' = 8 cuts")
]),
'examples': [" #isolate margin for example from fritzing arduino shield or any svg etc\n" +
" isolate BCu_margin -dia 3 -overlap 1\n" +
"\n" +
" #create exteriors from isolated object\n" +
" exteriors BCu_margin_iso -outname BCu_margin_iso_exterior\n" +
"\n" +
" #delete isolated object if you dond need id anymore\n" +
" delete BCu_margin_iso\n" +
"\n" +
" #finally cut holding gaps\n" +
" geocutout BCu_margin_iso_exterior -dia 3 -gapsize 0.6 -gaps 4\n"]
" isolate BCu_margin -dia 3 -overlap 1\n" +
"\n" +
" #create exteriors from isolated object\n" +
" exteriors BCu_margin_iso -outname BCu_margin_iso_exterior\n" +
"\n" +
" #delete isolated object if you dond need id anymore\n" +
" delete BCu_margin_iso\n" +
"\n" +
" #finally cut holding gaps\n" +
" geocutout BCu_margin_iso_exterior -dia 3 -gapsize 0.6 -gaps 4\n"]
}
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
:param args:
:param unnamed_args:
:return:
"""
# How gaps wil be rendered:
# lr - left + right
# tb - top + bottom
# 4 - left + right +top + bottom
# 2lr - 2*left + 2*right
# 2tb - 2*top + 2*bottom
# 8 - 2*left + 2*right +2*top + 2*bottom
name = args['name']
obj = None
def subtract_rectangle(obj_, x0, y0, x1, y1):
pts = [(x0, y0), (x1, y0), (x1, y1), (x0, y1)]
obj_.subtract_polygon(pts)
if 'name' in args:
name = args['name']
else:
self.app.inform.emit(
"[WARNING]The name of the object for which cutout is done is missing. Add it and retry.")
return
if 'margin' in args:
margin = args['margin']
else:
margin = 0.001
if 'dia' in args:
dia = args['dia']
else:
dia = 0.1
if 'gaps' in args:
gaps = args['gaps']
else:
gaps = 4
if 'gapsize' in args:
gapsize = args['gapsize']
else:
gapsize = 0.1
# Get source object.
try:
obj = self.app.collection.get_by_name(str(name))
cutout_obj = self.app.collection.get_by_name(str(name))
except:
self.raise_tcl_error("Could not retrieve object: %s" % name)
return "Could not retrieve object: %s" % name
if 0 in {dia}:
self.app.inform.emit("[WARNING]Tool Diameter is zero value. Change it to a positive integer.")
return "Tool Diameter is zero value. Change it to a positive integer."
if gaps not in ['lr', 'tb', '2lr', '2tb', 4, 8]:
self.app.inform.emit("[WARNING]Gaps value can be only one of: 'lr', 'tb', '2lr', '2tb', 4 or 8. "
"Fill in a correct value and retry. ")
return
# Get min and max data for each object as we just cut rectangles across X or Y
xmin, ymin, xmax, ymax = obj.bounds()
px = 0.5 * (xmin + xmax)
py = 0.5 * (ymin + ymax)
lenghtx = (xmax - xmin)
lenghty = (ymax - ymin)
gapsize = args['gapsize'] + (args['dia'] / 2)
xmin, ymin, xmax, ymax = cutout_obj.bounds()
px = 0.5 * (xmin + xmax) + margin
py = 0.5 * (ymin + ymax) + margin
lenghtx = (xmax - xmin) + (margin * 2)
lenghty = (ymax - ymin) + (margin * 2)
if args['gaps'] == '8' or args['gaps'] == '2lr':
subtract_rectangle(obj,
gapsize = gapsize + (dia / 2)
if isinstance(cutout_obj, FlatCAMGeometry):
# rename the obj name so it can be identified as cutout
cutout_obj.options["name"] += "_cutout"
elif isinstance(cutout_obj, FlatCAMGerber):
def geo_init(geo_obj, app_obj):
geo_obj.solid_geometry = obj_exteriors
outname = cutout_obj.options["name"] + "_cutout"
cutout_obj.isolate(dia=dia, passes=1, overlap=1, combine=False, outname="_temp")
ext_obj = self.app.collection.get_by_name("_temp")
try:
obj_exteriors = ext_obj.get_exteriors()
except:
obj_exteriors = ext_obj.solid_geometry
self.app.new_object('geometry', outname, geo_init)
self.app.collection.set_all_inactive()
self.app.collection.set_active("_temp")
self.app.on_delete()
cutout_obj = self.app.collection.get_by_name(outname)
else:
self.app.inform.emit("[ERROR]Cancelled. Object type is not supported.")
return
try:
gaps_u = int(gaps)
except ValueError:
gaps_u = gaps
if gaps_u == 8 or gaps_u == '2lr':
subtract_rectangle(cutout_obj,
xmin - gapsize, # botleft_x
py - gapsize + lenghty / 4, # botleft_y
xmax + gapsize, # topright_x
py + gapsize + lenghty / 4) # topright_y
subtract_rectangle(obj,
subtract_rectangle(cutout_obj,
xmin - gapsize,
py - gapsize - lenghty / 4,
xmax + gapsize,
py + gapsize - lenghty / 4)
if args['gaps'] == '8' or args['gaps'] == '2tb':
subtract_rectangle(obj,
if gaps_u == 8 or gaps_u == '2tb':
subtract_rectangle(cutout_obj,
px - gapsize + lenghtx / 4,
ymin - gapsize,
px + gapsize + lenghtx / 4,
ymax + gapsize)
subtract_rectangle(obj,
subtract_rectangle(cutout_obj,
px - gapsize - lenghtx / 4,
ymin - gapsize,
px + gapsize - lenghtx / 4,
ymax + gapsize)
if args['gaps'] == '4' or args['gaps'] == 'lr':
subtract_rectangle(obj,
if gaps_u == 4 or gaps_u == 'lr':
subtract_rectangle(cutout_obj,
xmin - gapsize,
py - gapsize,
xmax + gapsize,
py + gapsize)
if args['gaps'] == '4' or args['gaps'] == 'tb':
subtract_rectangle(obj,
if gaps_u == 4 or gaps_u == 'tb':
subtract_rectangle(cutout_obj,
px - gapsize,
ymin - gapsize,
px + gapsize,
ymax + gapsize)
cutout_obj.plot()
self.app.inform.emit("[success]Any-form Cutout operation finished.")

View File

@ -12,7 +12,6 @@ import tclCommands.TclCommandAlignDrillGrid
import tclCommands.TclCommandClearShell
import tclCommands.TclCommandCncjob
import tclCommands.TclCommandCutout
import tclCommands.TclCommandCutoutAny
import tclCommands.TclCommandDelete
import tclCommands.TclCommandDrillcncjob
import tclCommands.TclCommandExportGcode