Compare commits

..

2 Commits

Author SHA1 Message Date
cb82033e1c theme menu initial implementation
bump to 0.5.7a1

Issue #19
2023-11-15 23:34:53 +00:00
bde9020471 closes #17 2023-10-29 19:26:03 +00:00
6 changed files with 82 additions and 23 deletions

13
pdm.lock generated
View File

@@ -3,10 +3,9 @@
[metadata] [metadata]
groups = ["default", "build", "lint", "test"] groups = ["default", "build", "lint", "test"]
cross_platform = true strategy = ["cross_platform"]
static_urls = false lock_version = "4.4"
lock_version = "4.3" content_hash = "sha256:ca47eaae0de5aa6bcc3fde33b6c1fa7dc2476aeb680f00bb1c550fe06ad67c55"
content_hash = "sha256:680eff1b532e55860290380d4e2f331dc29af6fb898a0df16fdb033843bf15a4"
[[package]] [[package]]
name = "altgraph" name = "altgraph"
@@ -251,13 +250,13 @@ files = [
[[package]] [[package]]
name = "voicemeeter-api" name = "voicemeeter-api"
version = "2.4.11" version = "2.5.2"
requires_python = ">=3.10,<4.0" requires_python = ">=3.10,<4.0"
summary = "A Python wrapper for the Voiceemeter API" summary = "A Python wrapper for the Voiceemeter API"
dependencies = [ dependencies = [
"tomli<3.0.0,>=2.0.1; python_version < \"3.11\"", "tomli<3.0.0,>=2.0.1; python_version < \"3.11\"",
] ]
files = [ files = [
{file = "voicemeeter_api-2.4.11-py3-none-any.whl", hash = "sha256:7a1b290d90c851204438c18e2d343e568c242fcd1e664c5b88d4019a553d44e1"}, {file = "voicemeeter_api-2.5.2-py3-none-any.whl", hash = "sha256:304c14a6eef5f95d8b883e8e1752d23f17c3d662d25a28d114d33134f62e93ec"},
{file = "voicemeeter_api-2.4.11.tar.gz", hash = "sha256:875591ad326a7a13ef141536cca83953edcda81da256191bab3844bac46a0e70"}, {file = "voicemeeter_api-2.5.2.tar.gz", hash = "sha256:e2b9558a38ed290b184a3e46b598c0a716cef2e64521431f84a46e1180d539ca"},
] ]

View File

@@ -1,6 +1,6 @@
[project] [project]
name = "nvda_voicemeeter" name = "nvda_voicemeeter"
version = "0.5.6b1" version = "0.5.7a1"
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" },
@@ -8,7 +8,7 @@ authors = [
dependencies = [ dependencies = [
"pysimplegui>=4.60.5", "pysimplegui>=4.60.5",
"pyparsing>=3.1.1", "pyparsing>=3.1.1",
"voicemeeter-api>=2.4.11", "voicemeeter-api>=2.5.2",
] ]
requires-python = ">=3.10,<3.12" requires-python = ">=3.10,<3.12"
readme = "README.md" readme = "README.md"

View File

@@ -92,6 +92,8 @@ 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",
@@ -102,6 +104,7 @@ 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

@@ -0,0 +1,34 @@
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

@@ -196,3 +196,20 @@ 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)]
def get_themes_list() -> list:
return sorted(
[
"Black",
"Dark Blue",
"Dark Blue 3",
"Reddit",
"Light Gray 1",
"Bright Colors",
"Dark Amber",
"Light Grey 5",
"Reds",
"Dark Brown 5",
]
)

View File

@@ -4,7 +4,7 @@ from pathlib import Path
import PySimpleGUI as psg import PySimpleGUI as psg
from . import models, util from . import configuration, 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,14 +12,12 @@ from .popup import Popup
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
psg.theme("Dark Blue 3") psg.theme(configuration.get("default_theme", "Dark Blue 3"))
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
@@ -63,12 +61,10 @@ class NVDAVMWindow(psg.Window):
self["tabgroup"].set_focus() self["tabgroup"].set_focus()
def __enter__(self): def __enter__(self):
settings_path = Path.cwd() / self.SETTINGS settings_path = configuration.SETTINGS
if settings_path.exists(): if settings_path.exists():
try: try:
with open(settings_path, "r") as f: defaultconfig = Path(configuration.get("default_config", "")) # coerce the type
data = json.load(f)
defaultconfig = Path(data["default_config"])
if defaultconfig.exists(): 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")
@@ -78,7 +74,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 data in settings.json. silently continuing...") self.logger.debug("no default_config 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)
@@ -510,17 +506,27 @@ class NVDAVMWindow(psg.Window):
file_types=(("XML", ".xml"),), file_types=(("XML", ".xml"),),
): ):
filepath = Path(filepath) filepath = Path(filepath)
with open(self.SETTINGS, "w") as f: configuration.set("default_settings", str(filepath))
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:
with open(self.SETTINGS, "wb") as f: configuration.delete("default_settings")
f.truncate() self.logger.debug("default_settings removed from settings.json")
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"]]: