- structural changes in Preferences from David Robertson

This commit is contained in:
Marius Stanciu 2020-05-31 01:55:11 +03:00 committed by Marius
parent 808e1c5875
commit ede90d6775
8 changed files with 1010 additions and 3 deletions

View File

@ -0,0 +1,181 @@
# ##########################################################
# 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)

View File

@ -683,6 +683,100 @@ class NumericalEvalTupleEntry(FCEntry):
self.setValidator(validator)
class FCColorEntry(QtWidgets.QFrame):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.entry = FCEntry()
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)
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)
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()

View File

@ -0,0 +1,327 @@
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

View File

@ -1,4 +1,30 @@
# ##########################################################
# 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):
@ -6,7 +32,7 @@ class OptionsGroupUI(QtWidgets.QGroupBox):
def __init__(self, title, parent=None):
# QtGui.QGroupBox.__init__(self, title, parent=parent)
super(OptionsGroupUI, self).__init__()
super(OptionsGroupUI, self).__init__(title=title, parent=parent)
self.setStyleSheet("""
QGroupBox
{
@ -16,4 +42,36 @@ class OptionsGroupUI(QtWidgets.QGroupBox):
""")
self.layout = QtWidgets.QVBoxLayout()
self.setLayout(self.layout)
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

View File

@ -0,0 +1,41 @@
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

View File

@ -0,0 +1,302 @@
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 FlatCAM.",
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"]

View File

@ -535,7 +535,7 @@ class CNCJobObject(FlatCAMObj, CNCjob):
if self.app.defaults["global_open_style"] is False:
self.app.file_opened.emit("gcode", filename)
self.app.file_saved.emit("gcode", filename)
self.app.inform.emit('[success] %s: %s' % (_("Machine Code file saved to"), filename))
self.app.inform.emit('[success] %s: %s' % (_("File saved to"), filename))
def on_edit_code_click(self, *args):
"""

View File

@ -7,6 +7,10 @@ CHANGELOG for FlatCAM beta
=================================================
31.05.2020
- structural changes in Preferences from David Robertson
30.05.2020
- made confirmation messages for the values that are modified not to be printed in the Shell