mirror of
https://github.com/onyx-and-iris/voicemeeter-compact.git
synced 2026-04-18 05:23:31 +00:00
gui rewritten with builder classes and observables
gui rewritten with builder classes and observables
This commit is contained in:
@@ -2,21 +2,21 @@ import tkinter as tk
|
||||
from tkinter import ttk
|
||||
from functools import partial
|
||||
|
||||
from .data import _base_vals
|
||||
from . import builders
|
||||
from .data import _configuration, _base_values
|
||||
|
||||
|
||||
class Config(ttk.Frame):
|
||||
def __init__(self, parent, index, _id):
|
||||
super().__init__(parent)
|
||||
self._parent = parent
|
||||
self.parent = parent
|
||||
self.index = index
|
||||
self.id = _id
|
||||
self.s = parent.styletable
|
||||
|
||||
self.styletable = parent.styletable
|
||||
self.phys_in, self.virt_in = parent.kind.ins
|
||||
self.phys_out, self.virt_out = parent.kind.outs
|
||||
|
||||
self.watch_pdirty()
|
||||
self.parent.subject_pdirty.add(self)
|
||||
|
||||
@property
|
||||
def identifier(self):
|
||||
@@ -25,277 +25,99 @@ class Config(ttk.Frame):
|
||||
@property
|
||||
def target(self):
|
||||
"""returns the current interface"""
|
||||
return self._parent.target
|
||||
|
||||
return self.parent.target
|
||||
|
||||
def getter(self, param):
|
||||
if param in dir(self.target):
|
||||
return getattr(self.target, param)
|
||||
return getattr(self.target, param)
|
||||
|
||||
def setter(self, param, value):
|
||||
if param in dir(self.target):
|
||||
setattr(self.target, param, value)
|
||||
setattr(self.target, param, value)
|
||||
|
||||
def scale_enter(self, *args):
|
||||
_base_vals.in_scale_button_1 = True
|
||||
_base_values.in_scale_button_1 = True
|
||||
|
||||
def scale_leave(self, *args):
|
||||
_base_vals.in_scale_button_1 = False
|
||||
self._parent.nav_frame.info_text.set("")
|
||||
_base_values.in_scale_button_1 = False
|
||||
self.parent.nav_frame.info_text.set("")
|
||||
|
||||
def scale_callback(self, param, *args):
|
||||
"""callback function for scale widget"""
|
||||
|
||||
val = self.slider_vars[self.slider_params.index(param)].get()
|
||||
self.setter(param, val)
|
||||
self._parent.nav_frame.info_text.set(round(val, 1))
|
||||
self.parent.nav_frame.info_text.set(round(val, 1))
|
||||
|
||||
def reset_scale(self, param, val, *args):
|
||||
self.setter(param, val)
|
||||
self.slider_vars[self.slider_params.index(param)].set(val)
|
||||
|
||||
def col_row_configure(self):
|
||||
[
|
||||
child.grid_configure(padx=1, pady=1, sticky=(tk.W, tk.E))
|
||||
for child in self.winfo_children()
|
||||
if isinstance(child, ttk.Checkbutton)
|
||||
]
|
||||
self.grid(sticky=(tk.W))
|
||||
def toggle_p(self, param):
|
||||
val = self.param_vars[self.params.index(param)].get()
|
||||
self.setter(param, val)
|
||||
if not _configuration.themes_enabled:
|
||||
self.styletable.configure(
|
||||
f"{param}.TButton", background=f'{"green" if val else "white"}'
|
||||
)
|
||||
|
||||
def watch_pdirty(self):
|
||||
self.after(1, self.watch_pdirty_step)
|
||||
|
||||
def watch_pdirty_step(self):
|
||||
"""keeps params synced but ensures sliders are responsive"""
|
||||
if self._parent.pdirty and not _base_vals.in_scale_button_1:
|
||||
self.sync()
|
||||
self.after(_base_vals.pdelay, self.watch_pdirty_step)
|
||||
def update(self):
|
||||
self.sync()
|
||||
|
||||
|
||||
class StripConfig(Config):
|
||||
def __init__(self, parent, index, _id):
|
||||
super().__init__(parent, index, _id)
|
||||
self.grid(column=0, row=1, columnspan=4)
|
||||
self.builder = builders.StripConfigFrameBuilder(self)
|
||||
self.builder.setup()
|
||||
self.make_row_0()
|
||||
self.make_row_1()
|
||||
self.make_row_2()
|
||||
self.builder.grid_configure()
|
||||
|
||||
# create parameter variables
|
||||
if self._parent.kind.name == "Basic":
|
||||
self.slider_params = ("audibility",)
|
||||
self.slider_vars = (tk.DoubleVar(),)
|
||||
else:
|
||||
self.slider_params = ("comp", "gate", "limit")
|
||||
self.slider_vars = [
|
||||
tk.DoubleVar() for i, _ in enumerate(self.slider_params)
|
||||
]
|
||||
|
||||
self.phys_out_params = [f"A{i+1}" for i in range(self.phys_out)]
|
||||
self.phys_out_params_vars = [
|
||||
tk.BooleanVar() for i, _ in enumerate(self.phys_out_params)
|
||||
]
|
||||
|
||||
self.virt_out_params = [f"B{i+1}" for i in range(self.virt_out)]
|
||||
self.virt_out_params_vars = [
|
||||
tk.BooleanVar() for i, _ in enumerate(self.virt_out_params)
|
||||
]
|
||||
|
||||
self.params = ("mono", "solo")
|
||||
self.param_vars = list(tk.BooleanVar() for i, _ in enumerate(self.params))
|
||||
|
||||
self.make_row0()
|
||||
self.make_row1()
|
||||
self.make_row2()
|
||||
|
||||
# sync all parameters
|
||||
self.sync()
|
||||
self.sync_sliders()
|
||||
|
||||
self.col_row_configure()
|
||||
|
||||
@property
|
||||
def target(self):
|
||||
"""use the correct interface"""
|
||||
"""returns the strip class for this configframe in the current interface"""
|
||||
|
||||
_target = super(StripConfig, self).target
|
||||
return getattr(_target, self.identifier)[self.index]
|
||||
|
||||
def make_row0(self):
|
||||
# Create sliders
|
||||
def make_row_0(self):
|
||||
if self.index < self.phys_in:
|
||||
if self._parent.kind.name == "Basic":
|
||||
# audibility
|
||||
aud_label = ttk.Label(self, text="Audibility")
|
||||
aud_scale = ttk.Scale(
|
||||
self,
|
||||
from_=0.0,
|
||||
to=10.0,
|
||||
orient="horizontal",
|
||||
length=_base_vals.level_width,
|
||||
variable=self.slider_vars[self.slider_params.index("audibility")],
|
||||
command=partial(self.scale_callback, "audibility"),
|
||||
)
|
||||
aud_scale.bind(
|
||||
"<Double-Button-1>", partial(self.reset_scale, "audibility", 0)
|
||||
)
|
||||
aud_scale.bind("<Button-1>", self.scale_enter)
|
||||
aud_scale.bind("<ButtonRelease-1>", self.scale_leave)
|
||||
|
||||
aud_label.grid(column=0, row=0)
|
||||
aud_scale.grid(column=1, row=0)
|
||||
if self.parent.kind.name == "Basic":
|
||||
self.builder.create_audibility_slider()
|
||||
else:
|
||||
# comp
|
||||
comp_label = ttk.Label(self, text="Comp")
|
||||
comp_scale = ttk.Scale(
|
||||
self,
|
||||
from_=0.0,
|
||||
to=10.0,
|
||||
orient="horizontal",
|
||||
length=_base_vals.level_width,
|
||||
variable=self.slider_vars[self.slider_params.index("comp")],
|
||||
command=partial(self.scale_callback, "comp"),
|
||||
)
|
||||
comp_scale.bind(
|
||||
"<Double-Button-1>", partial(self.reset_scale, "comp", 0)
|
||||
)
|
||||
comp_scale.bind("<Button-1>", self.scale_enter)
|
||||
comp_scale.bind("<ButtonRelease-1>", self.scale_leave)
|
||||
self.builder.create_comp_slider()
|
||||
self.builder.create_gate_slider()
|
||||
self.builder.create_limit_slider()
|
||||
|
||||
# gate
|
||||
gate_label = ttk.Label(self, text="Gate")
|
||||
gate_scale = ttk.Scale(
|
||||
self,
|
||||
from_=0.0,
|
||||
to=10.0,
|
||||
orient="horizontal",
|
||||
length=_base_vals.level_width,
|
||||
variable=self.slider_vars[self.slider_params.index("gate")],
|
||||
command=partial(self.scale_callback, "gate"),
|
||||
)
|
||||
gate_scale.bind(
|
||||
"<Double-Button-1>", partial(self.reset_scale, "gate", 0)
|
||||
)
|
||||
gate_scale.bind("<Button-1>", self.scale_enter)
|
||||
gate_scale.bind("<ButtonRelease-1>", self.scale_leave)
|
||||
def make_row_1(self):
|
||||
self.builder.create_a_buttons()
|
||||
self.builder.create_b_buttons()
|
||||
|
||||
# limit
|
||||
limit_label = ttk.Label(self, text="Limit")
|
||||
limit_scale = ttk.Scale(
|
||||
self,
|
||||
from_=-40,
|
||||
to=12,
|
||||
orient="horizontal",
|
||||
length=_base_vals.level_width,
|
||||
variable=self.slider_vars[self.slider_params.index("limit")],
|
||||
command=partial(self.scale_callback, "limit"),
|
||||
)
|
||||
limit_scale.bind(
|
||||
"<Double-Button-1>", partial(self.reset_scale, "limit", 12)
|
||||
)
|
||||
limit_scale.bind("<Button-1>", self.scale_enter)
|
||||
limit_scale.bind("<ButtonRelease-1>", self.scale_leave)
|
||||
|
||||
# Position sliders
|
||||
comp_label.grid(column=0, row=0)
|
||||
comp_scale.grid(column=1, row=0)
|
||||
gate_label.grid(column=2, row=0)
|
||||
gate_scale.grid(column=3, row=0)
|
||||
limit_label.grid(column=4, row=0)
|
||||
limit_scale.grid(column=5, row=0)
|
||||
|
||||
def make_row1(self):
|
||||
# create buttons
|
||||
self.a_buttons = [
|
||||
ttk.Checkbutton(
|
||||
self,
|
||||
text=param,
|
||||
command=partial(self.toggle_a, param),
|
||||
style=f"{'Toggle.TButton' if _base_vals.using_theme else f'{param}.TButton'}",
|
||||
variable=self.phys_out_params_vars[self.phys_out_params.index(param)],
|
||||
)
|
||||
for param in self.phys_out_params
|
||||
]
|
||||
self.b_buttons = [
|
||||
ttk.Checkbutton(
|
||||
self,
|
||||
text=param,
|
||||
command=partial(self.toggle_b, param),
|
||||
style=f"{'Toggle.TButton' if _base_vals.using_theme else f'{param}.TButton'}",
|
||||
variable=self.virt_out_params_vars[self.virt_out_params.index(param)],
|
||||
)
|
||||
for param in self.virt_out_params
|
||||
]
|
||||
|
||||
# set button positions
|
||||
[
|
||||
button.grid(
|
||||
column=self.a_buttons.index(button),
|
||||
row=1,
|
||||
)
|
||||
for button in self.a_buttons
|
||||
]
|
||||
[
|
||||
button.grid(
|
||||
column=len(self.a_buttons) + self.b_buttons.index(button),
|
||||
row=1,
|
||||
)
|
||||
for button in self.b_buttons
|
||||
]
|
||||
def make_row_2(self):
|
||||
self.builder.create_param_buttons()
|
||||
|
||||
def toggle_a(self, param):
|
||||
val = self.phys_out_params_vars[self.phys_out_params.index(param)].get()
|
||||
self.setter(param, val)
|
||||
if not _base_vals.using_theme:
|
||||
self.s.configure(
|
||||
if not _configuration.themes_enabled:
|
||||
self.styletable.configure(
|
||||
f"{param}.TButton", background=f'{"green" if val else "white"}'
|
||||
)
|
||||
|
||||
def toggle_b(self, param):
|
||||
val = self.virt_out_params_vars[self.virt_out_params.index(param)].get()
|
||||
self.setter(param, val)
|
||||
if not _base_vals.using_theme:
|
||||
self.s.configure(
|
||||
if not _configuration.themes_enabled:
|
||||
self.styletable.configure(
|
||||
f"{param}.TButton", background=f'{"green" if val else "white"}'
|
||||
)
|
||||
|
||||
def make_row2(self):
|
||||
if self._parent.kind.name in ("Banana", "Potato"):
|
||||
if self.index == self.phys_in:
|
||||
self.params = list(map(lambda x: x.replace("mono", "mc"), self.params))
|
||||
if self._parent.kind.name == "Banana":
|
||||
pass
|
||||
# karaoke modes not in RT Packet yet. May implement in future
|
||||
"""
|
||||
if self.index == self.phys_in + 1:
|
||||
self.params = list(
|
||||
map(lambda x: x.replace("mono", "k"), self.params)
|
||||
)
|
||||
self.param_vars[self.params.index("k")] = tk.IntVar
|
||||
"""
|
||||
else:
|
||||
if self.index == self.phys_in + self.virt_in - 1:
|
||||
self.params = list(
|
||||
map(lambda x: x.replace("mono", "mc"), self.params)
|
||||
)
|
||||
|
||||
param_buttons = [
|
||||
ttk.Checkbutton(
|
||||
self,
|
||||
text=param,
|
||||
command=partial(self.toggle_p, param),
|
||||
style=f"{'Toggle.TButton' if _base_vals.using_theme else f'{param}.TButton'}",
|
||||
variable=self.param_vars[self.params.index(param)],
|
||||
)
|
||||
for param in self.params
|
||||
]
|
||||
[
|
||||
button.grid(
|
||||
column=param_buttons.index(button),
|
||||
row=2,
|
||||
)
|
||||
for button in param_buttons
|
||||
]
|
||||
|
||||
def toggle_p(self, param):
|
||||
val = self.param_vars[self.params.index(param)].get()
|
||||
self.setter(param, val)
|
||||
if not _base_vals.using_theme:
|
||||
self.s.configure(
|
||||
f"{param}.TButton", background=f'{"green" if val else "white"}'
|
||||
)
|
||||
def teardown(self):
|
||||
self.builder.teardown()
|
||||
|
||||
def sync(self):
|
||||
[
|
||||
@@ -314,154 +136,110 @@ class StripConfig(Config):
|
||||
self.param_vars[self.params.index(param)].set(self.getter(param))
|
||||
for param in self.params
|
||||
]
|
||||
if not _base_vals.using_theme:
|
||||
|
||||
if not _configuration.themes_enabled:
|
||||
[
|
||||
self.s.configure(
|
||||
self.styletable.configure(
|
||||
f"{param}.TButton",
|
||||
background=f'{"green" if self.phys_out_params_vars[self.phys_out_params.index(param)].get() else "white"}',
|
||||
)
|
||||
for param in self.phys_out_params
|
||||
]
|
||||
[
|
||||
self.s.configure(
|
||||
self.styletable.configure(
|
||||
f"{param}.TButton",
|
||||
background=f'{"green" if self.virt_out_params_vars[self.virt_out_params.index(param)].get() else "white"}',
|
||||
)
|
||||
for param in self.virt_out_params
|
||||
]
|
||||
[
|
||||
self.s.configure(
|
||||
self.styletable.configure(
|
||||
f"{param}.TButton",
|
||||
background=f'{"green" if self.param_vars[self.params.index(param)].get() else "white"}',
|
||||
)
|
||||
for param in self.params
|
||||
]
|
||||
|
||||
def sync_sliders(self):
|
||||
[
|
||||
self.slider_vars[self.slider_params.index(param)].set(self.getter(param))
|
||||
for param in self.slider_params
|
||||
]
|
||||
|
||||
def col_row_configure(self):
|
||||
super(StripConfig, self).col_row_configure()
|
||||
[
|
||||
self.columnconfigure(i, minsize=80)
|
||||
for i in range(self.phys_out + self.virt_out)
|
||||
]
|
||||
|
||||
|
||||
class BusConfig(Config):
|
||||
def __init__(self, parent, index, _id):
|
||||
super().__init__(parent, index, _id)
|
||||
# fmt: off
|
||||
# create parameter variables
|
||||
self.bus_modes = (
|
||||
"normal", "Amix", "Bmix", "Repeat", "Composite", "TVMix", "UpMix21",
|
||||
"UpMix41", "UpMix61", "CenterOnly", "LFEOnly", "RearOnly",
|
||||
)
|
||||
# fmt: on
|
||||
self.params = ("mono", "eq", "eq_ab")
|
||||
self.param_vars = [tk.BooleanVar() for i, _ in enumerate(self.params)]
|
||||
if _configuration.extends_horizontal:
|
||||
self.grid(column=0, row=1, columnspan=4)
|
||||
else:
|
||||
self.grid(column=0, row=3, columnspan=4)
|
||||
self.builder = builders.BusConfigFrameBuilder(self)
|
||||
self.builder.setup()
|
||||
self.make_row_0()
|
||||
self.make_row_1()
|
||||
self.builder.grid_configure()
|
||||
|
||||
# sync all parameters
|
||||
self.sync()
|
||||
|
||||
self.make_row0()
|
||||
self.make_row1()
|
||||
|
||||
self.col_row_configure()
|
||||
|
||||
@property
|
||||
def target(self):
|
||||
"""returns the current interface"""
|
||||
"""returns the bus class for this configframe in the current interface"""
|
||||
|
||||
_target = super(BusConfig, self).target
|
||||
return getattr(_target, self.identifier)[self.index]
|
||||
|
||||
@property
|
||||
def bus_mode(self):
|
||||
return self._parent.bus_modes_cache[
|
||||
"vban" if _base_vals.vban_connected else "vmr"
|
||||
][self.index].get()
|
||||
def make_row_0(self):
|
||||
self.builder.create_bus_mode_button()
|
||||
|
||||
@bus_mode.setter
|
||||
def bus_mode(self, val):
|
||||
self._parent.bus_modes_cache["vban" if _base_vals.vban_connected else "vmr"][
|
||||
self.index
|
||||
].set(val)
|
||||
def make_row_1(self):
|
||||
self.builder.create_param_buttons()
|
||||
|
||||
def make_row0(self):
|
||||
self.bus_mode_label_text = tk.StringVar(value=f"Bus Mode: {self.bus_mode}")
|
||||
self.busmode_button = ttk.Button(self, textvariable=self.bus_mode_label_text)
|
||||
self.busmode_button.grid(column=0, row=0, columnspan=2, sticky=(tk.W))
|
||||
self.busmode_button.bind("<Button-1>", self.rotate_bus_modes_right)
|
||||
self.busmode_button.bind("<Button-3>", self.rotate_bus_modes_left)
|
||||
def current_bus_mode(self):
|
||||
for mode in self.bus_modes:
|
||||
if getattr(self.target.mode, mode):
|
||||
return mode
|
||||
|
||||
def rotate_bus_modes_right(self, *args):
|
||||
current_index = self.bus_modes.index(self.bus_mode)
|
||||
if current_index + 1 < len(self.bus_modes):
|
||||
self.bus_mode = self.bus_modes[current_index + 1]
|
||||
current_mode = self.current_bus_mode()
|
||||
next = self.bus_modes.index(current_mode) + 1
|
||||
if next < len(self.bus_modes):
|
||||
setattr(
|
||||
self.target.mode,
|
||||
self.bus_modes[next],
|
||||
True,
|
||||
)
|
||||
self.bus_mode_label_text.set(self.bus_mode_map[self.bus_modes[next]])
|
||||
else:
|
||||
self.bus_mode = self.bus_modes[0]
|
||||
setattr(self.target.mode, self.bus_mode.lower(), True)
|
||||
self.bus_mode_label_text.set(f"Bus Mode: {self.bus_mode}")
|
||||
self.target.mode.normal = True
|
||||
self.bus_mode_label_text.set("Normal")
|
||||
|
||||
def rotate_bus_modes_left(self, *args):
|
||||
current_index = self.bus_modes.index(self.bus_mode)
|
||||
if current_index == 0:
|
||||
self.bus_mode = self.bus_modes[-1]
|
||||
current_mode = self.current_bus_mode()
|
||||
prev = self.bus_modes.index(current_mode) - 1
|
||||
if prev < 0:
|
||||
self.target.mode.rearonly = True
|
||||
self.bus_mode_label_text.set("Rear Only")
|
||||
else:
|
||||
self.bus_mode = self.bus_modes[current_index - 1]
|
||||
setattr(self.target.mode, self.bus_mode.lower(), True)
|
||||
self.bus_mode_label_text.set(f"Bus Mode: {self.bus_mode}")
|
||||
|
||||
def make_row1(self):
|
||||
param_buttons = [
|
||||
ttk.Checkbutton(
|
||||
self,
|
||||
text=param,
|
||||
command=partial(self.toggle_p, param),
|
||||
style=f"{'Toggle.TButton' if _base_vals.using_theme else f'{param}.TButton'}",
|
||||
variable=self.param_vars[self.params.index(param)],
|
||||
setattr(
|
||||
self.target.mode,
|
||||
self.bus_modes[prev],
|
||||
True,
|
||||
)
|
||||
for param in self.params
|
||||
]
|
||||
[
|
||||
button.grid(
|
||||
column=param_buttons.index(button),
|
||||
row=1,
|
||||
)
|
||||
for button in param_buttons
|
||||
]
|
||||
self.bus_mode_label_text.set(self.bus_mode_map[self.bus_modes[prev]])
|
||||
|
||||
def toggle_p(self, param):
|
||||
val = self.param_vars[self.params.index(param)].get()
|
||||
self.setter(param, val)
|
||||
if not _base_vals.using_theme:
|
||||
self.s.configure(
|
||||
f"{param}.TButton", background=f'{"green" if val else "white"}'
|
||||
)
|
||||
|
||||
def col_row_configure(self):
|
||||
super(BusConfig, self).col_row_configure()
|
||||
[
|
||||
self.columnconfigure(i, minsize=80)
|
||||
for i in range(self.phys_out + self.virt_out)
|
||||
]
|
||||
def teardown(self):
|
||||
self.builder.teardown()
|
||||
|
||||
def sync(self):
|
||||
for i, mode in enumerate(self.bus_modes):
|
||||
if getattr(self.target.mode, mode.lower()):
|
||||
self.bus_mode = self.bus_modes[i]
|
||||
[
|
||||
self.param_vars[self.params.index(param)].set(self.getter(param))
|
||||
for param in self.params
|
||||
]
|
||||
if not _base_vals.using_theme:
|
||||
self.bus_mode_label_text.set(self.bus_mode_map[self.current_bus_mode()])
|
||||
if not _configuration.themes_enabled:
|
||||
[
|
||||
self.s.configure(
|
||||
self.styletable.configure(
|
||||
f"{param}.TButton",
|
||||
background=f'{"green" if self.param_vars[self.params.index(param)].get() else "white"}',
|
||||
)
|
||||
for param in self.params
|
||||
]
|
||||
|
||||
|
||||
class Iterator:
|
||||
pass
|
||||
|
||||
Reference in New Issue
Block a user