- maintenance_1
|
@ -1,181 +0,0 @@
|
|||
# ##########################################################
|
||||
# FlatCAM: 2D Post-processing for Manufacturing #
|
||||
# File by: David Robertson (c) #
|
||||
# Date: 5/2020 #
|
||||
# License: MIT Licence #
|
||||
# ##########################################################
|
||||
|
||||
import sys
|
||||
|
||||
from PyQt5.QtCore import QPoint, QRect, QSize, Qt
|
||||
from PyQt5.QtWidgets import QLayout, QSizePolicy
|
||||
import math
|
||||
|
||||
|
||||
class ColumnarFlowLayout(QLayout):
|
||||
def __init__(self, parent=None, margin=0, spacing=-1):
|
||||
super().__init__(parent)
|
||||
|
||||
if parent is not None:
|
||||
self.setContentsMargins(margin, margin, margin, margin)
|
||||
|
||||
self.setSpacing(spacing)
|
||||
self.itemList = []
|
||||
|
||||
def __del__(self):
|
||||
del_item = self.takeAt(0)
|
||||
while del_item:
|
||||
del_item = self.takeAt(0)
|
||||
|
||||
def addItem(self, item):
|
||||
self.itemList.append(item)
|
||||
|
||||
def count(self):
|
||||
return len(self.itemList)
|
||||
|
||||
def itemAt(self, index):
|
||||
if 0 <= index < len(self.itemList):
|
||||
return self.itemList[index]
|
||||
return None
|
||||
|
||||
def takeAt(self, index):
|
||||
if 0 <= index < len(self.itemList):
|
||||
return self.itemList.pop(index)
|
||||
return None
|
||||
|
||||
def expandingDirections(self):
|
||||
return Qt.Orientations(Qt.Orientation(0))
|
||||
|
||||
def hasHeightForWidth(self):
|
||||
return True
|
||||
|
||||
def heightForWidth(self, width):
|
||||
height = self.doLayout(QRect(0, 0, width, 0), True)
|
||||
return height
|
||||
|
||||
def setGeometry(self, rect):
|
||||
super().setGeometry(rect)
|
||||
self.doLayout(rect, False)
|
||||
|
||||
def sizeHint(self):
|
||||
return self.minimumSize()
|
||||
|
||||
def minimumSize(self):
|
||||
size = QSize()
|
||||
|
||||
for item in self.itemList:
|
||||
size = size.expandedTo(item.minimumSize())
|
||||
|
||||
margin, _, _, _ = self.getContentsMargins()
|
||||
|
||||
size += QSize(2 * margin, 2 * margin)
|
||||
return size
|
||||
|
||||
def doLayout(self, rect: QRect, testOnly: bool) -> int:
|
||||
spacing = self.spacing()
|
||||
x = rect.x()
|
||||
y = rect.y()
|
||||
|
||||
# Determine width of widest item
|
||||
widest = 0
|
||||
for item in self.itemList:
|
||||
widest = max(widest, item.sizeHint().width())
|
||||
|
||||
# Determine how many equal-width columns we can get, and how wide each one should be
|
||||
column_count = math.floor(rect.width() / (widest + spacing))
|
||||
column_count = min(column_count, len(self.itemList))
|
||||
column_count = max(1, column_count)
|
||||
column_width = math.floor((rect.width() - (column_count-1)*spacing - 1) / column_count)
|
||||
|
||||
# Get the heights for all of our items
|
||||
item_heights = {}
|
||||
for item in self.itemList:
|
||||
height = item.heightForWidth(column_width) if item.hasHeightForWidth() else item.sizeHint().height()
|
||||
item_heights[item] = height
|
||||
|
||||
# Prepare our column representation
|
||||
column_contents = []
|
||||
column_heights = []
|
||||
for column_index in range(column_count):
|
||||
column_contents.append([])
|
||||
column_heights.append(0)
|
||||
|
||||
def add_to_column(column: int, item):
|
||||
column_contents[column].append(item)
|
||||
column_heights[column] += (item_heights[item] + spacing)
|
||||
|
||||
def shove_one(from_column: int) -> bool:
|
||||
if len(column_contents[from_column]) >= 1:
|
||||
item = column_contents[from_column].pop(0)
|
||||
column_heights[from_column] -= (item_heights[item] + spacing)
|
||||
add_to_column(from_column-1, item)
|
||||
return True
|
||||
return False
|
||||
|
||||
def shove_cascade_consider(from_column: int) -> bool:
|
||||
changed_item = False
|
||||
|
||||
if len(column_contents[from_column]) > 1:
|
||||
item = column_contents[from_column][0]
|
||||
item_height = item_heights[item]
|
||||
if column_heights[from_column-1] + item_height < max(column_heights):
|
||||
changed_item = shove_one(from_column) or changed_item
|
||||
|
||||
if from_column+1 < column_count:
|
||||
changed_item = shove_cascade_consider(from_column+1) or changed_item
|
||||
|
||||
return changed_item
|
||||
|
||||
def shove_cascade() -> bool:
|
||||
if column_count < 2:
|
||||
return False
|
||||
changed_item = True
|
||||
while changed_item:
|
||||
changed_item = shove_cascade_consider(1)
|
||||
return changed_item
|
||||
|
||||
def pick_best_shoving_position() -> int:
|
||||
best_pos = 1
|
||||
best_height = sys.maxsize
|
||||
for column_idx in range(1, column_count):
|
||||
if len(column_contents[column_idx]) == 0:
|
||||
continue
|
||||
item = column_contents[column_idx][0]
|
||||
height_after_shove = column_heights[column_idx-1] + item_heights[item]
|
||||
if height_after_shove < best_height:
|
||||
best_height = height_after_shove
|
||||
best_pos = column_idx
|
||||
return best_pos
|
||||
|
||||
# Calculate the best layout
|
||||
column_index = 0
|
||||
for item in self.itemList:
|
||||
item_height = item_heights[item]
|
||||
if column_heights[column_index] != 0 and (column_heights[column_index] + item_height) > max(column_heights):
|
||||
column_index += 1
|
||||
if column_index >= column_count:
|
||||
# Run out of room, need to shove more stuff in each column
|
||||
if column_count >= 2:
|
||||
changed = shove_cascade()
|
||||
if not changed:
|
||||
shoving_pos = pick_best_shoving_position()
|
||||
shove_one(shoving_pos)
|
||||
shove_cascade()
|
||||
column_index = column_count-1
|
||||
|
||||
add_to_column(column_index, item)
|
||||
|
||||
shove_cascade()
|
||||
|
||||
# Set geometry according to the layout we have calculated
|
||||
if not testOnly:
|
||||
for column_index, items in enumerate(column_contents):
|
||||
x = column_index * (column_width + spacing)
|
||||
y = 0
|
||||
for item in items:
|
||||
height = item_heights[item]
|
||||
item.setGeometry(QRect(x, y, column_width, height))
|
||||
y += (height + spacing)
|
||||
|
||||
# Return the overall height
|
||||
return max(column_heights)
|
|
@ -1,327 +0,0 @@
|
|||
from typing import Union, Sequence, List
|
||||
|
||||
from PyQt5 import QtWidgets, QtGui
|
||||
from PyQt5.QtCore import QSettings
|
||||
|
||||
from AppGUI.GUIElements import RadioSet, FCCheckBox, FCButton, FCComboBox, FCEntry, FCSpinner, FCColorEntry, \
|
||||
FCSliderWithSpinner, FCDoubleSpinner, FloatEntry, FCTextArea
|
||||
|
||||
import gettext
|
||||
import AppTranslation as fcTranslate
|
||||
import builtins
|
||||
|
||||
fcTranslate.apply_language('strings')
|
||||
if '_' not in builtins.__dict__:
|
||||
_ = gettext.gettext
|
||||
|
||||
|
||||
class OptionUI:
|
||||
|
||||
def __init__(self, option: str):
|
||||
self.option = option
|
||||
|
||||
def add_to_grid(self, grid: QtWidgets.QGridLayout, row: int) -> int:
|
||||
"""
|
||||
Adds the necessary widget to the grid, starting at the supplied row.
|
||||
Returns the number of rows used (normally 1)
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
|
||||
def get_field(self):
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
class BasicOptionUI(OptionUI):
|
||||
"""Abstract OptionUI that has a label on the left then some other widget on the right"""
|
||||
def __init__(self, option: str, label_text: str, label_tooltip: Union[str, None] = None,
|
||||
label_bold: bool = False, label_color: Union[str, None] = None):
|
||||
super().__init__(option=option)
|
||||
self.label_text = label_text
|
||||
self.label_tooltip = label_tooltip
|
||||
self.label_bold = label_bold
|
||||
self.label_color = label_color
|
||||
self.label_widget = self.build_label_widget()
|
||||
self.entry_widget = self.build_entry_widget()
|
||||
|
||||
def build_label_widget(self) -> QtWidgets.QLabel:
|
||||
fmt = "%s:"
|
||||
if self.label_bold:
|
||||
fmt = "<b>%s</b>" % fmt
|
||||
if self.label_color:
|
||||
fmt = "<span style=\"color:%s;\">%s</span>" % (self.label_color, fmt)
|
||||
label_widget = QtWidgets.QLabel(fmt % _(self.label_text))
|
||||
if self.label_tooltip is not None:
|
||||
label_widget.setToolTip(_(self.label_tooltip))
|
||||
return label_widget
|
||||
|
||||
def build_entry_widget(self) -> QtWidgets.QWidget:
|
||||
raise NotImplementedError()
|
||||
|
||||
def add_to_grid(self, grid: QtWidgets.QGridLayout, row: int) -> int:
|
||||
grid.addWidget(self.label_widget, row, 0)
|
||||
grid.addWidget(self.entry_widget, row, 1)
|
||||
return 1
|
||||
|
||||
def get_field(self):
|
||||
return self.entry_widget
|
||||
|
||||
|
||||
class LineEntryOptionUI(BasicOptionUI):
|
||||
def build_entry_widget(self) -> QtWidgets.QWidget:
|
||||
return FCEntry()
|
||||
|
||||
|
||||
# Not sure why this is needed over DoubleSpinnerOptionUI
|
||||
class FloatEntryOptionUI(BasicOptionUI):
|
||||
def build_entry_widget(self) -> QtWidgets.QWidget:
|
||||
return FloatEntry()
|
||||
|
||||
|
||||
class RadioSetOptionUI(BasicOptionUI):
|
||||
|
||||
def __init__(self, option: str, label_text: str, choices: list, orientation='horizontal', **kwargs):
|
||||
self.choices = choices
|
||||
self.orientation = orientation
|
||||
super().__init__(option=option, label_text=label_text, **kwargs)
|
||||
|
||||
def build_entry_widget(self) -> QtWidgets.QWidget:
|
||||
return RadioSet(choices=self.choices, orientation=self.orientation)
|
||||
|
||||
|
||||
class TextAreaOptionUI(OptionUI):
|
||||
|
||||
def __init__(self, option: str, label_text: str, label_tooltip: str):
|
||||
super().__init__(option=option)
|
||||
self.label_text = label_text
|
||||
self.label_tooltip = label_tooltip
|
||||
self.label_widget = self.build_label_widget()
|
||||
self.textarea_widget = self.build_textarea_widget()
|
||||
|
||||
def build_label_widget(self):
|
||||
label = QtWidgets.QLabel("%s:" % _(self.label_text))
|
||||
label.setToolTip(_(self.label_tooltip))
|
||||
return label
|
||||
|
||||
def build_textarea_widget(self):
|
||||
textarea = FCTextArea()
|
||||
textarea.setPlaceholderText(_(self.label_tooltip))
|
||||
|
||||
qsettings = QSettings("Open Source", "FlatCAM")
|
||||
if qsettings.contains("textbox_font_size"):
|
||||
tb_fsize = qsettings.value('textbox_font_size', type=int)
|
||||
else:
|
||||
tb_fsize = 10
|
||||
font = QtGui.QFont()
|
||||
font.setPointSize(tb_fsize)
|
||||
textarea.setFont(font)
|
||||
|
||||
return textarea
|
||||
|
||||
def get_field(self):
|
||||
return self.textarea_widget
|
||||
|
||||
def add_to_grid(self, grid: QtWidgets.QGridLayout, row: int) -> int:
|
||||
grid.addWidget(self.label_widget, row, 0, 1, 3)
|
||||
grid.addWidget(self.textarea_widget, row+1, 0, 1, 3)
|
||||
return 2
|
||||
|
||||
|
||||
class CheckboxOptionUI(OptionUI):
|
||||
|
||||
def __init__(self, option: str, label_text: str, label_tooltip: str):
|
||||
super().__init__(option=option)
|
||||
self.label_text = label_text
|
||||
self.label_tooltip = label_tooltip
|
||||
self.checkbox_widget = self.build_checkbox_widget()
|
||||
|
||||
def build_checkbox_widget(self):
|
||||
checkbox = FCCheckBox('%s' % _(self.label_text))
|
||||
checkbox.setToolTip(_(self.label_tooltip))
|
||||
return checkbox
|
||||
|
||||
def add_to_grid(self, grid: QtWidgets.QGridLayout, row: int) -> int:
|
||||
grid.addWidget(self.checkbox_widget, row, 0, 1, 3)
|
||||
return 1
|
||||
|
||||
def get_field(self):
|
||||
return self.checkbox_widget
|
||||
|
||||
|
||||
class ComboboxOptionUI(BasicOptionUI):
|
||||
|
||||
def __init__(self, option: str, label_text: str, choices: Sequence, **kwargs):
|
||||
self.choices = choices
|
||||
super().__init__(option=option, label_text=label_text, **kwargs)
|
||||
|
||||
def build_entry_widget(self):
|
||||
combo = FCComboBox()
|
||||
for choice in self.choices:
|
||||
# don't translate the QCombo items as they are used in QSettings and identified by name
|
||||
combo.addItem(choice)
|
||||
return combo
|
||||
|
||||
|
||||
class ColorOptionUI(BasicOptionUI):
|
||||
def build_entry_widget(self) -> QtWidgets.QWidget:
|
||||
entry = FCColorEntry()
|
||||
return entry
|
||||
|
||||
|
||||
class SliderWithSpinnerOptionUI(BasicOptionUI):
|
||||
def __init__(self, option: str, label_text: str, min_value=0, max_value=100, step=1, **kwargs):
|
||||
self.min_value = min_value
|
||||
self.max_value = max_value
|
||||
self.step = step
|
||||
super().__init__(option=option, label_text=label_text, **kwargs)
|
||||
|
||||
def build_entry_widget(self) -> QtWidgets.QWidget:
|
||||
entry = FCSliderWithSpinner(min=self.min_value, max=self.max_value, step=self.step)
|
||||
return entry
|
||||
|
||||
|
||||
class ColorAlphaSliderOptionUI(SliderWithSpinnerOptionUI):
|
||||
def __init__(self, applies_to: List[str], group, label_text: str, **kwargs):
|
||||
self.applies_to = applies_to
|
||||
self.group = group
|
||||
super().__init__(option="__color_alpha_slider", label_text=label_text, min_value=0, max_value=255, step=1,
|
||||
**kwargs)
|
||||
self.get_field().valueChanged.connect(self._on_alpha_change)
|
||||
|
||||
def add_to_grid(self, grid: QtWidgets.QGridLayout, row: int) -> int:
|
||||
for index, field in enumerate(self._get_target_fields()):
|
||||
field.entry.textChanged.connect(lambda value, i=index: self._on_target_change(target_index=i))
|
||||
return super().add_to_grid(grid, row)
|
||||
|
||||
def _get_target_fields(self):
|
||||
return list(map(lambda n: self.group.option_dict()[n].get_field(), self.applies_to))
|
||||
|
||||
def _on_target_change(self, target_index: int):
|
||||
field = self._get_target_fields()[target_index]
|
||||
color = field.get_value()
|
||||
alpha_part = color[7:]
|
||||
if len(alpha_part) != 2:
|
||||
return
|
||||
alpha = int(alpha_part, 16)
|
||||
if alpha < 0 or alpha > 255 or self.get_field().get_value() == alpha:
|
||||
return
|
||||
self.get_field().set_value(alpha)
|
||||
|
||||
def _on_alpha_change(self):
|
||||
alpha = self.get_field().get_value()
|
||||
for field in self._get_target_fields():
|
||||
old_value = field.get_value()
|
||||
new_value = self._modify_color_alpha(old_value, alpha=alpha)
|
||||
field.set_value(new_value)
|
||||
|
||||
@staticmethod
|
||||
def _modify_color_alpha(color: str, alpha: int):
|
||||
color_without_alpha = color[:7]
|
||||
if alpha > 255:
|
||||
return color_without_alpha + "FF"
|
||||
elif alpha < 0:
|
||||
return color_without_alpha + "00"
|
||||
else:
|
||||
hexalpha = hex(alpha)[2:]
|
||||
if len(hexalpha) == 1:
|
||||
hexalpha = "0" + hexalpha
|
||||
return color_without_alpha + hexalpha
|
||||
|
||||
|
||||
class SpinnerOptionUI(BasicOptionUI):
|
||||
def __init__(self, option: str, label_text: str, min_value: int, max_value: int, step: int = 1, **kwargs):
|
||||
self.min_value = min_value
|
||||
self.max_value = max_value
|
||||
self.step = step
|
||||
super().__init__(option=option, label_text=label_text, **kwargs)
|
||||
|
||||
def build_entry_widget(self) -> QtWidgets.QWidget:
|
||||
entry = FCSpinner()
|
||||
entry.set_range(self.min_value, self.max_value)
|
||||
entry.set_step(self.step)
|
||||
entry.setWrapping(True)
|
||||
return entry
|
||||
|
||||
|
||||
class DoubleSpinnerOptionUI(BasicOptionUI):
|
||||
def __init__(self, option: str, label_text: str, step: float, decimals: int, min_value=None, max_value=None,
|
||||
suffix=None, **kwargs):
|
||||
self.min_value = min_value
|
||||
self.max_value = max_value
|
||||
self.step = step
|
||||
self.suffix = suffix
|
||||
self.decimals = decimals
|
||||
super().__init__(option=option, label_text=label_text, **kwargs)
|
||||
|
||||
def build_entry_widget(self) -> QtWidgets.QWidget:
|
||||
entry = FCDoubleSpinner(suffix=self.suffix)
|
||||
entry.set_precision(self.decimals)
|
||||
entry.setSingleStep(self.step)
|
||||
if self.min_value is None:
|
||||
self.min_value = entry.minimum()
|
||||
else:
|
||||
entry.setMinimum(self.min_value)
|
||||
if self.max_value is None:
|
||||
self.max_value = entry.maximum()
|
||||
else:
|
||||
entry.setMaximum(self.max_value)
|
||||
return entry
|
||||
|
||||
|
||||
class HeadingOptionUI(OptionUI):
|
||||
def __init__(self, label_text: str, label_tooltip: Union[str, None] = None):
|
||||
super().__init__(option="__heading")
|
||||
self.label_text = label_text
|
||||
self.label_tooltip = label_tooltip
|
||||
|
||||
def build_heading_widget(self):
|
||||
heading = QtWidgets.QLabel('<b>%s</b>' % _(self.label_text))
|
||||
heading.setToolTip(_(self.label_tooltip))
|
||||
return heading
|
||||
|
||||
def add_to_grid(self, grid: QtWidgets.QGridLayout, row: int) -> int:
|
||||
grid.addWidget(self.build_heading_widget(), row, 0, 1, 2)
|
||||
return 1
|
||||
|
||||
def get_field(self):
|
||||
return None
|
||||
|
||||
|
||||
class SeparatorOptionUI(OptionUI):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__(option="__separator")
|
||||
|
||||
@staticmethod
|
||||
def build_separator_widget():
|
||||
separator = QtWidgets.QFrame()
|
||||
separator.setFrameShape(QtWidgets.QFrame.HLine)
|
||||
separator.setFrameShadow(QtWidgets.QFrame.Sunken)
|
||||
return separator
|
||||
|
||||
def add_to_grid(self, grid: QtWidgets.QGridLayout, row: int) -> int:
|
||||
grid.addWidget(self.build_separator_widget(), row, 0, 1, 2)
|
||||
return 1
|
||||
|
||||
def get_field(self):
|
||||
return None
|
||||
|
||||
|
||||
class FullWidthButtonOptionUI(OptionUI):
|
||||
def __init__(self, option: str, label_text: str, label_tooltip: Union[str, None]):
|
||||
super().__init__(option=option)
|
||||
self.label_text = label_text
|
||||
self.label_tooltip = label_tooltip
|
||||
self.button_widget = self.build_button_widget()
|
||||
|
||||
def build_button_widget(self):
|
||||
button = FCButton(_(self.label_text))
|
||||
if self.label_tooltip is not None:
|
||||
button.setToolTip(_(self.label_tooltip))
|
||||
return button
|
||||
|
||||
def add_to_grid(self, grid: QtWidgets.QGridLayout, row: int) -> int:
|
||||
grid.addWidget(self.button_widget, row, 0, 1, 3)
|
||||
return 1
|
||||
|
||||
def get_field(self):
|
||||
return self.button_widget
|
|
@ -1,77 +0,0 @@
|
|||
# ##########################################################
|
||||
# FlatCAM: 2D Post-processing for Manufacturing #
|
||||
# File by: David Robertson (c) #
|
||||
# Date: 5/2020 #
|
||||
# License: MIT Licence #
|
||||
# ##########################################################
|
||||
|
||||
from typing import Dict
|
||||
|
||||
from PyQt5 import QtWidgets
|
||||
from PyQt5.QtCore import QSettings
|
||||
|
||||
import gettext
|
||||
import AppTranslation as fcTranslate
|
||||
import builtins
|
||||
|
||||
from AppGUI.preferences.OptionUI import OptionUI
|
||||
|
||||
fcTranslate.apply_language('strings')
|
||||
if '_' not in builtins.__dict__:
|
||||
_ = gettext.gettext
|
||||
|
||||
settings = QSettings("Open Source", "FlatCAM")
|
||||
if settings.contains("machinist"):
|
||||
machinist_setting = settings.value('machinist', type=int)
|
||||
else:
|
||||
machinist_setting = 0
|
||||
|
||||
|
||||
class OptionsGroupUI(QtWidgets.QGroupBox):
|
||||
app = None
|
||||
|
||||
def __init__(self, title, parent=None):
|
||||
# QtGui.QGroupBox.__init__(self, title, parent=parent)
|
||||
super(OptionsGroupUI, self).__init__()
|
||||
self.setStyleSheet("""
|
||||
QGroupBox
|
||||
{
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
}
|
||||
""")
|
||||
|
||||
self.layout = QtWidgets.QVBoxLayout()
|
||||
self.setLayout(self.layout)
|
||||
|
||||
def option_dict(self) -> Dict[str, OptionUI]:
|
||||
# FIXME!
|
||||
return {}
|
||||
|
||||
|
||||
class OptionsGroupUI2(OptionsGroupUI):
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
|
||||
self.grid = QtWidgets.QGridLayout()
|
||||
self.layout.addLayout(self.grid)
|
||||
self.grid.setColumnStretch(0, 0)
|
||||
self.grid.setColumnStretch(1, 1)
|
||||
|
||||
self.options = self.build_options()
|
||||
|
||||
row = 0
|
||||
for option in self.options:
|
||||
row += option.add_to_grid(grid=self.grid, row=row)
|
||||
|
||||
self.layout.addStretch()
|
||||
|
||||
def build_options(self) -> [OptionUI]:
|
||||
return []
|
||||
|
||||
def option_dict(self) -> Dict[str, OptionUI]:
|
||||
result = {}
|
||||
for optionui in self.options:
|
||||
result[optionui.option] = optionui
|
||||
return result
|
|
@ -1,41 +0,0 @@
|
|||
from typing import Dict
|
||||
from PyQt5 import QtWidgets, QtCore
|
||||
|
||||
from AppGUI.ColumnarFlowLayout import ColumnarFlowLayout
|
||||
from AppGUI.preferences.OptionUI import OptionUI
|
||||
from AppGUI.preferences.OptionsGroupUI import OptionsGroupUI
|
||||
|
||||
|
||||
class PreferencesSectionUI(QtWidgets.QWidget):
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
self.layout = ColumnarFlowLayout() # QtWidgets.QHBoxLayout()
|
||||
self.setLayout(self.layout)
|
||||
|
||||
self.groups = self.build_groups()
|
||||
for group in self.groups:
|
||||
group.setMinimumWidth(250)
|
||||
self.layout.addWidget(group)
|
||||
|
||||
def build_groups(self) -> [OptionsGroupUI]:
|
||||
return []
|
||||
|
||||
def option_dict(self) -> Dict[str, OptionUI]:
|
||||
result = {}
|
||||
for group in self.groups:
|
||||
groupoptions = group.option_dict()
|
||||
result.update(groupoptions)
|
||||
return result
|
||||
|
||||
def build_tab(self):
|
||||
scroll_area = QtWidgets.QScrollArea()
|
||||
scroll_area.setWidget(self)
|
||||
scroll_area.setWidgetResizable(True)
|
||||
return scroll_area
|
||||
|
||||
def get_tab_id(self) -> str:
|
||||
raise NotImplementedError
|
||||
|
||||
def get_tab_label(self) -> str:
|
||||
raise NotImplementedError
|
|
@ -1,302 +0,0 @@
|
|||
|
||||
from PyQt5 import QtCore
|
||||
from PyQt5.QtCore import QSettings
|
||||
from AppGUI.GUIElements import OptionalInputSection
|
||||
from AppGUI.preferences import settings
|
||||
from AppGUI.preferences.OptionUI import *
|
||||
from AppGUI.preferences.OptionsGroupUI import OptionsGroupUI2
|
||||
|
||||
import gettext
|
||||
import AppTranslation as fcTranslate
|
||||
import builtins
|
||||
fcTranslate.apply_language('strings')
|
||||
if '_' not in builtins.__dict__:
|
||||
_ = gettext.gettext
|
||||
|
||||
|
||||
class GeneralAppSettingsGroupUI(OptionsGroupUI2):
|
||||
def __init__(self, decimals=4, **kwargs):
|
||||
self.decimals = decimals
|
||||
self.pagesize = {}
|
||||
self.pagesize.update(
|
||||
{
|
||||
'A0': (841, 1189),
|
||||
'A1': (594, 841),
|
||||
'A2': (420, 594),
|
||||
'A3': (297, 420),
|
||||
'A4': (210, 297),
|
||||
'A5': (148, 210),
|
||||
'A6': (105, 148),
|
||||
'A7': (74, 105),
|
||||
'A8': (52, 74),
|
||||
'A9': (37, 52),
|
||||
'A10': (26, 37),
|
||||
|
||||
'B0': (1000, 1414),
|
||||
'B1': (707, 1000),
|
||||
'B2': (500, 707),
|
||||
'B3': (353, 500),
|
||||
'B4': (250, 353),
|
||||
'B5': (176, 250),
|
||||
'B6': (125, 176),
|
||||
'B7': (88, 125),
|
||||
'B8': (62, 88),
|
||||
'B9': (44, 62),
|
||||
'B10': (31, 44),
|
||||
|
||||
'C0': (917, 1297),
|
||||
'C1': (648, 917),
|
||||
'C2': (458, 648),
|
||||
'C3': (324, 458),
|
||||
'C4': (229, 324),
|
||||
'C5': (162, 229),
|
||||
'C6': (114, 162),
|
||||
'C7': (81, 114),
|
||||
'C8': (57, 81),
|
||||
'C9': (40, 57),
|
||||
'C10': (28, 40),
|
||||
|
||||
# American paper sizes
|
||||
'LETTER': (8.5, 11),
|
||||
'LEGAL': (8.5, 14),
|
||||
'ELEVENSEVENTEEN': (11, 17),
|
||||
|
||||
# From https://en.wikipedia.org/wiki/Paper_size
|
||||
'JUNIOR_LEGAL': (5, 8),
|
||||
'HALF_LETTER': (5.5, 8),
|
||||
'GOV_LETTER': (8, 10.5),
|
||||
'GOV_LEGAL': (8.5, 13),
|
||||
'LEDGER': (17, 11),
|
||||
}
|
||||
)
|
||||
super().__init__(**kwargs)
|
||||
|
||||
self.setTitle(str(_("App Settings")))
|
||||
|
||||
qsettings = QSettings("Open Source", "FlatCAM")
|
||||
|
||||
self.notebook_font_size_field = self.option_dict()["notebook_font_size"].get_field()
|
||||
if qsettings.contains("notebook_font_size"):
|
||||
self.notebook_font_size_field.set_value(qsettings.value('notebook_font_size', type=int))
|
||||
else:
|
||||
self.notebook_font_size_field.set_value(12)
|
||||
|
||||
self.axis_font_size_field = self.option_dict()["axis_font_size"].get_field()
|
||||
if qsettings.contains("axis_font_size"):
|
||||
self.axis_font_size_field.set_value(qsettings.value('axis_font_size', type=int))
|
||||
else:
|
||||
self.axis_font_size_field.set_value(8)
|
||||
|
||||
self.textbox_font_size_field = self.option_dict()["textbox_font_size"].get_field()
|
||||
if qsettings.contains("textbox_font_size"):
|
||||
self.textbox_font_size_field.set_value(settings.value('textbox_font_size', type=int))
|
||||
else:
|
||||
self.textbox_font_size_field.set_value(10)
|
||||
|
||||
self.workspace_enabled_field = self.option_dict()["global_workspace"].get_field()
|
||||
self.workspace_type_field = self.option_dict()["global_workspaceT"].get_field()
|
||||
self.workspace_type_label = self.option_dict()["global_workspaceT"].label_widget
|
||||
self.workspace_orientation_field = self.option_dict()["global_workspace_orientation"].get_field()
|
||||
self.workspace_orientation_label = self.option_dict()["global_workspace_orientation"].label_widget
|
||||
self.wks = OptionalInputSection(self.workspace_enabled_field, [self.workspace_type_label, self.workspace_type_field, self.workspace_orientation_label, self.workspace_orientation_field])
|
||||
|
||||
self.mouse_cursor_color_enabled_field = self.option_dict()["global_cursor_color_enabled"].get_field()
|
||||
self.mouse_cursor_color_field = self.option_dict()["global_cursor_color"].get_field()
|
||||
self.mouse_cursor_color_label = self.option_dict()["global_cursor_color"].label_widget
|
||||
self.mois = OptionalInputSection(self.mouse_cursor_color_enabled_field, [self.mouse_cursor_color_label, self.mouse_cursor_color_field])
|
||||
self.mouse_cursor_color_enabled_field.stateChanged.connect(self.on_mouse_cursor_color_enable)
|
||||
self.mouse_cursor_color_field.entry.editingFinished.connect(self.on_mouse_cursor_entry)
|
||||
|
||||
def build_options(self) -> [OptionUI]:
|
||||
return [
|
||||
HeadingOptionUI(label_text="Grid Settings", label_tooltip=None),
|
||||
DoubleSpinnerOptionUI(
|
||||
option="global_gridx",
|
||||
label_text="X value",
|
||||
label_tooltip="This is the Grid snap value on X axis.",
|
||||
step=0.1,
|
||||
decimals=self.decimals
|
||||
),
|
||||
DoubleSpinnerOptionUI(
|
||||
option="global_gridy",
|
||||
label_text='Y value',
|
||||
label_tooltip="This is the Grid snap value on Y axis.",
|
||||
step=0.1,
|
||||
decimals=self.decimals
|
||||
),
|
||||
DoubleSpinnerOptionUI(
|
||||
option="global_snap_max",
|
||||
label_text="Snap Max",
|
||||
label_tooltip="Max. magnet distance",
|
||||
step=0.1,
|
||||
decimals=self.decimals
|
||||
),
|
||||
SeparatorOptionUI(),
|
||||
|
||||
HeadingOptionUI(label_text="Workspace Settings", label_tooltip=None),
|
||||
CheckboxOptionUI(
|
||||
option="global_workspace",
|
||||
label_text="Active",
|
||||
label_tooltip="Draw a delimiting rectangle on canvas.\n"
|
||||
"The purpose is to illustrate the limits for our work."
|
||||
),
|
||||
ComboboxOptionUI(
|
||||
option="global_workspaceT",
|
||||
label_text="Size",
|
||||
label_tooltip="Select the type of rectangle to be used on canvas,\nas valid workspace.",
|
||||
choices=list(self.pagesize.keys())
|
||||
),
|
||||
RadioSetOptionUI(
|
||||
option="global_workspace_orientation",
|
||||
label_text="Orientation",
|
||||
label_tooltip="Can be:\n- Portrait\n- Landscape",
|
||||
choices=[
|
||||
{'label': _('Portrait'), 'value': 'p'},
|
||||
{'label': _('Landscape'), 'value': 'l'},
|
||||
]
|
||||
),
|
||||
# FIXME enabling OptionalInputSection ??
|
||||
SeparatorOptionUI(),
|
||||
|
||||
HeadingOptionUI(label_text="Font Size", label_tooltip=None),
|
||||
SpinnerOptionUI(
|
||||
option="notebook_font_size",
|
||||
label_text="Notebook",
|
||||
label_tooltip="This sets the font size for the elements found in the Notebook.\n"
|
||||
"The notebook is the collapsible area in the left side of the GUI,\n"
|
||||
"and include the Project, Selected and Tool tabs.",
|
||||
min_value=8, max_value=40, step=1
|
||||
),
|
||||
SpinnerOptionUI(
|
||||
option="axis_font_size",
|
||||
label_text="Axis",
|
||||
label_tooltip="This sets the font size for canvas axis.",
|
||||
min_value=8, max_value=40, step=1
|
||||
),
|
||||
SpinnerOptionUI(
|
||||
option="textbox_font_size",
|
||||
label_text="Textbox",
|
||||
label_tooltip="This sets the font size for the Textbox GUI\n"
|
||||
"elements that are used in the application.",
|
||||
min_value=8, max_value=40, step=1
|
||||
),
|
||||
SeparatorOptionUI(),
|
||||
|
||||
HeadingOptionUI(label_text="Mouse Settings", label_tooltip=None),
|
||||
RadioSetOptionUI(
|
||||
option="global_cursor_type",
|
||||
label_text="Cursor Shape",
|
||||
label_tooltip="Choose a mouse cursor shape.\n"
|
||||
"- Small -> with a customizable size.\n"
|
||||
"- Big -> Infinite lines",
|
||||
choices=[
|
||||
{"label": _("Small"), "value": "small"},
|
||||
{"label": _("Big"), "value": "big"}
|
||||
]
|
||||
),
|
||||
SpinnerOptionUI(
|
||||
option="global_cursor_size",
|
||||
label_text="Cursor Size",
|
||||
label_tooltip="Set the size of the mouse cursor, in pixels.",
|
||||
min_value=10, max_value=70, step=1
|
||||
),
|
||||
SpinnerOptionUI(
|
||||
option="global_cursor_width",
|
||||
label_text="Cursor Width",
|
||||
label_tooltip="Set the line width of the mouse cursor, in pixels.",
|
||||
min_value=1, max_value=10, step=1
|
||||
),
|
||||
CheckboxOptionUI(
|
||||
option="global_cursor_color_enabled",
|
||||
label_text="Cursor Color",
|
||||
label_tooltip="Check this box to color mouse cursor."
|
||||
),
|
||||
ColorOptionUI(
|
||||
option="global_cursor_color",
|
||||
label_text="Cursor Color",
|
||||
label_tooltip="Set the color of the mouse cursor."
|
||||
),
|
||||
# FIXME enabling of cursor color
|
||||
RadioSetOptionUI(
|
||||
option="global_pan_button",
|
||||
label_text="Pan Button",
|
||||
label_tooltip="Select the mouse button to use for panning:\n"
|
||||
"- MMB --> Middle Mouse Button\n"
|
||||
"- RMB --> Right Mouse Button",
|
||||
choices=[{'label': _('MMB'), 'value': '3'},
|
||||
{'label': _('RMB'), 'value': '2'}]
|
||||
),
|
||||
RadioSetOptionUI(
|
||||
option="global_mselect_key",
|
||||
label_text="Multiple Selection",
|
||||
label_tooltip="Select the key used for multiple selection.",
|
||||
choices=[{'label': _('CTRL'), 'value': 'Control'},
|
||||
{'label': _('SHIFT'), 'value': 'Shift'}]
|
||||
),
|
||||
SeparatorOptionUI(),
|
||||
|
||||
CheckboxOptionUI(
|
||||
option="global_delete_confirmation",
|
||||
label_text="Delete object confirmation",
|
||||
label_tooltip="When checked the application will ask for user confirmation\n"
|
||||
"whenever the Delete object(s) event is triggered, either by\n"
|
||||
"menu shortcut or key shortcut."
|
||||
),
|
||||
CheckboxOptionUI(
|
||||
option="global_open_style",
|
||||
label_text='"Open" behavior',
|
||||
label_tooltip="When checked the path for the last saved file is used when saving files,\n"
|
||||
"and the path for the last opened file is used when opening files.\n\n"
|
||||
"When unchecked the path for opening files is the one used last: either the\n"
|
||||
"path for saving files or the path for opening files."
|
||||
),
|
||||
CheckboxOptionUI(
|
||||
option="global_toggle_tooltips",
|
||||
label_text="Enable ToolTips",
|
||||
label_tooltip="Check this box if you want to have toolTips displayed\n"
|
||||
"when hovering with mouse over items throughout the App."
|
||||
),
|
||||
CheckboxOptionUI(
|
||||
option="global_machinist_setting",
|
||||
label_text="Allow Machinist Unsafe Settings",
|
||||
label_tooltip="If checked, some of the application settings will be allowed\n"
|
||||
"to have values that are usually unsafe to use.\n"
|
||||
"Like Z travel negative values or Z Cut positive values.\n"
|
||||
"It will applied at the next application start.\n"
|
||||
"<<WARNING>>: Don't change this unless you know what you are doing !!!"
|
||||
),
|
||||
SpinnerOptionUI(
|
||||
option="global_bookmarks_limit",
|
||||
label_text="Bookmarks limit",
|
||||
label_tooltip="The maximum number of bookmarks that may be installed in the menu.\n"
|
||||
"The number of bookmarks in the bookmark manager may be greater\n"
|
||||
"but the menu will hold only so much.",
|
||||
min_value=0, max_value=9999, step=1
|
||||
),
|
||||
ComboboxOptionUI(
|
||||
option="global_activity_icon",
|
||||
label_text="Activity Icon",
|
||||
label_tooltip="Select the GIF that show activity when FlatCAM is active.",
|
||||
choices=['Ball black', 'Ball green', 'Arrow green', 'Eclipse green']
|
||||
)
|
||||
|
||||
]
|
||||
|
||||
def on_mouse_cursor_color_enable(self, val):
|
||||
if val:
|
||||
self.app.cursor_color_3D = self.app.defaults["global_cursor_color"]
|
||||
else:
|
||||
theme_settings = QtCore.QSettings("Open Source", "FlatCAM")
|
||||
if theme_settings.contains("theme"):
|
||||
theme = theme_settings.value('theme', type=str)
|
||||
else:
|
||||
theme = 'white'
|
||||
|
||||
if theme == 'white':
|
||||
self.app.cursor_color_3D = 'black'
|
||||
else:
|
||||
self.app.cursor_color_3D = 'gray'
|
||||
|
||||
def on_mouse_cursor_entry(self):
|
||||
self.app.defaults['global_cursor_color'] = self.mouse_cursor_color_field.get_value()
|
||||
self.app.cursor_color_3D = self.app.defaults["global_cursor_color"]
|
|
@ -1,100 +0,0 @@
|
|||
from PyQt5 import QtWidgets
|
||||
from PyQt5.QtCore import QSettings
|
||||
|
||||
from AppGUI.GUIElements import FCDoubleSpinner, FCSpinner, RadioSet, FCCheckBox, FCComboBox
|
||||
from AppGUI.preferences.OptionsGroupUI import OptionsGroupUI
|
||||
|
||||
import gettext
|
||||
import AppTranslation as fcTranslate
|
||||
import builtins
|
||||
|
||||
fcTranslate.apply_language('strings')
|
||||
if '_' not in builtins.__dict__:
|
||||
_ = gettext.gettext
|
||||
|
||||
settings = QSettings("Open Source", "FlatCAM")
|
||||
if settings.contains("machinist"):
|
||||
machinist_setting = settings.value('machinist', type=int)
|
||||
else:
|
||||
machinist_setting = 0
|
||||
|
||||
|
||||
class GerberOptPrefGroupUI(OptionsGroupUI):
|
||||
def __init__(self, decimals=4, parent=None):
|
||||
# OptionsGroupUI.__init__(self, "Gerber Options Preferences", parent=parent)
|
||||
super(GerberOptPrefGroupUI, self).__init__(self, parent=parent)
|
||||
|
||||
self.decimals = decimals
|
||||
|
||||
self.setTitle(str(_("Gerber Options")))
|
||||
|
||||
# ## Clear non-copper regions
|
||||
self.clearcopper_label = QtWidgets.QLabel("<b>%s:</b>" % _("Non-copper regions"))
|
||||
self.clearcopper_label.setToolTip(
|
||||
_("Create polygons covering the\n"
|
||||
"areas without copper on the PCB.\n"
|
||||
"Equivalent to the inverse of this\n"
|
||||
"object. Can be used to remove all\n"
|
||||
"copper from a specified region.")
|
||||
)
|
||||
self.layout.addWidget(self.clearcopper_label)
|
||||
|
||||
grid1 = QtWidgets.QGridLayout()
|
||||
self.layout.addLayout(grid1)
|
||||
|
||||
# Margin
|
||||
bmlabel = QtWidgets.QLabel('%s:' % _('Boundary Margin'))
|
||||
bmlabel.setToolTip(
|
||||
_("Specify the edge of the PCB\n"
|
||||
"by drawing a box around all\n"
|
||||
"objects with this minimum\n"
|
||||
"distance.")
|
||||
)
|
||||
grid1.addWidget(bmlabel, 0, 0)
|
||||
self.noncopper_margin_entry = FCDoubleSpinner()
|
||||
self.noncopper_margin_entry.set_precision(self.decimals)
|
||||
self.noncopper_margin_entry.setSingleStep(0.1)
|
||||
self.noncopper_margin_entry.set_range(-9999, 9999)
|
||||
grid1.addWidget(self.noncopper_margin_entry, 0, 1)
|
||||
|
||||
# Rounded corners
|
||||
self.noncopper_rounded_cb = FCCheckBox(label=_("Rounded Geo"))
|
||||
self.noncopper_rounded_cb.setToolTip(
|
||||
_("Resulting geometry will have rounded corners.")
|
||||
)
|
||||
grid1.addWidget(self.noncopper_rounded_cb, 1, 0, 1, 2)
|
||||
|
||||
separator_line = QtWidgets.QFrame()
|
||||
separator_line.setFrameShape(QtWidgets.QFrame.HLine)
|
||||
separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
|
||||
grid1.addWidget(separator_line, 2, 0, 1, 2)
|
||||
|
||||
# ## Bounding box
|
||||
self.boundingbox_label = QtWidgets.QLabel('<b>%s:</b>' % _('Bounding Box'))
|
||||
self.layout.addWidget(self.boundingbox_label)
|
||||
|
||||
grid2 = QtWidgets.QGridLayout()
|
||||
self.layout.addLayout(grid2)
|
||||
|
||||
bbmargin = QtWidgets.QLabel('%s:' % _('Boundary Margin'))
|
||||
bbmargin.setToolTip(
|
||||
_("Distance of the edges of the box\n"
|
||||
"to the nearest polygon.")
|
||||
)
|
||||
self.bbmargin_entry = FCDoubleSpinner()
|
||||
self.bbmargin_entry.set_precision(self.decimals)
|
||||
self.bbmargin_entry.setSingleStep(0.1)
|
||||
self.bbmargin_entry.set_range(-9999, 9999)
|
||||
|
||||
grid2.addWidget(bbmargin, 0, 0)
|
||||
grid2.addWidget(self.bbmargin_entry, 0, 1)
|
||||
|
||||
self.bbrounded_cb = FCCheckBox(label='%s' % _("Rounded Geo"))
|
||||
self.bbrounded_cb.setToolTip(
|
||||
_("If the bounding box is \n"
|
||||
"to have rounded corners\n"
|
||||
"their radius is equal to\n"
|
||||
"the margin.")
|
||||
)
|
||||
grid2.addWidget(self.bbrounded_cb, 1, 0, 1, 2)
|
||||
self.layout.addStretch()
|
|
@ -1,81 +0,0 @@
|
|||
from PyQt5 import QtWidgets
|
||||
from PyQt5.QtCore import QSettings
|
||||
|
||||
from AppGUI.GUIElements import FCDoubleSpinner
|
||||
from AppGUI.preferences.OptionsGroupUI import OptionsGroupUI
|
||||
|
||||
import gettext
|
||||
import AppTranslation as fcTranslate
|
||||
import builtins
|
||||
|
||||
fcTranslate.apply_language('strings')
|
||||
if '_' not in builtins.__dict__:
|
||||
_ = gettext.gettext
|
||||
|
||||
settings = QSettings("Open Source", "FlatCAM")
|
||||
if settings.contains("machinist"):
|
||||
machinist_setting = settings.value('machinist', type=int)
|
||||
else:
|
||||
machinist_setting = 0
|
||||
|
||||
|
||||
class ToolsCornersPrefGroupUI(OptionsGroupUI):
|
||||
def __init__(self, decimals=4, parent=None):
|
||||
# OptionsGroupUI.__init__(self, "Calculators Tool Options", parent=parent)
|
||||
super(ToolsCornersPrefGroupUI, self).__init__(self, parent=parent)
|
||||
|
||||
self.setTitle(str(_("Corner Markers Options")))
|
||||
self.decimals = decimals
|
||||
|
||||
grid0 = QtWidgets.QGridLayout()
|
||||
grid0.setColumnStretch(0, 0)
|
||||
grid0.setColumnStretch(1, 1)
|
||||
self.layout.addLayout(grid0)
|
||||
|
||||
self.param_label = QtWidgets.QLabel('<b>%s:</b>' % _('Parameters'))
|
||||
self.param_label.setToolTip(
|
||||
_("Parameters used for this tool.")
|
||||
)
|
||||
grid0.addWidget(self.param_label, 0, 0, 1, 2)
|
||||
|
||||
# Thickness #
|
||||
self.thick_label = QtWidgets.QLabel('%s:' % _("Thickness"))
|
||||
self.thick_label.setToolTip(
|
||||
_("The thickness of the line that makes the corner marker.")
|
||||
)
|
||||
self.thick_entry = FCDoubleSpinner()
|
||||
self.thick_entry.set_range(0.0000, 9.9999)
|
||||
self.thick_entry.set_precision(self.decimals)
|
||||
self.thick_entry.setWrapping(True)
|
||||
self.thick_entry.setSingleStep(10 ** -self.decimals)
|
||||
|
||||
grid0.addWidget(self.thick_label, 1, 0)
|
||||
grid0.addWidget(self.thick_entry, 1, 1)
|
||||
|
||||
# Length #
|
||||
self.l_label = QtWidgets.QLabel('%s:' % _("Length"))
|
||||
self.l_label.setToolTip(
|
||||
_("The length of the line that makes the corner marker.")
|
||||
)
|
||||
self.l_entry = FCDoubleSpinner()
|
||||
self.l_entry.set_range(-9999.9999, 9999.9999)
|
||||
self.l_entry.set_precision(self.decimals)
|
||||
self.l_entry.setSingleStep(10 ** -self.decimals)
|
||||
|
||||
# Margin #
|
||||
self.margin_label = QtWidgets.QLabel('%s:' % _("Margin"))
|
||||
self.margin_label.setToolTip(
|
||||
_("Bounding box margin.")
|
||||
)
|
||||
self.margin_entry = FCDoubleSpinner()
|
||||
self.margin_entry.set_range(-9999.9999, 9999.9999)
|
||||
self.margin_entry.set_precision(self.decimals)
|
||||
self.margin_entry.setSingleStep(0.1)
|
||||
|
||||
grid0.addWidget(self.margin_label, 2, 0)
|
||||
grid0.addWidget(self.margin_entry, 2, 1)
|
||||
|
||||
grid0.addWidget(self.l_label, 4, 0)
|
||||
grid0.addWidget(self.l_entry, 4, 1)
|
||||
|
||||
self.layout.addStretch()
|
|
@ -1,320 +0,0 @@
|
|||
from PyQt5 import QtWidgets
|
||||
from PyQt5.QtCore import QSettings
|
||||
|
||||
from AppGUI.GUIElements import RadioSet, FCDoubleSpinner, FCComboBox, FCCheckBox, FCSpinner, NumericalEvalTupleEntry
|
||||
from AppGUI.preferences.OptionsGroupUI import OptionsGroupUI
|
||||
|
||||
import gettext
|
||||
import AppTranslation as fcTranslate
|
||||
import builtins
|
||||
|
||||
fcTranslate.apply_language('strings')
|
||||
if '_' not in builtins.__dict__:
|
||||
_ = gettext.gettext
|
||||
|
||||
settings = QSettings("Open Source", "FlatCAM")
|
||||
if settings.contains("machinist"):
|
||||
machinist_setting = settings.value('machinist', type=int)
|
||||
else:
|
||||
machinist_setting = 0
|
||||
|
||||
|
||||
class ToolsISOPrefGroupUI(OptionsGroupUI):
|
||||
def __init__(self, decimals=4, parent=None):
|
||||
super(ToolsISOPrefGroupUI, self).__init__(self, parent=parent)
|
||||
|
||||
self.setTitle(str(_("Isolation Tool Options")))
|
||||
self.decimals = decimals
|
||||
|
||||
# ## Clear non-copper regions
|
||||
self.iso_label = QtWidgets.QLabel("<b>%s:</b>" % _("Parameters"))
|
||||
self.iso_label.setToolTip(
|
||||
_("Create a Geometry object with\n"
|
||||
"toolpaths to cut around polygons.")
|
||||
)
|
||||
self.layout.addWidget(self.iso_label)
|
||||
|
||||
grid0 = QtWidgets.QGridLayout()
|
||||
self.layout.addLayout(grid0)
|
||||
|
||||
# Tool Dias
|
||||
isotdlabel = QtWidgets.QLabel('<b><font color="green">%s:</font></b>' % _('Tools Dia'))
|
||||
isotdlabel.setToolTip(
|
||||
_("Diameters of the tools, separated by comma.\n"
|
||||
"The value of the diameter has to use the dot decimals separator.\n"
|
||||
"Valid values: 0.3, 1.0")
|
||||
)
|
||||
self.tool_dia_entry = NumericalEvalTupleEntry(border_color='#0069A9')
|
||||
self.tool_dia_entry.setPlaceholderText(_("Comma separated values"))
|
||||
|
||||
grid0.addWidget(isotdlabel, 0, 0)
|
||||
grid0.addWidget(self.tool_dia_entry, 0, 1, 1, 2)
|
||||
|
||||
# Tool order Radio Button
|
||||
self.order_label = QtWidgets.QLabel('%s:' % _('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' --> means 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'}])
|
||||
|
||||
grid0.addWidget(self.order_label, 1, 0)
|
||||
grid0.addWidget(self.order_radio, 1, 1, 1, 2)
|
||||
|
||||
# Tool Type Radio Button
|
||||
self.tool_type_label = QtWidgets.QLabel('%s:' % _('Tool Type'))
|
||||
self.tool_type_label.setToolTip(
|
||||
_("Default tool type:\n"
|
||||
"- 'V-shape'\n"
|
||||
"- Circular")
|
||||
)
|
||||
|
||||
self.tool_type_radio = RadioSet([{'label': _('V-shape'), 'value': 'V'},
|
||||
{'label': _('Circular'), 'value': 'C1'}])
|
||||
self.tool_type_radio.setToolTip(
|
||||
_("Default tool type:\n"
|
||||
"- 'V-shape'\n"
|
||||
"- Circular")
|
||||
)
|
||||
|
||||
grid0.addWidget(self.tool_type_label, 2, 0)
|
||||
grid0.addWidget(self.tool_type_radio, 2, 1, 1, 2)
|
||||
|
||||
# Tip Dia
|
||||
self.tipdialabel = QtWidgets.QLabel('%s:' % _('V-Tip Dia'))
|
||||
self.tipdialabel.setToolTip(
|
||||
_("The tip diameter for V-Shape Tool"))
|
||||
self.tipdia_entry = FCDoubleSpinner()
|
||||
self.tipdia_entry.set_precision(self.decimals)
|
||||
self.tipdia_entry.set_range(0, 1000)
|
||||
self.tipdia_entry.setSingleStep(0.1)
|
||||
|
||||
grid0.addWidget(self.tipdialabel, 3, 0)
|
||||
grid0.addWidget(self.tipdia_entry, 3, 1, 1, 2)
|
||||
|
||||
# Tip Angle
|
||||
self.tipanglelabel = QtWidgets.QLabel('%s:' % _('V-Tip Angle'))
|
||||
self.tipanglelabel.setToolTip(
|
||||
_("The tip angle for V-Shape Tool.\n"
|
||||
"In degrees."))
|
||||
self.tipangle_entry = FCDoubleSpinner()
|
||||
self.tipangle_entry.set_precision(self.decimals)
|
||||
self.tipangle_entry.set_range(1, 180)
|
||||
self.tipangle_entry.setSingleStep(5)
|
||||
self.tipangle_entry.setWrapping(True)
|
||||
|
||||
grid0.addWidget(self.tipanglelabel, 4, 0)
|
||||
grid0.addWidget(self.tipangle_entry, 4, 1, 1, 2)
|
||||
|
||||
# Cut Z entry
|
||||
cutzlabel = QtWidgets.QLabel('%s:' % _('Cut Z'))
|
||||
cutzlabel.setToolTip(
|
||||
_("Depth of cut into material. Negative value.\n"
|
||||
"In FlatCAM units.")
|
||||
)
|
||||
self.cutz_entry = FCDoubleSpinner()
|
||||
self.cutz_entry.set_precision(self.decimals)
|
||||
self.cutz_entry.set_range(-9999.9999, 0.0000)
|
||||
self.cutz_entry.setSingleStep(0.1)
|
||||
|
||||
self.cutz_entry.setToolTip(
|
||||
_("Depth of cut into material. Negative value.\n"
|
||||
"In FlatCAM units.")
|
||||
)
|
||||
|
||||
grid0.addWidget(cutzlabel, 5, 0)
|
||||
grid0.addWidget(self.cutz_entry, 5, 1, 1, 2)
|
||||
|
||||
# New Diameter
|
||||
self.newdialabel = QtWidgets.QLabel('%s:' % _('New Dia'))
|
||||
self.newdialabel.setToolTip(
|
||||
_("Diameter for the new tool to add in the Tool Table.\n"
|
||||
"If the tool is V-shape type then this value is automatically\n"
|
||||
"calculated from the other parameters.")
|
||||
)
|
||||
self.newdia_entry = FCDoubleSpinner()
|
||||
self.newdia_entry.set_precision(self.decimals)
|
||||
self.newdia_entry.set_range(0.0001, 9999.9999)
|
||||
self.newdia_entry.setSingleStep(0.1)
|
||||
|
||||
grid0.addWidget(self.newdialabel, 6, 0)
|
||||
grid0.addWidget(self.newdia_entry, 6, 1, 1, 2)
|
||||
|
||||
separator_line = QtWidgets.QFrame()
|
||||
separator_line.setFrameShape(QtWidgets.QFrame.HLine)
|
||||
separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
|
||||
grid0.addWidget(separator_line, 7, 0, 1, 3)
|
||||
|
||||
# Passes
|
||||
passlabel = QtWidgets.QLabel('%s:' % _('Passes'))
|
||||
passlabel.setToolTip(
|
||||
_("Width of the isolation gap in\n"
|
||||
"number (integer) of tool widths.")
|
||||
)
|
||||
self.passes_entry = FCSpinner()
|
||||
self.passes_entry.set_range(1, 999)
|
||||
self.passes_entry.setObjectName("i_passes")
|
||||
|
||||
grid0.addWidget(passlabel, 8, 0)
|
||||
grid0.addWidget(self.passes_entry, 8, 1, 1, 2)
|
||||
|
||||
# Overlap Entry
|
||||
overlabel = QtWidgets.QLabel('%s:' % _('Overlap'))
|
||||
overlabel.setToolTip(
|
||||
_("How much (percentage) of the tool width to overlap each tool pass.")
|
||||
)
|
||||
self.overlap_entry = FCDoubleSpinner(suffix='%')
|
||||
self.overlap_entry.set_precision(self.decimals)
|
||||
self.overlap_entry.setWrapping(True)
|
||||
self.overlap_entry.set_range(0.0000, 99.9999)
|
||||
self.overlap_entry.setSingleStep(0.1)
|
||||
self.overlap_entry.setObjectName("i_overlap")
|
||||
|
||||
grid0.addWidget(overlabel, 9, 0)
|
||||
grid0.addWidget(self.overlap_entry, 9, 1, 1, 2)
|
||||
|
||||
# Milling Type Radio Button
|
||||
self.milling_type_label = QtWidgets.QLabel('%s:' % _('Milling Type'))
|
||||
self.milling_type_label.setToolTip(
|
||||
_("Milling type when the selected tool is of type: 'iso_op':\n"
|
||||
"- climb / best for precision milling and to reduce tool usage\n"
|
||||
"- conventional / useful when there is no backlash compensation")
|
||||
)
|
||||
|
||||
self.milling_type_radio = RadioSet([{'label': _('Climb'), 'value': 'cl'},
|
||||
{'label': _('Conventional'), 'value': 'cv'}])
|
||||
self.milling_type_radio.setToolTip(
|
||||
_("Milling type when the selected tool is of type: 'iso_op':\n"
|
||||
"- climb / best for precision milling and to reduce tool usage\n"
|
||||
"- conventional / useful when there is no backlash compensation")
|
||||
)
|
||||
|
||||
grid0.addWidget(self.milling_type_label, 10, 0)
|
||||
grid0.addWidget(self.milling_type_radio, 10, 1, 1, 2)
|
||||
|
||||
# Follow
|
||||
self.follow_label = QtWidgets.QLabel('%s:' % _('Follow'))
|
||||
self.follow_label.setToolTip(
|
||||
_("Generate a 'Follow' geometry.\n"
|
||||
"This means that it will cut through\n"
|
||||
"the middle of the trace.")
|
||||
)
|
||||
|
||||
self.follow_cb = FCCheckBox()
|
||||
self.follow_cb.setToolTip(_("Generate a 'Follow' geometry.\n"
|
||||
"This means that it will cut through\n"
|
||||
"the middle of the trace."))
|
||||
self.follow_cb.setObjectName("i_follow")
|
||||
|
||||
grid0.addWidget(self.follow_label, 11, 0)
|
||||
grid0.addWidget(self.follow_cb, 11, 1, 1, 2)
|
||||
|
||||
# Isolation Type
|
||||
self.iso_type_label = QtWidgets.QLabel('%s:' % _('Isolation Type'))
|
||||
self.iso_type_label.setToolTip(
|
||||
_("Choose how the isolation will be executed:\n"
|
||||
"- 'Full' -> complete isolation of polygons\n"
|
||||
"- 'Ext' -> will isolate only on the outside\n"
|
||||
"- 'Int' -> will isolate only on the inside\n"
|
||||
"'Exterior' isolation is almost always possible\n"
|
||||
"(with the right tool) but 'Interior'\n"
|
||||
"isolation can be done only when there is an opening\n"
|
||||
"inside of the polygon (e.g polygon is a 'doughnut' shape).")
|
||||
)
|
||||
self.iso_type_radio = RadioSet([{'label': _('Full'), 'value': 'full'},
|
||||
{'label': _('Ext'), 'value': 'ext'},
|
||||
{'label': _('Int'), 'value': 'int'}])
|
||||
self.iso_type_radio.setObjectName("i_type")
|
||||
|
||||
grid0.addWidget(self.iso_type_label, 12, 0)
|
||||
grid0.addWidget(self.iso_type_radio, 12, 1, 1, 2)
|
||||
|
||||
separator_line = QtWidgets.QFrame()
|
||||
separator_line.setFrameShape(QtWidgets.QFrame.HLine)
|
||||
separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
|
||||
grid0.addWidget(separator_line, 13, 0, 1, 3)
|
||||
|
||||
# Rest machining CheckBox
|
||||
self.rest_cb = FCCheckBox('%s' % _("Rest"))
|
||||
self.rest_cb.setObjectName("i_rest_machining")
|
||||
self.rest_cb.setToolTip(
|
||||
_("If checked, use 'rest machining'.\n"
|
||||
"Basically it will isolate outside PCB features,\n"
|
||||
"using the biggest tool and continue with the next tools,\n"
|
||||
"from bigger to smaller, to isolate the copper features that\n"
|
||||
"could not be cleared by previous tool, until there is\n"
|
||||
"no more copper features to isolate or there are no more tools.\n"
|
||||
"If not checked, use the standard algorithm.")
|
||||
)
|
||||
|
||||
grid0.addWidget(self.rest_cb, 17, 0)
|
||||
|
||||
# Combine All Passes
|
||||
self.combine_passes_cb = FCCheckBox(label=_('Combine'))
|
||||
self.combine_passes_cb.setToolTip(
|
||||
_("Combine all passes into one object")
|
||||
)
|
||||
self.combine_passes_cb.setObjectName("i_combine")
|
||||
|
||||
grid0.addWidget(self.combine_passes_cb, 17, 1)
|
||||
|
||||
# Exception Areas
|
||||
self.except_cb = FCCheckBox(label=_('Except'))
|
||||
self.except_cb.setToolTip(_("When the isolation geometry is generated,\n"
|
||||
"by checking this, the area of the object below\n"
|
||||
"will be subtracted from the isolation geometry."))
|
||||
self.except_cb.setObjectName("i_except")
|
||||
grid0.addWidget(self.except_cb, 17, 2)
|
||||
|
||||
# Isolation Scope
|
||||
self.select_label = QtWidgets.QLabel('%s:' % _("Selection"))
|
||||
self.select_label.setToolTip(
|
||||
_("Isolation scope. Choose what to isolate:\n"
|
||||
"- 'All' -> Isolate all the polygons in the object\n"
|
||||
"- 'Area Selection' -> Isolate polygons within a selection area.\n"
|
||||
"- 'Polygon Selection' -> Isolate a selection of polygons.\n"
|
||||
"- 'Reference Object' - will process the area specified by another object.")
|
||||
)
|
||||
self.select_combo = FCComboBox()
|
||||
self.select_combo.addItems(
|
||||
[_("All"), _("Area Selection"), _("Polygon Selection"), _("Reference Object")]
|
||||
)
|
||||
self.select_combo.setObjectName("i_selection")
|
||||
|
||||
grid0.addWidget(self.select_label, 20, 0)
|
||||
grid0.addWidget(self.select_combo, 20, 1, 1, 2)
|
||||
|
||||
# Area Shape
|
||||
self.area_shape_label = QtWidgets.QLabel('%s:' % _("Shape"))
|
||||
self.area_shape_label.setToolTip(
|
||||
_("The kind of selection shape used for area selection.")
|
||||
)
|
||||
|
||||
self.area_shape_radio = RadioSet([{'label': _("Square"), 'value': 'square'},
|
||||
{'label': _("Polygon"), 'value': 'polygon'}])
|
||||
|
||||
grid0.addWidget(self.area_shape_label, 21, 0)
|
||||
grid0.addWidget(self.area_shape_radio, 21, 1, 1, 2)
|
||||
|
||||
separator_line = QtWidgets.QFrame()
|
||||
separator_line.setFrameShape(QtWidgets.QFrame.HLine)
|
||||
separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
|
||||
grid0.addWidget(separator_line, 22, 0, 1, 3)
|
||||
|
||||
# ## Plotting type
|
||||
self.plotting_radio = RadioSet([{'label': _('Normal'), 'value': 'normal'},
|
||||
{"label": _("Progressive"), "value": "progressive"}])
|
||||
plotting_label = QtWidgets.QLabel('%s:' % _("Plotting"))
|
||||
plotting_label.setToolTip(
|
||||
_("- 'Normal' - normal plotting, done at the end of the job\n"
|
||||
"- 'Progressive' - each shape is plotted after it is generated")
|
||||
)
|
||||
grid0.addWidget(plotting_label, 23, 0)
|
||||
grid0.addWidget(self.plotting_radio, 23, 1, 1, 2)
|
||||
|
||||
self.layout.addStretch()
|
|
@ -1,394 +0,0 @@
|
|||
# ###########################################################
|
||||
# FlatCAM: 2D Post-processing for Manufacturing #
|
||||
# http://flatcam.org #
|
||||
# Author: Juan Pablo Caram (c) #
|
||||
# Date: 2/5/2014 #
|
||||
# MIT Licence #
|
||||
# Modified by Marius Stanciu (2020) #
|
||||
# ###########################################################
|
||||
|
||||
from PyQt5 import QtCore
|
||||
from AppObjects.ObjectCollection import *
|
||||
from AppObjects.FlatCAMCNCJob import CNCJobObject
|
||||
from AppObjects.FlatCAMDocument import DocumentObject
|
||||
from AppObjects.FlatCAMExcellon import ExcellonObject
|
||||
from AppObjects.FlatCAMGeometry import GeometryObject
|
||||
from AppObjects.FlatCAMGerber import GerberObject
|
||||
from AppObjects.FlatCAMScript import ScriptObject
|
||||
|
||||
import time
|
||||
import traceback
|
||||
|
||||
# FlatCAM Translation
|
||||
import gettext
|
||||
import AppTranslation as fcTranslate
|
||||
import builtins
|
||||
|
||||
fcTranslate.apply_language('strings')
|
||||
if '_' not in builtins.__dict__:
|
||||
_ = gettext.gettext
|
||||
|
||||
|
||||
class AppObject(QtCore.QObject):
|
||||
|
||||
# Emitted by app_obj.new_object() and passes the new object as argument, plot flag.
|
||||
# on_object_created() adds the object to the collection, plots on appropriate flag
|
||||
# and emits app_obj.new_object_available.
|
||||
object_created = QtCore.pyqtSignal(object, bool, bool)
|
||||
|
||||
# Emitted when a object has been changed (like scaled, mirrored)
|
||||
object_changed = QtCore.pyqtSignal(object)
|
||||
|
||||
# Emitted after object has been plotted.
|
||||
# Calls 'on_zoom_fit' method to fit object in scene view in main thread to prevent drawing glitches.
|
||||
object_plotted = QtCore.pyqtSignal(object)
|
||||
|
||||
plots_updated = QtCore.pyqtSignal()
|
||||
|
||||
def __init__(self, app):
|
||||
super(AppObject, self).__init__()
|
||||
self.app = app
|
||||
self.inform = app.inform
|
||||
|
||||
# signals that are emitted when object state changes
|
||||
self.object_created.connect(self.on_object_created)
|
||||
self.object_changed.connect(self.on_object_changed)
|
||||
self.object_plotted.connect(self.on_object_plotted)
|
||||
self.plots_updated.connect(self.app.on_plots_updated)
|
||||
|
||||
def new_object(self, kind, name, initialize, plot=True, autoselected=True):
|
||||
"""
|
||||
Creates a new specialized FlatCAMObj and attaches it to the application,
|
||||
this is, updates the GUI accordingly, any other records and plots it.
|
||||
This method is thread-safe.
|
||||
|
||||
Notes:
|
||||
* If the name is in use, the self.collection will modify it
|
||||
when appending it to the collection. There is no need to handle
|
||||
name conflicts here.
|
||||
|
||||
:param kind: The kind of object to create. One of 'gerber', 'excellon', 'cncjob' and 'geometry'.
|
||||
:type kind: str
|
||||
:param name: Name for the object.
|
||||
:type name: str
|
||||
: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 plot: If to plot the resulting object
|
||||
:param autoselected: if the resulting object is autoselected in the Project tab and therefore in the
|
||||
self.collection
|
||||
:return: None
|
||||
:rtype: None
|
||||
"""
|
||||
|
||||
log.debug("AppObject.new_object()")
|
||||
obj_plot = plot
|
||||
obj_autoselected = autoselected
|
||||
|
||||
t0 = time.time() # Debug
|
||||
|
||||
# ## Create object
|
||||
classdict = {
|
||||
"gerber": GerberObject,
|
||||
"excellon": ExcellonObject,
|
||||
"cncjob": CNCJobObject,
|
||||
"geometry": GeometryObject,
|
||||
"script": ScriptObject,
|
||||
"document": DocumentObject
|
||||
}
|
||||
|
||||
log.debug("Calling object constructor...")
|
||||
|
||||
# Object creation/instantiation
|
||||
obj = classdict[kind](name)
|
||||
|
||||
obj.units = self.app.options["units"]
|
||||
|
||||
# IMPORTANT
|
||||
# The key names in defaults and options dictionary's are not random:
|
||||
# they have to have in name first the type of the object (geometry, excellon, cncjob and gerber) or how it's
|
||||
# called here, the 'kind' followed by an underline. Above the App default values from self.defaults are
|
||||
# copied to self.options. After that, below, depending on the type of
|
||||
# object that is created, it will strip the name of the object and the underline (if the original key was
|
||||
# let's say "excellon_toolchange", it will strip the excellon_) and to the obj.options the key will become
|
||||
# "toolchange"
|
||||
|
||||
for option in self.app.options:
|
||||
if option.find(kind + "_") == 0:
|
||||
oname = option[len(kind) + 1:]
|
||||
obj.options[oname] = self.app.options[option]
|
||||
|
||||
obj.isHovering = False
|
||||
obj.notHovering = True
|
||||
|
||||
# Initialize as per user request
|
||||
# User must take care to implement initialize
|
||||
# in a thread-safe way as is is likely that we
|
||||
# have been invoked in a separate thread.
|
||||
t1 = time.time()
|
||||
log.debug("%f seconds before initialize()." % (t1 - t0))
|
||||
try:
|
||||
return_value = initialize(obj, self.app)
|
||||
except Exception as e:
|
||||
msg = '[ERROR_NOTCL] %s' % _("An internal error has occurred. See shell.\n")
|
||||
msg += _("Object ({kind}) failed because: {error} \n\n").format(kind=kind, error=str(e))
|
||||
msg += traceback.format_exc()
|
||||
self.app.inform.emit(msg)
|
||||
return "fail"
|
||||
|
||||
t2 = time.time()
|
||||
log.debug("%f seconds executing initialize()." % (t2 - t1))
|
||||
|
||||
if return_value == 'fail':
|
||||
log.debug("Object (%s) parsing and/or geometry creation failed." % kind)
|
||||
return "fail"
|
||||
|
||||
# Check units and convert if necessary
|
||||
# This condition CAN be true because initialize() can change obj.units
|
||||
if self.app.options["units"].upper() != obj.units.upper():
|
||||
self.app.inform.emit('%s: %s' % (_("Converting units to "), self.app.options["units"]))
|
||||
obj.convert_units(self.app.options["units"])
|
||||
t3 = time.time()
|
||||
log.debug("%f seconds converting units." % (t3 - t2))
|
||||
|
||||
# Create the bounding box for the object and then add the results to the obj.options
|
||||
# But not for Scripts or for Documents
|
||||
if kind != 'document' and kind != 'script':
|
||||
try:
|
||||
xmin, ymin, xmax, ymax = obj.bounds()
|
||||
obj.options['xmin'] = xmin
|
||||
obj.options['ymin'] = ymin
|
||||
obj.options['xmax'] = xmax
|
||||
obj.options['ymax'] = ymax
|
||||
except Exception as e:
|
||||
log.warning("AppObject.new_object() -> The object has no bounds properties. %s" % str(e))
|
||||
return "fail"
|
||||
|
||||
try:
|
||||
if kind == 'excellon':
|
||||
obj.fill_color = self.app.defaults["excellon_plot_fill"]
|
||||
obj.outline_color = self.app.defaults["excellon_plot_line"]
|
||||
|
||||
if kind == 'gerber':
|
||||
obj.fill_color = self.app.defaults["gerber_plot_fill"]
|
||||
obj.outline_color = self.app.defaults["gerber_plot_line"]
|
||||
except Exception as e:
|
||||
log.warning("AppObject.new_object() -> setting colors error. %s" % str(e))
|
||||
|
||||
# update the KeyWords list with the name of the file
|
||||
self.app.myKeywords.append(obj.options['name'])
|
||||
|
||||
log.debug("Moving new object back to main thread.")
|
||||
|
||||
# Move the object to the main thread and let the app know that it is available.
|
||||
obj.moveToThread(self.app.main_thread)
|
||||
self.object_created.emit(obj, obj_plot, obj_autoselected)
|
||||
|
||||
return obj
|
||||
|
||||
def new_excellon_object(self):
|
||||
"""
|
||||
Creates a new, blank Excellon object.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
|
||||
self.new_object('excellon', 'new_exc', lambda x, y: None, plot=False)
|
||||
|
||||
def new_geometry_object(self):
|
||||
"""
|
||||
Creates a new, blank and single-tool Geometry object.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
|
||||
def initialize(obj, app):
|
||||
obj.multitool = False
|
||||
|
||||
self.new_object('geometry', 'new_geo', initialize, plot=False)
|
||||
|
||||
def new_gerber_object(self):
|
||||
"""
|
||||
Creates a new, blank Gerber object.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
|
||||
def initialize(grb_obj, app):
|
||||
grb_obj.multitool = False
|
||||
grb_obj.source_file = []
|
||||
grb_obj.multigeo = False
|
||||
grb_obj.follow = False
|
||||
grb_obj.apertures = {}
|
||||
grb_obj.solid_geometry = []
|
||||
|
||||
try:
|
||||
grb_obj.options['xmin'] = 0
|
||||
grb_obj.options['ymin'] = 0
|
||||
grb_obj.options['xmax'] = 0
|
||||
grb_obj.options['ymax'] = 0
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
self.new_object('gerber', 'new_grb', initialize, plot=False)
|
||||
|
||||
def new_script_object(self):
|
||||
"""
|
||||
Creates a new, blank TCL Script object.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
|
||||
# commands_list = "# AddCircle, AddPolygon, AddPolyline, AddRectangle, AlignDrill, " \
|
||||
# "AlignDrillGrid, Bbox, Bounds, ClearShell, CopperClear,\n" \
|
||||
# "# Cncjob, Cutout, Delete, Drillcncjob, ExportDXF, ExportExcellon, ExportGcode,\n" \
|
||||
# "# ExportGerber, ExportSVG, Exteriors, Follow, GeoCutout, GeoUnion, GetNames,\n" \
|
||||
# "# GetSys, ImportSvg, Interiors, Isolate, JoinExcellon, JoinGeometry, " \
|
||||
# "ListSys, MillDrills,\n" \
|
||||
# "# MillSlots, Mirror, New, NewExcellon, NewGeometry, NewGerber, Nregions, " \
|
||||
# "Offset, OpenExcellon, OpenGCode, OpenGerber, OpenProject,\n" \
|
||||
# "# Options, Paint, Panelize, PlotAl, PlotObjects, SaveProject, " \
|
||||
# "SaveSys, Scale, SetActive, SetSys, SetOrigin, Skew, SubtractPoly,\n" \
|
||||
# "# SubtractRectangle, Version, WriteGCode\n"
|
||||
|
||||
new_source_file = '# %s\n' % _('CREATE A NEW FLATCAM TCL SCRIPT') + \
|
||||
'# %s:\n' % _('TCL Tutorial is here') + \
|
||||
'# https://www.tcl.tk/man/tcl8.5/tutorial/tcltutorial.html\n' + '\n\n' + \
|
||||
'# %s:\n' % _("FlatCAM commands list")
|
||||
new_source_file += '# %s\n\n' % _("Type >help< followed by Run Code for a list of FlatCAM Tcl Commands "
|
||||
"(displayed in Tcl Shell).")
|
||||
|
||||
def initialize(obj, app):
|
||||
obj.source_file = deepcopy(new_source_file)
|
||||
|
||||
outname = 'new_script'
|
||||
self.new_object('script', outname, initialize, plot=False)
|
||||
|
||||
def new_document_object(self):
|
||||
"""
|
||||
Creates a new, blank Document object.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
|
||||
def initialize(obj, app):
|
||||
obj.source_file = ""
|
||||
|
||||
self.new_object('document', 'new_document', initialize, plot=False)
|
||||
|
||||
def on_object_created(self, obj, plot, auto_select):
|
||||
"""
|
||||
Event callback for object creation.
|
||||
It will add the new object to the collection. After that it will plot the object in a threaded way
|
||||
|
||||
:param obj: The newly created FlatCAM object.
|
||||
:param plot: if the newly create object t obe plotted
|
||||
:param auto_select: if the newly created object to be autoselected after creation
|
||||
:return: None
|
||||
"""
|
||||
t0 = time.time() # DEBUG
|
||||
log.debug("on_object_created()")
|
||||
|
||||
# The Collection might change the name if there is a collision
|
||||
self.app.collection.append(obj)
|
||||
|
||||
# after adding the object to the collection always update the list of objects that are in the collection
|
||||
self.app.all_objects_list = self.app.collection.get_list()
|
||||
|
||||
# self.app.inform.emit('[selected] %s created & selected: %s' %
|
||||
# (str(obj.kind).capitalize(), str(obj.options['name'])))
|
||||
if obj.kind == 'gerber':
|
||||
self.app.inform.emit('[selected] {kind} {tx}: <span style="color:{color};">{name}</span>'.format(
|
||||
kind=obj.kind.capitalize(),
|
||||
color='green',
|
||||
name=str(obj.options['name']), tx=_("created/selected"))
|
||||
)
|
||||
elif obj.kind == 'excellon':
|
||||
self.app.inform.emit('[selected] {kind} {tx}: <span style="color:{color};">{name}</span>'.format(
|
||||
kind=obj.kind.capitalize(),
|
||||
color='brown',
|
||||
name=str(obj.options['name']), tx=_("created/selected"))
|
||||
)
|
||||
elif obj.kind == 'cncjob':
|
||||
self.app.inform.emit('[selected] {kind} {tx}: <span style="color:{color};">{name}</span>'.format(
|
||||
kind=obj.kind.capitalize(),
|
||||
color='blue',
|
||||
name=str(obj.options['name']), tx=_("created/selected"))
|
||||
)
|
||||
elif obj.kind == 'geometry':
|
||||
self.app.inform.emit('[selected] {kind} {tx}: <span style="color:{color};">{name}</span>'.format(
|
||||
kind=obj.kind.capitalize(),
|
||||
color='red',
|
||||
name=str(obj.options['name']), tx=_("created/selected"))
|
||||
)
|
||||
elif obj.kind == 'script':
|
||||
self.app.inform.emit('[selected] {kind} {tx}: <span style="color:{color};">{name}</span>'.format(
|
||||
kind=obj.kind.capitalize(),
|
||||
color='orange',
|
||||
name=str(obj.options['name']), tx=_("created/selected"))
|
||||
)
|
||||
elif obj.kind == 'document':
|
||||
self.app.inform.emit('[selected] {kind} {tx}: <span style="color:{color};">{name}</span>'.format(
|
||||
kind=obj.kind.capitalize(),
|
||||
color='darkCyan',
|
||||
name=str(obj.options['name']), tx=_("created/selected"))
|
||||
)
|
||||
|
||||
# update the SHELL auto-completer model with the name of the new object
|
||||
self.app.shell._edit.set_model_data(self.app.myKeywords)
|
||||
|
||||
if auto_select:
|
||||
# select the just opened object but deselect the previous ones
|
||||
self.app.collection.set_all_inactive()
|
||||
self.app.collection.set_active(obj.options["name"])
|
||||
else:
|
||||
self.app.collection.set_all_inactive()
|
||||
|
||||
# here it is done the object plotting
|
||||
def task(t_obj):
|
||||
with self.app.proc_container.new(_("Plotting")):
|
||||
if t_obj.kind == 'cncjob':
|
||||
t_obj.plot(kind=self.app.defaults["cncjob_plot_kind"])
|
||||
else:
|
||||
t_obj.plot()
|
||||
|
||||
t1 = time.time() # DEBUG
|
||||
log.debug("%f seconds adding object and plotting." % (t1 - t0))
|
||||
self.object_plotted.emit(t_obj)
|
||||
|
||||
# Send to worker
|
||||
# self.worker.add_task(worker_task, [self])
|
||||
if plot is True:
|
||||
self.app.worker_task.emit({'fcn': task, 'params': [obj]})
|
||||
|
||||
def on_object_changed(self, obj):
|
||||
"""
|
||||
Called whenever the geometry of the object was changed in some way.
|
||||
This require the update of it's bounding values so it can be the selected on canvas.
|
||||
Update the bounding box data from obj.options
|
||||
|
||||
:param obj: the object that was changed
|
||||
:return: None
|
||||
"""
|
||||
|
||||
try:
|
||||
xmin, ymin, xmax, ymax = obj.bounds()
|
||||
except TypeError:
|
||||
return
|
||||
obj.options['xmin'] = xmin
|
||||
obj.options['ymin'] = ymin
|
||||
obj.options['xmax'] = xmax
|
||||
obj.options['ymax'] = ymax
|
||||
|
||||
log.debug("Object changed, updating the bounding box data on self.options")
|
||||
# delete the old selection shape
|
||||
self.app.delete_selection_shape()
|
||||
self.app.should_we_save = True
|
||||
|
||||
def on_object_plotted(self):
|
||||
"""
|
||||
Callback called whenever the plotted object needs to be fit into the viewport (canvas)
|
||||
|
||||
:return: None
|
||||
"""
|
||||
self.app.on_zoom_fit()
|
|
@ -1,440 +0,0 @@
|
|||
# ##########################################################
|
||||
# FlatCAM: 2D Post-processing for Manufacturing #
|
||||
# File Author: Marius Adrian Stanciu (c) #
|
||||
# Date: 5/17/2020 #
|
||||
# MIT Licence #
|
||||
# ##########################################################
|
||||
|
||||
from PyQt5 import QtWidgets, QtCore
|
||||
|
||||
from AppTool import AppTool
|
||||
from AppGUI.GUIElements import FCDoubleSpinner, FCCheckBox, FCComboBox, FCButton
|
||||
|
||||
from shapely.geometry import MultiPolygon, LineString
|
||||
|
||||
from copy import deepcopy
|
||||
import logging
|
||||
|
||||
import gettext
|
||||
import AppTranslation as fcTranslate
|
||||
import builtins
|
||||
|
||||
fcTranslate.apply_language('strings')
|
||||
if '_' not in builtins.__dict__:
|
||||
_ = gettext.gettext
|
||||
|
||||
log = logging.getLogger('base')
|
||||
|
||||
|
||||
class ToolCorners(AppTool):
|
||||
|
||||
toolName = _("Corner Markers Tool")
|
||||
|
||||
def __init__(self, app):
|
||||
AppTool.__init__(self, app)
|
||||
|
||||
self.app = app
|
||||
self.canvas = self.app.plotcanvas
|
||||
|
||||
self.decimals = self.app.decimals
|
||||
self.units = ''
|
||||
|
||||
# ## Title
|
||||
title_label = QtWidgets.QLabel("%s" % self.toolName)
|
||||
title_label.setStyleSheet("""
|
||||
QLabel
|
||||
{
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
}
|
||||
""")
|
||||
self.layout.addWidget(title_label)
|
||||
self.layout.addWidget(QtWidgets.QLabel(''))
|
||||
|
||||
# Gerber object #
|
||||
self.object_label = QtWidgets.QLabel('<b>%s:</b>' % _("GERBER"))
|
||||
self.object_label.setToolTip(
|
||||
_("The Gerber object to which will be added corner markers.")
|
||||
)
|
||||
self.object_combo = FCComboBox()
|
||||
self.object_combo.setModel(self.app.collection)
|
||||
self.object_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
|
||||
self.object_combo.is_last = True
|
||||
self.object_combo.obj_type = "Gerber"
|
||||
|
||||
self.layout.addWidget(self.object_label)
|
||||
self.layout.addWidget(self.object_combo)
|
||||
|
||||
separator_line = QtWidgets.QFrame()
|
||||
separator_line.setFrameShape(QtWidgets.QFrame.HLine)
|
||||
separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
|
||||
self.layout.addWidget(separator_line)
|
||||
|
||||
self.points_label = QtWidgets.QLabel('<b>%s:</b>' % _('Locations'))
|
||||
self.points_label.setToolTip(
|
||||
_("Locations where to place corner markers.")
|
||||
)
|
||||
self.layout.addWidget(self.points_label)
|
||||
|
||||
# BOTTOM LEFT
|
||||
self.bl_cb = FCCheckBox(_("Bottom Left"))
|
||||
self.layout.addWidget(self.bl_cb)
|
||||
|
||||
# BOTTOM RIGHT
|
||||
self.br_cb = FCCheckBox(_("Bottom Right"))
|
||||
self.layout.addWidget(self.br_cb)
|
||||
|
||||
# TOP LEFT
|
||||
self.tl_cb = FCCheckBox(_("Top Left"))
|
||||
self.layout.addWidget(self.tl_cb)
|
||||
|
||||
# TOP RIGHT
|
||||
self.tr_cb = FCCheckBox(_("Top Right"))
|
||||
self.layout.addWidget(self.tr_cb)
|
||||
|
||||
separator_line = QtWidgets.QFrame()
|
||||
separator_line.setFrameShape(QtWidgets.QFrame.HLine)
|
||||
separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
|
||||
self.layout.addWidget(separator_line)
|
||||
|
||||
# Toggle ALL
|
||||
self.toggle_all_cb = FCCheckBox(_("Toggle ALL"))
|
||||
self.layout.addWidget(self.toggle_all_cb)
|
||||
|
||||
separator_line = QtWidgets.QFrame()
|
||||
separator_line.setFrameShape(QtWidgets.QFrame.HLine)
|
||||
separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
|
||||
self.layout.addWidget(separator_line)
|
||||
|
||||
# ## Grid Layout
|
||||
grid_lay = QtWidgets.QGridLayout()
|
||||
self.layout.addLayout(grid_lay)
|
||||
grid_lay.setColumnStretch(0, 0)
|
||||
grid_lay.setColumnStretch(1, 1)
|
||||
|
||||
self.param_label = QtWidgets.QLabel('<b>%s:</b>' % _('Parameters'))
|
||||
self.param_label.setToolTip(
|
||||
_("Parameters used for this tool.")
|
||||
)
|
||||
grid_lay.addWidget(self.param_label, 0, 0, 1, 2)
|
||||
|
||||
# Thickness #
|
||||
self.thick_label = QtWidgets.QLabel('%s:' % _("Thickness"))
|
||||
self.thick_label.setToolTip(
|
||||
_("The thickness of the line that makes the corner marker.")
|
||||
)
|
||||
self.thick_entry = FCDoubleSpinner(callback=self.confirmation_message)
|
||||
self.thick_entry.set_range(0.0000, 9.9999)
|
||||
self.thick_entry.set_precision(self.decimals)
|
||||
self.thick_entry.setWrapping(True)
|
||||
self.thick_entry.setSingleStep(10 ** -self.decimals)
|
||||
|
||||
grid_lay.addWidget(self.thick_label, 1, 0)
|
||||
grid_lay.addWidget(self.thick_entry, 1, 1)
|
||||
|
||||
# Length #
|
||||
self.l_label = QtWidgets.QLabel('%s:' % _("Length"))
|
||||
self.l_label.setToolTip(
|
||||
_("The length of the line that makes the corner marker.")
|
||||
)
|
||||
self.l_entry = FCDoubleSpinner(callback=self.confirmation_message)
|
||||
self.l_entry.set_range(-9999.9999, 9999.9999)
|
||||
self.l_entry.set_precision(self.decimals)
|
||||
self.l_entry.setSingleStep(10 ** -self.decimals)
|
||||
|
||||
grid_lay.addWidget(self.l_label, 2, 0)
|
||||
grid_lay.addWidget(self.l_entry, 2, 1)
|
||||
|
||||
# Margin #
|
||||
self.margin_label = QtWidgets.QLabel('%s:' % _("Margin"))
|
||||
self.margin_label.setToolTip(
|
||||
_("Bounding box margin.")
|
||||
)
|
||||
self.margin_entry = FCDoubleSpinner(callback=self.confirmation_message)
|
||||
self.margin_entry.set_range(-9999.9999, 9999.9999)
|
||||
self.margin_entry.set_precision(self.decimals)
|
||||
self.margin_entry.setSingleStep(0.1)
|
||||
|
||||
grid_lay.addWidget(self.margin_label, 3, 0)
|
||||
grid_lay.addWidget(self.margin_entry, 3, 1)
|
||||
|
||||
separator_line_2 = QtWidgets.QFrame()
|
||||
separator_line_2.setFrameShape(QtWidgets.QFrame.HLine)
|
||||
separator_line_2.setFrameShadow(QtWidgets.QFrame.Sunken)
|
||||
grid_lay.addWidget(separator_line_2, 4, 0, 1, 2)
|
||||
|
||||
# ## Insert Corner Marker
|
||||
self.add_marker_button = FCButton(_("Add Marker"))
|
||||
self.add_marker_button.setToolTip(
|
||||
_("Will add corner markers to the selected Gerber file.")
|
||||
)
|
||||
self.add_marker_button.setStyleSheet("""
|
||||
QPushButton
|
||||
{
|
||||
font-weight: bold;
|
||||
}
|
||||
""")
|
||||
grid_lay.addWidget(self.add_marker_button, 11, 0, 1, 2)
|
||||
|
||||
self.layout.addStretch()
|
||||
|
||||
# ## Reset Tool
|
||||
self.reset_button = QtWidgets.QPushButton(_("Reset Tool"))
|
||||
self.reset_button.setToolTip(
|
||||
_("Will reset the tool parameters.")
|
||||
)
|
||||
self.reset_button.setStyleSheet("""
|
||||
QPushButton
|
||||
{
|
||||
font-weight: bold;
|
||||
}
|
||||
""")
|
||||
self.layout.addWidget(self.reset_button)
|
||||
|
||||
# Objects involved in Copper thieving
|
||||
self.grb_object = None
|
||||
|
||||
# store the flattened geometry here:
|
||||
self.flat_geometry = []
|
||||
|
||||
# Tool properties
|
||||
self.fid_dia = None
|
||||
|
||||
self.grb_steps_per_circle = self.app.defaults["gerber_circle_steps"]
|
||||
|
||||
# SIGNALS
|
||||
self.add_marker_button.clicked.connect(self.add_markers)
|
||||
self.toggle_all_cb.toggled.connect(self.on_toggle_all)
|
||||
|
||||
def run(self, toggle=True):
|
||||
self.app.defaults.report_usage("ToolCorners()")
|
||||
|
||||
if toggle:
|
||||
# if the splitter is hidden, display it, else hide it but only if the current widget is the same
|
||||
if self.app.ui.splitter.sizes()[0] == 0:
|
||||
self.app.ui.splitter.setSizes([1, 1])
|
||||
else:
|
||||
try:
|
||||
if self.app.ui.tool_scroll_area.widget().objectName() == self.toolName:
|
||||
# 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:
|
||||
if self.app.ui.splitter.sizes()[0] == 0:
|
||||
self.app.ui.splitter.setSizes([1, 1])
|
||||
|
||||
AppTool.run(self)
|
||||
|
||||
self.set_tool_ui()
|
||||
|
||||
self.app.ui.notebook.setTabText(2, _("Corners Tool"))
|
||||
|
||||
def install(self, icon=None, separator=None, **kwargs):
|
||||
AppTool.install(self, icon, separator, shortcut='Alt+M', **kwargs)
|
||||
|
||||
def set_tool_ui(self):
|
||||
self.units = self.app.defaults['units']
|
||||
self.thick_entry.set_value(self.app.defaults["tools_corners_thickness"])
|
||||
self.l_entry.set_value(float(self.app.defaults["tools_corners_length"]))
|
||||
self.margin_entry.set_value(float(self.app.defaults["tools_corners_margin"]))
|
||||
self.toggle_all_cb.set_value(False)
|
||||
|
||||
def on_toggle_all(self, val):
|
||||
self.bl_cb.set_value(val)
|
||||
self.br_cb.set_value(val)
|
||||
self.tl_cb.set_value(val)
|
||||
self.tr_cb.set_value(val)
|
||||
|
||||
def add_markers(self):
|
||||
self.app.call_source = "corners_tool"
|
||||
tl_state = self.tl_cb.get_value()
|
||||
tr_state = self.tr_cb.get_value()
|
||||
bl_state = self.bl_cb.get_value()
|
||||
br_state = self.br_cb.get_value()
|
||||
|
||||
# get the Gerber object on which the corner marker will be inserted
|
||||
selection_index = self.object_combo.currentIndex()
|
||||
model_index = self.app.collection.index(selection_index, 0, self.object_combo.rootModelIndex())
|
||||
|
||||
try:
|
||||
self.grb_object = model_index.internalPointer().obj
|
||||
except Exception as e:
|
||||
log.debug("ToolCorners.add_markers() --> %s" % str(e))
|
||||
self.app.inform.emit('[WARNING_NOTCL] %s' % _("There is no Gerber object loaded ..."))
|
||||
return
|
||||
|
||||
xmin, ymin, xmax, ymax = self.grb_object.bounds()
|
||||
points = {}
|
||||
if tl_state:
|
||||
points['tl'] = (xmin, ymax)
|
||||
if tr_state:
|
||||
points['tr'] = (xmax, ymax)
|
||||
if bl_state:
|
||||
points['bl'] = (xmin, ymin)
|
||||
if br_state:
|
||||
points['br'] = (xmax, ymin)
|
||||
|
||||
self.add_corners_geo(points, g_obj=self.grb_object)
|
||||
|
||||
self.grb_object.source_file = self.app.export_gerber(obj_name=self.grb_object.options['name'],
|
||||
filename=None,
|
||||
local_use=self.grb_object, use_thread=False)
|
||||
self.on_exit()
|
||||
|
||||
def add_corners_geo(self, points_storage, g_obj):
|
||||
"""
|
||||
Add geometry to the solid_geometry of the copper Gerber object
|
||||
|
||||
:param points_storage: a dictionary holding the points where to add corners
|
||||
:param g_obj: the Gerber object where to add the geometry
|
||||
:return: None
|
||||
"""
|
||||
|
||||
line_thickness = self.thick_entry.get_value()
|
||||
line_length = self.l_entry.get_value()
|
||||
margin = self.margin_entry.get_value()
|
||||
|
||||
geo_list = []
|
||||
|
||||
if not points_storage:
|
||||
self.app.inform.emit("[ERROR_NOTCL] %s." % _("Please select at least a location"))
|
||||
return
|
||||
|
||||
for key in points_storage:
|
||||
if key == 'tl':
|
||||
pt = points_storage[key]
|
||||
x = pt[0] - margin - line_thickness / 2.0
|
||||
y = pt[1] + margin + line_thickness / 2.0
|
||||
line_geo_hor = LineString([
|
||||
(x, y), (x + line_length, y)
|
||||
])
|
||||
line_geo_vert = LineString([
|
||||
(x, y), (x, y - line_length)
|
||||
])
|
||||
geo_list.append(line_geo_hor)
|
||||
geo_list.append(line_geo_vert)
|
||||
if key == 'tr':
|
||||
pt = points_storage[key]
|
||||
x = pt[0] + margin + line_thickness / 2.0
|
||||
y = pt[1] + margin + line_thickness / 2.0
|
||||
line_geo_hor = LineString([
|
||||
(x, y), (x - line_length, y)
|
||||
])
|
||||
line_geo_vert = LineString([
|
||||
(x, y), (x, y - line_length)
|
||||
])
|
||||
geo_list.append(line_geo_hor)
|
||||
geo_list.append(line_geo_vert)
|
||||
if key == 'bl':
|
||||
pt = points_storage[key]
|
||||
x = pt[0] - margin - line_thickness / 2.0
|
||||
y = pt[1] - margin - line_thickness / 2.0
|
||||
line_geo_hor = LineString([
|
||||
(x, y), (x + line_length, y)
|
||||
])
|
||||
line_geo_vert = LineString([
|
||||
(x, y), (x, y + line_length)
|
||||
])
|
||||
geo_list.append(line_geo_hor)
|
||||
geo_list.append(line_geo_vert)
|
||||
if key == 'br':
|
||||
pt = points_storage[key]
|
||||
x = pt[0] + margin + line_thickness / 2.0
|
||||
y = pt[1] - margin - line_thickness / 2.0
|
||||
line_geo_hor = LineString([
|
||||
(x, y), (x - line_length, y)
|
||||
])
|
||||
line_geo_vert = LineString([
|
||||
(x, y), (x, y + line_length)
|
||||
])
|
||||
geo_list.append(line_geo_hor)
|
||||
geo_list.append(line_geo_vert)
|
||||
|
||||
aperture_found = None
|
||||
for ap_id, ap_val in g_obj.apertures.items():
|
||||
if ap_val['type'] == 'C' and ap_val['size'] == line_thickness:
|
||||
aperture_found = ap_id
|
||||
break
|
||||
|
||||
geo_buff_list = []
|
||||
if aperture_found:
|
||||
for geo in geo_list:
|
||||
geo_buff = geo.buffer(line_thickness / 2.0, resolution=self.grb_steps_per_circle, join_style=2)
|
||||
geo_buff_list.append(geo_buff)
|
||||
|
||||
dict_el = {}
|
||||
dict_el['follow'] = geo
|
||||
dict_el['solid'] = geo_buff
|
||||
g_obj.apertures[aperture_found]['geometry'].append(deepcopy(dict_el))
|
||||
else:
|
||||
ap_keys = list(g_obj.apertures.keys())
|
||||
if ap_keys:
|
||||
new_apid = str(int(max(ap_keys)) + 1)
|
||||
else:
|
||||
new_apid = '10'
|
||||
|
||||
g_obj.apertures[new_apid] = {}
|
||||
g_obj.apertures[new_apid]['type'] = 'C'
|
||||
g_obj.apertures[new_apid]['size'] = line_thickness
|
||||
g_obj.apertures[new_apid]['geometry'] = []
|
||||
|
||||
for geo in geo_list:
|
||||
geo_buff = geo.buffer(line_thickness / 2.0, resolution=self.grb_steps_per_circle, join_style=3)
|
||||
geo_buff_list.append(geo_buff)
|
||||
|
||||
dict_el = {}
|
||||
dict_el['follow'] = geo
|
||||
dict_el['solid'] = geo_buff
|
||||
g_obj.apertures[new_apid]['geometry'].append(deepcopy(dict_el))
|
||||
|
||||
s_list = []
|
||||
if g_obj.solid_geometry:
|
||||
try:
|
||||
for poly in g_obj.solid_geometry:
|
||||
s_list.append(poly)
|
||||
except TypeError:
|
||||
s_list.append(g_obj.solid_geometry)
|
||||
|
||||
geo_buff_list = MultiPolygon(geo_buff_list)
|
||||
geo_buff_list = geo_buff_list.buffer(0)
|
||||
for poly in geo_buff_list:
|
||||
s_list.append(poly)
|
||||
g_obj.solid_geometry = MultiPolygon(s_list)
|
||||
|
||||
def replot(self, obj, run_thread=True):
|
||||
def worker_task():
|
||||
with self.app.proc_container.new('%s...' % _("Plotting")):
|
||||
obj.plot()
|
||||
|
||||
if run_thread:
|
||||
self.app.worker_task.emit({'fcn': worker_task, 'params': []})
|
||||
else:
|
||||
worker_task()
|
||||
|
||||
def on_exit(self):
|
||||
# plot the object
|
||||
try:
|
||||
self.replot(obj=self.grb_object)
|
||||
except (AttributeError, TypeError):
|
||||
return
|
||||
|
||||
# update the bounding box values
|
||||
try:
|
||||
a, b, c, d = self.grb_object.bounds()
|
||||
self.grb_object.options['xmin'] = a
|
||||
self.grb_object.options['ymin'] = b
|
||||
self.grb_object.options['xmax'] = c
|
||||
self.grb_object.options['ymax'] = d
|
||||
except Exception as e:
|
||||
log.debug("ToolCorners.on_exit() copper_obj bounds error --> %s" % str(e))
|
||||
|
||||
# reset the variables
|
||||
self.grb_object = None
|
||||
|
||||
self.app.call_source = "app"
|
||||
self.app.inform.emit('[success] %s' % _("Corners Tool exit."))
|
|
@ -1,455 +0,0 @@
|
|||
# ##########################################################
|
||||
# FlatCAM: 2D Post-processing for Manufacturing #
|
||||
# File Author: Marius Adrian Stanciu (c) #
|
||||
# Date: 2/14/2020 #
|
||||
# MIT Licence #
|
||||
# ##########################################################
|
||||
|
||||
from PyQt5 import QtWidgets, QtCore
|
||||
|
||||
from AppTool import AppTool
|
||||
from AppGUI.GUIElements import FCButton, FCDoubleSpinner, RadioSet, FCComboBox, NumericalEvalEntry, FCEntry
|
||||
|
||||
from shapely.ops import unary_union
|
||||
|
||||
from copy import deepcopy
|
||||
import math
|
||||
|
||||
import logging
|
||||
import gettext
|
||||
import AppTranslation as fcTranslate
|
||||
import builtins
|
||||
|
||||
fcTranslate.apply_language('strings')
|
||||
if '_' not in builtins.__dict__:
|
||||
_ = gettext.gettext
|
||||
|
||||
log = logging.getLogger('base')
|
||||
|
||||
|
||||
class ToolEtchCompensation(AppTool):
|
||||
|
||||
toolName = _("Etch Compensation Tool")
|
||||
|
||||
def __init__(self, app):
|
||||
self.app = app
|
||||
self.decimals = self.app.decimals
|
||||
|
||||
AppTool.__init__(self, app)
|
||||
|
||||
self.tools_frame = QtWidgets.QFrame()
|
||||
self.tools_frame.setContentsMargins(0, 0, 0, 0)
|
||||
self.layout.addWidget(self.tools_frame)
|
||||
self.tools_box = QtWidgets.QVBoxLayout()
|
||||
self.tools_box.setContentsMargins(0, 0, 0, 0)
|
||||
self.tools_frame.setLayout(self.tools_box)
|
||||
|
||||
# Title
|
||||
title_label = QtWidgets.QLabel("%s" % self.toolName)
|
||||
title_label.setStyleSheet("""
|
||||
QLabel
|
||||
{
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
}
|
||||
""")
|
||||
self.tools_box.addWidget(title_label)
|
||||
|
||||
# Grid Layout
|
||||
grid0 = QtWidgets.QGridLayout()
|
||||
grid0.setColumnStretch(0, 0)
|
||||
grid0.setColumnStretch(1, 1)
|
||||
self.tools_box.addLayout(grid0)
|
||||
|
||||
grid0.addWidget(QtWidgets.QLabel(''), 0, 0, 1, 2)
|
||||
|
||||
# Target Gerber Object
|
||||
self.gerber_combo = FCComboBox()
|
||||
self.gerber_combo.setModel(self.app.collection)
|
||||
self.gerber_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
|
||||
self.gerber_combo.is_last = True
|
||||
self.gerber_combo.obj_type = "Gerber"
|
||||
|
||||
self.gerber_label = QtWidgets.QLabel('<b>%s:</b>' % _("GERBER"))
|
||||
self.gerber_label.setToolTip(
|
||||
_("Gerber object that will be inverted.")
|
||||
)
|
||||
|
||||
grid0.addWidget(self.gerber_label, 1, 0, 1, 2)
|
||||
grid0.addWidget(self.gerber_combo, 2, 0, 1, 2)
|
||||
|
||||
separator_line = QtWidgets.QFrame()
|
||||
separator_line.setFrameShape(QtWidgets.QFrame.HLine)
|
||||
separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
|
||||
grid0.addWidget(separator_line, 3, 0, 1, 2)
|
||||
|
||||
self.util_label = QtWidgets.QLabel("<b>%s:</b>" % _("Utilities"))
|
||||
self.util_label.setToolTip('%s.' % _("Conversion utilities"))
|
||||
|
||||
grid0.addWidget(self.util_label, 4, 0, 1, 2)
|
||||
|
||||
# Oz to um conversion
|
||||
self.oz_um_label = QtWidgets.QLabel('%s:' % _('Oz to Microns'))
|
||||
self.oz_um_label.setToolTip(
|
||||
_("Will convert from oz thickness to microns [um].\n"
|
||||
"Can use formulas with operators: /, *, +, -, %, .\n"
|
||||
"The real numbers use the dot decimals separator.")
|
||||
)
|
||||
grid0.addWidget(self.oz_um_label, 5, 0, 1, 2)
|
||||
|
||||
hlay_1 = QtWidgets.QHBoxLayout()
|
||||
|
||||
self.oz_entry = NumericalEvalEntry(border_color='#0069A9')
|
||||
self.oz_entry.setPlaceholderText(_("Oz value"))
|
||||
self.oz_to_um_entry = FCEntry()
|
||||
self.oz_to_um_entry.setPlaceholderText(_("Microns value"))
|
||||
self.oz_to_um_entry.setReadOnly(True)
|
||||
|
||||
hlay_1.addWidget(self.oz_entry)
|
||||
hlay_1.addWidget(self.oz_to_um_entry)
|
||||
grid0.addLayout(hlay_1, 6, 0, 1, 2)
|
||||
|
||||
# Mils to um conversion
|
||||
self.mils_um_label = QtWidgets.QLabel('%s:' % _('Mils to Microns'))
|
||||
self.mils_um_label.setToolTip(
|
||||
_("Will convert from mils to microns [um].\n"
|
||||
"Can use formulas with operators: /, *, +, -, %, .\n"
|
||||
"The real numbers use the dot decimals separator.")
|
||||
)
|
||||
grid0.addWidget(self.mils_um_label, 7, 0, 1, 2)
|
||||
|
||||
hlay_2 = QtWidgets.QHBoxLayout()
|
||||
|
||||
self.mils_entry = NumericalEvalEntry(border_color='#0069A9')
|
||||
self.mils_entry.setPlaceholderText(_("Mils value"))
|
||||
self.mils_to_um_entry = FCEntry()
|
||||
self.mils_to_um_entry.setPlaceholderText(_("Microns value"))
|
||||
self.mils_to_um_entry.setReadOnly(True)
|
||||
|
||||
hlay_2.addWidget(self.mils_entry)
|
||||
hlay_2.addWidget(self.mils_to_um_entry)
|
||||
grid0.addLayout(hlay_2, 8, 0, 1, 2)
|
||||
|
||||
separator_line = QtWidgets.QFrame()
|
||||
separator_line.setFrameShape(QtWidgets.QFrame.HLine)
|
||||
separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
|
||||
grid0.addWidget(separator_line, 9, 0, 1, 2)
|
||||
|
||||
self.param_label = QtWidgets.QLabel("<b>%s:</b>" % _("Parameters"))
|
||||
self.param_label.setToolTip('%s.' % _("Parameters for this tool"))
|
||||
|
||||
grid0.addWidget(self.param_label, 10, 0, 1, 2)
|
||||
|
||||
# Thickness
|
||||
self.thick_label = QtWidgets.QLabel('%s:' % _('Copper Thickness'))
|
||||
self.thick_label.setToolTip(
|
||||
_("The thickness of the copper foil.\n"
|
||||
"In microns [um].")
|
||||
)
|
||||
self.thick_entry = FCDoubleSpinner(callback=self.confirmation_message)
|
||||
self.thick_entry.set_precision(self.decimals)
|
||||
self.thick_entry.set_range(0.0000, 9999.9999)
|
||||
self.thick_entry.setObjectName(_("Thickness"))
|
||||
|
||||
grid0.addWidget(self.thick_label, 12, 0)
|
||||
grid0.addWidget(self.thick_entry, 12, 1)
|
||||
|
||||
self.ratio_label = QtWidgets.QLabel('%s:' % _("Ratio"))
|
||||
self.ratio_label.setToolTip(
|
||||
_("The ratio of lateral etch versus depth etch.\n"
|
||||
"Can be:\n"
|
||||
"- custom -> the user will enter a custom value\n"
|
||||
"- preselection -> value which depends on a selection of etchants")
|
||||
)
|
||||
self.ratio_radio = RadioSet([
|
||||
{'label': _('Etch Factor'), 'value': 'factor'},
|
||||
{'label': _('Etchants list'), 'value': 'etch_list'},
|
||||
{'label': _('Manual offset'), 'value': 'manual'}
|
||||
], orientation='vertical', stretch=False)
|
||||
|
||||
grid0.addWidget(self.ratio_label, 14, 0, 1, 2)
|
||||
grid0.addWidget(self.ratio_radio, 16, 0, 1, 2)
|
||||
|
||||
# Etchants
|
||||
self.etchants_label = QtWidgets.QLabel('%s:' % _('Etchants'))
|
||||
self.etchants_label.setToolTip(
|
||||
_("A list of etchants.")
|
||||
)
|
||||
self.etchants_combo = FCComboBox(callback=self.confirmation_message)
|
||||
self.etchants_combo.setObjectName(_("Etchants"))
|
||||
self.etchants_combo.addItems(["CuCl2", "Fe3Cl", _("Alkaline baths")])
|
||||
|
||||
grid0.addWidget(self.etchants_label, 18, 0)
|
||||
grid0.addWidget(self.etchants_combo, 18, 1)
|
||||
|
||||
# Etch Factor
|
||||
self.factor_label = QtWidgets.QLabel('%s:' % _('Etch factor'))
|
||||
self.factor_label.setToolTip(
|
||||
_("The ratio between depth etch and lateral etch .\n"
|
||||
"Accepts real numbers and formulas using the operators: /,*,+,-,%")
|
||||
)
|
||||
self.factor_entry = NumericalEvalEntry(border_color='#0069A9')
|
||||
self.factor_entry.setPlaceholderText(_("Real number or formula"))
|
||||
self.factor_entry.setObjectName(_("Etch_factor"))
|
||||
|
||||
grid0.addWidget(self.factor_label, 19, 0)
|
||||
grid0.addWidget(self.factor_entry, 19, 1)
|
||||
|
||||
# Manual Offset
|
||||
self.offset_label = QtWidgets.QLabel('%s:' % _('Offset'))
|
||||
self.offset_label.setToolTip(
|
||||
_("Value with which to increase or decrease (buffer)\n"
|
||||
"the copper features. In microns [um].")
|
||||
)
|
||||
self.offset_entry = FCDoubleSpinner(callback=self.confirmation_message)
|
||||
self.offset_entry.set_precision(self.decimals)
|
||||
self.offset_entry.set_range(-9999.9999, 9999.9999)
|
||||
self.offset_entry.setObjectName(_("Offset"))
|
||||
|
||||
grid0.addWidget(self.offset_label, 20, 0)
|
||||
grid0.addWidget(self.offset_entry, 20, 1)
|
||||
|
||||
# Hide the Etchants and Etch factor
|
||||
self.etchants_label.hide()
|
||||
self.etchants_combo.hide()
|
||||
self.factor_label.hide()
|
||||
self.factor_entry.hide()
|
||||
self.offset_label.hide()
|
||||
self.offset_entry.hide()
|
||||
|
||||
separator_line = QtWidgets.QFrame()
|
||||
separator_line.setFrameShape(QtWidgets.QFrame.HLine)
|
||||
separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
|
||||
grid0.addWidget(separator_line, 22, 0, 1, 2)
|
||||
|
||||
self.compensate_btn = FCButton(_('Compensate'))
|
||||
self.compensate_btn.setToolTip(
|
||||
_("Will increase the copper features thickness to compensate the lateral etch.")
|
||||
)
|
||||
self.compensate_btn.setStyleSheet("""
|
||||
QPushButton
|
||||
{
|
||||
font-weight: bold;
|
||||
}
|
||||
""")
|
||||
grid0.addWidget(self.compensate_btn, 24, 0, 1, 2)
|
||||
|
||||
self.tools_box.addStretch()
|
||||
|
||||
# ## Reset Tool
|
||||
self.reset_button = QtWidgets.QPushButton(_("Reset Tool"))
|
||||
self.reset_button.setToolTip(
|
||||
_("Will reset the tool parameters.")
|
||||
)
|
||||
self.reset_button.setStyleSheet("""
|
||||
QPushButton
|
||||
{
|
||||
font-weight: bold;
|
||||
}
|
||||
""")
|
||||
self.tools_box.addWidget(self.reset_button)
|
||||
|
||||
self.compensate_btn.clicked.connect(self.on_compensate)
|
||||
self.reset_button.clicked.connect(self.set_tool_ui)
|
||||
self.ratio_radio.activated_custom.connect(self.on_ratio_change)
|
||||
|
||||
self.oz_entry.textChanged.connect(self.on_oz_conversion)
|
||||
self.mils_entry.textChanged.connect(self.on_mils_conversion)
|
||||
|
||||
def install(self, icon=None, separator=None, **kwargs):
|
||||
AppTool.install(self, icon, separator, shortcut='', **kwargs)
|
||||
|
||||
def run(self, toggle=True):
|
||||
self.app.defaults.report_usage("ToolEtchCompensation()")
|
||||
log.debug("ToolEtchCompensation() is running ...")
|
||||
|
||||
if toggle:
|
||||
# if the splitter is hidden, display it, else hide it but only if the current widget is the same
|
||||
if self.app.ui.splitter.sizes()[0] == 0:
|
||||
self.app.ui.splitter.setSizes([1, 1])
|
||||
else:
|
||||
try:
|
||||
if self.app.ui.tool_scroll_area.widget().objectName() == self.toolName:
|
||||
# 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:
|
||||
if self.app.ui.splitter.sizes()[0] == 0:
|
||||
self.app.ui.splitter.setSizes([1, 1])
|
||||
|
||||
AppTool.run(self)
|
||||
self.set_tool_ui()
|
||||
|
||||
self.app.ui.notebook.setTabText(2, _("Etch Compensation Tool"))
|
||||
|
||||
def set_tool_ui(self):
|
||||
self.thick_entry.set_value(18.0)
|
||||
self.ratio_radio.set_value('factor')
|
||||
|
||||
def on_ratio_change(self, val):
|
||||
"""
|
||||
Called on activated_custom signal of the RadioSet GUI element self.radio_ratio
|
||||
|
||||
:param val: 'c' or 'p': 'c' means custom factor and 'p' means preselected etchants
|
||||
:type val: str
|
||||
:return: None
|
||||
:rtype:
|
||||
"""
|
||||
if val == 'factor':
|
||||
self.etchants_label.hide()
|
||||
self.etchants_combo.hide()
|
||||
self.factor_label.show()
|
||||
self.factor_entry.show()
|
||||
self.offset_label.hide()
|
||||
self.offset_entry.hide()
|
||||
elif val == 'etch_list':
|
||||
self.etchants_label.show()
|
||||
self.etchants_combo.show()
|
||||
self.factor_label.hide()
|
||||
self.factor_entry.hide()
|
||||
self.offset_label.hide()
|
||||
self.offset_entry.hide()
|
||||
else:
|
||||
self.etchants_label.hide()
|
||||
self.etchants_combo.hide()
|
||||
self.factor_label.hide()
|
||||
self.factor_entry.hide()
|
||||
self.offset_label.show()
|
||||
self.offset_entry.show()
|
||||
|
||||
def on_oz_conversion(self, txt):
|
||||
try:
|
||||
val = eval(txt)
|
||||
# oz thickness to mils by multiplying with 1.37
|
||||
# mils to microns by multiplying with 25.4
|
||||
val *= 34.798
|
||||
except Exception:
|
||||
self.oz_to_um_entry.set_value('')
|
||||
return
|
||||
self.oz_to_um_entry.set_value(val, self.decimals)
|
||||
|
||||
def on_mils_conversion(self, txt):
|
||||
try:
|
||||
val = eval(txt)
|
||||
val *= 25.4
|
||||
except Exception:
|
||||
self.mils_to_um_entry.set_value('')
|
||||
return
|
||||
self.mils_to_um_entry.set_value(val, self.decimals)
|
||||
|
||||
def on_compensate(self):
|
||||
log.debug("ToolEtchCompensation.on_compensate()")
|
||||
|
||||
ratio_type = self.ratio_radio.get_value()
|
||||
thickness = self.thick_entry.get_value() / 1000 # in microns
|
||||
|
||||
grb_circle_steps = int(self.app.defaults["gerber_circle_steps"])
|
||||
obj_name = self.gerber_combo.currentText()
|
||||
|
||||
outname = obj_name + "_comp"
|
||||
|
||||
# Get source object.
|
||||
try:
|
||||
grb_obj = self.app.collection.get_by_name(obj_name)
|
||||
except Exception as e:
|
||||
self.app.inform.emit('[ERROR_NOTCL] %s: %s' % (_("Could not retrieve object"), str(obj_name)))
|
||||
return "Could not retrieve object: %s with error: %s" % (obj_name, str(e))
|
||||
|
||||
if grb_obj is None:
|
||||
if obj_name == '':
|
||||
obj_name = 'None'
|
||||
self.app.inform.emit('[ERROR_NOTCL] %s: %s' % (_("Object not found"), str(obj_name)))
|
||||
return
|
||||
|
||||
if ratio_type == 'factor':
|
||||
etch_factor = 1 / self.factor_entry.get_value()
|
||||
offset = thickness / etch_factor
|
||||
elif ratio_type == 'etch_list':
|
||||
etchant = self.etchants_combo.get_value()
|
||||
if etchant == "CuCl2":
|
||||
etch_factor = 0.33
|
||||
else:
|
||||
etch_factor = 0.25
|
||||
offset = thickness / etch_factor
|
||||
else:
|
||||
offset = self.offset_entry.get_value() / 1000 # in microns
|
||||
|
||||
try:
|
||||
__ = iter(grb_obj.solid_geometry)
|
||||
except TypeError:
|
||||
grb_obj.solid_geometry = list(grb_obj.solid_geometry)
|
||||
|
||||
new_solid_geometry = []
|
||||
|
||||
for poly in grb_obj.solid_geometry:
|
||||
new_solid_geometry.append(poly.buffer(offset, int(grb_circle_steps)))
|
||||
new_solid_geometry = unary_union(new_solid_geometry)
|
||||
|
||||
new_options = {}
|
||||
for opt in grb_obj.options:
|
||||
new_options[opt] = deepcopy(grb_obj.options[opt])
|
||||
|
||||
new_apertures = deepcopy(grb_obj.apertures)
|
||||
|
||||
# update the apertures attributes (keys in the apertures dict)
|
||||
for ap in new_apertures:
|
||||
type = new_apertures[ap]['type']
|
||||
for k in new_apertures[ap]:
|
||||
if type == 'R' or type == 'O':
|
||||
if k == 'width' or k == 'height':
|
||||
new_apertures[ap][k] += offset
|
||||
else:
|
||||
if k == 'size' or k == 'width' or k == 'height':
|
||||
new_apertures[ap][k] += offset
|
||||
|
||||
if k == 'geometry':
|
||||
for geo_el in new_apertures[ap][k]:
|
||||
if 'solid' in geo_el:
|
||||
geo_el['solid'] = geo_el['solid'].buffer(offset, int(grb_circle_steps))
|
||||
|
||||
# in case of 'R' or 'O' aperture type we need to update the aperture 'size' after
|
||||
# the 'width' and 'height' keys were updated
|
||||
for ap in new_apertures:
|
||||
type = new_apertures[ap]['type']
|
||||
for k in new_apertures[ap]:
|
||||
if type == 'R' or type == 'O':
|
||||
if k == 'size':
|
||||
new_apertures[ap][k] = math.sqrt(
|
||||
new_apertures[ap]['width'] ** 2 + new_apertures[ap]['height'] ** 2)
|
||||
|
||||
def init_func(new_obj, app_obj):
|
||||
"""
|
||||
Init a new object in FlatCAM Object collection
|
||||
|
||||
:param new_obj: New object
|
||||
:type new_obj: ObjectCollection
|
||||
:param app_obj: App
|
||||
:type app_obj: App_Main.App
|
||||
:return: None
|
||||
:rtype:
|
||||
"""
|
||||
new_obj.options.update(new_options)
|
||||
new_obj.options['name'] = outname
|
||||
new_obj.fill_color = deepcopy(grb_obj.fill_color)
|
||||
new_obj.outline_color = deepcopy(grb_obj.outline_color)
|
||||
|
||||
new_obj.apertures = deepcopy(new_apertures)
|
||||
|
||||
new_obj.solid_geometry = deepcopy(new_solid_geometry)
|
||||
new_obj.source_file = self.app.export_gerber(obj_name=outname, filename=None,
|
||||
local_use=new_obj, use_thread=False)
|
||||
|
||||
self.app.app_obj.new_object('gerber', outname, init_func)
|
||||
|
||||
def reset_fields(self):
|
||||
self.gerber_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
|
||||
|
||||
@staticmethod
|
||||
def poly2rings(poly):
|
||||
return [poly.exterior] + [interior for interior in poly.interiors]
|
||||
# end of file
|
|
@ -1,361 +0,0 @@
|
|||
# ##########################################################
|
||||
# FlatCAM: 2D Post-processing for Manufacturing #
|
||||
# File Author: Marius Adrian Stanciu (c) #
|
||||
# Date: 4/23/2019 #
|
||||
# MIT Licence #
|
||||
# ##########################################################
|
||||
|
||||
from PyQt5 import QtWidgets, QtCore
|
||||
|
||||
from AppTool import AppTool
|
||||
|
||||
from AppParsers.ParsePDF import PdfParser, grace
|
||||
from shapely.geometry import Point, MultiPolygon
|
||||
from shapely.ops import unary_union
|
||||
|
||||
from copy import deepcopy
|
||||
|
||||
import zlib
|
||||
import re
|
||||
import time
|
||||
import logging
|
||||
import traceback
|
||||
|
||||
import gettext
|
||||
import AppTranslation as fcTranslate
|
||||
import builtins
|
||||
|
||||
fcTranslate.apply_language('strings')
|
||||
if '_' not in builtins.__dict__:
|
||||
_ = gettext.gettext
|
||||
|
||||
log = logging.getLogger('base')
|
||||
|
||||
|
||||
class ToolPDF(AppTool):
|
||||
"""
|
||||
Parse a PDF file.
|
||||
Reference here: https://www.adobe.com/content/dam/acom/en/devnet/pdf/pdfs/pdf_reference_archives/PDFReference.pdf
|
||||
Return a list of geometries
|
||||
"""
|
||||
toolName = _("PDF Import Tool")
|
||||
|
||||
def __init__(self, app):
|
||||
AppTool.__init__(self, app)
|
||||
self.app = app
|
||||
self.decimals = self.app.decimals
|
||||
|
||||
self.stream_re = re.compile(b'.*?FlateDecode.*?stream(.*?)endstream', re.S)
|
||||
|
||||
self.pdf_decompressed = {}
|
||||
|
||||
# key = file name and extension
|
||||
# value is a dict to store the parsed content of the PDF
|
||||
self.pdf_parsed = {}
|
||||
|
||||
# QTimer for periodic check
|
||||
self.check_thread = QtCore.QTimer()
|
||||
|
||||
# Every time a parser is started we add a promise; every time a parser finished we remove a promise
|
||||
# when empty we start the layer rendering
|
||||
self.parsing_promises = []
|
||||
|
||||
self.parser = PdfParser(app=self.app)
|
||||
|
||||
def run(self, toggle=True):
|
||||
self.app.defaults.report_usage("ToolPDF()")
|
||||
|
||||
self.set_tool_ui()
|
||||
self.on_open_pdf_click()
|
||||
|
||||
def install(self, icon=None, separator=None, **kwargs):
|
||||
AppTool.install(self, icon, separator, shortcut='Ctrl+Q', **kwargs)
|
||||
|
||||
def set_tool_ui(self):
|
||||
pass
|
||||
|
||||
def on_open_pdf_click(self):
|
||||
"""
|
||||
File menu callback for opening an PDF file.
|
||||
|
||||
:return: None
|
||||
"""
|
||||
|
||||
self.app.defaults.report_usage("ToolPDF.on_open_pdf_click()")
|
||||
self.app.log.debug("ToolPDF.on_open_pdf_click()")
|
||||
|
||||
_filter_ = "Adobe PDF Files (*.pdf);;" \
|
||||
"All Files (*.*)"
|
||||
|
||||
try:
|
||||
filenames, _f = QtWidgets.QFileDialog.getOpenFileNames(caption=_("Open PDF"),
|
||||
directory=self.app.get_last_folder(),
|
||||
filter=_filter_)
|
||||
except TypeError:
|
||||
filenames, _f = QtWidgets.QFileDialog.getOpenFileNames(caption=_("Open PDF"), filter=_filter_)
|
||||
|
||||
if len(filenames) == 0:
|
||||
self.app.inform.emit('[WARNING_NOTCL] %s.' % _("Open PDF cancelled"))
|
||||
else:
|
||||
# start the parsing timer with a period of 1 second
|
||||
self.periodic_check(1000)
|
||||
|
||||
for filename in filenames:
|
||||
if filename != '':
|
||||
self.app.worker_task.emit({'fcn': self.open_pdf,
|
||||
'params': [filename]})
|
||||
|
||||
def open_pdf(self, filename):
|
||||
short_name = filename.split('/')[-1].split('\\')[-1]
|
||||
self.parsing_promises.append(short_name)
|
||||
|
||||
self.pdf_parsed[short_name] = {}
|
||||
self.pdf_parsed[short_name]['pdf'] = {}
|
||||
self.pdf_parsed[short_name]['filename'] = filename
|
||||
|
||||
self.pdf_decompressed[short_name] = ''
|
||||
|
||||
if self.app.abort_flag:
|
||||
# graceful abort requested by the user
|
||||
raise grace
|
||||
|
||||
with self.app.proc_container.new(_("Parsing PDF file ...")):
|
||||
with open(filename, "rb") as f:
|
||||
pdf = f.read()
|
||||
|
||||
stream_nr = 0
|
||||
for s in re.findall(self.stream_re, pdf):
|
||||
if self.app.abort_flag:
|
||||
# graceful abort requested by the user
|
||||
raise grace
|
||||
|
||||
stream_nr += 1
|
||||
log.debug("PDF STREAM: %d\n" % stream_nr)
|
||||
s = s.strip(b'\r\n')
|
||||
try:
|
||||
self.pdf_decompressed[short_name] += (zlib.decompress(s).decode('UTF-8') + '\r\n')
|
||||
except Exception as e:
|
||||
self.app.inform.emit('[ERROR_NOTCL] %s: %s\n%s' % (_("Failed to open"), str(filename), str(e)))
|
||||
log.debug("ToolPDF.open_pdf().obj_init() --> %s" % str(e))
|
||||
return
|
||||
|
||||
self.pdf_parsed[short_name]['pdf'] = self.parser.parse_pdf(pdf_content=self.pdf_decompressed[short_name])
|
||||
# we used it, now we delete it
|
||||
self.pdf_decompressed[short_name] = ''
|
||||
|
||||
# removal from list is done in a multithreaded way therefore not always the removal can be done
|
||||
# try to remove until it's done
|
||||
try:
|
||||
while True:
|
||||
self.parsing_promises.remove(short_name)
|
||||
time.sleep(0.1)
|
||||
except Exception as e:
|
||||
log.debug("ToolPDF.open_pdf() --> %s" % str(e))
|
||||
self.app.inform.emit('[success] %s: %s' % (_("Opened"), str(filename)))
|
||||
|
||||
def layer_rendering_as_excellon(self, filename, ap_dict, layer_nr):
|
||||
outname = filename.split('/')[-1].split('\\')[-1] + "_%s" % str(layer_nr)
|
||||
|
||||
# store the points here until reconstitution:
|
||||
# keys are diameters and values are list of (x,y) coords
|
||||
points = {}
|
||||
|
||||
def obj_init(exc_obj, app_obj):
|
||||
clear_geo = [geo_el['clear'] for geo_el in ap_dict['0']['geometry']]
|
||||
|
||||
for geo in clear_geo:
|
||||
xmin, ymin, xmax, ymax = geo.bounds
|
||||
center = (((xmax - xmin) / 2) + xmin, ((ymax - ymin) / 2) + ymin)
|
||||
|
||||
# for drill bits, even in INCH, it's enough 3 decimals
|
||||
correction_factor = 0.974
|
||||
dia = (xmax - xmin) * correction_factor
|
||||
dia = round(dia, 3)
|
||||
if dia in points:
|
||||
points[dia].append(center)
|
||||
else:
|
||||
points[dia] = [center]
|
||||
|
||||
sorted_dia = sorted(points.keys())
|
||||
|
||||
name_tool = 0
|
||||
for dia in sorted_dia:
|
||||
name_tool += 1
|
||||
|
||||
# create tools dictionary
|
||||
spec = {"C": dia, 'solid_geometry': []}
|
||||
exc_obj.tools[str(name_tool)] = spec
|
||||
|
||||
# create drill list of dictionaries
|
||||
for dia_points in points:
|
||||
if dia == dia_points:
|
||||
for pt in points[dia_points]:
|
||||
exc_obj.drills.append({'point': Point(pt), 'tool': str(name_tool)})
|
||||
break
|
||||
|
||||
ret = exc_obj.create_geometry()
|
||||
if ret == 'fail':
|
||||
log.debug("Could not create geometry for Excellon object.")
|
||||
return "fail"
|
||||
for tool in exc_obj.tools:
|
||||
if exc_obj.tools[tool]['solid_geometry']:
|
||||
return
|
||||
app_obj.inform.emit('[ERROR_NOTCL] %s: %s' % (_("No geometry found in file"), outname))
|
||||
return "fail"
|
||||
|
||||
with self.app.proc_container.new(_("Rendering PDF layer #%d ...") % int(layer_nr)):
|
||||
|
||||
ret_val = self.app.app_obj.new_object("excellon", outname, obj_init, autoselected=False)
|
||||
if ret_val == 'fail':
|
||||
self.app.inform.emit('[ERROR_NOTCL] %s' % _('Open PDF file failed.'))
|
||||
return
|
||||
# Register recent file
|
||||
self.app.file_opened.emit("excellon", filename)
|
||||
# GUI feedback
|
||||
self.app.inform.emit('[success] %s: %s' % (_("Rendered"), outname))
|
||||
|
||||
def layer_rendering_as_gerber(self, filename, ap_dict, layer_nr):
|
||||
outname = filename.split('/')[-1].split('\\')[-1] + "_%s" % str(layer_nr)
|
||||
|
||||
def obj_init(grb_obj, app_obj):
|
||||
|
||||
grb_obj.apertures = ap_dict
|
||||
|
||||
poly_buff = []
|
||||
follow_buf = []
|
||||
for ap in grb_obj.apertures:
|
||||
for k in grb_obj.apertures[ap]:
|
||||
if k == 'geometry':
|
||||
for geo_el in ap_dict[ap][k]:
|
||||
if 'solid' in geo_el:
|
||||
poly_buff.append(geo_el['solid'])
|
||||
if 'follow' in geo_el:
|
||||
follow_buf.append(geo_el['follow'])
|
||||
poly_buff = unary_union(poly_buff)
|
||||
|
||||
if '0' in grb_obj.apertures:
|
||||
global_clear_geo = []
|
||||
if 'geometry' in grb_obj.apertures['0']:
|
||||
for geo_el in ap_dict['0']['geometry']:
|
||||
if 'clear' in geo_el:
|
||||
global_clear_geo.append(geo_el['clear'])
|
||||
|
||||
if global_clear_geo:
|
||||
solid = []
|
||||
for apid in grb_obj.apertures:
|
||||
if 'geometry' in grb_obj.apertures[apid]:
|
||||
for elem in grb_obj.apertures[apid]['geometry']:
|
||||
if 'solid' in elem:
|
||||
solid_geo = deepcopy(elem['solid'])
|
||||
for clear_geo in global_clear_geo:
|
||||
# Make sure that the clear_geo is within the solid_geo otherwise we loose
|
||||
# the solid_geometry. We want for clear_geometry just to cut into solid_geometry
|
||||
# not to delete it
|
||||
if clear_geo.within(solid_geo):
|
||||
solid_geo = solid_geo.difference(clear_geo)
|
||||
if solid_geo.is_empty:
|
||||
solid_geo = elem['solid']
|
||||
try:
|
||||
for poly in solid_geo:
|
||||
solid.append(poly)
|
||||
except TypeError:
|
||||
solid.append(solid_geo)
|
||||
poly_buff = deepcopy(MultiPolygon(solid))
|
||||
|
||||
follow_buf = unary_union(follow_buf)
|
||||
|
||||
try:
|
||||
poly_buff = poly_buff.buffer(0.0000001)
|
||||
except ValueError:
|
||||
pass
|
||||
try:
|
||||
poly_buff = poly_buff.buffer(-0.0000001)
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
grb_obj.solid_geometry = deepcopy(poly_buff)
|
||||
grb_obj.follow_geometry = deepcopy(follow_buf)
|
||||
|
||||
with self.app.proc_container.new(_("Rendering PDF layer #%d ...") % int(layer_nr)):
|
||||
|
||||
ret = self.app.app_obj.new_object('gerber', outname, obj_init, autoselected=False)
|
||||
if ret == 'fail':
|
||||
self.app.inform.emit('[ERROR_NOTCL] %s' % _('Open PDF file failed.'))
|
||||
return
|
||||
# Register recent file
|
||||
self.app.file_opened.emit('gerber', filename)
|
||||
# GUI feedback
|
||||
self.app.inform.emit('[success] %s: %s' % (_("Rendered"), outname))
|
||||
|
||||
def periodic_check(self, check_period):
|
||||
"""
|
||||
This function starts an QTimer and it will periodically check if parsing was done
|
||||
|
||||
:param check_period: time at which to check periodically if all plots finished to be plotted
|
||||
:return:
|
||||
"""
|
||||
|
||||
# self.plot_thread = threading.Thread(target=lambda: self.check_plot_finished(check_period))
|
||||
# self.plot_thread.start()
|
||||
log.debug("ToolPDF --> Periodic Check started.")
|
||||
|
||||
try:
|
||||
self.check_thread.stop()
|
||||
except TypeError:
|
||||
pass
|
||||
|
||||
self.check_thread.setInterval(check_period)
|
||||
try:
|
||||
self.check_thread.timeout.disconnect(self.periodic_check_handler)
|
||||
except (TypeError, AttributeError):
|
||||
pass
|
||||
|
||||
self.check_thread.timeout.connect(self.periodic_check_handler)
|
||||
self.check_thread.start(QtCore.QThread.HighPriority)
|
||||
|
||||
def periodic_check_handler(self):
|
||||
"""
|
||||
If the parsing worker finished then start multithreaded rendering
|
||||
:return:
|
||||
"""
|
||||
# log.debug("checking parsing --> %s" % str(self.parsing_promises))
|
||||
|
||||
try:
|
||||
if not self.parsing_promises:
|
||||
self.check_thread.stop()
|
||||
log.debug("PDF --> start rendering")
|
||||
# parsing finished start the layer rendering
|
||||
if self.pdf_parsed:
|
||||
obj_to_delete = []
|
||||
for object_name in self.pdf_parsed:
|
||||
if self.app.abort_flag:
|
||||
# graceful abort requested by the user
|
||||
raise grace
|
||||
|
||||
filename = deepcopy(self.pdf_parsed[object_name]['filename'])
|
||||
pdf_content = deepcopy(self.pdf_parsed[object_name]['pdf'])
|
||||
obj_to_delete.append(object_name)
|
||||
for k in pdf_content:
|
||||
if self.app.abort_flag:
|
||||
# graceful abort requested by the user
|
||||
raise grace
|
||||
|
||||
ap_dict = pdf_content[k]
|
||||
print(k, ap_dict)
|
||||
if ap_dict:
|
||||
layer_nr = k
|
||||
if k == 0:
|
||||
self.app.worker_task.emit({'fcn': self.layer_rendering_as_excellon,
|
||||
'params': [filename, ap_dict, layer_nr]})
|
||||
else:
|
||||
self.app.worker_task.emit({'fcn': self.layer_rendering_as_gerber,
|
||||
'params': [filename, ap_dict, layer_nr]})
|
||||
# delete the object already processed so it will not be processed again for other objects
|
||||
# that were opened at the same time; like in drag & drop on AppGUI
|
||||
for obj_name in obj_to_delete:
|
||||
if obj_name in self.pdf_parsed:
|
||||
self.pdf_parsed.pop(obj_name)
|
||||
|
||||
log.debug("ToolPDF --> Periodic check finished.")
|
||||
except Exception:
|
||||
traceback.print_exc()
|
|
@ -1,45 +0,0 @@
|
|||
|
||||
from AppTools.ToolCalculators import ToolCalculator
|
||||
from AppTools.ToolCalibration import ToolCalibration
|
||||
|
||||
from AppTools.ToolDblSided import DblSidedTool
|
||||
from AppTools.ToolExtractDrills import ToolExtractDrills
|
||||
from AppTools.ToolAlignObjects import AlignObjects
|
||||
|
||||
from AppTools.ToolFilm import Film
|
||||
|
||||
from AppTools.ToolImage import ToolImage
|
||||
|
||||
from AppTools.ToolDistance import Distance
|
||||
from AppTools.ToolDistanceMin import DistanceMin
|
||||
|
||||
from AppTools.ToolMove import ToolMove
|
||||
|
||||
from AppTools.ToolCutOut import CutOut
|
||||
from AppTools.ToolNCC import NonCopperClear
|
||||
from AppTools.ToolPaint import ToolPaint
|
||||
from AppTools.ToolIsolation import ToolIsolation
|
||||
|
||||
from AppTools.ToolOptimal import ToolOptimal
|
||||
|
||||
from AppTools.ToolPanelize import Panelize
|
||||
from AppTools.ToolPcbWizard import PcbWizard
|
||||
from AppTools.ToolPDF import ToolPDF
|
||||
from AppTools.ToolProperties import Properties
|
||||
|
||||
from AppTools.ToolQRCode import QRCode
|
||||
from AppTools.ToolRulesCheck import RulesCheck
|
||||
|
||||
from AppTools.ToolCopperThieving import ToolCopperThieving
|
||||
from AppTools.ToolFiducials import ToolFiducials
|
||||
|
||||
from AppTools.ToolShell import FCShell
|
||||
from AppTools.ToolSolderPaste import SolderPaste
|
||||
from AppTools.ToolSub import ToolSub
|
||||
|
||||
from AppTools.ToolTransform import ToolTransform
|
||||
from AppTools.ToolPunchGerber import ToolPunchGerber
|
||||
|
||||
from AppTools.ToolInvertGerber import ToolInvertGerber
|
||||
from AppTools.ToolCorners import ToolCorners
|
||||
from AppTools.ToolEtchCompensation import ToolEtchCompensation
|
235
CHANGELOG.md
|
@ -7,229 +7,6 @@ CHANGELOG for FlatCAM beta
|
|||
|
||||
=================================================
|
||||
|
||||
2.06.2020
|
||||
|
||||
- Tcl Shell - added a button to delete the content of the active line
|
||||
- Tcl Command Isolate - fixed to work in the new configuration
|
||||
- Tcl Command Follow - fixed to work in the new configuration
|
||||
- Etch Compensation Tool - added a new etchant: alkaline baths
|
||||
- fixed spacing in the status toolbar icons
|
||||
- updated the translation files to the latest changes
|
||||
- modified behavior of object comboboxes in Paint, NCC and CutOut Tools: now if an object is selected in Project Tab and is of the supported kind in the Tool, it will be auto-selected
|
||||
- fixed some more strings
|
||||
- updated the Google-translations for the German, Spanish, French
|
||||
- updated the Romanian translation
|
||||
- replaced the icon for the Editor in Toolbar (both for the normal icons and for icons in dark theme)
|
||||
|
||||
1.06.2020
|
||||
|
||||
- made the Distance Tool display the angle in values between 0 and 359.9999 degrees
|
||||
- changed some strings
|
||||
- fixed the warning that old preferences found even for new installation
|
||||
- in Paint Tool fixed the message to select a polygon when using the Selection: Single Polygon being overwritten by the "Grid disabled" message
|
||||
- more changes in strings throughout the app
|
||||
- made some minor changes in the GUI of the FlatCAM Tools
|
||||
- in Tools Database made sure that each new tool added has a unique name
|
||||
- in AppTool made some methods to be class methods
|
||||
- reverted the class methods in AppTool
|
||||
- added a button for Transformations Tool in the lower side (common) of the Object UI
|
||||
- some other UI changes
|
||||
- after using Isolation Tool it will switch automatically to the Geometry UI
|
||||
- in Preferences replaced some widgets with a new one that combine a Slider with a Spinner (from David Robertson)
|
||||
- in Preferences replaced the widgets that sets colors with a compound one (from David Robertson)
|
||||
- made Progressive plotting work in Isolation Tool
|
||||
- fix an issue with progressive plotted shapes not being deleted on the end of the job
|
||||
- some fixed due of recent changes and some strings changed
|
||||
- added a validator for the FCColorEntry GUI element such that only the valid chars are accepted
|
||||
- changed the status bar label to have an icon instead of text
|
||||
- added a label in status bar that will toggle the Preferences tab
|
||||
- made some changes such that that the label in status bar for toggling the Preferences Tab will be updated in various cases of closing the tab
|
||||
- changed colors for the status bar labels and added some of the new icons in the gray version
|
||||
- remade visibility as threaded - it seems that I can't really squeeze more performance from this
|
||||
|
||||
31.05.2020
|
||||
|
||||
- structural changes in Preferences from David Robertson
|
||||
- made last filter selected for open file to be used next time when opening files (for Excellon, GCode and Gerber files, for now)
|
||||
|
||||
30.05.2020
|
||||
|
||||
- made confirmation messages for the values that are modified not to be printed in the Shell
|
||||
- Isolation Tool: working on the Rest machining: almost there, perhaps I will use multiprocessing
|
||||
- Isolation Tool: removed the tools that have empty geometry in case of rest machining
|
||||
- Isolation Tool: solved some naming issues
|
||||
- Isolation Tool: updated the tools dict with the common parameters value on isolating
|
||||
- Fixed a recent change that made the edited Geometry objects in the Geometry Editor not to be plotted after saving changes
|
||||
- modified the Tool Database such that when a tool shape is selected as 'V' any change in the Vdia or Vangle or CutZ parameters will update the tool diameter value
|
||||
- In Tool Isolation made sure that the use of ESC key while some processes are active will disconnect the mouse events that may be connected, correctly
|
||||
- optimized the Gerber UI
|
||||
- added a Multi-color checkbox for the Geometry UI (will color differently tool geometry when the geometry is multitool)
|
||||
- added a Multi-color checkbox for the Excellon UI (this way colors for each tool are easier to differentiate especially when the diameter is close)
|
||||
- made the Shell Dock always show docked
|
||||
- fixed NCC Tool behavior when selecting tools for Isolation operation
|
||||
|
||||
29.05.2020
|
||||
|
||||
- fixed the Tool Isolation when using the 'follow' parameter
|
||||
- in Isolation Tool when the Rest machining is checked the combine parameter is set True automatically because the rest machining concept make sense only when all tools are used together
|
||||
- some changes in the UI; added in the status bar an icon to control the Shell Dock
|
||||
- clicking on the activity icon will replot all objects
|
||||
- optimized UI in Tool Isolation
|
||||
- overloaded the App inform signal to allow not printing to shell if a second bool parameter is given; modified some GUI messages to use this feature
|
||||
- fixed the shell status label status on shell dock close from close button
|
||||
- refactored some methods from App class and moved them to plotcanvas (plotcanvaslegacy) class
|
||||
- added an label with icon in the status bar, clicking it will toggle (show status) of the X-Y axis on cavnas
|
||||
- optimized the UI, added to status bar an icon to toggle the axis
|
||||
- updated the Etch Compensation Tool by adding a new possibility to compensate the lateral etch (manual value)
|
||||
- updated the Etch Compensation Tool such that the resulting Gerber object will have the apertures attributes ('size', 'width', 'height') updated to the changes
|
||||
|
||||
28.05.2020
|
||||
|
||||
- made the visibility change (when using the Spacebar key in Project Tab) to be not threaded and to use the enabled property of the ShapesCollection which should be faster
|
||||
- updated the Tool Database class to have the Isolation Tool data
|
||||
- Isolation Tool - made to work the adding of tools from database
|
||||
- fixed some issues related to using the new Numerical... GUI elements
|
||||
- fixed issues in the Tool Subtract
|
||||
- remade Tool Subtract to use multiprocessing when processing geometry
|
||||
- the resulting Gerber file from Tool Subtract has now the attribute source_file populated
|
||||
|
||||
27.05.2020
|
||||
|
||||
- working on Isolation Tool: made to work the Isolation with multiple tools without rest machining
|
||||
|
||||
26.05.2020
|
||||
|
||||
- working on Isolation Tool: made to work the tool parameters data to GUI and GUI to data
|
||||
- Isolation Tool: reworked the GUI
|
||||
- if there is a Gerber object selected then in Isolation Tool the Gerber object combobox will show that object name as current
|
||||
- made the Project Tree items not editable by clicking on selected Tree items (the object rename can still be done in the Selected tab)
|
||||
- working on Isolation Tool: added a Preferences section in Edit -> Preferences and updated their usage within the Isolation tool
|
||||
- fixed milling drills not plotting the resulting Geometry object
|
||||
- all tuple entries in the Preferences UI are now protected against letter entry
|
||||
- all entries in the Preferences UI that have numerical entry are protected now against letters
|
||||
- cleaned the Preferences UI in the Gerber area
|
||||
- minor UI changes
|
||||
|
||||
25.05.2020
|
||||
|
||||
- updated the GUI fields for the Scale and Offset in the Object UI to allow only numeric values and operators in the list [/,*,+,-], spaces, dots and comma
|
||||
- modified the Etch Compensation Tool and added conversion utilities from Oz thickenss and mils to microns
|
||||
- added a Toggle All checkbox to Corner Markers Tool
|
||||
- added an Icon to the MessageBox that asks for saving if the user try to close the app and there is some unsaved work
|
||||
- changed and added some icons
|
||||
- fixed the Shortcuts Tab to reflect the actual current shortcut keys
|
||||
- started to work on moving the Isolation Routing from the Gerber Object UI to it's own tool
|
||||
- created a new tool: Isolation Routing Tool: work in progress
|
||||
- some fixes in NCC Tool
|
||||
- added a dialog in Menu -> Help -> ReadMe?
|
||||
|
||||
24.05.2020
|
||||
|
||||
- changes some icons
|
||||
- added a new GUI element which is a evaluated LineEdit that accepts only float numbers and /,*,+,-,% chars
|
||||
- finished the Etch Compensation Tool
|
||||
- fixed unreliable work of Gerber Editor and optimized the App.editor2object() method
|
||||
- updated the Gerber parser such that it will parse correctly Gerber files that have only one solid polygon inside with multiple clear polygons (like those generated by the Invert Tool)
|
||||
- fixed a small bug in the Geometry UI that made updating the storage from GUI not to work
|
||||
- some small changes in Gerber Editor
|
||||
|
||||
23.05.2020
|
||||
|
||||
- fixed a issue when testing for Exclusion areas overlap over the Geometry object solid_geometry
|
||||
|
||||
22.05.2020
|
||||
|
||||
- fixed the algorithm for calculating closest points in the Exclusion areas
|
||||
- added the Exclusion zones processing to Geometry GCode generation
|
||||
|
||||
21.05.2020
|
||||
|
||||
- added the Exclusion zones processing to Excellon GCode generation
|
||||
- fixed a non frequent plotting problem for CNCJob objects made out of Excellon objects
|
||||
|
||||
19.05.2020
|
||||
|
||||
- updated the Italian language (translation incomplete)
|
||||
- updated all the language strings to the latest changes; updated the POT file
|
||||
- fixed a possible malfunction in Tool Punch Gerber
|
||||
|
||||
18.05.2020
|
||||
|
||||
- fixed the PDF Tool when importing as Gerber objects
|
||||
- moved all the parsing out of the PDF Tool to a new file ParsePDF in the flatcamParsers folder
|
||||
- trying to fix the pixmap load crash when running a FlatCAMScript
|
||||
- made the workspace label in the status bar clickable and also added a status bar message on status toggle for workspace
|
||||
- modified the GUI for Film and Panelize Tools
|
||||
- moved some of the GUI related methods from FlatCAMApp.App to the flatcamGUI.MainGUI class
|
||||
- moved Shortcuts Tab creation in it's own class
|
||||
- renamed classes to have shorter names and grouped
|
||||
- removed reference to postprocessors and replaced it with preprocessors
|
||||
- more refactoring class names
|
||||
- moved some of the methods from the App class to the ObjectCollection class
|
||||
- moved all the new_object related methods in their own class AppObjects.AppObject
|
||||
- more refactoring; solved some issues introduced by the refactoring
|
||||
- solved a circular import
|
||||
- updated the language translation files to the latest changes (no translation)
|
||||
- working on a new Tool: Etch Compensation Tool -> installed the tool and created the GUI and class template
|
||||
- moved more methods out of App_Main class
|
||||
- added confirmation messages for toggle of HUD, Grid, Grid Snap, Axis
|
||||
- added icon in status bar for HUD; clicking on it will toggle the HUD (heads up display)
|
||||
- fixes due of recent changes
|
||||
- fixed issue #417
|
||||
|
||||
17.05.2020
|
||||
|
||||
- added new FlatCAM Tool: Corner Markers Tool which will add line markers in the selected corners of the bounding box of the targeted Gerber object
|
||||
- added a menu entry in Menu -> View for Toggle HUD
|
||||
- solved the issue with the GUI in the Notebook being expanded too much in width due of the FCDoubleSpinner and FCSpinner sizeHint by setting the sizePolicy to Ignored value
|
||||
- fixed the workspace being always A4
|
||||
- added a label in the status bar to show if the workplace is active and what size it is
|
||||
- now the Edit command (either from Menu Edit ->Edit Object) or through the shortcut key (E key) or project tab context menu works also for the CNCJob objects (will open a text Editor with the GCode)
|
||||
- fixed the object collection methods that return a list of objects or names of objects such that they have a parameter now to allow adding to those lists (or not) for the objects of type Script or Document. Thus fixing some of the Tcl commands such Set Origin
|
||||
- reverted the previous changes to object collection; it is better to create empty methods in FlatCAMScript and FlatCAMDocument objects
|
||||
|
||||
16.05.2020
|
||||
|
||||
- worked on the NCC Tool; added a new clear method named 'Combo' which will go through all methods until the clear is done
|
||||
- added a Preferences parameter for font size used in HUD
|
||||
|
||||
13.05.2020
|
||||
|
||||
- updated the French translation strings, made by @micmac (Michel)
|
||||
|
||||
12.05.2020
|
||||
|
||||
- fixed recent issues introduced in Tcl command Drillcncjob
|
||||
- updated the Cncjob to use the 'endxy' parameter which dictates the x,y position at the end of the job
|
||||
- now the Tcl commands Drillcncjob and Cncjob can use the toolchangexy and endxy parameters with or without parenthesis (but no spaces allowed)
|
||||
- modified the Tcl command Paint "single" parameter. Now it's value is a tuple with the x,y coordinates of the single polygon to be painted.
|
||||
- the HUD display state is now persistent between app restarts
|
||||
- updated the Distance Tool such that the right click of the mouse will cancel the tool unless it was a panning move
|
||||
- modified the PlotCanvasLegacy to decide if there is a mouse drag based on the distance between the press event position and the release event position. If the distance is smaller than a delta distance then it is not a drag move.
|
||||
|
||||
11.05.2020
|
||||
|
||||
- removed the labels in status bar that display X,Y positions and replaced it with a HUD display on canvas (combo key SHIFT+H) will toggle the display of the HUD
|
||||
- made the HUD work in Legacy2D mode
|
||||
- fixed situation when the mouse cursor is outside of the canvas and no therefore returning None values
|
||||
- remade the Snap Toolbar presence; now it is always active and situated in the Status Bar
|
||||
- Snap Toolbar is now visible in Fullscreen
|
||||
- in Fullscreen now the Notebook is available but it will be hidden on Fullscreen launch
|
||||
- fixed some minor issues (in the HUD added a separating line, missing an icon in toolbars on first launch)
|
||||
- made sure that the corner snap buttons are shown only in Editors
|
||||
- changed the HUD color when using Dark theme
|
||||
- fix issue in Legacy2D graphic mode where the snap function was not accessible when the PlotCanvasLegacy class was created
|
||||
- modified the HUD in Legacy2D when using Dark Theme to use different colors
|
||||
- modified how the graphic engine change act in Preferences: now only by clicking Apply(or Save) the change will happen. And there is also a message asking for confirmation
|
||||
- re-added the position labels in the status bar; they will be useful if HUD is Off (Altium does the same :) so learn from the best)
|
||||
- fixed the Tcl command Cncjob: there was a problem reported as issue #416. The command did not work due of the dpp parameter
|
||||
- modified the Tcl command Cncjob such that if some of the parameters are not used then the default values will be used (set with set_sys)
|
||||
- modified the Tcl command Drillcncjob to use the defaults when some of the parameters are not used
|
||||
|
||||
10.05.2020
|
||||
|
||||
- fixed the problem with using comma as decimal separator in Grid Snap fields
|
||||
|
||||
9.05.2020
|
||||
|
||||
- modified the GUI for Exclusion areas; now the shapes are displayed in a Table where they can be selected and deleted. Modification applied for Geometry Objects only (for now).
|
||||
|
@ -285,7 +62,7 @@ CHANGELOG for FlatCAM beta
|
|||
2.05.2020
|
||||
|
||||
- changed the icons for the grid snap in the status bar
|
||||
- moved some of the methods from FlatCAMApp.App to flatcamGUI.MainGUI class
|
||||
- moved some of the methods from FlatCAMApp.App to flatcamGUI.FlatCAMGUI class
|
||||
- fixed bug in Gerber Editor in which the units conversion wasn't calculated correct
|
||||
- fixed bug in Gerber Editor in which the QThread that is started on object edit was not stopped at clean up stage
|
||||
- fixed bug in Gerber Editor that kept all the apertures (including the geometry) of a previously edited object that was not saved after edit
|
||||
|
@ -1553,7 +1330,7 @@ CHANGELOG for FlatCAM beta
|
|||
- optimized Rules Check Tool so it runs faster when doing Copper 2 Copper rule
|
||||
- small GUI changes in Optimal Tool and in Film Tool
|
||||
- some PEP8 corrections
|
||||
- some code annotations to make it easier to navigate in the MainGUI.py
|
||||
- some code annotations to make it easier to navigate in the FlatCAMGUI.py
|
||||
- fixed exit FullScreen with Escape key
|
||||
- added a new menu category in the MenuBar named 'Objects'. It will hold the objects found in the Project tab. Useful when working in FullScreen
|
||||
- disabled a log.debug in ObjectColection.get_by_name()
|
||||
|
@ -2992,7 +2769,7 @@ CHANGELOG for FlatCAM beta
|
|||
- fix for issue #262: when doing Edit-> Save & Close Editor on a Geometry that is not generated through first entering into an Editor, the geometry disappear
|
||||
- finished preparing for internationalization for the files: camlib and objectCollection
|
||||
- fixed tools shortcuts not working anymore due of the new toggle parameter for the .run().
|
||||
- finished preparing for internationalization for the files: FlatCAMEditor, MainGUI
|
||||
- finished preparing for internationalization for the files: FlatCAMEditor, FlatCAMGUI
|
||||
- finished preparing for internationalization for the files: FlatCAMObj, ObjectUI
|
||||
- sorted the languages in the Preferences combobox
|
||||
|
||||
|
@ -3314,7 +3091,7 @@ CHANGELOG for FlatCAM beta
|
|||
- fixed the name self-insert in save dialog file for GCode; added protection in case the save path is None
|
||||
- fixed FlatCAM crash when trying to make drills GCode out of a file that have only slots.
|
||||
- changed the messages for Units Conversion
|
||||
- all key shortcuts work across the entire application; moved all the shortcuts definitions in MainGUI.keyPressEvent()
|
||||
- all key shortcuts work across the entire application; moved all the shortcuts definitions in FlatCAMGUI.keyPressEvent()
|
||||
- renamed the theme to layout because it is really a layout change
|
||||
- added plot kind for CNC Job in the App Preferences
|
||||
- combined the geocutout and cutout_any TCL commands - work in progress
|
||||
|
@ -3835,7 +3612,7 @@ For now they are used only for Excellon objects who do have toolchange events
|
|||
|
||||
- fixed a reported bug generated by a typo for feedrate_z object in camlib.py. Because of that, the project could not be saved.
|
||||
- fixed a G01 usage (should be G1) in Marlin preprocessor.
|
||||
- changed the position of the Tool Dia entry in the Object UI and in MainGUI
|
||||
- changed the position of the Tool Dia entry in the Object UI and in FlatCAMGUI
|
||||
- fixed issues in the installer
|
||||
|
||||
30.10.2018
|
||||
|
@ -4395,7 +4172,7 @@ still copper leftovers.
|
|||
- modified generate_milling method which had issues from the Python3 port (it could not sort the tools due of dict to dict comparison no longer possible).
|
||||
- modified the 'default' preprocessor in order to include a space between the value of Xcoord and the following Y
|
||||
- made optional the using of threads for the milling command; by default it is OFF (False) because in the current configuration it creates issues when it is using threads
|
||||
- modified the Panelize function and Tcl command Panelize. It was having issues due to multithreading (kept trying to modify a dictionary in redraw() method)and automatically selecting the last created object (feature introduced by me). I've added a parameter to the app_obj.new_object method, named autoselected (by default it is True) and in the panelize method I initialized it with False.
|
||||
- modified the Panelize function and Tcl command Panelize. It was having issues due to multithreading (kept trying to modify a dictionary in redraw() method)and automatically selecting the last created object (feature introduced by me). I've added a parameter to the new_object method, named autoselected (by default it is True) and in the panelize method I initialized it with False.
|
||||
By initializing the plot parameter with False for the temporary objects, I have increased dramatically the generation speed of the panel because now the temporary object are no longer ploted which consumed time.
|
||||
- replaced log.warn() with log.warning() in camlib.py. Reason: deprecated
|
||||
- fixed the issue that the "Defaults" button was having no effect when clicked and Options Combo was in Project Options
|
||||
|
|
|
@ -3,8 +3,8 @@ import os
|
|||
|
||||
from PyQt5 import QtWidgets
|
||||
from PyQt5.QtCore import QSettings, Qt
|
||||
from App_Main import App
|
||||
from AppGUI import VisPyPatches
|
||||
from FlatCAMApp import App
|
||||
from flatcamGUI import VisPyPatches
|
||||
|
||||
from multiprocessing import freeze_support
|
||||
# import copyreg
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
from PyQt5 import QtGui, QtCore, QtWidgets
|
||||
from AppGUI.GUIElements import FCTable, FCEntry, FCButton, FCFileSaveDialog
|
||||
from flatcamGUI.GUIElements import FCTable, FCEntry, FCButton, FCFileSaveDialog
|
||||
|
||||
import sys
|
||||
import webbrowser
|
||||
|
@ -7,7 +7,7 @@ import webbrowser
|
|||
from copy import deepcopy
|
||||
from datetime import datetime
|
||||
import gettext
|
||||
import AppTranslation as fcTranslate
|
||||
import FlatCAMTranslation as fcTranslate
|
||||
import builtins
|
||||
|
||||
fcTranslate.apply_language('strings')
|
||||
|
@ -287,12 +287,12 @@ class BookmarkManager(QtWidgets.QWidget):
|
|||
date = date.replace(' ', '_')
|
||||
|
||||
filter__ = "Text File (*.TXT);;All Files (*.*)"
|
||||
filename, _f = FCFileSaveDialog.get_saved_filename(caption=_("Export Bookmarks"),
|
||||
directory='{l_save}/{n}_{date}'.format(
|
||||
filename, _f = FCFileSaveDialog.get_saved_filename(caption=_("Export FlatCAM Bookmarks"),
|
||||
directory='{l_save}/FlatCAM_{n}_{date}'.format(
|
||||
l_save=str(self.app.get_last_save_folder()),
|
||||
n=_("Bookmarks"),
|
||||
date=date),
|
||||
ext_filter=filter__)
|
||||
filter=filter__)
|
||||
|
||||
filename = str(filename)
|
||||
|
||||
|
@ -334,7 +334,7 @@ class BookmarkManager(QtWidgets.QWidget):
|
|||
self.app.log.debug("on_import_bookmarks()")
|
||||
|
||||
filter_ = "Text File (*.txt);;All Files (*.*)"
|
||||
filename, _f = QtWidgets.QFileDialog.getOpenFileName(caption=_("Import Bookmarks"), filter=filter_)
|
||||
filename, _f = QtWidgets.QFileDialog.getOpenFileName(caption=_("Import FlatCAM Bookmarks"), filter=filter_)
|
||||
|
||||
filename = str(filename)
|
||||
|
|
@ -12,18 +12,15 @@
|
|||
# ##########################################################
|
||||
from PyQt5 import QtCore
|
||||
|
||||
from shapely.geometry import Polygon, Point, LineString
|
||||
from shapely.ops import unary_union
|
||||
from shapely.geometry import Polygon, MultiPolygon
|
||||
|
||||
from AppGUI.VisPyVisuals import ShapeCollection
|
||||
from AppTool import AppTool
|
||||
|
||||
from copy import deepcopy
|
||||
from flatcamGUI.VisPyVisuals import ShapeCollection
|
||||
from FlatCAMTool import FlatCAMTool
|
||||
|
||||
import numpy as np
|
||||
|
||||
import gettext
|
||||
import AppTranslation as fcTranslate
|
||||
import FlatCAMTranslation as fcTranslate
|
||||
import builtins
|
||||
|
||||
fcTranslate.apply_language('strings')
|
||||
|
@ -32,9 +29,7 @@ if '_' not in builtins.__dict__:
|
|||
|
||||
|
||||
class GracefulException(Exception):
|
||||
"""
|
||||
Graceful Exception raised when the user is requesting to cancel the current threaded task
|
||||
"""
|
||||
# Graceful Exception raised when the user is requesting to cancel the current threaded task
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
|
@ -109,11 +104,8 @@ def color_variant(hex_color, bright_factor=1):
|
|||
Takes a color in HEX format #FF00FF and produces a lighter or darker variant
|
||||
|
||||
:param hex_color: color to change
|
||||
:type hex_color: str
|
||||
:param bright_factor: factor to change the color brightness [0 ... 1]
|
||||
:type bright_factor: float
|
||||
:return: Modified color
|
||||
:rtype: str
|
||||
:param bright_factor: factor to change the color brightness [0 ... 1]
|
||||
:return: modified color
|
||||
"""
|
||||
|
||||
if len(hex_color) != 7:
|
||||
|
@ -138,9 +130,7 @@ def color_variant(hex_color, bright_factor=1):
|
|||
|
||||
|
||||
class ExclusionAreas(QtCore.QObject):
|
||||
"""
|
||||
Functionality for adding Exclusion Areas for the Excellon and Geometry FlatCAM Objects
|
||||
"""
|
||||
|
||||
e_shape_modified = QtCore.pyqtSignal()
|
||||
|
||||
def __init__(self, app):
|
||||
|
@ -156,7 +146,7 @@ class ExclusionAreas(QtCore.QObject):
|
|||
except AttributeError:
|
||||
self.exclusion_shapes = None
|
||||
else:
|
||||
from AppGUI.PlotCanvasLegacy import ShapeCollectionLegacy
|
||||
from flatcamGUI.PlotCanvasLegacy import ShapeCollectionLegacy
|
||||
self.exclusion_shapes = ShapeCollectionLegacy(obj=self, app=self.app, name="exclusion")
|
||||
|
||||
# Event signals disconnect id holders
|
||||
|
@ -177,8 +167,8 @@ class ExclusionAreas(QtCore.QObject):
|
|||
{
|
||||
"obj_type": string ("excellon" or "geometry") <- self.obj_type
|
||||
"shape": Shapely polygon
|
||||
"strategy": string ("over" or "around") <- self.strategy_button
|
||||
"overz": float <- self.over_z_button
|
||||
"strategy": string ("over" or "around") <- self.strategy
|
||||
"overz": float <- self.over_z
|
||||
}
|
||||
'''
|
||||
self.exclusion_areas_storage = []
|
||||
|
@ -188,9 +178,9 @@ class ExclusionAreas(QtCore.QObject):
|
|||
self.solid_geometry = []
|
||||
self.obj_type = None
|
||||
|
||||
self.shape_type_button = None
|
||||
self.over_z_button = None
|
||||
self.strategy_button = None
|
||||
self.shape_type = 'square' # TODO use the self.app.defaults when made general (not in Geo object Pref UI)
|
||||
self.over_z = 0.1
|
||||
self.strategy = None
|
||||
self.cnc_button = None
|
||||
|
||||
def on_add_area_click(self, shape_button, overz_button, strategy_radio, cnc_button, solid_geo, obj_type):
|
||||
|
@ -198,22 +188,21 @@ class ExclusionAreas(QtCore.QObject):
|
|||
|
||||
:param shape_button: a FCButton that has the value for the shape
|
||||
:param overz_button: a FCDoubleSpinner that holds the Over Z value
|
||||
:param strategy_radio: a RadioSet button with the strategy_button value
|
||||
:param strategy_radio: a RadioSet button with the strategy value
|
||||
:param cnc_button: a FCButton in Object UI that when clicked the CNCJob is created
|
||||
We have a reference here so we can change the color signifying that exclusion areas are
|
||||
available.
|
||||
:param solid_geo: reference to the object solid geometry for which we add exclusion areas
|
||||
:param obj_type: Type of FlatCAM object that called this method. String: "excellon" or "geometry"
|
||||
:type obj_type: str
|
||||
:return: None
|
||||
:param obj_type: Type of FlatCAM object that called this method
|
||||
:type obj_type: String: "excellon" or "geometry"
|
||||
:return:
|
||||
"""
|
||||
self.app.inform.emit('[WARNING_NOTCL] %s' % _("Click the start point of the area."))
|
||||
self.app.call_source = 'geometry'
|
||||
|
||||
self.shape_type_button = shape_button
|
||||
|
||||
self.over_z_button = overz_button
|
||||
self.strategy_button = strategy_radio
|
||||
self.shape_type = shape_button.get_value()
|
||||
self.over_z = overz_button.get_value()
|
||||
self.strategy = strategy_radio.get_value()
|
||||
self.cnc_button = cnc_button
|
||||
|
||||
self.solid_geometry = solid_geo
|
||||
|
@ -234,14 +223,6 @@ class ExclusionAreas(QtCore.QObject):
|
|||
|
||||
# To be called after clicking on the plot.
|
||||
def on_mouse_release(self, event):
|
||||
"""
|
||||
Called on mouse click release.
|
||||
|
||||
:param event: Mouse event
|
||||
:type event:
|
||||
:return: None
|
||||
:rtype:
|
||||
"""
|
||||
if self.app.is_legacy is False:
|
||||
event_pos = event.pos
|
||||
# event_is_dragging = event.is_dragging
|
||||
|
@ -259,11 +240,11 @@ class ExclusionAreas(QtCore.QObject):
|
|||
|
||||
x1, y1 = curr_pos[0], curr_pos[1]
|
||||
|
||||
# shape_type_button = self.ui.area_shape_radio.get_value()
|
||||
# shape_type = self.ui.area_shape_radio.get_value()
|
||||
|
||||
# do clear area only for left mouse clicks
|
||||
if event.button == 1:
|
||||
if self.shape_type_button.get_value() == "square":
|
||||
if self.shape_type == "square":
|
||||
if self.first_click is False:
|
||||
self.first_click = True
|
||||
self.app.inform.emit('[WARNING_NOTCL] %s' % _("Click the end point of the area."))
|
||||
|
@ -287,14 +268,14 @@ class ExclusionAreas(QtCore.QObject):
|
|||
# {
|
||||
# "obj_type": string("excellon" or "geometry") < - self.obj_type
|
||||
# "shape": Shapely polygon
|
||||
# "strategy_button": string("over" or "around") < - self.strategy_button
|
||||
# "overz": float < - self.over_z_button
|
||||
# "strategy": string("over" or "around") < - self.strategy
|
||||
# "overz": float < - self.over_z
|
||||
# }
|
||||
new_el = {
|
||||
"obj_type": self.obj_type,
|
||||
"shape": new_rectangle,
|
||||
"strategy": self.strategy_button.get_value(),
|
||||
"overz": self.over_z_button.get_value()
|
||||
"strategy": self.strategy,
|
||||
"overz": self.over_z
|
||||
}
|
||||
self.exclusion_areas_storage.append(new_el)
|
||||
|
||||
|
@ -306,7 +287,7 @@ class ExclusionAreas(QtCore.QObject):
|
|||
face_color = "#FF7400BF"
|
||||
|
||||
# add a temporary shape on canvas
|
||||
AppTool.draw_tool_selection_shape(
|
||||
FlatCAMTool.draw_tool_selection_shape(
|
||||
self, old_coords=(x0, y0), coords=(x1, y1),
|
||||
color=color,
|
||||
face_color=face_color,
|
||||
|
@ -324,7 +305,7 @@ class ExclusionAreas(QtCore.QObject):
|
|||
return ""
|
||||
elif event.button == right_button and self.mouse_is_dragging is False:
|
||||
|
||||
shape_type = self.shape_type_button.get_value()
|
||||
shape_type = self.shape_type
|
||||
|
||||
if shape_type == "square":
|
||||
self.first_click = False
|
||||
|
@ -341,23 +322,21 @@ class ExclusionAreas(QtCore.QObject):
|
|||
|
||||
# we need to add a Polygon and a Polygon can be made only from at least 3 points
|
||||
if len(self.points) > 2:
|
||||
AppTool.delete_moving_selection_shape(self)
|
||||
FlatCAMTool.delete_moving_selection_shape(self)
|
||||
pol = Polygon(self.points)
|
||||
# do not add invalid polygons even if they are drawn by utility geometry
|
||||
if pol.is_valid:
|
||||
"""
|
||||
{
|
||||
"obj_type": string("excellon" or "geometry") < - self.obj_type
|
||||
"shape": Shapely polygon
|
||||
"strategy": string("over" or "around") < - self.strategy_button
|
||||
"overz": float < - self.over_z_button
|
||||
}
|
||||
"""
|
||||
# {
|
||||
# "obj_type": string("excellon" or "geometry") < - self.obj_type
|
||||
# "shape": Shapely polygon
|
||||
# "strategy": string("over" or "around") < - self.strategy
|
||||
# "overz": float < - self.over_z
|
||||
# }
|
||||
new_el = {
|
||||
"obj_type": self.obj_type,
|
||||
"shape": pol,
|
||||
"strategy": self.strategy_button.get_value(),
|
||||
"overz": self.over_z_button.get_value()
|
||||
"strategy": self.strategy,
|
||||
"overz": self.over_z
|
||||
}
|
||||
self.exclusion_areas_storage.append(new_el)
|
||||
|
||||
|
@ -368,7 +347,7 @@ class ExclusionAreas(QtCore.QObject):
|
|||
color = "#098a8f"
|
||||
face_color = "#FF7400BF"
|
||||
|
||||
AppTool.draw_selection_shape_polygon(
|
||||
FlatCAMTool.draw_selection_shape_polygon(
|
||||
self, points=self.points,
|
||||
color=color,
|
||||
face_color=face_color,
|
||||
|
@ -380,7 +359,7 @@ class ExclusionAreas(QtCore.QObject):
|
|||
self.poly_drawn = False
|
||||
return
|
||||
|
||||
# AppTool.delete_tool_selection_shape(self, shapes_storage=self.exclusion_shapes)
|
||||
# FlatCAMTool.delete_tool_selection_shape(self, shapes_storage=self.exclusion_shapes)
|
||||
|
||||
if self.app.is_legacy is False:
|
||||
self.app.plotcanvas.graph_event_disconnect('mouse_release', self.on_mouse_release)
|
||||
|
@ -403,11 +382,11 @@ class ExclusionAreas(QtCore.QObject):
|
|||
if len(self.exclusion_areas_storage) == 0:
|
||||
return
|
||||
|
||||
# since the exclusion areas should apply to all objects in the app collection, this check is limited to
|
||||
# only the current object therefore it will not guarantee success
|
||||
self.app.inform.emit("%s" % _("Exclusion areas added. Checking overlap with the object geometry ..."))
|
||||
self.app.inform.emit(
|
||||
"[success] %s" % _("Exclusion areas added. Checking overlap with the object geometry ..."))
|
||||
|
||||
for el in self.exclusion_areas_storage:
|
||||
if el["shape"].intersects(unary_union(self.solid_geometry)):
|
||||
if el["shape"].intersects(MultiPolygon(self.solid_geometry)):
|
||||
self.on_clear_area_click()
|
||||
self.app.inform.emit(
|
||||
"[ERROR_NOTCL] %s" % _("Failed. Exclusion areas intersects the object geometry ..."))
|
||||
|
@ -427,15 +406,10 @@ class ExclusionAreas(QtCore.QObject):
|
|||
)
|
||||
|
||||
self.e_shape_modified.emit()
|
||||
for k in self.exclusion_areas_storage:
|
||||
print(k)
|
||||
|
||||
def area_disconnect(self):
|
||||
"""
|
||||
Will do the cleanup. Will disconnect the mouse events for the custom handlers in this class and initialize
|
||||
certain class attributes.
|
||||
|
||||
:return: None
|
||||
:rtype:
|
||||
"""
|
||||
if self.app.is_legacy is False:
|
||||
self.app.plotcanvas.graph_event_disconnect('mouse_release', self.on_mouse_release)
|
||||
self.app.plotcanvas.graph_event_disconnect('mouse_move', self.on_mouse_move)
|
||||
|
@ -454,22 +428,15 @@ class ExclusionAreas(QtCore.QObject):
|
|||
self.poly_drawn = False
|
||||
self.exclusion_areas_storage = []
|
||||
|
||||
AppTool.delete_moving_selection_shape(self)
|
||||
# AppTool.delete_tool_selection_shape(self, shapes_storage=self.exclusion_shapes)
|
||||
FlatCAMTool.delete_moving_selection_shape(self)
|
||||
# FlatCAMTool.delete_tool_selection_shape(self, shapes_storage=self.exclusion_shapes)
|
||||
|
||||
self.app.call_source = "app"
|
||||
self.app.inform.emit("[WARNING_NOTCL] %s" % _("Cancelled. Area exclusion drawing was interrupted."))
|
||||
|
||||
# called on mouse move
|
||||
def on_mouse_move(self, event):
|
||||
"""
|
||||
Called on mouse move
|
||||
|
||||
:param event: mouse event
|
||||
:type event:
|
||||
:return: None
|
||||
:rtype:
|
||||
"""
|
||||
shape_type = self.shape_type_button.get_value()
|
||||
shape_type = self.shape_type
|
||||
|
||||
if self.app.is_legacy is False:
|
||||
event_pos = event.pos
|
||||
|
@ -499,20 +466,15 @@ class ExclusionAreas(QtCore.QObject):
|
|||
size=self.app.defaults["global_cursor_size"])
|
||||
|
||||
# update the positions on status bar
|
||||
self.app.ui.position_label.setText(" <b>X</b>: %.4f "
|
||||
"<b>Y</b>: %.4f" % (curr_pos[0], curr_pos[1]))
|
||||
if self.cursor_pos is None:
|
||||
self.cursor_pos = (0, 0)
|
||||
|
||||
self.app.dx = curr_pos[0] - float(self.cursor_pos[0])
|
||||
self.app.dy = curr_pos[1] - float(self.cursor_pos[1])
|
||||
self.app.ui.position_label.setText(" <b>X</b>: %.4f "
|
||||
"<b>Y</b>: %.4f " % (curr_pos[0], curr_pos[1]))
|
||||
# self.app.ui.rel_position_label.setText("<b>Dx</b>: %.4f <b>Dy</b>: "
|
||||
# "%.4f " % (self.app.dx, self.app.dy))
|
||||
|
||||
units = self.app.defaults["units"].lower()
|
||||
self.app.plotcanvas.text_hud.text = \
|
||||
'Dx:\t{:<.4f} [{:s}]\nDy:\t{:<.4f} [{:s}]\n\nX: \t{:<.4f} [{:s}]\nY: \t{:<.4f} [{:s}]'.format(
|
||||
self.app.dx, units, self.app.dy, units, curr_pos[0], units, curr_pos[1], units)
|
||||
self.app.ui.rel_position_label.setText("<b>Dx</b>: %.4f <b>Dy</b>: "
|
||||
"%.4f " % (self.app.dx, self.app.dy))
|
||||
|
||||
if self.obj_type == 'excellon':
|
||||
color = "#FF7400"
|
||||
|
@ -531,20 +493,14 @@ class ExclusionAreas(QtCore.QObject):
|
|||
face_color=face_color,
|
||||
coords=(curr_pos[0], curr_pos[1]))
|
||||
else:
|
||||
AppTool.delete_moving_selection_shape(self)
|
||||
AppTool.draw_moving_selection_shape_poly(
|
||||
FlatCAMTool.delete_moving_selection_shape(self)
|
||||
FlatCAMTool.draw_moving_selection_shape_poly(
|
||||
self, points=self.points,
|
||||
color=color,
|
||||
face_color=face_color,
|
||||
data=(curr_pos[0], curr_pos[1]))
|
||||
|
||||
def on_clear_area_click(self):
|
||||
"""
|
||||
Slot for clicking the button for Deleting all the Exclusion areas.
|
||||
|
||||
:return: None
|
||||
:rtype:
|
||||
"""
|
||||
self.clear_shapes()
|
||||
|
||||
# restore the default StyleSheet
|
||||
|
@ -559,28 +515,21 @@ class ExclusionAreas(QtCore.QObject):
|
|||
self.cnc_button.setToolTip('%s' % _("Generate the CNC Job object."))
|
||||
|
||||
def clear_shapes(self):
|
||||
"""
|
||||
Will delete all the Exclusion areas; will delete on canvas any possible selection box for the Exclusion areas.
|
||||
|
||||
:return: None
|
||||
:rtype:
|
||||
"""
|
||||
self.exclusion_areas_storage.clear()
|
||||
AppTool.delete_moving_selection_shape(self)
|
||||
FlatCAMTool.delete_moving_selection_shape(self)
|
||||
self.app.delete_selection_shape()
|
||||
AppTool.delete_tool_selection_shape(self, shapes_storage=self.exclusion_shapes)
|
||||
self.app.inform.emit('%s' % _("All exclusion zones deleted."))
|
||||
FlatCAMTool.delete_tool_selection_shape(self, shapes_storage=self.exclusion_shapes)
|
||||
self.app.inform.emit('[success] %s' % _("All exclusion zones deleted."))
|
||||
|
||||
def delete_sel_shapes(self, idxs):
|
||||
"""
|
||||
|
||||
:param idxs: list of indexes in self.exclusion_areas_storage list to be deleted
|
||||
:type idxs: list
|
||||
:return: None
|
||||
:param idxs: list of indexes in self.exclusion_areas_storage list to be deleted
|
||||
:return:
|
||||
"""
|
||||
|
||||
# delete all plotted shapes
|
||||
AppTool.delete_tool_selection_shape(self, shapes_storage=self.exclusion_shapes)
|
||||
FlatCAMTool.delete_tool_selection_shape(self, shapes_storage=self.exclusion_shapes)
|
||||
|
||||
# delete shapes
|
||||
for idx in sorted(idxs, reverse=True):
|
||||
|
@ -618,234 +567,4 @@ class ExclusionAreas(QtCore.QObject):
|
|||
""")
|
||||
self.cnc_button.setToolTip('%s' % _("Generate the CNC Job object."))
|
||||
|
||||
self.app.inform.emit('%s' % _("All exclusion zones deleted."))
|
||||
|
||||
def travel_coordinates(self, start_point, end_point, tooldia):
|
||||
"""
|
||||
WIll create a path the go around the exclusion areas on the shortest path when travelling (at a Z above the
|
||||
material).
|
||||
|
||||
:param start_point: X,Y coordinates for the start point of the travel line
|
||||
:type start_point: tuple
|
||||
:param end_point: X,Y coordinates for the destination point of the travel line
|
||||
:type end_point: tuple
|
||||
:param tooldia: THe tool diameter used and which generates the travel lines
|
||||
:type tooldia float
|
||||
:return: A list of x,y tuples that describe the avoiding path
|
||||
:rtype: list
|
||||
"""
|
||||
|
||||
ret_list = []
|
||||
|
||||
# Travel lines: rapids. Should not pass through Exclusion areas
|
||||
travel_line = LineString([start_point, end_point])
|
||||
origin_point = Point(start_point)
|
||||
|
||||
buffered_storage = []
|
||||
# add a little something to the half diameter, to make sure that we really don't enter in the exclusion zones
|
||||
buffered_distance = (tooldia / 2.0) + (0.1 if self.app.defaults['units'] == 'MM' else 0.00393701)
|
||||
|
||||
for area in self.exclusion_areas_storage:
|
||||
new_area = deepcopy(area)
|
||||
new_area['shape'] = area['shape'].buffer(buffered_distance, join_style=2)
|
||||
buffered_storage.append(new_area)
|
||||
|
||||
# sort the Exclusion areas from the closest to the start_point to the farthest
|
||||
tmp = []
|
||||
for area in buffered_storage:
|
||||
dist = Point(start_point).distance(area['shape'])
|
||||
tmp.append((dist, area))
|
||||
tmp.sort(key=lambda k: k[0])
|
||||
|
||||
sorted_area_storage = [k[1] for k in tmp]
|
||||
|
||||
# process the ordered exclusion areas list
|
||||
for area in sorted_area_storage:
|
||||
outline = area['shape'].exterior
|
||||
if travel_line.intersects(outline):
|
||||
intersection_pts = travel_line.intersection(outline)
|
||||
|
||||
if isinstance(intersection_pts, Point):
|
||||
# it's just a touch, continue
|
||||
continue
|
||||
|
||||
entry_pt = nearest_point(origin_point, intersection_pts)
|
||||
exit_pt = farthest_point(origin_point, intersection_pts)
|
||||
|
||||
if area['strategy'] == 'around':
|
||||
full_vertex_points = [Point(x) for x in list(outline.coords)]
|
||||
|
||||
# the last coordinate in outline, a LinearRing, is the closing one
|
||||
# therefore a duplicate of the first one; discard it
|
||||
vertex_points = full_vertex_points[:-1]
|
||||
|
||||
# dist_from_entry = [(entry_pt.distance(vt), vertex_points.index(vt)) for vt in vertex_points]
|
||||
# closest_point_entry = nsmallest(1, dist_from_entry, key=lambda x: x[0])
|
||||
# start_idx = closest_point_entry[0][1]
|
||||
#
|
||||
# dist_from_exit = [(exit_pt.distance(vt), vertex_points.index(vt)) for vt in vertex_points]
|
||||
# closest_point_exit = nsmallest(1, dist_from_exit, key=lambda x: x[0])
|
||||
# end_idx = closest_point_exit[0][1]
|
||||
|
||||
# pts_line_entry = None
|
||||
# pts_line_exit = None
|
||||
# for i in range(len(full_vertex_points)):
|
||||
# try:
|
||||
# line = LineString(
|
||||
# [
|
||||
# (full_vertex_points[i].x, full_vertex_points[i].y),
|
||||
# (full_vertex_points[i + 1].x, full_vertex_points[i + 1].y)
|
||||
# ]
|
||||
# )
|
||||
# except IndexError:
|
||||
# continue
|
||||
#
|
||||
# if entry_pt.within(line) or entry_pt.equals(Point(line.coords[0])) or \
|
||||
# entry_pt.equals(Point(line.coords[1])):
|
||||
# pts_line_entry = [Point(x) for x in line.coords]
|
||||
#
|
||||
# if exit_pt.within(line) or exit_pt.equals(Point(line.coords[0])) or \
|
||||
# exit_pt.equals(Point(line.coords[1])):
|
||||
# pts_line_exit = [Point(x) for x in line.coords]
|
||||
#
|
||||
# closest_point_entry = nearest_point(entry_pt, pts_line_entry)
|
||||
# start_idx = vertex_points.index(closest_point_entry)
|
||||
#
|
||||
# closest_point_exit = nearest_point(exit_pt, pts_line_exit)
|
||||
# end_idx = vertex_points.index(closest_point_exit)
|
||||
|
||||
# find all vertexes for which a line from start_point does not cross the Exclusion area polygon
|
||||
# the same for end_point
|
||||
# we don't need closest points for which the path leads to crosses of the Exclusion area
|
||||
|
||||
close_start_points = []
|
||||
close_end_points = []
|
||||
for i in range(len(vertex_points)):
|
||||
try:
|
||||
start_line = LineString(
|
||||
[
|
||||
start_point,
|
||||
(vertex_points[i].x, vertex_points[i].y)
|
||||
]
|
||||
)
|
||||
end_line = LineString(
|
||||
[
|
||||
end_point,
|
||||
(vertex_points[i].x, vertex_points[i].y)
|
||||
]
|
||||
)
|
||||
except IndexError:
|
||||
continue
|
||||
|
||||
if not start_line.crosses(area['shape']):
|
||||
close_start_points.append(vertex_points[i])
|
||||
if not end_line.crosses(area['shape']):
|
||||
close_end_points.append(vertex_points[i])
|
||||
|
||||
closest_point_entry = nearest_point(entry_pt, close_start_points)
|
||||
closest_point_exit = nearest_point(exit_pt, close_end_points)
|
||||
|
||||
start_idx = vertex_points.index(closest_point_entry)
|
||||
end_idx = vertex_points.index(closest_point_exit)
|
||||
|
||||
# calculate possible paths: one clockwise the other counterclockwise on the exterior of the
|
||||
# exclusion area outline (Polygon.exterior)
|
||||
vp_len = len(vertex_points)
|
||||
if end_idx > start_idx:
|
||||
path_1 = vertex_points[start_idx:(end_idx + 1)]
|
||||
path_2 = [vertex_points[start_idx]]
|
||||
idx = start_idx
|
||||
for __ in range(vp_len):
|
||||
idx = idx - 1 if idx > 0 else (vp_len - 1)
|
||||
path_2.append(vertex_points[idx])
|
||||
if idx == end_idx:
|
||||
break
|
||||
else:
|
||||
path_1 = vertex_points[end_idx:(start_idx + 1)]
|
||||
path_2 = [vertex_points[end_idx]]
|
||||
idx = end_idx
|
||||
for __ in range(vp_len):
|
||||
idx = idx - 1 if idx > 0 else (vp_len - 1)
|
||||
path_2.append(vertex_points[idx])
|
||||
if idx == start_idx:
|
||||
break
|
||||
path_1.reverse()
|
||||
path_2.reverse()
|
||||
|
||||
# choose the one with the lesser length
|
||||
length_path_1 = 0
|
||||
for i in range(len(path_1)):
|
||||
try:
|
||||
length_path_1 += path_1[i].distance(path_1[i + 1])
|
||||
except IndexError:
|
||||
pass
|
||||
|
||||
length_path_2 = 0
|
||||
for i in range(len(path_2)):
|
||||
try:
|
||||
length_path_2 += path_2[i].distance(path_2[i + 1])
|
||||
except IndexError:
|
||||
pass
|
||||
|
||||
path = path_1 if length_path_1 < length_path_2 else path_2
|
||||
|
||||
# transform the list of Points into a list of Points coordinates
|
||||
path_coords = [[None, (p.x, p.y)] for p in path]
|
||||
ret_list += path_coords
|
||||
|
||||
else:
|
||||
path_coords = [[float(area['overz']), (entry_pt.x, entry_pt.y)], [None, (exit_pt.x, exit_pt.y)]]
|
||||
ret_list += path_coords
|
||||
|
||||
# create a new LineString to test again for possible other Exclusion zones
|
||||
last_pt_in_path = path_coords[-1][1]
|
||||
travel_line = LineString([last_pt_in_path, end_point])
|
||||
|
||||
ret_list.append([None, end_point])
|
||||
return ret_list
|
||||
|
||||
|
||||
def farthest_point(origin, points_list):
|
||||
"""
|
||||
Calculate the farthest Point in a list from another Point
|
||||
|
||||
:param origin: Reference Point
|
||||
:type origin: Point
|
||||
:param points_list: List of Points or a MultiPoint
|
||||
:type points_list: list
|
||||
:return: Farthest Point
|
||||
:rtype: Point
|
||||
"""
|
||||
old_dist = 0
|
||||
fartherst_pt = None
|
||||
|
||||
for pt in points_list:
|
||||
dist = abs(origin.distance(pt))
|
||||
if dist >= old_dist:
|
||||
fartherst_pt = pt
|
||||
old_dist = dist
|
||||
|
||||
return fartherst_pt
|
||||
|
||||
|
||||
def nearest_point(origin, points_list):
|
||||
"""
|
||||
Calculate the nearest Point in a list from another Point
|
||||
|
||||
:param origin: Reference Point
|
||||
:type origin: Point
|
||||
:param points_list: List of Points or a MultiPoint
|
||||
:type points_list: list
|
||||
:return: Nearest Point
|
||||
:rtype: Point
|
||||
"""
|
||||
old_dist = np.Inf
|
||||
nearest_pt = None
|
||||
|
||||
for pt in points_list:
|
||||
dist = abs(origin.distance(pt))
|
||||
if dist <= old_dist:
|
||||
nearest_pt = pt
|
||||
old_dist = dist
|
||||
|
||||
return nearest_pt
|
||||
self.app.inform.emit('[success] %s' % _("All exclusion zones deleted."))
|
|
@ -1,5 +1,5 @@
|
|||
from PyQt5 import QtGui, QtCore, QtWidgets
|
||||
from AppGUI.GUIElements import FCTable, FCEntry, FCButton, FCDoubleSpinner, FCComboBox, FCCheckBox, FCSpinner, \
|
||||
from flatcamGUI.GUIElements import FCTable, FCEntry, FCButton, FCDoubleSpinner, FCComboBox, FCCheckBox, FCSpinner, \
|
||||
FCTree, RadioSet, FCFileSaveDialog
|
||||
from camlib import to_dict
|
||||
|
||||
|
@ -8,10 +8,8 @@ import json
|
|||
|
||||
from copy import deepcopy
|
||||
from datetime import datetime
|
||||
import math
|
||||
|
||||
import gettext
|
||||
import AppTranslation as fcTranslate
|
||||
import FlatCAMTranslation as fcTranslate
|
||||
import builtins
|
||||
|
||||
fcTranslate.apply_language('strings')
|
||||
|
@ -119,7 +117,7 @@ class ToolsDB(QtWidgets.QWidget):
|
|||
)
|
||||
self.buttons_box.addWidget(import_db_btn)
|
||||
|
||||
self.add_tool_from_db = FCButton(_("Transfer the Tool"))
|
||||
self.add_tool_from_db = FCButton(_("Add Tool from Tools DB"))
|
||||
self.add_tool_from_db.setToolTip(
|
||||
_("Add a new tool in the Tools Table of the\n"
|
||||
"active Geometry object after selecting a tool\n"
|
||||
|
@ -315,7 +313,7 @@ class ToolsDB(QtWidgets.QWidget):
|
|||
self.app.inform.emit('[ERROR] %s' % _("Failed to parse Tools DB file."))
|
||||
return
|
||||
|
||||
self.app.inform.emit('[success] %s: %s' % (_("Loaded Tools DB from"), filename))
|
||||
self.app.inform.emit('[success] %s: %s' % (_("Loaded FlatCAM Tools DB from"), filename))
|
||||
|
||||
self.build_db_ui()
|
||||
|
||||
|
@ -657,7 +655,7 @@ class ToolsDB(QtWidgets.QWidget):
|
|||
l_save=str(self.app.get_last_save_folder()),
|
||||
n=_("Tools_Database"),
|
||||
date=date),
|
||||
ext_filter=filter__)
|
||||
filter=filter__)
|
||||
|
||||
filename = str(filename)
|
||||
|
||||
|
@ -726,7 +724,7 @@ class ToolsDB(QtWidgets.QWidget):
|
|||
self.app.inform.emit('[ERROR] %s' % _("Failed to parse Tools DB file."))
|
||||
return
|
||||
|
||||
self.app.inform.emit('[success] %s: %s' % (_("Loaded Tools DB from"), filename))
|
||||
self.app.inform.emit('[success] %s: %s' % (_("Loaded FlatCAM Tools DB from"), filename))
|
||||
self.build_db_ui()
|
||||
self.callback_on_edited()
|
||||
|
||||
|
@ -1032,7 +1030,6 @@ class ToolsDB2(QtWidgets.QWidget):
|
|||
self.advanced_box.setTitle(_("Advanced Geo Parameters"))
|
||||
self.advanced_box.setFixedWidth(250)
|
||||
|
||||
# NCC TOOL BOX
|
||||
self.ncc_box = QtWidgets.QGroupBox()
|
||||
self.ncc_box.setStyleSheet("""
|
||||
QGroupBox
|
||||
|
@ -1045,7 +1042,6 @@ class ToolsDB2(QtWidgets.QWidget):
|
|||
self.ncc_box.setTitle(_("NCC Parameters"))
|
||||
self.ncc_box.setFixedWidth(250)
|
||||
|
||||
# PAINT TOOL BOX
|
||||
self.paint_box = QtWidgets.QGroupBox()
|
||||
self.paint_box.setStyleSheet("""
|
||||
QGroupBox
|
||||
|
@ -1058,24 +1054,10 @@ class ToolsDB2(QtWidgets.QWidget):
|
|||
self.paint_box.setTitle(_("Paint Parameters"))
|
||||
self.paint_box.setFixedWidth(250)
|
||||
|
||||
# ISOLATION TOOL BOX
|
||||
self.iso_box = QtWidgets.QGroupBox()
|
||||
self.iso_box.setStyleSheet("""
|
||||
QGroupBox
|
||||
{
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
}
|
||||
""")
|
||||
self.iso_vlay = QtWidgets.QVBoxLayout()
|
||||
self.iso_box.setTitle(_("Isolation Parameters"))
|
||||
self.iso_box.setFixedWidth(250)
|
||||
|
||||
self.basic_box.setLayout(self.basic_vlay)
|
||||
self.advanced_box.setLayout(self.advanced_vlay)
|
||||
self.ncc_box.setLayout(self.ncc_vlay)
|
||||
self.paint_box.setLayout(self.paint_vlay)
|
||||
self.iso_box.setLayout(self.iso_vlay)
|
||||
|
||||
geo_vlay = QtWidgets.QVBoxLayout()
|
||||
geo_vlay.addWidget(self.basic_box)
|
||||
|
@ -1085,7 +1067,6 @@ class ToolsDB2(QtWidgets.QWidget):
|
|||
tools_vlay = QtWidgets.QVBoxLayout()
|
||||
tools_vlay.addWidget(self.ncc_box)
|
||||
tools_vlay.addWidget(self.paint_box)
|
||||
tools_vlay.addWidget(self.iso_box)
|
||||
tools_vlay.addStretch()
|
||||
|
||||
param_hlay.addLayout(geo_vlay)
|
||||
|
@ -1497,7 +1478,7 @@ class ToolsDB2(QtWidgets.QWidget):
|
|||
|
||||
self.ncc_method_combo = FCComboBox()
|
||||
self.ncc_method_combo.addItems(
|
||||
[_("Standard"), _("Seed"), _("Lines"), _("Combo")]
|
||||
[_("Standard"), _("Seed"), _("Lines")]
|
||||
)
|
||||
self.ncc_method_combo.setObjectName("gdb_n_method")
|
||||
|
||||
|
@ -1640,101 +1621,6 @@ class ToolsDB2(QtWidgets.QWidget):
|
|||
self.grid3.addWidget(self.pathconnect_cb, 10, 0)
|
||||
self.grid3.addWidget(self.paintcontour_cb, 10, 1)
|
||||
|
||||
# ###########################################################################
|
||||
# ############### Paint UI form #############################################
|
||||
# ###########################################################################
|
||||
|
||||
self.grid4 = QtWidgets.QGridLayout()
|
||||
self.iso_vlay.addLayout(self.grid4)
|
||||
self.grid4.setColumnStretch(0, 0)
|
||||
self.grid4.setColumnStretch(1, 1)
|
||||
self.iso_vlay.addStretch()
|
||||
|
||||
# Passes
|
||||
passlabel = QtWidgets.QLabel('%s:' % _('Passes'))
|
||||
passlabel.setToolTip(
|
||||
_("Width of the isolation gap in\n"
|
||||
"number (integer) of tool widths.")
|
||||
)
|
||||
self.passes_entry = FCSpinner()
|
||||
self.passes_entry.set_range(1, 999)
|
||||
self.passes_entry.setObjectName("gdb_i_passes")
|
||||
|
||||
self.grid4.addWidget(passlabel, 0, 0)
|
||||
self.grid4.addWidget(self.passes_entry, 0, 1)
|
||||
|
||||
# Overlap Entry
|
||||
overlabel = QtWidgets.QLabel('%s:' % _('Overlap'))
|
||||
overlabel.setToolTip(
|
||||
_("How much (percentage) of the tool width to overlap each tool pass.")
|
||||
)
|
||||
self.iso_overlap_entry = FCDoubleSpinner(suffix='%')
|
||||
self.iso_overlap_entry.set_precision(self.decimals)
|
||||
self.iso_overlap_entry.setWrapping(True)
|
||||
self.iso_overlap_entry.set_range(0.0000, 99.9999)
|
||||
self.iso_overlap_entry.setSingleStep(0.1)
|
||||
self.iso_overlap_entry.setObjectName("gdb_i_overlap")
|
||||
|
||||
self.grid4.addWidget(overlabel, 2, 0)
|
||||
self.grid4.addWidget(self.iso_overlap_entry, 2, 1)
|
||||
|
||||
# Milling Type Radio Button
|
||||
self.milling_type_label = QtWidgets.QLabel('%s:' % _('Milling Type'))
|
||||
self.milling_type_label.setToolTip(
|
||||
_("Milling type when the selected tool is of type: 'iso_op':\n"
|
||||
"- climb / best for precision milling and to reduce tool usage\n"
|
||||
"- conventional / useful when there is no backlash compensation")
|
||||
)
|
||||
|
||||
self.milling_type_radio = RadioSet([{'label': _('Climb'), 'value': 'cl'},
|
||||
{'label': _('Conventional'), 'value': 'cv'}])
|
||||
self.milling_type_radio.setToolTip(
|
||||
_("Milling type when the selected tool is of type: 'iso_op':\n"
|
||||
"- climb / best for precision milling and to reduce tool usage\n"
|
||||
"- conventional / useful when there is no backlash compensation")
|
||||
)
|
||||
self.milling_type_radio.setObjectName("gdb_i_milling_type")
|
||||
|
||||
self.grid4.addWidget(self.milling_type_label, 4, 0)
|
||||
self.grid4.addWidget(self.milling_type_radio, 4, 1)
|
||||
|
||||
# Follow
|
||||
self.follow_label = QtWidgets.QLabel('%s:' % _('Follow'))
|
||||
self.follow_label.setToolTip(
|
||||
_("Generate a 'Follow' geometry.\n"
|
||||
"This means that it will cut through\n"
|
||||
"the middle of the trace.")
|
||||
)
|
||||
|
||||
self.follow_cb = FCCheckBox()
|
||||
self.follow_cb.setToolTip(_("Generate a 'Follow' geometry.\n"
|
||||
"This means that it will cut through\n"
|
||||
"the middle of the trace."))
|
||||
self.follow_cb.setObjectName("gdb_i_follow")
|
||||
|
||||
self.grid4.addWidget(self.follow_label, 6, 0)
|
||||
self.grid4.addWidget(self.follow_cb, 6, 1)
|
||||
|
||||
# Isolation Type
|
||||
self.iso_type_label = QtWidgets.QLabel('%s:' % _('Isolation Type'))
|
||||
self.iso_type_label.setToolTip(
|
||||
_("Choose how the isolation will be executed:\n"
|
||||
"- 'Full' -> complete isolation of polygons\n"
|
||||
"- 'Ext' -> will isolate only on the outside\n"
|
||||
"- 'Int' -> will isolate only on the inside\n"
|
||||
"'Exterior' isolation is almost always possible\n"
|
||||
"(with the right tool) but 'Interior'\n"
|
||||
"isolation can be done only when there is an opening\n"
|
||||
"inside of the polygon (e.g polygon is a 'doughnut' shape).")
|
||||
)
|
||||
self.iso_type_radio = RadioSet([{'label': _('Full'), 'value': 'full'},
|
||||
{'label': _('Ext'), 'value': 'ext'},
|
||||
{'label': _('Int'), 'value': 'int'}])
|
||||
self.iso_type_radio.setObjectName("gdb_i_iso_type")
|
||||
|
||||
self.grid4.addWidget(self.iso_type_label, 8, 0)
|
||||
self.grid4.addWidget(self.iso_type_radio, 8, 1)
|
||||
|
||||
# ####################################################################
|
||||
# ####################################################################
|
||||
# GUI for the lower part of the window
|
||||
|
@ -1792,19 +1678,12 @@ class ToolsDB2(QtWidgets.QWidget):
|
|||
)
|
||||
self.buttons_box.addWidget(self.save_db_btn)
|
||||
|
||||
self.add_tool_from_db = FCButton(_("Transfer the Tool"))
|
||||
self.add_tool_from_db = FCButton(_("Add Tool from Tools DB"))
|
||||
self.add_tool_from_db.setToolTip(
|
||||
_("Insert a new tool in the Tools Table of the\n"
|
||||
"object/application tool after selecting a tool\n"
|
||||
_("Add a new tool in the Tools Table of the\n"
|
||||
"active Geometry object after selecting a tool\n"
|
||||
"in the Tools Database.")
|
||||
)
|
||||
self.add_tool_from_db.setStyleSheet("""
|
||||
QPushButton
|
||||
{
|
||||
font-weight: bold;
|
||||
color: green;
|
||||
}
|
||||
""")
|
||||
self.add_tool_from_db.hide()
|
||||
|
||||
self.cancel_tool_from_db = FCButton(_("Cancel"))
|
||||
|
@ -1814,7 +1693,7 @@ class ToolsDB2(QtWidgets.QWidget):
|
|||
tree_layout.addLayout(hlay)
|
||||
hlay.addWidget(self.add_tool_from_db)
|
||||
hlay.addWidget(self.cancel_tool_from_db)
|
||||
# hlay.addStretch()
|
||||
hlay.addStretch()
|
||||
|
||||
# ##############################################################################
|
||||
# ##############################################################################
|
||||
|
@ -1864,13 +1743,6 @@ class ToolsDB2(QtWidgets.QWidget):
|
|||
"tools_paintmethod": self.paintmethod_combo,
|
||||
"tools_pathconnect": self.pathconnect_cb,
|
||||
"tools_paintcontour": self.paintcontour_cb,
|
||||
|
||||
# Isolation
|
||||
"tools_iso_passes": self.passes_entry,
|
||||
"tools_iso_overlap": self.iso_overlap_entry,
|
||||
"tools_iso_milling_type": self.milling_type_radio,
|
||||
"tools_iso_follow": self.follow_cb,
|
||||
"tools_iso_isotype": self.iso_type_radio
|
||||
}
|
||||
|
||||
self.name2option = {
|
||||
|
@ -1915,13 +1787,6 @@ class ToolsDB2(QtWidgets.QWidget):
|
|||
'gdb_p_method': "tools_paintmethod",
|
||||
'gdb_p_connect': "tools_pathconnect",
|
||||
'gdb_p_contour': "tools_paintcontour",
|
||||
|
||||
# Isolation
|
||||
"gdb_i_passes": "tools_iso_passes",
|
||||
"gdb_i_overlap": "tools_iso_overlap",
|
||||
"gdb_i_milling_type": "tools_iso_milling_type",
|
||||
"gdb_i_follow": "tools_iso_follow",
|
||||
"gdb_i_iso_type": "tools_iso_isotype"
|
||||
}
|
||||
|
||||
self.current_toolid = None
|
||||
|
@ -2022,7 +1887,7 @@ class ToolsDB2(QtWidgets.QWidget):
|
|||
self.blockSignals(False)
|
||||
|
||||
def setup_db_ui(self):
|
||||
filename = self.app.data_path + '\geo_tools_db.FlatDB'
|
||||
filename = self.app.data_path + '/geo_tools_db.FlatDB'
|
||||
|
||||
# load the database tools from the file
|
||||
try:
|
||||
|
@ -2041,7 +1906,7 @@ class ToolsDB2(QtWidgets.QWidget):
|
|||
self.app.inform.emit('[ERROR] %s' % _("Failed to parse Tools DB file."))
|
||||
return
|
||||
|
||||
self.app.inform.emit('[success] %s: %s' % (_("Loaded Tools DB from"), filename))
|
||||
self.app.inform.emit('[success] %s: %s' % (_("Loaded FlatCAM Tools DB from"), filename))
|
||||
|
||||
self.build_db_ui()
|
||||
|
||||
|
@ -2074,23 +1939,21 @@ class ToolsDB2(QtWidgets.QWidget):
|
|||
if self.db_tool_dict:
|
||||
self.storage_to_form(self.db_tool_dict['1'])
|
||||
|
||||
# Enable AppGUI
|
||||
# Enable GUI
|
||||
self.basic_box.setEnabled(True)
|
||||
self.advanced_box.setEnabled(True)
|
||||
self.ncc_box.setEnabled(True)
|
||||
self.paint_box.setEnabled(True)
|
||||
self.iso_box.setEnabled(True)
|
||||
|
||||
self.tree_widget.setCurrentItem(self.tree_widget.topLevelItem(0))
|
||||
# self.tree_widget.setFocus()
|
||||
|
||||
else:
|
||||
# Disable AppGUI
|
||||
# Disable GUI
|
||||
self.basic_box.setEnabled(False)
|
||||
self.advanced_box.setEnabled(False)
|
||||
self.ncc_box.setEnabled(False)
|
||||
self.paint_box.setEnabled(False)
|
||||
self.iso_box.setEnabled(False)
|
||||
else:
|
||||
self.storage_to_form(self.db_tool_dict[str(self.current_toolid)])
|
||||
|
||||
|
@ -2143,27 +2006,10 @@ class ToolsDB2(QtWidgets.QWidget):
|
|||
"tools_paintmethod": self.app.defaults["tools_paintmethod"],
|
||||
"tools_pathconnect": self.app.defaults["tools_pathconnect"],
|
||||
"tools_paintcontour": self.app.defaults["tools_paintcontour"],
|
||||
|
||||
# Isolation
|
||||
"tools_iso_passes": int(self.app.defaults["tools_iso_passes"]),
|
||||
"tools_iso_overlap": float(self.app.defaults["tools_iso_overlap"]),
|
||||
"tools_iso_milling_type": self.app.defaults["tools_iso_milling_type"],
|
||||
"tools_iso_follow": self.app.defaults["tools_iso_follow"],
|
||||
"tools_iso_isotype": self.app.defaults["tools_iso_isotype"],
|
||||
})
|
||||
|
||||
temp = []
|
||||
for k, v in self.db_tool_dict.items():
|
||||
if "new_tool_" in v['name']:
|
||||
temp.append(float(v['name'].rpartition('_')[2]))
|
||||
|
||||
if temp:
|
||||
new_name = "new_tool_%d" % int(max(temp) + 1)
|
||||
else:
|
||||
new_name = "new_tool_1"
|
||||
|
||||
dict_elem = {}
|
||||
dict_elem['name'] = new_name
|
||||
dict_elem['name'] = 'new_tool'
|
||||
if type(self.app.defaults["geometry_cnctooldia"]) == float:
|
||||
dict_elem['tooldia'] = self.app.defaults["geometry_cnctooldia"]
|
||||
else:
|
||||
|
@ -2271,7 +2117,7 @@ class ToolsDB2(QtWidgets.QWidget):
|
|||
l_save=str(self.app.get_last_save_folder()),
|
||||
n=_("Tools_Database"),
|
||||
date=date),
|
||||
ext_filter=filter__)
|
||||
filter=filter__)
|
||||
|
||||
filename = str(filename)
|
||||
|
||||
|
@ -2340,7 +2186,7 @@ class ToolsDB2(QtWidgets.QWidget):
|
|||
self.app.inform.emit('[ERROR] %s' % _("Failed to parse Tools DB file."))
|
||||
return
|
||||
|
||||
self.app.inform.emit('[success] %s: %s' % (_("Loaded Tools DB from"), filename))
|
||||
self.app.inform.emit('[success] %s: %s' % (_("Loaded FlatCAM Tools DB from"), filename))
|
||||
self.build_db_ui()
|
||||
self.update_storage()
|
||||
|
||||
|
@ -2372,18 +2218,6 @@ class ToolsDB2(QtWidgets.QWidget):
|
|||
self.app.tools_db_changed_flag = False
|
||||
self.on_save_tools_db()
|
||||
|
||||
def on_calculate_tooldia(self):
|
||||
if self.shape_combo.get_value() == 'V':
|
||||
tip_dia = float(self.vdia_entry.get_value())
|
||||
half_tip_angle = float(self.vangle_entry.get_value()) / 2.0
|
||||
cut_z = float(self.cutz_entry.get_value())
|
||||
cut_z = -cut_z if cut_z < 0 else cut_z
|
||||
|
||||
# calculated tool diameter so the cut_z parameter is obeyed
|
||||
tool_dia = tip_dia + (2 * cut_z * math.tan(math.radians(half_tip_angle)))
|
||||
|
||||
self.dia_entry.set_value(tool_dia)
|
||||
|
||||
def ui_connect(self):
|
||||
# make sure that we don't make multiple connections to the widgets
|
||||
self.ui_disconnect()
|
||||
|
@ -2413,40 +2247,12 @@ class ToolsDB2(QtWidgets.QWidget):
|
|||
if isinstance(wdg, FCSpinner) or isinstance(wdg, FCDoubleSpinner):
|
||||
wdg.valueChanged.connect(self.update_storage)
|
||||
|
||||
# connect the calculate tooldia method to the controls
|
||||
# if the tool shape is 'V' the tool dia will be calculated to obey Cut Z parameter
|
||||
self.shape_combo.currentIndexChanged.connect(self.on_calculate_tooldia)
|
||||
self.cutz_entry.valueChanged.connect(self.on_calculate_tooldia)
|
||||
self.vdia_entry.valueChanged.connect(self.on_calculate_tooldia)
|
||||
self.vangle_entry.valueChanged.connect(self.on_calculate_tooldia)
|
||||
|
||||
|
||||
def ui_disconnect(self):
|
||||
try:
|
||||
self.name_entry.editingFinished.disconnect(self.update_tree_name)
|
||||
except (TypeError, AttributeError):
|
||||
pass
|
||||
|
||||
try:
|
||||
self.shape_combo.currentIndexChanged.disconnect(self.on_calculate_tooldia)
|
||||
except (TypeError, AttributeError):
|
||||
pass
|
||||
|
||||
try:
|
||||
self.cutz_entry.valueChanged.disconnect(self.on_calculate_tooldia)
|
||||
except (TypeError, AttributeError):
|
||||
pass
|
||||
|
||||
try:
|
||||
self.vdia_entry.valueChanged.disconnect(self.on_calculate_tooldia)
|
||||
except (TypeError, AttributeError):
|
||||
pass
|
||||
|
||||
try:
|
||||
self.vangle_entry.valueChanged.disconnect(self.on_calculate_tooldia)
|
||||
except (TypeError, AttributeError):
|
||||
pass
|
||||
|
||||
for key in self.form_fields:
|
||||
wdg = self.form_fields[key]
|
||||
|
||||
|
@ -2592,18 +2398,6 @@ class ToolsDB2(QtWidgets.QWidget):
|
|||
elif wdg_name == "gdb_p_contour":
|
||||
self.db_tool_dict[tool_id]['data']['tools_paintcontour'] = val
|
||||
|
||||
# Isolation Tool
|
||||
elif wdg_name == "gdb_i_passes":
|
||||
self.db_tool_dict[tool_id]['data']['tools_iso_passes'] = val
|
||||
elif wdg_name == "gdb_i_overlap":
|
||||
self.db_tool_dict[tool_id]['data']['tools_iso_overlap'] = val
|
||||
elif wdg_name == "gdb_i_milling_type":
|
||||
self.db_tool_dict[tool_id]['data']['tools_iso_milling_type'] = val
|
||||
elif wdg_name == "gdb_i_follow":
|
||||
self.db_tool_dict[tool_id]['data']['tools_iso_follow'] = val
|
||||
elif wdg_name == "gdb_i_iso_type":
|
||||
self.db_tool_dict[tool_id]['data']['tools_iso_isotype'] = val
|
||||
|
||||
self.callback_app()
|
||||
|
||||
def on_tool_requested_from_app(self):
|
|
@ -19,10 +19,10 @@ log = logging.getLogger('base')
|
|||
preprocessors = {}
|
||||
|
||||
|
||||
class ABCPreProcRegister(ABCMeta):
|
||||
class ABCPostProcRegister(ABCMeta):
|
||||
# handles preprocessors registration on instantiation
|
||||
def __new__(cls, clsname, bases, attrs):
|
||||
newclass = super(ABCPreProcRegister, cls).__new__(cls, clsname, bases, attrs)
|
||||
newclass = super(ABCPostProcRegister, cls).__new__(cls, clsname, bases, attrs)
|
||||
if object not in bases:
|
||||
if newclass.__name__ in preprocessors:
|
||||
log.warning('Preprocessor %s has been overriden' % newclass.__name__)
|
||||
|
@ -30,7 +30,7 @@ class ABCPreProcRegister(ABCMeta):
|
|||
return newclass
|
||||
|
||||
|
||||
class PreProc(object, metaclass=ABCPreProcRegister):
|
||||
class FlatCAMPostProc(object, metaclass=ABCPostProcRegister):
|
||||
@abstractmethod
|
||||
def start_code(self, p):
|
||||
pass
|
||||
|
@ -76,7 +76,7 @@ class PreProc(object, metaclass=ABCPreProcRegister):
|
|||
pass
|
||||
|
||||
|
||||
class AppPreProcTools(object, metaclass=ABCPreProcRegister):
|
||||
class FlatCAMPostProc_Tools(object, metaclass=ABCPostProcRegister):
|
||||
@abstractmethod
|
||||
def start_code(self, p):
|
||||
pass
|
|
@ -6,12 +6,12 @@
|
|||
# MIT Licence #
|
||||
# ##########################################################
|
||||
|
||||
from AppGUI.GUIElements import FlatCAMActivityView
|
||||
from flatcamGUI.FlatCAMGUI import FlatCAMActivityView
|
||||
from PyQt5 import QtCore
|
||||
import weakref
|
||||
|
||||
import gettext
|
||||
import AppTranslation as fcTranslate
|
||||
import FlatCAMTranslation as fcTranslate
|
||||
import builtins
|
||||
|
||||
fcTranslate.apply_language('strings')
|
|
@ -6,12 +6,13 @@
|
|||
# MIT Licence #
|
||||
# ########################################################## ##
|
||||
|
||||
from PyQt5 import QtCore, QtWidgets
|
||||
from PyQt5 import QtGui, QtCore, QtWidgets, QtWidgets
|
||||
from PyQt5.QtCore import Qt
|
||||
|
||||
from shapely.geometry import Polygon, LineString
|
||||
|
||||
import gettext
|
||||
import AppTranslation as fcTranslate
|
||||
import FlatCAMTranslation as fcTranslate
|
||||
import builtins
|
||||
|
||||
fcTranslate.apply_language('strings')
|
||||
|
@ -19,23 +20,22 @@ if '_' not in builtins.__dict__:
|
|||
_ = gettext.gettext
|
||||
|
||||
|
||||
class AppTool(QtWidgets.QWidget):
|
||||
class FlatCAMTool(QtWidgets.QWidget):
|
||||
|
||||
toolName = "FlatCAM Generic Tool"
|
||||
|
||||
def __init__(self, app, parent=None):
|
||||
"""
|
||||
|
||||
:param app: The application this tool will run in.
|
||||
:type app: App_Main.App
|
||||
:param parent: Qt Parent
|
||||
:return: AppTool
|
||||
:param app: The application this tool will run in.
|
||||
:type app: App
|
||||
:param parent: Qt Parent
|
||||
:return: FlatCAMTool
|
||||
"""
|
||||
QtWidgets.QWidget.__init__(self, parent)
|
||||
|
||||
self.app = app
|
||||
self.decimals = self.app.decimals
|
||||
self.decimals = app.decimals
|
||||
|
||||
QtWidgets.QWidget.__init__(self, parent)
|
||||
# self.setSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Maximum)
|
||||
|
||||
self.layout = QtWidgets.QVBoxLayout()
|
||||
|
@ -87,10 +87,10 @@ class AppTool(QtWidgets.QWidget):
|
|||
|
||||
if self.app.tool_tab_locked is True:
|
||||
return
|
||||
# Remove anything else in the AppGUI
|
||||
# Remove anything else in the GUI
|
||||
self.app.ui.tool_scroll_area.takeWidget()
|
||||
|
||||
# Put ourself in the AppGUI
|
||||
# Put ourself in the GUI
|
||||
self.app.ui.tool_scroll_area.setWidget(self)
|
||||
|
||||
# Switch notebook to tool page
|
||||
|
@ -277,25 +277,22 @@ class AppTool(QtWidgets.QWidget):
|
|||
|
||||
def confirmation_message(self, accepted, minval, maxval):
|
||||
if accepted is False:
|
||||
self.app.inform[str, bool].emit('[WARNING_NOTCL] %s: [%.*f, %.*f]' % (_("Edited value is out of range"),
|
||||
self.decimals,
|
||||
minval,
|
||||
self.decimals,
|
||||
maxval), False)
|
||||
self.app.inform.emit('[WARNING_NOTCL] %s: [%.*f, %.*f]' %
|
||||
(_("Edited value is out of range"), self.decimals, minval, self.decimals, maxval))
|
||||
else:
|
||||
self.app.inform[str, bool].emit('[success] %s' % _("Edited value is within limits."), False)
|
||||
self.app.inform.emit('[success] %s' % _("Edited value is within limits."))
|
||||
|
||||
def confirmation_message_int(self, accepted, minval, maxval):
|
||||
if accepted is False:
|
||||
self.app.inform[str, bool].emit('[WARNING_NOTCL] %s: [%d, %d]' %
|
||||
(_("Edited value is out of range"), minval, maxval), False)
|
||||
self.app.inform.emit('[WARNING_NOTCL] %s: [%d, %d]' %
|
||||
(_("Edited value is out of range"), minval, maxval))
|
||||
else:
|
||||
self.app.inform[str, bool].emit('[success] %s' % _("Edited value is within limits."), False)
|
||||
self.app.inform.emit('[success] %s' % _("Edited value is within limits."))
|
||||
|
||||
def sizeHint(self):
|
||||
"""
|
||||
I've overloaded this just in case I will need to make changes in the future to enforce dimensions
|
||||
:return:
|
||||
"""
|
||||
default_hint_size = super(AppTool, self).sizeHint()
|
||||
default_hint_size = super(FlatCAMTool, self).sizeHint()
|
||||
return QtCore.QSize(default_hint_size.width(), default_hint_size.height())
|
|
@ -106,8 +106,6 @@ def on_language_apply_click(app, restart=False):
|
|||
(_("Are you sure do you want to change the current language to"), name.capitalize()))
|
||||
msgbox.setWindowTitle(_("Apply Language ..."))
|
||||
msgbox.setWindowIcon(QtGui.QIcon(resource_loc + '/language32.png'))
|
||||
msgbox.setIcon(QtWidgets.QMessageBox.Question)
|
||||
|
||||
bt_yes = msgbox.addButton(_("Yes"), QtWidgets.QMessageBox.YesRole)
|
||||
bt_no = msgbox.addButton(_("No"), QtWidgets.QMessageBox.NoRole)
|
||||
|
||||
|
@ -205,8 +203,6 @@ def restart_program(app, ask=None):
|
|||
"Do you want to Save the project?"))
|
||||
msgbox.setWindowTitle(_("Save changes"))
|
||||
msgbox.setWindowIcon(QtGui.QIcon(resource_loc + '/save_as.png'))
|
||||
msgbox.setIcon(QtWidgets.QMessageBox.Question)
|
||||
|
||||
bt_yes = msgbox.addButton(_('Yes'), QtWidgets.QMessageBox.YesRole)
|
||||
bt_no = msgbox.addButton(_('No'), QtWidgets.QMessageBox.NoRole)
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
from PyQt5 import QtCore
|
||||
from AppWorker import Worker
|
||||
from FlatCAMWorker import Worker
|
||||
import multiprocessing
|
||||
|
||||
|
|
@ -1,195 +0,0 @@
|
|||
from PyQt5.QtGui import QPalette
|
||||
from PyQt5 import QtCore, QtWidgets
|
||||
|
||||
import vispy.scene as scene
|
||||
from vispy.scene.visuals import Rectangle, Text
|
||||
from vispy.color import Color
|
||||
|
||||
import sys
|
||||
|
||||
|
||||
class VisPyCanvas(scene.SceneCanvas):
|
||||
|
||||
def __init__(self, config=None):
|
||||
super().__init__(config=config, keys=None)
|
||||
|
||||
self.unfreeze()
|
||||
|
||||
# Colors used by the Scene
|
||||
theme_color = Color('#FFFFFF')
|
||||
tick_color = Color('#000000')
|
||||
back_color = str(QPalette().color(QPalette.Window).name())
|
||||
|
||||
# Central Widget Colors
|
||||
self.central_widget.bgcolor = back_color
|
||||
self.central_widget.border_color = back_color
|
||||
|
||||
self.grid_widget = self.central_widget.add_grid(margin=10)
|
||||
self.grid_widget.spacing = 0
|
||||
|
||||
# TOP Padding
|
||||
top_padding = self.grid_widget.add_widget(row=0, col=0, col_span=2)
|
||||
top_padding.height_max = 0
|
||||
|
||||
# RIGHT Padding
|
||||
right_padding = self.grid_widget.add_widget(row=0, col=2, row_span=2)
|
||||
right_padding.width_max = 0
|
||||
|
||||
# X Axis
|
||||
self.xaxis = scene.AxisWidget(
|
||||
orientation='bottom', axis_color=tick_color, text_color=tick_color,
|
||||
font_size=8, axis_width=1,
|
||||
anchors=['center', 'bottom']
|
||||
)
|
||||
self.xaxis.height_max = 30
|
||||
self.grid_widget.add_widget(self.xaxis, row=2, col=1)
|
||||
|
||||
# Y Axis
|
||||
self.yaxis = scene.AxisWidget(
|
||||
orientation='left', axis_color=tick_color, text_color=tick_color,
|
||||
font_size=8, axis_width=1
|
||||
)
|
||||
self.yaxis.width_max = 55
|
||||
self.grid_widget.add_widget(self.yaxis, row=1, col=0)
|
||||
|
||||
# View & Camera
|
||||
self.view = self.grid_widget.add_view(row=1, col=1, border_color=tick_color,
|
||||
bgcolor=theme_color)
|
||||
self.view.camera = scene.PanZoomCamera(aspect=1, rect=(-25, -25, 150, 150))
|
||||
|
||||
self.xaxis.link_view(self.view)
|
||||
self.yaxis.link_view(self.view)
|
||||
|
||||
self.grid = scene.GridLines(parent=self.view.scene, color='dimgray')
|
||||
self.grid.set_gl_state(depth_test=False)
|
||||
|
||||
self.rect = Rectangle(center=(65,30), color=Color('#0000FF10'), border_color=Color('#0000FF10'),
|
||||
width=120, height=50, radius=[5, 5, 5, 5], parent=self.view)
|
||||
self.rect.set_gl_state(depth_test=False)
|
||||
|
||||
self.text = Text('', parent=self.view, color='black', pos=(5, 30), method='gpu', anchor_x='left')
|
||||
self.text.font_size = 8
|
||||
self.text.text = 'Coordinates:\nX: %s\nY: %s' % ('0.0000', '0.0000')
|
||||
|
||||
self.freeze()
|
||||
|
||||
# self.measure_fps()
|
||||
|
||||
|
||||
class PlotCanvas(QtCore.QObject):
|
||||
|
||||
def __init__(self, container, my_app):
|
||||
"""
|
||||
The constructor configures the VisPy figure that
|
||||
will contain all plots, creates the base axes and connects
|
||||
events to the plotting area.
|
||||
|
||||
:param container: The parent container in which to draw plots.
|
||||
:rtype: PlotCanvas
|
||||
"""
|
||||
|
||||
super().__init__()
|
||||
|
||||
# VisPyCanvas instance
|
||||
self.vispy_canvas = VisPyCanvas()
|
||||
|
||||
self.vispy_canvas.unfreeze()
|
||||
|
||||
self.my_app = my_app
|
||||
|
||||
# Parent container
|
||||
self.container = container
|
||||
|
||||
# <VisPyCanvas>
|
||||
self.vispy_canvas.create_native()
|
||||
self.vispy_canvas.native.setParent(self.my_app.ui)
|
||||
|
||||
# <QtCore.QObject>
|
||||
self.container.addWidget(self.vispy_canvas.native)
|
||||
|
||||
# add two Infinite Lines to act as markers for the X,Y axis
|
||||
self.v_line = scene.visuals.InfiniteLine(
|
||||
pos=0, color=(0.0, 0.0, 1.0, 0.3), vertical=True,
|
||||
parent=self.vispy_canvas.view.scene)
|
||||
|
||||
self.h_line = scene.visuals.InfiniteLine(
|
||||
pos=0, color=(0.00, 0.0, 1.0, 0.3), vertical=False,
|
||||
parent=self.vispy_canvas.view.scene)
|
||||
|
||||
self.vispy_canvas.freeze()
|
||||
|
||||
def event_connect(self, event, callback):
|
||||
getattr(self.vispy_canvas.events, event).connect(callback)
|
||||
|
||||
def event_disconnect(self, event, callback):
|
||||
getattr(self.vispy_canvas.events, event).disconnect(callback)
|
||||
|
||||
def translate_coords(self, pos):
|
||||
"""
|
||||
Translate pixels to canvas units.
|
||||
"""
|
||||
tr = self.vispy_canvas.grid.get_transform('canvas', 'visual')
|
||||
return tr.map(pos)
|
||||
|
||||
|
||||
class MyGui(QtWidgets.QMainWindow):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
self.setWindowTitle("VisPy Test")
|
||||
|
||||
# add Menubar
|
||||
self.menu = self.menuBar()
|
||||
self.menufile = self.menu.addMenu("File")
|
||||
self.menuedit = self.menu.addMenu("Edit")
|
||||
self.menufhelp = self.menu.addMenu("Help")
|
||||
|
||||
# add a Toolbar
|
||||
self.file_toolbar = QtWidgets.QToolBar("File Toolbar")
|
||||
self.addToolBar(self.file_toolbar)
|
||||
self.button = self.file_toolbar.addAction("Open")
|
||||
|
||||
# add Central Widget
|
||||
self.c_widget = QtWidgets.QWidget()
|
||||
self.central_layout = QtWidgets.QVBoxLayout()
|
||||
self.c_widget.setLayout(self.central_layout)
|
||||
self.setCentralWidget(self.c_widget)
|
||||
|
||||
# add InfoBar
|
||||
# self.infobar = self.statusBar()
|
||||
# self.position_label = QtWidgets.QLabel("Position: X: 0.0000\tY: 0.0000")
|
||||
# self.infobar.addWidget(self.position_label)
|
||||
|
||||
|
||||
class MyApp(QtCore.QObject):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
self.ui = MyGui()
|
||||
self.plot = PlotCanvas(container=self.ui.central_layout, my_app=self)
|
||||
|
||||
self.ui.show()
|
||||
|
||||
self.plot.event_connect(event="mouse_move", callback=self.on_mouse_move)
|
||||
|
||||
def on_mouse_move(self, event):
|
||||
cursor_pos = event.pos
|
||||
|
||||
pos_canvas = self.plot.translate_coords(cursor_pos)
|
||||
|
||||
# we don't need all the info in the tuple returned by the translate_coords()
|
||||
# only first 2 elements
|
||||
pos_canvas = [pos_canvas[0], pos_canvas[1]]
|
||||
self.ui.position_label.setText("Position: X: %.4f\tY: %.4f" % (pos_canvas[0], pos_canvas[1]))
|
||||
# pos_text = 'Coordinates: \nX: {:<7.4f}\nY: {:<7.4f}'.format(pos_canvas[0], pos_canvas[1])
|
||||
pos_text = 'Coordinates: \nX: {:<.4f}\nY: {:<.4f}'.format(pos_canvas[0], pos_canvas[1])
|
||||
self.plot.vispy_canvas.text.text = pos_text
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
app = QtWidgets.QApplication(sys.argv)
|
||||
|
||||
m_app = MyApp()
|
||||
sys.exit(app.exec_())
|
Before Width: | Height: | Size: 404 B |
Before Width: | Height: | Size: 556 B |
Before Width: | Height: | Size: 9.6 KiB |
Before Width: | Height: | Size: 349 B |
Before Width: | Height: | Size: 174 B |
Before Width: | Height: | Size: 556 B |
Before Width: | Height: | Size: 20 KiB |
Before Width: | Height: | Size: 325 B |
Before Width: | Height: | Size: 386 B After Width: | Height: | Size: 510 B |
Before Width: | Height: | Size: 546 B After Width: | Height: | Size: 716 B |
Before Width: | Height: | Size: 18 KiB |
Before Width: | Height: | Size: 137 B |
Before Width: | Height: | Size: 224 B |
Before Width: | Height: | Size: 156 B |
Before Width: | Height: | Size: 425 B After Width: | Height: | Size: 554 B |
Before Width: | Height: | Size: 738 B |
Before Width: | Height: | Size: 163 B |
Before Width: | Height: | Size: 386 B After Width: | Height: | Size: 504 B |
Before Width: | Height: | Size: 541 B After Width: | Height: | Size: 700 B |
Before Width: | Height: | Size: 9.3 KiB |
Before Width: | Height: | Size: 898 B After Width: | Height: | Size: 904 B |
Before Width: | Height: | Size: 901 B |
Before Width: | Height: | Size: 382 B |
Before Width: | Height: | Size: 631 B |
Before Width: | Height: | Size: 156 B |
Before Width: | Height: | Size: 420 B After Width: | Height: | Size: 553 B |
Before Width: | Height: | Size: 597 B |
Before Width: | Height: | Size: 492 B |
62
defaults.py
|
@ -2,16 +2,16 @@ import os
|
|||
import stat
|
||||
import sys
|
||||
from copy import deepcopy
|
||||
from Common import LoudDict
|
||||
from FlatCAMCommon import LoudDict
|
||||
from camlib import to_dict, CNCjob, Geometry
|
||||
import simplejson
|
||||
import logging
|
||||
import gettext
|
||||
import AppTranslation as fcTranslate
|
||||
import FlatCAMTranslation as fcTranslate
|
||||
import builtins
|
||||
|
||||
from AppParsers.ParseExcellon import Excellon
|
||||
from AppParsers.ParseGerber import Gerber
|
||||
from flatcamParsers.ParseExcellon import Excellon
|
||||
from flatcamParsers.ParseGerber import Gerber
|
||||
|
||||
fcTranslate.apply_language('strings')
|
||||
if '_' not in builtins.__dict__:
|
||||
|
@ -43,7 +43,6 @@ class FlatCAMDefaults:
|
|||
|
||||
# General
|
||||
"global_graphic_engine": '3D',
|
||||
"global_hud": True,
|
||||
"global_app_level": 'b',
|
||||
"global_portable": False,
|
||||
"global_language": 'English',
|
||||
|
@ -172,6 +171,12 @@ class FlatCAMDefaults:
|
|||
"All Files (*.*)",
|
||||
|
||||
# Gerber Options
|
||||
"gerber_isotooldia": 0.1,
|
||||
"gerber_isopasses": 1,
|
||||
"gerber_isooverlap": 10,
|
||||
"gerber_milling_type": "cl",
|
||||
"gerber_combine_passes": False,
|
||||
"gerber_iso_scope": 'all',
|
||||
"gerber_noncoppermargin": 0.1,
|
||||
"gerber_noncopperrounded": False,
|
||||
"gerber_bboxmargin": 0.1,
|
||||
|
@ -182,6 +187,11 @@ class FlatCAMDefaults:
|
|||
"gerber_aperture_scale_factor": 1.0,
|
||||
"gerber_aperture_buffer_factor": 0.0,
|
||||
"gerber_follow": False,
|
||||
"gerber_tool_type": 'circular',
|
||||
"gerber_vtipdia": 0.1,
|
||||
"gerber_vtipangle": 30,
|
||||
"gerber_vcutz": -0.05,
|
||||
"gerber_iso_type": "full",
|
||||
"gerber_buffering": "full",
|
||||
"gerber_simplification": False,
|
||||
"gerber_simp_tolerance": 0.0005,
|
||||
|
@ -212,7 +222,6 @@ class FlatCAMDefaults:
|
|||
# Excellon General
|
||||
"excellon_plot": True,
|
||||
"excellon_solid": True,
|
||||
"excellon_multicolored": False,
|
||||
"excellon_format_upper_in": 2,
|
||||
"excellon_format_lower_in": 4,
|
||||
"excellon_format_upper_mm": 3,
|
||||
|
@ -301,7 +310,6 @@ class FlatCAMDefaults:
|
|||
|
||||
# Geometry General
|
||||
"geometry_plot": True,
|
||||
"geometry_multicolored": False,
|
||||
"geometry_circle_steps": 64,
|
||||
"geometry_cnctooldia": "2.4",
|
||||
"geometry_plot_line": "#FF0000",
|
||||
|
@ -382,28 +390,6 @@ class FlatCAMDefaults:
|
|||
"cncjob_annotation_fontsize": 9,
|
||||
"cncjob_annotation_fontcolor": '#990000',
|
||||
|
||||
# Isolation Routing Tool
|
||||
"tools_iso_tooldia": "0.1",
|
||||
"tools_iso_order": 'rev',
|
||||
"tools_iso_tool_type": 'C1',
|
||||
"tools_iso_tool_vtipdia": 0.1,
|
||||
"tools_iso_tool_vtipangle": 30,
|
||||
"tools_iso_tool_cutz": -0.05,
|
||||
"tools_iso_newdia": 0.1,
|
||||
|
||||
"tools_iso_passes": 1,
|
||||
"tools_iso_overlap": 10,
|
||||
"tools_iso_milling_type": "cl",
|
||||
"tools_iso_follow": False,
|
||||
"tools_iso_isotype": "full",
|
||||
|
||||
"tools_iso_rest": False,
|
||||
"tools_iso_combine_passes": False,
|
||||
"tools_iso_isoexcept": False,
|
||||
"tools_iso_selection": _("All"),
|
||||
"tools_iso_area_shape": "square",
|
||||
"tools_iso_plotting": 'normal',
|
||||
|
||||
# NCC Tool
|
||||
"tools_ncctools": "1.0, 0.5",
|
||||
"tools_nccorder": 'rev',
|
||||
|
@ -418,13 +404,13 @@ class FlatCAMDefaults:
|
|||
"tools_ncc_offset_value": 0.0000,
|
||||
"tools_nccref": _('Itself'),
|
||||
"tools_ncc_area_shape": "square",
|
||||
"tools_ncc_plotting": 'normal',
|
||||
"tools_nccmilling_type": 'cl',
|
||||
"tools_ncctool_type": 'C1',
|
||||
"tools_ncccutz": -0.05,
|
||||
"tools_ncctipdia": 0.1,
|
||||
"tools_ncctipangle": 30,
|
||||
"tools_nccnewdia": 0.1,
|
||||
"tools_ncc_plotting": 'normal',
|
||||
|
||||
# Cutout Tool
|
||||
"tools_cutouttooldia": 2.4,
|
||||
|
@ -443,7 +429,7 @@ class FlatCAMDefaults:
|
|||
"tools_paintoverlap": 20,
|
||||
"tools_paintmargin": 0.0,
|
||||
"tools_paintmethod": _("Seed"),
|
||||
"tools_selectmethod": _("All"),
|
||||
"tools_selectmethod": _("All Polygons"),
|
||||
"tools_paint_area_shape": "square",
|
||||
"tools_pathconnect": True,
|
||||
"tools_paintcontour": True,
|
||||
|
@ -538,12 +524,6 @@ class FlatCAMDefaults:
|
|||
# Distance Tool
|
||||
"tools_dist_snap_center": False,
|
||||
|
||||
# Corner Markers Tool
|
||||
|
||||
"tools_corners_thickness": 0.1,
|
||||
"tools_corners_length": 3.0,
|
||||
"tools_corners_margin": 0.0,
|
||||
|
||||
# ########################################################################################################
|
||||
# ################################ TOOLS 2 ###############################################################
|
||||
# ########################################################################################################
|
||||
|
@ -697,15 +677,13 @@ class FlatCAMDefaults:
|
|||
}
|
||||
|
||||
@classmethod
|
||||
def save_factory_defaults(cls, file_path: str, version: float):
|
||||
def save_factory_defaults(cls, file_path: str):
|
||||
"""Writes the factory defaults to a file at the given path, overwriting any existing file."""
|
||||
# Delete any existing factory defaults file
|
||||
if os.path.isfile(file_path):
|
||||
os.chmod(file_path, stat.S_IRWXO | stat.S_IWRITE | stat.S_IWGRP)
|
||||
os.remove(file_path)
|
||||
|
||||
cls.factory_defaults['version'] = version
|
||||
|
||||
try:
|
||||
# recreate a new factory defaults file and save the factory defaults data into it
|
||||
f_f_def_s = open(file_path, "w")
|
||||
|
@ -786,8 +764,8 @@ class FlatCAMDefaults:
|
|||
if defaults is None:
|
||||
return
|
||||
|
||||
# Perform migration if necessary but only if the defaults dict is not empty
|
||||
if self.__is_old_defaults(defaults) and defaults:
|
||||
# Perform migration if necessary
|
||||
if self.__is_old_defaults(defaults):
|
||||
self.old_defaults_found = True
|
||||
defaults = self.__migrate_old_defaults(defaults=defaults)
|
||||
else:
|
||||
|
|
|
@ -9,9 +9,9 @@ from PyQt5 import QtGui, QtCore, QtWidgets
|
|||
from PyQt5.QtCore import Qt, QSettings
|
||||
|
||||
from camlib import distance, arc, FlatCAMRTreeStorage
|
||||
from AppGUI.GUIElements import FCEntry, FCComboBox, FCTable, FCDoubleSpinner, RadioSet, FCSpinner
|
||||
from AppEditors.FlatCAMGeoEditor import FCShapeTool, DrawTool, DrawToolShape, DrawToolUtilityShape, FlatCAMGeoEditor
|
||||
from AppParsers.ParseExcellon import Excellon
|
||||
from flatcamGUI.GUIElements import FCEntry, FCComboBox, FCTable, FCDoubleSpinner, RadioSet, FCSpinner
|
||||
from flatcamEditors.FlatCAMGeoEditor import FCShapeTool, DrawTool, DrawToolShape, DrawToolUtilityShape, FlatCAMGeoEditor
|
||||
from flatcamParsers.ParseExcellon import Excellon
|
||||
|
||||
from shapely.geometry import LineString, LinearRing, MultiLineString, Polygon, MultiPolygon, Point
|
||||
import shapely.affinity as affinity
|
||||
|
@ -26,7 +26,7 @@ import logging
|
|||
from copy import deepcopy
|
||||
|
||||
import gettext
|
||||
import AppTranslation as fcTranslate
|
||||
import FlatCAMTranslation as fcTranslate
|
||||
import builtins
|
||||
|
||||
fcTranslate.apply_language('strings')
|
||||
|
@ -2123,7 +2123,7 @@ class FlatCAMExcEditor(QtCore.QObject):
|
|||
else:
|
||||
self.tool_shape = self.app.plotcanvas.new_shape_collection(layers=1)
|
||||
else:
|
||||
from AppGUI.PlotCanvasLegacy import ShapeCollectionLegacy
|
||||
from flatcamGUI.PlotCanvasLegacy import ShapeCollectionLegacy
|
||||
self.shapes = ShapeCollectionLegacy(obj=self, app=self.app, name='shapes_exc_editor')
|
||||
self.tool_shape = ShapeCollectionLegacy(obj=self, app=self.app, name='tool_shapes_exc_editor')
|
||||
|
||||
|
@ -2239,7 +2239,7 @@ class FlatCAMExcEditor(QtCore.QObject):
|
|||
|
||||
# store the status of the editor so the Delete at object level will not work until the edit is finished
|
||||
self.editor_active = False
|
||||
log.debug("Initialization of the Excellon Editor is finished ...")
|
||||
log.debug("Initialization of the FlatCAM Excellon Editor is finished ...")
|
||||
|
||||
def pool_recreated(self, pool):
|
||||
self.shapes.pool = pool
|
||||
|
@ -2312,7 +2312,7 @@ class FlatCAMExcEditor(QtCore.QObject):
|
|||
tool_dia = float('%.*f' % (self.decimals, v['C']))
|
||||
self.tool2tooldia[int(k)] = tool_dia
|
||||
|
||||
# Init AppGUI
|
||||
# Init GUI
|
||||
self.addtool_entry.set_value(float(self.app.defaults['excellon_editor_newdia']))
|
||||
self.drill_array_size_entry.set_value(int(self.app.defaults['excellon_editor_array_size']))
|
||||
self.drill_axis_radio.set_value(self.app.defaults['excellon_editor_lin_dir'])
|
||||
|
@ -2819,8 +2819,10 @@ class FlatCAMExcEditor(QtCore.QObject):
|
|||
self.tool_shape.enabled = True
|
||||
# self.app.app_cursor.enabled = True
|
||||
|
||||
self.app.ui.corner_snap_btn.setVisible(True)
|
||||
self.app.ui.snap_max_dist_entry.setEnabled(True)
|
||||
self.app.ui.corner_snap_btn.setEnabled(True)
|
||||
self.app.ui.snap_magnet.setVisible(True)
|
||||
self.app.ui.corner_snap_btn.setVisible(True)
|
||||
|
||||
self.app.ui.exc_editor_menu.setDisabled(False)
|
||||
self.app.ui.exc_editor_menu.menuAction().setVisible(True)
|
||||
|
@ -2830,11 +2832,12 @@ class FlatCAMExcEditor(QtCore.QObject):
|
|||
|
||||
self.app.ui.exc_edit_toolbar.setDisabled(False)
|
||||
self.app.ui.exc_edit_toolbar.setVisible(True)
|
||||
# self.app.ui.status_toolbar.setDisabled(False)
|
||||
# self.app.ui.snap_toolbar.setDisabled(False)
|
||||
|
||||
# start with GRID toolbar activated
|
||||
if self.app.ui.grid_snap_btn.isChecked() is False:
|
||||
self.app.ui.grid_snap_btn.trigger()
|
||||
self.app.ui.on_grid_snap_triggered(state=True)
|
||||
|
||||
self.app.ui.popmenu_disable.setVisible(False)
|
||||
self.app.ui.cmenu_newmenu.menuAction().setVisible(False)
|
||||
|
@ -2866,8 +2869,30 @@ class FlatCAMExcEditor(QtCore.QObject):
|
|||
self.clear()
|
||||
self.app.ui.exc_edit_toolbar.setDisabled(True)
|
||||
|
||||
self.app.ui.corner_snap_btn.setVisible(False)
|
||||
self.app.ui.snap_magnet.setVisible(False)
|
||||
settings = QSettings("Open Source", "FlatCAM")
|
||||
if settings.contains("layout"):
|
||||
layout = settings.value('layout', type=str)
|
||||
if layout == 'standard':
|
||||
# self.app.ui.exc_edit_toolbar.setVisible(False)
|
||||
|
||||
self.app.ui.snap_max_dist_entry.setEnabled(False)
|
||||
self.app.ui.corner_snap_btn.setEnabled(False)
|
||||
self.app.ui.snap_magnet.setVisible(False)
|
||||
self.app.ui.corner_snap_btn.setVisible(False)
|
||||
else:
|
||||
# self.app.ui.exc_edit_toolbar.setVisible(True)
|
||||
|
||||
self.app.ui.snap_max_dist_entry.setEnabled(False)
|
||||
self.app.ui.corner_snap_btn.setEnabled(False)
|
||||
self.app.ui.snap_magnet.setVisible(True)
|
||||
self.app.ui.corner_snap_btn.setVisible(True)
|
||||
else:
|
||||
# self.app.ui.exc_edit_toolbar.setVisible(False)
|
||||
|
||||
self.app.ui.snap_max_dist_entry.setEnabled(False)
|
||||
self.app.ui.corner_snap_btn.setEnabled(False)
|
||||
self.app.ui.snap_magnet.setVisible(False)
|
||||
self.app.ui.corner_snap_btn.setVisible(False)
|
||||
|
||||
# set the Editor Toolbar visibility to what was before entering in the Editor
|
||||
self.app.ui.exc_edit_toolbar.setVisible(False) if self.toolbar_old_state is False \
|
||||
|
@ -3043,7 +3068,7 @@ class FlatCAMExcEditor(QtCore.QObject):
|
|||
|
||||
self.set_ui()
|
||||
|
||||
# now that we hava data, create the AppGUI interface and add it to the Tool Tab
|
||||
# now that we hava data, create the GUI interface and add it to the Tool Tab
|
||||
self.build_ui(first_run=True)
|
||||
|
||||
# we activate this after the initial build as we don't need to see the tool been populated
|
||||
|
@ -3336,17 +3361,15 @@ class FlatCAMExcEditor(QtCore.QObject):
|
|||
with self.app.proc_container.new(_("Creating Excellon.")):
|
||||
|
||||
try:
|
||||
edited_obj = self.app.app_obj.new_object("excellon", outname, obj_init)
|
||||
edited_obj = self.app.new_object("excellon", outname, obj_init)
|
||||
edited_obj.source_file = self.app.export_excellon(obj_name=edited_obj.options['name'],
|
||||
local_use=edited_obj,
|
||||
filename=None,
|
||||
use_thread=False)
|
||||
except Exception as e:
|
||||
self.deactivate()
|
||||
log.error("Error on Edited object creation: %s" % str(e))
|
||||
return
|
||||
|
||||
self.deactivate()
|
||||
self.app.inform.emit('[success] %s' % _("Excellon editing finished."))
|
||||
|
||||
def on_tool_select(self, tool):
|
||||
|
@ -3440,8 +3463,8 @@ class FlatCAMExcEditor(QtCore.QObject):
|
|||
self.pos = (self.pos[0], self.pos[1])
|
||||
|
||||
if event.button == 1:
|
||||
# self.app.ui.rel_position_label.setText("<b>Dx</b>: %.4f <b>Dy</b>: "
|
||||
# "%.4f " % (0, 0))
|
||||
self.app.ui.rel_position_label.setText("<b>Dx</b>: %.4f <b>Dy</b>: "
|
||||
"%.4f " % (0, 0))
|
||||
|
||||
# Selection with left mouse button
|
||||
if self.active_tool is not None and event.button == 1:
|
||||
|
@ -3778,22 +3801,18 @@ class FlatCAMExcEditor(QtCore.QObject):
|
|||
self.snap_x = x
|
||||
self.snap_y = y
|
||||
|
||||
# update the position label in the infobar since the APP mouse event handlers are disconnected
|
||||
self.app.ui.position_label.setText(" <b>X</b>: %.4f "
|
||||
"<b>Y</b>: %.4f" % (x, y))
|
||||
|
||||
if self.pos is None:
|
||||
self.pos = (0, 0)
|
||||
self.app.dx = x - self.pos[0]
|
||||
self.app.dy = y - self.pos[1]
|
||||
|
||||
# # update the position label in the infobar since the APP mouse event handlers are disconnected
|
||||
self.app.ui.position_label.setText(" <b>X</b>: %.4f "
|
||||
"<b>Y</b>: %.4f " % (x, y))
|
||||
# # update the reference position label in the infobar since the APP mouse event handlers are disconnected
|
||||
# self.app.ui.rel_position_label.setText("<b>Dx</b>: %.4f <b>Dy</b>: "
|
||||
# "%.4f " % (self.app.dx, self.app.dy))
|
||||
|
||||
units = self.app.defaults["units"].lower()
|
||||
self.app.plotcanvas.text_hud.text = \
|
||||
'Dx:\t{:<.4f} [{:s}]\nDy:\t{:<.4f} [{:s}]\n\nX: \t{:<.4f} [{:s}]\nY: \t{:<.4f} [{:s}]'.format(
|
||||
self.app.dx, units, self.app.dy, units, x, units, y, units)
|
||||
# update the reference position label in the infobar since the APP mouse event handlers are disconnected
|
||||
self.app.ui.rel_position_label.setText("<b>Dx</b>: %.4f <b>Dy</b>: "
|
||||
"%.4f " % (self.app.dx, self.app.dy))
|
||||
|
||||
# ## Utility geometry (animated)
|
||||
self.update_utility_geometry(data=(x, y))
|
||||
|
@ -4026,7 +4045,7 @@ class FlatCAMExcEditor(QtCore.QObject):
|
|||
|
||||
def select_tool(self, toolname):
|
||||
"""
|
||||
Selects a drawing tool. Impacts the object and AppGUI.
|
||||
Selects a drawing tool. Impacts the object and GUI.
|
||||
|
||||
:param toolname: Name of the tool.
|
||||
:return: None
|
|
@ -15,10 +15,11 @@ from PyQt5 import QtGui, QtCore, QtWidgets
|
|||
from PyQt5.QtCore import Qt, QSettings
|
||||
|
||||
from camlib import distance, arc, three_point_circle, Geometry, FlatCAMRTreeStorage
|
||||
from AppTool import AppTool
|
||||
from AppGUI.GUIElements import OptionalInputSection, FCCheckBox, FCEntry, FCComboBox, FCTextAreaRich, \
|
||||
FCDoubleSpinner, FCButton, FCInputDialog, FCTree
|
||||
from AppParsers.ParseFont import *
|
||||
from FlatCAMTool import FlatCAMTool
|
||||
from flatcamGUI.ObjectUI import RadioSet
|
||||
from flatcamGUI.GUIElements import OptionalInputSection, FCCheckBox, FCEntry, FCComboBox, FCTextAreaRich, \
|
||||
FCTable, FCDoubleSpinner, FCButton, EvalEntry2, FCInputDialog, FCTree
|
||||
from flatcamParsers.ParseFont import *
|
||||
|
||||
from shapely.geometry import LineString, LinearRing, MultiLineString, Polygon, MultiPolygon
|
||||
from shapely.ops import cascaded_union, unary_union, linemerge
|
||||
|
@ -33,7 +34,7 @@ from rtree import index as rtindex
|
|||
from copy import deepcopy
|
||||
# from vispy.io import read_png
|
||||
import gettext
|
||||
import AppTranslation as fcTranslate
|
||||
import FlatCAMTranslation as fcTranslate
|
||||
import builtins
|
||||
|
||||
fcTranslate.apply_language('strings')
|
||||
|
@ -41,7 +42,7 @@ if '_' not in builtins.__dict__:
|
|||
_ = gettext.gettext
|
||||
|
||||
|
||||
class BufferSelectionTool(AppTool):
|
||||
class BufferSelectionTool(FlatCAMTool):
|
||||
"""
|
||||
Simple input for buffer distance.
|
||||
"""
|
||||
|
@ -49,7 +50,7 @@ class BufferSelectionTool(AppTool):
|
|||
toolName = "Buffer Selection"
|
||||
|
||||
def __init__(self, app, draw_app):
|
||||
AppTool.__init__(self, app)
|
||||
FlatCAMTool.__init__(self, app)
|
||||
|
||||
self.draw_app = draw_app
|
||||
self.decimals = app.decimals
|
||||
|
@ -117,12 +118,12 @@ class BufferSelectionTool(AppTool):
|
|||
self.buffer_int_button.clicked.connect(self.on_buffer_int)
|
||||
self.buffer_ext_button.clicked.connect(self.on_buffer_ext)
|
||||
|
||||
# Init AppGUI
|
||||
# Init GUI
|
||||
self.buffer_distance_entry.set_value(0.01)
|
||||
|
||||
def run(self):
|
||||
self.app.defaults.report_usage("Geo Editor ToolBuffer()")
|
||||
AppTool.run(self)
|
||||
FlatCAMTool.run(self)
|
||||
|
||||
# if the splitter us hidden, display it
|
||||
if self.app.ui.splitter.sizes()[0] == 0:
|
||||
|
@ -186,7 +187,7 @@ class BufferSelectionTool(AppTool):
|
|||
self.app.ui.notebook.setCurrentWidget(self.app.ui.project_tab)
|
||||
|
||||
|
||||
class TextInputTool(AppTool):
|
||||
class TextInputTool(FlatCAMTool):
|
||||
"""
|
||||
Simple input for buffer distance.
|
||||
"""
|
||||
|
@ -194,7 +195,7 @@ class TextInputTool(AppTool):
|
|||
toolName = "Text Input Tool"
|
||||
|
||||
def __init__(self, app):
|
||||
AppTool.__init__(self, app)
|
||||
FlatCAMTool.__init__(self, app)
|
||||
|
||||
self.app = app
|
||||
self.text_path = []
|
||||
|
@ -339,7 +340,7 @@ class TextInputTool(AppTool):
|
|||
|
||||
def run(self):
|
||||
self.app.defaults.report_usage("Geo Editor TextInputTool()")
|
||||
AppTool.run(self)
|
||||
FlatCAMTool.run(self)
|
||||
|
||||
# if the splitter us hidden, display it
|
||||
if self.app.ui.splitter.sizes()[0] == 0:
|
||||
|
@ -404,7 +405,7 @@ class TextInputTool(AppTool):
|
|||
self.app.ui.notebook.setTabText(2, _("Tool"))
|
||||
|
||||
|
||||
class PaintOptionsTool(AppTool):
|
||||
class PaintOptionsTool(FlatCAMTool):
|
||||
"""
|
||||
Inputs to specify how to paint the selected polygons.
|
||||
"""
|
||||
|
@ -412,7 +413,7 @@ class PaintOptionsTool(AppTool):
|
|||
toolName = "Paint Tool"
|
||||
|
||||
def __init__(self, app, fcdraw):
|
||||
AppTool.__init__(self, app)
|
||||
FlatCAMTool.__init__(self, app)
|
||||
|
||||
self.app = app
|
||||
self.fcdraw = fcdraw
|
||||
|
@ -537,7 +538,7 @@ class PaintOptionsTool(AppTool):
|
|||
|
||||
def run(self):
|
||||
self.app.defaults.report_usage("Geo Editor ToolPaint()")
|
||||
AppTool.run(self)
|
||||
FlatCAMTool.run(self)
|
||||
|
||||
# if the splitter us hidden, display it
|
||||
if self.app.ui.splitter.sizes()[0] == 0:
|
||||
|
@ -546,7 +547,7 @@ class PaintOptionsTool(AppTool):
|
|||
self.app.ui.notebook.setTabText(2, _("Paint Tool"))
|
||||
|
||||
def set_tool_ui(self):
|
||||
# Init AppGUI
|
||||
# Init GUI
|
||||
if self.app.defaults["tools_painttooldia"]:
|
||||
self.painttooldia_entry.set_value(self.app.defaults["tools_painttooldia"])
|
||||
else:
|
||||
|
@ -598,7 +599,7 @@ class PaintOptionsTool(AppTool):
|
|||
self.app.ui.splitter.setSizes([0, 1])
|
||||
|
||||
|
||||
class TransformEditorTool(AppTool):
|
||||
class TransformEditorTool(FlatCAMTool):
|
||||
"""
|
||||
Inputs to specify how to paint the selected polygons.
|
||||
"""
|
||||
|
@ -611,7 +612,7 @@ class TransformEditorTool(AppTool):
|
|||
offsetName = _("Offset")
|
||||
|
||||
def __init__(self, app, draw_app):
|
||||
AppTool.__init__(self, app)
|
||||
FlatCAMTool.__init__(self, app)
|
||||
|
||||
self.app = app
|
||||
self.draw_app = draw_app
|
||||
|
@ -980,7 +981,7 @@ class TransformEditorTool(AppTool):
|
|||
|
||||
def run(self):
|
||||
self.app.defaults.report_usage("Geo Editor Transform Tool()")
|
||||
AppTool.run(self)
|
||||
FlatCAMTool.run(self)
|
||||
self.set_tool_ui()
|
||||
|
||||
# if the splitter us hidden, display it
|
||||
|
@ -990,7 +991,7 @@ class TransformEditorTool(AppTool):
|
|||
self.app.ui.notebook.setTabText(2, _("Transform Tool"))
|
||||
|
||||
def install(self, icon=None, separator=None, **kwargs):
|
||||
AppTool.install(self, icon, separator, shortcut='Alt+T', **kwargs)
|
||||
FlatCAMTool.install(self, icon, separator, shortcut='Alt+T', **kwargs)
|
||||
|
||||
def set_tool_ui(self):
|
||||
# Initialize form
|
||||
|
@ -3382,7 +3383,7 @@ class FlatCAMGeoEditor(QtCore.QObject):
|
|||
self.shapes = self.app.plotcanvas.new_shape_collection(layers=1)
|
||||
self.tool_shape = self.app.plotcanvas.new_shape_collection(layers=1)
|
||||
else:
|
||||
from AppGUI.PlotCanvasLegacy import ShapeCollectionLegacy
|
||||
from flatcamGUI.PlotCanvasLegacy import ShapeCollectionLegacy
|
||||
self.shapes = ShapeCollectionLegacy(obj=self, app=self.app, name='shapes_geo_editor')
|
||||
self.tool_shape = ShapeCollectionLegacy(obj=self, app=self.app, name='tool_shapes_geo_editor')
|
||||
|
||||
|
@ -3466,32 +3467,22 @@ class FlatCAMGeoEditor(QtCore.QObject):
|
|||
:return:
|
||||
"""
|
||||
try:
|
||||
text_value = entry.text()
|
||||
if ',' in text_value:
|
||||
text_value = text_value.replace(',', '.')
|
||||
self.options[opt] = float(text_value)
|
||||
self.options[opt] = float(entry.text())
|
||||
except Exception as e:
|
||||
entry.set_value(self.app.defaults[opt])
|
||||
log.debug("FlatCAMGeoEditor.__init__().entry2option() --> %s" % str(e))
|
||||
return
|
||||
|
||||
def grid_changed(goption, gentry):
|
||||
def gridx_changed(goption, gentry):
|
||||
"""
|
||||
|
||||
:param goption: String. Can be either 'global_gridx' or 'global_gridy'
|
||||
:param gentry: A GUI element which text value is read and used
|
||||
:param goption: String. Can be either 'global_gridx' or 'global_gridy'
|
||||
:param gentry: A GUI element which text value is read and used
|
||||
:return:
|
||||
"""
|
||||
if goption not in ['global_gridx', 'global_gridy']:
|
||||
return
|
||||
|
||||
entry2option(opt=goption, entry=gentry)
|
||||
# if the grid link is checked copy the value in the GridX field to GridY
|
||||
try:
|
||||
text_value = gentry.text()
|
||||
if ',' in text_value:
|
||||
text_value = text_value.replace(',', '.')
|
||||
val = float(text_value)
|
||||
val = float(gentry.get_value())
|
||||
except ValueError:
|
||||
return
|
||||
|
||||
|
@ -3500,7 +3491,7 @@ class FlatCAMGeoEditor(QtCore.QObject):
|
|||
|
||||
self.app.ui.grid_gap_x_entry.setValidator(QtGui.QDoubleValidator())
|
||||
self.app.ui.grid_gap_x_entry.textChanged.connect(
|
||||
lambda: grid_changed("global_gridx", self.app.ui.grid_gap_x_entry))
|
||||
lambda: gridx_changed("global_gridx", self.app.ui.grid_gap_x_entry))
|
||||
|
||||
self.app.ui.grid_gap_y_entry.setValidator(QtGui.QDoubleValidator())
|
||||
self.app.ui.grid_gap_y_entry.textChanged.connect(
|
||||
|
@ -3551,7 +3542,7 @@ class FlatCAMGeoEditor(QtCore.QObject):
|
|||
|
||||
# store the status of the editor so the Delete at object level will not work until the edit is finished
|
||||
self.editor_active = False
|
||||
log.debug("Initialization of the Geometry Editor is finished ...")
|
||||
log.debug("Initialization of the FlatCAM Geometry Editor is finished ...")
|
||||
|
||||
def pool_recreated(self, pool):
|
||||
self.shapes.pool = pool
|
||||
|
@ -3568,14 +3559,14 @@ class FlatCAMGeoEditor(QtCore.QObject):
|
|||
|
||||
# Remove anything else in the GUI Selected Tab
|
||||
self.app.ui.selected_scroll_area.takeWidget()
|
||||
# Put ourselves in the AppGUI Selected Tab
|
||||
# Put ourselves in the GUI Selected Tab
|
||||
self.app.ui.selected_scroll_area.setWidget(self.geo_edit_widget)
|
||||
# Switch notebook to Selected page
|
||||
self.app.ui.notebook.setCurrentWidget(self.app.ui.selected_tab)
|
||||
|
||||
def build_ui(self):
|
||||
"""
|
||||
Build the AppGUI in the Selected Tab for this editor
|
||||
Build the GUI in the Selected Tab for this editor
|
||||
|
||||
:return:
|
||||
"""
|
||||
|
@ -3653,8 +3644,10 @@ class FlatCAMGeoEditor(QtCore.QObject):
|
|||
self.tool_shape.enabled = True
|
||||
self.app.app_cursor.enabled = True
|
||||
|
||||
self.app.ui.corner_snap_btn.setVisible(True)
|
||||
self.app.ui.snap_max_dist_entry.setEnabled(True)
|
||||
self.app.ui.corner_snap_btn.setEnabled(True)
|
||||
self.app.ui.snap_magnet.setVisible(True)
|
||||
self.app.ui.corner_snap_btn.setVisible(True)
|
||||
|
||||
self.app.ui.geo_editor_menu.setDisabled(False)
|
||||
self.app.ui.geo_editor_menu.menuAction().setVisible(True)
|
||||
|
@ -3665,7 +3658,7 @@ class FlatCAMGeoEditor(QtCore.QObject):
|
|||
self.app.ui.geo_edit_toolbar.setDisabled(False)
|
||||
self.app.ui.geo_edit_toolbar.setVisible(True)
|
||||
|
||||
self.app.ui.status_toolbar.setDisabled(False)
|
||||
self.app.ui.snap_toolbar.setDisabled(False)
|
||||
|
||||
self.app.ui.popmenu_disable.setVisible(False)
|
||||
self.app.ui.cmenu_newmenu.menuAction().setVisible(False)
|
||||
|
@ -3682,7 +3675,7 @@ class FlatCAMGeoEditor(QtCore.QObject):
|
|||
|
||||
self.item_selected.connect(self.on_geo_elem_selected)
|
||||
|
||||
# ## AppGUI Events
|
||||
# ## GUI Events
|
||||
self.tw.itemSelectionChanged.connect(self.on_tree_selection_change)
|
||||
# self.tw.keyPressed.connect(self.app.ui.keyPressEvent)
|
||||
# self.tw.customContextMenuRequested.connect(self.on_menu_request)
|
||||
|
@ -3710,8 +3703,27 @@ class FlatCAMGeoEditor(QtCore.QObject):
|
|||
self.app.ui.geo_edit_toolbar.setDisabled(True)
|
||||
|
||||
settings = QSettings("Open Source", "FlatCAM")
|
||||
self.app.ui.corner_snap_btn.setVisible(False)
|
||||
self.app.ui.snap_magnet.setVisible(False)
|
||||
if settings.contains("layout"):
|
||||
layout = settings.value('layout', type=str)
|
||||
if layout == 'standard':
|
||||
# self.app.ui.geo_edit_toolbar.setVisible(False)
|
||||
|
||||
self.app.ui.snap_max_dist_entry.setEnabled(False)
|
||||
self.app.ui.corner_snap_btn.setEnabled(False)
|
||||
self.app.ui.snap_magnet.setVisible(False)
|
||||
self.app.ui.corner_snap_btn.setVisible(False)
|
||||
else:
|
||||
# self.app.ui.geo_edit_toolbar.setVisible(True)
|
||||
|
||||
self.app.ui.snap_max_dist_entry.setEnabled(False)
|
||||
self.app.ui.corner_snap_btn.setEnabled(False)
|
||||
else:
|
||||
# self.app.ui.geo_edit_toolbar.setVisible(False)
|
||||
|
||||
self.app.ui.snap_magnet.setVisible(False)
|
||||
self.app.ui.corner_snap_btn.setVisible(False)
|
||||
self.app.ui.snap_max_dist_entry.setEnabled(False)
|
||||
self.app.ui.corner_snap_btn.setEnabled(False)
|
||||
|
||||
# set the Editor Toolbar visibility to what was before entering in the Editor
|
||||
self.app.ui.geo_edit_toolbar.setVisible(False) if self.toolbar_old_state is False \
|
||||
|
@ -3745,7 +3757,7 @@ class FlatCAMGeoEditor(QtCore.QObject):
|
|||
pass
|
||||
|
||||
try:
|
||||
# ## AppGUI Events
|
||||
# ## GUI Events
|
||||
self.tw.itemSelectionChanged.disconnect(self.on_tree_selection_change)
|
||||
# self.tw.keyPressed.connect(self.app.ui.keyPressEvent)
|
||||
# self.tw.customContextMenuRequested.connect(self.on_menu_request)
|
||||
|
@ -4088,6 +4100,7 @@ class FlatCAMGeoEditor(QtCore.QObject):
|
|||
# start with GRID toolbar activated
|
||||
if self.app.ui.grid_snap_btn.isChecked() is False:
|
||||
self.app.ui.grid_snap_btn.trigger()
|
||||
self.app.ui.on_grid_snap_triggered(state=True)
|
||||
|
||||
def on_buffer_tool(self):
|
||||
buff_tool = BufferSelectionTool(self.app, self)
|
||||
|
@ -4135,11 +4148,9 @@ class FlatCAMGeoEditor(QtCore.QObject):
|
|||
|
||||
# make sure that the cursor shape is enabled/disabled, too
|
||||
if self.options['grid_snap'] is True:
|
||||
self.app.inform[str, bool].emit(_("Grid Snap enabled."), False)
|
||||
self.app.app_cursor.enabled = True
|
||||
else:
|
||||
self.app.app_cursor.enabled = False
|
||||
self.app.inform[str, bool].emit(_("Grid Snap disabled."), False)
|
||||
|
||||
def on_canvas_click(self, event):
|
||||
"""
|
||||
|
@ -4162,8 +4173,8 @@ class FlatCAMGeoEditor(QtCore.QObject):
|
|||
self.pos = (self.pos[0], self.pos[1])
|
||||
|
||||
if event.button == 1:
|
||||
# self.app.ui.rel_position_label.setText("<b>Dx</b>: %.4f <b>Dy</b>: "
|
||||
# "%.4f " % (0, 0))
|
||||
self.app.ui.rel_position_label.setText("<b>Dx</b>: %.4f <b>Dy</b>: "
|
||||
"%.4f " % (0, 0))
|
||||
|
||||
modifiers = QtWidgets.QApplication.keyboardModifiers()
|
||||
# If the SHIFT key is pressed when LMB is clicked then the coordinates are copied to clipboard
|
||||
|
@ -4250,23 +4261,18 @@ class FlatCAMGeoEditor(QtCore.QObject):
|
|||
self.snap_y = y
|
||||
self.app.mouse = [x, y]
|
||||
|
||||
# update the position label in the infobar since the APP mouse event handlers are disconnected
|
||||
self.app.ui.position_label.setText(" <b>X</b>: %.4f "
|
||||
"<b>Y</b>: %.4f" % (x, y))
|
||||
|
||||
if self.pos is None:
|
||||
self.pos = (0, 0)
|
||||
self.app.dx = x - self.pos[0]
|
||||
self.app.dy = y - self.pos[1]
|
||||
|
||||
# # update the position label in the infobar since the APP mouse event handlers are disconnected
|
||||
self.app.ui.position_label.setText(" <b>X</b>: %.4f "
|
||||
"<b>Y</b>: %.4f " % (x, y))
|
||||
#
|
||||
# # update the reference position label in the infobar since the APP mouse event handlers are disconnected
|
||||
# self.app.ui.rel_position_label.setText("<b>Dx</b>: %.4f <b>Dy</b>: "
|
||||
# "%.4f " % (self.app.dx, self.app.dy))
|
||||
|
||||
units = self.app.defaults["units"].lower()
|
||||
self.app.plotcanvas.text_hud.text = \
|
||||
'Dx:\t{:<.4f} [{:s}]\nDy:\t{:<.4f} [{:s}]\n\nX: \t{:<.4f} [{:s}]\nY: \t{:<.4f} [{:s}]'.format(
|
||||
self.app.dx, units, self.app.dy, units, x, units, y, units)
|
||||
# update the reference position label in the infobar since the APP mouse event handlers are disconnected
|
||||
self.app.ui.rel_position_label.setText("<b>Dx</b>: %.4f <b>Dy</b>: "
|
||||
"%.4f " % (self.app.dx, self.app.dy))
|
||||
|
||||
if event.button == 1 and event_is_dragging and isinstance(self.active_tool, FCEraser):
|
||||
pass
|
||||
|
@ -4659,7 +4665,7 @@ class FlatCAMGeoEditor(QtCore.QObject):
|
|||
|
||||
def select_tool(self, toolname):
|
||||
"""
|
||||
Selects a drawing tool. Impacts the object and AppGUI.
|
||||
Selects a drawing tool. Impacts the object and GUI.
|
||||
|
||||
:param toolname: Name of the tool.
|
||||
:return: None
|
||||
|
@ -4744,8 +4750,8 @@ class FlatCAMGeoEditor(QtCore.QObject):
|
|||
Transfers the geometry tool shape buffer to the selected geometry
|
||||
object. The geometry already in the object are removed.
|
||||
|
||||
:param fcgeometry: GeometryObject
|
||||
:return: None
|
||||
:param fcgeometry: GeometryObject
|
||||
:return: None
|
||||
"""
|
||||
if self.multigeo_tool:
|
||||
fcgeometry.tools[self.multigeo_tool]['solid_geometry'] = []
|
||||
|
@ -4770,8 +4776,6 @@ class FlatCAMGeoEditor(QtCore.QObject):
|
|||
new_geo = linemerge(new_geo)
|
||||
fcgeometry.solid_geometry.append(new_geo)
|
||||
|
||||
self.deactivate()
|
||||
|
||||
def update_options(self, obj):
|
||||
if self.paint_tooldia:
|
||||
obj.options['cnctooldia'] = deepcopy(str(self.paint_tooldia))
|
|
@ -14,13 +14,15 @@ import shapely.affinity as affinity
|
|||
|
||||
from vispy.geometry import Rect
|
||||
|
||||
import threading
|
||||
import time
|
||||
from copy import copy, deepcopy
|
||||
import logging
|
||||
|
||||
from camlib import distance, arc, three_point_circle
|
||||
from AppGUI.GUIElements import FCEntry, FCComboBox, FCTable, FCDoubleSpinner, FCSpinner, RadioSet, \
|
||||
from flatcamGUI.GUIElements import FCEntry, FCComboBox, FCTable, FCDoubleSpinner, FCSpinner, RadioSet, \
|
||||
EvalEntry2, FCInputDialog, FCButton, OptionalInputSection, FCCheckBox
|
||||
from AppTool import AppTool
|
||||
from FlatCAMTool import FlatCAMTool
|
||||
|
||||
import numpy as np
|
||||
from numpy.linalg import norm as numpy_norm
|
||||
|
@ -30,7 +32,7 @@ import math
|
|||
# import pngcanvas
|
||||
import traceback
|
||||
import gettext
|
||||
import AppTranslation as fcTranslate
|
||||
import FlatCAMTranslation as fcTranslate
|
||||
import builtins
|
||||
|
||||
fcTranslate.apply_language('strings')
|
||||
|
@ -1084,6 +1086,15 @@ class FCRegion(FCShapeTool):
|
|||
|
||||
self.draw_app.app.inform.emit('[success] %s' % _("Done."))
|
||||
|
||||
def clean_up(self):
|
||||
self.draw_app.selected = []
|
||||
self.draw_app.apertures_table.clearSelection()
|
||||
self.draw_app.plot_all()
|
||||
try:
|
||||
self.draw_app.app.jump_signal.disconnect()
|
||||
except (TypeError, AttributeError):
|
||||
pass
|
||||
|
||||
def on_key(self, key):
|
||||
# Jump to coords
|
||||
if key == QtCore.Qt.Key_J or key == 'J':
|
||||
|
@ -1149,36 +1160,16 @@ class FCRegion(FCShapeTool):
|
|||
|
||||
return msg
|
||||
|
||||
def clean_up(self):
|
||||
self.draw_app.selected = []
|
||||
self.draw_app.apertures_table.clearSelection()
|
||||
self.draw_app.plot_all()
|
||||
try:
|
||||
self.draw_app.app.jump_signal.disconnect()
|
||||
except (TypeError, AttributeError):
|
||||
pass
|
||||
|
||||
|
||||
class FCTrack(FCShapeTool):
|
||||
class FCTrack(FCRegion):
|
||||
"""
|
||||
Resulting type: Polygon
|
||||
"""
|
||||
def __init__(self, draw_app):
|
||||
DrawTool.__init__(self, draw_app)
|
||||
FCRegion.__init__(self, draw_app)
|
||||
self.name = 'track'
|
||||
self.draw_app = draw_app
|
||||
|
||||
self.steps_per_circle = self.draw_app.app.defaults["gerber_circle_steps"]
|
||||
|
||||
size_ap = float(self.draw_app.storage_dict[self.draw_app.last_aperture_selected]['size'])
|
||||
self.buf_val = (size_ap / 2) if size_ap > 0 else 0.0000001
|
||||
|
||||
self.gridx_size = float(self.draw_app.app.ui.grid_gap_x_entry.get_value())
|
||||
self.gridy_size = float(self.draw_app.app.ui.grid_gap_y_entry.get_value())
|
||||
|
||||
self.temp_points = []
|
||||
|
||||
self. final_click = False
|
||||
try:
|
||||
QtGui.QGuiApplication.restoreOverrideCursor()
|
||||
except Exception as e:
|
||||
|
@ -1192,23 +1183,52 @@ class FCTrack(FCShapeTool):
|
|||
|
||||
self.draw_app.app.inform.emit(_('Track Mode 1: 45 degrees ...'))
|
||||
|
||||
def make(self):
|
||||
new_geo_el = {}
|
||||
if len(self.temp_points) == 1:
|
||||
new_geo_el['solid'] = Point(self.temp_points).buffer(self.buf_val,
|
||||
resolution=int(self.steps_per_circle / 4))
|
||||
new_geo_el['follow'] = Point(self.temp_points)
|
||||
else:
|
||||
new_geo_el['solid'] = (LineString(self.temp_points).buffer(
|
||||
self.buf_val, resolution=int(self.steps_per_circle / 4))).buffer(0)
|
||||
new_geo_el['follow'] = LineString(self.temp_points)
|
||||
|
||||
self.geometry = DrawToolShape(new_geo_el)
|
||||
|
||||
self.draw_app.in_action = False
|
||||
self.complete = True
|
||||
|
||||
self.draw_app.app.jump_signal.disconnect()
|
||||
|
||||
self.draw_app.app.inform.emit('[success] %s' % _("Done."))
|
||||
|
||||
def clean_up(self):
|
||||
self.draw_app.selected = []
|
||||
self.draw_app.apertures_table.clearSelection()
|
||||
self.draw_app.plot_all()
|
||||
try:
|
||||
self.draw_app.app.jump_signal.disconnect()
|
||||
except (TypeError, AttributeError):
|
||||
pass
|
||||
|
||||
def click(self, point):
|
||||
self.draw_app.in_action = True
|
||||
|
||||
if not self.points:
|
||||
try:
|
||||
if point != self.points[-1]:
|
||||
self.points.append(point)
|
||||
except IndexError:
|
||||
self.points.append(point)
|
||||
elif point != self.points[-1]:
|
||||
self.points.append(point)
|
||||
else:
|
||||
return
|
||||
|
||||
new_geo_el = {}
|
||||
|
||||
if len(self.temp_points) == 1:
|
||||
new_geo_el['solid'] = Point(self.temp_points).buffer(self.buf_val, int(self.steps_per_circle))
|
||||
new_geo_el['solid'] = Point(self.temp_points).buffer(self.buf_val,
|
||||
resolution=int(self.steps_per_circle / 4))
|
||||
new_geo_el['follow'] = Point(self.temp_points)
|
||||
else:
|
||||
new_geo_el['solid'] = LineString(self.temp_points).buffer(self.buf_val, int(self.steps_per_circle))
|
||||
new_geo_el['solid'] = LineString(self.temp_points).buffer(self.buf_val,
|
||||
resolution=int(self.steps_per_circle / 4))
|
||||
new_geo_el['follow'] = LineString(self.temp_points)
|
||||
|
||||
self.draw_app.add_gerber_shape(DrawToolShape(new_geo_el),
|
||||
|
@ -1221,25 +1241,23 @@ class FCTrack(FCShapeTool):
|
|||
|
||||
return ""
|
||||
|
||||
def update_grid_info(self):
|
||||
self.gridx_size = float(self.draw_app.app.ui.grid_gap_x_entry.get_value())
|
||||
self.gridy_size = float(self.draw_app.app.ui.grid_gap_y_entry.get_value())
|
||||
|
||||
def utility_geometry(self, data=None):
|
||||
self.update_grid_info()
|
||||
new_geo_el = {}
|
||||
|
||||
if not self.points:
|
||||
new_geo_el['solid'] = Point(data).buffer(self.buf_val, int(self.steps_per_circle))
|
||||
if len(self.points) == 0:
|
||||
new_geo_el['solid'] = Point(data).buffer(self.buf_val,
|
||||
resolution=int(self.steps_per_circle / 4))
|
||||
|
||||
return DrawToolUtilityShape(new_geo_el)
|
||||
else:
|
||||
elif len(self.points) > 0:
|
||||
|
||||
self.temp_points = [self.points[-1]]
|
||||
old_x = self.points[-1][0]
|
||||
old_y = self.points[-1][1]
|
||||
x = data[0]
|
||||
y = data[1]
|
||||
|
||||
self.temp_points = [self.points[-1]]
|
||||
|
||||
mx = abs(round((x - old_x) / self.gridx_size))
|
||||
my = abs(round((y - old_y) / self.gridy_size))
|
||||
|
||||
|
@ -1287,30 +1305,14 @@ class FCTrack(FCShapeTool):
|
|||
|
||||
self.temp_points.append(data)
|
||||
if len(self.temp_points) == 1:
|
||||
new_geo_el['solid'] = Point(self.temp_points).buffer(self.buf_val, int(self.steps_per_circle))
|
||||
new_geo_el['solid'] = Point(self.temp_points).buffer(self.buf_val,
|
||||
resolution=int(self.steps_per_circle / 4))
|
||||
return DrawToolUtilityShape(new_geo_el)
|
||||
|
||||
new_geo_el['solid'] = LineString(self.temp_points).buffer(self.buf_val, int(self.steps_per_circle))
|
||||
new_geo_el['solid'] = LineString(self.temp_points).buffer(self.buf_val,
|
||||
resolution=int(self.steps_per_circle / 4))
|
||||
return DrawToolUtilityShape(new_geo_el)
|
||||
|
||||
def make(self):
|
||||
new_geo_el = {}
|
||||
if len(self.temp_points) == 1:
|
||||
new_geo_el['solid'] = Point(self.temp_points).buffer(self.buf_val, int(self.steps_per_circle))
|
||||
new_geo_el['follow'] = Point(self.temp_points)
|
||||
else:
|
||||
new_geo_el['solid'] = LineString(self.temp_points).buffer(self.buf_val, int(self.steps_per_circle))
|
||||
new_geo_el['solid'] = new_geo_el['solid'].buffer(0) # try to clean the geometry
|
||||
new_geo_el['follow'] = LineString(self.temp_points)
|
||||
|
||||
self.geometry = DrawToolShape(new_geo_el)
|
||||
|
||||
self.draw_app.in_action = False
|
||||
self.complete = True
|
||||
|
||||
self.draw_app.app.jump_signal.disconnect()
|
||||
self.draw_app.app.inform.emit('[success] %s' % _("Done."))
|
||||
|
||||
def on_key(self, key):
|
||||
if key == 'Backspace' or key == QtCore.Qt.Key_Backspace:
|
||||
if len(self.points) > 0:
|
||||
|
@ -1403,15 +1405,6 @@ class FCTrack(FCShapeTool):
|
|||
|
||||
return msg
|
||||
|
||||
def clean_up(self):
|
||||
self.draw_app.selected = []
|
||||
self.draw_app.apertures_table.clearSelection()
|
||||
self.draw_app.plot_all()
|
||||
try:
|
||||
self.draw_app.app.jump_signal.disconnect()
|
||||
except (TypeError, AttributeError):
|
||||
pass
|
||||
|
||||
|
||||
class FCDisc(FCShapeTool):
|
||||
"""
|
||||
|
@ -2962,7 +2955,7 @@ class FlatCAMGrbEditor(QtCore.QObject):
|
|||
# this var will store the state of the toolbar before starting the editor
|
||||
self.toolbar_old_state = False
|
||||
|
||||
# Init AppGUI
|
||||
# Init GUI
|
||||
self.apdim_lbl.hide()
|
||||
self.apdim_entry.hide()
|
||||
self.gerber_obj = None
|
||||
|
@ -2974,7 +2967,7 @@ class FlatCAMGrbEditor(QtCore.QObject):
|
|||
self.tool_shape = self.canvas.new_shape_collection(layers=1)
|
||||
self.ma_annotation = self.canvas.new_text_group()
|
||||
else:
|
||||
from AppGUI.PlotCanvasLegacy import ShapeCollectionLegacy
|
||||
from flatcamGUI.PlotCanvasLegacy import ShapeCollectionLegacy
|
||||
self.shapes = ShapeCollectionLegacy(obj=self, app=self.app, name='shapes_grb_editor')
|
||||
self.tool_shape = ShapeCollectionLegacy(obj=self, app=self.app, name='tool_shapes_grb_editor')
|
||||
self.ma_annotation = ShapeCollectionLegacy(
|
||||
|
@ -3117,7 +3110,7 @@ class FlatCAMGrbEditor(QtCore.QObject):
|
|||
self.complete = True
|
||||
|
||||
self.set_ui()
|
||||
log.debug("Initialization of the Gerber Editor is finished ...")
|
||||
log.debug("Initialization of the FlatCAM Gerber Editor is finished ...")
|
||||
|
||||
def pool_recreated(self, pool):
|
||||
self.shapes.pool = pool
|
||||
|
@ -3146,7 +3139,7 @@ class FlatCAMGrbEditor(QtCore.QObject):
|
|||
tt_aperture = self.sorted_apcode[i]
|
||||
self.tid2apcode[i + 1] = tt_aperture
|
||||
|
||||
# Init AppGUI
|
||||
# Init GUI
|
||||
|
||||
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"])
|
||||
|
@ -3435,7 +3428,7 @@ class FlatCAMGrbEditor(QtCore.QObject):
|
|||
else:
|
||||
# deleted_tool_dia = float(self.apertures_table.item(self.apertures_table.currentRow(), 1).text())
|
||||
if len(self.apertures_table.selectionModel().selectedRows()) == 0:
|
||||
self.app.inform.emit('[WARNING_NOTCL] %s' % _(" Select an aperture in Aperture Table"))
|
||||
self.app.inform.emit('[WARNING_NOTCL]%s' % _(" Select an aperture in Aperture Table"))
|
||||
return
|
||||
|
||||
deleted_apcode_list = []
|
||||
|
@ -3692,8 +3685,10 @@ class FlatCAMGrbEditor(QtCore.QObject):
|
|||
self.shapes.enabled = True
|
||||
self.tool_shape.enabled = True
|
||||
|
||||
self.app.ui.corner_snap_btn.setVisible(True)
|
||||
self.app.ui.snap_max_dist_entry.setEnabled(True)
|
||||
self.app.ui.corner_snap_btn.setEnabled(True)
|
||||
self.app.ui.snap_magnet.setVisible(True)
|
||||
self.app.ui.corner_snap_btn.setVisible(True)
|
||||
|
||||
self.app.ui.grb_editor_menu.setDisabled(False)
|
||||
self.app.ui.grb_editor_menu.menuAction().setVisible(True)
|
||||
|
@ -3703,11 +3698,12 @@ class FlatCAMGrbEditor(QtCore.QObject):
|
|||
|
||||
self.app.ui.grb_edit_toolbar.setDisabled(False)
|
||||
self.app.ui.grb_edit_toolbar.setVisible(True)
|
||||
# self.app.ui.status_toolbar.setDisabled(False)
|
||||
# self.app.ui.snap_toolbar.setDisabled(False)
|
||||
|
||||
# start with GRID toolbar activated
|
||||
if self.app.ui.grid_snap_btn.isChecked() is False:
|
||||
self.app.ui.grid_snap_btn.trigger()
|
||||
self.app.ui.on_grid_snap_triggered(state=True)
|
||||
|
||||
# adjust the visibility of some of the canvas context menu
|
||||
self.app.ui.popmenu_edit.setVisible(False)
|
||||
|
@ -3740,8 +3736,29 @@ class FlatCAMGrbEditor(QtCore.QObject):
|
|||
self.app.ui.grb_edit_toolbar.setDisabled(True)
|
||||
|
||||
settings = QSettings("Open Source", "FlatCAM")
|
||||
self.app.ui.corner_snap_btn.setVisible(False)
|
||||
self.app.ui.snap_magnet.setVisible(False)
|
||||
if settings.contains("layout"):
|
||||
layout = settings.value('layout', type=str)
|
||||
if layout == 'standard':
|
||||
# self.app.ui.exc_edit_toolbar.setVisible(False)
|
||||
|
||||
self.app.ui.snap_max_dist_entry.setEnabled(False)
|
||||
self.app.ui.corner_snap_btn.setEnabled(False)
|
||||
self.app.ui.snap_magnet.setVisible(False)
|
||||
self.app.ui.corner_snap_btn.setVisible(False)
|
||||
else:
|
||||
# self.app.ui.exc_edit_toolbar.setVisible(True)
|
||||
|
||||
self.app.ui.snap_max_dist_entry.setEnabled(False)
|
||||
self.app.ui.corner_snap_btn.setEnabled(False)
|
||||
self.app.ui.snap_magnet.setVisible(True)
|
||||
self.app.ui.corner_snap_btn.setVisible(True)
|
||||
else:
|
||||
# self.app.ui.exc_edit_toolbar.setVisible(False)
|
||||
|
||||
self.app.ui.snap_max_dist_entry.setEnabled(False)
|
||||
self.app.ui.corner_snap_btn.setEnabled(False)
|
||||
self.app.ui.snap_magnet.setVisible(False)
|
||||
self.app.ui.corner_snap_btn.setVisible(False)
|
||||
|
||||
# set the Editor Toolbar visibility to what was before entering in the Editor
|
||||
self.app.ui.grb_edit_toolbar.setVisible(False) if self.toolbar_old_state is False \
|
||||
|
@ -4193,7 +4210,7 @@ class FlatCAMGrbEditor(QtCore.QObject):
|
|||
|
||||
def on_multiprocessing_finished(self):
|
||||
self.app.proc_container.update_view_text(' %s' % _("Setting up the UI"))
|
||||
self.app.inform.emit('[success] %s.' % _("Adding geometry finished. Preparing the AppGUI"))
|
||||
self.app.inform.emit('[success] %s.' % _("Adding geometry finished. Preparing the GUI"))
|
||||
self.set_ui()
|
||||
self.build_ui(first_run=True)
|
||||
self.plot_all()
|
||||
|
@ -4228,7 +4245,6 @@ class FlatCAMGrbEditor(QtCore.QObject):
|
|||
new_grb_name = self.edited_obj_name + "_edit"
|
||||
|
||||
self.app.worker_task.emit({'fcn': self.new_edited_gerber, 'params': [new_grb_name, self.storage_dict]})
|
||||
# self.new_edited_gerber(new_grb_name, self.storage_dict)
|
||||
|
||||
@staticmethod
|
||||
def update_options(obj):
|
||||
|
@ -4250,10 +4266,9 @@ class FlatCAMGrbEditor(QtCore.QObject):
|
|||
"""
|
||||
Creates a new Gerber object for the edited Gerber. Thread-safe.
|
||||
|
||||
:param outname: Name of the resulting object. None causes the name to be that of the file.
|
||||
:type outname: str
|
||||
:param aperture_storage: a dictionary that holds all the objects geometry
|
||||
:type aperture_storage: dict
|
||||
:param outname: Name of the resulting object. None causes the name to be that of the file.
|
||||
:type outname: str
|
||||
:param aperture_storage: a dictionary that holds all the objects geometry
|
||||
:return: None
|
||||
"""
|
||||
|
||||
|
@ -4345,27 +4360,26 @@ class FlatCAMGrbEditor(QtCore.QObject):
|
|||
self.app.inform.emit('[ERROR_NOTCL] %s' %
|
||||
_("There are no Aperture definitions in the file. Aborting Gerber creation."))
|
||||
except Exception:
|
||||
msg = '[ERROR] %s' % _("An internal error has occurred. See shell.\n")
|
||||
msg = '[ERROR] %s' % \
|
||||
_("An internal error has occurred. See shell.\n")
|
||||
msg += traceback.format_exc()
|
||||
app_obj.inform.emit(msg)
|
||||
raise
|
||||
|
||||
grb_obj.source_file = self.app.export_gerber(obj_name=out_name, filename=None,
|
||||
local_use=grb_obj, use_thread=False)
|
||||
|
||||
with self.app.proc_container.new(_("Creating Gerber.")):
|
||||
try:
|
||||
self.app.app_obj.new_object("gerber", outname, obj_init)
|
||||
self.app.new_object("gerber", outname, obj_init)
|
||||
except Exception as e:
|
||||
log.error("Error on Edited object creation: %s" % str(e))
|
||||
# make sure to clean the previous results
|
||||
self.results = []
|
||||
return
|
||||
|
||||
self.app.inform.emit('[success] %s' % _("Done. Gerber editing finished."))
|
||||
# make sure to clean the previous results
|
||||
self.results = []
|
||||
self.deactivate_grb_editor()
|
||||
self.app.inform.emit('[success] %s' % _("Done. Gerber editing finished."))
|
||||
|
||||
def on_tool_select(self, tool):
|
||||
"""
|
||||
|
@ -4523,8 +4537,8 @@ class FlatCAMGrbEditor(QtCore.QObject):
|
|||
self.pos = (self.pos[0], self.pos[1])
|
||||
|
||||
if event.button == 1:
|
||||
# self.app.ui.rel_position_label.setText("<b>Dx</b>: %.4f <b>Dy</b>: "
|
||||
# "%.4f " % (0, 0))
|
||||
self.app.ui.rel_position_label.setText("<b>Dx</b>: %.4f <b>Dy</b>: "
|
||||
"%.4f " % (0, 0))
|
||||
|
||||
# Selection with left mouse button
|
||||
if self.active_tool is not None:
|
||||
|
@ -4536,7 +4550,8 @@ class FlatCAMGrbEditor(QtCore.QObject):
|
|||
self.app.defaults["global_point_clipboard_format"] %
|
||||
(self.decimals, self.pos[0], self.decimals, self.pos[1])
|
||||
)
|
||||
self.app.inform.emit('[success] %s' % _("Coordinates copied to clipboard."))
|
||||
self.app.inform.emit('[success] %s' %
|
||||
_("Coordinates copied to clipboard."))
|
||||
return
|
||||
|
||||
# Dispatch event to active_tool
|
||||
|
@ -4547,7 +4562,6 @@ class FlatCAMGrbEditor(QtCore.QObject):
|
|||
if self.current_storage is not None:
|
||||
self.on_grb_shape_complete(self.current_storage)
|
||||
self.build_ui()
|
||||
|
||||
# MS: always return to the Select Tool if modifier key is not pressed
|
||||
# else return to the current tool
|
||||
key_modifier = QtWidgets.QApplication.keyboardModifiers()
|
||||
|
@ -4555,7 +4569,6 @@ class FlatCAMGrbEditor(QtCore.QObject):
|
|||
modifier_to_use = Qt.ControlModifier
|
||||
else:
|
||||
modifier_to_use = Qt.ShiftModifier
|
||||
|
||||
# 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 == modifier_to_use:
|
||||
|
@ -4616,14 +4629,12 @@ class FlatCAMGrbEditor(QtCore.QObject):
|
|||
# if right click on canvas and the active tool need to be finished (like Path or Polygon)
|
||||
# right mouse click will finish the action
|
||||
if isinstance(self.active_tool, FCShapeTool):
|
||||
if isinstance(self.active_tool, FCTrack):
|
||||
self.active_tool.make()
|
||||
else:
|
||||
self.active_tool.click(self.app.geo_editor.snap(self.x, self.y))
|
||||
self.active_tool.make()
|
||||
self.active_tool.click(self.app.geo_editor.snap(self.x, self.y))
|
||||
self.active_tool.make()
|
||||
if self.active_tool.complete:
|
||||
self.on_grb_shape_complete()
|
||||
self.app.inform.emit('[success] %s' % _("Done."))
|
||||
self.app.inform.emit('[success] %s' %
|
||||
_("Done."))
|
||||
|
||||
# MS: always return to the Select Tool if modifier key is not pressed
|
||||
# else return to the current tool but not for FCTrack
|
||||
|
@ -4763,23 +4774,18 @@ class FlatCAMGrbEditor(QtCore.QObject):
|
|||
|
||||
self.app.mouse = [x, y]
|
||||
|
||||
# update the position label in the infobar since the APP mouse event handlers are disconnected
|
||||
self.app.ui.position_label.setText(" <b>X</b>: %.4f "
|
||||
"<b>Y</b>: %.4f" % (x, y))
|
||||
|
||||
if self.pos is None:
|
||||
self.pos = (0, 0)
|
||||
self.app.dx = x - self.pos[0]
|
||||
self.app.dy = y - self.pos[1]
|
||||
|
||||
# # update the position label in the infobar since the APP mouse event handlers are disconnected
|
||||
self.app.ui.position_label.setText(" <b>X</b>: %.4f "
|
||||
"<b>Y</b>: %.4f " % (x, y))
|
||||
#
|
||||
# # update the reference position label in the infobar since the APP mouse event handlers are disconnected
|
||||
# self.app.ui.rel_position_label.setText("<b>Dx</b>: %.4f <b>Dy</b>: "
|
||||
# "%.4f " % (self.app.dx, self.app.dy))
|
||||
|
||||
units = self.app.defaults["units"].lower()
|
||||
self.app.plotcanvas.text_hud.text = \
|
||||
'Dx:\t{:<.4f} [{:s}]\nDy:\t{:<.4f} [{:s}]\n\nX: \t{:<.4f} [{:s}]\nY: \t{:<.4f} [{:s}]'.format(
|
||||
self.app.dx, units, self.app.dy, units, x, units, y, units)
|
||||
# update the reference position label in the infobar since the APP mouse event handlers are disconnected
|
||||
self.app.ui.rel_position_label.setText("<b>Dx</b>: %.4f <b>Dy</b>: "
|
||||
"%.4f " % (self.app.dx, self.app.dy))
|
||||
|
||||
self.update_utility_geometry(data=(x, y))
|
||||
|
||||
|
@ -5026,7 +5032,7 @@ class FlatCAMGrbEditor(QtCore.QObject):
|
|||
|
||||
def select_tool(self, toolname):
|
||||
"""
|
||||
Selects a drawing tool. Impacts the object and AppGUI.
|
||||
Selects a drawing tool. Impacts the object and GUI.
|
||||
|
||||
:param toolname: Name of the tool.
|
||||
:return: None
|
||||
|
@ -5292,7 +5298,7 @@ class FlatCAMGrbEditor(QtCore.QObject):
|
|||
self.app.ui.notebook.setCurrentWidget(self.app.ui.selected_tab)
|
||||
|
||||
|
||||
class TransformEditorTool(AppTool):
|
||||
class TransformEditorTool(FlatCAMTool):
|
||||
"""
|
||||
Inputs to specify how to paint the selected polygons.
|
||||
"""
|
||||
|
@ -5305,7 +5311,7 @@ class TransformEditorTool(AppTool):
|
|||
offsetName = _("Offset")
|
||||
|
||||
def __init__(self, app, draw_app):
|
||||
AppTool.__init__(self, app)
|
||||
FlatCAMTool.__init__(self, app)
|
||||
|
||||
self.app = app
|
||||
self.draw_app = draw_app
|
||||
|
@ -5691,13 +5697,13 @@ class TransformEditorTool(AppTool):
|
|||
except AttributeError:
|
||||
pass
|
||||
|
||||
AppTool.run(self)
|
||||
FlatCAMTool.run(self)
|
||||
self.set_tool_ui()
|
||||
|
||||
self.app.ui.notebook.setTabText(2, _("Transform Tool"))
|
||||
|
||||
def install(self, icon=None, separator=None, **kwargs):
|
||||
AppTool.install(self, icon, separator, shortcut='Alt+T', **kwargs)
|
||||
FlatCAMTool.install(self, icon, separator, shortcut='Alt+T', **kwargs)
|
||||
|
||||
def set_tool_ui(self):
|
||||
# Initialize form
|
|
@ -5,7 +5,7 @@
|
|||
# MIT Licence #
|
||||
# ##########################################################
|
||||
|
||||
from AppGUI.GUIElements import FCFileSaveDialog, FCEntry, FCTextAreaExtended, FCTextAreaLineNumber
|
||||
from flatcamGUI.GUIElements import FCFileSaveDialog, FCEntry, FCTextAreaExtended, FCTextAreaLineNumber
|
||||
from PyQt5 import QtPrintSupport, QtWidgets, QtCore, QtGui
|
||||
|
||||
from reportlab.platypus import SimpleDocTemplate, Paragraph
|
||||
|
@ -15,7 +15,7 @@ from reportlab.lib.units import inch, mm
|
|||
# from io import StringIO
|
||||
|
||||
import gettext
|
||||
import AppTranslation as fcTranslate
|
||||
import FlatCAMTranslation as fcTranslate
|
||||
import builtins
|
||||
|
||||
fcTranslate.apply_language('strings')
|
||||
|
@ -214,10 +214,10 @@ class TextEditor(QtWidgets.QWidget):
|
|||
filename = str(FCFileSaveDialog.get_saved_filename(
|
||||
caption=_("Export Code ..."),
|
||||
directory=self.app.defaults["global_last_folder"] + '/' + str(obj_name),
|
||||
ext_filter=_filter_
|
||||
filter=_filter_
|
||||
)[0])
|
||||
except TypeError:
|
||||
filename = str(FCFileSaveDialog.get_saved_filename(caption=_("Export Code ..."), ext_filter=_filter_)[0])
|
||||
filename = str(FCFileSaveDialog.get_saved_filename(caption=_("Export Code ..."), filter=_filter_)[0])
|
||||
|
||||
if filename == "":
|
||||
self.app.inform.emit('[WARNING_NOTCL] %s' % _("Cancelled."))
|
|
@ -23,7 +23,7 @@ import html
|
|||
import sys
|
||||
|
||||
import gettext
|
||||
import AppTranslation as fcTranslate
|
||||
import FlatCAMTranslation as fcTranslate
|
||||
import builtins
|
||||
|
||||
log = logging.getLogger('base')
|
||||
|
@ -570,13 +570,9 @@ class FCEntry3(FCEntry):
|
|||
|
||||
|
||||
class EvalEntry(QtWidgets.QLineEdit):
|
||||
def __init__(self, border_color=None, parent=None):
|
||||
def __init__(self, parent=None):
|
||||
super(EvalEntry, self).__init__(parent)
|
||||
self.readyToEdit = True
|
||||
|
||||
if border_color:
|
||||
self.setStyleSheet("QLineEdit {border: 1px solid %s;}" % border_color)
|
||||
|
||||
self.editingFinished.connect(self.on_edit_finished)
|
||||
|
||||
def on_edit_finished(self):
|
||||
|
@ -603,6 +599,7 @@ class EvalEntry(QtWidgets.QLineEdit):
|
|||
|
||||
def get_value(self):
|
||||
raw = str(self.text()).strip(' ')
|
||||
evaled = 0.0
|
||||
try:
|
||||
evaled = eval(raw)
|
||||
except Exception as e:
|
||||
|
@ -642,7 +639,7 @@ class EvalEntry2(QtWidgets.QLineEdit):
|
|||
|
||||
def get_value(self):
|
||||
raw = str(self.text()).strip(' ')
|
||||
|
||||
evaled = 0.0
|
||||
try:
|
||||
evaled = eval(raw)
|
||||
except Exception as e:
|
||||
|
@ -659,132 +656,6 @@ class EvalEntry2(QtWidgets.QLineEdit):
|
|||
return QtCore.QSize(EDIT_SIZE_HINT, default_hint_size.height())
|
||||
|
||||
|
||||
class NumericalEvalEntry(EvalEntry):
|
||||
"""
|
||||
Will evaluate the input and return a value. Accepts only float numbers and formulas using the operators: /,*,+,-,%
|
||||
"""
|
||||
def __init__(self, border_color=None):
|
||||
super().__init__(border_color=border_color)
|
||||
|
||||
regex = QtCore.QRegExp("[0-9\/\*\+\-\%\.\s]*")
|
||||
validator = QtGui.QRegExpValidator(regex, self)
|
||||
self.setValidator(validator)
|
||||
|
||||
|
||||
class NumericalEvalTupleEntry(FCEntry):
|
||||
"""
|
||||
Will evaluate the input and return a value. Accepts only float numbers and formulas using the operators: /,*,+,-,%
|
||||
"""
|
||||
def __init__(self, border_color=None):
|
||||
super().__init__(border_color=border_color)
|
||||
|
||||
regex = QtCore.QRegExp("[0-9\/\*\+\-\%\.\s\,]*")
|
||||
validator = QtGui.QRegExpValidator(regex, self)
|
||||
self.setValidator(validator)
|
||||
|
||||
|
||||
class FCColorEntry(QtWidgets.QFrame):
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
|
||||
self.entry = FCEntry()
|
||||
regex = QtCore.QRegExp("[#A-Fa-f0-9]*")
|
||||
validator = QtGui.QRegExpValidator(regex, self.entry)
|
||||
self.entry.setValidator(validator)
|
||||
|
||||
self.button = QtWidgets.QPushButton()
|
||||
self.button.setFixedSize(15, 15)
|
||||
self.button.setStyleSheet("border-color: dimgray;")
|
||||
|
||||
self.layout = QtWidgets.QHBoxLayout()
|
||||
self.layout.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter)
|
||||
self.layout.setContentsMargins(0, 0, 0, 0)
|
||||
self.layout.addWidget(self.entry)
|
||||
self.layout.addWidget(self.button)
|
||||
self.setLayout(self.layout)
|
||||
|
||||
self.entry.editingFinished.connect(self._sync_button_color)
|
||||
self.button.clicked.connect(self._on_button_clicked)
|
||||
|
||||
self.editingFinished = self.entry.editingFinished
|
||||
|
||||
def get_value(self) -> str:
|
||||
return self.entry.get_value()
|
||||
|
||||
def set_value(self, value: str):
|
||||
self.entry.set_value(value)
|
||||
self._sync_button_color()
|
||||
|
||||
def _sync_button_color(self):
|
||||
value = self.get_value()
|
||||
self.button.setStyleSheet("background-color:%s;" % self._extract_color(value))
|
||||
|
||||
def _on_button_clicked(self):
|
||||
value = self.entry.get_value()
|
||||
current_color = QtGui.QColor(self._extract_color(value))
|
||||
|
||||
color_dialog = QtWidgets.QColorDialog()
|
||||
selected_color = color_dialog.getColor(initial=current_color, options=QtWidgets.QColorDialog.ShowAlphaChannel)
|
||||
|
||||
if selected_color.isValid() is False:
|
||||
return
|
||||
|
||||
new_value = str(selected_color.name()) + self._extract_alpha(value)
|
||||
self.set_value(new_value)
|
||||
|
||||
def _extract_color(self, value: str) -> str:
|
||||
return value[:7]
|
||||
|
||||
def _extract_alpha(self, value: str) -> str:
|
||||
return value[7:9]
|
||||
|
||||
|
||||
class FCSliderWithSpinner(QtWidgets.QFrame):
|
||||
|
||||
def __init__(self, min=0, max=100, step=1, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
|
||||
self.slider = QtWidgets.QSlider(QtCore.Qt.Horizontal)
|
||||
self.slider.setMinimum(min)
|
||||
self.slider.setMaximum(max)
|
||||
self.slider.setSingleStep(step)
|
||||
|
||||
self.spinner = FCSpinner()
|
||||
self.spinner.set_range(min, max)
|
||||
self.spinner.set_step(step)
|
||||
self.spinner.setMinimumWidth(70)
|
||||
|
||||
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred)
|
||||
self.spinner.setSizePolicy(sizePolicy)
|
||||
|
||||
self.layout = QtWidgets.QHBoxLayout()
|
||||
self.layout.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter)
|
||||
self.layout.setContentsMargins(0, 0, 0, 0)
|
||||
self.layout.addWidget(self.slider)
|
||||
self.layout.addWidget(self.spinner)
|
||||
self.setLayout(self.layout)
|
||||
|
||||
self.slider.valueChanged.connect(self._on_slider)
|
||||
self.spinner.valueChanged.connect(self._on_spinner)
|
||||
|
||||
self.valueChanged = self.spinner.valueChanged
|
||||
|
||||
def get_value(self) -> int:
|
||||
return self.spinner.get_value()
|
||||
|
||||
def set_value(self, value: int):
|
||||
self.spinner.set_value(value)
|
||||
|
||||
def _on_spinner(self):
|
||||
spinner_value = self.spinner.value()
|
||||
self.slider.setValue(spinner_value)
|
||||
|
||||
def _on_slider(self):
|
||||
slider_value = self.slider.value()
|
||||
self.spinner.set_value(slider_value)
|
||||
|
||||
|
||||
class FCSpinner(QtWidgets.QSpinBox):
|
||||
|
||||
returnPressed = QtCore.pyqtSignal()
|
||||
|
@ -813,8 +684,6 @@ class FCSpinner(QtWidgets.QSpinBox):
|
|||
self.setAlignment(align_val)
|
||||
|
||||
self.prev_readyToEdit = True
|
||||
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Ignored, QtWidgets.QSizePolicy.Preferred)
|
||||
self.setSizePolicy(sizePolicy)
|
||||
|
||||
def eventFilter(self, object, event):
|
||||
if event.type() == QtCore.QEvent.MouseButtonPress and self.prev_readyToEdit is True:
|
||||
|
@ -947,8 +816,6 @@ class FCDoubleSpinner(QtWidgets.QDoubleSpinBox):
|
|||
self.setAlignment(align_val)
|
||||
|
||||
self.prev_readyToEdit = True
|
||||
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Ignored, QtWidgets.QSizePolicy.Preferred)
|
||||
self.setSizePolicy(sizePolicy)
|
||||
|
||||
def on_edit_finished(self):
|
||||
self.clearFocus()
|
||||
|
@ -2231,24 +2098,6 @@ class FCDetachableTab2(FCDetachableTab):
|
|||
def __init__(self, protect=None, protect_by_name=None, parent=None):
|
||||
super(FCDetachableTab2, self).__init__(protect=protect, protect_by_name=protect_by_name, parent=parent)
|
||||
|
||||
try:
|
||||
self.tabBar.onCloseTabSignal.disconnect()
|
||||
except TypeError:
|
||||
pass
|
||||
|
||||
self.tabBar.onCloseTabSignal.connect(self.on_closetab_middle_button)
|
||||
|
||||
def on_closetab_middle_button(self, current_index):
|
||||
"""
|
||||
|
||||
:param current_index:
|
||||
:return:
|
||||
"""
|
||||
|
||||
# if tab is protected don't delete it
|
||||
if self.tabBar.tabButton(current_index, QtWidgets.QTabBar.RightSide) is not None:
|
||||
self.closeTab(current_index)
|
||||
|
||||
def closeTab(self, currentIndex):
|
||||
"""
|
||||
Slot connected to the tabCloseRequested signal
|
||||
|
@ -2347,14 +2196,11 @@ class OptionalHideInputSection:
|
|||
"""
|
||||
Associates the a checkbox with a set of inputs.
|
||||
|
||||
:param cb: Checkbox that enables the optional inputs.
|
||||
:type cb: QtWidgets.QCheckBox
|
||||
:param optinputs: List of widgets that are optional.
|
||||
:type optinputs: list
|
||||
:param logic: When True the logic is normal, when False the logic is in reverse
|
||||
It means that for logic=True, when the checkbox is checked the widgets are Enabled, and
|
||||
for logic=False, when the checkbox is checked the widgets are Disabled
|
||||
:type logic: bool
|
||||
:param cb: Checkbox that enables the optional inputs.
|
||||
:param optinputs: List of widgets that are optional.
|
||||
:param logic: When True the logic is normal, when False the logic is in reverse
|
||||
It means that for logic=True, when the checkbox is checked the widgets are Enabled, and
|
||||
for logic=False, when the checkbox is checked the widgets are Disabled
|
||||
:return:
|
||||
"""
|
||||
assert isinstance(cb, FCCheckBox), \
|
||||
|
@ -2625,8 +2471,7 @@ class SpinBoxDelegate(QtWidgets.QItemDelegate):
|
|||
def updateEditorGeometry(self, editor, option, index):
|
||||
editor.setGeometry(option.rect)
|
||||
|
||||
@staticmethod
|
||||
def setDecimals(spinbox, digits):
|
||||
def setDecimals(self, spinbox, digits):
|
||||
spinbox.setDecimals(digits)
|
||||
|
||||
|
||||
|
@ -2674,7 +2519,7 @@ class DialogBoxRadio(QtWidgets.QDialog):
|
|||
:param title: string with the window title
|
||||
:param label: string with the message inside the dialog box
|
||||
"""
|
||||
super(DialogBoxRadio, self).__init__(parent=parent)
|
||||
super(DialogBoxRadio, self).__init__()
|
||||
if initial_text is None:
|
||||
self.location = str((0, 0))
|
||||
else:
|
||||
|
@ -2917,12 +2762,9 @@ class MyCompleter(QCompleter):
|
|||
insertText = QtCore.pyqtSignal(str)
|
||||
|
||||
def __init__(self, parent=None):
|
||||
QCompleter.__init__(self, parent=parent)
|
||||
QCompleter.__init__(self)
|
||||
self.setCompletionMode(QCompleter.PopupCompletion)
|
||||
self.highlighted.connect(self.setHighlighted)
|
||||
|
||||
self.lastSelected = ''
|
||||
|
||||
# self.popup().installEventFilter(self)
|
||||
|
||||
# def eventFilter(self, obj, event):
|
||||
|
@ -3078,9 +2920,9 @@ class FCFileSaveDialog(QtWidgets.QFileDialog):
|
|||
super(FCFileSaveDialog, self).__init__(*args)
|
||||
|
||||
@staticmethod
|
||||
def get_saved_filename(parent=None, caption='', directory='', ext_filter='', initialFilter=''):
|
||||
def get_saved_filename(parent=None, caption='', directory='', filter='', initialFilter=''):
|
||||
filename, _filter = QtWidgets.QFileDialog.getSaveFileName(parent=parent, caption=caption,
|
||||
directory=directory, filter=ext_filter,
|
||||
directory=directory, filter=filter,
|
||||
initialFilter=initialFilter)
|
||||
|
||||
filename = str(filename)
|
||||
|
@ -3096,225 +2938,6 @@ class FCFileSaveDialog(QtWidgets.QFileDialog):
|
|||
return filename, _filter
|
||||
|
||||
|
||||
class FCDock(QtWidgets.QDockWidget):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(FCDock, self).__init__(*args)
|
||||
self.close_callback = kwargs["close_callback"] if "close_callback" in kwargs else None
|
||||
|
||||
def closeEvent(self, event: QtGui.QCloseEvent) -> None:
|
||||
self.close_callback()
|
||||
super().closeEvent(event)
|
||||
|
||||
def show(self) -> None:
|
||||
if self.isFloating():
|
||||
self.setFloating(False)
|
||||
super().show()
|
||||
|
||||
|
||||
class FlatCAMActivityView(QtWidgets.QWidget):
|
||||
"""
|
||||
This class create and control the activity icon displayed in the App status bar
|
||||
"""
|
||||
|
||||
def __init__(self, app, parent=None):
|
||||
super().__init__(parent=parent)
|
||||
|
||||
self.app = app
|
||||
|
||||
if self.app.defaults["global_activity_icon"] == "Ball green":
|
||||
icon = self.app.resource_location + '/active_2_static.png'
|
||||
movie = self.app.resource_location + "/active_2.gif"
|
||||
elif self.app.defaults["global_activity_icon"] == "Ball black":
|
||||
icon = self.app.resource_location + '/active_static.png'
|
||||
movie = self.app.resource_location + "/active.gif"
|
||||
elif self.app.defaults["global_activity_icon"] == "Arrow green":
|
||||
icon = self.app.resource_location + '/active_3_static.png'
|
||||
movie = self.app.resource_location + "/active_3.gif"
|
||||
elif self.app.defaults["global_activity_icon"] == "Eclipse green":
|
||||
icon = self.app.resource_location + '/active_4_static.png'
|
||||
movie = self.app.resource_location + "/active_4.gif"
|
||||
else:
|
||||
icon = self.app.resource_location + '/active_static.png'
|
||||
movie = self.app.resource_location + "/active.gif"
|
||||
|
||||
self.setMinimumWidth(200)
|
||||
self.movie_path = movie
|
||||
self.icon_path = icon
|
||||
|
||||
self.icon = FCLabel(self)
|
||||
self.icon.setGeometry(0, 0, 16, 12)
|
||||
self.movie = QtGui.QMovie(self.movie_path)
|
||||
|
||||
self.icon.setMovie(self.movie)
|
||||
# self.movie.start()
|
||||
|
||||
layout = QtWidgets.QHBoxLayout()
|
||||
layout.setContentsMargins(5, 0, 5, 0)
|
||||
layout.setAlignment(QtCore.Qt.AlignLeft)
|
||||
self.setLayout(layout)
|
||||
|
||||
layout.addWidget(self.icon)
|
||||
self.text = QtWidgets.QLabel(self)
|
||||
self.text.setText(_("Idle."))
|
||||
self.icon.setPixmap(QtGui.QPixmap(self.icon_path))
|
||||
|
||||
layout.addWidget(self.text)
|
||||
|
||||
self.icon.clicked.connect(self.app.on_toolbar_replot)
|
||||
|
||||
def set_idle(self):
|
||||
self.movie.stop()
|
||||
self.text.setText(_("Idle."))
|
||||
|
||||
def set_busy(self, msg, no_movie=None):
|
||||
if no_movie is not True:
|
||||
self.icon.setMovie(self.movie)
|
||||
self.movie.start()
|
||||
self.text.setText(msg)
|
||||
|
||||
|
||||
class FlatCAMInfoBar(QtWidgets.QWidget):
|
||||
"""
|
||||
This class create a place to display the App messages in the Status Bar
|
||||
"""
|
||||
|
||||
def __init__(self, parent=None, app=None):
|
||||
super(FlatCAMInfoBar, self).__init__(parent=parent)
|
||||
|
||||
self.app = app
|
||||
|
||||
self.icon = QtWidgets.QLabel(self)
|
||||
self.icon.setGeometry(0, 0, 12, 12)
|
||||
self.pmap = QtGui.QPixmap(self.app.resource_location + '/graylight12.png')
|
||||
self.icon.setPixmap(self.pmap)
|
||||
|
||||
self.lock_pmaps = False
|
||||
|
||||
layout = QtWidgets.QHBoxLayout()
|
||||
layout.setContentsMargins(5, 0, 5, 0)
|
||||
self.setLayout(layout)
|
||||
|
||||
layout.addWidget(self.icon)
|
||||
|
||||
self.text = QtWidgets.QLabel(self)
|
||||
self.text.setText(_("Application started ..."))
|
||||
self.text.setToolTip(_("Hello!"))
|
||||
|
||||
layout.addWidget(self.text)
|
||||
layout.addStretch()
|
||||
|
||||
def set_text_(self, text, color=None):
|
||||
self.text.setText(text)
|
||||
self.text.setToolTip(text)
|
||||
if color:
|
||||
self.text.setStyleSheet('color: %s' % str(color))
|
||||
|
||||
def set_status(self, text, level="info"):
|
||||
level = str(level)
|
||||
|
||||
if self.lock_pmaps is not True:
|
||||
self.pmap.fill()
|
||||
if level == "ERROR" or level == "ERROR_NOTCL":
|
||||
self.pmap = QtGui.QPixmap(self.app.resource_location + '/redlight12.png')
|
||||
elif level.lower() == "success":
|
||||
self.pmap = QtGui.QPixmap(self.app.resource_location + '/greenlight12.png')
|
||||
elif level == "WARNING" or level == "WARNING_NOTCL":
|
||||
self.pmap = QtGui.QPixmap(self.app.resource_location + '/yellowlight12.png')
|
||||
elif level.lower() == "selected":
|
||||
self.pmap = QtGui.QPixmap(self.app.resource_location + '/bluelight12.png')
|
||||
else:
|
||||
self.pmap = QtGui.QPixmap(self.app.resource_location + '/graylight12.png')
|
||||
|
||||
try:
|
||||
self.set_text_(text)
|
||||
self.icon.setPixmap(self.pmap)
|
||||
except Exception as e:
|
||||
log.debug("FlatCAMInfoBar.set_status() --> %s" % str(e))
|
||||
|
||||
|
||||
class FlatCAMSystemTray(QtWidgets.QSystemTrayIcon):
|
||||
"""
|
||||
This class create the Sys Tray icon for the app
|
||||
"""
|
||||
|
||||
def __init__(self, app, icon, headless=None, parent=None):
|
||||
# QtWidgets.QSystemTrayIcon.__init__(self, icon, parent)
|
||||
super().__init__(icon, parent=parent)
|
||||
self.app = app
|
||||
|
||||
menu = QtWidgets.QMenu(parent)
|
||||
|
||||
menu_runscript = QtWidgets.QAction(QtGui.QIcon(self.app.resource_location + '/script14.png'),
|
||||
'%s' % _('Run Script ...'), self)
|
||||
menu_runscript.setToolTip(
|
||||
_("Will run the opened Tcl Script thus\n"
|
||||
"enabling the automation of certain\n"
|
||||
"functions of FlatCAM.")
|
||||
)
|
||||
menu.addAction(menu_runscript)
|
||||
|
||||
menu.addSeparator()
|
||||
|
||||
if headless is None:
|
||||
self.menu_open = menu.addMenu(QtGui.QIcon(self.app.resource_location + '/folder32_bis.png'), _('Open'))
|
||||
|
||||
# Open Project ...
|
||||
menu_openproject = QtWidgets.QAction(QtGui.QIcon(self.app.resource_location + '/folder16.png'),
|
||||
_('Open Project ...'), self)
|
||||
self.menu_open.addAction(menu_openproject)
|
||||
self.menu_open.addSeparator()
|
||||
|
||||
# Open Gerber ...
|
||||
menu_opengerber = QtWidgets.QAction(QtGui.QIcon(self.app.resource_location + '/flatcam_icon24.png'),
|
||||
_('Open &Gerber ...\tCtrl+G'), self)
|
||||
self.menu_open.addAction(menu_opengerber)
|
||||
|
||||
# Open Excellon ...
|
||||
menu_openexcellon = QtWidgets.QAction(QtGui.QIcon(self.app.resource_location + '/open_excellon32.png'),
|
||||
_('Open &Excellon ...\tCtrl+E'), self)
|
||||
self.menu_open.addAction(menu_openexcellon)
|
||||
|
||||
# Open G-Code ...
|
||||
menu_opengcode = QtWidgets.QAction(QtGui.QIcon(self.app.resource_location + '/code.png'),
|
||||
_('Open G-&Code ...'), self)
|
||||
self.menu_open.addAction(menu_opengcode)
|
||||
|
||||
self.menu_open.addSeparator()
|
||||
|
||||
menu_openproject.triggered.connect(self.app.on_file_openproject)
|
||||
menu_opengerber.triggered.connect(self.app.on_fileopengerber)
|
||||
menu_openexcellon.triggered.connect(self.app.on_fileopenexcellon)
|
||||
menu_opengcode.triggered.connect(self.app.on_fileopengcode)
|
||||
|
||||
exitAction = menu.addAction(_("Exit"))
|
||||
exitAction.setIcon(QtGui.QIcon(self.app.resource_location + '/power16.png'))
|
||||
self.setContextMenu(menu)
|
||||
|
||||
menu_runscript.triggered.connect(lambda: self.app.on_filerunscript(
|
||||
silent=True if self.app.cmd_line_headless == 1 else False))
|
||||
|
||||
exitAction.triggered.connect(self.app.final_save)
|
||||
|
||||
|
||||
def message_dialog(title, message, kind="info", parent=None):
|
||||
"""
|
||||
Builds and show a custom QMessageBox to be used in FlatCAM.
|
||||
|
||||
:param title: title of the QMessageBox
|
||||
:param message: message to be displayed
|
||||
:param kind: type of QMessageBox; will display a specific icon.
|
||||
:param parent: parent
|
||||
:return: None
|
||||
"""
|
||||
icon = {"info": QtWidgets.QMessageBox.Information,
|
||||
"warning": QtWidgets.QMessageBox.Warning,
|
||||
"error": QtWidgets.QMessageBox.Critical}[str(kind)]
|
||||
dlg = QtWidgets.QMessageBox(icon, title, message, parent=parent)
|
||||
dlg.setText(message)
|
||||
dlg.exec_()
|
||||
|
||||
|
||||
def rreplace(s, old, new, occurrence):
|
||||
"""
|
||||
Credits go here:
|
|
@ -11,11 +11,11 @@
|
|||
# Date: 3/10/2019 #
|
||||
# ##########################################################
|
||||
|
||||
from AppGUI.GUIElements import *
|
||||
from flatcamGUI.GUIElements import *
|
||||
import sys
|
||||
|
||||
import gettext
|
||||
import AppTranslation as fcTranslate
|
||||
import FlatCAMTranslation as fcTranslate
|
||||
import builtins
|
||||
|
||||
fcTranslate.apply_language('strings')
|
||||
|
@ -35,7 +35,7 @@ class ObjectUI(QtWidgets.QWidget):
|
|||
put UI elements in ObjectUI.custom_box (QtWidgets.QLayout).
|
||||
"""
|
||||
|
||||
def __init__(self, app, icon_file='assets/resources/flatcam_icon32.png', title=_('App Object'),
|
||||
def __init__(self, app, icon_file='assets/resources/flatcam_icon32.png', title=_('FlatCAM Object'),
|
||||
parent=None, common=True):
|
||||
QtWidgets.QWidget.__init__(self, parent=parent)
|
||||
|
||||
|
@ -114,7 +114,7 @@ class ObjectUI(QtWidgets.QWidget):
|
|||
self.common_grid.addWidget(self.transform_label, 2, 0, 1, 2)
|
||||
|
||||
# ### Scale ####
|
||||
self.scale_entry = NumericalEvalEntry(border_color='#0069A9')
|
||||
self.scale_entry = FCEntry()
|
||||
self.scale_entry.set_value(1.0)
|
||||
self.scale_entry.setToolTip(
|
||||
_("Factor by which to multiply\n"
|
||||
|
@ -132,7 +132,7 @@ class ObjectUI(QtWidgets.QWidget):
|
|||
self.common_grid.addWidget(self.scale_button, 3, 1)
|
||||
|
||||
# ### Offset ####
|
||||
self.offsetvector_entry = NumericalEvalTupleEntry(border_color='#0069A9')
|
||||
self.offsetvector_entry = EvalEntry2()
|
||||
self.offsetvector_entry.setText("(0.0, 0.0)")
|
||||
self.offsetvector_entry.setToolTip(
|
||||
_("Amount by which to move the object\n"
|
||||
|
@ -149,30 +149,21 @@ class ObjectUI(QtWidgets.QWidget):
|
|||
self.common_grid.addWidget(self.offsetvector_entry, 4, 0)
|
||||
self.common_grid.addWidget(self.offset_button, 4, 1)
|
||||
|
||||
self.transformations_button = QtWidgets.QPushButton(_('Transformations'))
|
||||
self.transformations_button.setToolTip(
|
||||
_("Geometrical transformations of the current object.")
|
||||
)
|
||||
self.common_grid.addWidget(self.transformations_button, 5, 0, 1, 2)
|
||||
|
||||
layout.addStretch()
|
||||
|
||||
def confirmation_message(self, accepted, minval, maxval):
|
||||
if accepted is False:
|
||||
self.app.inform[str, bool].emit('[WARNING_NOTCL] %s: [%.*f, %.*f]' % (_("Edited value is out of range"),
|
||||
self.decimals,
|
||||
minval,
|
||||
self.decimals,
|
||||
maxval), False)
|
||||
self.app.inform.emit('[WARNING_NOTCL] %s: [%.*f, %.*f]' %
|
||||
(_("Edited value is out of range"), self.decimals, minval, self.decimals, maxval))
|
||||
else:
|
||||
self.app.inform[str, bool].emit('[success] %s' % _("Edited value is within limits."), False)
|
||||
self.app.inform.emit('[success] %s' % _("Edited value is within limits."))
|
||||
|
||||
def confirmation_message_int(self, accepted, minval, maxval):
|
||||
if accepted is False:
|
||||
self.app.inform[str, bool].emit('[WARNING_NOTCL] %s: [%d, %d]' %
|
||||
(_("Edited value is out of range"), minval, maxval), False)
|
||||
self.app.inform.emit('[WARNING_NOTCL] %s: [%d, %d]' %
|
||||
(_("Edited value is out of range"), minval, maxval))
|
||||
else:
|
||||
self.app.inform[str, bool].emit('[success] %s' % _("Edited value is within limits."), False)
|
||||
self.app.inform.emit('[success] %s' % _("Edited value is within limits."))
|
||||
|
||||
|
||||
class GerberObjectUI(ObjectUI):
|
||||
|
@ -214,37 +205,27 @@ class GerberObjectUI(ObjectUI):
|
|||
self.multicolored_cb.setMinimumWidth(55)
|
||||
grid0.addWidget(self.multicolored_cb, 0, 2)
|
||||
|
||||
# Plot CB
|
||||
self.plot_cb = FCCheckBox('%s' % _("Plot"))
|
||||
# self.plot_cb.setLayoutDirection(QtCore.Qt.RightToLeft)
|
||||
self.plot_cb.setToolTip(_("Plot (show) this object."))
|
||||
|
||||
grid0.addWidget(self.plot_cb, 1, 0, 1, 2)
|
||||
|
||||
# ## Object name
|
||||
self.name_hlay = QtWidgets.QHBoxLayout()
|
||||
grid0.addLayout(self.name_hlay, 1, 0, 1, 3)
|
||||
|
||||
self.custom_box.addLayout(self.name_hlay)
|
||||
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)
|
||||
|
||||
# Plot CB
|
||||
self.plot_lbl = FCLabel('%s:' % _("Plot"))
|
||||
self.plot_lbl.setToolTip(_("Plot (show) this object."))
|
||||
self.plot_cb = FCCheckBox()
|
||||
|
||||
grid0.addWidget(self.plot_lbl, 2, 0)
|
||||
grid0.addWidget(self.plot_cb, 2, 1)
|
||||
|
||||
# generate follow
|
||||
self.follow_cb = FCCheckBox('%s' % _("Follow"))
|
||||
self.follow_cb.setToolTip(_("Generate a 'Follow' geometry.\n"
|
||||
"This means that it will cut through\n"
|
||||
"the middle of the trace."))
|
||||
self.follow_cb.setMinimumWidth(55)
|
||||
grid0.addWidget(self.follow_cb, 2, 2)
|
||||
|
||||
hlay_plot = QtWidgets.QHBoxLayout()
|
||||
self.custom_box.addLayout(hlay_plot)
|
||||
|
||||
# ### Gerber Apertures ####
|
||||
self.apertures_table_label = QtWidgets.QLabel('%s:' % _('Apertures'))
|
||||
self.apertures_table_label = QtWidgets.QLabel('<b>%s:</b>' % _('Apertures'))
|
||||
self.apertures_table_label.setToolTip(
|
||||
_("Apertures Table for the Gerber Object.")
|
||||
)
|
||||
|
@ -301,7 +282,254 @@ class GerberObjectUI(ObjectUI):
|
|||
# start with apertures table hidden
|
||||
self.apertures_table.setVisible(False)
|
||||
|
||||
# Buffer Geometry
|
||||
separator_line = QtWidgets.QFrame()
|
||||
separator_line.setFrameShape(QtWidgets.QFrame.HLine)
|
||||
separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
|
||||
self.custom_box.addWidget(separator_line)
|
||||
|
||||
# Isolation Routing
|
||||
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.")
|
||||
)
|
||||
self.custom_box.addWidget(self.isolation_routing_label)
|
||||
|
||||
# ###########################################
|
||||
# ########## NEW GRID #######################
|
||||
# ###########################################
|
||||
|
||||
grid1 = QtWidgets.QGridLayout()
|
||||
self.custom_box.addLayout(grid1)
|
||||
grid1.setColumnStretch(0, 0)
|
||||
grid1.setColumnStretch(1, 1)
|
||||
grid1.setColumnStretch(2, 1)
|
||||
|
||||
# Tool Type
|
||||
self.tool_type_label = QtWidgets.QLabel('%s:' % _('Tool Type'))
|
||||
self.tool_type_label.setToolTip(
|
||||
_("Choose which tool to use for Gerber isolation:\n"
|
||||
"'Circular' or 'V-shape'.\n"
|
||||
"When the 'V-shape' is selected then the tool\n"
|
||||
"diameter will depend on the chosen cut depth.")
|
||||
)
|
||||
self.tool_type_radio = RadioSet([{'label': _('Circular'), 'value': 'circular'},
|
||||
{'label': _('V-Shape'), 'value': 'v'}])
|
||||
|
||||
grid1.addWidget(self.tool_type_label, 0, 0)
|
||||
grid1.addWidget(self.tool_type_radio, 0, 1, 1, 2)
|
||||
|
||||
# Tip Dia
|
||||
self.tipdialabel = QtWidgets.QLabel('%s:' % _('V-Tip Dia'))
|
||||
self.tipdialabel.setToolTip(
|
||||
_("The tip diameter for V-Shape Tool")
|
||||
)
|
||||
self.tipdia_spinner = FCDoubleSpinner(callback=self.confirmation_message)
|
||||
self.tipdia_spinner.set_range(-99.9999, 99.9999)
|
||||
self.tipdia_spinner.set_precision(self.decimals)
|
||||
self.tipdia_spinner.setSingleStep(0.1)
|
||||
self.tipdia_spinner.setWrapping(True)
|
||||
grid1.addWidget(self.tipdialabel, 1, 0)
|
||||
grid1.addWidget(self.tipdia_spinner, 1, 1, 1, 2)
|
||||
|
||||
# Tip Angle
|
||||
self.tipanglelabel = QtWidgets.QLabel('%s:' % _('V-Tip Angle'))
|
||||
self.tipanglelabel.setToolTip(
|
||||
_("The tip angle for V-Shape Tool.\n"
|
||||
"In degree.")
|
||||
)
|
||||
self.tipangle_spinner = FCDoubleSpinner(callback=self.confirmation_message)
|
||||
self.tipangle_spinner.set_range(1, 180)
|
||||
self.tipangle_spinner.set_precision(self.decimals)
|
||||
self.tipangle_spinner.setSingleStep(5)
|
||||
self.tipangle_spinner.setWrapping(True)
|
||||
grid1.addWidget(self.tipanglelabel, 2, 0)
|
||||
grid1.addWidget(self.tipangle_spinner, 2, 1, 1, 2)
|
||||
|
||||
# Cut Z
|
||||
self.cutzlabel = QtWidgets.QLabel('%s:' % _('Cut Z'))
|
||||
self.cutzlabel.setToolTip(
|
||||
_("Cutting depth (negative)\n"
|
||||
"below the copper surface.")
|
||||
)
|
||||
self.cutz_spinner = FCDoubleSpinner(callback=self.confirmation_message)
|
||||
self.cutz_spinner.set_range(-9999.9999, 0.0000)
|
||||
self.cutz_spinner.set_precision(self.decimals)
|
||||
self.cutz_spinner.setSingleStep(0.1)
|
||||
self.cutz_spinner.setWrapping(True)
|
||||
grid1.addWidget(self.cutzlabel, 3, 0)
|
||||
grid1.addWidget(self.cutz_spinner, 3, 1, 1, 2)
|
||||
|
||||
# Tool diameter
|
||||
tdlabel = QtWidgets.QLabel('%s:' % _('Tool dia'))
|
||||
tdlabel.setToolTip(
|
||||
_("Diameter of the cutting tool.\n"
|
||||
"If you want to have an isolation path\n"
|
||||
"inside the actual shape of the Gerber\n"
|
||||
"feature, use a negative value for\n"
|
||||
"this parameter.")
|
||||
)
|
||||
tdlabel.setMinimumWidth(90)
|
||||
self.iso_tool_dia_entry = FCDoubleSpinner(callback=self.confirmation_message)
|
||||
self.iso_tool_dia_entry.set_range(-9999.9999, 9999.9999)
|
||||
self.iso_tool_dia_entry.set_precision(self.decimals)
|
||||
self.iso_tool_dia_entry.setSingleStep(0.1)
|
||||
|
||||
grid1.addWidget(tdlabel, 4, 0)
|
||||
grid1.addWidget(self.iso_tool_dia_entry, 4, 1, 1, 2)
|
||||
|
||||
# Number of Passes
|
||||
passlabel = QtWidgets.QLabel('%s:' % _('# Passes'))
|
||||
passlabel.setToolTip(
|
||||
_("Width of the isolation gap in\n"
|
||||
"number (integer) of tool widths.")
|
||||
)
|
||||
passlabel.setMinimumWidth(90)
|
||||
self.iso_width_entry = FCSpinner(callback=self.confirmation_message_int)
|
||||
self.iso_width_entry.set_range(1, 999)
|
||||
|
||||
grid1.addWidget(passlabel, 5, 0)
|
||||
grid1.addWidget(self.iso_width_entry, 5, 1, 1, 2)
|
||||
|
||||
# Pass overlap
|
||||
overlabel = QtWidgets.QLabel('%s:' % _('Pass overlap'))
|
||||
overlabel.setToolTip(
|
||||
_("How much (percentage) of the tool width to overlap each tool pass.")
|
||||
)
|
||||
overlabel.setMinimumWidth(90)
|
||||
self.iso_overlap_entry = FCDoubleSpinner(suffix='%', callback=self.confirmation_message)
|
||||
self.iso_overlap_entry.set_precision(self.decimals)
|
||||
self.iso_overlap_entry.setWrapping(True)
|
||||
self.iso_overlap_entry.set_range(0.0000, 99.9999)
|
||||
self.iso_overlap_entry.setSingleStep(0.1)
|
||||
grid1.addWidget(overlabel, 6, 0)
|
||||
grid1.addWidget(self.iso_overlap_entry, 6, 1, 1, 2)
|
||||
|
||||
# Milling Type Radio Button
|
||||
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"
|
||||
"- conventional / useful when there is no backlash compensation")
|
||||
)
|
||||
self.milling_type_radio = RadioSet([{'label': _('Climb'), 'value': 'cl'},
|
||||
{'label': _('Conventional'), 'value': 'cv'}])
|
||||
grid1.addWidget(self.milling_type_label, 7, 0)
|
||||
grid1.addWidget(self.milling_type_radio, 7, 1, 1, 2)
|
||||
|
||||
# combine all passes CB
|
||||
self.combine_passes_cb = FCCheckBox(label=_('Combine'))
|
||||
self.combine_passes_cb.setToolTip(
|
||||
_("Combine all passes into one object")
|
||||
)
|
||||
|
||||
# generate follow
|
||||
self.follow_cb = FCCheckBox(label=_('"Follow"'))
|
||||
self.follow_cb.setToolTip(_("Generate a 'Follow' geometry.\n"
|
||||
"This means that it will cut through\n"
|
||||
"the middle of the trace."))
|
||||
grid1.addWidget(self.combine_passes_cb, 8, 0)
|
||||
|
||||
# avoid an area from isolation
|
||||
self.except_cb = FCCheckBox(label=_('Except'))
|
||||
grid1.addWidget(self.follow_cb, 8, 1)
|
||||
|
||||
self.except_cb.setToolTip(_("When the isolation geometry is generated,\n"
|
||||
"by checking this, the area of the object below\n"
|
||||
"will be subtracted from the isolation geometry."))
|
||||
grid1.addWidget(self.except_cb, 8, 2)
|
||||
|
||||
# ## Form Layout
|
||||
form_layout = QtWidgets.QFormLayout()
|
||||
grid1.addLayout(form_layout, 9, 0, 1, 3)
|
||||
|
||||
# ################################################
|
||||
# ##### Type of object to be excepted ############
|
||||
# ################################################
|
||||
self.type_obj_combo = FCComboBox()
|
||||
self.type_obj_combo.addItems([_("Gerber"), _("Geometry")])
|
||||
|
||||
# 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(self.resource_loc + "/flatcam_icon16.png"))
|
||||
self.type_obj_combo.setItemIcon(1, QtGui.QIcon(self.resource_loc + "/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 excepted from isolation.\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 excepted ################
|
||||
# ################################################
|
||||
self.obj_combo = FCComboBox()
|
||||
|
||||
self.obj_label = QtWidgets.QLabel('%s:' % _("Object"))
|
||||
self.obj_label.setToolTip(_("Object whose area will be removed from isolation geometry."))
|
||||
|
||||
form_layout.addRow(self.obj_label, self.obj_combo)
|
||||
|
||||
# ---------------------------------------------- #
|
||||
# --------- Isolation scope -------------------- #
|
||||
# ---------------------------------------------- #
|
||||
self.iso_scope_label = QtWidgets.QLabel('<b>%s:</b>' % _('Scope'))
|
||||
self.iso_scope_label.setToolTip(
|
||||
_("Isolation scope. Choose what to isolate:\n"
|
||||
"- 'All' -> Isolate all the polygons in the object\n"
|
||||
"- 'Selection' -> Isolate a selection of polygons.")
|
||||
)
|
||||
self.iso_scope_radio = RadioSet([{'label': _('All'), 'value': 'all'},
|
||||
{'label': _('Selection'), 'value': 'single'}])
|
||||
|
||||
grid1.addWidget(self.iso_scope_label, 10, 0)
|
||||
grid1.addWidget(self.iso_scope_radio, 10, 1, 1, 2)
|
||||
|
||||
# ---------------------------------------------- #
|
||||
# --------- Isolation type -------------------- #
|
||||
# ---------------------------------------------- #
|
||||
self.iso_type_label = QtWidgets.QLabel('<b>%s:</b>' % _('Isolation Type'))
|
||||
self.iso_type_label.setToolTip(
|
||||
_("Choose how the isolation will be executed:\n"
|
||||
"- 'Full' -> complete isolation of polygons\n"
|
||||
"- 'Ext' -> will isolate only on the outside\n"
|
||||
"- 'Int' -> will isolate only on the inside\n"
|
||||
"'Exterior' isolation is almost always possible\n"
|
||||
"(with the right tool) but 'Interior'\n"
|
||||
"isolation can be done only when there is an opening\n"
|
||||
"inside of the polygon (e.g polygon is a 'doughnut' shape).")
|
||||
)
|
||||
self.iso_type_radio = RadioSet([{'label': _('Full'), 'value': 'full'},
|
||||
{'label': _('Ext'), 'value': 'ext'},
|
||||
{'label': _('Int'), 'value': 'int'}])
|
||||
|
||||
grid1.addWidget(self.iso_type_label, 11, 0)
|
||||
grid1.addWidget(self.iso_type_radio, 11, 1, 1, 2)
|
||||
|
||||
self.generate_iso_button = QtWidgets.QPushButton("%s" % _("Generate Isolation Geometry"))
|
||||
self.generate_iso_button.setStyleSheet("""
|
||||
QPushButton
|
||||
{
|
||||
font-weight: bold;
|
||||
}
|
||||
""")
|
||||
self.generate_iso_button.setToolTip(
|
||||
_("Create a Geometry object with toolpaths to cut \n"
|
||||
"isolation outside, inside or on both sides of the\n"
|
||||
"object. For a Gerber object outside means outside\n"
|
||||
"of the Gerber feature and inside means inside of\n"
|
||||
"the Gerber feature, if possible at all. This means\n"
|
||||
"that only if the Gerber feature has openings inside, they\n"
|
||||
"will be isolated. If what is wanted is to cut isolation\n"
|
||||
"inside the actual Gerber feature, use a negative tool\n"
|
||||
"diameter above.")
|
||||
)
|
||||
grid1.addWidget(self.generate_iso_button, 12, 0, 1, 3)
|
||||
|
||||
self.create_buffer_button = QtWidgets.QPushButton(_('Buffer Solid Geometry'))
|
||||
self.create_buffer_button.setToolTip(
|
||||
_("This button is shown only when the Gerber file\n"
|
||||
|
@ -309,12 +537,19 @@ class GerberObjectUI(ObjectUI):
|
|||
"Clicking this will create the buffered geometry\n"
|
||||
"required for isolation.")
|
||||
)
|
||||
self.custom_box.addWidget(self.create_buffer_button)
|
||||
grid1.addWidget(self.create_buffer_button, 13, 0, 1, 3)
|
||||
|
||||
separator_line = QtWidgets.QFrame()
|
||||
separator_line.setFrameShape(QtWidgets.QFrame.HLine)
|
||||
separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
|
||||
self.custom_box.addWidget(separator_line)
|
||||
self.ohis_iso = OptionalHideInputSection(
|
||||
self.except_cb,
|
||||
[self.type_obj_combo, self.type_obj_combo_label, self.obj_combo, self.obj_label],
|
||||
logic=True
|
||||
)
|
||||
|
||||
separator_line2 = QtWidgets.QFrame()
|
||||
separator_line2.setFrameShape(QtWidgets.QFrame.HLine)
|
||||
separator_line2.setFrameShadow(QtWidgets.QFrame.Sunken)
|
||||
grid1.addWidget(separator_line2, 14, 0, 1, 3)
|
||||
# grid1.addWidget(QtWidgets.QLabel(''), 15, 0)
|
||||
|
||||
# ###########################################
|
||||
# ########## NEW GRID #######################
|
||||
|
@ -328,21 +563,14 @@ class GerberObjectUI(ObjectUI):
|
|||
self.tool_lbl = QtWidgets.QLabel('<b>%s</b>' % _("TOOLS"))
|
||||
grid2.addWidget(self.tool_lbl, 0, 0, 1, 2)
|
||||
|
||||
# Isolation Tool - will create isolation paths around the copper features
|
||||
self.iso_button = QtWidgets.QPushButton(_('Isolation Routing'))
|
||||
self.iso_button.setToolTip(
|
||||
_("Create a Geometry object with\n"
|
||||
"toolpaths to cut around polygons.")
|
||||
)
|
||||
self.iso_button.setStyleSheet("""
|
||||
QPushButton
|
||||
{
|
||||
font-weight: bold;
|
||||
}
|
||||
""")
|
||||
grid2.addWidget(self.iso_button, 1, 0, 1, 2)
|
||||
|
||||
# ## Clear non-copper regions
|
||||
self.clearcopper_label = QtWidgets.QLabel("%s" % _("Clear N-copper"))
|
||||
self.clearcopper_label.setToolTip(
|
||||
_("Create a Geometry object with\n"
|
||||
"toolpaths to cut all non-copper regions.")
|
||||
)
|
||||
self.clearcopper_label.setMinimumWidth(90)
|
||||
|
||||
self.generate_ncc_button = QtWidgets.QPushButton(_('NCC Tool'))
|
||||
self.generate_ncc_button.setToolTip(
|
||||
_("Create the Geometry Object\n"
|
||||
|
@ -354,9 +582,17 @@ class GerberObjectUI(ObjectUI):
|
|||
font-weight: bold;
|
||||
}
|
||||
""")
|
||||
grid2.addWidget(self.generate_ncc_button, 2, 0, 1, 2)
|
||||
grid2.addWidget(self.clearcopper_label, 1, 0)
|
||||
grid2.addWidget(self.generate_ncc_button, 1, 1)
|
||||
|
||||
# ## Board cutout
|
||||
self.board_cutout_label = QtWidgets.QLabel("%s" % _("Board cutout"))
|
||||
self.board_cutout_label.setToolTip(
|
||||
_("Create toolpaths to cut around\n"
|
||||
"the PCB and separate it from\n"
|
||||
"the original board.")
|
||||
)
|
||||
|
||||
self.generate_cutout_button = QtWidgets.QPushButton(_('Cutout Tool'))
|
||||
self.generate_cutout_button.setToolTip(
|
||||
_("Generate the geometry for\n"
|
||||
|
@ -368,12 +604,13 @@ class GerberObjectUI(ObjectUI):
|
|||
font-weight: bold;
|
||||
}
|
||||
""")
|
||||
grid2.addWidget(self.generate_cutout_button, 3, 0, 1, 2)
|
||||
grid2.addWidget(self.board_cutout_label, 2, 0)
|
||||
grid2.addWidget(self.generate_cutout_button, 2, 1)
|
||||
|
||||
separator_line = QtWidgets.QFrame()
|
||||
separator_line.setFrameShape(QtWidgets.QFrame.HLine)
|
||||
separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
|
||||
grid2.addWidget(separator_line, 4, 0, 1, 2)
|
||||
grid2.addWidget(separator_line, 3, 0, 1, 2)
|
||||
|
||||
# ## Non-copper regions
|
||||
self.noncopper_label = QtWidgets.QLabel("<b>%s</b>" % _("Non-copper regions"))
|
||||
|
@ -385,7 +622,7 @@ class GerberObjectUI(ObjectUI):
|
|||
"copper from a specified region.")
|
||||
)
|
||||
|
||||
grid2.addWidget(self.noncopper_label, 5, 0, 1, 2)
|
||||
grid2.addWidget(self.noncopper_label, 4, 0, 1, 2)
|
||||
|
||||
# Margin
|
||||
bmlabel = QtWidgets.QLabel('%s:' % _('Boundary Margin'))
|
||||
|
@ -401,8 +638,8 @@ class GerberObjectUI(ObjectUI):
|
|||
self.noncopper_margin_entry.set_precision(self.decimals)
|
||||
self.noncopper_margin_entry.setSingleStep(0.1)
|
||||
|
||||
grid2.addWidget(bmlabel, 6, 0)
|
||||
grid2.addWidget(self.noncopper_margin_entry, 6, 1)
|
||||
grid2.addWidget(bmlabel, 5, 0)
|
||||
grid2.addWidget(self.noncopper_margin_entry, 5, 1)
|
||||
|
||||
# Rounded corners
|
||||
self.noncopper_rounded_cb = FCCheckBox(label=_("Rounded Geo"))
|
||||
|
@ -412,13 +649,13 @@ class GerberObjectUI(ObjectUI):
|
|||
self.noncopper_rounded_cb.setMinimumWidth(90)
|
||||
|
||||
self.generate_noncopper_button = QtWidgets.QPushButton(_('Generate Geo'))
|
||||
grid2.addWidget(self.noncopper_rounded_cb, 7, 0)
|
||||
grid2.addWidget(self.generate_noncopper_button, 7, 1)
|
||||
grid2.addWidget(self.noncopper_rounded_cb, 6, 0)
|
||||
grid2.addWidget(self.generate_noncopper_button, 6, 1)
|
||||
|
||||
separator_line1 = QtWidgets.QFrame()
|
||||
separator_line1.setFrameShape(QtWidgets.QFrame.HLine)
|
||||
separator_line1.setFrameShadow(QtWidgets.QFrame.Sunken)
|
||||
grid2.addWidget(separator_line1, 8, 0, 1, 2)
|
||||
grid2.addWidget(separator_line1, 7, 0, 1, 2)
|
||||
|
||||
# ## Bounding box
|
||||
self.boundingbox_label = QtWidgets.QLabel('<b>%s</b>' % _('Bounding Box'))
|
||||
|
@ -427,7 +664,7 @@ class GerberObjectUI(ObjectUI):
|
|||
"Square shape.")
|
||||
)
|
||||
|
||||
grid2.addWidget(self.boundingbox_label, 9, 0, 1, 2)
|
||||
grid2.addWidget(self.boundingbox_label, 8, 0, 1, 2)
|
||||
|
||||
bbmargin = QtWidgets.QLabel('%s:' % _('Boundary Margin'))
|
||||
bbmargin.setToolTip(
|
||||
|
@ -440,8 +677,8 @@ class GerberObjectUI(ObjectUI):
|
|||
self.bbmargin_entry.set_precision(self.decimals)
|
||||
self.bbmargin_entry.setSingleStep(0.1)
|
||||
|
||||
grid2.addWidget(bbmargin, 10, 0)
|
||||
grid2.addWidget(self.bbmargin_entry, 10, 1)
|
||||
grid2.addWidget(bbmargin, 9, 0)
|
||||
grid2.addWidget(self.bbmargin_entry, 9, 1)
|
||||
|
||||
self.bbrounded_cb = FCCheckBox(label=_("Rounded Geo"))
|
||||
self.bbrounded_cb.setToolTip(
|
||||
|
@ -456,8 +693,8 @@ class GerberObjectUI(ObjectUI):
|
|||
self.generate_bb_button.setToolTip(
|
||||
_("Generate the Geometry object.")
|
||||
)
|
||||
grid2.addWidget(self.bbrounded_cb, 11, 0)
|
||||
grid2.addWidget(self.generate_bb_button, 11, 1)
|
||||
grid2.addWidget(self.bbrounded_cb, 10, 0)
|
||||
grid2.addWidget(self.generate_bb_button, 10, 1)
|
||||
|
||||
|
||||
class ExcellonObjectUI(ObjectUI):
|
||||
|
@ -486,38 +723,22 @@ class ExcellonObjectUI(ObjectUI):
|
|||
parent=parent,
|
||||
app=self.app)
|
||||
|
||||
# Plot options
|
||||
grid_h = QtWidgets.QGridLayout()
|
||||
grid_h.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter)
|
||||
self.custom_box.addLayout(grid_h)
|
||||
grid_h.setColumnStretch(0, 0)
|
||||
grid_h.setColumnStretch(1, 1)
|
||||
# ### Plot options ####
|
||||
hlay_plot = QtWidgets.QHBoxLayout()
|
||||
self.custom_box.addLayout(hlay_plot)
|
||||
|
||||
self.plot_options_label = QtWidgets.QLabel("<b>%s:</b>" % _("Plot Options"))
|
||||
self.plot_options_label.setMinimumWidth(90)
|
||||
|
||||
grid_h.addWidget(self.plot_options_label, 0, 0)
|
||||
|
||||
# Solid CB
|
||||
self.solid_cb = FCCheckBox(label=_('Solid'))
|
||||
self.solid_cb.setToolTip(
|
||||
_("Solid circles.")
|
||||
)
|
||||
self.solid_cb.setMinimumWidth(50)
|
||||
grid_h.addWidget(self.solid_cb, 0, 1)
|
||||
|
||||
# Multicolored CB
|
||||
self.multicolored_cb = FCCheckBox(label=_('Multi-Color'))
|
||||
self.multicolored_cb.setToolTip(
|
||||
_("Draw polygons in different colors.")
|
||||
)
|
||||
self.multicolored_cb.setMinimumWidth(55)
|
||||
grid_h.addWidget(self.multicolored_cb, 0, 2)
|
||||
hlay_plot.addWidget(self.plot_options_label)
|
||||
hlay_plot.addStretch()
|
||||
hlay_plot.addWidget(self.solid_cb)
|
||||
|
||||
# ## Object name
|
||||
self.name_hlay = QtWidgets.QHBoxLayout()
|
||||
grid_h.addLayout(self.name_hlay, 1, 0, 1, 3)
|
||||
|
||||
self.custom_box.addLayout(self.name_hlay)
|
||||
name_label = QtWidgets.QLabel("<b>%s:</b>" % _("Name"))
|
||||
self.name_entry = FCEntry()
|
||||
self.name_entry.setFocusPolicy(QtCore.Qt.StrongFocus)
|
||||
|
@ -1304,28 +1525,12 @@ class GeometryObjectUI(ObjectUI):
|
|||
)
|
||||
|
||||
# Plot options
|
||||
grid_header = QtWidgets.QGridLayout()
|
||||
grid_header.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter)
|
||||
self.custom_box.addLayout(grid_header)
|
||||
grid_header.setColumnStretch(0, 0)
|
||||
grid_header.setColumnStretch(1, 1)
|
||||
|
||||
self.plot_options_label = QtWidgets.QLabel("<b>%s:</b>" % _("Plot Options"))
|
||||
self.plot_options_label.setMinimumWidth(90)
|
||||
|
||||
grid_header.addWidget(self.plot_options_label, 0, 0)
|
||||
|
||||
# Multicolored CB
|
||||
self.multicolored_cb = FCCheckBox(label=_('Multi-Color'))
|
||||
self.multicolored_cb.setToolTip(
|
||||
_("Draw polygons in different colors.")
|
||||
)
|
||||
self.multicolored_cb.setMinimumWidth(55)
|
||||
grid_header.addWidget(self.multicolored_cb, 0, 2)
|
||||
self.custom_box.addWidget(self.plot_options_label)
|
||||
|
||||
# ## Object name
|
||||
self.name_hlay = QtWidgets.QHBoxLayout()
|
||||
grid_header.addLayout(self.name_hlay, 1, 0, 1, 3)
|
||||
self.custom_box.addLayout(self.name_hlay)
|
||||
|
||||
name_label = QtWidgets.QLabel("<b>%s:</b>" % _("Name"))
|
||||
self.name_entry = FCEntry()
|
||||
|
@ -1489,24 +1694,19 @@ class GeometryObjectUI(ObjectUI):
|
|||
grid1.addWidget(self.addtool_entry_lbl, 3, 0)
|
||||
grid1.addWidget(self.addtool_entry, 3, 1)
|
||||
|
||||
bhlay = QtWidgets.QHBoxLayout()
|
||||
|
||||
self.addtool_btn = QtWidgets.QPushButton(_('Add'))
|
||||
self.addtool_btn.setToolTip(
|
||||
_("Add a new tool to the Tool Table\n"
|
||||
"with the diameter specified above.")
|
||||
"with the specified diameter.")
|
||||
)
|
||||
grid1.addWidget(self.addtool_btn, 4, 0, 1, 2)
|
||||
|
||||
self.addtool_from_db_btn = QtWidgets.QPushButton(_('Add from DB'))
|
||||
self.addtool_from_db_btn.setToolTip(
|
||||
_("Add a new tool to the Tool Table\n"
|
||||
"from the Tool DataBase.")
|
||||
)
|
||||
|
||||
bhlay.addWidget(self.addtool_btn)
|
||||
bhlay.addWidget(self.addtool_from_db_btn)
|
||||
|
||||
grid1.addLayout(bhlay, 5, 0, 1, 2)
|
||||
grid1.addWidget(self.addtool_from_db_btn, 7, 0, 1, 2)
|
||||
|
||||
separator_line = QtWidgets.QFrame()
|
||||
separator_line.setFrameShape(QtWidgets.QFrame.HLine)
|
||||
|
@ -1554,10 +1754,10 @@ class GeometryObjectUI(ObjectUI):
|
|||
# ################# GRID LAYOUT 3 ###############################
|
||||
# #################################################################
|
||||
|
||||
self.grid3 = QtWidgets.QGridLayout()
|
||||
self.grid3.setColumnStretch(0, 0)
|
||||
self.grid3.setColumnStretch(1, 1)
|
||||
self.geo_param_box.addLayout(self.grid3)
|
||||
grid3 = QtWidgets.QGridLayout()
|
||||
grid3.setColumnStretch(0, 0)
|
||||
grid3.setColumnStretch(1, 1)
|
||||
self.geo_param_box.addLayout(grid3)
|
||||
|
||||
# ### Tools Data ## ##
|
||||
self.tool_data_label = QtWidgets.QLabel(
|
||||
|
@ -1568,7 +1768,7 @@ class GeometryObjectUI(ObjectUI):
|
|||
"Each tool store it's own set of such data."
|
||||
)
|
||||
)
|
||||
self.grid3.addWidget(self.tool_data_label, 0, 0, 1, 2)
|
||||
grid3.addWidget(self.tool_data_label, 0, 0, 1, 2)
|
||||
|
||||
# Tip Dia
|
||||
self.tipdialabel = QtWidgets.QLabel('%s:' % _('V-Tip Dia'))
|
||||
|
@ -1582,8 +1782,8 @@ class GeometryObjectUI(ObjectUI):
|
|||
self.tipdia_entry.set_range(0.00001, 9999.9999)
|
||||
self.tipdia_entry.setSingleStep(0.1)
|
||||
|
||||
self.grid3.addWidget(self.tipdialabel, 1, 0)
|
||||
self.grid3.addWidget(self.tipdia_entry, 1, 1)
|
||||
grid3.addWidget(self.tipdialabel, 1, 0)
|
||||
grid3.addWidget(self.tipdia_entry, 1, 1)
|
||||
|
||||
# Tip Angle
|
||||
self.tipanglelabel = QtWidgets.QLabel('%s:' % _('V-Tip Angle'))
|
||||
|
@ -1598,8 +1798,8 @@ class GeometryObjectUI(ObjectUI):
|
|||
self.tipangle_entry.set_range(1.0, 180.0)
|
||||
self.tipangle_entry.setSingleStep(1)
|
||||
|
||||
self.grid3.addWidget(self.tipanglelabel, 2, 0)
|
||||
self.grid3.addWidget(self.tipangle_entry, 2, 1)
|
||||
grid3.addWidget(self.tipanglelabel, 2, 0)
|
||||
grid3.addWidget(self.tipangle_entry, 2, 1)
|
||||
|
||||
# Cut Z
|
||||
self.cutzlabel = QtWidgets.QLabel('%s:' % _('Cut Z'))
|
||||
|
@ -1619,8 +1819,8 @@ class GeometryObjectUI(ObjectUI):
|
|||
|
||||
self.cutz_entry.setSingleStep(0.1)
|
||||
|
||||
self.grid3.addWidget(self.cutzlabel, 3, 0)
|
||||
self.grid3.addWidget(self.cutz_entry, 3, 1)
|
||||
grid3.addWidget(self.cutzlabel, 3, 0)
|
||||
grid3.addWidget(self.cutz_entry, 3, 1)
|
||||
|
||||
# Multi-pass
|
||||
self.mpass_cb = FCCheckBox('%s:' % _("Multi-Depth"))
|
||||
|
@ -1645,8 +1845,8 @@ class GeometryObjectUI(ObjectUI):
|
|||
)
|
||||
self.ois_mpass_geo = OptionalInputSection(self.mpass_cb, [self.maxdepth_entry])
|
||||
|
||||
self.grid3.addWidget(self.mpass_cb, 4, 0)
|
||||
self.grid3.addWidget(self.maxdepth_entry, 4, 1)
|
||||
grid3.addWidget(self.mpass_cb, 4, 0)
|
||||
grid3.addWidget(self.maxdepth_entry, 4, 1)
|
||||
|
||||
# Travel Z
|
||||
self.travelzlabel = QtWidgets.QLabel('%s:' % _('Travel Z'))
|
||||
|
@ -1664,8 +1864,8 @@ class GeometryObjectUI(ObjectUI):
|
|||
|
||||
self.travelz_entry.setSingleStep(0.1)
|
||||
|
||||
self.grid3.addWidget(self.travelzlabel, 5, 0)
|
||||
self.grid3.addWidget(self.travelz_entry, 5, 1)
|
||||
grid3.addWidget(self.travelzlabel, 5, 0)
|
||||
grid3.addWidget(self.travelz_entry, 5, 1)
|
||||
|
||||
# Feedrate X-Y
|
||||
self.frlabel = QtWidgets.QLabel('%s:' % _('Feedrate X-Y'))
|
||||
|
@ -1678,8 +1878,8 @@ class GeometryObjectUI(ObjectUI):
|
|||
self.cncfeedrate_entry.set_range(0, 99999.9999)
|
||||
self.cncfeedrate_entry.setSingleStep(0.1)
|
||||
|
||||
self.grid3.addWidget(self.frlabel, 10, 0)
|
||||
self.grid3.addWidget(self.cncfeedrate_entry, 10, 1)
|
||||
grid3.addWidget(self.frlabel, 10, 0)
|
||||
grid3.addWidget(self.cncfeedrate_entry, 10, 1)
|
||||
|
||||
# Feedrate Z (Plunge)
|
||||
self.frzlabel = QtWidgets.QLabel('%s:' % _('Feedrate Z'))
|
||||
|
@ -1693,8 +1893,8 @@ class GeometryObjectUI(ObjectUI):
|
|||
self.feedrate_z_entry.set_range(0, 99999.9999)
|
||||
self.feedrate_z_entry.setSingleStep(0.1)
|
||||
|
||||
self.grid3.addWidget(self.frzlabel, 11, 0)
|
||||
self.grid3.addWidget(self.feedrate_z_entry, 11, 1)
|
||||
grid3.addWidget(self.frzlabel, 11, 0)
|
||||
grid3.addWidget(self.feedrate_z_entry, 11, 1)
|
||||
|
||||
# Feedrate rapids
|
||||
self.fr_rapidlabel = QtWidgets.QLabel('%s:' % _('Feedrate Rapids'))
|
||||
|
@ -1710,8 +1910,8 @@ class GeometryObjectUI(ObjectUI):
|
|||
self.feedrate_rapid_entry.set_range(0, 99999.9999)
|
||||
self.feedrate_rapid_entry.setSingleStep(0.1)
|
||||
|
||||
self.grid3.addWidget(self.fr_rapidlabel, 12, 0)
|
||||
self.grid3.addWidget(self.feedrate_rapid_entry, 12, 1)
|
||||
grid3.addWidget(self.fr_rapidlabel, 12, 0)
|
||||
grid3.addWidget(self.feedrate_rapid_entry, 12, 1)
|
||||
# default values is to hide
|
||||
self.fr_rapidlabel.hide()
|
||||
self.feedrate_rapid_entry.hide()
|
||||
|
@ -1736,8 +1936,8 @@ class GeometryObjectUI(ObjectUI):
|
|||
"meet with last cut, we generate an\n"
|
||||
"extended cut over the first cut section.")
|
||||
)
|
||||
self.grid3.addWidget(self.extracut_cb, 13, 0)
|
||||
self.grid3.addWidget(self.e_cut_entry, 13, 1)
|
||||
grid3.addWidget(self.extracut_cb, 13, 0)
|
||||
grid3.addWidget(self.e_cut_entry, 13, 1)
|
||||
|
||||
# Spindlespeed
|
||||
self.spindle_label = QtWidgets.QLabel('%s:' % _('Spindle speed'))
|
||||
|
@ -1752,8 +1952,8 @@ class GeometryObjectUI(ObjectUI):
|
|||
self.cncspindlespeed_entry.set_range(0, 1000000)
|
||||
self.cncspindlespeed_entry.set_step(100)
|
||||
|
||||
self.grid3.addWidget(self.spindle_label, 14, 0)
|
||||
self.grid3.addWidget(self.cncspindlespeed_entry, 14, 1)
|
||||
grid3.addWidget(self.spindle_label, 14, 0)
|
||||
grid3.addWidget(self.cncspindlespeed_entry, 14, 1)
|
||||
|
||||
# Dwell
|
||||
self.dwell_cb = FCCheckBox('%s:' % _('Dwell'))
|
||||
|
@ -1773,8 +1973,8 @@ class GeometryObjectUI(ObjectUI):
|
|||
)
|
||||
self.ois_dwell_geo = OptionalInputSection(self.dwell_cb, [self.dwelltime_entry])
|
||||
|
||||
self.grid3.addWidget(self.dwell_cb, 15, 0)
|
||||
self.grid3.addWidget(self.dwelltime_entry, 15, 1)
|
||||
grid3.addWidget(self.dwell_cb, 15, 0)
|
||||
grid3.addWidget(self.dwelltime_entry, 15, 1)
|
||||
|
||||
# Probe depth
|
||||
self.pdepth_label = QtWidgets.QLabel('%s:' % _("Probe Z depth"))
|
||||
|
@ -1787,8 +1987,8 @@ class GeometryObjectUI(ObjectUI):
|
|||
self.pdepth_entry.set_range(-9999.9999, 9999.9999)
|
||||
self.pdepth_entry.setSingleStep(0.1)
|
||||
|
||||
self.grid3.addWidget(self.pdepth_label, 17, 0)
|
||||
self.grid3.addWidget(self.pdepth_entry, 17, 1)
|
||||
grid3.addWidget(self.pdepth_label, 17, 0)
|
||||
grid3.addWidget(self.pdepth_entry, 17, 1)
|
||||
|
||||
self.pdepth_label.hide()
|
||||
self.pdepth_entry.setVisible(False)
|
||||
|
@ -1803,8 +2003,8 @@ class GeometryObjectUI(ObjectUI):
|
|||
self.feedrate_probe_entry.set_range(0.0, 9999.9999)
|
||||
self.feedrate_probe_entry.setSingleStep(0.1)
|
||||
|
||||
self.grid3.addWidget(self.feedrate_probe_label, 18, 0)
|
||||
self.grid3.addWidget(self.feedrate_probe_entry, 18, 1)
|
||||
grid3.addWidget(self.feedrate_probe_label, 18, 0)
|
||||
grid3.addWidget(self.feedrate_probe_entry, 18, 1)
|
||||
|
||||
self.feedrate_probe_label.hide()
|
||||
self.feedrate_probe_entry.setVisible(False)
|
|
@ -8,21 +8,13 @@
|
|||
from PyQt5 import QtCore
|
||||
|
||||
import logging
|
||||
from AppGUI.VisPyCanvas import VisPyCanvas, Color
|
||||
from AppGUI.VisPyVisuals import ShapeGroup, ShapeCollection, TextCollection, TextGroup, Cursor
|
||||
from vispy.scene.visuals import InfiniteLine, Line, Rectangle, Text
|
||||
|
||||
import gettext
|
||||
import AppTranslation as fcTranslate
|
||||
import builtins
|
||||
from flatcamGUI.VisPyCanvas import VisPyCanvas, Color
|
||||
from flatcamGUI.VisPyVisuals import ShapeGroup, ShapeCollection, TextCollection, TextGroup, Cursor
|
||||
from vispy.scene.visuals import InfiniteLine, Line
|
||||
|
||||
import numpy as np
|
||||
from vispy.geometry import Rect
|
||||
|
||||
fcTranslate.apply_language('strings')
|
||||
if '_' not in builtins.__dict__:
|
||||
_ = gettext.gettext
|
||||
|
||||
log = logging.getLogger('base')
|
||||
|
||||
|
||||
|
@ -62,12 +54,8 @@ class PlotCanvas(QtCore.QObject, VisPyCanvas):
|
|||
|
||||
if theme == 'white':
|
||||
self.line_color = (0.3, 0.0, 0.0, 1.0)
|
||||
self.rect_hud_color = Color('#0000FF10')
|
||||
self.text_hud_color = 'black'
|
||||
else:
|
||||
self.line_color = (0.4, 0.4, 0.4, 1.0)
|
||||
self.rect_hud_color = Color('#80808040')
|
||||
self.text_hud_color = 'white'
|
||||
|
||||
# workspace lines; I didn't use the rectangle because I didn't want to add another VisPy Node,
|
||||
# which might decrease performance
|
||||
|
@ -141,6 +129,11 @@ class PlotCanvas(QtCore.QObject, VisPyCanvas):
|
|||
self.h_line = InfiniteLine(pos=0, color=(0.70, 0.3, 0.3, 0.8), vertical=False,
|
||||
parent=self.view.scene)
|
||||
|
||||
# draw a rectangle made out of 4 lines on the canvas to serve as a hint for the work area
|
||||
# all CNC have a limited workspace
|
||||
if self.fcapp.defaults['global_workspace'] is True:
|
||||
self.draw_workspace(workspace_size=self.fcapp.defaults["global_workspaceT"])
|
||||
|
||||
self.line_parent = None
|
||||
if self.fcapp.defaults["global_cursor_color_enabled"]:
|
||||
c_color = Color(self.fcapp.defaults["global_cursor_color"]).rgba
|
||||
|
@ -153,61 +146,13 @@ class PlotCanvas(QtCore.QObject, VisPyCanvas):
|
|||
self.cursor_h_line = InfiniteLine(pos=None, color=c_color, vertical=False,
|
||||
parent=self.line_parent)
|
||||
|
||||
# font size
|
||||
qsettings = QtCore.QSettings("Open Source", "FlatCAM")
|
||||
if qsettings.contains("hud_font_size"):
|
||||
fsize = qsettings.value('hud_font_size', type=int)
|
||||
else:
|
||||
fsize = 8
|
||||
|
||||
# units
|
||||
units = self.fcapp.defaults["units"].lower()
|
||||
|
||||
# coordinates and anchors
|
||||
height = fsize * 11 # 90. Constant 11 is something that works
|
||||
width = height * 2 # width is double the height = it is something that works
|
||||
center_x = (width / 2) + 5
|
||||
center_y = (height / 2) + 5
|
||||
|
||||
# text
|
||||
self.text_hud = Text('', color=self.text_hud_color, pos=(10, center_y), method='gpu', anchor_x='left',
|
||||
parent=None)
|
||||
self.text_hud.font_size = fsize
|
||||
self.text_hud.text = 'Dx:\t%s [%s]\nDy:\t%s [%s]\n\nX: \t%s [%s]\nY: \t%s [%s]' % \
|
||||
('0.0000', units, '0.0000', units, '0.0000', units, '0.0000', units)
|
||||
|
||||
# rectangle
|
||||
self.rect_hud = Rectangle(center=(center_x, center_y), width=width, height=height, radius=[5, 5, 5, 5],
|
||||
border_color=self.rect_hud_color, color=self.rect_hud_color, parent=None)
|
||||
self.rect_hud.set_gl_state(depth_test=False)
|
||||
|
||||
# draw a rectangle made out of 4 lines on the canvas to serve as a hint for the work area
|
||||
# all CNC have a limited workspace
|
||||
if self.fcapp.defaults['global_workspace'] is True:
|
||||
self.draw_workspace(workspace_size=self.fcapp.defaults["global_workspaceT"])
|
||||
|
||||
# HUD Display
|
||||
self.hud_enabled = False
|
||||
|
||||
# enable the HUD if it is activated in FlatCAM Preferences
|
||||
if self.fcapp.defaults['global_hud'] is True:
|
||||
self.on_toggle_hud(state=True)
|
||||
|
||||
# Axis Display
|
||||
self.axis_enabled = True
|
||||
|
||||
# enable Axis
|
||||
self.on_toggle_axis(state=True)
|
||||
|
||||
# enable Grid lines
|
||||
self.grid_lines_enabled = True
|
||||
|
||||
self.shape_collections = []
|
||||
|
||||
self.shape_collection = self.new_shape_collection()
|
||||
self.fcapp.pool_recreated.connect(self.on_pool_recreated)
|
||||
self.text_collection = self.new_text_collection()
|
||||
|
||||
# TODO: Should be setting to show/hide CNC job annotations (global or per object)
|
||||
self.text_collection.enabled = True
|
||||
|
||||
self.c = None
|
||||
|
@ -218,76 +163,6 @@ class PlotCanvas(QtCore.QObject, VisPyCanvas):
|
|||
|
||||
self.graph_event_connect('mouse_wheel', self.on_mouse_scroll)
|
||||
|
||||
def on_toggle_axis(self, signal=None, state=None):
|
||||
if state is None:
|
||||
state = not self.axis_enabled
|
||||
|
||||
if state:
|
||||
self.axis_enabled = True
|
||||
self.v_line.parent = self.view.scene
|
||||
self.h_line.parent = self.view.scene
|
||||
self.fcapp.ui.axis_status_label.setStyleSheet("""
|
||||
QLabel
|
||||
{
|
||||
color: black;
|
||||
background-color: orange;
|
||||
}
|
||||
""")
|
||||
self.fcapp.inform[str, bool].emit(_("Axis enabled."), False)
|
||||
else:
|
||||
self.axis_enabled = False
|
||||
self.v_line.parent = None
|
||||
self.h_line.parent = None
|
||||
self.fcapp.ui.axis_status_label.setStyleSheet("")
|
||||
self.fcapp.inform[str, bool].emit(_("Axis disabled."), False)
|
||||
|
||||
def on_toggle_hud(self, signal=None, state=None):
|
||||
if state is None:
|
||||
state = not self.hud_enabled
|
||||
|
||||
if state:
|
||||
self.hud_enabled = True
|
||||
self.rect_hud.parent = self.view
|
||||
self.text_hud.parent = self.view
|
||||
self.fcapp.defaults['global_hud'] = True
|
||||
self.fcapp.ui.hud_label.setStyleSheet("""
|
||||
QLabel
|
||||
{
|
||||
color: black;
|
||||
background-color: mediumpurple;
|
||||
}
|
||||
""")
|
||||
self.fcapp.inform[str, bool].emit(_("HUD enabled."), False)
|
||||
|
||||
else:
|
||||
self.hud_enabled = False
|
||||
self.rect_hud.parent = None
|
||||
self.text_hud.parent = None
|
||||
self.fcapp.defaults['global_hud'] = False
|
||||
self.fcapp.ui.hud_label.setStyleSheet("")
|
||||
self.fcapp.inform[str, bool].emit(_("HUD disabled."), False)
|
||||
|
||||
def on_toggle_grid_lines(self):
|
||||
state = not self.grid_lines_enabled
|
||||
|
||||
if state:
|
||||
self.grid_lines_enabled = True
|
||||
self.grid.parent = self.view.scene
|
||||
self.fcapp.inform[str, bool].emit(_("Grid enabled."), False)
|
||||
else:
|
||||
self.grid_lines_enabled = False
|
||||
self.grid.parent = None
|
||||
self.fcapp.inform[str, bool].emit(_("Grid disabled."), False)
|
||||
|
||||
# HACK: enabling/disabling the cursor seams to somehow update the shapes on screen
|
||||
# - perhaps is a bug in VisPy implementation
|
||||
if self.fcapp.grid_status():
|
||||
self.fcapp.app_cursor.enabled = False
|
||||
self.fcapp.app_cursor.enabled = True
|
||||
else:
|
||||
self.fcapp.app_cursor.enabled = True
|
||||
self.fcapp.app_cursor.enabled = False
|
||||
|
||||
def draw_workspace(self, workspace_size):
|
||||
"""
|
||||
Draw a rectangular shape on canvas to specify our valid workspace.
|
||||
|
@ -308,30 +183,17 @@ class PlotCanvas(QtCore.QObject, VisPyCanvas):
|
|||
|
||||
a = np.array([(0, 0), (dims[0], 0), (dims[0], dims[1]), (0, dims[1])])
|
||||
|
||||
# if not self.workspace_line:
|
||||
# self.workspace_line = Line(pos=np.array((a[0], a[1], a[2], a[3], a[0])), color=(0.70, 0.3, 0.3, 0.7),
|
||||
# antialias=True, method='agg', parent=self.view.scene)
|
||||
# else:
|
||||
# self.workspace_line.parent = self.view.scene
|
||||
self.workspace_line = Line(pos=np.array((a[0], a[1], a[2], a[3], a[0])), color=(0.70, 0.3, 0.3, 0.7),
|
||||
antialias=True, method='agg', parent=self.view.scene)
|
||||
|
||||
self.fcapp.ui.wplace_label.set_value(workspace_size[:3])
|
||||
self.fcapp.ui.wplace_label.setToolTip(workspace_size)
|
||||
self.fcapp.ui.wplace_label.setStyleSheet("""
|
||||
QLabel
|
||||
{
|
||||
color: black;
|
||||
background-color: olivedrab;
|
||||
}
|
||||
""")
|
||||
if not self.workspace_line:
|
||||
self.workspace_line = Line(pos=np.array((a[0], a[1], a[2], a[3], a[0])), color=(0.70, 0.3, 0.3, 0.7),
|
||||
antialias=True, method='agg', parent=self.view.scene)
|
||||
else:
|
||||
self.workspace_line.parent = self.view.scene
|
||||
|
||||
def delete_workspace(self):
|
||||
try:
|
||||
self.workspace_line.parent = None
|
||||
except Exception:
|
||||
pass
|
||||
self.fcapp.ui.wplace_label.setStyleSheet("")
|
||||
|
||||
# redraw the workspace lines on the plot by re adding them to the parent view.scene
|
||||
def restore_workspace(self):
|
|
@ -19,10 +19,8 @@ from shapely.geometry import Polygon, LineString, LinearRing
|
|||
from copy import deepcopy
|
||||
import logging
|
||||
|
||||
import numpy as np
|
||||
|
||||
import gettext
|
||||
import AppTranslation as fcTranslate
|
||||
import FlatCAMTranslation as fcTranslate
|
||||
import builtins
|
||||
|
||||
# Prevent conflict with Qt5 and above.
|
||||
|
@ -31,13 +29,13 @@ mpl_use("Qt5Agg")
|
|||
from matplotlib.figure import Figure
|
||||
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
|
||||
from matplotlib.lines import Line2D
|
||||
from matplotlib.offsetbox import AnchoredText
|
||||
# from matplotlib.widgets import Cursor
|
||||
|
||||
fcTranslate.apply_language('strings')
|
||||
if '_' not in builtins.__dict__:
|
||||
_ = gettext.gettext
|
||||
|
||||
|
||||
log = logging.getLogger('base')
|
||||
|
||||
|
||||
|
@ -47,9 +45,9 @@ class CanvasCache(QtCore.QObject):
|
|||
Case story #1:
|
||||
|
||||
1) No objects in the project.
|
||||
2) Object is created (app_obj.new_object() emits object_created(obj)).
|
||||
2) Object is created (new_object() emits object_created(obj)).
|
||||
on_object_created() adds (i) object to collection and emits
|
||||
(ii) app_obj.new_object_available() then calls (iii) object.plot()
|
||||
(ii) new_object_available() then calls (iii) object.plot()
|
||||
3) object.plot() creates axes if necessary on
|
||||
app.collection.figure. Then plots on it.
|
||||
4) Plots on a cache-size canvas (in background).
|
||||
|
@ -115,7 +113,7 @@ class CanvasCache(QtCore.QObject):
|
|||
|
||||
# Continue to update the cache.
|
||||
|
||||
# def on_app_obj.new_object_available(self):
|
||||
# def on_new_object_available(self):
|
||||
#
|
||||
# log.debug("A new object is available. Should plot it!")
|
||||
|
||||
|
@ -149,13 +147,9 @@ class PlotCanvasLegacy(QtCore.QObject):
|
|||
if self.app.defaults['global_theme'] == 'white':
|
||||
theme_color = '#FFFFFF'
|
||||
tick_color = '#000000'
|
||||
self.rect_hud_color = '#0000FF10'
|
||||
self.text_hud_color = '#000000'
|
||||
else:
|
||||
theme_color = '#000000'
|
||||
tick_color = '#FFFFFF'
|
||||
self.rect_hud_color = '#80808040'
|
||||
self.text_hud_color = '#FFFFFF'
|
||||
|
||||
# workspace lines; I didn't use the rectangle because I didn't want to add another VisPy Node,
|
||||
# which might decrease performance
|
||||
|
@ -301,163 +295,14 @@ class PlotCanvasLegacy(QtCore.QObject):
|
|||
# signal is the mouse is dragging
|
||||
self.is_dragging = False
|
||||
|
||||
self.mouse_press_pos = None
|
||||
|
||||
# signal if there is a doubleclick
|
||||
self.is_dblclk = False
|
||||
|
||||
self.hud_enabled = False
|
||||
self.text_hud = self.Thud(plotcanvas=self)
|
||||
|
||||
# enable Grid lines
|
||||
self.grid_lines_enabled = True
|
||||
|
||||
# draw a rectangle made out of 4 lines on the canvas to serve as a hint for the work area
|
||||
# all CNC have a limited workspace
|
||||
if self.app.defaults['global_workspace'] is True:
|
||||
self.draw_workspace(workspace_size=self.app.defaults["global_workspaceT"])
|
||||
|
||||
if self.app.defaults['global_hud'] is True:
|
||||
self.on_toggle_hud(state=True)
|
||||
|
||||
# Axis Display
|
||||
self.axis_enabled = True
|
||||
|
||||
# enable Axis
|
||||
self.on_toggle_axis(state=True)
|
||||
|
||||
def on_toggle_axis(self, signal=None, state=None):
|
||||
if state is None:
|
||||
state = not self.axis_enabled
|
||||
|
||||
if state:
|
||||
self.axis_enabled = True
|
||||
if self.h_line not in self.axes.lines and self.v_line not in self.axes.lines:
|
||||
self.h_line = self.axes.axhline(color=(0.70, 0.3, 0.3), linewidth=2)
|
||||
self.v_line = self.axes.axvline(color=(0.70, 0.3, 0.3), linewidth=2)
|
||||
self.app.ui.axis_status_label.setStyleSheet("""
|
||||
QLabel
|
||||
{
|
||||
color: black;
|
||||
background-color: orange;
|
||||
}
|
||||
""")
|
||||
self.app.inform[str, bool].emit(_("Axis enabled."), False)
|
||||
else:
|
||||
self.axis_enabled = False
|
||||
if self.h_line in self.axes.lines and self.v_line in self.axes.lines:
|
||||
self.axes.lines.remove(self.h_line)
|
||||
self.axes.lines.remove(self.v_line)
|
||||
self.app.ui.axis_status_label.setStyleSheet("")
|
||||
self.app.inform[str, bool].emit(_("Axis disabled."), False)
|
||||
|
||||
self.canvas.draw()
|
||||
|
||||
def on_toggle_hud(self, signal=None, state=None):
|
||||
if state is None:
|
||||
state = not self.hud_enabled
|
||||
|
||||
if state:
|
||||
self.hud_enabled = True
|
||||
self.text_hud.add_artist()
|
||||
self.app.defaults['global_hud'] = True
|
||||
|
||||
self.app.ui.hud_label.setStyleSheet("""
|
||||
QLabel
|
||||
{
|
||||
color: black;
|
||||
background-color: mediumpurple;
|
||||
}
|
||||
""")
|
||||
self.app.inform[str, bool].emit(_("HUD enabled."), False)
|
||||
else:
|
||||
self.hud_enabled = False
|
||||
self.text_hud.remove_artist()
|
||||
self.app.defaults['global_hud'] = False
|
||||
self.app.ui.hud_label.setStyleSheet("")
|
||||
self.app.inform[str, bool].emit(_("HUD disabled."), False)
|
||||
|
||||
self.canvas.draw()
|
||||
|
||||
class Thud(QtCore.QObject):
|
||||
text_changed = QtCore.pyqtSignal(str)
|
||||
|
||||
def __init__(self, plotcanvas):
|
||||
super().__init__()
|
||||
|
||||
self.p = plotcanvas
|
||||
units = self.p.app.defaults['units']
|
||||
self._text = 'Dx: %s [%s]\nDy: %s [%s]\n\nX: %s [%s]\nY: %s [%s]' % \
|
||||
('0.0000', units, '0.0000', units, '0.0000', units, '0.0000', units)
|
||||
|
||||
# set font size
|
||||
qsettings = QtCore.QSettings("Open Source", "FlatCAM")
|
||||
if qsettings.contains("hud_font_size"):
|
||||
# I multiply with 2.5 because this seems to be the difference between the value taken by the VisPy (3D)
|
||||
# and Matplotlib (Legacy2D FlatCAM graphic engine)
|
||||
fsize = int(qsettings.value('hud_font_size', type=int) * 2.5)
|
||||
else:
|
||||
fsize = 20
|
||||
|
||||
self.hud_holder = AnchoredText(self._text, prop=dict(size=fsize), frameon=True, loc='upper left')
|
||||
self.hud_holder.patch.set_boxstyle("round,pad=0.,rounding_size=0.2")
|
||||
|
||||
fc_color = self.p.rect_hud_color[:-2]
|
||||
fc_alpha = int(self.p.rect_hud_color[-2:], 16) / 255
|
||||
text_color = self.p.text_hud_color
|
||||
|
||||
self.hud_holder.patch.set_facecolor(fc_color)
|
||||
self.hud_holder.patch.set_alpha(fc_alpha)
|
||||
self.hud_holder.patch.set_edgecolor((0, 0, 0, 0))
|
||||
|
||||
self. hud_holder.txt._text.set_color(color=text_color)
|
||||
self.text_changed.connect(self.on_text_changed)
|
||||
|
||||
@property
|
||||
def text(self):
|
||||
return self._text
|
||||
|
||||
@text.setter
|
||||
def text(self, val):
|
||||
self.text_changed.emit(val)
|
||||
self._text = val
|
||||
|
||||
def on_text_changed(self, txt):
|
||||
try:
|
||||
txt = txt.replace('\t', ' ')
|
||||
self.hud_holder.txt.set_text(txt)
|
||||
self.p.canvas.draw()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
def add_artist(self):
|
||||
if self.hud_holder not in self.p.axes.artists:
|
||||
self.p.axes.add_artist(self.hud_holder)
|
||||
|
||||
def remove_artist(self):
|
||||
if self.hud_holder in self.p.axes.artists:
|
||||
self.p.axes.artists.remove(self.hud_holder)
|
||||
|
||||
def on_toggle_grid_lines(self):
|
||||
state = not self.grid_lines_enabled
|
||||
|
||||
if state:
|
||||
self.grid_lines_enabled = True
|
||||
self.axes.grid(True)
|
||||
try:
|
||||
self.canvas.draw()
|
||||
except IndexError:
|
||||
pass
|
||||
self.app.inform[str, bool].emit(_("Grid enabled."), False)
|
||||
else:
|
||||
self.grid_lines_enabled = False
|
||||
self.axes.grid(False)
|
||||
try:
|
||||
self.canvas.draw()
|
||||
except IndexError:
|
||||
pass
|
||||
self.app.inform[str, bool].emit(_("Grid disabled."), False)
|
||||
|
||||
def draw_workspace(self, workspace_size):
|
||||
"""
|
||||
Draw a rectangular shape on canvas to specify our valid workspace.
|
||||
|
@ -484,23 +329,12 @@ class PlotCanvasLegacy(QtCore.QObject):
|
|||
self.axes.add_line(self.workspace_line)
|
||||
self.canvas.draw()
|
||||
|
||||
self.app.ui.wplace_label.set_value(workspace_size[:3])
|
||||
self.app.ui.wplace_label.setToolTip(workspace_size)
|
||||
self.fcapp.ui.wplace_label.setStyleSheet("""
|
||||
QLabel
|
||||
{
|
||||
color: black;
|
||||
background-color: olivedrab;
|
||||
}
|
||||
""")
|
||||
|
||||
def delete_workspace(self):
|
||||
try:
|
||||
self.axes.lines.remove(self.workspace_line)
|
||||
self.canvas.draw()
|
||||
except Exception:
|
||||
pass
|
||||
self.fcapp.ui.wplace_label.setStyleSheet("")
|
||||
|
||||
def graph_event_connect(self, event_name, callback):
|
||||
"""
|
||||
|
@ -589,7 +423,7 @@ class PlotCanvasLegacy(QtCore.QObject):
|
|||
|
||||
if self.big_cursor is False:
|
||||
try:
|
||||
x, y = self.snap(x_pos, y_pos)
|
||||
x, y = self.app.geo_editor.snap(x_pos, y_pos)
|
||||
|
||||
# Pointer (snapped)
|
||||
# The size of the cursor is multiplied by 1.65 because that value made the cursor similar with the
|
||||
|
@ -622,7 +456,7 @@ class PlotCanvasLegacy(QtCore.QObject):
|
|||
pass
|
||||
self.canvas.draw_idle()
|
||||
|
||||
self.canvas.blit(self.axes.bbox)
|
||||
self.canvas.blit(self.axes.bbox)
|
||||
|
||||
def clear_cursor(self, state):
|
||||
if state is True:
|
||||
|
@ -947,7 +781,6 @@ class PlotCanvasLegacy(QtCore.QObject):
|
|||
def on_mouse_press(self, event):
|
||||
|
||||
self.is_dragging = True
|
||||
self.mouse_press_pos = (event.x, event.y)
|
||||
|
||||
# Check for middle mouse button press
|
||||
if self.app.defaults["global_pan_button"] == '2':
|
||||
|
@ -973,11 +806,7 @@ class PlotCanvasLegacy(QtCore.QObject):
|
|||
|
||||
def on_mouse_release(self, event):
|
||||
|
||||
mouse_release_pos = (event.x, event.y)
|
||||
delta = 0.05
|
||||
|
||||
if abs(self.distance(self.mouse_press_pos, mouse_release_pos)) < delta:
|
||||
self.is_dragging = False
|
||||
self.is_dragging = False
|
||||
|
||||
# Check for middle mouse button release to complete pan procedure
|
||||
# Check for middle mouse button press
|
||||
|
@ -1029,7 +858,7 @@ class PlotCanvasLegacy(QtCore.QObject):
|
|||
self.canvas.draw_idle()
|
||||
|
||||
# #### Temporary place-holder for cached update #####
|
||||
# self.update_screen_request.emit([0, 0, 0, 0, 0])
|
||||
self.update_screen_request.emit([0, 0, 0, 0, 0])
|
||||
|
||||
if self.app.defaults["global_cursor_color_enabled"] is True:
|
||||
self.draw_cursor(x_pos=x, y_pos=y, color=self.app.cursor_color_3D)
|
||||
|
@ -1081,59 +910,6 @@ class PlotCanvasLegacy(QtCore.QObject):
|
|||
|
||||
return width / xpx, height / ypx
|
||||
|
||||
def snap(self, x, y):
|
||||
"""
|
||||
Adjusts coordinates to snap settings.
|
||||
|
||||
:param x: Input coordinate X
|
||||
:param y: Input coordinate Y
|
||||
:return: Snapped (x, y)
|
||||
"""
|
||||
|
||||
snap_x, snap_y = (x, y)
|
||||
snap_distance = np.Inf
|
||||
|
||||
# ### Grid snap
|
||||
if self.app.grid_status():
|
||||
if self.app.defaults["global_gridx"] != 0:
|
||||
try:
|
||||
snap_x_ = round(x / float(self.app.defaults["global_gridx"])) * \
|
||||
float(self.app.defaults["global_gridx"])
|
||||
except TypeError:
|
||||
snap_x_ = x
|
||||
else:
|
||||
snap_x_ = x
|
||||
|
||||
# If the Grid_gap_linked on Grid Toolbar is checked then the snap distance on GridY entry will be ignored
|
||||
# and it will use the snap distance from GridX entry
|
||||
if self.app.ui.grid_gap_link_cb.isChecked():
|
||||
if self.app.defaults["global_gridx"] != 0:
|
||||
try:
|
||||
snap_y_ = round(y / float(self.app.defaults["global_gridx"])) * \
|
||||
float(self.app.defaults["global_gridx"])
|
||||
except TypeError:
|
||||
snap_y_ = y
|
||||
else:
|
||||
snap_y_ = y
|
||||
else:
|
||||
if self.app.defaults["global_gridy"] != 0:
|
||||
try:
|
||||
snap_y_ = round(y / float(self.app.defaults["global_gridy"])) * \
|
||||
float(self.app.defaults["global_gridy"])
|
||||
except TypeError:
|
||||
snap_y_ = y
|
||||
else:
|
||||
snap_y_ = y
|
||||
nearest_grid_distance = self.distance((x, y), (snap_x_, snap_y_))
|
||||
if nearest_grid_distance < snap_distance:
|
||||
snap_x, snap_y = (snap_x_, snap_y_)
|
||||
|
||||
return snap_x, snap_y
|
||||
|
||||
@staticmethod
|
||||
def distance(pt1, pt2):
|
||||
return np.sqrt((pt1[0] - pt2[0]) ** 2 + (pt1[1] - pt2[1]) ** 2)
|
||||
|
||||
|
||||
class FakeCursor(QtCore.QObject):
|
||||
"""
|
|
@ -13,7 +13,6 @@ import numpy as np
|
|||
|
||||
import vispy.scene as scene
|
||||
from vispy.scene.cameras.base_camera import BaseCamera
|
||||
# from vispy.scene.widgets import Widget as VisPyWidget
|
||||
from vispy.color import Color
|
||||
|
||||
import time
|
|
@ -13,7 +13,7 @@ from vispy.color import Color
|
|||
from shapely.geometry import Polygon, LineString, LinearRing
|
||||
import threading
|
||||
import numpy as np
|
||||
from AppGUI.VisPyTesselators import GLUTess
|
||||
from flatcamGUI.VisPyTesselators import GLUTess
|
||||
|
||||
|
||||
class FlatCAMLineVisual(LineVisual):
|
|
@ -0,0 +1,19 @@
|
|||
from PyQt5 import QtWidgets
|
||||
|
||||
|
||||
class OptionsGroupUI(QtWidgets.QGroupBox):
|
||||
app = None
|
||||
|
||||
def __init__(self, title, parent=None):
|
||||
# QtGui.QGroupBox.__init__(self, title, parent=parent)
|
||||
super(OptionsGroupUI, self).__init__()
|
||||
self.setStyleSheet("""
|
||||
QGroupBox
|
||||
{
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
}
|
||||
""")
|
||||
|
||||
self.layout = QtWidgets.QVBoxLayout()
|
||||
self.setLayout(self.layout)
|
|
@ -5,7 +5,7 @@ from defaults import FlatCAMDefaults
|
|||
import logging
|
||||
|
||||
import gettext
|
||||
import AppTranslation as fcTranslate
|
||||
import FlatCAMTranslation as fcTranslate
|
||||
import builtins
|
||||
|
||||
fcTranslate.apply_language('strings')
|
||||
|
@ -29,7 +29,7 @@ class PreferencesUIManager:
|
|||
|
||||
:param defaults: a dictionary storage where all the application settings are stored
|
||||
:param data_path: a path to the file where all the preferences are stored for persistence
|
||||
:param ui: reference to the MainGUI class which constructs the UI
|
||||
:param ui: reference to the FlatCAMGUI class which constructs the UI
|
||||
:param inform: a pyqtSignal used to display information's in the StatusBar of the GUI
|
||||
"""
|
||||
|
||||
|
@ -43,7 +43,7 @@ class PreferencesUIManager:
|
|||
self.preferences_changed_flag = False
|
||||
|
||||
# when adding entries here read the comments in the method found below named:
|
||||
# def app_obj.new_object(self, kind, name, initialize, active=True, fit=True, plot=True)
|
||||
# def new_object(self, kind, name, initialize, active=True, fit=True, plot=True)
|
||||
self.defaults_form_fields = {
|
||||
# General App
|
||||
"decimals_inch": self.ui.general_defaults_form.general_app_group.precision_inch_entry,
|
||||
|
@ -123,10 +123,16 @@ class PreferencesUIManager:
|
|||
"gerber_def_zeros": self.ui.gerber_defaults_form.gerber_gen_group.gerber_zeros_radio,
|
||||
"gerber_clean_apertures": self.ui.gerber_defaults_form.gerber_gen_group.gerber_clean_cb,
|
||||
"gerber_extra_buffering": self.ui.gerber_defaults_form.gerber_gen_group.gerber_extra_buffering,
|
||||
"gerber_plot_fill": self.ui.gerber_defaults_form.gerber_gen_group.fill_color_entry,
|
||||
"gerber_plot_line": self.ui.gerber_defaults_form.gerber_gen_group.line_color_entry,
|
||||
"gerber_plot_fill": self.ui.gerber_defaults_form.gerber_gen_group.pf_color_entry,
|
||||
"gerber_plot_line": self.ui.gerber_defaults_form.gerber_gen_group.pl_color_entry,
|
||||
|
||||
# Gerber Options
|
||||
"gerber_isotooldia": self.ui.gerber_defaults_form.gerber_opt_group.iso_tool_dia_entry,
|
||||
"gerber_isopasses": self.ui.gerber_defaults_form.gerber_opt_group.iso_width_entry,
|
||||
"gerber_isooverlap": self.ui.gerber_defaults_form.gerber_opt_group.iso_overlap_entry,
|
||||
"gerber_combine_passes": self.ui.gerber_defaults_form.gerber_opt_group.combine_passes_cb,
|
||||
"gerber_iso_scope": self.ui.gerber_defaults_form.gerber_opt_group.iso_scope_radio,
|
||||
"gerber_milling_type": self.ui.gerber_defaults_form.gerber_opt_group.milling_type_radio,
|
||||
"gerber_noncoppermargin": self.ui.gerber_defaults_form.gerber_opt_group.noncopper_margin_entry,
|
||||
"gerber_noncopperrounded": self.ui.gerber_defaults_form.gerber_opt_group.noncopper_rounded_cb,
|
||||
"gerber_bboxmargin": self.ui.gerber_defaults_form.gerber_opt_group.bbmargin_entry,
|
||||
|
@ -137,6 +143,12 @@ class PreferencesUIManager:
|
|||
# "gerber_aperture_scale_factor": self.ui.gerber_defaults_form.gerber_adv_opt_group.scale_aperture_entry,
|
||||
# "gerber_aperture_buffer_factor": self.ui.gerber_defaults_form.gerber_adv_opt_group.buffer_aperture_entry,
|
||||
"gerber_follow": self.ui.gerber_defaults_form.gerber_adv_opt_group.follow_cb,
|
||||
"gerber_tool_type": self.ui.gerber_defaults_form.gerber_adv_opt_group.tool_type_radio,
|
||||
"gerber_vtipdia": self.ui.gerber_defaults_form.gerber_adv_opt_group.tipdia_spinner,
|
||||
"gerber_vtipangle": self.ui.gerber_defaults_form.gerber_adv_opt_group.tipangle_spinner,
|
||||
"gerber_vcutz": self.ui.gerber_defaults_form.gerber_adv_opt_group.cutz_spinner,
|
||||
"gerber_iso_type": self.ui.gerber_defaults_form.gerber_adv_opt_group.iso_type_radio,
|
||||
|
||||
"gerber_buffering": self.ui.gerber_defaults_form.gerber_adv_opt_group.buffering_radio,
|
||||
"gerber_simplification": self.ui.gerber_defaults_form.gerber_adv_opt_group.simplify_cb,
|
||||
"gerber_simp_tolerance": self.ui.gerber_defaults_form.gerber_adv_opt_group.simplification_tol_spinner,
|
||||
|
@ -168,7 +180,6 @@ class PreferencesUIManager:
|
|||
# Excellon General
|
||||
"excellon_plot": self.ui.excellon_defaults_form.excellon_gen_group.plot_cb,
|
||||
"excellon_solid": self.ui.excellon_defaults_form.excellon_gen_group.solid_cb,
|
||||
"excellon_multicolored": self.ui.excellon_defaults_form.excellon_gen_group.multicolored_cb,
|
||||
"excellon_format_upper_in":
|
||||
self.ui.excellon_defaults_form.excellon_gen_group.excellon_format_upper_in_entry,
|
||||
"excellon_format_lower_in":
|
||||
|
@ -210,31 +221,31 @@ class PreferencesUIManager:
|
|||
"excellon_gcode_type": self.ui.excellon_defaults_form.excellon_opt_group.excellon_gcode_type_radio,
|
||||
|
||||
# Excellon Advanced Options
|
||||
"excellon_offset": self.ui.excellon_defaults_form.excellon_adv_opt_group.offset_entry,
|
||||
"excellon_toolchangexy": self.ui.excellon_defaults_form.excellon_adv_opt_group.toolchangexy_entry,
|
||||
"excellon_startz": self.ui.excellon_defaults_form.excellon_adv_opt_group.estartz_entry,
|
||||
"excellon_feedrate_rapid": self.ui.excellon_defaults_form.excellon_adv_opt_group.feedrate_rapid_entry,
|
||||
"excellon_z_pdepth": self.ui.excellon_defaults_form.excellon_adv_opt_group.pdepth_entry,
|
||||
"excellon_feedrate_probe": self.ui.excellon_defaults_form.excellon_adv_opt_group.feedrate_probe_entry,
|
||||
"excellon_spindledir": self.ui.excellon_defaults_form.excellon_adv_opt_group.spindledir_radio,
|
||||
"excellon_f_plunge": self.ui.excellon_defaults_form.excellon_adv_opt_group.fplunge_cb,
|
||||
"excellon_f_retract": self.ui.excellon_defaults_form.excellon_adv_opt_group.fretract_cb,
|
||||
"excellon_offset": self.ui.excellon_defaults_form.excellon_adv_opt_group.offset_entry,
|
||||
"excellon_toolchangexy": self.ui.excellon_defaults_form.excellon_adv_opt_group.toolchangexy_entry,
|
||||
"excellon_startz": self.ui.excellon_defaults_form.excellon_adv_opt_group.estartz_entry,
|
||||
"excellon_feedrate_rapid": self.ui.excellon_defaults_form.excellon_adv_opt_group.feedrate_rapid_entry,
|
||||
"excellon_z_pdepth": self.ui.excellon_defaults_form.excellon_adv_opt_group.pdepth_entry,
|
||||
"excellon_feedrate_probe": self.ui.excellon_defaults_form.excellon_adv_opt_group.feedrate_probe_entry,
|
||||
"excellon_spindledir": self.ui.excellon_defaults_form.excellon_adv_opt_group.spindledir_radio,
|
||||
"excellon_f_plunge": self.ui.excellon_defaults_form.excellon_adv_opt_group.fplunge_cb,
|
||||
"excellon_f_retract": self.ui.excellon_defaults_form.excellon_adv_opt_group.fretract_cb,
|
||||
|
||||
# Excellon Export
|
||||
"excellon_exp_units": self.ui.excellon_defaults_form.excellon_exp_group.excellon_units_radio,
|
||||
"excellon_exp_format": self.ui.excellon_defaults_form.excellon_exp_group.format_radio,
|
||||
"excellon_exp_integer": self.ui.excellon_defaults_form.excellon_exp_group.format_whole_entry,
|
||||
"excellon_exp_decimals": self.ui.excellon_defaults_form.excellon_exp_group.format_dec_entry,
|
||||
"excellon_exp_zeros": self.ui.excellon_defaults_form.excellon_exp_group.zeros_radio,
|
||||
"excellon_exp_slot_type": self.ui.excellon_defaults_form.excellon_exp_group.slot_type_radio,
|
||||
"excellon_exp_units": self.ui.excellon_defaults_form.excellon_exp_group.excellon_units_radio,
|
||||
"excellon_exp_format": self.ui.excellon_defaults_form.excellon_exp_group.format_radio,
|
||||
"excellon_exp_integer": self.ui.excellon_defaults_form.excellon_exp_group.format_whole_entry,
|
||||
"excellon_exp_decimals": self.ui.excellon_defaults_form.excellon_exp_group.format_dec_entry,
|
||||
"excellon_exp_zeros": self.ui.excellon_defaults_form.excellon_exp_group.zeros_radio,
|
||||
"excellon_exp_slot_type": self.ui.excellon_defaults_form.excellon_exp_group.slot_type_radio,
|
||||
|
||||
# Excellon Editor
|
||||
"excellon_editor_sel_limit": self.ui.excellon_defaults_form.excellon_editor_group.sel_limit_entry,
|
||||
"excellon_editor_newdia": self.ui.excellon_defaults_form.excellon_editor_group.addtool_entry,
|
||||
"excellon_editor_array_size": self.ui.excellon_defaults_form.excellon_editor_group.drill_array_size_entry,
|
||||
"excellon_editor_lin_dir": self.ui.excellon_defaults_form.excellon_editor_group.drill_axis_radio,
|
||||
"excellon_editor_lin_pitch": self.ui.excellon_defaults_form.excellon_editor_group.drill_pitch_entry,
|
||||
"excellon_editor_lin_angle": self.ui.excellon_defaults_form.excellon_editor_group.drill_angle_entry,
|
||||
"excellon_editor_sel_limit": self.ui.excellon_defaults_form.excellon_editor_group.sel_limit_entry,
|
||||
"excellon_editor_newdia": self.ui.excellon_defaults_form.excellon_editor_group.addtool_entry,
|
||||
"excellon_editor_array_size": self.ui.excellon_defaults_form.excellon_editor_group.drill_array_size_entry,
|
||||
"excellon_editor_lin_dir": self.ui.excellon_defaults_form.excellon_editor_group.drill_axis_radio,
|
||||
"excellon_editor_lin_pitch": self.ui.excellon_defaults_form.excellon_editor_group.drill_pitch_entry,
|
||||
"excellon_editor_lin_angle": self.ui.excellon_defaults_form.excellon_editor_group.drill_angle_entry,
|
||||
"excellon_editor_circ_dir": self.ui.excellon_defaults_form.excellon_editor_group.drill_circular_dir_radio,
|
||||
"excellon_editor_circ_angle":
|
||||
self.ui.excellon_defaults_form.excellon_editor_group.drill_circular_angle_entry,
|
||||
|
@ -259,117 +270,94 @@ class PreferencesUIManager:
|
|||
self.ui.excellon_defaults_form.excellon_editor_group.slot_array_circular_angle_entry,
|
||||
|
||||
# Geometry General
|
||||
"geometry_plot": self.ui.geometry_defaults_form.geometry_gen_group.plot_cb,
|
||||
"geometry_multicolored": self.ui.geometry_defaults_form.geometry_gen_group.multicolored_cb,
|
||||
"geometry_circle_steps": self.ui.geometry_defaults_form.geometry_gen_group.circle_steps_entry,
|
||||
"geometry_cnctooldia": self.ui.geometry_defaults_form.geometry_gen_group.cnctooldia_entry,
|
||||
"geometry_plot_line": self.ui.geometry_defaults_form.geometry_gen_group.line_color_entry,
|
||||
"geometry_plot": self.ui.geometry_defaults_form.geometry_gen_group.plot_cb,
|
||||
"geometry_circle_steps": self.ui.geometry_defaults_form.geometry_gen_group.circle_steps_entry,
|
||||
"geometry_cnctooldia": self.ui.geometry_defaults_form.geometry_gen_group.cnctooldia_entry,
|
||||
"geometry_plot_line": self.ui.geometry_defaults_form.geometry_gen_group.line_color_entry,
|
||||
|
||||
# Geometry Options
|
||||
"geometry_cutz": self.ui.geometry_defaults_form.geometry_opt_group.cutz_entry,
|
||||
"geometry_travelz": self.ui.geometry_defaults_form.geometry_opt_group.travelz_entry,
|
||||
"geometry_feedrate": self.ui.geometry_defaults_form.geometry_opt_group.cncfeedrate_entry,
|
||||
"geometry_feedrate_z": self.ui.geometry_defaults_form.geometry_opt_group.feedrate_z_entry,
|
||||
"geometry_spindlespeed": self.ui.geometry_defaults_form.geometry_opt_group.cncspindlespeed_entry,
|
||||
"geometry_dwell": self.ui.geometry_defaults_form.geometry_opt_group.dwell_cb,
|
||||
"geometry_dwelltime": self.ui.geometry_defaults_form.geometry_opt_group.dwelltime_entry,
|
||||
"geometry_ppname_g": self.ui.geometry_defaults_form.geometry_opt_group.pp_geometry_name_cb,
|
||||
"geometry_toolchange": self.ui.geometry_defaults_form.geometry_opt_group.toolchange_cb,
|
||||
"geometry_toolchangez": self.ui.geometry_defaults_form.geometry_opt_group.toolchangez_entry,
|
||||
"geometry_endz": self.ui.geometry_defaults_form.geometry_opt_group.endz_entry,
|
||||
"geometry_endxy": self.ui.geometry_defaults_form.geometry_opt_group.endxy_entry,
|
||||
"geometry_depthperpass": self.ui.geometry_defaults_form.geometry_opt_group.depthperpass_entry,
|
||||
"geometry_multidepth": self.ui.geometry_defaults_form.geometry_opt_group.multidepth_cb,
|
||||
"geometry_cutz": self.ui.geometry_defaults_form.geometry_opt_group.cutz_entry,
|
||||
"geometry_travelz": self.ui.geometry_defaults_form.geometry_opt_group.travelz_entry,
|
||||
"geometry_feedrate": self.ui.geometry_defaults_form.geometry_opt_group.cncfeedrate_entry,
|
||||
"geometry_feedrate_z": self.ui.geometry_defaults_form.geometry_opt_group.feedrate_z_entry,
|
||||
"geometry_spindlespeed": self.ui.geometry_defaults_form.geometry_opt_group.cncspindlespeed_entry,
|
||||
"geometry_dwell": self.ui.geometry_defaults_form.geometry_opt_group.dwell_cb,
|
||||
"geometry_dwelltime": self.ui.geometry_defaults_form.geometry_opt_group.dwelltime_entry,
|
||||
"geometry_ppname_g": self.ui.geometry_defaults_form.geometry_opt_group.pp_geometry_name_cb,
|
||||
"geometry_toolchange": self.ui.geometry_defaults_form.geometry_opt_group.toolchange_cb,
|
||||
"geometry_toolchangez": self.ui.geometry_defaults_form.geometry_opt_group.toolchangez_entry,
|
||||
"geometry_endz": self.ui.geometry_defaults_form.geometry_opt_group.endz_entry,
|
||||
"geometry_endxy": self.ui.geometry_defaults_form.geometry_opt_group.endxy_entry,
|
||||
"geometry_depthperpass": self.ui.geometry_defaults_form.geometry_opt_group.depthperpass_entry,
|
||||
"geometry_multidepth": self.ui.geometry_defaults_form.geometry_opt_group.multidepth_cb,
|
||||
|
||||
# Geometry Advanced Options
|
||||
"geometry_toolchangexy": self.ui.geometry_defaults_form.geometry_adv_opt_group.toolchangexy_entry,
|
||||
"geometry_startz": self.ui.geometry_defaults_form.geometry_adv_opt_group.gstartz_entry,
|
||||
"geometry_feedrate_rapid": self.ui.geometry_defaults_form.geometry_adv_opt_group.feedrate_rapid_entry,
|
||||
"geometry_extracut": self.ui.geometry_defaults_form.geometry_adv_opt_group.extracut_cb,
|
||||
"geometry_toolchangexy": self.ui.geometry_defaults_form.geometry_adv_opt_group.toolchangexy_entry,
|
||||
"geometry_startz": self.ui.geometry_defaults_form.geometry_adv_opt_group.gstartz_entry,
|
||||
"geometry_feedrate_rapid": self.ui.geometry_defaults_form.geometry_adv_opt_group.feedrate_rapid_entry,
|
||||
"geometry_extracut": self.ui.geometry_defaults_form.geometry_adv_opt_group.extracut_cb,
|
||||
"geometry_extracut_length": self.ui.geometry_defaults_form.geometry_adv_opt_group.e_cut_entry,
|
||||
"geometry_z_pdepth": self.ui.geometry_defaults_form.geometry_adv_opt_group.pdepth_entry,
|
||||
"geometry_feedrate_probe": self.ui.geometry_defaults_form.geometry_adv_opt_group.feedrate_probe_entry,
|
||||
"geometry_spindledir": self.ui.geometry_defaults_form.geometry_adv_opt_group.spindledir_radio,
|
||||
"geometry_f_plunge": self.ui.geometry_defaults_form.geometry_adv_opt_group.fplunge_cb,
|
||||
"geometry_segx": self.ui.geometry_defaults_form.geometry_adv_opt_group.segx_entry,
|
||||
"geometry_segy": self.ui.geometry_defaults_form.geometry_adv_opt_group.segy_entry,
|
||||
"geometry_area_exclusion": self.ui.geometry_defaults_form.geometry_adv_opt_group.exclusion_cb,
|
||||
"geometry_area_shape": self.ui.geometry_defaults_form.geometry_adv_opt_group.area_shape_radio,
|
||||
"geometry_area_strategy": self.ui.geometry_defaults_form.geometry_adv_opt_group.strategy_radio,
|
||||
"geometry_area_overz": self.ui.geometry_defaults_form.geometry_adv_opt_group.over_z_entry,
|
||||
"geometry_z_pdepth": self.ui.geometry_defaults_form.geometry_adv_opt_group.pdepth_entry,
|
||||
"geometry_feedrate_probe": self.ui.geometry_defaults_form.geometry_adv_opt_group.feedrate_probe_entry,
|
||||
"geometry_spindledir": self.ui.geometry_defaults_form.geometry_adv_opt_group.spindledir_radio,
|
||||
"geometry_f_plunge": self.ui.geometry_defaults_form.geometry_adv_opt_group.fplunge_cb,
|
||||
"geometry_segx": self.ui.geometry_defaults_form.geometry_adv_opt_group.segx_entry,
|
||||
"geometry_segy": self.ui.geometry_defaults_form.geometry_adv_opt_group.segy_entry,
|
||||
"geometry_area_exclusion": self.ui.geometry_defaults_form.geometry_adv_opt_group.exclusion_cb,
|
||||
"geometry_area_shape": self.ui.geometry_defaults_form.geometry_adv_opt_group.area_shape_radio,
|
||||
"geometry_area_strategy": self.ui.geometry_defaults_form.geometry_adv_opt_group.strategy_radio,
|
||||
"geometry_area_overz": self.ui.geometry_defaults_form.geometry_adv_opt_group.over_z_entry,
|
||||
|
||||
# Geometry Editor
|
||||
"geometry_editor_sel_limit": self.ui.geometry_defaults_form.geometry_editor_group.sel_limit_entry,
|
||||
"geometry_editor_milling_type": self.ui.geometry_defaults_form.geometry_editor_group.milling_type_radio,
|
||||
"geometry_editor_sel_limit": self.ui.geometry_defaults_form.geometry_editor_group.sel_limit_entry,
|
||||
"geometry_editor_milling_type": self.ui.geometry_defaults_form.geometry_editor_group.milling_type_radio,
|
||||
|
||||
# CNCJob General
|
||||
"cncjob_plot": self.ui.cncjob_defaults_form.cncjob_gen_group.plot_cb,
|
||||
"cncjob_plot_kind": self.ui.cncjob_defaults_form.cncjob_gen_group.cncplot_method_radio,
|
||||
"cncjob_annotation": self.ui.cncjob_defaults_form.cncjob_gen_group.annotation_cb,
|
||||
"cncjob_plot": self.ui.cncjob_defaults_form.cncjob_gen_group.plot_cb,
|
||||
"cncjob_plot_kind": self.ui.cncjob_defaults_form.cncjob_gen_group.cncplot_method_radio,
|
||||
"cncjob_annotation": self.ui.cncjob_defaults_form.cncjob_gen_group.annotation_cb,
|
||||
|
||||
"cncjob_tooldia": self.ui.cncjob_defaults_form.cncjob_gen_group.tooldia_entry,
|
||||
"cncjob_coords_type": self.ui.cncjob_defaults_form.cncjob_gen_group.coords_type_radio,
|
||||
"cncjob_coords_decimals": self.ui.cncjob_defaults_form.cncjob_gen_group.coords_dec_entry,
|
||||
"cncjob_fr_decimals": self.ui.cncjob_defaults_form.cncjob_gen_group.fr_dec_entry,
|
||||
"cncjob_steps_per_circle": self.ui.cncjob_defaults_form.cncjob_gen_group.steps_per_circle_entry,
|
||||
"cncjob_line_ending": self.ui.cncjob_defaults_form.cncjob_gen_group.line_ending_cb,
|
||||
"cncjob_plot_line": self.ui.cncjob_defaults_form.cncjob_gen_group.line_color_entry,
|
||||
"cncjob_plot_fill": self.ui.cncjob_defaults_form.cncjob_gen_group.fill_color_entry,
|
||||
"cncjob_travel_line": self.ui.cncjob_defaults_form.cncjob_gen_group.tline_color_entry,
|
||||
"cncjob_travel_fill": self.ui.cncjob_defaults_form.cncjob_gen_group.tfill_color_entry,
|
||||
"cncjob_tooldia": self.ui.cncjob_defaults_form.cncjob_gen_group.tooldia_entry,
|
||||
"cncjob_coords_type": self.ui.cncjob_defaults_form.cncjob_gen_group.coords_type_radio,
|
||||
"cncjob_coords_decimals": self.ui.cncjob_defaults_form.cncjob_gen_group.coords_dec_entry,
|
||||
"cncjob_fr_decimals": self.ui.cncjob_defaults_form.cncjob_gen_group.fr_dec_entry,
|
||||
"cncjob_steps_per_circle": self.ui.cncjob_defaults_form.cncjob_gen_group.steps_per_circle_entry,
|
||||
"cncjob_line_ending": self.ui.cncjob_defaults_form.cncjob_gen_group.line_ending_cb,
|
||||
"cncjob_plot_line": self.ui.cncjob_defaults_form.cncjob_gen_group.line_color_entry,
|
||||
"cncjob_plot_fill": self.ui.cncjob_defaults_form.cncjob_gen_group.fill_color_entry,
|
||||
"cncjob_travel_line": self.ui.cncjob_defaults_form.cncjob_gen_group.tline_color_entry,
|
||||
"cncjob_travel_fill": self.ui.cncjob_defaults_form.cncjob_gen_group.tfill_color_entry,
|
||||
|
||||
# CNC Job Options
|
||||
"cncjob_prepend": self.ui.cncjob_defaults_form.cncjob_opt_group.prepend_text,
|
||||
"cncjob_append": self.ui.cncjob_defaults_form.cncjob_opt_group.append_text,
|
||||
"cncjob_prepend": self.ui.cncjob_defaults_form.cncjob_opt_group.prepend_text,
|
||||
"cncjob_append": self.ui.cncjob_defaults_form.cncjob_opt_group.append_text,
|
||||
|
||||
# CNC Job Advanced Options
|
||||
"cncjob_toolchange_macro": self.ui.cncjob_defaults_form.cncjob_adv_opt_group.toolchange_text,
|
||||
"cncjob_toolchange_macro_enable": self.ui.cncjob_defaults_form.cncjob_adv_opt_group.toolchange_cb,
|
||||
"cncjob_annotation_fontsize": self.ui.cncjob_defaults_form.cncjob_adv_opt_group.annotation_fontsize_sp,
|
||||
"cncjob_toolchange_macro": self.ui.cncjob_defaults_form.cncjob_adv_opt_group.toolchange_text,
|
||||
"cncjob_toolchange_macro_enable": self.ui.cncjob_defaults_form.cncjob_adv_opt_group.toolchange_cb,
|
||||
"cncjob_annotation_fontsize": self.ui.cncjob_defaults_form.cncjob_adv_opt_group.annotation_fontsize_sp,
|
||||
"cncjob_annotation_fontcolor": self.ui.cncjob_defaults_form.cncjob_adv_opt_group.annotation_fontcolor_entry,
|
||||
|
||||
# Isolation Routing Tool
|
||||
"tools_iso_tooldia": self.ui.tools_defaults_form.tools_iso_group.tool_dia_entry,
|
||||
"tools_iso_order": self.ui.tools_defaults_form.tools_iso_group.order_radio,
|
||||
"tools_iso_tool_type": self.ui.tools_defaults_form.tools_iso_group.tool_type_radio,
|
||||
"tools_iso_tool_vtipdia": self.ui.tools_defaults_form.tools_iso_group.tipdia_entry,
|
||||
"tools_iso_tool_vtipangle": self.ui.tools_defaults_form.tools_iso_group.tipangle_entry,
|
||||
"tools_iso_tool_cutz": self.ui.tools_defaults_form.tools_iso_group.cutz_entry,
|
||||
"tools_iso_newdia": self.ui.tools_defaults_form.tools_iso_group.newdia_entry,
|
||||
|
||||
"tools_iso_passes": self.ui.tools_defaults_form.tools_iso_group.passes_entry,
|
||||
"tools_iso_overlap": self.ui.tools_defaults_form.tools_iso_group.overlap_entry,
|
||||
"tools_iso_milling_type": self.ui.tools_defaults_form.tools_iso_group.milling_type_radio,
|
||||
"tools_iso_follow": self.ui.tools_defaults_form.tools_iso_group.follow_cb,
|
||||
"tools_iso_isotype": self.ui.tools_defaults_form.tools_iso_group.iso_type_radio,
|
||||
|
||||
"tools_iso_rest": self.ui.tools_defaults_form.tools_iso_group.rest_cb,
|
||||
"tools_iso_combine_passes": self.ui.tools_defaults_form.tools_iso_group.combine_passes_cb,
|
||||
"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_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,
|
||||
|
||||
# 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_combo,
|
||||
"tools_nccconnect": self.ui.tools_defaults_form.tools_ncc_group.ncc_connect_cb,
|
||||
"tools_ncccontour": self.ui.tools_defaults_form.tools_ncc_group.ncc_contour_cb,
|
||||
"tools_nccrest": self.ui.tools_defaults_form.tools_ncc_group.ncc_rest_cb,
|
||||
"tools_ncc_offset_choice": self.ui.tools_defaults_form.tools_ncc_group.ncc_choice_offset_cb,
|
||||
"tools_ncc_offset_value": self.ui.tools_defaults_form.tools_ncc_group.ncc_offset_spinner,
|
||||
"tools_nccref": self.ui.tools_defaults_form.tools_ncc_group.select_combo,
|
||||
"tools_ncc_area_shape": self.ui.tools_defaults_form.tools_ncc_group.area_shape_radio,
|
||||
"tools_nccmilling_type": self.ui.tools_defaults_form.tools_ncc_group.milling_type_radio,
|
||||
"tools_ncctool_type": self.ui.tools_defaults_form.tools_ncc_group.tool_type_radio,
|
||||
"tools_ncccutz": self.ui.tools_defaults_form.tools_ncc_group.cutz_entry,
|
||||
"tools_ncctipdia": self.ui.tools_defaults_form.tools_ncc_group.tipdia_entry,
|
||||
"tools_ncctipangle": self.ui.tools_defaults_form.tools_ncc_group.tipangle_entry,
|
||||
"tools_nccnewdia": self.ui.tools_defaults_form.tools_ncc_group.newdia_entry,
|
||||
"tools_ncc_plotting": self.ui.tools_defaults_form.tools_ncc_group.plotting_radio,
|
||||
"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_combo,
|
||||
"tools_nccconnect": self.ui.tools_defaults_form.tools_ncc_group.ncc_connect_cb,
|
||||
"tools_ncccontour": self.ui.tools_defaults_form.tools_ncc_group.ncc_contour_cb,
|
||||
"tools_nccrest": self.ui.tools_defaults_form.tools_ncc_group.ncc_rest_cb,
|
||||
"tools_ncc_offset_choice": self.ui.tools_defaults_form.tools_ncc_group.ncc_choice_offset_cb,
|
||||
"tools_ncc_offset_value": self.ui.tools_defaults_form.tools_ncc_group.ncc_offset_spinner,
|
||||
"tools_nccref": self.ui.tools_defaults_form.tools_ncc_group.select_combo,
|
||||
"tools_ncc_area_shape": self.ui.tools_defaults_form.tools_ncc_group.area_shape_radio,
|
||||
"tools_ncc_plotting": self.ui.tools_defaults_form.tools_ncc_group.ncc_plotting_radio,
|
||||
"tools_nccmilling_type": self.ui.tools_defaults_form.tools_ncc_group.milling_type_radio,
|
||||
"tools_ncctool_type": self.ui.tools_defaults_form.tools_ncc_group.tool_type_radio,
|
||||
"tools_ncccutz": self.ui.tools_defaults_form.tools_ncc_group.cutz_entry,
|
||||
"tools_ncctipdia": self.ui.tools_defaults_form.tools_ncc_group.tipdia_entry,
|
||||
"tools_ncctipangle": self.ui.tools_defaults_form.tools_ncc_group.tipangle_entry,
|
||||
"tools_nccnewdia": self.ui.tools_defaults_form.tools_ncc_group.newdia_entry,
|
||||
|
||||
# CutOut Tool
|
||||
"tools_cutouttooldia": self.ui.tools_defaults_form.tools_cutout_group.cutout_tooldia_entry,
|
||||
|
@ -479,12 +467,6 @@ class PreferencesUIManager:
|
|||
"tools_solderpaste_pp": self.ui.tools_defaults_form.tools_solderpaste_group.pp_combo,
|
||||
"tools_sub_close_paths": self.ui.tools_defaults_form.tools_sub_group.close_paths_cb,
|
||||
|
||||
# Corner Markers Tool
|
||||
|
||||
"tools_corners_thickness": self.ui.tools_defaults_form.tools_corners_group.thick_entry,
|
||||
"tools_corners_length": self.ui.tools_defaults_form.tools_corners_group.l_entry,
|
||||
"tools_corners_margin": self.ui.tools_defaults_form.tools_corners_group.margin_entry,
|
||||
|
||||
# #######################################################################################################
|
||||
# ########################################## TOOLS 2 ####################################################
|
||||
# #######################################################################################################
|
||||
|
@ -668,7 +650,7 @@ class PreferencesUIManager:
|
|||
|
||||
def show_preferences_gui(self):
|
||||
"""
|
||||
Called to initialize and show the Preferences AppGUI
|
||||
Called to initialize and show the Preferences GUI
|
||||
|
||||
:return: None
|
||||
"""
|
||||
|
@ -737,7 +719,7 @@ class PreferencesUIManager:
|
|||
self.ui.fa_scroll_area.setWidget(fa_form)
|
||||
fa_form.show()
|
||||
|
||||
# Initialize the color box's color in Preferences -> Global -> Colors
|
||||
# Initialize the color box's color in Preferences -> Global -> Colo
|
||||
self.__init_color_pickers()
|
||||
|
||||
# Button handlers
|
||||
|
@ -750,90 +732,167 @@ class PreferencesUIManager:
|
|||
|
||||
def __init_color_pickers(self):
|
||||
# Init Gerber Plot Colors
|
||||
self.ui.gerber_defaults_form.gerber_gen_group.fill_color_entry.set_value(self.defaults['gerber_plot_fill'])
|
||||
self.ui.gerber_defaults_form.gerber_gen_group.line_color_entry.set_value(self.defaults['gerber_plot_line'])
|
||||
self.ui.gerber_defaults_form.gerber_gen_group.pf_color_entry.set_value(self.defaults['gerber_plot_fill'])
|
||||
self.ui.gerber_defaults_form.gerber_gen_group.pf_color_button.setStyleSheet(
|
||||
"background-color:%s;"
|
||||
"border-color: dimgray" % str(self.defaults['gerber_plot_fill'])[:7])
|
||||
self.ui.gerber_defaults_form.gerber_gen_group.pf_color_alpha_spinner.set_value(
|
||||
int(self.defaults['gerber_plot_fill'][7:9], 16))
|
||||
self.ui.gerber_defaults_form.gerber_gen_group.pf_color_alpha_slider.setValue(
|
||||
int(self.defaults['gerber_plot_fill'][7:9], 16))
|
||||
|
||||
self.ui.gerber_defaults_form.gerber_gen_group.gerber_alpha_entry.set_value(
|
||||
int(self.defaults['gerber_plot_fill'][7:9], 16)) # alpha
|
||||
self.ui.gerber_defaults_form.gerber_gen_group.pl_color_entry.set_value(self.defaults['gerber_plot_line'])
|
||||
self.ui.gerber_defaults_form.gerber_gen_group.pl_color_button.setStyleSheet(
|
||||
"background-color:%s;"
|
||||
"border-color: dimgray" % str(self.defaults['gerber_plot_line'])[:7])
|
||||
|
||||
# Init Excellon Plot Colors
|
||||
self.ui.excellon_defaults_form.excellon_gen_group.fill_color_entry.set_value(
|
||||
self.defaults['excellon_plot_fill'])
|
||||
self.ui.excellon_defaults_form.excellon_gen_group.fill_color_button.setStyleSheet(
|
||||
"background-color:%s;"
|
||||
"border-color: dimgray" % str(self.defaults['excellon_plot_fill'])[:7])
|
||||
self.ui.excellon_defaults_form.excellon_gen_group.color_alpha_spinner.set_value(
|
||||
int(self.defaults['excellon_plot_fill'][7:9], 16))
|
||||
self.ui.excellon_defaults_form.excellon_gen_group.color_alpha_slider.setValue(
|
||||
int(self.defaults['excellon_plot_fill'][7:9], 16))
|
||||
|
||||
self.ui.excellon_defaults_form.excellon_gen_group.line_color_entry.set_value(
|
||||
self.defaults['excellon_plot_line'])
|
||||
|
||||
self.ui.excellon_defaults_form.excellon_gen_group.excellon_alpha_entry.set_value(
|
||||
int(self.defaults['excellon_plot_fill'][7:9], 16))
|
||||
self.ui.excellon_defaults_form.excellon_gen_group.line_color_button.setStyleSheet(
|
||||
"background-color:%s;"
|
||||
"border-color: dimgray" % str(self.defaults['excellon_plot_line'])[:7])
|
||||
|
||||
# Init Geometry Plot Colors
|
||||
self.ui.geometry_defaults_form.geometry_gen_group.line_color_entry.set_value(
|
||||
self.defaults['geometry_plot_line'])
|
||||
self.ui.geometry_defaults_form.geometry_gen_group.line_color_button.setStyleSheet(
|
||||
"background-color:%s;"
|
||||
"border-color: dimgray" % str(self.defaults['geometry_plot_line'])[:7])
|
||||
|
||||
# Init CNCJob Travel Line Colors
|
||||
self.ui.cncjob_defaults_form.cncjob_gen_group.tfill_color_entry.set_value(
|
||||
self.defaults['cncjob_travel_fill'])
|
||||
self.ui.cncjob_defaults_form.cncjob_gen_group.tfill_color_button.setStyleSheet(
|
||||
"background-color:%s;"
|
||||
"border-color: dimgray" % str(self.defaults['cncjob_travel_fill'])[:7])
|
||||
self.ui.cncjob_defaults_form.cncjob_gen_group.tcolor_alpha_spinner.set_value(
|
||||
int(self.defaults['cncjob_travel_fill'][7:9], 16))
|
||||
self.ui.cncjob_defaults_form.cncjob_gen_group.tcolor_alpha_slider.setValue(
|
||||
int(self.defaults['cncjob_travel_fill'][7:9], 16))
|
||||
|
||||
self.ui.cncjob_defaults_form.cncjob_gen_group.tline_color_entry.set_value(
|
||||
self.defaults['cncjob_travel_line'])
|
||||
|
||||
self.ui.cncjob_defaults_form.cncjob_gen_group.cncjob_alpha_entry.set_value(
|
||||
int(self.defaults['cncjob_travel_fill'][7:9], 16)) # alpha
|
||||
self.ui.cncjob_defaults_form.cncjob_gen_group.tline_color_button.setStyleSheet(
|
||||
"background-color:%s;"
|
||||
"border-color: dimgray" % str(self.defaults['cncjob_travel_line'])[:7])
|
||||
|
||||
# Init CNCJob Plot Colors
|
||||
self.ui.cncjob_defaults_form.cncjob_gen_group.fill_color_entry.set_value(
|
||||
self.defaults['cncjob_plot_fill'])
|
||||
self.ui.cncjob_defaults_form.cncjob_gen_group.fill_color_button.setStyleSheet(
|
||||
"background-color:%s;"
|
||||
"border-color: dimgray" % str(self.defaults['cncjob_plot_fill'])[:7])
|
||||
|
||||
self.ui.cncjob_defaults_form.cncjob_gen_group.line_color_entry.set_value(
|
||||
self.defaults['cncjob_plot_line'])
|
||||
self.ui.cncjob_defaults_form.cncjob_gen_group.line_color_button.setStyleSheet(
|
||||
"background-color:%s;"
|
||||
"border-color: dimgray" % str(self.defaults['cncjob_plot_line'])[:7])
|
||||
|
||||
# Init Left-Right Selection colors
|
||||
self.ui.general_defaults_form.general_gui_group.sf_color_entry.set_value(self.defaults['global_sel_fill'])
|
||||
self.ui.general_defaults_form.general_gui_group.sl_color_entry.set_value(self.defaults['global_sel_line'])
|
||||
|
||||
self.ui.general_defaults_form.general_gui_group.left_right_alpha_entry.set_value(
|
||||
self.ui.general_defaults_form.general_gui_group.sf_color_button.setStyleSheet(
|
||||
"background-color:%s;"
|
||||
"border-color: dimgray" % str(self.defaults['global_sel_fill'])[:7])
|
||||
self.ui.general_defaults_form.general_gui_group.sf_color_alpha_spinner.set_value(
|
||||
int(self.defaults['global_sel_fill'][7:9], 16))
|
||||
self.ui.general_defaults_form.general_gui_group.sf_color_alpha_slider.setValue(
|
||||
int(self.defaults['global_sel_fill'][7:9], 16))
|
||||
|
||||
self.ui.general_defaults_form.general_gui_group.sl_color_entry.set_value(self.defaults['global_sel_line'])
|
||||
self.ui.general_defaults_form.general_gui_group.sl_color_button.setStyleSheet(
|
||||
"background-color:%s;"
|
||||
"border-color: dimgray" % str(self.defaults['global_sel_line'])[:7])
|
||||
|
||||
# Init Right-Left Selection colors
|
||||
self.ui.general_defaults_form.general_gui_group.alt_sf_color_entry.set_value(
|
||||
self.defaults['global_alt_sel_fill'])
|
||||
self.ui.general_defaults_form.general_gui_group.alt_sf_color_button.setStyleSheet(
|
||||
"background-color:%s;"
|
||||
"border-color: dimgray" % str(self.defaults['global_alt_sel_fill'])[:7])
|
||||
self.ui.general_defaults_form.general_gui_group.alt_sf_color_alpha_spinner.set_value(
|
||||
int(self.defaults['global_sel_fill'][7:9], 16))
|
||||
self.ui.general_defaults_form.general_gui_group.alt_sf_color_alpha_slider.setValue(
|
||||
int(self.defaults['global_sel_fill'][7:9], 16))
|
||||
|
||||
self.ui.general_defaults_form.general_gui_group.alt_sl_color_entry.set_value(
|
||||
self.defaults['global_alt_sel_line'])
|
||||
|
||||
self.ui.general_defaults_form.general_gui_group.right_left_alpha_entry.set_value(
|
||||
int(self.defaults['global_sel_fill'][7:9], 16))
|
||||
self.ui.general_defaults_form.general_gui_group.alt_sl_color_button.setStyleSheet(
|
||||
"background-color:%s;"
|
||||
"border-color: dimgray" % str(self.defaults['global_alt_sel_line'])[:7])
|
||||
|
||||
# Init Draw color and Selection Draw Color
|
||||
self.ui.general_defaults_form.general_gui_group.draw_color_entry.set_value(
|
||||
self.defaults['global_draw_color'])
|
||||
self.ui.general_defaults_form.general_gui_group.draw_color_button.setStyleSheet(
|
||||
"background-color:%s;"
|
||||
"border-color: dimgray" % str(self.defaults['global_draw_color'])[:7])
|
||||
|
||||
self.ui.general_defaults_form.general_gui_group.sel_draw_color_entry.set_value(
|
||||
self.defaults['global_sel_draw_color'])
|
||||
self.ui.general_defaults_form.general_gui_group.sel_draw_color_button.setStyleSheet(
|
||||
"background-color:%s;"
|
||||
"border-color: dimgray" % str(self.defaults['global_sel_draw_color'])[:7])
|
||||
|
||||
# Init Project Items color
|
||||
self.ui.general_defaults_form.general_gui_group.proj_color_entry.set_value(
|
||||
self.defaults['global_proj_item_color'])
|
||||
self.ui.general_defaults_form.general_gui_group.proj_color_button.setStyleSheet(
|
||||
"background-color:%s;"
|
||||
"border-color: dimgray" % str(self.defaults['global_proj_item_color'])[:7])
|
||||
|
||||
# Init Project Disabled Items color
|
||||
self.ui.general_defaults_form.general_gui_group.proj_color_dis_entry.set_value(
|
||||
self.defaults['global_proj_item_dis_color'])
|
||||
self.ui.general_defaults_form.general_gui_group.proj_color_dis_button.setStyleSheet(
|
||||
"background-color:%s;"
|
||||
"border-color: dimgray" % str(self.defaults['global_proj_item_dis_color'])[:7])
|
||||
|
||||
# Init Mouse Cursor color
|
||||
# Init Project Disabled Items color
|
||||
self.ui.general_defaults_form.general_app_set_group.mouse_cursor_entry.set_value(
|
||||
self.defaults['global_cursor_color'])
|
||||
self.ui.general_defaults_form.general_app_set_group.mouse_cursor_button.setStyleSheet(
|
||||
"background-color:%s;"
|
||||
"border-color: dimgray" % str(self.defaults['global_cursor_color'])[:7])
|
||||
|
||||
# Init the Annotation CNC Job color
|
||||
self.ui.cncjob_defaults_form.cncjob_adv_opt_group.annotation_fontcolor_entry.set_value(
|
||||
self.defaults['cncjob_annotation_fontcolor'])
|
||||
self.ui.cncjob_defaults_form.cncjob_adv_opt_group.annotation_fontcolor_button.setStyleSheet(
|
||||
"background-color:%s;"
|
||||
"border-color: dimgray" % str(self.defaults['cncjob_annotation_fontcolor'])[:7])
|
||||
|
||||
# Init the Tool Film color
|
||||
self.ui.tools_defaults_form.tools_film_group.film_color_entry.set_value(
|
||||
self.defaults['tools_film_color'])
|
||||
self.ui.tools_defaults_form.tools_film_group.film_color_button.setStyleSheet(
|
||||
"background-color:%s;"
|
||||
"border-color: dimgray" % str(self.defaults['tools_film_color'])[:7]
|
||||
)
|
||||
|
||||
# Init the Tool QRCode colors
|
||||
self.ui.tools2_defaults_form.tools2_qrcode_group.fill_color_entry.set_value(
|
||||
self.defaults['tools_qrcode_fill_color'])
|
||||
self.ui.tools2_defaults_form.tools2_qrcode_group.fill_color_button.setStyleSheet(
|
||||
"background-color:%s;"
|
||||
"border-color: dimgray" % str(self.defaults['tools_qrcode_fill_color'])[:7])
|
||||
|
||||
self.ui.tools2_defaults_form.tools2_qrcode_group.back_color_entry.set_value(
|
||||
self.defaults['tools_qrcode_back_color'])
|
||||
self.ui.tools2_defaults_form.tools2_qrcode_group.back_color_button.setStyleSheet(
|
||||
"background-color:%s;"
|
||||
"border-color: dimgray" % str(self.defaults['tools_qrcode_back_color'])[:7])
|
||||
|
||||
def on_save_button(self, save_to_file=True):
|
||||
log.debug("on_save_button() --> Applying preferences to file.")
|
||||
|
@ -862,17 +921,12 @@ class PreferencesUIManager:
|
|||
theme = 'white'
|
||||
|
||||
should_restart = False
|
||||
theme_new_val = self.ui.general_defaults_form.general_gui_group.theme_radio.get_value()
|
||||
|
||||
ge = self.defaults["global_graphic_engine"]
|
||||
ge_val = self.ui.general_defaults_form.general_app_group.ge_radio.get_value()
|
||||
|
||||
if theme_new_val != theme or ge != ge_val:
|
||||
val = self.ui.general_defaults_form.general_gui_group.theme_radio.get_value()
|
||||
if val != theme:
|
||||
msgbox = QtWidgets.QMessageBox()
|
||||
msgbox.setText(_("Are you sure you want to continue?"))
|
||||
msgbox.setWindowTitle(_("Application will restart"))
|
||||
msgbox.setWindowTitle(_("Application restart"))
|
||||
msgbox.setWindowIcon(QtGui.QIcon(self.ui.app.resource_location + '/warning.png'))
|
||||
msgbox.setIcon(QtWidgets.QMessageBox.Question)
|
||||
|
||||
bt_yes = msgbox.addButton(_('Yes'), QtWidgets.QMessageBox.YesRole)
|
||||
msgbox.addButton(_('Cancel'), QtWidgets.QMessageBox.NoRole)
|
||||
|
@ -881,22 +935,15 @@ class PreferencesUIManager:
|
|||
msgbox.exec_()
|
||||
response = msgbox.clickedButton()
|
||||
|
||||
if theme_new_val != theme:
|
||||
if response == bt_yes:
|
||||
theme_settings.setValue('theme', theme_new_val)
|
||||
if response == bt_yes:
|
||||
theme_settings.setValue('theme', val)
|
||||
|
||||
# This will write the setting to the platform specific storage.
|
||||
del theme_settings
|
||||
# This will write the setting to the platform specific storage.
|
||||
del theme_settings
|
||||
|
||||
should_restart = True
|
||||
else:
|
||||
self.ui.general_defaults_form.general_gui_group.theme_radio.set_value(theme)
|
||||
should_restart = True
|
||||
else:
|
||||
if response == bt_yes:
|
||||
self.defaults["global_graphic_engine"] = ge_val
|
||||
should_restart = True
|
||||
else:
|
||||
self.ui.general_defaults_form.general_app_group.ge_radio.set_value(ge)
|
||||
self.ui.general_defaults_form.general_gui_group.theme_radio.set_value(theme)
|
||||
|
||||
if save_to_file or should_restart is True:
|
||||
self.save_defaults(silent=False)
|
||||
|
@ -920,10 +967,6 @@ class PreferencesUIManager:
|
|||
tb_fsize = self.ui.general_defaults_form.general_app_set_group.textbox_font_size_spinner.get_value()
|
||||
settgs.setValue('textbox_font_size', tb_fsize)
|
||||
|
||||
# save the HUD font size
|
||||
hud_fsize = self.ui.general_defaults_form.general_app_set_group.hud_font_size_spinner.get_value()
|
||||
settgs.setValue('hud_font_size', hud_fsize)
|
||||
|
||||
settgs.setValue(
|
||||
'machinist',
|
||||
1 if self.ui.general_defaults_form.general_app_set_group.machinist_cb.get_value() else 0
|
||||
|
@ -948,14 +991,10 @@ class PreferencesUIManager:
|
|||
self.preferences_changed_flag = False
|
||||
self.ignore_tab_close_event = True
|
||||
|
||||
# restore stylesheet to default for the statusBar icon
|
||||
self.ui.pref_status_label.setStyleSheet("")
|
||||
|
||||
try:
|
||||
self.ui.general_defaults_form.general_app_group.units_radio.activated_custom.disconnect()
|
||||
except (TypeError, AttributeError):
|
||||
pass
|
||||
|
||||
self.defaults_write_form(source_dict=self.defaults.current_defaults)
|
||||
self.ui.general_defaults_form.general_app_group.units_radio.activated_custom.connect(
|
||||
lambda: self.ui.app.on_toggle_units(no_pref=False))
|
||||
|
@ -996,7 +1035,6 @@ class PreferencesUIManager:
|
|||
:return: None
|
||||
"""
|
||||
self.defaults.report_usage("save_defaults")
|
||||
log.debug("App.PreferencesUIManager.save_defaults()")
|
||||
|
||||
if data_path is None:
|
||||
data_path = self.data_path
|
||||
|
@ -1033,7 +1071,7 @@ class PreferencesUIManager:
|
|||
if self.ui.toolbarfile.isVisible():
|
||||
tb_status += 1
|
||||
|
||||
if self.ui.toolbaredit.isVisible():
|
||||
if self.ui.toolbargeo.isVisible():
|
||||
tb_status += 2
|
||||
|
||||
if self.ui.toolbarview.isVisible():
|
||||
|
@ -1051,7 +1089,7 @@ class PreferencesUIManager:
|
|||
if self.ui.grb_edit_toolbar.isVisible():
|
||||
tb_status += 64
|
||||
|
||||
if self.ui.status_toolbar.isVisible():
|
||||
if self.ui.snap_toolbar.isVisible():
|
||||
tb_status += 128
|
||||
|
||||
if self.ui.toolbarshell.isVisible():
|
||||
|
@ -1080,9 +1118,6 @@ class PreferencesUIManager:
|
|||
if self.ignore_tab_close_event:
|
||||
return
|
||||
|
||||
# restore stylesheet to default for the statusBar icon
|
||||
self.ui.pref_status_label.setStyleSheet("")
|
||||
|
||||
# disconnect
|
||||
for idx in range(self.ui.pref_tab_area.count()):
|
||||
for tb in self.ui.pref_tab_area.widget(idx).findChildren(QtCore.QObject):
|
||||
|
@ -1118,7 +1153,6 @@ class PreferencesUIManager:
|
|||
"Do you want to save the Preferences?"))
|
||||
msgbox.setWindowTitle(_("Save Preferences"))
|
||||
msgbox.setWindowIcon(QtGui.QIcon(self.ui.app.resource_location + '/save_as.png'))
|
||||
msgbox.setIcon(QtWidgets.QMessageBox.Question)
|
||||
|
||||
bt_yes = msgbox.addButton(_('Yes'), QtWidgets.QMessageBox.YesRole)
|
||||
msgbox.addButton(_('No'), QtWidgets.QMessageBox.NoRole)
|
|
@ -1,6 +1,6 @@
|
|||
from AppGUI.GUIElements import *
|
||||
from flatcamGUI.GUIElements import *
|
||||
import gettext
|
||||
import AppTranslation as fcTranslate
|
||||
import FlatCAMTranslation as fcTranslate
|
||||
import builtins
|
||||
|
||||
|
|
@ -1,10 +1,10 @@
|
|||
from PyQt5 import QtWidgets, QtGui
|
||||
from PyQt5 import QtWidgets, QtGui, QtCore
|
||||
from PyQt5.QtCore import QSettings, Qt
|
||||
|
||||
from AppGUI.GUIElements import FCTextArea, FCCheckBox, FCComboBox, FCSpinner, FCColorEntry
|
||||
from AppGUI.preferences.OptionsGroupUI import OptionsGroupUI
|
||||
from flatcamGUI.GUIElements import FCTextArea, FCCheckBox, FCComboBox, FCSpinner, FCEntry
|
||||
from flatcamGUI.preferences.OptionsGroupUI import OptionsGroupUI
|
||||
import gettext
|
||||
import AppTranslation as fcTranslate
|
||||
import FlatCAMTranslation as fcTranslate
|
||||
import builtins
|
||||
|
||||
fcTranslate.apply_language('strings')
|
||||
|
@ -158,16 +158,28 @@ class CNCJobAdvOptPrefGroupUI(OptionsGroupUI):
|
|||
self.annotation_color_label.setToolTip(
|
||||
_("Set the font color for the annotation texts.")
|
||||
)
|
||||
self.annotation_fontcolor_entry = FCColorEntry()
|
||||
self.annotation_fontcolor_entry = FCEntry()
|
||||
self.annotation_fontcolor_button = QtWidgets.QPushButton()
|
||||
self.annotation_fontcolor_button.setFixedSize(15, 15)
|
||||
|
||||
self.form_box_child = QtWidgets.QHBoxLayout()
|
||||
self.form_box_child.setContentsMargins(0, 0, 0, 0)
|
||||
self.form_box_child.addWidget(self.annotation_fontcolor_entry)
|
||||
self.form_box_child.addWidget(self.annotation_fontcolor_button, alignment=Qt.AlignRight)
|
||||
self.form_box_child.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter)
|
||||
|
||||
color_widget = QtWidgets.QWidget()
|
||||
color_widget.setLayout(self.form_box_child)
|
||||
grid0.addWidget(self.annotation_color_label, 3, 0)
|
||||
grid0.addWidget(self.annotation_fontcolor_entry, 3, 1)
|
||||
|
||||
grid0.addWidget(color_widget, 3, 1)
|
||||
grid0.addWidget(QtWidgets.QLabel(''), 3, 2)
|
||||
|
||||
self.layout.addStretch()
|
||||
|
||||
self.tc_variable_combo.currentIndexChanged[str].connect(self.on_cnc_custom_parameters)
|
||||
|
||||
self.annotation_fontcolor_entry.editingFinished.connect(self.on_annotation_fontcolor_entry)
|
||||
self.annotation_fontcolor_button.clicked.connect(self.on_annotation_fontcolor_button)
|
||||
|
||||
def on_cnc_custom_parameters(self, signal_text):
|
||||
if signal_text == 'Parameters':
|
||||
|
@ -177,3 +189,20 @@ class CNCJobAdvOptPrefGroupUI(OptionsGroupUI):
|
|||
|
||||
def on_annotation_fontcolor_entry(self):
|
||||
self.app.defaults['cncjob_annotation_fontcolor'] = self.annotation_fontcolor_entry.get_value()
|
||||
self.annotation_fontcolor_button.setStyleSheet(
|
||||
"background-color:%s" % str(self.app.defaults['cncjob_annotation_fontcolor']))
|
||||
|
||||
def on_annotation_fontcolor_button(self):
|
||||
current_color = QtGui.QColor(self.app.defaults['cncjob_annotation_fontcolor'])
|
||||
|
||||
c_dialog = QtWidgets.QColorDialog()
|
||||
annotation_color = c_dialog.getColor(initial=current_color)
|
||||
|
||||
if annotation_color.isValid() is False:
|
||||
return
|
||||
|
||||
self.annotation_fontcolor_button.setStyleSheet("background-color:%s" % str(annotation_color.name()))
|
||||
|
||||
new_val_sel = str(annotation_color.name())
|
||||
self.annotation_fontcolor_entry.set_value(new_val_sel)
|
||||
self.app.defaults['cncjob_annotation_fontcolor'] = new_val_sel
|
|
@ -1,10 +1,10 @@
|
|||
from PyQt5 import QtWidgets, QtCore, QtGui
|
||||
from PyQt5.QtCore import QSettings
|
||||
|
||||
from AppGUI.GUIElements import FCCheckBox, RadioSet, FCSpinner, FCDoubleSpinner, FCSliderWithSpinner, FCColorEntry
|
||||
from AppGUI.preferences.OptionsGroupUI import OptionsGroupUI
|
||||
from flatcamGUI.GUIElements import FCCheckBox, RadioSet, FCSpinner, FCDoubleSpinner, FCEntry
|
||||
from flatcamGUI.preferences.OptionsGroupUI import OptionsGroupUI
|
||||
import gettext
|
||||
import AppTranslation as fcTranslate
|
||||
import FlatCAMTranslation as fcTranslate
|
||||
import builtins
|
||||
|
||||
fcTranslate.apply_language('strings')
|
||||
|
@ -170,10 +170,17 @@ class CNCJobGenPrefGroupUI(OptionsGroupUI):
|
|||
self.tline_color_label.setToolTip(
|
||||
_("Set the travel line color for plotted objects.")
|
||||
)
|
||||
self.tline_color_entry = FCColorEntry()
|
||||
self.tline_color_entry = FCEntry()
|
||||
self.tline_color_button = QtWidgets.QPushButton()
|
||||
self.tline_color_button.setFixedSize(15, 15)
|
||||
|
||||
self.form_box_child_2 = QtWidgets.QHBoxLayout()
|
||||
self.form_box_child_2.addWidget(self.tline_color_entry)
|
||||
self.form_box_child_2.addWidget(self.tline_color_button)
|
||||
self.form_box_child_2.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter)
|
||||
|
||||
grid0.addWidget(self.tline_color_label, 14, 0)
|
||||
grid0.addWidget(self.tline_color_entry, 14, 1)
|
||||
grid0.addLayout(self.form_box_child_2, 14, 1)
|
||||
|
||||
# Plot Fill Color
|
||||
self.tfill_color_label = QtWidgets.QLabel('%s:' % _('Fill'))
|
||||
|
@ -182,20 +189,38 @@ class CNCJobGenPrefGroupUI(OptionsGroupUI):
|
|||
"First 6 digits are the color and the last 2\n"
|
||||
"digits are for alpha (transparency) level.")
|
||||
)
|
||||
self.tfill_color_entry = FCColorEntry()
|
||||
self.tfill_color_entry = FCEntry()
|
||||
self.tfill_color_button = QtWidgets.QPushButton()
|
||||
self.tfill_color_button.setFixedSize(15, 15)
|
||||
|
||||
self.form_box_child_1 = QtWidgets.QHBoxLayout()
|
||||
self.form_box_child_1.addWidget(self.tfill_color_entry)
|
||||
self.form_box_child_1.addWidget(self.tfill_color_button)
|
||||
self.form_box_child_1.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter)
|
||||
|
||||
grid0.addWidget(self.tfill_color_label, 15, 0)
|
||||
grid0.addWidget(self.tfill_color_entry, 15, 1)
|
||||
grid0.addLayout(self.form_box_child_1, 15, 1)
|
||||
|
||||
# Plot Fill Transparency Level
|
||||
self.cncjob_alpha_label = QtWidgets.QLabel('%s:' % _('Alpha'))
|
||||
self.cncjob_alpha_label.setToolTip(
|
||||
self.alpha_label = QtWidgets.QLabel('%s:' % _('Alpha'))
|
||||
self.alpha_label.setToolTip(
|
||||
_("Set the fill transparency for plotted objects.")
|
||||
)
|
||||
self.cncjob_alpha_entry = FCSliderWithSpinner(0, 255, 1)
|
||||
self.tcolor_alpha_slider = QtWidgets.QSlider(QtCore.Qt.Horizontal)
|
||||
self.tcolor_alpha_slider.setMinimum(0)
|
||||
self.tcolor_alpha_slider.setMaximum(255)
|
||||
self.tcolor_alpha_slider.setSingleStep(1)
|
||||
|
||||
grid0.addWidget(self.cncjob_alpha_label, 16, 0)
|
||||
grid0.addWidget(self.cncjob_alpha_entry, 16, 1)
|
||||
self.tcolor_alpha_spinner = FCSpinner()
|
||||
self.tcolor_alpha_spinner.setMinimumWidth(70)
|
||||
self.tcolor_alpha_spinner.set_range(0, 255)
|
||||
|
||||
self.form_box_child_3 = QtWidgets.QHBoxLayout()
|
||||
self.form_box_child_3.addWidget(self.tcolor_alpha_slider)
|
||||
self.form_box_child_3.addWidget(self.tcolor_alpha_spinner)
|
||||
|
||||
grid0.addWidget(self.alpha_label, 16, 0)
|
||||
grid0.addLayout(self.form_box_child_3, 16, 1)
|
||||
|
||||
separator_line = QtWidgets.QFrame()
|
||||
separator_line.setFrameShape(QtWidgets.QFrame.HLine)
|
||||
|
@ -203,7 +228,7 @@ class CNCJobGenPrefGroupUI(OptionsGroupUI):
|
|||
grid0.addWidget(separator_line, 17, 0, 1, 2)
|
||||
|
||||
# CNCJob Object Color
|
||||
self.cnc_color_label = QtWidgets.QLabel('<b>%s</b>' % _('Object Color'))
|
||||
self.cnc_color_label = QtWidgets.QLabel('<b>%s</b>' % _('CNCJob Object Color'))
|
||||
grid0.addWidget(self.cnc_color_label, 18, 0, 1, 2)
|
||||
|
||||
# Plot Line Color
|
||||
|
@ -211,10 +236,17 @@ class CNCJobGenPrefGroupUI(OptionsGroupUI):
|
|||
self.line_color_label.setToolTip(
|
||||
_("Set the color for plotted objects.")
|
||||
)
|
||||
self.line_color_entry = FCColorEntry()
|
||||
self.line_color_entry = FCEntry()
|
||||
self.line_color_button = QtWidgets.QPushButton()
|
||||
self.line_color_button.setFixedSize(15, 15)
|
||||
|
||||
self.form_box_child_2 = QtWidgets.QHBoxLayout()
|
||||
self.form_box_child_2.addWidget(self.line_color_entry)
|
||||
self.form_box_child_2.addWidget(self.line_color_button)
|
||||
self.form_box_child_2.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter)
|
||||
|
||||
grid0.addWidget(self.line_color_label, 19, 0)
|
||||
grid0.addWidget(self.line_color_entry, 19, 1)
|
||||
grid0.addLayout(self.form_box_child_2, 19, 1)
|
||||
|
||||
# Plot Fill Color
|
||||
self.fill_color_label = QtWidgets.QLabel('%s:' % _('Fill'))
|
||||
|
@ -223,21 +255,32 @@ class CNCJobGenPrefGroupUI(OptionsGroupUI):
|
|||
"First 6 digits are the color and the last 2\n"
|
||||
"digits are for alpha (transparency) level.")
|
||||
)
|
||||
self.fill_color_entry = FCColorEntry()
|
||||
self.fill_color_entry = FCEntry()
|
||||
self.fill_color_button = QtWidgets.QPushButton()
|
||||
self.fill_color_button.setFixedSize(15, 15)
|
||||
|
||||
self.form_box_child_1 = QtWidgets.QHBoxLayout()
|
||||
self.form_box_child_1.addWidget(self.fill_color_entry)
|
||||
self.form_box_child_1.addWidget(self.fill_color_button)
|
||||
self.form_box_child_1.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter)
|
||||
|
||||
grid0.addWidget(self.fill_color_label, 20, 0)
|
||||
grid0.addWidget(self.fill_color_entry, 20, 1)
|
||||
grid0.addLayout(self.form_box_child_1, 20, 1)
|
||||
|
||||
self.layout.addStretch()
|
||||
|
||||
# Setting plot colors signals
|
||||
self.tline_color_entry.editingFinished.connect(self.on_tline_color_entry)
|
||||
self.tline_color_button.clicked.connect(self.on_tline_color_button)
|
||||
self.tfill_color_entry.editingFinished.connect(self.on_tfill_color_entry)
|
||||
|
||||
self.cncjob_alpha_entry.valueChanged.connect(self.on_cncjob_alpha_changed) # alpha
|
||||
self.tfill_color_button.clicked.connect(self.on_tfill_color_button)
|
||||
self.tcolor_alpha_spinner.valueChanged.connect(self.on_tcolor_spinner)
|
||||
self.tcolor_alpha_slider.valueChanged.connect(self.on_tcolor_slider)
|
||||
|
||||
self.line_color_entry.editingFinished.connect(self.on_line_color_entry)
|
||||
self.line_color_button.clicked.connect(self.on_line_color_button)
|
||||
self.fill_color_entry.editingFinished.connect(self.on_fill_color_entry)
|
||||
self.fill_color_button.clicked.connect(self.on_fill_color_button)
|
||||
|
||||
# ------------------------------------------------------
|
||||
# Setting travel colors handlers
|
||||
|
@ -245,12 +288,27 @@ class CNCJobGenPrefGroupUI(OptionsGroupUI):
|
|||
def on_tfill_color_entry(self):
|
||||
self.app.defaults['cncjob_travel_fill'] = self.tfill_color_entry.get_value()[:7] + \
|
||||
self.app.defaults['cncjob_travel_fill'][7:9]
|
||||
self.tfill_color_button.setStyleSheet(
|
||||
"background-color:%s" % str(self.app.defaults['cncjob_travel_fill'])[:7])
|
||||
|
||||
def on_tline_color_entry(self):
|
||||
self.app.defaults['cncjob_travel_line'] = self.tline_color_entry.get_value()[:7] + \
|
||||
self.app.defaults['cncjob_travel_line'][7:9]
|
||||
def on_tfill_color_button(self):
|
||||
current_color = QtGui.QColor(self.app.defaults['cncjob_travel_fill'][:7])
|
||||
|
||||
def on_cncjob_alpha_changed(self, spinner_value):
|
||||
c_dialog = QtWidgets.QColorDialog()
|
||||
plot_fill_color = c_dialog.getColor(initial=current_color)
|
||||
|
||||
if plot_fill_color.isValid() is False:
|
||||
return
|
||||
|
||||
self.tfill_color_button.setStyleSheet("background-color:%s" % str(plot_fill_color.name()))
|
||||
|
||||
new_val = str(plot_fill_color.name()) + str(self.app.defaults['cncjob_travel_fill'][7:9])
|
||||
self.tfill_color_entry.set_value(new_val)
|
||||
self.app.defaults['cncjob_travel_fill'] = new_val
|
||||
|
||||
def on_tcolor_spinner(self):
|
||||
spinner_value = self.tcolor_alpha_spinner.value()
|
||||
self.tcolor_alpha_slider.setValue(spinner_value)
|
||||
self.app.defaults['cncjob_travel_fill'] = \
|
||||
self.app.defaults['cncjob_travel_fill'][:7] + \
|
||||
(hex(spinner_value)[2:] if int(hex(spinner_value)[2:], 16) > 0 else '00')
|
||||
|
@ -258,13 +316,74 @@ class CNCJobGenPrefGroupUI(OptionsGroupUI):
|
|||
self.app.defaults['cncjob_travel_line'][:7] + \
|
||||
(hex(spinner_value)[2:] if int(hex(spinner_value)[2:], 16) > 0 else '00')
|
||||
|
||||
def on_tcolor_slider(self):
|
||||
slider_value = self.tcolor_alpha_slider.value()
|
||||
self.tcolor_alpha_spinner.setValue(slider_value)
|
||||
|
||||
def on_tline_color_entry(self):
|
||||
self.app.defaults['cncjob_travel_line'] = self.tline_color_entry.get_value()[:7] + \
|
||||
self.app.defaults['cncjob_travel_line'][7:9]
|
||||
self.tline_color_button.setStyleSheet(
|
||||
"background-color:%s" % str(self.app.defaults['cncjob_travel_line'])[:7])
|
||||
|
||||
def on_tline_color_button(self):
|
||||
current_color = QtGui.QColor(self.app.defaults['cncjob_travel_line'][:7])
|
||||
# print(current_color)
|
||||
|
||||
c_dialog = QtWidgets.QColorDialog()
|
||||
plot_line_color = c_dialog.getColor(initial=current_color)
|
||||
|
||||
if plot_line_color.isValid() is False:
|
||||
return
|
||||
|
||||
self.tline_color_button.setStyleSheet("background-color:%s" % str(plot_line_color.name()))
|
||||
|
||||
new_val_line = str(plot_line_color.name()) + str(self.app.defaults['cncjob_travel_line'][7:9])
|
||||
self.tline_color_entry.set_value(new_val_line)
|
||||
self.app.defaults['cncjob_travel_line'] = new_val_line
|
||||
|
||||
# ------------------------------------------------------
|
||||
# Setting plot colors handlers
|
||||
# ------------------------------------------------------
|
||||
def on_fill_color_entry(self):
|
||||
self.app.defaults['cncjob_plot_fill'] = self.fill_color_entry.get_value()[:7] + \
|
||||
self.app.defaults['cncjob_plot_fill'][7:9]
|
||||
self.fill_color_button.setStyleSheet(
|
||||
"background-color:%s" % str(self.app.defaults['cncjob_plot_fill'])[:7])
|
||||
|
||||
def on_fill_color_button(self):
|
||||
current_color = QtGui.QColor(self.app.defaults['cncjob_plot_fill'][:7])
|
||||
|
||||
c_dialog = QtWidgets.QColorDialog()
|
||||
plot_fill_color = c_dialog.getColor(initial=current_color)
|
||||
|
||||
if plot_fill_color.isValid() is False:
|
||||
return
|
||||
|
||||
self.fill_color_button.setStyleSheet("background-color:%s" % str(plot_fill_color.name()))
|
||||
|
||||
new_val = str(plot_fill_color.name()) + str(self.app.defaults['cncjob_plot_fill'][7:9])
|
||||
self.fill_color_entry.set_value(new_val)
|
||||
self.app.defaults['cncjob_plot_fill'] = new_val
|
||||
|
||||
def on_line_color_entry(self):
|
||||
self.app.defaults['cncjob_plot_line'] = self.line_color_entry.get_value()[:7] + \
|
||||
self.app.defaults['cncjob_plot_line'][7:9]
|
||||
self.line_color_button.setStyleSheet(
|
||||
"background-color:%s" % str(self.app.defaults['cncjob_plot_line'])[:7])
|
||||
|
||||
def on_line_color_button(self):
|
||||
current_color = QtGui.QColor(self.app.defaults['cncjob_plot_line'][:7])
|
||||
# print(current_color)
|
||||
|
||||
c_dialog = QtWidgets.QColorDialog()
|
||||
plot_line_color = c_dialog.getColor(initial=current_color)
|
||||
|
||||
if plot_line_color.isValid() is False:
|
||||
return
|
||||
|
||||
self.line_color_button.setStyleSheet("background-color:%s" % str(plot_line_color.name()))
|
||||
|
||||
new_val_line = str(plot_line_color.name()) + str(self.app.defaults['cncjob_plot_line'][7:9])
|
||||
self.line_color_entry.set_value(new_val_line)
|
||||
self.app.defaults['cncjob_plot_line'] = new_val_line
|
|
@ -1,11 +1,11 @@
|
|||
from PyQt5 import QtWidgets, QtGui
|
||||
from PyQt5.QtCore import QSettings
|
||||
|
||||
from AppGUI.GUIElements import FCTextArea
|
||||
from AppGUI.preferences.OptionsGroupUI import OptionsGroupUI
|
||||
from flatcamGUI.GUIElements import FCTextArea
|
||||
from flatcamGUI.preferences.OptionsGroupUI import OptionsGroupUI
|
||||
|
||||
import gettext
|
||||
import AppTranslation as fcTranslate
|
||||
import FlatCAMTranslation as fcTranslate
|
||||
import builtins
|
||||
|
||||
fcTranslate.apply_language('strings')
|
|
@ -1,8 +1,8 @@
|
|||
from PyQt5 import QtWidgets
|
||||
|
||||
from AppGUI.preferences.cncjob.CNCJobAdvOptPrefGroupUI import CNCJobAdvOptPrefGroupUI
|
||||
from AppGUI.preferences.cncjob.CNCJobOptPrefGroupUI import CNCJobOptPrefGroupUI
|
||||
from AppGUI.preferences.cncjob.CNCJobGenPrefGroupUI import CNCJobGenPrefGroupUI
|
||||
from flatcamGUI.preferences.cncjob.CNCJobAdvOptPrefGroupUI import CNCJobAdvOptPrefGroupUI
|
||||
from flatcamGUI.preferences.cncjob.CNCJobOptPrefGroupUI import CNCJobOptPrefGroupUI
|
||||
from flatcamGUI.preferences.cncjob.CNCJobGenPrefGroupUI import CNCJobGenPrefGroupUI
|
||||
|
||||
|
||||
class CNCJobPreferencesUI(QtWidgets.QWidget):
|
|
@ -1,10 +1,10 @@
|
|||
from PyQt5 import QtWidgets
|
||||
from PyQt5.QtCore import QSettings
|
||||
|
||||
from AppGUI.GUIElements import FCDoubleSpinner, RadioSet, FCCheckBox, NumericalEvalTupleEntry, NumericalEvalEntry
|
||||
from AppGUI.preferences.OptionsGroupUI import OptionsGroupUI
|
||||
from flatcamGUI.GUIElements import FCDoubleSpinner, FCEntry, FloatEntry, RadioSet, FCCheckBox
|
||||
from flatcamGUI.preferences.OptionsGroupUI import OptionsGroupUI
|
||||
import gettext
|
||||
import AppTranslation as fcTranslate
|
||||
import FlatCAMTranslation as fcTranslate
|
||||
import builtins
|
||||
|
||||
fcTranslate.apply_language('strings')
|
||||
|
@ -60,7 +60,7 @@ class ExcellonAdvOptPrefGroupUI(OptionsGroupUI):
|
|||
toolchange_xy_label.setToolTip(
|
||||
_("Toolchange X,Y position.")
|
||||
)
|
||||
self.toolchangexy_entry = NumericalEvalTupleEntry(border_color='#0069A9')
|
||||
self.toolchangexy_entry = FCEntry()
|
||||
|
||||
grid1.addWidget(toolchange_xy_label, 1, 0)
|
||||
grid1.addWidget(self.toolchangexy_entry, 1, 1)
|
||||
|
@ -71,7 +71,7 @@ class ExcellonAdvOptPrefGroupUI(OptionsGroupUI):
|
|||
_("Height of the tool just after start.\n"
|
||||
"Delete the value if you don't need this feature.")
|
||||
)
|
||||
self.estartz_entry = NumericalEvalEntry(border_color='#0069A9')
|
||||
self.estartz_entry = FloatEntry()
|
||||
|
||||
grid1.addWidget(startzlabel, 2, 0)
|
||||
grid1.addWidget(self.estartz_entry, 2, 1)
|
|
@ -1,11 +1,11 @@
|
|||
from PyQt5 import QtWidgets
|
||||
from PyQt5.QtCore import QSettings
|
||||
|
||||
from AppGUI.GUIElements import FCSpinner, FCDoubleSpinner, RadioSet
|
||||
from AppGUI.preferences.OptionsGroupUI import OptionsGroupUI
|
||||
from flatcamGUI.GUIElements import FCSpinner, FCDoubleSpinner, RadioSet
|
||||
from flatcamGUI.preferences.OptionsGroupUI import OptionsGroupUI
|
||||
|
||||
import gettext
|
||||
import AppTranslation as fcTranslate
|
||||
import FlatCAMTranslation as fcTranslate
|
||||
import builtins
|
||||
|
||||
fcTranslate.apply_language('strings')
|
|
@ -1,10 +1,10 @@
|
|||
from PyQt5 import QtWidgets, QtCore
|
||||
from PyQt5.QtCore import QSettings
|
||||
|
||||
from AppGUI.GUIElements import RadioSet, FCSpinner
|
||||
from AppGUI.preferences.OptionsGroupUI import OptionsGroupUI
|
||||
from flatcamGUI.GUIElements import RadioSet, FCSpinner
|
||||
from flatcamGUI.preferences.OptionsGroupUI import OptionsGroupUI
|
||||
import gettext
|
||||
import AppTranslation as fcTranslate
|
||||
import FlatCAMTranslation as fcTranslate
|
||||
import builtins
|
||||
|
||||
fcTranslate.apply_language('strings')
|
|
@ -3,10 +3,10 @@ import platform
|
|||
from PyQt5 import QtWidgets, QtCore, QtGui
|
||||
from PyQt5.QtCore import QSettings
|
||||
|
||||
from AppGUI.GUIElements import FCCheckBox, FCSpinner, RadioSet, FCEntry, FCSliderWithSpinner, FCColorEntry
|
||||
from AppGUI.preferences.OptionsGroupUI import OptionsGroupUI
|
||||
from flatcamGUI.GUIElements import FCCheckBox, FCSpinner, RadioSet, FCEntry
|
||||
from flatcamGUI.preferences.OptionsGroupUI import OptionsGroupUI
|
||||
import gettext
|
||||
import AppTranslation as fcTranslate
|
||||
import FlatCAMTranslation as fcTranslate
|
||||
import builtins
|
||||
|
||||
fcTranslate.apply_language('strings')
|
||||
|
@ -36,31 +36,22 @@ class ExcellonGenPrefGroupUI(OptionsGroupUI):
|
|||
grid1 = QtWidgets.QGridLayout()
|
||||
self.layout.addLayout(grid1)
|
||||
|
||||
# Plot CB
|
||||
self.plot_cb = FCCheckBox(label=_('Plot'))
|
||||
self.plot_cb.setToolTip(
|
||||
"Plot (show) this object."
|
||||
)
|
||||
grid1.addWidget(self.plot_cb, 0, 0)
|
||||
|
||||
# Solid CB
|
||||
self.solid_cb = FCCheckBox(label=_('Solid'))
|
||||
self.solid_cb.setToolTip(
|
||||
"Plot as solid circles."
|
||||
)
|
||||
grid1.addWidget(self.solid_cb, 0, 1)
|
||||
|
||||
# Multicolored CB
|
||||
self.multicolored_cb = FCCheckBox(label='%s' % _('M-Color'))
|
||||
self.multicolored_cb.setToolTip(
|
||||
_("Draw polygons in different colors.")
|
||||
)
|
||||
grid1.addWidget(self.multicolored_cb, 0, 2)
|
||||
|
||||
separator_line = QtWidgets.QFrame()
|
||||
separator_line.setFrameShape(QtWidgets.QFrame.HLine)
|
||||
separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
|
||||
grid1.addWidget(separator_line, 1, 0, 1, 3)
|
||||
grid1.addWidget(separator_line, 1, 0, 1, 2)
|
||||
|
||||
grid2 = QtWidgets.QGridLayout()
|
||||
self.layout.addLayout(grid2)
|
||||
|
@ -264,7 +255,7 @@ class ExcellonGenPrefGroupUI(OptionsGroupUI):
|
|||
grid2.addWidget(separator_line, 11, 0, 1, 2)
|
||||
|
||||
# Excellon Object Color
|
||||
self.gerber_color_label = QtWidgets.QLabel('<b>%s</b>' % _('Object Color'))
|
||||
self.gerber_color_label = QtWidgets.QLabel('<b>%s</b>' % _('Excellon Object Color'))
|
||||
grid2.addWidget(self.gerber_color_label, 12, 0, 1, 2)
|
||||
|
||||
# Plot Line Color
|
||||
|
@ -272,10 +263,17 @@ class ExcellonGenPrefGroupUI(OptionsGroupUI):
|
|||
self.line_color_label.setToolTip(
|
||||
_("Set the line color for plotted objects.")
|
||||
)
|
||||
self.line_color_entry = FCColorEntry()
|
||||
self.line_color_entry = FCEntry()
|
||||
self.line_color_button = QtWidgets.QPushButton()
|
||||
self.line_color_button.setFixedSize(15, 15)
|
||||
|
||||
self.form_box_child_2 = QtWidgets.QHBoxLayout()
|
||||
self.form_box_child_2.addWidget(self.line_color_entry)
|
||||
self.form_box_child_2.addWidget(self.line_color_button)
|
||||
self.form_box_child_2.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter)
|
||||
|
||||
grid2.addWidget(self.line_color_label, 13, 0)
|
||||
grid2.addWidget(self.line_color_entry, 13, 1)
|
||||
grid2.addLayout(self.form_box_child_2, 13, 1)
|
||||
|
||||
# Plot Fill Color
|
||||
self.fill_color_label = QtWidgets.QLabel('%s:' % _('Fill'))
|
||||
|
@ -284,20 +282,38 @@ class ExcellonGenPrefGroupUI(OptionsGroupUI):
|
|||
"First 6 digits are the color and the last 2\n"
|
||||
"digits are for alpha (transparency) level.")
|
||||
)
|
||||
self.fill_color_entry = FCColorEntry()
|
||||
self.fill_color_entry = FCEntry()
|
||||
self.fill_color_button = QtWidgets.QPushButton()
|
||||
self.fill_color_button.setFixedSize(15, 15)
|
||||
|
||||
self.form_box_child_1 = QtWidgets.QHBoxLayout()
|
||||
self.form_box_child_1.addWidget(self.fill_color_entry)
|
||||
self.form_box_child_1.addWidget(self.fill_color_button)
|
||||
self.form_box_child_1.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter)
|
||||
|
||||
grid2.addWidget(self.fill_color_label, 14, 0)
|
||||
grid2.addWidget(self.fill_color_entry, 14, 1)
|
||||
grid2.addLayout(self.form_box_child_1, 14, 1)
|
||||
|
||||
# Plot Fill Transparency Level
|
||||
self.excellon_alpha_label = QtWidgets.QLabel('%s:' % _('Alpha'))
|
||||
self.excellon_alpha_label.setToolTip(
|
||||
self.alpha_label = QtWidgets.QLabel('%s:' % _('Alpha'))
|
||||
self.alpha_label.setToolTip(
|
||||
_("Set the fill transparency for plotted objects.")
|
||||
)
|
||||
self.excellon_alpha_entry = FCSliderWithSpinner(0, 255, 1)
|
||||
self.color_alpha_slider = QtWidgets.QSlider(QtCore.Qt.Horizontal)
|
||||
self.color_alpha_slider.setMinimum(0)
|
||||
self.color_alpha_slider.setMaximum(255)
|
||||
self.color_alpha_slider.setSingleStep(1)
|
||||
|
||||
grid2.addWidget(self.excellon_alpha_label, 15, 0)
|
||||
grid2.addWidget(self.excellon_alpha_entry, 15, 1)
|
||||
self.color_alpha_spinner = FCSpinner()
|
||||
self.color_alpha_spinner.setMinimumWidth(70)
|
||||
self.color_alpha_spinner.set_range(0, 255)
|
||||
|
||||
self.form_box_child_3 = QtWidgets.QHBoxLayout()
|
||||
self.form_box_child_3.addWidget(self.color_alpha_slider)
|
||||
self.form_box_child_3.addWidget(self.color_alpha_spinner)
|
||||
|
||||
grid2.addWidget(self.alpha_label, 15, 0)
|
||||
grid2.addLayout(self.form_box_child_3, 15, 1)
|
||||
|
||||
self.layout.addStretch()
|
||||
|
||||
|
@ -317,18 +333,14 @@ class ExcellonGenPrefGroupUI(OptionsGroupUI):
|
|||
|
||||
# Setting plot colors signals
|
||||
self.line_color_entry.editingFinished.connect(self.on_line_color_entry)
|
||||
self.line_color_button.clicked.connect(self.on_line_color_button)
|
||||
self.fill_color_entry.editingFinished.connect(self.on_fill_color_entry)
|
||||
|
||||
self.excellon_alpha_entry.valueChanged.connect(self.on_excellon_alpha_changed) # alpha
|
||||
self.fill_color_button.clicked.connect(self.on_fill_color_button)
|
||||
self.color_alpha_spinner.valueChanged.connect(self.on_color_spinner)
|
||||
self.color_alpha_slider.valueChanged.connect(self.on_color_slider)
|
||||
|
||||
# Load the defaults values into the Excellon Format and Excellon Zeros fields
|
||||
self.excellon_defaults_button.clicked.connect(self.on_excellon_defaults_button)
|
||||
# Make sure that when the Excellon loading parameters are changed, the change is reflected in the
|
||||
# Export Excellon parameters.
|
||||
self.update_excellon_cb.stateChanged.connect(self.on_update_exc_export)
|
||||
|
||||
# call it once to make sure it is updated at startup
|
||||
self.on_update_exc_export(state=self.app.defaults["excellon_update"])
|
||||
|
||||
def optimization_selection(self):
|
||||
if self.excellon_optimization_radio.get_value() == 'M':
|
||||
|
@ -342,12 +354,26 @@ class ExcellonGenPrefGroupUI(OptionsGroupUI):
|
|||
def on_fill_color_entry(self):
|
||||
self.app.defaults['excellon_plot_fill'] = self.fill_color_entry.get_value()[:7] + \
|
||||
self.app.defaults['excellon_plot_fill'][7:9]
|
||||
self.fill_color_button.setStyleSheet("background-color:%s" % str(self.app.defaults['excellon_plot_fill'])[:7])
|
||||
|
||||
def on_line_color_entry(self):
|
||||
self.app.defaults['excellon_plot_line'] = self.line_color_entry.get_value()[:7] + \
|
||||
self.app.defaults['excellon_plot_line'][7:9]
|
||||
def on_fill_color_button(self):
|
||||
current_color = QtGui.QColor(self.app.defaults['excellon_plot_fill'][:7])
|
||||
|
||||
def on_excellon_alpha_changed(self, spinner_value):
|
||||
c_dialog = QtWidgets.QColorDialog()
|
||||
plot_fill_color = c_dialog.getColor(initial=current_color)
|
||||
|
||||
if plot_fill_color.isValid() is False:
|
||||
return
|
||||
|
||||
self.fill_color_button.setStyleSheet("background-color:%s" % str(plot_fill_color.name()))
|
||||
|
||||
new_val = str(plot_fill_color.name()) + str(self.app.defaults['excellon_plot_fill'][7:9])
|
||||
self.fill_color_entry.set_value(new_val)
|
||||
self.app.defaults['excellon_plot_fill'] = new_val
|
||||
|
||||
def on_color_spinner(self):
|
||||
spinner_value = self.color_alpha_spinner.value()
|
||||
self.color_alpha_slider.setValue(spinner_value)
|
||||
self.app.defaults['excellon_plot_fill'] = \
|
||||
self.app.defaults['excellon_plot_fill'][:7] + \
|
||||
(hex(spinner_value)[2:] if int(hex(spinner_value)[2:], 16) > 0 else '00')
|
||||
|
@ -355,6 +381,31 @@ class ExcellonGenPrefGroupUI(OptionsGroupUI):
|
|||
self.app.defaults['excellon_plot_line'][:7] + \
|
||||
(hex(spinner_value)[2:] if int(hex(spinner_value)[2:], 16) > 0 else '00')
|
||||
|
||||
def on_color_slider(self):
|
||||
slider_value = self.color_alpha_slider.value()
|
||||
self.color_alpha_spinner.setValue(slider_value)
|
||||
|
||||
def on_line_color_entry(self):
|
||||
self.app.defaults['excellon_plot_line'] = self.line_color_entry.get_value()[:7] + \
|
||||
self.app.defaults['excellon_plot_line'][7:9]
|
||||
self.line_color_button.setStyleSheet("background-color:%s" % str(self.app.defaults['excellon_plot_line'])[:7])
|
||||
|
||||
def on_line_color_button(self):
|
||||
current_color = QtGui.QColor(self.app.defaults['excellon_plot_line'][:7])
|
||||
# print(current_color)
|
||||
|
||||
c_dialog = QtWidgets.QColorDialog()
|
||||
plot_line_color = c_dialog.getColor(initial=current_color)
|
||||
|
||||
if plot_line_color.isValid() is False:
|
||||
return
|
||||
|
||||
self.line_color_button.setStyleSheet("background-color:%s" % str(plot_line_color.name()))
|
||||
|
||||
new_val_line = str(plot_line_color.name()) + str(self.app.defaults['excellon_plot_line'][7:9])
|
||||
self.line_color_entry.set_value(new_val_line)
|
||||
self.app.defaults['excellon_plot_line'] = new_val_line
|
||||
|
||||
def on_excellon_defaults_button(self):
|
||||
self.app.preferencesUiManager.defaults_form_fields["excellon_format_lower_in"].set_value('4')
|
||||
self.app.preferencesUiManager.defaults_form_fields["excellon_format_upper_in"].set_value('2')
|
||||
|
@ -362,105 +413,3 @@ class ExcellonGenPrefGroupUI(OptionsGroupUI):
|
|||
self.app.preferencesUiManager.defaults_form_fields["excellon_format_upper_mm"].set_value('3')
|
||||
self.app.preferencesUiManager.defaults_form_fields["excellon_zeros"].set_value('L')
|
||||
self.app.preferencesUiManager.defaults_form_fields["excellon_units"].set_value('INCH')
|
||||
|
||||
def on_update_exc_export(self, state):
|
||||
"""
|
||||
This is handling the update of Excellon Export parameters based on the ones in the Excellon General but only
|
||||
if the update_excellon_cb checkbox is checked
|
||||
|
||||
:param state: state of the checkbox whose signals is tied to his slot
|
||||
:return:
|
||||
"""
|
||||
if state:
|
||||
# first try to disconnect
|
||||
try:
|
||||
self.excellon_format_upper_in_entry.returnPressed.disconnect(self.on_excellon_format_changed)
|
||||
except TypeError:
|
||||
pass
|
||||
try:
|
||||
self.excellon_format_lower_in_entry.returnPressed.disconnect(self.on_excellon_format_changed)
|
||||
except TypeError:
|
||||
pass
|
||||
try:
|
||||
self.excellon_format_upper_mm_entry.returnPressed.disconnect(self.on_excellon_format_changed)
|
||||
except TypeError:
|
||||
pass
|
||||
try:
|
||||
self.excellon_format_lower_mm_entry.returnPressed.disconnect(self.on_excellon_format_changed)
|
||||
except TypeError:
|
||||
pass
|
||||
|
||||
try:
|
||||
self.excellon_zeros_radio.activated_custom.disconnect(self.on_excellon_zeros_changed)
|
||||
except TypeError:
|
||||
pass
|
||||
try:
|
||||
self.excellon_units_radio.activated_custom.disconnect(self.on_excellon_zeros_changed)
|
||||
except TypeError:
|
||||
pass
|
||||
|
||||
# the connect them
|
||||
self.excellon_format_upper_in_entry.returnPressed.connect(self.on_excellon_format_changed)
|
||||
self.excellon_format_lower_in_entry.returnPressed.connect(self.on_excellon_format_changed)
|
||||
self.excellon_format_upper_mm_entry.returnPressed.connect(self.on_excellon_format_changed)
|
||||
self.excellon_format_lower_mm_entry.returnPressed.connect(self.on_excellon_format_changed)
|
||||
self.excellon_zeros_radio.activated_custom.connect(self.on_excellon_zeros_changed)
|
||||
self.excellon_units_radio.activated_custom.connect(self.on_excellon_units_changed)
|
||||
else:
|
||||
# disconnect the signals
|
||||
try:
|
||||
self.excellon_format_upper_in_entry.returnPressed.disconnect(self.on_excellon_format_changed)
|
||||
except TypeError:
|
||||
pass
|
||||
try:
|
||||
self.excellon_format_lower_in_entry.returnPressed.disconnect(self.on_excellon_format_changed)
|
||||
except TypeError:
|
||||
pass
|
||||
try:
|
||||
self.excellon_format_upper_mm_entry.returnPressed.disconnect(self.on_excellon_format_changed)
|
||||
except TypeError:
|
||||
pass
|
||||
try:
|
||||
self.excellon_format_lower_mm_entry.returnPressed.disconnect(self.on_excellon_format_changed)
|
||||
except TypeError:
|
||||
pass
|
||||
|
||||
try:
|
||||
self.excellon_zeros_radio.activated_custom.disconnect(self.on_excellon_zeros_changed)
|
||||
except TypeError:
|
||||
pass
|
||||
try:
|
||||
self.excellon_units_radio.activated_custom.disconnect(self.on_excellon_zeros_changed)
|
||||
except TypeError:
|
||||
pass
|
||||
|
||||
def on_excellon_format_changed(self):
|
||||
"""
|
||||
Slot activated when the user changes the Excellon format values in Preferences -> Excellon -> Excellon General
|
||||
:return: None
|
||||
"""
|
||||
if self.excellon_units_radio.get_value().upper() == 'METRIC':
|
||||
self.app.ui.excellon_defaults_form.excellon_exp_group.format_whole_entry.set_value(
|
||||
self.excellon_format_upper_mm_entry.get_value())
|
||||
self.app.ui.excellon_defaults_form.excellon_exp_group.format_dec_entry.set_value(
|
||||
self.excellon_format_lower_mm_entry.get_value())
|
||||
else:
|
||||
self.app.ui.excellon_defaults_form.excellon_exp_group.format_whole_entry.set_value(
|
||||
self.excellon_format_upper_in_entry.get_value())
|
||||
self.app.ui.excellon_defaults_form.excellon_exp_group.format_dec_entry.set_value(
|
||||
self.excellon_format_lower_in_entry.get_value())
|
||||
|
||||
def on_excellon_zeros_changed(self, val):
|
||||
"""
|
||||
Slot activated when the user changes the Excellon zeros values in Preferences -> Excellon -> Excellon General
|
||||
:return: None
|
||||
"""
|
||||
self.app.ui.excellon_defaults_form.excellon_exp_group.zeros_radio.set_value(val + 'Z')
|
||||
|
||||
def on_excellon_units_changed(self, val):
|
||||
"""
|
||||
Slot activated when the user changes the Excellon unit values in Preferences -> Excellon -> Excellon General
|
||||
:return: None
|
||||
"""
|
||||
self.app.ui.excellon_defaults_form.excellon_exp_group.excellon_units_radio.set_value(val)
|
||||
self.on_excellon_format_changed()
|
|
@ -1,12 +1,12 @@
|
|||
from PyQt5 import QtWidgets
|
||||
from PyQt5.QtCore import Qt, QSettings
|
||||
|
||||
from AppGUI.GUIElements import RadioSet, FCDoubleSpinner, FCCheckBox, FCEntry, FCSpinner, OptionalInputSection, \
|
||||
FCComboBox, NumericalEvalTupleEntry
|
||||
from AppGUI.preferences import machinist_setting
|
||||
from AppGUI.preferences.OptionsGroupUI import OptionsGroupUI
|
||||
from flatcamGUI.GUIElements import RadioSet, FCDoubleSpinner, FCCheckBox, FCEntry, FCSpinner, OptionalInputSection, \
|
||||
FCComboBox
|
||||
from flatcamGUI.preferences import machinist_setting
|
||||
from flatcamGUI.preferences.OptionsGroupUI import OptionsGroupUI
|
||||
import gettext
|
||||
import AppTranslation as fcTranslate
|
||||
import FlatCAMTranslation as fcTranslate
|
||||
import builtins
|
||||
|
||||
fcTranslate.apply_language('strings')
|
||||
|
@ -198,7 +198,7 @@ class ExcellonOptPrefGroupUI(OptionsGroupUI):
|
|||
"If no value is entered then there is no move\n"
|
||||
"on X,Y plane at the end of the job.")
|
||||
)
|
||||
self.endxy_entry = NumericalEvalTupleEntry(border_color='#0069A9')
|
||||
self.endxy_entry = FCEntry()
|
||||
|
||||
grid2.addWidget(endmove_xy_label, 9, 0)
|
||||
grid2.addWidget(self.endxy_entry, 9, 1)
|
|
@ -1,14 +1,14 @@
|
|||
from PyQt5 import QtWidgets
|
||||
from PyQt5.QtCore import QSettings
|
||||
|
||||
from AppGUI.preferences.excellon.ExcellonEditorPrefGroupUI import ExcellonEditorPrefGroupUI
|
||||
from AppGUI.preferences.excellon.ExcellonExpPrefGroupUI import ExcellonExpPrefGroupUI
|
||||
from AppGUI.preferences.excellon.ExcellonAdvOptPrefGroupUI import ExcellonAdvOptPrefGroupUI
|
||||
from AppGUI.preferences.excellon.ExcellonOptPrefGroupUI import ExcellonOptPrefGroupUI
|
||||
from AppGUI.preferences.excellon.ExcellonGenPrefGroupUI import ExcellonGenPrefGroupUI
|
||||
from flatcamGUI.preferences.excellon.ExcellonEditorPrefGroupUI import ExcellonEditorPrefGroupUI
|
||||
from flatcamGUI.preferences.excellon.ExcellonExpPrefGroupUI import ExcellonExpPrefGroupUI
|
||||
from flatcamGUI.preferences.excellon.ExcellonAdvOptPrefGroupUI import ExcellonAdvOptPrefGroupUI
|
||||
from flatcamGUI.preferences.excellon.ExcellonOptPrefGroupUI import ExcellonOptPrefGroupUI
|
||||
from flatcamGUI.preferences.excellon.ExcellonGenPrefGroupUI import ExcellonGenPrefGroupUI
|
||||
|
||||
import gettext
|
||||
import AppTranslation as fcTranslate
|
||||
import FlatCAMTranslation as fcTranslate
|
||||
import builtins
|
||||
|
||||
fcTranslate.apply_language('strings')
|
||||
|
@ -31,7 +31,7 @@ class ExcellonPreferencesUI(QtWidgets.QWidget):
|
|||
self.decimals = decimals
|
||||
|
||||
self.excellon_gen_group = ExcellonGenPrefGroupUI(decimals=self.decimals)
|
||||
self.excellon_gen_group.setMinimumWidth(240)
|
||||
self.excellon_gen_group.setMinimumWidth(220)
|
||||
self.excellon_opt_group = ExcellonOptPrefGroupUI(decimals=self.decimals)
|
||||
self.excellon_opt_group.setMinimumWidth(290)
|
||||
self.excellon_exp_group = ExcellonExpPrefGroupUI(decimals=self.decimals)
|
|
@ -1,13 +1,13 @@
|
|||
from PyQt5 import QtCore, QtWidgets
|
||||
from PyQt5 import QtCore, QtWidgets, QtGui
|
||||
from PyQt5.QtCore import QSettings
|
||||
|
||||
from AppGUI.GUIElements import FCDoubleSpinner, FCCheckBox, FCComboBox, RadioSet, OptionalInputSection, FCSpinner, \
|
||||
FCColorEntry
|
||||
from AppGUI.preferences import settings
|
||||
from AppGUI.preferences.OptionsGroupUI import OptionsGroupUI
|
||||
from flatcamGUI.GUIElements import FCDoubleSpinner, FCCheckBox, FCComboBox, RadioSet, OptionalInputSection, FCSpinner, \
|
||||
FCEntry
|
||||
from flatcamGUI.preferences import settings
|
||||
from flatcamGUI.preferences.OptionsGroupUI import OptionsGroupUI
|
||||
|
||||
import gettext
|
||||
import AppTranslation as fcTranslate
|
||||
import FlatCAMTranslation as fcTranslate
|
||||
import builtins
|
||||
|
||||
fcTranslate.apply_language('strings')
|
||||
|
@ -177,6 +177,14 @@ class GeneralAPPSetGroupUI(OptionsGroupUI):
|
|||
{'label': _('Landscape'), 'value': 'l'},
|
||||
], stretch=False)
|
||||
|
||||
self.wks = OptionalInputSection(self.workspace_cb,
|
||||
[
|
||||
self.workspace_type_lbl,
|
||||
self.wk_cb,
|
||||
self.wk_orientation_label,
|
||||
self.wk_orientation_radio
|
||||
])
|
||||
|
||||
grid0.addWidget(self.wk_orientation_label, 8, 0)
|
||||
grid0.addWidget(self.wk_orientation_radio, 8, 1)
|
||||
|
||||
|
@ -193,7 +201,7 @@ class GeneralAPPSetGroupUI(OptionsGroupUI):
|
|||
self.notebook_font_size_label = QtWidgets.QLabel('%s:' % _('Notebook'))
|
||||
self.notebook_font_size_label.setToolTip(
|
||||
_("This sets the font size for the elements found in the Notebook.\n"
|
||||
"The notebook is the collapsible area in the left side of the AppGUI,\n"
|
||||
"The notebook is the collapsible area in the left side of the GUI,\n"
|
||||
"and include the Project, Selected and Tool tabs.")
|
||||
)
|
||||
|
||||
|
@ -232,8 +240,8 @@ class GeneralAPPSetGroupUI(OptionsGroupUI):
|
|||
# TextBox Font Size
|
||||
self.textbox_font_size_label = QtWidgets.QLabel('%s:' % _('Textbox'))
|
||||
self.textbox_font_size_label.setToolTip(
|
||||
_("This sets the font size for the Textbox AppGUI\n"
|
||||
"elements that are used in the application.")
|
||||
_("This sets the font size for the Textbox GUI\n"
|
||||
"elements that are used in FlatCAM.")
|
||||
)
|
||||
|
||||
self.textbox_font_size_spinner = FCSpinner()
|
||||
|
@ -249,29 +257,10 @@ class GeneralAPPSetGroupUI(OptionsGroupUI):
|
|||
grid0.addWidget(self.textbox_font_size_label, 13, 0)
|
||||
grid0.addWidget(self.textbox_font_size_spinner, 13, 1)
|
||||
|
||||
# HUD Font Size
|
||||
self.hud_font_size_label = QtWidgets.QLabel('%s:' % _('HUD'))
|
||||
self.hud_font_size_label.setToolTip(
|
||||
_("This sets the font size for the Heads Up Display.")
|
||||
)
|
||||
|
||||
self.hud_font_size_spinner = FCSpinner()
|
||||
self.hud_font_size_spinner.set_range(8, 40)
|
||||
self.hud_font_size_spinner.setWrapping(True)
|
||||
|
||||
qsettings = QSettings("Open Source", "FlatCAM")
|
||||
if qsettings.contains("hud_font_size"):
|
||||
self.hud_font_size_spinner.set_value(settings.value('hud_font_size', type=int))
|
||||
else:
|
||||
self.hud_font_size_spinner.set_value(8)
|
||||
|
||||
grid0.addWidget(self.hud_font_size_label, 14, 0)
|
||||
grid0.addWidget(self.hud_font_size_spinner, 14, 1)
|
||||
|
||||
separator_line = QtWidgets.QFrame()
|
||||
separator_line.setFrameShape(QtWidgets.QFrame.HLine)
|
||||
separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
|
||||
grid0.addWidget(separator_line, 16, 0, 1, 2)
|
||||
grid0.addWidget(separator_line, 14, 0, 1, 2)
|
||||
|
||||
# -----------------------------------------------------------
|
||||
# -------------- MOUSE SETTINGS -----------------------------
|
||||
|
@ -334,16 +323,24 @@ class GeneralAPPSetGroupUI(OptionsGroupUI):
|
|||
self.mouse_color_label.setToolTip(
|
||||
_("Set the color of the mouse cursor.")
|
||||
)
|
||||
self.mouse_cursor_entry = FCColorEntry()
|
||||
self.mouse_cursor_entry = FCEntry()
|
||||
self.mouse_cursor_button = QtWidgets.QPushButton()
|
||||
self.mouse_cursor_button.setFixedSize(15, 15)
|
||||
|
||||
self.form_box_child_1 = QtWidgets.QHBoxLayout()
|
||||
self.form_box_child_1.addWidget(self.mouse_cursor_entry)
|
||||
self.form_box_child_1.addWidget(self.mouse_cursor_button)
|
||||
self.form_box_child_1.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter)
|
||||
|
||||
grid0.addWidget(self.mouse_color_label, 26, 0)
|
||||
grid0.addWidget(self.mouse_cursor_entry, 26, 1)
|
||||
grid0.addLayout(self.form_box_child_1, 26, 1)
|
||||
|
||||
self.mois = OptionalInputSection(
|
||||
self.mouse_cursor_color_cb,
|
||||
[
|
||||
self.mouse_color_label,
|
||||
self.mouse_cursor_entry
|
||||
self.mouse_cursor_entry,
|
||||
self.mouse_cursor_button
|
||||
]
|
||||
)
|
||||
# Select mouse pan button
|
||||
|
@ -443,7 +440,9 @@ class GeneralAPPSetGroupUI(OptionsGroupUI):
|
|||
self.layout.addStretch()
|
||||
|
||||
self.mouse_cursor_color_cb.stateChanged.connect(self.on_mouse_cursor_color_enable)
|
||||
|
||||
self.mouse_cursor_entry.editingFinished.connect(self.on_mouse_cursor_entry)
|
||||
self.mouse_cursor_button.clicked.connect(self.on_mouse_cursor_button)
|
||||
|
||||
def on_mouse_cursor_color_enable(self, val):
|
||||
if val:
|
||||
|
@ -462,4 +461,23 @@ class GeneralAPPSetGroupUI(OptionsGroupUI):
|
|||
|
||||
def on_mouse_cursor_entry(self):
|
||||
self.app.defaults['global_cursor_color'] = self.mouse_cursor_entry.get_value()
|
||||
self.mouse_cursor_button.setStyleSheet("background-color:%s" % str(self.app.defaults['global_cursor_color']))
|
||||
|
||||
self.app.cursor_color_3D = self.app.defaults["global_cursor_color"]
|
||||
|
||||
def on_mouse_cursor_button(self):
|
||||
current_color = QtGui.QColor(self.app.defaults['global_cursor_color'])
|
||||
|
||||
c_dialog = QtWidgets.QColorDialog()
|
||||
proj_color = c_dialog.getColor(initial=current_color)
|
||||
|
||||
if proj_color.isValid() is False:
|
||||
return
|
||||
|
||||
self.mouse_cursor_button.setStyleSheet("background-color:%s" % str(proj_color.name()))
|
||||
|
||||
new_val_sel = str(proj_color.name())
|
||||
self.mouse_cursor_entry.set_value(new_val_sel)
|
||||
self.app.defaults['global_cursor_color'] = new_val_sel
|
||||
|
||||
self.app.cursor_color_3D = self.app.defaults["global_cursor_color"]
|
|
@ -3,12 +3,12 @@ import sys
|
|||
from PyQt5 import QtWidgets
|
||||
from PyQt5.QtCore import QSettings
|
||||
|
||||
from AppGUI.GUIElements import RadioSet, FCSpinner, FCCheckBox, FCComboBox, FCButton, OptionalInputSection, \
|
||||
from flatcamGUI.GUIElements import RadioSet, FCSpinner, FCCheckBox, FCComboBox, FCButton, OptionalInputSection, \
|
||||
FCDoubleSpinner
|
||||
from AppGUI.preferences.OptionsGroupUI import OptionsGroupUI
|
||||
from flatcamGUI.preferences.OptionsGroupUI import OptionsGroupUI
|
||||
|
||||
import gettext
|
||||
import AppTranslation as fcTranslate
|
||||
import FlatCAMTranslation as fcTranslate
|
||||
import builtins
|
||||
|
||||
fcTranslate.apply_language('strings')
|
||||
|
@ -380,11 +380,12 @@ class GeneralAppPrefGroupUI(OptionsGroupUI):
|
|||
|
||||
def on_toggle_shell_from_settings(self, state):
|
||||
"""
|
||||
Toggle shell ui: if is visible close it, if it is closed then open it
|
||||
|
||||
Toggle shell: if is visible close it, if it is closed then open it
|
||||
:return: None
|
||||
"""
|
||||
|
||||
self.app.defaults.report_usage("on_toggle_shell_from_settings()")
|
||||
|
||||
if state is True:
|
||||
if not self.app.ui.shell_dock.isVisible():
|
||||
self.app.ui.shell_dock.show()
|
|
@ -1,11 +1,11 @@
|
|||
from PyQt5 import QtWidgets, QtCore, QtGui
|
||||
from PyQt5.QtCore import QSettings, Qt
|
||||
|
||||
from AppGUI.GUIElements import RadioSet, FCCheckBox, FCComboBox, FCSliderWithSpinner, FCColorEntry
|
||||
from AppGUI.preferences.OptionsGroupUI import OptionsGroupUI
|
||||
from flatcamGUI.GUIElements import RadioSet, FCCheckBox, FCButton, FCComboBox, FCEntry, FCSpinner
|
||||
from flatcamGUI.preferences.OptionsGroupUI import OptionsGroupUI
|
||||
|
||||
import gettext
|
||||
import AppTranslation as fcTranslate
|
||||
import FlatCAMTranslation as fcTranslate
|
||||
import builtins
|
||||
|
||||
fcTranslate.apply_language('strings')
|
||||
|
@ -35,7 +35,7 @@ class GeneralGUIPrefGroupUI(OptionsGroupUI):
|
|||
# Theme selection
|
||||
self.theme_label = QtWidgets.QLabel('%s:' % _('Theme'))
|
||||
self.theme_label.setToolTip(
|
||||
_("Select a theme for the application.\n"
|
||||
_("Select a theme for FlatCAM.\n"
|
||||
"It will theme the plot area.")
|
||||
)
|
||||
|
||||
|
@ -72,7 +72,7 @@ class GeneralGUIPrefGroupUI(OptionsGroupUI):
|
|||
# Layout selection
|
||||
self.layout_label = QtWidgets.QLabel('%s:' % _('Layout'))
|
||||
self.layout_label.setToolTip(
|
||||
_("Select a layout for the application.\n"
|
||||
_("Select an layout for FlatCAM.\n"
|
||||
"It is applied immediately.")
|
||||
)
|
||||
self.layout_combo = FCComboBox()
|
||||
|
@ -94,7 +94,7 @@ class GeneralGUIPrefGroupUI(OptionsGroupUI):
|
|||
# Style selection
|
||||
self.style_label = QtWidgets.QLabel('%s:' % _('Style'))
|
||||
self.style_label.setToolTip(
|
||||
_("Select a style for the application.\n"
|
||||
_("Select an style for FlatCAM.\n"
|
||||
"It will be applied at the next app start.")
|
||||
)
|
||||
self.style_combo = FCComboBox()
|
||||
|
@ -110,7 +110,7 @@ class GeneralGUIPrefGroupUI(OptionsGroupUI):
|
|||
# Enable High DPI Support
|
||||
self.hdpi_cb = FCCheckBox('%s' % _('Activate HDPI Support'))
|
||||
self.hdpi_cb.setToolTip(
|
||||
_("Enable High DPI support for the application.\n"
|
||||
_("Enable High DPI support for FlatCAM.\n"
|
||||
"It will be applied at the next app start.")
|
||||
)
|
||||
|
||||
|
@ -126,7 +126,7 @@ class GeneralGUIPrefGroupUI(OptionsGroupUI):
|
|||
# Enable Hover box
|
||||
self.hover_cb = FCCheckBox('%s' % _('Display Hover Shape'))
|
||||
self.hover_cb.setToolTip(
|
||||
_("Enable display of a hover shape for the application objects.\n"
|
||||
_("Enable display of a hover shape for FlatCAM objects.\n"
|
||||
"It is displayed whenever the mouse cursor is hovering\n"
|
||||
"over any kind of not-selected object.")
|
||||
)
|
||||
|
@ -135,7 +135,7 @@ class GeneralGUIPrefGroupUI(OptionsGroupUI):
|
|||
# Enable Selection box
|
||||
self.selection_cb = FCCheckBox('%s' % _('Display Selection Shape'))
|
||||
self.selection_cb.setToolTip(
|
||||
_("Enable the display of a selection shape for the application objects.\n"
|
||||
_("Enable the display of a selection shape for FlatCAM objects.\n"
|
||||
"It is displayed whenever the mouse selects an object\n"
|
||||
"either by clicking or dragging mouse from left to right or\n"
|
||||
"right to left.")
|
||||
|
@ -155,10 +155,17 @@ class GeneralGUIPrefGroupUI(OptionsGroupUI):
|
|||
self.sl_color_label.setToolTip(
|
||||
_("Set the line color for the 'left to right' selection box.")
|
||||
)
|
||||
self.sl_color_entry = FCColorEntry()
|
||||
self.sl_color_entry = FCEntry()
|
||||
self.sl_color_button = QtWidgets.QPushButton()
|
||||
self.sl_color_button.setFixedSize(15, 15)
|
||||
|
||||
self.form_box_child_4 = QtWidgets.QHBoxLayout()
|
||||
self.form_box_child_4.addWidget(self.sl_color_entry)
|
||||
self.form_box_child_4.addWidget(self.sl_color_button)
|
||||
self.form_box_child_4.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter)
|
||||
|
||||
grid0.addWidget(self.sl_color_label, 16, 0)
|
||||
grid0.addWidget(self.sl_color_entry, 16, 1)
|
||||
grid0.addLayout(self.form_box_child_4, 16, 1)
|
||||
|
||||
self.sf_color_label = QtWidgets.QLabel('%s:' % _('Fill'))
|
||||
self.sf_color_label.setToolTip(
|
||||
|
@ -167,20 +174,38 @@ class GeneralGUIPrefGroupUI(OptionsGroupUI):
|
|||
"First 6 digits are the color and the last 2\n"
|
||||
"digits are for alpha (transparency) level.")
|
||||
)
|
||||
self.sf_color_entry = FCColorEntry()
|
||||
self.sf_color_entry = FCEntry()
|
||||
self.sf_color_button = QtWidgets.QPushButton()
|
||||
self.sf_color_button.setFixedSize(15, 15)
|
||||
|
||||
self.form_box_child_5 = QtWidgets.QHBoxLayout()
|
||||
self.form_box_child_5.addWidget(self.sf_color_entry)
|
||||
self.form_box_child_5.addWidget(self.sf_color_button)
|
||||
self.form_box_child_5.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter)
|
||||
|
||||
grid0.addWidget(self.sf_color_label, 17, 0)
|
||||
grid0.addWidget(self.sf_color_entry, 17, 1)
|
||||
grid0.addLayout(self.form_box_child_5, 17, 1)
|
||||
|
||||
# Plot Selection (left - right) Fill Transparency Level
|
||||
self.left_right_alpha_label = QtWidgets.QLabel('%s:' % _('Alpha'))
|
||||
self.left_right_alpha_label.setToolTip(
|
||||
self.sf_alpha_label = QtWidgets.QLabel('%s:' % _('Alpha'))
|
||||
self.sf_alpha_label.setToolTip(
|
||||
_("Set the fill transparency for the 'left to right' selection box.")
|
||||
)
|
||||
self.left_right_alpha_entry = FCSliderWithSpinner(0, 255, 1)
|
||||
self.sf_color_alpha_slider = QtWidgets.QSlider(QtCore.Qt.Horizontal)
|
||||
self.sf_color_alpha_slider.setMinimum(0)
|
||||
self.sf_color_alpha_slider.setMaximum(255)
|
||||
self.sf_color_alpha_slider.setSingleStep(1)
|
||||
|
||||
grid0.addWidget(self.left_right_alpha_label, 18, 0)
|
||||
grid0.addWidget(self.left_right_alpha_entry, 18, 1)
|
||||
self.sf_color_alpha_spinner = FCSpinner()
|
||||
self.sf_color_alpha_spinner.setMinimumWidth(70)
|
||||
self.sf_color_alpha_spinner.set_range(0, 255)
|
||||
|
||||
self.form_box_child_6 = QtWidgets.QHBoxLayout()
|
||||
self.form_box_child_6.addWidget(self.sf_color_alpha_slider)
|
||||
self.form_box_child_6.addWidget(self.sf_color_alpha_spinner)
|
||||
|
||||
grid0.addWidget(self.sf_alpha_label, 18, 0)
|
||||
grid0.addLayout(self.form_box_child_6, 18, 1)
|
||||
|
||||
separator_line = QtWidgets.QFrame()
|
||||
separator_line.setFrameShape(QtWidgets.QFrame.HLine)
|
||||
|
@ -196,10 +221,17 @@ class GeneralGUIPrefGroupUI(OptionsGroupUI):
|
|||
self.alt_sl_color_label.setToolTip(
|
||||
_("Set the line color for the 'right to left' selection box.")
|
||||
)
|
||||
self.alt_sl_color_entry = FCColorEntry()
|
||||
self.alt_sl_color_entry = FCEntry()
|
||||
self.alt_sl_color_button = QtWidgets.QPushButton()
|
||||
self.alt_sl_color_button.setFixedSize(15, 15)
|
||||
|
||||
self.form_box_child_7 = QtWidgets.QHBoxLayout()
|
||||
self.form_box_child_7.addWidget(self.alt_sl_color_entry)
|
||||
self.form_box_child_7.addWidget(self.alt_sl_color_button)
|
||||
self.form_box_child_7.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter)
|
||||
|
||||
grid0.addWidget(self.alt_sl_color_label, 21, 0)
|
||||
grid0.addWidget(self.alt_sl_color_entry, 21, 1)
|
||||
grid0.addLayout(self.form_box_child_7, 21, 1)
|
||||
|
||||
# Plot Selection (right - left) Fill Color
|
||||
self.alt_sf_color_label = QtWidgets.QLabel('%s:' % _('Fill'))
|
||||
|
@ -209,20 +241,38 @@ class GeneralGUIPrefGroupUI(OptionsGroupUI):
|
|||
"First 6 digits are the color and the last 2\n"
|
||||
"digits are for alpha (transparency) level.")
|
||||
)
|
||||
self.alt_sf_color_entry = FCColorEntry()
|
||||
self.alt_sf_color_entry = FCEntry()
|
||||
self.alt_sf_color_button = QtWidgets.QPushButton()
|
||||
self.alt_sf_color_button.setFixedSize(15, 15)
|
||||
|
||||
self.form_box_child_8 = QtWidgets.QHBoxLayout()
|
||||
self.form_box_child_8.addWidget(self.alt_sf_color_entry)
|
||||
self.form_box_child_8.addWidget(self.alt_sf_color_button)
|
||||
self.form_box_child_8.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter)
|
||||
|
||||
grid0.addWidget(self.alt_sf_color_label, 22, 0)
|
||||
grid0.addWidget(self.alt_sf_color_entry, 22, 1)
|
||||
grid0.addLayout(self.form_box_child_8, 22, 1)
|
||||
|
||||
# Plot Selection (right - left) Fill Transparency Level
|
||||
self.right_left_alpha_label = QtWidgets.QLabel('%s:' % _('Alpha'))
|
||||
self.right_left_alpha_label.setToolTip(
|
||||
self.alt_sf_alpha_label = QtWidgets.QLabel('%s:' % _('Alpha'))
|
||||
self.alt_sf_alpha_label.setToolTip(
|
||||
_("Set the fill transparency for selection 'right to left' box.")
|
||||
)
|
||||
self.right_left_alpha_entry = FCSliderWithSpinner(0, 255, 1)
|
||||
self.alt_sf_color_alpha_slider = QtWidgets.QSlider(QtCore.Qt.Horizontal)
|
||||
self.alt_sf_color_alpha_slider.setMinimum(0)
|
||||
self.alt_sf_color_alpha_slider.setMaximum(255)
|
||||
self.alt_sf_color_alpha_slider.setSingleStep(1)
|
||||
|
||||
grid0.addWidget(self.right_left_alpha_label, 23, 0)
|
||||
grid0.addWidget(self.right_left_alpha_entry, 23, 1)
|
||||
self.alt_sf_color_alpha_spinner = FCSpinner()
|
||||
self.alt_sf_color_alpha_spinner.setMinimumWidth(70)
|
||||
self.alt_sf_color_alpha_spinner.set_range(0, 255)
|
||||
|
||||
self.form_box_child_9 = QtWidgets.QHBoxLayout()
|
||||
self.form_box_child_9.addWidget(self.alt_sf_color_alpha_slider)
|
||||
self.form_box_child_9.addWidget(self.alt_sf_color_alpha_spinner)
|
||||
|
||||
grid0.addWidget(self.alt_sf_alpha_label, 23, 0)
|
||||
grid0.addLayout(self.form_box_child_9, 23, 1)
|
||||
|
||||
separator_line = QtWidgets.QFrame()
|
||||
separator_line.setFrameShape(QtWidgets.QFrame.HLine)
|
||||
|
@ -241,20 +291,34 @@ class GeneralGUIPrefGroupUI(OptionsGroupUI):
|
|||
self.alt_sf_color_label.setToolTip(
|
||||
_("Set the color for the shape.")
|
||||
)
|
||||
self.draw_color_entry = FCColorEntry()
|
||||
self.draw_color_entry = FCEntry()
|
||||
self.draw_color_button = QtWidgets.QPushButton()
|
||||
self.draw_color_button.setFixedSize(15, 15)
|
||||
|
||||
self.form_box_child_10 = QtWidgets.QHBoxLayout()
|
||||
self.form_box_child_10.addWidget(self.draw_color_entry)
|
||||
self.form_box_child_10.addWidget(self.draw_color_button)
|
||||
self.form_box_child_10.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter)
|
||||
|
||||
grid0.addWidget(self.draw_color_label, 26, 0)
|
||||
grid0.addWidget(self.draw_color_entry, 26, 1)
|
||||
grid0.addLayout(self.form_box_child_10, 26, 1)
|
||||
|
||||
# Editor Draw Selection Color
|
||||
self.sel_draw_color_label = QtWidgets.QLabel('%s:' % _('Selection'))
|
||||
self.sel_draw_color_label.setToolTip(
|
||||
_("Set the color of the shape when selected.")
|
||||
)
|
||||
self.sel_draw_color_entry = FCColorEntry()
|
||||
self.sel_draw_color_entry = FCEntry()
|
||||
self.sel_draw_color_button = QtWidgets.QPushButton()
|
||||
self.sel_draw_color_button.setFixedSize(15, 15)
|
||||
|
||||
self.form_box_child_11 = QtWidgets.QHBoxLayout()
|
||||
self.form_box_child_11.addWidget(self.sel_draw_color_entry)
|
||||
self.form_box_child_11.addWidget(self.sel_draw_color_button)
|
||||
self.form_box_child_11.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter)
|
||||
|
||||
grid0.addWidget(self.sel_draw_color_label, 27, 0)
|
||||
grid0.addWidget(self.sel_draw_color_entry, 27, 1)
|
||||
grid0.addLayout(self.form_box_child_11, 27, 1)
|
||||
|
||||
separator_line = QtWidgets.QFrame()
|
||||
separator_line.setFrameShape(QtWidgets.QFrame.HLine)
|
||||
|
@ -273,20 +337,34 @@ class GeneralGUIPrefGroupUI(OptionsGroupUI):
|
|||
self.proj_color_label.setToolTip(
|
||||
_("Set the color of the items in Project Tab Tree.")
|
||||
)
|
||||
self.proj_color_entry = FCColorEntry()
|
||||
self.proj_color_entry = FCEntry()
|
||||
self.proj_color_button = QtWidgets.QPushButton()
|
||||
self.proj_color_button.setFixedSize(15, 15)
|
||||
|
||||
self.form_box_child_12 = QtWidgets.QHBoxLayout()
|
||||
self.form_box_child_12.addWidget(self.proj_color_entry)
|
||||
self.form_box_child_12.addWidget(self.proj_color_button)
|
||||
self.form_box_child_12.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter)
|
||||
|
||||
grid0.addWidget(self.proj_color_label, 30, 0)
|
||||
grid0.addWidget(self.proj_color_entry, 30, 1)
|
||||
grid0.addLayout(self.form_box_child_12, 30, 1)
|
||||
|
||||
self.proj_color_dis_label = QtWidgets.QLabel('%s:' % _('Disabled'))
|
||||
self.proj_color_dis_label.setToolTip(
|
||||
_("Set the color of the items in Project Tab Tree,\n"
|
||||
"for the case when the items are disabled.")
|
||||
)
|
||||
self.proj_color_dis_entry = FCColorEntry()
|
||||
self.proj_color_dis_entry = FCEntry()
|
||||
self.proj_color_dis_button = QtWidgets.QPushButton()
|
||||
self.proj_color_dis_button.setFixedSize(15, 15)
|
||||
|
||||
self.form_box_child_13 = QtWidgets.QHBoxLayout()
|
||||
self.form_box_child_13.addWidget(self.proj_color_dis_entry)
|
||||
self.form_box_child_13.addWidget(self.proj_color_dis_button)
|
||||
self.form_box_child_13.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter)
|
||||
|
||||
grid0.addWidget(self.proj_color_dis_label, 31, 0)
|
||||
grid0.addWidget(self.proj_color_dis_entry, 31, 1)
|
||||
grid0.addLayout(self.form_box_child_13, 31, 1)
|
||||
|
||||
# Project autohide CB
|
||||
self.project_autohide_cb = FCCheckBox(label=_('Project AutoHide'))
|
||||
|
@ -309,22 +387,32 @@ class GeneralGUIPrefGroupUI(OptionsGroupUI):
|
|||
|
||||
# Setting selection (left - right) colors signals
|
||||
self.sf_color_entry.editingFinished.connect(self.on_sf_color_entry)
|
||||
self.sf_color_button.clicked.connect(self.on_sf_color_button)
|
||||
self.sf_color_alpha_spinner.valueChanged.connect(self.on_sf_color_spinner)
|
||||
self.sf_color_alpha_slider.valueChanged.connect(self.on_sf_color_slider)
|
||||
self.sl_color_entry.editingFinished.connect(self.on_sl_color_entry)
|
||||
|
||||
self.left_right_alpha_entry.valueChanged.connect(self.on_left_right_alpha_changed) # alpha
|
||||
self.sl_color_button.clicked.connect(self.on_sl_color_button)
|
||||
|
||||
# Setting selection (right - left) colors signals
|
||||
self.alt_sf_color_entry.editingFinished.connect(self.on_alt_sf_color_entry)
|
||||
self.alt_sf_color_button.clicked.connect(self.on_alt_sf_color_button)
|
||||
self.alt_sf_color_alpha_spinner.valueChanged.connect(self.on_alt_sf_color_spinner)
|
||||
self.alt_sf_color_alpha_slider.valueChanged.connect(self.on_alt_sf_color_slider)
|
||||
self.alt_sl_color_entry.editingFinished.connect(self.on_alt_sl_color_entry)
|
||||
|
||||
self.right_left_alpha_entry.valueChanged.connect(self.on_right_left_alpha_changed) # alpha
|
||||
self.alt_sl_color_button.clicked.connect(self.on_alt_sl_color_button)
|
||||
|
||||
# Setting Editor Draw colors signals
|
||||
self.draw_color_entry.editingFinished.connect(self.on_draw_color_entry)
|
||||
self.draw_color_button.clicked.connect(self.on_draw_color_button)
|
||||
|
||||
self.sel_draw_color_entry.editingFinished.connect(self.on_sel_draw_color_entry)
|
||||
self.sel_draw_color_button.clicked.connect(self.on_sel_draw_color_button)
|
||||
|
||||
self.proj_color_entry.editingFinished.connect(self.on_proj_color_entry)
|
||||
self.proj_color_button.clicked.connect(self.on_proj_color_button)
|
||||
|
||||
self.proj_color_dis_entry.editingFinished.connect(self.on_proj_color_dis_entry)
|
||||
self.proj_color_dis_button.clicked.connect(self.on_proj_color_dis_button)
|
||||
|
||||
self.layout_combo.activated.connect(self.on_layout)
|
||||
|
||||
|
@ -349,64 +437,191 @@ class GeneralGUIPrefGroupUI(OptionsGroupUI):
|
|||
# Setting selection colors (left - right) handlers
|
||||
def on_sf_color_entry(self):
|
||||
self.app.defaults['global_sel_fill'] = self.app.defaults['global_sel_fill'][7:9]
|
||||
self.sf_color_button.setStyleSheet("background-color:%s" % str(self.app.defaults['global_sel_fill'])[:7])
|
||||
|
||||
def on_sl_color_entry(self):
|
||||
self.app.defaults['global_sel_line'] = self.sl_color_entry.get_value()[:7] + \
|
||||
self.app.defaults['global_sel_line'][7:9]
|
||||
def on_sf_color_button(self):
|
||||
current_color = QtGui.QColor(self.app.defaults['global_sel_fill'][:7])
|
||||
|
||||
def on_left_right_alpha_changed(self, spinner_value):
|
||||
"""
|
||||
Change the alpha level for the color of the selection box when selection is done left to right.
|
||||
Called on valueChanged of a FCSliderWithSpinner.
|
||||
c_dialog = QtWidgets.QColorDialog()
|
||||
plot_fill_color = c_dialog.getColor(initial=current_color)
|
||||
|
||||
:param spinner_value: passed value within [0, 255]
|
||||
:type spinner_value: int
|
||||
:return: None
|
||||
:rtype:
|
||||
"""
|
||||
if plot_fill_color.isValid() is False:
|
||||
return
|
||||
|
||||
self.sf_color_button.setStyleSheet("background-color:%s" % str(plot_fill_color.name()))
|
||||
|
||||
new_val = str(plot_fill_color.name()) + str(self.app.defaults['global_sel_fill'][7:9])
|
||||
self.sf_color_entry.set_value(new_val)
|
||||
self.app.defaults['global_sel_fill'] = new_val
|
||||
|
||||
def on_sf_color_spinner(self):
|
||||
spinner_value = self.sf_color_alpha_spinner.value()
|
||||
self.sf_color_alpha_slider.setValue(spinner_value)
|
||||
self.app.defaults['global_sel_fill'] = self.app.defaults['global_sel_fill'][:7] + \
|
||||
(hex(spinner_value)[2:] if int(hex(spinner_value)[2:], 16) > 0 else '00')
|
||||
self.app.defaults['global_sel_line'] = self.app.defaults['global_sel_line'][:7] + \
|
||||
(hex(spinner_value)[2:] if int(hex(spinner_value)[2:], 16) > 0 else '00')
|
||||
|
||||
def on_sf_color_slider(self):
|
||||
slider_value = self.sf_color_alpha_slider.value()
|
||||
self.sf_color_alpha_spinner.setValue(slider_value)
|
||||
|
||||
def on_sl_color_entry(self):
|
||||
self.app.defaults['global_sel_line'] = self.sl_color_entry.get_value()[:7] + \
|
||||
self.app.defaults['global_sel_line'][7:9]
|
||||
self.sl_color_button.setStyleSheet("background-color:%s" % str(self.app.defaults['global_sel_line'])[:7])
|
||||
|
||||
def on_sl_color_button(self):
|
||||
current_color = QtGui.QColor(self.app.defaults['global_sel_line'][:7])
|
||||
|
||||
c_dialog = QtWidgets.QColorDialog()
|
||||
plot_line_color = c_dialog.getColor(initial=current_color)
|
||||
|
||||
if plot_line_color.isValid() is False:
|
||||
return
|
||||
|
||||
self.sl_color_button.setStyleSheet("background-color:%s" % str(plot_line_color.name()))
|
||||
|
||||
new_val_line = str(plot_line_color.name()) + str(self.app.defaults['global_sel_line'][7:9])
|
||||
self.sl_color_entry.set_value(new_val_line)
|
||||
self.app.defaults['global_sel_line'] = new_val_line
|
||||
|
||||
# Setting selection colors (right - left) handlers
|
||||
def on_alt_sf_color_entry(self):
|
||||
self.app.defaults['global_alt_sel_fill'] = self.alt_sf_color_entry.get_value()[:7] + \
|
||||
self.app.defaults['global_alt_sel_fill'][7:9]
|
||||
self.alt_sf_color_button.setStyleSheet(
|
||||
"background-color:%s" % str(self.app.defaults['global_alt_sel_fill'])[:7]
|
||||
)
|
||||
|
||||
def on_alt_sl_color_entry(self):
|
||||
self.app.defaults['global_alt_sel_line'] = self.alt_sl_color_entry.get_value()[:7] + \
|
||||
self.app.defaults['global_alt_sel_line'][7:9]
|
||||
def on_alt_sf_color_button(self):
|
||||
current_color = QtGui.QColor(self.app.defaults['global_alt_sel_fill'][:7])
|
||||
|
||||
def on_right_left_alpha_changed(self, spinner_value):
|
||||
"""
|
||||
Change the alpha level for the color of the selection box when selection is done right to left.
|
||||
Called on valueChanged of a FCSliderWithSpinner.
|
||||
c_dialog = QtWidgets.QColorDialog()
|
||||
plot_fill_color = c_dialog.getColor(initial=current_color)
|
||||
|
||||
:param spinner_value: passed value within [0, 255]
|
||||
:type spinner_value: int
|
||||
:return: None
|
||||
:rtype:
|
||||
"""
|
||||
if plot_fill_color.isValid() is False:
|
||||
return
|
||||
|
||||
self.alt_sf_color_button.setStyleSheet("background-color:%s" % str(plot_fill_color.name()))
|
||||
|
||||
new_val = str(plot_fill_color.name()) + str(self.app.defaults['global_alt_sel_fill'][7:9])
|
||||
self.alt_sf_color_entry.set_value(new_val)
|
||||
self.app.defaults['global_alt_sel_fill'] = new_val
|
||||
|
||||
def on_alt_sf_color_spinner(self):
|
||||
spinner_value = self.alt_sf_color_alpha_spinner.value()
|
||||
self.alt_sf_color_alpha_slider.setValue(spinner_value)
|
||||
self.app.defaults['global_alt_sel_fill'] = self.app.defaults['global_alt_sel_fill'][:7] + \
|
||||
(hex(spinner_value)[2:] if int(hex(spinner_value)[2:], 16) > 0 else '00')
|
||||
self.app.defaults['global_alt_sel_line'] = self.app.defaults['global_alt_sel_line'][:7] + \
|
||||
(hex(spinner_value)[2:] if int(hex(spinner_value)[2:], 16) > 0 else '00')
|
||||
|
||||
def on_alt_sf_color_slider(self):
|
||||
slider_value = self.alt_sf_color_alpha_slider.value()
|
||||
self.alt_sf_color_alpha_spinner.setValue(slider_value)
|
||||
|
||||
def on_alt_sl_color_entry(self):
|
||||
self.app.defaults['global_alt_sel_line'] = self.alt_sl_color_entry.get_value()[:7] + \
|
||||
self.app.defaults['global_alt_sel_line'][7:9]
|
||||
self.alt_sl_color_button.setStyleSheet(
|
||||
"background-color:%s" % str(self.app.defaults['global_alt_sel_line'])[:7]
|
||||
)
|
||||
|
||||
def on_alt_sl_color_button(self):
|
||||
current_color = QtGui.QColor(self.app.defaults['global_alt_sel_line'][:7])
|
||||
|
||||
c_dialog = QtWidgets.QColorDialog()
|
||||
plot_line_color = c_dialog.getColor(initial=current_color)
|
||||
|
||||
if plot_line_color.isValid() is False:
|
||||
return
|
||||
|
||||
self.alt_sl_color_button.setStyleSheet("background-color:%s" % str(plot_line_color.name()))
|
||||
|
||||
new_val_line = str(plot_line_color.name()) + str(self.app.defaults['global_alt_sel_line'][7:9])
|
||||
self.alt_sl_color_entry.set_value(new_val_line)
|
||||
self.app.defaults['global_alt_sel_line'] = new_val_line
|
||||
|
||||
# Setting Editor colors
|
||||
def on_draw_color_entry(self):
|
||||
self.app.defaults['global_draw_color'] = self.draw_color_entry.get_value()
|
||||
self.draw_color_button.setStyleSheet("background-color:%s" % str(self.app.defaults['global_draw_color']))
|
||||
|
||||
def on_draw_color_button(self):
|
||||
current_color = QtGui.QColor(self.app.defaults['global_draw_color'])
|
||||
|
||||
c_dialog = QtWidgets.QColorDialog()
|
||||
draw_color = c_dialog.getColor(initial=current_color)
|
||||
|
||||
if draw_color.isValid() is False:
|
||||
return
|
||||
|
||||
self.draw_color_button.setStyleSheet("background-color:%s" % str(draw_color.name()))
|
||||
|
||||
new_val = str(draw_color.name())
|
||||
self.draw_color_entry.set_value(new_val)
|
||||
self.app.defaults['global_draw_color'] = new_val
|
||||
|
||||
def on_sel_draw_color_entry(self):
|
||||
self.app.defaults['global_sel_draw_color'] = self.sel_draw_color_entry.get_value()
|
||||
self.sel_draw_color_button.setStyleSheet(
|
||||
"background-color:%s" % str(self.app.defaults['global_sel_draw_color']))
|
||||
|
||||
def on_sel_draw_color_button(self):
|
||||
current_color = QtGui.QColor(self.app.defaults['global_sel_draw_color'])
|
||||
|
||||
c_dialog = QtWidgets.QColorDialog()
|
||||
sel_draw_color = c_dialog.getColor(initial=current_color)
|
||||
|
||||
if sel_draw_color.isValid() is False:
|
||||
return
|
||||
|
||||
self.sel_draw_color_button.setStyleSheet("background-color:%s" % str(sel_draw_color.name()))
|
||||
|
||||
new_val_sel = str(sel_draw_color.name())
|
||||
self.sel_draw_color_entry.set_value(new_val_sel)
|
||||
self.app.defaults['global_sel_draw_color'] = new_val_sel
|
||||
|
||||
def on_proj_color_entry(self):
|
||||
self.app.defaults['global_proj_item_color'] = self.proj_color_entry.get_value()
|
||||
self.proj_color_button.setStyleSheet(
|
||||
"background-color:%s" % str(self.app.defaults['global_proj_item_color']))
|
||||
|
||||
def on_proj_color_button(self):
|
||||
current_color = QtGui.QColor(self.app.defaults['global_proj_item_color'])
|
||||
|
||||
c_dialog = QtWidgets.QColorDialog()
|
||||
proj_color = c_dialog.getColor(initial=current_color)
|
||||
|
||||
if proj_color.isValid() is False:
|
||||
return
|
||||
|
||||
self.proj_color_button.setStyleSheet("background-color:%s" % str(proj_color.name()))
|
||||
|
||||
new_val_sel = str(proj_color.name())
|
||||
self.proj_color_entry.set_value(new_val_sel)
|
||||
self.app.defaults['global_proj_item_color'] = new_val_sel
|
||||
|
||||
def on_proj_color_dis_entry(self):
|
||||
self.app.defaults['global_proj_item_dis_color'] = self.proj_color_dis_entry.get_value()
|
||||
self.proj_color_dis_button.setStyleSheet(
|
||||
"background-color:%s" % str(self.app.defaults['global_proj_item_dis_color']))
|
||||
|
||||
def on_proj_color_dis_button(self):
|
||||
current_color = QtGui.QColor(self.app.defaults['global_proj_item_dis_color'])
|
||||
|
||||
c_dialog = QtWidgets.QColorDialog()
|
||||
proj_color = c_dialog.getColor(initial=current_color)
|
||||
|
||||
if proj_color.isValid() is False:
|
||||
return
|
||||
|
||||
self.proj_color_dis_button.setStyleSheet("background-color:%s" % str(proj_color.name()))
|
||||
|
||||
new_val_sel = str(proj_color.name())
|
||||
self.proj_color_dis_entry.set_value(new_val_sel)
|
||||
self.app.defaults['global_proj_item_dis_color'] = new_val_sel
|
||||
|
||||
def on_layout(self, index=None, lay=None):
|
||||
"""
|
||||
|
@ -432,13 +647,14 @@ class GeneralGUIPrefGroupUI(OptionsGroupUI):
|
|||
# first remove the toolbars:
|
||||
try:
|
||||
self.app.ui.removeToolBar(self.app.ui.toolbarfile)
|
||||
self.app.ui.removeToolBar(self.app.ui.toolbaredit)
|
||||
self.app.ui.removeToolBar(self.app.ui.toolbargeo)
|
||||
self.app.ui.removeToolBar(self.app.ui.toolbarview)
|
||||
self.app.ui.removeToolBar(self.app.ui.toolbarshell)
|
||||
self.app.ui.removeToolBar(self.app.ui.toolbartools)
|
||||
self.app.ui.removeToolBar(self.app.ui.exc_edit_toolbar)
|
||||
self.app.ui.removeToolBar(self.app.ui.geo_edit_toolbar)
|
||||
self.app.ui.removeToolBar(self.app.ui.grb_edit_toolbar)
|
||||
self.app.ui.removeToolBar(self.app.ui.snap_toolbar)
|
||||
self.app.ui.removeToolBar(self.app.ui.toolbarshell)
|
||||
except Exception:
|
||||
pass
|
||||
|
@ -449,9 +665,9 @@ class GeneralGUIPrefGroupUI(OptionsGroupUI):
|
|||
self.app.ui.toolbarfile.setObjectName('File_TB')
|
||||
self.app.ui.addToolBar(Qt.LeftToolBarArea, self.app.ui.toolbarfile)
|
||||
|
||||
self.app.ui.toolbaredit = QtWidgets.QToolBar('Edit Toolbar')
|
||||
self.app.ui.toolbaredit.setObjectName('Edit_TB')
|
||||
self.app.ui.addToolBar(Qt.LeftToolBarArea, self.app.ui.toolbaredit)
|
||||
self.app.ui.toolbargeo = QtWidgets.QToolBar('Edit Toolbar')
|
||||
self.app.ui.toolbargeo.setObjectName('Edit_TB')
|
||||
self.app.ui.addToolBar(Qt.LeftToolBarArea, self.app.ui.toolbargeo)
|
||||
|
||||
self.app.ui.toolbarshell = QtWidgets.QToolBar('Shell Toolbar')
|
||||
self.app.ui.toolbarshell.setObjectName('Shell_TB')
|
||||
|
@ -481,15 +697,22 @@ class GeneralGUIPrefGroupUI(OptionsGroupUI):
|
|||
self.app.ui.exc_edit_toolbar.setObjectName('ExcEditor_TB')
|
||||
self.app.ui.addToolBar(Qt.RightToolBarArea, self.app.ui.exc_edit_toolbar)
|
||||
|
||||
self.app.ui.snap_toolbar = QtWidgets.QToolBar('Grid Toolbar')
|
||||
self.app.ui.snap_toolbar.setObjectName('Snap_TB')
|
||||
self.app.ui.snap_toolbar.setMaximumHeight(30)
|
||||
self.app.ui.splitter_left.addWidget(self.app.ui.snap_toolbar)
|
||||
|
||||
self.app.ui.corner_snap_btn.setVisible(True)
|
||||
self.app.ui.snap_magnet.setVisible(True)
|
||||
else:
|
||||
# ## TOOLBAR INSTALLATION # ##
|
||||
self.app.ui.toolbarfile = QtWidgets.QToolBar('File Toolbar')
|
||||
self.app.ui.toolbarfile.setObjectName('File_TB')
|
||||
self.app.ui.addToolBar(self.app.ui.toolbarfile)
|
||||
|
||||
self.app.ui.toolbaredit = QtWidgets.QToolBar('Edit Toolbar')
|
||||
self.app.ui.toolbaredit.setObjectName('Edit_TB')
|
||||
self.app.ui.addToolBar(self.app.ui.toolbaredit)
|
||||
self.app.ui.toolbargeo = QtWidgets.QToolBar('Edit Toolbar')
|
||||
self.app.ui.toolbargeo.setObjectName('Edit_TB')
|
||||
self.app.ui.addToolBar(self.app.ui.toolbargeo)
|
||||
|
||||
self.app.ui.toolbarview = QtWidgets.QToolBar('View Toolbar')
|
||||
self.app.ui.toolbarview.setObjectName('View_TB')
|
||||
|
@ -520,9 +743,18 @@ class GeneralGUIPrefGroupUI(OptionsGroupUI):
|
|||
self.app.ui.grb_edit_toolbar.setObjectName('GrbEditor_TB')
|
||||
self.app.ui.addToolBar(self.app.ui.grb_edit_toolbar)
|
||||
|
||||
self.app.ui.snap_toolbar = QtWidgets.QToolBar('Grid Toolbar')
|
||||
self.app.ui.snap_toolbar.setObjectName('Snap_TB')
|
||||
# self.app.ui.snap_toolbar.setMaximumHeight(30)
|
||||
self.app.ui.addToolBar(self.app.ui.snap_toolbar)
|
||||
|
||||
self.app.ui.corner_snap_btn.setVisible(False)
|
||||
self.app.ui.snap_magnet.setVisible(False)
|
||||
|
||||
if current_layout == 'minimal':
|
||||
self.app.ui.toolbarview.setVisible(False)
|
||||
self.app.ui.toolbarshell.setVisible(False)
|
||||
self.app.ui.snap_toolbar.setVisible(False)
|
||||
self.app.ui.geo_edit_toolbar.setVisible(False)
|
||||
self.app.ui.grb_edit_toolbar.setVisible(False)
|
||||
self.app.ui.exc_edit_toolbar.setVisible(False)
|
||||
|
@ -535,9 +767,7 @@ class GeneralGUIPrefGroupUI(OptionsGroupUI):
|
|||
self.app.connect_toolbar_signals()
|
||||
|
||||
self.app.ui.grid_snap_btn.setChecked(True)
|
||||
|
||||
self.app.ui.corner_snap_btn.setVisible(False)
|
||||
self.app.ui.snap_magnet.setVisible(False)
|
||||
self.app.ui.on_grid_snap_triggered(state=True)
|
||||
|
||||
self.app.ui.grid_gap_x_entry.setText(str(self.app.defaults["global_gridx"]))
|
||||
self.app.ui.grid_gap_y_entry.setText(str(self.app.defaults["global_gridy"]))
|
|
@ -1,12 +1,12 @@
|
|||
from PyQt5 import QtWidgets
|
||||
from PyQt5.QtCore import QSettings
|
||||
|
||||
from AppGUI.preferences.general.GeneralAppPrefGroupUI import GeneralAppPrefGroupUI
|
||||
from AppGUI.preferences.general.GeneralAPPSetGroupUI import GeneralAPPSetGroupUI
|
||||
from AppGUI.preferences.general.GeneralGUIPrefGroupUI import GeneralGUIPrefGroupUI
|
||||
from flatcamGUI.preferences.general.GeneralAppPrefGroupUI import GeneralAppPrefGroupUI
|
||||
from flatcamGUI.preferences.general.GeneralAPPSetGroupUI import GeneralAPPSetGroupUI
|
||||
from flatcamGUI.preferences.general.GeneralGUIPrefGroupUI import GeneralGUIPrefGroupUI
|
||||
|
||||
import gettext
|
||||
import AppTranslation as fcTranslate
|
||||
import FlatCAMTranslation as fcTranslate
|
||||
import builtins
|
||||
|
||||
fcTranslate.apply_language('strings')
|
|
@ -1,12 +1,11 @@
|
|||
from PyQt5 import QtWidgets
|
||||
from PyQt5.QtCore import QSettings
|
||||
|
||||
from AppGUI.GUIElements import FCDoubleSpinner, FCCheckBox, RadioSet, FCLabel, NumericalEvalTupleEntry, \
|
||||
NumericalEvalEntry
|
||||
from AppGUI.preferences.OptionsGroupUI import OptionsGroupUI
|
||||
from flatcamGUI.GUIElements import FCEntry, FloatEntry, FCDoubleSpinner, FCCheckBox, RadioSet, FCLabel
|
||||
from flatcamGUI.preferences.OptionsGroupUI import OptionsGroupUI
|
||||
|
||||
import gettext
|
||||
import AppTranslation as fcTranslate
|
||||
import FlatCAMTranslation as fcTranslate
|
||||
import builtins
|
||||
|
||||
fcTranslate.apply_language('strings')
|
||||
|
@ -47,9 +46,8 @@ class GeometryAdvOptPrefGroupUI(OptionsGroupUI):
|
|||
toolchange_xy_label.setToolTip(
|
||||
_("Toolchange X,Y position.")
|
||||
)
|
||||
self.toolchangexy_entry = NumericalEvalTupleEntry(border_color='#0069A9')
|
||||
|
||||
grid1.addWidget(toolchange_xy_label, 1, 0)
|
||||
self.toolchangexy_entry = FCEntry()
|
||||
grid1.addWidget(self.toolchangexy_entry, 1, 1)
|
||||
|
||||
# Start move Z
|
||||
|
@ -58,9 +56,8 @@ class GeometryAdvOptPrefGroupUI(OptionsGroupUI):
|
|||
_("Height of the tool just after starting the work.\n"
|
||||
"Delete the value if you don't need this feature.")
|
||||
)
|
||||
self.gstartz_entry = NumericalEvalEntry(border_color='#0069A9')
|
||||
|
||||
grid1.addWidget(startzlabel, 2, 0)
|
||||
self.gstartz_entry = FloatEntry()
|
||||
grid1.addWidget(self.gstartz_entry, 2, 1)
|
||||
|
||||
# Feedrate rapids
|
||||
|
@ -189,11 +186,6 @@ class GeometryAdvOptPrefGroupUI(OptionsGroupUI):
|
|||
grid1.addWidget(segy_label, 11, 0)
|
||||
grid1.addWidget(self.segy_entry, 11, 1)
|
||||
|
||||
separator_line = QtWidgets.QFrame()
|
||||
separator_line.setFrameShape(QtWidgets.QFrame.HLine)
|
||||
separator_line.setFrameShadow(QtWidgets.QFrame.Sunken)
|
||||
grid1.addWidget(separator_line, 12, 0, 1, 2)
|
||||
|
||||
# -----------------------------
|
||||
# --- Area Exclusion ----------
|
||||
# -----------------------------
|
||||
|
@ -203,10 +195,10 @@ class GeometryAdvOptPrefGroupUI(OptionsGroupUI):
|
|||
"Those parameters are available only for\n"
|
||||
"Advanced App. Level.")
|
||||
)
|
||||
grid1.addWidget(self.adv_label, 13, 0, 1, 2)
|
||||
grid1.addWidget(self.adv_label, 12, 0, 1, 2)
|
||||
|
||||
# Exclusion Area CB
|
||||
self.exclusion_cb = FCCheckBox('%s' % _("Exclusion areas"))
|
||||
self.exclusion_cb = FCCheckBox('%s:' % _("Exclusion areas"))
|
||||
self.exclusion_cb.setToolTip(
|
||||
_(
|
||||
"Include exclusion areas.\n"
|
||||
|
@ -214,7 +206,7 @@ class GeometryAdvOptPrefGroupUI(OptionsGroupUI):
|
|||
"is forbidden."
|
||||
)
|
||||
)
|
||||
grid1.addWidget(self.exclusion_cb, 14, 0, 1, 2)
|
||||
grid1.addWidget(self.exclusion_cb, 13, 0, 1, 2)
|
||||
|
||||
# Area Selection shape
|
||||
self.area_shape_label = QtWidgets.QLabel('%s:' % _("Shape"))
|
||||
|
@ -225,8 +217,8 @@ class GeometryAdvOptPrefGroupUI(OptionsGroupUI):
|
|||
self.area_shape_radio = RadioSet([{'label': _("Square"), 'value': 'square'},
|
||||
{'label': _("Polygon"), 'value': 'polygon'}])
|
||||
|
||||
grid1.addWidget(self.area_shape_label, 15, 0)
|
||||
grid1.addWidget(self.area_shape_radio, 15, 1)
|
||||
grid1.addWidget(self.area_shape_label, 14, 0)
|
||||
grid1.addWidget(self.area_shape_radio, 14, 1)
|
||||
|
||||
# Chose Strategy
|
||||
self.strategy_label = FCLabel('%s:' % _("Strategy"))
|
||||
|
@ -237,8 +229,8 @@ class GeometryAdvOptPrefGroupUI(OptionsGroupUI):
|
|||
self.strategy_radio = RadioSet([{'label': _('Over'), 'value': 'over'},
|
||||
{'label': _('Around'), 'value': 'around'}])
|
||||
|
||||
grid1.addWidget(self.strategy_label, 16, 0)
|
||||
grid1.addWidget(self.strategy_radio, 16, 1)
|
||||
grid1.addWidget(self.strategy_label, 15, 0)
|
||||
grid1.addWidget(self.strategy_radio, 15, 1)
|
||||
|
||||
# Over Z
|
||||
self.over_z_label = FCLabel('%s:' % _("Over Z"))
|
|
@ -1,11 +1,11 @@
|
|||
from PyQt5 import QtWidgets
|
||||
from PyQt5.QtCore import QSettings
|
||||
|
||||
from AppGUI.GUIElements import FCSpinner, RadioSet
|
||||
from AppGUI.preferences.OptionsGroupUI import OptionsGroupUI
|
||||
from flatcamGUI.GUIElements import FCSpinner, RadioSet
|
||||
from flatcamGUI.preferences.OptionsGroupUI import OptionsGroupUI
|
||||
|
||||
import gettext
|
||||
import AppTranslation as fcTranslate
|
||||
import FlatCAMTranslation as fcTranslate
|
||||
import builtins
|
||||
|
||||
fcTranslate.apply_language('strings')
|
|
@ -1,11 +1,11 @@
|
|||
from PyQt5 import QtWidgets
|
||||
from PyQt5 import QtWidgets, QtCore, QtGui
|
||||
from PyQt5.QtCore import QSettings
|
||||
|
||||
from AppGUI.GUIElements import FCCheckBox, FCSpinner, FCEntry, FCColorEntry
|
||||
from AppGUI.preferences.OptionsGroupUI import OptionsGroupUI
|
||||
from flatcamGUI.GUIElements import FCCheckBox, FCSpinner, FCEntry
|
||||
from flatcamGUI.preferences.OptionsGroupUI import OptionsGroupUI
|
||||
|
||||
import gettext
|
||||
import AppTranslation as fcTranslate
|
||||
import FlatCAMTranslation as fcTranslate
|
||||
import builtins
|
||||
|
||||
fcTranslate.apply_language('strings')
|
||||
|
@ -31,22 +31,12 @@ class GeometryGenPrefGroupUI(OptionsGroupUI):
|
|||
self.plot_options_label = QtWidgets.QLabel("<b>%s:</b>" % _("Plot Options"))
|
||||
self.layout.addWidget(self.plot_options_label)
|
||||
|
||||
plot_hlay = QtWidgets.QHBoxLayout()
|
||||
self.layout.addLayout(plot_hlay)
|
||||
|
||||
# Plot CB
|
||||
self.plot_cb = FCCheckBox(label=_('Plot'))
|
||||
self.plot_cb.setToolTip(
|
||||
_("Plot (show) this object.")
|
||||
)
|
||||
plot_hlay.addWidget(self.plot_cb)
|
||||
|
||||
# Multicolored CB
|
||||
self.multicolored_cb = FCCheckBox(label=_('M-Color'))
|
||||
self.multicolored_cb.setToolTip(
|
||||
_("Draw polygons in different colors.")
|
||||
)
|
||||
plot_hlay.addWidget(self.multicolored_cb)
|
||||
self.layout.addWidget(self.plot_cb)
|
||||
|
||||
grid0 = QtWidgets.QGridLayout()
|
||||
self.layout.addLayout(grid0)
|
||||
|
@ -87,7 +77,7 @@ class GeometryGenPrefGroupUI(OptionsGroupUI):
|
|||
grid0.addWidget(separator_line, 9, 0, 1, 2)
|
||||
|
||||
# Geometry Object Color
|
||||
self.gerber_color_label = QtWidgets.QLabel('<b>%s</b>' % _('Object Color'))
|
||||
self.gerber_color_label = QtWidgets.QLabel('<b>%s</b>' % _('Geometry Object Color'))
|
||||
grid0.addWidget(self.gerber_color_label, 10, 0, 1, 2)
|
||||
|
||||
# Plot Line Color
|
||||
|
@ -95,15 +85,39 @@ class GeometryGenPrefGroupUI(OptionsGroupUI):
|
|||
self.line_color_label.setToolTip(
|
||||
_("Set the line color for plotted objects.")
|
||||
)
|
||||
self.line_color_entry = FCColorEntry()
|
||||
self.line_color_entry = FCEntry()
|
||||
self.line_color_button = QtWidgets.QPushButton()
|
||||
self.line_color_button.setFixedSize(15, 15)
|
||||
|
||||
self.form_box_child_2 = QtWidgets.QHBoxLayout()
|
||||
self.form_box_child_2.addWidget(self.line_color_entry)
|
||||
self.form_box_child_2.addWidget(self.line_color_button)
|
||||
self.form_box_child_2.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter)
|
||||
|
||||
grid0.addWidget(self.line_color_label, 11, 0)
|
||||
grid0.addWidget(self.line_color_entry, 11, 1)
|
||||
grid0.addLayout(self.form_box_child_2, 11, 1)
|
||||
|
||||
self.layout.addStretch()
|
||||
|
||||
# Setting plot colors signals
|
||||
self.line_color_entry.editingFinished.connect(self.on_line_color_entry)
|
||||
self.line_color_button.clicked.connect(self.on_line_color_button)
|
||||
|
||||
def on_line_color_entry(self):
|
||||
self.app.defaults['geometry_plot_line'] = self.line_color_entry.get_value()[:7] + 'FF'
|
||||
self.line_color_button.setStyleSheet("background-color:%s" % str(self.app.defaults['geometry_plot_line'])[:7])
|
||||
|
||||
def on_line_color_button(self):
|
||||
current_color = QtGui.QColor(self.app.defaults['geometry_plot_line'][:7])
|
||||
# print(current_color)
|
||||
|
||||
c_dialog = QtWidgets.QColorDialog()
|
||||
plot_line_color = c_dialog.getColor(initial=current_color)
|
||||
|
||||
if plot_line_color.isValid() is False:
|
||||
return
|
||||
|
||||
self.line_color_button.setStyleSheet("background-color:%s" % str(plot_line_color.name()))
|
||||
|
||||
new_val_line = str(plot_line_color.name()) + str(self.app.defaults['geometry_plot_line'][7:9])
|
||||
self.line_color_entry.set_value(new_val_line)
|
|
@ -1,13 +1,12 @@
|
|||
from PyQt5 import QtWidgets
|
||||
from PyQt5.QtCore import Qt, QSettings
|
||||
|
||||
from AppGUI.GUIElements import FCDoubleSpinner, FCCheckBox, OptionalInputSection, FCSpinner, FCComboBox, \
|
||||
NumericalEvalTupleEntry
|
||||
from AppGUI.preferences import machinist_setting
|
||||
from AppGUI.preferences.OptionsGroupUI import OptionsGroupUI
|
||||
from flatcamGUI.GUIElements import FCDoubleSpinner, FCCheckBox, OptionalInputSection, FCEntry, FCSpinner, FCComboBox
|
||||
from flatcamGUI.preferences import machinist_setting
|
||||
from flatcamGUI.preferences.OptionsGroupUI import OptionsGroupUI
|
||||
|
||||
import gettext
|
||||
import AppTranslation as fcTranslate
|
||||
import FlatCAMTranslation as fcTranslate
|
||||
import builtins
|
||||
|
||||
fcTranslate.apply_language('strings')
|
||||
|
@ -177,7 +176,7 @@ class GeometryOptPrefGroupUI(OptionsGroupUI):
|
|||
"If no value is entered then there is no move\n"
|
||||
"on X,Y plane at the end of the job.")
|
||||
)
|
||||
self.endxy_entry = NumericalEvalTupleEntry(border_color='#0069A9')
|
||||
self.endxy_entry = FCEntry()
|
||||
|
||||
grid1.addWidget(endmove_xy_label, 7, 0)
|
||||
grid1.addWidget(self.endxy_entry, 7, 1)
|