you can drag things left and right and the mute and solo buttons update the ui now
This commit is contained in:
@@ -18,7 +18,8 @@ class SongPlayer:
|
||||
self.timer = Timer(
|
||||
timeline,
|
||||
0.1,
|
||||
pause=True
|
||||
pause=True,
|
||||
skip=False
|
||||
)
|
||||
|
||||
def play_callback(self, out, frames, time, status):
|
||||
|
||||
Binary file not shown.
@@ -100,7 +100,27 @@ class AppUI(App):
|
||||
|
||||
self.open_project_path = path
|
||||
|
||||
### load all the ui elements
|
||||
### load all the ui element
|
||||
|
||||
# timeline tracks
|
||||
timeline = self.query_one(Timeline)
|
||||
rows = timeline.query_one("#rows")
|
||||
|
||||
for i, channel in enumerate(self.project.channels):
|
||||
row = TimelineRow(channel, id=f"row-{i}")
|
||||
|
||||
|
||||
row.styles.width = timeline.bar_offset * self.project.song_length
|
||||
rows.mount(row)
|
||||
|
||||
for chunk in channel.chunks:
|
||||
|
||||
if chunk.chunk_type == ChunkType.CHUNK:
|
||||
row.mount(Chunk(chunk, chunk_name=chunk.name, bar_pos=chunk.position))
|
||||
elif chunk.chunk_type == ChunkType.AUDIO:
|
||||
row.mount(AudioChunk(chunk, chunk.name, chunk.position))
|
||||
|
||||
|
||||
# sidebar channels
|
||||
sidebar_channels = self.query_one("#channels")
|
||||
|
||||
@@ -121,25 +141,6 @@ class AppUI(App):
|
||||
channel.volume
|
||||
), before=-1)
|
||||
|
||||
# timeline tracks
|
||||
timeline = self.query_one(Timeline)
|
||||
rows = timeline.query_one("#rows")
|
||||
|
||||
for channel in self.project.channels:
|
||||
row = TimelineRow(channel)
|
||||
|
||||
|
||||
row.styles.width = timeline.bar_offset * self.project.song_length
|
||||
rows.mount(row)
|
||||
|
||||
for chunk in channel.chunks:
|
||||
|
||||
if chunk.chunk_type == ChunkType.CHUNK:
|
||||
row.mount(Chunk(chunk_name=chunk.name, bar_pos=chunk.position))
|
||||
elif chunk.chunk_type == ChunkType.AUDIO:
|
||||
row.mount(AudioChunk(chunk.audio_data, chunk.sample_rate, chunk.name, chunk.position))
|
||||
|
||||
|
||||
self.notify(f"Loaded \"{path}\"")
|
||||
|
||||
self.push_screen(FileOpen(
|
||||
@@ -163,10 +164,12 @@ class AppUI(App):
|
||||
case _:
|
||||
self.notify("Sorry, that isn't implemented yet... ;-;", severity="warning")
|
||||
|
||||
|
||||
|
||||
@on(Tabs.TabActivated)
|
||||
async def top_menu_tab_clicked(self, event: Tabs.TabActivated):
|
||||
if self.first_tab_click:
|
||||
event.tabs.active = None
|
||||
if self.first_tab_click:
|
||||
self.first_tab_click = False
|
||||
return
|
||||
|
||||
|
||||
@@ -102,7 +102,7 @@ class SettingsScreen(ModalScreen):
|
||||
with HorizontalGroup(classes="setting"):
|
||||
with VerticalGroup():
|
||||
yield Label("Colour Theme", classes="setting-name")
|
||||
yield Label("Colour theme used for the entire Berry app. You can get more themes with plugins!", classes="setting-desc")
|
||||
yield Label("Colour theme used for the entire app.", classes="setting-desc")
|
||||
|
||||
yield Select.from_values(
|
||||
(theme_name for theme_name in self.app._registered_themes.keys() if theme_name != "textual-ansi"),
|
||||
|
||||
@@ -57,15 +57,36 @@ class Channel(VerticalGroup):
|
||||
self.solo = solo
|
||||
self.pan = pan
|
||||
self.volume = volume
|
||||
print(self.channel_name)
|
||||
print("hi")
|
||||
print(self.timeline_row)
|
||||
|
||||
def on_mount(self):
|
||||
if self.muted:
|
||||
self.timeline_row.add_class("-muted")
|
||||
if self.solo:
|
||||
self.timeline_row.add_class("-solo")
|
||||
|
||||
@property
|
||||
def timeline_row(self):
|
||||
return self.app.query_one(f"#row-{self.channel_index}")
|
||||
|
||||
def on_checkbox_changed(self, event: Checkbox.Changed):
|
||||
if event.checkbox.id == "mute":
|
||||
self.muted = event.value
|
||||
self.project_channel.mute = self.muted
|
||||
|
||||
self.app.query_one("#timeline").query_one()
|
||||
if self.muted:
|
||||
self.timeline_row.add_class("-muted")
|
||||
else:
|
||||
self.timeline_row.remove_class("-muted")
|
||||
elif event.checkbox.id == "solo":
|
||||
self.solo = event.value
|
||||
self.project_channel.solo = self.solo
|
||||
|
||||
if self.solo:
|
||||
self.timeline_row.add_class("-solo")
|
||||
else:
|
||||
self.timeline_row.remove_class("-solo")
|
||||
|
||||
def on_slider_changed(self, event: Slider.Changed):
|
||||
if event.slider.id == "volume":
|
||||
|
||||
@@ -23,11 +23,11 @@ class AudioChunk(Chunk):
|
||||
}
|
||||
"""
|
||||
|
||||
def __init__(self, audio_data: np.ndarray, sample_rate: int, chunk_name: str = "Sample", bar_pos: float = 0.0):
|
||||
super().__init__(chunk_name, bar_pos)
|
||||
def __init__(self, project_chunk, chunk_name: str = "Sample", bar_pos: float = 0.0):
|
||||
super().__init__(project_chunk, chunk_name, bar_pos)
|
||||
|
||||
self.audio = audio_data
|
||||
self.sample_rate = sample_rate
|
||||
self.audio = project_chunk.audio_data
|
||||
self.sample_rate = project_chunk.sample_rate
|
||||
|
||||
self.num_channels = None
|
||||
if len(self.audio.shape) == 1:
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
from textual.containers import Container
|
||||
from textual import on, events
|
||||
from textual_window import Window
|
||||
from textual.widgets import Button
|
||||
|
||||
from project import ChannelChunk
|
||||
|
||||
|
||||
class Chunk(Container):
|
||||
@@ -11,16 +16,31 @@ class Chunk(Container):
|
||||
border: tab $surface;
|
||||
background: $surface-darken-1;
|
||||
dock: left;
|
||||
|
||||
&:focus {
|
||||
background-tint: $primary 25%;
|
||||
}
|
||||
|
||||
&.dragging {
|
||||
background: $surface-lighten-1;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
"""
|
||||
|
||||
def __init__(self, chunk_name: str = "Chunk", bar_pos: float = 0.0):
|
||||
can_focus = True
|
||||
|
||||
def __init__(self, project_chunk: ChannelChunk, chunk_name: str = "Chunk", bar_pos: float = 0.0):
|
||||
super().__init__()
|
||||
self.project_chunk = project_chunk
|
||||
self.chunk_name = chunk_name
|
||||
self.border_title = chunk_name
|
||||
self.bar_pos = bar_pos
|
||||
self.update_offset()
|
||||
|
||||
self.being_dragged = False
|
||||
|
||||
def update_offset(self, timeline=None):
|
||||
if timeline == None:
|
||||
timeline = self.app.query_one("#timeline")
|
||||
@@ -28,3 +48,33 @@ class Chunk(Container):
|
||||
|
||||
def calculate_size(self):
|
||||
pass
|
||||
|
||||
@on(events.MouseMove)
|
||||
def continue_drag(self, event: events.MouseUp):
|
||||
if not self.being_dragged: return
|
||||
|
||||
# move the widget in the ui
|
||||
offset_x = self.styles.offset.x.cells + event.delta_x
|
||||
self.styles.offset = (offset_x, 0)
|
||||
|
||||
# update the backend as well
|
||||
timeline = self.app.query_one("#timeline")
|
||||
pos = offset_x / (timeline.bar_offset * 4)
|
||||
|
||||
self.bar_pos = pos
|
||||
self.project_chunk.position = pos
|
||||
|
||||
@on(events.MouseUp)
|
||||
def end_drag(self, event: events.MouseUp):
|
||||
if event.button == 1:
|
||||
self.being_dragged = False
|
||||
self.remove_class("dragging")
|
||||
self.release_mouse()
|
||||
|
||||
@on(events.MouseDown)
|
||||
def start_drag(self, event: events.MouseDown):
|
||||
if event.button == 1:
|
||||
self.being_dragged = True
|
||||
self.add_class("dragging")
|
||||
self.capture_mouse()
|
||||
self.focus()
|
||||
@@ -29,14 +29,4 @@ class Sidebar(Vertical):
|
||||
|
||||
def compose(self) -> ComposeResult:
|
||||
with VerticalScroll(id="channels"):
|
||||
for i, channel in enumerate(self.app.project.channels):
|
||||
yield Channel(
|
||||
i,
|
||||
channel,
|
||||
channel.name,
|
||||
channel.mute,
|
||||
channel.solo,
|
||||
channel.pan,
|
||||
channel.volume
|
||||
)
|
||||
yield Button("+ New Channel", variant="success", id="add-channel")
|
||||
@@ -18,17 +18,17 @@ class TimelineRow(Horizontal):
|
||||
margin-bottom: 1;
|
||||
|
||||
&.-muted {
|
||||
background: $error 25%;
|
||||
background-tint: $background-darken-2 50%;
|
||||
}
|
||||
|
||||
&.-solo {
|
||||
background: $warning 25%;
|
||||
background-tint: $warning 20%;
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
def __init__(self, project_channel):
|
||||
super().__init__()
|
||||
def __init__(self, project_channel, id: str | None = None):
|
||||
super().__init__(id=id)
|
||||
self.project_channel = project_channel
|
||||
|
||||
class Timeline(Vertical):
|
||||
@@ -139,18 +139,6 @@ class Timeline(Vertical):
|
||||
|
||||
|
||||
with VerticalScroll(id="rows"):
|
||||
for channel in self.app.project.channels:
|
||||
with TimelineRow(channel) as row:
|
||||
|
||||
row.styles.width = self.bar_offset * self.app.project.song_length
|
||||
|
||||
for chunk in channel.chunks:
|
||||
|
||||
if chunk.chunk_type == ChunkType.CHUNK:
|
||||
yield Chunk(chunk_name=chunk.name, bar_pos=chunk.position)
|
||||
elif chunk.chunk_type == ChunkType.AUDIO:
|
||||
yield AudioChunk(chunk.audio_data, chunk.sample_rate, chunk.name, chunk.position)
|
||||
|
||||
for i in range(1, self.app.project.song_length+1):
|
||||
bar = None
|
||||
if i % 4 == 0:
|
||||
|
||||
Reference in New Issue
Block a user