settings: expand new settings type

This commit is contained in:
Peter F. Patel-Schneider 2025-11-02 14:33:10 +09:00
parent f739331dc2
commit 97b6b958c8
4 changed files with 95 additions and 22 deletions

View File

@ -2100,5 +2100,22 @@ class ForceSensingButtonArray(UserDict):
self[index] = button self[index] = button
return button return button
def acceptable(self, index: int, value: int) -> bool: def query(self):
for index in self:
button = ForceSensingButton.create(self.device, index)
if button:
self[index] = button
return self
# interface for single force button
def get_current(self):
return self[0].get_current()
def set_current(self, current: int) -> None:
self[0].set_current(current)
def acceptable(self, value: int) -> bool:
return self[0].acceptable(value)
def acceptable_current_key(self, index: int, value: int) -> bool:
return self[index].acceptable(value) return self[index].acceptable(value)

View File

@ -44,6 +44,18 @@ class Setting:
_device_object = None # The object that interacts with the feature for the device _device_object = None # The object that interacts with the feature for the device
_value = None # Stored value as maintained by Solaar, used for persistence _value = None # Stored value as maintained by Solaar, used for persistence
def __init__(self, device, device_object):
self._device = device
self._device_object = device_object
@classmethod
def build(cls, device):
cls.check_properties(cls)
device_object = getattr(device, cls.setup)()
if device_object:
setting = cls(device, device_object)
return setting
@classmethod @classmethod
def check_properties(cl, cls): def check_properties(cl, cls):
assert cls.name and cls.label and cls.description, "New settings require a name, label, and description" assert cls.name and cls.label and cls.description, "New settings require a name, label, and description"
@ -51,10 +63,20 @@ class Setting:
assert cls.setup, "New settings require a setup device method" assert cls.setup, "New settings require a setup device method"
assert cls.get and cls.set and cls.acceptable, "New settings require get, set, and acceptable methods" assert cls.get and cls.set and cls.acceptable, "New settings require get, set, and acceptable methods"
@classmethod def setup_from_class(self, clss):
def build(cls, device): """Copy settings methods for a new setting from a settting class"""
"""Create the setting.""" self.name = clss.name
pass self.label = clss.label
self.description = clss.description
self.feature = clss.feature
self.min_version = clss.min_version
self.setup = clss.setup
self.get = clss.get
self.set = clss.set
self.acceptable = clss.acceptable
self.choices_universe = clss.choices_universe
self.kind = clss.kind
self.persist = clss.persist
def _pre_read(self, cached): def _pre_read(self, cached):
"""Get information from and save information to the persister""" """Get information from and save information to the persister"""
@ -68,11 +90,21 @@ class Setting:
def read(self, cached=True): def read(self, cached=True):
"""Get all the data for the setting. If cached is True the data in the _value can be used.""" """Get all the data for the setting. If cached is True the data in the _value can be used."""
pass self._pre_read(cached)
if logger.isEnabledFor(logging.DEBUG):
logger.debug("%s: setting read %r from %s", self.name, self._value, self._device)
if cached and self._value is not None:
return self._value
if cached:
self._value = getattr(self._device_object, self.get)()
return self._value
if self._device.online:
self._value = getattr(self._device_object.query(), self.get)()
return self._value
def write(self, value, save=True): def write(self, value, save=True):
"""Write the value to the device. If saved is True also save in the persister""" """Write the value to the device. If saved is True also save in the persister"""
pass pass ## fill out
def apply(self): def apply(self):
"""Write saved data to the device, using persisted data if available""" """Write saved data to the device, using persisted data if available"""
@ -87,6 +119,11 @@ class Setting:
if logger.isEnabledFor(logging.WARNING): if logger.isEnabledFor(logging.WARNING):
logger.warning("%s: error applying %s so ignore it (%s): %s", self.name, value, self._device, repr(e)) logger.warning("%s: error applying %s so ignore it (%s): %s", self.name, value, self._device, repr(e))
@property
def range(self):
if self.kind == Kind.RANGE:
return self.min_value, self.max_value
def val_to_string(self, value): def val_to_string(self, value):
return str(value) return str(value)
@ -100,18 +137,12 @@ class Settings(Setting):
Picks out a field from the mapped device feature objects.""" Picks out a field from the mapped device feature objects."""
# setup creates a dictionary with entries for all the keys # setup creates a dictionary with entries for all the keys
# get, set, and acceptable are methods of dict value objects, not of the device object itself # _value is a map from keys to values
# get, set, and acceptable are methods of dict value objects, not of the device object itself #### FIX THIS! MAYBE??
@classmethod def __init__(self, device, device_object):
def build(cls, device): super().__init__(device, device_object)
cls.check_properties(cls) self._value = {}
_device_object = getattr(device, cls.setup)()
if _device_object:
setting = cls()
setting._device = device
setting._device_object = _device_object
setting._value = {}
return setting
def read(self, cached=True): def read(self, cached=True):
self._pre_read(cached) self._pre_read(cached)
@ -122,7 +153,7 @@ class Settings(Setting):
return self._value return self._value
def read_key(self, key, cached=True): def read_key(self, key, cached=True):
"""Get the data for the key. If cached is True the data in the _device_object can be used.""" """Get the data for the key. If cached is True the data in the device_object can be used."""
self._pre_read(cached) self._pre_read(cached)
if key not in self._device_object: if key not in self._device_object:
logger.error("%s: settings illegal read key %r for %s", self.name, key, self._device) logger.error("%s: settings illegal read key %r for %s", self.name, key, self._device)
@ -143,8 +174,13 @@ class Settings(Setting):
def write(self, value, save=True): def write(self, value, save=True):
if logger.isEnabledFor(logging.DEBUG): if logger.isEnabledFor(logging.DEBUG):
logger.debug("%s: settings read %r from %s", self.name, self._value, self._device) logger.debug("%s: settings read %r from %s", self.name, self._value, self._device)
for key, val in value.items(): if isinstance(value, dict):
self.write_key_value(key, val, save) for key, val in value.items():
self.write_key_value(key, val, save)
else: # to mimic interface for non-dict setting
key = next(iter(self._device_object))
self.write_key_value(key, value, save)
return value
def write_key_value(self, key, value, save=True): def write_key_value(self, key, value, save=True):
"""Write the data for the key. If saved is True also save in the persister""" """Write the data for the key. If saved is True also save in the persister"""

View File

@ -1789,10 +1789,25 @@ class ForceSensing(settings_new.Settings):
setup = "force_buttons" setup = "force_buttons"
get = "get_current" get = "get_current"
set = "set_current" set = "set_current"
acceptable = "acceptable_current" acceptable = "acceptable_current_key"
choices_universe = list(range(0, 256)) choices_universe = list(range(0, 256))
kind = settings.Kind.MAP_RANGE kind = settings.Kind.MAP_RANGE
@classmethod
def build(cls, device):
cls.check_properties(cls)
device_object = getattr(device, cls.setup)()
if device_object:
setting = cls(device, device_object)
if setting and len(device_object) == 1:
## If there is only one force button a simpler interface can be used
setting.label = _("Force Sensing Button")
setting.acceptable = "acceptable_current"
setting.min_value = device_object[0].min_value
setting.max_value = device_object[0].max_value
setting.kind = settings.Kind.RANGE
return setting
SETTINGS: list[settings.Setting] = [ SETTINGS: list[settings.Setting] = [
RegisterHandDetection, # simple RegisterHandDetection, # simple

View File

@ -147,6 +147,11 @@ class SliderControl(Gtk.Scale, Control):
self.set_increments(1, 5) self.set_increments(1, 5)
self.connect(GtkSignal.VALUE_CHANGED.value, self.changed) self.connect(GtkSignal.VALUE_CHANGED.value, self.changed)
def set_value(self, value):
if isinstance(value, dict):
value = next(iter(value.values()))
return super().set_value(value)
def get_value(self): def get_value(self):
return int(super().get_value()) return int(super().get_value())