Compare commits

..

No commits in common. "59d2a95ec41c5b688cfc0aac8daa5ce19fa76e47" and "5ab1fd71029fb7775e670859ed465e821cba7a9f" have entirely different histories.

12 changed files with 44 additions and 114 deletions

View File

@ -9,21 +9,6 @@ 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.8.0] - 2023-06-29
### Added
- Ability to toggle the navigation frame. This may also be set in app.toml, check example config.
### Changed
- xpadding added to channel labelframes. This may also be configured through app.toml.
- During startup of the app there is now a twelve second grace period before parameter updates begin if the GUI was not previously launched. This is aimed at removing the stutter (due to VM engine startup) on initial launch. Be mindful of this if changing settings on the base Voicemeeter app. After the grace period all updates continue as normal.
- dependency updates:
- sv_ttk updated to v2.5.1.
- voicemeeter-api updated to v2.0.2.
## [1.7.0] - 2023-06-26 ## [1.7.0] - 2023-06-26
### Changed ### Changed

View File

@ -3,23 +3,19 @@
# config="example" # config="example"
# load with themes enabled? set the default mode # load with themes enabled? set the default mode
[theme] [theme]
enabled = true enabled=true
mode = "light" mode="light"
# load in extended mode? if so which orientation # load in extended mode? if so which orientation
[extends] [extends]
extended = true extended=true
extends_horizontal = true extends_horizontal=true
# default dimensions for channel label frames # default dimensions for channel label frames
[channel] [channel]
width = 80 width=80
height = 130 height=130
xpadding = 2
# size of a single mouse wheel scroll step # size of a single mouse wheel scroll step
[mwscroll_step] [mwscroll_step]
size = 3 size=3
# default submix bus # default submix bus
[submixes] [submixes]
default = 0 default=0
# show the navigation frame?
[navigation]
show = true

30
poetry.lock generated
View File

@ -1,6 +1,6 @@
[[package]] [[package]]
name = "black" name = "black"
version = "22.12.0" version = "22.10.0"
description = "The uncompromising code formatter." description = "The uncompromising code formatter."
category = "dev" category = "dev"
optional = false optional = false
@ -32,11 +32,11 @@ colorama = {version = "*", markers = "platform_system == \"Windows\""}
[[package]] [[package]]
name = "colorama" name = "colorama"
version = "0.4.6" version = "0.4.5"
description = "Cross-platform colored terminal text." description = "Cross-platform colored terminal text."
category = "dev" 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 = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
[[package]] [[package]]
name = "isort" name = "isort"
@ -54,15 +54,15 @@ plugins = ["setuptools"]
[[package]] [[package]]
name = "mypy-extensions" name = "mypy-extensions"
version = "1.0.0" version = "0.4.3"
description = "Type system extensions for programs checked with the mypy type checker." description = "Experimental type system extensions for programs checked with the mypy typechecker."
category = "dev" category = "dev"
optional = false optional = false
python-versions = ">=3.5" python-versions = "*"
[[package]] [[package]]
name = "pathspec" name = "pathspec"
version = "0.11.1" version = "0.10.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" category = "dev"
optional = false optional = false
@ -70,23 +70,23 @@ python-versions = ">=3.7"
[[package]] [[package]]
name = "platformdirs" name = "platformdirs"
version = "3.8.0" version = "2.5.2"
description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"."
category = "dev" category = "dev"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
[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 (>=2021.7.5b38)", "proselint (>=0.10.2)", "sphinx-autodoc-typehints (>=1.12)", "sphinx (>=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)", "pytest-cov (>=2.7)", "pytest-mock (>=3.6)", "pytest (>=6)"]
[[package]] [[package]]
name = "sv-ttk" name = "sv-ttk"
version = "2.5.1" version = "2.4.5"
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" category = "main"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.4"
[[package]] [[package]]
name = "tomli" name = "tomli"
@ -109,7 +109,7 @@ 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.0.1"
description = "A Python wrapper for the Voiceemeter API" description = "A Python wrapper for the Voiceemeter API"
category = "main" category = "main"
optional = false optional = false
@ -121,7 +121,7 @@ tomli = {version = ">=2.0.1,<3.0.0", markers = "python_version < \"3.11\""}
[metadata] [metadata]
lock-version = "1.1" lock-version = "1.1"
python-versions = "^3.10" python-versions = "^3.10"
content-hash = "3a59de3a76e4c0ca11c0166750fa1af7d7c887750f855b48c45359068ef04798" content-hash = "ffb9af7ef7aa87ac08a09293de5e99487155faaa459cd49964ac95589deb69fa"
[metadata.files] [metadata.files]
black = [] black = []

View File

@ -1,6 +1,6 @@
[tool.poetry] [tool.poetry]
name = "voicemeeter-compact" name = "voicemeeter-compact"
version = "1.8.0" version = "1.7.1"
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"
@ -12,9 +12,9 @@ include = ["vmcompact/img/cat.ico"]
[tool.poetry.dependencies] [tool.poetry.dependencies]
python = "^3.10" python = "^3.10"
sv-ttk = "^2.5.1" sv-ttk = "^2.4.5"
tomli = { version = "^2.0.1", python = "<3.11" } tomli = { version = "^2.0.1", python = "<3.11" }
voicemeeter-api = "^2.0.2" voicemeeter-api = "^2.0.1"
vban-cmd = "^2.0.0" vban-cmd = "^2.0.0"
[tool.poetry.dev-dependencies] [tool.poetry.dev-dependencies]

View File

@ -1,4 +1,3 @@
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
@ -12,8 +11,6 @@ from .errors import VMCompactError
from .menu import Menus from .menu import Menus
from .subject import Subject from .subject import Subject
logger = logging.getLogger(__name__)
class App(tk.Tk): class App(tk.Tk):
"""App mainframe""" """App mainframe"""
@ -37,10 +34,9 @@ class App(tk.Tk):
def __init__(self, vmr): def __init__(self, vmr):
super().__init__() super().__init__()
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._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():
@ -58,12 +54,6 @@ 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.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"

View File

@ -195,9 +195,9 @@ class NavigationFrameBuilder(AbstractBuilder):
if isinstance(child, ttk.Checkbutton) if isinstance(child, ttk.Checkbutton)
] ]
if _configuration.themes_enabled: if _configuration.themes_enabled:
self.navframe.rowconfigure(1, minsize=_configuration.channel_height) self.navframe.rowconfigure(1, minsize=_configuration.level_height)
else: else:
self.navframe.rowconfigure(1, minsize=_configuration.channel_height + 10) self.navframe.rowconfigure(1, minsize=_configuration.level_height + 10)
def teardown(self): def teardown(self):
pass pass
@ -243,7 +243,7 @@ class ChannelLabelFrameBuilder(AbstractBuilder):
orient="vertical", orient="vertical",
variable=self.labelframe.gain, variable=self.labelframe.gain,
command=self.labelframe.scale_callback, command=self.labelframe.scale_callback,
length=_configuration.channel_height, length=_configuration.level_height,
) )
self.scale.grid(column=1, row=0) self.scale.grid(column=1, row=0)
self.scale.bind("<Double-Button-1>", self.labelframe.reset_gain) self.scale.bind("<Double-Button-1>", self.labelframe.reset_gain)
@ -324,7 +324,7 @@ class ChannelConfigFrameBuilder(AbstractBuilder):
] ]
self.configframe.grid(sticky=(tk.W)) self.configframe.grid(sticky=(tk.W))
[ [
self.configframe.columnconfigure(i, minsize=_configuration.channel_width) self.configframe.columnconfigure(i, minsize=_configuration.level_width)
for i in range(self.configframe.phys_out + self.configframe.virt_out) for i in range(self.configframe.phys_out + self.configframe.virt_out)
] ]
@ -392,7 +392,7 @@ class StripConfigFrameBuilder(ChannelConfigFrameBuilder):
from_=0.0, from_=0.0,
to=10.0, to=10.0,
orient="horizontal", orient="horizontal",
length=_configuration.channel_width, length=_configuration.level_width,
variable=self.configframe.slider_vars[ variable=self.configframe.slider_vars[
self.configframe.slider_params.index("comp.knob") self.configframe.slider_params.index("comp.knob")
], ],
@ -416,7 +416,7 @@ class StripConfigFrameBuilder(ChannelConfigFrameBuilder):
from_=0.0, from_=0.0,
to=10.0, to=10.0,
orient="horizontal", orient="horizontal",
length=_configuration.channel_width, length=_configuration.level_width,
variable=self.configframe.slider_vars[ variable=self.configframe.slider_vars[
self.configframe.slider_params.index("gate.knob") self.configframe.slider_params.index("gate.knob")
], ],
@ -440,7 +440,7 @@ class StripConfigFrameBuilder(ChannelConfigFrameBuilder):
from_=-40, from_=-40,
to=12, to=12,
orient="horizontal", orient="horizontal",
length=_configuration.channel_width, length=_configuration.level_width,
variable=self.configframe.slider_vars[ variable=self.configframe.slider_vars[
self.configframe.slider_params.index("limit") self.configframe.slider_params.index("limit")
], ],
@ -464,7 +464,7 @@ class StripConfigFrameBuilder(ChannelConfigFrameBuilder):
from_=0.0, from_=0.0,
to=10.0, to=10.0,
orient="horizontal", orient="horizontal",
length=_configuration.channel_width, length=_configuration.level_width,
variable=self.configframe.slider_vars[ variable=self.configframe.slider_vars[
self.configframe.slider_params.index("audibility") self.configframe.slider_params.index("audibility")
], ],

View File

@ -154,7 +154,7 @@ class ChannelLabelFrame(ttk.LabelFrame):
self.configure(text=retval) 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(sticky=(tk.N, tk.S))
[ [
child.grid_configure(padx=1, pady=1, sticky=(tk.W, tk.E)) child.grid_configure(padx=1, pady=1, sticky=(tk.W, tk.E))
for child in self.winfo_children() for child in self.winfo_children()
@ -258,7 +258,7 @@ class ChannelFrame(ttk.Frame):
def grid_configure(self): def grid_configure(self):
[ [
self.columnconfigure(i, minsize=_configuration.channel_width) self.columnconfigure(i, minsize=_configuration.level_width)
for i, _ in enumerate(self.labelframes) for i, _ in enumerate(self.labelframes)
] ]
[self.rowconfigure(0, minsize=100) for i, _ in enumerate(self.labelframes)] [self.rowconfigure(0, minsize=100) for i, _ in enumerate(self.labelframes)]

View File

@ -48,7 +48,6 @@ _defaults = {
"channel": { "channel": {
"width": 80, "width": 80,
"height": 130, "height": 130,
"xpadding": 3,
}, },
"mwscroll_step": { "mwscroll_step": {
"size": 3, "size": 3,
@ -56,7 +55,6 @@ _defaults = {
"submixes": { "submixes": {
"default": 0, "default": 0,
}, },
"navigation": {"show": True},
} }
if "app" in configuration: if "app" in configuration:

View File

@ -32,15 +32,10 @@ class Configurations(metaclass=SingletonMeta):
# bus assigned as current submix # bus assigned as current submix
submixes: int = configuration["submixes"]["default"] submixes: int = configuration["submixes"]["default"]
# width of a single channel labelframe # width of a single labelframe
channel_width: int = configuration["channel"]["width"] level_width: int = configuration["channel"]["width"]
# height of a single channel labelframe # height of a single labelframe
channel_height: int = configuration["channel"]["height"] level_height: int = configuration["channel"]["height"]
# xpadding for a single channel labelframe
channel_xpadding: int = configuration["channel"]["xpadding"]
# do we grid the navigation frame?
navigation_show: bool = configuration["navigation"]["show"]
@property @property
def config(self): def config(self):
@ -51,7 +46,7 @@ class Configurations(metaclass=SingletonMeta):
@dataclass @dataclass
class BaseValues(metaclass=SingletonMeta): class BaseValues(metaclass=SingletonMeta):
# pause updates after releasing scale # pause updates after releasing scale
run_update: bool = False run_update: bool = True
# are we dragging main window with mouse 1 # are we dragging main window with mouse 1
dragging: bool = False dragging: bool = False
# a vban connection established # a vban connection established

View File

@ -166,7 +166,6 @@ class GainLayer(ttk.LabelFrame):
) )
def grid_configure(self): def grid_configure(self):
self.grid(padx=_configuration.channel_xpadding, sticky=(tk.N, tk.S))
[ [
child.grid_configure(padx=1, pady=1, sticky=(tk.N, tk.S, tk.W, tk.E)) child.grid_configure(padx=1, pady=1, sticky=(tk.N, tk.S, tk.W, tk.E))
for child in self.winfo_children() for child in self.winfo_children()
@ -254,11 +253,11 @@ class SubMixFrame(ttk.Frame):
def grid_configure(self): def grid_configure(self):
[ [
self.columnconfigure(i, minsize=_configuration.channel_width) self.columnconfigure(i, minsize=_configuration.level_width)
for i, _ in enumerate(self.labelframes) for i, _ in enumerate(self.labelframes)
] ]
[ [
self.rowconfigure(0, minsize=_configuration.channel_height) self.rowconfigure(0, minsize=_configuration.level_height)
for i, _ in enumerate(self.labelframes) for i, _ in enumerate(self.labelframes)
] ]

View File

@ -24,8 +24,6 @@ class Menus(tk.Menu):
self._is_topmost = tk.BooleanVar() self._is_topmost = tk.BooleanVar()
self._lock = tk.BooleanVar() self._lock = tk.BooleanVar()
self._unlock = tk.BooleanVar() self._unlock = tk.BooleanVar()
self._navigation_show = tk.BooleanVar(value=_configuration.navigation_show)
self._navigation_hide = tk.BooleanVar(value=not _configuration.navigation_show)
self._selected_bus = list(tk.BooleanVar() for _ in range(8)) self._selected_bus = list(tk.BooleanVar() for _ in range(8))
# voicemeeter menu # voicemeeter menu
@ -164,23 +162,6 @@ class Menus(tk.Menu):
) )
if not _configuration.themes_enabled: if not _configuration.themes_enabled:
self.menu_layout.entryconfig(2, state="disabled") self.menu_layout.entryconfig(2, state="disabled")
# layout/navigation
self.menu_navigation = tk.Menu(self.menu_layout, tearoff=0)
self.menu_layout.add_cascade(menu=self.menu_navigation, label="Navigation")
self.menu_navigation.add_checkbutton(
label="show",
onvalue=1,
offvalue=0,
variable=self._navigation_show,
command=partial(self.toggle_navigation, "show"),
)
self.menu_navigation.add_checkbutton(
label="hide",
onvalue=1,
offvalue=0,
variable=self._navigation_hide,
command=partial(self.toggle_navigation, "hide"),
)
# vban connect menu # vban connect menu
self.menu_vban = tk.Menu(self, tearoff=0) self.menu_vban = tk.Menu(self, tearoff=0)
@ -354,18 +335,6 @@ class Menus(tk.Menu):
else: else:
self.menu_configs.entryconfig(0, state="disabled") self.menu_configs.entryconfig(0, state="disabled")
def toggle_navigation(self, cmd=None):
if cmd == "show":
self.logger.debug("show navframe")
self.parent.nav_frame.grid()
self._navigation_show.set(True)
self._navigation_hide.set(not self._navigation_show.get())
else:
self.logger.debug("hide navframe")
self.parent.nav_frame.grid_remove()
self._navigation_hide.set(True)
self._navigation_show.set(not self._navigation_hide.get())
def vban_connect(self, i): def vban_connect(self, i):
opts = {} opts = {}
opts |= self.vban_config[f"connection-{i+1}"] opts |= self.vban_config[f"connection-{i+1}"]

View File

@ -15,8 +15,6 @@ class Navigation(ttk.Frame):
self.parent = parent self.parent = parent
self.logger = logger.getChild(self.__class__.__name__) self.logger = logger.getChild(self.__class__.__name__)
self.grid(row=0, column=3, padx=(0, 2), pady=(5, 5), sticky=(tk.W, tk.E)) self.grid(row=0, column=3, padx=(0, 2), pady=(5, 5), sticky=(tk.W, tk.E))
if not _configuration.navigation_show:
self.grid_remove()
self.styletable = self.parent.styletable self.styletable = self.parent.styletable
self.builder = builders.NavigationFrameBuilder(self) self.builder = builders.NavigationFrameBuilder(self)