Rename package directory AbletonOSC/ -> ableton_osc/
Python package naming convention uses snake_case. Update the import in the root __init__.py and the setuptools include pattern in pyproject.toml. Internal relative imports within the package are unaffected. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,216 @@
|
||||
"""Handles /live/view/* OSC addresses (UI navigation)."""
|
||||
import logging
|
||||
from typing import Optional
|
||||
from .handler import AbletonOSCHandler
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ViewHandler(AbletonOSCHandler):
|
||||
def init_api(self) -> None:
|
||||
self.clear_listeners()
|
||||
view = self._song_view()
|
||||
|
||||
# selected scene
|
||||
self._add("/live/view/get/selected_scene", self._get_selected_scene)
|
||||
self._add("/live/view/set/selected_scene", self._set_selected_scene)
|
||||
self._add("/live/view/start_listen/selected_scene", self._start_listen_selected_scene)
|
||||
self._add("/live/view/stop_listen/selected_scene", self._stop_listen_selected_scene)
|
||||
|
||||
# selected track
|
||||
self._add("/live/view/get/selected_track", self._get_selected_track)
|
||||
self._add("/live/view/set/selected_track", self._set_selected_track)
|
||||
self._add("/live/view/start_listen/selected_track", self._start_listen_selected_track)
|
||||
self._add("/live/view/stop_listen/selected_track", self._stop_listen_selected_track)
|
||||
|
||||
# selected clip
|
||||
self._add("/live/view/get/selected_clip", self._get_selected_clip)
|
||||
self._add("/live/view/set/selected_clip", self._set_selected_clip)
|
||||
|
||||
# selected device
|
||||
self._add("/live/view/get/selected_device", self._get_selected_device)
|
||||
|
||||
# focus
|
||||
self._add("/live/view/show_clip_detail_view", self._show_clip_detail_view)
|
||||
self._add("/live/view/show_device_detail_view", self._show_device_detail_view)
|
||||
self._add("/live/view/focus_browser", self._focus_browser)
|
||||
|
||||
# arrangement / session toggle
|
||||
self._add("/live/view/get/focused_document_view", self._get_focused_document_view)
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
def _song_view(self):
|
||||
try:
|
||||
return self.song.view
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
def _get_selected_scene(self, params: tuple) -> Optional[tuple]:
|
||||
try:
|
||||
view = self._song_view()
|
||||
scenes = list(self.song.scenes)
|
||||
scene = view.selected_scene
|
||||
idx = scenes.index(scene)
|
||||
return (idx,)
|
||||
except Exception as e:
|
||||
logger.warning("get selected_scene: %s", e)
|
||||
return None
|
||||
|
||||
def _set_selected_scene(self, params: tuple) -> None:
|
||||
if not params:
|
||||
return None
|
||||
try:
|
||||
idx = int(params[0])
|
||||
scenes = list(self.song.scenes)
|
||||
if 0 <= idx < len(scenes):
|
||||
self._song_view().selected_scene = scenes[idx]
|
||||
except Exception as e:
|
||||
logger.warning("set selected_scene: %s", e)
|
||||
return None
|
||||
|
||||
def _start_listen_selected_scene(self, params: tuple) -> None:
|
||||
view = self._song_view()
|
||||
if view is None:
|
||||
return
|
||||
key = "view.selected_scene"
|
||||
self._remove_listener(key)
|
||||
|
||||
def cb():
|
||||
result = self._get_selected_scene(())
|
||||
if result:
|
||||
self._send("/live/view/get/selected_scene", result)
|
||||
|
||||
try:
|
||||
view.add_selected_scene_listener(cb)
|
||||
self._listener_store[key] = (view.remove_selected_scene_listener, cb)
|
||||
cb()
|
||||
except Exception as e:
|
||||
logger.warning("selected_scene listener: %s", e)
|
||||
|
||||
def _stop_listen_selected_scene(self, params: tuple) -> None:
|
||||
self._remove_listener("view.selected_scene")
|
||||
|
||||
def _get_selected_track(self, params: tuple) -> Optional[tuple]:
|
||||
try:
|
||||
view = self._song_view()
|
||||
all_tracks = list(self.song.tracks) + list(self.song.return_tracks)
|
||||
track = view.selected_track
|
||||
idx = all_tracks.index(track)
|
||||
return (idx,)
|
||||
except Exception as e:
|
||||
logger.warning("get selected_track: %s", e)
|
||||
return None
|
||||
|
||||
def _set_selected_track(self, params: tuple) -> None:
|
||||
if not params:
|
||||
return None
|
||||
try:
|
||||
idx = int(params[0])
|
||||
all_tracks = list(self.song.tracks) + list(self.song.return_tracks)
|
||||
if 0 <= idx < len(all_tracks):
|
||||
self._song_view().selected_track = all_tracks[idx]
|
||||
except Exception as e:
|
||||
logger.warning("set selected_track: %s", e)
|
||||
return None
|
||||
|
||||
def _start_listen_selected_track(self, params: tuple) -> None:
|
||||
view = self._song_view()
|
||||
if view is None:
|
||||
return
|
||||
key = "view.selected_track"
|
||||
self._remove_listener(key)
|
||||
|
||||
def cb():
|
||||
result = self._get_selected_track(())
|
||||
if result:
|
||||
self._send("/live/view/get/selected_track", result)
|
||||
|
||||
try:
|
||||
view.add_selected_track_listener(cb)
|
||||
self._listener_store[key] = (view.remove_selected_track_listener, cb)
|
||||
cb()
|
||||
except Exception as e:
|
||||
logger.warning("selected_track listener: %s", e)
|
||||
|
||||
def _stop_listen_selected_track(self, params: tuple) -> None:
|
||||
self._remove_listener("view.selected_track")
|
||||
|
||||
def _get_selected_clip(self, params: tuple) -> Optional[tuple]:
|
||||
try:
|
||||
view = self._song_view()
|
||||
clip_view = view.detail_clip
|
||||
if clip_view is None:
|
||||
return None
|
||||
tracks = list(self.song.tracks)
|
||||
for ti, track in enumerate(tracks):
|
||||
for ci, slot in enumerate(track.clip_slots):
|
||||
if slot.has_clip and slot.clip == clip_view:
|
||||
return (ti, ci)
|
||||
except Exception as e:
|
||||
logger.warning("get selected_clip: %s", e)
|
||||
return None
|
||||
|
||||
def _set_selected_clip(self, params: tuple) -> None:
|
||||
if len(params) < 2:
|
||||
return None
|
||||
try:
|
||||
track_idx = int(params[0])
|
||||
clip_idx = int(params[1])
|
||||
tracks = list(self.song.tracks)
|
||||
if 0 <= track_idx < len(tracks):
|
||||
slots = list(tracks[track_idx].clip_slots)
|
||||
if 0 <= clip_idx < len(slots) and slots[clip_idx].has_clip:
|
||||
self._song_view().detail_clip = slots[clip_idx].clip
|
||||
except Exception as e:
|
||||
logger.warning("set selected_clip: %s", e)
|
||||
return None
|
||||
|
||||
def _get_selected_device(self, params: tuple) -> Optional[tuple]:
|
||||
try:
|
||||
view = self._song_view()
|
||||
track = view.selected_track
|
||||
tracks = list(self.song.tracks) + list(self.song.return_tracks)
|
||||
track_idx = tracks.index(track)
|
||||
selected = track.view.selected_device
|
||||
if selected is None:
|
||||
return None
|
||||
devices = list(track.devices)
|
||||
device_idx = devices.index(selected)
|
||||
return (track_idx, device_idx)
|
||||
except Exception as e:
|
||||
logger.warning("get selected_device: %s", e)
|
||||
return None
|
||||
|
||||
def _show_clip_detail_view(self, params: tuple) -> None:
|
||||
try:
|
||||
app = self.manager.application
|
||||
app.view.show_view("Detail/Clip")
|
||||
except Exception as e:
|
||||
logger.warning("show_clip_detail_view: %s", e)
|
||||
return None
|
||||
|
||||
def _show_device_detail_view(self, params: tuple) -> None:
|
||||
try:
|
||||
app = self.manager.application
|
||||
app.view.show_view("Detail/DeviceChain")
|
||||
except Exception as e:
|
||||
logger.warning("show_device_detail_view: %s", e)
|
||||
return None
|
||||
|
||||
def _focus_browser(self, params: tuple) -> None:
|
||||
try:
|
||||
app = self.manager.application
|
||||
app.view.show_view("Browser")
|
||||
except Exception as e:
|
||||
logger.warning("focus_browser: %s", e)
|
||||
return None
|
||||
|
||||
def _get_focused_document_view(self, params: tuple) -> Optional[tuple]:
|
||||
try:
|
||||
app = self.manager.application
|
||||
view = app.view.focused_document_view
|
||||
return (view,)
|
||||
except Exception as e:
|
||||
logger.warning("get focused_document_view: %s", e)
|
||||
return None
|
||||
Reference in New Issue
Block a user