2024-09-24 12:54:57 +00:00
/*
* ChannelManagerDlg . cpp
* - - - - - - - - - - - - - - - - - - - - -
* Purpose : Dialog class for moving , removing , managing channels
* Notes : ( currently none )
* Authors : OpenMPT Devs
* The OpenMPT source code is released under the BSD license . Read LICENSE for more details .
*/
# include "stdafx.h"
# include "Moddoc.h"
# include "Mainfrm.h"
# include "ChannelManagerDlg.h"
# include "../common/mptStringBuffer.h"
# include <functional>
OPENMPT_NAMESPACE_BEGIN
# define CM_NB_COLS 8
# define CM_BT_HEIGHT 22
///////////////////////////////////////////////////////////
// CChannelManagerDlg
BEGIN_MESSAGE_MAP ( CChannelManagerDlg , CDialog )
ON_WM_PAINT ( )
ON_WM_MOUSEMOVE ( )
ON_WM_LBUTTONUP ( )
ON_WM_LBUTTONDOWN ( )
ON_WM_RBUTTONUP ( )
ON_WM_RBUTTONDOWN ( )
ON_WM_MBUTTONDOWN ( )
ON_WM_CLOSE ( )
ON_COMMAND ( IDC_BUTTON1 , & CChannelManagerDlg : : OnApply )
ON_COMMAND ( IDC_BUTTON2 , & CChannelManagerDlg : : OnClose )
ON_COMMAND ( IDC_BUTTON3 , & CChannelManagerDlg : : OnSelectAll )
ON_COMMAND ( IDC_BUTTON4 , & CChannelManagerDlg : : OnInvert )
ON_COMMAND ( IDC_BUTTON5 , & CChannelManagerDlg : : OnAction1 )
ON_COMMAND ( IDC_BUTTON6 , & CChannelManagerDlg : : OnAction2 )
ON_COMMAND ( IDC_BUTTON7 , & CChannelManagerDlg : : OnStore )
ON_COMMAND ( IDC_BUTTON8 , & CChannelManagerDlg : : OnRestore )
ON_NOTIFY ( TCN_SELCHANGE , IDC_TAB1 , & CChannelManagerDlg : : OnTabSelchange )
ON_WM_LBUTTONDBLCLK ( )
ON_WM_RBUTTONDBLCLK ( )
END_MESSAGE_MAP ( )
CChannelManagerDlg * CChannelManagerDlg : : sharedInstance_ = nullptr ;
CChannelManagerDlg * CChannelManagerDlg : : sharedInstanceCreate ( )
{
try
{
if ( sharedInstance_ = = nullptr )
sharedInstance_ = new CChannelManagerDlg ( ) ;
} catch ( mpt : : out_of_memory e )
{
mpt : : delete_out_of_memory ( e ) ;
}
return sharedInstance_ ;
}
void CChannelManagerDlg : : SetDocument ( CModDoc * modDoc )
{
if ( modDoc ! = m_ModDoc )
{
m_ModDoc = modDoc ;
ResetState ( true , true , true , true , false ) ;
if ( m_show )
{
if ( m_ModDoc )
{
ResizeWindow ( ) ;
ShowWindow ( SW_SHOWNOACTIVATE ) ; // In case the window was hidden because no module was loaded
InvalidateRect ( m_drawableArea , FALSE ) ;
} else
{
ShowWindow ( SW_HIDE ) ;
}
}
}
}
bool CChannelManagerDlg : : IsDisplayed ( ) const
{
return m_show ;
}
void CChannelManagerDlg : : Update ( UpdateHint hint , CObject * pHint )
{
if ( ! m_hWnd | | ! m_show )
return ;
if ( ! hint . ToType < GeneralHint > ( ) . GetType ( ) [ HINT_MODCHANNELS | HINT_MODGENERAL | HINT_MODTYPE | HINT_MPTOPTIONS ] )
return ;
ResizeWindow ( ) ;
InvalidateRect ( nullptr , FALSE ) ;
if ( hint . ToType < GeneralHint > ( ) . GetType ( ) [ HINT_MODCHANNELS ] & & m_quickChannelProperties . m_hWnd & & pHint ! = & m_quickChannelProperties )
m_quickChannelProperties . UpdateDisplay ( ) ;
}
void CChannelManagerDlg : : Show ( )
{
if ( ! m_hWnd )
{
Create ( IDD_CHANNELMANAGER , nullptr ) ;
}
ResizeWindow ( ) ;
ShowWindow ( SW_SHOW ) ;
m_show = true ;
}
void CChannelManagerDlg : : Hide ( )
{
if ( m_hWnd ! = nullptr & & m_show )
{
ResetState ( true , true , true , true , true ) ;
ShowWindow ( SW_HIDE ) ;
m_show = false ;
}
}
CChannelManagerDlg : : CChannelManagerDlg ( )
: m_buttonHeight ( CM_BT_HEIGHT )
{
for ( CHANNELINDEX chn = 0 ; chn < MAX_BASECHANNELS ; chn + + )
{
pattern [ chn ] = chn ;
memory [ 0 ] [ chn ] = 0 ;
memory [ 1 ] [ chn ] = 0 ;
memory [ 2 ] [ chn ] = 0 ;
memory [ 3 ] [ chn ] = chn ;
}
}
CChannelManagerDlg : : ~ CChannelManagerDlg ( )
{
if ( this = = sharedInstance_ )
sharedInstance_ = nullptr ;
if ( m_bkgnd )
DeleteBitmap ( m_bkgnd ) ;
DestroyWindow ( ) ;
}
BOOL CChannelManagerDlg : : OnInitDialog ( )
{
CDialog : : OnInitDialog ( ) ;
HWND menu = : : GetDlgItem ( m_hWnd , IDC_TAB1 ) ;
TCITEM tie ;
tie . mask = TCIF_TEXT | TCIF_IMAGE ;
tie . iImage = - 1 ;
tie . pszText = const_cast < LPTSTR > ( _T ( " Solo/Mute " ) ) ;
TabCtrl_InsertItem ( menu , kSoloMute , & tie ) ;
tie . pszText = const_cast < LPTSTR > ( _T ( " Record select " ) ) ;
TabCtrl_InsertItem ( menu , kRecordSelect , & tie ) ;
tie . pszText = const_cast < LPTSTR > ( _T ( " Plugins " ) ) ;
TabCtrl_InsertItem ( menu , kPluginState , & tie ) ;
tie . pszText = const_cast < LPTSTR > ( _T ( " Reorder/Remove " ) ) ;
TabCtrl_InsertItem ( menu , kReorderRemove , & tie ) ;
m_currentTab = kSoloMute ;
m_buttonHeight = MulDiv ( CM_BT_HEIGHT , Util : : GetDPIy ( m_hWnd ) , 96 ) ;
: : ShowWindow ( : : GetDlgItem ( m_hWnd , IDC_BUTTON1 ) , SW_HIDE ) ;
return TRUE ;
}
void CChannelManagerDlg : : OnApply ( )
{
if ( ! m_ModDoc ) return ;
CHANNELINDEX numChannels , newMemory [ 4 ] [ MAX_BASECHANNELS ] ;
std : : vector < CHANNELINDEX > newChnOrder ;
newChnOrder . reserve ( m_ModDoc - > GetNumChannels ( ) ) ;
// Count new number of channels, copy pattern pointers & manager internal store memory
numChannels = 0 ;
for ( CHANNELINDEX chn = 0 ; chn < m_ModDoc - > GetNumChannels ( ) ; chn + + )
{
if ( ! removed [ pattern [ chn ] ] )
{
newMemory [ 0 ] [ numChannels ] = memory [ 0 ] [ numChannels ] ;
newMemory [ 1 ] [ numChannels ] = memory [ 1 ] [ numChannels ] ;
newMemory [ 2 ] [ numChannels ] = memory [ 2 ] [ numChannels ] ;
newChnOrder . push_back ( pattern [ chn ] ) ;
numChannels + + ;
}
}
BeginWaitCursor ( ) ;
//Creating new order-vector for ReArrangeChannels.
CriticalSection cs ;
if ( m_ModDoc - > ReArrangeChannels ( newChnOrder ) ! = numChannels )
{
cs . Leave ( ) ;
EndWaitCursor ( ) ;
return ;
}
// Update manager internal store memory
for ( CHANNELINDEX chn = 0 ; chn < numChannels ; chn + + )
{
CHANNELINDEX newChn = newChnOrder [ chn ] ;
if ( chn ! = newChn )
{
memory [ 0 ] [ chn ] = newMemory [ 0 ] [ newChn ] ;
memory [ 1 ] [ chn ] = newMemory [ 1 ] [ newChn ] ;
memory [ 2 ] [ chn ] = newMemory [ 2 ] [ newChn ] ;
}
memory [ 3 ] [ chn ] = chn ;
}
cs . Leave ( ) ;
EndWaitCursor ( ) ;
ResetState ( true , true , true , true , true ) ;
2024-09-29 02:04:03 +00:00
// Update document & arch
2024-09-24 12:54:57 +00:00
m_ModDoc - > SetModified ( ) ;
m_ModDoc - > UpdateAllViews ( nullptr , GeneralHint ( ) . Channels ( ) . ModType ( ) , this ) ; //refresh channel headers
// Redraw channel manager window
ResizeWindow ( ) ;
InvalidateRect ( nullptr , FALSE ) ;
}
void CChannelManagerDlg : : OnClose ( )
{
if ( m_bkgnd ) DeleteBitmap ( m_bkgnd ) ;
ResetState ( true , true , true , true , true ) ;
m_bkgnd = nullptr ;
m_show = false ;
CDialog : : OnCancel ( ) ;
}
void CChannelManagerDlg : : OnSelectAll ( )
{
select . set ( ) ;
InvalidateRect ( m_drawableArea , FALSE ) ;
}
void CChannelManagerDlg : : OnInvert ( )
{
select . flip ( ) ;
InvalidateRect ( m_drawableArea , FALSE ) ;
}
void CChannelManagerDlg : : OnAction1 ( )
{
if ( m_ModDoc )
{
int nbOk = 0 , nbSelect = 0 ;
switch ( m_currentTab )
{
case kSoloMute :
for ( CHANNELINDEX chn = 0 ; chn < m_ModDoc - > GetNumChannels ( ) ; chn + + )
{
CHANNELINDEX sourceChn = pattern [ chn ] ;
if ( ! removed [ sourceChn ] )
{
if ( select [ sourceChn ] )
nbSelect + + ;
if ( select [ sourceChn ] & & m_ModDoc - > IsChannelSolo ( sourceChn ) )
nbOk + + ;
}
}
for ( CHANNELINDEX chn = 0 ; chn < m_ModDoc - > GetNumChannels ( ) ; chn + + )
{
CHANNELINDEX sourceChn = pattern [ chn ] ;
if ( select [ sourceChn ] & & ! removed [ sourceChn ] )
{
if ( m_ModDoc - > IsChannelMuted ( sourceChn ) )
m_ModDoc - > MuteChannel ( sourceChn , false ) ;
if ( nbSelect = = nbOk )
m_ModDoc - > SoloChannel ( sourceChn , ! m_ModDoc - > IsChannelSolo ( sourceChn ) ) ;
else
m_ModDoc - > SoloChannel ( sourceChn , true ) ;
}
else if ( ! m_ModDoc - > IsChannelSolo ( sourceChn ) )
m_ModDoc - > MuteChannel ( sourceChn , true ) ;
}
break ;
case kRecordSelect :
for ( CHANNELINDEX chn = 0 ; chn < m_ModDoc - > GetNumChannels ( ) ; chn + + )
{
CHANNELINDEX sourceChn = pattern [ chn ] ;
if ( ! removed [ sourceChn ] )
{
if ( select [ sourceChn ] )
nbSelect + + ;
if ( select [ sourceChn ] & & m_ModDoc - > GetChannelRecordGroup ( sourceChn ) = = RecordGroup : : Group1 )
nbOk + + ;
}
}
for ( CHANNELINDEX chn = 0 ; chn < m_ModDoc - > GetNumChannels ( ) ; chn + + )
{
CHANNELINDEX sourceChn = pattern [ chn ] ;
if ( ! removed [ sourceChn ] & & select [ sourceChn ] )
{
if ( select [ sourceChn ] & & nbSelect ! = nbOk & & m_ModDoc - > GetChannelRecordGroup ( sourceChn ) ! = RecordGroup : : Group1 )
m_ModDoc - > SetChannelRecordGroup ( sourceChn , RecordGroup : : Group1 ) ;
else if ( nbSelect = = nbOk )
m_ModDoc - > SetChannelRecordGroup ( sourceChn , RecordGroup : : NoGroup ) ;
}
}
break ;
case kPluginState :
for ( CHANNELINDEX chn = 0 ; chn < m_ModDoc - > GetNumChannels ( ) ; chn + + )
{
CHANNELINDEX sourceChn = pattern [ chn ] ;
if ( select [ sourceChn ] & & ! removed [ sourceChn ] )
m_ModDoc - > NoFxChannel ( sourceChn , false ) ;
}
break ;
case kReorderRemove :
for ( CHANNELINDEX chn = 0 ; chn < m_ModDoc - > GetNumChannels ( ) ; chn + + )
{
CHANNELINDEX sourceChn = pattern [ chn ] ;
if ( select [ sourceChn ] )
removed [ sourceChn ] = ! removed [ sourceChn ] ;
}
break ;
default :
break ;
}
ResetState ( ) ;
m_ModDoc - > UpdateAllViews ( nullptr , GeneralHint ( ) . Channels ( ) , this ) ;
InvalidateRect ( m_drawableArea , FALSE ) ;
}
}
void CChannelManagerDlg : : OnAction2 ( )
{
if ( m_ModDoc )
{
int nbOk = 0 , nbSelect = 0 ;
switch ( m_currentTab )
{
case kSoloMute :
for ( CHANNELINDEX chn = 0 ; chn < m_ModDoc - > GetNumChannels ( ) ; chn + + )
{
CHANNELINDEX sourceChn = pattern [ chn ] ;
if ( ! removed [ sourceChn ] )
{
if ( select [ sourceChn ] )
nbSelect + + ;
if ( select [ sourceChn ] & & m_ModDoc - > IsChannelMuted ( sourceChn ) )
nbOk + + ;
}
}
for ( CHANNELINDEX chn = 0 ; chn < m_ModDoc - > GetNumChannels ( ) ; chn + + )
{
CHANNELINDEX sourceChn = pattern [ chn ] ;
if ( select [ sourceChn ] & & ! removed [ sourceChn ] )
{
if ( m_ModDoc - > IsChannelSolo ( sourceChn ) )
m_ModDoc - > SoloChannel ( sourceChn , false ) ;
if ( nbSelect = = nbOk )
m_ModDoc - > MuteChannel ( sourceChn , ! m_ModDoc - > IsChannelMuted ( sourceChn ) ) ;
else
m_ModDoc - > MuteChannel ( sourceChn , true ) ;
}
}
break ;
case kRecordSelect :
for ( CHANNELINDEX chn = 0 ; chn < m_ModDoc - > GetNumChannels ( ) ; chn + + )
{
CHANNELINDEX sourceChn = pattern [ chn ] ;
if ( ! removed [ sourceChn ] )
{
if ( select [ sourceChn ] )
nbSelect + + ;
if ( select [ sourceChn ] & & m_ModDoc - > GetChannelRecordGroup ( sourceChn ) = = RecordGroup : : Group2 )
nbOk + + ;
}
}
for ( CHANNELINDEX chn = 0 ; chn < m_ModDoc - > GetNumChannels ( ) ; chn + + )
{
CHANNELINDEX sourceChn = pattern [ chn ] ;
if ( ! removed [ sourceChn ] & & select [ sourceChn ] )
{
if ( select [ sourceChn ] & & nbSelect ! = nbOk & & m_ModDoc - > GetChannelRecordGroup ( sourceChn ) ! = RecordGroup : : Group2 )
m_ModDoc - > SetChannelRecordGroup ( sourceChn , RecordGroup : : Group2 ) ;
else if ( nbSelect = = nbOk )
m_ModDoc - > SetChannelRecordGroup ( sourceChn , RecordGroup : : NoGroup ) ;
}
}
break ;
case kPluginState :
for ( CHANNELINDEX chn = 0 ; chn < m_ModDoc - > GetNumChannels ( ) ; chn + + )
{
CHANNELINDEX sourceChn = pattern [ chn ] ;
if ( select [ sourceChn ] & & ! removed [ sourceChn ] )
m_ModDoc - > NoFxChannel ( sourceChn , true ) ;
}
break ;
case kReorderRemove :
ResetState ( false , false , false , false , true ) ;
break ;
default :
break ;
}
if ( m_currentTab ! = 3 ) ResetState ( ) ;
m_ModDoc - > UpdateAllViews ( nullptr , GeneralHint ( ) . Channels ( ) , this ) ;
InvalidateRect ( m_drawableArea , FALSE ) ;
}
}
void CChannelManagerDlg : : OnStore ( void )
{
if ( ! m_show | | m_ModDoc = = nullptr )
{
return ;
}
switch ( m_currentTab )
{
case kSoloMute :
for ( CHANNELINDEX chn = 0 ; chn < m_ModDoc - > GetNumChannels ( ) ; chn + + )
{
CHANNELINDEX sourceChn = pattern [ chn ] ;
memory [ 0 ] [ sourceChn ] = 0 ;
if ( m_ModDoc - > IsChannelMuted ( sourceChn ) ) memory [ 0 ] [ chn ] | = 1 ;
if ( m_ModDoc - > IsChannelSolo ( sourceChn ) ) memory [ 0 ] [ chn ] | = 2 ;
}
break ;
case kRecordSelect :
for ( CHANNELINDEX chn = 0 ; chn < m_ModDoc - > GetNumChannels ( ) ; chn + + )
memory [ 1 ] [ chn ] = static_cast < uint8 > ( m_ModDoc - > GetChannelRecordGroup ( pattern [ chn ] ) ) ;
break ;
case kPluginState :
for ( CHANNELINDEX chn = 0 ; chn < m_ModDoc - > GetNumChannels ( ) ; chn + + )
memory [ 2 ] [ chn ] = m_ModDoc - > IsChannelNoFx ( pattern [ chn ] ) ;
break ;
case kReorderRemove :
for ( CHANNELINDEX chn = 0 ; chn < m_ModDoc - > GetNumChannels ( ) ; chn + + )
memory [ 3 ] [ chn ] = pattern [ chn ] ;
break ;
default :
break ;
}
}
void CChannelManagerDlg : : OnRestore ( void )
{
if ( ! m_show | | m_ModDoc = = nullptr )
{
return ;
}
switch ( m_currentTab )
{
case kSoloMute :
for ( CHANNELINDEX chn = 0 ; chn < m_ModDoc - > GetNumChannels ( ) ; chn + + )
{
CHANNELINDEX sourceChn = pattern [ chn ] ;
m_ModDoc - > MuteChannel ( sourceChn , ( memory [ 0 ] [ chn ] & 1 ) ! = 0 ) ;
m_ModDoc - > SoloChannel ( sourceChn , ( memory [ 0 ] [ chn ] & 2 ) ! = 0 ) ;
}
break ;
case kRecordSelect :
m_ModDoc - > ReinitRecordState ( true ) ;
for ( CHANNELINDEX chn = 0 ; chn < m_ModDoc - > GetNumChannels ( ) ; chn + + )
{
m_ModDoc - > SetChannelRecordGroup ( chn , static_cast < RecordGroup > ( memory [ 1 ] [ chn ] ) ) ;
}
break ;
case kPluginState :
for ( CHANNELINDEX chn = 0 ; chn < m_ModDoc - > GetNumChannels ( ) ; chn + + )
m_ModDoc - > NoFxChannel ( pattern [ chn ] , memory [ 2 ] [ chn ] ! = 0 ) ;
break ;
case kReorderRemove :
for ( CHANNELINDEX chn = 0 ; chn < m_ModDoc - > GetNumChannels ( ) ; chn + + )
pattern [ chn ] = memory [ 3 ] [ chn ] ;
ResetState ( false , false , false , false , true ) ;
break ;
default :
break ;
}
if ( m_currentTab ! = 3 ) ResetState ( ) ;
m_ModDoc - > UpdateAllViews ( nullptr , GeneralHint ( ) . Channels ( ) , this ) ;
InvalidateRect ( m_drawableArea , FALSE ) ;
}
void CChannelManagerDlg : : OnTabSelchange ( NMHDR * /*header*/ , LRESULT * /*pResult*/ )
{
if ( ! m_show ) return ;
m_currentTab = static_cast < Tab > ( TabCtrl_GetCurFocus ( : : GetDlgItem ( m_hWnd , IDC_TAB1 ) ) ) ;
switch ( m_currentTab )
{
case kSoloMute :
SetDlgItemText ( IDC_BUTTON5 , _T ( " Solo " ) ) ;
SetDlgItemText ( IDC_BUTTON6 , _T ( " Mute " ) ) ;
: : ShowWindow ( : : GetDlgItem ( m_hWnd , IDC_BUTTON5 ) , SW_SHOW ) ;
: : ShowWindow ( : : GetDlgItem ( m_hWnd , IDC_BUTTON6 ) , SW_SHOW ) ;
: : ShowWindow ( : : GetDlgItem ( m_hWnd , IDC_BUTTON1 ) , SW_HIDE ) ;
break ;
case kRecordSelect :
SetDlgItemText ( IDC_BUTTON5 , _T ( " Instrument 1 " ) ) ;
SetDlgItemText ( IDC_BUTTON6 , _T ( " Instrument 2 " ) ) ;
: : ShowWindow ( : : GetDlgItem ( m_hWnd , IDC_BUTTON5 ) , SW_SHOW ) ;
: : ShowWindow ( : : GetDlgItem ( m_hWnd , IDC_BUTTON6 ) , SW_SHOW ) ;
: : ShowWindow ( : : GetDlgItem ( m_hWnd , IDC_BUTTON1 ) , SW_HIDE ) ;
break ;
case kPluginState :
SetDlgItemText ( IDC_BUTTON5 , _T ( " Enable FX " ) ) ;
SetDlgItemText ( IDC_BUTTON6 , _T ( " Disable FX " ) ) ;
: : ShowWindow ( : : GetDlgItem ( m_hWnd , IDC_BUTTON5 ) , SW_SHOW ) ;
: : ShowWindow ( : : GetDlgItem ( m_hWnd , IDC_BUTTON6 ) , SW_SHOW ) ;
: : ShowWindow ( : : GetDlgItem ( m_hWnd , IDC_BUTTON1 ) , SW_HIDE ) ;
break ;
case kReorderRemove :
SetDlgItemText ( IDC_BUTTON5 , _T ( " Remove " ) ) ;
SetDlgItemText ( IDC_BUTTON6 , _T ( " Cancel All " ) ) ;
: : ShowWindow ( : : GetDlgItem ( m_hWnd , IDC_BUTTON5 ) , SW_SHOW ) ;
: : ShowWindow ( : : GetDlgItem ( m_hWnd , IDC_BUTTON6 ) , SW_SHOW ) ;
: : ShowWindow ( : : GetDlgItem ( m_hWnd , IDC_BUTTON1 ) , SW_SHOW ) ;
break ;
default :
break ;
}
InvalidateRect ( m_drawableArea , FALSE ) ;
}
void CChannelManagerDlg : : ResizeWindow ( )
{
if ( ! m_hWnd | | ! m_ModDoc ) return ;
const int dpiX = Util : : GetDPIx ( m_hWnd ) ;
const int dpiY = Util : : GetDPIy ( m_hWnd ) ;
m_buttonHeight = MulDiv ( CM_BT_HEIGHT , dpiY , 96 ) ;
CHANNELINDEX channels = m_ModDoc - > GetNumChannels ( ) ;
int lines = channels / CM_NB_COLS + ( channels % CM_NB_COLS ? 1 : 0 ) ;
CRect window ;
GetWindowRect ( window ) ;
CRect client ;
GetClientRect ( client ) ;
m_drawableArea = client ;
m_drawableArea . DeflateRect ( MulDiv ( 10 , dpiX , 96 ) , MulDiv ( 38 , dpiY , 96 ) , MulDiv ( 8 , dpiX , 96 ) , MulDiv ( 30 , dpiY , 96 ) ) ;
int chnSizeY = m_drawableArea . Height ( ) / lines ;
if ( chnSizeY ! = m_buttonHeight )
{
SetWindowPos ( nullptr , 0 , 0 , window . Width ( ) , window . Height ( ) + ( m_buttonHeight - chnSizeY ) * lines , SWP_NOMOVE | SWP_NOZORDER | SWP_NOREDRAW ) ;
GetClientRect ( client ) ;
// Move butttons to bottom of the window
for ( auto id : { IDC_BUTTON1 , IDC_BUTTON2 , IDC_BUTTON3 , IDC_BUTTON4 , IDC_BUTTON5 , IDC_BUTTON6 } )
{
CWnd * button = GetDlgItem ( id ) ;
if ( button ! = nullptr )
{
CRect btn ;
button - > GetClientRect ( btn ) ;
button - > MapWindowPoints ( this , btn ) ;
button - > SetWindowPos ( nullptr , btn . left , client . Height ( ) - btn . Height ( ) - MulDiv ( 3 , dpiY , 96 ) , 0 , 0 , SWP_NOSIZE | SWP_NOZORDER ) ;
}
}
if ( m_bkgnd )
{
DeleteObject ( m_bkgnd ) ;
m_bkgnd = nullptr ;
}
m_drawableArea = client ;
m_drawableArea . DeflateRect ( MulDiv ( 10 , dpiX , 96 ) , MulDiv ( 38 , dpiY , 96 ) , MulDiv ( 8 , dpiX , 96 ) , MulDiv ( 30 , dpiY , 96 ) ) ;
InvalidateRect ( nullptr , FALSE ) ;
}
}
void CChannelManagerDlg : : OnPaint ( )
{
if ( ! m_hWnd | | ! m_show | | m_ModDoc = = nullptr )
{
CDialog : : OnPaint ( ) ;
ShowWindow ( SW_HIDE ) ;
return ;
}
if ( IsIconic ( ) )
{
CDialog : : OnPaint ( ) ;
return ;
}
const int dpiX = Util : : GetDPIx ( m_hWnd ) ;
const int dpiY = Util : : GetDPIy ( m_hWnd ) ;
const CHANNELINDEX channels = m_ModDoc - > GetNumChannels ( ) ;
PAINTSTRUCT pDC ;
: : BeginPaint ( m_hWnd , & pDC ) ;
const CRect & rcPaint = pDC . rcPaint ;
const int chnSizeX = m_drawableArea . Width ( ) / CM_NB_COLS ;
const int chnSizeY = m_buttonHeight ;
if ( m_currentTab = = 3 & & m_moveRect & & m_bkgnd )
{
// Only draw channels to be moved around
HDC bdc = : : CreateCompatibleDC ( pDC . hdc ) ;
: : SelectObject ( bdc , m_bkgnd ) ;
: : BitBlt ( pDC . hdc , rcPaint . left , rcPaint . top , rcPaint . Width ( ) , rcPaint . Height ( ) , bdc , rcPaint . left , rcPaint . top , SRCCOPY ) ;
BLENDFUNCTION ftn ;
ftn . BlendOp = AC_SRC_OVER ;
ftn . BlendFlags = 0 ;
ftn . SourceConstantAlpha = 192 ;
ftn . AlphaFormat = 0 ;
for ( CHANNELINDEX chn = 0 ; chn < channels ; chn + + )
{
CHANNELINDEX sourceChn = pattern [ chn ] ;
if ( select [ sourceChn ] )
{
CRect btn = move [ sourceChn ] ;
btn . DeflateRect ( 3 , 3 , 0 , 0 ) ;
AlphaBlend ( pDC . hdc , btn . left + m_moveX - m_downX , btn . top + m_moveY - m_downY , btn . Width ( ) , btn . Height ( ) , bdc ,
btn . left , btn . top , btn . Width ( ) , btn . Height ( ) , ftn ) ;
}
}
: : SelectObject ( bdc , ( HBITMAP ) NULL ) ;
: : DeleteDC ( bdc ) ;
: : EndPaint ( m_hWnd , & pDC ) ;
return ;
}
CRect client ;
GetClientRect ( & client ) ;
HDC dc = : : CreateCompatibleDC ( pDC . hdc ) ;
if ( ! m_bkgnd )
m_bkgnd = : : CreateCompatibleBitmap ( pDC . hdc , client . Width ( ) , client . Height ( ) ) ;
HGDIOBJ oldBmp = : : SelectObject ( dc , m_bkgnd ) ;
HGDIOBJ oldFont = : : SelectObject ( dc , CMainFrame : : GetGUIFont ( ) ) ;
const auto dcBrush = GetStockBrush ( DC_BRUSH ) ;
client . SetRect ( client . left + MulDiv ( 2 , dpiX , 96 ) , client . top + MulDiv ( 32 , dpiY , 96 ) , client . right - MulDiv ( 2 , dpiX , 96 ) , client . bottom - MulDiv ( 24 , dpiY , 96 ) ) ;
// Draw background
{
const auto bgIntersected = client & pDC . rcPaint ; // In case of partial redraws, FillRect may still draw into areas that are not part of the redraw area and thus make some buttons disappear
: : FillRect ( dc , & pDC . rcPaint , GetSysColorBrush ( COLOR_BTNFACE ) ) ;
: : FillRect ( dc , & bgIntersected , GetSysColorBrush ( COLOR_HIGHLIGHT ) ) ;
: : SetDCBrushColor ( dc , RGB ( 20 , 20 , 20 ) ) ;
: : FrameRect ( dc , & client , dcBrush ) ;
}
client . SetRect ( client . left + 8 , client . top + 6 , client . right - 6 , client . bottom - 6 ) ;
const COLORREF highlight = GetSysColor ( COLOR_HIGHLIGHT ) , red = RGB ( 192 , 96 , 96 ) , green = RGB ( 96 , 192 , 96 ) , redBright = RGB ( 218 , 163 , 163 ) , greenBright = RGB ( 163 , 218 , 163 ) ;
const COLORREF brushColors [ ] = { highlight , green , red } ;
const COLORREF brushColorsBright [ ] = { highlight , greenBright , redBright } ;
const auto buttonFaceColor = GetSysColor ( COLOR_BTNFACE ) , windowColor = GetSysColor ( COLOR_WINDOW ) ;
uint32 col = 0 , row = 0 ;
const CSoundFile & sndFile = m_ModDoc - > GetSoundFile ( ) ;
CString s ;
for ( CHANNELINDEX chn = 0 ; chn < channels ; chn + + , col + + )
{
if ( col > = CM_NB_COLS )
{
col = 0 ;
row + + ;
}
const CHANNELINDEX sourceChn = pattern [ chn ] ;
const auto & chnSettings = sndFile . ChnSettings [ sourceChn ] ;
if ( ! chnSettings . szName . empty ( ) )
s = MPT_CFORMAT ( " {}: {} " ) ( sourceChn + 1 , mpt : : ToCString ( sndFile . GetCharsetInternal ( ) , sndFile . ChnSettings [ sourceChn ] . szName ) ) ;
else
s = MPT_CFORMAT ( " Channel {} " ) ( sourceChn + 1 ) ;
const int borderX = MulDiv ( 3 , dpiX , 96 ) , borderY = MulDiv ( 3 , dpiY , 96 ) ;
CRect btn ;
btn . left = client . left + col * chnSizeX + borderX ;
btn . right = btn . left + chnSizeX - borderX ;
btn . top = client . top + row * chnSizeY + borderY ;
btn . bottom = btn . top + chnSizeY - borderY ;
if ( ! CRect { } . IntersectRect ( & pDC . rcPaint , & btn ) )
continue ;
// Button
const bool activate = select [ sourceChn ] ;
const bool enable = ! removed [ sourceChn ] ;
auto btnAdjusted = btn ; // Without border
: : DrawEdge ( dc , btnAdjusted , enable ? EDGE_RAISED : EDGE_SUNKEN , BF_RECT | BF_MIDDLE | BF_ADJUST ) ;
if ( activate )
: : FillRect ( dc , btnAdjusted , GetSysColorBrush ( COLOR_WINDOW ) ) ;
if ( chnSettings . color ! = ModChannelSettings : : INVALID_COLOR )
{
// Channel color
const auto startColor = chnSettings . color ;
const auto endColor = activate ? windowColor : buttonFaceColor ;
const auto width = btnAdjusted . Width ( ) / 2 ;
auto rect = btnAdjusted ;
rect . right = rect . left + 1 ;
for ( int i = 0 ; i < width ; i + + )
{
auto blend = static_cast < double > ( i ) / width , blendInv = 1.0 - blend ;
auto blendColor = RGB ( mpt : : saturate_round < uint8 > ( GetRValue ( startColor ) * blendInv + GetRValue ( endColor ) * blend ) ,
mpt : : saturate_round < uint8 > ( GetGValue ( startColor ) * blendInv + GetGValue ( endColor ) * blend ) ,
mpt : : saturate_round < uint8 > ( GetBValue ( startColor ) * blendInv + GetBValue ( endColor ) * blend ) ) ;
: : SetDCBrushColor ( dc , blendColor ) ;
: : FillRect ( dc , & rect , dcBrush ) ;
rect . left + + ;
rect . right + + ;
}
}
// Text
{
auto rect = btnAdjusted ;
rect . left + = Util : : ScalePixels ( 9 , m_hWnd ) ;
rect . right - = Util : : ScalePixels ( 3 , m_hWnd ) ;
: : SetBkMode ( dc , TRANSPARENT ) ;
: : SetTextColor ( dc , GetSysColor ( enable | | activate ? COLOR_BTNTEXT : COLOR_GRAYTEXT ) ) ;
: : DrawText ( dc , s , - 1 , & rect , DT_RIGHT | DT_VCENTER | DT_SINGLELINE | DT_NOPREFIX ) ;
}
// Draw red/green markers
{
const int margin = Util : : ScalePixels ( 1 , m_hWnd ) ;
auto rect = btnAdjusted ;
rect . DeflateRect ( margin , margin ) ;
rect . right = rect . left + Util : : ScalePixels ( 7 , m_hWnd ) ;
const auto & brushes = activate ? brushColorsBright : brushColors ;
const auto redBrush = brushes [ 2 ] , greenBrush = brushes [ 1 ] ;
COLORREF color = 0 ;
switch ( m_currentTab )
{
case kSoloMute :
color = chnSettings . dwFlags [ CHN_MUTE ] ? redBrush : greenBrush ;
break ;
case kRecordSelect :
color = brushColors [ static_cast < size_t > ( m_ModDoc - > GetChannelRecordGroup ( sourceChn ) ) % std : : size ( brushColors ) ] ;
break ;
case kPluginState :
color = chnSettings . dwFlags [ CHN_NOFX ] ? redBrush : greenBrush ;
break ;
case kReorderRemove :
color = removed [ sourceChn ] ? redBrush : greenBrush ;
break ;
}
: : SetDCBrushColor ( dc , color ) ;
: : FillRect ( dc , rect , dcBrush ) ;
// Draw border around marker
: : SetDCBrushColor ( dc , RGB ( 20 , 20 , 20 ) ) ;
: : FrameRect ( dc , rect , dcBrush ) ;
}
}
: : BitBlt ( pDC . hdc , rcPaint . left , rcPaint . top , rcPaint . Width ( ) , rcPaint . Height ( ) , dc , rcPaint . left , rcPaint . top , SRCCOPY ) ;
: : SelectObject ( dc , oldFont ) ;
: : SelectObject ( dc , oldBmp ) ;
: : DeleteDC ( dc ) ;
: : EndPaint ( m_hWnd , & pDC ) ;
}
bool CChannelManagerDlg : : ButtonHit ( CPoint point , CHANNELINDEX * id , CRect * invalidate ) const
{
const CRect & client = m_drawableArea ;
if ( PtInRect ( client , point ) & & m_ModDoc ! = nullptr )
{
UINT nColns = CM_NB_COLS ;
int x = point . x - client . left ;
int y = point . y - client . top ;
int dx = client . Width ( ) / ( int ) nColns ;
int dy = m_buttonHeight ;
x = x / dx ;
y = y / dy ;
CHANNELINDEX n = static_cast < CHANNELINDEX > ( y * nColns + x ) ;
if ( n < m_ModDoc - > GetNumChannels ( ) )
{
if ( id ) * id = n ;
if ( invalidate )
{
invalidate - > left = client . left + x * dx ;
invalidate - > right = invalidate - > left + dx ;
invalidate - > top = client . top + y * dy ;
invalidate - > bottom = invalidate - > top + dy ;
}
return true ;
}
}
return false ;
}
void CChannelManagerDlg : : ResetState ( bool bSelection , bool bMove , bool bButton , bool bInternal , bool bOrder )
{
for ( CHANNELINDEX chn = 0 ; chn < MAX_BASECHANNELS ; chn + + )
{
if ( bSelection )
select [ pattern [ chn ] ] = false ;
if ( bButton )
state [ pattern [ chn ] ] = false ;
if ( bOrder )
{
pattern [ chn ] = chn ;
removed [ chn ] = false ;
}
}
if ( bMove | | bInternal )
{
m_leftButton = false ;
m_rightButton = false ;
}
if ( bMove ) m_moveRect = false ;
}
void CChannelManagerDlg : : OnMouseMove ( UINT nFlags , CPoint point )
{
if ( ! m_hWnd | | m_show = = false ) return ;
if ( ! m_leftButton & & ! m_rightButton )
{
m_moveX = point . x ;
m_moveY = point . y ;
return ;
}
MouseEvent ( nFlags , point , m_moveRect ? CM_BT_NONE : ( m_leftButton ? CM_BT_LEFT : CM_BT_RIGHT ) ) ;
}
void CChannelManagerDlg : : OnLButtonUp ( UINT /*nFlags*/ , CPoint point )
{
ReleaseCapture ( ) ;
if ( ! m_hWnd | | m_show = = false ) return ;
if ( m_moveRect & & m_ModDoc )
{
CHANNELINDEX dropChn = 0 ;
CRect dropRect ;
if ( ButtonHit ( point , & dropChn , & dropRect ) )
{
// Rearrange channels
const auto IsSelected = std : : bind ( & decltype ( select ) : : test , & select , std : : placeholders : : _1 ) ;
const auto numChannels = m_ModDoc - > GetNumChannels ( ) ;
if ( point . x > dropRect . left + dropRect . Width ( ) / 2 & & dropChn < numChannels )
dropChn + + ;
std : : vector < CHANNELINDEX > newOrder { pattern . begin ( ) , pattern . begin ( ) + numChannels } ;
// How many selected channels are there before the drop target?
// cppcheck false-positive
// cppcheck-suppress danglingTemporaryLifetime
const CHANNELINDEX selectedBeforeDropChn = static_cast < CHANNELINDEX > ( std : : count_if ( pattern . begin ( ) , pattern . begin ( ) + dropChn , IsSelected ) ) ;
dropChn - = selectedBeforeDropChn ;
// Remove all selected channels from the order
newOrder . erase ( std : : remove_if ( newOrder . begin ( ) , newOrder . end ( ) , IsSelected ) , newOrder . end ( ) ) ;
const CHANNELINDEX numSelected = static_cast < CHANNELINDEX > ( numChannels - newOrder . size ( ) ) ;
// Then insert them at the drop position
newOrder . insert ( newOrder . begin ( ) + dropChn , numSelected , PATTERNINDEX_INVALID ) ;
std : : copy_if ( pattern . begin ( ) , pattern . begin ( ) + numChannels , newOrder . begin ( ) + dropChn , IsSelected ) ;
std : : copy ( newOrder . begin ( ) , newOrder . begin ( ) + numChannels , pattern . begin ( ) ) ;
select . reset ( ) ;
} else
{
ResetState ( true , false , false , false , false ) ;
}
m_moveRect = false ;
InvalidateRect ( m_drawableArea , FALSE ) ;
if ( m_ModDoc ) m_ModDoc - > UpdateAllViews ( nullptr , GeneralHint ( ) . Channels ( ) , this ) ;
}
m_leftButton = false ;
for ( CHANNELINDEX chn : pattern )
state [ chn ] = false ;
}
void CChannelManagerDlg : : OnLButtonDown ( UINT nFlags , CPoint point )
{
if ( ! m_hWnd | | m_show = = false ) return ;
SetCapture ( ) ;
if ( ! ButtonHit ( point , nullptr , nullptr ) ) ResetState ( true , false , false , false ) ;
m_leftButton = true ;
m_buttonAction = kUndetermined ;
MouseEvent ( nFlags , point , CM_BT_LEFT ) ;
m_downX = point . x ;
m_downY = point . y ;
}
void CChannelManagerDlg : : OnRButtonUp ( UINT /*nFlags*/ , CPoint /*point*/ )
{
ReleaseCapture ( ) ;
if ( ! m_hWnd | | m_show = = false ) return ;
ResetState ( false , false , true , false ) ;
m_rightButton = false ;
}
void CChannelManagerDlg : : OnRButtonDown ( UINT nFlags , CPoint point )
{
if ( ! m_hWnd | | m_show = = false ) return ;
SetCapture ( ) ;
m_rightButton = true ;
m_buttonAction = kUndetermined ;
if ( m_moveRect )
{
ResetState ( true , true , false , false , false ) ;
InvalidateRect ( m_drawableArea , FALSE ) ;
} else
{
MouseEvent ( nFlags , point , CM_BT_RIGHT ) ;
m_downX = point . x ;
m_downY = point . y ;
}
}
void CChannelManagerDlg : : OnMButtonDown ( UINT /*nFlags*/ , CPoint point )
{
CHANNELINDEX chn ;
CRect rect ;
if ( m_ModDoc ! = nullptr & & ( m_ModDoc - > GetModType ( ) & ( MOD_TYPE_XM | MOD_TYPE_IT | MOD_TYPE_MPT ) ) & & ButtonHit ( point , & chn , & rect ) )
{
ClientToScreen ( & point ) ;
m_quickChannelProperties . Show ( m_ModDoc , pattern [ chn ] , point ) ;
}
}
void CChannelManagerDlg : : MouseEvent ( UINT nFlags , CPoint point , MouseButton button )
{
CHANNELINDEX n ;
CRect client , invalidate ;
bool hit = ButtonHit ( point , & n , & invalidate ) ;
if ( hit ) n = pattern [ n ] ;
m_moveX = point . x ;
m_moveY = point . y ;
if ( ! m_ModDoc ) return ;
if ( hit & & ! state [ n ] & & button ! = CM_BT_NONE )
{
if ( nFlags & MK_CONTROL )
{
if ( button = = CM_BT_LEFT )
{
if ( ! select [ n ] & & ! removed [ n ] ) move [ n ] = invalidate ;
select [ n ] = true ;
}
else if ( button = = CM_BT_RIGHT ) select [ n ] = false ;
}
else if ( ! removed [ n ] | | m_currentTab = = 3 )
{
switch ( m_currentTab )
{
case kSoloMute :
if ( button = = CM_BT_LEFT )
{
if ( m_buttonAction = = kUndetermined )
m_buttonAction = ( ! m_ModDoc - > IsChannelSolo ( n ) | | m_ModDoc - > IsChannelMuted ( n ) ) ? kAction1 : kAction2 ;
if ( m_buttonAction = = kAction1 )
{
m_ModDoc - > MuteChannel ( n , false ) ;
m_ModDoc - > SoloChannel ( n , true ) ;
for ( CHANNELINDEX chn = 0 ; chn < m_ModDoc - > GetNumChannels ( ) ; chn + + )
{
if ( chn ! = n )
m_ModDoc - > MuteChannel ( chn , true ) ;
}
invalidate = client = m_drawableArea ;
}
else m_ModDoc - > SoloChannel ( n , false ) ;
} else
{
if ( m_ModDoc - > IsChannelSolo ( n ) ) m_ModDoc - > SoloChannel ( n , false ) ;
if ( m_buttonAction = = kUndetermined )
m_buttonAction = m_ModDoc - > IsChannelMuted ( n ) ? kAction1 : kAction2 ;
m_ModDoc - > MuteChannel ( n , m_buttonAction = = kAction2 ) ;
}
m_ModDoc - > SetModified ( ) ;
m_ModDoc - > UpdateAllViews ( nullptr , GeneralHint ( n ) . Channels ( ) , this ) ;
break ;
case kRecordSelect :
{
auto rec = m_ModDoc - > GetChannelRecordGroup ( n ) ;
if ( m_buttonAction = = kUndetermined )
m_buttonAction = ( rec = = RecordGroup : : NoGroup | | rec ! = ( button = = CM_BT_LEFT ? RecordGroup : : Group1 : RecordGroup : : Group2 ) ) ? kAction1 : kAction2 ;
if ( m_buttonAction = = kAction1 & & button = = CM_BT_LEFT )
m_ModDoc - > SetChannelRecordGroup ( n , RecordGroup : : Group1 ) ;
else if ( m_buttonAction = = kAction1 & & button = = CM_BT_RIGHT )
m_ModDoc - > SetChannelRecordGroup ( n , RecordGroup : : Group2 ) ;
else
m_ModDoc - > SetChannelRecordGroup ( n , RecordGroup : : NoGroup ) ;
m_ModDoc - > UpdateAllViews ( nullptr , GeneralHint ( n ) . Channels ( ) , this ) ;
break ;
}
case kPluginState :
if ( button = = CM_BT_LEFT ) m_ModDoc - > NoFxChannel ( n , false ) ;
else m_ModDoc - > NoFxChannel ( n , true ) ;
m_ModDoc - > SetModified ( ) ;
m_ModDoc - > UpdateAllViews ( nullptr , GeneralHint ( n ) . Channels ( ) , this ) ;
break ;
case kReorderRemove :
if ( button = = CM_BT_LEFT )
{
move [ n ] = invalidate ;
select [ n ] = true ;
}
if ( button = = CM_BT_RIGHT )
{
if ( m_buttonAction = = kUndetermined )
m_buttonAction = removed [ n ] ? kAction1 : kAction2 ;
select [ n ] = false ;
removed [ n ] = ( m_buttonAction = = kAction2 ) ;
}
if ( select [ n ] | | button = = 0 )
{
m_moveRect = true ;
}
break ;
}
}
state [ n ] = false ;
InvalidateRect ( invalidate , FALSE ) ;
} else
{
InvalidateRect ( m_drawableArea , FALSE ) ;
}
}
void CChannelManagerDlg : : OnLButtonDblClk ( UINT nFlags , CPoint point )
{
OnLButtonDown ( nFlags , point ) ;
CDialog : : OnLButtonDblClk ( nFlags , point ) ;
}
void CChannelManagerDlg : : OnRButtonDblClk ( UINT nFlags , CPoint point )
{
OnRButtonDown ( nFlags , point ) ;
CDialog : : OnRButtonDblClk ( nFlags , point ) ;
}
OPENMPT_NAMESPACE_END