Compare commits

..

No commits in common. "5ab1fd71029fb7775e670859ed465e821cba7a9f" and "3b6e1f61a4a263ca26d5bf0d71417c68d96e215c" have entirely different histories.

16 changed files with 107 additions and 260 deletions

2
.gitignore vendored
View File

@ -131,5 +131,3 @@ dmypy.json
# Pyre type checker
.pyre/
.vscode/

View File

@ -7,33 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
- [ ] Add support for forest theme (if rbende adds it to pypi)
## [1.7.0] - 2023-06-26
### Changed
- There are changes to how some parameters must be set in user toml configs.
- use `comp.knob` to set a strip comp slider.
- use `gate.knob` to set a strip gate slider.
- use `eq.on` to set a bus eq.on button.
- use `eq.ab` to set a bus eq.ab button.
Check example configs.
- `configs` directory may now be located in one of the following locations:
- \<current working directory>/configs/
- \<user home directory>/.configs/vm-compact/configs/
- \<user home directory>/Documents/Voicemeeter/configs/
- dependency updates:
- sv_ttk updated to v2.4.5.
- voicemeeter-api updated to v2.0.1.
- vban-cmd updated to v2.0.0.
### Fixed
- A number of changes that reduce the amount of api calls being made.
- [ ] Add support for forest theme (should be coming soon)
## [1.6.0] - 2022-09-29

View File

@ -2,12 +2,12 @@
label = "PhysStrip0"
A1 = true
gain = -8.8
comp.knob = 3.2
comp = 3.2
[strip-1]
label = "PhysStrip1"
B1 = true
gate.knob = 4.1
gate = 4.1
[strip-2]
label = "PhysStrip2"
@ -34,12 +34,12 @@ mono = true
[bus-2]
label = "PhysBus2"
eq.on = true
eq = true
mode = "composite"
[bus-3]
label = "VirtBus0"
eq.ab = true
eq_ab = true
mode = "upmix61"
[bus-4]

View File

@ -2,12 +2,12 @@
label = "PhysStrip0"
A1 = true
gain = -8.8
comp.knob = 3.2
comp = 3.2
[strip-1]
label = "PhysStrip1"
B1 = true
gate.knob = 4.1
gate = 4.1
[strip-2]
label = "PhysStrip2"
@ -50,7 +50,7 @@ mono = true
[bus-2]
label = "PhysBus2"
eq.on = true
eq = true
[bus-3]
label = "PhysBus3"
@ -62,7 +62,7 @@ mode = "composite"
[bus-5]
label = "VirtBus0"
eq.ab = true
eq_ab = true
[bus-6]
label = "VirtBus1"

25
poetry.lock generated
View File

@ -38,20 +38,6 @@ category = "dev"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
[[package]]
name = "isort"
version = "5.12.0"
description = "A Python utility / library to sort Python imports."
category = "dev"
optional = false
python-versions = ">=3.8.0"
[package.extras]
colors = ["colorama (>=0.4.3)"]
requirements-deprecated-finder = ["pip-api", "pipreqs"]
pipfile-deprecated-finder = ["pip-shims (>=0.5.2)", "pipreqs", "requirementslib"]
plugins = ["setuptools"]
[[package]]
name = "mypy-extensions"
version = "0.4.3"
@ -82,8 +68,8 @@ test = ["appdirs (==1.4.4)", "pytest-cov (>=2.7)", "pytest-mock (>=3.6)", "pytes
[[package]]
name = "sv-ttk"
version = "2.4.5"
description = "A gorgeous theme for Tkinter, based on Windows 11's UI"
version = "2.0"
description = "A gorgeous theme for Tkinter that looks like Windows 11"
category = "main"
optional = false
python-versions = ">=3.4"
@ -98,7 +84,7 @@ python-versions = ">=3.7"
[[package]]
name = "vban-cmd"
version = "2.0.0"
version = "1.8.1"
description = "Python interface for the VBAN RT Packet Service (Sendtext)"
category = "main"
optional = false
@ -109,7 +95,7 @@ tomli = {version = ">=2.0.1,<3.0.0", markers = "python_version < \"3.11\""}
[[package]]
name = "voicemeeter-api"
version = "2.0.1"
version = "0.8.4"
description = "A Python wrapper for the Voiceemeter API"
category = "main"
optional = false
@ -121,13 +107,12 @@ tomli = {version = ">=2.0.1,<3.0.0", markers = "python_version < \"3.11\""}
[metadata]
lock-version = "1.1"
python-versions = "^3.10"
content-hash = "ffb9af7ef7aa87ac08a09293de5e99487155faaa459cd49964ac95589deb69fa"
content-hash = "ba702e1c74c507e75070c2c58bffe5a7787d1dfa1b4ff7b5cedce7374871f7db"
[metadata.files]
black = []
click = []
colorama = []
isort = []
mypy-extensions = []
pathspec = []
platformdirs = []

View File

@ -1,25 +1,26 @@
[tool.poetry]
name = "voicemeeter-compact"
version = "1.7.1"
version = "1.6.5"
description = "A Compact Voicemeeter Remote App"
authors = ["onyx-and-iris <code@onyxandiris.online>"]
license = "MIT"
readme = "README.md"
repository = "https://github.com/onyx-and-iris/voicemeeter-compact"
packages = [{ include = "vmcompact" }]
packages = [
{ include = "vmcompact" },
]
include = ["vmcompact/img/cat.ico"]
[tool.poetry.dependencies]
python = "^3.10"
sv-ttk = "^2.4.5"
sv-ttk = "^2.0"
tomli = { version = "^2.0.1", python = "<3.11" }
voicemeeter-api = "^2.0.1"
vban-cmd = "^2.0.0"
voicemeeter-api = "^0.8.4"
vban-cmd = "^1.8.1"
[tool.poetry.dev-dependencies]
black = { version = "^22.6.0", allow-prereleases = true }
isort = "^5.12.0"
black = {version = "^22.6.0", allow-prereleases = true}
[build-system]
requires = ["poetry-core>=1.0.0"]

View File

@ -1,13 +1,11 @@
import tkinter as tk
from functools import cached_property
from pathlib import Path
from tkinter import ttk
from typing import NamedTuple
from .builders import MainFrameBuilder
from .configurations import loader
from .data import _base_values, _configuration, _kinds_all
from .errors import VMCompactError
from .errors import VMCompactErrors
from .menu import Menus
from .subject import Subject
@ -36,14 +34,13 @@ class App(tk.Tk):
super().__init__()
self._vmr = vmr
self._vmr.event.add(["pdirty", "ldirty"])
self._vmr.init_thread()
self._vmr.event.ldirty = True
self._vmr.event.remove(["mdirty", "midi"])
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["menu"] = Menus(self, vmr)
self.styletable = ttk.Style()
if _configuration.config:
@ -54,9 +51,6 @@ class App(tk.Tk):
self.drag_id = ""
self.bind("<Configure>", self.dragging)
def __str__(self):
return f"{type(self).__name__}App"
@property
def target(self):
"""returns the current interface"""
@ -81,8 +75,8 @@ class App(tk.Tk):
if kind:
self.kind = kind
# register event callbacks
self.target.subject.add([self.on_pdirty, self.on_ldirty])
# register app as observer
self.target.subject.add(self)
self.bus_frame = None
self.submix_frame = None
@ -97,12 +91,12 @@ class App(tk.Tk):
if self.kind.name == "potato":
self.builder.create_banner()
def on_pdirty(self):
if _base_values.run_update:
self.after(1, self.subject.notify, "pdirty")
def on_update(self, subject):
"""called whenever notified of update"""
def on_ldirty(self):
if not _base_values.dragging:
if subject == "pdirty" and _base_values.run_update:
self.after(1, self.subject.notify, "pdirty")
elif subject == "ldirty" and not _base_values.dragging:
self.after(1, self.subject.notify, "ldirty")
def _destroy_top_level_frames(self):
@ -133,11 +127,6 @@ class App(tk.Tk):
self.drag_id = ""
_base_values.dragging = False
@cached_property
def userconfigs(self):
self._configs = loader(self.kind.name)
return self._configs
_apps = {kind.name: App.make(kind) for kind in _kinds_all}
@ -148,5 +137,5 @@ def connect(kind_id: str, vmr) -> App:
try:
VMMIN_cls = _apps[kind_id]
except KeyError:
raise VMCompactError(f"Invalid kind: {kind_id}")
raise VMCompactErrors(f"Invalid kind: {kind_id}")
return VMMIN_cls(vmr)

View File

@ -1,19 +1,15 @@
import logging
import tkinter as tk
from tkinter import ttk
from .data import _base_values, _configuration
logger = logging.getLogger(__name__)
class Banner(ttk.Frame):
def __init__(self, parent):
super().__init__()
self.parent = parent
self.parent.subject.add(self)
self.logger = logger.getChild(self.__class__.__name__)
self.submix = tk.StringVar(value=self.target.bus[_configuration.submixes].label)
self.submix = tk.StringVar()
self.submix.set(self.target.bus[_configuration.submixes].label)
self.label = ttk.Label(
self,
@ -21,15 +17,19 @@ class Banner(ttk.Frame):
)
self.label.grid(column=0, row=0, sticky=(tk.N, tk.S, tk.W, tk.E))
self.upd_submix()
@property
def target(self):
"""returns the current interface"""
return self.parent.target
def on_update(self, subject):
if subject == "submix":
if not _base_values.dragging:
self.logger.debug("checking submix for banner")
self.submix.set(self.target.bus[_configuration.submixes].label)
self.label["text"] = f"SUBMIX: {self.submix.get().upper()}"
def upd_submix(self):
self.after(1, self.upd_submix_step)
def upd_submix_step(self):
if not _base_values.dragging:
self.submix.set(self.target.bus[_configuration.submixes].label)
self.label["text"] = f"SUBMIX: {self.submix.get().upper()}"
self.after(100, self.upd_submix_step)

View File

@ -12,8 +12,6 @@ from .config import BusConfig, StripConfig
from .data import _base_values, _configuration
from .navigation import Navigation
logger = logging.getLogger(__name__)
class AbstractBuilder(abc.ABC):
@abc.abstractmethod
@ -30,10 +28,11 @@ class AbstractBuilder(abc.ABC):
class MainFrameBuilder(AbstractBuilder):
"""Responsible for building the frames that sit directly on the mainframe"""
logger = logging.getLogger("builders.mainframebuilder")
def __init__(self, app):
self.kind = app.kind
self.app = app
self.logger = logger.getChild(self.__class__.__name__)
def setup(self):
self.app.title(
@ -337,7 +336,7 @@ class StripConfigFrameBuilder(ChannelConfigFrameBuilder):
self.configframe.slider_params = ("audibility",)
self.configframe.slider_vars = (tk.DoubleVar(),)
else:
self.configframe.slider_params = ("comp.knob", "gate.knob", "limit")
self.configframe.slider_params = ("comp", "gate", "limit")
self.configframe.slider_vars = [
tk.DoubleVar() for _ in self.configframe.slider_params
]
@ -394,16 +393,16 @@ class StripConfigFrameBuilder(ChannelConfigFrameBuilder):
orient="horizontal",
length=_configuration.level_width,
variable=self.configframe.slider_vars[
self.configframe.slider_params.index("comp.knob")
self.configframe.slider_params.index("comp")
],
command=partial(self.configframe.scale_callback, "comp.knob"),
command=partial(self.configframe.scale_callback, "comp"),
)
comp_scale.bind(
"<Double-Button-1>", partial(self.configframe.reset_scale, "comp.knob", 0)
"<Double-Button-1>", partial(self.configframe.reset_scale, "comp", 0)
)
comp_scale.bind("<Button-1>", self.configframe.scale_press)
comp_scale.bind("<ButtonRelease-1>", self.configframe.scale_release)
comp_scale.bind("<Enter>", partial(self.configframe.scale_enter, "comp.knob"))
comp_scale.bind("<Enter>", partial(self.configframe.scale_enter, "comp"))
comp_scale.bind("<Leave>", self.configframe.scale_leave)
comp_label.grid(column=0, row=0)
@ -418,16 +417,16 @@ class StripConfigFrameBuilder(ChannelConfigFrameBuilder):
orient="horizontal",
length=_configuration.level_width,
variable=self.configframe.slider_vars[
self.configframe.slider_params.index("gate.knob")
self.configframe.slider_params.index("gate")
],
command=partial(self.configframe.scale_callback, "gate.knob"),
command=partial(self.configframe.scale_callback, "gate"),
)
gate_scale.bind(
"<Double-Button-1>", partial(self.configframe.reset_scale, "gate.knob", 0)
"<Double-Button-1>", partial(self.configframe.reset_scale, "gate", 0)
)
gate_scale.bind("<Button-1>", self.configframe.scale_press)
gate_scale.bind("<ButtonRelease-1>", self.configframe.scale_release)
gate_scale.bind("<Enter>", partial(self.configframe.scale_enter, "gate.knob"))
gate_scale.bind("<Enter>", partial(self.configframe.scale_enter, "gate"))
gate_scale.bind("<Leave>", self.configframe.scale_leave)
gate_label.grid(column=2, row=0)
@ -564,7 +563,7 @@ class BusConfigFrameBuilder(ChannelConfigFrameBuilder):
}
self.configframe.bus_modes = list(self.configframe.bus_mode_map.keys())
# fmt: on
self.configframe.params = ("mono", "eq.on", "eq.ab")
self.configframe.params = ("mono", "eq", "eq_ab")
self.configframe.param_vars = [tk.BooleanVar() for _ in self.configframe.params]
self.configframe.bus_mode_label_text = tk.StringVar(
value=self.configframe.bus_mode_map[self.configframe.current_bus_mode()]

View File

@ -1,12 +1,10 @@
import logging
import tkinter as tk
from math import log
from tkinter import ttk
from . import builders
from .data import _base_values, _configuration
logger = logging.getLogger(__name__)
class ChannelLabelFrame(ttk.LabelFrame):
"""Base class for a single channel"""
@ -16,7 +14,6 @@ class ChannelLabelFrame(ttk.LabelFrame):
self.parent = parent
self.index = index
self.id = id
self.logger = logger.getChild(self.__class__.__name__)
self.styletable = self.parent.parent.styletable
self.builder = builders.ChannelLabelFrameBuilder(self, index, id)
@ -43,21 +40,18 @@ class ChannelLabelFrame(ttk.LabelFrame):
return self.parent.target
def getter(self, param):
try:
if hasattr(self.target, param):
return getattr(self.target, param)
except AttributeError as e:
self.logger(f"{type(e).__name__}: {e}")
def setter(self, param, value):
if param in dir(self.target): # avoid calling getattr (with hasattr)
if hasattr(self.target, param):
setattr(self.target, param, value)
def scale_callback(self, *args):
"""callback function for scale widget"""
val = round(self.gain.get(), 1)
self.setter("gain", val)
self.gainlabel.set(val)
self.setter("gain", self.gain.get())
self.gainlabel.set(round(self.gain.get(), 1))
def toggle_mute(self, *args):
self.target.mute = self.mute.get()

View File

@ -1,11 +1,10 @@
import logging
import tkinter as tk
from functools import partial
from tkinter import ttk
from . import builders
from .data import _base_values, _configuration
logger = logging.getLogger(__name__)
class Config(ttk.Frame):
def __init__(self, parent, index, _id):
@ -13,7 +12,6 @@ class Config(ttk.Frame):
self.parent = parent
self.index = index
self.id = _id
self.logger = logger.getChild(self.__class__.__name__)
self.styletable = parent.styletable
self.phys_in, self.virt_in = parent.kind.ins
self.phys_out, self.virt_out = parent.kind.outs
@ -31,26 +29,12 @@ class Config(ttk.Frame):
return self.parent.target
def getter(self, param):
param = param.split(".")
try:
if len(param) == 2:
target = getattr(self.target, param[0])
return getattr(target, param[1])
else:
return getattr(self.target, param[0])
except AttributeError as e:
self.logger.error(f"{type(e).__name__}: {e}")
if hasattr(self.target, param):
return getattr(self.target, param)
def setter(self, param, value):
param = param.split(".")
try:
if len(param) == 2:
target = getattr(self.target, param[0])
setattr(target, param[1], value)
else:
setattr(self.target, param[0], value)
except AttributeError as e:
self.logger(f"{type(e).__name__}: {e}")
if hasattr(self.target, param):
setattr(self.target, param, value)
def scale_press(self, *args):
self.after(1, self.remove_events)
@ -82,7 +66,7 @@ class Config(ttk.Frame):
"""callback function for scale widget"""
val = self.slider_vars[self.slider_params.index(param)].get()
self.setter(param, round(val, 1))
self.setter(param, val)
self.parent.nav_frame.info_text.set(round(val, 1))
def reset_scale(self, param, val, *args):
@ -114,7 +98,6 @@ class StripConfig(Config):
self.make_row_2()
self.builder.grid_configure()
self.parent.target.clear_dirty()
self.sync()
@property
@ -172,12 +155,6 @@ class StripConfig(Config):
self.param_vars[i].set(self.getter(param))
for i, param in enumerate(self.params)
]
if not _base_values.vban_connected: # slider vars not defined in RT Packet
[
self.slider_vars[i].set(self.getter(param))
for i, param in enumerate(self.slider_params)
if self.index < self.phys_in
]
if not _configuration.themes_enabled:
[
@ -216,7 +193,6 @@ class BusConfig(Config):
self.make_row_1()
self.builder.grid_configure()
self.parent.target.clear_dirty()
self.sync()
@property

View File

@ -6,32 +6,26 @@ try:
except ModuleNotFoundError:
import tomli as tomllib
logger = logging.getLogger(__name__)
LOGGER = logging.getLogger("configurations")
configuration = {}
configpaths = [
Path.cwd() / "configs",
Path.home() / ".config" / "vm-compact" / "configs",
Path.home() / "Documents" / "Voicemeeter" / "configs",
]
for configpath in configpaths:
if configpath.is_dir():
filepaths = list(configpath.glob("*.toml"))
if any(f.stem in ("app", "vban") for f in filepaths):
configs = {}
for filepath in filepaths:
filename = filepath.with_suffix("").stem
if filename in ("app", "vban"):
try:
with open(filepath, "rb") as f:
configs[filename] = tomllib.load(f)
logger.info(f"configuration: {filename} loaded into memory")
except tomllib.TOMLDecodeError:
logger.error(f"Invalid TOML config: configs/{filename.stem}")
config_path = [Path.cwd() / "configs"]
for path in config_path:
if path.is_dir():
filenames = list(path.glob("*.toml"))
configs = {}
for filename in filenames:
name = filename.with_suffix("").stem
try:
with open(filename, "rb") as f:
configs[name] = tomllib.load(f)
except tomllib.TOMLDecodeError:
print(f"Invalid TOML config: configs/{filename.stem}")
configuration |= configs
break
for name, cfg in configs.items():
LOGGER.info(f"Loaded configuration configs/{name}")
configuration[name] = cfg
_defaults = {
"configs": {
@ -66,19 +60,3 @@ else:
def get_configuration(key):
if key in configuration:
return configuration[key]
def loader(kind_id):
configs = {}
userconfigpath = Path.home() / ".config" / "vm-compact" / "configs" / kind_id
if userconfigpath.exists():
filepaths = list(userconfigpath.glob("*.toml"))
for filepath in filepaths:
identifier = filepath.with_suffix("").stem
try:
with open(filepath, "rb") as f:
configs[identifier] = tomllib.load(f)
logger.info(f"loader: {identifier} loaded into memory")
except tomllib.TOMLDecodeError:
logger.error(f"Invalid TOML config: configs/{filename.stem}")
return configs

View File

@ -1,2 +1,4 @@
class VMCompactError(Exception):
"""Exception raised when general errors occur"""
class VMCompactErrors(Exception):
"""Base classs for VMCompact Errors"""
pass

View File

@ -1,4 +1,5 @@
import tkinter as tk
from math import log
from tkinter import ttk
from . import builders
@ -41,13 +42,11 @@ class GainLayer(ttk.LabelFrame):
return "gainlayer"
def getter(self, param):
try:
if hasattr(self.target, param):
return getattr(self.target, param)
except AttributeError as e:
self.logger(f"{type(e).__name__}: {e}")
def setter(self, param, value):
if param in dir(self.target): # avoid calling getattr (with hasattr)
if hasattr(self.target, param):
setattr(self.target, param, value)
def reset_gain(self, *args):
@ -58,9 +57,8 @@ class GainLayer(ttk.LabelFrame):
def scale_callback(self, *args):
"""callback function for scale widget"""
val = round(self.gain.get(), 1)
self.setter("gain", val)
self.gainlabel.set(val)
self.setter("gain", self.gain.get())
self.gainlabel.set(round(self.gain.get(), 1))
def scale_press(self, *args):
self.after(1, self.remove_events)
@ -159,8 +157,7 @@ class GainLayer(ttk.LabelFrame):
self.level.set(
(
0
if self.parent.parent.strip_frame.strips[self.index].mute.get()
or not self.on.get()
if self.parent.target.strip[self.index].mute or not self.on.get()
else 72 + val - 12 + self.gain.get()
)
)

View File

@ -2,23 +2,22 @@ import logging
import tkinter as tk
import webbrowser
from functools import partial
from tkinter import messagebox
from tkinter import messagebox, ttk
import sv_ttk
import vban_cmd
from vban_cmd.error import VBANCMDConnectionError
from vban_cmd.error import VBANCMDError
from .data import _base_values, _configuration, get_configuration, kind_get
logger = logging.getLogger(__name__)
class Menus(tk.Menu):
logger = logging.getLogger("menu.menus")
def __init__(self, parent, vmr):
super().__init__()
self.parent = parent
self.vmr = vmr
self.logger = logger.getChild(self.__class__.__name__)
self.vban_config = get_configuration("vban")
self.app_config = get_configuration("app")
self._is_topmost = tk.BooleanVar()
@ -93,14 +92,6 @@ class Menus(tk.Menu):
for profile in self.target.configs.keys()
if profile not in self.config_defaults
]
elif self.parent.userconfigs:
[
self.menu_configs_load.add_command(
label=name, command=partial(self.load_custom_profile, data)
)
for name, data in self.parent.userconfigs.items()
if name not in self.config_defaults
]
else:
self.menu_configs.entryconfig(0, state="disabled")
self.menu_configs.add_command(
@ -221,24 +212,15 @@ class Menus(tk.Menu):
self._unlock.set(not self._lock.get())
setattr(self.target.command, cmd, val)
def load_custom_profile(self, profile):
self.logger.info(f"loading user profile {profile}")
self.target.apply(profile)
def load_profile(self, profile):
self.logger.info(f"loading user profile {profile}")
self.target.apply_config(profile)
def load_defaults(self):
msg = (
"Are you sure you want to Reset values to defaults?",
"Physical strips B1, Virtual strips A1",
"Mono, Solo, Mute, EQ all OFF",
"Gain sliders for Strip/Bus at 0.0",
resp = messagebox.askyesno(
message="Are you sure you want to Reset values to defaults?\nPhysical strips B1, Virtual strips A1\nMono, Solo, Mute, EQ all OFF"
)
resp = messagebox.askyesno(message="\n".join(msg))
if resp:
self.load_profile("reset")
self.target.apply_config("reset")
def always_on_top(self):
self.parent.attributes("-topmost", self._is_topmost.get())
@ -260,7 +242,6 @@ class Menus(tk.Menu):
self.parent.nav_frame.show_submix()
for j, var in enumerate(self._selected_bus):
var.set(i == j)
self.parent.subject.notify("submix")
def load_theme(self, theme):
sv_ttk.set_theme(theme)
@ -301,11 +282,6 @@ class Menus(tk.Menu):
for key in self.target.configs.keys()
if key not in self.config_defaults
]
[
self.menu_configs_load.delete(key)
for key in self.parent.userconfigs.keys()
if key not in self.config_defaults
]
[
self.menu_vban.entryconfig(j, state="disabled")
@ -324,14 +300,6 @@ class Menus(tk.Menu):
for profile in self.target.configs.keys()
if profile not in self.config_defaults
]
elif self.parent.userconfigs:
[
self.menu_configs_load.add_command(
label=name, command=partial(self.load_custom_profile, data)
)
for name, data in self.parent.userconfigs.items()
if name not in self.config_defaults
]
else:
self.menu_configs.entryconfig(0, state="disabled")
@ -344,19 +312,16 @@ class Menus(tk.Menu):
try:
self.logger.info(f"Attempting vban connection to {opts.get('ip')}")
self.vban.login()
except VBANCMDConnectionError as e:
except VBANCMDError as e:
self.vban.logout()
msg = (
f"Timeout attempting to establish connection to {opts.get('ip')}",
f"Please check your connection settings",
)
msg = (str(e), f"Please check your connection settings")
messagebox.showerror("Connection Error", "\n".join(msg))
msg = (str(e), f"resuming local connection")
self.logger.error(", ".join(msg))
self.after(1, self.enable_vban_menus)
return
self.menu_teardown(i)
self.vban.event.add(["pdirty", "ldirty"])
self.vban.event.ldirty = True
# destroy the current App frames
self.parent._destroy_top_level_frames()
_base_values.vban_connected = True
@ -371,11 +336,6 @@ class Menus(tk.Menu):
self.menu_layout.entryconfig(
0, state=f"{'normal' if kind.name == 'potato' else 'disabled'}"
)
# ensure the configs are reloaded into memory
if "config" in self.parent.target.__dict__:
del self.parent.target.__dict__["config"]
if "userconfigs" in self.parent.__dict__:
del self.parent.__dict__["userconfigs"]
self.menu_setup()
def vban_disconnect(self, i):
@ -396,11 +356,6 @@ class Menus(tk.Menu):
self.menu_layout.entryconfig(
0, state=f"{'normal' if kind.name == 'potato' else 'disabled'}"
)
# ensure the configs are reloaded into memory
if "config" in self.parent.target.__dict__:
del self.parent.target.__dict__["config"]
if "userconfigs" in self.parent.__dict__:
del self.parent.__dict__["userconfigs"]
self.menu_setup()
self.after(15000, self.enable_vban_menus)

View File

@ -6,14 +6,13 @@ from . import builders
from .data import _configuration
from .gainlayer import SubMixFrame
logger = logging.getLogger(__name__)
class Navigation(ttk.Frame):
logger = logging.getLogger("navigation.navigation")
def __init__(self, parent):
super().__init__(parent)
self.parent = parent
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.styletable = self.parent.styletable