IS-Matrix-Forge 1.0.0.dev5__tar.gz → 1.0.0.dev6__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.
Files changed (148) hide show
  1. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/PKG-INFO +3 -1
  2. is_matrix_forge-1.0.0.dev6/is_matrix_forge/common/decorators/__init__.py +12 -0
  3. is_matrix_forge-1.0.0.dev5/is_matrix_forge/common/decorators/__init__.py → is_matrix_forge-1.0.0.dev6/is_matrix_forge/common/decorators/freeze_setter.py +2 -12
  4. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/controller/controller.py +77 -30
  5. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/display/animations/__init__.py +9 -0
  6. is_matrix_forge-1.0.0.dev6/is_matrix_forge/led_matrix/display/animations/audio_visualizer.py +124 -0
  7. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/display/effects/breather.py +1 -1
  8. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/display/grid/grid.py +43 -8
  9. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/helpers/device.py +1 -0
  10. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/pyproject.toml +5 -2
  11. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/LICENSE.md +0 -0
  12. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/README.md +0 -0
  13. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/__init__.py +0 -0
  14. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/assets/__init__.py +0 -0
  15. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/assets/audio/__init__.py +0 -0
  16. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/assets/audio/files/__init__.py +0 -0
  17. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/assets/audio/files/plugged.wav +0 -0
  18. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/assets/audio/files/unplugged.wav +0 -0
  19. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/assets/char_map.json +0 -0
  20. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/assets/font_map.py +0 -0
  21. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/common/__init__.py +0 -0
  22. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/common/dirs.py +0 -0
  23. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/common/helpers/__init__.py +0 -0
  24. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/common/helpers/github_api.py +0 -0
  25. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/designer_gui/__init__.py +0 -0
  26. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/designer_gui/main_window/__init__.py +0 -0
  27. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/designer_gui/main_window/layout/__init__.py +0 -0
  28. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/designer_gui/main_window/layout/button_grid/__init__.py +0 -0
  29. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/designer_gui/main_window/layout/button_grid/column.py +0 -0
  30. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/designer_gui/main_window/layout/button_grid/grid.py +0 -0
  31. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/designer_gui/main_window/streamlit_app.py +0 -0
  32. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/dev_tools/__init__.py +0 -0
  33. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/dev_tools/debug.py +0 -0
  34. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/dev_tools/presets.py +0 -0
  35. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/inputmodule/__init__.py +0 -0
  36. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/inputmodule/b1display.py +0 -0
  37. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/inputmodule/c1minimal.py +0 -0
  38. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/inputmodule/font.py +0 -0
  39. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/inputmodule/helpers/__init__.py +0 -0
  40. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/inputmodule/ledmatrix.py +0 -0
  41. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/Scripts/__init__.py +0 -0
  42. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/Scripts/battery_monitor.py +0 -0
  43. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/Scripts/identify_matrices.py +0 -0
  44. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/Scripts/install_presets/__init__.py +0 -0
  45. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/Scripts/install_presets/arguments.py +0 -0
  46. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/Scripts/install_presets/main.py +0 -0
  47. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/__init__.py +0 -0
  48. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/commands/__init__.py +0 -0
  49. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/commands/map.py +0 -0
  50. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/constants.py +0 -0
  51. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/controller/__init__.py +0 -0
  52. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/controller/helpers/__init__.py +0 -0
  53. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/controller/helpers/threading.py +0 -0
  54. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/controller/multiton.py +0 -0
  55. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/controller/threaded.py +0 -0
  56. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/display/__init__.py +0 -0
  57. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/display/animations/animation.py +0 -0
  58. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/display/animations/effects/__init__.py +0 -0
  59. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/display/animations/errors.py +0 -0
  60. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/display/animations/font/__init__.py +0 -0
  61. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/display/animations/font/font.py +0 -0
  62. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/display/animations/font/map_builder.py +0 -0
  63. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/display/animations/frame/__init__.py +0 -0
  64. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/display/animations/frame/base.py +0 -0
  65. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/display/animations/frame/helpers.py +0 -0
  66. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/display/animations/keep_awake.py +0 -0
  67. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/display/animations/plugged.py +0 -0
  68. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/display/animations/text_scroller.py +0 -0
  69. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/display/effects/__init__.py +0 -0
  70. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/display/effects/fade.py +0 -0
  71. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/display/effects/scroller/__init__.py +0 -0
  72. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/display/effects/scroller/base.py +0 -0
  73. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/display/effects/scroller/helpers.py +0 -0
  74. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/display/grid/__init__.py +0 -0
  75. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/display/grid/helpers.py +0 -0
  76. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/display/grid/presets/__init__.py +0 -0
  77. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/display/grid/presets/manifest.py +0 -0
  78. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/display/helpers/__init__.py +0 -0
  79. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/display/helpers/columns.py +0 -0
  80. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/display/media.py +0 -0
  81. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/display/patterns/built_in/__init__.py +0 -0
  82. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/display/patterns/built_in/commands.py +0 -0
  83. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/display/patterns/built_in/constants.py +0 -0
  84. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/display/patterns/built_in/stencils/__init__.py +0 -0
  85. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/display/patterns/built_in/stencils/res.py +0 -0
  86. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/display/text/__init__.py +0 -0
  87. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/display/text/scroller.py +0 -0
  88. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/errors/__init__.py +0 -0
  89. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/errors/base.py +0 -0
  90. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/errors/grid.py +0 -0
  91. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/errors/matrix.py +0 -0
  92. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/errors/misc.py +0 -0
  93. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/fonts.py +0 -0
  94. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/hardware.py +0 -0
  95. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/helpers/__init__.py +0 -0
  96. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/helpers/core/__init__.py +0 -0
  97. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/helpers/core/lazy_mod_load.py +0 -0
  98. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/helpers/status_handler.py +0 -0
  99. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/helpers/stream/__init__.py +0 -0
  100. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/helpers/stream/errors.py +0 -0
  101. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/led_matrix.py +0 -0
  102. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/status.py +0 -0
  103. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/tools/__init__.py +0 -0
  104. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/tools/identify.py +0 -0
  105. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/led_matrix/utils/__init__.py +0 -0
  106. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/log_engine.py +0 -0
  107. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/monitor/__init__.py +0 -0
  108. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/monitor/errors.py +0 -0
  109. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/monitor/events.py +0 -0
  110. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/monitor/gui/__init__.py +0 -0
  111. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/monitor/gui/errors.py +0 -0
  112. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/monitor/gui/event/__init__.py +0 -0
  113. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/monitor/gui/event/collection.py +0 -0
  114. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/monitor/gui/event/errors.py +0 -0
  115. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/monitor/gui/event/event.py +0 -0
  116. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/monitor/gui/layout/__init__.py +0 -0
  117. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/monitor/gui/layout/base.py +0 -0
  118. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/monitor/gui/metaclasses/__init__.py +0 -0
  119. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/monitor/gui/windows/__init__.py +0 -0
  120. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/monitor/gui/windows/base.py +0 -0
  121. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/monitor/gui/windows/main/__init__.py +0 -0
  122. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/monitor/gui/windows/main/layout.py +0 -0
  123. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/monitor/helpers.py +0 -0
  124. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/monitor/monitor.py +0 -0
  125. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/notify/__init__.py +0 -0
  126. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/notify/sounds/__init__.py +0 -0
  127. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/notify/sounds/base.py +0 -0
  128. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/progress.py +0 -0
  129. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/scripts/__init__.py +0 -0
  130. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/scripts/preset_installer.py +0 -0
  131. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/serial_com/__init__.py +0 -0
  132. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/serial_com/base/__init__.py +0 -0
  133. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/serial_com/base/answer.py +0 -0
  134. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/serial_com/base/message.py +0 -0
  135. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/serial_com/base/request.py +0 -0
  136. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/is_matrix_forge/serial_com/exchange.py +0 -0
  137. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/presets/blank.json +0 -0
  138. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/presets/manifest.json +0 -0
  139. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/presets/shock_face.json +0 -0
  140. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/presets/test1.json +0 -0
  141. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/presets/test2.json +0 -0
  142. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/presets/test3.json +0 -0
  143. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/presets/test4.json +0 -0
  144. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/presets/test5.json +0 -0
  145. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/presets/test6.json +0 -0
  146. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/presets/test7.json +0 -0
  147. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/presets/x_animation II.json +0 -0
  148. {is_matrix_forge-1.0.0.dev5 → is_matrix_forge-1.0.0.dev6}/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.dev5
3
+ Version: 1.0.0.dev6
4
4
  Summary:
5
5
  License: MIT
6
6
  Keywords: led,matrix,framework,hardware
@@ -12,6 +12,7 @@ Classifier: Programming Language :: Python :: 3
12
12
  Classifier: Programming Language :: Python :: 3.12
13
13
  Classifier: Programming Language :: Python :: 3.13
14
14
  Provides-Extra: clipboard-support
15
+ Requires-Dist: aliaser (>=1.0.0.dev4,<2.0.0)
15
16
  Requires-Dist: chime (>=0.7.0,<0.8.0)
16
17
  Requires-Dist: clipboard (>=0.0.4,<0.0.5) ; extra == "clipboard-support"
17
18
  Requires-Dist: easy-exit-calls (>=1.0.0.dev1,<2.0.0)
@@ -23,6 +24,7 @@ Requires-Dist: pillow (>=11.2.1,<12.0.0)
23
24
  Requires-Dist: pyserial (>=3.5,<4.0)
24
25
  Requires-Dist: pysimplegui-4-foss (==4.60.4.1)
25
26
  Requires-Dist: pysimpleguiweb (==0.39.0)
27
+ Requires-Dist: requests (>=2.32.4,<3.0.0)
26
28
  Project-URL: Homepage, https://github.com/Inspyre-Softworks/IS-Matrix-Forge
27
29
  Project-URL: Repository, https://github.com/Inspyre-Softworks/IS-Matrix-Forge
28
30
  Description-Content-Type: text/markdown
@@ -0,0 +1,12 @@
1
+ from inspyre_toolbox.syntactic_sweets.classes.decorators import validate_type
2
+ from is_matrix_forge.common.decorators.freeze_setter import freeze_setter
3
+ from is_matrix_forge.led_matrix.errors.misc import ImplicitNameDerivationError
4
+ from aliaser import Aliases
5
+
6
+
7
+ __all__ = [
8
+ 'Aliases',
9
+ 'ImplicitNameDerivationError',
10
+ 'freeze_setter',
11
+ 'validate_type',
12
+ ]
@@ -1,11 +1,6 @@
1
1
  import functools
2
2
  from typing import Optional, Type, Callable, Any
3
3
 
4
- import functools
5
- from typing import Optional, Type, Callable, Any
6
- from inspyre_toolbox.syntactic_sweets.classes.decorators import validate_type
7
- from is_matrix_forge.led_matrix.errors.misc import ImplicitNameDerivationError
8
-
9
4
 
10
5
  def freeze_setter(
11
6
  attr_name: Optional[str] = None,
@@ -94,6 +89,8 @@ def freeze_setter(
94
89
  - `ImplicitNameDerivationError`: Raised for configuration issues with underscore-prefixed setters.
95
90
  - `AttributeError`: Default exception for reassigning a frozen attribute.
96
91
  """
92
+ from is_matrix_forge.led_matrix.errors.misc import ImplicitNameDerivationError
93
+
97
94
  def decorator(setter: Callable) -> Callable:
98
95
  setter_name = setter.__name__
99
96
 
@@ -143,10 +140,3 @@ def freeze_setter(
143
140
  return wrapper
144
141
 
145
142
  return decorator
146
-
147
-
148
- __all__ = [
149
- 'ImplicitNameDerivationError',
150
- 'freeze_setter',
151
- 'validate_type',
152
- ]
@@ -26,20 +26,20 @@ from inspyre_toolbox.syntactic_sweets.classes.decorators.aliases import add_alia
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
+ from aliaser.metaclass import AliasMeta
29
30
  from is_matrix_forge.led_matrix.constants import SLOT_MAP
30
31
  from is_matrix_forge.led_matrix.display.text import show_string as _show_string_raw
31
32
  from is_matrix_forge.led_matrix.controller import MultitonMeta
32
33
  from is_matrix_forge.led_matrix.controller.helpers.threading import synchronized
33
34
  from is_matrix_forge.led_matrix.commands.map import CommandVals
34
- from is_matrix_forge.led_matrix.hardware import send_serial, send_command
35
+ from is_matrix_forge.led_matrix.hardware import send_command
35
36
  from is_matrix_forge.led_matrix.display.effects.breather import Breather
36
37
  from is_matrix_forge.led_matrix.display.text import show_string
37
38
 
38
39
  COMMANDS = CommandVals
39
40
 
40
41
 
41
- @add_aliases
42
- class LEDMatrixController(metaclass=MultitonMeta):
42
+ class LEDMatrixController(metaclass=AliasMeta):
43
43
  """
44
44
  Controller class for LED Matrix devices.
45
45
 
@@ -115,6 +115,8 @@ class LEDMatrixController(metaclass=MultitonMeta):
115
115
  self.__show_grid_on_init = None
116
116
  self._thread_safe = None
117
117
  self._cmd_lock = None
118
+ self._keep_alive = False
119
+ self._KEEP_ALIVE_INTERVAL = 50
118
120
 
119
121
  self.hold_all = hold_all or False
120
122
 
@@ -129,6 +131,7 @@ class LEDMatrixController(metaclass=MultitonMeta):
129
131
  self.__init_clear = not skip_init_clear
130
132
 
131
133
  if init_grid is not None:
134
+ from is_matrix_forge.led_matrix.display.grid import Grid
132
135
  if not isinstance(init_grid, Grid):
133
136
  raise TypeError(f'init_grid must be of type `Grid`, not {type(init_grid)}')
134
137
 
@@ -145,13 +148,75 @@ class LEDMatrixController(metaclass=MultitonMeta):
145
148
 
146
149
  self.__post_init__()
147
150
 
151
+ # ---------------------------------------------------------------------
152
+ # Keep‑alive internal worker
153
+ # ---------------------------------------------------------------------
154
+
155
+ @synchronized
156
+ def __keep_alive_worker(self):
157
+ """Loop until signalled, polling :pyattr:`animating` every 50 s."""
158
+ # Lazily create the stop event (should already exist, but be safe)
159
+ stop_evt = self._keep_alive_stop_evt or threading.Event()
160
+ self._keep_alive_stop_evt = stop_evt
161
+
162
+ while not stop_evt.is_set():
163
+ try:
164
+ _ = self.animating # A simple query is enough to keep FW awake
165
+ except Exception: # pragma: no cover – we don't crash the thread
166
+ pass
167
+
168
+ # Wait with timeout so the thread can exit early when stop_evt is set
169
+ stop_evt.wait(self._KEEP_ALIVE_INTERVAL)
170
+
171
+ # ---------------------------------------------------------------------
172
+ # Property controlling the keep‑alive thread
173
+ # ---------------------------------------------------------------------
174
+
175
+ @property
176
+ def keep_alive(self) -> bool:
177
+ """Whether the background keep‑alive thread is active."""
178
+ return self._keep_alive
179
+
180
+ @keep_alive.setter
181
+ def keep_alive(self, enable: bool):
182
+ if not isinstance(enable, bool):
183
+ raise TypeError('keep_alive must be a boolean.')
184
+
185
+ # No change ➜ nothing to do
186
+ if enable == self._keep_alive:
187
+ return
188
+
189
+ if enable:
190
+ # Start background thread
191
+ self._keep_alive_stop_evt = threading.Event()
192
+ self._keep_alive_thread = threading.Thread(
193
+ target=self.__keep_alive_worker,
194
+ name=f"{self.__class__.__name__}-KeepAlive-{self.device.name}",
195
+ daemon=True,
196
+ )
197
+ self._keep_alive_thread.start()
198
+ self._keep_alive = True
199
+ else:
200
+ # Signal thread to exit and wait (briefly) for it
201
+ if self._keep_alive_stop_evt is not None:
202
+ self._keep_alive_stop_evt.set()
203
+ if (
204
+ self._keep_alive_thread is not None
205
+ and self._keep_alive_thread.is_alive()
206
+ ):
207
+ self._keep_alive_thread.join(timeout=self._KEEP_ALIVE_INTERVAL + 1)
208
+ self._keep_alive_thread = None
209
+ self._keep_alive_stop_evt = None
210
+ self._keep_alive = False
211
+ self.__post_init__()
212
+
148
213
  def __post_init__(self):
149
214
  from is_matrix_forge.led_matrix.display.effects.breather import Breather
150
215
 
151
216
  self.__breather = Breather(self)
152
217
 
153
218
  if self.clear_on_init:
154
- self.clear()
219
+ self.clear_matrix()
155
220
 
156
221
  if self.set_brightness_on_init:
157
222
  self.set_brightness(self.__default_brightness)
@@ -184,7 +249,6 @@ class LEDMatrixController(metaclass=MultitonMeta):
184
249
  bool: True if the device is animating, False otherwise.
185
250
  """
186
251
  return bool(send_command(self.device, COMMANDS.Animate, with_response=True)[0])
187
- # return animate(self.device)
188
252
 
189
253
  @property
190
254
  def breather(self) -> Breather:
@@ -321,7 +385,10 @@ class LEDMatrixController(metaclass=MultitonMeta):
321
385
 
322
386
  @property
323
387
  def name(self) -> str:
324
- return self.__name if self.__name is not None else self.device.name
388
+ if self.__name is None:
389
+ self.__name = self.device.name
390
+
391
+ return self.__name
325
392
 
326
393
  def play_animation(self, animation):
327
394
  from is_matrix_forge.led_matrix.display.animations.animation import Animation
@@ -344,9 +411,6 @@ class LEDMatrixController(metaclass=MultitonMeta):
344
411
  text_animation.loop = True
345
412
  return self.play_animation(text_animation)
346
413
 
347
- def show_text(self, text: str):
348
- self.draw_text(text)
349
-
350
414
  @property
351
415
  def set_brightness_on_init(self):
352
416
  """
@@ -405,6 +469,7 @@ class LEDMatrixController(metaclass=MultitonMeta):
405
469
  animate(self.device, enable)
406
470
 
407
471
  @synchronized
472
+ @method_alias('clear')
408
473
  def clear_matrix(self) -> None:
409
474
  """
410
475
  Clear the LED matrix display.
@@ -419,12 +484,7 @@ class LEDMatrixController(metaclass=MultitonMeta):
419
484
  grid = Grid(init_grid=data)
420
485
  self.draw_grid(grid)
421
486
 
422
- def clear(self):
423
- self.clear_matrix()
424
-
425
- def draw(self, grid: 'Grid' = None) -> None:
426
- return self.draw_grid(grid)
427
-
487
+ @alias('draw')
428
488
  @synchronized
429
489
  def draw_grid(self, grid: 'Grid' = None) -> None:
430
490
  """
@@ -443,7 +503,7 @@ class LEDMatrixController(metaclass=MultitonMeta):
443
503
  render_matrix(self.device, grid.grid)
444
504
 
445
505
  @synchronized
446
- @method_alias('pattern')
506
+ @alias('pattern', 'show_pattern')
447
507
  def draw_pattern(self, pattern: str) -> None:
448
508
  """
449
509
  Draw a pattern on the LED matrix.
@@ -476,12 +536,6 @@ class LEDMatrixController(metaclass=MultitonMeta):
476
536
 
477
537
  _show_percentage_raw(self.device, percentage)
478
538
 
479
- def draw_string(self, text: str):
480
- self.show_text(text)
481
-
482
- def draw_text(self, text: str):
483
- self.show_text(text)
484
-
485
539
  @synchronized
486
540
  def display_location(self):
487
541
  """
@@ -613,15 +667,8 @@ class LEDMatrixController(metaclass=MultitonMeta):
613
667
  if not __from_setter:
614
668
  self.__brightness = brightness
615
669
 
616
- def show_string(self, text: str) -> None:
617
- """
618
- Alias for LEDMatrixController.show_text.
619
-
620
- See Also:
621
- LEDMatrixController.show_text
622
- """
623
- self.show_text(text)
624
670
 
671
+ @method_alias('draw_text', 'show_string', 'draw_string')
625
672
  @synchronized
626
673
  def show_text(self, text: str) -> None:
627
674
  """
@@ -2,6 +2,7 @@ from time import sleep
2
2
 
3
3
  from is_matrix_forge.led_matrix.hardware import brightness
4
4
  from is_matrix_forge.led_matrix.display.text import show_string
5
+ from .audio_visualizer import AudioVisualizer
5
6
 
6
7
 
7
8
  def clear(dev):
@@ -26,3 +27,11 @@ def goodbye_animation(dev):
26
27
  checkerboard_cycle(dev)
27
28
  sleep(.5)
28
29
  show_string(dev, 'Bye')
30
+
31
+
32
+ __all__ = [
33
+ 'AudioVisualizer',
34
+ 'clear',
35
+ 'checkerboard_cycle',
36
+ 'goodbye_animation',
37
+ ]
@@ -0,0 +1,124 @@
1
+ """Real-time audio visualizer for the LED matrix.
2
+
3
+ This module provides a small utility that streams audio data and renders simple
4
+ bar style visualizations on one or more LED matrix controllers. By default it
5
+ uses the system microphone for input, however an audio file may also be used as
6
+ the source allowing "regular" audio to be visualized. ``sounddevice`` and
7
+ ``soundfile`` are optional dependencies and the visualiser gracefully degrades
8
+ if they are unavailable.
9
+ """
10
+
11
+ from __future__ import annotations
12
+
13
+ import threading
14
+ from pathlib import Path
15
+ from typing import Iterable, List, Optional, Union
16
+
17
+ import numpy as np
18
+
19
+ try: # ``sounddevice`` is an optional dependency
20
+ import sounddevice as sd
21
+ except Exception: # pragma: no cover - optional dependency missing
22
+ sd = None # type: ignore
23
+
24
+ try: # ``soundfile`` is also optional
25
+ import soundfile as sf
26
+ except Exception: # pragma: no cover - optional dependency missing
27
+ sf = None # type: ignore
28
+
29
+ from is_matrix_forge.led_matrix.controller.controller import LEDMatrixController
30
+ from is_matrix_forge.led_matrix.display.animations.frame.base import Frame
31
+
32
+
33
+ class AudioVisualizer:
34
+ """Stream audio data and render a simple bar visualisation."""
35
+
36
+ def __init__(
37
+ self,
38
+ controllers: Iterable[LEDMatrixController],
39
+ sample_rate: int = 44_100,
40
+ chunk_size: int = 1_024,
41
+ audio_source: Union[str, Path, None] = None,
42
+ loop_file: bool = True,
43
+ ) -> None:
44
+ self.controllers: List[LEDMatrixController] = list(controllers)
45
+ self.sample_rate = sample_rate
46
+ self.chunk_size = chunk_size
47
+ self._stream: Optional[sd.InputStream] = None # type: ignore[var-annotated]
48
+ self._thread: Optional[threading.Thread] = None
49
+ self._running = False
50
+ self._audio_source: Optional[Path] = Path(audio_source) if audio_source else None
51
+ self._loop_file = loop_file
52
+
53
+ # ------------------------------------------------------------------ utils --
54
+ def _process_chunk(self, data: np.ndarray) -> None: # pragma: no cover - real time
55
+ """Render a frame based on ``data`` samples."""
56
+ amplitude = float(np.linalg.norm(data) / len(data))
57
+ bar_height = min(int(amplitude * 34), 34)
58
+
59
+ grid = [[0 for _ in range(34)] for _ in range(9)]
60
+ for x in range(9):
61
+ for y in range(bar_height):
62
+ grid[x][33 - y] = 1
63
+
64
+ frame = Frame(grid=grid, duration=0.01)
65
+
66
+ for ctrl in self.controllers:
67
+ ctrl.draw_grid(frame.grid)
68
+
69
+ def _audio_callback(self, indata, frames, time, status) -> None: # pragma: no cover - real time
70
+ if not self._running:
71
+ return
72
+ self._process_chunk(indata[:, 0])
73
+
74
+ def _file_loop(self) -> None: # pragma: no cover - requires soundfile
75
+ assert sf is not None and self._audio_source is not None
76
+ while self._running:
77
+ with sf.SoundFile(self._audio_source) as f:
78
+ while self._running:
79
+ data = f.read(self.chunk_size, dtype='float32')
80
+ if len(data) == 0:
81
+ break
82
+ self._process_chunk(data)
83
+ if not self._loop_file:
84
+ break
85
+
86
+ # ------------------------------------------------------------------- API --
87
+ def start(self) -> None:
88
+ if sd is None: # pragma: no cover - environment without sounddevice
89
+ raise RuntimeError("sounddevice is required for AudioVisualizer")
90
+
91
+ if self._running:
92
+ return
93
+
94
+ self._running = True
95
+ if self._audio_source is not None:
96
+ if sf is None:
97
+ raise RuntimeError("soundfile is required for file playback")
98
+ self._thread = threading.Thread(target=self._file_loop, daemon=True)
99
+ self._thread.start()
100
+ else:
101
+ self._stream = sd.InputStream(
102
+ channels=1,
103
+ samplerate=self.sample_rate,
104
+ blocksize=self.chunk_size,
105
+ callback=self._audio_callback,
106
+ )
107
+ self._stream.start()
108
+
109
+ def stop(self) -> None:
110
+ if not self._running:
111
+ return
112
+
113
+ self._running = False
114
+ if self._stream is not None:
115
+ self._stream.stop()
116
+ self._stream.close()
117
+ self._stream = None
118
+ if self._thread is not None:
119
+ self._thread.join(timeout=1)
120
+ self._thread = None
121
+
122
+
123
+ __all__ = ["AudioVisualizer"]
124
+
@@ -1,6 +1,6 @@
1
1
  import threading
2
2
  import time
3
- from is_matrix_forge.common.decorators import freeze_setter
3
+ from is_matrix_forge.common.decorators.freeze_setter import freeze_setter
4
4
  from is_matrix_forge.log_engine import ROOT_LOGGER, Loggable
5
5
 
6
6
 
@@ -22,6 +22,7 @@ from pathlib import Path
22
22
  from typing import List, Optional, Union, ClassVar, Type, Any, Dict # Added Any, Dict
23
23
  from ...constants import WIDTH as __WIDTH, HEIGHT as __HEIGHT, PRESETS_DIR
24
24
  from .helpers import is_valid_grid, generate_blank_grid
25
+ from ...helpers import load_from_file as _helpers_load_from_file
25
26
  from is_matrix_forge.common.helpers import coerce_to_int
26
27
 
27
28
  MATRIX_HEIGHT = __HEIGHT
@@ -35,6 +36,24 @@ This constant defines the default width for new Grid instances and for loading o
35
36
  """
36
37
 
37
38
 
39
+ def load_from_file(
40
+ path: Union[str, Path],
41
+ expected_width: Optional[int] | None = None,
42
+ expected_height: Optional[int] | None = None,
43
+ fallback_duration: Optional[Union[int, float]] = None,
44
+ ) -> Any:
45
+ """Wrapper around :func:`is_matrix_forge.led_matrix.helpers.load_from_file`.
46
+
47
+ Exists primarily for unit tests which monkeypatch this function directly.
48
+ """
49
+ return _helpers_load_from_file(
50
+ path,
51
+ expected_width,
52
+ expected_height,
53
+ fallback_duration,
54
+ )
55
+
56
+
38
57
  class Grid:
39
58
  """
40
59
  Represents a 2D column-major grid for the LED display (grid[x][y], 9×34).
@@ -127,8 +146,18 @@ class Grid:
127
146
  cls,
128
147
  spec: List[List[int]]
129
148
  ) -> 'Grid':
130
- """Instantiate directly from a column-major spec list."""
131
- return cls(init_grid=spec)
149
+ """Instantiate directly from a column-major spec list.
150
+
151
+ The dimensions of the grid are inferred from ``spec`` so tests can
152
+ provide arbitrary sized grids.
153
+ """
154
+ width = len(spec)
155
+ height = len(spec[0]) if spec else 0
156
+ if not is_valid_grid(spec, width, height):
157
+ raise ValueError(
158
+ f"init_grid must be {width}×{height} column-major 0/1 list"
159
+ )
160
+ return cls(width=width, height=height, init_grid=spec)
132
161
 
133
162
  @classmethod
134
163
  def from_file(
@@ -141,10 +170,16 @@ class Grid:
141
170
  """
142
171
  Load a column-major grid from file (single grid or frames of grids).
143
172
  """
144
- from ...helpers import load_from_file
145
173
  raw = load_from_file(str(filename))
146
174
  # Single-grid JSON: list of lists
147
- if isinstance(raw, list) and raw and isinstance(raw[0], list):
175
+ if (
176
+ isinstance(raw, list)
177
+ and raw
178
+ and isinstance(raw[0], list)
179
+ and is_valid_grid(raw[0], width, height)
180
+ ):
181
+ grid_data = raw[0]
182
+ elif isinstance(raw, list) and raw and isinstance(raw[0], list):
148
183
  grid_data = raw
149
184
  # Frame-list JSON: list of dicts
150
185
  elif isinstance(raw, list) and all(isinstance(f, dict) for f in raw):
@@ -187,11 +222,11 @@ class Grid:
187
222
  new = generate_blank_grid(self._width, self._height, self._fill_value)
188
223
 
189
224
  for c, r in itertools.product(range(self._width), range(self._height)):
190
- src_c = (c + dx) % self._width if wrap else c + dx
191
- src_r = (r + dy) % self._height if wrap else r + dy
225
+ dest_c = (c + dx) % self._width if wrap else c + dx
226
+ dest_r = (r + dy) % self._height if wrap else r + dy
192
227
 
193
- if 0 <= src_c < self._width and 0 <= src_r < self._height:
194
- new[c][r] = self._grid[src_c][src_r]
228
+ if 0 <= dest_c < self._width and 0 <= dest_r < self._height:
229
+ new[dest_c][dest_r] = self._grid[c][r]
195
230
 
196
231
  return Grid(width=self._width, height=self._height, fill_value=self._fill_value, init_grid=new)
197
232
 
@@ -7,6 +7,7 @@ including functions to convert between different device location formats.
7
7
  from serial import Serial, SerialException
8
8
  from serial.tools import list_ports
9
9
  from is_matrix_forge.log_engine import ROOT_LOGGER
10
+ from is_matrix_forge.led_matrix.constants import VID as EXPECTED_VID, PID as EXPECTED_PID
10
11
 
11
12
 
12
13
  MOD_LOGGER = ROOT_LOGGER.get_child('led_matrix.helpers.device')
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "IS-Matrix-Forge"
3
- version = "1.0.0-dev.5"
3
+ version = "1.0.0-dev.6"
4
4
  description = ""
5
5
  authors = ["Taylor B. <t.blackstone@inspyre.tech>"]
6
6
  readme = "README.md"
@@ -31,6 +31,8 @@ clipboard = { version = "^0.0.4", optional = true }
31
31
  pysimplegui-4-foss = "==4.60.4.1"
32
32
  pysimpleguiweb = "==0.39.0"
33
33
  imapclient = "==3.0.1"
34
+ requests = "^2.32.4"
35
+ aliaser = "^1.0.0.dev4"
34
36
 
35
37
  [tool.poetry.extras]
36
38
  clipboard_support = ["clipboard"]
@@ -44,7 +46,8 @@ ipyboost = { version = "1.0.0.a3", source = "testpypi" }
44
46
  [tool.poetry.scripts]
45
47
  python-path = "Scripts.python_path:main"
46
48
  led-matrix-identify = "is_matrix_forge.led_matrix.Scripts.identify_matrices:main"
47
- install-presets = "Scripts.install_presets:main"
49
+ install-presets = "is_matrix_forge.led_matrix.Scripts.install_presets.main:main"
50
+ pixel-grid = "is_matrix_forge.designer_gui.main_window:main"
48
51
 
49
52
  [[tool.poetry.include]]
50
53
  path = "presets/**"