1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087 |
- /*
- * 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);
- // Update document & windows
- 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
|