""" 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