5 Commits

Author SHA1 Message Date
b809bcb28f 1.9.0 section added to changelog
minor version bump
2023-07-11 08:36:19 +01:00
a0b9a92a2a added healthcheck_step
checks connection to Voicemeeter.
2023-07-11 08:35:23 +01:00
9faf8ae10c easier to read 2023-07-11 01:27:05 +01:00
82cf0e914b wrap button callbacks with {cls}.pause_updates() 2023-07-11 01:26:46 +01:00
3e68488231 bump deps 2023-07-08 18:19:06 +01:00
11 changed files with 197 additions and 71 deletions

View File

@@ -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

View File

@@ -34,16 +34,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 +53,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`

View File

@@ -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()

92
poetry.lock generated
View File

@@ -1,10 +1,25 @@
# This file is automatically @generated by Poetry 1.5.1 and should not be changed by hand.
[[package]] [[package]]
name = "black" name = "black"
version = "22.12.0" version = "22.12.0"
description = "The uncompromising code formatter." description = "The uncompromising code formatter."
category = "dev"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
files = [
{file = "black-22.12.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9eedd20838bd5d75b80c9f5487dbcb06836a43833a37846cf1d8c1cc01cef59d"},
{file = "black-22.12.0-cp310-cp310-win_amd64.whl", hash = "sha256:159a46a4947f73387b4d83e87ea006dbb2337eab6c879620a3ba52699b1f4351"},
{file = "black-22.12.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d30b212bffeb1e252b31dd269dfae69dd17e06d92b87ad26e23890f3efea366f"},
{file = "black-22.12.0-cp311-cp311-win_amd64.whl", hash = "sha256:7412e75863aa5c5411886804678b7d083c7c28421210180d67dfd8cf1221e1f4"},
{file = "black-22.12.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c116eed0efb9ff870ded8b62fe9f28dd61ef6e9ddd28d83d7d264a38417dcee2"},
{file = "black-22.12.0-cp37-cp37m-win_amd64.whl", hash = "sha256:1f58cbe16dfe8c12b7434e50ff889fa479072096d79f0a7f25e4ab8e94cd8350"},
{file = "black-22.12.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:77d86c9f3db9b1bf6761244bc0b3572a546f5fe37917a044e02f3166d5aafa7d"},
{file = "black-22.12.0-cp38-cp38-win_amd64.whl", hash = "sha256:82d9fe8fee3401e02e79767016b4907820a7dc28d70d137eb397b92ef3cc5bfc"},
{file = "black-22.12.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:101c69b23df9b44247bd88e1d7e90154336ac4992502d4197bdac35dd7ee3320"},
{file = "black-22.12.0-cp39-cp39-win_amd64.whl", hash = "sha256:559c7a1ba9a006226f09e4916060982fd27334ae1998e7a38b3f33a37f7a2148"},
{file = "black-22.12.0-py3-none-any.whl", hash = "sha256:436cc9167dd28040ad90d3b404aec22cedf24a6e4d7de221bec2730ec0c97bcf"},
{file = "black-22.12.0.tar.gz", hash = "sha256:229351e5a18ca30f447bf724d007f890f97e13af070bb6ad4c0a441cd7596a2f"},
]
[package.dependencies] [package.dependencies]
click = ">=8.0.0" click = ">=8.0.0"
@@ -23,9 +38,12 @@ uvloop = ["uvloop (>=0.15.2)"]
name = "click" name = "click"
version = "8.1.3" version = "8.1.3"
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.3-py3-none-any.whl", hash = "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48"},
{file = "click-8.1.3.tar.gz", hash = "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e"},
]
[package.dependencies] [package.dependencies]
colorama = {version = "*", markers = "platform_system == \"Windows\""} colorama = {version = "*", markers = "platform_system == \"Windows\""}
@@ -34,104 +52,118 @@ 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.12.0"
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.12.0-py3-none-any.whl", hash = "sha256:f84c2818376e66cf843d497486ea8fed8700b340f308f076c6fb1229dff318b6"},
{file = "isort-5.12.0.tar.gz", hash = "sha256:8bef7dde241278824a6d83f44a544709b065191b95b6e50894bdc722fcba0504"},
]
[package.extras] [package.extras]
colors = ["colorama (>=0.4.3)"] colors = ["colorama (>=0.4.3)"]
requirements-deprecated-finder = ["pip-api", "pipreqs"]
pipfile-deprecated-finder = ["pip-shims (>=0.5.2)", "pipreqs", "requirementslib"] pipfile-deprecated-finder = ["pip-shims (>=0.5.2)", "pipreqs", "requirementslib"]
plugins = ["setuptools"] plugins = ["setuptools"]
requirements-deprecated-finder = ["pip-api", "pipreqs"]
[[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]] [[package]]
name = "pathspec" name = "pathspec"
version = "0.11.1" version = "0.11.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.7"
files = [
{file = "pathspec-0.11.1-py3-none-any.whl", hash = "sha256:d8af70af76652554bd134c22b3e8a1cc46ed7d91edcdd721ef1a0c51a84a5293"},
{file = "pathspec-0.11.1.tar.gz", hash = "sha256:2798de800fa92780e33acca925945e9a19a133b715067cf165b8866c15a31687"},
]
[[package]] [[package]]
name = "platformdirs" name = "platformdirs"
version = "3.8.0" version = "3.8.0"
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.7"
files = [
{file = "platformdirs-3.8.0-py3-none-any.whl", hash = "sha256:ca9ed98ce73076ba72e092b23d3c93ea6c4e186b3f1c3dad6edd98ff6ffcca2e"},
{file = "platformdirs-3.8.0.tar.gz", hash = "sha256:b0cabcb11063d21a0b261d557acb0a9d2126350e63b70cdf7db6347baea456dc"},
]
[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.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-cov (>=4.1)", "pytest-mock (>=3.10)", "pytest (>=7.3.1)"] test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.3.1)", "pytest-cov (>=4.1)", "pytest-mock (>=3.10)"]
[[package]] [[package]]
name = "sv-ttk" name = "sv-ttk"
version = "2.5.1" version = "2.5.1"
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.7"
files = [
{file = "sv_ttk-2.5.1-py3-none-any.whl", hash = "sha256:c7388741e14316b4e9c3b9fd135e1e2e5b501f1b30c89b7af1e26286b38f2ccc"},
{file = "sv_ttk-2.5.1.tar.gz", hash = "sha256:e32d60587db7debe4d7d7438f66257ffcd9db5b8efbcb52151697fa8a662a4f5"},
]
[[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]] [[package]]
name = "vban-cmd" name = "vban-cmd"
version = "2.0.0" version = "2.2.0"
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.2.0-py3-none-any.whl", hash = "sha256:ad0bd848b5412004c4c14976e8a9a18d0fc727599e343db0fb67f9427c8541fa"},
{file = "vban_cmd-2.2.0.tar.gz", hash = "sha256:7bad6001504fd052df3192c7d817e604703353f57efa7648c1f1d6e425665006"},
]
[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.1.2"
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 = ">=3.10,<4.0"
files = [
{file = "voicemeeter_api-2.1.2-py3-none-any.whl", hash = "sha256:43a6e36282a89f2701b58f627bdd21c5e17f9f9044bf3337059d89e91f25fc09"},
{file = "voicemeeter_api-2.1.2.tar.gz", hash = "sha256:c24c643e868535786860420fe5775a10e2ace6f79ec4905a172a1c64712f3d6b"},
]
[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"
content-hash = "3a59de3a76e4c0ca11c0166750fa1af7d7c887750f855b48c45359068ef04798" content-hash = "3a59de3a76e4c0ca11c0166750fa1af7d7c887750f855b48c45359068ef04798"
[metadata.files]
black = []
click = []
colorama = []
isort = []
mypy-extensions = []
pathspec = []
platformdirs = []
sv-ttk = []
tomli = []
vban-cmd = []
voicemeeter-api = []

View File

@@ -1,6 +1,6 @@
[tool.poetry] [tool.poetry]
name = "voicemeeter-compact" name = "voicemeeter-compact"
version = "1.8.4" version = "1.9.0"
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"
@@ -14,8 +14,8 @@ include = ["vmcompact/img/cat.ico"]
python = "^3.10" python = "^3.10"
sv-ttk = "^2.5.1" sv-ttk = "^2.5.1"
tomli = { version = "^2.0.1", python = "<3.11" } tomli = { version = "^2.0.1", python = "<3.11" }
voicemeeter-api = "^2.0.2" voicemeeter-api = "^2.1.2"
vban-cmd = "^2.0.0" vban-cmd = "^2.2.0"
[tool.poetry.dev-dependencies] [tool.poetry.dev-dependencies]
black = { version = "^22.6.0", allow-prereleases = true } black = { version = "^22.6.0", allow-prereleases = true }

View 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
@@ -48,7 +50,7 @@ class App(tk.Tk):
self.minsize(275, False) self.minsize(275, False)
self.subject = Subject() self.subject = Subject()
self._configs = None self._configs = None
self["menu"] = Menus(self, vmr) 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 +60,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 +146,42 @@ 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):
self.logger.debug("updates started")
_base_values.run_update = True
if self._vmr.gui.launched_by_api:
self.on_pdirty()
def healthcheck_step(self):
if not _base_values.vban_connected:
try:
self._vmr.pdirty
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)
_apps = {kind.name: App.make(kind) for kind in _kinds_all} _apps = {kind.name: App.make(kind) for kind in _kinds_all}

View File

@@ -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],
) )

View File

@@ -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():

View File

@@ -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

View File

@@ -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

View File

@@ -224,7 +224,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.destroy()
def action_set_voicemeeter(self, cmd, val=True): def action_set_voicemeeter(self, cmd, val=True):
if cmd == "lock": if cmd == "lock":
@@ -398,7 +401,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")