mirror of
https://github.com/onyx-and-iris/voicemeeter-compact.git
synced 2026-04-08 17:03:32 +00:00
Compare commits
21 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c3f20ea43f | |||
| 2e868705d5 | |||
| df6f215514 | |||
|
|
0a5987631f | ||
| 3d3bc71d15 | |||
| 7b148b2614 | |||
| ef558fdde6 | |||
| c684ed9981 | |||
| 1498daf36f | |||
| e964c94d07 | |||
| 9f20225a59 | |||
| f63c36c94a | |||
| c2db0f2757 | |||
| bfb0482c32 | |||
| 6222ab1e62 | |||
| 0ad40ab708 | |||
| b809bcb28f | |||
| a0b9a92a2a | |||
| 9faf8ae10c | |||
| 82cf0e914b | |||
| 3e68488231 |
7
.gitignore
vendored
7
.gitignore
vendored
@@ -132,4 +132,11 @@ dmypy.json
|
|||||||
# Pyre type checker
|
# Pyre type checker
|
||||||
.pyre/
|
.pyre/
|
||||||
|
|
||||||
|
# build
|
||||||
|
sv_ttk/
|
||||||
|
theme/
|
||||||
|
|
||||||
|
sv_*.py
|
||||||
|
fst_*.py
|
||||||
|
|
||||||
.vscode/
|
.vscode/
|
||||||
11
CHANGELOG.md
11
CHANGELOG.md
@@ -9,6 +9,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
|
|
||||||
- [ ] Add support for forest theme (if rbende adds it to pypi)
|
- [ ] Add support for forest theme (if rbende adds it to pypi)
|
||||||
|
|
||||||
|
## [1.9.0] - 2023-07-10
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Should the voicemeeter-compact app lose communication with Voicemeeter GUI a popup will show asking to restart the GUI.
|
||||||
|
- If yes is selected the app's mainframe will redraw, there will be a grace period before updates start again due to Voicemeeter engine startup.
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- From the menu, Voicemeeter->Shutdown now closes both the compact app and the main Voicemeeter GUI.
|
||||||
|
|
||||||
## [1.8.0] - 2023-06-29
|
## [1.8.0] - 2023-06-29
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|||||||
28
README.md
28
README.md
@@ -1,5 +1,6 @@
|
|||||||
[](https://badge.fury.io/py/voicemeeter-compact)
|
[](https://badge.fury.io/py/voicemeeter-compact)
|
||||||
[](https://github.com/onyx-and-iris/voicemeeter-compact/blob/main/LICENSE)
|
[](https://github.com/onyx-and-iris/voicemeeter-compact/blob/main/LICENSE)
|
||||||
|
[](https://python-poetry.org/)
|
||||||
[](https://github.com/psf/black)
|
[](https://github.com/psf/black)
|
||||||

|

|
||||||
|
|
||||||
@@ -34,16 +35,16 @@ import vmcompact
|
|||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
# pass the kind_id and the vm object to the app
|
# choose the kind of Voicemeeter (Local connection)
|
||||||
with voicemeeterlib.api(kind_id) as vm:
|
KIND_ID = "banana"
|
||||||
app = vmcompact.connect(kind_id, vm)
|
|
||||||
|
# pass the KIND_ID and the vm object to the app
|
||||||
|
with voicemeeterlib.api(KIND_ID) as vm:
|
||||||
|
app = vmcompact.connect(KIND_ID, vm)
|
||||||
app.mainloop()
|
app.mainloop()
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
# choose the kind of Voicemeeter (Local connection)
|
|
||||||
kind_id = "banana"
|
|
||||||
|
|
||||||
main()
|
main()
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -53,9 +54,9 @@ It's important to know that only labelled strips and buses will appear in the Ch
|
|||||||
|
|
||||||
If the GUI looks like the above when you first load it, then no channels are labelled. From the menu, `Configs->Load config` you may load an example config. Save your current Voicemeeter settings first :).
|
If the GUI looks like the above when you first load it, then no channels are labelled. From the menu, `Configs->Load config` you may load an example config. Save your current Voicemeeter settings first :).
|
||||||
|
|
||||||
### kind_id
|
### KIND_ID
|
||||||
|
|
||||||
Set the kind of Voicemeeter, kind_id may be:
|
Set the kind of Voicemeeter, KIND_ID may be:
|
||||||
|
|
||||||
- `basic`
|
- `basic`
|
||||||
- `banana`
|
- `banana`
|
||||||
@@ -109,7 +110,7 @@ Configure certain startup states for the app.
|
|||||||
Configure a user config to load on app startup. Don't include the .toml extension in the config name.
|
Configure a user config to load on app startup. Don't include the .toml extension in the config name.
|
||||||
|
|
||||||
- `theme`
|
- `theme`
|
||||||
By default the app loads up the [Sun Valley light or dark theme](https://github.com/rdbende/Sun-Valley-ttk-theme) by @rdbende. You have the option to load up the app without any theme loaded. Simply set `enabled` to false and `mode` will take no effect.
|
By default the app loads up the [Sun Valley light or dark theme][def] by @rdbende. You have the option to load up the app without any theme loaded. Simply set `enabled` to false and `mode` will take no effect.
|
||||||
|
|
||||||
- `extends`
|
- `extends`
|
||||||
Extending the app will show both strips and buses. In reduced mode only one or the other. This app will extend both horizontally and vertically, simply set `extends_horizontal` true or false accordingly.
|
Extending the app will show both strips and buses. In reduced mode only one or the other. This app will extend both horizontally and vertically, simply set `extends_horizontal` true or false accordingly.
|
||||||
@@ -149,7 +150,7 @@ port = 6990
|
|||||||
|
|
||||||
Three example user configs are included with the package, one for each kind of Voicemeeter. Use these to configure parameter startup states. Any parameter supported by the underlying interfaces may be used. Check the 'multiple-parameters' section for more info:
|
Three example user configs are included with the package, one for each kind of Voicemeeter. Use these to configure parameter startup states. Any parameter supported by the underlying interfaces may be used. Check the 'multiple-parameters' section for more info:
|
||||||
|
|
||||||
[Python Interface for Voicemeeter API](https://github.com/onyx-and-iris/voicemeeter-api-python#multiple-parameters)
|
[Python Interface for the Voicemeeter API](https://github.com/onyx-and-iris/voicemeeter-api-python#multiple-parameters)
|
||||||
|
|
||||||
[Python Interface for VBAN CMD](https://github.com/onyx-and-iris/vban-cmd-python#multiple-parameters)
|
[Python Interface for VBAN CMD](https://github.com/onyx-and-iris/vban-cmd-python#multiple-parameters)
|
||||||
|
|
||||||
@@ -157,6 +158,9 @@ User configs may be loaded at any time via the menu.
|
|||||||
|
|
||||||
## Special Thanks
|
## Special Thanks
|
||||||
|
|
||||||
[Vincent Burel](https://github.com/vburel2018) for creating Voicemeeter, its SDK, the C Remote API, the RT Packet service and Streamer View app!
|
[Vincent Burel](https://github.com/vburel2018) for creating Voicemeeter and its SDK.
|
||||||
|
|
||||||
[Rdbende](https://github.com/rdbende) for creating the beautiful Sun Valley Tkinter theme and adding it to Pypi!
|
[Rdbende](https://github.com/rdbende) for creating the beautiful [Sun Valley theme][sv-theme].
|
||||||
|
|
||||||
|
|
||||||
|
[sv-theme]: https://github.com/rdbende/Sun-Valley-ttk-theme
|
||||||
@@ -4,12 +4,12 @@ import vmcompact
|
|||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
with voicemeeterlib.api(kind_id) as vmr:
|
KIND_ID = "banana"
|
||||||
app = vmcompact.connect(kind_id, vmr)
|
|
||||||
|
with voicemeeterlib.api(KIND_ID) as vmr:
|
||||||
|
app = vmcompact.connect(KIND_ID, vmr)
|
||||||
app.mainloop()
|
app.mainloop()
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
kind_id = "banana"
|
|
||||||
|
|
||||||
main()
|
main()
|
||||||
|
|||||||
40
build.ps1
Normal file
40
build.ps1
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
param(
|
||||||
|
[Parameter(Mandatory = $true)]
|
||||||
|
[string]$prefix,
|
||||||
|
[string]$theme
|
||||||
|
)
|
||||||
|
|
||||||
|
function Format-Path {
|
||||||
|
param($Kind)
|
||||||
|
return @(
|
||||||
|
$prefix,
|
||||||
|
(& { if ($theme) { $theme } else { "" } }),
|
||||||
|
"${Kind}"
|
||||||
|
).Where({ $_ -ne "" }) -Join "_"
|
||||||
|
}
|
||||||
|
|
||||||
|
function Compress-Builds {
|
||||||
|
$target = Join-Path -Path $PSScriptRoot -ChildPath "dist"
|
||||||
|
@("basic", "banana", "potato") | ForEach-Object {
|
||||||
|
$compress_path = Format-Path -Kind $_
|
||||||
|
Compress-Archive -Path $(Join-Path -Path $target -ChildPath $compress_path) -DestinationPath $(Join-Path -Path $target -ChildPath "${compress_path}.zip") -Force
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function Get-Builds {
|
||||||
|
@("basic", "banana", "potato") | ForEach-Object {
|
||||||
|
$spec_path = Format-Path -Kind $_
|
||||||
|
|
||||||
|
"building $spec_path" | Write-Host
|
||||||
|
|
||||||
|
poetry run pyinstaller "$spec_path.spec" --noconfirm
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function main {
|
||||||
|
Get-Builds
|
||||||
|
|
||||||
|
Compress-Builds
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($MyInvocation.InvocationName -ne '.') { main }
|
||||||
273
poetry.lock
generated
273
poetry.lock
generated
@@ -1,31 +1,72 @@
|
|||||||
|
# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand.
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "altgraph"
|
||||||
|
version = "0.17.4"
|
||||||
|
description = "Python graph (network) package"
|
||||||
|
optional = false
|
||||||
|
python-versions = "*"
|
||||||
|
files = [
|
||||||
|
{file = "altgraph-0.17.4-py2.py3-none-any.whl", hash = "sha256:642743b4750de17e655e6711601b077bc6598dbfa3ba5fa2b2a35ce12b508dff"},
|
||||||
|
{file = "altgraph-0.17.4.tar.gz", hash = "sha256:1b5afbb98f6c4dcadb2e2ae6ab9fa994bbb8c1d75f4fa96d340f9437ae454406"},
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "black"
|
name = "black"
|
||||||
version = "22.12.0"
|
version = "24.4.2"
|
||||||
description = "The uncompromising code formatter."
|
description = "The uncompromising code formatter."
|
||||||
category = "dev"
|
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.7"
|
python-versions = ">=3.8"
|
||||||
|
files = [
|
||||||
|
{file = "black-24.4.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:dd1b5a14e417189db4c7b64a6540f31730713d173f0b63e55fabd52d61d8fdce"},
|
||||||
|
{file = "black-24.4.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8e537d281831ad0e71007dcdcbe50a71470b978c453fa41ce77186bbe0ed6021"},
|
||||||
|
{file = "black-24.4.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eaea3008c281f1038edb473c1aa8ed8143a5535ff18f978a318f10302b254063"},
|
||||||
|
{file = "black-24.4.2-cp310-cp310-win_amd64.whl", hash = "sha256:7768a0dbf16a39aa5e9a3ded568bb545c8c2727396d063bbaf847df05b08cd96"},
|
||||||
|
{file = "black-24.4.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:257d724c2c9b1660f353b36c802ccece186a30accc7742c176d29c146df6e474"},
|
||||||
|
{file = "black-24.4.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:bdde6f877a18f24844e381d45e9947a49e97933573ac9d4345399be37621e26c"},
|
||||||
|
{file = "black-24.4.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e151054aa00bad1f4e1f04919542885f89f5f7d086b8a59e5000e6c616896ffb"},
|
||||||
|
{file = "black-24.4.2-cp311-cp311-win_amd64.whl", hash = "sha256:7e122b1c4fb252fd85df3ca93578732b4749d9be076593076ef4d07a0233c3e1"},
|
||||||
|
{file = "black-24.4.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:accf49e151c8ed2c0cdc528691838afd217c50412534e876a19270fea1e28e2d"},
|
||||||
|
{file = "black-24.4.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:88c57dc656038f1ab9f92b3eb5335ee9b021412feaa46330d5eba4e51fe49b04"},
|
||||||
|
{file = "black-24.4.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:be8bef99eb46d5021bf053114442914baeb3649a89dc5f3a555c88737e5e98fc"},
|
||||||
|
{file = "black-24.4.2-cp312-cp312-win_amd64.whl", hash = "sha256:415e686e87dbbe6f4cd5ef0fbf764af7b89f9057b97c908742b6008cc554b9c0"},
|
||||||
|
{file = "black-24.4.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:bf10f7310db693bb62692609b397e8d67257c55f949abde4c67f9cc574492cc7"},
|
||||||
|
{file = "black-24.4.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:98e123f1d5cfd42f886624d84464f7756f60ff6eab89ae845210631714f6db94"},
|
||||||
|
{file = "black-24.4.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:48a85f2cb5e6799a9ef05347b476cce6c182d6c71ee36925a6c194d074336ef8"},
|
||||||
|
{file = "black-24.4.2-cp38-cp38-win_amd64.whl", hash = "sha256:b1530ae42e9d6d5b670a34db49a94115a64596bc77710b1d05e9801e62ca0a7c"},
|
||||||
|
{file = "black-24.4.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:37aae07b029fa0174d39daf02748b379399b909652a806e5708199bd93899da1"},
|
||||||
|
{file = "black-24.4.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:da33a1a5e49c4122ccdfd56cd021ff1ebc4a1ec4e2d01594fef9b6f267a9e741"},
|
||||||
|
{file = "black-24.4.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ef703f83fc32e131e9bcc0a5094cfe85599e7109f896fe8bc96cc402f3eb4b6e"},
|
||||||
|
{file = "black-24.4.2-cp39-cp39-win_amd64.whl", hash = "sha256:b9176b9832e84308818a99a561e90aa479e73c523b3f77afd07913380ae2eab7"},
|
||||||
|
{file = "black-24.4.2-py3-none-any.whl", hash = "sha256:d36ed1124bb81b32f8614555b34cc4259c3fbc7eec17870e8ff8ded335b58d8c"},
|
||||||
|
{file = "black-24.4.2.tar.gz", hash = "sha256:c872b53057f000085da66a19c55d68f6f8ddcac2642392ad3a355878406fbd4d"},
|
||||||
|
]
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
click = ">=8.0.0"
|
click = ">=8.0.0"
|
||||||
mypy-extensions = ">=0.4.3"
|
mypy-extensions = ">=0.4.3"
|
||||||
|
packaging = ">=22.0"
|
||||||
pathspec = ">=0.9.0"
|
pathspec = ">=0.9.0"
|
||||||
platformdirs = ">=2"
|
platformdirs = ">=2"
|
||||||
tomli = {version = ">=1.1.0", markers = "python_full_version < \"3.11.0a7\""}
|
tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""}
|
||||||
|
typing-extensions = {version = ">=4.0.1", markers = "python_version < \"3.11\""}
|
||||||
|
|
||||||
[package.extras]
|
[package.extras]
|
||||||
colorama = ["colorama (>=0.4.3)"]
|
colorama = ["colorama (>=0.4.3)"]
|
||||||
d = ["aiohttp (>=3.7.4)"]
|
d = ["aiohttp (>=3.7.4)", "aiohttp (>=3.7.4,!=3.9.0)"]
|
||||||
jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"]
|
jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"]
|
||||||
uvloop = ["uvloop (>=0.15.2)"]
|
uvloop = ["uvloop (>=0.15.2)"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "click"
|
name = "click"
|
||||||
version = "8.1.3"
|
version = "8.1.7"
|
||||||
description = "Composable command line interface toolkit"
|
description = "Composable command line interface toolkit"
|
||||||
category = "dev"
|
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.7"
|
python-versions = ">=3.7"
|
||||||
|
files = [
|
||||||
|
{file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"},
|
||||||
|
{file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"},
|
||||||
|
]
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
colorama = {version = "*", markers = "platform_system == \"Windows\""}
|
colorama = {version = "*", markers = "platform_system == \"Windows\""}
|
||||||
@@ -34,104 +75,238 @@ colorama = {version = "*", markers = "platform_system == \"Windows\""}
|
|||||||
name = "colorama"
|
name = "colorama"
|
||||||
version = "0.4.6"
|
version = "0.4.6"
|
||||||
description = "Cross-platform colored terminal text."
|
description = "Cross-platform colored terminal text."
|
||||||
category = "dev"
|
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
|
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
|
||||||
|
files = [
|
||||||
|
{file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"},
|
||||||
|
{file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "isort"
|
name = "isort"
|
||||||
version = "5.12.0"
|
version = "5.13.2"
|
||||||
description = "A Python utility / library to sort Python imports."
|
description = "A Python utility / library to sort Python imports."
|
||||||
category = "dev"
|
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8.0"
|
python-versions = ">=3.8.0"
|
||||||
|
files = [
|
||||||
|
{file = "isort-5.13.2-py3-none-any.whl", hash = "sha256:8ca5e72a8d85860d5a3fa69b8745237f2939afe12dbf656afbcb47fe72d947a6"},
|
||||||
|
{file = "isort-5.13.2.tar.gz", hash = "sha256:48fdfcb9face5d58a4f6dde2e72a1fb8dcaf8ab26f95ab49fab84c2ddefb0109"},
|
||||||
|
]
|
||||||
|
|
||||||
[package.extras]
|
[package.extras]
|
||||||
colors = ["colorama (>=0.4.3)"]
|
colors = ["colorama (>=0.4.6)"]
|
||||||
requirements-deprecated-finder = ["pip-api", "pipreqs"]
|
|
||||||
pipfile-deprecated-finder = ["pip-shims (>=0.5.2)", "pipreqs", "requirementslib"]
|
[[package]]
|
||||||
plugins = ["setuptools"]
|
name = "macholib"
|
||||||
|
version = "1.16.3"
|
||||||
|
description = "Mach-O header analysis and editing"
|
||||||
|
optional = false
|
||||||
|
python-versions = "*"
|
||||||
|
files = [
|
||||||
|
{file = "macholib-1.16.3-py2.py3-none-any.whl", hash = "sha256:0e315d7583d38b8c77e815b1ecbdbf504a8258d8b3e17b61165c6feb60d18f2c"},
|
||||||
|
{file = "macholib-1.16.3.tar.gz", hash = "sha256:07ae9e15e8e4cd9a788013d81f5908b3609aa76f9b1421bae9c4d7606ec86a30"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
altgraph = ">=0.17"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "mypy-extensions"
|
name = "mypy-extensions"
|
||||||
version = "1.0.0"
|
version = "1.0.0"
|
||||||
description = "Type system extensions for programs checked with the mypy type checker."
|
description = "Type system extensions for programs checked with the mypy type checker."
|
||||||
category = "dev"
|
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.5"
|
python-versions = ">=3.5"
|
||||||
|
files = [
|
||||||
|
{file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"},
|
||||||
|
{file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "packaging"
|
||||||
|
version = "24.1"
|
||||||
|
description = "Core utilities for Python packages"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.8"
|
||||||
|
files = [
|
||||||
|
{file = "packaging-24.1-py3-none-any.whl", hash = "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124"},
|
||||||
|
{file = "packaging-24.1.tar.gz", hash = "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002"},
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pathspec"
|
name = "pathspec"
|
||||||
version = "0.11.1"
|
version = "0.12.1"
|
||||||
description = "Utility library for gitignore style pattern matching of file paths."
|
description = "Utility library for gitignore style pattern matching of file paths."
|
||||||
category = "dev"
|
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.7"
|
python-versions = ">=3.8"
|
||||||
|
files = [
|
||||||
|
{file = "pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"},
|
||||||
|
{file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pefile"
|
||||||
|
version = "2023.2.7"
|
||||||
|
description = "Python PE parsing module"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.6.0"
|
||||||
|
files = [
|
||||||
|
{file = "pefile-2023.2.7-py3-none-any.whl", hash = "sha256:da185cd2af68c08a6cd4481f7325ed600a88f6a813bad9dea07ab3ef73d8d8d6"},
|
||||||
|
{file = "pefile-2023.2.7.tar.gz", hash = "sha256:82e6114004b3d6911c77c3953e3838654b04511b8b66e8583db70c65998017dc"},
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "platformdirs"
|
name = "platformdirs"
|
||||||
version = "3.8.0"
|
version = "4.2.2"
|
||||||
description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"."
|
description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`."
|
||||||
category = "dev"
|
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.7"
|
python-versions = ">=3.8"
|
||||||
|
files = [
|
||||||
|
{file = "platformdirs-4.2.2-py3-none-any.whl", hash = "sha256:2d7a1657e36a80ea911db832a8a6ece5ee53d8de21edd5cc5879af6530b1bfee"},
|
||||||
|
{file = "platformdirs-4.2.2.tar.gz", hash = "sha256:38b7b51f512eed9e84a22788b4bce1de17c0adb134d6becb09836e37d8654cd3"},
|
||||||
|
]
|
||||||
|
|
||||||
[package.extras]
|
[package.extras]
|
||||||
docs = ["furo (>=2023.5.20)", "proselint (>=0.13)", "sphinx-autodoc-typehints (>=1.23,!=1.23.4)", "sphinx (>=7.0.1)"]
|
docs = ["furo (>=2023.9.10)", "proselint (>=0.13)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.25.2)"]
|
||||||
test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.10)", "pytest (>=7.3.1)"]
|
test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)"]
|
||||||
|
type = ["mypy (>=1.8)"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pyinstaller"
|
||||||
|
version = "6.8.0"
|
||||||
|
description = "PyInstaller bundles a Python application and all its dependencies into a single package."
|
||||||
|
optional = false
|
||||||
|
python-versions = "<3.13,>=3.8"
|
||||||
|
files = [
|
||||||
|
{file = "pyinstaller-6.8.0-py3-none-macosx_10_13_universal2.whl", hash = "sha256:5ff6bc2784c1026f8e2f04aa3760cbed41408e108a9d4cf1dd52ee8351a3f6e1"},
|
||||||
|
{file = "pyinstaller-6.8.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:39ac424d2ee2457d2ab11a5091436e75a0cccae207d460d180aa1fcbbafdd528"},
|
||||||
|
{file = "pyinstaller-6.8.0-py3-none-manylinux2014_i686.whl", hash = "sha256:355832a3acc7de90a255ecacd4b9f9e166a547a79c8905d49f14e3a75c1acdb9"},
|
||||||
|
{file = "pyinstaller-6.8.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:6303c7a009f47e6a96ef65aed49f41e36ece8d079b9193ca92fe807403e5fe80"},
|
||||||
|
{file = "pyinstaller-6.8.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:2b71509468c811968c0b5decb5bbe85b6292ea52d7b1f26313d2aabb673fa9a5"},
|
||||||
|
{file = "pyinstaller-6.8.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:ff31c5b99e05a4384bbe2071df67ec8b2b347640a375eae9b40218be2f1754c6"},
|
||||||
|
{file = "pyinstaller-6.8.0-py3-none-musllinux_1_1_aarch64.whl", hash = "sha256:000c36b13fe4cd8d0d8c2bc855b1ddcf39867b5adf389e6b5ca45b25fa3e619d"},
|
||||||
|
{file = "pyinstaller-6.8.0-py3-none-musllinux_1_1_x86_64.whl", hash = "sha256:fe0af018d7d5077180e3144ada89a4da5df8d07716eb7e9482834a56dc57a4e8"},
|
||||||
|
{file = "pyinstaller-6.8.0-py3-none-win32.whl", hash = "sha256:d257f6645c7334cbd66f38a4fac62c3ad614cc46302b2b5d9f8cc48c563bce0e"},
|
||||||
|
{file = "pyinstaller-6.8.0-py3-none-win_amd64.whl", hash = "sha256:81cccfa9b16699b457f4788c5cc119b50f3cd4d0db924955f15c33f2ad27a50d"},
|
||||||
|
{file = "pyinstaller-6.8.0-py3-none-win_arm64.whl", hash = "sha256:1c3060a263758cf7f0144ab4c016097b20451b2469d468763414665db1bb743d"},
|
||||||
|
{file = "pyinstaller-6.8.0.tar.gz", hash = "sha256:3f4b6520f4423fe19bcc2fd63ab7238851ae2bdcbc98f25bc5d2f97cc62012e9"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
altgraph = "*"
|
||||||
|
macholib = {version = ">=1.8", markers = "sys_platform == \"darwin\""}
|
||||||
|
packaging = ">=22.0"
|
||||||
|
pefile = {version = ">=2022.5.30", markers = "sys_platform == \"win32\""}
|
||||||
|
pyinstaller-hooks-contrib = ">=2024.6"
|
||||||
|
pywin32-ctypes = {version = ">=0.2.1", markers = "sys_platform == \"win32\""}
|
||||||
|
setuptools = ">=42.0.0"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
completion = ["argcomplete"]
|
||||||
|
hook-testing = ["execnet (>=1.5.0)", "psutil", "pytest (>=2.7.3)"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pyinstaller-hooks-contrib"
|
||||||
|
version = "2024.7"
|
||||||
|
description = "Community maintained hooks for PyInstaller"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.7"
|
||||||
|
files = [
|
||||||
|
{file = "pyinstaller_hooks_contrib-2024.7-py2.py3-none-any.whl", hash = "sha256:8bf0775771fbaf96bcd2f4dfd6f7ae6c1dd1b1efe254c7e50477b3c08e7841d8"},
|
||||||
|
{file = "pyinstaller_hooks_contrib-2024.7.tar.gz", hash = "sha256:fd5f37dcf99bece184e40642af88be16a9b89613ecb958a8bd1136634fc9fac5"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
packaging = ">=22.0"
|
||||||
|
setuptools = ">=42.0.0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pywin32-ctypes"
|
||||||
|
version = "0.2.2"
|
||||||
|
description = "A (partial) reimplementation of pywin32 using ctypes/cffi"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.6"
|
||||||
|
files = [
|
||||||
|
{file = "pywin32-ctypes-0.2.2.tar.gz", hash = "sha256:3426e063bdd5fd4df74a14fa3cf80a0b42845a87e1d1e81f6549f9daec593a60"},
|
||||||
|
{file = "pywin32_ctypes-0.2.2-py3-none-any.whl", hash = "sha256:bf490a1a709baf35d688fe0ecf980ed4de11d2b3e37b51e5442587a75d9957e7"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "setuptools"
|
||||||
|
version = "70.2.0"
|
||||||
|
description = "Easily download, build, install, upgrade, and uninstall Python packages"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.8"
|
||||||
|
files = [
|
||||||
|
{file = "setuptools-70.2.0-py3-none-any.whl", hash = "sha256:b8b8060bb426838fbe942479c90296ce976249451118ef566a5a0b7d8b78fb05"},
|
||||||
|
{file = "setuptools-70.2.0.tar.gz", hash = "sha256:bd63e505105011b25c3c11f753f7e3b8465ea739efddaccef8f0efac2137bac1"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "pyproject-hooks (!=1.1)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"]
|
||||||
|
test = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "importlib-metadata", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "jaraco.test", "mypy (==1.10.0)", "packaging (>=23.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-home (>=0.5)", "pytest-mypy", "pytest-perf", "pytest-ruff (>=0.3.2)", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sv-ttk"
|
name = "sv-ttk"
|
||||||
version = "2.5.1"
|
version = "2.6.0"
|
||||||
description = "A gorgeous theme for Tkinter, based on Windows 11's UI"
|
description = "A gorgeous theme for Tkinter, based on Windows 11's UI"
|
||||||
category = "main"
|
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.7"
|
python-versions = ">=3.8"
|
||||||
|
files = [
|
||||||
|
{file = "sv_ttk-2.6.0-py3-none-any.whl", hash = "sha256:4319c52edf2e14732fe84bdc9788e26f9e9a1ad79451ec0f89f0120ffc8105d9"},
|
||||||
|
{file = "sv_ttk-2.6.0.tar.gz", hash = "sha256:3fd440396c95e30e88f686fcf28be425480f7320d6bf346f9cea5d6f56702cc2"},
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tomli"
|
name = "tomli"
|
||||||
version = "2.0.1"
|
version = "2.0.1"
|
||||||
description = "A lil' TOML parser"
|
description = "A lil' TOML parser"
|
||||||
category = "main"
|
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.7"
|
python-versions = ">=3.7"
|
||||||
|
files = [
|
||||||
|
{file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"},
|
||||||
|
{file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"},
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "typing-extensions"
|
||||||
|
version = "4.12.2"
|
||||||
|
description = "Backported and Experimental Type Hints for Python 3.8+"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.8"
|
||||||
|
files = [
|
||||||
|
{file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"},
|
||||||
|
{file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"},
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "vban-cmd"
|
name = "vban-cmd"
|
||||||
version = "2.0.0"
|
version = "2.4.11"
|
||||||
description = "Python interface for the VBAN RT Packet Service (Sendtext)"
|
description = "Python interface for the VBAN RT Packet Service (Sendtext)"
|
||||||
category = "main"
|
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.10,<4.0"
|
python-versions = ">=3.10,<4.0"
|
||||||
|
files = [
|
||||||
|
{file = "vban_cmd-2.4.11-py3-none-any.whl", hash = "sha256:a74b7631222f340488f5d45bc9aa9d4e7a0f919687c9715619e8809c684875b7"},
|
||||||
|
{file = "vban_cmd-2.4.11.tar.gz", hash = "sha256:250ca8043f075eee11d2a811142d0205900d14d7e2f0cd98eb597901ead738f5"},
|
||||||
|
]
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
tomli = {version = ">=2.0.1,<3.0.0", markers = "python_version < \"3.11\""}
|
tomli = {version = ">=2.0.1,<3.0.0", markers = "python_version < \"3.11\""}
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "voicemeeter-api"
|
name = "voicemeeter-api"
|
||||||
version = "2.0.2"
|
version = "2.6.0"
|
||||||
description = "A Python wrapper for the Voiceemeter API"
|
description = "A Python wrapper for the Voiceemeter API"
|
||||||
category = "main"
|
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.10,<4.0"
|
python-versions = "<4.0,>=3.10"
|
||||||
|
files = [
|
||||||
|
{file = "voicemeeter_api-2.6.0-py3-none-any.whl", hash = "sha256:c2ef8eb063ce3aeac4827ad7883150c407a0effb0fde3778782cd3024a295255"},
|
||||||
|
{file = "voicemeeter_api-2.6.0.tar.gz", hash = "sha256:db93f27b58ce927c7d56084b224e1d0cdd6406ab7f26e4f99a9a873495a3d2e7"},
|
||||||
|
]
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
tomli = {version = ">=2.0.1,<3.0.0", markers = "python_version < \"3.11\""}
|
tomli = {version = ">=2.0.1,<3.0.0", markers = "python_version < \"3.11\""}
|
||||||
|
|
||||||
[metadata]
|
[metadata]
|
||||||
lock-version = "1.1"
|
lock-version = "2.0"
|
||||||
python-versions = "^3.10"
|
python-versions = ">=3.10,<3.13"
|
||||||
content-hash = "3a59de3a76e4c0ca11c0166750fa1af7d7c887750f855b48c45359068ef04798"
|
content-hash = "343eb64c79bba2d92eeb9af614c782dd175bd8a7b1a236a330b1dd9ae4d18a57"
|
||||||
|
|
||||||
[metadata.files]
|
|
||||||
black = []
|
|
||||||
click = []
|
|
||||||
colorama = []
|
|
||||||
isort = []
|
|
||||||
mypy-extensions = []
|
|
||||||
pathspec = []
|
|
||||||
platformdirs = []
|
|
||||||
sv-ttk = []
|
|
||||||
tomli = []
|
|
||||||
vban-cmd = []
|
|
||||||
voicemeeter-api = []
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[tool.poetry]
|
[tool.poetry]
|
||||||
name = "voicemeeter-compact"
|
name = "voicemeeter-compact"
|
||||||
version = "1.8.4"
|
version = "1.9.5"
|
||||||
description = "A Compact Voicemeeter Remote App"
|
description = "A Compact Voicemeeter Remote App"
|
||||||
authors = ["onyx-and-iris <code@onyxandiris.online>"]
|
authors = ["onyx-and-iris <code@onyxandiris.online>"]
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
@@ -11,16 +11,25 @@ packages = [{ include = "vmcompact" }]
|
|||||||
include = ["vmcompact/img/cat.ico"]
|
include = ["vmcompact/img/cat.ico"]
|
||||||
|
|
||||||
[tool.poetry.dependencies]
|
[tool.poetry.dependencies]
|
||||||
python = "^3.10"
|
python = ">=3.10,<3.13"
|
||||||
sv-ttk = "^2.5.1"
|
sv-ttk = "^2.6.0"
|
||||||
tomli = { version = "^2.0.1", python = "<3.11" }
|
tomli = { version = "^2.0.1", python = "<3.11" }
|
||||||
voicemeeter-api = "^2.0.2"
|
voicemeeter-api = "^2.6.0"
|
||||||
vban-cmd = "^2.0.0"
|
vban-cmd = "^2.4.11"
|
||||||
|
|
||||||
[tool.poetry.dev-dependencies]
|
[tool.poetry.group.dev.dependencies]
|
||||||
black = { version = "^22.6.0", allow-prereleases = true }
|
black = { version = ">=22.6,<25.0", allow-prereleases = true }
|
||||||
isort = "^5.12.0"
|
isort = "^5.12.0"
|
||||||
|
|
||||||
|
|
||||||
|
[tool.poetry.group.build.dependencies]
|
||||||
|
pyinstaller = "^6.3.0"
|
||||||
|
|
||||||
[build-system]
|
[build-system]
|
||||||
requires = ["poetry-core>=1.0.0"]
|
requires = ["poetry-core>=1.0.0"]
|
||||||
build-backend = "poetry.core.masonry.api"
|
build-backend = "poetry.core.masonry.api"
|
||||||
|
|
||||||
|
[tool.poetry.scripts]
|
||||||
|
build_sunvalley = "scripts:build_sunvalley"
|
||||||
|
build_forest = "scripts:build_forest"
|
||||||
|
build_all = "scripts:build_all"
|
||||||
|
|||||||
24
scripts.py
Normal file
24
scripts.py
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
def build_sunvalley():
|
||||||
|
buildscript = Path.cwd() / "build.ps1"
|
||||||
|
subprocess.run(["powershell", str(buildscript), "sv"])
|
||||||
|
|
||||||
|
|
||||||
|
def build_forest():
|
||||||
|
rewriter = Path.cwd() / "tools" / "rewriter.py"
|
||||||
|
subprocess.run([sys.executable, str(rewriter), "-r"])
|
||||||
|
|
||||||
|
buildscript = Path.cwd() / "build.ps1"
|
||||||
|
for theme in ("light", "dark"):
|
||||||
|
subprocess.run(["powershell", str(buildscript), "fst", theme])
|
||||||
|
|
||||||
|
subprocess.run([sys.executable, str(rewriter), "-c"])
|
||||||
|
|
||||||
|
|
||||||
|
def build_all():
|
||||||
|
steps = (build_sunvalley, build_forest)
|
||||||
|
[step() for step in steps]
|
||||||
250
tools/rewriter.py
Normal file
250
tools/rewriter.py
Normal file
@@ -0,0 +1,250 @@
|
|||||||
|
import argparse
|
||||||
|
import logging
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
logging.basicConfig(level=logging.DEBUG)
|
||||||
|
|
||||||
|
logger = logging.getLogger("vm-compact-rewriter")
|
||||||
|
|
||||||
|
PACKAGE_DIR = Path(__file__).parent.parent / "vmcompact"
|
||||||
|
|
||||||
|
SRC_DIR = Path(__file__).parent / "src"
|
||||||
|
|
||||||
|
|
||||||
|
def write_outs(output, outs: tuple):
|
||||||
|
for out in outs:
|
||||||
|
output.write(out)
|
||||||
|
|
||||||
|
|
||||||
|
def rewrite_app():
|
||||||
|
app_logger = logger.getChild("app")
|
||||||
|
app_logger.info("rewriting app.py")
|
||||||
|
infile = Path(SRC_DIR) / "app.bk"
|
||||||
|
outfile = Path(PACKAGE_DIR) / "app.py"
|
||||||
|
with open(infile, "r") as input:
|
||||||
|
with open(outfile, "w") as output:
|
||||||
|
for line in input:
|
||||||
|
match line:
|
||||||
|
# App init()
|
||||||
|
case " def __init__(self, vmr):\n":
|
||||||
|
output.write(" def __init__(self, vmr, theme):\n")
|
||||||
|
case " self._vmr = vmr\n":
|
||||||
|
write_outs(
|
||||||
|
output,
|
||||||
|
(
|
||||||
|
" self._vmr = vmr\n",
|
||||||
|
" self._theme = theme\n",
|
||||||
|
' tcldir = Path.cwd() / "theme"\n',
|
||||||
|
" if not tcldir.is_dir():\n",
|
||||||
|
' tcldir = Path.cwd() / "_internal" / "theme"\n',
|
||||||
|
' self.tk.call("source", tcldir.resolve() / f"forest-{self._theme}.tcl")\n',
|
||||||
|
),
|
||||||
|
)
|
||||||
|
# def connect()
|
||||||
|
case "def connect(kind_id: str, vmr) -> App:\n":
|
||||||
|
output.write(
|
||||||
|
'def connect(kind_id: str, vmr, theme="light") -> App:\n'
|
||||||
|
)
|
||||||
|
case " return VMMIN_cls(vmr)\n":
|
||||||
|
output.write(" return VMMIN_cls(vmr, theme)\n")
|
||||||
|
case _:
|
||||||
|
output.write(line)
|
||||||
|
|
||||||
|
|
||||||
|
def rewrite_builders():
|
||||||
|
builders_logger = logger.getChild("builders")
|
||||||
|
builders_logger.info("rewriting builders.py")
|
||||||
|
infile = Path(SRC_DIR) / "builders.bk"
|
||||||
|
outfile = Path(PACKAGE_DIR) / "builders.py"
|
||||||
|
with open(infile, "r") as input:
|
||||||
|
with open(outfile, "w") as output:
|
||||||
|
ignore_next_lines = 0
|
||||||
|
|
||||||
|
for line in input:
|
||||||
|
if ignore_next_lines > 0:
|
||||||
|
builders_logger.info(f"ignoring: {line}")
|
||||||
|
ignore_next_lines -= 1
|
||||||
|
continue
|
||||||
|
|
||||||
|
match line:
|
||||||
|
# loading themes
|
||||||
|
case "import sv_ttk\n":
|
||||||
|
output.write("#import sv_ttk\n")
|
||||||
|
case " self.app.resizable(False, False)\n":
|
||||||
|
write_outs(
|
||||||
|
output,
|
||||||
|
(
|
||||||
|
" self.app.resizable(False, False)\n"
|
||||||
|
" if _configuration.themes_enabled:\n",
|
||||||
|
' ttk.Style().theme_use(f"forest-{self.app._theme}")\n',
|
||||||
|
' self.logger.info(f"Forest Theme applied")\n',
|
||||||
|
),
|
||||||
|
)
|
||||||
|
ignore_next_lines = 6
|
||||||
|
# setting navframe button widths
|
||||||
|
case " variable=self.navframe.submix,\n":
|
||||||
|
write_outs(
|
||||||
|
output,
|
||||||
|
(
|
||||||
|
" variable=self.navframe.submix,\n"
|
||||||
|
" width=8,\n",
|
||||||
|
),
|
||||||
|
)
|
||||||
|
case " variable=self.navframe.channel,\n":
|
||||||
|
write_outs(
|
||||||
|
output,
|
||||||
|
(
|
||||||
|
" variable=self.navframe.channel,\n"
|
||||||
|
" width=8,\n",
|
||||||
|
),
|
||||||
|
)
|
||||||
|
case " variable=self.navframe.extend,\n":
|
||||||
|
write_outs(
|
||||||
|
output,
|
||||||
|
(
|
||||||
|
" variable=self.navframe.extend,\n"
|
||||||
|
" width=8,\n",
|
||||||
|
),
|
||||||
|
)
|
||||||
|
case " variable=self.navframe.info,\n":
|
||||||
|
write_outs(
|
||||||
|
output,
|
||||||
|
(
|
||||||
|
" variable=self.navframe.info,\n"
|
||||||
|
" width=8,\n",
|
||||||
|
),
|
||||||
|
)
|
||||||
|
# set channelframe button widths
|
||||||
|
case " variable=self.labelframe.mute,\n":
|
||||||
|
write_outs(
|
||||||
|
output,
|
||||||
|
(
|
||||||
|
" variable=self.labelframe.mute,\n"
|
||||||
|
" width=7,\n",
|
||||||
|
),
|
||||||
|
)
|
||||||
|
case " variable=self.labelframe.conf,\n":
|
||||||
|
write_outs(
|
||||||
|
output,
|
||||||
|
(
|
||||||
|
" variable=self.labelframe.conf,\n"
|
||||||
|
" width=7,\n",
|
||||||
|
),
|
||||||
|
)
|
||||||
|
case " variable=self.labelframe.on,\n":
|
||||||
|
write_outs(
|
||||||
|
output,
|
||||||
|
(
|
||||||
|
" variable=self.labelframe.on,\n"
|
||||||
|
" width=7,\n",
|
||||||
|
),
|
||||||
|
)
|
||||||
|
# set stripconfigframe button widths
|
||||||
|
case " self.configframe.phys_out_params.index(param)\n":
|
||||||
|
write_outs(
|
||||||
|
output,
|
||||||
|
(
|
||||||
|
" self.configframe.phys_out_params.index(param)\n",
|
||||||
|
" ],\n",
|
||||||
|
" width=6,\n",
|
||||||
|
),
|
||||||
|
)
|
||||||
|
ignore_next_lines = 1
|
||||||
|
case " self.configframe.virt_out_params.index(param)\n":
|
||||||
|
write_outs(
|
||||||
|
output,
|
||||||
|
(
|
||||||
|
" self.configframe.virt_out_params.index(param)\n",
|
||||||
|
" ],\n",
|
||||||
|
" width=6,\n",
|
||||||
|
),
|
||||||
|
)
|
||||||
|
ignore_next_lines = 1
|
||||||
|
# This does both strip and bus param vars buttons
|
||||||
|
case " variable=self.configframe.param_vars[i],\n":
|
||||||
|
write_outs(
|
||||||
|
output,
|
||||||
|
(
|
||||||
|
" variable=self.configframe.param_vars[i],\n",
|
||||||
|
" width=6,\n",
|
||||||
|
),
|
||||||
|
)
|
||||||
|
case _:
|
||||||
|
if "Toggle.TButton" in line:
|
||||||
|
output.write(line.replace("Toggle.TButton", "ToggleButton"))
|
||||||
|
else:
|
||||||
|
output.write(line)
|
||||||
|
|
||||||
|
|
||||||
|
def rewrite_menu():
|
||||||
|
menu_logger = logger.getChild("menu")
|
||||||
|
menu_logger.info("rewriting menu.py")
|
||||||
|
infile = Path(SRC_DIR) / "menu.bk"
|
||||||
|
outfile = Path(PACKAGE_DIR) / "menu.py"
|
||||||
|
with open(infile, "r") as input:
|
||||||
|
with open(outfile, "w") as output:
|
||||||
|
ignore_next_lines = 0
|
||||||
|
|
||||||
|
for line in input:
|
||||||
|
if ignore_next_lines > 0:
|
||||||
|
menu_logger.info(f"ignoring: {line}")
|
||||||
|
ignore_next_lines -= 1
|
||||||
|
continue
|
||||||
|
match line:
|
||||||
|
case "import sv_ttk\n":
|
||||||
|
output.write("#import sv_ttk\n")
|
||||||
|
case " # layout/themes\n":
|
||||||
|
ignore_next_lines = 14
|
||||||
|
case _:
|
||||||
|
output.write(line)
|
||||||
|
|
||||||
|
|
||||||
|
def prepare_for_build():
|
||||||
|
################# MOVE FILES FROM PACKAGE DIR INTO SRC DIR #########################
|
||||||
|
for file in (
|
||||||
|
PACKAGE_DIR / "app.py",
|
||||||
|
PACKAGE_DIR / "builders.py",
|
||||||
|
PACKAGE_DIR / "menu.py",
|
||||||
|
):
|
||||||
|
if file.exists():
|
||||||
|
logger.debug(f"moving {str(file)}")
|
||||||
|
file.rename(SRC_DIR / f"{file.stem}.bk")
|
||||||
|
|
||||||
|
###################### RUN THE FILE REWRITER FOR EACH *.BK #########################
|
||||||
|
steps = (
|
||||||
|
rewrite_app,
|
||||||
|
rewrite_builders,
|
||||||
|
rewrite_menu,
|
||||||
|
)
|
||||||
|
[step() for step in steps]
|
||||||
|
|
||||||
|
|
||||||
|
def cleanup():
|
||||||
|
########################## RESTORE *.BK FILES #####################################
|
||||||
|
for file in (
|
||||||
|
PACKAGE_DIR / "app.py",
|
||||||
|
PACKAGE_DIR / "builders.py",
|
||||||
|
PACKAGE_DIR / "menu.py",
|
||||||
|
):
|
||||||
|
file.unlink()
|
||||||
|
|
||||||
|
for file in (
|
||||||
|
SRC_DIR / "app.bk",
|
||||||
|
SRC_DIR / "builders.bk",
|
||||||
|
SRC_DIR / "menu.bk",
|
||||||
|
):
|
||||||
|
file.rename(PACKAGE_DIR / f"{file.stem}.py")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
parser.add_argument("-r", "--rewrite", action="store_true")
|
||||||
|
parser.add_argument("-c", "--cleanup", action="store_true")
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
if args.rewrite:
|
||||||
|
logger.info("preparing files for build")
|
||||||
|
prepare_for_build()
|
||||||
|
elif args.cleanup:
|
||||||
|
logger.info("cleaning up files")
|
||||||
|
cleanup()
|
||||||
0
tools/src/.gitkeep
Normal file
0
tools/src/.gitkeep
Normal file
@@ -2,12 +2,14 @@ import logging
|
|||||||
import tkinter as tk
|
import tkinter as tk
|
||||||
from functools import cached_property
|
from functools import cached_property
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from tkinter import ttk
|
from tkinter import messagebox, ttk
|
||||||
from typing import NamedTuple
|
from typing import NamedTuple
|
||||||
|
|
||||||
|
import voicemeeterlib
|
||||||
|
|
||||||
from .builders import MainFrameBuilder
|
from .builders import MainFrameBuilder
|
||||||
from .configurations import loader
|
from .configurations import loader
|
||||||
from .data import _base_values, _configuration, _kinds_all
|
from .data import _base_values, _configuration, _kinds_all, get_configuration
|
||||||
from .errors import VMCompactError
|
from .errors import VMCompactError
|
||||||
from .menu import Menus
|
from .menu import Menus
|
||||||
from .subject import Subject
|
from .subject import Subject
|
||||||
@@ -40,15 +42,16 @@ class App(tk.Tk):
|
|||||||
self.logger = logger.getChild(self.__class__.__name__)
|
self.logger = logger.getChild(self.__class__.__name__)
|
||||||
self._vmr = vmr
|
self._vmr = vmr
|
||||||
self._vmr.event.add(["pdirty", "ldirty"])
|
self._vmr.event.add(["pdirty", "ldirty"])
|
||||||
self.after(12000 if self._vmr.gui.launched_by_api else 1, self.start_updates)
|
self.subject = Subject()
|
||||||
|
self.start_updates()
|
||||||
self._vmr.init_thread()
|
self._vmr.init_thread()
|
||||||
icon_path = Path(__file__).parent.resolve() / "img" / "cat.ico"
|
icon_path = Path(__file__).parent.resolve() / "img" / "cat.ico"
|
||||||
if icon_path.is_file():
|
if icon_path.is_file():
|
||||||
self.iconbitmap(str(icon_path))
|
self.iconbitmap(str(icon_path))
|
||||||
self.minsize(275, False)
|
self.minsize(275, False)
|
||||||
self.subject = Subject()
|
|
||||||
self._configs = None
|
self._configs = None
|
||||||
self["menu"] = Menus(self, vmr)
|
self.protocol("WM_DELETE_WINDOW", self.on_close_window)
|
||||||
|
self.menu = self["menu"] = Menus(self, vmr)
|
||||||
self.styletable = ttk.Style()
|
self.styletable = ttk.Style()
|
||||||
if _configuration.config:
|
if _configuration.config:
|
||||||
vmr.apply_config(_configuration.config)
|
vmr.apply_config(_configuration.config)
|
||||||
@@ -58,11 +61,7 @@ class App(tk.Tk):
|
|||||||
self.drag_id = ""
|
self.drag_id = ""
|
||||||
self.bind("<Configure>", self.dragging)
|
self.bind("<Configure>", self.dragging)
|
||||||
|
|
||||||
def start_updates(self):
|
self.after(1, self.healthcheck_step)
|
||||||
self.logger.debug("updates started")
|
|
||||||
_base_values.run_update = True
|
|
||||||
if self._vmr.gui.launched_by_api:
|
|
||||||
self.on_pdirty()
|
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return f"{type(self).__name__}App"
|
return f"{type(self).__name__}App"
|
||||||
@@ -148,6 +147,52 @@ class App(tk.Tk):
|
|||||||
self._configs = loader(self.kind.name, self.target)
|
self._configs = loader(self.kind.name, self.target)
|
||||||
return self._configs
|
return self._configs
|
||||||
|
|
||||||
|
def start_updates(self):
|
||||||
|
def init():
|
||||||
|
self.logger.debug("updates started")
|
||||||
|
_base_values.run_update = True
|
||||||
|
|
||||||
|
if self._vmr.gui.launched_by_api:
|
||||||
|
self.subject.notify("pdirty")
|
||||||
|
self.after(12000, init)
|
||||||
|
else:
|
||||||
|
init()
|
||||||
|
|
||||||
|
def healthcheck_step(self):
|
||||||
|
if not _base_values.vban_connected:
|
||||||
|
try:
|
||||||
|
self._vmr.version
|
||||||
|
except voicemeeterlib.error.CAPIError:
|
||||||
|
resp = messagebox.askyesno(message="Restart Voicemeeter GUI?")
|
||||||
|
if resp:
|
||||||
|
self.logger.debug(
|
||||||
|
"healthcheck failed, rebuilding the app after GUI restart."
|
||||||
|
)
|
||||||
|
self._vmr.end_thread()
|
||||||
|
self._vmr.run_voicemeeter(self._vmr.kind.name)
|
||||||
|
_base_values.run_update = False
|
||||||
|
self._vmr.init_thread()
|
||||||
|
self.after(8000, self.start_updates)
|
||||||
|
self._destroy_top_level_frames()
|
||||||
|
self.build_app(self._vmr.kind)
|
||||||
|
vban_config = get_configuration("vban")
|
||||||
|
for i, _ in enumerate(vban_config):
|
||||||
|
target = getattr(self.menu, f"menu_vban_{i+1}")
|
||||||
|
target.entryconfig(0, state="normal")
|
||||||
|
target.entryconfig(1, state="disabled")
|
||||||
|
[
|
||||||
|
self.menu.menu_vban.entryconfig(j, state="normal")
|
||||||
|
for j, _ in enumerate(self.menu.menu_vban.winfo_children())
|
||||||
|
]
|
||||||
|
else:
|
||||||
|
self.destroy()
|
||||||
|
self.after(250, self.healthcheck_step)
|
||||||
|
|
||||||
|
def on_close_window(self):
|
||||||
|
if _base_values.vban_connected:
|
||||||
|
self._vban.logout()
|
||||||
|
self.destroy()
|
||||||
|
|
||||||
|
|
||||||
_apps = {kind.name: App.make(kind) for kind in _kinds_all}
|
_apps = {kind.name: App.make(kind) for kind in _kinds_all}
|
||||||
|
|
||||||
|
|||||||
@@ -249,7 +249,13 @@ class ChannelLabelFrameBuilder(AbstractBuilder):
|
|||||||
self.scale.bind("<Double-Button-1>", self.labelframe.reset_gain)
|
self.scale.bind("<Double-Button-1>", self.labelframe.reset_gain)
|
||||||
self.scale.bind("<Button-1>", self.labelframe.scale_press)
|
self.scale.bind("<Button-1>", self.labelframe.scale_press)
|
||||||
self.scale.bind("<ButtonRelease-1>", self.labelframe.scale_release)
|
self.scale.bind("<ButtonRelease-1>", self.labelframe.scale_release)
|
||||||
self.scale.bind("<MouseWheel>", self.labelframe._on_mousewheel)
|
self.scale.bind(
|
||||||
|
"<MouseWheel>",
|
||||||
|
partial(
|
||||||
|
self.labelframe.pause_updates,
|
||||||
|
self.labelframe._on_mousewheel,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
def add_gain_label(self):
|
def add_gain_label(self):
|
||||||
self.labelframe.gain_label = ttk.Label(
|
self.labelframe.gain_label = ttk.Label(
|
||||||
@@ -263,7 +269,7 @@ class ChannelLabelFrameBuilder(AbstractBuilder):
|
|||||||
self.button_mute = ttk.Checkbutton(
|
self.button_mute = ttk.Checkbutton(
|
||||||
self.labelframe,
|
self.labelframe,
|
||||||
text="MUTE",
|
text="MUTE",
|
||||||
command=partial(self.labelframe.toggle_mute, "mute"),
|
command=partial(self.labelframe.pause_updates, self.labelframe.toggle_mute),
|
||||||
style=f"{'Toggle.TButton' if _configuration.themes_enabled else f'{self.identifier}Mute{self.index}.TButton'}",
|
style=f"{'Toggle.TButton' if _configuration.themes_enabled else f'{self.identifier}Mute{self.index}.TButton'}",
|
||||||
variable=self.labelframe.mute,
|
variable=self.labelframe.mute,
|
||||||
)
|
)
|
||||||
@@ -283,7 +289,7 @@ class ChannelLabelFrameBuilder(AbstractBuilder):
|
|||||||
self.button_on = ttk.Checkbutton(
|
self.button_on = ttk.Checkbutton(
|
||||||
self.labelframe,
|
self.labelframe,
|
||||||
text="ON",
|
text="ON",
|
||||||
command=self.labelframe.set_on,
|
command=partial(self.labelframe.pause_updates, self.labelframe.set_on),
|
||||||
style=f"{'Toggle.TButton' if _configuration.themes_enabled else f'{self.identifier}On{self.index}.TButton'}",
|
style=f"{'Toggle.TButton' if _configuration.themes_enabled else f'{self.identifier}On{self.index}.TButton'}",
|
||||||
variable=self.labelframe.on,
|
variable=self.labelframe.on,
|
||||||
)
|
)
|
||||||
@@ -486,7 +492,9 @@ class StripConfigFrameBuilder(ChannelConfigFrameBuilder):
|
|||||||
ttk.Checkbutton(
|
ttk.Checkbutton(
|
||||||
self.configframe,
|
self.configframe,
|
||||||
text=param,
|
text=param,
|
||||||
command=partial(self.configframe.toggle_a, param),
|
command=partial(
|
||||||
|
self.configframe.pause_updates, self.configframe.toggle_a, param
|
||||||
|
),
|
||||||
style=f"{'Toggle.TButton' if _configuration.themes_enabled else f'{param}.TButton'}",
|
style=f"{'Toggle.TButton' if _configuration.themes_enabled else f'{param}.TButton'}",
|
||||||
variable=self.configframe.phys_out_params_vars[
|
variable=self.configframe.phys_out_params_vars[
|
||||||
self.configframe.phys_out_params.index(param)
|
self.configframe.phys_out_params.index(param)
|
||||||
@@ -507,7 +515,9 @@ class StripConfigFrameBuilder(ChannelConfigFrameBuilder):
|
|||||||
ttk.Checkbutton(
|
ttk.Checkbutton(
|
||||||
self.configframe,
|
self.configframe,
|
||||||
text=param,
|
text=param,
|
||||||
command=partial(self.configframe.toggle_b, param),
|
command=partial(
|
||||||
|
self.configframe.pause_updates, self.configframe.toggle_b, param
|
||||||
|
),
|
||||||
style=f"{'Toggle.TButton' if _configuration.themes_enabled else f'{param}.TButton'}",
|
style=f"{'Toggle.TButton' if _configuration.themes_enabled else f'{param}.TButton'}",
|
||||||
variable=self.configframe.virt_out_params_vars[
|
variable=self.configframe.virt_out_params_vars[
|
||||||
self.configframe.virt_out_params.index(param)
|
self.configframe.virt_out_params.index(param)
|
||||||
@@ -528,7 +538,9 @@ class StripConfigFrameBuilder(ChannelConfigFrameBuilder):
|
|||||||
ttk.Checkbutton(
|
ttk.Checkbutton(
|
||||||
self.configframe,
|
self.configframe,
|
||||||
text=param,
|
text=param,
|
||||||
command=partial(self.configframe.toggle_p, param),
|
command=partial(
|
||||||
|
self.configframe.pause_updates, self.configframe.toggle_p, param
|
||||||
|
),
|
||||||
style=f"{'Toggle.TButton' if _configuration.themes_enabled else f'{param}.TButton'}",
|
style=f"{'Toggle.TButton' if _configuration.themes_enabled else f'{param}.TButton'}",
|
||||||
variable=self.configframe.param_vars[i],
|
variable=self.configframe.param_vars[i],
|
||||||
)
|
)
|
||||||
@@ -578,10 +590,16 @@ class BusConfigFrameBuilder(ChannelConfigFrameBuilder):
|
|||||||
column=0, row=0, columnspan=2, sticky=(tk.W)
|
column=0, row=0, columnspan=2, sticky=(tk.W)
|
||||||
)
|
)
|
||||||
self.configframe.busmode_button.bind(
|
self.configframe.busmode_button.bind(
|
||||||
"<Button-1>", self.configframe.rotate_bus_modes_right
|
"<Button-1>",
|
||||||
|
partial(
|
||||||
|
self.configframe.pause_updates, self.configframe.rotate_bus_modes_right
|
||||||
|
),
|
||||||
)
|
)
|
||||||
self.configframe.busmode_button.bind(
|
self.configframe.busmode_button.bind(
|
||||||
"<Button-3>", self.configframe.rotate_bus_modes_left
|
"<Button-3>",
|
||||||
|
partial(
|
||||||
|
self.configframe.pause_updates, self.configframe.rotate_bus_modes_left
|
||||||
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
def create_param_buttons(self):
|
def create_param_buttons(self):
|
||||||
@@ -589,7 +607,9 @@ class BusConfigFrameBuilder(ChannelConfigFrameBuilder):
|
|||||||
ttk.Checkbutton(
|
ttk.Checkbutton(
|
||||||
self.configframe,
|
self.configframe,
|
||||||
text=param,
|
text=param,
|
||||||
command=partial(self.configframe.toggle_p, param),
|
command=partial(
|
||||||
|
self.configframe.pause_updates, self.configframe.toggle_p, param
|
||||||
|
),
|
||||||
style=f"{'Toggle.TButton' if _configuration.themes_enabled else f'{param}.TButton'}",
|
style=f"{'Toggle.TButton' if _configuration.themes_enabled else f'{param}.TButton'}",
|
||||||
variable=self.configframe.param_vars[i],
|
variable=self.configframe.param_vars[i],
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -88,17 +88,27 @@ class ChannelLabelFrame(ttk.LabelFrame):
|
|||||||
self.parent.target.event.add("ldirty")
|
self.parent.target.event.add("ldirty")
|
||||||
self.after(500, self.resume_updates)
|
self.after(500, self.resume_updates)
|
||||||
|
|
||||||
|
def pause_updates(self, func, *args):
|
||||||
|
"""function wrapper, adds a 50ms delay on updates"""
|
||||||
|
_base_values.run_update = False
|
||||||
|
|
||||||
|
func(*args)
|
||||||
|
|
||||||
|
self.after(50, self.resume_updates)
|
||||||
|
|
||||||
def resume_updates(self):
|
def resume_updates(self):
|
||||||
_base_values.run_update = True
|
_base_values.run_update = True
|
||||||
|
|
||||||
def _on_mousewheel(self, event):
|
def _on_mousewheel(self, event):
|
||||||
_base_values.run_update = False
|
|
||||||
self.gain.set(
|
self.gain.set(
|
||||||
self.gain.get()
|
round(
|
||||||
+ (
|
self.gain.get()
|
||||||
_configuration.mwscroll_step
|
+ (
|
||||||
if event.delta > 0
|
_configuration.mwscroll_step
|
||||||
else -_configuration.mwscroll_step
|
if event.delta > 0
|
||||||
|
else -_configuration.mwscroll_step
|
||||||
|
),
|
||||||
|
1,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
if self.gain.get() > 12:
|
if self.gain.get() > 12:
|
||||||
@@ -106,7 +116,7 @@ class ChannelLabelFrame(ttk.LabelFrame):
|
|||||||
elif self.gain.get() < -60:
|
elif self.gain.get() < -60:
|
||||||
self.gain.set(-60)
|
self.gain.set(-60)
|
||||||
self.setter("gain", self.gain.get())
|
self.setter("gain", self.gain.get())
|
||||||
self.after(1, self.resume_updates)
|
self.gainlabel.set(round(self.gain.get(), 1))
|
||||||
|
|
||||||
def open_config(self):
|
def open_config(self):
|
||||||
if self.conf.get():
|
if self.conf.get():
|
||||||
@@ -141,17 +151,18 @@ class ChannelLabelFrame(ttk.LabelFrame):
|
|||||||
def sync_labels(self):
|
def sync_labels(self):
|
||||||
"""sync labelframes according to label text"""
|
"""sync labelframes according to label text"""
|
||||||
retval = self.getter("label")
|
retval = self.getter("label")
|
||||||
self.parent.label_cache[self.id].insert(self.index, retval)
|
if self.parent.label_cache[self.id][self.index] != retval:
|
||||||
if len(retval) > 10:
|
self.parent.label_cache[self.id][self.index] = retval
|
||||||
retval = f"{retval[:8]}.."
|
if len(retval) > 10:
|
||||||
if not retval:
|
retval = f"{retval[:8]}.."
|
||||||
self.parent.columnconfigure(self.index, minsize=0)
|
if not retval:
|
||||||
self.parent.parent.subject.remove(self)
|
self.parent.columnconfigure(self.index, minsize=0)
|
||||||
self.grid_remove()
|
self.parent.parent.subject.remove(self)
|
||||||
else:
|
self.grid_remove()
|
||||||
self.parent.parent.subject.add(self)
|
else:
|
||||||
self.grid()
|
self.parent.parent.subject.add(self)
|
||||||
self.configure(text=retval)
|
self.grid()
|
||||||
|
self.configure(text=retval)
|
||||||
|
|
||||||
def grid_configure(self):
|
def grid_configure(self):
|
||||||
self.grid(padx=_configuration.channel_xpadding, sticky=(tk.N, tk.S))
|
self.grid(padx=_configuration.channel_xpadding, sticky=(tk.N, tk.S))
|
||||||
@@ -218,15 +229,18 @@ class Bus(ChannelLabelFrame):
|
|||||||
|
|
||||||
|
|
||||||
class ChannelFrame(ttk.Frame):
|
class ChannelFrame(ttk.Frame):
|
||||||
label_cache = {"strip": list(), "bus": list()}
|
|
||||||
|
|
||||||
def init(self, parent, id):
|
def init(self, parent, id):
|
||||||
super().__init__(parent)
|
super().__init__(parent)
|
||||||
self.parent = parent
|
self.parent = parent
|
||||||
self.id = id
|
self.id = id
|
||||||
self.phys_in, self.virt_in = parent.kind.ins
|
self.phys_in, self.virt_in = parent.kind.ins
|
||||||
self.phys_out, self.virt_out = parent.kind.outs
|
self.phys_out, self.virt_out = parent.kind.outs
|
||||||
|
self.label_cache = {
|
||||||
|
"strip": [""] * (self.phys_in + self.virt_in),
|
||||||
|
"bus": [""] * (self.phys_out + self.virt_out),
|
||||||
|
}
|
||||||
self.parent.subject.add(self)
|
self.parent.subject.add(self)
|
||||||
|
self.update_labels()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def target(self):
|
def target(self):
|
||||||
@@ -248,13 +262,13 @@ class ChannelFrame(ttk.Frame):
|
|||||||
if isinstance(frame, ttk.LabelFrame)
|
if isinstance(frame, ttk.LabelFrame)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def update_labels(self):
|
||||||
|
for labelframe in self.labelframes:
|
||||||
|
labelframe.on_update("labelframe")
|
||||||
|
|
||||||
def on_update(self, subject):
|
def on_update(self, subject):
|
||||||
if subject == "pdirty":
|
if subject == "pdirty":
|
||||||
target = getattr(self.target, self.id)
|
self.update_labels()
|
||||||
num = getattr(self.parent.kind, f"num_{self.id}")
|
|
||||||
if self.label_cache[self.id] != [target[i].label for i in range(num)]:
|
|
||||||
for labelframe in self.labelframes:
|
|
||||||
labelframe.on_update("labelframe")
|
|
||||||
|
|
||||||
def grid_configure(self):
|
def grid_configure(self):
|
||||||
[
|
[
|
||||||
@@ -270,7 +284,7 @@ class ChannelFrame(ttk.Frame):
|
|||||||
setattr(self.parent, f"{self.identifier}_frame", None)
|
setattr(self.parent, f"{self.identifier}_frame", None)
|
||||||
|
|
||||||
|
|
||||||
def _make_channelframe(parent, id):
|
def _make_channelframe(parent, identifier):
|
||||||
"""
|
"""
|
||||||
Creates a Channel Frame class of type strip or bus
|
Creates a Channel Frame class of type strip or bus
|
||||||
"""
|
"""
|
||||||
@@ -278,29 +292,33 @@ def _make_channelframe(parent, id):
|
|||||||
phys_in, virt_in = parent.kind.ins
|
phys_in, virt_in = parent.kind.ins
|
||||||
phys_out, virt_out = parent.kind.outs
|
phys_out, virt_out = parent.kind.outs
|
||||||
|
|
||||||
def init_labels(self, id):
|
def init_labels(self):
|
||||||
"""
|
"""
|
||||||
Grids each labelframe, grid_removes any without a label
|
Grids each labelframe, grid_removes any without a label
|
||||||
"""
|
"""
|
||||||
|
|
||||||
for i, labelframe in enumerate(
|
for i, labelframe in enumerate(
|
||||||
getattr(self, "strips" if id == "strip" else "buses")
|
getattr(self, "strips" if identifier == "strip" else "buses")
|
||||||
):
|
):
|
||||||
labelframe.grid(row=0, column=i)
|
labelframe.grid(row=0, column=i)
|
||||||
if not labelframe.target.label:
|
label = labelframe.target.label
|
||||||
|
if not label:
|
||||||
self.columnconfigure(i, minsize=0)
|
self.columnconfigure(i, minsize=0)
|
||||||
labelframe.grid_remove()
|
labelframe.grid_remove()
|
||||||
|
self.label_cache[identifier][i] = label
|
||||||
|
|
||||||
def init_strip(self, *args, **kwargs):
|
def init_strip(self, *args, **kwargs):
|
||||||
self.init(parent, id)
|
self.init(parent, identifier)
|
||||||
self.strips = tuple(Strip(self, i, id) for i in range(phys_in + virt_in))
|
self.strips = tuple(
|
||||||
|
Strip(self, i, identifier) for i in range(phys_in + virt_in)
|
||||||
|
)
|
||||||
self.grid(row=0, column=0, sticky=(tk.W))
|
self.grid(row=0, column=0, sticky=(tk.W))
|
||||||
self.grid_configure()
|
self.grid_configure()
|
||||||
init_labels(self, id)
|
init_labels(self)
|
||||||
|
|
||||||
def init_bus(self, *args, **kwargs):
|
def init_bus(self, *args, **kwargs):
|
||||||
self.init(parent, id)
|
self.init(parent, identifier)
|
||||||
self.buses = tuple(Bus(self, i, id) for i in range(phys_out + virt_out))
|
self.buses = tuple(Bus(self, i, identifier) for i in range(phys_out + virt_out))
|
||||||
if _configuration.extended:
|
if _configuration.extended:
|
||||||
if _configuration.extends_horizontal:
|
if _configuration.extends_horizontal:
|
||||||
self.grid(row=0, column=2, sticky=(tk.W))
|
self.grid(row=0, column=2, sticky=(tk.W))
|
||||||
@@ -309,11 +327,11 @@ def _make_channelframe(parent, id):
|
|||||||
else:
|
else:
|
||||||
self.grid(row=0, column=0)
|
self.grid(row=0, column=0)
|
||||||
self.grid_configure()
|
self.grid_configure()
|
||||||
init_labels(self, id)
|
init_labels(self)
|
||||||
|
|
||||||
if id == "strip":
|
if identifier == "strip":
|
||||||
CHANNELFRAME_cls = type(
|
CHANNELFRAME_cls = type(
|
||||||
f"ChannelFrame{id.capitalize()}",
|
f"ChannelFrame{identifier.capitalize()}",
|
||||||
(ChannelFrame,),
|
(ChannelFrame,),
|
||||||
{
|
{
|
||||||
"__init__": init_strip,
|
"__init__": init_strip,
|
||||||
@@ -321,7 +339,7 @@ def _make_channelframe(parent, id):
|
|||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
CHANNELFRAME_cls = type(
|
CHANNELFRAME_cls = type(
|
||||||
f"ChannelFrame{id.capitalize()}",
|
f"ChannelFrame{identifier.capitalize()}",
|
||||||
(ChannelFrame,),
|
(ChannelFrame,),
|
||||||
{
|
{
|
||||||
"__init__": init_bus,
|
"__init__": init_bus,
|
||||||
|
|||||||
@@ -68,6 +68,14 @@ class Config(ttk.Frame):
|
|||||||
self.parent.target.event.add("ldirty")
|
self.parent.target.event.add("ldirty")
|
||||||
self.after(350, self.resume_updates)
|
self.after(350, self.resume_updates)
|
||||||
|
|
||||||
|
def pause_updates(self, func, *args):
|
||||||
|
"""function wrapper, adds a 50ms delay on updates"""
|
||||||
|
_base_values.run_update = False
|
||||||
|
|
||||||
|
func(*args)
|
||||||
|
|
||||||
|
self.after(50, self.resume_updates)
|
||||||
|
|
||||||
def resume_updates(self):
|
def resume_updates(self):
|
||||||
_base_values.run_update = True
|
_base_values.run_update = True
|
||||||
|
|
||||||
|
|||||||
@@ -78,6 +78,14 @@ class GainLayer(ttk.LabelFrame):
|
|||||||
self.parent.target.event.add("ldirty")
|
self.parent.target.event.add("ldirty")
|
||||||
self.after(500, self.resume_updates)
|
self.after(500, self.resume_updates)
|
||||||
|
|
||||||
|
def pause_updates(self, func, *args):
|
||||||
|
"""function wrapper, adds a 50ms delay on updates"""
|
||||||
|
_base_values.run_update = False
|
||||||
|
|
||||||
|
func(*args)
|
||||||
|
|
||||||
|
self.after(50, self.resume_updates)
|
||||||
|
|
||||||
def resume_updates(self):
|
def resume_updates(self):
|
||||||
_base_values.run_update = True
|
_base_values.run_update = True
|
||||||
|
|
||||||
|
|||||||
@@ -4,10 +4,11 @@ import webbrowser
|
|||||||
from functools import partial
|
from functools import partial
|
||||||
from tkinter import messagebox
|
from tkinter import messagebox
|
||||||
|
|
||||||
import sv_ttk
|
|
||||||
import vban_cmd
|
import vban_cmd
|
||||||
from vban_cmd.error import VBANCMDConnectionError
|
from vban_cmd.error import VBANCMDConnectionError
|
||||||
|
|
||||||
|
import sv_ttk
|
||||||
|
|
||||||
from .data import _base_values, _configuration, get_configuration, kind_get
|
from .data import _base_values, _configuration, get_configuration, kind_get
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
@@ -224,7 +225,10 @@ class Menus(tk.Menu):
|
|||||||
]
|
]
|
||||||
|
|
||||||
def action_invoke_voicemeeter(self, cmd):
|
def action_invoke_voicemeeter(self, cmd):
|
||||||
getattr(self.target.command, cmd)()
|
if fn := getattr(self.target.command, cmd):
|
||||||
|
fn()
|
||||||
|
if cmd == "shutdown":
|
||||||
|
self.parent.on_close_window()
|
||||||
|
|
||||||
def action_set_voicemeeter(self, cmd, val=True):
|
def action_set_voicemeeter(self, cmd, val=True):
|
||||||
if cmd == "lock":
|
if cmd == "lock":
|
||||||
@@ -235,10 +239,14 @@ class Menus(tk.Menu):
|
|||||||
def load_custom_profile(self, profile):
|
def load_custom_profile(self, profile):
|
||||||
self.logger.info(f"loading user profile {profile}")
|
self.logger.info(f"loading user profile {profile}")
|
||||||
self.target.apply(profile)
|
self.target.apply(profile)
|
||||||
|
if not _base_values.run_update:
|
||||||
|
self.parent.subject.notify("pdirty")
|
||||||
|
|
||||||
def load_profile(self, profile):
|
def load_profile(self, profile):
|
||||||
self.logger.info(f"loading user profile {profile}")
|
self.logger.info(f"loading user profile {profile}")
|
||||||
self.target.apply_config(profile)
|
self.target.apply_config(profile)
|
||||||
|
if not _base_values.run_update:
|
||||||
|
self.parent.subject.notify("pdirty")
|
||||||
|
|
||||||
def load_defaults(self):
|
def load_defaults(self):
|
||||||
msg = (
|
msg = (
|
||||||
@@ -398,7 +406,7 @@ class Menus(tk.Menu):
|
|||||||
self.vban.logout()
|
self.vban.logout()
|
||||||
# build new app frames according to a kind
|
# build new app frames according to a kind
|
||||||
kind = kind_get(self.vmr.type)
|
kind = kind_get(self.vmr.type)
|
||||||
self.parent.build_app(kind, None)
|
self.parent.build_app(kind)
|
||||||
target_menu = getattr(self, f"menu_vban_{i+1}")
|
target_menu = getattr(self, f"menu_vban_{i+1}")
|
||||||
target_menu.entryconfig(0, state="normal")
|
target_menu.entryconfig(0, state="normal")
|
||||||
target_menu.entryconfig(1, state="disabled")
|
target_menu.entryconfig(1, state="disabled")
|
||||||
|
|||||||
Reference in New Issue
Block a user