- renamed classes to have shorter names and grouped

This commit is contained in:
Marius Stanciu
2020-05-18 16:02:41 +03:00
committed by Marius
parent 4c83e87feb
commit ba3f10d355
185 changed files with 749 additions and 748 deletions

1221
AppObjects/FlatCAMCNCJob.py Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,335 @@
# ##########################################################
# FlatCAM: 2D Post-processing for Manufacturing #
# http://flatcam.org #
# Author: Juan Pablo Caram (c) #
# Date: 2/5/2014 #
# MIT Licence #
# ##########################################################
# ##########################################################
# File modified by: Marius Stanciu #
# ##########################################################
from AppEditors.FlatCAMTextEditor import TextEditor
from AppObjects.FlatCAMObj import *
import gettext
import AppTranslation as fcTranslate
import builtins
fcTranslate.apply_language('strings')
if '_' not in builtins.__dict__:
_ = gettext.gettext
class DocumentObject(FlatCAMObj):
"""
Represents a Document object.
"""
optionChanged = QtCore.pyqtSignal(str)
ui_type = DocumentObjectUI
def __init__(self, name):
self.decimals = self.app.decimals
log.debug("Creating a Document object...")
FlatCAMObj.__init__(self, name)
self.kind = "document"
self.units = ''
self.ser_attrs = ['options', 'kind', 'source_file']
self.source_file = ''
self.doc_code = ''
self.font_name = None
self.font_italic = None
self.font_bold = None
self.font_underline = None
self.document_editor_tab = None
self._read_only = False
self.units_found = self.app.defaults['units']
def set_ui(self, ui):
FlatCAMObj.set_ui(self, ui)
log.debug("DocumentObject.set_ui()")
assert isinstance(self.ui, DocumentObjectUI), \
"Expected a DocumentObjectUI, got %s" % type(self.ui)
self.units = self.app.defaults['units'].upper()
self.units_found = self.app.defaults['units']
# Fill form fields only on object create
self.to_form()
# Show/Hide Advanced Options
if self.app.defaults["global_app_level"] == 'b':
self.ui.level.setText(_(
'<span style="color:green;"><b>Basic</b></span>'
))
else:
self.ui.level.setText(_(
'<span style="color:red;"><b>Advanced</b></span>'
))
self.document_editor_tab = TextEditor(app=self.app)
stylesheet = """
QTextEdit {selection-background-color:%s;
selection-color:white;
}
""" % self.app.defaults["document_sel_color"]
self.document_editor_tab.code_editor.setStyleSheet(stylesheet)
# first clear previous text in text editor (if any)
self.document_editor_tab.code_editor.clear()
self.document_editor_tab.code_editor.setReadOnly(self._read_only)
self.document_editor_tab.buttonRun.hide()
self.ui.autocomplete_cb.set_value(self.app.defaults['document_autocompleter'])
self.on_autocomplete_changed(state=self.app.defaults['document_autocompleter'])
self.on_tab_size_change(val=self.app.defaults['document_tab_size'])
flt = "FlatCAM Docs (*.FlatDoc);;All Files (*.*)"
# ######################################################################
# ######################## SIGNALS #####################################
# ######################################################################
self.document_editor_tab.buttonOpen.clicked.disconnect()
self.document_editor_tab.buttonOpen.clicked.connect(lambda: self.document_editor_tab.handleOpen(filt=flt))
self.document_editor_tab.buttonSave.clicked.disconnect()
self.document_editor_tab.buttonSave.clicked.connect(lambda: self.document_editor_tab.handleSaveGCode(filt=flt))
self.document_editor_tab.code_editor.textChanged.connect(self.on_text_changed)
self.ui.font_type_cb.currentFontChanged.connect(self.font_family)
self.ui.font_size_cb.activated.connect(self.font_size)
self.ui.font_bold_tb.clicked.connect(self.on_bold_button)
self.ui.font_italic_tb.clicked.connect(self.on_italic_button)
self.ui.font_under_tb.clicked.connect(self.on_underline_button)
self.ui.font_color_entry.editingFinished.connect(self.on_font_color_entry)
self.ui.font_color_button.clicked.connect(self.on_font_color_button)
self.ui.sel_color_entry.editingFinished.connect(self.on_selection_color_entry)
self.ui.sel_color_button.clicked.connect(self.on_selection_color_button)
self.ui.al_left_tb.clicked.connect(lambda: self.document_editor_tab.code_editor.setAlignment(Qt.AlignLeft))
self.ui.al_center_tb.clicked.connect(lambda: self.document_editor_tab.code_editor.setAlignment(Qt.AlignCenter))
self.ui.al_right_tb.clicked.connect(lambda: self.document_editor_tab.code_editor.setAlignment(Qt.AlignRight))
self.ui.al_justify_tb.clicked.connect(
lambda: self.document_editor_tab.code_editor.setAlignment(Qt.AlignJustify)
)
self.ui.autocomplete_cb.stateChanged.connect(self.on_autocomplete_changed)
self.ui.tab_size_spinner.returnPressed.connect(self.on_tab_size_change)
# #######################################################################
self.ui.font_color_entry.set_value(self.app.defaults['document_font_color'])
self.ui.font_color_button.setStyleSheet(
"background-color:%s" % str(self.app.defaults['document_font_color']))
self.ui.sel_color_entry.set_value(self.app.defaults['document_sel_color'])
self.ui.sel_color_button.setStyleSheet(
"background-color:%s" % self.app.defaults['document_sel_color'])
self.ui.font_size_cb.setCurrentIndex(int(self.app.defaults['document_font_size']))
self.document_editor_tab.handleTextChanged()
self.ser_attrs = ['options', 'kind', 'source_file']
if Qt.mightBeRichText(self.source_file):
self.document_editor_tab.code_editor.setHtml(self.source_file)
else:
for line in self.source_file.splitlines():
self.document_editor_tab.code_editor.append(line)
self.build_ui()
@property
def read_only(self):
return self._read_only
@read_only.setter
def read_only(self, val):
if val:
self._read_only = True
else:
self._read_only = False
def build_ui(self):
FlatCAMObj.build_ui(self)
tab_here = False
# try to not add too many times a tab that it is already installed
for idx in range(self.app.ui.plot_tab_area.count()):
if self.app.ui.plot_tab_area.widget(idx).objectName() == self.options['name']:
tab_here = True
break
# add the tab if it is not already added
if tab_here is False:
self.app.ui.plot_tab_area.addTab(self.document_editor_tab, '%s' % _("Document Editor"))
self.document_editor_tab.setObjectName(self.options['name'])
# Switch plot_area to CNCJob tab
self.app.ui.plot_tab_area.setCurrentWidget(self.document_editor_tab)
def on_autocomplete_changed(self, state):
if state:
self.document_editor_tab.code_editor.completer_enable = True
else:
self.document_editor_tab.code_editor.completer_enable = False
def on_tab_size_change(self, val=None):
try:
self.ui.tab_size_spinner.returnPressed.disconnect(self.on_tab_size_change)
except TypeError:
pass
if val:
self.ui.tab_size_spinner.set_value(val)
tab_balue = int(self.ui.tab_size_spinner.get_value())
self.document_editor_tab.code_editor.setTabStopWidth(tab_balue)
self.app.defaults['document_tab_size'] = tab_balue
self.ui.tab_size_spinner.returnPressed.connect(self.on_tab_size_change)
def on_text_changed(self):
self.source_file = self.document_editor_tab.code_editor.toHtml()
# print(self.source_file)
def font_family(self, font):
# self.document_editor_tab.code_editor.selectAll()
font.setPointSize(float(self.ui.font_size_cb.get_value()))
self.document_editor_tab.code_editor.setCurrentFont(font)
self.font_name = self.ui.font_type_cb.currentFont().family()
def font_size(self):
# self.document_editor_tab.code_editor.selectAll()
self.document_editor_tab.code_editor.setFontPointSize(float(self.ui.font_size_cb.get_value()))
def on_bold_button(self):
if self.ui.font_bold_tb.isChecked():
self.document_editor_tab.code_editor.setFontWeight(QtGui.QFont.Bold)
self.font_bold = True
else:
self.document_editor_tab.code_editor.setFontWeight(QtGui.QFont.Normal)
self.font_bold = False
def on_italic_button(self):
if self.ui.font_italic_tb.isChecked():
self.document_editor_tab.code_editor.setFontItalic(True)
self.font_italic = True
else:
self.document_editor_tab.code_editor.setFontItalic(False)
self.font_italic = False
def on_underline_button(self):
if self.ui.font_under_tb.isChecked():
self.document_editor_tab.code_editor.setFontUnderline(True)
self.font_underline = True
else:
self.document_editor_tab.code_editor.setFontUnderline(False)
self.font_underline = False
# Setting font colors handlers
def on_font_color_entry(self):
self.app.defaults['document_font_color'] = self.ui.font_color_entry.get_value()
self.ui.font_color_button.setStyleSheet("background-color:%s" % str(self.app.defaults['document_font_color']))
def on_font_color_button(self):
current_color = QtGui.QColor(self.app.defaults['document_font_color'])
c_dialog = QtWidgets.QColorDialog()
font_color = c_dialog.getColor(initial=current_color)
if font_color.isValid() is False:
return
self.document_editor_tab.code_editor.setTextColor(font_color)
self.ui.font_color_button.setStyleSheet("background-color:%s" % str(font_color.name()))
new_val = str(font_color.name())
self.ui.font_color_entry.set_value(new_val)
self.app.defaults['document_font_color'] = new_val
# Setting selection colors handlers
def on_selection_color_entry(self):
self.app.defaults['document_sel_color'] = self.ui.sel_color_entry.get_value()
self.ui.sel_color_button.setStyleSheet("background-color:%s" % str(self.app.defaults['document_sel_color']))
def on_selection_color_button(self):
current_color = QtGui.QColor(self.app.defaults['document_sel_color'])
c_dialog = QtWidgets.QColorDialog()
sel_color = c_dialog.getColor(initial=current_color)
if sel_color.isValid() is False:
return
p = QtGui.QPalette()
p.setColor(QtGui.QPalette.Highlight, sel_color)
p.setColor(QtGui.QPalette.HighlightedText, QtGui.QColor('white'))
self.document_editor_tab.code_editor.setPalette(p)
self.ui.sel_color_button.setStyleSheet("background-color:%s" % str(sel_color.name()))
new_val = str(sel_color.name())
self.ui.sel_color_entry.set_value(new_val)
self.app.defaults['document_sel_color'] = new_val
def mirror(self, axis, point):
pass
def offset(self, vect):
pass
def rotate(self, angle, point):
pass
def scale(self, xfactor, yfactor=None, point=None):
pass
def skew(self, angle_x, angle_y, point):
pass
def buffer(self, distance, join, factor=None):
pass
def bounds(self, flatten=False):
return None, None, None, None
def to_dict(self):
"""
Returns a representation of the object as a dictionary.
Attributes to include are listed in ``self.ser_attrs``.
:return: A dictionary-encoded copy of the object.
:rtype: dict
"""
d = {}
for attr in self.ser_attrs:
d[attr] = getattr(self, attr)
return d
def from_dict(self, d):
"""
Sets object's attributes from a dictionary.
Attributes to include are listed in ``self.ser_attrs``.
This method will look only for only and all the
attributes in ``self.ser_attrs``. They must all
be present. Use only for deserializing saved
objects.
:param d: Dictionary of attributes to set in the object.
:type d: dict
:return: None
"""
for attr in self.ser_attrs:
setattr(self, attr, d[attr])

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

1869
AppObjects/FlatCAMGerber.py Normal file

File diff suppressed because it is too large Load Diff

503
AppObjects/FlatCAMObj.py Normal file
View File

@@ -0,0 +1,503 @@
# ##########################################################
# FlatCAM: 2D Post-processing for Manufacturing #
# http://flatcam.org #
# Author: Juan Pablo Caram (c) #
# Date: 2/5/2014 #
# MIT Licence #
# ##########################################################
# ##########################################################
# File modified by: Marius Stanciu #
# ##########################################################
import inspect # TODO: For debugging only.
from AppGUI.ObjectUI import *
from Common import LoudDict
from AppGUI.PlotCanvasLegacy import ShapeCollectionLegacy
import sys
import gettext
import AppTranslation as fcTranslate
import builtins
fcTranslate.apply_language('strings')
if '_' not in builtins.__dict__:
_ = gettext.gettext
# Interrupts plotting process if FlatCAMObj has been deleted
class ObjectDeleted(Exception):
pass
class ValidationError(Exception):
def __init__(self, message, errors):
super().__init__(message)
self.errors = errors
class FlatCAMObj(QtCore.QObject):
"""
Base type of objects handled in FlatCAM. These become interactive
in the AppGUI, can be plotted, and their options can be modified
by the user in their respective forms.
"""
# Instance of the application to which these are related.
# The app should set this value.
app = None
# signal to plot a single object
plot_single_object = QtCore.pyqtSignal()
def __init__(self, name):
"""
Constructor.
:param name: Name of the object given by the user.
:return: FlatCAMObj
"""
QtCore.QObject.__init__(self)
# View
self.ui = None
self.options = LoudDict(name=name)
self.options.set_change_callback(self.on_options_change)
self.form_fields = {}
# store here the default data for Geometry Data
self.default_data = {}
# 2D mode
# Axes must exist and be attached to canvas.
self.axes = None
self.kind = None # Override with proper name
if self.app.is_legacy is False:
self.shapes = self.app.plotcanvas.new_shape_group()
# self.shapes = ShapeCollection(parent=self.app.plotcanvas.view.scene, pool=self.app.pool, layers=2)
else:
self.shapes = ShapeCollectionLegacy(obj=self, app=self.app, name=name)
self.mark_shapes = {}
self.item = None # Link with project view item
self.muted_ui = False
self.deleted = False
try:
self._drawing_tolerance = float(self.app.defaults["global_tolerance"]) if \
self.app.defaults["global_tolerance"] else 0.01
except ValueError:
self._drawing_tolerance = 0.01
self.isHovering = False
self.notHovering = True
# Flag to show if a selection shape is drawn
self.selection_shape_drawn = False
# self.units = 'IN'
self.units = self.app.defaults['units']
self.plot_single_object.connect(self.single_object_plot)
def __del__(self):
pass
def __str__(self):
return "<FlatCAMObj({:12s}): {:20s}>".format(self.kind, self.options["name"])
def from_dict(self, d):
"""
This supersedes ``from_dict`` in derived classes. Derived classes
must inherit from FlatCAMObj first, then from derivatives of Geometry.
``self.options`` is only updated, not overwritten. This ensures that
options set by the app do not vanish when reading the objects
from a project file.
:param d: Dictionary with attributes to set.
:return: None
"""
for attr in self.ser_attrs:
if attr == 'options':
self.options.update(d[attr])
else:
try:
setattr(self, attr, d[attr])
except KeyError:
log.debug("FlatCAMObj.from_dict() --> KeyError: %s. "
"Means that we are loading an old project that don't"
"have all attributes in the latest FlatCAM." % str(attr))
pass
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']
self.optionChanged.emit(key)
def set_ui(self, ui):
self.ui = ui
self.form_fields = {"name": self.ui.name_entry}
assert isinstance(self.ui, ObjectUI)
self.ui.name_entry.returnPressed.connect(self.on_name_activate)
try:
# it will raise an exception for those FlatCAM objects that do not build UI with the common elements
self.ui.offset_button.clicked.connect(self.on_offset_button_click)
except (TypeError, AttributeError):
pass
try:
self.ui.scale_button.clicked.connect(self.on_scale_button_click)
except (TypeError, AttributeError):
pass
try:
self.ui.offsetvector_entry.returnPressed.connect(self.on_offset_button_click)
except (TypeError, AttributeError):
pass
# Creates problems on focusOut
try:
self.ui.scale_entry.returnPressed.connect(self.on_scale_button_click)
except (TypeError, AttributeError):
pass
# self.ui.skew_button.clicked.connect(self.on_skew_button_click)
def build_ui(self):
"""
Sets up the UI/form for this object. Show the UI in the App.
:return: None
"""
self.muted_ui = True
log.debug(str(inspect.stack()[1][3]) + "--> FlatCAMObj.build_ui()")
try:
# HACK: disconnect the scale entry signal since on focus out event will trigger an undesired scale()
# it seems that the takewidget() does generate a focus out event for the QDoubleSpinbox ...
# and reconnect after the takeWidget() is done
# self.ui.scale_entry.returnPressed.disconnect(self.on_scale_button_click)
self.app.ui.selected_scroll_area.takeWidget()
# self.ui.scale_entry.returnPressed.connect(self.on_scale_button_click)
except Exception as e:
self.app.log.debug("FlatCAMObj.build_ui() --> Nothing to remove: %s" % str(e))
self.app.ui.selected_scroll_area.setWidget(self.ui)
# self.ui.setMinimumWidth(100)
# self.ui.setMaximumWidth(self.app.ui.selected_tab.sizeHint().width())
self.muted_ui = False
def on_name_activate(self, silent=None):
old_name = copy(self.options["name"])
new_name = self.ui.name_entry.get_value()
if new_name != old_name:
# update the SHELL auto-completer model data
try:
self.app.myKeywords.remove(old_name)
self.app.myKeywords.append(new_name)
self.app.shell._edit.set_model_data(self.app.myKeywords)
self.app.ui.code_editor.set_model_data(self.app.myKeywords)
except Exception:
log.debug("on_name_activate() --> Could not remove the old object name from auto-completer model list")
self.options["name"] = self.ui.name_entry.get_value()
self.default_data["name"] = self.ui.name_entry.get_value()
self.app.collection.update_view()
if silent:
self.app.inform.emit('[success] %s: %s %s: %s' % (
_("Name changed from"), str(old_name), _("to"), str(new_name)
)
)
def on_offset_button_click(self):
self.app.defaults.report_usage("obj_on_offset_button")
self.read_form()
vector_val = self.ui.offsetvector_entry.get_value()
def worker_task():
with self.app.proc_container.new(_("Offsetting...")):
self.offset(vector_val)
self.app.proc_container.update_view_text('')
with self.app.proc_container.new('%s...' % _("Plotting")):
self.plot()
self.app.object_changed.emit(self)
self.app.worker_task.emit({'fcn': worker_task, 'params': []})
def on_scale_button_click(self):
self.read_form()
try:
factor = float(eval(self.ui.scale_entry.get_value()))
except Exception as e:
self.app.inform.emit('[ERROR_NOTCL] %s' % _("Scaling could not be executed."))
log.debug("FlatCAMObj.on_scale_button_click() -- %s" % str(e))
return
if type(factor) != float:
self.app.inform.emit('[ERROR_NOTCL] %s' % _("Scaling could not be executed."))
# if factor is 1.0 do nothing, there is no point in scaling with a factor of 1.0
if factor == 1.0:
self.app.inform.emit('[success] %s' % _("Scale done."))
return
log.debug("FlatCAMObj.on_scale_button_click()")
def worker_task():
with self.app.proc_container.new(_("Scaling...")):
self.scale(factor)
self.app.inform.emit('[success] %s' % _("Scale done."))
self.app.proc_container.update_view_text('')
with self.app.proc_container.new('%s...' % _("Plotting")):
self.plot()
self.app.object_changed.emit(self)
self.app.worker_task.emit({'fcn': worker_task, 'params': []})
def on_skew_button_click(self):
self.app.defaults.report_usage("obj_on_skew_button")
self.read_form()
x_angle = self.ui.xangle_entry.get_value()
y_angle = self.ui.yangle_entry.get_value()
def worker_task():
with self.app.proc_container.new(_("Skewing...")):
self.skew(x_angle, y_angle)
self.app.proc_container.update_view_text('')
with self.app.proc_container.new('%s...' % _("Plotting")):
self.plot()
self.app.object_changed.emit(self)
self.app.worker_task.emit({'fcn': worker_task, 'params': []})
def to_form(self):
"""
Copies options to the UI form.
:return: None
"""
log.debug(str(inspect.stack()[1][3]) + " --> FlatCAMObj.to_form()")
for option in self.options:
try:
self.set_form_item(option)
except Exception as err:
self.app.log.warning("Unexpected error: %s" % str(sys.exc_info()), str(err))
def read_form(self):
"""
Reads form into ``self.options``.
:return: None
:rtype: None
"""
log.debug(str(inspect.stack()[1][3]) + "--> FlatCAMObj.read_form()")
for option in self.options:
try:
self.read_form_item(option)
except Exception:
self.app.log.warning("Unexpected error: %s" % str(sys.exc_info()))
def set_form_item(self, option):
"""
Copies the specified option to the UI form.
:param option: Name of the option (Key in ``self.options``).
:type option: str
:return: None
"""
try:
self.form_fields[option].set_value(self.options[option])
except KeyError:
# self.app.log.warn("Tried to set an option or field that does not exist: %s" % option)
pass
def read_form_item(self, option):
"""
Reads the specified option from the UI form into ``self.options``.
:param option: Name of the option.
:type option: str
:return: None
"""
try:
self.options[option] = self.form_fields[option].get_value()
except KeyError:
pass
# self.app.log.warning("Failed to read option from field: %s" % option)
def plot(self, kind=None):
"""
Plot this object (Extend this method to implement the actual plotting).
Call this in descendants before doing the plotting.
:param kind: Used by only some of the FlatCAM objects
:return: Whether to continue plotting or not depending on the "plot" option. Boolean
"""
log.debug(str(inspect.stack()[1][3]) + " --> FlatCAMObj.plot()")
if self.deleted:
return False
self.clear()
return True
def single_object_plot(self):
def plot_task():
with self.app.proc_container.new('%s...' % _("Plotting")):
self.plot()
self.app.object_changed.emit(self)
self.app.worker_task.emit({'fcn': plot_task, 'params': []})
def serialize(self):
"""
Returns a representation of the object as a dictionary so
it can be later exported as JSON. Override this method.
:return: Dictionary representing the object
:rtype: dict
"""
return
def deserialize(self, obj_dict):
"""
Re-builds an object from its serialized version.
:param obj_dict: Dictionary representing a FlatCAMObj
:type obj_dict: dict
:return: None
"""
return
def add_shape(self, **kwargs):
if self.deleted:
raise ObjectDeleted()
else:
key = self.shapes.add(tolerance=self.drawing_tolerance, **kwargs)
return key
def add_mark_shape(self, apid, **kwargs):
if self.deleted:
raise ObjectDeleted()
else:
key = self.mark_shapes[apid].add(tolerance=self.drawing_tolerance, layer=0, **kwargs)
return key
def update_filters(self, last_ext, filter_string):
"""
Will modify the filter string that is used when saving a file (a list of file extensions) to have the last
used file extension as the first one in the special string
:param last_ext: The file extension that was last used to save a file
:param filter_string: A key in self.app.defaults that holds a string with the filter from QFileDialog
used when saving a file
:return: None
"""
filters = copy(self.app.defaults[filter_string])
filter_list = filters.split(';;')
filter_list_enum_1 = enumerate(filter_list)
# search for the last element in the filters which should always be "All Files (*.*)"
last_elem = ''
for elem in list(filter_list_enum_1):
if '(*.*)' in elem[1]:
last_elem = filter_list.pop(elem[0])
filter_list_enum = enumerate(filter_list)
for elem in list(filter_list_enum):
if '.' + last_ext in elem[1]:
used_ext = filter_list.pop(elem[0])
# sort the extensions back
filter_list.sort(key=lambda x: x.rpartition('.')[2])
# add as a first element the last used extension
filter_list.insert(0, used_ext)
# add back the element that should always be the last (All Files)
filter_list.append(last_elem)
self.app.defaults[filter_string] = ';;'.join(filter_list)
return
@staticmethod
def poly2rings(poly):
return [poly.exterior] + [interior for interior in poly.interiors]
@property
def visible(self):
return self.shapes.visible
@visible.setter
def visible(self, value, threaded=True):
log.debug("FlatCAMObj.visible()")
def worker_task(app_obj):
self.shapes.visible = value
if self.app.is_legacy is False:
# Not all object types has annotations
try:
self.annotation.visible = value
except Exception:
pass
if threaded is False:
worker_task(app_obj=self.app)
else:
self.app.worker_task.emit({'fcn': worker_task, 'params': [self]})
@property
def drawing_tolerance(self):
self.units = self.app.defaults['units'].upper()
tol = self._drawing_tolerance if self.units == 'MM' or not self.units else self._drawing_tolerance / 25.4
return tol
@drawing_tolerance.setter
def drawing_tolerance(self, value):
self.units = self.app.defaults['units'].upper()
self._drawing_tolerance = value if self.units == 'MM' or not self.units else value / 25.4
def clear(self, update=False):
self.shapes.clear(update)
# Not all object types has annotations
try:
self.annotation.clear(update)
except AttributeError:
pass
def delete(self):
# Free resources
del self.ui
del self.options
# Set flag
self.deleted = True

284
AppObjects/FlatCAMScript.py Normal file
View File

@@ -0,0 +1,284 @@
# ##########################################################
# FlatCAM: 2D Post-processing for Manufacturing #
# http://flatcam.org #
# Author: Juan Pablo Caram (c) #
# Date: 2/5/2014 #
# MIT Licence #
# ##########################################################
# ##########################################################
# File modified by: Marius Stanciu #
# ##########################################################
from AppEditors.FlatCAMTextEditor import TextEditor
from AppObjects.FlatCAMObj import *
from AppGUI.ObjectUI import *
import tkinter as tk
import sys
from copy import deepcopy
import gettext
import AppTranslation as fcTranslate
import builtins
fcTranslate.apply_language('strings')
if '_' not in builtins.__dict__:
_ = gettext.gettext
class ScriptObject(FlatCAMObj):
"""
Represents a TCL script object.
"""
optionChanged = QtCore.pyqtSignal(str)
ui_type = ScriptObjectUI
def __init__(self, name):
self.decimals = self.app.decimals
log.debug("Creating a ScriptObject object...")
FlatCAMObj.__init__(self, name)
self.kind = "script"
self.options.update({
"plot": True,
"type": 'Script',
"source_file": '',
})
self.units = ''
self.script_editor_tab = None
self.ser_attrs = ['options', 'kind', 'source_file']
self.source_file = ''
self.script_code = ''
self.units_found = self.app.defaults['units']
def set_ui(self, ui):
"""
Sets the Object UI in Selected Tab for the FlatCAM Script type of object.
:param ui:
:return:
"""
FlatCAMObj.set_ui(self, ui)
log.debug("ScriptObject.set_ui()")
assert isinstance(self.ui, ScriptObjectUI), \
"Expected a ScriptObjectUI, got %s" % type(self.ui)
self.units = self.app.defaults['units'].upper()
self.units_found = self.app.defaults['units']
# Fill form fields only on object create
self.to_form()
# Show/Hide Advanced Options
if self.app.defaults["global_app_level"] == 'b':
self.ui.level.setText(_(
'<span style="color:green;"><b>Basic</b></span>'
))
else:
self.ui.level.setText(_(
'<span style="color:red;"><b>Advanced</b></span>'
))
self.script_editor_tab = TextEditor(app=self.app, plain_text=True, parent=self.app.ui)
# tab_here = False
# # try to not add too many times a tab that it is already installed
# for idx in range(self.app.ui.plot_tab_area.count()):
# if self.app.ui.plot_tab_area.widget(idx).objectName() == self.options['name']:
# tab_here = True
# break
#
# # add the tab if it is not already added
# if tab_here is False:
# self.app.ui.plot_tab_area.addTab(self.script_editor_tab, '%s' % _("Script Editor"))
# self.script_editor_tab.setObjectName(self.options['name'])
# self.app.ui.plot_tab_area.addTab(self.script_editor_tab, '%s' % _("Script Editor"))
# self.script_editor_tab.setObjectName(self.options['name'])
# first clear previous text in text editor (if any)
# self.script_editor_tab.code_editor.clear()
# self.script_editor_tab.code_editor.setReadOnly(False)
self.ui.autocomplete_cb.set_value(self.app.defaults['script_autocompleter'])
self.on_autocomplete_changed(state=self.app.defaults['script_autocompleter'])
self.script_editor_tab.buttonRun.show()
# Switch plot_area to Script Editor tab
self.app.ui.plot_tab_area.setCurrentWidget(self.script_editor_tab)
flt = "FlatCAM Scripts (*.FlatScript);;All Files (*.*)"
self.script_editor_tab.buttonOpen.clicked.disconnect()
self.script_editor_tab.buttonOpen.clicked.connect(lambda: self.script_editor_tab.handleOpen(filt=flt))
self.script_editor_tab.buttonSave.clicked.disconnect()
self.script_editor_tab.buttonSave.clicked.connect(lambda: self.script_editor_tab.handleSaveGCode(filt=flt))
self.script_editor_tab.buttonRun.clicked.connect(self.handle_run_code)
self.script_editor_tab.handleTextChanged()
self.ui.autocomplete_cb.stateChanged.connect(self.on_autocomplete_changed)
self.ser_attrs = ['options', 'kind', 'source_file']
# ---------------------------------------------------- #
# ----------- LOAD THE TEXT SOURCE FILE -------------- #
# ---------------------------------------------------- #
self.app.proc_container.view.set_busy(_("Loading..."))
self.script_editor_tab.t_frame.hide()
try:
self.script_editor_tab.code_editor.setPlainText(self.source_file)
# for line in self.source_file.splitlines():
# QtWidgets.QApplication.processEvents()
# self.script_editor_tab.code_editor.append(line)
except Exception as e:
log.debug("ScriptObject.set_ui() --> %s" % str(e))
self.script_editor_tab.code_editor.moveCursor(QtGui.QTextCursor.End)
self.script_editor_tab.t_frame.show()
self.app.proc_container.view.set_idle()
self.build_ui()
def build_ui(self):
FlatCAMObj.build_ui(self)
tab_here = False
# try to not add too many times a tab that it is already installed
for idx in range(self.app.ui.plot_tab_area.count()):
if self.app.ui.plot_tab_area.widget(idx).objectName() == self.options['name']:
tab_here = True
break
# add the tab if it is not already added
if tab_here is False:
self.app.ui.plot_tab_area.addTab(self.script_editor_tab, '%s' % _("Script Editor"))
self.script_editor_tab.setObjectName(self.options['name'])
self.app.ui.plot_tab_area.setCurrentWidget(self.script_editor_tab)
def parse_file(self, filename):
"""
Will set an attribute of the object, self.source_file, with the parsed data.
:param filename: Tcl Script file to parse
:return: None
"""
with open(filename, "r") as opened_script:
script_content = opened_script.readlines()
script_content = ''.join(script_content)
self.source_file = script_content
def handle_run_code(self):
# trying to run a Tcl command without having the Shell open will create some warnings because the Tcl Shell
# tries to print on a hidden widget, therefore show the dock if hidden
if self.app.ui.shell_dock.isHidden():
self.app.ui.shell_dock.show()
self.app.shell.open_processing() # Disables input box.
# make sure that the pixmaps are not updated when running this as they will crash
# TODO find why the pixmaps load crash when run from this object (perhaps another thread?)
self.app.ui.fcinfo.lock_pmaps = True
self.script_code = self.script_editor_tab.code_editor.toPlainText()
old_line = ''
for tcl_command_line in self.script_code.splitlines():
# do not process lines starting with '#' = comment and empty lines
if not tcl_command_line.startswith('#') and tcl_command_line != '':
# id FlatCAM is run in Windows then replace all the slashes with
# the UNIX style slash that TCL understands
if sys.platform == 'win32':
if "open" in tcl_command_line:
tcl_command_line = tcl_command_line.replace('\\', '/')
if old_line != '':
new_command = old_line + tcl_command_line + '\n'
else:
new_command = tcl_command_line
# execute the actual Tcl command
try:
result = self.app.shell.tcl.eval(str(new_command))
if result != 'None':
self.app.shell.append_output(result + '\n')
old_line = ''
except tk.TclError:
old_line = old_line + tcl_command_line + '\n'
except Exception as e:
log.debug("ScriptObject.handleRunCode() --> %s" % str(e))
if old_line != '':
# it means that the script finished with an error
result = self.app.shell.tcl.eval("set errorInfo")
log.error("Exec command Exception: %s\n" % result)
self.app.shell.append_error('ERROR: %s\n '% result)
self.app.ui.fcinfo.lock_pmaps = False
self.app.shell.close_processing()
def on_autocomplete_changed(self, state):
if state:
self.script_editor_tab.code_editor.completer_enable = True
else:
self.script_editor_tab.code_editor.completer_enable = False
def mirror(self, axis, point):
pass
def offset(self, vect):
pass
def rotate(self, angle, point):
pass
def scale(self, xfactor, yfactor=None, point=None):
pass
def skew(self, angle_x, angle_y, point):
pass
def buffer(self, distance, join, factor=None):
pass
def bounds(self, flatten=False):
return None, None, None, None
def to_dict(self):
"""
Returns a representation of the object as a dictionary.
Attributes to include are listed in ``self.ser_attrs``.
:return: A dictionary-encoded copy of the object.
:rtype: dict
"""
d = {}
for attr in self.ser_attrs:
d[attr] = getattr(self, attr)
return d
def from_dict(self, d):
"""
Sets object's attributes from a dictionary.
Attributes to include are listed in ``self.ser_attrs``.
This method will look only for only and all the
attributes in ``self.ser_attrs``. They must all
be present. Use only for deserializing saved
objects.
:param d: Dictionary of attributes to set in the object.
:type d: dict
:return: None
"""
for attr in self.ser_attrs:
setattr(self, attr, d[attr])

File diff suppressed because it is too large Load Diff

0
AppObjects/__init__.py Normal file
View File