1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
|
from textual.app import App, ComposeResult
from textual.reactive import reactive
from textual.binding import Binding
from textual.css.query import NoMatches
from renardo.SCFilesHandling import is_renardo_scfiles_installed, write_sc_renardo_files_in_user_config
from renardo.widgets.Widgets import LeftPane
from renardo.widgets.TutoTabPane import TutoTabPane
from textual import work
from textual.containers import Horizontal, Vertical
from textual.widgets import (
Header,
Footer,
Button,
Label,
TabbedContent,
TabPane,
Log,
)
class RenardoTUI(App[None]):
CSS_PATH = "RenardoTUI.tcss"
left_pane_mode = reactive("start-renardo")
BINDINGS = [
Binding("ctrl+q", "quit", "Quit", show=True, priority=True),
]
def __init__(self, renardo_app, *args, **kwargs):
super().__init__(*args, **kwargs)
self.renardo_app = renardo_app
self.left_pane_mode = self.calculate_left_pane_mode()
def calculate_left_pane_mode(self):
if not self.renardo_app.sc_instance.supercollider_ready:
return "sc-not-ready"
if not is_renardo_scfiles_installed():
return "init-renardo-scfiles"
if not self.renardo_app.spack_manager.is_default_spack_initialized():
return "dl-renardo-samples"
return "start-renardo"
def watch_left_pane_mode(self): # This is a special method from textual that is not easy to move from the app
"""watch function textual reactive param"""
try:
self.query_one(LeftPane).current = self.left_pane_mode
except NoMatches:
pass
def compose(self) -> ComposeResult:
yield Header()
with TabbedContent():
with TabPane("Welcome", id="welcome-tab"):
yield Label("Welcome to renardo terminal user interface (TUI) !!")
yield Label("Here you can configure, learn renardo and start it's different modules")
with TabPane("Autostart", id="start-tab"):
with Horizontal():
with Vertical():
yield LeftPane(initial=self.calculate_left_pane_mode())
with Vertical():
yield Log(id="log-output")
yield TutoTabPane(title="Tutorials", id="tuto-tab")
yield Footer()
@work(exclusive=True, thread=True)
def dl_samples_background(self) -> None:
log_output_widget = self.query_one("#log-output", Log)
self.renardo_app.spack_manager.set_logger(log_output_widget)
self.renardo_app.spack_manager.init_default_spack()
self.left_pane_mode = self.calculate_left_pane_mode()
@work(exclusive=True, thread=True)
def init_scfile_background(self) -> None:
write_sc_renardo_files_in_user_config()
self.query_one("#log-output", Log).write_line("Renardo SC files created in user config")
self.left_pane_mode = self.calculate_left_pane_mode()
@work(exclusive=True, thread=True)
def start_sc_background(self) -> None:
if self.renardo_app.sc_instance.start_sclang_subprocess():
self.query_one("#log-output", Log).write_line("Launching Renardo SC module with SCLang...")
output_line = self.renardo_app.sc_instance.read_stdout_line()
while "Welcome to" not in output_line:
self.query_one("#log-output", Log).write_line(output_line)
output_line = self.renardo_app.sc_instance.read_stdout_line()
self.renardo_app.sc_instance.evaluate_sclang_code("Renardo.start;")
self.renardo_app.sc_instance.evaluate_sclang_code("Renardo.midi;")
self.query_one("#start-renardo-foxdot-editor-btn", Button).disabled = False
if self.renardo_app.pulsar_instance.pulsar_ready:
self.query_one("#start-pulsar-btn", Button).disabled = False
else:
self.query_one("#start-pulsar-btn", Button).label = "Pulsar not ready"
while True:
self.query_one("#log-output", Log).write_line(self.renardo_app.sc_instance.read_stdout_line())
else:
self.query_one("#log-output", Log).write_line("SuperCollider backend already started (sclang backend externally managed)\nIf you want to handle the backend manually you should ensure... \n...you executed Renardo.start; correctly in SuperCollider IDE")
self.query_one("#start-renardo-foxdot-editor-btn", Button).disabled = False
if self.renardo_app.pulsar_instance.pulsar_ready:
self.query_one("#start-pulsar-btn", Button).disabled = False
@work(exclusive=True, thread=True)
def start_pulsar_background(self) -> None:
self.query_one("#log-output", Log).write_line("Launching Renardo SC module with SCLang...")
self.renardo_app.pulsar_instance.start_pulsar_subprocess()
while True:
self.query_one("#log-output", Log).write_line(self.renardo_app.pulsar_instance.read_stdout_line())
@work(exclusive=True, thread=True)
def start_foxdoteditor_background(self) -> None:
from renardo_lib import FoxDotCode
# Open the GUI
from FoxDotEditor.Editor import workspace
FoxDot = workspace(FoxDotCode).run()
self.app.exit(0) # Exit renardo when editor is closed because there is a bug when relaunching editor
# def on_radio_set_changed(self, event: RadioSet.Changed) -> None:
# self.renardo_app.args.boot = True if event.radio_set.pressed_index == 1 else False
def on_button_pressed(self, event: Button.Pressed) -> None:
"""Event handler called when a button is pressed."""
button_id = event.button.id
if button_id == "dl-renardo-samples-btn":
self.dl_samples_background()
if button_id == "init-renardo-scfiles-btn":
self.init_scfile_background()
#if button_id == "start-renardo-pipe-btn":
# self.renardo_app.args.pipe = True
# self.exit()
if button_id == "start-pulsar-btn":
self.start_pulsar_background()
if button_id == "start-sc-btn":
self.start_sc_background()
if button_id == "start-renardo-foxdot-editor-btn":
self.start_foxdoteditor_background()
def on_mount(self) -> None:
self.title = "Renardo"
#self.query_one(RadioSet).focus()
def quit(self):
# self.renardo_app.sc_instance.sclang_process.kill()
self.exit()
|