mirror of
https://github.com/onyx-and-iris/voicemeeter-compact.git
synced 2024-11-21 12:20:56 +00:00
updates to gui to match changes to interfaces
updates to gui to match changes to interfaces now packaged with poetry and on pypi
This commit is contained in:
parent
0688a36a76
commit
2c39b9d215
22
README.md
22
README.md
@ -13,17 +13,14 @@ For an outline of past/future changes refer to: [CHANGELOG](CHANGELOG.md)
|
||||
## Prerequisites
|
||||
|
||||
- [Voicemeeter](https://voicemeeter.com/) (Basic v1.0.8.2), (Banana v2.0.6.2) or (Potato v3.0.2.2)
|
||||
- [Git for Windows](https://gitforwindows.org/)
|
||||
- Python 3.9+
|
||||
- Python 3.11+
|
||||
|
||||
## Installation
|
||||
|
||||
For a step-by-step guide [click here](INSTALLATION.md)
|
||||
|
||||
```
|
||||
git clone https://github.com/onyx-and-iris/voicemeeter-compact
|
||||
cd voicemeeter-compact
|
||||
pip install .
|
||||
pip install voicemeeter-compact
|
||||
```
|
||||
|
||||
## Usage
|
||||
@ -31,13 +28,13 @@ pip install .
|
||||
Example `__main__.py` file:
|
||||
|
||||
```python
|
||||
import voicemeeter
|
||||
import voicemeeterlib
|
||||
import vmcompact
|
||||
|
||||
|
||||
def main():
|
||||
# pass the kind_id and the vmr object to the app
|
||||
with voicemeeter.remote(kind_id) as vmr:
|
||||
with voicemeeterlib.api(kind_id) as vmr:
|
||||
app = vmcompact.connect(kind_id, vmr)
|
||||
app.mainloop()
|
||||
|
||||
@ -46,8 +43,6 @@ if __name__ == "__main__":
|
||||
# choose the kind of Voicemeeter (Local connection)
|
||||
kind_id = "banana"
|
||||
|
||||
voicemeeter.launch(kind_id, hide=False)
|
||||
|
||||
main()
|
||||
```
|
||||
|
||||
@ -141,13 +136,13 @@ A valid `vban.toml` might look like this:
|
||||
[connection-1]
|
||||
kind = 'banana'
|
||||
ip = '192.168.1.2'
|
||||
streamname = 'streampc'
|
||||
port = 6990
|
||||
streamname = 'worklaptop'
|
||||
port = 6980
|
||||
|
||||
[connection-2]
|
||||
kind = 'potato'
|
||||
ip = '192.168.1.3'
|
||||
streamname = 'worklaptop'
|
||||
streamname = 'streampc'
|
||||
port = 6990
|
||||
```
|
||||
|
||||
@ -165,7 +160,4 @@ Profiles may be loaded at any time via the menu.
|
||||
|
||||
[Vincent Burel](https://github.com/vburel2018) for creating Voicemeeter, its SDK, the C Remote API, the RT Packet service and Streamer View app!
|
||||
|
||||
[Christian Volkmann](https://github.com/chvolkmann) for the detailed work that went into creating the underlying Remote API Python Interface.
|
||||
Unfortunately, the Remote API Python Interface has `NOT` been open source licensed. I have [raised an issue](https://github.com/chvolkmann/voicemeeter-remote-python/issues/13) and asked directly and politely but so far no response. If a license is added in future I will update this section. Without an open source license there is no guarantee that in future this package may not be pulled down, without any notice.
|
||||
|
||||
[Rdbende](https://github.com/rdbende) for creating the beautiful Sun Valley Tkinter theme and adding it to Pypi!
|
||||
|
@ -1,9 +1,10 @@
|
||||
import voicemeeter
|
||||
import voicemeeterlib
|
||||
|
||||
import vmcompact
|
||||
|
||||
|
||||
def main():
|
||||
with voicemeeter.remote(kind_id) as vmr:
|
||||
with voicemeeterlib.api(kind_id) as vmr:
|
||||
app = vmcompact.connect(kind_id, vmr)
|
||||
app.mainloop()
|
||||
|
||||
@ -11,6 +12,4 @@ def main():
|
||||
if __name__ == "__main__":
|
||||
kind_id = "banana"
|
||||
|
||||
voicemeeter.launch(kind_id, hide=False)
|
||||
|
||||
main()
|
||||
|
45
configs/banana/example.toml
Normal file
45
configs/banana/example.toml
Normal file
@ -0,0 +1,45 @@
|
||||
[strip-0]
|
||||
label = "PhysStrip0"
|
||||
A1 = true
|
||||
gain = -8.8
|
||||
comp = 3.2
|
||||
|
||||
[strip-1]
|
||||
label = "PhysStrip1"
|
||||
B1 = true
|
||||
gate = 4.1
|
||||
|
||||
[strip-2]
|
||||
label = "PhysStrip2"
|
||||
gain = 1.1
|
||||
limit = -15
|
||||
|
||||
[strip-3]
|
||||
label = "VirtStrip0"
|
||||
bass = -3.2
|
||||
mid = 1.5
|
||||
treble = 2.1
|
||||
|
||||
[strip-4]
|
||||
label = "VirtStrip1"
|
||||
limit = -12
|
||||
|
||||
[bus-0]
|
||||
label = "PhysBus0"
|
||||
mute = true
|
||||
|
||||
[bus-1]
|
||||
label = "PhysBus1"
|
||||
mono = true
|
||||
|
||||
[bus-2]
|
||||
label = "PhysBus2"
|
||||
eq = true
|
||||
|
||||
[bus-3]
|
||||
label = "VirtBus0"
|
||||
eq_ab = true
|
||||
|
||||
[bus-4]
|
||||
label = "VirtBus1"
|
||||
gain = -22.8
|
23
configs/basic/example.toml
Normal file
23
configs/basic/example.toml
Normal file
@ -0,0 +1,23 @@
|
||||
[strip-0]
|
||||
label = "PhysStrip0"
|
||||
A1 = true
|
||||
gain = -8.8
|
||||
|
||||
[strip-1]
|
||||
label = "PhysStrip1"
|
||||
B1 = true
|
||||
audibility = 3.2
|
||||
|
||||
[strip-2]
|
||||
label = "VirtStrip0"
|
||||
bass = -3.2
|
||||
mid = 1.5
|
||||
treble = 2.1
|
||||
|
||||
[bus-0]
|
||||
label = "PhysBus0"
|
||||
mute = true
|
||||
|
||||
[bus-1]
|
||||
label = "PhysBus1"
|
||||
mono = true
|
70
configs/potato/example.toml
Normal file
70
configs/potato/example.toml
Normal file
@ -0,0 +1,70 @@
|
||||
[strip-0]
|
||||
label = "PhysStrip0"
|
||||
A1 = true
|
||||
gain = -8.8
|
||||
comp = 3.2
|
||||
|
||||
[strip-1]
|
||||
label = "PhysStrip1"
|
||||
B1 = true
|
||||
gate = 4.1
|
||||
|
||||
[strip-2]
|
||||
label = "PhysStrip2"
|
||||
gain = 1.1
|
||||
limit = -15
|
||||
|
||||
[strip-3]
|
||||
label = "PhysStrip3"
|
||||
B2 = false
|
||||
|
||||
[strip-4]
|
||||
label = "PhysStrip4"
|
||||
B3 = true
|
||||
gain = -8.8
|
||||
|
||||
[strip-5]
|
||||
label = "VirtStrip0"
|
||||
A3 = true
|
||||
A5 = true
|
||||
bass = -3.2
|
||||
mid = 1.5
|
||||
treble = 2.1
|
||||
|
||||
[strip-6]
|
||||
label = "VirtStrip1"
|
||||
limit = -12
|
||||
k = 3
|
||||
|
||||
[strip-7]
|
||||
label = "VirtStrip2"
|
||||
mc = true
|
||||
|
||||
[bus-0]
|
||||
label = "PhysBus0"
|
||||
mute = true
|
||||
|
||||
[bus-1]
|
||||
label = "PhysBus1"
|
||||
mono = true
|
||||
|
||||
[bus-2]
|
||||
label = "PhysBus2"
|
||||
eq = true
|
||||
|
||||
[bus-3]
|
||||
label = "PhysBus3"
|
||||
|
||||
[bus-4]
|
||||
label = "PhysBus4"
|
||||
|
||||
[bus-5]
|
||||
label = "VirtBus0"
|
||||
eq_ab = true
|
||||
|
||||
[bus-6]
|
||||
label = "VirtBus1"
|
||||
gain = -22.8
|
||||
|
||||
[bus-7]
|
||||
label = "VirtBus2"
|
42
poetry.lock
generated
Normal file
42
poetry.lock
generated
Normal file
@ -0,0 +1,42 @@
|
||||
[[package]]
|
||||
name = "sv-ttk"
|
||||
version = "0.1"
|
||||
description = "Python module to easily use the Sun Valley ttk theme"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.4"
|
||||
|
||||
[[package]]
|
||||
name = "vban-cmd"
|
||||
version = "1.0.5"
|
||||
description = "Python interface for the VBAN RT Packet Service (Sendtext)"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.11,<4.0"
|
||||
|
||||
[[package]]
|
||||
name = "voicemeeter-api"
|
||||
version = "0.1.6"
|
||||
description = "A Python wrapper for the Voiceemeter API"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.11,<4.0"
|
||||
|
||||
[metadata]
|
||||
lock-version = "1.1"
|
||||
python-versions = "^3.11"
|
||||
content-hash = "3b50c0fa4701fbf590b50609cf3d56a8f97b274ebb9e259ba52ce6771b106d0c"
|
||||
|
||||
[metadata.files]
|
||||
sv-ttk = [
|
||||
{file = "sv_ttk-0.1-py3-none-any.whl", hash = "sha256:c47ab1c70aad0333bc7f5063ab55e8a16b562e700e89e7853e577a1e2fdaa091"},
|
||||
{file = "sv_ttk-0.1.tar.gz", hash = "sha256:342754618292b6d224060307eccaa35b6f6c284b34b4da1d0cf0484b652ffb0f"},
|
||||
]
|
||||
vban-cmd = [
|
||||
{file = "vban-cmd-1.0.5.tar.gz", hash = "sha256:e50efd373816c01fb7e62f9ad90c33113b26cc12fbb46866b952b1946030282b"},
|
||||
{file = "vban_cmd-1.0.5-py3-none-any.whl", hash = "sha256:c51008049652fec61a94fb1b8ccd173cb0296684eee6249e9865f395340d32c5"},
|
||||
]
|
||||
voicemeeter-api = [
|
||||
{file = "voicemeeter-api-0.1.6.tar.gz", hash = "sha256:354fe37aea680f2431d428c9bd489d7d9c9e143cbd84a769c567dd657e63370d"},
|
||||
{file = "voicemeeter_api-0.1.6-py3-none-any.whl", hash = "sha256:20a3072b0379862254d5ee3cf4ec96f6c839291faa4ecbd29d3c1ed66a5492cb"},
|
||||
]
|
25
pyproject.toml
Normal file
25
pyproject.toml
Normal file
@ -0,0 +1,25 @@
|
||||
[tool.poetry]
|
||||
name = "voicemeeter-compact"
|
||||
version = "1.0.1"
|
||||
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" },
|
||||
]
|
||||
include = ["vmcompact/img/cat.ico"]
|
||||
|
||||
[tool.poetry.dependencies]
|
||||
python = "^3.11"
|
||||
sv-ttk = "^0.1"
|
||||
voicemeeter-api = { version = "^0.1.6", python = "^3.10" }
|
||||
vban-cmd = { version = "^1.0.5", python = "^3.10" }
|
||||
|
||||
[tool.poetry.dev-dependencies]
|
||||
|
||||
[build-system]
|
||||
requires = ["poetry-core>=1.0.0"]
|
||||
build-backend = "poetry.core.masonry.api"
|
@ -1,13 +1,13 @@
|
||||
import tkinter as tk
|
||||
from pathlib import Path
|
||||
from tkinter import ttk
|
||||
from typing import NamedTuple
|
||||
from pathlib import Path
|
||||
|
||||
from .errors import VMCompactErrors
|
||||
from .data import _kinds_all, _configuration, _base_values
|
||||
from .subject import Subject
|
||||
from .builders import MainFrameBuilder
|
||||
from .data import _base_values, _configuration, _kinds_all
|
||||
from .errors import VMCompactErrors
|
||||
from .menu import Menus
|
||||
from .subject import Subject
|
||||
|
||||
|
||||
class App(tk.Tk):
|
||||
@ -89,7 +89,7 @@ class App(tk.Tk):
|
||||
if _configuration.extended:
|
||||
self.nav_frame.extend.set(True)
|
||||
self.nav_frame.extend_frame()
|
||||
if self.kind.name == "Potato":
|
||||
if self.kind.name == "potato":
|
||||
self.builder.create_banner()
|
||||
|
||||
def on_update(self, subject, data):
|
||||
@ -145,7 +145,7 @@ class App(tk.Tk):
|
||||
self.drag_id = ""
|
||||
|
||||
|
||||
_apps = {kind.id: App.make(kind) for kind in _kinds_all}
|
||||
_apps = {kind.name: App.make(kind) for kind in _kinds_all}
|
||||
|
||||
|
||||
def connect(kind_id: str, vmr) -> App:
|
||||
|
@ -1,15 +1,15 @@
|
||||
import tkinter as tk
|
||||
from tkinter import ttk
|
||||
from functools import partial
|
||||
import abc
|
||||
import tkinter as tk
|
||||
from functools import partial
|
||||
from tkinter import ttk
|
||||
|
||||
import sv_ttk
|
||||
|
||||
|
||||
from .data import _base_values, _configuration
|
||||
from .channels import _make_channelframe
|
||||
from .navigation import Navigation
|
||||
from .config import StripConfig, BusConfig
|
||||
from .banner import Banner
|
||||
from .channels import _make_channelframe
|
||||
from .config import BusConfig, StripConfig
|
||||
from .data import _base_values, _configuration
|
||||
from .navigation import Navigation
|
||||
|
||||
|
||||
class AbstractBuilder(abc.ABC):
|
||||
@ -144,7 +144,7 @@ class NavigationFrameBuilder(AbstractBuilder):
|
||||
variable=self.navframe.submix,
|
||||
)
|
||||
self.navframe.submix_button.grid(column=0, row=0)
|
||||
if self.navframe.parent.kind.name != "Potato":
|
||||
if self.navframe.parent.kind.name != "potato":
|
||||
self.navframe.submix_button["state"] = "disabled"
|
||||
|
||||
def create_channel_button(self):
|
||||
@ -321,7 +321,7 @@ class StripConfigFrameBuilder(ChannelConfigFrameBuilder):
|
||||
"""Responsible for building channel configframe widgets"""
|
||||
|
||||
def setup(self):
|
||||
if self.configframe.parent.kind.name == "Basic":
|
||||
if self.configframe.parent.kind.name == "basic":
|
||||
self.configframe.slider_params = ("audibility",)
|
||||
self.configframe.slider_vars = (tk.DoubleVar(),)
|
||||
else:
|
||||
@ -349,12 +349,12 @@ class StripConfigFrameBuilder(ChannelConfigFrameBuilder):
|
||||
tk.BooleanVar() for _ in self.configframe.params
|
||||
)
|
||||
|
||||
if self.configframe.parent.kind.name in ("Banana", "Potato"):
|
||||
if self.configframe.parent.kind.name in ("banana", "potato"):
|
||||
if self.configframe.index == self.configframe.phys_in:
|
||||
self.configframe.params = list(
|
||||
map(lambda x: x.replace("mono", "mc"), self.configframe.params)
|
||||
)
|
||||
if self.configframe.parent.kind.name == "Banana":
|
||||
if self.configframe.parent.kind.name == "banana":
|
||||
pass
|
||||
# karaoke modes not in RT Packet yet. May implement in future
|
||||
"""
|
||||
|
@ -1,6 +1,6 @@
|
||||
import tkinter as tk
|
||||
from tkinter import ttk
|
||||
from math import log
|
||||
from tkinter import ttk
|
||||
|
||||
from . import builders
|
||||
from .data import _base_values, _configuration
|
||||
|
@ -1,9 +1,9 @@
|
||||
import tkinter as tk
|
||||
from tkinter import ttk
|
||||
from functools import partial
|
||||
from tkinter import ttk
|
||||
|
||||
from . import builders
|
||||
from .data import _configuration, _base_values
|
||||
from .data import _base_values, _configuration
|
||||
|
||||
|
||||
class Config(ttk.Frame):
|
||||
@ -96,7 +96,7 @@ class StripConfig(Config):
|
||||
|
||||
def make_row_0(self):
|
||||
if self.index < self.phys_in:
|
||||
if self.parent.kind.name == "Basic":
|
||||
if self.parent.kind.name == "basic":
|
||||
self.builder.create_audibility_slider()
|
||||
else:
|
||||
self.builder.create_comp_slider()
|
||||
|
@ -1,6 +1,7 @@
|
||||
import toml
|
||||
from pathlib import Path
|
||||
|
||||
import tomllib
|
||||
|
||||
configuration = {}
|
||||
|
||||
config_path = [Path.cwd() / "configs"]
|
||||
@ -11,8 +12,9 @@ for path in config_path:
|
||||
for filename in filenames:
|
||||
name = filename.with_suffix("").stem
|
||||
try:
|
||||
configs[name] = toml.load(filename)
|
||||
except toml.TomlDecodeError:
|
||||
with open(filename, "rb") as f:
|
||||
configs[name] = tomllib.load(f)
|
||||
except tomllib.TOMLDecodeError:
|
||||
print(f"Invalid TOML profile: configs/{filename.stem}")
|
||||
|
||||
for name, cfg in configs.items():
|
||||
|
@ -1,5 +1,6 @@
|
||||
from dataclasses import dataclass
|
||||
from voicemeeter import kinds
|
||||
|
||||
from voicemeeterlib import kinds
|
||||
|
||||
from .configurations import get_configuration
|
||||
|
||||
@ -51,7 +52,7 @@ class BaseValues(metaclass=SingletonMeta):
|
||||
# a vban connection established
|
||||
vban_connected: bool = False
|
||||
# pdirty delay
|
||||
pdelay: int = 5
|
||||
pdelay: int = 1
|
||||
# ldirty delay
|
||||
ldelay: int = 5
|
||||
|
||||
@ -59,7 +60,7 @@ class BaseValues(metaclass=SingletonMeta):
|
||||
_base_values = BaseValues()
|
||||
_configuration = Configurations()
|
||||
|
||||
_kinds = {kind.id: kind for kind in kinds.all}
|
||||
_kinds = {kind.name: kind for kind in kinds.kinds_all}
|
||||
|
||||
_kinds_all = _kinds.values()
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
import tkinter as tk
|
||||
from tkinter import ttk
|
||||
from math import log
|
||||
from tkinter import ttk
|
||||
|
||||
from . import builders
|
||||
from .data import _base_values, _configuration
|
||||
|
@ -1,16 +1,12 @@
|
||||
import tkinter as tk
|
||||
from tkinter import ttk, messagebox
|
||||
from functools import partial
|
||||
import webbrowser
|
||||
import sv_ttk
|
||||
import vbancmd
|
||||
from functools import partial
|
||||
from tkinter import messagebox, ttk
|
||||
|
||||
from .data import (
|
||||
get_configuration,
|
||||
_base_values,
|
||||
_configuration,
|
||||
kind_get,
|
||||
)
|
||||
import sv_ttk
|
||||
import vban_cmd
|
||||
|
||||
from .data import _base_values, _configuration, get_configuration, kind_get
|
||||
|
||||
|
||||
class Menus(tk.Menu):
|
||||
@ -76,31 +72,31 @@ class Menus(tk.Menu):
|
||||
command=partial(self.action_set_voicemeeter, "lock", False),
|
||||
)
|
||||
|
||||
# profiles menu
|
||||
menu_profiles = tk.Menu(self, tearoff=0)
|
||||
self.add_cascade(menu=menu_profiles, label="Profiles")
|
||||
self.menu_profiles_load = tk.Menu(menu_profiles, tearoff=0)
|
||||
menu_profiles.add_cascade(menu=self.menu_profiles_load, label="Load profile")
|
||||
defaults = {"base", "blank"}
|
||||
if len(self.target.profiles) > len(defaults) and all(
|
||||
key in self.target.profiles for key in defaults
|
||||
# configs menu
|
||||
menu_configs = tk.Menu(self, tearoff=0)
|
||||
self.add_cascade(menu=menu_configs, label="Configs")
|
||||
self.menu_configs_load = tk.Menu(menu_configs, tearoff=0)
|
||||
menu_configs.add_cascade(menu=self.menu_configs_load, label="Load profile")
|
||||
defaults = {"reset"}
|
||||
if len(self.target.configs) > len(defaults) and all(
|
||||
key in self.target.configs for key in defaults
|
||||
):
|
||||
[
|
||||
self.menu_profiles_load.add_command(
|
||||
self.menu_configs_load.add_command(
|
||||
label=profile, command=partial(self.load_profile, profile)
|
||||
)
|
||||
for profile in self.target.profiles.keys()
|
||||
for profile in self.target.configs.keys()
|
||||
if profile not in defaults
|
||||
]
|
||||
else:
|
||||
menu_profiles.entryconfig(0, state="disabled")
|
||||
menu_profiles.add_command(label="Reset to defaults", command=self.load_defaults)
|
||||
menu_configs.entryconfig(0, state="disabled")
|
||||
menu_configs.add_command(label="Reset to defaults", command=self.load_defaults)
|
||||
|
||||
# layout menu
|
||||
self.menu_layout = tk.Menu(self, tearoff=0)
|
||||
self.add_cascade(menu=self.menu_layout, label="Layout")
|
||||
# layout/submixes
|
||||
# here we build menu regardless of kind but disable if not Potato
|
||||
# here we build menu regardless of kind but disable if not potato
|
||||
buses = tuple(f"A{i+1}" for i in range(5)) + tuple(f"B{i+1}" for i in range(3))
|
||||
self.menu_submixes = tk.Menu(self.menu_layout, tearoff=0)
|
||||
self.menu_layout.add_cascade(menu=self.menu_submixes, label="Submixes")
|
||||
@ -116,7 +112,7 @@ class Menus(tk.Menu):
|
||||
for i in range(8)
|
||||
]
|
||||
self._selected_bus[_configuration.submixes].set(True)
|
||||
if self.parent.kind.name != "Potato":
|
||||
if self.parent.kind.name != "potato":
|
||||
self.menu_layout.entryconfig(0, state="disabled")
|
||||
# layout/extends
|
||||
self.menu_extends = tk.Menu(self.menu_layout, tearoff=0)
|
||||
@ -211,14 +207,14 @@ class Menus(tk.Menu):
|
||||
setattr(self.target.command, cmd, val)
|
||||
|
||||
def load_profile(self, profile):
|
||||
self.target.apply_profile(profile)
|
||||
self.target.apply_config(profile)
|
||||
|
||||
def load_defaults(self):
|
||||
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"
|
||||
)
|
||||
if resp:
|
||||
self.target.apply_profile("base")
|
||||
self.target.apply_config("reset")
|
||||
|
||||
def always_on_top(self):
|
||||
self.parent.attributes("-topmost", self._is_topmost.get())
|
||||
@ -258,7 +254,7 @@ class Menus(tk.Menu):
|
||||
if isinstance(menu, tk.Menu)
|
||||
]
|
||||
self.menu_lock.config(bg=f"{'black' if theme == 'dark' else 'white'}")
|
||||
self.menu_profiles_load.config(bg=f"{'black' if theme == 'dark' else 'white'}")
|
||||
self.menu_configs_load.config(bg=f"{'black' if theme == 'dark' else 'white'}")
|
||||
[
|
||||
menu.config(bg=f"{'black' if theme == 'dark' else 'white'}")
|
||||
for menu in self.menu_vban.winfo_children()
|
||||
@ -280,7 +276,7 @@ class Menus(tk.Menu):
|
||||
opts = {}
|
||||
opts |= self.vban_config[f"connection-{i+1}"]
|
||||
kind_id = opts.pop("kind")
|
||||
self.vban = vbancmd.connect(kind_id, **opts)
|
||||
self.vban = vban_cmd.api(kind_id, **opts)
|
||||
# login to vban interface
|
||||
self.vban.login()
|
||||
# destroy the current App frames
|
||||
@ -294,7 +290,7 @@ class Menus(tk.Menu):
|
||||
target_menu.entryconfig(0, state="disabled")
|
||||
target_menu.entryconfig(1, state="normal")
|
||||
self.menu_layout.entryconfig(
|
||||
0, state=f"{'normal' if kind.name == 'Potato' else 'disabled'}"
|
||||
0, state=f"{'normal' if kind.name == 'potato' else 'disabled'}"
|
||||
)
|
||||
|
||||
def vban_disconnect(self, i):
|
||||
@ -311,7 +307,7 @@ class Menus(tk.Menu):
|
||||
target_menu.entryconfig(0, state="normal")
|
||||
target_menu.entryconfig(1, state="disabled")
|
||||
self.menu_layout.entryconfig(
|
||||
0, state=f"{'normal' if kind.name == 'Potato' else 'disabled'}"
|
||||
0, state=f"{'normal' if kind.name == 'potato' else 'disabled'}"
|
||||
)
|
||||
|
||||
self.after(15000, self.enable_vban_menus)
|
||||
|
Loading…
Reference in New Issue
Block a user