BLKSerene/Wordless

View on GitHub
wordless/wl_widgets/wl_boxes.py

Summary

Maintainability
B
5 hrs
Test Coverage
# ----------------------------------------------------------------------
# Wordless: Widgets - Boxes
# Copyright (C) 2018-2024  Ye Lei (叶磊)
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
# ----------------------------------------------------------------------

from PyQt5.QtCore import QCoreApplication, Qt
from PyQt5.QtWidgets import (
    QCheckBox,
    QComboBox,
    QDoubleSpinBox,
    QFontComboBox,
    QLabel,
    QSpinBox
)

from wordless.wl_measures import wl_measure_utils
from wordless.wl_utils import wl_misc

_tr = QCoreApplication.translate

# Combo boxes
class Wl_Combo_Box(QComboBox):
    def __init__(self, parent):
        super().__init__(parent)

        self.main = wl_misc.find_wl_main(parent)

        self.setMaxVisibleItems(20)
        self.setFocusPolicy(Qt.StrongFocus)

    def wheelEvent(self, event):
        if self.hasFocus():
            QComboBox.wheelEvent(self, event)
        else:
            event.ignore()

class Wl_Combo_Box_Adjustable(Wl_Combo_Box):
    def __init__(self, parent):
        super().__init__(parent)

        self.setSizeAdjustPolicy(QComboBox.AdjustToContents)

class Wl_Combo_Box_Enums(Wl_Combo_Box):
    def __init__(self, parent, enums):
        super().__init__(parent)

        self._enums = enums

        self.addItems(self._enums)

    def get_val(self):
        return self._enums[self.currentText()]

    def set_val(self, val):
        for val_name, val_code in self._enums.items():
            if val == val_code:
                super().setCurrentText(val_name)

                break

class Wl_Combo_Box_Yes_No(Wl_Combo_Box_Enums):
    def __init__(self, parent):
        super().__init__(parent, enums = {
            _tr('wl_boxes', 'Yes'): True,
            _tr('wl_boxes', 'No'): False
        })

    def get_yes_no(self):
        return super().get_val()

    def set_yes_no(self, yes_no):
        super().set_val(yes_no)

class Wl_Combo_Box_Lang(Wl_Combo_Box):
    def __init__(self, parent):
        super().__init__(parent)

        self.addItems(list(self.main.settings_global['langs']))

class Wl_Combo_Box_Encoding(Wl_Combo_Box):
    def __init__(self, parent):
        super().__init__(parent)

        self.addItems(list(self.main.settings_global['encodings']))

class Wl_Combo_Box_Measure(Wl_Combo_Box):
    def __init__(self, parent, measure_type):
        super().__init__(parent)

        self.measure_type = measure_type

        self.addItems(self.main.settings_global['mapping_measures'][self.measure_type])

    def get_measure(self):
        return wl_measure_utils.to_measure_code(self.main, self.measure_type, self.currentText())

    def set_measure(self, measure):
        for i in range(self.count()):
            if wl_measure_utils.to_measure_text(self.main, self.measure_type, measure) == self.itemText(i):
                self.setCurrentIndex(i)

class Wl_Combo_Box_File_To_Filter(Wl_Combo_Box):
    def __init__(self, parent, table):
        super().__init__(parent)

        self.table = table

        self.table.model().itemChanged.connect(self.table_item_changed)

        self.table_item_changed()

    def table_item_changed(self):
        self.blockSignals(True)

        file_to_filter_old = self.currentText()

        self.clear()

        for file in self.table.settings['file_area']['files_open']:
            if file['selected']:
                self.addItem(file['name'])

        self.addItem(self.tr('Total'))

        self.setCurrentText(file_to_filter_old)

        self.blockSignals(False)

        self.currentTextChanged.emit(self.currentText())

class Wl_Combo_Box_File(Wl_Combo_Box):
    def __init__(self, parent):
        super().__init__(parent)

        # Clip long file names
        self.setSizeAdjustPolicy(QComboBox.AdjustToMinimumContentsLengthWithIcon)

        self.addItems(self.main.wl_file_area.get_selected_file_names())

        self.main.wl_file_area.table_files.model().itemChanged.connect(self.wl_files_changed)

        self.wl_files_changed()

    def wl_files_changed(self):
        pass

    def get_file(self):
        return self.main.wl_file_area.find_file_by_name(self.currentText(), selected_only = True)

class Wl_Combo_Box_Font_Family(QFontComboBox):
    def __init__(self, parent):
        super().__init__(parent)

        self.main = wl_misc.find_wl_main(parent)

        self.setMaxVisibleItems(20)
        self.setFocusPolicy(Qt.StrongFocus)

    def wheelEvent(self, event):
        if self.hasFocus():
            QComboBox.wheelEvent(self, event)
        else:
            event.ignore()

# Spin boxes
class Wl_Spin_Box(QSpinBox):
    def __init__(self, parent):
        super().__init__(parent)

        self.main = wl_misc.find_wl_main(parent)

        self.setFocusPolicy(Qt.StrongFocus)

    def wheelEvent(self, event):
        if self.hasFocus():
            QSpinBox.wheelEvent(self, event)
        else:
            event.ignore()

class Wl_Spin_Box_Window(Wl_Spin_Box):
    def __init__(self, parent):
        super().__init__(parent)

        self.setRange(-100, 100)

        self.valueChanged.connect(self.value_changed)

    def stepBy(self, steps):
        if self.prefix() == self.tr('L'):
            super().stepBy(-steps)
        elif self.prefix() == self.tr('R'):
            super().stepBy(steps)

    def value_changed(self):
        if self.value() <= 0:
            if self.prefix() == self.tr('L'):
                self.setPrefix(self.tr('R'))
            else:
                self.setPrefix(self.tr('L'))

            self.setValue(-self.value() + 1)

class Wl_Spin_Box_Font_Size(Wl_Spin_Box):
    def __init__(self, parent):
        super().__init__(parent)

        self.setRange(6, 20)

class Wl_Spin_Box_Font_Weight(Wl_Spin_Box):
    def __init__(self, parent):
        super().__init__(parent)

        self.setRange(0, 1000)

# Double spin boxes
class Wl_Double_Spin_Box(QDoubleSpinBox):
    def __init__(self, parent):
        super().__init__(parent)

        self.main = wl_misc.find_wl_main(parent)

        self.setDecimals(2)
        self.setSingleStep(.01)
        self.setFocusPolicy(Qt.StrongFocus)

    def wheelEvent(self, event):
        if self.hasFocus():
            QDoubleSpinBox.wheelEvent(self, event)
        else:
            event.ignore()

class Wl_Double_Spin_Box_Alpha(Wl_Double_Spin_Box):
    def __init__(self, parent):
        super().__init__(parent)

        self.setRange(0, 1)

# Box combinations
def wl_spin_box_no_limit(parent, val_min = 1, val_max = 100, double = False):
    def no_limit_changed():
        if checkbox_no_limit.isChecked():
            spin_box_val.setEnabled(False)
        else:
            spin_box_val.setEnabled(True)

    if double:
        spin_box_val = Wl_Double_Spin_Box(parent)
    else:
        spin_box_val = Wl_Spin_Box(parent)

    checkbox_no_limit = QCheckBox(_tr('wl_boxes', 'No limit'), parent)

    spin_box_val.setRange(val_min, val_max)

    checkbox_no_limit.stateChanged.connect(no_limit_changed)

    no_limit_changed()

    return spin_box_val, checkbox_no_limit

# Defer evaluation of default values of functions until QTranslator is initialized
def wl_spin_boxes_min_max(
    parent,
    label_min = None, label_max = None,
    val_min = 1, val_max = 100,
    double = False
):
    def min_changed():
        if spin_box_min.value() > spin_box_max.value():
            spin_box_max.setValue(spin_box_min.value())

    def max_changed():
        if spin_box_min.value() > spin_box_max.value():
            spin_box_min.setValue(spin_box_max.value())

    label_min = label_min or _tr('wl_boxes', 'From')
    label_max = label_max or _tr('wl_boxes', 'to')

    label_min = QLabel(label_min, parent)
    label_max = QLabel(label_max, parent)

    if double:
        spin_box_min = Wl_Double_Spin_Box(parent)
        spin_box_max = Wl_Double_Spin_Box(parent)
    else:
        spin_box_min = Wl_Spin_Box(parent)
        spin_box_max = Wl_Spin_Box(parent)

    spin_box_min.setRange(val_min, val_max)
    spin_box_max.setRange(val_min, val_max)

    spin_box_min.valueChanged.connect(min_changed)
    spin_box_max.valueChanged.connect(max_changed)

    min_changed()
    max_changed()

    return (
        label_min, spin_box_min,
        label_max, spin_box_max
    )

def wl_spin_boxes_min_max_sync(
    parent,
    label_min = None, label_max = None,
    val_min = 1, val_max = 100,
    double = False
):
    def sync_changed():
        if checkbox_sync.isChecked():
            spin_box_min.setValue(spin_box_max.value())

    def min_changed():
        if checkbox_sync.isChecked() or spin_box_min.value() > spin_box_max.value():
            spin_box_max.setValue(spin_box_min.value())

    def max_changed():
        if checkbox_sync.isChecked() or spin_box_min.value() > spin_box_max.value():
            spin_box_min.setValue(spin_box_max.value())

    label_min = label_min or _tr('wl_boxes', 'From')
    label_max = label_max or _tr('wl_boxes', 'to')

    checkbox_sync = QCheckBox(_tr('wl_boxes', 'Sync'), parent)

    (
        label_min, spin_box_min,
        label_max, spin_box_max
    ) = wl_spin_boxes_min_max(parent, label_min, label_max, val_min, val_max, double)

    spin_box_min.valueChanged.disconnect()
    spin_box_max.valueChanged.disconnect()

    spin_box_min.valueChanged.connect(min_changed)
    spin_box_max.valueChanged.connect(max_changed)

    checkbox_sync.stateChanged.connect(sync_changed)

    min_changed()
    max_changed()
    sync_changed()

    return (
        checkbox_sync,
        label_min, spin_box_min,
        label_max, spin_box_max
    )

def wl_spin_boxes_min_max_sync_window(parent):
    def sync_changed():
        if checkbox_sync.isChecked():
            spin_box_left.setPrefix(spin_box_right.prefix())
            spin_box_left.setValue(spin_box_right.value())

    def left_changed():
        if (
            checkbox_sync.isChecked()
            or (
                spin_box_left.prefix() == _tr('wl_boxes', 'L')
                and spin_box_right.prefix() == _tr('wl_boxes', 'L')
                and spin_box_left.value() < spin_box_right.value()
            ) or (
                spin_box_left.prefix() == _tr('wl_boxes', 'R')
                and spin_box_right.prefix() == _tr('wl_boxes', 'R')
                and spin_box_left.value() > spin_box_right.value()
            ) or (
                spin_box_left.prefix() == _tr('wl_boxes', 'R')
                and spin_box_right.prefix() == _tr('wl_boxes', 'L')
            )
        ):
            spin_box_right.setPrefix(spin_box_left.prefix())
            spin_box_right.setValue(spin_box_left.value())

    def right_changed():
        if (
            checkbox_sync.isChecked()
            or (
                spin_box_left.prefix() == _tr('wl_boxes', 'L')
                and spin_box_right.prefix() == _tr('wl_boxes', 'L')
                and spin_box_left.value() < spin_box_right.value()
            ) or (
                spin_box_left.prefix() == _tr('wl_boxes', 'R')
                and spin_box_right.prefix() == _tr('wl_boxes', 'R')
                and spin_box_left.value() > spin_box_right.value()
            ) or (
                spin_box_left.prefix() == _tr('wl_boxes', 'R')
                and spin_box_right.prefix() == _tr('wl_boxes', 'L')
            )
        ):
            spin_box_left.setPrefix(spin_box_right.prefix())
            spin_box_left.setValue(spin_box_right.value())

    checkbox_sync = QCheckBox(_tr('wl_boxes', 'Sync'), parent)
    label_left = QLabel(_tr('wl_boxes', 'From'), parent)
    spin_box_left = Wl_Spin_Box_Window(parent)
    label_right = QLabel(_tr('wl_boxes', 'to'), parent)
    spin_box_right = Wl_Spin_Box_Window(parent)

    spin_box_left.setRange(-100, 100)
    spin_box_right.setRange(-100, 100)

    checkbox_sync.stateChanged.connect(sync_changed)
    spin_box_left.valueChanged.connect(left_changed)
    spin_box_right.valueChanged.connect(right_changed)

    sync_changed()
    left_changed()
    right_changed()

    return (
        checkbox_sync,
        label_left, spin_box_left,
        label_right, spin_box_right
    )

def wl_spin_boxes_min_max_no_limit(
    parent,
    label_min = None, label_max = None,
    val_min = 1, val_max = 100,
    double = False, sync = True
):
    def no_limit_min_changed():
        if checkbox_min_no_limit.isChecked():
            spin_box_min.setEnabled(False)
        else:
            spin_box_min.setEnabled(True)

    def no_limit_max_changed():
        if checkbox_max_no_limit.isChecked():
            spin_box_max.setEnabled(False)
        else:
            spin_box_max.setEnabled(True)

    label_min = label_min or _tr('wl_boxes', 'From')
    label_max = label_max or _tr('wl_boxes', 'to')

    (
        checkbox_sync,
        label_min, spin_box_min,
        label_max, spin_box_max
    ) = wl_spin_boxes_min_max_sync(parent, label_min, label_max, val_min, val_max, double)

    checkbox_min_no_limit = QCheckBox(_tr('wl_boxes', 'No limit'), parent)
    checkbox_max_no_limit = QCheckBox(_tr('wl_boxes', 'No limit'), parent)

    checkbox_min_no_limit.stateChanged.connect(no_limit_min_changed)
    checkbox_max_no_limit.stateChanged.connect(no_limit_max_changed)

    if not sync:
        checkbox_sync.setChecked(False)

    no_limit_min_changed()
    no_limit_max_changed()

    if sync:
        return (
            checkbox_sync,
            label_min, spin_box_min, checkbox_min_no_limit,
            label_max, spin_box_max, checkbox_max_no_limit
        )
    else:
        return (
            label_min, spin_box_min, checkbox_min_no_limit,
            label_max, spin_box_max, checkbox_max_no_limit
        )