1
0

ChannelManagerDlg.cpp 30 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087
  1. /*
  2. * ChannelManagerDlg.cpp
  3. * ---------------------
  4. * Purpose: Dialog class for moving, removing, managing channels
  5. * Notes : (currently none)
  6. * Authors: OpenMPT Devs
  7. * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
  8. */
  9. #include "stdafx.h"
  10. #include "Moddoc.h"
  11. #include "Mainfrm.h"
  12. #include "ChannelManagerDlg.h"
  13. #include "../common/mptStringBuffer.h"
  14. #include <functional>
  15. OPENMPT_NAMESPACE_BEGIN
  16. #define CM_NB_COLS 8
  17. #define CM_BT_HEIGHT 22
  18. ///////////////////////////////////////////////////////////
  19. // CChannelManagerDlg
  20. BEGIN_MESSAGE_MAP(CChannelManagerDlg, CDialog)
  21. ON_WM_PAINT()
  22. ON_WM_MOUSEMOVE()
  23. ON_WM_LBUTTONUP()
  24. ON_WM_LBUTTONDOWN()
  25. ON_WM_RBUTTONUP()
  26. ON_WM_RBUTTONDOWN()
  27. ON_WM_MBUTTONDOWN()
  28. ON_WM_CLOSE()
  29. ON_COMMAND(IDC_BUTTON1, &CChannelManagerDlg::OnApply)
  30. ON_COMMAND(IDC_BUTTON2, &CChannelManagerDlg::OnClose)
  31. ON_COMMAND(IDC_BUTTON3, &CChannelManagerDlg::OnSelectAll)
  32. ON_COMMAND(IDC_BUTTON4, &CChannelManagerDlg::OnInvert)
  33. ON_COMMAND(IDC_BUTTON5, &CChannelManagerDlg::OnAction1)
  34. ON_COMMAND(IDC_BUTTON6, &CChannelManagerDlg::OnAction2)
  35. ON_COMMAND(IDC_BUTTON7, &CChannelManagerDlg::OnStore)
  36. ON_COMMAND(IDC_BUTTON8, &CChannelManagerDlg::OnRestore)
  37. ON_NOTIFY(TCN_SELCHANGE, IDC_TAB1, &CChannelManagerDlg::OnTabSelchange)
  38. ON_WM_LBUTTONDBLCLK()
  39. ON_WM_RBUTTONDBLCLK()
  40. END_MESSAGE_MAP()
  41. CChannelManagerDlg * CChannelManagerDlg::sharedInstance_ = nullptr;
  42. CChannelManagerDlg * CChannelManagerDlg::sharedInstanceCreate()
  43. {
  44. try
  45. {
  46. if(sharedInstance_ == nullptr)
  47. sharedInstance_ = new CChannelManagerDlg();
  48. } catch(mpt::out_of_memory e)
  49. {
  50. mpt::delete_out_of_memory(e);
  51. }
  52. return sharedInstance_;
  53. }
  54. void CChannelManagerDlg::SetDocument(CModDoc *modDoc)
  55. {
  56. if(modDoc != m_ModDoc)
  57. {
  58. m_ModDoc = modDoc;
  59. ResetState(true, true, true, true, false);
  60. if(m_show)
  61. {
  62. if(m_ModDoc)
  63. {
  64. ResizeWindow();
  65. ShowWindow(SW_SHOWNOACTIVATE); // In case the window was hidden because no module was loaded
  66. InvalidateRect(m_drawableArea, FALSE);
  67. } else
  68. {
  69. ShowWindow(SW_HIDE);
  70. }
  71. }
  72. }
  73. }
  74. bool CChannelManagerDlg::IsDisplayed() const
  75. {
  76. return m_show;
  77. }
  78. void CChannelManagerDlg::Update(UpdateHint hint, CObject* pHint)
  79. {
  80. if(!m_hWnd || !m_show)
  81. return;
  82. if(!hint.ToType<GeneralHint>().GetType()[HINT_MODCHANNELS | HINT_MODGENERAL | HINT_MODTYPE | HINT_MPTOPTIONS])
  83. return;
  84. ResizeWindow();
  85. InvalidateRect(nullptr, FALSE);
  86. if(hint.ToType<GeneralHint>().GetType()[HINT_MODCHANNELS] && m_quickChannelProperties.m_hWnd && pHint != &m_quickChannelProperties)
  87. m_quickChannelProperties.UpdateDisplay();
  88. }
  89. void CChannelManagerDlg::Show()
  90. {
  91. if(!m_hWnd)
  92. {
  93. Create(IDD_CHANNELMANAGER, nullptr);
  94. }
  95. ResizeWindow();
  96. ShowWindow(SW_SHOW);
  97. m_show = true;
  98. }
  99. void CChannelManagerDlg::Hide()
  100. {
  101. if(m_hWnd != nullptr && m_show)
  102. {
  103. ResetState(true, true, true, true, true);
  104. ShowWindow(SW_HIDE);
  105. m_show = false;
  106. }
  107. }
  108. CChannelManagerDlg::CChannelManagerDlg()
  109. : m_buttonHeight(CM_BT_HEIGHT)
  110. {
  111. for(CHANNELINDEX chn = 0; chn < MAX_BASECHANNELS; chn++)
  112. {
  113. pattern[chn] = chn;
  114. memory[0][chn] = 0;
  115. memory[1][chn] = 0;
  116. memory[2][chn] = 0;
  117. memory[3][chn] = chn;
  118. }
  119. }
  120. CChannelManagerDlg::~CChannelManagerDlg()
  121. {
  122. if(this == sharedInstance_)
  123. sharedInstance_ = nullptr;
  124. if(m_bkgnd)
  125. DeleteBitmap(m_bkgnd);
  126. DestroyWindow();
  127. }
  128. BOOL CChannelManagerDlg::OnInitDialog()
  129. {
  130. CDialog::OnInitDialog();
  131. HWND menu = ::GetDlgItem(m_hWnd, IDC_TAB1);
  132. TCITEM tie;
  133. tie.mask = TCIF_TEXT | TCIF_IMAGE;
  134. tie.iImage = -1;
  135. tie.pszText = const_cast<LPTSTR>(_T("Solo/Mute"));
  136. TabCtrl_InsertItem(menu, kSoloMute, &tie);
  137. tie.pszText = const_cast<LPTSTR>(_T("Record select"));
  138. TabCtrl_InsertItem(menu, kRecordSelect, &tie);
  139. tie.pszText = const_cast<LPTSTR>(_T("Plugins"));
  140. TabCtrl_InsertItem(menu, kPluginState, &tie);
  141. tie.pszText = const_cast<LPTSTR>(_T("Reorder/Remove"));
  142. TabCtrl_InsertItem(menu, kReorderRemove, &tie);
  143. m_currentTab = kSoloMute;
  144. m_buttonHeight = MulDiv(CM_BT_HEIGHT, Util::GetDPIy(m_hWnd), 96);
  145. ::ShowWindow(::GetDlgItem(m_hWnd, IDC_BUTTON1), SW_HIDE);
  146. return TRUE;
  147. }
  148. void CChannelManagerDlg::OnApply()
  149. {
  150. if(!m_ModDoc) return;
  151. CHANNELINDEX numChannels, newMemory[4][MAX_BASECHANNELS];
  152. std::vector<CHANNELINDEX> newChnOrder;
  153. newChnOrder.reserve(m_ModDoc->GetNumChannels());
  154. // Count new number of channels, copy pattern pointers & manager internal store memory
  155. numChannels = 0;
  156. for(CHANNELINDEX chn = 0; chn < m_ModDoc->GetNumChannels(); chn++)
  157. {
  158. if(!removed[pattern[chn]])
  159. {
  160. newMemory[0][numChannels] = memory[0][numChannels];
  161. newMemory[1][numChannels] = memory[1][numChannels];
  162. newMemory[2][numChannels] = memory[2][numChannels];
  163. newChnOrder.push_back(pattern[chn]);
  164. numChannels++;
  165. }
  166. }
  167. BeginWaitCursor();
  168. //Creating new order-vector for ReArrangeChannels.
  169. CriticalSection cs;
  170. if(m_ModDoc->ReArrangeChannels(newChnOrder) != numChannels)
  171. {
  172. cs.Leave();
  173. EndWaitCursor();
  174. return;
  175. }
  176. // Update manager internal store memory
  177. for(CHANNELINDEX chn = 0; chn < numChannels; chn++)
  178. {
  179. CHANNELINDEX newChn = newChnOrder[chn];
  180. if(chn != newChn)
  181. {
  182. memory[0][chn] = newMemory[0][newChn];
  183. memory[1][chn] = newMemory[1][newChn];
  184. memory[2][chn] = newMemory[2][newChn];
  185. }
  186. memory[3][chn] = chn;
  187. }
  188. cs.Leave();
  189. EndWaitCursor();
  190. ResetState(true, true, true, true, true);
  191. // Update document & windows
  192. m_ModDoc->SetModified();
  193. m_ModDoc->UpdateAllViews(nullptr, GeneralHint().Channels().ModType(), this); //refresh channel headers
  194. // Redraw channel manager window
  195. ResizeWindow();
  196. InvalidateRect(nullptr, FALSE);
  197. }
  198. void CChannelManagerDlg::OnClose()
  199. {
  200. if(m_bkgnd) DeleteBitmap(m_bkgnd);
  201. ResetState(true, true, true, true, true);
  202. m_bkgnd = nullptr;
  203. m_show = false;
  204. CDialog::OnCancel();
  205. }
  206. void CChannelManagerDlg::OnSelectAll()
  207. {
  208. select.set();
  209. InvalidateRect(m_drawableArea, FALSE);
  210. }
  211. void CChannelManagerDlg::OnInvert()
  212. {
  213. select.flip();
  214. InvalidateRect(m_drawableArea, FALSE);
  215. }
  216. void CChannelManagerDlg::OnAction1()
  217. {
  218. if(m_ModDoc)
  219. {
  220. int nbOk = 0, nbSelect = 0;
  221. switch(m_currentTab)
  222. {
  223. case kSoloMute:
  224. for(CHANNELINDEX chn = 0; chn < m_ModDoc->GetNumChannels(); chn++)
  225. {
  226. CHANNELINDEX sourceChn = pattern[chn];
  227. if(!removed[sourceChn])
  228. {
  229. if(select[sourceChn])
  230. nbSelect++;
  231. if(select[sourceChn] && m_ModDoc->IsChannelSolo(sourceChn))
  232. nbOk++;
  233. }
  234. }
  235. for(CHANNELINDEX chn = 0; chn < m_ModDoc->GetNumChannels(); chn++)
  236. {
  237. CHANNELINDEX sourceChn = pattern[chn];
  238. if(select[sourceChn] && !removed[sourceChn])
  239. {
  240. if(m_ModDoc->IsChannelMuted(sourceChn))
  241. m_ModDoc->MuteChannel(sourceChn, false);
  242. if(nbSelect == nbOk)
  243. m_ModDoc->SoloChannel(sourceChn, !m_ModDoc->IsChannelSolo(sourceChn));
  244. else
  245. m_ModDoc->SoloChannel(sourceChn, true);
  246. }
  247. else if(!m_ModDoc->IsChannelSolo(sourceChn))
  248. m_ModDoc->MuteChannel(sourceChn, true);
  249. }
  250. break;
  251. case kRecordSelect:
  252. for(CHANNELINDEX chn = 0; chn < m_ModDoc->GetNumChannels(); chn++)
  253. {
  254. CHANNELINDEX sourceChn = pattern[chn];
  255. if(!removed[sourceChn])
  256. {
  257. if(select[sourceChn])
  258. nbSelect++;
  259. if(select[sourceChn] && m_ModDoc->GetChannelRecordGroup(sourceChn) == RecordGroup::Group1)
  260. nbOk++;
  261. }
  262. }
  263. for(CHANNELINDEX chn = 0; chn < m_ModDoc->GetNumChannels(); chn++)
  264. {
  265. CHANNELINDEX sourceChn = pattern[chn];
  266. if(!removed[sourceChn] && select[sourceChn])
  267. {
  268. if(select[sourceChn] && nbSelect != nbOk && m_ModDoc->GetChannelRecordGroup(sourceChn) != RecordGroup::Group1)
  269. m_ModDoc->SetChannelRecordGroup(sourceChn, RecordGroup::Group1);
  270. else if(nbSelect == nbOk)
  271. m_ModDoc->SetChannelRecordGroup(sourceChn, RecordGroup::NoGroup);
  272. }
  273. }
  274. break;
  275. case kPluginState:
  276. for(CHANNELINDEX chn = 0; chn < m_ModDoc->GetNumChannels(); chn++)
  277. {
  278. CHANNELINDEX sourceChn = pattern[chn];
  279. if(select[sourceChn] && !removed[sourceChn])
  280. m_ModDoc->NoFxChannel(sourceChn, false);
  281. }
  282. break;
  283. case kReorderRemove:
  284. for(CHANNELINDEX chn = 0; chn < m_ModDoc->GetNumChannels(); chn++)
  285. {
  286. CHANNELINDEX sourceChn = pattern[chn];
  287. if(select[sourceChn])
  288. removed[sourceChn] = !removed[sourceChn];
  289. }
  290. break;
  291. default:
  292. break;
  293. }
  294. ResetState();
  295. m_ModDoc->UpdateAllViews(nullptr, GeneralHint().Channels(), this);
  296. InvalidateRect(m_drawableArea, FALSE);
  297. }
  298. }
  299. void CChannelManagerDlg::OnAction2()
  300. {
  301. if(m_ModDoc)
  302. {
  303. int nbOk = 0, nbSelect = 0;
  304. switch(m_currentTab)
  305. {
  306. case kSoloMute:
  307. for(CHANNELINDEX chn = 0; chn < m_ModDoc->GetNumChannels(); chn++)
  308. {
  309. CHANNELINDEX sourceChn = pattern[chn];
  310. if(!removed[sourceChn])
  311. {
  312. if(select[sourceChn])
  313. nbSelect++;
  314. if(select[sourceChn] && m_ModDoc->IsChannelMuted(sourceChn))
  315. nbOk++;
  316. }
  317. }
  318. for(CHANNELINDEX chn = 0; chn < m_ModDoc->GetNumChannels(); chn++)
  319. {
  320. CHANNELINDEX sourceChn = pattern[chn];
  321. if(select[sourceChn] && !removed[sourceChn])
  322. {
  323. if(m_ModDoc->IsChannelSolo(sourceChn))
  324. m_ModDoc->SoloChannel(sourceChn, false);
  325. if(nbSelect == nbOk)
  326. m_ModDoc->MuteChannel(sourceChn, !m_ModDoc->IsChannelMuted(sourceChn));
  327. else
  328. m_ModDoc->MuteChannel(sourceChn, true);
  329. }
  330. }
  331. break;
  332. case kRecordSelect:
  333. for(CHANNELINDEX chn = 0; chn < m_ModDoc->GetNumChannels(); chn++)
  334. {
  335. CHANNELINDEX sourceChn = pattern[chn];
  336. if(!removed[sourceChn])
  337. {
  338. if(select[sourceChn])
  339. nbSelect++;
  340. if(select[sourceChn] && m_ModDoc->GetChannelRecordGroup(sourceChn) == RecordGroup::Group2)
  341. nbOk++;
  342. }
  343. }
  344. for(CHANNELINDEX chn = 0; chn < m_ModDoc->GetNumChannels(); chn++)
  345. {
  346. CHANNELINDEX sourceChn = pattern[chn];
  347. if(!removed[sourceChn] && select[sourceChn])
  348. {
  349. if(select[sourceChn] && nbSelect != nbOk && m_ModDoc->GetChannelRecordGroup(sourceChn) != RecordGroup::Group2)
  350. m_ModDoc->SetChannelRecordGroup(sourceChn, RecordGroup::Group2);
  351. else if(nbSelect == nbOk)
  352. m_ModDoc->SetChannelRecordGroup(sourceChn, RecordGroup::NoGroup);
  353. }
  354. }
  355. break;
  356. case kPluginState:
  357. for(CHANNELINDEX chn = 0; chn < m_ModDoc->GetNumChannels(); chn++)
  358. {
  359. CHANNELINDEX sourceChn = pattern[chn];
  360. if(select[sourceChn] && !removed[sourceChn])
  361. m_ModDoc->NoFxChannel(sourceChn, true);
  362. }
  363. break;
  364. case kReorderRemove:
  365. ResetState(false, false, false, false, true);
  366. break;
  367. default:
  368. break;
  369. }
  370. if(m_currentTab != 3) ResetState();
  371. m_ModDoc->UpdateAllViews(nullptr, GeneralHint().Channels(), this);
  372. InvalidateRect(m_drawableArea, FALSE);
  373. }
  374. }
  375. void CChannelManagerDlg::OnStore(void)
  376. {
  377. if(!m_show || m_ModDoc == nullptr)
  378. {
  379. return;
  380. }
  381. switch(m_currentTab)
  382. {
  383. case kSoloMute:
  384. for(CHANNELINDEX chn = 0; chn < m_ModDoc->GetNumChannels(); chn++)
  385. {
  386. CHANNELINDEX sourceChn = pattern[chn];
  387. memory[0][sourceChn] = 0;
  388. if(m_ModDoc->IsChannelMuted(sourceChn)) memory[0][chn] |= 1;
  389. if(m_ModDoc->IsChannelSolo(sourceChn)) memory[0][chn] |= 2;
  390. }
  391. break;
  392. case kRecordSelect:
  393. for(CHANNELINDEX chn = 0; chn < m_ModDoc->GetNumChannels(); chn++)
  394. memory[1][chn] = static_cast<uint8>(m_ModDoc->GetChannelRecordGroup(pattern[chn]));
  395. break;
  396. case kPluginState:
  397. for(CHANNELINDEX chn = 0; chn < m_ModDoc->GetNumChannels(); chn++)
  398. memory[2][chn] = m_ModDoc->IsChannelNoFx(pattern[chn]);
  399. break;
  400. case kReorderRemove:
  401. for(CHANNELINDEX chn = 0; chn < m_ModDoc->GetNumChannels(); chn++)
  402. memory[3][chn] = pattern[chn];
  403. break;
  404. default:
  405. break;
  406. }
  407. }
  408. void CChannelManagerDlg::OnRestore(void)
  409. {
  410. if(!m_show || m_ModDoc == nullptr)
  411. {
  412. return;
  413. }
  414. switch(m_currentTab)
  415. {
  416. case kSoloMute:
  417. for(CHANNELINDEX chn = 0; chn < m_ModDoc->GetNumChannels(); chn++)
  418. {
  419. CHANNELINDEX sourceChn = pattern[chn];
  420. m_ModDoc->MuteChannel(sourceChn, (memory[0][chn] & 1) != 0);
  421. m_ModDoc->SoloChannel(sourceChn, (memory[0][chn] & 2) != 0);
  422. }
  423. break;
  424. case kRecordSelect:
  425. m_ModDoc->ReinitRecordState(true);
  426. for(CHANNELINDEX chn = 0; chn < m_ModDoc->GetNumChannels(); chn++)
  427. {
  428. m_ModDoc->SetChannelRecordGroup(chn, static_cast<RecordGroup>(memory[1][chn]));
  429. }
  430. break;
  431. case kPluginState:
  432. for(CHANNELINDEX chn = 0; chn < m_ModDoc->GetNumChannels(); chn++)
  433. m_ModDoc->NoFxChannel(pattern[chn], memory[2][chn] != 0);
  434. break;
  435. case kReorderRemove:
  436. for(CHANNELINDEX chn = 0; chn < m_ModDoc->GetNumChannels(); chn++)
  437. pattern[chn] = memory[3][chn];
  438. ResetState(false, false, false, false, true);
  439. break;
  440. default:
  441. break;
  442. }
  443. if(m_currentTab != 3) ResetState();
  444. m_ModDoc->UpdateAllViews(nullptr, GeneralHint().Channels(), this);
  445. InvalidateRect(m_drawableArea, FALSE);
  446. }
  447. void CChannelManagerDlg::OnTabSelchange(NMHDR* /*header*/, LRESULT* /*pResult*/)
  448. {
  449. if(!m_show) return;
  450. m_currentTab = static_cast<Tab>(TabCtrl_GetCurFocus(::GetDlgItem(m_hWnd, IDC_TAB1)));
  451. switch(m_currentTab)
  452. {
  453. case kSoloMute:
  454. SetDlgItemText(IDC_BUTTON5, _T("Solo"));
  455. SetDlgItemText(IDC_BUTTON6, _T("Mute"));
  456. ::ShowWindow(::GetDlgItem(m_hWnd, IDC_BUTTON5),SW_SHOW);
  457. ::ShowWindow(::GetDlgItem(m_hWnd, IDC_BUTTON6),SW_SHOW);
  458. ::ShowWindow(::GetDlgItem(m_hWnd, IDC_BUTTON1),SW_HIDE);
  459. break;
  460. case kRecordSelect:
  461. SetDlgItemText(IDC_BUTTON5, _T("Instrument 1"));
  462. SetDlgItemText(IDC_BUTTON6, _T("Instrument 2"));
  463. ::ShowWindow(::GetDlgItem(m_hWnd, IDC_BUTTON5),SW_SHOW);
  464. ::ShowWindow(::GetDlgItem(m_hWnd, IDC_BUTTON6),SW_SHOW);
  465. ::ShowWindow(::GetDlgItem(m_hWnd, IDC_BUTTON1),SW_HIDE);
  466. break;
  467. case kPluginState:
  468. SetDlgItemText(IDC_BUTTON5, _T("Enable FX"));
  469. SetDlgItemText(IDC_BUTTON6, _T("Disable FX"));
  470. ::ShowWindow(::GetDlgItem(m_hWnd, IDC_BUTTON5),SW_SHOW);
  471. ::ShowWindow(::GetDlgItem(m_hWnd, IDC_BUTTON6),SW_SHOW);
  472. ::ShowWindow(::GetDlgItem(m_hWnd, IDC_BUTTON1),SW_HIDE);
  473. break;
  474. case kReorderRemove:
  475. SetDlgItemText(IDC_BUTTON5, _T("Remove"));
  476. SetDlgItemText(IDC_BUTTON6, _T("Cancel All"));
  477. ::ShowWindow(::GetDlgItem(m_hWnd, IDC_BUTTON5),SW_SHOW);
  478. ::ShowWindow(::GetDlgItem(m_hWnd, IDC_BUTTON6),SW_SHOW);
  479. ::ShowWindow(::GetDlgItem(m_hWnd, IDC_BUTTON1),SW_SHOW);
  480. break;
  481. default:
  482. break;
  483. }
  484. InvalidateRect(m_drawableArea, FALSE);
  485. }
  486. void CChannelManagerDlg::ResizeWindow()
  487. {
  488. if(!m_hWnd || !m_ModDoc) return;
  489. const int dpiX = Util::GetDPIx(m_hWnd);
  490. const int dpiY = Util::GetDPIy(m_hWnd);
  491. m_buttonHeight = MulDiv(CM_BT_HEIGHT, dpiY, 96);
  492. CHANNELINDEX channels = m_ModDoc->GetNumChannels();
  493. int lines = channels / CM_NB_COLS + (channels % CM_NB_COLS ? 1 : 0);
  494. CRect window;
  495. GetWindowRect(window);
  496. CRect client;
  497. GetClientRect(client);
  498. m_drawableArea = client;
  499. m_drawableArea.DeflateRect(MulDiv(10, dpiX, 96), MulDiv(38, dpiY, 96), MulDiv(8, dpiX, 96), MulDiv(30, dpiY, 96));
  500. int chnSizeY = m_drawableArea.Height() / lines;
  501. if(chnSizeY != m_buttonHeight)
  502. {
  503. SetWindowPos(nullptr, 0, 0, window.Width(), window.Height() + (m_buttonHeight - chnSizeY) * lines, SWP_NOMOVE | SWP_NOZORDER | SWP_NOREDRAW);
  504. GetClientRect(client);
  505. // Move butttons to bottom of the window
  506. for(auto id : { IDC_BUTTON1, IDC_BUTTON2, IDC_BUTTON3, IDC_BUTTON4, IDC_BUTTON5, IDC_BUTTON6 })
  507. {
  508. CWnd *button = GetDlgItem(id);
  509. if(button != nullptr)
  510. {
  511. CRect btn;
  512. button->GetClientRect(btn);
  513. button->MapWindowPoints(this, btn);
  514. button->SetWindowPos(nullptr, btn.left, client.Height() - btn.Height() - MulDiv(3, dpiY, 96), 0, 0, SWP_NOSIZE | SWP_NOZORDER);
  515. }
  516. }
  517. if(m_bkgnd)
  518. {
  519. DeleteObject(m_bkgnd);
  520. m_bkgnd = nullptr;
  521. }
  522. m_drawableArea = client;
  523. m_drawableArea.DeflateRect(MulDiv(10, dpiX, 96), MulDiv(38, dpiY, 96), MulDiv(8, dpiX, 96), MulDiv(30, dpiY, 96));
  524. InvalidateRect(nullptr, FALSE);
  525. }
  526. }
  527. void CChannelManagerDlg::OnPaint()
  528. {
  529. if(!m_hWnd || !m_show || m_ModDoc == nullptr)
  530. {
  531. CDialog::OnPaint();
  532. ShowWindow(SW_HIDE);
  533. return;
  534. }
  535. if(IsIconic())
  536. {
  537. CDialog::OnPaint();
  538. return;
  539. }
  540. const int dpiX = Util::GetDPIx(m_hWnd);
  541. const int dpiY = Util::GetDPIy(m_hWnd);
  542. const CHANNELINDEX channels = m_ModDoc->GetNumChannels();
  543. PAINTSTRUCT pDC;
  544. ::BeginPaint(m_hWnd, &pDC);
  545. const CRect &rcPaint = pDC.rcPaint;
  546. const int chnSizeX = m_drawableArea.Width() / CM_NB_COLS;
  547. const int chnSizeY = m_buttonHeight;
  548. if(m_currentTab == 3 && m_moveRect && m_bkgnd)
  549. {
  550. // Only draw channels to be moved around
  551. HDC bdc = ::CreateCompatibleDC(pDC.hdc);
  552. ::SelectObject(bdc, m_bkgnd);
  553. ::BitBlt(pDC.hdc, rcPaint.left, rcPaint.top, rcPaint.Width(), rcPaint.Height(), bdc, rcPaint.left, rcPaint.top, SRCCOPY);
  554. BLENDFUNCTION ftn;
  555. ftn.BlendOp = AC_SRC_OVER;
  556. ftn.BlendFlags = 0;
  557. ftn.SourceConstantAlpha = 192;
  558. ftn.AlphaFormat = 0;
  559. for(CHANNELINDEX chn = 0; chn < channels; chn++)
  560. {
  561. CHANNELINDEX sourceChn = pattern[chn];
  562. if(select[sourceChn])
  563. {
  564. CRect btn = move[sourceChn];
  565. btn.DeflateRect(3, 3, 0, 0);
  566. AlphaBlend(pDC.hdc, btn.left + m_moveX - m_downX, btn.top + m_moveY - m_downY, btn.Width(), btn.Height(), bdc,
  567. btn.left, btn.top, btn.Width(), btn.Height(), ftn);
  568. }
  569. }
  570. ::SelectObject(bdc, (HBITMAP)NULL);
  571. ::DeleteDC(bdc);
  572. ::EndPaint(m_hWnd, &pDC);
  573. return;
  574. }
  575. CRect client;
  576. GetClientRect(&client);
  577. HDC dc = ::CreateCompatibleDC(pDC.hdc);
  578. if(!m_bkgnd)
  579. m_bkgnd = ::CreateCompatibleBitmap(pDC.hdc, client.Width(), client.Height());
  580. HGDIOBJ oldBmp = ::SelectObject(dc, m_bkgnd);
  581. HGDIOBJ oldFont = ::SelectObject(dc, CMainFrame::GetGUIFont());
  582. const auto dcBrush = GetStockBrush(DC_BRUSH);
  583. 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));
  584. // Draw background
  585. {
  586. 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
  587. ::FillRect(dc, &pDC.rcPaint, GetSysColorBrush(COLOR_BTNFACE));
  588. ::FillRect(dc, &bgIntersected, GetSysColorBrush(COLOR_HIGHLIGHT));
  589. ::SetDCBrushColor(dc, RGB(20, 20, 20));
  590. ::FrameRect(dc, &client, dcBrush);
  591. }
  592. client.SetRect(client.left + 8,client.top + 6,client.right - 6,client.bottom - 6);
  593. 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);
  594. const COLORREF brushColors[] = { highlight, green, red };
  595. const COLORREF brushColorsBright[] = { highlight, greenBright, redBright };
  596. const auto buttonFaceColor = GetSysColor(COLOR_BTNFACE), windowColor = GetSysColor(COLOR_WINDOW);
  597. uint32 col = 0, row = 0;
  598. const CSoundFile &sndFile = m_ModDoc->GetSoundFile();
  599. CString s;
  600. for(CHANNELINDEX chn = 0; chn < channels; chn++, col++)
  601. {
  602. if(col >= CM_NB_COLS)
  603. {
  604. col = 0;
  605. row++;
  606. }
  607. const CHANNELINDEX sourceChn = pattern[chn];
  608. const auto &chnSettings = sndFile.ChnSettings[sourceChn];
  609. if(!chnSettings.szName.empty())
  610. s = MPT_CFORMAT("{}: {}")(sourceChn + 1, mpt::ToCString(sndFile.GetCharsetInternal(), sndFile.ChnSettings[sourceChn].szName));
  611. else
  612. s = MPT_CFORMAT("Channel {}")(sourceChn + 1);
  613. const int borderX = MulDiv(3, dpiX, 96), borderY = MulDiv(3, dpiY, 96);
  614. CRect btn;
  615. btn.left = client.left + col * chnSizeX + borderX;
  616. btn.right = btn.left + chnSizeX - borderX;
  617. btn.top = client.top + row * chnSizeY + borderY;
  618. btn.bottom = btn.top + chnSizeY - borderY;
  619. if(!CRect{}.IntersectRect(&pDC.rcPaint, &btn))
  620. continue;
  621. // Button
  622. const bool activate = select[sourceChn];
  623. const bool enable = !removed[sourceChn];
  624. auto btnAdjusted = btn; // Without border
  625. ::DrawEdge(dc, btnAdjusted, enable ? EDGE_RAISED : EDGE_SUNKEN, BF_RECT | BF_MIDDLE | BF_ADJUST);
  626. if(activate)
  627. ::FillRect(dc, btnAdjusted, GetSysColorBrush(COLOR_WINDOW));
  628. if(chnSettings.color != ModChannelSettings::INVALID_COLOR)
  629. {
  630. // Channel color
  631. const auto startColor = chnSettings.color;
  632. const auto endColor = activate ? windowColor : buttonFaceColor;
  633. const auto width = btnAdjusted.Width() / 2;
  634. auto rect = btnAdjusted;
  635. rect.right = rect.left + 1;
  636. for(int i = 0; i < width; i++)
  637. {
  638. auto blend = static_cast<double>(i) / width, blendInv = 1.0 - blend;
  639. auto blendColor = RGB(mpt::saturate_round<uint8>(GetRValue(startColor) * blendInv + GetRValue(endColor) * blend),
  640. mpt::saturate_round<uint8>(GetGValue(startColor) * blendInv + GetGValue(endColor) * blend),
  641. mpt::saturate_round<uint8>(GetBValue(startColor) * blendInv + GetBValue(endColor) * blend));
  642. ::SetDCBrushColor(dc, blendColor);
  643. ::FillRect(dc, &rect, dcBrush);
  644. rect.left++;
  645. rect.right++;
  646. }
  647. }
  648. // Text
  649. {
  650. auto rect = btnAdjusted;
  651. rect.left += Util::ScalePixels(9, m_hWnd);
  652. rect.right -= Util::ScalePixels(3, m_hWnd);
  653. ::SetBkMode(dc, TRANSPARENT);
  654. ::SetTextColor(dc, GetSysColor(enable || activate ? COLOR_BTNTEXT : COLOR_GRAYTEXT));
  655. ::DrawText(dc, s, -1, &rect, DT_RIGHT | DT_VCENTER | DT_SINGLELINE | DT_NOPREFIX);
  656. }
  657. // Draw red/green markers
  658. {
  659. const int margin = Util::ScalePixels(1, m_hWnd);
  660. auto rect = btnAdjusted;
  661. rect.DeflateRect(margin, margin);
  662. rect.right = rect.left + Util::ScalePixels(7, m_hWnd);
  663. const auto &brushes = activate ? brushColorsBright : brushColors;
  664. const auto redBrush = brushes[2], greenBrush = brushes[1];
  665. COLORREF color = 0;
  666. switch(m_currentTab)
  667. {
  668. case kSoloMute:
  669. color = chnSettings.dwFlags[CHN_MUTE] ? redBrush : greenBrush;
  670. break;
  671. case kRecordSelect:
  672. color = brushColors[static_cast<size_t>(m_ModDoc->GetChannelRecordGroup(sourceChn)) % std::size(brushColors)];
  673. break;
  674. case kPluginState:
  675. color = chnSettings.dwFlags[CHN_NOFX] ? redBrush : greenBrush;
  676. break;
  677. case kReorderRemove:
  678. color = removed[sourceChn] ? redBrush : greenBrush;
  679. break;
  680. }
  681. ::SetDCBrushColor(dc, color);
  682. ::FillRect(dc, rect, dcBrush);
  683. // Draw border around marker
  684. ::SetDCBrushColor(dc, RGB(20, 20, 20));
  685. ::FrameRect(dc, rect, dcBrush);
  686. }
  687. }
  688. ::BitBlt(pDC.hdc, rcPaint.left, rcPaint.top, rcPaint.Width(), rcPaint.Height(), dc, rcPaint.left, rcPaint.top, SRCCOPY);
  689. ::SelectObject(dc, oldFont);
  690. ::SelectObject(dc, oldBmp);
  691. ::DeleteDC(dc);
  692. ::EndPaint(m_hWnd, &pDC);
  693. }
  694. bool CChannelManagerDlg::ButtonHit(CPoint point, CHANNELINDEX *id, CRect *invalidate) const
  695. {
  696. const CRect &client = m_drawableArea;
  697. if(PtInRect(client, point) && m_ModDoc != nullptr)
  698. {
  699. UINT nColns = CM_NB_COLS;
  700. int x = point.x - client.left;
  701. int y = point.y - client.top;
  702. int dx = client.Width() / (int)nColns;
  703. int dy = m_buttonHeight;
  704. x = x / dx;
  705. y = y / dy;
  706. CHANNELINDEX n = static_cast<CHANNELINDEX>(y * nColns + x);
  707. if(n < m_ModDoc->GetNumChannels())
  708. {
  709. if(id) *id = n;
  710. if(invalidate)
  711. {
  712. invalidate->left = client.left + x * dx;
  713. invalidate->right = invalidate->left + dx;
  714. invalidate->top = client.top + y * dy;
  715. invalidate->bottom = invalidate->top + dy;
  716. }
  717. return true;
  718. }
  719. }
  720. return false;
  721. }
  722. void CChannelManagerDlg::ResetState(bool bSelection, bool bMove, bool bButton, bool bInternal, bool bOrder)
  723. {
  724. for(CHANNELINDEX chn = 0; chn < MAX_BASECHANNELS; chn++)
  725. {
  726. if(bSelection)
  727. select[pattern[chn]] = false;
  728. if(bButton)
  729. state[pattern[chn]] = false;
  730. if(bOrder)
  731. {
  732. pattern[chn] = chn;
  733. removed[chn] = false;
  734. }
  735. }
  736. if(bMove || bInternal)
  737. {
  738. m_leftButton = false;
  739. m_rightButton = false;
  740. }
  741. if(bMove) m_moveRect = false;
  742. }
  743. void CChannelManagerDlg::OnMouseMove(UINT nFlags,CPoint point)
  744. {
  745. if(!m_hWnd || m_show == false) return;
  746. if(!m_leftButton && !m_rightButton)
  747. {
  748. m_moveX = point.x;
  749. m_moveY = point.y;
  750. return;
  751. }
  752. MouseEvent(nFlags, point, m_moveRect ? CM_BT_NONE : (m_leftButton ? CM_BT_LEFT : CM_BT_RIGHT));
  753. }
  754. void CChannelManagerDlg::OnLButtonUp(UINT /*nFlags*/,CPoint point)
  755. {
  756. ReleaseCapture();
  757. if(!m_hWnd || m_show == false) return;
  758. if(m_moveRect && m_ModDoc)
  759. {
  760. CHANNELINDEX dropChn = 0;
  761. CRect dropRect;
  762. if(ButtonHit(point, &dropChn, &dropRect))
  763. {
  764. // Rearrange channels
  765. const auto IsSelected = std::bind(&decltype(select)::test, &select, std::placeholders::_1);
  766. const auto numChannels = m_ModDoc->GetNumChannels();
  767. if(point.x > dropRect.left + dropRect.Width() / 2 && dropChn < numChannels)
  768. dropChn++;
  769. std::vector<CHANNELINDEX> newOrder{ pattern.begin(), pattern.begin() + numChannels };
  770. // How many selected channels are there before the drop target?
  771. // cppcheck false-positive
  772. // cppcheck-suppress danglingTemporaryLifetime
  773. const CHANNELINDEX selectedBeforeDropChn = static_cast<CHANNELINDEX>(std::count_if(pattern.begin(), pattern.begin() + dropChn, IsSelected));
  774. dropChn -= selectedBeforeDropChn;
  775. // Remove all selected channels from the order
  776. newOrder.erase(std::remove_if(newOrder.begin(), newOrder.end(), IsSelected), newOrder.end());
  777. const CHANNELINDEX numSelected = static_cast<CHANNELINDEX>(numChannels - newOrder.size());
  778. // Then insert them at the drop position
  779. newOrder.insert(newOrder.begin() + dropChn, numSelected, PATTERNINDEX_INVALID);
  780. std::copy_if(pattern.begin(), pattern.begin() + numChannels, newOrder.begin() + dropChn, IsSelected);
  781. std::copy(newOrder.begin(), newOrder.begin() + numChannels, pattern.begin());
  782. select.reset();
  783. } else
  784. {
  785. ResetState(true, false, false, false, false);
  786. }
  787. m_moveRect = false;
  788. InvalidateRect(m_drawableArea, FALSE);
  789. if(m_ModDoc) m_ModDoc->UpdateAllViews(nullptr, GeneralHint().Channels(), this);
  790. }
  791. m_leftButton = false;
  792. for(CHANNELINDEX chn : pattern)
  793. state[chn] = false;
  794. }
  795. void CChannelManagerDlg::OnLButtonDown(UINT nFlags,CPoint point)
  796. {
  797. if(!m_hWnd || m_show == false) return;
  798. SetCapture();
  799. if(!ButtonHit(point, nullptr, nullptr)) ResetState(true, false, false, false);
  800. m_leftButton = true;
  801. m_buttonAction = kUndetermined;
  802. MouseEvent(nFlags,point,CM_BT_LEFT);
  803. m_downX = point.x;
  804. m_downY = point.y;
  805. }
  806. void CChannelManagerDlg::OnRButtonUp(UINT /*nFlags*/,CPoint /*point*/)
  807. {
  808. ReleaseCapture();
  809. if(!m_hWnd || m_show == false) return;
  810. ResetState(false, false, true, false);
  811. m_rightButton = false;
  812. }
  813. void CChannelManagerDlg::OnRButtonDown(UINT nFlags,CPoint point)
  814. {
  815. if(!m_hWnd || m_show == false) return;
  816. SetCapture();
  817. m_rightButton = true;
  818. m_buttonAction = kUndetermined;
  819. if(m_moveRect)
  820. {
  821. ResetState(true, true, false, false, false);
  822. InvalidateRect(m_drawableArea, FALSE);
  823. } else
  824. {
  825. MouseEvent(nFlags, point, CM_BT_RIGHT);
  826. m_downX = point.x;
  827. m_downY = point.y;
  828. }
  829. }
  830. void CChannelManagerDlg::OnMButtonDown(UINT /*nFlags*/, CPoint point)
  831. {
  832. CHANNELINDEX chn;
  833. CRect rect;
  834. if(m_ModDoc != nullptr && (m_ModDoc->GetModType() & (MOD_TYPE_XM | MOD_TYPE_IT | MOD_TYPE_MPT)) && ButtonHit(point, &chn, &rect))
  835. {
  836. ClientToScreen(&point);
  837. m_quickChannelProperties.Show(m_ModDoc, pattern[chn], point);
  838. }
  839. }
  840. void CChannelManagerDlg::MouseEvent(UINT nFlags,CPoint point, MouseButton button)
  841. {
  842. CHANNELINDEX n;
  843. CRect client, invalidate;
  844. bool hit = ButtonHit(point, &n, &invalidate);
  845. if(hit) n = pattern[n];
  846. m_moveX = point.x;
  847. m_moveY = point.y;
  848. if(!m_ModDoc) return;
  849. if(hit && !state[n] && button != CM_BT_NONE)
  850. {
  851. if(nFlags & MK_CONTROL)
  852. {
  853. if(button == CM_BT_LEFT)
  854. {
  855. if(!select[n] && !removed[n]) move[n] = invalidate;
  856. select[n] = true;
  857. }
  858. else if(button == CM_BT_RIGHT) select[n] = false;
  859. }
  860. else if(!removed[n] || m_currentTab == 3)
  861. {
  862. switch(m_currentTab)
  863. {
  864. case kSoloMute:
  865. if(button == CM_BT_LEFT)
  866. {
  867. if(m_buttonAction == kUndetermined)
  868. m_buttonAction = (!m_ModDoc->IsChannelSolo(n) || m_ModDoc->IsChannelMuted(n)) ? kAction1 : kAction2;
  869. if(m_buttonAction == kAction1)
  870. {
  871. m_ModDoc->MuteChannel(n, false);
  872. m_ModDoc->SoloChannel(n, true);
  873. for(CHANNELINDEX chn = 0; chn < m_ModDoc->GetNumChannels(); chn++)
  874. {
  875. if(chn != n)
  876. m_ModDoc->MuteChannel(chn, true);
  877. }
  878. invalidate = client = m_drawableArea;
  879. }
  880. else m_ModDoc->SoloChannel(n, false);
  881. } else
  882. {
  883. if(m_ModDoc->IsChannelSolo(n)) m_ModDoc->SoloChannel(n, false);
  884. if(m_buttonAction == kUndetermined)
  885. m_buttonAction = m_ModDoc->IsChannelMuted(n) ? kAction1 : kAction2;
  886. m_ModDoc->MuteChannel(n, m_buttonAction == kAction2);
  887. }
  888. m_ModDoc->SetModified();
  889. m_ModDoc->UpdateAllViews(nullptr, GeneralHint(n).Channels(), this);
  890. break;
  891. case kRecordSelect:
  892. {
  893. auto rec = m_ModDoc->GetChannelRecordGroup(n);
  894. if(m_buttonAction == kUndetermined)
  895. m_buttonAction = (rec == RecordGroup::NoGroup || rec != (button == CM_BT_LEFT ? RecordGroup::Group1 : RecordGroup::Group2)) ? kAction1 : kAction2;
  896. if(m_buttonAction == kAction1 && button == CM_BT_LEFT)
  897. m_ModDoc->SetChannelRecordGroup(n, RecordGroup::Group1);
  898. else if(m_buttonAction == kAction1 && button == CM_BT_RIGHT)
  899. m_ModDoc->SetChannelRecordGroup(n, RecordGroup::Group2);
  900. else
  901. m_ModDoc->SetChannelRecordGroup(n, RecordGroup::NoGroup);
  902. m_ModDoc->UpdateAllViews(nullptr, GeneralHint(n).Channels(), this);
  903. break;
  904. }
  905. case kPluginState:
  906. if(button == CM_BT_LEFT) m_ModDoc->NoFxChannel(n, false);
  907. else m_ModDoc->NoFxChannel(n, true);
  908. m_ModDoc->SetModified();
  909. m_ModDoc->UpdateAllViews(nullptr, GeneralHint(n).Channels(), this);
  910. break;
  911. case kReorderRemove:
  912. if(button == CM_BT_LEFT)
  913. {
  914. move[n] = invalidate;
  915. select[n] = true;
  916. }
  917. if(button == CM_BT_RIGHT)
  918. {
  919. if(m_buttonAction == kUndetermined)
  920. m_buttonAction = removed[n] ? kAction1 : kAction2;
  921. select[n] = false;
  922. removed[n] = (m_buttonAction == kAction2);
  923. }
  924. if(select[n] || button == 0)
  925. {
  926. m_moveRect = true;
  927. }
  928. break;
  929. }
  930. }
  931. state[n] = false;
  932. InvalidateRect(invalidate, FALSE);
  933. } else
  934. {
  935. InvalidateRect(m_drawableArea, FALSE);
  936. }
  937. }
  938. void CChannelManagerDlg::OnLButtonDblClk(UINT nFlags, CPoint point)
  939. {
  940. OnLButtonDown(nFlags, point);
  941. CDialog::OnLButtonDblClk(nFlags, point);
  942. }
  943. void CChannelManagerDlg::OnRButtonDblClk(UINT nFlags, CPoint point)
  944. {
  945. OnRButtonDown(nFlags, point);
  946. CDialog::OnRButtonDblClk(nFlags, point);
  947. }
  948. OPENMPT_NAMESPACE_END