fix app title.

merge subject classes.

modify obsevers callback

ensure sunvalley theme loaded only once.

minor version bump
This commit is contained in:
onyx-and-iris 2022-06-20 00:09:27 +01:00
parent 60e55fd7f9
commit fd30a5ef0d
8 changed files with 59 additions and 70 deletions

View File

@ -1,6 +1,6 @@
[tool.poetry] [tool.poetry]
name = "voicemeeter-compact" name = "voicemeeter-compact"
version = "1.0.4" version = "1.0.5"
description = "A Compact Voicemeeter Remote App" description = "A Compact Voicemeeter Remote App"
authors = ["onyx-and-iris <code@onyxandiris.online>"] authors = ["onyx-and-iris <code@onyxandiris.online>"]
license = "MIT" license = "MIT"

View File

@ -22,7 +22,7 @@ class App(tk.Tk):
""" """
APP_cls = type( APP_cls = type(
f"Voicemeeter{kind.name}.Compact", f"Voicemeeter{kind}.Compact",
(cls,), (cls,),
{ {
"kind": kind, "kind": kind,
@ -38,8 +38,7 @@ class App(tk.Tk):
if icon_path.is_file(): if icon_path.is_file():
self.iconbitmap(str(icon_path)) self.iconbitmap(str(icon_path))
self.minsize(275, False) self.minsize(275, False)
self.subject_pdirty = Subject() self.subject = Subject()
self.subject_ldirty = Subject()
self.strip_levels = None self.strip_levels = None
self.bus_levels = None self.bus_levels = None
self["menu"] = Menus(self, vmr) self["menu"] = Menus(self, vmr)
@ -92,26 +91,14 @@ class App(tk.Tk):
if self.kind.name == "potato": if self.kind.name == "potato":
self.builder.create_banner() self.builder.create_banner()
def on_update(self, subject, data): def on_update(self, subject):
"""called whenever notified of update""" """called whenever notified of update"""
if not _base_values.in_scale_button_1: if not _base_values.in_scale_button_1:
if subject == "pdirty": if subject == "pdirty":
self.after(1, self.notify_pdirty) self.subject.notify("pdirty")
elif subject == "ldirty" and not _base_values.dragging: elif subject == "ldirty" and not _base_values.dragging:
( self.subject.notify("ldirty")
self.strip_levels,
self.strip_comp,
self.bus_levels,
self.bus_comp,
) = data
self.after(1, self.notify_ldirty)
def notify_pdirty(self):
self.subject_pdirty.notify()
def notify_ldirty(self):
self.subject_ldirty.notify()
def _destroy_top_level_frames(self): def _destroy_top_level_frames(self):
""" """
@ -122,8 +109,7 @@ class App(tk.Tk):
Destroy all top level frames. Destroy all top level frames.
""" """
self.target.subject.remove(self) self.target.subject.remove(self)
self.subject_pdirty.clear() self.subject.clear()
self.subject_ldirty.clear()
[ [
frame.destroy() frame.destroy()
for frame in self.winfo_children() for frame in self.winfo_children()

View File

@ -37,8 +37,9 @@ class MainFrameBuilder(AbstractBuilder):
) )
self.app.resizable(False, False) self.app.resizable(False, False)
if _configuration.themes_enabled: if _configuration.themes_enabled:
print("Applying Sunvalley Theme") if sv_ttk.get_theme() not in ("light", "dark"):
sv_ttk.set_theme(_configuration.theme_mode) sv_ttk.set_theme(_configuration.theme_mode)
print(f"Sunvalley {sv_ttk.get_theme().capitalize()} Theme applied")
def create_channelframe(self, type_): def create_channelframe(self, type_):
if type_ == "strip": if type_ == "strip":
@ -301,7 +302,7 @@ class ChannelConfigFrameBuilder(AbstractBuilder):
def teardown(self): def teardown(self):
"""Deregister as observable, then destroy frame""" """Deregister as observable, then destroy frame"""
self.configframe.parent.subject_pdirty.remove(self.configframe) self.configframe.parent.subject.remove(self.configframe)
self.configframe.destroy() self.configframe.destroy()
def grid_configure(self): def grid_configure(self):

View File

@ -118,10 +118,10 @@ class ChannelLabelFrame(ttk.LabelFrame):
retval = f"{retval[:8]}.." retval = f"{retval[:8]}.."
if not retval: if not retval:
self.parent.columnconfigure(self.index, minsize=0) self.parent.columnconfigure(self.index, minsize=0)
self.parent.parent.subject_ldirty.remove(self) self.parent.parent.subject.remove(self)
self.grid_remove() self.grid_remove()
else: else:
self.parent.parent.subject_ldirty.add(self) self.parent.parent.subject.add(self)
self.grid() self.grid()
self.configure(text=retval) self.configure(text=retval)
@ -167,10 +167,10 @@ class Strip(ChannelLabelFrame):
Checks offset against expected level array size to avoid a race condition Checks offset against expected level array size to avoid a race condition
""" """
if self.level_offset + 1 < len(self.parent.parent.strip_levels): if self.level_offset + 1 < len(self.parent.target.strip_levels):
if ( if (
any( any(
self.parent.parent.strip_comp[ self.parent.target._strip_comp[
self.level_offset : self.level_offset + 1 self.level_offset : self.level_offset + 1
] ]
) )
@ -178,7 +178,7 @@ class Strip(ChannelLabelFrame):
): ):
val = self.convert_level( val = self.convert_level(
max( max(
self.parent.parent.strip_levels[ self.parent.target.strip_levels[
self.level_offset : self.level_offset + 1 self.level_offset : self.level_offset + 1
] ]
) )
@ -187,9 +187,9 @@ class Strip(ChannelLabelFrame):
(0 if self.mute.get() else 100 + val - 18 + self.gain.get()) (0 if self.mute.get() else 100 + val - 18 + self.gain.get())
) )
def on_update(self): def on_update(self, subject):
"""update levels""" """update levels"""
if subject == "ldirty":
self.after(_base_values.ldelay, self.upd_levels) self.after(_base_values.ldelay, self.upd_levels)
@ -208,10 +208,10 @@ class Bus(ChannelLabelFrame):
return getattr(_target, self.identifier)[self.index] return getattr(_target, self.identifier)[self.index]
def upd_levels(self): def upd_levels(self):
if self.level_offset + 1 < len(self.parent.parent.bus_levels): if self.level_offset + 1 < len(self.parent.target.bus_levels):
if ( if (
any( any(
self.parent.parent.bus_comp[ self.parent.target._bus_comp[
self.level_offset : self.level_offset + 1 self.level_offset : self.level_offset + 1
] ]
) )
@ -219,16 +219,16 @@ class Bus(ChannelLabelFrame):
): ):
val = self.convert_level( val = self.convert_level(
max( max(
self.parent.parent.bus_levels[ self.parent.target.bus_levels[
self.level_offset : self.level_offset + 1 self.level_offset : self.level_offset + 1
] ]
) )
) )
self.level.set((0 if self.mute.get() else 100 + val - 18)) self.level.set((0 if self.mute.get() else 100 + val - 18))
def on_update(self): def on_update(self, subject):
"""update levels""" """update levels"""
if subject == "ldirty":
self.after(_base_values.ldelay, self.upd_levels) self.after(_base_values.ldelay, self.upd_levels)
@ -241,7 +241,7 @@ class ChannelFrame(ttk.Frame):
self.phys_out, self.virt_out = parent.kind.outs self.phys_out, self.virt_out = parent.kind.outs
# registers channelframe as pdirty observer # registers channelframe as pdirty observer
self.parent.subject_pdirty.add(self) self.parent.subject.add(self)
@property @property
def target(self): def target(self):
@ -273,16 +273,16 @@ class ChannelFrame(ttk.Frame):
def upd_labelframe(self, labelframe): def upd_labelframe(self, labelframe):
labelframe.sync() labelframe.sync()
def on_update(self): def on_update(self, subject):
"""update parameters""" """update parameters"""
if subject == "pdirty":
for labelframe in self.labelframes: for labelframe in self.labelframes:
self.after(1, self.upd_labelframe, labelframe) self.after(1, self.upd_labelframe, labelframe)
def teardown(self): def teardown(self):
# deregisters channelframe as pdirty observer # deregisters channelframe as pdirty observer
self.parent.subject_pdirty.remove(self) self.parent.subject.remove(self)
self.destroy() self.destroy()
setattr(self.parent, f"{self.identifier}_frame", None) setattr(self.parent, f"{self.identifier}_frame", None)

View File

@ -16,7 +16,7 @@ class Config(ttk.Frame):
self.phys_in, self.virt_in = parent.kind.ins self.phys_in, self.virt_in = parent.kind.ins
self.phys_out, self.virt_out = parent.kind.outs self.phys_out, self.virt_out = parent.kind.outs
self.parent.subject_pdirty.add(self) self.parent.subject.add(self)
@property @property
def identifier(self): def identifier(self):
@ -68,9 +68,9 @@ class Config(ttk.Frame):
f"{param}.TButton", background=f'{"green" if val else "white"}' f"{param}.TButton", background=f'{"green" if val else "white"}'
) )
def on_update(self): def on_update(self, subject):
"""update parameters""" """update parameters"""
if subject == "pdirty":
self.after(_base_values.pdelay, self.sync) self.after(_base_values.pdelay, self.sync)

View File

@ -120,10 +120,10 @@ class GainLayer(ttk.LabelFrame):
retval = f"{retval[:8]}.." retval = f"{retval[:8]}.."
if not retval: if not retval:
self.parent.columnconfigure(self.index, minsize=0) self.parent.columnconfigure(self.index, minsize=0)
self.parent.parent.subject_ldirty.remove(self) self.parent.parent.subject.remove(self)
self.grid_remove() self.grid_remove()
else: else:
self.parent.parent.subject_ldirty.add(self) self.parent.parent.subject.add(self)
self.grid() self.grid()
self.configure(text=retval) self.configure(text=retval)
@ -138,10 +138,10 @@ class GainLayer(ttk.LabelFrame):
Checks offset against expected level array size to avoid a race condition Checks offset against expected level array size to avoid a race condition
""" """
if self.level_offset + 1 < len(self.parent.parent.strip_levels): if self.level_offset + 1 < len(self.parent.target.strip_levels):
if ( if (
any( any(
self.parent.parent.strip_comp[ self.parent.target._strip_comp[
self.level_offset : self.level_offset + 1 self.level_offset : self.level_offset + 1
] ]
) )
@ -149,7 +149,7 @@ class GainLayer(ttk.LabelFrame):
): ):
val = self.convert_level( val = self.convert_level(
max( max(
self.parent.parent.strip_levels[ self.parent.target.strip_levels[
self.level_offset : self.level_offset + 1 self.level_offset : self.level_offset + 1
] ]
) )
@ -163,9 +163,9 @@ class GainLayer(ttk.LabelFrame):
) )
) )
def on_update(self): def on_update(self, subject):
"""update levels""" """update levels"""
if subject == "ldirty":
self.after(_base_values.ldelay, self.upd_levels) self.after(_base_values.ldelay, self.upd_levels)
def grid_configure(self): def grid_configure(self):
@ -222,7 +222,7 @@ class SubMixFrame(ttk.Frame):
self.grid(row=2, column=0, sticky=(tk.W)) self.grid(row=2, column=0, sticky=(tk.W))
# registers submixframe as pdirty observer # registers submixframe as pdirty observer
self.parent.subject_pdirty.add(self) self.parent.subject.add(self)
self.grid_configure() self.grid_configure()
""" """
@ -263,11 +263,12 @@ class SubMixFrame(ttk.Frame):
def upd_labelframe(self, labelframe): def upd_labelframe(self, labelframe):
labelframe.sync() labelframe.sync()
def on_update(self): def on_update(self, subject):
if subject == "pdirty":
for labelframe in self.labelframes: for labelframe in self.labelframes:
self.after(1, self.upd_labelframe, labelframe) self.after(1, self.upd_labelframe, labelframe)
def teardown(self): def teardown(self):
# deregisters submixframe as pdirty observer # deregisters submixframe as pdirty observer
self.parent.subject_pdirty.remove(self) self.parent.subject.remove(self)
self.destroy() self.destroy()

View File

@ -10,7 +10,7 @@ class Navigation(ttk.Frame):
def __init__(self, parent): def __init__(self, parent):
super().__init__(parent) super().__init__(parent)
self.parent = parent self.parent = parent
self.grid(row=0, column=3, padx=(0, 5), pady=(5, 5), sticky=(tk.W, tk.E)) self.grid(row=0, column=3, padx=(0, 2), pady=(5, 5), sticky=(tk.W, tk.E))
self.styletable = self.parent.styletable self.styletable = self.parent.styletable
self.builder = builders.NavigationFrameBuilder(self) self.builder = builders.NavigationFrameBuilder(self)

View File

@ -1,35 +1,36 @@
class Subject: class Subject:
"""Adds support for observers"""
def __init__(self): def __init__(self):
"""list of current observers""" """list of current observers"""
self._observables = [] self._observers = list()
def notify(self, modifier=None): def notify(self, modifier=None):
"""run callbacks on update""" """run callbacks on update"""
for observer in self._observables: [o.on_update(modifier) for o in self._observers]
observer.on_update()
def add(self, observer): def add(self, observer):
"""adds an observer to observables""" """adds an observer to observables"""
if observer not in self._observables: if observer not in self._observers:
self._observables.append(observer) self._observers.append(observer)
def remove(self, observer): def remove(self, observer):
"""removes an observer from observables""" """removes an observer from observables"""
try: try:
self._observables.remove(observer) self._observers.remove(observer)
except ValueError: except ValueError:
pass pass
def get(self) -> list: def get(self) -> list:
"""returns the current observables""" """returns the current observables"""
return self._observables return self._observers
def clear(self): def clear(self):
"""clears the observables list""" """clears the observables list"""
self._observables.clear() self._observers.clear()