You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 

601 lines
29 KiB

"""
Arpeggiator Controls - READABLE BUTTONS WITH PROPER SIZING
"""
from PyQt5.QtWidgets import (QWidget, QVBoxLayout, QHBoxLayout, QGridLayout,
QGroupBox, QComboBox, QSlider, QSpinBox, QLabel,
QPushButton, QFrame)
from PyQt5.QtCore import Qt, pyqtSlot
class ArpeggiatorControls(QWidget):
"""Readable arpeggiator controls with properly sized buttons"""
def __init__(self, arpeggiator, channel_manager, simulator=None):
super().__init__()
self.arpeggiator = arpeggiator
self.channel_manager = channel_manager
self.simulator = simulator
# State tracking
self.presets = {}
self.current_preset = None
self.root_note_buttons = {}
self.octave_buttons = {}
self.scale_buttons = {}
self.pattern_buttons = {}
self.distribution_buttons = {}
self.speed_buttons = {}
self.current_root_note = 0
self.current_octave = 4
self.current_scale = "major"
self.current_pattern = "up"
self.current_distribution = "up"
self.current_speed = "1/8"
# Armed state tracking
self.armed_root_note_button = None
self.armed_octave_button = None
self.armed_scale_button = None
self.armed_pattern_button = None
self.armed_distribution_button = None
# Speed changes apply immediately - no armed state needed
self.setup_ui()
self.connect_signals()
def setup_ui(self):
"""Clean quadrant layout with readable buttons"""
# Main grid
main = QGridLayout(self)
main.setSpacing(8)
main.setContentsMargins(8, 8, 8, 8)
# Equal quadrants
main.addWidget(self.basic_quadrant(), 0, 0)
main.addWidget(self.distribution_quadrant(), 0, 1)
main.addWidget(self.pattern_quadrant(), 1, 0)
main.addWidget(self.timing_quadrant(), 1, 1)
main.setRowStretch(0, 1)
main.setRowStretch(1, 1)
main.setColumnStretch(0, 1)
main.setColumnStretch(1, 1)
def basic_quadrant(self):
"""Basic settings with readable buttons"""
group = QGroupBox("Basic Settings")
layout = QVBoxLayout(group)
layout.setSpacing(6)
layout.setContentsMargins(8, 8, 8, 8)
# Root notes - 12 buttons in horizontal row, NO spacing between buttons
layout.addWidget(QLabel("Root Note:"))
notes_widget = QWidget()
notes_layout = QHBoxLayout(notes_widget)
notes_layout.setSpacing(0) # NO spacing between buttons
notes_layout.setContentsMargins(0, 0, 0, 0)
notes = ["C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"]
for i, note in enumerate(notes):
btn = QPushButton(note)
btn.setFixedSize(40, 22) # Taller buttons for better readability
btn.setCheckable(True)
btn.setStyleSheet("background: #3a3a3a; color: #ffffff; font-size: 12px; font-weight: bold; padding: 0px; border: 1px solid #555555;")
btn.clicked.connect(lambda checked, n=i: self.on_root_note_clicked(n))
if i == 0:
btn.setChecked(True)
btn.setStyleSheet("background: #00aa44; color: white; font-size: 12px; font-weight: bold; padding: 0px; border: 1px solid #00cc55;")
self.root_note_buttons[i] = btn
notes_layout.addWidget(btn)
layout.addWidget(notes_widget)
# Octaves - 6 buttons in horizontal row, NO spacing between buttons
layout.addWidget(QLabel("Octave:"))
octave_widget = QWidget()
octave_layout = QHBoxLayout(octave_widget)
octave_layout.setSpacing(0) # NO spacing between buttons
octave_layout.setContentsMargins(0, 0, 0, 0)
for octave in range(3, 9): # C3 to C8
btn = QPushButton(f"C{octave}")
btn.setFixedSize(50, 22) # Taller buttons for better readability
btn.setCheckable(True)
btn.setStyleSheet("background: #3a3a3a; color: #ffffff; font-size: 12px; font-weight: bold; padding: 0px; border: 1px solid #555555;")
btn.clicked.connect(lambda checked, o=octave: self.on_octave_clicked(o))
if octave == 4:
btn.setChecked(True)
btn.setStyleSheet("background: #00aa44; color: white; font-size: 12px; font-weight: bold; padding: 0px; border: 1px solid #00cc55;")
self.octave_buttons[octave] = btn
octave_layout.addWidget(btn)
layout.addWidget(octave_widget)
# Scales - 2 rows of 4, minimal vertical spacing
layout.addWidget(QLabel("Scale:"))
scales_widget = QWidget()
scales_layout = QGridLayout(scales_widget)
scales_layout.setSpacing(0) # NO horizontal spacing
scales_layout.setVerticalSpacing(2) # Minimal vertical spacing
scales_layout.setContentsMargins(0, 0, 0, 0)
main_scales = ["major", "minor", "dorian", "phrygian", "lydian", "mixolydian", "pentatonic_major", "pentatonic_minor"]
for i, scale in enumerate(main_scales):
display_name = scale.replace("_", " ").title()
if len(display_name) > 10:
display_name = display_name[:10]
btn = QPushButton(display_name)
btn.setFixedSize(120, 22) # Taller buttons for better readability
btn.setCheckable(True)
btn.setStyleSheet("background: #3a3a3a; color: #ffffff; font-size: 12px; font-weight: bold; padding: 0px; border: 1px solid #555555;")
btn.clicked.connect(lambda checked, s=scale: self.on_scale_clicked(s))
if scale == "major":
btn.setChecked(True)
btn.setStyleSheet("background: #00aa44; color: white; font-size: 12px; font-weight: bold; padding: 0px; border: 1px solid #00cc55;")
self.scale_buttons[scale] = btn
scales_layout.addWidget(btn, i // 4, i % 4)
layout.addWidget(scales_widget)
# Octave range dropdown
layout.addWidget(QLabel("Octave Range:"))
self.octave_range_combo = QComboBox()
self.octave_range_combo.setFixedHeight(20)
for i in range(1, 5):
self.octave_range_combo.addItem(f"{i} octave{'s' if i > 1 else ''}")
layout.addWidget(self.octave_range_combo)
return group
def distribution_quadrant(self):
"""Distribution with readable buttons and simulator display"""
group = QGroupBox("Channel Distribution")
layout = QVBoxLayout(group)
layout.setSpacing(6)
layout.setContentsMargins(8, 8, 8, 8)
layout.addWidget(QLabel("Distribution Pattern:"))
# 2 rows of 4 distribution buttons
dist_widget = QWidget()
dist_layout = QGridLayout(dist_widget)
dist_layout.setSpacing(0) # NO horizontal spacing
dist_layout.setVerticalSpacing(2) # Minimal vertical spacing
dist_layout.setContentsMargins(0, 0, 0, 0)
patterns = ["up", "down", "up_down", "bounce", "random", "cycle", "alternating", "single_channel"]
for i, pattern in enumerate(patterns):
display_name = pattern.replace("_", " ").title()
if len(display_name) > 12:
display_name = display_name[:12]
btn = QPushButton(display_name)
btn.setFixedSize(120, 22) # Taller buttons for better readability
btn.setCheckable(True)
btn.setStyleSheet("background: #3a3a3a; color: #ffffff; font-size: 12px; font-weight: bold; padding: 0px; border: 1px solid #555555;")
btn.clicked.connect(lambda checked, p=pattern: self.on_distribution_clicked(p))
if pattern == "up":
btn.setChecked(True)
btn.setStyleSheet("background: #0066cc; color: white; font-size: 12px; font-weight: bold; padding: 0px; border: 1px solid #0088ee;")
self.distribution_buttons[pattern] = btn
dist_layout.addWidget(btn, i // 4, i % 4)
layout.addWidget(dist_widget)
# Description
self.dist_desc = QLabel("Channels: 1 → 2 → 3 → 4 → 5 → 6...")
self.dist_desc.setStyleSheet("font-size: 10px; color: gray;")
layout.addWidget(self.dist_desc)
# Simulator display
if self.simulator:
from .simulator_display import SimulatorDisplay
self.simulator_display = SimulatorDisplay(self.simulator, self.channel_manager)
layout.addWidget(self.simulator_display)
else:
# Create placeholder for now
placeholder = QLabel("Simulator display will appear here")
placeholder.setStyleSheet("font-size: 10px; color: gray; text-align: center;")
placeholder.setAlignment(Qt.AlignCenter)
layout.addWidget(placeholder)
return group
def pattern_quadrant(self):
"""Pattern with readable buttons"""
group = QGroupBox("Pattern Settings")
layout = QVBoxLayout(group)
layout.setSpacing(6)
layout.setContentsMargins(8, 8, 8, 8)
layout.addWidget(QLabel("Arpeggio Pattern:"))
# 2 rows of 4 pattern buttons
pattern_widget = QWidget()
pattern_layout = QGridLayout(pattern_widget)
pattern_layout.setSpacing(0) # NO horizontal spacing
pattern_layout.setVerticalSpacing(2) # Minimal vertical spacing
pattern_layout.setContentsMargins(0, 0, 0, 0)
patterns = ["up", "down", "up_down", "down_up", "random", "chord", "note_order", "custom"]
for i, pattern in enumerate(patterns):
display_name = pattern.replace("_", " ").title()
if len(display_name) > 12:
display_name = display_name[:12]
btn = QPushButton(display_name)
btn.setFixedSize(120, 22) # Taller buttons for better readability
btn.setCheckable(True)
btn.setStyleSheet("background: #3a3a3a; color: #ffffff; font-size: 12px; font-weight: bold; padding: 0px; border: 1px solid #555555;")
btn.clicked.connect(lambda checked, p=pattern: self.on_pattern_clicked(p))
if pattern == "up":
btn.setChecked(True)
btn.setStyleSheet("background: #cc6600; color: white; font-size: 12px; font-weight: bold; padding: 0px; border: 1px solid #ee8800;")
self.pattern_buttons[pattern] = btn
pattern_layout.addWidget(btn, i // 4, i % 4)
layout.addWidget(pattern_widget)
return group
def timing_quadrant(self):
"""Timing with readable controls"""
group = QGroupBox("Timing Settings")
layout = QVBoxLayout(group)
layout.setSpacing(6)
layout.setContentsMargins(8, 8, 8, 8)
# Tempo
tempo_layout = QHBoxLayout()
tempo_layout.addWidget(QLabel("Tempo:"))
self.tempo_spin = QSpinBox()
self.tempo_spin.setRange(40, 200)
self.tempo_spin.setValue(120)
self.tempo_spin.setSuffix(" BPM")
self.tempo_spin.setFixedHeight(20)
tempo_layout.addWidget(self.tempo_spin)
layout.addLayout(tempo_layout)
# Speed buttons
layout.addWidget(QLabel("Note Speed:"))
speed_widget = QWidget()
speed_layout = QHBoxLayout(speed_widget)
speed_layout.setSpacing(0) # NO spacing between buttons
speed_layout.setContentsMargins(0, 0, 0, 0)
self.speed_buttons = {}
speeds = ["1/32", "1/16", "1/8", "1/4", "1/2", "1/1"]
for speed in speeds:
btn = QPushButton(speed)
btn.setFixedSize(50, 22) # Taller buttons for better readability
btn.setCheckable(True)
btn.setStyleSheet("background: #3a3a3a; color: #ffffff; font-size: 12px; font-weight: bold; padding: 0px; border: 1px solid #555555;")
btn.clicked.connect(lambda checked, s=speed: self.on_speed_clicked(s))
if speed == "1/8":
btn.setChecked(True)
btn.setStyleSheet("background: #9933cc; color: white; font-size: 12px; font-weight: bold; padding: 0px; border: 1px solid #bb55ee;")
self.speed_buttons[speed] = btn
speed_layout.addWidget(btn)
layout.addWidget(speed_widget)
# Gate
gate_layout = QHBoxLayout()
gate_layout.addWidget(QLabel("Gate:"))
self.gate_slider = QSlider(Qt.Horizontal)
self.gate_slider.setRange(10, 200)
self.gate_slider.setValue(100)
self.gate_slider.setFixedHeight(20)
gate_layout.addWidget(self.gate_slider)
self.gate_label = QLabel("100%")
self.gate_label.setFixedWidth(40)
gate_layout.addWidget(self.gate_label)
layout.addLayout(gate_layout)
# Swing
swing_layout = QHBoxLayout()
swing_layout.addWidget(QLabel("Swing:"))
self.swing_slider = QSlider(Qt.Horizontal)
self.swing_slider.setRange(-100, 100)
self.swing_slider.setValue(0)
self.swing_slider.setFixedHeight(20)
swing_layout.addWidget(self.swing_slider)
self.swing_label = QLabel("0%")
self.swing_label.setFixedWidth(40)
swing_layout.addWidget(self.swing_label)
layout.addLayout(swing_layout)
# Velocity
velocity_layout = QHBoxLayout()
velocity_layout.addWidget(QLabel("Velocity:"))
self.velocity_slider = QSlider(Qt.Horizontal)
self.velocity_slider.setRange(1, 127)
self.velocity_slider.setValue(80)
self.velocity_slider.setFixedHeight(20)
velocity_layout.addWidget(self.velocity_slider)
self.velocity_label = QLabel("80")
self.velocity_label.setFixedWidth(40)
velocity_layout.addWidget(self.velocity_label)
layout.addLayout(velocity_layout)
# Presets
preset_layout = QHBoxLayout()
self.save_btn = QPushButton("Save Preset")
self.save_btn.setFixedSize(80, 20)
self.load_btn = QPushButton("Load Preset")
self.load_btn.setFixedSize(80, 20)
preset_layout.addWidget(self.save_btn)
preset_layout.addWidget(self.load_btn)
preset_layout.addStretch()
layout.addLayout(preset_layout)
return group
def connect_signals(self):
"""Connect all signals"""
self.tempo_spin.valueChanged.connect(self.on_tempo_changed)
# Speed is now handled by individual button click handlers
self.gate_slider.valueChanged.connect(self.on_gate_changed)
self.swing_slider.valueChanged.connect(self.on_swing_changed)
self.velocity_slider.valueChanged.connect(self.on_velocity_changed)
self.octave_range_combo.currentIndexChanged.connect(self.on_octave_range_changed)
self.save_btn.clicked.connect(self.save_preset)
self.load_btn.clicked.connect(self.load_preset)
if hasattr(self.arpeggiator, 'armed_state_changed'):
self.arpeggiator.armed_state_changed.connect(self.update_armed_states)
# Event handlers
def on_root_note_clicked(self, note_index):
midi_note = self.current_octave * 12 + note_index
if hasattr(self.arpeggiator, 'is_playing') and self.arpeggiator.is_playing:
# ARMED STATE - button turns orange, waits for pattern end
if self.armed_root_note_button:
self.armed_root_note_button.setStyleSheet("background: #3a3a3a; color: #ffffff; font-size: 12px; font-weight: bold; padding: 0px; border: 1px solid #555555;")
self.armed_root_note_button = self.root_note_buttons[note_index]
self.root_note_buttons[note_index].setStyleSheet("background: #ff8800; color: white; font-size: 12px; font-weight: bold; padding: 0px; border: 1px solid #ffaa00;")
if hasattr(self.arpeggiator, 'arm_root_note'):
self.arpeggiator.arm_root_note(midi_note)
else:
# IMMEDIATE CHANGE - apply right away
if self.current_root_note in self.root_note_buttons:
self.root_note_buttons[self.current_root_note].setStyleSheet("font-size: 12px; font-weight: bold; padding: 0px;")
self.current_root_note = note_index
self.root_note_buttons[note_index].setStyleSheet("background: #4CAF50; color: white; font-size: 12px; font-weight: bold; padding: 0px;")
if hasattr(self.arpeggiator, 'set_root_note'):
self.arpeggiator.set_root_note(midi_note)
def on_octave_clicked(self, octave):
midi_note = octave * 12 + self.current_root_note
if hasattr(self.arpeggiator, 'is_playing') and self.arpeggiator.is_playing:
# ARMED STATE - button turns orange
if self.armed_octave_button:
self.armed_octave_button.setStyleSheet("background: #3a3a3a; color: #ffffff; font-size: 12px; font-weight: bold; padding: 0px; border: 1px solid #555555;")
self.armed_octave_button = self.octave_buttons[octave]
self.octave_buttons[octave].setStyleSheet("background: #ff8800; color: white; font-size: 12px; font-weight: bold; padding: 0px; border: 1px solid #ffaa00;")
if hasattr(self.arpeggiator, 'arm_root_note'):
self.arpeggiator.arm_root_note(midi_note)
else:
# IMMEDIATE CHANGE
if self.current_octave in self.octave_buttons:
self.octave_buttons[self.current_octave].setStyleSheet("font-size: 12px; font-weight: bold; padding: 0px;")
self.current_octave = octave
self.octave_buttons[octave].setStyleSheet("background: #4CAF50; color: white; font-size: 12px; font-weight: bold; padding: 0px;")
if hasattr(self.arpeggiator, 'set_root_note'):
self.arpeggiator.set_root_note(midi_note)
def on_scale_clicked(self, scale):
if hasattr(self.arpeggiator, 'is_playing') and self.arpeggiator.is_playing:
# ARMED STATE - button turns orange
if self.armed_scale_button:
self.armed_scale_button.setStyleSheet("background: #3a3a3a; color: #ffffff; font-size: 12px; font-weight: bold; padding: 0px; border: 1px solid #555555;")
self.armed_scale_button = self.scale_buttons[scale]
self.scale_buttons[scale].setStyleSheet("background: #ff8800; color: white; font-size: 12px; font-weight: bold; padding: 0px; border: 1px solid #ffaa00;")
if hasattr(self.arpeggiator, 'arm_scale'):
self.arpeggiator.arm_scale(scale)
else:
# IMMEDIATE CHANGE
if self.current_scale in self.scale_buttons:
self.scale_buttons[self.current_scale].setStyleSheet("font-size: 12px; font-weight: bold; padding: 0px;")
self.current_scale = scale
self.scale_buttons[scale].setStyleSheet("background: #4CAF50; color: white; font-size: 12px; font-weight: bold; padding: 0px;")
if hasattr(self.arpeggiator, 'set_scale'):
self.arpeggiator.set_scale(scale)
def on_pattern_clicked(self, pattern):
if hasattr(self.arpeggiator, 'is_playing') and self.arpeggiator.is_playing:
# ARMED STATE - button turns orange
if self.armed_pattern_button:
self.armed_pattern_button.setStyleSheet("background: #3a3a3a; color: #ffffff; font-size: 12px; font-weight: bold; padding: 0px; border: 1px solid #555555;")
self.armed_pattern_button = self.pattern_buttons[pattern]
self.pattern_buttons[pattern].setStyleSheet("background: #ff8800; color: white; font-size: 12px; font-weight: bold; padding: 0px; border: 1px solid #ffaa00;")
if hasattr(self.arpeggiator, 'arm_pattern_type'):
self.arpeggiator.arm_pattern_type(pattern)
else:
# IMMEDIATE CHANGE
if self.current_pattern in self.pattern_buttons:
self.pattern_buttons[self.current_pattern].setStyleSheet("font-size: 12px; font-weight: bold; padding: 0px;")
self.current_pattern = pattern
self.pattern_buttons[pattern].setStyleSheet("background: #4CAF50; color: white; font-size: 12px; font-weight: bold; padding: 0px;")
if hasattr(self.arpeggiator, 'set_pattern_type'):
self.arpeggiator.set_pattern_type(pattern)
def on_distribution_clicked(self, pattern):
if hasattr(self.arpeggiator, 'is_playing') and self.arpeggiator.is_playing:
# ARMED STATE - button turns orange
if self.armed_distribution_button:
self.armed_distribution_button.setStyleSheet("background: #3a3a3a; color: #ffffff; font-size: 12px; font-weight: bold; padding: 0px; border: 1px solid #555555;")
self.armed_distribution_button = self.distribution_buttons[pattern]
self.distribution_buttons[pattern].setStyleSheet("background: #ff8800; color: white; font-size: 12px; font-weight: bold; padding: 0px; border: 1px solid #ffaa00;")
if hasattr(self.arpeggiator, 'arm_channel_distribution'):
self.arpeggiator.arm_channel_distribution(pattern)
else:
# IMMEDIATE CHANGE
if self.current_distribution in self.distribution_buttons:
self.distribution_buttons[self.current_distribution].setStyleSheet("font-size: 12px; font-weight: bold; padding: 0px;")
self.current_distribution = pattern
self.distribution_buttons[pattern].setStyleSheet("background: #4CAF50; color: white; font-size: 12px; font-weight: bold; padding: 0px;")
if hasattr(self.arpeggiator, 'set_channel_distribution'):
self.arpeggiator.set_channel_distribution(pattern)
def on_speed_clicked(self, speed):
# Speed changes apply immediately (no armed state needed for timing)
if self.current_speed in self.speed_buttons:
self.speed_buttons[self.current_speed].setStyleSheet("background: #3a3a3a; color: #ffffff; font-size: 12px; font-weight: bold; padding: 0px; border: 1px solid #555555;")
self.current_speed = speed
self.speed_buttons[speed].setStyleSheet("background: #9933cc; color: white; font-size: 12px; font-weight: bold; padding: 0px; border: 1px solid #bb55ee;")
if hasattr(self.arpeggiator, 'set_note_speed'):
self.arpeggiator.set_note_speed(speed)
@pyqtSlot(int)
def on_tempo_changed(self, tempo):
if hasattr(self.arpeggiator, 'set_tempo'):
self.arpeggiator.set_tempo(float(tempo))
# on_speed_changed removed - now using on_speed_clicked with buttons
@pyqtSlot(int)
def on_gate_changed(self, value):
self.gate_label.setText(f"{value}%")
if hasattr(self.arpeggiator, 'set_gate'):
self.arpeggiator.set_gate(value / 100.0)
@pyqtSlot(int)
def on_swing_changed(self, value):
self.swing_label.setText(f"{value}%")
if hasattr(self.arpeggiator, 'set_swing'):
self.arpeggiator.set_swing(value / 100.0)
@pyqtSlot(int)
def on_velocity_changed(self, value):
self.velocity_label.setText(str(value))
if hasattr(self.arpeggiator, 'set_velocity'):
self.arpeggiator.set_velocity(value)
@pyqtSlot(int)
def on_octave_range_changed(self, index):
if hasattr(self.arpeggiator, 'set_octave_range'):
self.arpeggiator.set_octave_range(index + 1)
def save_preset(self):
preset_name = f"Preset_{len(self.presets) + 1}"
self.presets[preset_name] = {
'root_note': self.current_root_note,
'octave': self.current_octave,
'scale': self.current_scale,
'pattern': self.current_pattern,
'distribution': self.current_distribution
}
print(f"Saved {preset_name}")
def load_preset(self):
if not self.presets:
print("No presets saved")
return
preset_name = list(self.presets.keys())[0]
preset = self.presets[preset_name]
# Apply preset logic here
print(f"Loaded {preset_name}")
@pyqtSlot()
def update_armed_states(self):
"""Handle armed state updates - orange buttons become green at pattern end"""
# Check if armed states were applied (armed values become None when applied)
# Root note armed -> active
if self.armed_root_note_button and hasattr(self.arpeggiator, 'armed_root_note') and self.arpeggiator.armed_root_note is None:
# Find which note this was
for note_index, btn in self.root_note_buttons.items():
if btn == self.armed_root_note_button:
# Clear old active
if self.current_root_note in self.root_note_buttons:
self.root_note_buttons[self.current_root_note].setStyleSheet("font-size: 12px; font-weight: bold; padding: 0px;")
# Set new active (orange -> green)
self.current_root_note = note_index
btn.setStyleSheet("background: #4CAF50; color: white; font-size: 12px; font-weight: bold; padding: 0px;")
self.armed_root_note_button = None
break
# Octave armed -> active
if self.armed_octave_button and hasattr(self.arpeggiator, 'armed_root_note') and self.arpeggiator.armed_root_note is None:
for octave, btn in self.octave_buttons.items():
if btn == self.armed_octave_button:
if self.current_octave in self.octave_buttons:
self.octave_buttons[self.current_octave].setStyleSheet("font-size: 12px; font-weight: bold; padding: 0px;")
self.current_octave = octave
btn.setStyleSheet("background: #4CAF50; color: white; font-size: 12px; font-weight: bold; padding: 0px;")
self.armed_octave_button = None
break
# Scale armed -> active
if self.armed_scale_button and hasattr(self.arpeggiator, 'armed_scale') and self.arpeggiator.armed_scale is None:
for scale, btn in self.scale_buttons.items():
if btn == self.armed_scale_button:
if self.current_scale in self.scale_buttons:
self.scale_buttons[self.current_scale].setStyleSheet("font-size: 12px; font-weight: bold; padding: 0px;")
self.current_scale = scale
btn.setStyleSheet("background: #4CAF50; color: white; font-size: 12px; font-weight: bold; padding: 0px;")
self.armed_scale_button = None
break
# Pattern armed -> active
if self.armed_pattern_button and hasattr(self.arpeggiator, 'armed_pattern_type') and self.arpeggiator.armed_pattern_type is None:
for pattern, btn in self.pattern_buttons.items():
if btn == self.armed_pattern_button:
if self.current_pattern in self.pattern_buttons:
self.pattern_buttons[self.current_pattern].setStyleSheet("font-size: 12px; font-weight: bold; padding: 0px;")
self.current_pattern = pattern
btn.setStyleSheet("background: #4CAF50; color: white; font-size: 12px; font-weight: bold; padding: 0px;")
self.armed_pattern_button = None
break
# Distribution armed -> active
if self.armed_distribution_button and hasattr(self.arpeggiator, 'armed_channel_distribution') and self.arpeggiator.armed_channel_distribution is None:
for distribution, btn in self.distribution_buttons.items():
if btn == self.armed_distribution_button:
if self.current_distribution in self.distribution_buttons:
self.distribution_buttons[self.current_distribution].setStyleSheet("font-size: 12px; font-weight: bold; padding: 0px;")
self.current_distribution = distribution
btn.setStyleSheet("background: #4CAF50; color: white; font-size: 12px; font-weight: bold; padding: 0px;")
self.armed_distribution_button = None
break
# Speed changes apply immediately - no armed state needed