Compare commits

..

No commits in common. "dacc972b1730924eb34f040b30d5248eb71f0e5a" and "bde9020471f0154f7ab9ad4369587ca5aff66ec5" have entirely different histories.

9 changed files with 22 additions and 157 deletions

View File

@ -131,11 +131,9 @@ For Gate BP Sidechain, Attack, Hold, Release you may use:
To reset a slider back to its default value you may use `Control + Shift + R`. To reset a slider back to its default value you may use `Control + Shift + R`.
### Menu #### `Menu`
#### `Voicemeeter` A single menu item `Voicemeeter` can be opened using `Alt` and then `v`. The menu allows you to:
The `Voicemeeter` menu can be opened using `Alt` and then `v`. It offers the following options:
- Restart Voicemeeter audio engine - Restart Voicemeeter audio engine
- Save/Load current settings (as an xml file) - Save/Load current settings (as an xml file)
@ -145,11 +143,7 @@ The `Save Settings` option opens a popup window with two buttons, `Browse` and `
`Load Settings` and `Load on Startup` both open an Open dialog box immediately. `Load Settings` and `Load on Startup` both open an Open dialog box immediately.
#### `Theme` ### `Quick access binds`
The `Theme` menu can be opened using `Alt` and then `t`. Use this menu to select from a list of coloured themes. Some themes offer higher contrast colours. An application restart is required to load a new theme. Once a theme is selected it will become the default for future startups.
### Quick access binds
There are a number of quick binds available to assist with faster navigation and general use. There are a number of quick binds available to assist with faster navigation and general use.

37
pdm.lock generated
View File

@ -5,7 +5,7 @@
groups = ["default", "build", "lint", "test"] groups = ["default", "build", "lint", "test"]
strategy = ["cross_platform"] strategy = ["cross_platform"]
lock_version = "4.4" lock_version = "4.4"
content_hash = "sha256:4295f6824f37484ec423b53bd425334b0e039a51d81261b52c8890928fcf3948" content_hash = "sha256:ca47eaae0de5aa6bcc3fde33b6c1fa7dc2476aeb680f00bb1c550fe06ad67c55"
[[package]] [[package]]
name = "altgraph" name = "altgraph"
@ -74,31 +74,6 @@ files = [
{file = "macholib-1.16.2.tar.gz", hash = "sha256:557bbfa1bb255c20e9abafe7ed6cd8046b48d9525db2f9b77d3122a63a2a8bf8"}, {file = "macholib-1.16.2.tar.gz", hash = "sha256:557bbfa1bb255c20e9abafe7ed6cd8046b48d9525db2f9b77d3122a63a2a8bf8"},
] ]
[[package]]
name = "mypy"
version = "1.7.0"
requires_python = ">=3.8"
summary = "Optional static typing for Python"
dependencies = [
"mypy-extensions>=1.0.0",
"tomli>=1.1.0; python_version < \"3.11\"",
"typing-extensions>=4.1.0",
]
files = [
{file = "mypy-1.7.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5da84d7bf257fd8f66b4f759a904fd2c5a765f70d8b52dde62b521972a0a2357"},
{file = "mypy-1.7.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a3637c03f4025f6405737570d6cbfa4f1400eb3c649317634d273687a09ffc2f"},
{file = "mypy-1.7.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b633f188fc5ae1b6edca39dae566974d7ef4e9aaaae00bc36efe1f855e5173ac"},
{file = "mypy-1.7.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:d6ed9a3997b90c6f891138e3f83fb8f475c74db4ccaa942a1c7bf99e83a989a1"},
{file = "mypy-1.7.0-cp310-cp310-win_amd64.whl", hash = "sha256:1fe46e96ae319df21359c8db77e1aecac8e5949da4773c0274c0ef3d8d1268a9"},
{file = "mypy-1.7.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:df67fbeb666ee8828f675fee724cc2cbd2e4828cc3df56703e02fe6a421b7401"},
{file = "mypy-1.7.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a79cdc12a02eb526d808a32a934c6fe6df07b05f3573d210e41808020aed8b5d"},
{file = "mypy-1.7.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f65f385a6f43211effe8c682e8ec3f55d79391f70a201575def73d08db68ead1"},
{file = "mypy-1.7.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:0e81ffd120ee24959b449b647c4b2fbfcf8acf3465e082b8d58fd6c4c2b27e46"},
{file = "mypy-1.7.0-cp311-cp311-win_amd64.whl", hash = "sha256:f29386804c3577c83d76520abf18cfcd7d68264c7e431c5907d250ab502658ee"},
{file = "mypy-1.7.0-py3-none-any.whl", hash = "sha256:96650d9a4c651bc2a4991cf46f100973f656d69edc7faf91844e87fe627f7e96"},
{file = "mypy-1.7.0.tar.gz", hash = "sha256:1e280b5697202efa698372d2f39e9a6713a0395a756b1c6bd48995f8d72690dc"},
]
[[package]] [[package]]
name = "mypy-extensions" name = "mypy-extensions"
version = "1.0.0" version = "1.0.0"
@ -273,16 +248,6 @@ files = [
{file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"},
] ]
[[package]]
name = "typing-extensions"
version = "4.8.0"
requires_python = ">=3.8"
summary = "Backported and Experimental Type Hints for Python 3.8+"
files = [
{file = "typing_extensions-4.8.0-py3-none-any.whl", hash = "sha256:8f92fc8806f9a6b641eaa5318da32b44d401efaac0f6678c9bc448ba3605faa0"},
{file = "typing_extensions-4.8.0.tar.gz", hash = "sha256:df8e4339e9cb77357558cbdbceca33c303714cf861d1eef15e1070055ae8b7ef"},
]
[[package]] [[package]]
name = "voicemeeter-api" name = "voicemeeter-api"
version = "2.5.2" version = "2.5.2"

View File

@ -1,6 +1,6 @@
[project] [project]
name = "nvda_voicemeeter" name = "nvda_voicemeeter"
version = "0.6.0" version = "0.5.6"
description = "A Voicemeeter app compatible with NVDA" description = "A Voicemeeter app compatible with NVDA"
authors = [ authors = [
{ name = "onyx-and-iris", email = "code@onyxandiris.online" }, { name = "onyx-and-iris", email = "code@onyxandiris.online" },
@ -23,7 +23,6 @@ build = [
lint = [ lint = [
"black>=23.7.0", "black>=23.7.0",
"ruff>=0.0.291", "ruff>=0.0.291",
"mypy>=1.7.0",
] ]
test = [ test = [
"psgdemos>=1.12.1", "psgdemos>=1.12.1",

View File

@ -92,8 +92,6 @@ class Builder:
return [[menu], [tab_group]] return [[menu], [tab_group]]
def make_menu(self) -> psg.Menu: def make_menu(self) -> psg.Menu:
themes = [f"{theme}::MENU THEME" for theme in util.get_themes_list()]
themes.append("Default::MENU THEME")
menu_def = [ menu_def = [
[ [
"&Voicemeeter", "&Voicemeeter",
@ -104,7 +102,6 @@ class Builder:
"Load Settings on Startup ::MENU", "Load Settings on Startup ::MENU",
], ],
], ],
["&Theme", themes],
] ]
return psg.Menu(menu_def, key="menus") return psg.Menu(menu_def, key="menus")

View File

@ -5,7 +5,7 @@ from pathlib import Path
from .errors import NVDAVMError from .errors import NVDAVMError
bits = 64 if ct.sizeof(ct.c_void_p) == 8 else 32 bits = 64 if ct.sizeof(ct.c_voidp) == 8 else 32
if platform.system() != "Windows": if platform.system() != "Windows":
raise NVDAVMError("Only Windows OS supported") raise NVDAVMError("Only Windows OS supported")

View File

@ -12,9 +12,6 @@ class LabelSlider(psg.Frame):
self.parent = parent self.parent = parent
if param in ("AUDIBILITY", "DENOISER"): if param in ("AUDIBILITY", "DENOISER"):
size = 7 size = 7
else:
if psg.theme() == "HighContrast":
size = 5
else: else:
size = 4 size = 4
layout = [ layout = [

View File

@ -1,34 +0,0 @@
import json
from pathlib import Path
SETTINGS = Path.cwd() / "settings.json"
def config_from_json():
data = {}
if not SETTINGS.exists():
return data
with open(SETTINGS, "r") as f:
data = json.load(f)
return data
config = config_from_json()
def get(key, default=None):
if key in config:
return config[key]
return default
def set(key, value):
config[key] = value
with open(SETTINGS, "w") as f:
json.dump(config, f)
def delete(key):
del config[key]
with open(SETTINGS, "w") as f:
json.dump(config, f)

View File

@ -1,7 +1,5 @@
from typing import Iterable from typing import Iterable
import PySimpleGUI as psg
def get_asio_input_spinbox_index(channel, num) -> int: def get_asio_input_spinbox_index(channel, num) -> int:
if channel == 0: if channel == 0:
@ -198,45 +196,3 @@ def get_slider_modes() -> Iterable:
def _get_bus_assignments(kind) -> list: def _get_bus_assignments(kind) -> list:
return [f"A{i}" for i in range(1, kind.phys_out + 1)] + [f"B{i}" for i in range(1, kind.virt_out + 1)] return [f"A{i}" for i in range(1, kind.phys_out + 1)] + [f"B{i}" for i in range(1, kind.virt_out + 1)]
psg.theme_add_new(
"HighContrast",
{
"BACKGROUND": "#FFFFFF",
"TEXT": "#000000",
"INPUT": "#FAF9F6",
"TEXT_INPUT": "#000000",
"SCROLL": "#FAF9F6",
"BUTTON": ("#000000", "#FFFFFF"),
"PROGRESS": ("#000000", "#FFFFFF"),
"BORDER": 2,
"SLIDER_DEPTH": 3,
"PROGRESS_DEPTH": 0,
},
)
def get_themes_list() -> list:
return [
"Bright Colors",
"Dark Blue 14",
"Dark Brown 2",
"Dark Brown 3",
"Dark Green 2",
"Dark Grey 2",
"Dark Teal1",
"Dark Teal6",
"Kayak",
"Light Blue 2",
"Light Brown 2",
"Light Brown 5",
"Light Green",
"Light Green 3",
"Light Grey 2",
"Light Purple",
"Neutral Blue",
"Reds",
"Sandy Beach",
"High Contrast",
]

View File

@ -4,7 +4,7 @@ from pathlib import Path
import PySimpleGUI as psg import PySimpleGUI as psg
from . import configuration, models, util from . import models, util
from .builder import Builder from .builder import Builder
from .nvda import Nvda from .nvda import Nvda
from .parser import Parser from .parser import Parser
@ -12,19 +12,18 @@ from .popup import Popup
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
psg.theme(configuration.get("default_theme", "Dark Blue 3")) psg.theme("Dark Blue 3")
if psg.theme() == "HighContrast":
psg.set_options(font=("Arial", 14))
class NVDAVMWindow(psg.Window): class NVDAVMWindow(psg.Window):
"""Represents the main window of the Voicemeeter NVDA application""" """Represents the main window of the Voicemeeter NVDA application"""
SETTINGS = "settings.json"
def __init__(self, title, vm): def __init__(self, title, vm):
self.vm = vm self.vm = vm
self.kind = self.vm.kind self.kind = self.vm.kind
self.logger = logger.getChild(type(self).__name__) self.logger = logger.getChild(type(self).__name__)
self.logger.debug(f"loaded with theme: {psg.theme()}")
self.cache = { self.cache = {
"hw_ins": models._make_hardware_ins_cache(self.vm), "hw_ins": models._make_hardware_ins_cache(self.vm),
"hw_outs": models._make_hardware_outs_cache(self.vm), "hw_outs": models._make_hardware_outs_cache(self.vm),
@ -64,11 +63,13 @@ class NVDAVMWindow(psg.Window):
self["tabgroup"].set_focus() self["tabgroup"].set_focus()
def __enter__(self): def __enter__(self):
settings_path = configuration.SETTINGS settings_path = Path.cwd() / self.SETTINGS
if settings_path.exists(): if settings_path.exists():
try: try:
defaultconfig = Path(configuration.get("default_config", "")) # coerce the type with open(settings_path, "r") as f:
if defaultconfig.is_file() and defaultconfig.exists(): data = json.load(f)
defaultconfig = Path(data["default_config"])
if defaultconfig.exists():
self.vm.set("command.load", str(defaultconfig)) self.vm.set("command.load", str(defaultconfig))
self.logger.debug(f"config {defaultconfig} loaded") self.logger.debug(f"config {defaultconfig} loaded")
self.TKroot.after( self.TKroot.after(
@ -77,7 +78,7 @@ class NVDAVMWindow(psg.Window):
f"config {defaultconfig.stem} has been loaded", f"config {defaultconfig.stem} has been loaded",
) )
except json.JSONDecodeError: except json.JSONDecodeError:
self.logger.debug("no default_config in settings.json. silently continuing...") self.logger.debug("no data in settings.json. silently continuing...")
self.vm.init_thread() self.vm.init_thread()
self.vm.observer.add(self.on_pdirty) self.vm.observer.add(self.on_pdirty)
@ -509,27 +510,17 @@ class NVDAVMWindow(psg.Window):
file_types=(("XML", ".xml"),), file_types=(("XML", ".xml"),),
): ):
filepath = Path(filepath) filepath = Path(filepath)
configuration.set("default_settings", str(filepath)) with open(self.SETTINGS, "w") as f:
json.dump({"default_config": str(filepath)}, f)
self.TKroot.after( self.TKroot.after(
200, 200,
self.nvda.speak, self.nvda.speak,
f"config {filepath.stem} set as default on startup", f"config {filepath.stem} set as default on startup",
) )
else: else:
configuration.delete("default_settings") with open(self.SETTINGS, "wb") as f:
self.logger.debug("default_settings removed from settings.json") f.truncate()
self.logger.debug("settings.json was truncated")
case [theme, ["MENU", "THEME"]]:
chosen = " ".join(theme)
if chosen == "Default":
chosen = "Dark Blue 3"
configuration.set("default_theme", chosen)
self.TKroot.after(
200,
self.nvda.speak,
f"theme {chosen} selected.",
)
self.logger.debug(f"theme {chosen} selected")
# Tabs # Tabs
case ["tabgroup"] | [["tabgroup"], ["FOCUS", "IN"]]: case ["tabgroup"] | [["tabgroup"], ["FOCUS", "IN"]]: