Compare commits
8 Commits
6b175c74c5
...
326b1c0334
Author | SHA1 | Date |
---|---|---|
|
326b1c0334 | |
|
bdb0e9589b | |
|
0335dd003c | |
|
8bea0121cc | |
|
c3f3c91e59 | |
|
515f97269d | |
|
a70366a786 | |
|
9af34b33e8 |
72
CHANGELOG.md
72
CHANGELOG.md
|
@ -1,3 +1,75 @@
|
|||
# 1.1.15rc1
|
||||
|
||||
* Center labels and remove buggy entry resizing logic
|
||||
* Add shape keys from Key POP Icon
|
||||
* Device and Action rule conditions match on codename and name
|
||||
* Fix listing hidpp10 devices - bytes vs string concatenation (#2856)
|
||||
* Add present flag, unset when internal error occurs, set when notification appears
|
||||
* Pause setting up features when error occurs; use ADC message to signal connection and disconnection
|
||||
* Fix listing of hidpp10 peripherals
|
||||
* Complete DEVICE_FEATURES to DeviceFeature transition for hidpp10 devices
|
||||
* Fix NOTIFICATION_FLAG to NotificationFlag transition leftovers
|
||||
* Fix github workflow stopping all matrix jobs when one of them fails
|
||||
* Fix ubuntu github CI
|
||||
* Update index.md
|
||||
* Python documentation appears to be broken so don't set it up
|
||||
* Improve documentation on onboard profiles
|
||||
* Use correct LOD values for extended adjustable dpi
|
||||
* Better support RGB Effects - not readable
|
||||
* Fix crash when asking for help about config
|
||||
* Fix error when updating ChoiceControlBig box
|
||||
* Add uninstallation docs
|
||||
* Handle unknown power switch locations again
|
||||
* Correctly handle selection of [empty] in rule editor
|
||||
* Handle `HIDError` in `hidapi.hidapi_impl._match()` (#2804)
|
||||
* Give ghost devices a path
|
||||
* Guard against typeerror when setting the value of a control box
|
||||
* Recover from errors in ping
|
||||
* Replace spaces by underscores when looking up features
|
||||
* Rewrote string concatenation/format with f strings
|
||||
* Fix logo not showing in about dialog box
|
||||
* Make typing-extensions dependency mandatory
|
||||
* Properly ignore unsupported locale
|
||||
* hidapi: skip unsupported devices and handle exception on open
|
||||
* Ignore macOS junk files and pipenv config
|
||||
* Fix ui desktop notifications test
|
||||
* hidpp20: Remove dependency to NamedInts
|
||||
* Estimate accurate battery level for some rechargable devices (#2745)
|
||||
* Upgrade desktop notifications tests to take notifications availability into account
|
||||
* Update tests to run on Python 3.13
|
||||
* Remove outdated logger enabled checks
|
||||
* Introduce GTK signal types
|
||||
* Introduce error types
|
||||
* Remove alias for SupportedFeature
|
||||
* Refactor process_device_notification
|
||||
* Refactor process_receiver_notification
|
||||
* Refactor receiver event handling
|
||||
* Introduce custom logger
|
||||
* Refactor notifications
|
||||
* Rename variable to full name notification
|
||||
* Test notifications
|
||||
* Test extraction of serial and max. devices
|
||||
* Refactor extraction of serial and max. devices
|
||||
* macOS: Fix int.from_bytes, int.to_bytes for show.py
|
||||
* macOS: Remove udev rule warning
|
||||
* macOS: Add support for Bluetooth devices
|
||||
* Add back and forward mouseclick actions
|
||||
* Speedup lookup of known receivers
|
||||
* Refactor device filtering
|
||||
* Reorder private functions and variable definitions
|
||||
* Turn filter_products_of_interest into a public function
|
||||
* Improve tests of known receivers
|
||||
* Refactor: Remove NamedInts and move enums where used
|
||||
* Add docstrings and type hints
|
||||
* Enforce rules on RuleComponentUI subclasses
|
||||
* Simplify settings UI class
|
||||
* Remove diversion alias
|
||||
* Refactor: Convert Kind to IntEnum
|
||||
* Split up huge settings module
|
||||
* Remove Python 2 specific path handling
|
||||
* Delete logging temp file on exit
|
||||
* Update Swedish translation
|
||||
|
||||
# 1.1.14
|
||||
|
||||
* Handle fake feature enums in show
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
## Version 1.1.15
|
||||
|
||||
* Device and Action rule conditions match on device codename and name
|
||||
* Solaar supports configuration of Bluetooth devices on macOS.
|
||||
|
||||
## Version 1.1.13
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
solaar show
|
||||
rules cannot access modifier keys in Wayland, accessing process only works on GNOME with Solaar Gnome extension installed
|
||||
solaar version 1.1.14-2
|
||||
|
||||
Unifying Receiver
|
||||
Device path : /dev/hidraw1
|
||||
USB id : 046d:C52B
|
||||
Serial : EC219AC2
|
||||
C Pending : ff
|
||||
0 : 12.11.B0032
|
||||
1 : 04.16
|
||||
3 : AA.AA
|
||||
Has 2 paired device(s) out of a maximum of 6.
|
||||
Notifications: wireless (0x000100)
|
||||
Device activity counters: 1=195, 2=74
|
||||
|
||||
1: Wireless Mouse M175
|
||||
Device path : /dev/hidraw2
|
||||
WPID : 4008
|
||||
Codename : M175
|
||||
Kind : mouse
|
||||
Protocol : HID++ 2.0
|
||||
Report Rate : 8ms
|
||||
Serial number: 16E46E8C
|
||||
Model ID: 000000000000
|
||||
Unit ID: 00000000
|
||||
0: RQM 40.00.B0016
|
||||
The power switch is located on the base.
|
||||
Supports 21 HID++ 2.0 features:
|
||||
0: ROOT {0000} V0
|
||||
1: FEATURE SET {0001} V0
|
||||
2: DEVICE FW VERSION {0003} V0
|
||||
Firmware: 0 RQM 40.00.B0016 4008
|
||||
Unit ID: 00000000 Model ID: 000000000000 Transport IDs: {}
|
||||
3: DEVICE NAME {0005} V0
|
||||
Name: Wireless Mouse M185
|
||||
Kind: mouse
|
||||
4: BATTERY STATUS {1000} V0
|
||||
Battery: 70%, 0, next level 5%.
|
||||
5: unknown:1830 {1830} V0 internal, hidden
|
||||
6: unknown:1850 {1850} V0 internal, hidden
|
||||
7: unknown:1860 {1860} V0 internal, hidden
|
||||
8: unknown:1890 {1890} V0 internal, hidden
|
||||
9: unknown:18A0 {18A0} V0 internal, hidden
|
||||
10: unknown:18C0 {18C0} V0 internal, hidden
|
||||
11: WIRELESS DEVICE STATUS {1D4B} V0
|
||||
12: unknown:1DF3 {1DF3} V0 internal, hidden
|
||||
13: REPROG CONTROLS {1B00} V0
|
||||
14: REMAINING PAIRING {1DF0} V0 hidden
|
||||
Remaining Pairings: 117
|
||||
15: unknown:1E00 {1E00} V0 hidden
|
||||
16: unknown:1E80 {1E80} V0 internal, hidden
|
||||
17: unknown:1E90 {1E90} V0 internal, hidden
|
||||
18: unknown:1F03 {1F03} V0 internal, hidden
|
||||
19: VERTICAL SCROLLING {2100} V0
|
||||
Roller type: standard
|
||||
Ratchet per turn: 24
|
||||
Scroll lines: 0
|
||||
20: MOUSE POINTER {2200} V0
|
||||
DPI: 1000
|
||||
Acceleration: low
|
||||
Override OS ballistics
|
||||
No vertical tuning, standard mice
|
||||
Battery: 70%, 0, next level 5%.
|
|
@ -511,35 +511,33 @@ MOUSE_GESTURE_TESTS = {
|
|||
"mouse-noop": [],
|
||||
}
|
||||
|
||||
# COMPONENTS = {}
|
||||
|
||||
|
||||
class RuleComponent:
|
||||
def compile(self, c):
|
||||
if isinstance(c, RuleComponent):
|
||||
return c
|
||||
elif isinstance(c, dict) and len(c) == 1:
|
||||
k, v = next(iter(c.items()))
|
||||
if k in COMPONENTS:
|
||||
return COMPONENTS[k](v)
|
||||
logger.warning("illegal component in rule: %s", c)
|
||||
return Condition()
|
||||
def compile_component(c) -> Rule | type[ConditionProtocol] | type[ActionProtocol]:
|
||||
if isinstance(c, Rule) or isinstance(c, ConditionProtocol) or isinstance(c, ActionProtocol):
|
||||
return c
|
||||
elif isinstance(c, dict) and len(c) == 1:
|
||||
k, v = next(iter(c.items()))
|
||||
if k in COMPONENTS:
|
||||
cls: Rule | type[ConditionProtocol] | type[ActionProtocol] = COMPONENTS[k]
|
||||
return cls(v)
|
||||
logger.warning("illegal component in rule: %s", c)
|
||||
return FallbackCondition()
|
||||
|
||||
|
||||
def _evaluate(components, feature, notification: HIDPPNotification, device, result) -> Any:
|
||||
res = True
|
||||
for component in components:
|
||||
res = component.evaluate(feature, notification, device, result)
|
||||
if not isinstance(component, Action) and res is None:
|
||||
if not isinstance(component, ActionProtocol) and res is None:
|
||||
return None
|
||||
if isinstance(component, Condition) and not res:
|
||||
if isinstance(component, ConditionProtocol) and not res:
|
||||
return res
|
||||
return res
|
||||
|
||||
|
||||
class Rule(RuleComponent):
|
||||
class Rule:
|
||||
def __init__(self, args, source=None, warn=True):
|
||||
self.components = [self.compile(a) for a in args]
|
||||
self.components = [compile_component(a) for a in args]
|
||||
self.source = source
|
||||
|
||||
def __str__(self):
|
||||
|
@ -559,7 +557,22 @@ class Rule(RuleComponent):
|
|||
return {"Rule": [c.data() for c in self.components]}
|
||||
|
||||
|
||||
class Condition(RuleComponent):
|
||||
@typing.runtime_checkable
|
||||
class ConditionProtocol(typing.Protocol):
|
||||
def __init__(self, args: Any, warn: bool) -> None:
|
||||
...
|
||||
|
||||
def __str__(self) -> str:
|
||||
...
|
||||
|
||||
def evaluate(self, feature, notification: HIDPPNotification, device, last_result) -> bool:
|
||||
...
|
||||
|
||||
def data(self) -> dict[str, Any]:
|
||||
...
|
||||
|
||||
|
||||
class FallbackCondition(ConditionProtocol):
|
||||
def __init__(self, *args):
|
||||
pass
|
||||
|
||||
|
@ -572,12 +585,12 @@ class Condition(RuleComponent):
|
|||
return False
|
||||
|
||||
|
||||
class Not(Condition):
|
||||
class Not(ConditionProtocol):
|
||||
def __init__(self, op, warn=True):
|
||||
if isinstance(op, list) and len(op) == 1:
|
||||
op = op[0]
|
||||
self.op = op
|
||||
self.component = self.compile(op)
|
||||
self.component = compile_component(op)
|
||||
|
||||
def __str__(self):
|
||||
return f"Not: {str(self.component)}"
|
||||
|
@ -592,9 +605,9 @@ class Not(Condition):
|
|||
return {"Not": self.component.data()}
|
||||
|
||||
|
||||
class Or(Condition):
|
||||
class Or(ConditionProtocol):
|
||||
def __init__(self, args, warn=True):
|
||||
self.components = [self.compile(a) for a in args]
|
||||
self.components = [compile_component(a) for a in args]
|
||||
|
||||
def __str__(self):
|
||||
return "Or: [" + ", ".join(str(c) for c in self.components) + "]"
|
||||
|
@ -605,9 +618,9 @@ class Or(Condition):
|
|||
result = False
|
||||
for component in self.components:
|
||||
result = component.evaluate(feature, notification, device, last_result)
|
||||
if not isinstance(component, Action) and result is None:
|
||||
if not isinstance(component, ActionProtocol) and result is None:
|
||||
return None
|
||||
if isinstance(component, Condition) and result:
|
||||
if isinstance(component, ConditionProtocol) and result:
|
||||
return result
|
||||
return result
|
||||
|
||||
|
@ -615,9 +628,9 @@ class Or(Condition):
|
|||
return {"Or": [c.data() for c in self.components]}
|
||||
|
||||
|
||||
class And(Condition):
|
||||
class And(ConditionProtocol):
|
||||
def __init__(self, args, warn=True):
|
||||
self.components = [self.compile(a) for a in args]
|
||||
self.components = [compile_component(a) for a in args]
|
||||
|
||||
def __str__(self):
|
||||
return "And: [" + ", ".join(str(c) for c in self.components) + "]"
|
||||
|
@ -677,7 +690,7 @@ def gnome_dbus_pointer_prog():
|
|||
return (wm_class,) if wm_class else None
|
||||
|
||||
|
||||
class Process(Condition):
|
||||
class Process(ConditionProtocol):
|
||||
def __init__(self, process, warn=True):
|
||||
self.process = process
|
||||
if (not wayland and not x11_setup()) or (wayland and not gnome_dbus_interface_setup()):
|
||||
|
@ -708,7 +721,7 @@ class Process(Condition):
|
|||
return {"Process": str(self.process)}
|
||||
|
||||
|
||||
class MouseProcess(Condition):
|
||||
class MouseProcess(ConditionProtocol):
|
||||
def __init__(self, process, warn=True):
|
||||
self.process = process
|
||||
if (not wayland and not x11_setup()) or (wayland and not gnome_dbus_interface_setup()):
|
||||
|
@ -739,7 +752,7 @@ class MouseProcess(Condition):
|
|||
return {"MouseProcess": str(self.process)}
|
||||
|
||||
|
||||
class Feature(Condition):
|
||||
class Feature(ConditionProtocol):
|
||||
def __init__(self, feature: str, warn: bool = True):
|
||||
try:
|
||||
self.feature = SupportedFeature[feature.replace(" ", "_")]
|
||||
|
@ -760,7 +773,7 @@ class Feature(Condition):
|
|||
return {"Feature": str(self.feature)}
|
||||
|
||||
|
||||
class Report(Condition):
|
||||
class Report(ConditionProtocol):
|
||||
def __init__(self, report, warn=True):
|
||||
if not (isinstance(report, int)):
|
||||
if warn:
|
||||
|
@ -782,7 +795,7 @@ class Report(Condition):
|
|||
|
||||
|
||||
# Setting(device, setting, [key], value...)
|
||||
class Setting(Condition):
|
||||
class Setting(ConditionProtocol):
|
||||
def __init__(self, args, warn=True):
|
||||
if not (isinstance(args, list) and len(args) > 2):
|
||||
if warn:
|
||||
|
@ -829,7 +842,7 @@ MODIFIERS = {
|
|||
MODIFIER_MASK = MODIFIERS["Shift"] + MODIFIERS["Control"] + MODIFIERS["Alt"] + MODIFIERS["Super"]
|
||||
|
||||
|
||||
class Modifiers(Condition):
|
||||
class Modifiers(ConditionProtocol):
|
||||
def __init__(self, modifiers, warn=True):
|
||||
modifiers = [modifiers] if isinstance(modifiers, str) else modifiers
|
||||
self.desired = 0
|
||||
|
@ -859,7 +872,7 @@ class Modifiers(Condition):
|
|||
return {"Modifiers": [str(m) for m in self.modifiers]}
|
||||
|
||||
|
||||
class Key(Condition):
|
||||
class Key(ConditionProtocol):
|
||||
DOWN = "pressed"
|
||||
UP = "released"
|
||||
|
||||
|
@ -914,7 +927,7 @@ class Key(Condition):
|
|||
return {"Key": [str(self.key), self.action]}
|
||||
|
||||
|
||||
class KeyIsDown(Condition):
|
||||
class KeyIsDown(ConditionProtocol):
|
||||
def __init__(self, args, warn=True):
|
||||
default_key = 0
|
||||
|
||||
|
@ -958,7 +971,7 @@ def range_test(start, end, min, max):
|
|||
return range_test_helper
|
||||
|
||||
|
||||
class Test(Condition):
|
||||
class Test(ConditionProtocol):
|
||||
def __init__(self, test, warn=True):
|
||||
self.test = ""
|
||||
self.parameter = None
|
||||
|
@ -1000,7 +1013,7 @@ class Test(Condition):
|
|||
return {"Test": ([self.test, self.parameter] if self.parameter is not None else [self.test])}
|
||||
|
||||
|
||||
class TestBytes(Condition):
|
||||
class TestBytes(ConditionProtocol):
|
||||
def __init__(self, test, warn=True):
|
||||
self.test = test
|
||||
if (
|
||||
|
@ -1028,7 +1041,7 @@ class TestBytes(Condition):
|
|||
return {"TestBytes": self.test[:]}
|
||||
|
||||
|
||||
class MouseGesture(Condition):
|
||||
class MouseGesture(ConditionProtocol):
|
||||
MOVEMENTS = [
|
||||
"Mouse Up",
|
||||
"Mouse Down",
|
||||
|
@ -1083,7 +1096,7 @@ class MouseGesture(Condition):
|
|||
return {"MouseGesture": [str(m) for m in self.movements]}
|
||||
|
||||
|
||||
class Active(Condition):
|
||||
class Active(ConditionProtocol):
|
||||
def __init__(self, devID, warn=True):
|
||||
if not (isinstance(devID, str)):
|
||||
if warn:
|
||||
|
@ -1104,7 +1117,7 @@ class Active(Condition):
|
|||
return {"Active": self.devID}
|
||||
|
||||
|
||||
class Device(Condition):
|
||||
class Device(ConditionProtocol):
|
||||
def __init__(self, devID, warn=True):
|
||||
if not (isinstance(devID, str)):
|
||||
if warn:
|
||||
|
@ -1129,7 +1142,7 @@ class Device(Condition):
|
|||
return {"Device": self.devID}
|
||||
|
||||
|
||||
class Host(Condition):
|
||||
class Host(ConditionProtocol):
|
||||
def __init__(self, host, warn=True):
|
||||
if not (isinstance(host, str)):
|
||||
if warn:
|
||||
|
@ -1150,12 +1163,16 @@ class Host(Condition):
|
|||
return {"Host": self.host}
|
||||
|
||||
|
||||
class Action(RuleComponent):
|
||||
def __init__(self, *args):
|
||||
pass
|
||||
@typing.runtime_checkable
|
||||
class ActionProtocol(typing.Protocol):
|
||||
def __init__(self, args: Any, warn: bool) -> None:
|
||||
...
|
||||
|
||||
def evaluate(self, feature, notification: HIDPPNotification, device, last_result):
|
||||
return None
|
||||
def evaluate(self, feature, notification: HIDPPNotification, device, last_result) -> None:
|
||||
...
|
||||
|
||||
def data(self) -> dict[str, Any]:
|
||||
...
|
||||
|
||||
|
||||
def keysym_to_keycode(keysym, _modifiers) -> Tuple[int, int]: # maybe should take shift into account
|
||||
|
@ -1184,7 +1201,7 @@ def keysym_to_keycode(keysym, _modifiers) -> Tuple[int, int]: # maybe should ta
|
|||
return keycode, level
|
||||
|
||||
|
||||
class KeyPress(Action):
|
||||
class KeyPress(ActionProtocol):
|
||||
def __init__(self, args, warn=True):
|
||||
self.key_names, self.action = self.regularize_args(args)
|
||||
if not isinstance(self.key_names, list):
|
||||
|
@ -1274,7 +1291,7 @@ class KeyPress(Action):
|
|||
# super().keyUp(self.keys, current_key_modifiers)
|
||||
|
||||
|
||||
class MouseScroll(Action):
|
||||
class MouseScroll(ActionProtocol):
|
||||
def __init__(self, amounts, warn=True):
|
||||
if len(amounts) == 1 and isinstance(amounts[0], list):
|
||||
amounts = amounts[0]
|
||||
|
@ -1302,7 +1319,7 @@ class MouseScroll(Action):
|
|||
return {"MouseScroll": self.amounts[:]}
|
||||
|
||||
|
||||
class MouseClick(Action):
|
||||
class MouseClick(ActionProtocol):
|
||||
def __init__(self, args, warn=True):
|
||||
if len(args) == 1 and isinstance(args[0], list):
|
||||
args = args[0]
|
||||
|
@ -1341,7 +1358,7 @@ class MouseClick(Action):
|
|||
return {"MouseClick": [self.button, self.count]}
|
||||
|
||||
|
||||
class Set(Action):
|
||||
class Set(ActionProtocol):
|
||||
def __init__(self, args, warn=True):
|
||||
if not (isinstance(args, list) and len(args) > 2):
|
||||
if warn:
|
||||
|
@ -1387,7 +1404,7 @@ class Set(Action):
|
|||
return {"Set": self.args[:]}
|
||||
|
||||
|
||||
class Execute(Action):
|
||||
class Execute(ActionProtocol):
|
||||
def __init__(self, args, warn=True):
|
||||
if isinstance(args, str):
|
||||
args = [args]
|
||||
|
@ -1411,7 +1428,7 @@ class Execute(Action):
|
|||
return {"Execute": self.args[:]}
|
||||
|
||||
|
||||
class Later(Action):
|
||||
class Later(ActionProtocol):
|
||||
def __init__(self, args, warn=True):
|
||||
self.delay = 0
|
||||
self.rule = Rule([])
|
||||
|
@ -1446,7 +1463,7 @@ class Later(Action):
|
|||
return {"Later": data}
|
||||
|
||||
|
||||
COMPONENTS = {
|
||||
COMPONENTS: dict[str, Rule | ConditionProtocol | ActionProtocol] = {
|
||||
"Rule": Rule,
|
||||
"Not": Not,
|
||||
"Or": Or,
|
||||
|
|
|
@ -248,7 +248,9 @@ def _process_bluez_dbus(device: Device, path, dictionary: dict, signature):
|
|||
|
||||
def _cleanup_bluez_dbus(device: Device):
|
||||
"""Remove dbus signal receiver for device"""
|
||||
logger.info("bluez cleanup for %s", device)
|
||||
diversion_remove_inheritance
|
||||
if device and logger.isEnabledFor(logging.INFO):
|
||||
logger.info(f"bluez cleanup for {device}")
|
||||
dbus.watch_bluez_connect(device.hid_serial, None)
|
||||
|
||||
|
||||
|
|
|
@ -524,7 +524,7 @@ class ActionMenu:
|
|||
|
||||
wrapped = m[it][0]
|
||||
c = wrapped.component
|
||||
_rule_component_clipboard = diversion.RuleComponent().compile(c.data())
|
||||
_rule_component_clipboard = diversion.compile_component(c.data())
|
||||
|
||||
def menu_do_cut(self, _mitem, m, it):
|
||||
global _rule_component_clipboard
|
||||
|
@ -545,7 +545,7 @@ class ActionMenu:
|
|||
c = _rule_component_clipboard
|
||||
_rule_component_clipboard = None
|
||||
if c:
|
||||
_rule_component_clipboard = diversion.RuleComponent().compile(c.data())
|
||||
_rule_component_clipboard = diversion.compile_component(c.data())
|
||||
self._menu_do_insert(_mitem, m, it, new_c=c, below=below)
|
||||
self._on_update()
|
||||
|
||||
|
@ -1208,7 +1208,7 @@ class NotUI(RuleComponentUI):
|
|||
|
||||
|
||||
class ActionUI(RuleComponentUI):
|
||||
CLASS = diversion.Action
|
||||
CLASS = diversion.ActionProtocol
|
||||
|
||||
@classmethod
|
||||
def icon_name(cls):
|
||||
|
|
|
@ -36,7 +36,7 @@ class GtkSignal(Enum):
|
|||
|
||||
|
||||
class ActionUI(RuleComponentUI):
|
||||
CLASS = diversion.Action
|
||||
CLASS = diversion.ActionProtocol
|
||||
|
||||
@classmethod
|
||||
def icon_name(cls):
|
||||
|
|
|
@ -20,7 +20,6 @@ from typing import Any
|
|||
from typing import Callable
|
||||
|
||||
from gi.repository import Gtk
|
||||
from logitech_receiver import diversion
|
||||
|
||||
|
||||
def norm(s):
|
||||
|
@ -50,8 +49,6 @@ class CompletionEntry(Gtk.Entry):
|
|||
|
||||
|
||||
class RuleComponentUI(abc.ABC):
|
||||
CLASS = diversion.RuleComponent
|
||||
|
||||
def __init__(self, panel, on_update: Callable = None):
|
||||
self.panel = panel
|
||||
self.widgets = {} # widget -> coord. in grid
|
||||
|
@ -109,5 +106,5 @@ class RuleComponentUI(abc.ABC):
|
|||
for c in self.panel.get_children():
|
||||
self.panel.remove(c)
|
||||
|
||||
def update_devices(self): # noqa: B027
|
||||
pass
|
||||
def update_devices(self) -> None:
|
||||
return None
|
||||
|
|
|
@ -36,7 +36,7 @@ class GtkSignal(Enum):
|
|||
|
||||
|
||||
class ConditionUI(RuleComponentUI):
|
||||
CLASS = diversion.Condition
|
||||
CLASS = diversion.ConditionProtocol
|
||||
|
||||
@classmethod
|
||||
def icon_name(cls):
|
||||
|
|
Loading…
Reference in New Issue