mirror of
https://github.com/onyx-and-iris/voicemeeter-compact.git
synced 2026-04-08 17:03:32 +00:00
Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ef558fdde6 | |||
| c684ed9981 | |||
| 1498daf36f | |||
| e964c94d07 | |||
| 9f20225a59 | |||
| f63c36c94a | |||
| c2db0f2757 | |||
| bfb0482c32 | |||
| 6222ab1e62 |
7
.gitignore
vendored
7
.gitignore
vendored
@@ -132,4 +132,11 @@ dmypy.json
|
||||
# Pyre type checker
|
||||
.pyre/
|
||||
|
||||
# build
|
||||
sv_ttk/
|
||||
theme/
|
||||
|
||||
sv_*.py
|
||||
fst_*.py
|
||||
|
||||
.vscode/
|
||||
@@ -1,5 +1,6 @@
|
||||
[](https://badge.fury.io/py/voicemeeter-compact)
|
||||
[](https://github.com/onyx-and-iris/voicemeeter-compact/blob/main/LICENSE)
|
||||
[](https://python-poetry.org/)
|
||||
[](https://github.com/psf/black)
|
||||

|
||||
|
||||
|
||||
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 }
|
||||
129
poetry.lock
generated
129
poetry.lock
generated
@@ -1,5 +1,16 @@
|
||||
# This file is automatically @generated by Poetry 1.5.1 and should not be changed by hand.
|
||||
|
||||
[[package]]
|
||||
name = "altgraph"
|
||||
version = "0.17.3"
|
||||
description = "Python graph (network) package"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
{file = "altgraph-0.17.3-py2.py3-none-any.whl", hash = "sha256:c8ac1ca6772207179ed8003ce7687757c04b0b71536f81e2ac5755c6226458fe"},
|
||||
{file = "altgraph-0.17.3.tar.gz", hash = "sha256:ad33358114df7c9416cdb8fa1eaa5852166c505118717021c6a8c7c7abbd03dd"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "black"
|
||||
version = "22.12.0"
|
||||
@@ -76,6 +87,20 @@ pipfile-deprecated-finder = ["pip-shims (>=0.5.2)", "pipreqs", "requirementslib"
|
||||
plugins = ["setuptools"]
|
||||
requirements-deprecated-finder = ["pip-api", "pipreqs"]
|
||||
|
||||
[[package]]
|
||||
name = "macholib"
|
||||
version = "1.16.2"
|
||||
description = "Mach-O header analysis and editing"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
{file = "macholib-1.16.2-py2.py3-none-any.whl", hash = "sha256:44c40f2cd7d6726af8fa6fe22549178d3a4dfecc35a9cd15ea916d9c83a688e0"},
|
||||
{file = "macholib-1.16.2.tar.gz", hash = "sha256:557bbfa1bb255c20e9abafe7ed6cd8046b48d9525db2f9b77d3122a63a2a8bf8"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
altgraph = ">=0.17"
|
||||
|
||||
[[package]]
|
||||
name = "mypy-extensions"
|
||||
version = "1.0.0"
|
||||
@@ -98,6 +123,17 @@ files = [
|
||||
{file = "pathspec-0.11.1.tar.gz", hash = "sha256:2798de800fa92780e33acca925945e9a19a133b715067cf165b8866c15a31687"},
|
||||
]
|
||||
|
||||
[[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]]
|
||||
name = "platformdirs"
|
||||
version = "3.8.1"
|
||||
@@ -113,15 +149,86 @@ files = [
|
||||
docs = ["furo (>=2023.5.20)", "proselint (>=0.13)", "sphinx (>=7.0.1)", "sphinx-autodoc-typehints (>=1.23,!=1.23.4)"]
|
||||
test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.3.1)", "pytest-cov (>=4.1)", "pytest-mock (>=3.10)"]
|
||||
|
||||
[[package]]
|
||||
name = "pyinstaller"
|
||||
version = "5.13.1"
|
||||
description = "PyInstaller bundles a Python application and all its dependencies into a single package."
|
||||
optional = false
|
||||
python-versions = "<3.13,>=3.7"
|
||||
files = [
|
||||
{file = "pyinstaller-5.13.1-py3-none-macosx_10_13_universal2.whl", hash = "sha256:3c9cfe6d5d2f392d5d47389f6d377a8f225db460cdd01048b5a3de1d99c24ebe"},
|
||||
{file = "pyinstaller-5.13.1-py3-none-manylinux2014_aarch64.whl", hash = "sha256:29341d2e86d5ce7df993e797ee96ef679041fc85376d31c35c7b714085a21299"},
|
||||
{file = "pyinstaller-5.13.1-py3-none-manylinux2014_i686.whl", hash = "sha256:ad6e31a8f35a463c6140e4cf979859197edc9831a1039253408b0fe5eec274dc"},
|
||||
{file = "pyinstaller-5.13.1-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:5d801db3ceee58d01337473ea897e96e4bb21421a169dd7cf8716754617ff7fc"},
|
||||
{file = "pyinstaller-5.13.1-py3-none-manylinux2014_s390x.whl", hash = "sha256:2519db3edec87d8c33924c2c4b7e176d8c1bbd9ba892d77efb67281925e621d6"},
|
||||
{file = "pyinstaller-5.13.1-py3-none-manylinux2014_x86_64.whl", hash = "sha256:e033218c8922f0342b6095fb444ecb3bc6747dfa58cac5eac2b985350f4b681e"},
|
||||
{file = "pyinstaller-5.13.1-py3-none-musllinux_1_1_aarch64.whl", hash = "sha256:086e68aa1e72f6aa13b9d170a395755e2b194b8ab410caeed02d16b432410c8c"},
|
||||
{file = "pyinstaller-5.13.1-py3-none-musllinux_1_1_x86_64.whl", hash = "sha256:aa609aca62edd8cdcf7740677a21525e6c23b5e9a8f821ec8a80c68947771b5d"},
|
||||
{file = "pyinstaller-5.13.1-py3-none-win32.whl", hash = "sha256:b8d4000af72bf72f8185d420cd0a0aee0961f03a5c3511dc3ff08cdaef0583de"},
|
||||
{file = "pyinstaller-5.13.1-py3-none-win_amd64.whl", hash = "sha256:b70ebc10811b30bbea4cf5b81fd1477db992c2614cf215edc987cda9c5468911"},
|
||||
{file = "pyinstaller-5.13.1-py3-none-win_arm64.whl", hash = "sha256:78d1601a11475b95dceff6eaf0c9cd74d93e3f47b5ce4ad63cd76e7a369d3d04"},
|
||||
{file = "pyinstaller-5.13.1.tar.gz", hash = "sha256:a2e7a1d76a7ac26f1db849d691a374f2048b0e204233028d25d79a90ecd1fec8"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
altgraph = "*"
|
||||
macholib = {version = ">=1.8", markers = "sys_platform == \"darwin\""}
|
||||
pefile = {version = ">=2022.5.30", markers = "sys_platform == \"win32\""}
|
||||
pyinstaller-hooks-contrib = ">=2021.4"
|
||||
pywin32-ctypes = {version = ">=0.2.1", markers = "sys_platform == \"win32\""}
|
||||
setuptools = ">=42.0.0"
|
||||
|
||||
[package.extras]
|
||||
encryption = ["tinyaes (>=1.0.0)"]
|
||||
hook-testing = ["execnet (>=1.5.0)", "psutil", "pytest (>=2.7.3)"]
|
||||
|
||||
[[package]]
|
||||
name = "pyinstaller-hooks-contrib"
|
||||
version = "2023.7"
|
||||
description = "Community maintained hooks for PyInstaller"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "pyinstaller-hooks-contrib-2023.7.tar.gz", hash = "sha256:0c436a4c3506020e34116a8a7ddfd854c1ad6ddca9a8cd84500bd6e69c9e68f9"},
|
||||
{file = "pyinstaller_hooks_contrib-2023.7-py2.py3-none-any.whl", hash = "sha256:3c10df14c0f71ab388dfbf1625375b087e7330d9444cbfd2b310ba027fa0cff0"},
|
||||
]
|
||||
|
||||
[[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 = "68.1.2"
|
||||
description = "Easily download, build, install, upgrade, and uninstall Python packages"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "setuptools-68.1.2-py3-none-any.whl", hash = "sha256:3d8083eed2d13afc9426f227b24fd1659489ec107c0e86cec2ffdde5c92e790b"},
|
||||
{file = "setuptools-68.1.2.tar.gz", hash = "sha256:3d4dfa6d95f1b101d695a6160a7626e15583af71a5f52176efa5d39a054d475d"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5,<=7.1.2)", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (==0.8.3)", "sphinx-reredirects", "sphinxcontrib-towncrier"]
|
||||
testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"]
|
||||
testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"]
|
||||
|
||||
[[package]]
|
||||
name = "sv-ttk"
|
||||
version = "2.5.3"
|
||||
version = "2.5.5"
|
||||
description = "A gorgeous theme for Tkinter, based on Windows 11's UI"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "sv_ttk-2.5.3-py3-none-any.whl", hash = "sha256:d13bf6a7b49316431eefcf83f30d0daf312c00553c4e0b6f91acffd7b2aaa1d3"},
|
||||
{file = "sv_ttk-2.5.3.tar.gz", hash = "sha256:d9b9a5d14f4cbdd4e0bda2e1a84445b0aa852b99f74aafce9386459e385717b3"},
|
||||
{file = "sv_ttk-2.5.5-py3-none-any.whl", hash = "sha256:49d1cd03c032728c183d1fe2318f88cdb658ef3e87157e1ca3fcf6661054965b"},
|
||||
{file = "sv_ttk-2.5.5.tar.gz", hash = "sha256:9bbfe2aba6cc6f9fdf70d79331046543c9666fcccc78bad5ff648a9987e3cedb"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -137,13 +244,13 @@ files = [
|
||||
|
||||
[[package]]
|
||||
name = "vban-cmd"
|
||||
version = "2.3.2"
|
||||
version = "2.4.11"
|
||||
description = "Python interface for the VBAN RT Packet Service (Sendtext)"
|
||||
optional = false
|
||||
python-versions = ">=3.10,<4.0"
|
||||
files = [
|
||||
{file = "vban_cmd-2.3.2-py3-none-any.whl", hash = "sha256:28168a7ec1c6966fd4bcbaed3144219f8cdc2490f15dd8ecba2aa19f2a3461f5"},
|
||||
{file = "vban_cmd-2.3.2.tar.gz", hash = "sha256:c33e338e3207f35a6b9f9026d29cf68af9e5f6d7c96aea4b581225f4befd844e"},
|
||||
{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]
|
||||
@@ -151,13 +258,13 @@ tomli = {version = ">=2.0.1,<3.0.0", markers = "python_version < \"3.11\""}
|
||||
|
||||
[[package]]
|
||||
name = "voicemeeter-api"
|
||||
version = "2.3.2"
|
||||
version = "2.5.3"
|
||||
description = "A Python wrapper for the Voiceemeter API"
|
||||
optional = false
|
||||
python-versions = ">=3.10,<4.0"
|
||||
files = [
|
||||
{file = "voicemeeter_api-2.3.2-py3-none-any.whl", hash = "sha256:081bd6b3e27d8757e4c5ed239b4c58f9bcb4f4d16ebc9c88229e9390dac184c8"},
|
||||
{file = "voicemeeter_api-2.3.2.tar.gz", hash = "sha256:aa700600b5910e4bb55df20cdf028aae2a44cc14bfd80dd0fe060aa03bbf7e02"},
|
||||
{file = "voicemeeter_api-2.5.3-py3-none-any.whl", hash = "sha256:00c1f5b4027844d09ae19042f1662501dc28b1cee12a4238503790a50293c8f7"},
|
||||
{file = "voicemeeter_api-2.5.3.tar.gz", hash = "sha256:b40f77e94446b4a5ab561c777109bdaf9c2478dfaa19e728c91ade3b44226704"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
@@ -165,5 +272,5 @@ tomli = {version = ">=2.0.1,<3.0.0", markers = "python_version < \"3.11\""}
|
||||
|
||||
[metadata]
|
||||
lock-version = "2.0"
|
||||
python-versions = "^3.10"
|
||||
content-hash = "770291c3645dd9bfd28051c0deb13bf5ae17a510bfc2785b51be1bc5c7266b1a"
|
||||
python-versions = ">=3.10,<3.13"
|
||||
content-hash = "13e82f3aaab5c1c9f3dc30b76959b3e71e83835da099acd2e103dba05084c853"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[tool.poetry]
|
||||
name = "voicemeeter-compact"
|
||||
version = "1.9.1"
|
||||
version = "1.9.4"
|
||||
description = "A Compact Voicemeeter Remote App"
|
||||
authors = ["onyx-and-iris <code@onyxandiris.online>"]
|
||||
license = "MIT"
|
||||
@@ -11,16 +11,24 @@ packages = [{ include = "vmcompact" }]
|
||||
include = ["vmcompact/img/cat.ico"]
|
||||
|
||||
[tool.poetry.dependencies]
|
||||
python = "^3.10"
|
||||
sv-ttk = "^2.5.1"
|
||||
python = ">=3.10,<3.13"
|
||||
sv-ttk = "^2.5.5"
|
||||
tomli = { version = "^2.0.1", python = "<3.11" }
|
||||
voicemeeter-api = "^2.3.2"
|
||||
vban-cmd = "^2.3.2"
|
||||
voicemeeter-api = "^2.5.3"
|
||||
vban-cmd = "^2.4.11"
|
||||
|
||||
[tool.poetry.dev-dependencies]
|
||||
[tool.poetry.group.dev.dependencies]
|
||||
black = { version = "^22.6.0", allow-prereleases = true }
|
||||
isort = "^5.12.0"
|
||||
|
||||
[tool.poetry.group.build.dependencies]
|
||||
pyinstaller = "^5.13.1"
|
||||
|
||||
[build-system]
|
||||
requires = ["poetry-core>=1.0.0"]
|
||||
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() / "builds" / "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
@@ -42,14 +42,15 @@ class App(tk.Tk):
|
||||
self.logger = logger.getChild(self.__class__.__name__)
|
||||
self._vmr = vmr
|
||||
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()
|
||||
icon_path = Path(__file__).parent.resolve() / "img" / "cat.ico"
|
||||
if icon_path.is_file():
|
||||
self.iconbitmap(str(icon_path))
|
||||
self.minsize(275, False)
|
||||
self.subject = Subject()
|
||||
self._configs = None
|
||||
self.protocol("WM_DELETE_WINDOW", self.on_close_window)
|
||||
self.menu = self["menu"] = Menus(self, vmr)
|
||||
self.styletable = ttk.Style()
|
||||
if _configuration.config:
|
||||
@@ -147,10 +148,15 @@ class App(tk.Tk):
|
||||
return self._configs
|
||||
|
||||
def start_updates(self):
|
||||
self.logger.debug("updates started")
|
||||
_base_values.run_update = True
|
||||
def init():
|
||||
self.logger.debug("updates started")
|
||||
_base_values.run_update = True
|
||||
|
||||
if self._vmr.gui.launched_by_api:
|
||||
self.on_pdirty()
|
||||
self.subject.notify("pdirty")
|
||||
self.after(12000, init)
|
||||
else:
|
||||
init()
|
||||
|
||||
def healthcheck_step(self):
|
||||
if not _base_values.vban_connected:
|
||||
@@ -182,6 +188,11 @@ class App(tk.Tk):
|
||||
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}
|
||||
|
||||
|
||||
@@ -151,17 +151,18 @@ class ChannelLabelFrame(ttk.LabelFrame):
|
||||
def sync_labels(self):
|
||||
"""sync labelframes according to label text"""
|
||||
retval = self.getter("label")
|
||||
self.parent.label_cache[self.id].insert(self.index, retval)
|
||||
if len(retval) > 10:
|
||||
retval = f"{retval[:8]}.."
|
||||
if not retval:
|
||||
self.parent.columnconfigure(self.index, minsize=0)
|
||||
self.parent.parent.subject.remove(self)
|
||||
self.grid_remove()
|
||||
else:
|
||||
self.parent.parent.subject.add(self)
|
||||
self.grid()
|
||||
self.configure(text=retval)
|
||||
if self.parent.label_cache[self.id][self.index] != retval:
|
||||
self.parent.label_cache[self.id][self.index] = retval
|
||||
if len(retval) > 10:
|
||||
retval = f"{retval[:8]}.."
|
||||
if not retval:
|
||||
self.parent.columnconfigure(self.index, minsize=0)
|
||||
self.parent.parent.subject.remove(self)
|
||||
self.grid_remove()
|
||||
else:
|
||||
self.parent.parent.subject.add(self)
|
||||
self.grid()
|
||||
self.configure(text=retval)
|
||||
|
||||
def grid_configure(self):
|
||||
self.grid(padx=_configuration.channel_xpadding, sticky=(tk.N, tk.S))
|
||||
@@ -228,15 +229,18 @@ class Bus(ChannelLabelFrame):
|
||||
|
||||
|
||||
class ChannelFrame(ttk.Frame):
|
||||
label_cache = {"strip": list(), "bus": list()}
|
||||
|
||||
def init(self, parent, id):
|
||||
super().__init__(parent)
|
||||
self.parent = parent
|
||||
self.id = id
|
||||
self.phys_in, self.virt_in = parent.kind.ins
|
||||
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.update_labels()
|
||||
|
||||
@property
|
||||
def target(self):
|
||||
@@ -258,13 +262,13 @@ class ChannelFrame(ttk.Frame):
|
||||
if isinstance(frame, ttk.LabelFrame)
|
||||
)
|
||||
|
||||
def update_labels(self):
|
||||
for labelframe in self.labelframes:
|
||||
labelframe.on_update("labelframe")
|
||||
|
||||
def on_update(self, subject):
|
||||
if subject == "pdirty":
|
||||
target = getattr(self.target, self.id)
|
||||
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")
|
||||
self.update_labels()
|
||||
|
||||
def grid_configure(self):
|
||||
[
|
||||
@@ -280,7 +284,7 @@ class ChannelFrame(ttk.Frame):
|
||||
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
|
||||
"""
|
||||
@@ -288,29 +292,33 @@ def _make_channelframe(parent, id):
|
||||
phys_in, virt_in = parent.kind.ins
|
||||
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
|
||||
"""
|
||||
|
||||
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)
|
||||
if not labelframe.target.label:
|
||||
label = labelframe.target.label
|
||||
if not label:
|
||||
self.columnconfigure(i, minsize=0)
|
||||
labelframe.grid_remove()
|
||||
self.label_cache[identifier][i] = label
|
||||
|
||||
def init_strip(self, *args, **kwargs):
|
||||
self.init(parent, id)
|
||||
self.strips = tuple(Strip(self, i, id) for i in range(phys_in + virt_in))
|
||||
self.init(parent, identifier)
|
||||
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_configure()
|
||||
init_labels(self, id)
|
||||
init_labels(self)
|
||||
|
||||
def init_bus(self, *args, **kwargs):
|
||||
self.init(parent, id)
|
||||
self.buses = tuple(Bus(self, i, id) for i in range(phys_out + virt_out))
|
||||
self.init(parent, identifier)
|
||||
self.buses = tuple(Bus(self, i, identifier) for i in range(phys_out + virt_out))
|
||||
if _configuration.extended:
|
||||
if _configuration.extends_horizontal:
|
||||
self.grid(row=0, column=2, sticky=(tk.W))
|
||||
@@ -319,11 +327,11 @@ def _make_channelframe(parent, id):
|
||||
else:
|
||||
self.grid(row=0, column=0)
|
||||
self.grid_configure()
|
||||
init_labels(self, id)
|
||||
init_labels(self)
|
||||
|
||||
if id == "strip":
|
||||
if identifier == "strip":
|
||||
CHANNELFRAME_cls = type(
|
||||
f"ChannelFrame{id.capitalize()}",
|
||||
f"ChannelFrame{identifier.capitalize()}",
|
||||
(ChannelFrame,),
|
||||
{
|
||||
"__init__": init_strip,
|
||||
@@ -331,7 +339,7 @@ def _make_channelframe(parent, id):
|
||||
)
|
||||
else:
|
||||
CHANNELFRAME_cls = type(
|
||||
f"ChannelFrame{id.capitalize()}",
|
||||
f"ChannelFrame{identifier.capitalize()}",
|
||||
(ChannelFrame,),
|
||||
{
|
||||
"__init__": init_bus,
|
||||
|
||||
@@ -4,10 +4,11 @@ import webbrowser
|
||||
from functools import partial
|
||||
from tkinter import messagebox
|
||||
|
||||
import sv_ttk
|
||||
import vban_cmd
|
||||
from vban_cmd.error import VBANCMDConnectionError
|
||||
|
||||
import sv_ttk
|
||||
|
||||
from .data import _base_values, _configuration, get_configuration, kind_get
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -227,7 +228,7 @@ class Menus(tk.Menu):
|
||||
if fn := getattr(self.target.command, cmd):
|
||||
fn()
|
||||
if cmd == "shutdown":
|
||||
self.parent.destroy()
|
||||
self.parent.on_close_window()
|
||||
|
||||
def action_set_voicemeeter(self, cmd, val=True):
|
||||
if cmd == "lock":
|
||||
@@ -238,10 +239,14 @@ class Menus(tk.Menu):
|
||||
def load_custom_profile(self, profile):
|
||||
self.logger.info(f"loading user profile {profile}")
|
||||
self.target.apply(profile)
|
||||
if not _base_values.run_update:
|
||||
self.parent.subject.notify("pdirty")
|
||||
|
||||
def load_profile(self, profile):
|
||||
self.logger.info(f"loading user profile {profile}")
|
||||
self.target.apply_config(profile)
|
||||
if not _base_values.run_update:
|
||||
self.parent.subject.notify("pdirty")
|
||||
|
||||
def load_defaults(self):
|
||||
msg = (
|
||||
|
||||
Reference in New Issue
Block a user