commit
43dcdef14a
507
FlatCAMApp.py
507
FlatCAMApp.py
|
@ -98,8 +98,8 @@ class App(QtCore.QObject):
|
|||
# ####################################
|
||||
# Version and VERSION DATE ###########
|
||||
# ####################################
|
||||
version = 8.95
|
||||
version_date = "2019/08/17"
|
||||
version = 8.96
|
||||
version_date = "2019/08/23"
|
||||
beta = True
|
||||
|
||||
# current date now
|
||||
|
@ -183,6 +183,9 @@ class App(QtCore.QObject):
|
|||
# in the worker task.
|
||||
thread_exception = QtCore.pyqtSignal(object)
|
||||
|
||||
# used to signal that there are arguments for the app
|
||||
args_at_startup = QtCore.pyqtSignal()
|
||||
|
||||
def __init__(self, user_defaults=True, post_gui=None):
|
||||
"""
|
||||
Starts the application.
|
||||
|
@ -320,7 +323,6 @@ class App(QtCore.QObject):
|
|||
|
||||
QtCore.QObject.__init__(self)
|
||||
self.ui = FlatCAMGUI(self.version, self.beta, self)
|
||||
self.set_ui_title(name=_("New Project - Not saved"))
|
||||
|
||||
self.ui.geom_update[int, int, int, int, int].connect(self.save_geometry)
|
||||
self.ui.final_save.connect(self.final_save)
|
||||
|
@ -345,6 +347,7 @@ class App(QtCore.QObject):
|
|||
# General App
|
||||
"units": self.ui.general_defaults_form.general_app_group.units_radio,
|
||||
"global_app_level": self.ui.general_defaults_form.general_app_group.app_level_radio,
|
||||
"global_portable": self.ui.general_defaults_form.general_app_group.portability_cb,
|
||||
"global_language": self.ui.general_defaults_form.general_app_group.language_cb,
|
||||
|
||||
"global_shell_at_startup": self.ui.general_defaults_form.general_app_group.shell_startup_cb,
|
||||
|
@ -420,6 +423,21 @@ class App(QtCore.QObject):
|
|||
|
||||
# Gerber Editor
|
||||
"gerber_editor_sel_limit": self.ui.gerber_defaults_form.gerber_editor_group.sel_limit_entry,
|
||||
"gerber_editor_newcode": self.ui.gerber_defaults_form.gerber_editor_group.addcode_entry,
|
||||
"gerber_editor_newsize": self.ui.gerber_defaults_form.gerber_editor_group.addsize_entry,
|
||||
"gerber_editor_newtype": self.ui.gerber_defaults_form.gerber_editor_group.addtype_combo,
|
||||
"gerber_editor_newdim": self.ui.gerber_defaults_form.gerber_editor_group.adddim_entry,
|
||||
"gerber_editor_array_size": self.ui.gerber_defaults_form.gerber_editor_group.grb_array_size_entry,
|
||||
"gerber_editor_lin_axis": self.ui.gerber_defaults_form.gerber_editor_group.grb_axis_radio,
|
||||
"gerber_editor_lin_pitch": self.ui.gerber_defaults_form.gerber_editor_group.grb_pitch_entry,
|
||||
"gerber_editor_lin_angle": self.ui.gerber_defaults_form.gerber_editor_group.grb_angle_entry,
|
||||
"gerber_editor_circ_dir": self.ui.gerber_defaults_form.gerber_editor_group.grb_circular_dir_radio,
|
||||
"gerber_editor_circ_angle":
|
||||
self.ui.gerber_defaults_form.gerber_editor_group.grb_circular_angle_entry,
|
||||
"gerber_editor_scale_f": self.ui.gerber_defaults_form.gerber_editor_group.grb_scale_entry,
|
||||
"gerber_editor_buff_f": self.ui.gerber_defaults_form.gerber_editor_group.grb_buff_entry,
|
||||
"gerber_editor_ma_low": self.ui.gerber_defaults_form.gerber_editor_group.grb_ma_low_entry,
|
||||
"gerber_editor_ma_high": self.ui.gerber_defaults_form.gerber_editor_group.grb_ma_high_entry,
|
||||
|
||||
# Excellon General
|
||||
"excellon_plot": self.ui.excellon_defaults_form.excellon_gen_group.plot_cb,
|
||||
|
@ -558,6 +576,7 @@ class App(QtCore.QObject):
|
|||
|
||||
# NCC Tool
|
||||
"tools_ncctools": self.ui.tools_defaults_form.tools_ncc_group.ncc_tool_dia_entry,
|
||||
"tools_nccorder": self.ui.tools_defaults_form.tools_ncc_group.ncc_order_radio,
|
||||
"tools_nccoverlap": self.ui.tools_defaults_form.tools_ncc_group.ncc_overlap_entry,
|
||||
"tools_nccmargin": self.ui.tools_defaults_form.tools_ncc_group.ncc_margin_entry,
|
||||
"tools_nccmethod": self.ui.tools_defaults_form.tools_ncc_group.ncc_method_radio,
|
||||
|
@ -578,6 +597,7 @@ class App(QtCore.QObject):
|
|||
|
||||
# Paint Area Tool
|
||||
"tools_painttooldia": self.ui.tools_defaults_form.tools_paint_group.painttooldia_entry,
|
||||
"tools_paintorder": self.ui.tools_defaults_form.tools_paint_group.paint_order_radio,
|
||||
"tools_paintoverlap": self.ui.tools_defaults_form.tools_paint_group.paintoverlap_entry,
|
||||
"tools_paintmargin": self.ui.tools_defaults_form.tools_paint_group.paintmargin_entry,
|
||||
"tools_paintmethod": self.ui.tools_defaults_form.tools_paint_group.paintmethod_combo,
|
||||
|
@ -681,8 +701,10 @@ class App(QtCore.QObject):
|
|||
# Global APP Preferences
|
||||
"global_serial": 0,
|
||||
"global_stats": {},
|
||||
"global_tabs_detachable": True,
|
||||
"units": "IN",
|
||||
"global_app_level": 'b',
|
||||
"global_portable": False,
|
||||
"global_language": 'English',
|
||||
"global_version_check": True,
|
||||
"global_send_stats": True,
|
||||
|
@ -791,6 +813,20 @@ class App(QtCore.QObject):
|
|||
|
||||
# Gerber Editor
|
||||
"gerber_editor_sel_limit": 30,
|
||||
"gerber_editor_newcode": 10,
|
||||
"gerber_editor_newsize": 0.8,
|
||||
"gerber_editor_newtype": 'C',
|
||||
"gerber_editor_newdim": "0.5, 0.5",
|
||||
"gerber_editor_array_size": 5,
|
||||
"gerber_editor_lin_axis": 'X',
|
||||
"gerber_editor_lin_pitch": 1,
|
||||
"gerber_editor_lin_angle": 0.0,
|
||||
"gerber_editor_circ_dir": 'CW',
|
||||
"gerber_editor_circ_angle": 0.0,
|
||||
"gerber_editor_scale_f": 1.0,
|
||||
"gerber_editor_buff_f": 0.1,
|
||||
"gerber_editor_ma_low": 0.0,
|
||||
"gerber_editor_ma_high": 1.0,
|
||||
|
||||
# Excellon General
|
||||
"excellon_plot": True,
|
||||
|
@ -916,6 +952,7 @@ class App(QtCore.QObject):
|
|||
"cncjob_toolchange_macro_enable": False,
|
||||
|
||||
"tools_ncctools": "0.0393701, 0.019685",
|
||||
"tools_nccorder": 'rev',
|
||||
"tools_nccoverlap": 0.015748,
|
||||
"tools_nccmargin": 0.0393701,
|
||||
"tools_nccmethod": "seed",
|
||||
|
@ -934,6 +971,7 @@ class App(QtCore.QObject):
|
|||
"tools_cutout_convexshape": False,
|
||||
|
||||
"tools_painttooldia": 0.023622,
|
||||
"tools_paintorder": 'rev',
|
||||
"tools_paintoverlap": 0.015748,
|
||||
"tools_paintmargin": 0.0,
|
||||
"tools_paintmethod": "seed",
|
||||
|
@ -1290,13 +1328,8 @@ class App(QtCore.QObject):
|
|||
self.tools_form = None
|
||||
self.on_options_combo_change(0) # Will show the initial form
|
||||
|
||||
# ### Define OBJECT COLLECTION ###
|
||||
self.collection = ObjectCollection(self)
|
||||
self.ui.project_tab_layout.addWidget(self.collection.view)
|
||||
# ################################
|
||||
|
||||
self.log.debug("Finished creating Object Collection.")
|
||||
|
||||
# ### Initialize the color box's color in Preferences -> Global -> Color
|
||||
# Init Plot Colors
|
||||
self.ui.general_defaults_form.general_gui_group.pf_color_entry.set_value(self.defaults['global_plot_fill'])
|
||||
|
@ -1368,46 +1401,52 @@ class App(QtCore.QObject):
|
|||
"background-color:%s" % str(self.defaults['cncjob_annotation_fontcolor'])[:7])
|
||||
# ### End of Data ####
|
||||
|
||||
# ### Plot Area ####
|
||||
# ###############################################
|
||||
# ############# SETUP Plot Area #################
|
||||
# ###############################################
|
||||
|
||||
start_plot_time = time.time() # debug
|
||||
self.plotcanvas = PlotCanvas(self.ui.right_layout, self)
|
||||
|
||||
self.plotcanvas.vis_connect('mouse_move', self.on_mouse_move_over_plot)
|
||||
self.plotcanvas.vis_connect('mouse_press', self.on_mouse_click_over_plot)
|
||||
self.plotcanvas.vis_connect('mouse_release', self.on_mouse_click_release_over_plot)
|
||||
self.plotcanvas.vis_connect('mouse_double_click', self.on_double_click_over_plot)
|
||||
|
||||
# Keys over plot enabled
|
||||
self.plotcanvas.vis_connect('key_press', self.ui.keyPressEvent)
|
||||
self.plotcanvas = None
|
||||
self.app_cursor = None
|
||||
self.hover_shapes = None
|
||||
self.on_plotcanvas_setup()
|
||||
end_plot_time = time.time()
|
||||
self.log.debug("Finished Canvas initialization in %s seconds." % (str(end_plot_time - start_plot_time)))
|
||||
|
||||
self.ui.splitter.setStretchFactor(1, 2)
|
||||
|
||||
# So it can receive key presses
|
||||
self.plotcanvas.vispy_canvas.native.setFocus()
|
||||
|
||||
self.app_cursor = self.plotcanvas.new_cursor()
|
||||
self.app_cursor.enabled = False
|
||||
|
||||
# to use for tools like Measurement tool who depends on the event sources who are changed inside the Editors
|
||||
# depending on from where those tools are called different actions can be done
|
||||
self.call_source = 'app'
|
||||
|
||||
end_plot_time = time.time()
|
||||
self.log.debug("Finished Canvas initialization in %s seconds." % (str(end_plot_time - start_plot_time)))
|
||||
# ##############################################
|
||||
# ######### SETUP OBJECT COLLECTION ############
|
||||
# ##############################################
|
||||
|
||||
self.collection = ObjectCollection(self)
|
||||
self.ui.project_tab_layout.addWidget(self.collection.view)
|
||||
|
||||
# ### Adjust tabs width ## ##
|
||||
# self.collection.view.setMinimumWidth(self.ui.options_scroll_area.widget().sizeHint().width() +
|
||||
# self.ui.options_scroll_area.verticalScrollBar().sizeHint().width())
|
||||
self.collection.view.setMinimumWidth(290)
|
||||
self.log.debug("Finished creating Object Collection.")
|
||||
|
||||
# ###############################################
|
||||
# ############# Worker SETUP ####################
|
||||
# ###############################################
|
||||
|
||||
# ### Worker ####
|
||||
if self.defaults["global_worker_number"]:
|
||||
self.workers = WorkerStack(workers_number=int(self.defaults["global_worker_number"]))
|
||||
else:
|
||||
self.workers = WorkerStack(workers_number=2)
|
||||
self.worker_task.connect(self.workers.add_task)
|
||||
self.log.debug("Finished creating Workers crew.")
|
||||
|
||||
# ################################################
|
||||
# ############### Signal handling ################
|
||||
# ################################################
|
||||
|
||||
# ### Signal handling ###
|
||||
# ### Custom signals ###
|
||||
self.inform.connect(self.info)
|
||||
self.app_quit.connect(self.quit_application)
|
||||
|
@ -1506,12 +1545,8 @@ class App(QtCore.QObject):
|
|||
self.ui.menuviewenable.triggered.connect(self.enable_all_plots)
|
||||
|
||||
self.ui.menuview_zoom_fit.triggered.connect(self.on_zoom_fit)
|
||||
self.ui.menuview_zoom_in.triggered.connect(
|
||||
lambda: self.plotcanvas.zoom(1 / float(self.defaults['global_zoom_ratio']))
|
||||
)
|
||||
self.ui.menuview_zoom_out.triggered.connect(
|
||||
lambda: self.plotcanvas.zoom(float(self.defaults['global_zoom_ratio']))
|
||||
)
|
||||
self.ui.menuview_zoom_in.triggered.connect(self.on_zoom_in)
|
||||
self.ui.menuview_zoom_out.triggered.connect(self.on_zoom_out)
|
||||
|
||||
self.ui.menuview_toggle_code_editor.triggered.connect(self.on_toggle_code_editor)
|
||||
self.ui.menuview_toggle_fscreen.triggered.connect(self.on_fullscreen)
|
||||
|
@ -1545,6 +1580,15 @@ class App(QtCore.QObject):
|
|||
# ToolBar signals
|
||||
self.connect_toolbar_signals()
|
||||
|
||||
# Notebook signals
|
||||
# make the right click on the notebook tab connect to a function
|
||||
self.ui.notebook.setupContextMenu()
|
||||
self.ui.notebook.addContextMenu(
|
||||
_("Detachable Tabs"), self.on_notebook_tab_rmb_click,
|
||||
initial_checked=self.defaults["global_tabs_detachable"])
|
||||
# activate initial state
|
||||
self.on_notebook_tab_rmb_click(self.defaults["global_tabs_detachable"])
|
||||
|
||||
# Context Menu
|
||||
self.ui.popmenu_disable.triggered.connect(lambda: self.toggle_plots(self.collection.get_selected()))
|
||||
self.ui.popmenu_panel_toggle.triggered.connect(self.on_toggle_notebook)
|
||||
|
@ -1668,6 +1712,9 @@ class App(QtCore.QObject):
|
|||
self.ui.buttonFind.clicked.connect(self.handleFindGCode)
|
||||
self.ui.buttonReplace.clicked.connect(self.handleReplaceGCode)
|
||||
|
||||
# portability changed
|
||||
self.ui.general_defaults_form.general_app_group.portability_cb.stateChanged.connect(self.on_portable_checked)
|
||||
|
||||
# Object list
|
||||
self.collection.view.activated.connect(self.on_row_activated)
|
||||
|
||||
|
@ -1682,6 +1729,10 @@ class App(QtCore.QObject):
|
|||
self.ui.excellon_options_form.excellon_opt_group.excellon_defaults_button.clicked.connect(
|
||||
self.on_excellon_options_button)
|
||||
|
||||
# when there are arguments at application startup this get launched
|
||||
self.args_at_startup.connect(self.on_startup_args)
|
||||
self.log.debug("Finished connecting Signals.")
|
||||
|
||||
# this is a flag to signal to other tools that the ui tooltab is locked and not accessible
|
||||
self.tool_tab_locked = False
|
||||
|
||||
|
@ -1691,21 +1742,18 @@ class App(QtCore.QObject):
|
|||
else:
|
||||
self.ui.splitter.setSizes([0, 1])
|
||||
|
||||
# ###################
|
||||
# ### Other setups ##
|
||||
# ###################
|
||||
# ###########################################
|
||||
# ################# Other setups ############
|
||||
# ###########################################
|
||||
|
||||
# Sets up FlatCAMObj, FCProcess and FCProcessContainer.
|
||||
self.setup_obj_classes()
|
||||
self.setup_recent_items()
|
||||
self.setup_component_editor()
|
||||
|
||||
# ############
|
||||
# ### Shell ##
|
||||
# ############
|
||||
|
||||
# #########################
|
||||
# Auto-complete KEYWORDS ##
|
||||
# #########################
|
||||
# ###########################################
|
||||
# #######Auto-complete KEYWORDS #############
|
||||
# ###########################################
|
||||
self.tcl_commands_list = ['add_circle', 'add_poly', 'add_polygon', 'add_polyline', 'add_rectangle',
|
||||
'aligndrill', 'clear',
|
||||
'aligndrillgrid', 'cncjob', 'cutout', 'delete', 'drillcncjob',
|
||||
|
@ -1915,6 +1963,10 @@ class App(QtCore.QObject):
|
|||
|
||||
self.myKeywords = self.tcl_commands_list + self.ordinary_keywords + self.tcl_keywords
|
||||
|
||||
# ###########################################
|
||||
# ########### Shell SETUP ###################
|
||||
# ###########################################
|
||||
|
||||
self.shell = FCShell(self, version=self.version)
|
||||
self.shell._edit.set_model_data(self.myKeywords)
|
||||
self.ui.code_editor.set_model_data(self.myKeywords)
|
||||
|
@ -1941,9 +1993,9 @@ class App(QtCore.QObject):
|
|||
else:
|
||||
self.ui.shell_dock.hide()
|
||||
|
||||
# ########################
|
||||
# ### Tools and Plugins ##
|
||||
# ########################
|
||||
# ###########################################
|
||||
# ######### Tools and Plugins ###############
|
||||
# ###########################################
|
||||
|
||||
self.dblsidedtool = None
|
||||
self.measurement_tool = None
|
||||
|
@ -1969,6 +2021,10 @@ class App(QtCore.QObject):
|
|||
# self.f_parse = ParseFont(self)
|
||||
# self.parse_system_fonts()
|
||||
|
||||
# ###############################################
|
||||
# ######## START-UP ARGUMENTS ###################
|
||||
# ###############################################
|
||||
|
||||
# test if the program was started with a script as parameter
|
||||
if self.cmd_line_shellfile:
|
||||
try:
|
||||
|
@ -1979,9 +2035,9 @@ class App(QtCore.QObject):
|
|||
print("ERROR: ", ext)
|
||||
sys.exit(2)
|
||||
|
||||
# ##########################
|
||||
# ### Check for updates ####
|
||||
# ##########################
|
||||
# ###############################################
|
||||
# ############# Check for updates ###############
|
||||
# ###############################################
|
||||
|
||||
# Separate thread (Not worker)
|
||||
# Check for updates on startup but only if the user consent and the app is not in Beta version
|
||||
|
@ -1994,9 +2050,9 @@ class App(QtCore.QObject):
|
|||
'params': []})
|
||||
self.thr2.start(QtCore.QThread.LowPriority)
|
||||
|
||||
# ###################################
|
||||
# ### Variables for global usage ####
|
||||
# ###################################
|
||||
# ################################################
|
||||
# ######### Variables for global usage ###########
|
||||
# ################################################
|
||||
|
||||
# coordinates for relative position display
|
||||
self.rel_point1 = (0, 0)
|
||||
|
@ -2061,13 +2117,13 @@ class App(QtCore.QObject):
|
|||
self.dxf_list = ['dxf']
|
||||
self.pdf_list = ['pdf']
|
||||
self.prj_list = ['flatprj']
|
||||
self.conf_list = ['flatconfig']
|
||||
|
||||
# global variable used by NCC Tool to signal that some polygons could not be cleared, if True
|
||||
# flag for polygons not cleared
|
||||
self.poly_not_cleared = False
|
||||
|
||||
# VisPy visuals
|
||||
self.hover_shapes = ShapeCollection(parent=self.plotcanvas.vispy_canvas.view.scene, layers=1)
|
||||
self.isHovering = False
|
||||
self.notHovering = True
|
||||
|
||||
|
@ -2096,7 +2152,7 @@ class App(QtCore.QObject):
|
|||
os.chmod(filename_factory, S_IREAD | S_IRGRP | S_IROTH)
|
||||
|
||||
####################################################
|
||||
# ### EDITOR section ###############################
|
||||
# ### ADDING FlatCAM EDITORS section ###############
|
||||
####################################################
|
||||
|
||||
# watch out for the position of the editors instantiation ... if it is done before a save of the default values
|
||||
|
@ -2113,50 +2169,13 @@ class App(QtCore.QObject):
|
|||
|
||||
App.log.debug("END of constructor. Releasing control.")
|
||||
|
||||
# accept a project file as command line parameter
|
||||
self.set_ui_title(name=_("New Project - Not saved"))
|
||||
|
||||
# accept some type file as command line parameter: FlatCAM project, FlatCAM preferences or scripts
|
||||
# the path/file_name must be enclosed in quotes if it contain spaces
|
||||
for argument in App.args:
|
||||
if '.FlatPrj' in argument:
|
||||
try:
|
||||
project_name = str(argument)
|
||||
if App.args:
|
||||
self.args_at_startup.emit()
|
||||
|
||||
if project_name == "":
|
||||
self.inform.emit(_("Open cancelled."))
|
||||
else:
|
||||
# self.open_project(project_name)
|
||||
run_from_arg = True
|
||||
self.worker_task.emit({'fcn': self.open_project,
|
||||
'params': [project_name, run_from_arg]})
|
||||
except Exception as e:
|
||||
log.debug("Could not open FlatCAM project file as App parameter due: %s" % str(e))
|
||||
|
||||
if '.FlatConfig' in argument:
|
||||
try:
|
||||
file_name = str(argument)
|
||||
|
||||
if file_name == "":
|
||||
self.inform.emit(_("Open Config file failed."))
|
||||
else:
|
||||
# run_from_arg = True
|
||||
# self.worker_task.emit({'fcn': self.open_config_file,
|
||||
# 'params': [file_name, run_from_arg]})
|
||||
self.open_config_file(file_name, run_from_arg=True)
|
||||
except Exception as e:
|
||||
log.debug("Could not open FlatCAM Config file as App parameter due: %s" % str(e))
|
||||
|
||||
if '.FlatScript' in argument:
|
||||
try:
|
||||
file_name = str(argument)
|
||||
|
||||
if file_name == "":
|
||||
self.inform.emit(_("Open Script file failed."))
|
||||
else:
|
||||
# run_from_arg = True
|
||||
# self.worker_task.emit({'fcn': self.open_script_file,
|
||||
# 'params': [file_name, run_from_arg]})
|
||||
self.on_filerunscript(name=file_name)
|
||||
except Exception as e:
|
||||
log.debug("Could not open FlatCAM Script file as App parameter due: %s" % str(e))
|
||||
|
||||
@staticmethod
|
||||
def copy_and_overwrite(from_path, to_path):
|
||||
|
@ -2175,6 +2194,52 @@ class App(QtCore.QObject):
|
|||
from_new_path = os.path.dirname(os.path.realpath(__file__)) + '\\flatcamGUI\\VisPyData\\data'
|
||||
shutil.copytree(from_new_path, to_path)
|
||||
|
||||
def on_startup_args(self):
|
||||
log.debug("Application was started with an argument. Processing ...")
|
||||
for argument in App.args:
|
||||
if '.FlatPrj' in argument:
|
||||
try:
|
||||
project_name = str(argument)
|
||||
|
||||
if project_name == "":
|
||||
self.inform.emit(_("Open cancelled."))
|
||||
else:
|
||||
# self.open_project(project_name)
|
||||
run_from_arg = True
|
||||
# self.worker_task.emit({'fcn': self.open_project,
|
||||
# 'params': [project_name, run_from_arg]})
|
||||
self.open_project(filename=project_name, run_from_arg=run_from_arg)
|
||||
except Exception as e:
|
||||
log.debug("Could not open FlatCAM project file as App parameter due: %s" % str(e))
|
||||
|
||||
elif '.FlatConfig' in argument:
|
||||
try:
|
||||
file_name = str(argument)
|
||||
|
||||
if file_name == "":
|
||||
self.inform.emit(_("Open Config file failed."))
|
||||
else:
|
||||
# run_from_arg = True
|
||||
# self.worker_task.emit({'fcn': self.open_config_file,
|
||||
# 'params': [file_name, run_from_arg]})
|
||||
self.open_config_file(file_name, run_from_arg=True)
|
||||
except Exception as e:
|
||||
log.debug("Could not open FlatCAM Config file as App parameter due: %s" % str(e))
|
||||
|
||||
elif '.FlatScript' in argument:
|
||||
try:
|
||||
file_name = str(argument)
|
||||
|
||||
if file_name == "":
|
||||
self.inform.emit(_("Open Script file failed."))
|
||||
else:
|
||||
# run_from_arg = True
|
||||
# self.worker_task.emit({'fcn': self.open_script_file,
|
||||
# 'params': [file_name, run_from_arg]})
|
||||
self.on_filerunscript(name=file_name)
|
||||
except Exception as e:
|
||||
log.debug("Could not open FlatCAM Script file as App parameter due: %s" % str(e))
|
||||
|
||||
def set_ui_title(self, name):
|
||||
self.ui.setWindowTitle('FlatCAM %s %s - %s %s' %
|
||||
(self.version,
|
||||
|
@ -3006,7 +3071,7 @@ class App(QtCore.QObject):
|
|||
# Save update options
|
||||
try:
|
||||
f = open(filename, "w")
|
||||
json.dump(defaults_from_file, f)
|
||||
json.dump(defaults_from_file, f, default=to_dict, indent=2, sort_keys=True)
|
||||
f.close()
|
||||
except:
|
||||
self.inform.emit(_("[ERROR_NOTCL] Failed to write defaults to file."))
|
||||
|
@ -3106,6 +3171,11 @@ class App(QtCore.QObject):
|
|||
:param initialize: Function to run after creation of the object but before it is attached to the application.
|
||||
The function is called with 2 parameters: the new object and the App instance.
|
||||
:type initialize: function
|
||||
:param active:
|
||||
:param fit:
|
||||
:param plot: If to plot the resulting object
|
||||
:param autoselected: if the resulting object is autoselected in the Project tab and therefore in the
|
||||
self.colleaction
|
||||
:return: None
|
||||
:rtype: None
|
||||
"""
|
||||
|
@ -3189,11 +3259,9 @@ class App(QtCore.QObject):
|
|||
obj.options['ymin'] = ymin
|
||||
obj.options['xmax'] = xmax
|
||||
obj.options['ymax'] = ymax
|
||||
except:
|
||||
log.warning("The object has no bounds properties.")
|
||||
# don't plot objects with no bounds, there is nothing to plot
|
||||
self.plot = False
|
||||
pass
|
||||
except Exception as e:
|
||||
log.warning("The object has no bounds properties. %s" % str(e))
|
||||
return "fail"
|
||||
|
||||
FlatCAMApp.App.log.debug("Moving new object back to main thread.")
|
||||
|
||||
|
@ -3438,7 +3506,7 @@ class App(QtCore.QObject):
|
|||
# log.debug("Application defaults saved ... Exit event.")
|
||||
# QtWidgets.qApp.quit()
|
||||
|
||||
def save_defaults(self, silent=False):
|
||||
def save_defaults(self, silent=False, data_path=None):
|
||||
"""
|
||||
Saves application default options
|
||||
``self.defaults`` to current_defaults.FlatConfig.
|
||||
|
@ -3447,9 +3515,12 @@ class App(QtCore.QObject):
|
|||
"""
|
||||
self.report_usage("save_defaults")
|
||||
|
||||
if data_path is None:
|
||||
data_path = self.data_path
|
||||
|
||||
# Read options from file
|
||||
try:
|
||||
f = open(self.data_path + "/current_defaults.FlatConfig")
|
||||
f = open(data_path + "/current_defaults.FlatConfig")
|
||||
defaults_file_content = f.read()
|
||||
f.close()
|
||||
except:
|
||||
|
@ -3506,7 +3577,7 @@ class App(QtCore.QObject):
|
|||
|
||||
# Save update options
|
||||
try:
|
||||
f = open(self.data_path + "/current_defaults.FlatConfig", "w")
|
||||
f = open(data_path + "/current_defaults.FlatConfig", "w")
|
||||
json.dump(defaults, f, default=to_dict, indent=2, sort_keys=True)
|
||||
f.close()
|
||||
except:
|
||||
|
@ -3516,7 +3587,7 @@ class App(QtCore.QObject):
|
|||
if not silent:
|
||||
self.inform.emit(_("[success] Defaults saved."))
|
||||
|
||||
def save_factory_defaults(self, silent=False):
|
||||
def save_factory_defaults(self, silent=False, data_path=None):
|
||||
"""
|
||||
Saves application factory default options
|
||||
``self.defaults`` to factory_defaults.FlatConfig.
|
||||
|
@ -3526,9 +3597,12 @@ class App(QtCore.QObject):
|
|||
"""
|
||||
self.report_usage("save_factory_defaults")
|
||||
|
||||
if data_path is None:
|
||||
data_path = self.data_path
|
||||
|
||||
# Read options from file
|
||||
try:
|
||||
f_f_def = open(self.data_path + "/factory_defaults.FlatConfig")
|
||||
f_f_def = open(data_path + "/factory_defaults.FlatConfig")
|
||||
factory_defaults_file_content = f_f_def.read()
|
||||
f_f_def.close()
|
||||
except:
|
||||
|
@ -3554,7 +3628,7 @@ class App(QtCore.QObject):
|
|||
|
||||
# Save update options
|
||||
try:
|
||||
f_f_def_s = open(self.data_path + "/factory_defaults.FlatConfig", "w")
|
||||
f_f_def_s = open(data_path + "/factory_defaults.FlatConfig", "w")
|
||||
json.dump(factory_defaults, f_f_def_s, default=to_dict, indent=2, sort_keys=True)
|
||||
f_f_def_s.close()
|
||||
except:
|
||||
|
@ -3608,11 +3682,96 @@ class App(QtCore.QObject):
|
|||
settings.setValue('axis_font_size',
|
||||
self.ui.general_defaults_form.general_gui_set_group.axis_font_size_spinner.get_value())
|
||||
|
||||
settings.setValue('toolbar_lock', self.ui.lock_action.isChecked())
|
||||
|
||||
# This will write the setting to the platform specific storage.
|
||||
del settings
|
||||
log.debug("App.final_save() --> App UI state saved.")
|
||||
QtWidgets.qApp.quit()
|
||||
|
||||
def on_portable_checked(self, state):
|
||||
line_no = 0
|
||||
data = None
|
||||
|
||||
if sys.platform != 'win32':
|
||||
# this won't work in Linux or MacOS
|
||||
return
|
||||
|
||||
# test if the app was frozen and choose the path for the configuration file
|
||||
if getattr(sys, "frozen", False) is True:
|
||||
current_data_path = os.path.dirname(os.path.dirname(os.path.realpath(__file__))) + '\\config'
|
||||
else:
|
||||
current_data_path = os.path.dirname(os.path.realpath(__file__)) + '\\config'
|
||||
|
||||
config_file = current_data_path + '\\configuration.txt'
|
||||
try:
|
||||
with open(config_file, 'r') as f:
|
||||
try:
|
||||
data = f.readlines()
|
||||
except Exception as e:
|
||||
log.debug('App.__init__() -->%s' % str(e))
|
||||
return
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
|
||||
for line in data:
|
||||
line = line.strip('\n')
|
||||
param = str(line).rpartition('=')
|
||||
if param[0] == 'portable':
|
||||
break
|
||||
line_no += 1
|
||||
|
||||
if state:
|
||||
data[line_no] = 'portable=True\n'
|
||||
# create the new defauults files
|
||||
# create current_defaults.FlatConfig file if there is none
|
||||
try:
|
||||
f = open(current_data_path + '/current_defaults.FlatConfig')
|
||||
f.close()
|
||||
except IOError:
|
||||
App.log.debug('Creating empty current_defaults.FlatConfig')
|
||||
f = open(current_data_path + '/current_defaults.FlatConfig', 'w')
|
||||
json.dump({}, f)
|
||||
f.close()
|
||||
|
||||
# create factory_defaults.FlatConfig file if there is none
|
||||
try:
|
||||
f = open(current_data_path + '/factory_defaults.FlatConfig')
|
||||
f.close()
|
||||
except IOError:
|
||||
App.log.debug('Creating empty factory_defaults.FlatConfig')
|
||||
f = open(current_data_path + '/factory_defaults.FlatConfig', 'w')
|
||||
json.dump({}, f)
|
||||
f.close()
|
||||
|
||||
try:
|
||||
f = open(current_data_path + '/recent.json')
|
||||
f.close()
|
||||
except IOError:
|
||||
App.log.debug('Creating empty recent.json')
|
||||
f = open(current_data_path + '/recent.json', 'w')
|
||||
json.dump([], f)
|
||||
f.close()
|
||||
|
||||
try:
|
||||
fp = open(current_data_path + '/recent_projects.json')
|
||||
fp.close()
|
||||
except IOError:
|
||||
App.log.debug('Creating empty recent_projects.json')
|
||||
fp = open(current_data_path + '/recent_projects.json', 'w')
|
||||
json.dump([], fp)
|
||||
fp.close()
|
||||
|
||||
# save the current defaults to the new defaults file
|
||||
self.save_defaults(silent=True, data_path=current_data_path)
|
||||
self.save_factory_defaults(silent=True, data_path=current_data_path)
|
||||
|
||||
else:
|
||||
data[line_no] = 'portable=False\n'
|
||||
|
||||
with open(config_file, 'w') as f:
|
||||
f.writelines(data)
|
||||
|
||||
def on_toggle_shell(self):
|
||||
"""
|
||||
toggle shell if is visible close it if closed open it
|
||||
|
@ -4010,7 +4169,7 @@ class App(QtCore.QObject):
|
|||
msgbox = QtWidgets.QMessageBox()
|
||||
msgbox.setWindowTitle(_("Toggle Units"))
|
||||
msgbox.setWindowIcon(QtGui.QIcon('share/toggle_units32.png'))
|
||||
msgbox.setText(_("<B>Change project units ...</B>"))
|
||||
msgbox.setText("<B>%s</B>" % _("Change project units ..."))
|
||||
msgbox.setInformativeText(_("Changing the units of the project causes all geometrical "
|
||||
"properties of all objects to be scaled accordingly.\nContinue?"))
|
||||
bt_ok = msgbox.addButton(_('Ok'), QtWidgets.QMessageBox.AcceptRole)
|
||||
|
@ -4545,6 +4704,13 @@ class App(QtCore.QObject):
|
|||
self.ui.cncjob_defaults_form.cncjob_gen_group.annotation_fontcolor_entry.set_value(new_val_sel)
|
||||
self.defaults['global_proj_item_dis_color'] = new_val_sel
|
||||
|
||||
def on_notebook_tab_rmb_click(self, checked):
|
||||
self.ui.notebook.set_detachable(val=checked)
|
||||
self.defaults["global_tabs_detachable"] = checked
|
||||
|
||||
self.ui.plot_tab_area.set_detachable(val=checked)
|
||||
self.defaults["global_tabs_detachable"] = checked
|
||||
|
||||
def on_deselect_all(self):
|
||||
self.collection.set_all_inactive()
|
||||
self.delete_selection_shape()
|
||||
|
@ -4990,7 +5156,7 @@ class App(QtCore.QObject):
|
|||
msgbox = QtWidgets.QMessageBox()
|
||||
msgbox.setWindowTitle(_("Delete objects"))
|
||||
msgbox.setWindowIcon(QtGui.QIcon('share/deleteshape32.png'))
|
||||
# msgbox.setText(_("<B>Delete FlatCAM objects ...</B>"))
|
||||
# msgbox.setText("<B>%s</B>" % _("Change project units ..."))
|
||||
msgbox.setText(_("Are you sure you want to permanently delete\n"
|
||||
"the selected objects?"))
|
||||
bt_ok = msgbox.addButton(_('Ok'), QtWidgets.QMessageBox.AcceptRole)
|
||||
|
@ -7166,12 +7332,15 @@ class App(QtCore.QObject):
|
|||
|
||||
self.should_we_save = False
|
||||
|
||||
def on_file_saveprojectas(self, make_copy=False, thread=True, quit=False):
|
||||
def on_file_saveprojectas(self, make_copy=False, use_thread=True, quit_action=False):
|
||||
"""
|
||||
Callback for menu item File->Save Project As... Opens a file
|
||||
chooser and saves the project to the given file via
|
||||
``self.save_project()``.
|
||||
|
||||
:param make_copy if to be create a copy of the project; boolean
|
||||
:param use_thread: if to be run in a separate thread; boolean
|
||||
:param quit_action: if to be followed by quiting the application; boolean
|
||||
:return: None
|
||||
"""
|
||||
|
||||
|
@ -7202,16 +7371,17 @@ class App(QtCore.QObject):
|
|||
except IOError:
|
||||
pass
|
||||
|
||||
if thread is True:
|
||||
if use_thread is True:
|
||||
self.worker_task.emit({'fcn': self.save_project,
|
||||
'params': [filename, quit]})
|
||||
'params': [filename, quit_action]})
|
||||
else:
|
||||
self.save_project(filename, quit)
|
||||
self.save_project(filename, quit_action)
|
||||
|
||||
# self.save_project(filename)
|
||||
if self.defaults["global_open_style"] is False:
|
||||
self.file_opened.emit("project", filename)
|
||||
self.file_saved.emit("project", filename)
|
||||
|
||||
if not make_copy:
|
||||
self.project_filename = filename
|
||||
|
||||
|
@ -7222,7 +7392,9 @@ class App(QtCore.QObject):
|
|||
"""
|
||||
Exports a Geometry Object to an SVG file.
|
||||
|
||||
:param obj_name: the name of the FlatCAM object to be saved as SVG
|
||||
:param filename: Path to the SVG file to save to.
|
||||
:param scale_factor: factor by which to change/scale the thickness of the features
|
||||
:return:
|
||||
"""
|
||||
self.report_usage("export_svg()")
|
||||
|
@ -7284,9 +7456,12 @@ class App(QtCore.QObject):
|
|||
"""
|
||||
Exports a Geometry Object to an SVG file in negative.
|
||||
|
||||
:param obj_name: the name of the FlatCAM object to be saved as SVG
|
||||
:param box_name: the name of the FlatCAM object to be used as delimitation of the content to be saved
|
||||
:param filename: Path to the SVG file to save to.
|
||||
:param: use_thread: If True use threads
|
||||
:type: Bool
|
||||
:param boundary: thickness of a black border to surround all the features
|
||||
:param scale_factor: factor by which to change/scale the thickness of the features
|
||||
:param use_thread: if to be run in a separate thread; boolean
|
||||
:return:
|
||||
"""
|
||||
self.report_usage("export_negative()")
|
||||
|
@ -7408,11 +7583,13 @@ class App(QtCore.QObject):
|
|||
|
||||
def export_svg_black(self, obj_name, box_name, filename, scale_factor=0.00, use_thread=True):
|
||||
"""
|
||||
Exports a Geometry Object to an SVG file in negative.
|
||||
Exports a Geometry Object to an SVG file in positive black.
|
||||
|
||||
:param obj_name: the name of the FlatCAM object to be saved as SVG
|
||||
:param box_name: the name of the FlatCAM object to be used as delimitation of the content to be saved
|
||||
:param filename: Path to the SVG file to save to.
|
||||
:param: use_thread: If True use threads
|
||||
:type: Bool
|
||||
:param scale_factor: factor by which to change/scale the thickness of the features
|
||||
:param use_thread: if to be run in a separate thread; boolean
|
||||
:return:
|
||||
"""
|
||||
self.report_usage("export_svg_black()")
|
||||
|
@ -7529,9 +7706,11 @@ class App(QtCore.QObject):
|
|||
|
||||
def save_source_file(self, obj_name, filename, use_thread=True):
|
||||
"""
|
||||
Exports a Gerber Object to an Gerber file.
|
||||
Exports a FlatCAM Object to an Gerber/Excellon file.
|
||||
|
||||
:param obj_name: the name of the FlatCAM object for which to save it's embedded source file
|
||||
:param filename: Path to the Gerber file to save to.
|
||||
:param use_thread: if to be run in a separate thread
|
||||
:return:
|
||||
"""
|
||||
self.report_usage("save source file()")
|
||||
|
@ -7565,7 +7744,9 @@ class App(QtCore.QObject):
|
|||
"""
|
||||
Exports a Excellon Object to an Excellon file.
|
||||
|
||||
:param obj_name: the name of the FlatCAM object to be saved as Excellon
|
||||
:param filename: Path to the Excellon file to save to.
|
||||
:param use_thread: if to be run in a separate thread
|
||||
:return:
|
||||
"""
|
||||
self.report_usage("export_excellon()")
|
||||
|
@ -7701,7 +7882,9 @@ class App(QtCore.QObject):
|
|||
"""
|
||||
Exports a Gerber Object to an Gerber file.
|
||||
|
||||
:param obj_name: the name of the FlatCAM object to be saved as Gerber
|
||||
:param filename: Path to the Gerber file to save to.
|
||||
:param use_thread: if to be run in a separate thread
|
||||
:return:
|
||||
"""
|
||||
self.report_usage("export_gerber()")
|
||||
|
@ -7824,7 +8007,9 @@ class App(QtCore.QObject):
|
|||
"""
|
||||
Exports a Geometry Object to an DXF file.
|
||||
|
||||
:param obj_name: the name of the FlatCAM object to be saved as DXF
|
||||
:param filename: Path to the DXF file to save to.
|
||||
:param use_thread: if to be run in a separate thread
|
||||
:return:
|
||||
"""
|
||||
self.report_usage("export_dxf()")
|
||||
|
@ -7868,7 +8053,7 @@ class App(QtCore.QObject):
|
|||
def job_thread_exc(app_obj):
|
||||
ret = make_dxf()
|
||||
if ret == 'fail':
|
||||
self.inform.emit(_('[[WARNING_NOTCL]] Could not export DXF file.'))
|
||||
app_obj.inform.emit(_('[[WARNING_NOTCL]] Could not export DXF file.'))
|
||||
return
|
||||
|
||||
self.worker_task.emit({'fcn': job_thread_exc, 'params': [self]})
|
||||
|
@ -8254,6 +8439,8 @@ class App(QtCore.QObject):
|
|||
"""
|
||||
App.log.debug("Opening project: " + filename)
|
||||
|
||||
self.set_ui_title(name=_("Loading Project ... Please Wait ..."))
|
||||
|
||||
# Open and parse an uncompressed Project file
|
||||
try:
|
||||
f = open(filename, 'r')
|
||||
|
@ -8293,20 +8480,26 @@ class App(QtCore.QObject):
|
|||
self.set_screen_units(self.options["units"])
|
||||
|
||||
# Re create objects
|
||||
App.log.debug("Re-creating objects...")
|
||||
App.log.debug(" **************** Started PROEJCT loading... **************** ")
|
||||
|
||||
for obj in d['objs']:
|
||||
def obj_init(obj_inst, app_inst):
|
||||
obj_inst.from_dict(obj)
|
||||
App.log.debug(obj['kind'] + ": " + obj['options']['name'])
|
||||
App.log.debug("Recreating from opened project an %s object: %s" %
|
||||
(obj['kind'].capitalize(), obj['options']['name']))
|
||||
|
||||
self.set_ui_title(name="{} {}: {}".format(_("Loading Project ... restoring"), obj['kind'].upper(), obj['options']['name']))
|
||||
|
||||
self.new_object(obj['kind'], obj['options']['name'], obj_init, active=False, fit=False, plot=True)
|
||||
self.plot_all()
|
||||
|
||||
# self.plot_all()
|
||||
self.inform.emit(_("[success] Project loaded from: %s") % filename)
|
||||
|
||||
self.should_we_save = False
|
||||
self.file_opened.emit("project", filename)
|
||||
self.set_ui_title(name=self.project_filename)
|
||||
|
||||
App.log.debug("Project loaded")
|
||||
App.log.debug(" **************** Finished PROJECT loading... **************** ")
|
||||
|
||||
def propagate_defaults(self, silent=False):
|
||||
"""
|
||||
|
@ -8856,6 +9049,35 @@ The normal flow when working in FlatCAM is the following:</span></p>
|
|||
_("info")
|
||||
)
|
||||
|
||||
def on_plotcanvas_setup(self, container=None):
|
||||
"""
|
||||
This is doing the setup for the plot area (VisPy canvas)
|
||||
|
||||
:param container: widget where to install the canvas
|
||||
:return: None
|
||||
"""
|
||||
if container:
|
||||
plot_container = container
|
||||
else:
|
||||
plot_container = self.ui.right_layout
|
||||
|
||||
self.plotcanvas = PlotCanvas(plot_container, self)
|
||||
|
||||
# So it can receive key presses
|
||||
self.plotcanvas.vispy_canvas.native.setFocus()
|
||||
|
||||
self.plotcanvas.vis_connect('mouse_move', self.on_mouse_move_over_plot)
|
||||
self.plotcanvas.vis_connect('mouse_press', self.on_mouse_click_over_plot)
|
||||
self.plotcanvas.vis_connect('mouse_release', self.on_mouse_click_release_over_plot)
|
||||
self.plotcanvas.vis_connect('mouse_double_click', self.on_double_click_over_plot)
|
||||
|
||||
# Keys over plot enabled
|
||||
self.plotcanvas.vis_connect('key_press', self.ui.keyPressEvent)
|
||||
|
||||
self.app_cursor = self.plotcanvas.new_cursor()
|
||||
self.app_cursor.enabled = False
|
||||
self.hover_shapes = ShapeCollection(parent=self.plotcanvas.vispy_canvas.view.scene, layers=1)
|
||||
|
||||
def on_zoom_fit(self, event):
|
||||
"""
|
||||
Callback for zoom-out request. This can be either from the corresponding
|
||||
|
@ -8868,6 +9090,12 @@ The normal flow when working in FlatCAM is the following:</span></p>
|
|||
|
||||
self.plotcanvas.fit_view()
|
||||
|
||||
def on_zoom_in(self):
|
||||
self.plotcanvas.zoom(1 / float(self.defaults['global_zoom_ratio']))
|
||||
|
||||
def on_zoom_out(self):
|
||||
self.plotcanvas.zoom(float(self.defaults['global_zoom_ratio']))
|
||||
|
||||
def disable_all_plots(self):
|
||||
self.report_usage("disable_all_plots()")
|
||||
|
||||
|
@ -8906,7 +9134,6 @@ The normal flow when working in FlatCAM is the following:</span></p>
|
|||
:param objects: list of Objects to be enabled
|
||||
:return:
|
||||
"""
|
||||
|
||||
log.debug("Enabling plots ...")
|
||||
self.inform.emit(_("Working ..."))
|
||||
for obj in objects:
|
||||
|
@ -8970,12 +9197,13 @@ The normal flow when working in FlatCAM is the following:</span></p>
|
|||
for obj in objects:
|
||||
obj.on_generatecnc_button_click()
|
||||
|
||||
def save_project(self, filename, quit=False):
|
||||
def save_project(self, filename, quit_action=False):
|
||||
"""
|
||||
Saves the current project to the specified file.
|
||||
|
||||
:param filename: Name of the file in which to save.
|
||||
:type filename: str
|
||||
:param quit_action: if the project saving will be followed by an app quit; boolean
|
||||
:return: None
|
||||
"""
|
||||
self.log.debug("save_project()")
|
||||
|
@ -9037,28 +9265,37 @@ The normal flow when working in FlatCAM is the following:</span></p>
|
|||
else:
|
||||
self.inform.emit(_("[ERROR_NOTCL] Failed to save project file: %s. Retry to save it.") % filename)
|
||||
|
||||
settings = QSettings("Open Source", "FlatCAM")
|
||||
lock_state = self.ui.lock_action.isChecked()
|
||||
settings.setValue('toolbar_lock', lock_state)
|
||||
|
||||
# This will write the setting to the platform specific storage.
|
||||
del settings
|
||||
|
||||
# if quit:
|
||||
# t = threading.Thread(target=lambda: self.check_project_file_size(1, filename=filename))
|
||||
# t.start()
|
||||
self.start_delayed_quit(delay=500, filename=filename, quit=quit)
|
||||
self.start_delayed_quit(delay=500, filename=filename, should_quit=quit_action)
|
||||
|
||||
def start_delayed_quit(self, delay, filename, quit=None):
|
||||
def start_delayed_quit(self, delay, filename, should_quit=None):
|
||||
"""
|
||||
|
||||
:param delay: period of checking if project file size is more than zero; in seconds
|
||||
:param filename: the name of the project file to be checked periodically for size more than zero
|
||||
:param should_quit: if the task finished will be followed by an app quit; boolean
|
||||
:return:
|
||||
"""
|
||||
to_quit = quit
|
||||
to_quit = should_quit
|
||||
self.save_timer = QtCore.QTimer()
|
||||
self.save_timer.setInterval(delay)
|
||||
self.save_timer.timeout.connect(lambda: self.check_project_file_size(filename=filename, quit=to_quit))
|
||||
self.save_timer.timeout.connect(lambda: self.check_project_file_size(filename=filename, should_quit=to_quit))
|
||||
self.save_timer.start()
|
||||
|
||||
def check_project_file_size(self, filename, quit=None):
|
||||
def check_project_file_size(self, filename, should_quit=None):
|
||||
"""
|
||||
|
||||
:param filename: the name of the project file to be checked periodically for size more than zero
|
||||
:param should_quit: will quit the app if True; boolean
|
||||
:return:
|
||||
"""
|
||||
|
||||
|
@ -9066,9 +9303,9 @@ The normal flow when working in FlatCAM is the following:</span></p>
|
|||
if os.stat(filename).st_size > 0:
|
||||
self.save_in_progress = False
|
||||
self.save_timer.stop()
|
||||
if quit:
|
||||
if should_quit:
|
||||
self.app_quit.emit()
|
||||
except Exception:
|
||||
except Exception as e:
|
||||
traceback.print_exc()
|
||||
|
||||
def on_options_app2project(self):
|
||||
|
|
|
@ -136,7 +136,6 @@ class FlatCAMObj(QtCore.QObject):
|
|||
def on_options_change(self, key):
|
||||
# Update form on programmatically options change
|
||||
self.set_form_item(key)
|
||||
|
||||
# Set object visibility
|
||||
if key == 'plot':
|
||||
self.visible = self.options['plot']
|
||||
|
@ -774,7 +773,7 @@ class FlatCAMGerber(FlatCAMObj, Gerber):
|
|||
|
||||
if self.ui.follow_cb.get_value() is True:
|
||||
obj = self.app.collection.get_active()
|
||||
obj.follow()
|
||||
obj.follow_geo()
|
||||
# in the end toggle the visibility of the origin object so we can see the generated Geometry
|
||||
obj.ui.plot_cb.toggle()
|
||||
else:
|
||||
|
@ -786,7 +785,7 @@ class FlatCAMGerber(FlatCAMObj, Gerber):
|
|||
|
||||
if self.ui.follow_cb.get_value() is True:
|
||||
obj = self.app.collection.get_active()
|
||||
obj.follow()
|
||||
obj.follow_geo()
|
||||
# in the end toggle the visibility of the origin object so we can see the generated Geometry
|
||||
obj.ui.plot_cb.toggle()
|
||||
else:
|
||||
|
@ -1130,6 +1129,7 @@ class FlatCAMGerber(FlatCAMObj, Gerber):
|
|||
:return: None
|
||||
:rtype: None
|
||||
"""
|
||||
log.debug("FlatCAMObj.FlatCAMGerber.convert_units()")
|
||||
|
||||
factor = Gerber.convert_units(self, units)
|
||||
|
||||
|
@ -2769,8 +2769,9 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
|
|||
self.app.worker_task.emit({'fcn': job_thread, 'params': [self.app]})
|
||||
|
||||
def convert_units(self, units):
|
||||
factor = Excellon.convert_units(self, units)
|
||||
log.debug("FlatCAMObj.FlatCAMExcellon.convert_units()")
|
||||
|
||||
factor = Excellon.convert_units(self, units)
|
||||
self.options['drillz'] = float(self.options['drillz']) * factor
|
||||
self.options['travelz'] = float(self.options['travelz']) * factor
|
||||
self.options['feedrate'] = float(self.options['feedrate']) * factor
|
||||
|
@ -3423,7 +3424,6 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
|
|||
self.ui.level.setText(_(
|
||||
'<span style="color:red;"><b>Advanced</b></span>'
|
||||
))
|
||||
|
||||
self.ui.plot_cb.stateChanged.connect(self.on_plot_cb_click)
|
||||
self.ui.generate_cnc_button.clicked.connect(self.on_generatecnc_button_click)
|
||||
self.ui.paint_tool_button.clicked.connect(lambda: self.app.paint_tool.run(toggle=False))
|
||||
|
@ -4958,6 +4958,7 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
|
|||
:return: None
|
||||
:rtype: None
|
||||
"""
|
||||
log.debug("FlatCAMObj.FlatCAMGeometry.scale()")
|
||||
|
||||
try:
|
||||
xfactor = float(xfactor)
|
||||
|
@ -5027,6 +5028,7 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
|
|||
:return: None
|
||||
:rtype: None
|
||||
"""
|
||||
log.debug("FlatCAMObj.FlatCAMGeometry.offset()")
|
||||
|
||||
try:
|
||||
dx, dy = vect
|
||||
|
@ -5057,6 +5059,8 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
|
|||
self.app.inform.emit(_("[success] Geometry Offset done."))
|
||||
|
||||
def convert_units(self, units):
|
||||
log.debug("FlatCAMObj.FlatCAMGeometry.convert_units()")
|
||||
|
||||
self.ui_disconnect()
|
||||
|
||||
factor = Geometry.convert_units(self, units)
|
||||
|
@ -5203,11 +5207,11 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
|
|||
for tooluid_key in self.tools:
|
||||
solid_geometry = self.tools[tooluid_key]['solid_geometry']
|
||||
self.plot_element(solid_geometry, visible=visible)
|
||||
|
||||
# plot solid geometry that may be an direct attribute of the geometry object
|
||||
# for SingleGeo
|
||||
if self.solid_geometry:
|
||||
self.plot_element(self.solid_geometry, visible=visible)
|
||||
else:
|
||||
# plot solid geometry that may be an direct attribute of the geometry object
|
||||
# for SingleGeo
|
||||
if self.solid_geometry:
|
||||
self.plot_element(self.solid_geometry, visible=visible)
|
||||
|
||||
# self.plot_element(self.solid_geometry, visible=self.options['plot'])
|
||||
self.shapes.redraw()
|
||||
|
@ -5217,8 +5221,8 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
|
|||
def on_plot_cb_click(self, *args):
|
||||
if self.muted_ui:
|
||||
return
|
||||
self.plot()
|
||||
self.read_form_item('plot')
|
||||
self.plot()
|
||||
|
||||
self.ui_disconnect()
|
||||
cb_flag = self.ui.plot_cb.isChecked()
|
||||
|
@ -6024,8 +6028,9 @@ class FlatCAMCNCjob(FlatCAMObj, CNCjob):
|
|||
self.annotation.redraw()
|
||||
|
||||
def convert_units(self, units):
|
||||
log.debug("FlatCAMObj.FlatCAMECNCjob.convert_units()")
|
||||
|
||||
factor = CNCjob.convert_units(self, units)
|
||||
FlatCAMApp.App.log.debug("FlatCAMCNCjob.convert_units()")
|
||||
self.options["tooldia"] = float(self.options["tooldia"]) * factor
|
||||
|
||||
param_list = ['cutz', 'depthperpass', 'travelz', 'feedrate', 'feedrate_z', 'feedrate_rapid',
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
# ########################################################## ##
|
||||
|
||||
from PyQt5 import QtCore
|
||||
# import traceback
|
||||
|
||||
|
||||
class Worker(QtCore.QObject):
|
||||
|
@ -60,6 +61,7 @@ class Worker(QtCore.QObject):
|
|||
task['fcn'](*task['params'])
|
||||
except Exception as e:
|
||||
self.app.thread_exception.emit(e)
|
||||
# print(traceback.format_exc())
|
||||
# raise e
|
||||
finally:
|
||||
self.task_completed.emit(self.name)
|
||||
|
|
|
@ -693,7 +693,7 @@ class ObjectCollection(QtCore.QAbstractItemModel):
|
|||
:param name: Name of the FlatCAM Object
|
||||
:return: None
|
||||
"""
|
||||
log.debug("ObjectCollection.set_inactive()")
|
||||
# log.debug("ObjectCollection.set_inactive()")
|
||||
|
||||
obj = self.get_by_name(name)
|
||||
item = obj.item
|
||||
|
|
68
README.md
68
README.md
|
@ -9,6 +9,74 @@ CAD program, and create G-Code for Isolation routing.
|
|||
|
||||
=================================================
|
||||
|
||||
23.08.2019
|
||||
|
||||
- in Tool Cutout for the manual gaps, right mouse button click will exit from the action of adding gaps
|
||||
- in Tool Cutout tool I've added the possibility to create a cutout without bridge gaps; added the 'None' option in the Gaps combobox
|
||||
- in NCC Tool added ability to add multiple zones to clear when Area option is checked and the modifier key is pressed (either CTRL or SHIFT as set in Preferences). Right click of the mouse is an additional way to finish the job.
|
||||
- fixed a bug in Excellon Editor that made that the selection of drills is always cumulative
|
||||
- in Paint Tool added ability to add multiple zones to paint when Area option is checked and the modifier key is pressed (either CTRL or SHIFT as set in Preferences). Right click of the mouse is an additional way to finish the job.
|
||||
- in Paint Tool and NCC Tool, for the Area option, now mouse panning is allowed while adding areas to process
|
||||
- for all the FlatCAM tools launched from toolbar the behavior is modified: first click it will launch the tool; second click: if the Tool tab has focus it will close the tool but if another tab is selected, the tool will have focus
|
||||
- modified the NCC Tool and Paint Tool to work multiple times after first launch
|
||||
- fixed the issue with GUI entries content being deselected on right click in the box in order to copy the value
|
||||
- some changes in GUI tooltips
|
||||
- modified the way key modifiers are detected in Gerber Editor Selection class and in Excellon Editor Selection class
|
||||
- updated the translations
|
||||
- fixed aperture move in Gerber Editor
|
||||
- fixed drills/slots move in Excellon Editor
|
||||
- RELEASE 8.96
|
||||
|
||||
22.08.2019
|
||||
|
||||
- added ability to turn ON/OFF the detachable capability of the tabs in Notebook through a context menu activated by right mouse button click on the Notebook header
|
||||
- added ability to turn ON/OFF the detachable capability of the tabs in Plot Tab Area through a context menu activated by right mouse button click on the Notebook header
|
||||
- added possibility to turn application portable from the Edit -> Preferences -> General -> App. Preferences -> Portable checkbox
|
||||
- moved the canvas setup into it's own function and called it in the init() function
|
||||
- fixed the Buffer Tool in Geometry Editor; made the Buffer entry field a QDoubleSpinner and set the lower limit to zero.
|
||||
- fixed Tool Cutout so when the target Gerber is a single Polygon then the created manual geometry will follow the shape if shape is freeform
|
||||
- fixed TclCommandFollow command; an older function name was used who yielded wrong results
|
||||
- in Tool Cutout for the manual gaps, now the moving geometry that cuts gaps will orient itself to fit the angle of the cutout geometry
|
||||
|
||||
21.08.2019
|
||||
|
||||
- added feature in Paint Tool allowing the painting to be done on Gerber objects
|
||||
- added feature in Paint Tool to set how (and if) the tools are sorted
|
||||
- added Edit -> Preferences GUI entries for the above just added features
|
||||
- added new entry in Properties Tool which is the calculated Convex Hull Area (should give a more precise area for the irregular shapes than the box area)
|
||||
- added some more strings in Properties Tool for the translation
|
||||
- in NCC Tool added area selection feature
|
||||
- fixed bug in Excellon parser for the Excellon files that do not put the type of zero suppression they use in the file (like DipTrace eCAD)
|
||||
- fixed some issues introduced in NCC Tool
|
||||
|
||||
20.08.2019
|
||||
|
||||
- added ability to do copper clearing through NCC Tool on Geometry objects
|
||||
- replaced the layout from Grid to Form for the Reference objects comboboxes in Paint Tool and in NCC Tool
|
||||
|
||||
19.08.2019
|
||||
|
||||
- updated the Edit -> Preferences to include also the Gerber Editor complete Preferences
|
||||
- started to update the app strings to make it easier for future translations
|
||||
- fixed the POT file and the German translation
|
||||
- some mods in the Tool Sub
|
||||
- fixed bug in Tool Sub that created issues when toggling visibility of the plots
|
||||
- fixed the Spanish, Brazilian Portuguese and Romanian translations
|
||||
|
||||
18.08.2019
|
||||
|
||||
- made the exported preferences formatted therefore more easily read
|
||||
- projects at startup don't work in another thread so there is no multithreading if I want to double click an project and to load it
|
||||
- added messages in the application window title which show the progress in loading a project (which is not thread-safe therefore keeping the app from fully initialize until finished)
|
||||
- in NCC Tool added a new parameter (radio button) that offer the choice on the order of the tools both in tools table and in execution of engraving; added as a parameter also in Edit -> Preferences -> Tools -> NCC Tool
|
||||
- added possibility to drag & drop FlatCAM config files (*.FlatConfig) into the canvas to be opened into the application
|
||||
- added GUI in Paint tool in beginning to add Paint by external reference object
|
||||
- finished adding in Paint Tool the usage of an external object to set the extent of th area painted. For simple shapes (single Polygon) the shape can be anything, for the rest will be a convex hull of the reference object
|
||||
- modified NCC tool so for simple objects (single Polygon) the external object used as reference can have any shape, for the other types of objects the copper cleared area will be the convex hull of the reference object
|
||||
- modified the strings of the app wherever they contained the char seq <b> </b> so it is not included in the translated string
|
||||
- updated the translation files for the modified strings (and for the newly added strings)
|
||||
- added ability to lock toolbars within the context menu that is popped up on any toolbars right mouse click. The value is saved in QSettings and it is persistent between application startup's.
|
||||
|
||||
17.08.2019
|
||||
|
||||
- added estimated time of routing for the CNCJob and added travelled distance parameter for geometry, too
|
||||
|
|
47
camlib.py
47
camlib.py
|
@ -229,7 +229,8 @@ class Geometry(object):
|
|||
# fixed issue of getting bounds only for one level lists of objects
|
||||
# now it can get bounds for nested lists of objects
|
||||
|
||||
log.debug("Geometry->bounds()")
|
||||
log.debug("camlib.Geometry.bounds()")
|
||||
|
||||
if self.solid_geometry is None:
|
||||
log.debug("solid_geometry is None")
|
||||
return 0, 0, 0, 0
|
||||
|
@ -1278,7 +1279,7 @@ class Geometry(object):
|
|||
:return: Scaling factor resulting from unit change.
|
||||
:rtype: float
|
||||
"""
|
||||
log.debug("Geometry.convert_units()")
|
||||
log.debug("camlib.Geometry.convert_units()")
|
||||
|
||||
if units.upper() == self.units.upper():
|
||||
return 1.0
|
||||
|
@ -1378,6 +1379,7 @@ class Geometry(object):
|
|||
:type point: list
|
||||
:return: None
|
||||
"""
|
||||
log.debug("camlib.Geometry.mirror()")
|
||||
|
||||
px, py = point
|
||||
xscale, yscale = {"X": (1.0, -1.0), "Y": (-1.0, 1.0)}[axis]
|
||||
|
@ -1420,6 +1422,7 @@ class Geometry(object):
|
|||
See shapely manual for more information:
|
||||
http://toblerity.org/shapely/manual.html#affine-transformations
|
||||
"""
|
||||
log.debug("camlib.Geometry.rotate()")
|
||||
|
||||
px, py = point
|
||||
|
||||
|
@ -1460,6 +1463,8 @@ class Geometry(object):
|
|||
See shapely manual for more information:
|
||||
http://toblerity.org/shapely/manual.html#affine-transformations
|
||||
"""
|
||||
log.debug("camlib.Geometry.skew()")
|
||||
|
||||
px, py = point
|
||||
|
||||
def skew_geom(obj):
|
||||
|
@ -3298,7 +3303,8 @@ class Gerber (Geometry):
|
|||
# fixed issue of getting bounds only for one level lists of objects
|
||||
# now it can get bounds for nested lists of objects
|
||||
|
||||
log.debug("Gerber->bounds()")
|
||||
log.debug("camlib.Gerber.bounds()")
|
||||
|
||||
if self.solid_geometry is None:
|
||||
log.debug("solid_geometry is None")
|
||||
return 0, 0, 0, 0
|
||||
|
@ -3442,6 +3448,8 @@ class Gerber (Geometry):
|
|||
:type vect: tuple
|
||||
:return: None
|
||||
"""
|
||||
log.debug("camlib.Gerber.offset()")
|
||||
|
||||
try:
|
||||
dx, dy = vect
|
||||
except TypeError:
|
||||
|
@ -3504,6 +3512,7 @@ class Gerber (Geometry):
|
|||
:type point: list
|
||||
:return: None
|
||||
"""
|
||||
log.debug("camlib.Gerber.mirror()")
|
||||
|
||||
px, py = point
|
||||
xscale, yscale = {"X": (1.0, -1.0), "Y": (-1.0, 1.0)}[axis]
|
||||
|
@ -3554,6 +3563,7 @@ class Gerber (Geometry):
|
|||
See shapely manual for more information:
|
||||
http://toblerity.org/shapely/manual.html#affine-transformations
|
||||
"""
|
||||
log.debug("camlib.Gerber.skew()")
|
||||
|
||||
px, py = point
|
||||
|
||||
|
@ -3596,6 +3606,7 @@ class Gerber (Geometry):
|
|||
:param point:
|
||||
:return:
|
||||
"""
|
||||
log.debug("camlib.Gerber.rotate()")
|
||||
|
||||
px, py = point
|
||||
|
||||
|
@ -4521,7 +4532,7 @@ class Excellon(Geometry):
|
|||
else:
|
||||
result = float(number_str) / (10 ** (float(nr_length) - float(self.excellon_format_upper_mm)))
|
||||
return result
|
||||
elif self.zeros == "T" or self.zeros == "TZ": # Trailing
|
||||
else: # Trailing
|
||||
# You must show all zeros to the right of the number and can omit
|
||||
# all zeros to the left of the number. The CNC-7 will count the number
|
||||
# of digits you typed and automatically fill in the missing zeros.
|
||||
|
@ -4533,9 +4544,6 @@ class Excellon(Geometry):
|
|||
else: # Metric is 000.000
|
||||
result = float(number_str) / (10 ** (float(self.excellon_format_lower_mm)))
|
||||
return result
|
||||
else: # None - the numbers are in decimal format
|
||||
return float(number_str)
|
||||
|
||||
except Exception as e:
|
||||
log.error("Aborted. Operation could not be completed due of %s" % str(e))
|
||||
return
|
||||
|
@ -4631,7 +4639,7 @@ class Excellon(Geometry):
|
|||
# fixed issue of getting bounds only for one level lists of objects
|
||||
# now it can get bounds for nested lists of objects
|
||||
|
||||
log.debug("Excellon() -> bounds()")
|
||||
log.debug("camlib.Excellon.bounds()")
|
||||
# if self.solid_geometry is None:
|
||||
# log.debug("solid_geometry is None")
|
||||
# return 0, 0, 0, 0
|
||||
|
@ -4691,6 +4699,8 @@ class Excellon(Geometry):
|
|||
:type str: IN or MM
|
||||
:return:
|
||||
"""
|
||||
log.debug("camlib.Excellon.convert_units()")
|
||||
|
||||
factor = Geometry.convert_units(self, units)
|
||||
|
||||
# Tools
|
||||
|
@ -4711,6 +4721,8 @@ class Excellon(Geometry):
|
|||
:return: None
|
||||
:rtype: NOne
|
||||
"""
|
||||
log.debug("camlib.Excellon.scale()")
|
||||
|
||||
if yfactor is None:
|
||||
yfactor = xfactor
|
||||
|
||||
|
@ -4755,6 +4767,7 @@ class Excellon(Geometry):
|
|||
:type vect: tuple
|
||||
:return: None
|
||||
"""
|
||||
log.debug("camlib.Excellon.offset()")
|
||||
|
||||
dx, dy = vect
|
||||
|
||||
|
@ -4795,6 +4808,8 @@ class Excellon(Geometry):
|
|||
:type point: list
|
||||
:return: None
|
||||
"""
|
||||
log.debug("camlib.Excellon.mirror()")
|
||||
|
||||
px, py = point
|
||||
xscale, yscale = {"X": (1.0, -1.0), "Y": (-1.0, 1.0)}[axis]
|
||||
|
||||
|
@ -4842,6 +4857,8 @@ class Excellon(Geometry):
|
|||
See shapely manual for more information:
|
||||
http://toblerity.org/shapely/manual.html#affine-transformations
|
||||
"""
|
||||
log.debug("camlib.Excellon.skew()")
|
||||
|
||||
if angle_x is None:
|
||||
angle_x = 0.0
|
||||
|
||||
|
@ -4900,6 +4917,7 @@ class Excellon(Geometry):
|
|||
:param point: tuple of coordinates (x, y)
|
||||
:return:
|
||||
"""
|
||||
log.debug("camlib.Excellon.rotate()")
|
||||
|
||||
def rotate_geom(obj, origin=None):
|
||||
if type(obj) is list:
|
||||
|
@ -5092,8 +5110,9 @@ class CNCjob(Geometry):
|
|||
return self.__dict__
|
||||
|
||||
def convert_units(self, units):
|
||||
log.debug("camlib.CNCJob.convert_units()")
|
||||
|
||||
factor = Geometry.convert_units(self, units)
|
||||
log.debug("CNCjob.convert_units()")
|
||||
|
||||
self.z_cut = float(self.z_cut) * factor
|
||||
self.z_move *= factor
|
||||
|
@ -6987,6 +7006,8 @@ class CNCjob(Geometry):
|
|||
# fixed issue of getting bounds only for one level lists of objects
|
||||
# now it can get bounds for nested lists of objects
|
||||
|
||||
log.debug("camlib.CNCJob.bounds()")
|
||||
|
||||
def bounds_rec(obj):
|
||||
if type(obj) is list:
|
||||
minx = Inf
|
||||
|
@ -7058,6 +7079,7 @@ class CNCjob(Geometry):
|
|||
:return: None
|
||||
:rtype: None
|
||||
"""
|
||||
log.debug("camlib.CNCJob.scale()")
|
||||
|
||||
if yfactor is None:
|
||||
yfactor = xfactor
|
||||
|
@ -7207,6 +7229,8 @@ class CNCjob(Geometry):
|
|||
:type vect: tuple
|
||||
:return: None
|
||||
"""
|
||||
log.debug("camlib.CNCJob.offset()")
|
||||
|
||||
dx, dy = vect
|
||||
|
||||
def offset_g(g):
|
||||
|
@ -7271,6 +7295,8 @@ class CNCjob(Geometry):
|
|||
:param point: tupple of coordinates (x,y)
|
||||
:return:
|
||||
"""
|
||||
log.debug("camlib.CNCJob.mirror()")
|
||||
|
||||
px, py = point
|
||||
xscale, yscale = {"X": (1.0, -1.0), "Y": (-1.0, 1.0)}[axis]
|
||||
|
||||
|
@ -7296,6 +7322,8 @@ class CNCjob(Geometry):
|
|||
See shapely manual for more information:
|
||||
http://toblerity.org/shapely/manual.html#affine-transformations
|
||||
"""
|
||||
log.debug("camlib.CNCJob.skew()")
|
||||
|
||||
px, py = point
|
||||
|
||||
for g in self.gcode_parsed:
|
||||
|
@ -7312,6 +7340,7 @@ class CNCjob(Geometry):
|
|||
:param point: tupple of coordinates (x,y)
|
||||
:return:
|
||||
"""
|
||||
log.debug("camlib.CNCJob.rotate()")
|
||||
|
||||
px, py = point
|
||||
|
||||
|
|
|
@ -1 +1 @@
|
|||
portable=False
|
||||
portable=False
|
||||
|
|
|
@ -1251,6 +1251,9 @@ class FCDrillSelect(DrawTool):
|
|||
self.storage = self.exc_editor_app.storage_dict
|
||||
# self.selected = self.exc_editor_app.selected
|
||||
|
||||
# here we store the selected tools
|
||||
self.sel_tools = set()
|
||||
|
||||
# here we store all shapes that were selected so we can search for the nearest to our click location
|
||||
self.sel_storage = FlatCAMExcEditor.make_storage()
|
||||
|
||||
|
@ -1261,16 +1264,18 @@ class FCDrillSelect(DrawTool):
|
|||
|
||||
def click(self, point):
|
||||
key_modifier = QtWidgets.QApplication.keyboardModifiers()
|
||||
if self.exc_editor_app.app.defaults["global_mselect_key"] == 'Control':
|
||||
if key_modifier == Qt.ControlModifier:
|
||||
pass
|
||||
else:
|
||||
self.exc_editor_app.selected = []
|
||||
|
||||
if key_modifier == QtCore.Qt.ShiftModifier:
|
||||
mod_key = 'Shift'
|
||||
elif key_modifier == QtCore.Qt.ControlModifier:
|
||||
mod_key = 'Control'
|
||||
else:
|
||||
if key_modifier == Qt.ShiftModifier:
|
||||
pass
|
||||
else:
|
||||
self.exc_editor_app.selected = []
|
||||
mod_key = None
|
||||
|
||||
if mod_key == self.draw_app.app.defaults["global_mselect_key"]:
|
||||
pass
|
||||
else:
|
||||
self.exc_editor_app.selected = []
|
||||
|
||||
def click_release(self, pos):
|
||||
self.exc_editor_app.tools_table_exc.clearSelection()
|
||||
|
@ -1308,11 +1313,13 @@ class FCDrillSelect(DrawTool):
|
|||
self.exc_editor_app.selected = []
|
||||
else:
|
||||
modifiers = QtWidgets.QApplication.keyboardModifiers()
|
||||
mod_key = 'Control'
|
||||
|
||||
if modifiers == QtCore.Qt.ShiftModifier:
|
||||
mod_key = 'Shift'
|
||||
elif modifiers == QtCore.Qt.ControlModifier:
|
||||
mod_key = 'Control'
|
||||
else:
|
||||
mod_key = None
|
||||
|
||||
if mod_key == self.draw_app.app.defaults["global_mselect_key"]:
|
||||
if closest_shape in self.exc_editor_app.selected:
|
||||
|
@ -1329,14 +1336,13 @@ class FCDrillSelect(DrawTool):
|
|||
except (TypeError, AttributeError):
|
||||
pass
|
||||
|
||||
sel_tools = set()
|
||||
self.exc_editor_app.tools_table_exc.setSelectionMode(QtWidgets.QAbstractItemView.MultiSelection)
|
||||
for shape_s in self.exc_editor_app.selected:
|
||||
for storage in self.exc_editor_app.storage_dict:
|
||||
if shape_s in self.exc_editor_app.storage_dict[storage].get_objects():
|
||||
sel_tools.add(storage)
|
||||
self.sel_tools.add(storage)
|
||||
|
||||
for storage in sel_tools:
|
||||
for storage in self.sel_tools:
|
||||
for k, v in self.draw_app.tool2tooldia.items():
|
||||
if v == storage:
|
||||
self.exc_editor_app.tools_table_exc.selectRow(int(k) - 1)
|
||||
|
|
|
@ -76,7 +76,9 @@ class BufferSelectionTool(FlatCAMTool):
|
|||
self.buffer_tools_box.addLayout(form_layout)
|
||||
|
||||
# Buffer distance
|
||||
self.buffer_distance_entry = FCEntry()
|
||||
self.buffer_distance_entry = FCDoubleSpinner()
|
||||
self.buffer_distance_entry.set_precision(4)
|
||||
self.buffer_distance_entry.set_range(0.0000, 999999.9999)
|
||||
form_layout.addRow(_("Buffer distance:"), self.buffer_distance_entry)
|
||||
self.buffer_corner_lbl = QtWidgets.QLabel(_("Buffer corner:"))
|
||||
self.buffer_corner_lbl.setToolTip(
|
||||
|
@ -2358,10 +2360,6 @@ class FCSelect(DrawTool):
|
|||
|
||||
def click_release(self, point):
|
||||
|
||||
self.select_shapes(point)
|
||||
return ""
|
||||
|
||||
def select_shapes(self, pos):
|
||||
# list where we store the overlapped shapes under our mouse left click position
|
||||
over_shape_list = []
|
||||
|
||||
|
@ -2381,7 +2379,7 @@ class FCSelect(DrawTool):
|
|||
|
||||
# 3rd method of click selection -> inconvenient
|
||||
try:
|
||||
_, closest_shape = self.storage.nearest(pos)
|
||||
_, closest_shape = self.storage.nearest(point)
|
||||
except StopIteration:
|
||||
return ""
|
||||
|
||||
|
@ -2400,30 +2398,28 @@ class FCSelect(DrawTool):
|
|||
obj_to_add = over_shape_list[int(FlatCAMGeoEditor.draw_shape_idx)]
|
||||
|
||||
key_modifier = QtWidgets.QApplication.keyboardModifiers()
|
||||
if self.draw_app.app.defaults["global_mselect_key"] == 'Control':
|
||||
# if CONTROL key is pressed then we add to the selected list the current shape but if it's already
|
||||
|
||||
if key_modifier == QtCore.Qt.ShiftModifier:
|
||||
mod_key = 'Shift'
|
||||
elif key_modifier == QtCore.Qt.ControlModifier:
|
||||
mod_key = 'Control'
|
||||
else:
|
||||
mod_key = None
|
||||
|
||||
if mod_key == self.draw_app.app.defaults["global_mselect_key"]:
|
||||
# if modifier key is pressed then we add to the selected list the current shape but if it's already
|
||||
# in the selected list, we removed it. Therefore first click selects, second deselects.
|
||||
if key_modifier == Qt.ControlModifier:
|
||||
if obj_to_add in self.draw_app.selected:
|
||||
self.draw_app.selected.remove(obj_to_add)
|
||||
else:
|
||||
self.draw_app.selected.append(obj_to_add)
|
||||
if obj_to_add in self.draw_app.selected:
|
||||
self.draw_app.selected.remove(obj_to_add)
|
||||
else:
|
||||
self.draw_app.selected = []
|
||||
self.draw_app.selected.append(obj_to_add)
|
||||
else:
|
||||
if key_modifier == Qt.ShiftModifier:
|
||||
if obj_to_add in self.draw_app.selected:
|
||||
self.draw_app.selected.remove(obj_to_add)
|
||||
else:
|
||||
self.draw_app.selected.append(obj_to_add)
|
||||
else:
|
||||
self.draw_app.selected = []
|
||||
self.draw_app.selected.append(obj_to_add)
|
||||
|
||||
self.draw_app.selected = []
|
||||
self.draw_app.selected.append(obj_to_add)
|
||||
except Exception as e:
|
||||
log.error("[ERROR] Something went bad. %s" % str(e))
|
||||
raise
|
||||
return ""
|
||||
|
||||
|
||||
class FCMove(FCShapeTool):
|
||||
|
@ -2708,11 +2704,13 @@ class FCBuffer(FCShapeTool):
|
|||
# the cb index start from 0 but the join styles for the buffer start from 1 therefore the adjustment
|
||||
# I populated the combobox such that the index coincide with the join styles value (whcih is really an INT)
|
||||
join_style = self.buff_tool.buffer_corner_cb.currentIndex() + 1
|
||||
self.draw_app.buffer(buffer_distance, join_style)
|
||||
ret_val = self.draw_app.buffer(buffer_distance, join_style)
|
||||
self.app.ui.notebook.setTabText(2, _("Tools"))
|
||||
self.draw_app.app.ui.splitter.setSizes([0, 1])
|
||||
|
||||
self.disactivate()
|
||||
if ret_val == 'fail':
|
||||
return
|
||||
self.draw_app.app.inform.emit(_("[success] Done. Buffer Tool completed."))
|
||||
|
||||
def on_buffer_int(self):
|
||||
|
@ -2734,11 +2732,13 @@ class FCBuffer(FCShapeTool):
|
|||
# the cb index start from 0 but the join styles for the buffer start from 1 therefore the adjustment
|
||||
# I populated the combobox such that the index coincide with the join styles value (whcih is really an INT)
|
||||
join_style = self.buff_tool.buffer_corner_cb.currentIndex() + 1
|
||||
self.draw_app.buffer_int(buffer_distance, join_style)
|
||||
ret_val = self.draw_app.buffer_int(buffer_distance, join_style)
|
||||
self.app.ui.notebook.setTabText(2, _("Tools"))
|
||||
self.draw_app.app.ui.splitter.setSizes([0, 1])
|
||||
|
||||
self.disactivate()
|
||||
if ret_val == 'fail':
|
||||
return
|
||||
self.draw_app.app.inform.emit(_("[success] Done. Buffer Int Tool completed."))
|
||||
|
||||
def on_buffer_ext(self):
|
||||
|
@ -2760,11 +2760,13 @@ class FCBuffer(FCShapeTool):
|
|||
# the cb index start from 0 but the join styles for the buffer start from 1 therefore the adjustment
|
||||
# I populated the combobox such that the index coincide with the join styles value (whcih is really an INT)
|
||||
join_style = self.buff_tool.buffer_corner_cb.currentIndex() + 1
|
||||
self.draw_app.buffer_ext(buffer_distance, join_style)
|
||||
ret_val = self.draw_app.buffer_ext(buffer_distance, join_style)
|
||||
self.app.ui.notebook.setTabText(2, _("Tools"))
|
||||
self.draw_app.app.ui.splitter.setSizes([0, 1])
|
||||
|
||||
self.disactivate()
|
||||
if ret_val == 'fail':
|
||||
return
|
||||
self.draw_app.app.inform.emit(_("[success] Done. Buffer Ext Tool completed."))
|
||||
|
||||
def activate(self):
|
||||
|
@ -2922,9 +2924,9 @@ class FCTransform(FCShapeTool):
|
|||
self.draw_app.transform_tool.run()
|
||||
|
||||
|
||||
# ##################### ##
|
||||
# # ## Main Application # ##
|
||||
# ##################### ##
|
||||
# ###############################################
|
||||
# ################ Main Application #############
|
||||
# ###############################################
|
||||
class FlatCAMGeoEditor(QtCore.QObject):
|
||||
|
||||
transform_complete = QtCore.pyqtSignal()
|
||||
|
@ -4230,11 +4232,11 @@ class FlatCAMGeoEditor(QtCore.QObject):
|
|||
# deselect everything
|
||||
self.selected = []
|
||||
self.replot()
|
||||
return
|
||||
return 'fail'
|
||||
|
||||
if len(selected) == 0:
|
||||
self.app.inform.emit(_("[WARNING_NOTCL] Nothing selected for buffering."))
|
||||
return
|
||||
return 'fail'
|
||||
|
||||
if not isinstance(buf_distance, float):
|
||||
self.app.inform.emit(_("[WARNING_NOTCL] Invalid distance for buffering."))
|
||||
|
@ -4242,17 +4244,32 @@ class FlatCAMGeoEditor(QtCore.QObject):
|
|||
# deselect everything
|
||||
self.selected = []
|
||||
self.replot()
|
||||
return
|
||||
return 'fail'
|
||||
|
||||
pre_buffer = cascaded_union([t.geo for t in selected])
|
||||
results = pre_buffer.buffer(buf_distance - 1e-10, resolution=32, join_style=join_style)
|
||||
if results.is_empty:
|
||||
results = []
|
||||
for t in selected:
|
||||
if isinstance(t.geo, Polygon) and not t.geo.is_empty:
|
||||
results.append((t.geo.exterior).buffer(
|
||||
buf_distance - 1e-10,
|
||||
resolution=int(int(self.app.defaults["geometry_circle_steps"]) / 4),
|
||||
join_style=join_style)
|
||||
)
|
||||
else:
|
||||
results.append(t.geo.buffer(
|
||||
buf_distance - 1e-10,
|
||||
resolution=int(int(self.app.defaults["geometry_circle_steps"]) / 4),
|
||||
join_style=join_style)
|
||||
)
|
||||
|
||||
if not results:
|
||||
self.app.inform.emit(_("[ERROR_NOTCL] Failed, the result is empty. Choose a different buffer value."))
|
||||
# deselect everything
|
||||
self.selected = []
|
||||
self.replot()
|
||||
return
|
||||
self.add_shape(DrawToolShape(results))
|
||||
return 'fail'
|
||||
|
||||
for sha in results:
|
||||
self.add_shape(DrawToolShape(sha))
|
||||
|
||||
self.replot()
|
||||
self.app.inform.emit(_("[success] Full buffer geometry created."))
|
||||
|
@ -4262,77 +4279,48 @@ class FlatCAMGeoEditor(QtCore.QObject):
|
|||
|
||||
if buf_distance < 0:
|
||||
self.app.inform.emit(
|
||||
_("[ERROR_NOTCL] Negative buffer value is not accepted. "
|
||||
"Use Buffer interior to generate an 'inside' shape")
|
||||
_("[ERROR_NOTCL] Negative buffer value is not accepted.")
|
||||
)
|
||||
# deselect everything
|
||||
self.selected = []
|
||||
self.replot()
|
||||
return
|
||||
return 'fail'
|
||||
|
||||
if len(selected) == 0:
|
||||
self.app.inform.emit(_("[WARNING_NOTCL] Nothing selected for buffering."))
|
||||
return
|
||||
return 'fail'
|
||||
|
||||
if not isinstance(buf_distance, float):
|
||||
self.app.inform.emit(_("[WARNING_NOTCL] Invalid distance for buffering."))
|
||||
# deselect everything
|
||||
self.selected = []
|
||||
self.replot()
|
||||
return
|
||||
return 'fail'
|
||||
|
||||
pre_buffer = cascaded_union([t.geo for t in selected])
|
||||
results = pre_buffer.buffer(buf_distance + 1e-10, resolution=32, join_style=join_style)
|
||||
results = []
|
||||
for t in selected:
|
||||
if isinstance(t.geo, LinearRing):
|
||||
t.geo = Polygon(t.geo)
|
||||
|
||||
if results.is_empty:
|
||||
if isinstance(t.geo, Polygon) and not t.geo.is_empty:
|
||||
results.append((t.geo).buffer(
|
||||
-buf_distance + 1e-10,
|
||||
resolution=int(int(self.app.defaults["geometry_circle_steps"]) / 4),
|
||||
join_style=join_style)
|
||||
)
|
||||
|
||||
if not results:
|
||||
self.app.inform.emit(_("[ERROR_NOTCL] Failed, the result is empty. Choose a smaller buffer value."))
|
||||
# deselect everything
|
||||
self.selected = []
|
||||
self.replot()
|
||||
return
|
||||
return 'fail'
|
||||
|
||||
if type(results) == MultiPolygon:
|
||||
for poly in results:
|
||||
for interior in poly.interiors:
|
||||
self.add_shape(DrawToolShape(interior))
|
||||
else:
|
||||
for interior in results:
|
||||
self.add_shape(DrawToolShape(interior))
|
||||
for sha in results:
|
||||
self.add_shape(DrawToolShape(sha))
|
||||
|
||||
self.replot()
|
||||
self.app.inform.emit(_("[success] Interior buffer geometry created."))
|
||||
# selected = self.get_selected()
|
||||
#
|
||||
# if len(selected) == 0:
|
||||
# self.app.inform.emit("[WARNING] Nothing selected for buffering.")
|
||||
# return
|
||||
#
|
||||
# if not isinstance(buf_distance, float):
|
||||
# self.app.inform.emit("[WARNING] Invalid distance for buffering.")
|
||||
# return
|
||||
#
|
||||
# pre_buffer = cascaded_union([t.geo for t in selected])
|
||||
# results = pre_buffer.buffer(buf_distance)
|
||||
# if results.is_empty:
|
||||
# self.app.inform.emit("Failed. Choose a smaller buffer value.")
|
||||
# return
|
||||
#
|
||||
# int_geo = []
|
||||
# if type(results) == MultiPolygon:
|
||||
# for poly in results:
|
||||
# for g in poly.interiors:
|
||||
# int_geo.append(g)
|
||||
# res = cascaded_union(int_geo)
|
||||
# self.add_shape(DrawToolShape(res))
|
||||
# else:
|
||||
# print(results.interiors)
|
||||
# for g in results.interiors:
|
||||
# int_geo.append(g)
|
||||
# res = cascaded_union(int_geo)
|
||||
# self.add_shape(DrawToolShape(res))
|
||||
#
|
||||
# self.replot()
|
||||
# self.app.inform.emit("Interior buffer geometry created.")
|
||||
|
||||
def buffer_ext(self, buf_distance, join_style):
|
||||
selected = self.get_selected()
|
||||
|
@ -4356,19 +4344,27 @@ class FlatCAMGeoEditor(QtCore.QObject):
|
|||
self.replot()
|
||||
return
|
||||
|
||||
pre_buffer = cascaded_union([t.geo for t in selected])
|
||||
results = pre_buffer.buffer(buf_distance - 1e-10, resolution=32, join_style=join_style)
|
||||
if results.is_empty:
|
||||
results = []
|
||||
for t in selected:
|
||||
if isinstance(t.geo, LinearRing):
|
||||
t.geo = Polygon(t.geo)
|
||||
|
||||
if isinstance(t.geo, Polygon) and not t.geo.is_empty:
|
||||
results.append((t.geo).buffer(
|
||||
buf_distance,
|
||||
resolution=int(int(self.app.defaults["geometry_circle_steps"]) / 4),
|
||||
join_style=join_style)
|
||||
)
|
||||
|
||||
if not results:
|
||||
self.app.inform.emit(_("[ERROR_NOTCL] Failed, the result is empty. Choose a different buffer value."))
|
||||
# deselect everything
|
||||
self.selected = []
|
||||
self.replot()
|
||||
return
|
||||
if type(results) == MultiPolygon:
|
||||
for poly in results:
|
||||
self.add_shape(DrawToolShape(poly.exterior))
|
||||
else:
|
||||
self.add_shape(DrawToolShape(results.exterior))
|
||||
|
||||
for sha in results:
|
||||
self.add_shape(DrawToolShape(sha))
|
||||
|
||||
self.replot()
|
||||
self.app.inform.emit(_("[success] Exterior buffer geometry created."))
|
||||
|
|
|
@ -2195,6 +2195,9 @@ class FCApertureSelect(DrawTool):
|
|||
# bending modes using in FCRegion and FCTrack
|
||||
self.draw_app.bend_mode = 1
|
||||
|
||||
# here store the selected apertures
|
||||
self.sel_aperture = set()
|
||||
|
||||
try:
|
||||
self.grb_editor_app.apertures_table.clearSelection()
|
||||
except Exception as e:
|
||||
|
@ -2202,6 +2205,7 @@ class FCApertureSelect(DrawTool):
|
|||
|
||||
self.grb_editor_app.hide_tool('all')
|
||||
self.grb_editor_app.hide_tool('select')
|
||||
self.grb_editor_app.array_frame.hide()
|
||||
|
||||
try:
|
||||
QtGui.QGuiApplication.restoreOverrideCursor()
|
||||
|
@ -2213,42 +2217,47 @@ class FCApertureSelect(DrawTool):
|
|||
|
||||
def click(self, point):
|
||||
key_modifier = QtWidgets.QApplication.keyboardModifiers()
|
||||
if self.grb_editor_app.app.defaults["global_mselect_key"] == 'Control':
|
||||
if key_modifier == Qt.ControlModifier:
|
||||
pass
|
||||
else:
|
||||
self.grb_editor_app.selected = []
|
||||
|
||||
if key_modifier == QtCore.Qt.ShiftModifier:
|
||||
mod_key = 'Shift'
|
||||
elif key_modifier == QtCore.Qt.ControlModifier:
|
||||
mod_key = 'Control'
|
||||
else:
|
||||
if key_modifier == Qt.ShiftModifier:
|
||||
pass
|
||||
else:
|
||||
self.grb_editor_app.selected = []
|
||||
mod_key = None
|
||||
|
||||
if mod_key == self.draw_app.app.defaults["global_mselect_key"]:
|
||||
pass
|
||||
else:
|
||||
self.grb_editor_app.selected = []
|
||||
|
||||
def click_release(self, point):
|
||||
self.grb_editor_app.apertures_table.clearSelection()
|
||||
sel_aperture = set()
|
||||
key_modifier = QtWidgets.QApplication.keyboardModifiers()
|
||||
|
||||
if key_modifier == QtCore.Qt.ShiftModifier:
|
||||
mod_key = 'Shift'
|
||||
elif key_modifier == QtCore.Qt.ControlModifier:
|
||||
mod_key = 'Control'
|
||||
else:
|
||||
mod_key = None
|
||||
|
||||
for storage in self.grb_editor_app.storage_dict:
|
||||
try:
|
||||
for geo_el in self.grb_editor_app.storage_dict[storage]['geometry']:
|
||||
if 'solid' in geo_el.geo:
|
||||
geometric_data = geo_el.geo['solid']
|
||||
if Point(point).within(geometric_data):
|
||||
if (self.grb_editor_app.app.defaults["global_mselect_key"] == 'Control' and
|
||||
key_modifier == Qt.ControlModifier) or \
|
||||
(self.grb_editor_app.app.defaults["global_mselect_key"] == 'Shift' and
|
||||
key_modifier == Qt.ShiftModifier):
|
||||
|
||||
if mod_key == self.grb_editor_app.app.defaults["global_mselect_key"]:
|
||||
if geo_el in self.draw_app.selected:
|
||||
self.draw_app.selected.remove(geo_el)
|
||||
self.sel_aperture.remove(storage)
|
||||
else:
|
||||
# add the object to the selected shapes
|
||||
self.draw_app.selected.append(geo_el)
|
||||
sel_aperture.add(storage)
|
||||
self.sel_aperture.add(storage)
|
||||
else:
|
||||
self.draw_app.selected.append(geo_el)
|
||||
sel_aperture.add(storage)
|
||||
self.sel_aperture.add(storage)
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
|
@ -2259,7 +2268,7 @@ class FCApertureSelect(DrawTool):
|
|||
log.debug("FlatCAMGrbEditor.FCApertureSelect.click_release() --> %s" % str(e))
|
||||
|
||||
self.grb_editor_app.apertures_table.setSelectionMode(QtWidgets.QAbstractItemView.MultiSelection)
|
||||
for aper in sel_aperture:
|
||||
for aper in self.sel_aperture:
|
||||
for row in range(self.grb_editor_app.apertures_table.rowCount()):
|
||||
if str(aper) == self.grb_editor_app.apertures_table.item(row, 1).text():
|
||||
self.grb_editor_app.apertures_table.selectRow(row)
|
||||
|
@ -2345,7 +2354,7 @@ class FlatCAMGrbEditor(QtCore.QObject):
|
|||
# #########################
|
||||
# ### Gerber Apertures ####
|
||||
# #########################
|
||||
self.apertures_table_label = QtWidgets.QLabel(_('<b>Apertures:</b>'))
|
||||
self.apertures_table_label = QtWidgets.QLabel('<b>%s:</b>' % _('Apertures'))
|
||||
self.apertures_table_label.setToolTip(
|
||||
_("Apertures Table for the Gerber Object.")
|
||||
)
|
||||
|
@ -2391,7 +2400,7 @@ class FlatCAMGrbEditor(QtCore.QObject):
|
|||
grid1 = QtWidgets.QGridLayout()
|
||||
self.apertures_box.addLayout(grid1)
|
||||
|
||||
apcode_lbl = QtWidgets.QLabel(_('Aperture Code:'))
|
||||
apcode_lbl = QtWidgets.QLabel('%s:' % _('Aperture Code'))
|
||||
apcode_lbl.setToolTip(
|
||||
_("Code for the new aperture")
|
||||
)
|
||||
|
@ -2401,7 +2410,7 @@ class FlatCAMGrbEditor(QtCore.QObject):
|
|||
self.apcode_entry.setValidator(QtGui.QIntValidator(0, 999))
|
||||
grid1.addWidget(self.apcode_entry, 1, 1)
|
||||
|
||||
apsize_lbl = QtWidgets.QLabel(_('Aperture Size:'))
|
||||
apsize_lbl = QtWidgets.QLabel('%s:' % _('Aperture Size'))
|
||||
apsize_lbl.setToolTip(
|
||||
_("Size for the new aperture.\n"
|
||||
"If aperture type is 'R' or 'O' then\n"
|
||||
|
@ -2415,7 +2424,7 @@ class FlatCAMGrbEditor(QtCore.QObject):
|
|||
self.apsize_entry.setValidator(QtGui.QDoubleValidator(0.0001, 99.9999, 4))
|
||||
grid1.addWidget(self.apsize_entry, 2, 1)
|
||||
|
||||
aptype_lbl = QtWidgets.QLabel(_('Aperture Type:'))
|
||||
aptype_lbl = QtWidgets.QLabel('%s:' % _('Aperture Type'))
|
||||
aptype_lbl.setToolTip(
|
||||
_("Select the type of new aperture. Can be:\n"
|
||||
"C = circular\n"
|
||||
|
@ -2428,7 +2437,7 @@ class FlatCAMGrbEditor(QtCore.QObject):
|
|||
self.aptype_cb.addItems(['C', 'R', 'O'])
|
||||
grid1.addWidget(self.aptype_cb, 3, 1)
|
||||
|
||||
self.apdim_lbl = QtWidgets.QLabel(_('Aperture Dim:'))
|
||||
self.apdim_lbl = QtWidgets.QLabel('%s:' % _('Aperture Dim'))
|
||||
self.apdim_lbl.setToolTip(
|
||||
_("Dimensions for the new aperture.\n"
|
||||
"Active only for rectangular apertures (type R).\n"
|
||||
|
@ -2484,8 +2493,8 @@ class FlatCAMGrbEditor(QtCore.QObject):
|
|||
|
||||
# Buffer distance
|
||||
self.buffer_distance_entry = FCEntry()
|
||||
buf_form_layout.addRow(_("Buffer distance:"), self.buffer_distance_entry)
|
||||
self.buffer_corner_lbl = QtWidgets.QLabel(_("Buffer corner:"))
|
||||
buf_form_layout.addRow('%s:' % _("Buffer distance"), self.buffer_distance_entry)
|
||||
self.buffer_corner_lbl = QtWidgets.QLabel('%s:' % _("Buffer corner"))
|
||||
self.buffer_corner_lbl.setToolTip(
|
||||
_("There are 3 types of corners:\n"
|
||||
" - 'Round': the corner is rounded.\n"
|
||||
|
@ -2517,7 +2526,7 @@ class FlatCAMGrbEditor(QtCore.QObject):
|
|||
self.scale_tool_frame.hide()
|
||||
|
||||
# Title
|
||||
scale_title_lbl = QtWidgets.QLabel('<b>%s</b>' % _('Scale Aperture:'))
|
||||
scale_title_lbl = QtWidgets.QLabel('<b>%s:</b>' % _('Scale Aperture'))
|
||||
scale_title_lbl.setToolTip(
|
||||
_("Scale a aperture in the aperture list")
|
||||
)
|
||||
|
@ -2527,7 +2536,7 @@ class FlatCAMGrbEditor(QtCore.QObject):
|
|||
scale_form_layout = QtWidgets.QFormLayout()
|
||||
self.scale_tools_box.addLayout(scale_form_layout)
|
||||
|
||||
self.scale_factor_lbl = QtWidgets.QLabel(_("Scale factor:"))
|
||||
self.scale_factor_lbl = QtWidgets.QLabel('%s:' % _("Scale factor"))
|
||||
self.scale_factor_lbl.setToolTip(
|
||||
_("The factor by which to scale the selected aperture.\n"
|
||||
"Values can be between 0.0000 and 999.9999")
|
||||
|
@ -2555,7 +2564,7 @@ class FlatCAMGrbEditor(QtCore.QObject):
|
|||
self.ma_tool_frame.hide()
|
||||
|
||||
# Title
|
||||
ma_title_lbl = QtWidgets.QLabel('<b>%s</b>' % _('Mark polygon areas:'))
|
||||
ma_title_lbl = QtWidgets.QLabel('<b>%s:</b>' % _('Mark polygon areas'))
|
||||
ma_title_lbl.setToolTip(
|
||||
_("Mark the polygon areas.")
|
||||
)
|
||||
|
@ -2565,7 +2574,7 @@ class FlatCAMGrbEditor(QtCore.QObject):
|
|||
ma_form_layout = QtWidgets.QFormLayout()
|
||||
self.ma_tools_box.addLayout(ma_form_layout)
|
||||
|
||||
self.ma_upper_threshold_lbl = QtWidgets.QLabel(_("Area UPPER threshold:"))
|
||||
self.ma_upper_threshold_lbl = QtWidgets.QLabel('%s:' % _("Area UPPER threshold"))
|
||||
self.ma_upper_threshold_lbl.setToolTip(
|
||||
_("The threshold value, all areas less than this are marked.\n"
|
||||
"Can have a value between 0.0000 and 9999.9999")
|
||||
|
@ -2573,7 +2582,7 @@ class FlatCAMGrbEditor(QtCore.QObject):
|
|||
self.ma_upper_threshold_entry = FCEntry()
|
||||
self.ma_upper_threshold_entry.setValidator(QtGui.QDoubleValidator(0.0000, 9999.9999, 4))
|
||||
|
||||
self.ma_lower_threshold_lbl = QtWidgets.QLabel(_("Area LOWER threshold:"))
|
||||
self.ma_lower_threshold_lbl = QtWidgets.QLabel('%s:' % _("Area LOWER threshold"))
|
||||
self.ma_lower_threshold_lbl.setToolTip(
|
||||
_("The threshold value, all areas more than this are marked.\n"
|
||||
"Can have a value between 0.0000 and 9999.9999")
|
||||
|
@ -2594,7 +2603,6 @@ class FlatCAMGrbEditor(QtCore.QObject):
|
|||
# ######################
|
||||
# ### Add Pad Array ####
|
||||
# ######################
|
||||
|
||||
# add a frame and inside add a vertical box layout. Inside this vbox layout I add
|
||||
# all the add Pad array widgets
|
||||
# this way I can hide/show the frame
|
||||
|
@ -2627,7 +2635,7 @@ class FlatCAMGrbEditor(QtCore.QObject):
|
|||
self.array_form = QtWidgets.QFormLayout()
|
||||
self.array_box.addLayout(self.array_form)
|
||||
|
||||
self.pad_array_size_label = QtWidgets.QLabel(_('Nr of pads:'))
|
||||
self.pad_array_size_label = QtWidgets.QLabel('%s:' % _('Nr of pads'))
|
||||
self.pad_array_size_label.setToolTip(
|
||||
_("Specify how many pads to be in the array.")
|
||||
)
|
||||
|
@ -2646,7 +2654,7 @@ class FlatCAMGrbEditor(QtCore.QObject):
|
|||
self.linear_form = QtWidgets.QFormLayout()
|
||||
self.linear_box.addLayout(self.linear_form)
|
||||
|
||||
self.pad_axis_label = QtWidgets.QLabel(_('Direction:'))
|
||||
self.pad_axis_label = QtWidgets.QLabel('%s:' % _('Direction'))
|
||||
self.pad_axis_label.setToolTip(
|
||||
_("Direction on which the linear array is oriented:\n"
|
||||
"- 'X' - horizontal axis \n"
|
||||
|
@ -2661,7 +2669,7 @@ class FlatCAMGrbEditor(QtCore.QObject):
|
|||
self.pad_axis_radio.set_value('X')
|
||||
self.linear_form.addRow(self.pad_axis_label, self.pad_axis_radio)
|
||||
|
||||
self.pad_pitch_label = QtWidgets.QLabel(_('Pitch:'))
|
||||
self.pad_pitch_label = QtWidgets.QLabel('%s:' % _('Pitch'))
|
||||
self.pad_pitch_label.setToolTip(
|
||||
_("Pitch = Distance between elements of the array.")
|
||||
)
|
||||
|
@ -2670,7 +2678,7 @@ class FlatCAMGrbEditor(QtCore.QObject):
|
|||
self.pad_pitch_entry = LengthEntry()
|
||||
self.linear_form.addRow(self.pad_pitch_label, self.pad_pitch_entry)
|
||||
|
||||
self.linear_angle_label = QtWidgets.QLabel(_('Angle:'))
|
||||
self.linear_angle_label = QtWidgets.QLabel('%s:' % _('Angle'))
|
||||
self.linear_angle_label.setToolTip(
|
||||
_( "Angle at which the linear array is placed.\n"
|
||||
"The precision is of max 2 decimals.\n"
|
||||
|
@ -2691,7 +2699,7 @@ class FlatCAMGrbEditor(QtCore.QObject):
|
|||
self.circular_box.setContentsMargins(0, 0, 0, 0)
|
||||
self.array_circular_frame.setLayout(self.circular_box)
|
||||
|
||||
self.pad_direction_label = QtWidgets.QLabel(_('Direction:'))
|
||||
self.pad_direction_label = QtWidgets.QLabel('%s:' % _('Direction'))
|
||||
self.pad_direction_label.setToolTip(
|
||||
_("Direction for circular array."
|
||||
"Can be CW = clockwise or CCW = counter clockwise.")
|
||||
|
@ -2706,7 +2714,7 @@ class FlatCAMGrbEditor(QtCore.QObject):
|
|||
self.pad_direction_radio.set_value('CW')
|
||||
self.circular_form.addRow(self.pad_direction_label, self.pad_direction_radio)
|
||||
|
||||
self.pad_angle_label = QtWidgets.QLabel(_('Angle:'))
|
||||
self.pad_angle_label = QtWidgets.QLabel('%s:' % _('Angle'))
|
||||
self.pad_angle_label.setToolTip(
|
||||
_("Angle at which each element in circular array is placed.")
|
||||
)
|
||||
|
@ -2944,23 +2952,24 @@ class FlatCAMGrbEditor(QtCore.QObject):
|
|||
self.tool2tooldia[i + 1] = tt_aperture
|
||||
|
||||
# Init GUI
|
||||
if self.units == 'MM':
|
||||
self.buffer_distance_entry.set_value(0.01)
|
||||
self.scale_factor_entry.set_value(1.0)
|
||||
self.ma_upper_threshold_entry.set_value(1.0)
|
||||
self.apsize_entry.set_value(1.00)
|
||||
else:
|
||||
self.buffer_distance_entry.set_value(0.0003937)
|
||||
self.scale_factor_entry.set_value(0.03937)
|
||||
self.ma_upper_threshold_entry.set_value(0.00155)
|
||||
self.apsize_entry.set_value(0.039)
|
||||
self.ma_lower_threshold_entry.set_value(0.0)
|
||||
|
||||
self.pad_array_size_entry.set_value(5)
|
||||
self.pad_pitch_entry.set_value(2.54)
|
||||
self.pad_angle_entry.set_value(12)
|
||||
self.pad_direction_radio.set_value('CW')
|
||||
self.pad_axis_radio.set_value('X')
|
||||
self.buffer_distance_entry.set_value(self.app.defaults["gerber_editor_buff_f"])
|
||||
self.scale_factor_entry.set_value(self.app.defaults["gerber_editor_scale_f"])
|
||||
self.ma_upper_threshold_entry.set_value(self.app.defaults["gerber_editor_ma_low"])
|
||||
self.ma_lower_threshold_entry.set_value(self.app.defaults["gerber_editor_ma_high"])
|
||||
|
||||
self.apsize_entry.set_value(self.app.defaults["gerber_editor_newsize"])
|
||||
self.aptype_cb.set_value(self.app.defaults["gerber_editor_newtype"])
|
||||
self.apdim_entry.set_value(self.app.defaults["gerber_editor_newdim"])
|
||||
|
||||
self.pad_array_size_entry.set_value(self.app.defaults["gerber_editor_array_size"])
|
||||
# linear array
|
||||
self.pad_axis_radio.set_value(self.app.defaults["gerber_editor_lin_axis"])
|
||||
self.pad_pitch_entry.set_value(self.app.defaults["gerber_editor_lin_pitch"])
|
||||
self.linear_angle_spinner.set_value(self.app.defaults["gerber_editor_lin_angle"])
|
||||
# circular array
|
||||
self.pad_direction_radio.set_value(self.app.defaults["gerber_editor_circ_dir"])
|
||||
self.pad_angle_entry.set_value(self.app.defaults["gerber_editor_circ_angle"])
|
||||
|
||||
def build_ui(self, first_run=None):
|
||||
|
||||
|
@ -3113,7 +3122,7 @@ class FlatCAMGrbEditor(QtCore.QObject):
|
|||
self.apcode_entry.set_value(max(self.tool2tooldia.values()) + 1)
|
||||
except ValueError:
|
||||
# this means that the edited object has no apertures so we start with 10 (Gerber specifications)
|
||||
self.apcode_entry.set_value(10)
|
||||
self.apcode_entry.set_value(self.app.defaults["gerber_editor_newcode"])
|
||||
|
||||
def on_aperture_add(self, apid=None):
|
||||
self.is_modified = True
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -171,9 +171,11 @@ class LengthEntry(QtWidgets.QLineEdit):
|
|||
self.readyToEdit = False
|
||||
|
||||
def focusOutEvent(self, e):
|
||||
super(LengthEntry, self).focusOutEvent(e) # required to remove cursor on focusOut
|
||||
self.deselect()
|
||||
self.readyToEdit = True
|
||||
# don't focus out if the user requests an popup menu
|
||||
if e.reason() != QtCore.Qt.PopupFocusReason:
|
||||
super(LengthEntry, self).focusOutEvent(e) # required to remove cursor on focusOut
|
||||
self.deselect()
|
||||
self.readyToEdit = True
|
||||
|
||||
def returnPressed(self, *args, **kwargs):
|
||||
val = self.get_value()
|
||||
|
@ -225,9 +227,11 @@ class FloatEntry(QtWidgets.QLineEdit):
|
|||
self.readyToEdit = False
|
||||
|
||||
def focusOutEvent(self, e):
|
||||
super(FloatEntry, self).focusOutEvent(e) # required to remove cursor on focusOut
|
||||
self.deselect()
|
||||
self.readyToEdit = True
|
||||
# don't focus out if the user requests an popup menu
|
||||
if e.reason() != QtCore.Qt.PopupFocusReason:
|
||||
super(FloatEntry, self).focusOutEvent(e) # required to remove cursor on focusOut
|
||||
self.deselect()
|
||||
self.readyToEdit = True
|
||||
|
||||
def returnPressed(self, *args, **kwargs):
|
||||
val = self.get_value()
|
||||
|
@ -274,9 +278,11 @@ class FloatEntry2(QtWidgets.QLineEdit):
|
|||
self.readyToEdit = False
|
||||
|
||||
def focusOutEvent(self, e):
|
||||
super(FloatEntry2, self).focusOutEvent(e) # required to remove cursor on focusOut
|
||||
self.deselect()
|
||||
self.readyToEdit = True
|
||||
# don't focus out if the user requests an popup menu
|
||||
if e.reason() != QtCore.Qt.PopupFocusReason:
|
||||
super(FloatEntry2, self).focusOutEvent(e) # required to remove cursor on focusOut
|
||||
self.deselect()
|
||||
self.readyToEdit = True
|
||||
|
||||
def get_value(self):
|
||||
raw = str(self.text()).strip(' ')
|
||||
|
@ -316,9 +322,11 @@ class IntEntry(QtWidgets.QLineEdit):
|
|||
self.readyToEdit = False
|
||||
|
||||
def focusOutEvent(self, e):
|
||||
super(IntEntry, self).focusOutEvent(e) # required to remove cursor on focusOut
|
||||
self.deselect()
|
||||
self.readyToEdit = True
|
||||
# don't focus out if the user requests an popup menu
|
||||
if e.reason() != QtCore.Qt.PopupFocusReason:
|
||||
super(IntEntry, self).focusOutEvent(e) # required to remove cursor on focusOut
|
||||
self.deselect()
|
||||
self.readyToEdit = True
|
||||
|
||||
def get_value(self):
|
||||
|
||||
|
@ -353,16 +361,17 @@ class FCEntry(QtWidgets.QLineEdit):
|
|||
def on_edit_finished(self):
|
||||
self.clearFocus()
|
||||
|
||||
def mousePressEvent(self, e, Parent=None):
|
||||
def mousePressEvent(self, e, parent=None):
|
||||
super(FCEntry, self).mousePressEvent(e) # required to deselect on 2e click
|
||||
if self.readyToEdit:
|
||||
self.selectAll()
|
||||
self.readyToEdit = False
|
||||
|
||||
def focusOutEvent(self, e):
|
||||
super(FCEntry, self).focusOutEvent(e) # required to remove cursor on focusOut
|
||||
self.deselect()
|
||||
self.readyToEdit = True
|
||||
if e.reason() != QtCore.Qt.PopupFocusReason:
|
||||
super(FCEntry, self).focusOutEvent(e) # required to remove cursor on focusOut
|
||||
self.deselect()
|
||||
self.readyToEdit = True
|
||||
|
||||
def get_value(self):
|
||||
return str(self.text())
|
||||
|
@ -381,36 +390,24 @@ class FCEntry(QtWidgets.QLineEdit):
|
|||
class FCEntry2(FCEntry):
|
||||
def __init__(self, parent=None):
|
||||
super(FCEntry2, self).__init__(parent)
|
||||
self.readyToEdit = True
|
||||
self.editingFinished.connect(self.on_edit_finished)
|
||||
|
||||
def on_edit_finished(self):
|
||||
self.clearFocus()
|
||||
|
||||
def set_value(self, val, decimals=4):
|
||||
try:
|
||||
fval = float(val)
|
||||
except ValueError:
|
||||
return
|
||||
|
||||
self.setText('%.*f' % (decimals, fval))
|
||||
|
||||
|
||||
class FCEntry3(FCEntry):
|
||||
def __init__(self, parent=None):
|
||||
super(FCEntry3, self).__init__(parent)
|
||||
self.readyToEdit = True
|
||||
self.editingFinished.connect(self.on_edit_finished)
|
||||
|
||||
def on_edit_finished(self):
|
||||
self.clearFocus()
|
||||
|
||||
def set_value(self, val, decimals=4):
|
||||
try:
|
||||
fval = float(val)
|
||||
except ValueError:
|
||||
return
|
||||
|
||||
self.setText('%.*f' % (decimals, fval))
|
||||
|
||||
def get_value(self):
|
||||
|
@ -432,16 +429,17 @@ class EvalEntry(QtWidgets.QLineEdit):
|
|||
def on_edit_finished(self):
|
||||
self.clearFocus()
|
||||
|
||||
def mousePressEvent(self, e, Parent=None):
|
||||
def mousePressEvent(self, e, parent=None):
|
||||
super(EvalEntry, self).mousePressEvent(e) # required to deselect on 2e click
|
||||
if self.readyToEdit:
|
||||
self.selectAll()
|
||||
self.readyToEdit = False
|
||||
|
||||
def focusOutEvent(self, e):
|
||||
super(EvalEntry, self).focusOutEvent(e) # required to remove cursor on focusOut
|
||||
self.deselect()
|
||||
self.readyToEdit = True
|
||||
if e.reason() != QtCore.Qt.PopupFocusReason:
|
||||
super(EvalEntry, self).focusOutEvent(e) # required to remove cursor on focusOut
|
||||
self.deselect()
|
||||
self.readyToEdit = True
|
||||
|
||||
def returnPressed(self, *args, **kwargs):
|
||||
val = self.get_value()
|
||||
|
@ -478,16 +476,17 @@ class EvalEntry2(QtWidgets.QLineEdit):
|
|||
def on_edit_finished(self):
|
||||
self.clearFocus()
|
||||
|
||||
def mousePressEvent(self, e, Parent=None):
|
||||
def mousePressEvent(self, e, parent=None):
|
||||
super(EvalEntry2, self).mousePressEvent(e) # required to deselect on 2e click
|
||||
if self.readyToEdit:
|
||||
self.selectAll()
|
||||
self.readyToEdit = False
|
||||
|
||||
def focusOutEvent(self, e):
|
||||
super(EvalEntry2, self).focusOutEvent(e) # required to remove cursor on focusOut
|
||||
self.deselect()
|
||||
self.readyToEdit = True
|
||||
if e.reason() != QtCore.Qt.PopupFocusReason:
|
||||
super(EvalEntry2, self).focusOutEvent(e) # required to remove cursor on focusOut
|
||||
self.deselect()
|
||||
self.readyToEdit = True
|
||||
|
||||
def get_value(self):
|
||||
raw = str(self.text()).strip(' ')
|
||||
|
@ -847,9 +846,9 @@ class FCDetachableTab(QtWidgets.QTabWidget):
|
|||
super().__init__()
|
||||
|
||||
self.tabBar = self.FCTabBar(self)
|
||||
self.tabBar.onDetachTabSignal.connect(self.detachTab)
|
||||
self.tabBar.onMoveTabSignal.connect(self.moveTab)
|
||||
self.tabBar.detachedTabDropSignal.connect(self.detachedTabDrop)
|
||||
self.set_detachable(val=True)
|
||||
|
||||
self.setTabBar(self.tabBar)
|
||||
|
||||
|
@ -872,6 +871,48 @@ class FCDetachableTab(QtWidgets.QTabWidget):
|
|||
self.setTabsClosable(True)
|
||||
self.tabCloseRequested.connect(self.closeTab)
|
||||
|
||||
def set_rmb_callback(self, callback):
|
||||
"""
|
||||
|
||||
:param callback: Function to call on right mouse click on tab
|
||||
:type callback: func
|
||||
:return: None
|
||||
"""
|
||||
|
||||
self.tabBar.right_click.connect(callback)
|
||||
|
||||
def set_detachable(self, val=True):
|
||||
try:
|
||||
self.tabBar.onDetachTabSignal.disconnect()
|
||||
except TypeError:
|
||||
pass
|
||||
|
||||
if val is True:
|
||||
self.tabBar.onDetachTabSignal.connect(self.detachTab)
|
||||
# the tab can be moved around
|
||||
self.tabBar.can_be_dragged = True
|
||||
else:
|
||||
# the detached tab can't be moved
|
||||
self.tabBar.can_be_dragged = False
|
||||
|
||||
return val
|
||||
|
||||
def setupContextMenu(self):
|
||||
self.setContextMenuPolicy(QtCore.Qt.ActionsContextMenu)
|
||||
|
||||
def addContextMenu(self, entry, call_function, icon=None, initial_checked=False):
|
||||
action_name = str(entry)
|
||||
action = QtWidgets.QAction(self)
|
||||
action.setCheckable(True)
|
||||
action.setText(action_name)
|
||||
if icon:
|
||||
assert isinstance(icon, QtGui.QIcon), \
|
||||
"Expected the argument to be QtGui.QIcon. Instead it is %s" % type(icon)
|
||||
action.setIcon(icon)
|
||||
action.setChecked(initial_checked)
|
||||
self.addAction(action)
|
||||
action.triggered.connect(call_function)
|
||||
|
||||
def useOldIndex(self, param):
|
||||
if param:
|
||||
self.use_old_index = True
|
||||
|
@ -1209,6 +1250,8 @@ class FCDetachableTab(QtWidgets.QTabWidget):
|
|||
onMoveTabSignal = pyqtSignal(int, int)
|
||||
detachedTabDropSignal = pyqtSignal(str, int, QtCore.QPoint)
|
||||
|
||||
right_click = pyqtSignal(int)
|
||||
|
||||
def __init__(self, parent=None):
|
||||
QtWidgets.QTabBar.__init__(self, parent)
|
||||
|
||||
|
@ -1216,11 +1259,16 @@ class FCDetachableTab(QtWidgets.QTabWidget):
|
|||
self.setElideMode(QtCore.Qt.ElideRight)
|
||||
self.setSelectionBehaviorOnRemove(QtWidgets.QTabBar.SelectLeftTab)
|
||||
|
||||
self.prev_index = -1
|
||||
|
||||
self.dragStartPos = QtCore.QPoint()
|
||||
self.dragDropedPos = QtCore.QPoint()
|
||||
self.mouseCursor = QtGui.QCursor()
|
||||
self.dragInitiated = False
|
||||
|
||||
# set this to False and the tab will no longer be displayed as detached
|
||||
self.can_be_dragged = True
|
||||
|
||||
def mouseDoubleClickEvent(self, event):
|
||||
"""
|
||||
Send the onDetachTabSignal when a tab is double clicked
|
||||
|
@ -1234,21 +1282,37 @@ class FCDetachableTab(QtWidgets.QTabWidget):
|
|||
|
||||
def mousePressEvent(self, event):
|
||||
"""
|
||||
Set the starting position for a drag event when the mouse button is pressed
|
||||
Set the starting position for a drag event when the left mouse button is pressed.
|
||||
Start detection of a right mouse click.
|
||||
|
||||
:param event: a mouse press event
|
||||
:return:
|
||||
"""
|
||||
if event.button() == QtCore.Qt.LeftButton:
|
||||
self.dragStartPos = event.pos()
|
||||
elif event.button() == QtCore.Qt.RightButton:
|
||||
self.prev_index = self.tabAt(event.pos())
|
||||
|
||||
self.dragDropedPos.setX(0)
|
||||
self.dragDropedPos.setY(0)
|
||||
|
||||
self.dragInitiated = False
|
||||
|
||||
QtWidgets.QTabBar.mousePressEvent(self, event)
|
||||
|
||||
def mouseReleaseEvent(self, event):
|
||||
"""
|
||||
Finish the detection of the right mouse click on the tab
|
||||
|
||||
|
||||
:param event: a mouse press event
|
||||
:return:
|
||||
"""
|
||||
if event.button() == QtCore.Qt.RightButton and self.prev_index == self.tabAt(event.pos()):
|
||||
self.right_click.emit(self.prev_index)
|
||||
self.prev_index = -1
|
||||
|
||||
QtWidgets.QTabBar.mouseReleaseEvent(self, event)
|
||||
|
||||
def mouseMoveEvent(self, event):
|
||||
"""
|
||||
Determine if the current movement is a drag. If it is, convert it into a QDrag. If the
|
||||
|
@ -1264,7 +1328,7 @@ class FCDetachableTab(QtWidgets.QTabWidget):
|
|||
self.dragInitiated = True
|
||||
|
||||
# If the current movement is a drag initiated by the left button
|
||||
if (((event.buttons() & QtCore.Qt.LeftButton)) and self.dragInitiated):
|
||||
if (((event.buttons() & QtCore.Qt.LeftButton)) and self.dragInitiated and self.can_be_dragged):
|
||||
|
||||
# Stop the move event
|
||||
finishMoveEvent = QtGui.QMouseEvent(
|
||||
|
@ -1561,9 +1625,11 @@ class FCSpinner(QtWidgets.QSpinBox):
|
|||
self.readyToEdit = False
|
||||
|
||||
def focusOutEvent(self, e):
|
||||
super(FCSpinner, self).focusOutEvent(e) # required to remove cursor on focusOut
|
||||
self.lineEdit().deselect()
|
||||
self.readyToEdit = True
|
||||
# don't focus out if the user requests an popup menu
|
||||
if e.reason() != QtCore.Qt.PopupFocusReason:
|
||||
super(FCSpinner, self).focusOutEvent(e) # required to remove cursor on focusOut
|
||||
self.lineEdit().deselect()
|
||||
self.readyToEdit = True
|
||||
|
||||
def get_value(self):
|
||||
return str(self.value())
|
||||
|
@ -1600,9 +1666,11 @@ class FCDoubleSpinner(QtWidgets.QDoubleSpinBox):
|
|||
self.readyToEdit = False
|
||||
|
||||
def focusOutEvent(self, e):
|
||||
super(FCDoubleSpinner, self).focusOutEvent(e) # required to remove cursor on focusOut
|
||||
self.lineEdit().deselect()
|
||||
self.readyToEdit = True
|
||||
# don't focus out if the user requests an popup menu
|
||||
if e.reason() != QtCore.Qt.PopupFocusReason:
|
||||
super(FCDoubleSpinner, self).focusOutEvent(e) # required to remove cursor on focusOut
|
||||
self.lineEdit().deselect()
|
||||
self.readyToEdit = True
|
||||
|
||||
def get_value(self):
|
||||
return str(self.value())
|
||||
|
@ -1647,9 +1715,11 @@ class Dialog_box(QtWidgets.QWidget):
|
|||
self.readyToEdit = False
|
||||
|
||||
def focusOutEvent(self, e):
|
||||
super(Dialog_box, self).focusOutEvent(e) # required to remove cursor on focusOut
|
||||
self.lineEdit().deselect()
|
||||
self.readyToEdit = True
|
||||
# don't focus out if the user requests an popup menu
|
||||
if e.reason() != QtCore.Qt.PopupFocusReason:
|
||||
super(Dialog_box, self).focusOutEvent(e) # required to remove cursor on focusOut
|
||||
self.lineEdit().deselect()
|
||||
self.readyToEdit = True
|
||||
|
||||
|
||||
class _BrowserTextEdit(QTextEdit):
|
||||
|
@ -1811,9 +1881,16 @@ class MyCompleter(QCompleter):
|
|||
QCompleter.__init__(self)
|
||||
self.setCompletionMode(QCompleter.PopupCompletion)
|
||||
self.highlighted.connect(self.setHighlighted)
|
||||
# self.popup().installEventFilter(self)
|
||||
|
||||
# def eventFilter(self, obj, event):
|
||||
# if event.type() == QtCore.QEvent.Wheel and obj is self.popup():
|
||||
# pass
|
||||
# return False
|
||||
|
||||
def setHighlighted(self, text):
|
||||
self.lastSelected = text
|
||||
|
||||
def getSelected(self):
|
||||
return self.lastSelected
|
||||
|
||||
|
|
|
@ -76,7 +76,7 @@ class ObjectUI(QtWidgets.QWidget):
|
|||
# ###########################
|
||||
|
||||
# ### Scale ####
|
||||
self.scale_label = QtWidgets.QLabel(_('<b>Scale:</b>'))
|
||||
self.scale_label = QtWidgets.QLabel('<b>%s:</b>' % _('Scale'))
|
||||
self.scale_label.setToolTip(
|
||||
_("Change the size of the object.")
|
||||
)
|
||||
|
@ -86,7 +86,7 @@ class ObjectUI(QtWidgets.QWidget):
|
|||
layout.addLayout(self.scale_grid)
|
||||
|
||||
# Factor
|
||||
faclabel = QtWidgets.QLabel(_('Factor:'))
|
||||
faclabel = QtWidgets.QLabel('%s:' % _('Factor'))
|
||||
faclabel.setToolTip(
|
||||
_("Factor by which to multiply\n"
|
||||
"geometric features of this object.")
|
||||
|
@ -105,7 +105,7 @@ class ObjectUI(QtWidgets.QWidget):
|
|||
self.scale_grid.addWidget(self.scale_button, 0, 2)
|
||||
|
||||
# ### Offset ####
|
||||
self.offset_label = QtWidgets.QLabel(_('<b>Offset:</b>'))
|
||||
self.offset_label = QtWidgets.QLabel('<b>%s:</b>' % _('Offset'))
|
||||
self.offset_label.setToolTip(
|
||||
_("Change the position of this object.")
|
||||
)
|
||||
|
@ -114,7 +114,7 @@ class ObjectUI(QtWidgets.QWidget):
|
|||
self.offset_grid = QtWidgets.QGridLayout()
|
||||
layout.addLayout(self.offset_grid)
|
||||
|
||||
self.offset_vectorlabel = QtWidgets.QLabel(_('Vector:'))
|
||||
self.offset_vectorlabel = QtWidgets.QLabel('%s:' % _('Vector'))
|
||||
self.offset_vectorlabel.setToolTip(
|
||||
_("Amount by which to move the object\n"
|
||||
"in the x and y axes in (x, y) format.")
|
||||
|
@ -147,7 +147,7 @@ class GerberObjectUI(ObjectUI):
|
|||
grid0.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter)
|
||||
self.custom_box.addLayout(grid0)
|
||||
|
||||
self.plot_options_label = QtWidgets.QLabel(_("<b>Plot Options:</b>"))
|
||||
self.plot_options_label = QtWidgets.QLabel("<b>%s:</b>" % _("Plot Options"))
|
||||
self.plot_options_label.setMinimumWidth(90)
|
||||
|
||||
grid0.addWidget(self.plot_options_label, 0, 0)
|
||||
|
@ -179,7 +179,7 @@ class GerberObjectUI(ObjectUI):
|
|||
# ## Object name
|
||||
self.name_hlay = QtWidgets.QHBoxLayout()
|
||||
self.custom_box.addLayout(self.name_hlay)
|
||||
name_label = QtWidgets.QLabel(_("<b>Name:</b>"))
|
||||
name_label = QtWidgets.QLabel("<b>%s:</b>" % _("Name"))
|
||||
self.name_entry = FCEntry()
|
||||
self.name_entry.setFocusPolicy(QtCore.Qt.StrongFocus)
|
||||
self.name_hlay.addWidget(name_label)
|
||||
|
@ -189,7 +189,7 @@ class GerberObjectUI(ObjectUI):
|
|||
self.custom_box.addLayout(hlay_plot)
|
||||
|
||||
# ### Gerber Apertures ####
|
||||
self.apertures_table_label = QtWidgets.QLabel(_('<b>Apertures:</b>'))
|
||||
self.apertures_table_label = QtWidgets.QLabel('<b>%s:</b>' % _('Apertures'))
|
||||
self.apertures_table_label.setToolTip(
|
||||
_("Apertures Table for the Gerber Object.")
|
||||
)
|
||||
|
@ -247,7 +247,7 @@ class GerberObjectUI(ObjectUI):
|
|||
self.apertures_table.setVisible(False)
|
||||
|
||||
# Isolation Routing
|
||||
self.isolation_routing_label = QtWidgets.QLabel(_("<b>Isolation Routing:</b>"))
|
||||
self.isolation_routing_label = QtWidgets.QLabel("<b>%s:</b>" % _("Isolation Routing"))
|
||||
self.isolation_routing_label.setToolTip(
|
||||
_("Create a Geometry object with\n"
|
||||
"toolpaths to cut outside polygons.")
|
||||
|
@ -256,7 +256,7 @@ class GerberObjectUI(ObjectUI):
|
|||
|
||||
grid1 = QtWidgets.QGridLayout()
|
||||
self.custom_box.addLayout(grid1)
|
||||
tdlabel = QtWidgets.QLabel(_('Tool dia:'))
|
||||
tdlabel = QtWidgets.QLabel('%s:' % _('Tool dia'))
|
||||
tdlabel.setToolTip(
|
||||
_("Diameter of the cutting tool.\n"
|
||||
"If you want to have an isolation path\n"
|
||||
|
@ -269,7 +269,7 @@ class GerberObjectUI(ObjectUI):
|
|||
self.iso_tool_dia_entry = LengthEntry()
|
||||
grid1.addWidget(self.iso_tool_dia_entry, 0, 1)
|
||||
|
||||
passlabel = QtWidgets.QLabel(_('Passes:'))
|
||||
passlabel = QtWidgets.QLabel('%s:' % _('# Passes'))
|
||||
passlabel.setToolTip(
|
||||
_("Width of the isolation gap in\n"
|
||||
"number (integer) of tool widths.")
|
||||
|
@ -280,7 +280,7 @@ class GerberObjectUI(ObjectUI):
|
|||
self.iso_width_entry.setRange(1, 999)
|
||||
grid1.addWidget(self.iso_width_entry, 1, 1)
|
||||
|
||||
overlabel = QtWidgets.QLabel(_('Pass overlap:'))
|
||||
overlabel = QtWidgets.QLabel('%s:' % _('Pass overlap'))
|
||||
overlabel.setToolTip(
|
||||
_("How much (fraction) of the tool width to overlap each tool pass.\n"
|
||||
"Example:\n"
|
||||
|
@ -292,7 +292,7 @@ class GerberObjectUI(ObjectUI):
|
|||
grid1.addWidget(self.iso_overlap_entry, 2, 1)
|
||||
|
||||
# Milling Type Radio Button
|
||||
self.milling_type_label = QtWidgets.QLabel(_('Milling Type:'))
|
||||
self.milling_type_label = QtWidgets.QLabel('%s:' % _('Milling Type'))
|
||||
self.milling_type_label.setToolTip(
|
||||
_("Milling type:\n"
|
||||
"- climb / best for precision milling and to reduce tool usage\n"
|
||||
|
@ -304,7 +304,7 @@ class GerberObjectUI(ObjectUI):
|
|||
grid1.addWidget(self.milling_type_radio, 3, 1)
|
||||
|
||||
# combine all passes CB
|
||||
self.combine_passes_cb = FCCheckBox(label=_('Combine'))
|
||||
self.combine_passes_cb = FCCheckBox(label=_('Combine Passes'))
|
||||
self.combine_passes_cb.setToolTip(
|
||||
_("Combine all passes into one object")
|
||||
)
|
||||
|
@ -320,7 +320,7 @@ class GerberObjectUI(ObjectUI):
|
|||
)
|
||||
grid1.addWidget(self.follow_cb, 4, 1)
|
||||
|
||||
self.gen_iso_label = QtWidgets.QLabel(_("<b>Generate Isolation Geometry:</b>"))
|
||||
self.gen_iso_label = QtWidgets.QLabel("<b>%s:</b>" % _("Generate Isolation Geometry"))
|
||||
self.gen_iso_label.setToolTip(
|
||||
_("Create a Geometry object with toolpaths to cut \n"
|
||||
"isolation outside, inside or on both sides of the\n"
|
||||
|
@ -379,7 +379,7 @@ class GerberObjectUI(ObjectUI):
|
|||
self.custom_box.addLayout(grid2)
|
||||
|
||||
# ## Clear non-copper regions
|
||||
self.clearcopper_label = QtWidgets.QLabel(_("<b>Clear N-copper:</b>"))
|
||||
self.clearcopper_label = QtWidgets.QLabel("<b>%s:</b>" % _("Clear N-copper"))
|
||||
self.clearcopper_label.setToolTip(
|
||||
_("Create a Geometry object with\n"
|
||||
"toolpaths to cut all non-copper regions.")
|
||||
|
@ -395,7 +395,7 @@ class GerberObjectUI(ObjectUI):
|
|||
grid2.addWidget(self.generate_ncc_button, 0, 1)
|
||||
|
||||
# ## Board cutout
|
||||
self.board_cutout_label = QtWidgets.QLabel(_("<b>Board cutout:</b>"))
|
||||
self.board_cutout_label = QtWidgets.QLabel("<b>%s:</b>" % _("Board cutout"))
|
||||
self.board_cutout_label.setToolTip(
|
||||
_("Create toolpaths to cut around\n"
|
||||
"the PCB and separate it from\n"
|
||||
|
@ -411,7 +411,7 @@ class GerberObjectUI(ObjectUI):
|
|||
grid2.addWidget(self.generate_cutout_button, 1, 1)
|
||||
|
||||
# ## Non-copper regions
|
||||
self.noncopper_label = QtWidgets.QLabel(_("<b>Non-copper regions:</b>"))
|
||||
self.noncopper_label = QtWidgets.QLabel("<b>%s:</b>" % _("Non-copper regions"))
|
||||
self.noncopper_label.setToolTip(
|
||||
_("Create polygons covering the\n"
|
||||
"areas without copper on the PCB.\n"
|
||||
|
@ -425,7 +425,7 @@ class GerberObjectUI(ObjectUI):
|
|||
self.custom_box.addLayout(grid4)
|
||||
|
||||
# Margin
|
||||
bmlabel = QtWidgets.QLabel(_('Boundary Margin:'))
|
||||
bmlabel = QtWidgets.QLabel('%s:' % _('Boundary Margin'))
|
||||
bmlabel.setToolTip(
|
||||
_("Specify the edge of the PCB\n"
|
||||
"by drawing a box around all\n"
|
||||
|
@ -449,7 +449,7 @@ class GerberObjectUI(ObjectUI):
|
|||
grid4.addWidget(self.generate_noncopper_button, 1, 1)
|
||||
|
||||
# ## Bounding box
|
||||
self.boundingbox_label = QtWidgets.QLabel(_('<b>Bounding Box:</b>'))
|
||||
self.boundingbox_label = QtWidgets.QLabel('<b>%s:</b>' % _('Bounding Box'))
|
||||
self.boundingbox_label.setToolTip(
|
||||
_("Create a geometry surrounding the Gerber object.\n"
|
||||
"Square shape.")
|
||||
|
@ -459,7 +459,7 @@ class GerberObjectUI(ObjectUI):
|
|||
grid5 = QtWidgets.QGridLayout()
|
||||
self.custom_box.addLayout(grid5)
|
||||
|
||||
bbmargin = QtWidgets.QLabel(_('Boundary Margin:'))
|
||||
bbmargin = QtWidgets.QLabel('%s:' % _('Boundary Margin'))
|
||||
bbmargin.setToolTip(
|
||||
_("Distance of the edges of the box\n"
|
||||
"to the nearest polygon.")
|
||||
|
@ -500,7 +500,7 @@ class ExcellonObjectUI(ObjectUI):
|
|||
hlay_plot = QtWidgets.QHBoxLayout()
|
||||
self.custom_box.addLayout(hlay_plot)
|
||||
|
||||
self.plot_options_label = QtWidgets.QLabel(_("<b>Plot Options:</b>"))
|
||||
self.plot_options_label = QtWidgets.QLabel("<b>%s:</b>" % _("Plot Options"))
|
||||
self.solid_cb = FCCheckBox(label=_('Solid'))
|
||||
self.solid_cb.setToolTip(
|
||||
_("Solid circles.")
|
||||
|
@ -512,7 +512,7 @@ class ExcellonObjectUI(ObjectUI):
|
|||
# ## Object name
|
||||
self.name_hlay = QtWidgets.QHBoxLayout()
|
||||
self.custom_box.addLayout(self.name_hlay)
|
||||
name_label = QtWidgets.QLabel(_("<b>Name:</b>"))
|
||||
name_label = QtWidgets.QLabel("<b>%s:</b>" % _("Name"))
|
||||
self.name_entry = FCEntry()
|
||||
self.name_entry.setFocusPolicy(QtCore.Qt.StrongFocus)
|
||||
self.name_hlay.addWidget(name_label)
|
||||
|
@ -531,7 +531,7 @@ class ExcellonObjectUI(ObjectUI):
|
|||
self.tools_box.addLayout(hlay_plot)
|
||||
|
||||
# ### Tools Drills ####
|
||||
self.tools_table_label = QtWidgets.QLabel(_('<b>Tools Table</b>'))
|
||||
self.tools_table_label = QtWidgets.QLabel('<b>%s:</b>' % _('Tools Table'))
|
||||
self.tools_table_label.setToolTip(
|
||||
_("Tools in this Excellon object\n"
|
||||
"when are used for drilling.")
|
||||
|
@ -539,7 +539,7 @@ class ExcellonObjectUI(ObjectUI):
|
|||
hlay_plot.addWidget(self.tools_table_label)
|
||||
|
||||
# Plot CB
|
||||
self.plot_cb = FCCheckBox(_('Plot Object'))
|
||||
self.plot_cb = FCCheckBox(_('Plot'))
|
||||
self.plot_cb.setToolTip(
|
||||
_("Plot (show) this object.")
|
||||
)
|
||||
|
@ -579,7 +579,7 @@ class ExcellonObjectUI(ObjectUI):
|
|||
self.tools_box.addWidget(self.empty_label)
|
||||
|
||||
# ### Create CNC Job ####
|
||||
self.cncjob_label = QtWidgets.QLabel(_('<b>Create CNC Job</b>'))
|
||||
self.cncjob_label = QtWidgets.QLabel('<b>%s</b>' % _('Create CNC Job'))
|
||||
self.cncjob_label.setToolTip(
|
||||
_("Create a CNC Job object\n"
|
||||
"for this drill object.")
|
||||
|
@ -590,7 +590,7 @@ class ExcellonObjectUI(ObjectUI):
|
|||
self.tools_box.addLayout(grid1)
|
||||
|
||||
# Cut Z
|
||||
cutzlabel = QtWidgets.QLabel(_('Cut Z:'))
|
||||
cutzlabel = QtWidgets.QLabel('%s:' % _('Cut Z'))
|
||||
cutzlabel.setToolTip(
|
||||
_("Drill depth (negative)\n"
|
||||
"below the copper surface.")
|
||||
|
@ -600,7 +600,7 @@ class ExcellonObjectUI(ObjectUI):
|
|||
grid1.addWidget(self.cutz_entry, 0, 1)
|
||||
|
||||
# Travel Z (z_move)
|
||||
travelzlabel = QtWidgets.QLabel(_('Travel Z:'))
|
||||
travelzlabel = QtWidgets.QLabel('%s:' % _('Travel Z'))
|
||||
travelzlabel.setToolTip(
|
||||
_("Tool height when travelling\n"
|
||||
"across the XY plane.")
|
||||
|
@ -610,7 +610,7 @@ class ExcellonObjectUI(ObjectUI):
|
|||
grid1.addWidget(self.travelz_entry, 1, 1)
|
||||
|
||||
# Tool change:
|
||||
self.toolchange_cb = FCCheckBox(_("Tool change"))
|
||||
self.toolchange_cb = FCCheckBox('%s:' % _("Tool change"))
|
||||
self.toolchange_cb.setToolTip(
|
||||
_("Include tool-change sequence\n"
|
||||
"in G-Code (Pause for tool change).")
|
||||
|
@ -618,7 +618,7 @@ class ExcellonObjectUI(ObjectUI):
|
|||
grid1.addWidget(self.toolchange_cb, 2, 0)
|
||||
|
||||
# Tool change Z:
|
||||
toolchzlabel = QtWidgets.QLabel(_("Tool change Z:"))
|
||||
toolchzlabel = QtWidgets.QLabel('%s:' % _("Tool change Z"))
|
||||
toolchzlabel.setToolTip(
|
||||
_("Z-axis position (height) for\n"
|
||||
"tool change.")
|
||||
|
@ -629,9 +629,9 @@ class ExcellonObjectUI(ObjectUI):
|
|||
self.ois_tcz_e = OptionalInputSection(self.toolchange_cb, [self.toolchangez_entry])
|
||||
|
||||
# Start move Z:
|
||||
self.estartz_label = QtWidgets.QLabel(_("Start move Z:"))
|
||||
self.estartz_label = QtWidgets.QLabel('%s:' % _("Start move Z"))
|
||||
self.estartz_label.setToolTip(
|
||||
_("Tool height just before starting the work.\n"
|
||||
_("Height of the tool just after start.\n"
|
||||
"Delete the value if you don't need this feature.")
|
||||
)
|
||||
grid1.addWidget(self.estartz_label, 4, 0)
|
||||
|
@ -639,17 +639,17 @@ class ExcellonObjectUI(ObjectUI):
|
|||
grid1.addWidget(self.estartz_entry, 4, 1)
|
||||
|
||||
# End move Z:
|
||||
self.eendz_label = QtWidgets.QLabel(_("End move Z:"))
|
||||
self.eendz_label = QtWidgets.QLabel('%s:' % _("End move Z"))
|
||||
self.eendz_label.setToolTip(
|
||||
_("Z-axis position (height) for\n"
|
||||
"the last move.")
|
||||
_("Height of the tool after\n"
|
||||
"the last move at the end of the job.")
|
||||
)
|
||||
grid1.addWidget(self.eendz_label, 5, 0)
|
||||
self.eendz_entry = LengthEntry()
|
||||
grid1.addWidget(self.eendz_entry, 5, 1)
|
||||
|
||||
# Excellon Feedrate
|
||||
frlabel = QtWidgets.QLabel(_('Feedrate (Plunge):'))
|
||||
frlabel = QtWidgets.QLabel('%s:' % _('Feedrate (Plunge):'))
|
||||
frlabel.setToolTip(
|
||||
_("Tool speed while drilling\n"
|
||||
"(in units per minute).\n"
|
||||
|
@ -660,14 +660,13 @@ class ExcellonObjectUI(ObjectUI):
|
|||
grid1.addWidget(self.feedrate_entry, 6, 1)
|
||||
|
||||
# Excellon Rapid Feedrate
|
||||
self.feedrate_rapid_label = QtWidgets.QLabel(_('Feedrate Rapids:'))
|
||||
self.feedrate_rapid_label = QtWidgets.QLabel('%s:' % _('Feedrate Rapids'))
|
||||
self.feedrate_rapid_label.setToolTip(
|
||||
_("Tool speed while drilling\n"
|
||||
"(in units per minute).\n"
|
||||
"This is for the rapid move G00.\n"
|
||||
"It is useful only for Marlin,\n"
|
||||
"ignore for any other cases."
|
||||
)
|
||||
"ignore for any other cases.")
|
||||
)
|
||||
grid1.addWidget(self.feedrate_rapid_label, 7, 0)
|
||||
self.feedrate_rapid_entry = LengthEntry()
|
||||
|
@ -677,7 +676,7 @@ class ExcellonObjectUI(ObjectUI):
|
|||
self.feedrate_rapid_entry.hide()
|
||||
|
||||
# Spindlespeed
|
||||
spdlabel = QtWidgets.QLabel(_('Spindle speed:'))
|
||||
spdlabel = QtWidgets.QLabel('%s:' % _('Spindle speed'))
|
||||
spdlabel.setToolTip(
|
||||
_("Speed of the spindle\n"
|
||||
"in RPM (optional)")
|
||||
|
@ -687,14 +686,14 @@ class ExcellonObjectUI(ObjectUI):
|
|||
grid1.addWidget(self.spindlespeed_entry, 8, 1)
|
||||
|
||||
# Dwell
|
||||
self.dwell_cb = FCCheckBox(_('Dwell:'))
|
||||
self.dwell_cb = FCCheckBox('%s:' % _('Dwell'))
|
||||
self.dwell_cb.setToolTip(
|
||||
_("Pause to allow the spindle to reach its\n"
|
||||
"speed before cutting.")
|
||||
)
|
||||
self.dwelltime_entry = FCEntry()
|
||||
self.dwelltime_entry.setToolTip(
|
||||
_("Number of milliseconds for spindle to dwell.")
|
||||
_("Number of time units for spindle to dwell.")
|
||||
)
|
||||
grid1.addWidget(self.dwell_cb, 9, 0)
|
||||
grid1.addWidget(self.dwelltime_entry, 9, 1)
|
||||
|
@ -702,10 +701,10 @@ class ExcellonObjectUI(ObjectUI):
|
|||
self.ois_dwell = OptionalInputSection(self.dwell_cb, [self.dwelltime_entry])
|
||||
|
||||
# postprocessor selection
|
||||
pp_excellon_label = QtWidgets.QLabel(_("Postprocessor:"))
|
||||
pp_excellon_label = QtWidgets.QLabel('%s:' % _("Postprocessor"))
|
||||
pp_excellon_label.setToolTip(
|
||||
_("The json file that dictates\n"
|
||||
"gcode output.")
|
||||
_("The postprocessor JSON file that dictates\n"
|
||||
"Gcode output.")
|
||||
)
|
||||
self.pp_excellon_name_cb = FCComboBox()
|
||||
self.pp_excellon_name_cb.setFocusPolicy(QtCore.Qt.StrongFocus)
|
||||
|
@ -713,7 +712,7 @@ class ExcellonObjectUI(ObjectUI):
|
|||
grid1.addWidget(self.pp_excellon_name_cb, 10, 1)
|
||||
|
||||
# Probe depth
|
||||
self.pdepth_label = QtWidgets.QLabel(_("Probe Z depth:"))
|
||||
self.pdepth_label = QtWidgets.QLabel('%s:' % _("Probe Z depth"))
|
||||
self.pdepth_label.setToolTip(
|
||||
_("The maximum depth that the probe is allowed\n"
|
||||
"to probe. Negative value, in current units.")
|
||||
|
@ -725,7 +724,7 @@ class ExcellonObjectUI(ObjectUI):
|
|||
self.pdepth_entry.setVisible(False)
|
||||
|
||||
# Probe feedrate
|
||||
self.feedrate_probe_label = QtWidgets.QLabel(_("Feedrate Probe:"))
|
||||
self.feedrate_probe_label = QtWidgets.QLabel('%s:' % _("Feedrate Probe"))
|
||||
self.feedrate_probe_label.setToolTip(
|
||||
_("The feedrate used while the probe is probing.")
|
||||
)
|
||||
|
@ -743,7 +742,7 @@ class ExcellonObjectUI(ObjectUI):
|
|||
|
||||
# ### Choose what to use for Gcode creation: Drills, Slots or Both
|
||||
gcode_box = QtWidgets.QFormLayout()
|
||||
gcode_type_label = QtWidgets.QLabel(_('<b>Type: </b>'))
|
||||
gcode_type_label = QtWidgets.QLabel('<b>%s</b>' % _('Gcode'))
|
||||
gcode_type_label.setToolTip(
|
||||
_("Choose what to use for GCode generation:\n"
|
||||
"'Drills', 'Slots' or 'Both'.\n"
|
||||
|
@ -767,7 +766,7 @@ class ExcellonObjectUI(ObjectUI):
|
|||
self.tools_box.addWidget(self.generate_cnc_button)
|
||||
|
||||
# ### Milling Holes Drills ####
|
||||
self.mill_hole_label = QtWidgets.QLabel(_('<b>Mill Holes</b>'))
|
||||
self.mill_hole_label = QtWidgets.QLabel('<b>%s</b>' % _('Mill Holes'))
|
||||
self.mill_hole_label.setToolTip(
|
||||
_("Create Geometry for milling holes.")
|
||||
)
|
||||
|
@ -781,7 +780,7 @@ class ExcellonObjectUI(ObjectUI):
|
|||
|
||||
grid2 = QtWidgets.QGridLayout()
|
||||
self.tools_box.addLayout(grid2)
|
||||
self.tdlabel = QtWidgets.QLabel(_('Drills Tool dia:'))
|
||||
self.tdlabel = QtWidgets.QLabel('%s:' % _('Drill Tool dia'))
|
||||
self.tdlabel.setToolTip(
|
||||
_("Diameter of the cutting tool.")
|
||||
)
|
||||
|
@ -797,9 +796,10 @@ class ExcellonObjectUI(ObjectUI):
|
|||
|
||||
grid3 = QtWidgets.QGridLayout()
|
||||
self.custom_box.addLayout(grid3)
|
||||
self.stdlabel = QtWidgets.QLabel(_('Slots Tool dia:'))
|
||||
self.stdlabel = QtWidgets.QLabel('%s:' % _('Slot Tool dia'))
|
||||
self.stdlabel.setToolTip(
|
||||
_("Diameter of the cutting tool.")
|
||||
_("Diameter of the cutting tool\n"
|
||||
"when milling slots.")
|
||||
)
|
||||
grid3.addWidget(self.stdlabel, 0, 0)
|
||||
self.slot_tooldia_entry = LengthEntry()
|
||||
|
@ -828,13 +828,13 @@ class GeometryObjectUI(ObjectUI):
|
|||
icon_file='share/geometry32.png', parent=parent)
|
||||
|
||||
# Plot options
|
||||
self.plot_options_label = QtWidgets.QLabel(_("<b>Plot Options:</b>"))
|
||||
self.plot_options_label = QtWidgets.QLabel("<b>%s:</b>" % _("Plot Options"))
|
||||
self.custom_box.addWidget(self.plot_options_label)
|
||||
|
||||
# ## Object name
|
||||
self.name_hlay = QtWidgets.QHBoxLayout()
|
||||
self.custom_box.addLayout(self.name_hlay)
|
||||
name_label = QtWidgets.QLabel(_("<b>Name:</b>"))
|
||||
name_label = QtWidgets.QLabel("<b>%s:</b>" % _("Name"))
|
||||
self.name_entry = FCEntry()
|
||||
self.name_entry.setFocusPolicy(QtCore.Qt.StrongFocus)
|
||||
self.name_hlay.addWidget(name_label)
|
||||
|
@ -853,7 +853,7 @@ class GeometryObjectUI(ObjectUI):
|
|||
self.geo_tools_box.addLayout(hlay_plot)
|
||||
|
||||
# ### Tools ####
|
||||
self.tools_table_label = QtWidgets.QLabel(_('<b>Tools Table</b>'))
|
||||
self.tools_table_label = QtWidgets.QLabel('<b>%s:</b>' % _('Tools Table'))
|
||||
self.tools_table_label.setToolTip(
|
||||
_("Tools in this Geometry object used for cutting.\n"
|
||||
"The 'Offset' entry will set an offset for the cut.\n"
|
||||
|
@ -945,7 +945,7 @@ class GeometryObjectUI(ObjectUI):
|
|||
self.grid1 = QtWidgets.QGridLayout()
|
||||
self.geo_tools_box.addLayout(self.grid1)
|
||||
|
||||
self.tool_offset_lbl = QtWidgets.QLabel(_('Tool Offset:'))
|
||||
self.tool_offset_lbl = QtWidgets.QLabel('%s:' % _('Tool Offset'))
|
||||
self.tool_offset_lbl.setToolTip(
|
||||
_(
|
||||
"The value to offset the cut when \n"
|
||||
|
@ -971,7 +971,7 @@ class GeometryObjectUI(ObjectUI):
|
|||
# self.addtool_label.setToolTip(
|
||||
# "Add/Copy/Delete a tool to the tool list."
|
||||
# )
|
||||
self.addtool_entry_lbl = QtWidgets.QLabel(_('<b>Tool Dia:</b>'))
|
||||
self.addtool_entry_lbl = QtWidgets.QLabel('<b>%s:</b>' % _('Tool Dia'))
|
||||
self.addtool_entry_lbl.setToolTip(
|
||||
_(
|
||||
"Diameter for the new tool"
|
||||
|
@ -1022,7 +1022,7 @@ class GeometryObjectUI(ObjectUI):
|
|||
# Create CNC Job ###
|
||||
# ##################
|
||||
# ### Tools Data ## ##
|
||||
self.tool_data_label = QtWidgets.QLabel(_('<b>Tool Data</b>'))
|
||||
self.tool_data_label = QtWidgets.QLabel('<b>%s</b>' % _('Tool Data'))
|
||||
self.tool_data_label.setToolTip(
|
||||
_(
|
||||
"The data used for creating GCode.\n"
|
||||
|
@ -1043,7 +1043,7 @@ class GeometryObjectUI(ObjectUI):
|
|||
self.geo_param_box.addLayout(self.grid3)
|
||||
|
||||
# Tip Dia
|
||||
self.tipdialabel = QtWidgets.QLabel(_('V-Tip Dia:'))
|
||||
self.tipdialabel = QtWidgets.QLabel('%s:' % _('V-Tip Dia'))
|
||||
self.tipdialabel.setToolTip(
|
||||
_(
|
||||
"The tip diameter for V-Shape Tool"
|
||||
|
@ -1054,7 +1054,7 @@ class GeometryObjectUI(ObjectUI):
|
|||
self.grid3.addWidget(self.tipdia_entry, 1, 1)
|
||||
|
||||
# Tip Angle
|
||||
self.tipanglelabel = QtWidgets.QLabel(_('V-Tip Angle:'))
|
||||
self.tipanglelabel = QtWidgets.QLabel('%s:' % _('V-Tip Angle'))
|
||||
self.tipanglelabel.setToolTip(
|
||||
_(
|
||||
"The tip angle for V-Shape Tool.\n"
|
||||
|
@ -1066,7 +1066,7 @@ class GeometryObjectUI(ObjectUI):
|
|||
self.grid3.addWidget(self.tipangle_entry, 2, 1)
|
||||
|
||||
# Cut Z
|
||||
cutzlabel = QtWidgets.QLabel(_('Cut Z:'))
|
||||
cutzlabel = QtWidgets.QLabel('%s:' % _('Cut Z'))
|
||||
cutzlabel.setToolTip(
|
||||
_(
|
||||
"Cutting depth (negative)\n"
|
||||
|
@ -1078,15 +1078,13 @@ class GeometryObjectUI(ObjectUI):
|
|||
self.grid3.addWidget(self.cutz_entry, 3, 1)
|
||||
|
||||
# Multi-pass
|
||||
self.mpass_cb = FCCheckBox(_("Multi-Depth:"))
|
||||
self.mpass_cb = FCCheckBox('%s:' % _("Multi-Depth"))
|
||||
self.mpass_cb.setToolTip(
|
||||
_(
|
||||
"Use multiple passes to limit\n"
|
||||
"the cut depth in each pass. Will\n"
|
||||
"cut multiple times until Cut Z is\n"
|
||||
"reached.\n"
|
||||
"To the right, input the depth of \n"
|
||||
"each pass (positive value)."
|
||||
"reached."
|
||||
)
|
||||
)
|
||||
self.grid3.addWidget(self.mpass_cb, 4, 0)
|
||||
|
@ -1102,12 +1100,10 @@ class GeometryObjectUI(ObjectUI):
|
|||
self.ois_mpass_geo = OptionalInputSection(self.mpass_cb, [self.maxdepth_entry])
|
||||
|
||||
# Travel Z
|
||||
travelzlabel = QtWidgets.QLabel(_('Travel Z:'))
|
||||
travelzlabel = QtWidgets.QLabel('%s:' % _('Travel Z'))
|
||||
travelzlabel.setToolTip(
|
||||
_(
|
||||
"Height of the tool when\n"
|
||||
"moving without cutting."
|
||||
)
|
||||
_("Height of the tool when\n"
|
||||
"moving without cutting.")
|
||||
)
|
||||
self.grid3.addWidget(travelzlabel, 5, 0)
|
||||
self.travelz_entry = FloatEntry()
|
||||
|
@ -1115,14 +1111,14 @@ class GeometryObjectUI(ObjectUI):
|
|||
|
||||
# Tool change:
|
||||
|
||||
self.toolchzlabel = QtWidgets.QLabel(_("Tool change Z:"))
|
||||
self.toolchzlabel = QtWidgets.QLabel('%s:' %_("Tool change Z"))
|
||||
self.toolchzlabel.setToolTip(
|
||||
_(
|
||||
"Z-axis position (height) for\n"
|
||||
"tool change."
|
||||
)
|
||||
)
|
||||
self.toolchangeg_cb = FCCheckBox(_("Tool change"))
|
||||
self.toolchangeg_cb = FCCheckBox('%s:' % _("Tool change"))
|
||||
self.toolchangeg_cb.setToolTip(
|
||||
_(
|
||||
"Include tool-change sequence\n"
|
||||
|
@ -1148,52 +1144,44 @@ class GeometryObjectUI(ObjectUI):
|
|||
# self.grid3.addWidget(self.gstartz_entry, 8, 1)
|
||||
|
||||
# The Z value for the end move
|
||||
self.endzlabel = QtWidgets.QLabel(_('End move Z:'))
|
||||
self.endzlabel = QtWidgets.QLabel('%s:' % _('End move Z'))
|
||||
self.endzlabel.setToolTip(
|
||||
_(
|
||||
"This is the height (Z) at which the CNC\n"
|
||||
"will go as the last move."
|
||||
)
|
||||
_("Height of the tool after\n"
|
||||
"the last move at the end of the job.")
|
||||
)
|
||||
self.grid3.addWidget(self.endzlabel, 9, 0)
|
||||
self.gendz_entry = FloatEntry()
|
||||
self.grid3.addWidget(self.gendz_entry, 9, 1)
|
||||
|
||||
# Feedrate X-Y
|
||||
frlabel = QtWidgets.QLabel(_('Feed Rate X-Y:'))
|
||||
frlabel = QtWidgets.QLabel('%s:' % _('Feed Rate X-Y'))
|
||||
frlabel.setToolTip(
|
||||
_(
|
||||
"Cutting speed in the XY\n"
|
||||
"plane in units per minute"
|
||||
)
|
||||
_("Cutting speed in the XY\n"
|
||||
"plane in units per minute")
|
||||
)
|
||||
self.grid3.addWidget(frlabel, 10, 0)
|
||||
self.cncfeedrate_entry = FloatEntry()
|
||||
self.grid3.addWidget(self.cncfeedrate_entry, 10, 1)
|
||||
|
||||
# Feedrate Z (Plunge)
|
||||
frzlabel = QtWidgets.QLabel(_('Feed Rate Z (Plunge):'))
|
||||
frzlabel = QtWidgets.QLabel('%s:' % _('Feed Rate Z'))
|
||||
frzlabel.setToolTip(
|
||||
_(
|
||||
"Cutting speed in the Z\n"
|
||||
"plane in units per minute"
|
||||
)
|
||||
_("Cutting speed in the XY\n"
|
||||
"plane in units per minute.\n"
|
||||
"It is called also Plunge.")
|
||||
)
|
||||
self.grid3.addWidget(frzlabel, 11, 0)
|
||||
self.cncplunge_entry = FloatEntry()
|
||||
self.grid3.addWidget(self.cncplunge_entry, 11, 1)
|
||||
|
||||
# Feedrate rapids
|
||||
self.fr_rapidlabel = QtWidgets.QLabel(_('Feed Rate Rapids:'))
|
||||
self.fr_rapidlabel = QtWidgets.QLabel('%s:' % _('Feed Rate Rapids'))
|
||||
self.fr_rapidlabel.setToolTip(
|
||||
_(
|
||||
"Cutting speed in the XY\n"
|
||||
"plane in units per minute\n"
|
||||
_("Cutting speed in the XY plane\n"
|
||||
"(in units per minute).\n"
|
||||
"This is for the rapid move G00.\n"
|
||||
"It is useful only for Marlin,\n"
|
||||
"ignore for any other cases."
|
||||
)
|
||||
"ignore for any other cases.")
|
||||
)
|
||||
self.grid3.addWidget(self.fr_rapidlabel, 12, 0)
|
||||
self.cncfeedrate_rapid_entry = FloatEntry()
|
||||
|
@ -1203,19 +1191,17 @@ class GeometryObjectUI(ObjectUI):
|
|||
self.cncfeedrate_rapid_entry.hide()
|
||||
|
||||
# Cut over 1st point in path
|
||||
self.extracut_cb = FCCheckBox(_('Cut over 1st pt'))
|
||||
self.extracut_cb = FCCheckBox('%s' % _('Re-cut 1st pt.'))
|
||||
self.extracut_cb.setToolTip(
|
||||
_(
|
||||
"In order to remove possible\n"
|
||||
"copper leftovers where first cut\n"
|
||||
"meet with last cut, we generate an\n"
|
||||
"extended cut over the first cut section."
|
||||
)
|
||||
_("In order to remove possible\n"
|
||||
"copper leftovers where first cut\n"
|
||||
"meet with last cut, we generate an\n"
|
||||
"extended cut over the first cut section.")
|
||||
)
|
||||
self.grid3.addWidget(self.extracut_cb, 13, 0)
|
||||
|
||||
# Spindlespeed
|
||||
spdlabel = QtWidgets.QLabel(_('Spindle speed:'))
|
||||
spdlabel = QtWidgets.QLabel('%s:' % _('Spindle speed'))
|
||||
spdlabel.setToolTip(
|
||||
_(
|
||||
"Speed of the spindle in RPM (optional).\n"
|
||||
|
@ -1228,7 +1214,7 @@ class GeometryObjectUI(ObjectUI):
|
|||
self.grid3.addWidget(self.cncspindlespeed_entry, 14, 1)
|
||||
|
||||
# Dwell
|
||||
self.dwell_cb = FCCheckBox(_('Dwell:'))
|
||||
self.dwell_cb = FCCheckBox('%s:' % _('Dwell'))
|
||||
self.dwell_cb.setToolTip(
|
||||
_(
|
||||
"Pause to allow the spindle to reach its\n"
|
||||
|
@ -1237,9 +1223,7 @@ class GeometryObjectUI(ObjectUI):
|
|||
)
|
||||
self.dwelltime_entry = FloatEntry()
|
||||
self.dwelltime_entry.setToolTip(
|
||||
_(
|
||||
"Number of milliseconds for spindle to dwell."
|
||||
)
|
||||
_("Number of time units for spindle to dwell.")
|
||||
)
|
||||
self.grid3.addWidget(self.dwell_cb, 15, 0)
|
||||
self.grid3.addWidget(self.dwelltime_entry, 15, 1)
|
||||
|
@ -1247,12 +1231,10 @@ class GeometryObjectUI(ObjectUI):
|
|||
self.ois_dwell_geo = OptionalInputSection(self.dwell_cb, [self.dwelltime_entry])
|
||||
|
||||
# postprocessor selection
|
||||
pp_label = QtWidgets.QLabel(_("PostProcessor:"))
|
||||
pp_label = QtWidgets.QLabel('%s:' % _("PostProcessor"))
|
||||
pp_label.setToolTip(
|
||||
_(
|
||||
"The Postprocessor file that dictates\n"
|
||||
"the Machine Code (like GCode, RML, HPGL) output."
|
||||
)
|
||||
_("The Postprocessor file that dictates\n"
|
||||
"the Machine Code (like GCode, RML, HPGL) output.")
|
||||
)
|
||||
self.grid3.addWidget(pp_label, 16, 0)
|
||||
self.pp_geometry_name_cb = FCComboBox()
|
||||
|
@ -1260,12 +1242,10 @@ class GeometryObjectUI(ObjectUI):
|
|||
self.grid3.addWidget(self.pp_geometry_name_cb, 16, 1)
|
||||
|
||||
# Probe depth
|
||||
self.pdepth_label = QtWidgets.QLabel(_("Probe Z depth:"))
|
||||
self.pdepth_label = QtWidgets.QLabel('%s:' % _("Probe Z depth"))
|
||||
self.pdepth_label.setToolTip(
|
||||
_(
|
||||
"The maximum depth that the probe is allowed\n"
|
||||
"to probe. Negative value, in current units."
|
||||
)
|
||||
_("The maximum depth that the probe is allowed\n"
|
||||
"to probe. Negative value, in current units.")
|
||||
)
|
||||
self.grid3.addWidget(self.pdepth_label, 17, 0)
|
||||
self.pdepth_entry = FCEntry()
|
||||
|
@ -1274,11 +1254,9 @@ class GeometryObjectUI(ObjectUI):
|
|||
self.pdepth_entry.setVisible(False)
|
||||
|
||||
# Probe feedrate
|
||||
self.feedrate_probe_label = QtWidgets.QLabel(_("Feedrate Probe:"))
|
||||
self.feedrate_probe_label = QtWidgets.QLabel('%s:' % _("Feedrate Probe"))
|
||||
self.feedrate_probe_label.setToolTip(
|
||||
_(
|
||||
"The feedrate used while the probe is probing."
|
||||
)
|
||||
_("The feedrate used while the probe is probing.")
|
||||
)
|
||||
self.grid3.addWidget(self.feedrate_probe_label, 18, 0)
|
||||
self.feedrate_probe_entry = FCEntry()
|
||||
|
@ -1297,16 +1275,14 @@ class GeometryObjectUI(ObjectUI):
|
|||
# Button
|
||||
self.generate_cnc_button = QtWidgets.QPushButton(_('Generate'))
|
||||
self.generate_cnc_button.setToolTip(
|
||||
_(
|
||||
"Generate the CNC Job object."
|
||||
)
|
||||
_("Generate the CNC Job object.")
|
||||
)
|
||||
self.geo_param_box.addWidget(self.generate_cnc_button)
|
||||
|
||||
# ##############
|
||||
# Paint area ##
|
||||
# ##############
|
||||
self.paint_label = QtWidgets.QLabel(_('<b>Paint Area:</b>'))
|
||||
self.paint_label = QtWidgets.QLabel('<b>%s</b>' % _('Paint Area'))
|
||||
self.paint_label.setToolTip(
|
||||
_(
|
||||
"Creates tool paths to cover the\n"
|
||||
|
@ -1320,9 +1296,7 @@ class GeometryObjectUI(ObjectUI):
|
|||
# GO Button
|
||||
self.paint_tool_button = QtWidgets.QPushButton(_('Paint Tool'))
|
||||
self.paint_tool_button.setToolTip(
|
||||
_(
|
||||
"Launch Paint Tool in Tools Tab."
|
||||
)
|
||||
_("Launch Paint Tool in Tools Tab.")
|
||||
)
|
||||
self.geo_tools_box.addWidget(self.paint_tool_button)
|
||||
|
||||
|
@ -1353,10 +1327,10 @@ class CNCObjectUI(ObjectUI):
|
|||
self.offset_button.hide()
|
||||
|
||||
# ## Plot options
|
||||
self.plot_options_label = QtWidgets.QLabel(_("<b>Plot Options:</b>"))
|
||||
self.plot_options_label = QtWidgets.QLabel("<b>%s:</b>" % _("Plot Options"))
|
||||
self.custom_box.addWidget(self.plot_options_label)
|
||||
|
||||
self.cncplot_method_label = QtWidgets.QLabel(_("<b>Plot kind:</b>"))
|
||||
self.cncplot_method_label = QtWidgets.QLabel("<b>%s:</b>" % _("Plot kind"))
|
||||
self.cncplot_method_label.setToolTip(
|
||||
_(
|
||||
"This selects the kind of geometries on the canvas to plot.\n"
|
||||
|
@ -1372,12 +1346,11 @@ class CNCObjectUI(ObjectUI):
|
|||
{"label": _("Cut"), "value": "cut"}
|
||||
], stretch=False)
|
||||
|
||||
self.annotation_label = QtWidgets.QLabel(_("<b>Display Annotation:</b>"))
|
||||
self.annotation_label = QtWidgets.QLabel("<b>%s:</b>" % _("Display Annotation"))
|
||||
self.annotation_label.setToolTip(
|
||||
_(
|
||||
"This selects if to display text annotation on the plot.\n"
|
||||
"When checked it will display numbers in order for each end\n"
|
||||
"of a travel line."
|
||||
_("This selects if to display text annotation on the plot.\n"
|
||||
"When checked it will display numbers in order for each end\n"
|
||||
"of a travel line."
|
||||
)
|
||||
)
|
||||
self.annotation_cb = FCCheckBox()
|
||||
|
@ -1385,13 +1358,13 @@ class CNCObjectUI(ObjectUI):
|
|||
# ## Object name
|
||||
self.name_hlay = QtWidgets.QHBoxLayout()
|
||||
self.custom_box.addLayout(self.name_hlay)
|
||||
name_label = QtWidgets.QLabel(_("<b>Name:</b>"))
|
||||
name_label = QtWidgets.QLabel("<b>%s:</b>" % _("Name"))
|
||||
self.name_entry = FCEntry()
|
||||
self.name_entry.setFocusPolicy(QtCore.Qt.StrongFocus)
|
||||
self.name_hlay.addWidget(name_label)
|
||||
self.name_hlay.addWidget(self.name_entry)
|
||||
|
||||
self.t_distance_label = QtWidgets.QLabel(_("<b>Travelled dist.:</b>"))
|
||||
self.t_distance_label = QtWidgets.QLabel("<b>%s:</b>" % _("Travelled dist."))
|
||||
self.t_distance_label.setToolTip(
|
||||
_("This is the total travelled distance on X-Y plane.\n"
|
||||
"In current units.")
|
||||
|
@ -1403,7 +1376,7 @@ class CNCObjectUI(ObjectUI):
|
|||
)
|
||||
self.units_label = QtWidgets.QLabel()
|
||||
|
||||
self.t_time_label = QtWidgets.QLabel(_("<b>Estimated time:</b>"))
|
||||
self.t_time_label = QtWidgets.QLabel("<b>%s:</b>" % _("Estimated time"))
|
||||
self.t_time_label.setToolTip(
|
||||
_("This is the estimated time to do the routing/drilling,\n"
|
||||
"without the time spent in ToolChange events.")
|
||||
|
@ -1445,7 +1418,7 @@ class CNCObjectUI(ObjectUI):
|
|||
self.custom_box.addLayout(hlay)
|
||||
|
||||
# CNC Tools Table for plot
|
||||
self.cnc_tools_table_label = QtWidgets.QLabel(_('<b>CNC Tools Table</b>'))
|
||||
self.cnc_tools_table_label = QtWidgets.QLabel('<b>%s</b>' % _('CNC Tools Table'))
|
||||
self.cnc_tools_table_label.setToolTip(
|
||||
_(
|
||||
"Tools in this CNCJob object used for cutting.\n"
|
||||
|
@ -1465,9 +1438,7 @@ class CNCObjectUI(ObjectUI):
|
|||
# self.plot_cb = QtWidgets.QCheckBox('Plot')
|
||||
self.plot_cb = FCCheckBox(_('Plot Object'))
|
||||
self.plot_cb.setToolTip(
|
||||
_(
|
||||
"Plot (show) this object."
|
||||
)
|
||||
_("Plot (show) this object.")
|
||||
)
|
||||
self.plot_cb.setLayoutDirection(QtCore.Qt.RightToLeft)
|
||||
hlay.addStretch()
|
||||
|
@ -1497,20 +1468,18 @@ class CNCObjectUI(ObjectUI):
|
|||
# ####################
|
||||
# ## Export G-Code ##
|
||||
# ####################
|
||||
self.export_gcode_label = QtWidgets.QLabel(_("<b>Export CNC Code:</b>"))
|
||||
self.export_gcode_label = QtWidgets.QLabel("<b>%s:</b>" % _("Export CNC Code"))
|
||||
self.export_gcode_label.setToolTip(
|
||||
_("Export and save G-Code to\n"
|
||||
"make this object to a file.")
|
||||
"make this object to a file.")
|
||||
)
|
||||
self.custom_box.addWidget(self.export_gcode_label)
|
||||
|
||||
# Prepend text to GCode
|
||||
prependlabel = QtWidgets.QLabel(_('Prepend to CNC Code:'))
|
||||
prependlabel = QtWidgets.QLabel('%s:' % _('Prepend to CNC Code'))
|
||||
prependlabel.setToolTip(
|
||||
_(
|
||||
"Type here any G-Code commands you would\n"
|
||||
"like to add to the beginning of the generated file."
|
||||
)
|
||||
_("Type here any G-Code commands you would\n"
|
||||
"like to add at the beginning of the G-Code file.")
|
||||
)
|
||||
self.custom_box.addWidget(prependlabel)
|
||||
|
||||
|
@ -1518,13 +1487,11 @@ class CNCObjectUI(ObjectUI):
|
|||
self.custom_box.addWidget(self.prepend_text)
|
||||
|
||||
# Append text to GCode
|
||||
appendlabel = QtWidgets.QLabel(_('Append to CNC Code:'))
|
||||
appendlabel = QtWidgets.QLabel('%s:' % _('Append to CNC Code'))
|
||||
appendlabel.setToolTip(
|
||||
_(
|
||||
"Type here any G-Code commands you would\n"
|
||||
"like to append to the generated file.\n"
|
||||
"I.e.: M2 (End of program)"
|
||||
)
|
||||
_("Type here any G-Code commands you would\n"
|
||||
"like to append to the generated file.\n"
|
||||
"I.e.: M2 (End of program)")
|
||||
)
|
||||
self.custom_box.addWidget(appendlabel)
|
||||
|
||||
|
@ -1539,7 +1506,7 @@ class CNCObjectUI(ObjectUI):
|
|||
self.cnc_frame.setLayout(self.cnc_box)
|
||||
|
||||
# Toolchange Custom G-Code
|
||||
self.toolchangelabel = QtWidgets.QLabel(_('Toolchange G-Code:'))
|
||||
self.toolchangelabel = QtWidgets.QLabel('%s:' % _('Toolchange G-Code'))
|
||||
self.toolchangelabel.setToolTip(
|
||||
_(
|
||||
"Type here any G-Code commands you would\n"
|
||||
|
@ -1561,12 +1528,10 @@ class CNCObjectUI(ObjectUI):
|
|||
self.cnc_box.addLayout(cnclay)
|
||||
|
||||
# Toolchange Replacement Enable
|
||||
self.toolchange_cb = FCCheckBox(label=_('Use Toolchange Macro'))
|
||||
self.toolchange_cb = FCCheckBox(label='%s' % _('Use Toolchange Macro'))
|
||||
self.toolchange_cb.setToolTip(
|
||||
_(
|
||||
"Check this box if you want to use\n"
|
||||
"a Custom Toolchange GCode (macro)."
|
||||
)
|
||||
_("Check this box if you want to use\n"
|
||||
"a Custom Toolchange GCode (macro).")
|
||||
)
|
||||
|
||||
# Variable list
|
||||
|
@ -1612,19 +1577,15 @@ class CNCObjectUI(ObjectUI):
|
|||
# Edit GCode Button
|
||||
self.modify_gcode_button = QtWidgets.QPushButton(_('View CNC Code'))
|
||||
self.modify_gcode_button.setToolTip(
|
||||
_(
|
||||
"Opens TAB to view/modify/print G-Code\n"
|
||||
"file."
|
||||
)
|
||||
_("Opens TAB to view/modify/print G-Code\n"
|
||||
"file.")
|
||||
)
|
||||
|
||||
# GO Button
|
||||
self.export_gcode_button = QtWidgets.QPushButton(_('Save CNC Code'))
|
||||
self.export_gcode_button.setToolTip(
|
||||
_(
|
||||
"Opens dialog to save G-Code\n"
|
||||
"file."
|
||||
)
|
||||
_("Opens dialog to save G-Code\n"
|
||||
"file.")
|
||||
)
|
||||
|
||||
h_lay.addWidget(self.modify_gcode_button)
|
||||
|
|
|
@ -89,28 +89,29 @@ class ToolCalculator(FlatCAMTool):
|
|||
form_layout = QtWidgets.QFormLayout()
|
||||
self.layout.addLayout(form_layout)
|
||||
|
||||
self.tipDia_label = QtWidgets.QLabel(_("Tip Diameter:"))
|
||||
self.tipDia_label = QtWidgets.QLabel('%s:' % _("Tip Diameter"))
|
||||
self.tipDia_entry = FCEntry()
|
||||
# self.tipDia_entry.setFixedWidth(70)
|
||||
self.tipDia_entry.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
|
||||
self.tipDia_label.setToolTip(_('This is the diameter of the tool tip.\n'
|
||||
'The manufacturer specifies it.'))
|
||||
|
||||
self.tipAngle_label = QtWidgets.QLabel(_("Tip Angle:"))
|
||||
self.tipDia_label.setToolTip(
|
||||
_("This is the tool tip diameter.\n"
|
||||
"It is specified by manufacturer.")
|
||||
)
|
||||
self.tipAngle_label = QtWidgets.QLabel('%s:' % _("Tip Angle"))
|
||||
self.tipAngle_entry = FCEntry()
|
||||
# self.tipAngle_entry.setFixedWidth(70)
|
||||
self.tipAngle_entry.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
|
||||
self.tipAngle_label.setToolTip(_("This is the angle of the tip of the tool.\n"
|
||||
"It is specified by manufacturer."))
|
||||
|
||||
self.cutDepth_label = QtWidgets.QLabel(_("Cut Z:"))
|
||||
self.cutDepth_label = QtWidgets.QLabel('%s:' % _("Cut Z"))
|
||||
self.cutDepth_entry = FCEntry()
|
||||
# self.cutDepth_entry.setFixedWidth(70)
|
||||
self.cutDepth_entry.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
|
||||
self.cutDepth_label.setToolTip(_("This is the depth to cut into the material.\n"
|
||||
"In the CNCJob is the CutZ parameter."))
|
||||
|
||||
self.effectiveToolDia_label = QtWidgets.QLabel(_("Tool Diameter:"))
|
||||
self.effectiveToolDia_label = QtWidgets.QLabel('%s:' % _("Tool Diameter"))
|
||||
self.effectiveToolDia_entry = FCEntry()
|
||||
# self.effectiveToolDia_entry.setFixedWidth(70)
|
||||
self.effectiveToolDia_entry.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
|
||||
|
@ -154,26 +155,26 @@ class ToolCalculator(FlatCAMTool):
|
|||
plate_form_layout = QtWidgets.QFormLayout()
|
||||
self.layout.addLayout(plate_form_layout)
|
||||
|
||||
self.pcblengthlabel = QtWidgets.QLabel(_("Board Length:"))
|
||||
self.pcblengthlabel = QtWidgets.QLabel('%s:' % _("Board Length"))
|
||||
self.pcblength_entry = FCEntry()
|
||||
# self.pcblengthlabel.setFixedWidth(70)
|
||||
self.pcblength_entry.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
|
||||
self.pcblengthlabel.setToolTip(_('This is the board length. In centimeters.'))
|
||||
|
||||
self.pcbwidthlabel = QtWidgets.QLabel(_("Board Width:"))
|
||||
self.pcbwidthlabel = QtWidgets.QLabel('%s:' % _("Board Width"))
|
||||
self.pcbwidth_entry = FCEntry()
|
||||
# self.pcbwidthlabel.setFixedWidth(70)
|
||||
self.pcbwidth_entry.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
|
||||
self.pcbwidthlabel.setToolTip(_('This is the board width.In centimeters.'))
|
||||
|
||||
self.cdensity_label = QtWidgets.QLabel(_("Current Density:"))
|
||||
self.cdensity_label = QtWidgets.QLabel('%s:' % _("Current Density"))
|
||||
self.cdensity_entry = FCEntry()
|
||||
# self.cdensity_entry.setFixedWidth(70)
|
||||
self.cdensity_entry.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
|
||||
self.cdensity_label.setToolTip(_("Current density to pass through the board. \n"
|
||||
"In Amps per Square Feet ASF."))
|
||||
|
||||
self.growth_label = QtWidgets.QLabel(_("Copper Growth:"))
|
||||
self.growth_label = QtWidgets.QLabel('%s:' % _("Copper Growth"))
|
||||
self.growth_entry = FCEntry()
|
||||
# self.growth_entry.setFixedWidth(70)
|
||||
self.growth_entry.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
|
||||
|
@ -182,7 +183,7 @@ class ToolCalculator(FlatCAMTool):
|
|||
|
||||
# self.growth_entry.setEnabled(False)
|
||||
|
||||
self.cvaluelabel = QtWidgets.QLabel(_("Current Value:"))
|
||||
self.cvaluelabel = QtWidgets.QLabel('%s:' % _("Current Value"))
|
||||
self.cvalue_entry = FCEntry()
|
||||
# self.cvaluelabel.setFixedWidth(70)
|
||||
self.cvalue_entry.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
|
||||
|
@ -190,7 +191,7 @@ class ToolCalculator(FlatCAMTool):
|
|||
'to be set on the Power Supply. In Amps.'))
|
||||
self.cvalue_entry.setDisabled(True)
|
||||
|
||||
self.timelabel = QtWidgets.QLabel(_("Time:"))
|
||||
self.timelabel = QtWidgets.QLabel('%s:' % _("Time"))
|
||||
self.time_entry = FCEntry()
|
||||
# self.timelabel.setFixedWidth(70)
|
||||
self.time_entry.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
|
||||
|
@ -242,7 +243,12 @@ class ToolCalculator(FlatCAMTool):
|
|||
else:
|
||||
try:
|
||||
if self.app.ui.tool_scroll_area.widget().objectName() == self.toolName:
|
||||
self.app.ui.splitter.setSizes([0, 1])
|
||||
# if tab is populated with the tool but it does not have the focus, focus on it
|
||||
if not self.app.ui.notebook.currentWidget() is self.app.ui.tool_tab:
|
||||
# focus on Tool Tab
|
||||
self.app.ui.notebook.setCurrentWidget(self.app.ui.tool_tab)
|
||||
else:
|
||||
self.app.ui.splitter.setSizes([0, 1])
|
||||
except AttributeError:
|
||||
pass
|
||||
else:
|
||||
|
|
|
@ -51,7 +51,7 @@ class CutOut(FlatCAMTool):
|
|||
# self.type_obj_combo.setItemIcon(1, QtGui.QIcon("share/drill16.png"))
|
||||
self.type_obj_combo.setItemIcon(2, QtGui.QIcon("share/geometry16.png"))
|
||||
|
||||
self.type_obj_combo_label = QtWidgets.QLabel(_("Obj Type:"))
|
||||
self.type_obj_combo_label = QtWidgets.QLabel('%s:' % _("Obj Type"))
|
||||
self.type_obj_combo_label.setToolTip(
|
||||
_("Specify the type of object to be cutout.\n"
|
||||
"It can be of type: Gerber or Geometry.\n"
|
||||
|
@ -67,14 +67,14 @@ class CutOut(FlatCAMTool):
|
|||
self.obj_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
|
||||
self.obj_combo.setCurrentIndex(1)
|
||||
|
||||
self.object_label = QtWidgets.QLabel(_("Object:"))
|
||||
self.object_label = QtWidgets.QLabel('%s:' % _("Object"))
|
||||
self.object_label.setToolTip(
|
||||
_("Object to be cutout. ")
|
||||
)
|
||||
form_layout.addRow(self.object_label, self.obj_combo)
|
||||
|
||||
# Object kind
|
||||
self.kindlabel = QtWidgets.QLabel(_('Obj kind:'))
|
||||
self.kindlabel = QtWidgets.QLabel('%s:' % _('Obj kind'))
|
||||
self.kindlabel.setToolTip(
|
||||
_("Choice of what kind the object we want to cutout is.<BR>"
|
||||
"- <B>Single</B>: contain a single PCB Gerber outline object.<BR>"
|
||||
|
@ -89,7 +89,7 @@ class CutOut(FlatCAMTool):
|
|||
|
||||
# Tool Diameter
|
||||
self.dia = FCEntry()
|
||||
self.dia_label = QtWidgets.QLabel(_("Tool Dia:"))
|
||||
self.dia_label = QtWidgets.QLabel('%s:' % _("Tool dia"))
|
||||
self.dia_label.setToolTip(
|
||||
_("Diameter of the tool used to cutout\n"
|
||||
"the PCB shape out of the surrounding material.")
|
||||
|
@ -98,7 +98,7 @@ class CutOut(FlatCAMTool):
|
|||
|
||||
# Margin
|
||||
self.margin = FCEntry()
|
||||
self.margin_label = QtWidgets.QLabel(_("Margin:"))
|
||||
self.margin_label = QtWidgets.QLabel('%s:' % _("Margin:"))
|
||||
self.margin_label.setToolTip(
|
||||
_("Margin over bounds. A positive value here\n"
|
||||
"will make the cutout of the PCB further from\n"
|
||||
|
@ -108,7 +108,7 @@ class CutOut(FlatCAMTool):
|
|||
|
||||
# Gapsize
|
||||
self.gapsize = FCEntry()
|
||||
self.gapsize_label = QtWidgets.QLabel(_("Gap size:"))
|
||||
self.gapsize_label = QtWidgets.QLabel('%s:' % _("Gap size:"))
|
||||
self.gapsize_label.setToolTip(
|
||||
_("The size of the bridge gaps in the cutout\n"
|
||||
"used to keep the board connected to\n"
|
||||
|
@ -127,7 +127,7 @@ class CutOut(FlatCAMTool):
|
|||
|
||||
# Surrounding convex box shape
|
||||
self.convex_box = FCCheckBox()
|
||||
self.convex_box_label = QtWidgets.QLabel(_("Convex Sh.:"))
|
||||
self.convex_box_label = QtWidgets.QLabel('%s:' % _("Convex Sh."))
|
||||
self.convex_box_label.setToolTip(
|
||||
_("Create a convex shape surrounding the entire PCB.\n"
|
||||
"Used only if the source object type is Gerber.")
|
||||
|
@ -146,11 +146,12 @@ class CutOut(FlatCAMTool):
|
|||
self.layout.addLayout(form_layout_2)
|
||||
|
||||
# Gaps
|
||||
gaps_label = QtWidgets.QLabel(_('Gaps:'))
|
||||
gaps_label = QtWidgets.QLabel('%s:' % _('Gaps'))
|
||||
gaps_label.setToolTip(
|
||||
_("Number of gaps used for the Automatic cutout.\n"
|
||||
"There can be maximum 8 bridges/gaps.\n"
|
||||
"The choices are:\n"
|
||||
"- None - no gaps\n"
|
||||
"- lr - left + right\n"
|
||||
"- tb - top + bottom\n"
|
||||
"- 4 - left + right +top + bottom\n"
|
||||
|
@ -161,7 +162,7 @@ class CutOut(FlatCAMTool):
|
|||
gaps_label.setMinimumWidth(60)
|
||||
|
||||
self.gaps = FCComboBox()
|
||||
gaps_items = ['LR', 'TB', '4', '2LR', '2TB', '8']
|
||||
gaps_items = ['None', 'LR', 'TB', '4', '2LR', '2TB', '8']
|
||||
for it in gaps_items:
|
||||
self.gaps.addItem(it)
|
||||
self.gaps.setStyleSheet('background-color: rgb(255,255,255)')
|
||||
|
@ -171,7 +172,7 @@ class CutOut(FlatCAMTool):
|
|||
hlay = QtWidgets.QHBoxLayout()
|
||||
self.layout.addLayout(hlay)
|
||||
|
||||
title_ff_label = QtWidgets.QLabel("<b>%s</b>" % _('FreeForm:'))
|
||||
title_ff_label = QtWidgets.QLabel("<b>%s:</b>" % _('FreeForm'))
|
||||
title_ff_label.setToolTip(
|
||||
_("The cutout shape can be of ny shape.\n"
|
||||
"Useful when the PCB has a non-rectangular shape.")
|
||||
|
@ -191,7 +192,7 @@ class CutOut(FlatCAMTool):
|
|||
hlay2 = QtWidgets.QHBoxLayout()
|
||||
self.layout.addLayout(hlay2)
|
||||
|
||||
title_rct_label = QtWidgets.QLabel("<b>%s</b>" % _('Rectangular:'))
|
||||
title_rct_label = QtWidgets.QLabel("<b>%s:</b>" % _('Rectangular'))
|
||||
title_rct_label.setToolTip(
|
||||
_("The resulting cutout shape is\n"
|
||||
"always a rectangle shape and it will be\n"
|
||||
|
@ -228,7 +229,7 @@ class CutOut(FlatCAMTool):
|
|||
self.man_object_combo.setRootModelIndex(self.app.collection.index(2, 0, QtCore.QModelIndex()))
|
||||
self.man_object_combo.setCurrentIndex(1)
|
||||
|
||||
self.man_object_label = QtWidgets.QLabel(_("Geo Obj:"))
|
||||
self.man_object_label = QtWidgets.QLabel('%s:' % _("Geo Obj"))
|
||||
self.man_object_label.setToolTip(
|
||||
_("Geometry object used to create the manual cutout.")
|
||||
)
|
||||
|
@ -241,7 +242,7 @@ class CutOut(FlatCAMTool):
|
|||
hlay3 = QtWidgets.QHBoxLayout()
|
||||
self.layout.addLayout(hlay3)
|
||||
|
||||
self.man_geo_label = QtWidgets.QLabel(_("Manual Geo:"))
|
||||
self.man_geo_label = QtWidgets.QLabel('%s:' % _("Manual Geo"))
|
||||
self.man_geo_label.setToolTip(
|
||||
_("If the object to be cutout is a Gerber\n"
|
||||
"first create a Geometry that surrounds it,\n"
|
||||
|
@ -263,7 +264,7 @@ class CutOut(FlatCAMTool):
|
|||
hlay4 = QtWidgets.QHBoxLayout()
|
||||
self.layout.addLayout(hlay4)
|
||||
|
||||
self.man_bridge_gaps_label = QtWidgets.QLabel(_("Manual Add Bridge Gaps:"))
|
||||
self.man_bridge_gaps_label = QtWidgets.QLabel('%s:' % _("Manual Add Bridge Gaps"))
|
||||
self.man_bridge_gaps_label.setToolTip(
|
||||
_("Use the left mouse button (LMB) click\n"
|
||||
"to create a bridge gap to separate the PCB from\n"
|
||||
|
@ -292,6 +293,9 @@ class CutOut(FlatCAMTool):
|
|||
|
||||
self.flat_geometry = []
|
||||
|
||||
# this is the Geometry object generated in this class to be used for adding manual gaps
|
||||
self.man_cutout_obj = None
|
||||
|
||||
# Signals
|
||||
self.ff_cutout_object_btn.clicked.connect(self.on_freeform_cutout)
|
||||
self.rect_cutout_object_btn.clicked.connect(self.on_rectangular_cutout)
|
||||
|
@ -315,7 +319,12 @@ class CutOut(FlatCAMTool):
|
|||
else:
|
||||
try:
|
||||
if self.app.ui.tool_scroll_area.widget().objectName() == self.toolName:
|
||||
self.app.ui.splitter.setSizes([0, 1])
|
||||
# if tab is populated with the tool but it does not have the focus, focus on it
|
||||
if not self.app.ui.notebook.currentWidget() is self.app.ui.tool_tab:
|
||||
# focus on Tool Tab
|
||||
self.app.ui.notebook.setCurrentWidget(self.app.ui.tool_tab)
|
||||
else:
|
||||
self.app.ui.splitter.setSizes([0, 1])
|
||||
except AttributeError:
|
||||
pass
|
||||
else:
|
||||
|
@ -410,8 +419,9 @@ class CutOut(FlatCAMTool):
|
|||
self.app.inform.emit(_("[WARNING_NOTCL] Number of gaps value is missing. Add it and retry."))
|
||||
return
|
||||
|
||||
if gaps not in ['LR', 'TB', '2LR', '2TB', '4', '8']:
|
||||
self.app.inform.emit(_("[WARNING_NOTCL] Gaps value can be only one of: 'lr', 'tb', '2lr', '2tb', 4 or 8. "
|
||||
if gaps not in ['None', 'LR', 'TB', '2LR', '2TB', '4', '8']:
|
||||
self.app.inform.emit(_("[WARNING_NOTCL] Gaps value can be only one of: "
|
||||
"'None', 'lr', 'tb', '2lr', '2tb', 4 or 8. "
|
||||
"Fill in a correct value and retry. "))
|
||||
return
|
||||
|
||||
|
@ -446,44 +456,46 @@ class CutOut(FlatCAMTool):
|
|||
leny = (ymax - ymin) + (margin * 2)
|
||||
|
||||
proc_geometry = []
|
||||
if gaps == 'None':
|
||||
pass
|
||||
else:
|
||||
if gaps == '8' or gaps == '2LR':
|
||||
geom = self.subtract_poly_from_geo(geom,
|
||||
xmin - gapsize, # botleft_x
|
||||
py - gapsize + leny / 4, # botleft_y
|
||||
xmax + gapsize, # topright_x
|
||||
py + gapsize + leny / 4) # topright_y
|
||||
geom = self.subtract_poly_from_geo(geom,
|
||||
xmin - gapsize,
|
||||
py - gapsize - leny / 4,
|
||||
xmax + gapsize,
|
||||
py + gapsize - leny / 4)
|
||||
|
||||
if gaps == '8' or gaps == '2LR':
|
||||
geom = self.subtract_poly_from_geo(geom,
|
||||
xmin - gapsize, # botleft_x
|
||||
py - gapsize + leny / 4, # botleft_y
|
||||
xmax + gapsize, # topright_x
|
||||
py + gapsize + leny / 4) # topright_y
|
||||
geom = self.subtract_poly_from_geo(geom,
|
||||
xmin - gapsize,
|
||||
py - gapsize - leny / 4,
|
||||
xmax + gapsize,
|
||||
py + gapsize - leny / 4)
|
||||
if gaps == '8' or gaps == '2TB':
|
||||
geom = self.subtract_poly_from_geo(geom,
|
||||
px - gapsize + lenx / 4,
|
||||
ymin - gapsize,
|
||||
px + gapsize + lenx / 4,
|
||||
ymax + gapsize)
|
||||
geom = self.subtract_poly_from_geo(geom,
|
||||
px - gapsize - lenx / 4,
|
||||
ymin - gapsize,
|
||||
px + gapsize - lenx / 4,
|
||||
ymax + gapsize)
|
||||
|
||||
if gaps == '8' or gaps == '2TB':
|
||||
geom = self.subtract_poly_from_geo(geom,
|
||||
px - gapsize + lenx / 4,
|
||||
ymin - gapsize,
|
||||
px + gapsize + lenx / 4,
|
||||
ymax + gapsize)
|
||||
geom = self.subtract_poly_from_geo(geom,
|
||||
px - gapsize - lenx / 4,
|
||||
ymin - gapsize,
|
||||
px + gapsize - lenx / 4,
|
||||
ymax + gapsize)
|
||||
if gaps == '4' or gaps == 'LR':
|
||||
geom = self.subtract_poly_from_geo(geom,
|
||||
xmin - gapsize,
|
||||
py - gapsize,
|
||||
xmax + gapsize,
|
||||
py + gapsize)
|
||||
|
||||
if gaps == '4' or gaps == 'LR':
|
||||
geom = self.subtract_poly_from_geo(geom,
|
||||
xmin - gapsize,
|
||||
py - gapsize,
|
||||
xmax + gapsize,
|
||||
py + gapsize)
|
||||
|
||||
if gaps == '4' or gaps == 'TB':
|
||||
geom = self.subtract_poly_from_geo(geom,
|
||||
px - gapsize,
|
||||
ymin - gapsize,
|
||||
px + gapsize,
|
||||
ymax + gapsize)
|
||||
if gaps == '4' or gaps == 'TB':
|
||||
geom = self.subtract_poly_from_geo(geom,
|
||||
px - gapsize,
|
||||
ymin - gapsize,
|
||||
px + gapsize,
|
||||
ymax + gapsize)
|
||||
|
||||
try:
|
||||
for g in geom:
|
||||
|
@ -603,8 +615,9 @@ class CutOut(FlatCAMTool):
|
|||
self.app.inform.emit(_("[WARNING_NOTCL] Number of gaps value is missing. Add it and retry."))
|
||||
return
|
||||
|
||||
if gaps not in ['LR', 'TB', '2LR', '2TB', '4', '8']:
|
||||
self.app.inform.emit(_("[WARNING_NOTCL] Gaps value can be only one of: 'lr', 'tb', '2lr', '2tb', 4 or 8. "
|
||||
if gaps not in ['None', 'LR', 'TB', '2LR', '2TB', '4', '8']:
|
||||
self.app.inform.emit(_("[WARNING_NOTCL] Gaps value can be only one of: "
|
||||
"'None', 'lr', 'tb', '2lr', '2tb', 4 or 8. "
|
||||
"Fill in a correct value and retry. "))
|
||||
return
|
||||
|
||||
|
@ -630,43 +643,46 @@ class CutOut(FlatCAMTool):
|
|||
lenx = (xmax - xmin) + (margin * 2)
|
||||
leny = (ymax - ymin) + (margin * 2)
|
||||
|
||||
if gaps == '8' or gaps == '2LR':
|
||||
geom = self.subtract_poly_from_geo(geom,
|
||||
xmin - gapsize, # botleft_x
|
||||
py - gapsize + leny / 4, # botleft_y
|
||||
xmax + gapsize, # topright_x
|
||||
py + gapsize + leny / 4) # topright_y
|
||||
geom = self.subtract_poly_from_geo(geom,
|
||||
xmin - gapsize,
|
||||
py - gapsize - leny / 4,
|
||||
xmax + gapsize,
|
||||
py + gapsize - leny / 4)
|
||||
if gaps == 'None':
|
||||
pass
|
||||
else:
|
||||
if gaps == '8' or gaps == '2LR':
|
||||
geom = self.subtract_poly_from_geo(geom,
|
||||
xmin - gapsize, # botleft_x
|
||||
py - gapsize + leny / 4, # botleft_y
|
||||
xmax + gapsize, # topright_x
|
||||
py + gapsize + leny / 4) # topright_y
|
||||
geom = self.subtract_poly_from_geo(geom,
|
||||
xmin - gapsize,
|
||||
py - gapsize - leny / 4,
|
||||
xmax + gapsize,
|
||||
py + gapsize - leny / 4)
|
||||
|
||||
if gaps == '8' or gaps == '2TB':
|
||||
geom = self.subtract_poly_from_geo(geom,
|
||||
px - gapsize + lenx / 4,
|
||||
ymin - gapsize,
|
||||
px + gapsize + lenx / 4,
|
||||
ymax + gapsize)
|
||||
geom = self.subtract_poly_from_geo(geom,
|
||||
px - gapsize - lenx / 4,
|
||||
ymin - gapsize,
|
||||
px + gapsize - lenx / 4,
|
||||
ymax + gapsize)
|
||||
if gaps == '8' or gaps == '2TB':
|
||||
geom = self.subtract_poly_from_geo(geom,
|
||||
px - gapsize + lenx / 4,
|
||||
ymin - gapsize,
|
||||
px + gapsize + lenx / 4,
|
||||
ymax + gapsize)
|
||||
geom = self.subtract_poly_from_geo(geom,
|
||||
px - gapsize - lenx / 4,
|
||||
ymin - gapsize,
|
||||
px + gapsize - lenx / 4,
|
||||
ymax + gapsize)
|
||||
|
||||
if gaps == '4' or gaps == 'LR':
|
||||
geom = self.subtract_poly_from_geo(geom,
|
||||
xmin - gapsize,
|
||||
py - gapsize,
|
||||
xmax + gapsize,
|
||||
py + gapsize)
|
||||
if gaps == '4' or gaps == 'LR':
|
||||
geom = self.subtract_poly_from_geo(geom,
|
||||
xmin - gapsize,
|
||||
py - gapsize,
|
||||
xmax + gapsize,
|
||||
py + gapsize)
|
||||
|
||||
if gaps == '4' or gaps == 'TB':
|
||||
geom = self.subtract_poly_from_geo(geom,
|
||||
px - gapsize,
|
||||
ymin - gapsize,
|
||||
px + gapsize,
|
||||
ymax + gapsize)
|
||||
if gaps == '4' or gaps == 'TB':
|
||||
geom = self.subtract_poly_from_geo(geom,
|
||||
px - gapsize,
|
||||
ymin - gapsize,
|
||||
px + gapsize,
|
||||
ymax + gapsize)
|
||||
try:
|
||||
for g in geom:
|
||||
proc_geometry.append(g)
|
||||
|
@ -743,6 +759,15 @@ class CutOut(FlatCAMTool):
|
|||
"Add it and retry."))
|
||||
return
|
||||
|
||||
name = self.man_object_combo.currentText()
|
||||
# Get Geometry source object to be used as target for Manual adding Gaps
|
||||
try:
|
||||
self.man_cutout_obj = self.app.collection.get_by_name(str(name))
|
||||
except Exception as e:
|
||||
log.debug("CutOut.on_manual_cutout() --> %s" % str(e))
|
||||
self.app.inform.emit(_("[ERROR_NOTCL] Could not retrieve Geometry object: %s") % name)
|
||||
return "Could not retrieve object: %s" % name
|
||||
|
||||
self.app.plotcanvas.vis_disconnect('key_press', self.app.ui.keyPressEvent)
|
||||
self.app.plotcanvas.vis_disconnect('mouse_press', self.app.on_mouse_click_over_plot)
|
||||
self.app.plotcanvas.vis_disconnect('mouse_release', self.app.on_mouse_click_release_over_plot)
|
||||
|
@ -770,29 +795,43 @@ class CutOut(FlatCAMTool):
|
|||
self.app.geo_editor.tool_shape.clear(update=True)
|
||||
self.app.geo_editor.tool_shape.enabled = False
|
||||
self.gapFinished.emit()
|
||||
# if RMB then we exit
|
||||
elif event.button == 2:
|
||||
self.app.plotcanvas.vis_disconnect('key_press', self.on_key_press)
|
||||
self.app.plotcanvas.vis_disconnect('mouse_move', self.on_mouse_move)
|
||||
self.app.plotcanvas.vis_disconnect('mouse_release', self.doit)
|
||||
self.app.plotcanvas.vis_connect('key_press', self.app.ui.keyPressEvent)
|
||||
self.app.plotcanvas.vis_connect('mouse_press', self.app.on_mouse_click_over_plot)
|
||||
self.app.plotcanvas.vis_connect('mouse_release', self.app.on_mouse_click_release_over_plot)
|
||||
self.app.plotcanvas.vis_connect('mouse_move', self.app.on_mouse_move_over_plot)
|
||||
|
||||
# Remove any previous utility shape
|
||||
self.app.geo_editor.tool_shape.clear(update=True)
|
||||
self.app.geo_editor.tool_shape.enabled = False
|
||||
|
||||
def on_manual_cutout(self, click_pos):
|
||||
name = self.man_object_combo.currentText()
|
||||
|
||||
# Get source object.
|
||||
try:
|
||||
cutout_obj = self.app.collection.get_by_name(str(name))
|
||||
self.man_cutout_obj = self.app.collection.get_by_name(str(name))
|
||||
except Exception as e:
|
||||
log.debug("CutOut.on_manual_cutout() --> %s" % str(e))
|
||||
self.app.inform.emit(_("[ERROR_NOTCL] Could not retrieve Geometry object: %s") % name)
|
||||
return "Could not retrieve object: %s" % name
|
||||
|
||||
if cutout_obj is None:
|
||||
self.app.inform.emit(_("[ERROR_NOTCL] Geometry object for manual cutout not found: %s") % cutout_obj)
|
||||
if self.man_cutout_obj is None:
|
||||
self.app.inform.emit(
|
||||
_("[ERROR_NOTCL] Geometry object for manual cutout not found: %s") % self.man_cutout_obj)
|
||||
return
|
||||
|
||||
# use the snapped position as reference
|
||||
snapped_pos = self.app.geo_editor.snap(click_pos[0], click_pos[1])
|
||||
|
||||
cut_poly = self.cutting_geo(pos=(snapped_pos[0], snapped_pos[1]))
|
||||
cutout_obj.subtract_polygon(cut_poly)
|
||||
self.man_cutout_obj.subtract_polygon(cut_poly)
|
||||
|
||||
cutout_obj.plot()
|
||||
self.man_cutout_obj.plot()
|
||||
self.app.inform.emit(_("[success] Added manual Bridge Gap."))
|
||||
|
||||
self.app.should_we_save = True
|
||||
|
@ -864,9 +903,17 @@ class CutOut(FlatCAMTool):
|
|||
geo = geo_union.convex_hull
|
||||
geo_obj.solid_geometry = geo.buffer(margin + abs(dia / 2))
|
||||
elif kind == 'single':
|
||||
x0, y0, x1, y1 = geo_union.bounds
|
||||
geo = box(x0, y0, x1, y1)
|
||||
geo_obj.solid_geometry = geo.buffer(margin + abs(dia / 2))
|
||||
if isinstance(geo_union, Polygon) or \
|
||||
(isinstance(geo_union, list) and len(geo_union) == 1) or \
|
||||
(isinstance(geo_union, MultiPolygon) and len(geo_union) == 1):
|
||||
geo_obj.solid_geometry = geo_union.buffer(margin + abs(dia / 2)).exterior
|
||||
elif isinstance(geo_union, MultiPolygon):
|
||||
x0, y0, x1, y1 = geo_union.bounds
|
||||
geo = box(x0, y0, x1, y1)
|
||||
geo_obj.solid_geometry = geo.buffer(margin + abs(dia / 2))
|
||||
else:
|
||||
self.app.inform.emit(_("[ERROR_NOTCL] Geometry not supported for cutout: %s") % type(geo_union))
|
||||
return 'fail'
|
||||
else:
|
||||
geo = geo_union
|
||||
geo = geo.buffer(margin + abs(dia / 2))
|
||||
|
@ -911,11 +958,67 @@ class CutOut(FlatCAMTool):
|
|||
|
||||
snap_x, snap_y = self.app.geo_editor.snap(x, y)
|
||||
|
||||
geo = self.cutting_geo(pos=(snap_x, snap_y))
|
||||
# #################################################
|
||||
# ### This section makes the cutting geo to #######
|
||||
# ### rotate if it intersects the target geo ######
|
||||
# #################################################
|
||||
cut_geo = self.cutting_geo(pos=(snap_x, snap_y))
|
||||
man_geo = self.man_cutout_obj.solid_geometry
|
||||
|
||||
def get_angle(geo):
|
||||
line = cut_geo.intersection(geo)
|
||||
|
||||
try:
|
||||
pt1_x = line.coords[0][0]
|
||||
pt1_y = line.coords[0][1]
|
||||
pt2_x = line.coords[1][0]
|
||||
pt2_y = line.coords[1][1]
|
||||
dx = pt1_x - pt2_x
|
||||
dy = pt1_y - pt2_y
|
||||
|
||||
if dx == 0 or dy == 0:
|
||||
angle = 0
|
||||
else:
|
||||
radian = math.atan(dx / dy)
|
||||
angle = radian * 180 / math.pi
|
||||
except Exception as e:
|
||||
angle = 0
|
||||
return angle
|
||||
|
||||
try:
|
||||
rot_angle = 0
|
||||
for geo_el in man_geo:
|
||||
if isinstance(geo_el, Polygon):
|
||||
work_geo = geo_el.exterior
|
||||
if cut_geo.intersects(work_geo):
|
||||
rot_angle = get_angle(geo=work_geo)
|
||||
else:
|
||||
rot_angle = 0
|
||||
else:
|
||||
rot_angle = 0
|
||||
if cut_geo.intersects(geo_el):
|
||||
rot_angle = get_angle(geo=geo_el)
|
||||
if rot_angle != 0:
|
||||
break
|
||||
except TypeError:
|
||||
if isinstance(man_geo, Polygon):
|
||||
work_geo = man_geo.exterior
|
||||
if cut_geo.intersects(work_geo):
|
||||
rot_angle = get_angle(geo=work_geo)
|
||||
else:
|
||||
rot_angle = 0
|
||||
else:
|
||||
rot_angle = 0
|
||||
if cut_geo.intersects(man_geo):
|
||||
rot_angle = get_angle(geo=man_geo)
|
||||
|
||||
# rotate only if there is an angle to rotate to
|
||||
if rot_angle != 0:
|
||||
cut_geo = affinity.rotate(cut_geo, -rot_angle)
|
||||
|
||||
# Remove any previous utility shape
|
||||
self.app.geo_editor.tool_shape.clear(update=True)
|
||||
self.draw_utility_geometry(geo=geo)
|
||||
self.draw_utility_geometry(geo=cut_geo)
|
||||
|
||||
def draw_utility_geometry(self, geo):
|
||||
self.app.geo_editor.tool_shape.add(
|
||||
|
|
|
@ -44,7 +44,7 @@ class DblSidedTool(FlatCAMTool):
|
|||
self.gerber_object_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
|
||||
self.gerber_object_combo.setCurrentIndex(1)
|
||||
|
||||
self.botlay_label = QtWidgets.QLabel(_("<b>GERBER:</b>"))
|
||||
self.botlay_label = QtWidgets.QLabel("<b>%s:</b>" % _("GERBER"))
|
||||
self.botlay_label.setToolTip(
|
||||
"Gerber to be mirrored."
|
||||
)
|
||||
|
@ -68,7 +68,7 @@ class DblSidedTool(FlatCAMTool):
|
|||
self.exc_object_combo.setRootModelIndex(self.app.collection.index(1, 0, QtCore.QModelIndex()))
|
||||
self.exc_object_combo.setCurrentIndex(1)
|
||||
|
||||
self.excobj_label = QtWidgets.QLabel(_("<b>EXCELLON:</b>"))
|
||||
self.excobj_label = QtWidgets.QLabel("<b>%s:</b>" % _("EXCELLON"))
|
||||
self.excobj_label.setToolTip(
|
||||
_("Excellon Object to be mirrored.")
|
||||
)
|
||||
|
@ -92,7 +92,7 @@ class DblSidedTool(FlatCAMTool):
|
|||
self.geo_object_combo.setRootModelIndex(self.app.collection.index(2, 0, QtCore.QModelIndex()))
|
||||
self.geo_object_combo.setCurrentIndex(1)
|
||||
|
||||
self.geoobj_label = QtWidgets.QLabel(_("<b>GEOMETRY</b>:"))
|
||||
self.geoobj_label = QtWidgets.QLabel("<b>%s</b>:" % _("GEOMETRY"))
|
||||
self.geoobj_label.setToolTip(
|
||||
_("Geometry Obj to be mirrored.")
|
||||
)
|
||||
|
@ -149,7 +149,7 @@ class DblSidedTool(FlatCAMTool):
|
|||
|
||||
# ## Point/Box
|
||||
self.point_box_container = QtWidgets.QVBoxLayout()
|
||||
self.pb_label = QtWidgets.QLabel("<b>%s</b>" % _('Point/Box Reference:'))
|
||||
self.pb_label = QtWidgets.QLabel("<b>%s:</b>" % _('Point/Box Reference'))
|
||||
self.pb_label.setToolTip(
|
||||
_("If 'Point' is selected above it store the coordinates (x, y) through which\n"
|
||||
"the mirroring axis passes.\n"
|
||||
|
@ -189,7 +189,7 @@ class DblSidedTool(FlatCAMTool):
|
|||
self.box_combo_type.hide()
|
||||
|
||||
# ## Alignment holes
|
||||
self.ah_label = QtWidgets.QLabel("<b>%s</b>" % _('Alignment Drill Coordinates:'))
|
||||
self.ah_label = QtWidgets.QLabel("<b>%s:</b>" % _('Alignment Drill Coordinates'))
|
||||
self.ah_label.setToolTip(
|
||||
_("Alignment holes (x1, y1), (x2, y2), ... "
|
||||
"on one side of the mirror axis. For each set of (x, y) coordinates\n"
|
||||
|
@ -220,7 +220,7 @@ class DblSidedTool(FlatCAMTool):
|
|||
grid_lay3.addWidget(self.add_drill_point_button, 0, 1)
|
||||
|
||||
# ## Drill diameter for alignment holes
|
||||
self.dt_label = QtWidgets.QLabel("<b>%s</b>:" % _('Alignment Drill Diameter'))
|
||||
self.dt_label = QtWidgets.QLabel("<b>%s:</b>" % _('Alignment Drill Diameter'))
|
||||
self.dt_label.setToolTip(
|
||||
_("Diameter of the drill for the "
|
||||
"alignment holes.")
|
||||
|
@ -231,7 +231,7 @@ class DblSidedTool(FlatCAMTool):
|
|||
self.layout.addLayout(hlay)
|
||||
|
||||
self.drill_dia = FCEntry()
|
||||
self.dd_label = QtWidgets.QLabel(_("Drill diam.:"))
|
||||
self.dd_label = QtWidgets.QLabel('%s:' % _("Drill dia"))
|
||||
self.dd_label.setToolTip(
|
||||
_("Diameter of the drill for the "
|
||||
"alignment holes.")
|
||||
|
@ -288,7 +288,12 @@ class DblSidedTool(FlatCAMTool):
|
|||
else:
|
||||
try:
|
||||
if self.app.ui.tool_scroll_area.widget().objectName() == self.toolName:
|
||||
self.app.ui.splitter.setSizes([0, 1])
|
||||
# if tab is populated with the tool but it does not have the focus, focus on it
|
||||
if not self.app.ui.notebook.currentWidget() is self.app.ui.tool_tab:
|
||||
# focus on Tool Tab
|
||||
self.app.ui.notebook.setCurrentWidget(self.app.ui.tool_tab)
|
||||
else:
|
||||
self.app.ui.splitter.setSizes([0, 1])
|
||||
except AttributeError:
|
||||
pass
|
||||
else:
|
||||
|
|
|
@ -53,7 +53,7 @@ class Film(FlatCAMTool):
|
|||
self.tf_type_obj_combo.setItemIcon(0, QtGui.QIcon("share/flatcam_icon16.png"))
|
||||
self.tf_type_obj_combo.setItemIcon(2, QtGui.QIcon("share/geometry16.png"))
|
||||
|
||||
self.tf_type_obj_combo_label = QtWidgets.QLabel(_("Object Type:"))
|
||||
self.tf_type_obj_combo_label = QtWidgets.QLabel('%s:' % _("Object Type"))
|
||||
self.tf_type_obj_combo_label.setToolTip(
|
||||
_("Specify the type of object for which to create the film.\n"
|
||||
"The object can be of type: Gerber or Geometry.\n"
|
||||
|
@ -68,7 +68,7 @@ class Film(FlatCAMTool):
|
|||
self.tf_object_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
|
||||
self.tf_object_combo.setCurrentIndex(1)
|
||||
|
||||
self.tf_object_label = QtWidgets.QLabel(_("Film Object:"))
|
||||
self.tf_object_label = QtWidgets.QLabel('%s:' % _("Film Object"))
|
||||
self.tf_object_label.setToolTip(
|
||||
_("Object for which to create the film.")
|
||||
)
|
||||
|
@ -101,7 +101,7 @@ class Film(FlatCAMTool):
|
|||
self.tf_box_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
|
||||
self.tf_box_combo.setCurrentIndex(1)
|
||||
|
||||
self.tf_box_combo_label = QtWidgets.QLabel(_("Box Object:"))
|
||||
self.tf_box_combo_label = QtWidgets.QLabel('%s:' % _("Box Object"))
|
||||
self.tf_box_combo_label.setToolTip(
|
||||
_("The actual object that is used a container for the\n "
|
||||
"selected object for which we create the film.\n"
|
||||
|
@ -127,7 +127,7 @@ class Film(FlatCAMTool):
|
|||
# Boundary for negative film generation
|
||||
|
||||
self.boundary_entry = FCEntry()
|
||||
self.boundary_label = QtWidgets.QLabel(_("Border:"))
|
||||
self.boundary_label = QtWidgets.QLabel('%s:' % _("Border"))
|
||||
self.boundary_label.setToolTip(
|
||||
_("Specify a border around the object.\n"
|
||||
"Only for negative film.\n"
|
||||
|
@ -141,7 +141,7 @@ class Film(FlatCAMTool):
|
|||
tf_form_layout.addRow(self.boundary_label, self.boundary_entry)
|
||||
|
||||
self.film_scale_entry = FCEntry()
|
||||
self.film_scale_label = QtWidgets.QLabel(_("Scale Stroke:"))
|
||||
self.film_scale_label = QtWidgets.QLabel('%s:' % _("Scale Stroke"))
|
||||
self.film_scale_label.setToolTip(
|
||||
_("Scale the line stroke thickness of each feature in the SVG file.\n"
|
||||
"It means that the line that envelope each SVG feature will be thicker or thinner,\n"
|
||||
|
@ -190,7 +190,12 @@ class Film(FlatCAMTool):
|
|||
else:
|
||||
try:
|
||||
if self.app.ui.tool_scroll_area.widget().objectName() == self.toolName:
|
||||
self.app.ui.splitter.setSizes([0, 1])
|
||||
# if tab is populated with the tool but it does not have the focus, focus on it
|
||||
if not self.app.ui.notebook.currentWidget() is self.app.ui.tool_tab:
|
||||
# focus on Tool Tab
|
||||
self.app.ui.notebook.setCurrentWidget(self.app.ui.tool_tab)
|
||||
else:
|
||||
self.app.ui.splitter.setSizes([0, 1])
|
||||
except AttributeError:
|
||||
pass
|
||||
else:
|
||||
|
|
|
@ -50,7 +50,7 @@ class ToolImage(FlatCAMTool):
|
|||
self.tf_type_obj_combo.setItemIcon(0, QtGui.QIcon("share/flatcam_icon16.png"))
|
||||
self.tf_type_obj_combo.setItemIcon(1, QtGui.QIcon("share/geometry16.png"))
|
||||
|
||||
self.tf_type_obj_combo_label = QtWidgets.QLabel(_("Object Type:"))
|
||||
self.tf_type_obj_combo_label = QtWidgets.QLabel('%s:' % _("Object Type"))
|
||||
self.tf_type_obj_combo_label.setToolTip(
|
||||
_("Specify the type of object to create from the image.\n"
|
||||
"It can be of type: Gerber or Geometry.")
|
||||
|
@ -60,7 +60,7 @@ class ToolImage(FlatCAMTool):
|
|||
|
||||
# DPI value of the imported image
|
||||
self.dpi_entry = IntEntry()
|
||||
self.dpi_label = QtWidgets.QLabel(_("DPI value:"))
|
||||
self.dpi_label = QtWidgets.QLabel('%s:' % _("DPI value"))
|
||||
self.dpi_label.setToolTip(
|
||||
_("Specify a DPI value for the image.")
|
||||
)
|
||||
|
@ -69,7 +69,7 @@ class ToolImage(FlatCAMTool):
|
|||
self.emty_lbl = QtWidgets.QLabel("")
|
||||
self.layout.addWidget(self.emty_lbl)
|
||||
|
||||
self.detail_label = QtWidgets.QLabel("<font size=4><b>%s:</b>" % _('Level of detail'))
|
||||
self.detail_label = QtWidgets.QLabel("<font size=4><b>%s:</b></font>" % _('Level of detail'))
|
||||
self.layout.addWidget(self.detail_label)
|
||||
|
||||
ti2_form_layout = QtWidgets.QFormLayout()
|
||||
|
@ -157,7 +157,12 @@ class ToolImage(FlatCAMTool):
|
|||
else:
|
||||
try:
|
||||
if self.app.ui.tool_scroll_area.widget().objectName() == self.toolName:
|
||||
self.app.ui.splitter.setSizes([0, 1])
|
||||
# if tab is populated with the tool but it does not have the focus, focus on it
|
||||
if not self.app.ui.notebook.currentWidget() is self.app.ui.tool_tab:
|
||||
# focus on Tool Tab
|
||||
self.app.ui.notebook.setCurrentWidget(self.app.ui.tool_tab)
|
||||
else:
|
||||
self.app.ui.splitter.setSizes([0, 1])
|
||||
except AttributeError:
|
||||
pass
|
||||
else:
|
||||
|
|
|
@ -40,7 +40,7 @@ class Measurement(FlatCAMTool):
|
|||
form_layout = QtWidgets.QFormLayout()
|
||||
self.layout.addLayout(form_layout)
|
||||
|
||||
self.units_label = QtWidgets.QLabel(_("Units:"))
|
||||
self.units_label = QtWidgets.QLabel('%s:' % _("Units"))
|
||||
self.units_label.setToolTip(_("Those are the units in which the distance is measured."))
|
||||
self.units_value = QtWidgets.QLabel("%s" % str({'mm': _("METRIC (mm)"), 'in': _("INCH (in)")}[self.units]))
|
||||
self.units_value.setDisabled(True)
|
||||
|
@ -51,10 +51,10 @@ class Measurement(FlatCAMTool):
|
|||
self.stop_label = QtWidgets.QLabel("<b>%s</b> %s:" % (_('Stop'), _('Coords')))
|
||||
self.stop_label.setToolTip(_("This is the measuring Stop point coordinates."))
|
||||
|
||||
self.distance_x_label = QtWidgets.QLabel(_("Dx:"))
|
||||
self.distance_x_label = QtWidgets.QLabel('%s:' % _("Dx"))
|
||||
self.distance_x_label.setToolTip(_("This is the distance measured over the X axis."))
|
||||
|
||||
self.distance_y_label = QtWidgets.QLabel(_("Dy:"))
|
||||
self.distance_y_label = QtWidgets.QLabel('%s:' % _("Dy"))
|
||||
self.distance_y_label.setToolTip(_("This is the distance measured over the Y axis."))
|
||||
|
||||
self.total_distance_label = QtWidgets.QLabel("<b>%s:</b>" % _('DISTANCE'))
|
||||
|
|
|
@ -10,10 +10,10 @@ from FlatCAMTool import FlatCAMTool
|
|||
from copy import copy, deepcopy
|
||||
from ObjectCollection import *
|
||||
import time
|
||||
from shapely.geometry import base
|
||||
|
||||
import gettext
|
||||
import FlatCAMTranslation as fcTranslate
|
||||
from shapely.geometry import base
|
||||
import builtins
|
||||
|
||||
fcTranslate.apply_language('strings')
|
||||
|
@ -53,22 +53,46 @@ class NonCopperClear(FlatCAMTool, Gerber):
|
|||
form_layout = QtWidgets.QFormLayout()
|
||||
self.tools_box.addLayout(form_layout)
|
||||
|
||||
# ## Object
|
||||
self.object_combo = QtWidgets.QComboBox()
|
||||
self.object_combo.setModel(self.app.collection)
|
||||
self.object_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
|
||||
self.object_combo.setCurrentIndex(1)
|
||||
# ################################################
|
||||
# ##### Type of object to be copper cleaned ######
|
||||
# ################################################
|
||||
self.type_obj_combo = QtWidgets.QComboBox()
|
||||
self.type_obj_combo.addItem("Gerber")
|
||||
self.type_obj_combo.addItem("Excellon")
|
||||
self.type_obj_combo.addItem("Geometry")
|
||||
|
||||
self.object_label = QtWidgets.QLabel("Gerber:")
|
||||
self.object_label.setToolTip(
|
||||
_("Gerber object to be cleared of excess copper. ")
|
||||
# we get rid of item1 ("Excellon") as it is not suitable
|
||||
self.type_obj_combo.view().setRowHidden(1, True)
|
||||
self.type_obj_combo.setItemIcon(0, QtGui.QIcon("share/flatcam_icon16.png"))
|
||||
self.type_obj_combo.setItemIcon(2, QtGui.QIcon("share/geometry16.png"))
|
||||
|
||||
self.type_obj_combo_label = QtWidgets.QLabel('%s:' % _("Obj Type"))
|
||||
self.type_obj_combo_label.setToolTip(
|
||||
_("Specify the type of object to be cleared of excess copper.\n"
|
||||
"It can be of type: Gerber or Geometry.\n"
|
||||
"What is selected here will dictate the kind\n"
|
||||
"of objects that will populate the 'Object' combobox.")
|
||||
)
|
||||
e_lab_0 = QtWidgets.QLabel('')
|
||||
self.type_obj_combo_label.setMinimumWidth(60)
|
||||
form_layout.addRow(self.type_obj_combo_label, self.type_obj_combo)
|
||||
|
||||
form_layout.addRow(self.object_label, self.object_combo)
|
||||
# ################################################
|
||||
# ##### The object to be copper cleaned ##########
|
||||
# ################################################
|
||||
self.obj_combo = QtWidgets.QComboBox()
|
||||
self.obj_combo.setModel(self.app.collection)
|
||||
self.obj_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
|
||||
self.obj_combo.setCurrentIndex(1)
|
||||
|
||||
self.object_label = QtWidgets.QLabel('%s:' % _("Object"))
|
||||
self.object_label.setToolTip(_("Object to be cleared of excess copper."))
|
||||
|
||||
form_layout.addRow(self.object_label, self.obj_combo)
|
||||
|
||||
e_lab_0 = QtWidgets.QLabel('')
|
||||
form_layout.addRow(e_lab_0)
|
||||
|
||||
#### Tools ## ##
|
||||
# ### Tools ## ##
|
||||
self.tools_table_label = QtWidgets.QLabel('<b>%s</b>' % _('Tools Table'))
|
||||
self.tools_table_label.setToolTip(
|
||||
_("Tools pool from which the algorithm\n"
|
||||
|
@ -110,23 +134,35 @@ class NonCopperClear(FlatCAMTool, Gerber):
|
|||
"Choosing the <B>V-Shape</B> Tool Type automatically will select the Operation Type "
|
||||
"in the resulting geometry as Isolation."))
|
||||
|
||||
self.empty_label = QtWidgets.QLabel('')
|
||||
self.tools_box.addWidget(self.empty_label)
|
||||
self.ncc_order_label = QtWidgets.QLabel('<b>%s:</b>' % _('Tool order'))
|
||||
self.ncc_order_label.setToolTip(_("This set the way that the tools in the tools table are used.\n"
|
||||
"'No' --> means that the used order is the one in the tool table\n"
|
||||
"'Forward' --> means that the tools will be ordered from small to big\n"
|
||||
"'Reverse' --> menas that the tools will ordered from big to small\n\n"
|
||||
"WARNING: using rest machining will automatically set the order\n"
|
||||
"in reverse and disable this control."))
|
||||
|
||||
self.ncc_order_radio = RadioSet([{'label': _('No'), 'value': 'no'},
|
||||
{'label': _('Forward'), 'value': 'fwd'},
|
||||
{'label': _('Reverse'), 'value': 'rev'}])
|
||||
self.ncc_order_radio.setToolTip(_("This set the way that the tools in the tools table are used.\n"
|
||||
"'No' --> means that the used order is the one in the tool table\n"
|
||||
"'Forward' --> means that the tools will be ordered from small to big\n"
|
||||
"'Reverse' --> menas that the tools will ordered from big to small\n\n"
|
||||
"WARNING: using rest machining will automatically set the order\n"
|
||||
"in reverse and disable this control."))
|
||||
form = QtWidgets.QFormLayout()
|
||||
self.tools_box.addLayout(form)
|
||||
form.addRow(QtWidgets.QLabel(''), QtWidgets.QLabel(''))
|
||||
form.addRow(self.ncc_order_label, self.ncc_order_radio)
|
||||
|
||||
# ### Add a new Tool ####
|
||||
hlay = QtWidgets.QHBoxLayout()
|
||||
self.tools_box.addLayout(hlay)
|
||||
|
||||
self.addtool_entry_lbl = QtWidgets.QLabel('<b>%s:</b>' % _('Tool Dia'))
|
||||
self.addtool_entry_lbl.setToolTip(
|
||||
_("Diameter for the new tool to add in the Tool Table")
|
||||
)
|
||||
self.addtool_entry = FCEntry2()
|
||||
|
||||
# hlay.addWidget(self.addtool_label)
|
||||
# hlay.addStretch()
|
||||
hlay.addWidget(self.addtool_entry_lbl)
|
||||
hlay.addWidget(self.addtool_entry)
|
||||
form.addRow(self.addtool_entry_lbl, self.addtool_entry)
|
||||
|
||||
grid2 = QtWidgets.QGridLayout()
|
||||
self.tools_box.addLayout(grid2)
|
||||
|
@ -159,7 +195,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
|
|||
grid3 = QtWidgets.QGridLayout()
|
||||
self.tools_box.addLayout(grid3)
|
||||
|
||||
e_lab_1 = QtWidgets.QLabel('')
|
||||
e_lab_1 = QtWidgets.QLabel('<b>%s:</b>' % _("Parameters"))
|
||||
grid3.addWidget(e_lab_1, 0, 0)
|
||||
|
||||
nccoverlabel = QtWidgets.QLabel(_('Overlap Rate:'))
|
||||
|
@ -178,7 +214,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
|
|||
self.ncc_overlap_entry = FCEntry()
|
||||
grid3.addWidget(self.ncc_overlap_entry, 1, 1)
|
||||
|
||||
nccmarginlabel = QtWidgets.QLabel(_('Margin:'))
|
||||
nccmarginlabel = QtWidgets.QLabel('%s:' % _('Margin'))
|
||||
nccmarginlabel.setToolTip(
|
||||
_("Bounding box margin.")
|
||||
)
|
||||
|
@ -187,7 +223,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
|
|||
grid3.addWidget(self.ncc_margin_entry, 2, 1)
|
||||
|
||||
# Method
|
||||
methodlabel = QtWidgets.QLabel(_('Method:'))
|
||||
methodlabel = QtWidgets.QLabel('%s:' % _('Method'))
|
||||
methodlabel.setToolTip(
|
||||
_("Algorithm for non-copper clearing:<BR>"
|
||||
"<B>Standard</B>: Fixed step inwards.<BR>"
|
||||
|
@ -203,7 +239,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
|
|||
grid3.addWidget(self.ncc_method_radio, 3, 1)
|
||||
|
||||
# Connect lines
|
||||
pathconnectlabel = QtWidgets.QLabel(_("Connect:"))
|
||||
pathconnectlabel = QtWidgets.QLabel('%s:' % _("Connect"))
|
||||
pathconnectlabel.setToolTip(
|
||||
_("Draw lines between resulting\n"
|
||||
"segments to minimize tool lifts.")
|
||||
|
@ -212,7 +248,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
|
|||
self.ncc_connect_cb = FCCheckBox()
|
||||
grid3.addWidget(self.ncc_connect_cb, 4, 1)
|
||||
|
||||
contourlabel = QtWidgets.QLabel(_("Contour:"))
|
||||
contourlabel = QtWidgets.QLabel('%s:' % _("Contour"))
|
||||
contourlabel.setToolTip(
|
||||
_("Cut around the perimeter of the polygon\n"
|
||||
"to trim rough edges.")
|
||||
|
@ -221,7 +257,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
|
|||
self.ncc_contour_cb = FCCheckBox()
|
||||
grid3.addWidget(self.ncc_contour_cb, 5, 1)
|
||||
|
||||
restlabel = QtWidgets.QLabel(_("Rest M.:"))
|
||||
restlabel = QtWidgets.QLabel('%s:' % _("Rest M."))
|
||||
restlabel.setToolTip(
|
||||
_("If checked, use 'rest machining'.\n"
|
||||
"Basically it will clear copper outside PCB features,\n"
|
||||
|
@ -236,7 +272,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
|
|||
grid3.addWidget(self.ncc_rest_cb, 6, 1)
|
||||
|
||||
# ## NCC Offset choice
|
||||
self.ncc_offset_choice_label = QtWidgets.QLabel(_("Offset:"))
|
||||
self.ncc_offset_choice_label = QtWidgets.QLabel('%s:' % _("Offset"))
|
||||
self.ncc_offset_choice_label.setToolTip(
|
||||
_("If used, it will add an offset to the copper features.\n"
|
||||
"The copper clearing will finish to a distance\n"
|
||||
|
@ -248,7 +284,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
|
|||
grid3.addWidget(self.ncc_choice_offset_cb, 7, 1)
|
||||
|
||||
# ## NCC Offset value
|
||||
self.ncc_offset_label = QtWidgets.QLabel(_("Offset value:"))
|
||||
self.ncc_offset_label = QtWidgets.QLabel('%s:' % _("Offset value"))
|
||||
self.ncc_offset_label.setToolTip(
|
||||
_("If used, it will add an offset to the copper features.\n"
|
||||
"The copper clearing will finish to a distance\n"
|
||||
|
@ -273,22 +309,27 @@ class NonCopperClear(FlatCAMTool, Gerber):
|
|||
self.ncc_offset_spinner.hide()
|
||||
|
||||
# ## Reference
|
||||
self.reference_radio = RadioSet([{'label': _('Itself'), 'value': 'itself'},
|
||||
{'label': _('Box'), 'value': 'box'}])
|
||||
self.reference_radio = RadioSet([
|
||||
{'label': _('Itself'), 'value': 'itself'},
|
||||
{"label": _("Area Selection"), "value": "area"},
|
||||
{'label': _("Reference Object"), 'value': 'box'}
|
||||
], orientation='vertical', stretch=False)
|
||||
self.reference_label = QtWidgets.QLabel(_("Reference:"))
|
||||
self.reference_label.setToolTip(
|
||||
_("- 'Itself': the non copper clearing extent\n"
|
||||
_("- 'Itself' - the non copper clearing extent\n"
|
||||
"is based on the object that is copper cleared.\n "
|
||||
"- 'Box': will do non copper clearing within the box\n"
|
||||
"specified by the object selected in the Ref. Object combobox.")
|
||||
"- 'Area Selection' - left mouse click to start selection of the area to be painted.\n"
|
||||
"Keeping a modifier key pressed (CTRL or SHIFT) will allow to add multiple areas.\n"
|
||||
"- 'Reference Object' - will do non copper clearing within the area\n"
|
||||
"specified by another object.")
|
||||
)
|
||||
grid3.addWidget(self.reference_label, 9, 0)
|
||||
grid3.addWidget(self.reference_radio, 9, 1)
|
||||
|
||||
grid4 = QtWidgets.QGridLayout()
|
||||
self.tools_box.addLayout(grid4)
|
||||
form1 = QtWidgets.QFormLayout()
|
||||
self.tools_box.addLayout(form1)
|
||||
|
||||
self.box_combo_type_label = QtWidgets.QLabel(_("Ref. Type:"))
|
||||
self.box_combo_type_label = QtWidgets.QLabel('%s:' % _("Ref. Type"))
|
||||
self.box_combo_type_label.setToolTip(
|
||||
_("The type of FlatCAM object to be used as non copper clearing reference.\n"
|
||||
"It can be Gerber, Excellon or Geometry.")
|
||||
|
@ -297,11 +338,9 @@ class NonCopperClear(FlatCAMTool, Gerber):
|
|||
self.box_combo_type.addItem(_("Gerber Reference Box Object"))
|
||||
self.box_combo_type.addItem(_("Excellon Reference Box Object"))
|
||||
self.box_combo_type.addItem(_("Geometry Reference Box Object"))
|
||||
form1.addRow(self.box_combo_type_label, self.box_combo_type)
|
||||
|
||||
grid4.addWidget(self.box_combo_type_label, 0, 0)
|
||||
grid4.addWidget(self.box_combo_type, 0, 1)
|
||||
|
||||
self.box_combo_label = QtWidgets.QLabel(_("Ref. Object:"))
|
||||
self.box_combo_label = QtWidgets.QLabel('%s:' % _("Ref. Object"))
|
||||
self.box_combo_label.setToolTip(
|
||||
_("The FlatCAM object to be used as non copper clearing reference.")
|
||||
)
|
||||
|
@ -309,8 +348,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
|
|||
self.box_combo.setModel(self.app.collection)
|
||||
self.box_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
|
||||
self.box_combo.setCurrentIndex(1)
|
||||
grid4.addWidget(self.box_combo_label, 1, 0)
|
||||
grid4.addWidget(self.box_combo, 1, 1)
|
||||
form1.addRow(self.box_combo_label, self.box_combo)
|
||||
|
||||
self.box_combo.hide()
|
||||
self.box_combo_label.hide()
|
||||
|
@ -323,6 +361,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
|
|||
"for non-copper routing.")
|
||||
)
|
||||
self.tools_box.addWidget(self.generate_ncc_button)
|
||||
self.tools_box.addStretch()
|
||||
|
||||
self.units = ''
|
||||
self.ncc_tools = {}
|
||||
|
@ -333,19 +372,32 @@ class NonCopperClear(FlatCAMTool, Gerber):
|
|||
self.obj_name = ""
|
||||
self.ncc_obj = None
|
||||
|
||||
self.sel_rect = []
|
||||
|
||||
self.bound_obj_name = ""
|
||||
self.bound_obj = None
|
||||
|
||||
self.tools_box.addStretch()
|
||||
self.first_click = False
|
||||
self.cursor_pos = None
|
||||
self.mouse_is_dragging = False
|
||||
|
||||
self.addtool_btn.clicked.connect(self.on_tool_add)
|
||||
self.addtool_entry.returnPressed.connect(self.on_tool_add)
|
||||
self.deltool_btn.clicked.connect(self.on_tool_delete)
|
||||
self.generate_ncc_button.clicked.connect(self.on_ncc)
|
||||
self.generate_ncc_button.clicked.connect(self.on_ncc_click)
|
||||
|
||||
self.box_combo_type.currentIndexChanged.connect(self.on_combo_box_type)
|
||||
self.reference_radio.group_toggle_fn = self.on_toggle_reference
|
||||
self.ncc_choice_offset_cb.stateChanged.connect(self.on_offset_choice)
|
||||
self.ncc_rest_cb.stateChanged.connect(self.on_rest_machining_check)
|
||||
self.ncc_order_radio.activated_custom[str].connect(self.on_order_changed)
|
||||
|
||||
self.type_obj_combo.currentIndexChanged.connect(self.on_type_obj_index_changed)
|
||||
|
||||
def on_type_obj_index_changed(self, index):
|
||||
obj_type = self.type_obj_combo.currentIndex()
|
||||
self.obj_combo.setRootModelIndex(self.app.collection.index(obj_type, 0, QtCore.QModelIndex()))
|
||||
self.obj_combo.setCurrentIndex(0)
|
||||
|
||||
def install(self, icon=None, separator=None, **kwargs):
|
||||
FlatCAMTool.install(self, icon, separator, shortcut='ALT+N', **kwargs)
|
||||
|
@ -360,7 +412,12 @@ class NonCopperClear(FlatCAMTool, Gerber):
|
|||
else:
|
||||
try:
|
||||
if self.app.ui.tool_scroll_area.widget().objectName() == self.toolName:
|
||||
self.app.ui.splitter.setSizes([0, 1])
|
||||
# if tab is populated with the tool but it does not have the focus, focus on it
|
||||
if not self.app.ui.notebook.currentWidget() is self.app.ui.tool_tab:
|
||||
# focus on Tool Tab
|
||||
self.app.ui.notebook.setCurrentWidget(self.app.ui.tool_tab)
|
||||
else:
|
||||
self.app.ui.splitter.setSizes([0, 1])
|
||||
except AttributeError:
|
||||
pass
|
||||
else:
|
||||
|
@ -382,6 +439,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
|
|||
def set_tool_ui(self):
|
||||
self.tools_frame.show()
|
||||
|
||||
self.ncc_order_radio.set_value(self.app.defaults["tools_nccorder"])
|
||||
self.ncc_overlap_entry.set_value(self.app.defaults["tools_nccoverlap"])
|
||||
self.ncc_margin_entry.set_value(self.app.defaults["tools_nccmargin"])
|
||||
self.ncc_method_radio.set_value(self.app.defaults["tools_nccmethod"])
|
||||
|
@ -484,7 +542,14 @@ class NonCopperClear(FlatCAMTool, Gerber):
|
|||
sorted_tools = []
|
||||
for k, v in self.ncc_tools.items():
|
||||
sorted_tools.append(float('%.4f' % float(v['tooldia'])))
|
||||
sorted_tools.sort()
|
||||
|
||||
order = self.ncc_order_radio.get_value()
|
||||
if order == 'fwd':
|
||||
sorted_tools.sort(reverse=False)
|
||||
elif order == 'rev':
|
||||
sorted_tools.sort(reverse=True)
|
||||
else:
|
||||
pass
|
||||
|
||||
n = len(sorted_tools)
|
||||
self.tools_table.setRowCount(n)
|
||||
|
@ -570,7 +635,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
|
|||
self.box_combo.setCurrentIndex(0)
|
||||
|
||||
def on_toggle_reference(self):
|
||||
if self.reference_radio.get_value() == "itself":
|
||||
if self.reference_radio.get_value() == "itself" or self.reference_radio.get_value() == "area":
|
||||
self.box_combo.hide()
|
||||
self.box_combo_label.hide()
|
||||
self.box_combo_type.hide()
|
||||
|
@ -589,6 +654,19 @@ class NonCopperClear(FlatCAMTool, Gerber):
|
|||
self.ncc_offset_label.hide()
|
||||
self.ncc_offset_spinner.hide()
|
||||
|
||||
def on_order_changed(self, order):
|
||||
if order != 'no':
|
||||
self.build_ui()
|
||||
|
||||
def on_rest_machining_check(self, state):
|
||||
if state:
|
||||
self.ncc_order_radio.set_value('rev')
|
||||
self.ncc_order_label.setDisabled(True)
|
||||
self.ncc_order_radio.setDisabled(True)
|
||||
else:
|
||||
self.ncc_order_label.setDisabled(False)
|
||||
self.ncc_order_radio.setDisabled(False)
|
||||
|
||||
def on_tool_add(self, dia=None, muted=None):
|
||||
|
||||
self.ui_disconnect()
|
||||
|
@ -743,10 +821,128 @@ class NonCopperClear(FlatCAMTool, Gerber):
|
|||
self.app.inform.emit(_("[success] Tool(s) deleted from Tool Table."))
|
||||
self.build_ui()
|
||||
|
||||
def on_ncc(self):
|
||||
def on_ncc_click(self):
|
||||
self.bound_obj = None
|
||||
self.ncc_obj = None
|
||||
|
||||
ref_choice = self.reference_radio.get_value()
|
||||
|
||||
if ref_choice == 'itself':
|
||||
self.bound_obj_name = self.object_combo.currentText()
|
||||
# Get source object.
|
||||
try:
|
||||
self.bound_obj = self.app.collection.get_by_name(self.bound_obj_name)
|
||||
except Exception as e:
|
||||
self.app.inform.emit(_("[ERROR_NOTCL] Could not retrieve object: %s") % self.obj_name)
|
||||
return "Could not retrieve object: %s" % self.obj_name
|
||||
self.on_ncc()
|
||||
elif ref_choice == 'box':
|
||||
self.bound_obj_name = self.box_combo.currentText()
|
||||
# Get source object.
|
||||
try:
|
||||
self.bound_obj = self.app.collection.get_by_name(self.bound_obj_name)
|
||||
except Exception as e:
|
||||
self.app.inform.emit(_("[ERROR_NOTCL] Could not retrieve object: %s") % self.bound_obj_name)
|
||||
return "Could not retrieve object: %s. Error: %s" % (self.bound_obj_name, str(e))
|
||||
self.on_ncc()
|
||||
else:
|
||||
self.app.inform.emit(_("[WARNING_NOTCL] Click the start point of the area."))
|
||||
|
||||
# use the first tool in the tool table; get the diameter
|
||||
tooldia = float('%.4f' % float(self.tools_table.item(0, 1).text()))
|
||||
|
||||
# To be called after clicking on the plot.
|
||||
def on_mouse_release(event):
|
||||
# do paint single only for left mouse clicks
|
||||
if event.button == 1:
|
||||
if self.first_click is False:
|
||||
self.first_click = True
|
||||
self.app.inform.emit(_("[WARNING_NOTCL] Click the end point of the paint area."))
|
||||
|
||||
self.cursor_pos = self.app.plotcanvas.vispy_canvas.translate_coords(event.pos)
|
||||
if self.app.grid_status() == True:
|
||||
self.cursor_pos = self.app.geo_editor.snap(self.cursor_pos[0], self.cursor_pos[1])
|
||||
else:
|
||||
self.app.inform.emit(_("Zone added. Right click to finish."))
|
||||
self.app.delete_selection_shape()
|
||||
|
||||
curr_pos = self.app.plotcanvas.vispy_canvas.translate_coords(event.pos)
|
||||
if self.app.grid_status() == True:
|
||||
curr_pos = self.app.geo_editor.snap(curr_pos[0], curr_pos[1])
|
||||
|
||||
x0, y0 = self.cursor_pos[0], self.cursor_pos[1]
|
||||
x1, y1 = curr_pos[0], curr_pos[1]
|
||||
pt1 = (x0, y0)
|
||||
pt2 = (x1, y0)
|
||||
pt3 = (x1, y1)
|
||||
pt4 = (x0, y1)
|
||||
self.sel_rect.append(Polygon([pt1, pt2, pt3, pt4]))
|
||||
|
||||
modifiers = QtWidgets.QApplication.keyboardModifiers()
|
||||
|
||||
if modifiers == QtCore.Qt.ShiftModifier:
|
||||
mod_key = 'Shift'
|
||||
elif modifiers == QtCore.Qt.ControlModifier:
|
||||
mod_key = 'Control'
|
||||
else:
|
||||
mod_key = None
|
||||
|
||||
if mod_key == self.app.defaults["global_mselect_key"]:
|
||||
self.first_click = False
|
||||
return
|
||||
|
||||
self.app.plotcanvas.vis_disconnect('mouse_release', on_mouse_release)
|
||||
self.app.plotcanvas.vis_disconnect('mouse_move', on_mouse_move)
|
||||
|
||||
self.app.plotcanvas.vis_connect('mouse_press', self.app.on_mouse_click_over_plot)
|
||||
self.app.plotcanvas.vis_connect('mouse_move', self.app.on_mouse_move_over_plot)
|
||||
self.app.plotcanvas.vis_connect('mouse_release', self.app.on_mouse_click_release_over_plot)
|
||||
|
||||
self.on_ncc()
|
||||
elif event.button == 2 and self.first_click is False and self.mouse_is_dragging is False:
|
||||
self.first_click = False
|
||||
self.app.plotcanvas.vis_disconnect('mouse_release', on_mouse_release)
|
||||
self.app.plotcanvas.vis_disconnect('mouse_move', on_mouse_move)
|
||||
|
||||
self.app.plotcanvas.vis_connect('mouse_press', self.app.on_mouse_click_over_plot)
|
||||
self.app.plotcanvas.vis_connect('mouse_move', self.app.on_mouse_move_over_plot)
|
||||
self.app.plotcanvas.vis_connect('mouse_release', self.app.on_mouse_click_release_over_plot)
|
||||
|
||||
self.on_ncc()
|
||||
|
||||
# called on mouse move
|
||||
def on_mouse_move(event):
|
||||
curr_pos = self.app.plotcanvas.vispy_canvas.translate_coords(event.pos)
|
||||
self.app.app_cursor.enabled = False
|
||||
|
||||
if event.button == 2:
|
||||
if event.is_dragging is True:
|
||||
self.mouse_is_dragging = True
|
||||
else:
|
||||
self.mouse_is_dragging = False
|
||||
|
||||
if self.app.grid_status() == True:
|
||||
self.app.app_cursor.enabled = True
|
||||
# Update cursor
|
||||
curr_pos = self.app.geo_editor.snap(curr_pos[0], curr_pos[1])
|
||||
self.app.app_cursor.set_data(np.asarray([(curr_pos[0], curr_pos[1])]),
|
||||
symbol='++', edge_color='black', size=20)
|
||||
|
||||
if self.first_click:
|
||||
self.app.delete_selection_shape()
|
||||
self.app.draw_moving_selection_shape(old_coords=(self.cursor_pos[0], self.cursor_pos[1]),
|
||||
coords=(curr_pos[0], curr_pos[1]),
|
||||
face_alpha=0.0)
|
||||
|
||||
self.app.plotcanvas.vis_disconnect('mouse_press', self.app.on_mouse_click_over_plot)
|
||||
self.app.plotcanvas.vis_disconnect('mouse_move', self.app.on_mouse_move_over_plot)
|
||||
self.app.plotcanvas.vis_disconnect('mouse_release', self.app.on_mouse_click_release_over_plot)
|
||||
|
||||
self.app.plotcanvas.vis_connect('mouse_release', on_mouse_release)
|
||||
self.app.plotcanvas.vis_connect('mouse_move', on_mouse_move)
|
||||
|
||||
def on_ncc(self):
|
||||
|
||||
try:
|
||||
over = float(self.ncc_overlap_entry.get_value())
|
||||
except ValueError:
|
||||
|
@ -797,24 +993,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
|
|||
pol_method = self.ncc_method_radio.get_value()
|
||||
pol_method = pol_method if pol_method else self.app.defaults["tools_nccmethod"]
|
||||
|
||||
if self.reference_radio.get_value() == 'itself':
|
||||
self.bound_obj_name = self.object_combo.currentText()
|
||||
# Get source object.
|
||||
try:
|
||||
self.bound_obj = self.app.collection.get_by_name(self.bound_obj_name)
|
||||
except Exception as e:
|
||||
self.app.inform.emit(_("[ERROR_NOTCL] Could not retrieve object: %s") % self.obj_name)
|
||||
return "Could not retrieve object: %s" % self.obj_name
|
||||
else:
|
||||
self.bound_obj_name = self.box_combo.currentText()
|
||||
# Get source object.
|
||||
try:
|
||||
self.bound_obj = self.app.collection.get_by_name(self.bound_obj_name)
|
||||
except Exception as e:
|
||||
self.app.inform.emit(_("[ERROR_NOTCL] Could not retrieve object: %s") % self.obj_name)
|
||||
return "Could not retrieve object: %s" % self.obj_name
|
||||
|
||||
self.obj_name = self.object_combo.currentText()
|
||||
self.obj_name = self.obj_combo.currentText()
|
||||
# Get source object.
|
||||
try:
|
||||
self.ncc_obj = self.app.collection.get_by_name(self.obj_name)
|
||||
|
@ -823,26 +1002,52 @@ class NonCopperClear(FlatCAMTool, Gerber):
|
|||
return "Could not retrieve object: %s" % self.obj_name
|
||||
|
||||
# Prepare non-copper polygons
|
||||
try:
|
||||
if not isinstance(self.bound_obj.solid_geometry, MultiPolygon):
|
||||
env_obj = cascaded_union(self.bound_obj.solid_geometry)
|
||||
env_obj = env_obj.convex_hull
|
||||
else:
|
||||
env_obj = self.bound_obj.solid_geometry.convex_hull
|
||||
bounding_box = env_obj.buffer(distance=margin, join_style=base.JOIN_STYLE.mitre)
|
||||
except Exception as e:
|
||||
log.debug("NonCopperClear.on_ncc() --> %s" % str(e))
|
||||
self.app.inform.emit(_("[ERROR_NOTCL] No object available."))
|
||||
return
|
||||
if self.reference_radio.get_value() == 'area':
|
||||
geo_n = self.sel_rect
|
||||
|
||||
geo_buff_list = []
|
||||
for poly in geo_n:
|
||||
geo_buff_list.append(poly.buffer(distance=margin, join_style=base.JOIN_STYLE.mitre))
|
||||
bounding_box = cascaded_union(geo_buff_list)
|
||||
else:
|
||||
geo_n = self.bound_obj.solid_geometry
|
||||
|
||||
try:
|
||||
if isinstance(geo_n, MultiPolygon):
|
||||
env_obj = geo_n.convex_hull
|
||||
elif (isinstance(geo_n, MultiPolygon) and len(geo_n) == 1) or \
|
||||
(isinstance(geo_n, list) and len(geo_n) == 1) and isinstance(geo_n[0], Polygon):
|
||||
env_obj = cascaded_union(geo_n)
|
||||
else:
|
||||
env_obj = cascaded_union(geo_n)
|
||||
env_obj = env_obj.convex_hull
|
||||
bounding_box = env_obj.buffer(distance=margin, join_style=base.JOIN_STYLE.mitre)
|
||||
except Exception as e:
|
||||
log.debug("NonCopperClear.on_ncc() --> %s" % str(e))
|
||||
self.app.inform.emit(_("[ERROR_NOTCL] No object available."))
|
||||
return
|
||||
|
||||
# calculate the empty area by subtracting the solid_geometry from the object bounding box geometry
|
||||
if self.ncc_choice_offset_cb.isChecked():
|
||||
self.app.inform.emit(_("[WARNING_NOTCL] Buffering ..."))
|
||||
offseted_geo = self.ncc_obj.solid_geometry.buffer(distance=ncc_offset_value)
|
||||
self.app.inform.emit(_("[success] Buffering finished ..."))
|
||||
empty = self.get_ncc_empty_area(target=offseted_geo, boundary=bounding_box)
|
||||
if isinstance(self.ncc_obj, FlatCAMGerber):
|
||||
if self.ncc_choice_offset_cb.isChecked():
|
||||
self.app.inform.emit(_("[WARNING_NOTCL] Buffering ..."))
|
||||
offseted_geo = self.ncc_obj.solid_geometry.buffer(distance=ncc_offset_value)
|
||||
self.app.inform.emit(_("[success] Buffering finished ..."))
|
||||
empty = self.get_ncc_empty_area(target=offseted_geo, boundary=bounding_box)
|
||||
else:
|
||||
empty = self.get_ncc_empty_area(target=self.ncc_obj.solid_geometry, boundary=bounding_box)
|
||||
elif isinstance(self.ncc_obj, FlatCAMGeometry):
|
||||
sol_geo = cascaded_union(self.ncc_obj.solid_geometry)
|
||||
if self.ncc_choice_offset_cb.isChecked():
|
||||
self.app.inform.emit(_("[WARNING_NOTCL] Buffering ..."))
|
||||
offseted_geo = sol_geo.buffer(distance=ncc_offset_value)
|
||||
self.app.inform.emit(_("[success] Buffering finished ..."))
|
||||
empty = self.get_ncc_empty_area(target=offseted_geo, boundary=bounding_box)
|
||||
else:
|
||||
empty = self.get_ncc_empty_area(target=sol_geo, boundary=bounding_box)
|
||||
else:
|
||||
empty = self.get_ncc_empty_area(target=self.ncc_obj.solid_geometry, boundary=bounding_box)
|
||||
self.inform.emit(_('[ERROR_NOTCL] The selected object is not suitable for copper clearing.'))
|
||||
return
|
||||
|
||||
if type(empty) is Polygon:
|
||||
empty = MultiPolygon([empty])
|
||||
|
@ -878,7 +1083,14 @@ class NonCopperClear(FlatCAMTool, Gerber):
|
|||
sorted_tools = []
|
||||
for k, v in self.ncc_tools.items():
|
||||
sorted_tools.append(float('%.4f' % float(v['tooldia'])))
|
||||
sorted_tools.sort(reverse=True)
|
||||
|
||||
order = self.ncc_order_radio.get_value()
|
||||
if order == 'fwd':
|
||||
sorted_tools.sort(reverse=False)
|
||||
elif order == 'rev':
|
||||
sorted_tools.sort(reverse=True)
|
||||
else:
|
||||
pass
|
||||
|
||||
# Do job in background
|
||||
proc = self.app.proc_container.new(_("Clearing Non-Copper areas."))
|
||||
|
@ -897,6 +1109,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
|
|||
# Generate area for each tool
|
||||
offset = sum(sorted_tools)
|
||||
current_uid = int(1)
|
||||
tool = eval(self.app.defaults["tools_ncctools"])[0]
|
||||
|
||||
for tool in sorted_tools:
|
||||
self.app.inform.emit(_('[success] Non-Copper Clearing with ToolDia = %s started.') % str(tool))
|
||||
|
@ -982,8 +1195,6 @@ class NonCopperClear(FlatCAMTool, Gerber):
|
|||
|
||||
# focus on Selected Tab
|
||||
self.app.ui.notebook.setCurrentWidget(self.app.ui.selected_tab)
|
||||
self.tools_frame.hide()
|
||||
self.app.ui.notebook.setTabText(2, _("Tools"))
|
||||
|
||||
# Promise object with the new name
|
||||
self.app.collection.promise(name)
|
||||
|
@ -1013,6 +1224,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
|
|||
cleared_by_last_tool = []
|
||||
rest_geo = []
|
||||
current_uid = 1
|
||||
tool = eval(self.app.defaults["tools_ncctools"])[0]
|
||||
|
||||
# repurposed flag for final object, geo_obj. True if it has any solid_geometry, False if not.
|
||||
app_obj.poly_not_cleared = True
|
||||
|
@ -1135,9 +1347,6 @@ class NonCopperClear(FlatCAMTool, Gerber):
|
|||
# reset the variable for next use
|
||||
app_obj.poly_not_cleared = False
|
||||
|
||||
self.tools_frame.hide()
|
||||
app_obj.ui.notebook.setTabText(2, "Tools")
|
||||
|
||||
# Promise object with the new name
|
||||
self.app.collection.promise(name)
|
||||
|
||||
|
@ -1157,3 +1366,14 @@ class NonCopperClear(FlatCAMTool, Gerber):
|
|||
|
||||
def reset_fields(self):
|
||||
self.object_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
|
||||
|
||||
def reset_usage(self):
|
||||
self.obj_name = ""
|
||||
self.ncc_obj = None
|
||||
self.bound_obj = None
|
||||
|
||||
self.first_click = False
|
||||
self.cursor_pos = None
|
||||
self.mouse_is_dragging = False
|
||||
|
||||
self.sel_rect = []
|
||||
|
|
|
@ -1,14 +1,15 @@
|
|||
# ########################################################## ##
|
||||
# ##########################################################
|
||||
# FlatCAM: 2D Post-processing for Manufacturing #
|
||||
# http://flatcam.org #
|
||||
# File Modified: Marius Adrian Stanciu (c) #
|
||||
# Date: 3/10/2019 #
|
||||
# MIT Licence #
|
||||
# ########################################################## ##
|
||||
# ##########################################################
|
||||
|
||||
from FlatCAMTool import FlatCAMTool
|
||||
from copy import copy, deepcopy
|
||||
from ObjectCollection import *
|
||||
from shapely.geometry import base
|
||||
|
||||
import gettext
|
||||
import FlatCAMTranslation as fcTranslate
|
||||
|
@ -21,7 +22,7 @@ if '_' not in builtins.__dict__:
|
|||
|
||||
class ToolPaint(FlatCAMTool, Gerber):
|
||||
|
||||
toolName = _("Paint Area")
|
||||
toolName = _("Paint Tool")
|
||||
|
||||
def __init__(self, app):
|
||||
self.app = app
|
||||
|
@ -51,18 +52,43 @@ class ToolPaint(FlatCAMTool, Gerber):
|
|||
form_layout = QtWidgets.QFormLayout()
|
||||
self.tools_box.addLayout(form_layout)
|
||||
|
||||
# ## Object
|
||||
self.object_combo = QtWidgets.QComboBox()
|
||||
self.object_combo.setModel(self.app.collection)
|
||||
self.object_combo.setRootModelIndex(self.app.collection.index(2, 0, QtCore.QModelIndex()))
|
||||
self.object_combo.setCurrentIndex(1)
|
||||
# ################################################
|
||||
# ##### Type of object to be painted #############
|
||||
# ################################################
|
||||
self.type_obj_combo = QtWidgets.QComboBox()
|
||||
self.type_obj_combo.addItem("Gerber")
|
||||
self.type_obj_combo.addItem("Excellon")
|
||||
self.type_obj_combo.addItem("Geometry")
|
||||
|
||||
self.object_label = QtWidgets.QLabel(_("Geometry:"))
|
||||
self.object_label.setToolTip(
|
||||
_("Geometry object to be painted. ")
|
||||
# we get rid of item1 ("Excellon") as it is not suitable
|
||||
self.type_obj_combo.view().setRowHidden(1, True)
|
||||
self.type_obj_combo.setItemIcon(0, QtGui.QIcon("share/flatcam_icon16.png"))
|
||||
self.type_obj_combo.setItemIcon(2, QtGui.QIcon("share/geometry16.png"))
|
||||
|
||||
self.type_obj_combo_label = QtWidgets.QLabel('%s:' % _("Obj Type"))
|
||||
self.type_obj_combo_label.setToolTip(
|
||||
_("Specify the type of object to be painted.\n"
|
||||
"It can be of type: Gerber or Geometry.\n"
|
||||
"What is selected here will dictate the kind\n"
|
||||
"of objects that will populate the 'Object' combobox.")
|
||||
)
|
||||
self.type_obj_combo_label.setMinimumWidth(60)
|
||||
form_layout.addRow(self.type_obj_combo_label, self.type_obj_combo)
|
||||
|
||||
# ################################################
|
||||
# ##### The object to be painted #################
|
||||
# ################################################
|
||||
self.obj_combo = QtWidgets.QComboBox()
|
||||
self.obj_combo.setModel(self.app.collection)
|
||||
self.obj_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
|
||||
self.obj_combo.setCurrentIndex(1)
|
||||
|
||||
self.object_label = QtWidgets.QLabel('%s:' % _("Object"))
|
||||
self.object_label.setToolTip(_("Object to be painted."))
|
||||
|
||||
form_layout.addRow(self.object_label, self.obj_combo)
|
||||
|
||||
e_lab_0 = QtWidgets.QLabel('')
|
||||
form_layout.addRow(self.object_label, self.object_combo)
|
||||
form_layout.addRow(e_lab_0)
|
||||
|
||||
# ### Tools ## ##
|
||||
|
@ -107,8 +133,27 @@ class ToolPaint(FlatCAMTool, Gerber):
|
|||
"Choosing the <B>V-Shape</B> Tool Type automatically will select the Operation Type "
|
||||
"in the resulting geometry as Isolation."))
|
||||
|
||||
self.empty_label = QtWidgets.QLabel('')
|
||||
self.tools_box.addWidget(self.empty_label)
|
||||
self.order_label = QtWidgets.QLabel('<b>%s:</b>' % _('Tool order'))
|
||||
self.order_label.setToolTip(_("This set the way that the tools in the tools table are used.\n"
|
||||
"'No' --> means that the used order is the one in the tool table\n"
|
||||
"'Forward' --> means that the tools will be ordered from small to big\n"
|
||||
"'Reverse' --> menas that the tools will ordered from big to small\n\n"
|
||||
"WARNING: using rest machining will automatically set the order\n"
|
||||
"in reverse and disable this control."))
|
||||
|
||||
self.order_radio = RadioSet([{'label': _('No'), 'value': 'no'},
|
||||
{'label': _('Forward'), 'value': 'fwd'},
|
||||
{'label': _('Reverse'), 'value': 'rev'}])
|
||||
self.order_radio.setToolTip(_("This set the way that the tools in the tools table are used.\n"
|
||||
"'No' --> means that the used order is the one in the tool table\n"
|
||||
"'Forward' --> means that the tools will be ordered from small to big\n"
|
||||
"'Reverse' --> menas that the tools will ordered from big to small\n\n"
|
||||
"WARNING: using rest machining will automatically set the order\n"
|
||||
"in reverse and disable this control."))
|
||||
form = QtWidgets.QFormLayout()
|
||||
self.tools_box.addLayout(form)
|
||||
form.addRow(QtWidgets.QLabel(''), QtWidgets.QLabel(''))
|
||||
form.addRow(self.order_label, self.order_radio)
|
||||
|
||||
# ### Add a new Tool ## ##
|
||||
hlay = QtWidgets.QHBoxLayout()
|
||||
|
@ -157,7 +202,7 @@ class ToolPaint(FlatCAMTool, Gerber):
|
|||
self.tools_box.addLayout(grid3)
|
||||
|
||||
# Overlap
|
||||
ovlabel = QtWidgets.QLabel(_('Overlap Rate:'))
|
||||
ovlabel = QtWidgets.QLabel('%s:' % _('Overlap Rate'))
|
||||
ovlabel.setToolTip(
|
||||
_("How much (fraction) of the tool width to overlap each tool pass.\n"
|
||||
"Example:\n"
|
||||
|
@ -174,7 +219,7 @@ class ToolPaint(FlatCAMTool, Gerber):
|
|||
grid3.addWidget(self.paintoverlap_entry, 1, 1)
|
||||
|
||||
# Margin
|
||||
marginlabel = QtWidgets.QLabel(_('Margin:'))
|
||||
marginlabel = QtWidgets.QLabel('%s:' % _('Margin'))
|
||||
marginlabel.setToolTip(
|
||||
_("Distance by which to avoid\n"
|
||||
"the edges of the polygon to\n"
|
||||
|
@ -185,7 +230,7 @@ class ToolPaint(FlatCAMTool, Gerber):
|
|||
grid3.addWidget(self.paintmargin_entry, 2, 1)
|
||||
|
||||
# Method
|
||||
methodlabel = QtWidgets.QLabel(_('Method:'))
|
||||
methodlabel = QtWidgets.QLabel('%s:' % _('Method'))
|
||||
methodlabel.setToolTip(
|
||||
_("Algorithm for non-copper clearing:<BR>"
|
||||
"<B>Standard</B>: Fixed step inwards.<BR>"
|
||||
|
@ -201,7 +246,7 @@ class ToolPaint(FlatCAMTool, Gerber):
|
|||
grid3.addWidget(self.paintmethod_combo, 3, 1)
|
||||
|
||||
# Connect lines
|
||||
pathconnectlabel = QtWidgets.QLabel(_("Connect:"))
|
||||
pathconnectlabel = QtWidgets.QLabel('%s:' % _("Connect"))
|
||||
pathconnectlabel.setToolTip(
|
||||
_("Draw lines between resulting\n"
|
||||
"segments to minimize tool lifts.")
|
||||
|
@ -210,7 +255,7 @@ class ToolPaint(FlatCAMTool, Gerber):
|
|||
self.pathconnect_cb = FCCheckBox()
|
||||
grid3.addWidget(self.pathconnect_cb, 4, 1)
|
||||
|
||||
contourlabel = QtWidgets.QLabel(_("Contour:"))
|
||||
contourlabel = QtWidgets.QLabel('%s:' % _("Contour"))
|
||||
contourlabel.setToolTip(
|
||||
_("Cut around the perimeter of the polygon\n"
|
||||
"to trim rough edges.")
|
||||
|
@ -219,7 +264,7 @@ class ToolPaint(FlatCAMTool, Gerber):
|
|||
self.paintcontour_cb = FCCheckBox()
|
||||
grid3.addWidget(self.paintcontour_cb, 5, 1)
|
||||
|
||||
restlabel = QtWidgets.QLabel(_("Rest M.:"))
|
||||
restlabel = QtWidgets.QLabel('%s:' % _("Rest M."))
|
||||
restlabel.setToolTip(
|
||||
_("If checked, use 'rest machining'.\n"
|
||||
"Basically it will clear copper outside PCB features,\n"
|
||||
|
@ -234,30 +279,70 @@ class ToolPaint(FlatCAMTool, Gerber):
|
|||
grid3.addWidget(self.rest_cb, 6, 1)
|
||||
|
||||
# Polygon selection
|
||||
selectlabel = QtWidgets.QLabel(_('Selection:'))
|
||||
selectlabel = QtWidgets.QLabel('%s:' % _('Selection'))
|
||||
selectlabel.setToolTip(
|
||||
_("How to select the polygons to paint.<BR>"
|
||||
"Options:<BR>"
|
||||
"- <B>Single</B>: left mouse click on the polygon to be painted.<BR>"
|
||||
"- <B>All</B>: paint all polygons.")
|
||||
"- <B>Single Polygons</B>: left mouse click on the polygon to be painted.<BR>"
|
||||
"- <B>Area Selection</B>: left mouse click to start selection of the area to be painted.<BR>"
|
||||
"- <B>All Polygons</B>: paint all polygons.<BR>"
|
||||
"- <B>Reference Object</B>: paint an area described by an external reference object.")
|
||||
)
|
||||
grid3.addWidget(selectlabel, 7, 0)
|
||||
# grid3 = QtWidgets.QGridLayout()
|
||||
self.selectmethod_combo = RadioSet([
|
||||
{"label": _("Single"), "value": "single"},
|
||||
{"label": _("Area"), "value": "area"},
|
||||
{"label": _("All"), "value": "all"}
|
||||
])
|
||||
{"label": _("Single Polygon"), "value": "single"},
|
||||
{"label": _("Area Selection"), "value": "area"},
|
||||
{"label": _("All Polygons"), "value": "all"},
|
||||
{"label": _("Reference Object"), "value": "ref"}
|
||||
], orientation='vertical', stretch=False)
|
||||
self.selectmethod_combo.setToolTip(
|
||||
_("How to select Polygons to be painted.\n\n"
|
||||
"- 'Area Selection' - left mouse click to start selection of the area to be painted.\n"
|
||||
"Keeping a modifier key pressed (CTRL or SHIFT) will allow to add multiple areas.\n"
|
||||
"- 'All Polygons' - the Paint will start after click.\n"
|
||||
"- 'Reference Object' - will do non copper clearing within the area\n"
|
||||
"specified by another object.")
|
||||
)
|
||||
grid3.addWidget(self.selectmethod_combo, 7, 1)
|
||||
|
||||
form1 = QtWidgets.QFormLayout()
|
||||
self.tools_box.addLayout(form1)
|
||||
|
||||
self.box_combo_type_label = QtWidgets.QLabel('%s:' % _("Ref. Type"))
|
||||
self.box_combo_type_label.setToolTip(
|
||||
_("The type of FlatCAM object to be used as paint reference.\n"
|
||||
"It can be Gerber, Excellon or Geometry.")
|
||||
)
|
||||
self.box_combo_type = QtWidgets.QComboBox()
|
||||
self.box_combo_type.addItem(_("Gerber Reference Box Object"))
|
||||
self.box_combo_type.addItem(_("Excellon Reference Box Object"))
|
||||
self.box_combo_type.addItem(_("Geometry Reference Box Object"))
|
||||
form1.addRow(self.box_combo_type_label, self.box_combo_type)
|
||||
|
||||
self.box_combo_label = QtWidgets.QLabel('%s:' % _("Ref. Object"))
|
||||
self.box_combo_label.setToolTip(
|
||||
_("The FlatCAM object to be used as non copper clearing reference.")
|
||||
)
|
||||
self.box_combo = QtWidgets.QComboBox()
|
||||
self.box_combo.setModel(self.app.collection)
|
||||
self.box_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
|
||||
self.box_combo.setCurrentIndex(1)
|
||||
form1.addRow(self.box_combo_label, self.box_combo)
|
||||
|
||||
self.box_combo.hide()
|
||||
self.box_combo_label.hide()
|
||||
self.box_combo_type.hide()
|
||||
self.box_combo_type_label.hide()
|
||||
|
||||
# GO Button
|
||||
self.generate_paint_button = QtWidgets.QPushButton(_('Create Paint Geometry'))
|
||||
self.generate_paint_button.setToolTip(
|
||||
_("After clicking here, click inside<BR>"
|
||||
"the polygon you wish to be painted if <B>Single</B> is selected.<BR>"
|
||||
"If <B>All</B> is selected then the Paint will start after click.<BR>"
|
||||
"A new Geometry object with the tool<BR>"
|
||||
"paths will be created.")
|
||||
_("- 'Area Selection' - left mouse click to start selection of the area to be painted.\n"
|
||||
"Keeping a modifier key pressed (CTRL or SHIFT) will allow to add multiple areas.\n"
|
||||
"- 'All Polygons' - the Paint will start after click.\n"
|
||||
"- 'Reference Object' - will do non copper clearing within the area\n"
|
||||
"specified by another object.")
|
||||
)
|
||||
self.tools_box.addWidget(self.generate_paint_button)
|
||||
|
||||
|
@ -271,6 +356,9 @@ class ToolPaint(FlatCAMTool, Gerber):
|
|||
self.tooluid = 0
|
||||
self.first_click = False
|
||||
self.cursor_pos = None
|
||||
self.mouse_is_dragging = False
|
||||
|
||||
self.sel_rect = []
|
||||
|
||||
# store here the default data for Geometry Data
|
||||
self.default_data = {}
|
||||
|
@ -316,6 +404,16 @@ class ToolPaint(FlatCAMTool, Gerber):
|
|||
self.deltool_btn.clicked.connect(self.on_tool_delete)
|
||||
self.generate_paint_button.clicked.connect(self.on_paint_button_click)
|
||||
self.selectmethod_combo.activated_custom.connect(self.on_radio_selection)
|
||||
self.order_radio.activated_custom[str].connect(self.on_order_changed)
|
||||
self.rest_cb.stateChanged.connect(self.on_rest_machining_check)
|
||||
|
||||
self.box_combo_type.currentIndexChanged.connect(self.on_combo_box_type)
|
||||
self.type_obj_combo.currentIndexChanged.connect(self.on_type_obj_index_changed)
|
||||
|
||||
def on_type_obj_index_changed(self, index):
|
||||
obj_type = self.type_obj_combo.currentIndex()
|
||||
self.obj_combo.setRootModelIndex(self.app.collection.index(obj_type, 0, QtCore.QModelIndex()))
|
||||
self.obj_combo.setCurrentIndex(0)
|
||||
|
||||
def install(self, icon=None, separator=None, **kwargs):
|
||||
FlatCAMTool.install(self, icon, separator, shortcut='ALT+P', **kwargs)
|
||||
|
@ -330,7 +428,12 @@ class ToolPaint(FlatCAMTool, Gerber):
|
|||
else:
|
||||
try:
|
||||
if self.app.ui.tool_scroll_area.widget().objectName() == self.toolName:
|
||||
self.app.ui.splitter.setSizes([0, 1])
|
||||
# if tab is populated with the tool but it does not have the focus, focus on it
|
||||
if not self.app.ui.notebook.currentWidget() is self.app.ui.tool_tab:
|
||||
# focus on Tool Tab
|
||||
self.app.ui.notebook.setCurrentWidget(self.app.ui.tool_tab)
|
||||
else:
|
||||
self.app.ui.splitter.setSizes([0, 1])
|
||||
except AttributeError:
|
||||
pass
|
||||
else:
|
||||
|
@ -342,7 +445,29 @@ class ToolPaint(FlatCAMTool, Gerber):
|
|||
|
||||
self.app.ui.notebook.setTabText(2, _("Paint Tool"))
|
||||
|
||||
def reset_usage(self):
|
||||
self.obj_name = ""
|
||||
self.paint_obj = None
|
||||
self.bound_obj = None
|
||||
|
||||
self.first_click = False
|
||||
self.cursor_pos = None
|
||||
self.mouse_is_dragging = False
|
||||
|
||||
self.sel_rect = []
|
||||
|
||||
def on_radio_selection(self):
|
||||
if self.selectmethod_combo.get_value() == "ref":
|
||||
self.box_combo.show()
|
||||
self.box_combo_label.show()
|
||||
self.box_combo_type.show()
|
||||
self.box_combo_type_label.show()
|
||||
else:
|
||||
self.box_combo.hide()
|
||||
self.box_combo_label.hide()
|
||||
self.box_combo_type.hide()
|
||||
self.box_combo_type_label.hide()
|
||||
|
||||
if self.selectmethod_combo.get_value() == 'single':
|
||||
# disable rest-machining for single polygon painting
|
||||
self.rest_cb.set_value(False)
|
||||
|
@ -367,11 +492,25 @@ class ToolPaint(FlatCAMTool, Gerber):
|
|||
self.deltool_btn.setDisabled(False)
|
||||
self.tools_table.setContextMenuPolicy(Qt.ActionsContextMenu)
|
||||
|
||||
def on_order_changed(self, order):
|
||||
if order != 'no':
|
||||
self.build_ui()
|
||||
|
||||
def on_rest_machining_check(self, state):
|
||||
if state:
|
||||
self.order_radio.set_value('rev')
|
||||
self.order_label.setDisabled(True)
|
||||
self.order_radio.setDisabled(True)
|
||||
else:
|
||||
self.order_label.setDisabled(False)
|
||||
self.order_radio.setDisabled(False)
|
||||
|
||||
def set_tool_ui(self):
|
||||
self.tools_frame.show()
|
||||
self.reset_fields()
|
||||
|
||||
# ## Init the GUI interface
|
||||
self.order_radio.set_value(self.app.defaults["tools_paintorder"])
|
||||
self.paintmargin_entry.set_value(self.default_data["paintmargin"])
|
||||
self.paintmethod_combo.set_value(self.default_data["paintmethod"])
|
||||
self.selectmethod_combo.set_value(self.default_data["selectmethod"])
|
||||
|
@ -452,7 +591,14 @@ class ToolPaint(FlatCAMTool, Gerber):
|
|||
sorted_tools = []
|
||||
for k, v in self.paint_tools.items():
|
||||
sorted_tools.append(float('%.4f' % float(v['tooldia'])))
|
||||
sorted_tools.sort()
|
||||
|
||||
order = self.order_radio.get_value()
|
||||
if order == 'fwd':
|
||||
sorted_tools.sort(reverse=False)
|
||||
elif order == 'rev':
|
||||
sorted_tools.sort(reverse=True)
|
||||
else:
|
||||
pass
|
||||
|
||||
n = len(sorted_tools)
|
||||
self.tools_table.setRowCount(n)
|
||||
|
@ -523,6 +669,11 @@ class ToolPaint(FlatCAMTool, Gerber):
|
|||
# we reactivate the signals after the after the tool adding as we don't need to see the tool been populated
|
||||
self.tools_table.itemChanged.connect(self.on_tool_edit)
|
||||
|
||||
def on_combo_box_type(self):
|
||||
obj_type = self.box_combo_type.currentIndex()
|
||||
self.box_combo.setRootModelIndex(self.app.collection.index(obj_type, 0, QtCore.QModelIndex()))
|
||||
self.box_combo.setCurrentIndex(0)
|
||||
|
||||
def on_tool_add(self, dia=None, muted=None):
|
||||
|
||||
try:
|
||||
|
@ -541,7 +692,7 @@ class ToolPaint(FlatCAMTool, Gerber):
|
|||
tool_dia = float(self.addtool_entry.get_value().replace(',', '.'))
|
||||
except ValueError:
|
||||
self.app.inform.emit(_("[ERROR_NOTCL] Wrong value format entered, "
|
||||
"use a number."))
|
||||
"use a number."))
|
||||
return
|
||||
|
||||
if tool_dia is None:
|
||||
|
@ -739,6 +890,10 @@ class ToolPaint(FlatCAMTool, Gerber):
|
|||
self.build_ui()
|
||||
|
||||
def on_paint_button_click(self):
|
||||
|
||||
# init values for the next usage
|
||||
self.reset_usage()
|
||||
|
||||
self.app.report_usage(_("geometry_on_paint_button"))
|
||||
# self.app.call_source = 'paint'
|
||||
|
||||
|
@ -764,7 +919,7 @@ class ToolPaint(FlatCAMTool, Gerber):
|
|||
contour = self.paintcontour_cb.get_value()
|
||||
select_method = self.selectmethod_combo.get_value()
|
||||
|
||||
self.obj_name = self.object_combo.currentText()
|
||||
self.obj_name = self.obj_combo.currentText()
|
||||
|
||||
# Get source object.
|
||||
try:
|
||||
|
@ -828,7 +983,7 @@ class ToolPaint(FlatCAMTool, Gerber):
|
|||
tooldia = float('%.4f' % float(self.tools_table.item(0, 1).text()))
|
||||
|
||||
# To be called after clicking on the plot.
|
||||
def on_mouse_press(event):
|
||||
def on_mouse_release(event):
|
||||
# do paint single only for left mouse clicks
|
||||
if event.button == 1:
|
||||
if not self.first_click:
|
||||
|
@ -839,8 +994,7 @@ class ToolPaint(FlatCAMTool, Gerber):
|
|||
if self.app.grid_status() == True:
|
||||
self.cursor_pos = self.app.geo_editor.snap(self.cursor_pos[0], self.cursor_pos[1])
|
||||
else:
|
||||
self.app.inform.emit(_("Done."))
|
||||
self.first_click = False
|
||||
self.app.inform.emit(_("Zone added. Right click to finish."))
|
||||
self.app.delete_selection_shape()
|
||||
|
||||
curr_pos = self.app.plotcanvas.vispy_canvas.translate_coords(event.pos)
|
||||
|
@ -853,27 +1007,63 @@ class ToolPaint(FlatCAMTool, Gerber):
|
|||
pt2 = (x1, y0)
|
||||
pt3 = (x1, y1)
|
||||
pt4 = (x0, y1)
|
||||
sel_rect = Polygon([pt1, pt2, pt3, pt4])
|
||||
self.sel_rect.append(Polygon([pt1, pt2, pt3, pt4]))
|
||||
|
||||
modifiers = QtWidgets.QApplication.keyboardModifiers()
|
||||
|
||||
if modifiers == QtCore.Qt.ShiftModifier:
|
||||
mod_key = 'Shift'
|
||||
elif modifiers == QtCore.Qt.ControlModifier:
|
||||
mod_key = 'Control'
|
||||
else:
|
||||
mod_key = None
|
||||
|
||||
if mod_key == self.app.defaults["global_mselect_key"]:
|
||||
self.first_click = False
|
||||
return
|
||||
|
||||
self.sel_rect = cascaded_union(self.sel_rect)
|
||||
self.paint_poly_area(obj=self.paint_obj,
|
||||
sel_obj= sel_rect,
|
||||
sel_obj= self.sel_rect,
|
||||
outname=o_name,
|
||||
overlap=overlap,
|
||||
connect=connect,
|
||||
contour=contour)
|
||||
|
||||
self.app.plotcanvas.vis_disconnect('mouse_press', on_mouse_press)
|
||||
self.app.plotcanvas.vis_disconnect('mouse_release', on_mouse_release)
|
||||
self.app.plotcanvas.vis_disconnect('mouse_move', on_mouse_move)
|
||||
|
||||
self.app.plotcanvas.vis_connect('mouse_press', self.app.on_mouse_click_over_plot)
|
||||
self.app.plotcanvas.vis_connect('mouse_move', self.app.on_mouse_move_over_plot)
|
||||
self.app.plotcanvas.vis_connect('mouse_release', self.app.on_mouse_click_release_over_plot)
|
||||
elif event.button == 2 and self.first_click is False and self.mouse_is_dragging is False:
|
||||
self.first_click = False
|
||||
self.app.plotcanvas.vis_disconnect('mouse_release', on_mouse_release)
|
||||
self.app.plotcanvas.vis_disconnect('mouse_move', on_mouse_move)
|
||||
|
||||
self.app.plotcanvas.vis_connect('mouse_press', self.app.on_mouse_click_over_plot)
|
||||
self.app.plotcanvas.vis_connect('mouse_move', self.app.on_mouse_move_over_plot)
|
||||
self.app.plotcanvas.vis_connect('mouse_release', self.app.on_mouse_click_release_over_plot)
|
||||
|
||||
self.sel_rect = cascaded_union(self.sel_rect)
|
||||
self.paint_poly_area(obj=self.paint_obj,
|
||||
sel_obj=self.sel_rect,
|
||||
outname=o_name,
|
||||
overlap=overlap,
|
||||
connect=connect,
|
||||
contour=contour)
|
||||
|
||||
# called on mouse move
|
||||
def on_mouse_move(event):
|
||||
curr_pos = self.app.plotcanvas.vispy_canvas.translate_coords(event.pos)
|
||||
self.app.app_cursor.enabled = False
|
||||
|
||||
if event.button == 2:
|
||||
if event.is_dragging is True:
|
||||
self.mouse_is_dragging = True
|
||||
else:
|
||||
self.mouse_is_dragging = False
|
||||
|
||||
if self.app.grid_status() == True:
|
||||
self.app.app_cursor.enabled = True
|
||||
# Update cursor
|
||||
|
@ -891,9 +1081,41 @@ class ToolPaint(FlatCAMTool, Gerber):
|
|||
self.app.plotcanvas.vis_disconnect('mouse_move', self.app.on_mouse_move_over_plot)
|
||||
self.app.plotcanvas.vis_disconnect('mouse_release', self.app.on_mouse_click_release_over_plot)
|
||||
|
||||
self.app.plotcanvas.vis_connect('mouse_press', on_mouse_press)
|
||||
self.app.plotcanvas.vis_connect('mouse_release', on_mouse_release)
|
||||
self.app.plotcanvas.vis_connect('mouse_move', on_mouse_move)
|
||||
|
||||
elif select_method == 'ref':
|
||||
self.bound_obj_name = self.box_combo.currentText()
|
||||
# Get source object.
|
||||
try:
|
||||
self.bound_obj = self.app.collection.get_by_name(self.bound_obj_name)
|
||||
except Exception as e:
|
||||
self.app.inform.emit(_("[ERROR_NOTCL] Could not retrieve object: %s") % self.obj_name)
|
||||
return "Could not retrieve object: %s" % self.obj_name
|
||||
|
||||
geo = self.bound_obj.solid_geometry
|
||||
try:
|
||||
if isinstance(geo, MultiPolygon):
|
||||
env_obj = geo.convex_hull
|
||||
elif (isinstance(geo, MultiPolygon) and len(geo) == 1) or \
|
||||
(isinstance(geo, list) and len(geo) == 1) and isinstance(geo[0], Polygon):
|
||||
env_obj = cascaded_union(self.bound_obj.solid_geometry)
|
||||
else:
|
||||
env_obj = cascaded_union(self.bound_obj.solid_geometry)
|
||||
env_obj = env_obj.convex_hull
|
||||
sel_rect = env_obj.buffer(distance=0.0000001, join_style=base.JOIN_STYLE.mitre)
|
||||
except Exception as e:
|
||||
log.debug("ToolPaint.on_paint_button_click() --> %s" % str(e))
|
||||
self.app.inform.emit(_("[ERROR_NOTCL] No object available."))
|
||||
return
|
||||
|
||||
self.paint_poly_area(obj=self.paint_obj,
|
||||
sel_obj=sel_rect,
|
||||
outname=o_name,
|
||||
overlap=overlap,
|
||||
connect=connect,
|
||||
contour=contour)
|
||||
|
||||
def paint_poly(self, obj, inside_pt, tooldia, overlap, outname=None, connect=True, contour=True):
|
||||
"""
|
||||
Paints a polygon selected by clicking on its interior.
|
||||
|
@ -1140,7 +1362,14 @@ class ToolPaint(FlatCAMTool, Gerber):
|
|||
sorted_tools = []
|
||||
for row in range(self.tools_table.rowCount()):
|
||||
sorted_tools.append(float(self.tools_table.item(row, 1).text()))
|
||||
sorted_tools.sort(reverse=True)
|
||||
|
||||
order = self.order_radio.get_value()
|
||||
if order == 'fwd':
|
||||
sorted_tools.sort(reverse=False)
|
||||
elif order == 'rev':
|
||||
sorted_tools.sort(reverse=True)
|
||||
else:
|
||||
pass
|
||||
|
||||
try:
|
||||
a, b, c, d = obj.bounds()
|
||||
|
@ -1426,10 +1655,22 @@ class ToolPaint(FlatCAMTool, Gerber):
|
|||
sorted_tools = []
|
||||
for row in range(self.tools_table.rowCount()):
|
||||
sorted_tools.append(float(self.tools_table.item(row, 1).text()))
|
||||
sorted_tools.sort(reverse=True)
|
||||
|
||||
order = self.order_radio.get_value()
|
||||
if order == 'fwd':
|
||||
sorted_tools.sort(reverse=False)
|
||||
elif order == 'rev':
|
||||
sorted_tools.sort(reverse=True)
|
||||
else:
|
||||
pass
|
||||
|
||||
geo_to_paint = []
|
||||
for poly in obj.solid_geometry:
|
||||
if not isinstance(obj.solid_geometry, list):
|
||||
target_geo = [obj.solid_geometry]
|
||||
else:
|
||||
target_geo = obj.solid_geometry
|
||||
|
||||
for poly in target_geo:
|
||||
new_pol = poly.intersection(sel_obj)
|
||||
geo_to_paint.append(new_pol)
|
||||
|
||||
|
@ -1674,4 +1915,4 @@ class ToolPaint(FlatCAMTool, Gerber):
|
|||
return bounds_rec(geometry)
|
||||
|
||||
def reset_fields(self):
|
||||
self.object_combo.setRootModelIndex(self.app.collection.index(2, 0, QtCore.QModelIndex()))
|
||||
self.obj_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
|
||||
|
|
|
@ -53,7 +53,7 @@ class Panelize(FlatCAMTool):
|
|||
self.type_obj_combo.setItemIcon(1, QtGui.QIcon("share/drill16.png"))
|
||||
self.type_obj_combo.setItemIcon(2, QtGui.QIcon("share/geometry16.png"))
|
||||
|
||||
self.type_obj_combo_label = QtWidgets.QLabel(_("Object Type:"))
|
||||
self.type_obj_combo_label = QtWidgets.QLabel('%s:' % _("Object Type"))
|
||||
self.type_obj_combo_label.setToolTip(
|
||||
_("Specify the type of object to be panelized\n"
|
||||
"It can be of type: Gerber, Excellon or Geometry.\n"
|
||||
|
@ -68,7 +68,7 @@ class Panelize(FlatCAMTool):
|
|||
self.object_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
|
||||
self.object_combo.setCurrentIndex(1)
|
||||
|
||||
self.object_label = QtWidgets.QLabel(_("Object:"))
|
||||
self.object_label = QtWidgets.QLabel('%s:' % _("Object"))
|
||||
self.object_label.setToolTip(
|
||||
_("Object to be panelized. This means that it will\n"
|
||||
"be duplicated in an array of rows and columns.")
|
||||
|
@ -83,7 +83,7 @@ class Panelize(FlatCAMTool):
|
|||
# Type of box Panel object
|
||||
self.reference_radio = RadioSet([{'label': _('Object'), 'value': 'object'},
|
||||
{'label': _('Bounding Box'), 'value': 'bbox'}])
|
||||
self.box_label = QtWidgets.QLabel(_("<b>Penelization Reference:</b>"))
|
||||
self.box_label = QtWidgets.QLabel("<b>%s:</b>" % _("Penelization Reference"))
|
||||
self.box_label.setToolTip(
|
||||
_("Choose the reference for panelization:\n"
|
||||
"- Object = the bounding box of a different object\n"
|
||||
|
@ -108,7 +108,7 @@ class Panelize(FlatCAMTool):
|
|||
self.type_box_combo.setItemIcon(0, QtGui.QIcon("share/flatcam_icon16.png"))
|
||||
self.type_box_combo.setItemIcon(2, QtGui.QIcon("share/geometry16.png"))
|
||||
|
||||
self.type_box_combo_label = QtWidgets.QLabel(_("Box Type:"))
|
||||
self.type_box_combo_label = QtWidgets.QLabel('%s:' % _("Box Type"))
|
||||
self.type_box_combo_label.setToolTip(
|
||||
_("Specify the type of object to be used as an container for\n"
|
||||
"panelization. It can be: Gerber or Geometry type.\n"
|
||||
|
@ -123,7 +123,7 @@ class Panelize(FlatCAMTool):
|
|||
self.box_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
|
||||
self.box_combo.setCurrentIndex(1)
|
||||
|
||||
self.box_combo_label = QtWidgets.QLabel(_("Box Object:"))
|
||||
self.box_combo_label = QtWidgets.QLabel('%s:' % _("Box Object"))
|
||||
self.box_combo_label.setToolTip(
|
||||
_("The actual object that is used a container for the\n "
|
||||
"selected object that is to be panelized.")
|
||||
|
@ -131,7 +131,7 @@ class Panelize(FlatCAMTool):
|
|||
form_layout.addRow(self.box_combo_label, self.box_combo)
|
||||
form_layout.addRow(QtWidgets.QLabel(""))
|
||||
|
||||
panel_data_label = QtWidgets.QLabel(_("<b>Panel Data:</b>"))
|
||||
panel_data_label = QtWidgets.QLabel("<b>%s:</b>" % _("Panel Data"))
|
||||
panel_data_label.setToolTip(
|
||||
_("This informations will shape the resulting panel.\n"
|
||||
"The number of rows and columns will set how many\n"
|
||||
|
@ -144,7 +144,7 @@ class Panelize(FlatCAMTool):
|
|||
|
||||
# Spacing Columns
|
||||
self.spacing_columns = FCEntry()
|
||||
self.spacing_columns_label = QtWidgets.QLabel(_("Spacing cols:"))
|
||||
self.spacing_columns_label = QtWidgets.QLabel('%s:' % _("Spacing cols"))
|
||||
self.spacing_columns_label.setToolTip(
|
||||
_("Spacing between columns of the desired panel.\n"
|
||||
"In current units.")
|
||||
|
@ -153,7 +153,7 @@ class Panelize(FlatCAMTool):
|
|||
|
||||
# Spacing Rows
|
||||
self.spacing_rows = FCEntry()
|
||||
self.spacing_rows_label = QtWidgets.QLabel(_("Spacing rows:"))
|
||||
self.spacing_rows_label = QtWidgets.QLabel('%s:' % _("Spacing rows"))
|
||||
self.spacing_rows_label.setToolTip(
|
||||
_("Spacing between rows of the desired panel.\n"
|
||||
"In current units.")
|
||||
|
@ -162,7 +162,7 @@ class Panelize(FlatCAMTool):
|
|||
|
||||
# Columns
|
||||
self.columns = FCEntry()
|
||||
self.columns_label = QtWidgets.QLabel(_("Columns:"))
|
||||
self.columns_label = QtWidgets.QLabel('%s:' % _("Columns"))
|
||||
self.columns_label.setToolTip(
|
||||
_("Number of columns of the desired panel")
|
||||
)
|
||||
|
@ -170,7 +170,7 @@ class Panelize(FlatCAMTool):
|
|||
|
||||
# Rows
|
||||
self.rows = FCEntry()
|
||||
self.rows_label = QtWidgets.QLabel(_("Rows:"))
|
||||
self.rows_label = QtWidgets.QLabel('%s:' % _("Rows"))
|
||||
self.rows_label.setToolTip(
|
||||
_("Number of rows of the desired panel")
|
||||
)
|
||||
|
@ -180,7 +180,7 @@ class Panelize(FlatCAMTool):
|
|||
# Type of resulting Panel object
|
||||
self.panel_type_radio = RadioSet([{'label': _('Gerber'), 'value': 'gerber'},
|
||||
{'label': _('Geo'), 'value': 'geometry'}])
|
||||
self.panel_type_label = QtWidgets.QLabel(_("<b>Panel Type:</b>"))
|
||||
self.panel_type_label = QtWidgets.QLabel("<b>%s:</b>" % _("Panel Type"))
|
||||
self.panel_type_label.setToolTip(
|
||||
_("Choose the type of object for the panel object:\n"
|
||||
"- Geometry\n"
|
||||
|
@ -190,7 +190,7 @@ class Panelize(FlatCAMTool):
|
|||
form_layout.addRow(self.panel_type_radio)
|
||||
|
||||
# Constrains
|
||||
self.constrain_cb = FCCheckBox(_("Constrain panel within:"))
|
||||
self.constrain_cb = FCCheckBox('%s:' % _("Constrain panel within"))
|
||||
self.constrain_cb.setToolTip(
|
||||
_("Area define by DX and DY within to constrain the panel.\n"
|
||||
"DX and DY values are in current units.\n"
|
||||
|
@ -201,7 +201,7 @@ class Panelize(FlatCAMTool):
|
|||
form_layout.addRow(self.constrain_cb)
|
||||
|
||||
self.x_width_entry = FCEntry()
|
||||
self.x_width_lbl = QtWidgets.QLabel(_("Width (DX):"))
|
||||
self.x_width_lbl = QtWidgets.QLabel('%s:' % _("Width (DX)"))
|
||||
self.x_width_lbl.setToolTip(
|
||||
_("The width (DX) within which the panel must fit.\n"
|
||||
"In current units.")
|
||||
|
@ -209,7 +209,7 @@ class Panelize(FlatCAMTool):
|
|||
form_layout.addRow(self.x_width_lbl, self.x_width_entry)
|
||||
|
||||
self.y_height_entry = FCEntry()
|
||||
self.y_height_lbl = QtWidgets.QLabel(_("Height (DY):"))
|
||||
self.y_height_lbl = QtWidgets.QLabel('%s:' % _("Height (DY)"))
|
||||
self.y_height_lbl.setToolTip(
|
||||
_("The height (DY)within which the panel must fit.\n"
|
||||
"In current units.")
|
||||
|
@ -259,7 +259,12 @@ class Panelize(FlatCAMTool):
|
|||
else:
|
||||
try:
|
||||
if self.app.ui.tool_scroll_area.widget().objectName() == self.toolName:
|
||||
self.app.ui.splitter.setSizes([0, 1])
|
||||
# if tab is populated with the tool but it does not have the focus, focus on it
|
||||
if not self.app.ui.notebook.currentWidget() is self.app.ui.tool_tab:
|
||||
# focus on Tool Tab
|
||||
self.app.ui.notebook.setCurrentWidget(self.app.ui.tool_tab)
|
||||
else:
|
||||
self.app.ui.splitter.setSizes([0, 1])
|
||||
except AttributeError:
|
||||
pass
|
||||
else:
|
||||
|
|
|
@ -48,13 +48,13 @@ class PcbWizard(FlatCAMTool):
|
|||
self.layout.addWidget(title_label)
|
||||
|
||||
self.layout.addWidget(QtWidgets.QLabel(""))
|
||||
self.layout.addWidget(QtWidgets.QLabel(_("<b>Load files:</b>")))
|
||||
self.layout.addWidget(QtWidgets.QLabel("<b>%s:</b>" % _("Load files")))
|
||||
|
||||
# Form Layout
|
||||
form_layout = QtWidgets.QFormLayout()
|
||||
self.layout.addLayout(form_layout)
|
||||
|
||||
self.excellon_label = QtWidgets.QLabel(_("Excellon file:"))
|
||||
self.excellon_label = QtWidgets.QLabel('%s:' % _("Excellon file"))
|
||||
self.excellon_label.setToolTip(
|
||||
_("Load the Excellon file.\n"
|
||||
"Usually it has a .DRL extension")
|
||||
|
@ -62,7 +62,7 @@ class PcbWizard(FlatCAMTool):
|
|||
self.excellon_brn = FCButton(_("Open"))
|
||||
form_layout.addRow(self.excellon_label, self.excellon_brn)
|
||||
|
||||
self.inf_label = QtWidgets.QLabel(_("INF file:"))
|
||||
self.inf_label = QtWidgets.QLabel('%s:' % _("INF file"))
|
||||
self.inf_label.setToolTip(
|
||||
_("Load the INF file.")
|
||||
)
|
||||
|
@ -84,7 +84,7 @@ class PcbWizard(FlatCAMTool):
|
|||
self.tools_table.setVisible(False)
|
||||
|
||||
self.layout.addWidget(QtWidgets.QLabel(""))
|
||||
self.layout.addWidget(QtWidgets.QLabel(_("<b>Excellon format:</b>")))
|
||||
self.layout.addWidget(QtWidgets.QLabel("<b>%s:</b>" % _("Excellon format")))
|
||||
# Form Layout
|
||||
form_layout1 = QtWidgets.QFormLayout()
|
||||
self.layout.addLayout(form_layout1)
|
||||
|
@ -92,7 +92,7 @@ class PcbWizard(FlatCAMTool):
|
|||
# Integral part of the coordinates
|
||||
self.int_entry = FCSpinner()
|
||||
self.int_entry.set_range(1, 10)
|
||||
self.int_label = QtWidgets.QLabel(_("Int. digits:"))
|
||||
self.int_label = QtWidgets.QLabel('%s:' % _("Int. digits"))
|
||||
self.int_label.setToolTip(
|
||||
_("The number of digits for the integral part of the coordinates.")
|
||||
)
|
||||
|
@ -101,7 +101,7 @@ class PcbWizard(FlatCAMTool):
|
|||
# Fractional part of the coordinates
|
||||
self.frac_entry = FCSpinner()
|
||||
self.frac_entry.set_range(1, 10)
|
||||
self.frac_label = QtWidgets.QLabel(_("Frac. digits:"))
|
||||
self.frac_label = QtWidgets.QLabel('%s:' % _("Frac. digits"))
|
||||
self.frac_label.setToolTip(
|
||||
_("The number of digits for the fractional part of the coordinates.")
|
||||
)
|
||||
|
@ -111,7 +111,7 @@ class PcbWizard(FlatCAMTool):
|
|||
self.zeros_radio = RadioSet([{'label': _('LZ'), 'value': 'LZ'},
|
||||
{'label': _('TZ'), 'value': 'TZ'},
|
||||
{'label': _('No Suppression'), 'value': 'D'}])
|
||||
self.zeros_label = QtWidgets.QLabel(_("Zeros supp.:"))
|
||||
self.zeros_label = QtWidgets.QLabel('%s:' % _("Zeros supp."))
|
||||
self.zeros_label.setToolTip(
|
||||
_("The type of zeros suppression used.\n"
|
||||
"Can be of type:\n"
|
||||
|
@ -179,7 +179,12 @@ class PcbWizard(FlatCAMTool):
|
|||
else:
|
||||
try:
|
||||
if self.app.ui.tool_scroll_area.widget().objectName() == self.toolName:
|
||||
self.app.ui.splitter.setSizes([0, 1])
|
||||
# if tab is populated with the tool but it does not have the focus, focus on it
|
||||
if not self.app.ui.notebook.currentWidget() is self.app.ui.tool_tab:
|
||||
# focus on Tool Tab
|
||||
self.app.ui.notebook.setCurrentWidget(self.app.ui.tool_tab)
|
||||
else:
|
||||
self.app.ui.splitter.setSizes([0, 1])
|
||||
except AttributeError:
|
||||
pass
|
||||
else:
|
||||
|
|
|
@ -77,7 +77,12 @@ class Properties(FlatCAMTool):
|
|||
else:
|
||||
try:
|
||||
if self.app.ui.tool_scroll_area.widget().objectName() == self.toolName:
|
||||
self.app.ui.splitter.setSizes([0, 1])
|
||||
# if tab is populated with the tool but it does not have the focus, focus on it
|
||||
if not self.app.ui.notebook.currentWidget() is self.app.ui.tool_tab:
|
||||
# focus on Tool Tab
|
||||
self.app.ui.notebook.setCurrentWidget(self.app.ui.tool_tab)
|
||||
else:
|
||||
self.app.ui.splitter.setSizes([0, 1])
|
||||
except AttributeError:
|
||||
pass
|
||||
else:
|
||||
|
@ -117,23 +122,24 @@ class Properties(FlatCAMTool):
|
|||
|
||||
font = QtGui.QFont()
|
||||
font.setBold(True)
|
||||
obj_type = self.addParent(parent, 'TYPE', expanded=True, color=QtGui.QColor("#000000"), font=font)
|
||||
obj_name = self.addParent(parent, 'NAME', expanded=True, color=QtGui.QColor("#000000"), font=font)
|
||||
dims = self.addParent(parent, 'Dimensions', expanded=True, color=QtGui.QColor("#000000"), font=font)
|
||||
units = self.addParent(parent, 'Units', expanded=True, color=QtGui.QColor("#000000"), font=font)
|
||||
obj_type = self.addParent(parent, _('TYPE'), expanded=True, color=QtGui.QColor("#000000"), font=font)
|
||||
obj_name = self.addParent(parent, _('NAME'), expanded=True, color=QtGui.QColor("#000000"), font=font)
|
||||
dims = self.addParent(parent, _('Dimensions'), expanded=True, color=QtGui.QColor("#000000"), font=font)
|
||||
units = self.addParent(parent, _('Units'), expanded=True, color=QtGui.QColor("#000000"), font=font)
|
||||
|
||||
options = self.addParent(parent, 'Options', color=QtGui.QColor("#000000"), font=font)
|
||||
options = self.addParent(parent, _('Options'), color=QtGui.QColor("#000000"), font=font)
|
||||
if obj.kind.lower() == 'gerber':
|
||||
apertures = self.addParent(parent, 'Apertures', expanded=True, color=QtGui.QColor("#000000"), font=font)
|
||||
apertures = self.addParent(parent, _('Apertures'), expanded=True, color=QtGui.QColor("#000000"), font=font)
|
||||
else:
|
||||
tools = self.addParent(parent, 'Tools', expanded=True, color=QtGui.QColor("#000000"), font=font)
|
||||
tools = self.addParent(parent, _('Tools'), expanded=True, color=QtGui.QColor("#000000"), font=font)
|
||||
|
||||
separator = self.addParent(parent, '')
|
||||
|
||||
self.addChild(obj_type, ['Object Type:', ('%s' % (obj.kind.capitalize()))], True)
|
||||
self.addChild(obj_type, ['%s:' % _('Object Type'), ('%s' % (obj.kind.capitalize()))], True)
|
||||
try:
|
||||
self.addChild(obj_type,
|
||||
['Geo Type:', ('%s' % ({False: "Single-Geo", True: "Multi-Geo"}[obj.multigeo]))],
|
||||
['%s:' % _('Geo Type'),
|
||||
('%s' % ({False: _("Single-Geo"), True: _("Multi-Geo")}[obj.multigeo]))],
|
||||
True)
|
||||
except Exception as e:
|
||||
log.debug("Properties.addItems() --> %s" % str(e))
|
||||
|
@ -150,22 +156,44 @@ class Properties(FlatCAMTool):
|
|||
length = abs(xmax - xmin)
|
||||
width = abs(ymax - ymin)
|
||||
|
||||
self.addChild(dims, ['Length:', '%.4f %s' % (
|
||||
self.addChild(dims, ['%s:' % _('Length'), '%.4f %s' % (
|
||||
length, self.app.ui.general_defaults_form.general_app_group.units_radio.get_value().lower())], True)
|
||||
self.addChild(dims, ['Width:', '%.4f %s' % (
|
||||
self.addChild(dims, ['%s:' % _('Width'), '%.4f %s' % (
|
||||
width, self.app.ui.general_defaults_form.general_app_group.units_radio.get_value().lower())], True)
|
||||
|
||||
# calculate and add box area
|
||||
if self.app.ui.general_defaults_form.general_app_group.units_radio.get_value().lower() == 'mm':
|
||||
area = (length * width) / 100
|
||||
self.addChild(dims, ['Box Area:', '%.4f %s' % (area, 'cm2')], True)
|
||||
self.addChild(dims, ['%s:' % _('Box Area'), '%.4f %s' % (area, 'cm2')], True)
|
||||
else:
|
||||
area = length * width
|
||||
self.addChild(dims, ['Box Area:', '%.4f %s' % (area, 'in2')], True)
|
||||
self.addChild(dims, ['%s:' % _('Box Area'), '%.4f %s' % (area, 'in2')], True)
|
||||
|
||||
# calculate and add convex hull area
|
||||
geo = obj.solid_geometry
|
||||
if isinstance(geo, MultiPolygon):
|
||||
env_obj = geo.convex_hull
|
||||
elif (isinstance(geo, MultiPolygon) and len(geo) == 1) or \
|
||||
(isinstance(geo, list) and len(geo) == 1) and isinstance(geo[0], Polygon):
|
||||
env_obj = cascaded_union(self.bound_obj.solid_geometry)
|
||||
env_obj = env_obj.convex_hull
|
||||
else:
|
||||
env_obj = cascaded_union(self.bound_obj.solid_geometry)
|
||||
env_obj = env_obj.convex_hull
|
||||
|
||||
area_chull = env_obj.area
|
||||
if self.app.ui.general_defaults_form.general_app_group.units_radio.get_value().lower() == 'mm':
|
||||
area_chull = area_chull / 100
|
||||
self.addChild(dims, ['%s:' % _('Convex_Hull Area'), '%.4f %s' % (area_chull, 'cm2')], True)
|
||||
else:
|
||||
area_chull = area_chull
|
||||
self.addChild(dims, ['%s:' % _('Convex_Hull Area'), '%.4f %s' % (area_chull, 'in2')], True)
|
||||
|
||||
self.addChild(units,
|
||||
['FlatCAM units:',
|
||||
{
|
||||
'in': 'Inch',
|
||||
'mm': 'Metric'
|
||||
'in': _('Inch'),
|
||||
'mm': _('Metric')
|
||||
}
|
||||
[str(self.app.ui.general_defaults_form.general_app_group.units_radio.get_value().lower())]
|
||||
],
|
||||
|
@ -216,7 +244,7 @@ class Properties(FlatCAMTool):
|
|||
geo_tool = self.addParent(tools, str(tool), expanded=True, color=QtGui.QColor("#000000"), font=font)
|
||||
for k, v in value.items():
|
||||
if k == 'solid_geometry':
|
||||
printed_value = 'Present' if v else 'None'
|
||||
printed_value = _('Present') if v else _('None')
|
||||
self.addChild(geo_tool, [str(k), printed_value], True)
|
||||
elif k == 'data':
|
||||
tool_data = self.addParent(geo_tool, str(k).capitalize(),
|
||||
|
@ -230,13 +258,13 @@ class Properties(FlatCAMTool):
|
|||
geo_tool = self.addParent(tools, str(tool), expanded=True, color=QtGui.QColor("#000000"), font=font)
|
||||
for k, v in value.items():
|
||||
if k == 'solid_geometry':
|
||||
printed_value = 'Present' if v else 'None'
|
||||
printed_value = _('Present') if v else _('None')
|
||||
self.addChild(geo_tool, [str(k), printed_value], True)
|
||||
elif k == 'gcode':
|
||||
printed_value = 'Present' if v != '' else 'None'
|
||||
printed_value = _('Present') if v != '' else _('None')
|
||||
self.addChild(geo_tool, [str(k), printed_value], True)
|
||||
elif k == 'gcode_parsed':
|
||||
printed_value = 'Present' if v else 'None'
|
||||
printed_value = _('Present') if v else _('None')
|
||||
self.addChild(geo_tool, [str(k), printed_value], True)
|
||||
elif k == 'data':
|
||||
tool_data = self.addParent(geo_tool, str(k).capitalize(),
|
||||
|
|
|
@ -139,7 +139,7 @@ class SolderPaste(FlatCAMTool):
|
|||
grid0_1 = QtWidgets.QGridLayout()
|
||||
self.layout.addLayout(grid0_1)
|
||||
|
||||
step1_lbl = QtWidgets.QLabel("<b>%s:</b>" % _('STEP 1:'))
|
||||
step1_lbl = QtWidgets.QLabel("<b>%s:</b>" % _('STEP 1'))
|
||||
step1_lbl.setToolTip(
|
||||
_("First step is to select a number of nozzle tools for usage\n"
|
||||
"and then optionally modify the GCode parameters bellow.")
|
||||
|
@ -163,7 +163,7 @@ class SolderPaste(FlatCAMTool):
|
|||
|
||||
# Z dispense start
|
||||
self.z_start_entry = FCEntry()
|
||||
self.z_start_label = QtWidgets.QLabel(_("Z Dispense Start:"))
|
||||
self.z_start_label = QtWidgets.QLabel('%s:' % _("Z Dispense Start"))
|
||||
self.z_start_label.setToolTip(
|
||||
_("The height (Z) when solder paste dispensing starts.")
|
||||
)
|
||||
|
@ -171,7 +171,7 @@ class SolderPaste(FlatCAMTool):
|
|||
|
||||
# Z dispense
|
||||
self.z_dispense_entry = FCEntry()
|
||||
self.z_dispense_label = QtWidgets.QLabel(_("Z Dispense:"))
|
||||
self.z_dispense_label = QtWidgets.QLabel('%s:' % _("Z Dispense"))
|
||||
self.z_dispense_label.setToolTip(
|
||||
_("The height (Z) when doing solder paste dispensing.")
|
||||
)
|
||||
|
@ -179,7 +179,7 @@ class SolderPaste(FlatCAMTool):
|
|||
|
||||
# Z dispense stop
|
||||
self.z_stop_entry = FCEntry()
|
||||
self.z_stop_label = QtWidgets.QLabel(_("Z Dispense Stop:"))
|
||||
self.z_stop_label = QtWidgets.QLabel('%s:' % _("Z Dispense Stop"))
|
||||
self.z_stop_label.setToolTip(
|
||||
_("The height (Z) when solder paste dispensing stops.")
|
||||
)
|
||||
|
@ -187,7 +187,7 @@ class SolderPaste(FlatCAMTool):
|
|||
|
||||
# Z travel
|
||||
self.z_travel_entry = FCEntry()
|
||||
self.z_travel_label = QtWidgets.QLabel(_("Z Travel:"))
|
||||
self.z_travel_label = QtWidgets.QLabel('%s:' % _("Z Travel"))
|
||||
self.z_travel_label.setToolTip(
|
||||
_("The height (Z) for travel between pads\n"
|
||||
"(without dispensing solder paste).")
|
||||
|
@ -196,7 +196,7 @@ class SolderPaste(FlatCAMTool):
|
|||
|
||||
# Z toolchange location
|
||||
self.z_toolchange_entry = FCEntry()
|
||||
self.z_toolchange_label = QtWidgets.QLabel(_("Z Toolchange:"))
|
||||
self.z_toolchange_label = QtWidgets.QLabel('%s:' % _("Z Toolchange"))
|
||||
self.z_toolchange_label.setToolTip(
|
||||
_("The height (Z) for tool (nozzle) change.")
|
||||
)
|
||||
|
@ -204,7 +204,7 @@ class SolderPaste(FlatCAMTool):
|
|||
|
||||
# X,Y Toolchange location
|
||||
self.xy_toolchange_entry = FCEntry()
|
||||
self.xy_toolchange_label = QtWidgets.QLabel(_("XY Toolchange:"))
|
||||
self.xy_toolchange_label = QtWidgets.QLabel('%s:' % _("Toolchange X-Y"))
|
||||
self.xy_toolchange_label.setToolTip(
|
||||
_("The X,Y location for tool (nozzle) change.\n"
|
||||
"The format is (x, y) where x and y are real numbers.")
|
||||
|
@ -213,7 +213,7 @@ class SolderPaste(FlatCAMTool):
|
|||
|
||||
# Feedrate X-Y
|
||||
self.frxy_entry = FCEntry()
|
||||
self.frxy_label = QtWidgets.QLabel(_("Feedrate X-Y:"))
|
||||
self.frxy_label = QtWidgets.QLabel('%s:' % _("Feedrate X-Y"))
|
||||
self.frxy_label.setToolTip(
|
||||
_("Feedrate (speed) while moving on the X-Y plane.")
|
||||
)
|
||||
|
@ -221,7 +221,7 @@ class SolderPaste(FlatCAMTool):
|
|||
|
||||
# Feedrate Z
|
||||
self.frz_entry = FCEntry()
|
||||
self.frz_label = QtWidgets.QLabel(_("Feedrate Z:"))
|
||||
self.frz_label = QtWidgets.QLabel('%s:' % _("Feedrate Z"))
|
||||
self.frz_label.setToolTip(
|
||||
_("Feedrate (speed) while moving vertically\n"
|
||||
"(on Z plane).")
|
||||
|
@ -230,7 +230,7 @@ class SolderPaste(FlatCAMTool):
|
|||
|
||||
# Feedrate Z Dispense
|
||||
self.frz_dispense_entry = FCEntry()
|
||||
self.frz_dispense_label = QtWidgets.QLabel(_("Feedrate Z Dispense:"))
|
||||
self.frz_dispense_label = QtWidgets.QLabel('%s:' % _("Feedrate Z Dispense"))
|
||||
self.frz_dispense_label.setToolTip(
|
||||
_("Feedrate (speed) while moving up vertically\n"
|
||||
" to Dispense position (on Z plane).")
|
||||
|
@ -239,7 +239,7 @@ class SolderPaste(FlatCAMTool):
|
|||
|
||||
# Spindle Speed Forward
|
||||
self.speedfwd_entry = FCEntry()
|
||||
self.speedfwd_label = QtWidgets.QLabel(_("Spindle Speed FWD:"))
|
||||
self.speedfwd_label = QtWidgets.QLabel('%s:' % _("Spindle Speed FWD"))
|
||||
self.speedfwd_label.setToolTip(
|
||||
_("The dispenser speed while pushing solder paste\n"
|
||||
"through the dispenser nozzle.")
|
||||
|
@ -248,7 +248,7 @@ class SolderPaste(FlatCAMTool):
|
|||
|
||||
# Dwell Forward
|
||||
self.dwellfwd_entry = FCEntry()
|
||||
self.dwellfwd_label = QtWidgets.QLabel(_("Dwell FWD:"))
|
||||
self.dwellfwd_label = QtWidgets.QLabel('%s:' % _("Dwell FWD"))
|
||||
self.dwellfwd_label.setToolTip(
|
||||
_("Pause after solder dispensing.")
|
||||
)
|
||||
|
@ -256,7 +256,7 @@ class SolderPaste(FlatCAMTool):
|
|||
|
||||
# Spindle Speed Reverse
|
||||
self.speedrev_entry = FCEntry()
|
||||
self.speedrev_label = QtWidgets.QLabel(_("Spindle Speed REV:"))
|
||||
self.speedrev_label = QtWidgets.QLabel('%s:' % _("Spindle Speed REV"))
|
||||
self.speedrev_label.setToolTip(
|
||||
_("The dispenser speed while retracting solder paste\n"
|
||||
"through the dispenser nozzle.")
|
||||
|
@ -265,7 +265,7 @@ class SolderPaste(FlatCAMTool):
|
|||
|
||||
# Dwell Reverse
|
||||
self.dwellrev_entry = FCEntry()
|
||||
self.dwellrev_label = QtWidgets.QLabel(_("Dwell REV:"))
|
||||
self.dwellrev_label = QtWidgets.QLabel('%s:' % _("Dwell REV"))
|
||||
self.dwellrev_label.setToolTip(
|
||||
_("Pause after solder paste dispenser retracted,\n"
|
||||
"to allow pressure equilibrium.")
|
||||
|
@ -273,7 +273,7 @@ class SolderPaste(FlatCAMTool):
|
|||
self.gcode_form_layout.addRow(self.dwellrev_label, self.dwellrev_entry)
|
||||
|
||||
# Postprocessors
|
||||
pp_label = QtWidgets.QLabel(_('PostProcessors:'))
|
||||
pp_label = QtWidgets.QLabel('%s:' % _('PostProcessor'))
|
||||
pp_label.setToolTip(
|
||||
_("Files that control the GCode generation.")
|
||||
)
|
||||
|
@ -303,7 +303,7 @@ class SolderPaste(FlatCAMTool):
|
|||
grid2 = QtWidgets.QGridLayout()
|
||||
self.generation_box.addLayout(grid2)
|
||||
|
||||
step2_lbl = QtWidgets.QLabel("<b>%s</b>" % _('STEP 2:'))
|
||||
step2_lbl = QtWidgets.QLabel("<b>%s:</b>" % _('STEP 2'))
|
||||
step2_lbl.setToolTip(
|
||||
_("Second step is to create a solder paste dispensing\n"
|
||||
"geometry out of an Solder Paste Mask Gerber file.")
|
||||
|
@ -321,7 +321,7 @@ class SolderPaste(FlatCAMTool):
|
|||
self.geo_obj_combo.setRootModelIndex(self.app.collection.index(2, 0, QtCore.QModelIndex()))
|
||||
self.geo_obj_combo.setCurrentIndex(1)
|
||||
|
||||
self.geo_object_label = QtWidgets.QLabel(_("Geo Result:"))
|
||||
self.geo_object_label = QtWidgets.QLabel('%s:' % _("Geo Result"))
|
||||
self.geo_object_label.setToolTip(
|
||||
_("Geometry Solder Paste object.\n"
|
||||
"The name of the object has to end in:\n"
|
||||
|
@ -332,7 +332,7 @@ class SolderPaste(FlatCAMTool):
|
|||
grid3 = QtWidgets.QGridLayout()
|
||||
self.generation_box.addLayout(grid3)
|
||||
|
||||
step3_lbl = QtWidgets.QLabel("<b>%s</b>" % _('STEP 3:'))
|
||||
step3_lbl = QtWidgets.QLabel("<b>%s:</b>" % _('STEP 3'))
|
||||
step3_lbl.setToolTip(
|
||||
_("Third step is to select a solder paste dispensing geometry,\n"
|
||||
"and then generate a CNCJob object.\n\n"
|
||||
|
@ -354,7 +354,7 @@ class SolderPaste(FlatCAMTool):
|
|||
self.cnc_obj_combo.setRootModelIndex(self.app.collection.index(3, 0, QtCore.QModelIndex()))
|
||||
self.cnc_obj_combo.setCurrentIndex(1)
|
||||
|
||||
self.cnc_object_label = QtWidgets.QLabel(_("CNC Result:"))
|
||||
self.cnc_object_label = QtWidgets.QLabel('%s:' % _("CNC Result"))
|
||||
self.cnc_object_label.setToolTip(
|
||||
_("CNCJob Solder paste object.\n"
|
||||
"In order to enable the GCode save section,\n"
|
||||
|
@ -378,7 +378,7 @@ class SolderPaste(FlatCAMTool):
|
|||
"on PCB pads, to a file.")
|
||||
)
|
||||
|
||||
step4_lbl = QtWidgets.QLabel("<b>%s</b>" % _('STEP 4:'))
|
||||
step4_lbl = QtWidgets.QLabel("<b>%s:</b>" % _('STEP 4'))
|
||||
step4_lbl.setToolTip(
|
||||
_("Fourth step (and last) is to select a CNCJob made from \n"
|
||||
"a solder paste dispensing geometry, and then view/save it's GCode.")
|
||||
|
@ -436,7 +436,12 @@ class SolderPaste(FlatCAMTool):
|
|||
else:
|
||||
try:
|
||||
if self.app.ui.tool_scroll_area.widget().objectName() == self.toolName:
|
||||
self.app.ui.splitter.setSizes([0, 1])
|
||||
# if tab is populated with the tool but it does not have the focus, focus on it
|
||||
if not self.app.ui.notebook.currentWidget() is self.app.ui.tool_tab:
|
||||
# focus on Tool Tab
|
||||
self.app.ui.notebook.setCurrentWidget(self.app.ui.tool_tab)
|
||||
else:
|
||||
self.app.ui.splitter.setSizes([0, 1])
|
||||
except AttributeError:
|
||||
pass
|
||||
else:
|
||||
|
|
|
@ -23,6 +23,8 @@ if '_' not in builtins.__dict__:
|
|||
|
||||
class ToolSub(FlatCAMTool):
|
||||
|
||||
job_finished = QtCore.pyqtSignal(bool)
|
||||
|
||||
toolName = _("Substract Tool")
|
||||
|
||||
def __init__(self, app):
|
||||
|
@ -52,7 +54,7 @@ class ToolSub(FlatCAMTool):
|
|||
form_layout = QtWidgets.QFormLayout()
|
||||
self.tools_box.addLayout(form_layout)
|
||||
|
||||
self.gerber_title = QtWidgets.QLabel(_("<b>Gerber Objects</b>"))
|
||||
self.gerber_title = QtWidgets.QLabel("<b>%s</b>" % _("Gerber Objects"))
|
||||
form_layout.addRow(self.gerber_title)
|
||||
|
||||
# Target Gerber Object
|
||||
|
@ -61,7 +63,7 @@ class ToolSub(FlatCAMTool):
|
|||
self.target_gerber_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
|
||||
self.target_gerber_combo.setCurrentIndex(1)
|
||||
|
||||
self.target_gerber_label = QtWidgets.QLabel(_("Target:"))
|
||||
self.target_gerber_label = QtWidgets.QLabel('%s:' % _("Target"))
|
||||
self.target_gerber_label.setToolTip(
|
||||
_("Gerber object from which to substract\n"
|
||||
"the substractor Gerber object.")
|
||||
|
@ -75,7 +77,7 @@ class ToolSub(FlatCAMTool):
|
|||
self.sub_gerber_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
|
||||
self.sub_gerber_combo.setCurrentIndex(1)
|
||||
|
||||
self.sub_gerber_label = QtWidgets.QLabel(_("Substractor:"))
|
||||
self.sub_gerber_label = QtWidgets.QLabel('%s:' % _("Substractor"))
|
||||
self.sub_gerber_label.setToolTip(
|
||||
_("Gerber object that will be substracted\n"
|
||||
"from the target Gerber object.")
|
||||
|
@ -98,7 +100,7 @@ class ToolSub(FlatCAMTool):
|
|||
form_geo_layout = QtWidgets.QFormLayout()
|
||||
self.tools_box.addLayout(form_geo_layout)
|
||||
|
||||
self.geo_title = QtWidgets.QLabel(_("<b>Geometry Objects</b>"))
|
||||
self.geo_title = QtWidgets.QLabel("<b>%s</b>" % _("Geometry Objects"))
|
||||
form_geo_layout.addRow(self.geo_title)
|
||||
|
||||
# Target Geometry Object
|
||||
|
@ -107,7 +109,7 @@ class ToolSub(FlatCAMTool):
|
|||
self.target_geo_combo.setRootModelIndex(self.app.collection.index(2, 0, QtCore.QModelIndex()))
|
||||
self.target_geo_combo.setCurrentIndex(1)
|
||||
|
||||
self.target_geo_label = QtWidgets.QLabel(_("Target:"))
|
||||
self.target_geo_label = QtWidgets.QLabel('%s:' % _("Target"))
|
||||
self.target_geo_label.setToolTip(
|
||||
_("Geometry object from which to substract\n"
|
||||
"the substractor Geometry object.")
|
||||
|
@ -121,7 +123,7 @@ class ToolSub(FlatCAMTool):
|
|||
self.sub_geo_combo.setRootModelIndex(self.app.collection.index(2, 0, QtCore.QModelIndex()))
|
||||
self.sub_geo_combo.setCurrentIndex(1)
|
||||
|
||||
self.sub_geo_label = QtWidgets.QLabel(_("Substractor:"))
|
||||
self.sub_geo_label = QtWidgets.QLabel('%s:' % _("Substractor"))
|
||||
self.sub_geo_label.setToolTip(
|
||||
_("Geometry object that will be substracted\n"
|
||||
"from the target Geometry object.")
|
||||
|
@ -188,6 +190,7 @@ class ToolSub(FlatCAMTool):
|
|||
except (TypeError, AttributeError):
|
||||
pass
|
||||
self.intersect_geo_btn.clicked.connect(self.on_geo_intersection_click)
|
||||
self.job_finished.connect(self.on_job_finished)
|
||||
|
||||
def install(self, icon=None, separator=None, **kwargs):
|
||||
FlatCAMTool.install(self, icon, separator, shortcut='ALT+W', **kwargs)
|
||||
|
@ -202,7 +205,12 @@ class ToolSub(FlatCAMTool):
|
|||
else:
|
||||
try:
|
||||
if self.app.ui.tool_scroll_area.widget().objectName() == self.toolName:
|
||||
self.app.ui.splitter.setSizes([0, 1])
|
||||
# if tab is populated with the tool but it does not have the focus, focus on it
|
||||
if not self.app.ui.notebook.currentWidget() is self.app.ui.tool_tab:
|
||||
# focus on Tool Tab
|
||||
self.app.ui.notebook.setCurrentWidget(self.app.ui.tool_tab)
|
||||
else:
|
||||
self.app.ui.splitter.setSizes([0, 1])
|
||||
except AttributeError:
|
||||
pass
|
||||
else:
|
||||
|
@ -286,7 +294,7 @@ class ToolSub(FlatCAMTool):
|
|||
for apid in self.target_grb_obj.apertures:
|
||||
self.promises.append(apid)
|
||||
|
||||
# start the QTimer to check for promises with 1 second period check
|
||||
# start the QTimer to check for promises with 0.5 second period check
|
||||
self.periodic_check(500, reset=True)
|
||||
|
||||
for apid in self.target_grb_obj.apertures:
|
||||
|
@ -413,7 +421,10 @@ class ToolSub(FlatCAMTool):
|
|||
# cleanup
|
||||
self.new_apertures.clear()
|
||||
self.new_solid_geometry[:] = []
|
||||
self.sub_union[:] = []
|
||||
try:
|
||||
self.sub_union[:] = []
|
||||
except TypeError:
|
||||
self.sub_union = []
|
||||
|
||||
def on_geo_intersection_click(self):
|
||||
# reset previous values
|
||||
|
@ -455,14 +466,14 @@ class ToolSub(FlatCAMTool):
|
|||
return
|
||||
|
||||
# create the target_options obj
|
||||
self.target_options = {}
|
||||
for opt in self.target_geo_obj.options:
|
||||
if opt != 'name':
|
||||
self.target_options[opt] = deepcopy(self.target_geo_obj.options[opt])
|
||||
# self.target_options = dict()
|
||||
# for k, v in self.target_geo_obj.options.items():
|
||||
# if k != 'name':
|
||||
# self.target_options[k] = v
|
||||
|
||||
# crate the new_tools dict structure
|
||||
for tool in self.target_geo_obj.tools:
|
||||
self.new_tools[tool] = {}
|
||||
self.new_tools[tool] = dict()
|
||||
for key in self.target_geo_obj.tools[tool]:
|
||||
if key == 'solid_geometry':
|
||||
self.new_tools[tool][key] = []
|
||||
|
@ -514,16 +525,14 @@ class ToolSub(FlatCAMTool):
|
|||
if isinstance(geo_elem, Polygon):
|
||||
for ring in self.poly2rings(geo_elem):
|
||||
new_geo = ring.difference(self.sub_union)
|
||||
if new_geo:
|
||||
if not new_geo.is_empty:
|
||||
new_geometry.append(new_geo)
|
||||
if new_geo and not new_geo.is_empty:
|
||||
new_geometry.append(new_geo)
|
||||
elif isinstance(geo_elem, MultiPolygon):
|
||||
for poly in geo_elem:
|
||||
for ring in self.poly2rings(poly):
|
||||
new_geo = ring.difference(self.sub_union)
|
||||
if new_geo:
|
||||
if not new_geo.is_empty:
|
||||
new_geometry.append(new_geo)
|
||||
if new_geo and not new_geo.is_empty:
|
||||
new_geometry.append(new_geo)
|
||||
elif isinstance(geo_elem, LineString):
|
||||
new_geo = geo_elem.difference(self.sub_union)
|
||||
if new_geo:
|
||||
|
@ -532,9 +541,8 @@ class ToolSub(FlatCAMTool):
|
|||
elif isinstance(geo_elem, MultiLineString):
|
||||
for line_elem in geo_elem:
|
||||
new_geo = line_elem.difference(self.sub_union)
|
||||
if new_geo:
|
||||
if not new_geo.is_empty:
|
||||
new_geometry.append(new_geo)
|
||||
if new_geo and not new_geo.is_empty:
|
||||
new_geometry.append(new_geo)
|
||||
except TypeError:
|
||||
if isinstance(geo, Polygon):
|
||||
for ring in self.poly2rings(geo):
|
||||
|
@ -544,15 +552,13 @@ class ToolSub(FlatCAMTool):
|
|||
new_geometry.append(new_geo)
|
||||
elif isinstance(geo, LineString):
|
||||
new_geo = geo.difference(self.sub_union)
|
||||
if new_geo:
|
||||
if not new_geo.is_empty:
|
||||
new_geometry.append(new_geo)
|
||||
if new_geo and not new_geo.is_empty:
|
||||
new_geometry.append(new_geo)
|
||||
elif isinstance(geo, MultiLineString):
|
||||
for line_elem in geo:
|
||||
new_geo = line_elem.difference(self.sub_union)
|
||||
if new_geo:
|
||||
if not new_geo.is_empty:
|
||||
new_geometry.append(new_geo)
|
||||
if new_geo and not new_geo.is_empty:
|
||||
new_geometry.append(new_geo)
|
||||
|
||||
if new_geometry:
|
||||
if tool == "single":
|
||||
|
@ -575,10 +581,14 @@ class ToolSub(FlatCAMTool):
|
|||
log.debug("Promise fulfilled: %s" % str(tool))
|
||||
|
||||
def new_geo_object(self, outname):
|
||||
geo_name = outname
|
||||
def obj_init(geo_obj, app_obj):
|
||||
|
||||
geo_obj.options = deepcopy(self.target_options)
|
||||
geo_obj.options['name'] = outname
|
||||
# geo_obj.options = self.target_options
|
||||
# create the target_options obj
|
||||
for k, v in self.target_geo_obj.options.items():
|
||||
geo_obj.options[k] = v
|
||||
geo_obj.options['name'] = geo_name
|
||||
|
||||
if self.target_geo_obj.multigeo:
|
||||
geo_obj.tools = deepcopy(self.new_tools)
|
||||
|
@ -593,6 +603,7 @@ class ToolSub(FlatCAMTool):
|
|||
geo_obj.tools[tool]['solid_geometry'] = deepcopy(self.new_solid_geometry)
|
||||
except Exception as e:
|
||||
log.debug("ToolSub.new_geo_object() --> %s" % str(e))
|
||||
geo_obj.multigeo = False
|
||||
|
||||
with self.app.proc_container.new(_("Generating new object ...")):
|
||||
ret = self.app.new_object('geometry', outname, obj_init, autoselected=False)
|
||||
|
@ -607,7 +618,7 @@ class ToolSub(FlatCAMTool):
|
|||
# cleanup
|
||||
self.new_tools.clear()
|
||||
self.new_solid_geometry[:] = []
|
||||
self.sub_union[:] = []
|
||||
self.sub_union = []
|
||||
|
||||
def periodic_check(self, check_period, reset=False):
|
||||
"""
|
||||
|
@ -645,27 +656,39 @@ class ToolSub(FlatCAMTool):
|
|||
try:
|
||||
if not self.promises:
|
||||
self.check_thread.stop()
|
||||
if self.sub_type == "gerber":
|
||||
outname = self.target_gerber_combo.currentText() + '_sub'
|
||||
|
||||
# intersection jobs finished, start the creation of solid_geometry
|
||||
self.app.worker_task.emit({'fcn': self.new_gerber_object,
|
||||
'params': [outname]})
|
||||
else:
|
||||
outname = self.target_geo_combo.currentText() + '_sub'
|
||||
|
||||
# intersection jobs finished, start the creation of solid_geometry
|
||||
self.app.worker_task.emit({'fcn': self.new_geo_object,
|
||||
'params': [outname]})
|
||||
self.job_finished.emit(True)
|
||||
|
||||
# reset the type of substraction for next time
|
||||
self.sub_type = None
|
||||
|
||||
log.debug("ToolSub --> Periodic check finished.")
|
||||
except Exception as e:
|
||||
self.job_finished.emit(False)
|
||||
log.debug("ToolSub().periodic_check_handler() --> %s" % str(e))
|
||||
traceback.print_exc()
|
||||
|
||||
def on_job_finished(self, succcess):
|
||||
"""
|
||||
|
||||
:param succcess: boolean, this parameter signal if all the apertures were processed
|
||||
:return: None
|
||||
"""
|
||||
if succcess is True:
|
||||
if self.sub_type == "gerber":
|
||||
outname = self.target_gerber_combo.currentText() + '_sub'
|
||||
|
||||
# intersection jobs finished, start the creation of solid_geometry
|
||||
self.app.worker_task.emit({'fcn': self.new_gerber_object,
|
||||
'params': [outname]})
|
||||
else:
|
||||
outname = self.target_geo_combo.currentText() + '_sub'
|
||||
|
||||
# intersection jobs finished, start the creation of solid_geometry
|
||||
self.app.worker_task.emit({'fcn': self.new_geo_object,
|
||||
'params': [outname]})
|
||||
else:
|
||||
self.app.inform.emit(_('[ERROR_NOTCL] Generating new object failed.'))
|
||||
|
||||
def reset_fields(self):
|
||||
self.target_gerber_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
|
||||
self.sub_gerber_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
|
||||
|
|
|
@ -65,7 +65,7 @@ class ToolTransform(FlatCAMTool):
|
|||
self.transform_lay.addLayout(form_layout)
|
||||
form_child = QtWidgets.QHBoxLayout()
|
||||
|
||||
self.rotate_label = QtWidgets.QLabel(_("Angle:"))
|
||||
self.rotate_label = QtWidgets.QLabel('%s:' % _("Angle"))
|
||||
self.rotate_label.setToolTip(
|
||||
_("Angle for Rotation action, in degrees.\n"
|
||||
"Float number between -360 and 359.\n"
|
||||
|
@ -104,7 +104,7 @@ class ToolTransform(FlatCAMTool):
|
|||
form1_child_1 = QtWidgets.QHBoxLayout()
|
||||
form1_child_2 = QtWidgets.QHBoxLayout()
|
||||
|
||||
self.skewx_label = QtWidgets.QLabel(_("Angle X:"))
|
||||
self.skewx_label = QtWidgets.QLabel('%s:' % _("Skew_X angle"))
|
||||
self.skewx_label.setToolTip(
|
||||
_("Angle for Skew action, in degrees.\n"
|
||||
"Float number between -360 and 359.")
|
||||
|
@ -122,7 +122,7 @@ class ToolTransform(FlatCAMTool):
|
|||
"the bounding box for all selected objects."))
|
||||
self.skewx_button.setMinimumWidth(90)
|
||||
|
||||
self.skewy_label = QtWidgets.QLabel(_("Angle Y:"))
|
||||
self.skewy_label = QtWidgets.QLabel('%s:' % _("Skew_Y angle"))
|
||||
self.skewy_label.setToolTip(
|
||||
_("Angle for Skew action, in degrees.\n"
|
||||
"Float number between -360 and 359.")
|
||||
|
@ -161,9 +161,9 @@ class ToolTransform(FlatCAMTool):
|
|||
form2_child_1 = QtWidgets.QHBoxLayout()
|
||||
form2_child_2 = QtWidgets.QHBoxLayout()
|
||||
|
||||
self.scalex_label = QtWidgets.QLabel(_("Factor X:"))
|
||||
self.scalex_label = QtWidgets.QLabel('%s:' % _("Scale_X factor"))
|
||||
self.scalex_label.setToolTip(
|
||||
_("Factor for Scale action over X axis.")
|
||||
_("Factor for scaling on X axis.")
|
||||
)
|
||||
self.scalex_label.setMinimumWidth(70)
|
||||
self.scalex_entry = FCEntry()
|
||||
|
@ -178,9 +178,9 @@ class ToolTransform(FlatCAMTool):
|
|||
"the Scale reference checkbox state."))
|
||||
self.scalex_button.setMinimumWidth(90)
|
||||
|
||||
self.scaley_label = QtWidgets.QLabel(_("Factor Y:"))
|
||||
self.scaley_label = QtWidgets.QLabel('%s:' % _("Scale_Y factor"))
|
||||
self.scaley_label.setToolTip(
|
||||
_("Factor for Scale action over Y axis.")
|
||||
_("Factor for scaling on Y axis.")
|
||||
)
|
||||
self.scaley_label.setMinimumWidth(70)
|
||||
self.scaley_entry = FCEntry()
|
||||
|
@ -200,12 +200,13 @@ class ToolTransform(FlatCAMTool):
|
|||
self.scale_link_cb.setText(_("Link"))
|
||||
self.scale_link_cb.setToolTip(
|
||||
_("Scale the selected object(s)\n"
|
||||
"using the Scale Factor X for both axis."))
|
||||
"using the Scale_X factor for both axis.")
|
||||
)
|
||||
self.scale_link_cb.setMinimumWidth(70)
|
||||
|
||||
self.scale_zero_ref_cb = FCCheckBox()
|
||||
self.scale_zero_ref_cb.set_value(True)
|
||||
self.scale_zero_ref_cb.setText(_("Scale Reference"))
|
||||
self.scale_zero_ref_cb.setText('%s' % _("Scale Reference"))
|
||||
self.scale_zero_ref_cb.setToolTip(
|
||||
_("Scale the selected object(s)\n"
|
||||
"using the origin reference when checked,\n"
|
||||
|
@ -235,9 +236,9 @@ class ToolTransform(FlatCAMTool):
|
|||
form3_child_1 = QtWidgets.QHBoxLayout()
|
||||
form3_child_2 = QtWidgets.QHBoxLayout()
|
||||
|
||||
self.offx_label = QtWidgets.QLabel(_("Value X:"))
|
||||
self.offx_label = QtWidgets.QLabel('%s:' % _("Offset_X val"))
|
||||
self.offx_label.setToolTip(
|
||||
_("Value for Offset action on X axis.")
|
||||
_("Distance to offset on X axis. In current units.")
|
||||
)
|
||||
self.offx_label.setMinimumWidth(70)
|
||||
self.offx_entry = FCEntry()
|
||||
|
@ -252,9 +253,9 @@ class ToolTransform(FlatCAMTool):
|
|||
"the bounding box for all selected objects.\n"))
|
||||
self.offx_button.setMinimumWidth(90)
|
||||
|
||||
self.offy_label = QtWidgets.QLabel(_("Value Y:"))
|
||||
self.offy_label = QtWidgets.QLabel('%s:' % _("Offset_Y val"))
|
||||
self.offy_label.setToolTip(
|
||||
_("Value for Offset action on Y axis.")
|
||||
_("Distance to offset on Y axis. In current units.")
|
||||
)
|
||||
self.offy_label.setMinimumWidth(70)
|
||||
self.offy_entry = FCEntry()
|
||||
|
@ -309,7 +310,7 @@ class ToolTransform(FlatCAMTool):
|
|||
|
||||
self.flip_ref_cb = FCCheckBox()
|
||||
self.flip_ref_cb.set_value(True)
|
||||
self.flip_ref_cb.setText(_("Ref Pt"))
|
||||
self.flip_ref_cb.setText('%s' % _("Mirror Reference"))
|
||||
self.flip_ref_cb.setToolTip(
|
||||
_("Flip the selected object(s)\n"
|
||||
"around the point in Point Entry Field.\n"
|
||||
|
@ -322,7 +323,7 @@ class ToolTransform(FlatCAMTool):
|
|||
"Point Entry field and click Flip on X(Y)"))
|
||||
self.flip_ref_cb.setMinimumWidth(70)
|
||||
|
||||
self.flip_ref_label = QtWidgets.QLabel(_("Point:"))
|
||||
self.flip_ref_label = QtWidgets.QLabel('%s:' % _(" Mirror Ref. Point"))
|
||||
self.flip_ref_label.setToolTip(
|
||||
_("Coordinates in format (x, y) used as reference for mirroring.\n"
|
||||
"The 'x' in (x, y) will be used when using Flip on X and\n"
|
||||
|
@ -384,7 +385,12 @@ class ToolTransform(FlatCAMTool):
|
|||
else:
|
||||
try:
|
||||
if self.app.ui.tool_scroll_area.widget().objectName() == self.toolName:
|
||||
self.app.ui.splitter.setSizes([0, 1])
|
||||
# if tab is populated with the tool but it does not have the focus, focus on it
|
||||
if not self.app.ui.notebook.currentWidget() is self.app.ui.tool_tab:
|
||||
# focus on Tool Tab
|
||||
self.app.ui.notebook.setCurrentWidget(self.app.ui.tool_tab)
|
||||
else:
|
||||
self.app.ui.splitter.setSizes([0, 1])
|
||||
except AttributeError:
|
||||
pass
|
||||
else:
|
||||
|
|
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -57,7 +57,7 @@ class TclCommandFollow(TclCommandSignaled):
|
|||
|
||||
del args['name']
|
||||
try:
|
||||
obj.follow(**args)
|
||||
obj.follow_geo(**args)
|
||||
except Exception as e:
|
||||
return "Operation failed: %s" % str(e)
|
||||
|
||||
|
|
Loading…
Reference in New Issue