class ControlButton(PyQt5.QtWidgets.QLabel): def __init__(self, image, height, callback, parent=None): super(ControlButton, self).__init__(parent) self._signal = Observer() self._signal.subscribe(callback) pixmap = PyQt5.QtGui.QPixmap(image) self.setPixmap(pixmap.scaledToHeight(height)) def onMouseRelease(self, _): self._signal.notify()
def test_reset_removes_any_subscribers(self): observer = Observer() callback = mock.Mock() observer.subscribe(callback) observer.reset() observer.notify() callback.assert_not_called()
class TextSetting(LineEdit): def __init__(self, label="", parent=None): super(TextSetting, self).__init__(label, parent) self._signal = Observer() def get_value(self): return self.text() def connect(self, function): self._signal.subscribe(function) def focusInEvent(self, e): super(TextSetting, self).focusInEvent(e) self._signal.notify(self.mapToGlobal(PyQt5.QtCore.QPoint(0, 0)).y())
def test_can_notify_multiple_objects(self): observer = Observer() callback1 = mock.Mock() observer.subscribe(callback1) callback2 = mock.Mock() observer.subscribe(callback2) observer.notify() callback1.assert_called() callback2.assert_called()
class PlayerSettings(Settings): _signal = Observer() _settings = {} _options = { "Volume": OptionMetadata(o_type="select", options=list(range(100)), default=40), "Cross Fade": OptionMetadata(o_type="toggle", options=None, default=False), "Gapless": OptionMetadata(o_type="toggle", options=None, default=False), "Normalise Volume": OptionMetadata(o_type="toggle", options=None, default=True), }
class GeneralSettings(Settings): _signal = Observer() _settings = {} _options = { "Brightness": OptionMetadata( o_type="select", options=list(range(1, 101)), default=19 ), "Theme": OptionMetadata(o_type="select", options=["Dark", "Light"], default=0), }
class WeatherSettings(Settings): _signal = Observer() _settings = {} _options = { "Api": OptionMetadata(o_type="select", options=["Darksky"], default=0), "Api Key": OptionMetadata(o_type="text", options=None, default="",), "Home Weather": OptionMetadata( o_type="select", options=["Hourly", "Three hourly", "Daily"], default=1, ), }
class AlarmSettings(Settings): _signal = Observer() _settings = {} _options = { "No. of Snoozes": OptionMetadata( o_type="select", options=list(range(10)), default=5 ), "Snooze Time": OptionMetadata( o_type="select", options=list(range(1, 30)), default=9 ), "Alarms": OptionMetadata(o_type="none", options=None, default=[]), }
class LightSettings(Settings): _signal = Observer() _settings = {} _options = { "Warm": OptionMetadata(o_type="colour", options=[], default=[255, 140, 50]), "Custom1": OptionMetadata(o_type="colour", options=[], default=[0, 0, 0]), "Custom2": OptionMetadata(o_type="colour", options=[], default=[0, 0, 0]), "Custom3": OptionMetadata(o_type="colour", options=[], default=[0, 0, 0]), "Main Light Colour": OptionMetadata( o_type="select", options=["Warm", "Custom1", "Custom2", "Custom3"], default=0, ), }
def test_can_pass_arguments_to_objects(self): observer = Observer() callback = mock.Mock() observer.subscribe(callback) observer.notify("0000") arg_list = callback.call_args[0] # This is because we are using args and kwargs expected = ("0000", ) self.assertEqual(arg_list, expected)
def test_throws_error_if_object_expects_different_arguments_to_notify( self): observer = Observer() observer.subscribe(lambda arg1, arg2: print(arg1, arg2)) self.assertRaises(ValueError, observer.notify, "0000")
def test_callback_called_by_notify(self): observer = Observer() callback = mock.Mock() observer.subscribe(callback) observer.notify() callback.assert_called()
class AlarmJob(Job): _local_complete = Observer()
def __init__(self, label="", parent=None): super(TextSetting, self).__init__(label, parent) self._signal = Observer()
class Settings: _signal = Observer() _options = {} def __init__(self, settings): self._settings = self._process_settings(settings) def get_settings(self): return self._settings.copy() def update_setting(self, setting, value, emit=True): if setting in self._settings: if self._validate_new_setting(setting, value): self._settings[setting] = value if emit: self._signal.notify(setting, value) else: raise ValueError("Setting not an acceptable value") else: raise ValueError("The setting, " + setting + ", does not exist") def get_setting_options(self, setting): return self._options[setting] @classmethod def connect(cls, func): cls._signal.subscribe(func) def emit_all(self): for setting, value in self._settings.items(): self._signal.notify(setting, value) def _process_settings(self, settings): return { key: settings.get(key, self._get_default(value)) for key, value in self._options.items() } def _get_default(self, setting): if setting.o_type == "select": return setting.options[setting.default] else: return setting.default def _validate_new_setting(self, setting, value): option = self._options[setting] if option.o_type == "select": return value in option.options elif option.o_type == "toggle": return value == True or value == False elif option.o_type == "text": return isinstance(value, str) elif option.o_type == "colour": return ( isinstance(value, list) and len(value) == 3 and value[0] in range(256) and value[1] in range(256) and value[2] in range(256) ) return True
def test_throws_if_callback_not_callable(self): observer = Observer() self.assertRaises(ValueError, observer.subscribe, "Hello")
class Keyboard(PyQt5.QtWidgets.QDockWidget): _signal = Observer() def __init__(self, parent=None): super(Keyboard, self).__init__(parent) self.setFeatures(PyQt5.QtWidgets.QDockWidget.NoDockWidgetFeatures) self._key_values = [ [ CharKey("q", "0"), CharKey("w", "1"), CharKey("e", "2"), CharKey("r", "3"), CharKey("t", "4"), CharKey("y", "5"), CharKey("u", "6"), CharKey("i", "7"), CharKey("o", "8"), CharKey("p", "9"), ], [ CharKey("a", "@"), CharKey("s", "#"), CharKey("e", "£"), CharKey("f", "_"), CharKey("g", "&"), CharKey("h", "-"), CharKey("j", "+"), CharKey("k", "("), CharKey("l", ")"), ], [ ShiftKey(), CharKey("z", '"'), CharKey("x", ":"), CharKey("c", ";"), CharKey("v", "!"), CharKey("b", "?"), CharKey("n", "="), CharKey("m", "%"), DeleteKey(), ], [ AltKey(), CharKey("/", "\\"), SpaceKey(), CharKey(".", ","), CloseKey() ], ] v_widget = PyQt5.QtWidgets.QWidget() self.setWidget(v_widget) v_layout = PyQt5.QtWidgets.QVBoxLayout(v_widget) v_layout.addStretch() for row in self._key_values: row_widget = PyQt5.QtWidgets.QWidget() row_layout = PyQt5.QtWidgets.QHBoxLayout() row_widget.setLayout(row_layout) row_layout.addStretch() for key in row: row_layout.addWidget(key) if (isinstance(key, CharKey) or isinstance(key, DeleteKey) or isinstance(key, SpaceKey)): key.connect(self._emit) elif isinstance(key, ShiftKey): key.connect(self._shift_event) elif isinstance(key, AltKey): key.connect(self._alt_event) elif isinstance(key, CloseKey): key.connect(self.close) row_layout.addStretch() v_layout.addWidget(row_widget) v_layout.addStretch() def connect(self, function): self._signal.subscribe(function) def reset(self): self._signal.reset() def _emit(self, key): self.findChild(ShiftKey).unshift() self._shift_event() self._signal.notify(key) def _shift_event(self): caps = self.findChild(ShiftKey).is_capitalised() for key in self.findChildren(CharKey): key.capitalise(caps) def _alt_event(self): self.findChild(ShiftKey).unshift(True) for key in self.findChildren(CharKey): key.toggle_alt()
def __init__(self, image, height, callback, parent=None): super(ControlButton, self).__init__(parent) self._signal = Observer() self._signal.subscribe(callback) pixmap = PyQt5.QtGui.QPixmap(image) self.setPixmap(pixmap.scaledToHeight(height))