From e92a1e121627a077af44322c3759a1b4262d54ea Mon Sep 17 00:00:00 2001 From: Miguel Guthridge Date: Mon, 31 Jul 2023 01:05:12 +1000 Subject: [PATCH] Refactor window plugins --- src/common/plug_indexes/window.py | 15 +++++++ src/common/tracks/mixer_track.py | 15 +++++++ src/common/tracks/playlist_track.py | 4 ++ src/common/types/color.py | 2 + src/plugs/windows/browser.py | 5 ++- src/plugs/windows/mixer.py | 67 ++++++++++++++++------------- src/plugs/windows/piano_roll.py | 7 ++- src/plugs/windows/playlist.py | 30 +++++-------- 8 files changed, 89 insertions(+), 56 deletions(-) diff --git a/src/common/plug_indexes/window.py b/src/common/plug_indexes/window.py index 6d650bd6..648d88f9 100644 --- a/src/common/plug_indexes/window.py +++ b/src/common/plug_indexes/window.py @@ -28,3 +28,18 @@ def getName(self) -> str: def focus(self) -> None: ui.showWindow(self.index) + + # Hopefully this duplicate code can be fixed if I get a better answer to + # https://stackoverflow.com/q/75000973/6335363 + MIXER: 'WindowIndex' + CHANNEL_RACK: 'WindowIndex' + PLAYLIST: 'WindowIndex' + PIANO_ROLL: 'WindowIndex' + BROWSER: 'WindowIndex' + + +WindowIndex.MIXER = WindowIndex(0) +WindowIndex.CHANNEL_RACK = WindowIndex(1) +WindowIndex.PLAYLIST = WindowIndex(2) +WindowIndex.PIANO_ROLL = WindowIndex(3) +WindowIndex.BROWSER = WindowIndex(4) diff --git a/src/common/tracks/mixer_track.py b/src/common/tracks/mixer_track.py index 317932fd..d5c0ac59 100644 --- a/src/common/tracks/mixer_track.py +++ b/src/common/tracks/mixer_track.py @@ -11,6 +11,21 @@ class MixerTrack(AbstractTrack): def __init__(self, index: int) -> None: self.__index = index + def __eq__(self, __value: object) -> bool: + if isinstance(__value, MixerTrack): + return __value.index == self.__index + return NotImplemented + + def __gt__(self, __value: object) -> bool: + if isinstance(__value, MixerTrack): + return self.index > __value.index + return NotImplemented + + def __lt__(self, __value: object) -> bool: + if isinstance(__value, MixerTrack): + return self.index < __value.index + return NotImplemented + @property def index(self) -> int: return self.__index diff --git a/src/common/tracks/playlist_track.py b/src/common/tracks/playlist_track.py index 1171611f..e1b4ac29 100644 --- a/src/common/tracks/playlist_track.py +++ b/src/common/tracks/playlist_track.py @@ -11,6 +11,10 @@ class PlaylistTrack(AbstractTrack): def __init__(self, index: int) -> None: self.__index = index + @property + def index(self) -> int: + return self.__index + @property def color(self) -> Color: return Color.fromInteger(playlist.getTrackColor(self.__index)) diff --git a/src/common/types/color.py b/src/common/types/color.py index 9eb61748..bebbd1ac 100644 --- a/src/common/types/color.py +++ b/src/common/types/color.py @@ -771,6 +771,8 @@ def __eq__(self, other: object) -> bool: else: return NotImplemented + # Hopefully this duplicate code can be fixed if I get a better answer to + # https://stackoverflow.com/q/75000973/6335363 WHITE: 'Color' GRAY: 'Color' BLACK: 'Color' diff --git a/src/plugs/windows/browser.py b/src/plugs/windows/browser.py index 45254bda..db81f724 100644 --- a/src/plugs/windows/browser.py +++ b/src/plugs/windows/browser.py @@ -10,10 +10,11 @@ more details. """ from common.extension_manager import ExtensionManager +from common.plug_indexes.window import WindowIndex from devices import DeviceShadow from plugs import WindowPlugin -INDEX = 4 +INDEX = WindowIndex.BROWSER class Browser(WindowPlugin): @@ -27,7 +28,7 @@ def __init__(self, shadow: DeviceShadow) -> None: super().__init__(shadow, []) @classmethod - def getWindowId(cls) -> int: + def getWindowId(cls) -> WindowIndex: return INDEX @classmethod diff --git a/src/plugs/windows/mixer.py b/src/plugs/windows/mixer.py index c2dfc8f2..bc3235b6 100644 --- a/src/plugs/windows/mixer.py +++ b/src/plugs/windows/mixer.py @@ -13,9 +13,10 @@ import ui import mixer from common import getContext +from common.tracks.mixer_track import MixerTrack from common.types import Color from common.extension_manager import ExtensionManager -from common.plug_indexes.fl_index import (UnsafeIndex) +from common.plug_indexes.fl_index import WindowIndex from common.util.api_fixes import ( getSelectedDockMixerTracks, getMixerDockSides, @@ -43,7 +44,7 @@ from plugs.mapping_strategies import MuteSoloStrategy from plugs import WindowPlugin -INDEX = 0 +INDEX = WindowIndex.MIXER COLOR_DISABLED = Color.fromGrayscale(0.3, False) COLOR_ARMED = Color.fromInteger(0xAF0000, 1.0, True) @@ -129,21 +130,14 @@ def __init__(self, shadow: DeviceShadow) -> None: ).annotate("Show selected").colorize(Color.fromGrayscale(0.5)) # Create bindings for mute, solo and generic buttons - mutes_solos = MuteSoloStrategy( - lambda i: self._selection[i], - mixer.muteTrack, - mixer.isTrackMuted, - mixer.soloTrack, - mixer.isTrackSolo, - mixer.getTrackColor, - ) + mutes_solos = MuteSoloStrategy(lambda i: self._selection[i]) # TODO: Bind master controls # List of mapped channels - self._selection: list[int] = [] + self._selection: list[MixerTrack] = [] # List of mapped channels, respecting the dock side - self._selection_docked: list[int] = [] + self._selection_docked: list[MixerTrack] = [] # Dock side that we're mapping to self._dock_side = 1 # Length of mapped channels @@ -151,7 +145,7 @@ def __init__(self, shadow: DeviceShadow) -> None: super().__init__(shadow, [mutes_solos]) @classmethod - def getWindowId(cls) -> int: + def getWindowId(cls) -> WindowIndex: return INDEX @classmethod @@ -163,8 +157,14 @@ def updateSelected(self): Update the list of selected tracks """ dock_side = mixer.getTrackDockSide(mixer.trackNumber()) - selected = getSelectedDockMixerTracks()[dock_side] - dock_sides = getMixerDockSides()[dock_side] + selected = list(map( + MixerTrack, + getSelectedDockMixerTracks()[dock_side], + )) + dock_sides = list(map( + MixerTrack, + getMixerDockSides()[dock_side], + )) if len(selected) == 0: # No selection, we need to generate one @@ -194,7 +194,7 @@ def updateSelected(self): or index > self._selection_docked[-1] ): self._selection = [dock_sides[i] for i in range(first, last)] - self._selection_docked = list(range(first, last)) + self._selection_docked = list(map(MixerTrack, range(first, last))) self._dock_side = dock_side self.displayRect() @@ -204,7 +204,7 @@ def displayRect(self): """ first = self._selection_docked[0] ui.miDisplayDockRect( - first + 1, + first.index + 1, len(self._selection), self._dock_side, 2000, @@ -254,7 +254,7 @@ def fader( ) -> bool: """Faders -> volume""" index = self._selection[control.getControl().coordinate[1]] - mixer.setTrackVolume(index, snapFaders( + mixer.setTrackVolume(index.index, snapFaders( control.value, control.getControl())) return True @@ -283,10 +283,12 @@ def updateColors(self): self._fader_master.annotation = name # For each selected track for n, i in enumerate(self._selection): - c = Color.fromInteger(mixer.getTrackColor(i)) - name = mixer.getTrackName(i) - vol = mixer.getTrackVolume(i) - pan = mixer.getTrackPan(i) + c = i.color + name = i.name + # FIXME: Refactor to make volume and pan properties of the + # MixerTrack type + vol = mixer.getTrackVolume(i.index) + pan = mixer.getTrackPan(i.index) # Only apply to controls that are within range if len(self._faders) > n: self._faders[n].color = c @@ -299,13 +301,15 @@ def updateColors(self): self._knobs[n].value = unsnapKnobs(pan) # Select buttons if len(self._selects) > n: - if mixer.isTrackSelected(i): + # FIXME: Also make this a property + if mixer.isTrackSelected(i.index): self._selects[n].color = c else: self._selects[n].color = COLOR_DISABLED # Arm buttons if len(self._arms) > n: - if mixer.isTrackArmed(i): + # FIXME: Also make this a property + if mixer.isTrackArmed(i.index): self._arms[n].color = COLOR_ARMED else: self._arms[n].color = COLOR_DISABLED @@ -317,7 +321,8 @@ def knob( ) -> bool: """Knobs -> panning""" index = self._selection[control.getControl().coordinate[1]] - mixer.setTrackPan(index, snapKnobs(control.value)) + # FIXME: Use properties + mixer.setTrackPan(index.index, snapKnobs(control.value)) return True def masterKnob( @@ -336,24 +341,24 @@ def masterKnob( def arm( self, control: ControlShadowEvent, - index: UnsafeIndex, + index: WindowIndex, *args: Any ) -> bool: """Arm track""" - index = self._selection[control.getControl().coordinate[1]] - mixer.armTrack(index) + track = self._selection[control.getControl().coordinate[1]] + mixer.armTrack(track.index) return True @filterButtonLift() def select( self, control: ControlShadowEvent, - index: UnsafeIndex, + index: WindowIndex, *args: Any ) -> bool: """Select track""" - index = self._selection[control.getControl().coordinate[1]] - mixer.selectTrack(index) + track = self._selection[control.getControl().coordinate[1]] + mixer.selectTrack(track.index) return True @filterButtonLift() diff --git a/src/plugs/windows/piano_roll.py b/src/plugs/windows/piano_roll.py index 6f4e27dd..2112e564 100644 --- a/src/plugs/windows/piano_roll.py +++ b/src/plugs/windows/piano_roll.py @@ -12,14 +12,13 @@ import transport import ui from common.extension_manager import ExtensionManager +from common.plug_indexes import WindowIndex from common.types import Color from devices import DeviceShadow from plugs import WindowPlugin from plugs.event_filters import filterButtonLift from control_surfaces import ToolSelector, ControlShadowEvent -INDEX = 3 - TOOL_COLORS = [ Color.fromInteger(0xffc43f), # Pencil @@ -52,8 +51,8 @@ def __init__(self, shadow: DeviceShadow) -> None: super().__init__(shadow, []) @classmethod - def getWindowId(cls) -> int: - return INDEX + def getWindowId(cls) -> WindowIndex: + return WindowIndex.PIANO_ROLL @classmethod def create(cls, shadow: DeviceShadow) -> 'WindowPlugin': diff --git a/src/plugs/windows/playlist.py b/src/plugs/windows/playlist.py index 1caf1e47..42702dc5 100644 --- a/src/plugs/windows/playlist.py +++ b/src/plugs/windows/playlist.py @@ -17,9 +17,10 @@ import transport import general from common import getContext +from common.tracks import PlaylistTrack from common.types import Color from common.extension_manager import ExtensionManager -from common.plug_indexes.fl_index import UnsafeIndex +from common.plug_indexes import WindowIndex, FlIndex from common.util.api_fixes import getFirstPlaylistSelection from control_surfaces import consts from control_surfaces import ControlShadowEvent @@ -40,8 +41,6 @@ from plugs.event_filters import filterButtonLift from plugs.mapping_strategies import MuteSoloStrategy -INDEX = 2 - TOOL_COLORS = [ Color.fromInteger(0xffc43f), # Pencil Color.fromInteger(0x7bcefd), # Paint @@ -61,11 +60,11 @@ def getNumDrumCols() -> int: return getContext().getDevice().getDrumPadSize()[1] -def getSelection(i: int): +def getSelection(i: int) -> PlaylistTrack: selection = getFirstPlaylistSelection() if i >= getNumDrumCols(): raise IndexError() - return selection + i + return PlaylistTrack(selection + i) class Playlist(WindowPlugin): @@ -82,14 +81,7 @@ def __init__(self, shadow: DeviceShadow) -> None: target_num=len(TOOL_COLORS), )\ .colorize(TOOL_COLORS) - mute_solo = MuteSoloStrategy( - getSelection, - playlist.muteTrack, - playlist.isTrackMuted, - playlist.soloTrack, - playlist.isTrackSolo, - playlist.getTrackColor, - ) + mute_solo = MuteSoloStrategy(getSelection) # Navigation mappings # FIXME: This is super yucky, come up with a better system for it @@ -152,8 +144,8 @@ def __init__(self, shadow: DeviceShadow) -> None: super().__init__(shadow, [mute_solo]) @classmethod - def getWindowId(cls) -> int: - return INDEX + def getWindowId(cls) -> WindowIndex: + return WindowIndex.PLAYLIST @classmethod def create(cls, shadow: DeviceShadow) -> 'WindowPlugin': @@ -162,7 +154,7 @@ def create(cls, shadow: DeviceShadow) -> 'WindowPlugin': def jogWheel( self, control: ControlShadowEvent, - index: UnsafeIndex, + index: FlIndex, *args: Any ) -> bool: if control.value == consts.JOG_NEXT: @@ -184,12 +176,12 @@ def jogWheel( track = playlist.trackCount() - 1 playlist.deselectAll() playlist.selectTrack(track) - ui.scrollWindow(INDEX, track) + ui.scrollWindow(WindowIndex.PLAYLIST.index, track) elif isinstance(control.getControl(), StandardJogWheel): # Need to account for ticks being zero-indexed and bars being # 1-indexed bar = int(transport.getSongPos(3)) + increment - 1 - ui.scrollWindow(INDEX, bar, 1) + ui.scrollWindow(WindowIndex.PLAYLIST.index, bar, 1) # TODO: Make this work with time signature markers transport.setSongPos(bar * general.getRecPPB(), 2) return True @@ -201,7 +193,7 @@ def eSelectTool( window, idx: int, ) -> bool: - # FIXME: This uses keyboard shortcuts which are extremely unreliable + # HACK: This uses keyboard shortcuts which are extremely unreliable if idx < len(TOOL_COLORS): # If we're already in a menu, close it if ui.isInPopupMenu():