2024-09-24 12:54:57 +00:00
/*
* PatternEditorDialogs . cpp
* - - - - - - - - - - - - - - - - - - - - - - - -
* Purpose : Code for various dialogs that are used in the pattern editor .
* Notes : ( currently none )
* Authors : Olivier Lapicque
* OpenMPT Devs
* The OpenMPT source code is released under the BSD license . Read LICENSE for more details .
*/
# include "stdafx.h"
# include "Mptrack.h"
# include "Mainfrm.h"
# include "InputHandler.h"
# include "Moddoc.h"
# include "View_pat.h"
# include "PatternEditorDialogs.h"
# include "TempoSwingDialog.h"
# include "../soundlib/mod_specifications.h"
# include "../common/mptStringBuffer.h"
OPENMPT_NAMESPACE_BEGIN
static constexpr EffectCommand ExtendedCommands [ ] = { CMD_OFFSET , CMD_PATTERNBREAK , CMD_POSITIONJUMP , CMD_TEMPO , CMD_FINETUNE , CMD_FINETUNE_SMOOTH } ;
// For a given pattern cell, check if it contains a command supported by the X-Param mechanism.
// If so, calculate the multipler for this cell and the value of all the other cells belonging to this param.
void getXParam ( ModCommand : : COMMAND command , PATTERNINDEX nPat , ROWINDEX nRow , CHANNELINDEX nChannel , const CSoundFile & sndFile , UINT & xparam , UINT & multiplier )
{
UINT xp = 0 , mult = 1 ;
int cmdRow = static_cast < int > ( nRow ) ;
const auto & pattern = sndFile . Patterns [ nPat ] ;
if ( command = = CMD_XPARAM )
{
// current command is a parameter extension command
cmdRow - - ;
// Try to find previous command parameter to be extended
while ( cmdRow > = 0 )
{
const ModCommand & m = * pattern . GetpModCommand ( cmdRow , nChannel ) ;
if ( mpt : : contains ( ExtendedCommands , m . command ) )
break ;
if ( m . command ! = CMD_XPARAM )
{
cmdRow = - 1 ;
break ;
}
cmdRow - - ;
}
} else if ( ! mpt : : contains ( ExtendedCommands , command ) )
{
// If current row do not own any satisfying command parameter to extend, set return state
cmdRow = - 1 ;
}
if ( cmdRow > = 0 )
{
// An 'extendable' command parameter has been found
const ModCommand & m = * pattern . GetpModCommand ( cmdRow , nChannel ) ;
// Find extension resolution (8 to 24 bits)
uint32 n = 1 ;
while ( n < 4 & & cmdRow + n < pattern . GetNumRows ( ) )
{
if ( pattern . GetpModCommand ( cmdRow + n , nChannel ) - > command ! = CMD_XPARAM )
break ;
n + + ;
}
// Parameter extension found (above 8 bits non-standard parameters)
if ( n > 1 )
{
// Limit offset command to 24 bits, other commands to 16 bits
n = m . command = = CMD_OFFSET ? n : ( n > 2 ? 2 : n ) ;
// Compute extended value WITHOUT current row parameter value : this parameter
// is being currently edited (this is why this function is being called) so we
// only need to compute a multiplier so that we can add its contribution while
// its value is changed by user
for ( uint32 j = 0 ; j < n ; j + + )
{
const ModCommand & mx = * pattern . GetpModCommand ( cmdRow + j , nChannel ) ;
uint32 k = 8 * ( n - j - 1 ) ;
if ( cmdRow + j = = nRow )
mult = 1 < < k ;
else
xp + = ( mx . param < < k ) ;
}
} else if ( m . command = = CMD_OFFSET | | m . command = = CMD_FINETUNE | | m . command = = CMD_FINETUNE_SMOOTH )
{
// No parameter extension to perform (8 bits standard parameter),
// just care about offset command special case (16 bits, fake)
mult < < = 8 ;
}
const auto modDoc = sndFile . GetpModDoc ( ) ;
if ( m . command = = CMD_OFFSET & & m . volcmd = = VOLCMD_OFFSET & & modDoc ! = nullptr )
{
SAMPLEINDEX smp = modDoc - > GetSampleIndex ( m ) ;
if ( m . vol = = 0 & & smp ! = 0 )
{
xp = Util : : muldivr_unsigned ( sndFile . GetSample ( smp ) . nLength , pattern . GetpModCommand ( nRow , nChannel ) - > param * mult + xp , 256u < < ( 8u * ( std : : max ( uint32 ( 2 ) , n ) - 1u ) ) ) ;
mult = 0 ;
} else if ( m . vol > 0 & & smp ! = 0 )
{
xp + = sndFile . GetSample ( smp ) . cues [ m . vol - 1 ] ;
}
}
}
// Return x-parameter
multiplier = mult ;
xparam = xp ;
}
/////////////////////////////////////////////////////////////////////////////////////////////
// CPatternPropertiesDlg
BEGIN_MESSAGE_MAP ( CPatternPropertiesDlg , CDialog )
ON_COMMAND ( IDC_BUTTON_HALF , & CPatternPropertiesDlg : : OnHalfRowNumber )
ON_COMMAND ( IDC_BUTTON_DOUBLE , & CPatternPropertiesDlg : : OnDoubleRowNumber )
ON_COMMAND ( IDC_CHECK1 , & CPatternPropertiesDlg : : OnOverrideSignature )
ON_COMMAND ( IDC_BUTTON1 , & CPatternPropertiesDlg : : OnTempoSwing )
END_MESSAGE_MAP ( )
BOOL CPatternPropertiesDlg : : OnInitDialog ( )
{
CComboBox * combo ;
CDialog : : OnInitDialog ( ) ;
combo = ( CComboBox * ) GetDlgItem ( IDC_COMBO1 ) ;
const CSoundFile & sndFile = modDoc . GetSoundFile ( ) ;
if ( m_nPattern < sndFile . Patterns . Size ( ) & & combo )
{
CString s ;
const CPattern & pattern = sndFile . Patterns [ m_nPattern ] ;
ROWINDEX nrows = pattern . GetNumRows ( ) ;
const CModSpecifications & specs = sndFile . GetModSpecifications ( ) ;
combo - > SetRedraw ( FALSE ) ;
for ( UINT irow = specs . patternRowsMin ; irow < = specs . patternRowsMax ; irow + + )
{
combo - > AddString ( mpt : : cfmt : : dec ( irow ) ) ;
}
combo - > SetCurSel ( nrows - specs . patternRowsMin ) ;
combo - > SetRedraw ( TRUE ) ;
CheckRadioButton ( IDC_RADIO1 , IDC_RADIO2 , IDC_RADIO2 ) ;
s = MPT_CFORMAT ( " Pattern #{}: {} row{} ({}K) " ) (
m_nPattern ,
pattern . GetNumRows ( ) ,
( pattern . GetNumRows ( ) = = 1 ) ? CString ( _T ( " " ) ) : CString ( _T ( " s " ) ) ,
static_cast < int > ( ( pattern . GetNumRows ( ) * sndFile . GetNumChannels ( ) * sizeof ( ModCommand ) ) / 1024 ) ) ;
SetDlgItemText ( IDC_TEXT1 , s ) ;
// Window title
const CString patternName = mpt : : ToCString ( sndFile . GetCharsetInternal ( ) , pattern . GetName ( ) ) ;
s = MPT_CFORMAT ( " Pattern Properties for Pattern #{} " ) ( m_nPattern ) ;
if ( ! patternName . IsEmpty ( ) )
{
s + = _T ( " ( " ) ;
s + = patternName ;
s + = _T ( " ) " ) ;
}
SetWindowText ( s ) ;
// Pattern time signature
const bool bOverride = pattern . GetOverrideSignature ( ) ;
ROWINDEX nRPB = pattern . GetRowsPerBeat ( ) , nRPM = pattern . GetRowsPerMeasure ( ) ;
if ( nRPB = = 0 | | ! bOverride )
nRPB = sndFile . m_nDefaultRowsPerBeat ;
if ( nRPM = = 0 | | ! bOverride )
nRPM = sndFile . m_nDefaultRowsPerMeasure ;
m_tempoSwing = pattern . HasTempoSwing ( ) ? pattern . GetTempoSwing ( ) : sndFile . m_tempoSwing ;
GetDlgItem ( IDC_CHECK1 ) - > EnableWindow ( sndFile . GetModSpecifications ( ) . hasPatternSignatures ? TRUE : FALSE ) ;
CheckDlgButton ( IDC_CHECK1 , bOverride ? BST_CHECKED : BST_UNCHECKED ) ;
SetDlgItemInt ( IDC_ROWSPERBEAT , nRPB , FALSE ) ;
SetDlgItemInt ( IDC_ROWSPERMEASURE , nRPM , FALSE ) ;
OnOverrideSignature ( ) ;
}
return TRUE ;
}
void CPatternPropertiesDlg : : OnHalfRowNumber ( )
{
const CSoundFile & sndFile = modDoc . GetSoundFile ( ) ;
UINT nRows = GetDlgItemInt ( IDC_COMBO1 , NULL , FALSE ) ;
nRows / = 2 ;
if ( nRows < sndFile . GetModSpecifications ( ) . patternRowsMin )
nRows = sndFile . GetModSpecifications ( ) . patternRowsMin ;
SetDlgItemInt ( IDC_COMBO1 , nRows , FALSE ) ;
}
void CPatternPropertiesDlg : : OnDoubleRowNumber ( )
{
const CSoundFile & sndFile = modDoc . GetSoundFile ( ) ;
UINT nRows = GetDlgItemInt ( IDC_COMBO1 , NULL , FALSE ) ;
nRows * = 2 ;
if ( nRows > sndFile . GetModSpecifications ( ) . patternRowsMax )
nRows = sndFile . GetModSpecifications ( ) . patternRowsMax ;
SetDlgItemInt ( IDC_COMBO1 , nRows , FALSE ) ;
}
void CPatternPropertiesDlg : : OnOverrideSignature ( )
{
GetDlgItem ( IDC_ROWSPERBEAT ) - > EnableWindow ( IsDlgButtonChecked ( IDC_CHECK1 ) ) ;
GetDlgItem ( IDC_ROWSPERMEASURE ) - > EnableWindow ( IsDlgButtonChecked ( IDC_CHECK1 ) ) ;
GetDlgItem ( IDC_BUTTON1 ) - > EnableWindow ( IsDlgButtonChecked ( IDC_CHECK1 ) & & modDoc . GetSoundFile ( ) . m_nTempoMode = = TempoMode : : Modern ) ;
}
void CPatternPropertiesDlg : : OnTempoSwing ( )
{
CPattern & pat = modDoc . GetSoundFile ( ) . Patterns [ m_nPattern ] ;
const ROWINDEX oldRPB = pat . GetRowsPerBeat ( ) ;
const ROWINDEX oldRPM = pat . GetRowsPerMeasure ( ) ;
// Temporarily apply new tempo signature for preview
const ROWINDEX newRPB = std : : clamp ( static_cast < ROWINDEX > ( GetDlgItemInt ( IDC_ROWSPERBEAT ) ) , ROWINDEX ( 1 ) , MAX_ROWS_PER_BEAT ) ;
const ROWINDEX newRPM = std : : clamp ( static_cast < ROWINDEX > ( GetDlgItemInt ( IDC_ROWSPERMEASURE ) ) , newRPB , MAX_ROWS_PER_BEAT ) ;
pat . SetSignature ( newRPB , newRPM ) ;
m_tempoSwing . resize ( newRPB , TempoSwing : : Unity ) ;
CTempoSwingDlg dlg ( this , m_tempoSwing , modDoc . GetSoundFile ( ) , m_nPattern ) ;
if ( dlg . DoModal ( ) = = IDOK )
{
m_tempoSwing = dlg . m_tempoSwing ;
}
pat . SetSignature ( oldRPB , oldRPM ) ;
}
void CPatternPropertiesDlg : : OnOK ( )
{
CSoundFile & sndFile = modDoc . GetSoundFile ( ) ;
CPattern & pattern = sndFile . Patterns [ m_nPattern ] ;
// Update pattern signature if necessary
if ( sndFile . GetModSpecifications ( ) . hasPatternSignatures )
{
if ( IsDlgButtonChecked ( IDC_CHECK1 ) )
{
// Enable signature
const ROWINDEX newRPB = std : : min ( static_cast < ROWINDEX > ( GetDlgItemInt ( IDC_ROWSPERBEAT , NULL , FALSE ) ) , MAX_ROWS_PER_BEAT ) ;
const ROWINDEX newRPM = std : : min ( static_cast < ROWINDEX > ( GetDlgItemInt ( IDC_ROWSPERMEASURE , NULL , FALSE ) ) , MAX_ROWS_PER_BEAT ) ;
if ( newRPB ! = pattern . GetRowsPerBeat ( ) | | newRPM ! = pattern . GetRowsPerMeasure ( ) | | m_tempoSwing ! = pattern . GetTempoSwing ( ) )
{
if ( ! pattern . SetSignature ( newRPB , newRPM ) )
{
Reporting : : Error ( " Invalid time signature! " , " Pattern Properties " ) ;
GetDlgItem ( IDC_ROWSPERBEAT ) - > SetFocus ( ) ;
return ;
}
m_tempoSwing . resize ( newRPB , TempoSwing : : Unity ) ;
pattern . SetTempoSwing ( m_tempoSwing ) ;
modDoc . SetModified ( ) ;
}
} else
{
// Disable signature
if ( pattern . GetOverrideSignature ( ) | | pattern . HasTempoSwing ( ) )
{
pattern . RemoveSignature ( ) ;
pattern . RemoveTempoSwing ( ) ;
modDoc . SetModified ( ) ;
}
}
}
const ROWINDEX newSize = ( ROWINDEX ) GetDlgItemInt ( IDC_COMBO1 , NULL , FALSE ) ;
// Check if any pattern data would be removed.
bool resize = ( newSize ! = sndFile . Patterns [ m_nPattern ] . GetNumRows ( ) ) ;
bool resizeAtEnd = IsDlgButtonChecked ( IDC_RADIO2 ) ! = BST_UNCHECKED ;
if ( newSize < sndFile . Patterns [ m_nPattern ] . GetNumRows ( ) )
{
ROWINDEX firstRow = resizeAtEnd ? newSize : 0 ;
ROWINDEX lastRow = resizeAtEnd ? sndFile . Patterns [ m_nPattern ] . GetNumRows ( ) : sndFile . Patterns [ m_nPattern ] . GetNumRows ( ) - newSize ;
for ( ROWINDEX row = firstRow ; row < lastRow ; row + + )
{
if ( ! sndFile . Patterns [ m_nPattern ] . IsEmptyRow ( row ) )
{
resize = ( Reporting : : Confirm ( MPT_AFORMAT ( " Data at the {} of the pattern will be lost. \n Do you want to continue? " ) ( resizeAtEnd ? " end " : " start " ) , " Shrink Pattern " ) = = cnfYes ) ;
break ;
}
}
}
if ( resize )
{
modDoc . BeginWaitCursor ( ) ;
modDoc . GetPatternUndo ( ) . PrepareUndo ( m_nPattern , 0 , 0 , sndFile . Patterns [ m_nPattern ] . GetNumChannels ( ) , sndFile . Patterns [ m_nPattern ] . GetNumRows ( ) , " Resize " ) ;
if ( sndFile . Patterns [ m_nPattern ] . Resize ( newSize , true , resizeAtEnd ) )
{
modDoc . SetModified ( ) ;
}
modDoc . EndWaitCursor ( ) ;
}
CDialog : : OnOK ( ) ;
}
////////////////////////////////////////////////////////////////////////////////////////////
// CEditCommand
BEGIN_MESSAGE_MAP ( CEditCommand , CDialog )
ON_WM_ACTIVATE ( )
ON_WM_CLOSE ( )
ON_CBN_SELCHANGE ( IDC_COMBO1 , & CEditCommand : : OnNoteChanged )
ON_CBN_SELCHANGE ( IDC_COMBO2 , & CEditCommand : : OnNoteChanged )
ON_CBN_SELCHANGE ( IDC_COMBO3 , & CEditCommand : : OnVolCmdChanged )
ON_CBN_SELCHANGE ( IDC_COMBO4 , & CEditCommand : : OnCommandChanged )
ON_CBN_SELCHANGE ( IDC_COMBO5 , & CEditCommand : : OnPlugParamChanged )
ON_WM_HSCROLL ( )
END_MESSAGE_MAP ( )
void CEditCommand : : DoDataExchange ( CDataExchange * pDX )
{
CDialog : : DoDataExchange ( pDX ) ;
//{{AFX_DATA_MAP(CSplitKeyboadSettings)
DDX_Control ( pDX , IDC_COMBO1 , cbnNote ) ;
DDX_Control ( pDX , IDC_COMBO2 , cbnInstr ) ;
DDX_Control ( pDX , IDC_COMBO3 , cbnVolCmd ) ;
DDX_Control ( pDX , IDC_COMBO4 , cbnCommand ) ;
DDX_Control ( pDX , IDC_COMBO5 , cbnPlugParam ) ;
DDX_Control ( pDX , IDC_SLIDER1 , sldVolParam ) ;
DDX_Control ( pDX , IDC_SLIDER2 , sldParam ) ;
//}}AFX_DATA_MAP
}
CEditCommand : : CEditCommand ( CSoundFile & sndFile )
: sndFile ( sndFile ) , effectInfo ( sndFile )
{
CDialog : : Create ( IDD_PATTERN_EDITCOMMAND ) ;
}
BOOL CEditCommand : : PreTranslateMessage ( MSG * pMsg )
{
if ( ( pMsg ) & & ( pMsg - > message = = WM_KEYDOWN ) )
{
if ( ( pMsg - > wParam = = VK_ESCAPE ) | | ( pMsg - > wParam = = VK_RETURN ) | | ( pMsg - > wParam = = VK_APPS ) )
{
OnClose ( ) ;
return TRUE ;
}
}
return CDialog : : PreTranslateMessage ( pMsg ) ;
}
bool CEditCommand : : ShowEditWindow ( PATTERNINDEX pat , const PatternCursor & cursor , CWnd * parent )
{
editPattern = pat ;
const ROWINDEX row = editRow = cursor . GetRow ( ) ;
const CHANNELINDEX chn = editChannel = cursor . GetChannel ( ) ;
if ( ! sndFile . Patterns . IsValidPat ( pat )
| | ! sndFile . Patterns [ pat ] . IsValidRow ( row )
| | chn > = sndFile . GetNumChannels ( ) )
{
ShowWindow ( SW_HIDE ) ;
return false ;
}
m = sndFile . Patterns [ pat ] . GetpModCommand ( row , chn ) ;
modified = false ;
InitAll ( ) ;
switch ( cursor . GetColumnType ( ) )
{
case PatternCursor : : noteColumn :
cbnNote . SetFocus ( ) ;
break ;
case PatternCursor : : instrColumn :
cbnInstr . SetFocus ( ) ;
break ;
case PatternCursor : : volumeColumn :
if ( m - > IsPcNote ( ) )
cbnPlugParam . SetFocus ( ) ;
else
cbnVolCmd . SetFocus ( ) ;
break ;
case PatternCursor : : effectColumn :
if ( m - > IsPcNote ( ) )
sldParam . SetFocus ( ) ;
else
cbnCommand . SetFocus ( ) ;
break ;
case PatternCursor : : paramColumn :
sldParam . SetFocus ( ) ;
break ;
}
// Update Window Title
SetWindowText ( MPT_CFORMAT ( " Note Properties - Row {}, Channel {} " ) ( row , chn + 1 ) ) ;
CRect rectParent , rectWnd ;
parent - > GetWindowRect ( & rectParent ) ;
GetClientRect ( & rectWnd ) ;
SetWindowPos ( CMainFrame : : GetMainFrame ( ) ,
rectParent . left + ( rectParent . Width ( ) - rectWnd . right ) / 2 ,
rectParent . top + ( rectParent . Height ( ) - rectWnd . bottom ) / 2 ,
- 1 , - 1 , SWP_NOSIZE | SWP_NOACTIVATE ) ;
ShowWindow ( SW_RESTORE ) ;
return true ;
}
void CEditCommand : : InitNote ( )
{
// Note
cbnNote . SetRedraw ( FALSE ) ;
if ( oldSpecs ! = & sndFile . GetModSpecifications ( ) )
{
cbnNote . ResetContent ( ) ;
cbnNote . SetItemData ( cbnNote . AddString ( _T ( " No Note " ) ) , 0 ) ;
AppendNotesToControlEx ( cbnNote , sndFile , m - > instr ) ;
oldSpecs = & sndFile . GetModSpecifications ( ) ;
}
if ( m - > IsNote ( ) )
{
// Normal note / no note
const ModCommand : : NOTE noteStart = sndFile . GetModSpecifications ( ) . noteMin ;
cbnNote . SetCurSel ( m - > note - ( noteStart - 1 ) ) ;
} else if ( m - > note = = NOTE_NONE )
{
cbnNote . SetCurSel ( 0 ) ;
} else
{
// Special notes
for ( int i = cbnNote . GetCount ( ) - 1 ; i > = 0 ; - - i )
{
if ( cbnNote . GetItemData ( i ) = = m - > note )
{
cbnNote . SetCurSel ( i ) ;
break ;
}
}
}
cbnNote . SetRedraw ( TRUE ) ;
// Instrument
cbnInstr . SetRedraw ( FALSE ) ;
cbnInstr . ResetContent ( ) ;
if ( m - > IsPcNote ( ) )
{
// control plugin param note
cbnInstr . SetItemData ( cbnInstr . AddString ( _T ( " No Effect " ) ) , 0 ) ;
AddPluginNamesToCombobox ( cbnInstr , sndFile . m_MixPlugins , false ) ;
} else
{
// instrument / sample
cbnInstr . SetItemData ( cbnInstr . AddString ( _T ( " No Instrument " ) ) , 0 ) ;
const uint32 nmax = sndFile . GetNumInstruments ( ) ? sndFile . GetNumInstruments ( ) : sndFile . GetNumSamples ( ) ;
for ( uint32 i = 1 ; i < = nmax ; i + + )
{
CString s = mpt : : cfmt : : val ( i ) + _T ( " : " ) ;
// instrument / sample
if ( sndFile . GetNumInstruments ( ) )
{
if ( sndFile . Instruments [ i ] )
s + = mpt : : ToCString ( sndFile . GetCharsetInternal ( ) , sndFile . Instruments [ i ] - > name ) ;
} else
s + = mpt : : ToCString ( sndFile . GetCharsetInternal ( ) , sndFile . m_szNames [ i ] ) ;
cbnInstr . SetItemData ( cbnInstr . AddString ( s ) , i ) ;
}
}
cbnInstr . SetCurSel ( m - > instr ) ;
cbnInstr . SetRedraw ( TRUE ) ;
}
void CEditCommand : : InitVolume ( )
{
cbnVolCmd . SetRedraw ( FALSE ) ;
cbnVolCmd . ResetContent ( ) ;
if ( sndFile . GetType ( ) = = MOD_TYPE_MOD | | m - > IsPcNote ( ) )
{
cbnVolCmd . EnableWindow ( FALSE ) ;
sldVolParam . EnableWindow ( FALSE ) ;
} else
{
// Normal volume column effect
cbnVolCmd . EnableWindow ( TRUE ) ;
sldVolParam . EnableWindow ( TRUE ) ;
uint32 count = effectInfo . GetNumVolCmds ( ) ;
cbnVolCmd . SetItemData ( cbnVolCmd . AddString ( _T ( " None " ) ) , ( DWORD_PTR ) - 1 ) ;
cbnVolCmd . SetCurSel ( 0 ) ;
UINT fxndx = effectInfo . GetIndexFromVolCmd ( m - > volcmd ) ;
for ( uint32 i = 0 ; i < count ; i + + )
{
CString s ;
if ( effectInfo . GetVolCmdInfo ( i , & s ) )
{
int k = cbnVolCmd . AddString ( s ) ;
cbnVolCmd . SetItemData ( k , i ) ;
if ( i = = fxndx )
cbnVolCmd . SetCurSel ( k ) ;
}
}
UpdateVolCmdRange ( ) ;
}
cbnVolCmd . SetRedraw ( TRUE ) ;
}
void CEditCommand : : InitEffect ( )
{
if ( m - > IsPcNote ( ) )
{
cbnCommand . ShowWindow ( SW_HIDE ) ;
return ;
}
cbnCommand . ShowWindow ( SW_SHOW ) ;
xParam = 0 ;
xMultiplier = 1 ;
getXParam ( m - > command , editPattern , editRow , editChannel , sndFile , xParam , xMultiplier ) ;
cbnCommand . SetRedraw ( FALSE ) ;
cbnCommand . ResetContent ( ) ;
uint32 numfx = effectInfo . GetNumEffects ( ) ;
uint32 fxndx = effectInfo . GetIndexFromEffect ( m - > command , m - > param ) ;
cbnCommand . SetItemData ( cbnCommand . AddString ( _T ( " None " ) ) , ( DWORD_PTR ) - 1 ) ;
if ( m - > command = = CMD_NONE )
cbnCommand . SetCurSel ( 0 ) ;
CString s ;
for ( uint32 i = 0 ; i < numfx ; i + + )
{
if ( effectInfo . GetEffectInfo ( i , & s , true ) )
{
int k = cbnCommand . AddString ( s ) ;
cbnCommand . SetItemData ( k , i ) ;
if ( i = = fxndx )
cbnCommand . SetCurSel ( k ) ;
}
}
UpdateEffectRange ( false ) ;
cbnCommand . SetRedraw ( TRUE ) ;
cbnCommand . Invalidate ( ) ;
}
void CEditCommand : : InitPlugParam ( )
{
if ( ! m - > IsPcNote ( ) )
{
cbnPlugParam . ShowWindow ( SW_HIDE ) ;
return ;
}
cbnPlugParam . ShowWindow ( SW_SHOW ) ;
cbnPlugParam . SetRedraw ( FALSE ) ;
cbnPlugParam . ResetContent ( ) ;
if ( m - > instr > 0 & & m - > instr < = MAX_MIXPLUGINS )
{
AddPluginParameternamesToCombobox ( cbnPlugParam , sndFile . m_MixPlugins [ m - > instr - 1 ] ) ;
cbnPlugParam . SetCurSel ( m - > GetValueVolCol ( ) ) ;
}
UpdateEffectRange ( false ) ;
cbnPlugParam . SetRedraw ( TRUE ) ;
cbnPlugParam . Invalidate ( ) ;
}
void CEditCommand : : UpdateVolCmdRange ( )
{
ModCommand : : VOL rangeMin = 0 , rangeMax = 0 ;
LONG fxndx = effectInfo . GetIndexFromVolCmd ( m - > volcmd ) ;
bool ok = effectInfo . GetVolCmdInfo ( fxndx , NULL , & rangeMin , & rangeMax ) ;
if ( ok & & rangeMax > rangeMin )
{
sldVolParam . EnableWindow ( TRUE ) ;
sldVolParam . SetRange ( rangeMin , rangeMax ) ;
Limit ( m - > vol , rangeMin , rangeMax ) ;
sldVolParam . SetPos ( m - > vol ) ;
} else
{
// Why does this not update the display at all?
sldVolParam . SetRange ( 0 , 0 ) ;
sldVolParam . SetPos ( 0 ) ;
sldVolParam . EnableWindow ( FALSE ) ;
}
UpdateVolCmdValue ( ) ;
}
void CEditCommand : : UpdateEffectRange ( bool set )
{
DWORD pos ;
bool enable = true ;
if ( m - > IsPcNote ( ) )
{
// plugin param control note
sldParam . SetRange ( 0 , ModCommand : : maxColumnValue ) ;
pos = m - > GetValueEffectCol ( ) ;
} else
{
// process as effect
ModCommand : : PARAM rangeMin = 0 , rangeMax = 0 ;
LONG fxndx = effectInfo . GetIndexFromEffect ( m - > command , m - > param ) ;
enable = ( ( fxndx > = 0 ) & & ( effectInfo . GetEffectInfo ( fxndx , NULL , false , & rangeMin , & rangeMax ) ) ) ;
pos = effectInfo . MapValueToPos ( fxndx , m - > param ) ;
if ( pos > rangeMax )
pos = rangeMin | ( pos & 0x0F ) ;
Limit ( pos , rangeMin , rangeMax ) ;
sldParam . SetRange ( rangeMin , rangeMax ) ;
}
if ( enable )
{
sldParam . EnableWindow ( TRUE ) ;
sldParam . SetPageSize ( 1 ) ;
sldParam . SetPos ( pos ) ;
} else
{
// Why does this not update the display at all?
sldParam . SetRange ( 0 , 0 ) ;
sldParam . SetPos ( 0 ) ;
sldParam . EnableWindow ( FALSE ) ;
}
UpdateEffectValue ( set ) ;
}
void CEditCommand : : OnNoteChanged ( )
{
const bool wasParamControl = m - > IsPcNote ( ) ;
ModCommand : : NOTE newNote = m - > note ;
ModCommand : : INSTR newInstr = m - > instr ;
int n = cbnNote . GetCurSel ( ) ;
if ( n > = 0 )
newNote = static_cast < ModCommand : : NOTE > ( cbnNote . GetItemData ( n ) ) ;
n = cbnInstr . GetCurSel ( ) ;
if ( n > = 0 )
newInstr = static_cast < ModCommand : : INSTR > ( cbnInstr . GetItemData ( n ) ) ;
if ( m - > note ! = newNote | | m - > instr ! = newInstr )
{
PrepareUndo ( " Note Entry " ) ;
CModDoc * modDoc = sndFile . GetpModDoc ( ) ;
m - > note = newNote ;
m - > instr = newInstr ;
modDoc - > UpdateAllViews ( nullptr , RowHint ( editRow ) , nullptr ) ;
if ( wasParamControl ! = m - > IsPcNote ( ) )
{
InitAll ( ) ;
} else if ( ! m - > IsPcNote ( )
& & m - > instr < = sndFile . GetNumInstruments ( )
& & newInstr < = sndFile . GetNumInstruments ( )
& & sndFile . Instruments [ m - > instr ] ! = nullptr
& & sndFile . Instruments [ newInstr ] ! = nullptr
& & sndFile . Instruments [ newInstr ] - > pTuning ! = sndFile . Instruments [ m - > instr ] - > pTuning )
{
//Checking whether note names should be recreated.
InitNote ( ) ;
} else if ( m - > IsPcNote ( ) )
{
// Update parameter list
InitPlugParam ( ) ;
}
}
}
void CEditCommand : : OnVolCmdChanged ( )
{
ModCommand : : VOLCMD newVolCmd = m - > volcmd ;
ModCommand : : VOL newVol = m - > vol ;
int n = cbnVolCmd . GetCurSel ( ) ;
if ( n > = 0 )
{
newVolCmd = effectInfo . GetVolCmdFromIndex ( static_cast < UINT > ( cbnVolCmd . GetItemData ( n ) ) ) ;
}
newVol = static_cast < ModCommand : : VOL > ( sldVolParam . GetPos ( ) ) ;
const bool volCmdChanged = m - > volcmd ! = newVolCmd ;
if ( volCmdChanged | | m - > vol ! = newVol )
{
PrepareUndo ( " Volume Entry " ) ;
CModDoc * modDoc = sndFile . GetpModDoc ( ) ;
m - > volcmd = newVolCmd ;
m - > vol = newVol ;
modDoc - > UpdateAllViews ( nullptr , RowHint ( editRow ) , nullptr ) ;
if ( volCmdChanged )
UpdateVolCmdRange ( ) ;
else
UpdateVolCmdValue ( ) ;
}
}
void CEditCommand : : OnCommandChanged ( )
{
ModCommand : : COMMAND newCommand = m - > command ;
ModCommand : : PARAM newParam = m - > param ;
int n = cbnCommand . GetCurSel ( ) ;
if ( n > = 0 )
{
int ndx = static_cast < int > ( cbnCommand . GetItemData ( n ) ) ;
newCommand = static_cast < ModCommand : : COMMAND > ( ( ndx > = 0 ) ? effectInfo . GetEffectFromIndex ( ndx , newParam ) : CMD_NONE ) ;
}
if ( m - > command ! = newCommand | | m - > param ! = newParam )
{
PrepareUndo ( " Effect Entry " ) ;
m - > command = newCommand ;
if ( newCommand ! = CMD_NONE )
{
m - > param = newParam ;
}
xParam = 0 ;
xMultiplier = 1 ;
if ( newCommand = = CMD_XPARAM | | mpt : : contains ( ExtendedCommands , newCommand ) )
{
getXParam ( newCommand , editPattern , editRow , editChannel , sndFile , xParam , xMultiplier ) ;
}
UpdateEffectRange ( true ) ;
sndFile . GetpModDoc ( ) - > UpdateAllViews ( nullptr , RowHint ( editRow ) , nullptr ) ;
}
}
void CEditCommand : : OnPlugParamChanged ( )
{
uint16 newPlugParam = m - > GetValueVolCol ( ) ;
int n = cbnPlugParam . GetCurSel ( ) ;
if ( n > = 0 )
{
newPlugParam = static_cast < uint16 > ( cbnPlugParam . GetItemData ( n ) ) ;
}
if ( m - > GetValueVolCol ( ) ! = newPlugParam )
{
PrepareUndo ( " Effect Entry " ) ;
m - > SetValueVolCol ( newPlugParam ) ;
sndFile . GetpModDoc ( ) - > UpdateAllViews ( nullptr , RowHint ( editRow ) , nullptr ) ;
}
}
void CEditCommand : : UpdateVolCmdValue ( )
{
CString s ;
if ( m - > IsPcNote ( ) )
{
// plugin param control note
uint16 plugParam = static_cast < uint16 > ( sldVolParam . GetPos ( ) ) ;
s . Format ( _T ( " Value: %u " ) , plugParam ) ;
} else
{
// process as effect
effectInfo . GetVolCmdParamInfo ( * m , & s ) ;
}
SetDlgItemText ( IDC_TEXT2 , s ) ;
}
void CEditCommand : : UpdateEffectValue ( bool set )
{
CString s ;
uint16 newPlugParam = 0 ;
ModCommand : : PARAM newParam = 0 ;
if ( m - > IsPcNote ( ) )
{
// plugin param control note
newPlugParam = static_cast < uint16 > ( sldParam . GetPos ( ) ) ;
s . Format ( _T ( " Value: %u " ) , newPlugParam ) ;
} else
{
// process as effect
LONG fxndx = effectInfo . GetIndexFromEffect ( m - > command , m - > param ) ;
if ( fxndx > = 0 )
{
newParam = static_cast < ModCommand : : PARAM > ( effectInfo . MapPosToValue ( fxndx , sldParam . GetPos ( ) ) ) ;
effectInfo . GetEffectNameEx ( s , * m , newParam * xMultiplier + xParam , editChannel ) ;
}
}
SetDlgItemText ( IDC_TEXT1 , s ) ;
if ( set )
{
if ( ( ! m - > IsPcNote ( ) & & m - > param ! = newParam )
| | ( m - > IsPcNote ( ) & & m - > GetValueVolCol ( ) ! = newPlugParam ) )
{
PrepareUndo ( " Effect Entry " ) ;
CModDoc * modDoc = sndFile . GetpModDoc ( ) ;
if ( m - > IsPcNote ( ) )
{
m - > SetValueEffectCol ( newPlugParam ) ;
} else
{
m - > param = newParam ;
}
modDoc - > UpdateAllViews ( nullptr , RowHint ( editRow ) , nullptr ) ;
}
}
}
void CEditCommand : : PrepareUndo ( const char * description )
{
CModDoc * modDoc = sndFile . GetpModDoc ( ) ;
if ( ! modified )
{
// Let's create just one undo step.
modDoc - > GetPatternUndo ( ) . PrepareUndo ( editPattern , editChannel , editRow , 1 , 1 , description ) ;
modified = true ;
}
modDoc - > SetModified ( ) ;
}
void CEditCommand : : OnHScroll ( UINT , UINT , CScrollBar * bar )
{
if ( bar = = static_cast < CWnd * > ( & sldVolParam ) )
{
OnVolCmdChanged ( ) ;
} else if ( bar = = static_cast < CWnd * > ( & sldParam ) )
{
UpdateEffectValue ( true ) ;
}
}
void CEditCommand : : OnActivate ( UINT nState , CWnd * pWndOther , BOOL bMinimized )
{
CDialog : : OnActivate ( nState , pWndOther , bMinimized ) ;
if ( nState = = WA_INACTIVE )
ShowWindow ( SW_HIDE ) ;
}
////////////////////////////////////////////////////////////////////////////////////////////
// Chord Editor
BEGIN_MESSAGE_MAP ( CChordEditor , ResizableDialog )
ON_MESSAGE ( WM_MOD_KBDNOTIFY , & CChordEditor : : OnKeyboardNotify )
ON_CBN_SELCHANGE ( IDC_COMBO1 , & CChordEditor : : OnChordChanged )
ON_CBN_SELCHANGE ( IDC_COMBO2 , & CChordEditor : : OnBaseNoteChanged )
ON_CBN_SELCHANGE ( IDC_COMBO3 , & CChordEditor : : OnNote1Changed )
ON_CBN_SELCHANGE ( IDC_COMBO4 , & CChordEditor : : OnNote2Changed )
ON_CBN_SELCHANGE ( IDC_COMBO5 , & CChordEditor : : OnNote3Changed )
END_MESSAGE_MAP ( )
void CChordEditor : : DoDataExchange ( CDataExchange * pDX )
{
ResizableDialog : : DoDataExchange ( pDX ) ;
//{{AFX_DATA_MAP(CChordEditor)
DDX_Control ( pDX , IDC_KEYBOARD1 , m_Keyboard ) ;
DDX_Control ( pDX , IDC_COMBO1 , m_CbnShortcut ) ;
DDX_Control ( pDX , IDC_COMBO2 , m_CbnBaseNote ) ;
DDX_Control ( pDX , IDC_COMBO3 , m_CbnNote [ 0 ] ) ;
DDX_Control ( pDX , IDC_COMBO4 , m_CbnNote [ 1 ] ) ;
DDX_Control ( pDX , IDC_COMBO5 , m_CbnNote [ 2 ] ) ;
static_assert ( mpt : : array_size < decltype ( m_CbnNote ) > : : size = = 3 ) ;
//}}AFX_DATA_MAP
}
CChordEditor : : CChordEditor ( CWnd * parent )
: ResizableDialog ( IDD_CHORDEDIT , parent )
{
m_chords = TrackerSettings : : GetChords ( ) ;
}
BOOL CChordEditor : : OnInitDialog ( )
{
ResizableDialog : : OnInitDialog ( ) ;
m_Keyboard . Init ( this , ( CHORD_MAX - CHORD_MIN ) / 12 , true ) ;
m_CbnShortcut . SetRedraw ( FALSE ) ;
m_CbnBaseNote . SetRedraw ( FALSE ) ;
for ( auto & combo : m_CbnNote )
combo . SetRedraw ( FALSE ) ;
// Shortcut key combo box
AppendNotesToControl ( m_CbnShortcut , NOTE_MIN , NOTE_MIN + static_cast < int > ( kcVPEndChords ) - static_cast < int > ( kcVPStartChords ) ) ;
m_CbnShortcut . SetCurSel ( 0 ) ;
// Base Note combo box
m_CbnBaseNote . SetItemData ( m_CbnBaseNote . AddString ( _T ( " Relative " ) ) , MPTChord : : relativeMode ) ;
AppendNotesToControl ( m_CbnBaseNote , NOTE_MIN , NOTE_MIN + 3 * 12 - 1 ) ;
// Chord Note combo boxes
CString s ;
for ( int note = CHORD_MIN - 1 ; note < CHORD_MAX ; note + + )
{
int noteVal = note ;
if ( note = = CHORD_MIN - 1 )
{
s = _T ( " -- " ) ;
noteVal = MPTChord : : noNote ;
} else
{
s = mpt : : ToCString ( CSoundFile : : GetDefaultNoteName ( mpt : : wrapping_modulo ( note , 12 ) ) ) ;
const int octave = mpt : : wrapping_divide ( note , 12 ) ;
if ( octave > 0 )
s . AppendFormat ( _T ( " (+%d) " ) , octave ) ;
else if ( octave < 0 )
s . AppendFormat ( _T ( " (%d) " ) , octave ) ;
}
for ( auto & combo : m_CbnNote )
combo . SetItemData ( combo . AddString ( s ) , noteVal ) ;
}
m_CbnShortcut . SetRedraw ( TRUE ) ;
m_CbnBaseNote . SetRedraw ( TRUE ) ;
for ( auto & combo : m_CbnNote )
combo . SetRedraw ( TRUE ) ;
// Update Dialog
OnChordChanged ( ) ;
return TRUE ;
}
void CChordEditor : : OnOK ( )
{
TrackerSettings : : GetChords ( ) = m_chords ;
ResizableDialog : : OnOK ( ) ;
}
MPTChord & CChordEditor : : GetChord ( )
{
int chord = m_CbnShortcut . GetCurSel ( ) ;
if ( chord > = 0 )
chord = static_cast < int > ( m_CbnShortcut . GetItemData ( chord ) ) - NOTE_MIN ;
if ( chord < 0 | | chord > = static_cast < int > ( m_chords . size ( ) ) )
chord = 0 ;
return m_chords [ chord ] ;
}
LRESULT CChordEditor : : OnKeyboardNotify ( WPARAM cmd , LPARAM nKey )
{
const bool outside = static_cast < int > ( nKey ) = = - 1 ;
if ( cmd = = KBDNOTIFY_LBUTTONUP & & outside )
{
// Stopped dragging ouside of keyboard area
m_mouseDownKey = m_dragKey = MPTChord : : noNote ;
return 0 ;
} else if ( cmd = = KBDNOTIFY_MOUSEMOVE | | outside )
{
return 0 ;
}
MPTChord & chord = GetChord ( ) ;
const MPTChord : : NoteType key = static_cast < MPTChord : : NoteType > ( nKey ) + CHORD_MIN ;
bool update = false ;
if ( cmd = = KBDNOTIFY_LBUTTONDOWN & & m_mouseDownKey = = MPTChord : : noNote )
{
// Initial mouse down
m_mouseDownKey = key ;
m_dragKey = MPTChord : : noNote ;
return 0 ;
}
if ( cmd = = KBDNOTIFY_LBUTTONDOWN & & m_dragKey = = MPTChord : : noNote & & key ! = m_mouseDownKey )
{
// Start dragging
m_dragKey = m_mouseDownKey ;
}
// Remove dragged note or toggle
bool noteIsSet = false ;
for ( auto & note : chord . notes )
{
if ( ( m_dragKey ! = MPTChord : : noNote & & note = = m_dragKey )
| | ( m_dragKey = = MPTChord : : noNote & & note = = m_mouseDownKey ) )
{
note = MPTChord : : noNote ;
noteIsSet = update = true ;
break ;
}
}
// Move or toggle note
if ( cmd ! = KBDNOTIFY_LBUTTONUP | | m_dragKey ! = MPTChord : : noNote | | ! noteIsSet )
{
for ( auto & note : chord . notes )
{
if ( note = = MPTChord : : noNote )
{
note = key ;
update = true ;
break ;
}
}
}
if ( cmd = = KBDNOTIFY_LBUTTONUP )
m_mouseDownKey = m_dragKey = MPTChord : : noNote ;
else
m_dragKey = key ;
if ( update )
{
std : : sort ( chord . notes . begin ( ) , chord . notes . end ( ) , [ ] ( MPTChord : : NoteType left , MPTChord : : NoteType right )
{
return ( left = = MPTChord : : noNote ) ? false : ( left < right ) ;
} ) ;
OnChordChanged ( ) ;
}
return 0 ;
}
void CChordEditor : : OnChordChanged ( )
{
const MPTChord & chord = GetChord ( ) ;
if ( chord . key ! = MPTChord : : relativeMode )
m_CbnBaseNote . SetCurSel ( chord . key + 1 ) ;
else
m_CbnBaseNote . SetCurSel ( 0 ) ;
for ( int i = 0 ; i < MPTChord : : notesPerChord - 1 ; i + + )
{
int note = chord . notes [ i ] ;
if ( note = = MPTChord : : noNote )
note = 0 ;
else
note + = 1 - CHORD_MIN ;
m_CbnNote [ i ] . SetCurSel ( note ) ;
}
UpdateKeyboard ( ) ;
}
void CChordEditor : : UpdateKeyboard ( )
{
MPTChord & chord = GetChord ( ) ;
const int baseNote = ( chord . key = = MPTChord : : relativeMode ) ? 0 : ( chord . key % 12 ) ;
for ( int i = CHORD_MIN ; i < CHORD_MAX ; i + + )
{
uint8 b = CKeyboardControl : : KEYFLAG_NORMAL ;
for ( const auto note : chord . notes )
{
if ( i = = note )
b | = CKeyboardControl : : KEYFLAG_REDDOT ;
}
if ( i = = baseNote )
b | = CKeyboardControl : : KEYFLAG_BRIGHTDOT ;
m_Keyboard . SetFlags ( i - CHORD_MIN , b ) ;
}
m_Keyboard . InvalidateRect ( nullptr , FALSE ) ;
}
void CChordEditor : : OnBaseNoteChanged ( )
{
MPTChord & chord = GetChord ( ) ;
int basenote = static_cast < int > ( m_CbnBaseNote . GetItemData ( m_CbnBaseNote . GetCurSel ( ) ) ) ;
if ( basenote ! = MPTChord : : relativeMode )
basenote - = NOTE_MIN ;
chord . key = ( uint8 ) basenote ;
UpdateKeyboard ( ) ;
}
void CChordEditor : : OnNoteChanged ( int noteIndex )
{
MPTChord & chord = GetChord ( ) ;
int note = m_CbnNote [ noteIndex ] . GetCurSel ( ) ;
if ( note < 0 )
return ;
chord . notes [ noteIndex ] = static_cast < int8 > ( m_CbnNote [ noteIndex ] . GetItemData ( note ) ) ;
UpdateKeyboard ( ) ;
}
////////////////////////////////////////////////////////////////////////////////////////////
// Keyboard Split Settings (pattern editor)
BEGIN_MESSAGE_MAP ( CSplitKeyboardSettings , CDialog )
ON_CBN_SELCHANGE ( IDC_COMBO_OCTAVEMODIFIER , & CSplitKeyboardSettings : : OnOctaveModifierChanged )
END_MESSAGE_MAP ( )
void CSplitKeyboardSettings : : DoDataExchange ( CDataExchange * pDX )
{
CDialog : : DoDataExchange ( pDX ) ;
//{{AFX_DATA_MAP(CSplitKeyboadSettings)
DDX_Control ( pDX , IDC_COMBO_SPLITINSTRUMENT , m_CbnSplitInstrument ) ;
DDX_Control ( pDX , IDC_COMBO_SPLITNOTE , m_CbnSplitNote ) ;
DDX_Control ( pDX , IDC_COMBO_OCTAVEMODIFIER , m_CbnOctaveModifier ) ;
DDX_Control ( pDX , IDC_COMBO_SPLITVOLUME , m_CbnSplitVolume ) ;
//}}AFX_DATA_MAP
}
BOOL CSplitKeyboardSettings : : OnInitDialog ( )
{
if ( sndFile . GetpModDoc ( ) = = nullptr )
return TRUE ;
CDialog : : OnInitDialog ( ) ;
CString s ;
// Split Notes
AppendNotesToControl ( m_CbnSplitNote , sndFile . GetModSpecifications ( ) . noteMin , sndFile . GetModSpecifications ( ) . noteMax ) ;
m_CbnSplitNote . SetCurSel ( m_Settings . splitNote - ( sndFile . GetModSpecifications ( ) . noteMin - NOTE_MIN ) ) ;
// Octave modifier
m_CbnOctaveModifier . SetRedraw ( FALSE ) ;
m_CbnSplitVolume . InitStorage ( SplitKeyboardSettings : : splitOctaveRange * 2 + 1 , 9 ) ;
for ( int i = - SplitKeyboardSettings : : splitOctaveRange ; i < SplitKeyboardSettings : : splitOctaveRange + 1 ; i + + )
{
s . Format ( i < 0 ? _T ( " Octave -%d " ) : i > 0 ? _T ( " Octave +%d " ) : _T ( " No Change " ) , std : : abs ( i ) ) ;
int n = m_CbnOctaveModifier . AddString ( s ) ;
m_CbnOctaveModifier . SetItemData ( n , i ) ;
}
m_CbnOctaveModifier . SetRedraw ( TRUE ) ;
m_CbnOctaveModifier . SetCurSel ( m_Settings . octaveModifier + SplitKeyboardSettings : : splitOctaveRange ) ;
CheckDlgButton ( IDC_PATTERN_OCTAVELINK , ( m_Settings . octaveLink & & m_Settings . octaveModifier ! = 0 ) ? BST_CHECKED : BST_UNCHECKED ) ;
// Volume
m_CbnSplitVolume . SetRedraw ( FALSE ) ;
m_CbnSplitVolume . InitStorage ( 65 , 4 ) ;
m_CbnSplitVolume . AddString ( _T ( " No Change " ) ) ;
m_CbnSplitVolume . SetItemData ( 0 , 0 ) ;
for ( int i = 1 ; i < = 64 ; i + + )
{
s . Format ( _T ( " %d " ) , i ) ;
int n = m_CbnSplitVolume . AddString ( s ) ;
m_CbnSplitVolume . SetItemData ( n , i ) ;
}
m_CbnSplitVolume . SetRedraw ( TRUE ) ;
m_CbnSplitVolume . SetCurSel ( m_Settings . splitVolume ) ;
// Instruments
m_CbnSplitInstrument . SetRedraw ( FALSE ) ;
m_CbnSplitInstrument . InitStorage ( 1 + ( sndFile . GetNumInstruments ( ) ? sndFile . GetNumInstruments ( ) : sndFile . GetNumSamples ( ) ) , 16 ) ;
m_CbnSplitInstrument . SetItemData ( m_CbnSplitInstrument . AddString ( _T ( " No Change " ) ) , 0 ) ;
if ( sndFile . GetNumInstruments ( ) )
{
for ( INSTRUMENTINDEX nIns = 1 ; nIns < = sndFile . GetNumInstruments ( ) ; nIns + + )
{
if ( sndFile . Instruments [ nIns ] = = nullptr )
continue ;
CString displayName = sndFile . GetpModDoc ( ) - > GetPatternViewInstrumentName ( nIns ) ;
int n = m_CbnSplitInstrument . AddString ( displayName ) ;
m_CbnSplitInstrument . SetItemData ( n , nIns ) ;
}
} else
{
for ( SAMPLEINDEX nSmp = 1 ; nSmp < = sndFile . GetNumSamples ( ) ; nSmp + + )
{
if ( sndFile . GetSample ( nSmp ) . HasSampleData ( ) )
{
s . Format ( _T ( " %02d: " ) , nSmp ) ;
s + = mpt : : ToCString ( sndFile . GetCharsetInternal ( ) , sndFile . m_szNames [ nSmp ] ) ;
int n = m_CbnSplitInstrument . AddString ( s ) ;
m_CbnSplitInstrument . SetItemData ( n , nSmp ) ;
}
}
}
m_CbnSplitInstrument . SetRedraw ( TRUE ) ;
m_CbnSplitInstrument . SetCurSel ( m_Settings . splitInstrument ) ;
return TRUE ;
}
void CSplitKeyboardSettings : : OnOK ( )
{
CDialog : : OnOK ( ) ;
m_Settings . splitNote = static_cast < ModCommand : : NOTE > ( m_CbnSplitNote . GetItemData ( m_CbnSplitNote . GetCurSel ( ) ) - 1 ) ;
m_Settings . octaveModifier = m_CbnOctaveModifier . GetCurSel ( ) - SplitKeyboardSettings : : splitOctaveRange ;
m_Settings . octaveLink = ( IsDlgButtonChecked ( IDC_PATTERN_OCTAVELINK ) ! = BST_UNCHECKED ) ;
m_Settings . splitVolume = static_cast < ModCommand : : VOL > ( m_CbnSplitVolume . GetCurSel ( ) ) ;
m_Settings . splitInstrument = static_cast < ModCommand : : INSTR > ( m_CbnSplitInstrument . GetItemData ( m_CbnSplitInstrument . GetCurSel ( ) ) ) ;
}
void CSplitKeyboardSettings : : OnCancel ( )
{
CDialog : : OnCancel ( ) ;
}
void CSplitKeyboardSettings : : OnOctaveModifierChanged ( )
{
CheckDlgButton ( IDC_PATTERN_OCTAVELINK , ( m_CbnOctaveModifier . GetCurSel ( ) ! = 9 ) ? BST_CHECKED : BST_UNCHECKED ) ;
}
/////////////////////////////////////////////////////////////////////////
// Show channel properties from pattern editor
BEGIN_MESSAGE_MAP ( QuickChannelProperties , CDialog )
ON_WM_HSCROLL ( ) // Sliders
ON_WM_ACTIVATE ( ) // Catch Window focus change
ON_EN_UPDATE ( IDC_EDIT1 , & QuickChannelProperties : : OnVolChanged )
ON_EN_UPDATE ( IDC_EDIT2 , & QuickChannelProperties : : OnPanChanged )
ON_EN_UPDATE ( IDC_EDIT3 , & QuickChannelProperties : : OnNameChanged )
ON_COMMAND ( IDC_CHECK1 , & QuickChannelProperties : : OnMuteChanged )
ON_COMMAND ( IDC_CHECK2 , & QuickChannelProperties : : OnSurroundChanged )
ON_COMMAND ( IDC_BUTTON1 , & QuickChannelProperties : : OnPrevChannel )
ON_COMMAND ( IDC_BUTTON2 , & QuickChannelProperties : : OnNextChannel )
ON_COMMAND ( IDC_BUTTON3 , & QuickChannelProperties : : OnChangeColor )
ON_COMMAND ( IDC_BUTTON4 , & QuickChannelProperties : : OnChangeColor )
ON_COMMAND ( IDC_BUTTON5 , & QuickChannelProperties : : OnPickPrevColor )
ON_COMMAND ( IDC_BUTTON6 , & QuickChannelProperties : : OnPickNextColor )
ON_MESSAGE ( WM_MOD_KEYCOMMAND , & QuickChannelProperties : : OnCustomKeyMsg )
ON_NOTIFY_EX_RANGE ( TTN_NEEDTEXT , 0 , 0xFFFF , & QuickChannelProperties : : OnToolTipText )
END_MESSAGE_MAP ( )
void QuickChannelProperties : : DoDataExchange ( CDataExchange * pDX )
{
DDX_Control ( pDX , IDC_SLIDER1 , m_volSlider ) ;
DDX_Control ( pDX , IDC_SLIDER2 , m_panSlider ) ;
DDX_Control ( pDX , IDC_SPIN1 , m_volSpin ) ;
DDX_Control ( pDX , IDC_SPIN2 , m_panSpin ) ;
DDX_Control ( pDX , IDC_EDIT3 , m_nameEdit ) ;
}
QuickChannelProperties : : ~ QuickChannelProperties ( )
{
DestroyWindow ( ) ;
}
void QuickChannelProperties : : OnActivate ( UINT nState , CWnd * , BOOL )
{
if ( nState = = WA_INACTIVE & & ! m_settingColor )
{
// Hide window when changing focus to another window.
m_visible = false ;
ShowWindow ( SW_HIDE ) ;
}
}
// Show channel properties for a given channel at a given screen position.
void QuickChannelProperties : : Show ( CModDoc * modDoc , CHANNELINDEX chn , CPoint position )
{
if ( ! m_hWnd )
{
Create ( IDD_CHANNELSETTINGS , nullptr ) ;
EnableToolTips ( ) ;
m_colorBtn . SubclassDlgItem ( IDC_BUTTON4 , this ) ;
m_colorBtnPrev . SubclassDlgItem ( IDC_BUTTON5 , this ) ;
m_colorBtnNext . SubclassDlgItem ( IDC_BUTTON6 , this ) ;
m_volSlider . SetRange ( 0 , 64 ) ;
m_volSlider . SetTicFreq ( 8 ) ;
m_volSpin . SetRange ( 0 , 64 ) ;
m_panSlider . SetRange ( 0 , 64 ) ;
m_panSlider . SetTicFreq ( 8 ) ;
m_panSpin . SetRange ( 0 , 256 ) ;
m_nameEdit . SetFocus ( ) ;
}
m_document = modDoc ;
m_channel = chn ;
SetParent ( nullptr ) ;
// Center window around point where user clicked.
CRect rect , screenRect ;
GetWindowRect ( rect ) ;
: : GetWindowRect ( : : GetDesktopWindow ( ) , & screenRect ) ;
rect . MoveToXY (
Clamp ( static_cast < int > ( position . x ) - rect . Width ( ) / 2 , 0 , static_cast < int > ( screenRect . right ) - rect . Width ( ) ) ,
Clamp ( static_cast < int > ( position . y ) - rect . Height ( ) / 2 , 0 , static_cast < int > ( screenRect . bottom ) - rect . Height ( ) ) ) ;
MoveWindow ( rect ) ;
SetWindowText ( MPT_TFORMAT ( " Settings for Channel {} " ) ( chn + 1 ) . c_str ( ) ) ;
UpdateDisplay ( ) ;
const BOOL enablePan = ( m_document - > GetModType ( ) & ( MOD_TYPE_XM | MOD_TYPE_MOD ) ) ? FALSE : TRUE ;
const BOOL itOnly = ( m_document - > GetModType ( ) & ( MOD_TYPE_IT | MOD_TYPE_MPT ) ) ? TRUE : FALSE ;
// Volume controls
m_volSlider . EnableWindow ( itOnly ) ;
m_volSpin . EnableWindow ( itOnly ) ;
: : EnableWindow ( : : GetDlgItem ( m_hWnd , IDC_EDIT1 ) , itOnly ) ;
// Pan controls
m_panSlider . EnableWindow ( enablePan ) ;
m_panSpin . EnableWindow ( enablePan ) ;
: : EnableWindow ( : : GetDlgItem ( m_hWnd , IDC_EDIT2 ) , enablePan ) ;
: : EnableWindow ( : : GetDlgItem ( m_hWnd , IDC_CHECK2 ) , itOnly ) ;
// Channel name
m_nameEdit . EnableWindow ( ( m_document - > GetModType ( ) & ( MOD_TYPE_IT | MOD_TYPE_MPT | MOD_TYPE_XM ) ) ? TRUE : FALSE ) ;
ShowWindow ( SW_SHOW ) ;
m_visible = true ;
}
void QuickChannelProperties : : UpdateDisplay ( )
{
// Set up channel properties
m_visible = false ;
const ModChannelSettings & settings = m_document - > GetSoundFile ( ) . ChnSettings [ m_channel ] ;
SetDlgItemInt ( IDC_EDIT1 , settings . nVolume , FALSE ) ;
SetDlgItemInt ( IDC_EDIT2 , settings . nPan , FALSE ) ;
m_volSlider . SetPos ( settings . nVolume ) ;
m_panSlider . SetPos ( settings . nPan / 4u ) ;
CheckDlgButton ( IDC_CHECK1 , ( settings . dwFlags [ CHN_MUTE ] ) ? TRUE : FALSE ) ;
CheckDlgButton ( IDC_CHECK2 , ( settings . dwFlags [ CHN_SURROUND ] ) ? TRUE : FALSE ) ;
TCHAR description [ 16 ] ;
wsprintf ( description , _T ( " Channel %d: " ) , m_channel + 1 ) ;
SetDlgItemText ( IDC_STATIC_CHANNEL_NAME , description ) ;
m_nameEdit . LimitText ( MAX_CHANNELNAME - 1 ) ;
m_nameEdit . SetWindowText ( mpt : : ToCString ( m_document - > GetSoundFile ( ) . GetCharsetInternal ( ) , settings . szName ) ) ;
const bool isFirst = ( m_channel < = 0 ) , isLast = ( m_channel > = m_document - > GetNumChannels ( ) - 1 ) ;
m_colorBtn . SetColor ( settings . color ) ;
m_colorBtnPrev . EnableWindow ( isFirst ? FALSE : TRUE ) ;
if ( ! isFirst )
m_colorBtnPrev . SetColor ( m_document - > GetSoundFile ( ) . ChnSettings [ m_channel - 1 ] . color ) ;
m_colorBtnNext . EnableWindow ( isLast ? FALSE : TRUE ) ;
if ( ! isLast )
m_colorBtnNext . SetColor ( m_document - > GetSoundFile ( ) . ChnSettings [ m_channel + 1 ] . color ) ;
m_settingsChanged = false ;
m_visible = true ;
: : EnableWindow ( : : GetDlgItem ( m_hWnd , IDC_BUTTON1 ) , isFirst ? FALSE : TRUE ) ;
: : EnableWindow ( : : GetDlgItem ( m_hWnd , IDC_BUTTON2 ) , isLast ? FALSE : TRUE ) ;
}
void QuickChannelProperties : : PrepareUndo ( )
{
if ( ! m_settingsChanged )
{
// Backup old channel settings through pattern undo.
m_settingsChanged = true ;
m_document - > GetPatternUndo ( ) . PrepareChannelUndo ( m_channel , 1 , " Channel Settings " ) ;
}
}
void QuickChannelProperties : : OnVolChanged ( )
{
if ( ! m_visible )
{
return ;
}
uint16 volume = static_cast < uint16 > ( GetDlgItemInt ( IDC_EDIT1 ) ) ;
if ( volume > = 0 & & volume < = 64 )
{
PrepareUndo ( ) ;
m_document - > SetChannelGlobalVolume ( m_channel , volume ) ;
m_volSlider . SetPos ( volume ) ;
m_document - > UpdateAllViews ( nullptr , GeneralHint ( m_channel ) . Channels ( ) , this ) ;
}
}
void QuickChannelProperties : : OnPanChanged ( )
{
if ( ! m_visible )
{
return ;
}
uint16 panning = static_cast < uint16 > ( GetDlgItemInt ( IDC_EDIT2 ) ) ;
if ( panning > = 0 & & panning < = 256 )
{
PrepareUndo ( ) ;
m_document - > SetChannelDefaultPan ( m_channel , panning ) ;
m_panSlider . SetPos ( panning / 4u ) ;
m_document - > UpdateAllViews ( nullptr , GeneralHint ( m_channel ) . Channels ( ) , this ) ;
// Surround is forced off when changing pan, so uncheck the checkbox.
CheckDlgButton ( IDC_CHECK2 , BST_UNCHECKED ) ;
}
}
void QuickChannelProperties : : OnHScroll ( UINT , UINT , CScrollBar * bar )
{
if ( ! m_visible )
{
return ;
}
bool update = false ;
// Volume slider
if ( bar = = reinterpret_cast < CScrollBar * > ( & m_volSlider ) )
{
uint16 pos = static_cast < uint16 > ( m_volSlider . GetPos ( ) ) ;
PrepareUndo ( ) ;
if ( m_document - > SetChannelGlobalVolume ( m_channel , pos ) )
{
SetDlgItemInt ( IDC_EDIT1 , pos ) ;
update = true ;
}
}
// Pan slider
if ( bar = = reinterpret_cast < CScrollBar * > ( & m_panSlider ) )
{
uint16 pos = static_cast < uint16 > ( m_panSlider . GetPos ( ) ) ;
PrepareUndo ( ) ;
if ( m_document - > SetChannelDefaultPan ( m_channel , pos * 4u ) )
{
SetDlgItemInt ( IDC_EDIT2 , pos * 4u ) ;
CheckDlgButton ( IDC_CHECK2 , BST_UNCHECKED ) ;
update = true ;
}
}
if ( update )
{
m_document - > UpdateAllViews ( nullptr , GeneralHint ( m_channel ) . Channels ( ) , this ) ;
}
}
void QuickChannelProperties : : OnMuteChanged ( )
{
if ( ! m_visible )
{
return ;
}
m_document - > MuteChannel ( m_channel , IsDlgButtonChecked ( IDC_CHECK1 ) ! = BST_UNCHECKED ) ;
m_document - > UpdateAllViews ( nullptr , GeneralHint ( m_channel ) . Channels ( ) , this ) ;
}
void QuickChannelProperties : : OnSurroundChanged ( )
{
if ( ! m_visible )
{
return ;
}
PrepareUndo ( ) ;
m_document - > SurroundChannel ( m_channel , IsDlgButtonChecked ( IDC_CHECK2 ) ! = BST_UNCHECKED ) ;
m_document - > UpdateAllViews ( nullptr , GeneralHint ( m_channel ) . Channels ( ) , this ) ;
UpdateDisplay ( ) ;
}
void QuickChannelProperties : : OnNameChanged ( )
{
if ( ! m_visible )
{
return ;
}
ModChannelSettings & settings = m_document - > GetSoundFile ( ) . ChnSettings [ m_channel ] ;
CString newNameTmp ;
m_nameEdit . GetWindowText ( newNameTmp ) ;
std : : string newName = mpt : : ToCharset ( m_document - > GetSoundFile ( ) . GetCharsetInternal ( ) , newNameTmp ) ;
if ( newName ! = settings . szName )
{
PrepareUndo ( ) ;
settings . szName = newName ;
m_document - > SetModified ( ) ;
m_document - > UpdateAllViews ( nullptr , GeneralHint ( m_channel ) . Channels ( ) , this ) ;
}
}
void QuickChannelProperties : : OnChangeColor ( )
{
m_settingColor = true ;
if ( auto color = m_colorBtn . PickColor ( m_document - > GetSoundFile ( ) , m_channel ) ; color . has_value ( ) )
{
PrepareUndo ( ) ;
m_document - > GetSoundFile ( ) . ChnSettings [ m_channel ] . color = * color ;
if ( m_document - > SupportsChannelColors ( ) )
m_document - > SetModified ( ) ;
m_document - > UpdateAllViews ( nullptr , GeneralHint ( m_channel ) . Channels ( ) , this ) ;
}
m_settingColor = false ;
}
void QuickChannelProperties : : OnPickPrevColor ( )
{
if ( m_channel > 0 )
PickColorFromChannel ( m_channel - 1 ) ;
}
void QuickChannelProperties : : OnPickNextColor ( )
{
if ( m_channel < m_document - > GetNumChannels ( ) - 1 )
PickColorFromChannel ( m_channel + 1 ) ;
}
void QuickChannelProperties : : PickColorFromChannel ( CHANNELINDEX channel )
{
auto & channels = m_document - > GetSoundFile ( ) . ChnSettings ;
if ( channels [ channel ] . color ! = channels [ m_channel ] . color )
{
PrepareUndo ( ) ;
channels [ m_channel ] . color = channels [ channel ] . color ;
m_colorBtn . SetColor ( channels [ m_channel ] . color ) ;
if ( m_document - > SupportsChannelColors ( ) )
m_document - > SetModified ( ) ;
m_document - > UpdateAllViews ( nullptr , GeneralHint ( m_channel ) . Channels ( ) , this ) ;
}
}
void QuickChannelProperties : : OnPrevChannel ( )
{
if ( m_channel > 0 )
{
m_channel - - ;
UpdateDisplay ( ) ;
}
}
void QuickChannelProperties : : OnNextChannel ( )
{
if ( m_channel < m_document - > GetNumChannels ( ) - 1 )
{
m_channel + + ;
UpdateDisplay ( ) ;
}
}
BOOL QuickChannelProperties : : PreTranslateMessage ( MSG * pMsg )
{
if ( pMsg )
{
//We handle keypresses before Windows has a chance to handle them (for alt etc..)
if ( ( pMsg - > message = = WM_SYSKEYUP ) | | ( pMsg - > message = = WM_KEYUP ) | |
( pMsg - > message = = WM_SYSKEYDOWN ) | | ( pMsg - > message = = WM_KEYDOWN ) )
{
CInputHandler * ih = CMainFrame : : GetInputHandler ( ) ;
//Translate message manually
UINT nChar = static_cast < UINT > ( pMsg - > wParam ) ;
UINT nRepCnt = LOWORD ( pMsg - > lParam ) ;
UINT nFlags = HIWORD ( pMsg - > lParam ) ;
KeyEventType kT = ih - > GetKeyEventType ( nFlags ) ;
if ( ih - > KeyEvent ( kCtxChannelSettings , nChar , nRepCnt , nFlags , kT , this ) ! = kcNull )
{
return TRUE ; // Mapped to a command, no need to pass message on.
}
}
}
return CDialog : : PreTranslateMessage ( pMsg ) ;
}
LRESULT QuickChannelProperties : : OnCustomKeyMsg ( WPARAM wParam , LPARAM )
{
switch ( wParam )
{
case kcChnSettingsPrev :
OnPrevChannel ( ) ;
return wParam ;
case kcChnSettingsNext :
OnNextChannel ( ) ;
return wParam ;
case kcChnColorFromPrev :
OnPickPrevColor ( ) ;
return wParam ;
case kcChnColorFromNext :
OnPickNextColor ( ) ;
return wParam ;
case kcChnSettingsClose :
OnActivate ( WA_INACTIVE , nullptr , FALSE ) ;
return wParam ;
}
return kcNull ;
}
BOOL QuickChannelProperties : : OnToolTipText ( UINT , NMHDR * pNMHDR , LRESULT * pResult )
{
auto pTTT = reinterpret_cast < TOOLTIPTEXT * > ( pNMHDR ) ;
UINT_PTR id = pNMHDR - > idFrom ;
if ( pTTT - > uFlags & TTF_IDISHWND )
{
// idFrom is actually the HWND of the tool
id = static_cast < UINT_PTR > ( : : GetDlgCtrlID ( reinterpret_cast < HWND > ( id ) ) ) ;
}
mpt : : tstring text ;
CommandID cmd = kcNull ;
switch ( id )
{
case IDC_EDIT1 :
case IDC_SLIDER1 :
text = CModDoc : : LinearToDecibels ( m_document - > GetSoundFile ( ) . ChnSettings [ m_channel ] . nVolume , 64.0 ) ;
break ;
case IDC_EDIT2 :
case IDC_SLIDER2 :
text = CModDoc : : PanningToString ( m_document - > GetSoundFile ( ) . ChnSettings [ m_channel ] . nPan , 128 ) ;
break ;
case IDC_BUTTON1 :
text = _T ( " Previous Channel " ) ;
cmd = kcChnSettingsPrev ;
break ;
case IDC_BUTTON2 :
text = _T ( " Next Channel " ) ;
cmd = kcChnSettingsNext ;
break ;
case IDC_BUTTON5 :
text = _T ( " Take color from previous channel " ) ;
cmd = kcChnColorFromPrev ;
break ;
case IDC_BUTTON6 :
text = _T ( " Take color from next channel " ) ;
cmd = kcChnColorFromNext ;
break ;
default :
return FALSE ;
}
if ( cmd ! = kcNull )
{
auto keyText = CMainFrame : : GetInputHandler ( ) - > m_activeCommandSet - > GetKeyTextFromCommand ( cmd , 0 ) ;
if ( ! keyText . IsEmpty ( ) )
text + = MPT_TFORMAT ( " ({}) " ) ( keyText ) ;
}
mpt : : String : : WriteWinBuf ( pTTT - > szText ) = text ;
* pResult = 0 ;
2024-09-29 02:04:03 +00:00
// bring the tooltip window above other popup arch
2024-09-24 12:54:57 +00:00
: : SetWindowPos ( pNMHDR - > hwndFrom , HWND_TOP , 0 , 0 , 0 , 0 , SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOMOVE | SWP_NOOWNERZORDER ) ;
return TRUE ; // message was handled
}
OPENMPT_NAMESPACE_END