implementing UI for bottom controls

This commit is contained in:
2026-01-13 21:33:25 +11:00
parent f8f41212f3
commit 30835a506e
4 changed files with 62 additions and 3 deletions

View File

@@ -1,4 +1,5 @@
pymp3 pymp3
textual textual
textual-slider textual-slider
textual-plot
numpy numpy

View File

@@ -3,6 +3,7 @@ from textual.widgets import Footer
from ui.widgets.sidebar import Sidebar from ui.widgets.sidebar import Sidebar
from ui.widgets.timeline import Timeline from ui.widgets.timeline import Timeline
from ui.widgets.project_settings import ProjectSettings
class AppUI(App): class AppUI(App):
@@ -13,4 +14,5 @@ class AppUI(App):
def compose(self) -> ComposeResult: def compose(self) -> ComposeResult:
yield Sidebar() yield Sidebar()
yield Timeline() yield Timeline()
yield ProjectSettings()
yield Footer() yield Footer()

View File

@@ -1,9 +1,11 @@
import librosa import librosa
import pyloudnorm as pyln import pyloudnorm as pyln
import math import math
import random
from textual.containers import Vertical from textual.containers import Vertical
from textual.widgets import Sparkline from textual.widgets import Sparkline
from textual_plot import HiResMode, PlotWidget
from ui.widgets.chunk_types.chunk import Chunk from ui.widgets.chunk_types.chunk import Chunk
@@ -12,7 +14,7 @@ from ui.widgets.chunk_types.chunk import Chunk
class AudioChunk(Chunk): class AudioChunk(Chunk):
DEFAULT_CSS = """ DEFAULT_CSS = """
AudioChunk { AudioChunk {
align: left middle;
Sparkline { Sparkline {
margin: 1; margin: 1;
} }
@@ -41,6 +43,11 @@ class AudioChunk(Chunk):
self.styles.width = (self.num_samples / self.sample_rate) / self.app.zoom_level self.styles.width = (self.num_samples / self.sample_rate) / self.app.zoom_level
def on_mount(self):
for plot in self.query(PlotWidget):
plot.margin_top = 0
plot.margin_left = 0
plot.margin_bottom = 0
def compose(self) -> ComposeResult: def compose(self) -> ComposeResult:
@@ -56,6 +63,8 @@ class AudioChunk(Chunk):
samples.append(self.audio[channel, sample]) samples.append(self.audio[channel, sample])
yield Sparkline(data=samples) yield Sparkline(data=samples)
else: else:
# just display the one channel # just display the one channel
samples = [] samples = []
@@ -63,5 +72,4 @@ class AudioChunk(Chunk):
for sample in range(0, self.num_samples, int(self.sample_rate*0.1)): for sample in range(0, self.num_samples, int(self.sample_rate*0.1)):
samples.append(self.audio[sample]) samples.append(self.audio[sample])
yield Sparkline(data=samples) yield Sparkline(data=samples)

View File

@@ -0,0 +1,48 @@
from textual.containers import Horizontal
from textual.app import ComposeResult
from textual.widgets import Button, Input, Static
class ProjectSettings(Horizontal):
DEFAULT_CSS = """
ProjectSettings {
height: 6;
margin-bottom: 1;
dock: bottom;
background: $surface-darken-1;
border-top: tall $surface-lighten-1;
align-vertical: middle;
padding: 0 1;
Button {
max-width: 5;
}
#song-bpm {
max-width: 12;
}
#song-time-sig {
max-width: 16;
}
Static {
height: 3;
content-align: left middle;
width: auto;
}
}
"""
def __init__(self):
super().__init__()
self.border_title = "Project"
def compose(self) -> ComposeResult:
yield Button("", tooltip="Play song", flat=True, id="play-button", variant="success") # icon becomes "⏸" when song is playing
yield Static(" BPM: ")
yield Input("120", placeholder="120", valid_empty=False, type="integer", max_length=3, id="song-bpm")
yield Static(" Time Signature: ")
yield Input("4/4", placeholder="4/4", valid_empty=False, id="song-time-sig")