- remade the ReadMe tab

- Tool Isolation - added a GUI element to control if the isolation of a polygon, when done with rest, should be done with the current tool even if its interiors (holes in it) could not be isolated or to be left for the next tool
- updated all the translation strings to the latest changes
This commit is contained in:
Marius Stanciu 2020-06-05 20:38:13 +03:00 committed by Marius
parent 8f07d95017
commit fc60677cb8
25 changed files with 7213 additions and 6517 deletions

View File

@ -16,6 +16,9 @@ CHANGELOG for FlatCAM beta
- changed how the import of svg.path module is done in the ParseSVG.py file
- Tool Isolation - new feature that allow to isolate interiors of polygons (holes in polygons). It is possible that the isolation to be reported as successful (internal limitations) but some interiors to not be isolated. This way the user get to fix the isolation by doing an extra isolation.
- added mouse events disconnect in the quit_application() method
- remade the ReadMe tab
- Tool Isolation - added a GUI element to control if the isolation of a polygon, when done with rest, should be done with the current tool even if its interiors (holes in it) could not be isolated or to be left for the next tool
- updated all the translation strings to the latest changes
4.06.2020

View File

@ -349,6 +349,7 @@ class PreferencesUIManager:
"tools_iso_isoexcept": self.ui.tools_defaults_form.tools_iso_group.except_cb,
"tools_iso_selection": self.ui.tools_defaults_form.tools_iso_group.select_combo,
"tools_iso_poly_ints": self.ui.tools_defaults_form.tools_iso_group.poly_int_cb,
"tools_iso_force": self.ui.tools_defaults_form.tools_iso_group.force_iso_cb,
"tools_iso_area_shape": self.ui.tools_defaults_form.tools_iso_group.area_shape_radio,
"tools_iso_plotting": self.ui.tools_defaults_form.tools_iso_group.plotting_radio,

View File

@ -302,15 +302,21 @@ class ToolsISOPrefGroupUI(OptionsGroupUI):
grid0.addWidget(self.area_shape_radio, 21, 1, 1, 2)
# Polygon interiors selection
self.poly_int_label = QtWidgets.QLabel('%s:' % _("Interiors"))
self.poly_int_label.setToolTip(
self.poly_int_cb = FCCheckBox(_("Interiors"))
self.poly_int_cb.setToolTip(
_("When checked the user can select interiors of a polygon.\n"
"(holes in the polygon).")
)
self.poly_int_cb = FCCheckBox()
grid0.addWidget(self.poly_int_label, 22, 0)
grid0.addWidget(self.poly_int_cb, 22, 1)
# Force isolation even if the interiors are not isolated
self.force_iso_cb = FCCheckBox(_("Forced Rest"))
self.force_iso_cb.setToolTip(
_("When checked the isolation will be done with the current tool even if\n"
"interiors of a polygon (holes in the polygon) could not be isolated.\n"
"Works when 'rest machining' is used.")
)
grid0.addWidget(self.poly_int_cb, 22, 0)
grid0.addWidget(self.force_iso_cb, 22, 1)
separator_line = QtWidgets.QFrame()
separator_line.setFrameShape(QtWidgets.QFrame.HLine)

View File

@ -443,6 +443,16 @@ class ToolIsolation(AppTool, Gerber):
self.grid3.addWidget(self.rest_cb, 25, 0)
# Force isolation even if the interiors are not isolated
self.forced_rest_iso_cb = FCCheckBox(_("Forced Rest"))
self.forced_rest_iso_cb.setToolTip(
_("When checked the isolation will be done with the current tool even if\n"
"interiors of a polygon (holes in the polygon) could not be isolated.\n"
"Works when 'rest machining' is used.")
)
self.grid3.addWidget(self.forced_rest_iso_cb, 25, 1)
# Combine All Passes
self.combine_passes_cb = FCCheckBox(label=_('Combine'))
self.combine_passes_cb.setToolTip(
@ -450,7 +460,7 @@ class ToolIsolation(AppTool, Gerber):
)
self.combine_passes_cb.setObjectName("i_combine")
self.grid3.addWidget(self.combine_passes_cb, 25, 1)
self.grid3.addWidget(self.combine_passes_cb, 26, 0, 1, 2)
# Exception Areas
self.except_cb = FCCheckBox(label=_('Except'))
@ -537,17 +547,14 @@ class ToolIsolation(AppTool, Gerber):
self.reference_combo_type_label.hide()
# Polygon interiors selection
self.poly_int_label = QtWidgets.QLabel('%s:' % _("Interiors"))
self.poly_int_label.setToolTip(
self.poly_int_cb = FCCheckBox(_("Interiors"))
self.poly_int_cb.setToolTip(
_("When checked the user can select interiors of a polygon.\n"
"(holes in the polygon).")
)
self.poly_int_cb = FCCheckBox()
self.grid3.addWidget(self.poly_int_label, 33, 0)
self.grid3.addWidget(self.poly_int_cb, 33, 1)
self.grid3.addWidget(self.poly_int_cb, 33, 0)
self.poly_int_label.hide()
self.poly_int_cb.hide()
# Area Selection shape
@ -880,6 +887,7 @@ class ToolIsolation(AppTool, Gerber):
self.combine_passes_cb.set_value(self.app.defaults["tools_iso_combine_passes"])
self.area_shape_radio.set_value(self.app.defaults["tools_iso_area_shape"])
self.poly_int_cb.set_value(self.app.defaults["tools_iso_poly_ints"])
self.forced_rest_iso_cb.set_value(self.app.defaults["tools_iso_force"])
self.cutz_entry.set_value(self.app.defaults["tools_iso_tool_cutz"])
self.tool_type_radio.set_value(self.app.defaults["tools_iso_tool_type"])
@ -938,6 +946,8 @@ class ToolIsolation(AppTool, Gerber):
"tools_iso_combine_passes": self.app.defaults["tools_iso_combine_passes"],
"tools_iso_isoexcept": self.app.defaults["tools_iso_isoexcept"],
"tools_iso_selection": self.app.defaults["tools_iso_selection"],
"tools_iso_poly_ints": self.app.defaults["tools_iso_poly_ints"],
"tools_iso_force": self.app.defaults["tools_iso_force"],
"tools_iso_area_shape": self.app.defaults["tools_iso_area_shape"]
}
@ -1306,7 +1316,6 @@ class ToolIsolation(AppTool, Gerber):
self.reference_combo_type_label.hide()
self.area_shape_label.hide()
self.area_shape_radio.hide()
self.poly_int_label.hide()
self.poly_int_cb.hide()
# disable rest-machining for area painting
@ -1318,7 +1327,6 @@ class ToolIsolation(AppTool, Gerber):
self.reference_combo_type_label.hide()
self.area_shape_label.show()
self.area_shape_radio.show()
self.poly_int_label.hide()
self.poly_int_cb.hide()
# disable rest-machining for area isolation
@ -1331,7 +1339,6 @@ class ToolIsolation(AppTool, Gerber):
self.reference_combo_type_label.hide()
self.area_shape_label.hide()
self.area_shape_radio.hide()
self.poly_int_label.show()
self.poly_int_cb.show()
else:
self.reference_combo.show()
@ -1340,7 +1347,6 @@ class ToolIsolation(AppTool, Gerber):
self.reference_combo_type_label.show()
self.area_shape_label.hide()
self.area_shape_radio.hide()
self.poly_int_label.hide()
self.poly_int_cb.hide()
# disable rest-machining for area painting
@ -1359,6 +1365,8 @@ class ToolIsolation(AppTool, Gerber):
self.old_combine_state = self.combine_passes_cb.get_value()
self.combine_passes_cb.set_value(True)
self.combine_passes_cb.setDisabled(True)
self.forced_rest_iso_cb.setDisabled(False)
else:
self.order_label.setDisabled(False)
self.order_radio.setDisabled(False)
@ -1366,6 +1374,8 @@ class ToolIsolation(AppTool, Gerber):
self.combine_passes_cb.set_value(self.old_combine_state)
self.combine_passes_cb.setDisabled(False)
self.forced_rest_iso_cb.setDisabled(True)
def on_tooltable_cellwidget_change(self):
cw = self.sender()
assert isinstance(cw, QtWidgets.QComboBox), \
@ -1660,6 +1670,7 @@ class ToolIsolation(AppTool, Gerber):
# Propagate options
follow_obj.options["cnctooldia"] = str(tooldia)
follow_obj.solid_geometry = self.grb_obj.follow_geometry
app_obj.inform.emit('[success] %s.' % _("Following geometry was generated"))
# in the end toggle the visibility of the origin object so we can see the generated Geometry
followed_obj.ui.plot_cb.set_value(False)
@ -1957,12 +1968,6 @@ class ToolIsolation(AppTool, Gerber):
tool_type = tools_storage[tool]['tool_type']
tool_data = tools_storage[tool]['data']
iso_t = {
'ext': 0,
'int': 1,
'full': 2
}[tool_data['tools_iso_isotype']]
passes = tool_data['tools_iso_passes']
overlap = tool_data['tools_iso_overlap']
overlap /= 100.0
@ -1970,11 +1975,16 @@ class ToolIsolation(AppTool, Gerber):
milling_type = tool_data['tools_iso_milling_type']
# if milling type is climb then the move is counter-clockwise around features
mill_dir = True if milling_type == 'cl' else False
iso_t = {
'ext': 0,
'int': 1,
'full': 2
}[tool_data['tools_iso_isotype']]
forced_rest = self.forced_rest_iso_cb.get_value()
iso_except = self.except_cb.get_value()
outname = "%s_%.*f" % (iso_obj.options["name"], self.decimals, float(tool_dia))
internal_name = outname + "_iso"
if iso_t == 0:
internal_name = outname + "_ext_iso"
@ -1988,6 +1998,7 @@ class ToolIsolation(AppTool, Gerber):
solid_geo, work_geo = self.generate_rest_geometry(geometry=work_geo, tooldia=tool_dia,
passes=passes, overlap=overlap, invert=mill_dir,
env_iso_type=iso_t, negative_dia=negative_dia,
forced_rest=forced_rest,
prog_plot=prog_plot,
prog_plot_handler=self.plot_temp_shapes)
@ -2965,6 +2976,7 @@ class ToolIsolation(AppTool, Gerber):
@staticmethod
def generate_rest_geometry(geometry, tooldia, passes, overlap, invert, env_iso_type=2, negative_dia=None,
forced_rest=False,
prog_plot="normal", prog_plot_handler=None):
"""
Will try to isolate the geometry and return a tuple made of list of paths made through isolation
@ -2982,8 +2994,10 @@ class ToolIsolation(AppTool, Gerber):
:type invert: bool
:param env_iso_type: can be either 0 = keep exteriors or 1 = keep interiors or 2 = keep all paths
:type env_iso_type: int
:param negative_dia: isolate the geometry with a negative value for the tool diameter
:type negative_dia: bool
:param negative_dia: isolate the geometry with a negative value for the tool diameter
:type negative_dia: bool
:param forced_rest: isolate the polygon even if the interiors can not be isolated
:type forced_rest: bool
:param prog_plot: kind of plotting: "progressive" or "normal"
:type prog_plot: str
:param prog_plot_handler: method used to plot shapes if plot_prog is "proggressive"
@ -3030,7 +3044,7 @@ class ToolIsolation(AppTool, Gerber):
# resulting isolated geometry (buffered) number of subgeo is the same as the exterior + interiors
# if not it means that the geo interiors most likely could not be isolated with this tool so we
# abandon the whole isolation for this geo and add this geo to the not_isolated_geo
if nr_pass == 0:
if nr_pass == 0 and forced_rest is True:
if geo.interiors:
len_interiors = len(geo.interiors)
if len_interiors > 1:

View File

@ -2947,7 +2947,13 @@ class App(QtCore.QObject):
AboutDialog(app=self, parent=self.ui).exec_()
def on_readme(self):
class AboutDialog(QtWidgets.QDialog):
"""
Displays the "about" dialog found in the Menu --> Help.
:return: None
"""
class ReadmeDialog(QtWidgets.QDialog):
def __init__(self, app, parent=None):
QtWidgets.QDialog.__init__(self, parent)
@ -2955,73 +2961,139 @@ class App(QtCore.QObject):
open_source_link = "<a href = 'https://opensource.org/'<b>Open Source</b></a>"
new_features_link = "<a href = 'https://bitbucket.org/jpcgt/flatcam/pull-requests/'" \
"<b>new features</b></a>"
"<b>click</b></a>"
bugs_link = "<a href = 'https://bitbucket.org/jpcgt/flatcam/issues/new'<b>report bugs</b></a>"
bugs_link = "<a href = 'https://bitbucket.org/jpcgt/flatcam/issues/new'<b>click</b></a>"
donation_link = "<a href = 'https://www.paypal.com/cgi-bin/webscr?cmd=_" \
"donations&business=WLTJJ3Q77D98L&currency_code=USD&source=url'<b>donation</b></a>"
"donations&business=WLTJJ3Q77D98L&currency_code=USD&source=url'<b>click</b></a>"
# Icon and title
self.setWindowIcon(parent.app_icon)
self.setWindowTitle(_("Important Information's"))
self.resize(720, 330)
self.resize(750, 375)
logo = QtWidgets.QLabel()
logo.setPixmap(QtGui.QPixmap(self.app.resource_location + '/contribute256.png'))
content = QtWidgets.QLabel(
"This program is %s and free in a very wide meaning of the word.<br>"
"Yet it cannot evolve without <b>contributions</b>.<br><br>"
"If you want to see this application evolve and grow, or if you make money with it,<br>"
"you can <b>contribute</b> to the development yourself by:<br>"
"%s<br>"
"%s<br><br>"
"%s,<br>"
"%s<br>"
"<ul>"
"<li>adding %s through a Pull Request on the Bitbucket repository</li>"
"<li>%s by providing the steps required to reproduce the bug</li>"
"<li>or by making a %s.</li>"
"<li> &nbsp;%s %s</li>"
"<li> &nbsp;%s %s</li>"
"</ul>"
"There are no strings attached.<br>"
"You don't have to make a %s, and it is totally optional but:"
"%s %s.<br>"
"%s"
"<ul>"
"<li>it will be welcomed with joy &#128077;</li>"
"<li>it will give me a reason to continue &#128513;</li>"
"<li> &nbsp;%s &#128077;</li>"
"<li> &nbsp;%s &#128513;</li>"
"</ul>" %
(open_source_link, new_features_link, bugs_link, donation_link, donation_link)
(
_("This program is %s and free in a very wide meaning of the word.") % open_source_link,
_("Yet it cannot evolve without <b>contributions</b>."),
_("If you want to see this application grow and become better and better"),
_("you can <b>contribute</b> to the development yourself by:"),
_("Pull Requests on the Bitbucket repository, if you are a developer"),
new_features_link,
_("Bug Reports by providing the steps required to reproduce the bug"),
bugs_link,
_("If you like or use this program you can make a donation"),
donation_link,
_("You don't have to make a donation %s, and it is totally optional but:") % donation_link,
_("it will be welcomed with joy"),
_("it will give me a reason to continue")
)
)
content.setOpenExternalLinks(True)
closebtn = QtWidgets.QPushButton(_("Close"))
# layouts
layout1 = QtWidgets.QVBoxLayout()
self.setLayout(layout1)
# palette
pal = QtGui.QPalette()
pal.setColor(QtGui.QPalette.Background, Qt.white)
# layouts
main_layout = QtWidgets.QVBoxLayout()
self.setLayout(main_layout)
tab_layout = QtWidgets.QHBoxLayout()
buttons_hlay = QtWidgets.QHBoxLayout()
main_layout.addLayout(tab_layout)
main_layout.addLayout(buttons_hlay)
tab_widget = QtWidgets.QTabWidget()
tab_layout.addWidget(tab_widget)
closebtn = QtWidgets.QPushButton(_("Close"))
buttons_hlay.addStretch()
buttons_hlay.addWidget(closebtn)
# CONTRIBUTE section
self.intro_tab = QtWidgets.QWidget()
self.intro_tab_layout = QtWidgets.QHBoxLayout(self.intro_tab)
self.intro_tab_layout.setContentsMargins(2, 2, 2, 2)
tab_widget.addTab(self.intro_tab, _("Contribute"))
self.grid_lay = QtWidgets.QGridLayout()
self.grid_lay.setHorizontalSpacing(20)
self.grid_lay.setColumnStretch(0, 0)
self.grid_lay.setColumnStretch(1, 1)
content_widget = QtWidgets.QWidget()
content_widget.setLayout(self.grid_lay)
scroll_area = QtWidgets.QScrollArea()
scroll_area.setWidget(content_widget)
scroll_area.setWidgetResizable(True)
scroll_area.setFrameShape(QtWidgets.QFrame.NoFrame)
scroll_area.setPalette(pal)
intro_wdg = QtWidgets.QWidget()
intro_wdg.setLayout(self.grid_lay)
intro_scroll_area = QtWidgets.QScrollArea()
intro_scroll_area.setWidget(intro_wdg)
intro_scroll_area.setWidgetResizable(True)
intro_scroll_area.setFrameShape(QtWidgets.QFrame.NoFrame)
intro_scroll_area.setPalette(pal)
self.grid_lay.addWidget(logo, 0, 0)
self.grid_lay.addWidget(content, 0, 1)
layout1.addWidget(scroll_area)
self.intro_tab_layout.addWidget(intro_scroll_area)
layout2 = QtWidgets.QHBoxLayout()
layout1.addLayout(layout2)
layout2.addStretch()
layout2.addWidget(closebtn)
# LINKS EXCHANGE section
self.links_tab = QtWidgets.QWidget()
self.links_tab_layout = QtWidgets.QVBoxLayout(self.links_tab)
self.links_tab_layout.setContentsMargins(2, 2, 2, 2)
tab_widget.addTab(self.links_tab, _("Links Exchange"))
self.links_lay = QtWidgets.QHBoxLayout()
links_wdg = QtWidgets.QWidget()
links_wdg.setLayout(self.links_lay)
links_scroll_area = QtWidgets.QScrollArea()
links_scroll_area.setWidget(links_wdg)
links_scroll_area.setWidgetResizable(True)
links_scroll_area.setFrameShape(QtWidgets.QFrame.NoFrame)
links_scroll_area.setPalette(pal)
self.links_lay.addWidget(QtWidgets.QLabel('%s' % _("Soon ...")), alignment=QtCore.Qt.AlignCenter)
self.links_tab_layout.addWidget(links_scroll_area)
# HOW TO section
self.howto_tab = QtWidgets.QWidget()
self.howto_tab_layout = QtWidgets.QVBoxLayout(self.howto_tab)
self.howto_tab_layout.setContentsMargins(2, 2, 2, 2)
tab_widget.addTab(self.howto_tab, _("How To's"))
self.howto_lay = QtWidgets.QHBoxLayout()
howto_wdg = QtWidgets.QWidget()
howto_wdg.setLayout(self.howto_lay)
howto_scroll_area = QtWidgets.QScrollArea()
howto_scroll_area.setWidget(howto_wdg)
howto_scroll_area.setWidgetResizable(True)
howto_scroll_area.setFrameShape(QtWidgets.QFrame.NoFrame)
howto_scroll_area.setPalette(pal)
self.howto_lay.addWidget(QtWidgets.QLabel('%s' % _("Soon ...")), alignment=QtCore.Qt.AlignCenter)
self.howto_tab_layout.addWidget(howto_scroll_area)
# BUTTONS section
closebtn.clicked.connect(self.accept)
AboutDialog(app=self, parent=self.ui).exec_()
ReadmeDialog(app=self, parent=self.ui).exec_()
def install_bookmarks(self, book_dict=None):
"""

View File

@ -403,6 +403,7 @@ class FlatCAMDefaults:
"tools_iso_isoexcept": False,
"tools_iso_selection": _("All"),
"tools_iso_poly_ints": False,
"tools_iso_force": True,
"tools_iso_area_shape": "square",
"tools_iso_plotting": 'normal',

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

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