IS-Matrix-Forge 1.0.0.dev7__tar.gz → 1.0.0.dev9__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/PKG-INFO +5 -1
- is_matrix_forge-1.0.0.dev9/is_matrix_forge/Untitled.ipynb +109 -0
- is_matrix_forge-1.0.0.dev9/is_matrix_forge/assets/digit_map.py +82 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/designer_gui/main_window/__init__.py +48 -2
- is_matrix_forge-1.0.0.dev9/is_matrix_forge/designer_gui/main_window/layout/menu_bar.py +43 -0
- is_matrix_forge-1.0.0.dev9/is_matrix_forge/led_matrix/Scripts/pixel_grid.py +27 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/led_matrix/controller/controller.py +77 -10
- is_matrix_forge-1.0.0.dev9/is_matrix_forge/led_matrix/controller/helpers/__init__.py +45 -0
- is_matrix_forge-1.0.0.dev9/is_matrix_forge/led_matrix/controller/helpers/threading.py +67 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/led_matrix/display/animations/animation.py +0 -1
- is_matrix_forge-1.0.0.dev9/is_matrix_forge/led_matrix/display/animations/font/font.py +2 -0
- is_matrix_forge-1.0.0.dev9/is_matrix_forge/led_matrix/display/assets/__init__.py +2 -0
- {is_matrix_forge-1.0.0.dev7/is_matrix_forge/led_matrix → is_matrix_forge-1.0.0.dev9/is_matrix_forge/led_matrix/display/assets}/fonts.py +2 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/led_matrix/display/effects/breather.py +34 -13
- is_matrix_forge-1.0.0.dev9/is_matrix_forge/led_matrix/display/grid/composite/__init__.py +13 -0
- is_matrix_forge-1.0.0.dev9/is_matrix_forge/led_matrix/display/grid/composite/background.py +11 -0
- is_matrix_forge-1.0.0.dev9/is_matrix_forge/led_matrix/display/grid/composite/composite.py +91 -0
- is_matrix_forge-1.0.0.dev9/is_matrix_forge/led_matrix/display/grid/composite/foreground.py +53 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/led_matrix/display/grid/grid.py +21 -5
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/led_matrix/display/helpers/columns.py +9 -3
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/led_matrix/display/patterns/built_in/__init__.py +1 -1
- is_matrix_forge-1.0.0.dev9/is_matrix_forge/led_matrix/display/patterns/built_in/stencils/__init__.py +69 -0
- is_matrix_forge-1.0.0.dev9/is_matrix_forge/led_matrix/display/scene/__init__.py +17 -0
- is_matrix_forge-1.0.0.dev9/is_matrix_forge/led_matrix/display/scene/errors.py +12 -0
- is_matrix_forge-1.0.0.dev9/is_matrix_forge/led_matrix/display/scene/scene.py +93 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/led_matrix/display/text/__init__.py +1 -1
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/led_matrix/display/text/scroller.py +0 -2
- is_matrix_forge-1.0.0.dev9/is_matrix_forge/led_matrix/errors/composite_grid.py +1 -0
- is_matrix_forge-1.0.0.dev7/is_matrix_forge/led_matrix/helpers/device.py → is_matrix_forge-1.0.0.dev9/is_matrix_forge/led_matrix/helpers/device/__init__.py +28 -0
- is_matrix_forge-1.0.0.dev9/is_matrix_forge/led_matrix/helpers/device/bootloader/__init__.py +47 -0
- is_matrix_forge-1.0.0.dev9/is_matrix_forge/led_matrix/helpers/device/bootloader/constants.py +3 -0
- is_matrix_forge-1.0.0.dev9/is_matrix_forge/led_matrix/helpers/device/bootloader/unix.py +33 -0
- is_matrix_forge-1.0.0.dev9/is_matrix_forge/led_matrix/helpers/device/bootloader/win.py +44 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/pyproject.toml +6 -2
- is_matrix_forge-1.0.0.dev7/is_matrix_forge/led_matrix/controller/helpers/__init__.py +0 -7
- is_matrix_forge-1.0.0.dev7/is_matrix_forge/led_matrix/controller/helpers/threading.py +0 -41
- is_matrix_forge-1.0.0.dev7/is_matrix_forge/led_matrix/display/animations/font/font.py +0 -4
- is_matrix_forge-1.0.0.dev7/is_matrix_forge/led_matrix/display/patterns/built_in/stencils/__init__.py +0 -70
- is_matrix_forge-1.0.0.dev7/is_matrix_forge/led_matrix/helpers/core/__init__.py +0 -17
- is_matrix_forge-1.0.0.dev7/is_matrix_forge/led_matrix/helpers/core/lazy_mod_load.py +0 -84
- is_matrix_forge-1.0.0.dev7/is_matrix_forge/led_matrix/helpers/stream/__init__.py +0 -70
- is_matrix_forge-1.0.0.dev7/is_matrix_forge/led_matrix/helpers/stream/errors.py +0 -17
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/LICENSE.md +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/README.md +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/__init__.py +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/assets/__init__.py +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/assets/audio/__init__.py +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/assets/audio/files/__init__.py +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/assets/audio/files/plugged.wav +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/assets/audio/files/unplugged.wav +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/assets/char_map.json +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/assets/font_map.py +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/common/__init__.py +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/common/decorators/__init__.py +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/common/decorators/freeze_setter.py +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/common/dirs.py +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/common/helpers/__init__.py +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/common/helpers/github_api.py +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/designer_gui/__init__.py +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/designer_gui/main_window/layout/__init__.py +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/designer_gui/main_window/layout/button_grid/__init__.py +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/designer_gui/main_window/layout/button_grid/column.py +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/designer_gui/main_window/layout/button_grid/grid.py +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/designer_gui/main_window/streamlit_app.py +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/dev_tools/__init__.py +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/dev_tools/debug.py +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/dev_tools/presets.py +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/inputmodule/__init__.py +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/inputmodule/b1display.py +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/inputmodule/c1minimal.py +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/inputmodule/font.py +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/inputmodule/helpers/__init__.py +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/inputmodule/ledmatrix.py +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/led_matrix/Scripts/__init__.py +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/led_matrix/Scripts/battery_monitor.py +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/led_matrix/Scripts/identify_matrices.py +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/led_matrix/Scripts/install_presets/__init__.py +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/led_matrix/Scripts/install_presets/arguments.py +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/led_matrix/Scripts/install_presets/main.py +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/led_matrix/__init__.py +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/led_matrix/commands/__init__.py +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/led_matrix/commands/map.py +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/led_matrix/constants.py +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/led_matrix/controller/__init__.py +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/led_matrix/controller/multiton.py +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/led_matrix/controller/threaded.py +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/led_matrix/display/__init__.py +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/led_matrix/display/animations/__init__.py +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/led_matrix/display/animations/audio_visualizer.py +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/led_matrix/display/animations/effects/__init__.py +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/led_matrix/display/animations/errors.py +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/led_matrix/display/animations/font/__init__.py +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/led_matrix/display/animations/font/map_builder.py +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/led_matrix/display/animations/frame/__init__.py +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/led_matrix/display/animations/frame/base.py +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/led_matrix/display/animations/frame/helpers.py +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/led_matrix/display/animations/keep_awake.py +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/led_matrix/display/animations/plugged.py +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/led_matrix/display/animations/text_scroller.py +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/led_matrix/display/effects/__init__.py +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/led_matrix/display/effects/fade.py +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/led_matrix/display/effects/scroller/__init__.py +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/led_matrix/display/effects/scroller/base.py +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/led_matrix/display/effects/scroller/helpers.py +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/led_matrix/display/grid/__init__.py +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/led_matrix/display/grid/helpers.py +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/led_matrix/display/grid/presets/__init__.py +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/led_matrix/display/grid/presets/manifest.py +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/led_matrix/display/helpers/__init__.py +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/led_matrix/display/media.py +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/led_matrix/display/patterns/built_in/commands.py +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/led_matrix/display/patterns/built_in/constants.py +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/led_matrix/display/patterns/built_in/stencils/res.py +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/led_matrix/errors/__init__.py +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/led_matrix/errors/base.py +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/led_matrix/errors/grid.py +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/led_matrix/errors/matrix.py +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/led_matrix/errors/misc.py +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/led_matrix/hardware.py +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/led_matrix/helpers/__init__.py +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/led_matrix/helpers/status_handler.py +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/led_matrix/led_matrix.py +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/led_matrix/status.py +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/led_matrix/tools/__init__.py +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/led_matrix/tools/identify.py +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/led_matrix/utils/__init__.py +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/log_engine.py +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/monitor/__init__.py +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/monitor/errors.py +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/monitor/events.py +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/monitor/gui/__init__.py +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/monitor/gui/errors.py +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/monitor/gui/event/__init__.py +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/monitor/gui/event/collection.py +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/monitor/gui/event/errors.py +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/monitor/gui/event/event.py +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/monitor/gui/layout/__init__.py +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/monitor/gui/layout/base.py +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/monitor/gui/metaclasses/__init__.py +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/monitor/gui/windows/__init__.py +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/monitor/gui/windows/base.py +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/monitor/gui/windows/main/__init__.py +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/monitor/gui/windows/main/layout.py +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/monitor/helpers.py +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/monitor/monitor.py +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/notify/__init__.py +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/notify/sounds/__init__.py +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/notify/sounds/base.py +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/progress.py +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/scripts/__init__.py +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/scripts/preset_installer.py +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/serial_com/__init__.py +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/serial_com/base/__init__.py +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/serial_com/base/answer.py +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/serial_com/base/message.py +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/serial_com/base/request.py +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/is_matrix_forge/serial_com/exchange.py +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/presets/blank.json +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/presets/manifest.json +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/presets/shock_face.json +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/presets/test1.json +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/presets/test2.json +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/presets/test3.json +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/presets/test4.json +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/presets/test5.json +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/presets/test6.json +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/presets/test7.json +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/presets/x_animation II.json +0 -0
- {is_matrix_forge-1.0.0.dev7 → is_matrix_forge-1.0.0.dev9}/presets/x_animation.json +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: IS-Matrix-Forge
|
|
3
|
-
Version: 1.0.0.
|
|
3
|
+
Version: 1.0.0.dev9
|
|
4
4
|
Summary:
|
|
5
5
|
License: MIT
|
|
6
6
|
Keywords: led,matrix,framework,hardware
|
|
@@ -19,12 +19,16 @@ Requires-Dist: easy-exit-calls (>=1.0.0.dev1,<2.0.0)
|
|
|
19
19
|
Requires-Dist: imapclient (==3.0.1)
|
|
20
20
|
Requires-Dist: inspy-logger (>=3.2.3,<4.0.0)
|
|
21
21
|
Requires-Dist: inspyre-toolbox (>=1.6.0.dev23)
|
|
22
|
+
Requires-Dist: ipywidgets (==8.1.7)
|
|
23
|
+
Requires-Dist: notebook (>=7.4.4,<8.0.0)
|
|
22
24
|
Requires-Dist: opencv-python (>=4.11.0.86,<5.0.0.0)
|
|
23
25
|
Requires-Dist: pillow (>=11.2.1,<12.0.0)
|
|
26
|
+
Requires-Dist: psutil (==6.1.1)
|
|
24
27
|
Requires-Dist: pyserial (>=3.5,<4.0)
|
|
25
28
|
Requires-Dist: pysimplegui-4-foss (==4.60.4.1)
|
|
26
29
|
Requires-Dist: pysimpleguiweb (==0.39.0)
|
|
27
30
|
Requires-Dist: requests (>=2.32.4,<3.0.0)
|
|
31
|
+
Requires-Dist: wmi (>=1.5.1,<2.0.0)
|
|
28
32
|
Project-URL: Homepage, https://github.com/Inspyre-Softworks/IS-Matrix-Forge
|
|
29
33
|
Project-URL: Repository, https://github.com/Inspyre-Softworks/IS-Matrix-Forge
|
|
30
34
|
Description-Content-Type: text/markdown
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
{
|
|
2
|
+
"cells": [
|
|
3
|
+
{
|
|
4
|
+
"cell_type": "code",
|
|
5
|
+
"execution_count": 5,
|
|
6
|
+
"id": "a6d553a0-fca1-411a-a7bd-cf15dce52e97",
|
|
7
|
+
"metadata": {},
|
|
8
|
+
"outputs": [
|
|
9
|
+
{
|
|
10
|
+
"data": {
|
|
11
|
+
"application/vnd.jupyter.widget-view+json": {
|
|
12
|
+
"model_id": "a9c234aa78a641018ba78e54e9a3755b",
|
|
13
|
+
"version_major": 2,
|
|
14
|
+
"version_minor": 0
|
|
15
|
+
},
|
|
16
|
+
"text/plain": [
|
|
17
|
+
"VBox(children=(Dropdown(description='Pick a pattern to render...', options=('All LEDs on', 'Gradient (0-13% Br…"
|
|
18
|
+
]
|
|
19
|
+
},
|
|
20
|
+
"metadata": {},
|
|
21
|
+
"output_type": "display_data"
|
|
22
|
+
}
|
|
23
|
+
],
|
|
24
|
+
"source": [
|
|
25
|
+
"from is_matrix_forge.led_matrix import get_controllers\n",
|
|
26
|
+
"import ipywidgets as widgets\n",
|
|
27
|
+
"CONTROLLERS = get_controllers(threaded = True)\n",
|
|
28
|
+
"PATTERNS = CONTROLLERS[0].built_in_pattern_names\n",
|
|
29
|
+
"\n",
|
|
30
|
+
"\n",
|
|
31
|
+
"class DropdownWithButton:\n",
|
|
32
|
+
" def __init__(self, options, description='Choose:', button_desc='Run', callback=None):\n",
|
|
33
|
+
" self.output = widgets.Output()\n",
|
|
34
|
+
" self.dropdown = widgets.Dropdown(\n",
|
|
35
|
+
" options=options, description=description, disabled=False\n",
|
|
36
|
+
" )\n",
|
|
37
|
+
" self.button = widgets.Button(\n",
|
|
38
|
+
" description=button_desc, disabled=True, button_style='primary'\n",
|
|
39
|
+
" )\n",
|
|
40
|
+
" self.callback = callback or self.default_callback\n",
|
|
41
|
+
"\n",
|
|
42
|
+
" # Set up observers\n",
|
|
43
|
+
" self.dropdown.observe(self._on_select, names='value')\n",
|
|
44
|
+
" self.button.on_click(self._on_click)\n",
|
|
45
|
+
"\n",
|
|
46
|
+
" # Layout\n",
|
|
47
|
+
" self.container = widgets.VBox([self.dropdown, self.button, self.output])\n",
|
|
48
|
+
" display(self.container)\n",
|
|
49
|
+
"\n",
|
|
50
|
+
" def _on_select(self, change):\n",
|
|
51
|
+
" self.button.disabled = False # Enable button once a selection is made\n",
|
|
52
|
+
"\n",
|
|
53
|
+
" def _on_click(self, b):\n",
|
|
54
|
+
" with self.output:\n",
|
|
55
|
+
" # Clear prior output\n",
|
|
56
|
+
" self.output.clear_output()\n",
|
|
57
|
+
" self.callback(self.dropdown.value)\n",
|
|
58
|
+
"\n",
|
|
59
|
+
" @staticmethod\n",
|
|
60
|
+
" def default_callback(value):\n",
|
|
61
|
+
" print(f\"You selected: {value}\")\n",
|
|
62
|
+
"\n",
|
|
63
|
+
"\n",
|
|
64
|
+
"\n",
|
|
65
|
+
"def render(selection):\n",
|
|
66
|
+
" CONTROLLERS[0].draw_pattern(selection)\n",
|
|
67
|
+
"\n",
|
|
68
|
+
"\n",
|
|
69
|
+
"\n",
|
|
70
|
+
"drp_bttn = DropdownWithButton(\n",
|
|
71
|
+
" options=PATTERNS,\n",
|
|
72
|
+
" description='Pick a pattern to render...',\n",
|
|
73
|
+
" button_desc='Render',\n",
|
|
74
|
+
" callback=render\n",
|
|
75
|
+
"\n",
|
|
76
|
+
")\n"
|
|
77
|
+
]
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
"cell_type": "code",
|
|
81
|
+
"execution_count": null,
|
|
82
|
+
"id": "8533a241-ef3b-4a44-99cd-2e88cabb9fbb",
|
|
83
|
+
"metadata": {},
|
|
84
|
+
"outputs": [],
|
|
85
|
+
"source": []
|
|
86
|
+
}
|
|
87
|
+
],
|
|
88
|
+
"metadata": {
|
|
89
|
+
"kernelspec": {
|
|
90
|
+
"display_name": "Python 3 (ipykernel)",
|
|
91
|
+
"language": "python",
|
|
92
|
+
"name": "python3"
|
|
93
|
+
},
|
|
94
|
+
"language_info": {
|
|
95
|
+
"codemirror_mode": {
|
|
96
|
+
"name": "ipython",
|
|
97
|
+
"version": 3
|
|
98
|
+
},
|
|
99
|
+
"file_extension": ".py",
|
|
100
|
+
"mimetype": "text/x-python",
|
|
101
|
+
"name": "python",
|
|
102
|
+
"nbconvert_exporter": "python",
|
|
103
|
+
"pygments_lexer": "ipython3",
|
|
104
|
+
"version": "3.12.10"
|
|
105
|
+
}
|
|
106
|
+
},
|
|
107
|
+
"nbformat": 4,
|
|
108
|
+
"nbformat_minor": 5
|
|
109
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Contains the pixel representation of the ld states within a 3x5 grid.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
DIGITS = {
|
|
7
|
+
"0": [
|
|
8
|
+
[1, 1, 1],
|
|
9
|
+
[1, 0, 1],
|
|
10
|
+
[1, 0, 1],
|
|
11
|
+
[1, 0, 1],
|
|
12
|
+
[1, 1, 1],
|
|
13
|
+
],
|
|
14
|
+
"1": [
|
|
15
|
+
[0, 1, 0],
|
|
16
|
+
[1, 1, 0],
|
|
17
|
+
[0, 1, 0],
|
|
18
|
+
[0, 1, 0],
|
|
19
|
+
[1, 1, 1],
|
|
20
|
+
],
|
|
21
|
+
"2": [
|
|
22
|
+
[1, 1, 1],
|
|
23
|
+
[0, 0, 1],
|
|
24
|
+
[1, 1, 1],
|
|
25
|
+
[1, 0, 0],
|
|
26
|
+
[1, 1, 1],
|
|
27
|
+
],
|
|
28
|
+
"3": [
|
|
29
|
+
[1, 1, 1],
|
|
30
|
+
[0, 0, 1],
|
|
31
|
+
[1, 1, 1],
|
|
32
|
+
[0, 0, 1],
|
|
33
|
+
[1, 1, 1],
|
|
34
|
+
],
|
|
35
|
+
"4": [
|
|
36
|
+
[1, 0, 1],
|
|
37
|
+
[1, 0, 1],
|
|
38
|
+
[1, 1, 1],
|
|
39
|
+
[0, 0, 1],
|
|
40
|
+
[0, 0, 1],
|
|
41
|
+
],
|
|
42
|
+
"5": [
|
|
43
|
+
[1, 1, 1],
|
|
44
|
+
[1, 0, 0],
|
|
45
|
+
[1, 1, 1],
|
|
46
|
+
[0, 0, 1],
|
|
47
|
+
[1, 1, 1],
|
|
48
|
+
],
|
|
49
|
+
"6": [
|
|
50
|
+
[1, 1, 1],
|
|
51
|
+
[1, 0, 0],
|
|
52
|
+
[1, 1, 1],
|
|
53
|
+
[1, 0, 1],
|
|
54
|
+
[1, 1, 1],
|
|
55
|
+
],
|
|
56
|
+
"7": [
|
|
57
|
+
[1, 1, 1],
|
|
58
|
+
[0, 0, 1],
|
|
59
|
+
[0, 0, 1],
|
|
60
|
+
[0, 0, 1],
|
|
61
|
+
[0, 0, 1],
|
|
62
|
+
],
|
|
63
|
+
"8": [
|
|
64
|
+
[1, 1, 1],
|
|
65
|
+
[1, 0, 1],
|
|
66
|
+
[1, 1, 1],
|
|
67
|
+
[1, 0, 1],
|
|
68
|
+
[1, 1, 1],
|
|
69
|
+
],
|
|
70
|
+
"9": [
|
|
71
|
+
[1, 1, 1],
|
|
72
|
+
[1, 0, 1],
|
|
73
|
+
[1, 1, 1],
|
|
74
|
+
[0, 0, 1],
|
|
75
|
+
[1, 1, 1],
|
|
76
|
+
],
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
__all__ = [
|
|
81
|
+
'DIGITS'
|
|
82
|
+
]
|
|
@@ -46,7 +46,7 @@ class PixelGrid:
|
|
|
46
46
|
self.preferred_device = None
|
|
47
47
|
|
|
48
48
|
layout = PixelGridLayout(self.width, self.height).build()
|
|
49
|
-
self.window = sg.Window('Pixel Grid', layout, finalize=True)
|
|
49
|
+
self.window = sg.Window('Pixel Grid', layout, finalize=True, resizable=True)
|
|
50
50
|
self._init_button_colors()
|
|
51
51
|
self._update_frame_indicator()
|
|
52
52
|
|
|
@@ -86,16 +86,44 @@ class PixelGrid:
|
|
|
86
86
|
|
|
87
87
|
@current_frame.setter
|
|
88
88
|
def current_frame(self, value: Any) -> None:
|
|
89
|
+
"""
|
|
90
|
+
Setter indicating which frame index to display..
|
|
91
|
+
|
|
92
|
+
Note:
|
|
93
|
+
Must be an integer between 0 and len(frames) - 1.
|
|
94
|
+
"""
|
|
89
95
|
if not isinstance(value, int) or not (0 <= value < len(self.frames)):
|
|
90
96
|
raise ValueError("current_frame must be an index into frames list")
|
|
91
97
|
self.__current_frame = value
|
|
92
98
|
|
|
93
99
|
@property
|
|
94
100
|
def grid(self) -> List[List[int]]:
|
|
101
|
+
"""
|
|
102
|
+
A column-major 0/1 list representing the pixel grid.
|
|
103
|
+
"""
|
|
95
104
|
return self.__grid
|
|
96
105
|
|
|
97
106
|
@grid.setter
|
|
98
107
|
def grid(self, value: Any) -> None:
|
|
108
|
+
"""
|
|
109
|
+
Setter for the grid data.
|
|
110
|
+
|
|
111
|
+
Note:
|
|
112
|
+
A valid grid is structured as follows:
|
|
113
|
+
- Must be a list
|
|
114
|
+
- Containing 9 lists
|
|
115
|
+
- Each list:
|
|
116
|
+
- Must be the same length
|
|
117
|
+
- Each item:
|
|
118
|
+
- Integer
|
|
119
|
+
- 0-1
|
|
120
|
+
|
|
121
|
+
Example:
|
|
122
|
+
Framework Laptop 9x34:
|
|
123
|
+
- 9 lists
|
|
124
|
+
- each with 34 items
|
|
125
|
+
- 0-1
|
|
126
|
+
"""
|
|
99
127
|
if not is_valid_grid(value, self.width, self.height):
|
|
100
128
|
raise ValueError("Grid must match width/height and be 0/1 values")
|
|
101
129
|
self.__grid = value
|
|
@@ -105,6 +133,9 @@ class PixelGrid:
|
|
|
105
133
|
|
|
106
134
|
@property
|
|
107
135
|
def preferred_device(self):
|
|
136
|
+
"""
|
|
137
|
+
The device we want to send the grid to.
|
|
138
|
+
"""
|
|
108
139
|
return self.__preferred_device
|
|
109
140
|
|
|
110
141
|
@preferred_device.setter
|
|
@@ -128,6 +159,9 @@ class PixelGrid:
|
|
|
128
159
|
)
|
|
129
160
|
|
|
130
161
|
def run(self) -> None:
|
|
162
|
+
"""
|
|
163
|
+
Run the UI.
|
|
164
|
+
"""
|
|
131
165
|
while True:
|
|
132
166
|
event, _ = self.window.read()
|
|
133
167
|
if event in (sg.WINDOW_CLOSED, 'Exit'):
|
|
@@ -152,6 +186,9 @@ class PixelGrid:
|
|
|
152
186
|
|
|
153
187
|
# Frame management
|
|
154
188
|
def add_frame(self) -> None:
|
|
189
|
+
"""
|
|
190
|
+
Add a new frame to the grid.
|
|
191
|
+
"""
|
|
155
192
|
new_grid = copy.deepcopy(self.grid)
|
|
156
193
|
frm = Frame(new_grid)
|
|
157
194
|
self.frames = self.frames + [frm]
|
|
@@ -161,6 +198,11 @@ class PixelGrid:
|
|
|
161
198
|
self._update_frame_indicator()
|
|
162
199
|
|
|
163
200
|
def prev_frame(self) -> None:
|
|
201
|
+
"""
|
|
202
|
+
Go back one frame.
|
|
203
|
+
|
|
204
|
+
Show the frame that's before the current one.
|
|
205
|
+
"""
|
|
164
206
|
if self.current_frame > 0:
|
|
165
207
|
self.current_frame -= 1
|
|
166
208
|
self._load_frame()
|
|
@@ -256,5 +298,9 @@ class PixelGrid:
|
|
|
256
298
|
return is_valid_grid(grid, self.width, self.height)
|
|
257
299
|
|
|
258
300
|
|
|
259
|
-
|
|
301
|
+
def main():
|
|
260
302
|
PixelGrid().run()
|
|
303
|
+
|
|
304
|
+
|
|
305
|
+
if __name__ == '__main__':
|
|
306
|
+
main()
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import PySimpleGUI as sg
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
MENU_DEF = [
|
|
5
|
+
['File', [
|
|
6
|
+
'Export',
|
|
7
|
+
'Export to File',
|
|
8
|
+
'Load from File',
|
|
9
|
+
'---',
|
|
10
|
+
'Exit'
|
|
11
|
+
]],
|
|
12
|
+
['Matrix', [
|
|
13
|
+
'Send to Matrix'
|
|
14
|
+
]],
|
|
15
|
+
['Frame', [
|
|
16
|
+
'Add Frame'
|
|
17
|
+
]]
|
|
18
|
+
]
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class MenuBar:
|
|
22
|
+
def __init__(self):
|
|
23
|
+
self.__layout = None
|
|
24
|
+
self.__menu_bar = None
|
|
25
|
+
|
|
26
|
+
@property
|
|
27
|
+
def is_built(self):
|
|
28
|
+
return self.__layout is not None and self.__menu_bar is not None
|
|
29
|
+
|
|
30
|
+
@property
|
|
31
|
+
def layout(self):
|
|
32
|
+
return self.__layout
|
|
33
|
+
|
|
34
|
+
@property
|
|
35
|
+
def menu_bar(self):
|
|
36
|
+
return self.__menu_bar
|
|
37
|
+
|
|
38
|
+
def build(self):
|
|
39
|
+
if self.__layout is not None and self.menu_bar is not None:
|
|
40
|
+
return [self.menu_bar, [sg.VPush()], *self.__layout]
|
|
41
|
+
raise RuntimeError("Menu bar or layout is not defined.")
|
|
42
|
+
|
|
43
|
+
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Author:
|
|
3
|
+
Inspyre Softworks
|
|
4
|
+
|
|
5
|
+
Project:
|
|
6
|
+
IS-Matrix-Forge
|
|
7
|
+
|
|
8
|
+
File:
|
|
9
|
+
is_matrix_forge/led_matrix/Scripts/pixel_grid.py
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
Description:
|
|
13
|
+
Entry point for the pixel grid designer GUI.
|
|
14
|
+
"""
|
|
15
|
+
from is_matrix_forge.designer_gui.main_window import PixelGrid
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def main():
|
|
19
|
+
"""
|
|
20
|
+
Entry point for the pixel grid designer GUI.
|
|
21
|
+
"""
|
|
22
|
+
PixelGrid().run()
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
if __name__ == "__main__":
|
|
26
|
+
main()
|
|
27
|
+
|
|
@@ -22,14 +22,13 @@ from time import sleep
|
|
|
22
22
|
from typing import Optional, Dict, Any, Union, List
|
|
23
23
|
|
|
24
24
|
from inspyre_toolbox.syntactic_sweets.classes import validate_type
|
|
25
|
-
from inspyre_toolbox.syntactic_sweets.classes.decorators.aliases import
|
|
25
|
+
from inspyre_toolbox.syntactic_sweets.classes.decorators.aliases import method_alias
|
|
26
26
|
from serial.tools.list_ports_common import ListPortInfo
|
|
27
27
|
|
|
28
28
|
from is_matrix_forge.common.helpers import coerce_to_int
|
|
29
29
|
from aliaser.metaclass import AliasMeta
|
|
30
30
|
from is_matrix_forge.led_matrix.constants import SLOT_MAP
|
|
31
31
|
from is_matrix_forge.led_matrix.display.text import show_string as _show_string_raw
|
|
32
|
-
from is_matrix_forge.led_matrix.controller import MultitonMeta
|
|
33
32
|
from is_matrix_forge.led_matrix.controller.helpers.threading import synchronized
|
|
34
33
|
from is_matrix_forge.led_matrix.commands.map import CommandVals
|
|
35
34
|
from is_matrix_forge.led_matrix.hardware import send_command
|
|
@@ -39,6 +38,30 @@ from is_matrix_forge.led_matrix.display.text import show_string
|
|
|
39
38
|
COMMANDS = CommandVals
|
|
40
39
|
|
|
41
40
|
|
|
41
|
+
class _BreatherPauseCtx:
|
|
42
|
+
def __init__(self, controller: LEDMatrixController):
|
|
43
|
+
self.controller = controller
|
|
44
|
+
self._was_breathing = False
|
|
45
|
+
|
|
46
|
+
def __enter__(self):
|
|
47
|
+
"""
|
|
48
|
+
Pause the breathing animation. This context manager ensures that the
|
|
49
|
+
device is not breathing when the context is exited. **A sleep of .05
|
|
50
|
+
seconds is carried out to ensure the hardware settles before the
|
|
51
|
+
context is exited. This is to ensure that the device has time to
|
|
52
|
+
leave the breathing state and restore the previous state.**
|
|
53
|
+
|
|
54
|
+
"""
|
|
55
|
+
if getattr(self.controller, "breathing", False):
|
|
56
|
+
self._was_breathing = True
|
|
57
|
+
self.controller.breathing = False
|
|
58
|
+
sleep(0.05) # Required short delay to ensure hardware settles
|
|
59
|
+
|
|
60
|
+
def __exit__(self, exc_type, exc_val, exc_tb):
|
|
61
|
+
if self._was_breathing:
|
|
62
|
+
self.controller.breathing = True
|
|
63
|
+
|
|
64
|
+
|
|
42
65
|
class LEDMatrixController(metaclass=AliasMeta):
|
|
43
66
|
"""
|
|
44
67
|
Controller class for LED Matrix devices.
|
|
@@ -85,7 +108,10 @@ class LEDMatrixController(metaclass=AliasMeta):
|
|
|
85
108
|
do_not_show_grid_on_init: Optional[bool] = False,
|
|
86
109
|
thread_safe: Optional[bool] = False,
|
|
87
110
|
do_not_warn_on_thread_misuse: Optional[bool] = False,
|
|
88
|
-
hold_all: Optional[bool] = False
|
|
111
|
+
hold_all: Optional[bool] = False,
|
|
112
|
+
skip_greeting: Optional[bool] = False,
|
|
113
|
+
skip_identify: Optional[bool] = False,
|
|
114
|
+
skip_all_init_animations: Optional[bool] = False
|
|
89
115
|
):
|
|
90
116
|
"""
|
|
91
117
|
Initialize a new LED Matrix Controller.
|
|
@@ -146,7 +172,16 @@ class LEDMatrixController(metaclass=AliasMeta):
|
|
|
146
172
|
|
|
147
173
|
self.__set_up_thread_safety__(thread_safe)
|
|
148
174
|
|
|
149
|
-
self.__post_init__(
|
|
175
|
+
self.__post_init__(
|
|
176
|
+
skip_identify=skip_identify or skip_all_init_animations,
|
|
177
|
+
skip_greeting=skip_greeting or skip_all_init_animations
|
|
178
|
+
)
|
|
179
|
+
|
|
180
|
+
def __breather_paused(self):
|
|
181
|
+
return _BreatherPauseCtx(self)
|
|
182
|
+
|
|
183
|
+
def __greet(self):
|
|
184
|
+
self.scroll_text('Hello')
|
|
150
185
|
|
|
151
186
|
# ---------------------------------------------------------------------
|
|
152
187
|
# Keep‑alive internal worker
|
|
@@ -168,7 +203,7 @@ class LEDMatrixController(metaclass=AliasMeta):
|
|
|
168
203
|
# Wait with timeout so the thread can exit early when stop_evt is set
|
|
169
204
|
stop_evt.wait(self._KEEP_ALIVE_INTERVAL)
|
|
170
205
|
|
|
171
|
-
#
|
|
206
|
+
# ----------------------------------f-----------------------------------
|
|
172
207
|
# Property controlling the keep‑alive thread
|
|
173
208
|
# ---------------------------------------------------------------------
|
|
174
209
|
|
|
@@ -210,7 +245,7 @@ class LEDMatrixController(metaclass=AliasMeta):
|
|
|
210
245
|
self._keep_alive = False
|
|
211
246
|
self.__post_init__()
|
|
212
247
|
|
|
213
|
-
def __post_init__(self):
|
|
248
|
+
def __post_init__(self, skip_greeting= False, skip_identify=False):
|
|
214
249
|
from is_matrix_forge.led_matrix.display.effects.breather import Breather
|
|
215
250
|
|
|
216
251
|
self.__breather = Breather(self)
|
|
@@ -231,6 +266,12 @@ class LEDMatrixController(metaclass=AliasMeta):
|
|
|
231
266
|
if self.breather is None:
|
|
232
267
|
self.__breather = Breather(self)
|
|
233
268
|
|
|
269
|
+
if not skip_greeting:
|
|
270
|
+
self.__greet()
|
|
271
|
+
|
|
272
|
+
if not skip_identify:
|
|
273
|
+
self.identify()
|
|
274
|
+
|
|
234
275
|
def __set_up_thread_safety__(self, thread_safe_opt: bool):
|
|
235
276
|
if thread_safe_opt is None or not thread_safe_opt:
|
|
236
277
|
self._thread_safe = False
|
|
@@ -248,7 +289,9 @@ class LEDMatrixController(metaclass=AliasMeta):
|
|
|
248
289
|
Returns:
|
|
249
290
|
bool: True if the device is animating, False otherwise.
|
|
250
291
|
"""
|
|
251
|
-
|
|
292
|
+
# Guard against `None`, and empty lists
|
|
293
|
+
res = send_command(dev= self.device, command= COMMANDS.Animate, with_response= True)
|
|
294
|
+
return bool(res and res[0])
|
|
252
295
|
|
|
253
296
|
@property
|
|
254
297
|
def breather(self) -> Breather:
|
|
@@ -404,7 +447,7 @@ class LEDMatrixController(metaclass=AliasMeta):
|
|
|
404
447
|
def scroll_text(self, text: str, skip_end_space: bool = False, loop: bool = False):
|
|
405
448
|
from is_matrix_forge.led_matrix.display.text.scroller import TextScroller
|
|
406
449
|
from is_matrix_forge.led_matrix.display.animations.animation import Animation
|
|
407
|
-
from is_matrix_forge.led_matrix import fonts as font
|
|
450
|
+
from is_matrix_forge.led_matrix.display.assets import fonts as font
|
|
408
451
|
|
|
409
452
|
text_animation = Animation(TextScroller(font).scroll(text, skip_end_space))
|
|
410
453
|
text_animation.set_all_frame_durations(.03)
|
|
@@ -412,6 +455,17 @@ class LEDMatrixController(metaclass=AliasMeta):
|
|
|
412
455
|
text_animation.loop = True
|
|
413
456
|
return self.play_animation(text_animation)
|
|
414
457
|
|
|
458
|
+
@property
|
|
459
|
+
def serial_number(self) -> str:
|
|
460
|
+
"""
|
|
461
|
+
Get the USB serial number of the device, if available.
|
|
462
|
+
|
|
463
|
+
Returns:
|
|
464
|
+
str:
|
|
465
|
+
The USB serial number of the device, or an empty string if not available.
|
|
466
|
+
"""
|
|
467
|
+
return self.device.serial_number
|
|
468
|
+
|
|
415
469
|
@property
|
|
416
470
|
def set_brightness_on_init(self):
|
|
417
471
|
"""
|
|
@@ -633,8 +687,21 @@ class LEDMatrixController(metaclass=AliasMeta):
|
|
|
633
687
|
from is_matrix_forge.led_matrix.hardware import bootloader_jump
|
|
634
688
|
bootloader_jump(self.device)
|
|
635
689
|
|
|
636
|
-
def list_patterns(self):
|
|
637
|
-
|
|
690
|
+
def list_patterns(self, skip_print=False):
|
|
691
|
+
"""
|
|
692
|
+
List the built-in patterns available on the device.
|
|
693
|
+
|
|
694
|
+
The primary purpose for this method is to return the pattern names,
|
|
695
|
+
but also prints them if `skip_print` is set to `False`.
|
|
696
|
+
|
|
697
|
+
Parameters:
|
|
698
|
+
skip_print (bool, optional):
|
|
699
|
+
If True, don't print the pattern names. (optional, defaults to False).
|
|
700
|
+
"""
|
|
701
|
+
if not skip_print:
|
|
702
|
+
print(', '.join(self.built_in_pattern_names))
|
|
703
|
+
|
|
704
|
+
return self.built_in_pattern_names
|
|
638
705
|
|
|
639
706
|
@synchronized
|
|
640
707
|
def set_brightness(self, brightness: Union[int, float], __from_setter=False) -> None:
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
from concurrent.futures import ThreadPoolExecutor, as_completed
|
|
3
|
+
from typing import List, Type, Optional
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def get_controllers(
|
|
7
|
+
threaded: bool = False,
|
|
8
|
+
max_workers: Optional[int] = None,
|
|
9
|
+
controller_cls: Optional[Type] = None,
|
|
10
|
+
devices: Optional[list] = None,
|
|
11
|
+
**controller_kwargs
|
|
12
|
+
) -> List['LEDMatrixController']:
|
|
13
|
+
"""
|
|
14
|
+
Create LEDMatrixController objects, optionally in parallel threads.
|
|
15
|
+
|
|
16
|
+
Parameters:
|
|
17
|
+
threaded (bool): If True, create controllers in threads.
|
|
18
|
+
max_workers (int, optional): Maximum threads to use (default: len(devices)).
|
|
19
|
+
controller_cls (Type, optional): Alternate controller class (default: LEDMatrixController).
|
|
20
|
+
devices (list, optional): Device list (default: imported DEVICES).
|
|
21
|
+
**controller_kwargs: Additional kwargs for controller class.
|
|
22
|
+
|
|
23
|
+
Returns:
|
|
24
|
+
List[LEDMatrixController]: List of controller instances.
|
|
25
|
+
"""
|
|
26
|
+
from is_matrix_forge.led_matrix.constants import DEVICES
|
|
27
|
+
from is_matrix_forge.led_matrix.controller.controller import LEDMatrixController
|
|
28
|
+
|
|
29
|
+
_devices = devices or DEVICES
|
|
30
|
+
_controller_cls = controller_cls or LEDMatrixController
|
|
31
|
+
_max_workers = max_workers or len(_devices)
|
|
32
|
+
|
|
33
|
+
def create_controller(device):
|
|
34
|
+
# Here’s where you could add try/except if your hardware is flaky!
|
|
35
|
+
return _controller_cls(device, 100, thread_safe=True, **controller_kwargs)
|
|
36
|
+
|
|
37
|
+
if not threaded:
|
|
38
|
+
return [create_controller(dev) for dev in _devices]
|
|
39
|
+
|
|
40
|
+
with ThreadPoolExecutor(max_workers=_max_workers) as executor:
|
|
41
|
+
futures = [executor.submit(create_controller, dev) for dev in _devices]
|
|
42
|
+
controllers = []
|
|
43
|
+
for fut in as_completed(futures):
|
|
44
|
+
controllers.append(fut.result())
|
|
45
|
+
return controllers
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import functools
|
|
2
|
+
import threading
|
|
3
|
+
|
|
4
|
+
from is_matrix_forge.log_engine import ROOT_LOGGER as PARENT_LOGGER
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def synchronized(method=None, *, pause_breather=True):
|
|
8
|
+
"""
|
|
9
|
+
Lock & warn if you’re calling off-thread with thread_safe=False.
|
|
10
|
+
Optionally pause/resume the breather around the method.
|
|
11
|
+
|
|
12
|
+
Usage:
|
|
13
|
+
@synchronized
|
|
14
|
+
def foo(...): ...
|
|
15
|
+
|
|
16
|
+
@synchronized(pause_breather=True)
|
|
17
|
+
def draw_grid(...): ...
|
|
18
|
+
"""
|
|
19
|
+
def decorator(method):
|
|
20
|
+
@functools.wraps(method)
|
|
21
|
+
def wrapper(self, *args, **kwargs):
|
|
22
|
+
cur_thread_id = threading.get_ident()
|
|
23
|
+
|
|
24
|
+
# ⚠️ misuse detection: warn if another thread calls while thread_safe is False
|
|
25
|
+
if (
|
|
26
|
+
not getattr(self, "_thread_safe", False)
|
|
27
|
+
and getattr(self, "_warn_on_thread_misuse", True)
|
|
28
|
+
and cur_thread_id != getattr(self, "_owner_thread_id", None)
|
|
29
|
+
):
|
|
30
|
+
PARENT_LOGGER.warning(
|
|
31
|
+
"%r called from thread %r but thread_safe=False",
|
|
32
|
+
self,
|
|
33
|
+
threading.current_thread().name
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
ctx = None
|
|
37
|
+
if pause_breather:
|
|
38
|
+
# Try to get the Breather context manager in a robust way
|
|
39
|
+
breather = getattr(self, "breather", None)
|
|
40
|
+
if breather is not None and hasattr(breather, "paused"):
|
|
41
|
+
ctx = breather.paused
|
|
42
|
+
else:
|
|
43
|
+
# fallback to legacy or alternate pause context
|
|
44
|
+
ctx = getattr(self, "breather_paused", None)
|
|
45
|
+
if ctx is None:
|
|
46
|
+
raise RuntimeError(
|
|
47
|
+
"Could not find a valid breather pause context. "
|
|
48
|
+
"Neither 'breather.paused' nor 'breather_paused' are present on this object."
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
if ctx is not None:
|
|
52
|
+
with ctx():
|
|
53
|
+
return _run_locked(self, method, *args, **kwargs)
|
|
54
|
+
else:
|
|
55
|
+
return _run_locked(self, method, *args, **kwargs)
|
|
56
|
+
|
|
57
|
+
return wrapper
|
|
58
|
+
|
|
59
|
+
def _run_locked(self, method, *args, **kwargs):
|
|
60
|
+
# 🔐 actual lock if thread_safe=True
|
|
61
|
+
if getattr(self, "_thread_safe", False) and getattr(self, "_cmd_lock", None):
|
|
62
|
+
with self._cmd_lock:
|
|
63
|
+
return method(self, *args, **kwargs)
|
|
64
|
+
# fallback: call method directly
|
|
65
|
+
return method(self, *args, **kwargs)
|
|
66
|
+
|
|
67
|
+
return decorator if method is None else decorator(method)
|