@ -27,6 +27,7 @@ class ArpeggiatorControls(QWidget):
self . distribution_buttons = { }
self . speed_buttons = { }
self . pattern_length_buttons = { }
self . note_limit_buttons = { }
# Scaling support
self . scale_factor = 1.0
@ -39,6 +40,7 @@ class ArpeggiatorControls(QWidget):
self . current_distribution = " up "
self . current_speed = " 1/8 "
self . current_pattern_length = 8
self . current_note_limit = 7 # Default to 7 (full scale)
self . current_delay_timing = " 1/4 "
# Armed state tracking
@ -48,6 +50,8 @@ class ArpeggiatorControls(QWidget):
self . armed_scale_note_button = None
self . armed_pattern_button = None
self . armed_distribution_button = None
self . armed_pattern_length_button = None
self . armed_note_limit_button = None
# Speed changes apply immediately - no armed state needed
self . setup_ui ( )
@ -409,6 +413,28 @@ class ArpeggiatorControls(QWidget):
layout . addWidget ( length_widget )
# Note limit buttons
layout . addWidget ( QLabel ( " Note Limit: " ) )
note_limit_widget = QWidget ( )
note_limit_layout = QGridLayout ( note_limit_widget )
note_limit_layout . setSpacing ( 0 ) # NO horizontal spacing
note_limit_layout . setVerticalSpacing ( 2 ) # Minimal vertical spacing
note_limit_layout . setContentsMargins ( 0 , 0 , 0 , 0 )
self . note_limit_buttons = { }
for i in range ( 1 , 8 ) : # 1-7 note limits (1-7 notes from scale)
btn = self . create_scalable_button ( str ( i ) , 30 , 22 , 12 , checkable = True ,
style_type = " blue " if i == 7 else " normal " )
btn . clicked . connect ( lambda checked , limit = i : self . on_note_limit_clicked ( limit ) )
if i == 7 : # Default to 7 (full scale)
btn . setChecked ( True )
self . note_limit_buttons [ i ] = btn
note_limit_layout . addWidget ( btn , 0 , i - 1 ) # Single row
layout . addWidget ( note_limit_widget )
return group
def timing_quadrant ( self ) :
@ -753,16 +779,27 @@ class ArpeggiatorControls(QWidget):
self . arpeggiator . set_note_speed ( speed )
def on_pattern_length_clicked ( self , length ) :
# Pattern length changes apply immediately
if self . current_pattern_length in self . pattern_length_buttons :
self . pattern_length_buttons [ self . current_pattern_length ] . setStyleSheet ( " background: #3a3a3a; color: #ffffff; font-size: 12px; font-weight: bold; padding: 0px; border: 1px solid #555555; " )
# Pattern length changes are armed (applied at pattern end)
if self . armed_pattern_length_button :
self . apply_button_style ( self . armed_pattern_length_button , 12 , " normal " )
self . current_pattern_length = length
self . pattern_length_buttons [ length ] . setStyleSheet ( " background: #cc6600; col or: white; font-size: 12px; font-weight: bold; p addi ng: 0px; bord er: 1px solid #ee8800; " )
self . armed_pattern_length_button = self . pattern_length_buttons [ length ]
self . apply_button_style ( self . pattern_length_buttons [ length ] , 12 , " orange " )
if hasattr ( self . arpeggiator , ' set_pattern_length ' ) :
self . arpeggiator . set_pattern_length ( length )
def on_note_limit_clicked ( self , limit ) :
""" Handle note limit button clicks (armed - applied at pattern end) """
if self . armed_note_limit_button :
self . apply_button_style ( self . armed_note_limit_button , 12 , " normal " )
self . armed_note_limit_button = self . note_limit_buttons [ limit ]
self . apply_button_style ( self . note_limit_buttons [ limit ] , 12 , " orange " )
if hasattr ( self . arpeggiator , ' set_note_limit ' ) :
self . arpeggiator . set_note_limit ( limit )
def on_delay_toggle ( self ) :
""" Handle delay on/off toggle """
self . delay_enabled = self . delay_toggle . isChecked ( )
@ -962,6 +999,32 @@ class ArpeggiatorControls(QWidget):
self . armed_scale_note_button = None
break
# Pattern length armed -> active
if self . armed_pattern_length_button and hasattr ( self . arpeggiator , ' armed_pattern_length ' ) and self . arpeggiator . armed_pattern_length is None :
for length , btn in self . pattern_length_buttons . items ( ) :
if btn == self . armed_pattern_length_button :
# Clear old active pattern length
if self . current_pattern_length in self . pattern_length_buttons :
self . apply_button_style ( self . pattern_length_buttons [ self . current_pattern_length ] , 12 , " normal " )
# Set new active pattern length (orange -> orange)
self . current_pattern_length = length
self . apply_button_style ( btn , 12 , " orange " )
self . armed_pattern_length_button = None
break
# Note limit armed -> active
if self . armed_note_limit_button and hasattr ( self . arpeggiator , ' armed_note_limit ' ) and self . arpeggiator . armed_note_limit is None :
for limit , btn in self . note_limit_buttons . items ( ) :
if btn == self . armed_note_limit_button :
# Clear old active note limit
if self . current_note_limit in self . note_limit_buttons :
self . apply_button_style ( self . note_limit_buttons [ self . current_note_limit ] , 12 , " normal " )
# Set new active note limit (orange -> blue)
self . current_note_limit = limit
self . apply_button_style ( btn , 12 , " blue " )
self . armed_note_limit_button = None
break
# Speed changes apply immediately - no armed state needed
def update_gui_from_engine ( self ) :
@ -1011,12 +1074,23 @@ class ArpeggiatorControls(QWidget):
if hasattr ( self , ' pattern_length_buttons ' ) :
# Clear current pattern length styling
if hasattr ( self , ' current_pattern_length ' ) and self . current_pattern_length in self . pattern_length_buttons :
self . pattern_length_buttons [ self . current_pattern_length ] . setStyleSheet ( " background: #3a3a3a; color: #ffffff; font-size: 12px; font-weight: bold; padding: 0px; border: 1px solid #555555; " )
self . apply_button_style ( self . pattern_length_buttons [ self . current_pattern_length ] , 12 , " normal " )
# Set new active pattern length
if hasattr ( self . arpeggiator , ' user_pattern_length ' ) :
self . current_pattern_length = self . arpeggiator . user_pattern_length
if self . current_pattern_length in self . pattern_length_buttons :
self . pattern_length_buttons [ self . current_pattern_length ] . setStyleSheet ( " background: #cc6600; color: white; font-size: 12px; font-weight: bold; padding: 0px; border: 1px solid #ee8800; " )
self . apply_button_style ( self . pattern_length_buttons [ self . current_pattern_length ] , 12 , " orange " )
# Update note limit buttons
if hasattr ( self , ' note_limit_buttons ' ) :
# Clear current note limit styling
if hasattr ( self , ' current_note_limit ' ) and self . current_note_limit in self . note_limit_buttons :
self . apply_button_style ( self . note_limit_buttons [ self . current_note_limit ] , 12 , " normal " )
# Set new active note limit
if hasattr ( self . arpeggiator , ' note_limit ' ) :
self . current_note_limit = self . arpeggiator . note_limit
if self . current_note_limit in self . note_limit_buttons :
self . apply_button_style ( self . note_limit_buttons [ self . current_note_limit ] , 12 , " blue " )
# Update delay controls
if hasattr ( self , ' delay_enabled_checkbox ' ) :