diff --git a/flatcamGUI/GUIElements.py b/flatcamGUI/GUIElements.py index 9a6229c1..7319457a 100644 --- a/flatcamGUI/GUIElements.py +++ b/flatcamGUI/GUIElements.py @@ -707,6 +707,45 @@ class FCColorEntry(QtWidgets.QFrame): 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) + + 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) + diff --git a/flatcamGUI/preferences/OptionUI.py b/flatcamGUI/preferences/OptionUI.py index 0d52037a..8915237f 100644 --- a/flatcamGUI/preferences/OptionUI.py +++ b/flatcamGUI/preferences/OptionUI.py @@ -1,7 +1,8 @@ from typing import Union from PyQt5 import QtWidgets -from flatcamGUI.GUIElements import RadioSet, FCCheckBox, FCButton, FCComboBox, FCEntry, FCSpinner, FCColorEntry +from flatcamGUI.GUIElements import RadioSet, FCCheckBox, FCButton, FCComboBox, FCEntry, FCSpinner, FCColorEntry, \ + FCSliderWithSpinner import gettext import FlatCAMTranslation as fcTranslate @@ -106,6 +107,18 @@ class ColorOptionUI(BasicOptionUI): return entry +class SliderWithSpinnerOptionUI(BasicOptionUI): + def __init__(self, option: str, label_text: str, label_tooltip: str, min=0, max=100, step=1): + self.min = min + self.max = max + self.step = step + super().__init__(option=option, label_text=label_text, label_tooltip=label_tooltip) + + def build_entry_widget(self) -> QtWidgets.QWidget: + entry = FCSliderWithSpinner(min=self.min, max=self.max, step=self.step) + return entry + + class HeadingOptionUI(OptionUI): def __init__(self, label_text: str, label_tooltip: Union[str, None]): super().__init__(option="__heading") diff --git a/flatcamGUI/preferences/general/GeneralGUIPrefGroupUI.py b/flatcamGUI/preferences/general/GeneralGUIPrefGroupUI.py index 49529713..ae56c3e6 100644 --- a/flatcamGUI/preferences/general/GeneralGUIPrefGroupUI.py +++ b/flatcamGUI/preferences/general/GeneralGUIPrefGroupUI.py @@ -10,7 +10,8 @@ if '_' not in builtins.__dict__: _ = gettext.gettext from flatcamGUI.preferences.OptionUI import OptionUI, CheckboxOptionUI, RadioSetOptionUI, \ - SeparatorOptionUI, HeadingOptionUI, ComboboxOptionUI, ColorOptionUI, FullWidthButtonOptionUI + SeparatorOptionUI, HeadingOptionUI, ComboboxOptionUI, ColorOptionUI, FullWidthButtonOptionUI, \ + SliderWithSpinnerOptionUI class GeneralGUIPrefGroupUI(OptionsGroupUI2): @@ -40,6 +41,16 @@ class GeneralGUIPrefGroupUI(OptionsGroupUI2): self.hdpi_field.set_value(False) self.hdpi_field.stateChanged.connect(self.handle_hdpi) + self.sel_line_field = self.option_dict()["global_sel_line"].get_field() + self.sel_fill_field = self.option_dict()["global_sel_fill"].get_field() + self.sel_alpha_field = self.option_dict()["_global_sel_alpha"].get_field() + self.sel_alpha_field.spinner.valueChanged.connect(self.on_sel_alpha_change) + + self.alt_sel_line_field = self.option_dict()["global_alt_sel_line"].get_field() + self.alt_sel_fill_field = self.option_dict()["global_alt_sel_fill"].get_field() + self.alt_sel_alpha_field = self.option_dict()["_global_alt_sel_alpha"].get_field() + self.alt_sel_alpha_field.spinner.valueChanged.connect(self.on_alt_sel_alpha_change) + def build_options(self) -> [OptionUI]: return [ @@ -117,7 +128,12 @@ class GeneralGUIPrefGroupUI(OptionsGroupUI2): "First 6 digits are the color and the last 2\n" "digits are for alpha (transparency) level." ), - # FIXME: opacity slider? + SliderWithSpinnerOptionUI( + option="_global_sel_alpha", + label_text="Alpha", + label_tooltip="Set the fill transparency for the 'left to right' selection box.", + min=0, max=255, step=1 + ), SeparatorOptionUI(), HeadingOptionUI(label_text="Right-Left Selection Color", label_tooltip=None), @@ -134,7 +150,12 @@ class GeneralGUIPrefGroupUI(OptionsGroupUI2): "First 6 digits are the color and the last 2\n" "digits are for alpha (transparency) level." ), - # FIXME: opacity slider? + SliderWithSpinnerOptionUI( + option="_global_alt_sel_alpha", + label_text="Alpha", + label_tooltip="Set the fill transparency for the 'right to left' selection box.", + min=0, max=255, step=1 + ), SeparatorOptionUI(), HeadingOptionUI(label_text='Editor Color', label_tooltip=None), @@ -171,6 +192,35 @@ class GeneralGUIPrefGroupUI(OptionsGroupUI2): ), ] + def on_sel_alpha_change(self): + alpha = self.sel_alpha_field.get_value() + fill = self._modify_color_alpha(color=self.sel_fill_field.get_value(), alpha=alpha) + self.sel_fill_field.set_value(fill) + line = self._modify_color_alpha(color=self.sel_line_field.get_value(), alpha=alpha) + self.sel_line_field.set_value(line) + + def on_alt_sel_alpha_change(self): + alpha = self.alt_sel_alpha_field.get_value() + fill = self._modify_color_alpha(color=self.alt_sel_fill_field.get_value(), alpha=alpha) + self.alt_sel_fill_field.set_value(fill) + line = self._modify_color_alpha(color=self.alt_sel_line_field.get_value(), alpha=alpha) + self.alt_sel_line_field.set_value(line) + + + + def _modify_color_alpha(self, 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 + + def on_theme_change(self): # FIXME: this should be moved out to a view model val = self.theme_field.get_value()