99 lines
3.4 KiB
Python
99 lines
3.4 KiB
Python
from functools import partial
|
|
from typing import Union
|
|
|
|
from krita import QComboBox, QHBoxLayout, Qt, QValidator
|
|
|
|
from ..config import Config
|
|
from .misc import QLabel
|
|
|
|
|
|
class QOptionValidator(QValidator):
|
|
def __init__(self, opts: set, *args, **kwargs):
|
|
super(QOptionValidator, self).__init__(*args, **kwargs)
|
|
self.opts = opts
|
|
|
|
def validate(self, input, pos):
|
|
# Below validation rules make it impossible to type invalid options
|
|
if len(self.opts) < 2:
|
|
# List hasn't loaded yet
|
|
return QValidator.Intermediate, input, pos
|
|
elif input in self.opts:
|
|
return QValidator.Acceptable, input, pos
|
|
elif any(o.find(input) == 0 for o in self.opts):
|
|
return QValidator.Intermediate, input, pos
|
|
else:
|
|
return QValidator.Invalid, input, pos
|
|
|
|
def fixup(self, input):
|
|
return ""
|
|
|
|
|
|
class QComboBoxLayout(QHBoxLayout):
|
|
def __init__(
|
|
self,
|
|
cfg: Config,
|
|
options_cfg: Union[str, list],
|
|
selected_cfg: str,
|
|
label: str = None,
|
|
*args,
|
|
**kwargs
|
|
):
|
|
"""Layout for labelled QComboBox.
|
|
|
|
Args:
|
|
cfg (Config): Config to connect to.
|
|
options_cfg (Union[str, list]): Config key to read available options from or list of options.
|
|
selected_cfg (str): Config key to read/write selected option to.
|
|
label (str, optional): Label, uses `selected_cfg` if None. Defaults to None.
|
|
num_chars (int, optional): Max length of qcombo in chars. Defaults to None.
|
|
"""
|
|
super(QComboBoxLayout, self).__init__(*args, **kwargs)
|
|
|
|
# Used to connect to config stored in script
|
|
self.cfg = cfg
|
|
self.options_cfg = options_cfg
|
|
self.selected_cfg = selected_cfg
|
|
self._items = set()
|
|
|
|
self.qlabel = QLabel(self.selected_cfg if label is None else label)
|
|
self.qcombo = QComboBox()
|
|
self.qcombo.view().setTextElideMode(Qt.ElideLeft)
|
|
self.qcombo.setEditable(True)
|
|
self.qcombo.setInsertPolicy(QComboBox.NoInsert)
|
|
self.qcombo.setMinimumWidth(10)
|
|
|
|
self.addWidget(self.qlabel)
|
|
self.addWidget(self.qcombo)
|
|
|
|
def cfg_init(self):
|
|
opts = sorted(
|
|
set(
|
|
self.cfg(self.options_cfg, "QStringList")
|
|
if isinstance(self.options_cfg, str)
|
|
else self.options_cfg
|
|
),
|
|
key=str.casefold,
|
|
)
|
|
|
|
# NOTE: assumes the None option will always be labelled as "None"
|
|
if "None" in opts:
|
|
opts.remove("None")
|
|
opts.insert(0, "None")
|
|
|
|
# prevent dropdown from closing when cfg_init is called by update
|
|
if set(opts) != self._items:
|
|
self._items = set(opts)
|
|
# as using editable mode, text isn't affected by clearing options
|
|
self.qcombo.clear()
|
|
self.qcombo.addItems(opts)
|
|
self.qcombo.setValidator(QOptionValidator(self._items))
|
|
|
|
# avoid resetting the auto-completer
|
|
if self.qcombo.currentText() != self.cfg(self.selected_cfg):
|
|
self.qcombo.setEditText(self.cfg(self.selected_cfg))
|
|
|
|
def cfg_connect(self):
|
|
# Possible to get invalid by backspacing after selecting option
|
|
# but no one would do that deliberately
|
|
self.qcombo.editTextChanged.connect(partial(self.cfg.set, self.selected_cfg))
|