1
0

PatternFindReplaceDlg.cpp 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952
  1. /*
  2. * PatternFindReplaceDlg.cpp
  3. * -------------------------
  4. * Purpose: The find/replace dialog for pattern data.
  5. * Notes : (currently none)
  6. * Authors: Olivier Lapicque
  7. * OpenMPT Devs
  8. * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
  9. */
  10. #include "stdafx.h"
  11. #include "Mptrack.h"
  12. #include "Mainfrm.h"
  13. #include "View_pat.h"
  14. #include "PatternFindReplace.h"
  15. #include "PatternFindReplaceDlg.h"
  16. OPENMPT_NAMESPACE_BEGIN
  17. // CFindRangeDlg: Find a range of values.
  18. class CFindRangeDlg : public CDialog
  19. {
  20. public:
  21. enum DisplayMode
  22. {
  23. kDecimal,
  24. kHex,
  25. kNotes,
  26. };
  27. protected:
  28. CComboBox m_cbnMin, m_cbnMax;
  29. int m_minVal, m_minDefault;
  30. int m_maxVal, m_maxDefault;
  31. DisplayMode m_displayMode;
  32. public:
  33. CFindRangeDlg(CWnd *parent, int minVal, int minDefault, int maxVal, int maxDefault, DisplayMode displayMode) : CDialog(IDD_FIND_RANGE, parent)
  34. , m_minVal(minVal)
  35. , m_minDefault(minDefault)
  36. , m_maxVal(maxVal)
  37. , m_maxDefault(maxDefault)
  38. , m_displayMode(displayMode)
  39. { }
  40. int GetMinVal() const { return m_minVal; }
  41. int GetMaxVal() const { return m_maxVal; }
  42. protected:
  43. virtual void DoDataExchange(CDataExchange* pDX)
  44. {
  45. CDialog::DoDataExchange(pDX);
  46. DDX_Control(pDX, IDC_COMBO1, m_cbnMin);
  47. DDX_Control(pDX, IDC_COMBO2, m_cbnMax);
  48. }
  49. virtual BOOL OnInitDialog()
  50. {
  51. CDialog::OnInitDialog();
  52. if(m_displayMode == kNotes)
  53. {
  54. AppendNotesToControl(m_cbnMin, static_cast<ModCommand::NOTE>(m_minVal), static_cast<ModCommand::NOTE>(m_maxVal));
  55. AppendNotesToControl(m_cbnMax, static_cast<ModCommand::NOTE>(m_minVal), static_cast<ModCommand::NOTE>(m_maxVal));
  56. } else
  57. {
  58. m_cbnMin.InitStorage(m_minVal - m_maxVal + 1, 4);
  59. m_cbnMax.InitStorage(m_minVal - m_maxVal + 1, 4);
  60. const TCHAR *formatString;
  61. if(m_displayMode == kHex && m_maxVal <= 0x0F)
  62. formatString = _T("%01X");
  63. else if(m_displayMode == kHex)
  64. formatString = _T("%02X");
  65. else
  66. formatString = _T("%d");
  67. for(int i = m_minVal; i <= m_maxVal; i++)
  68. {
  69. TCHAR s[16];
  70. wsprintf(s, formatString, i);
  71. m_cbnMin.SetItemData(m_cbnMin.AddString(s), i);
  72. m_cbnMax.SetItemData(m_cbnMax.AddString(s), i);
  73. }
  74. }
  75. if(m_minDefault < m_minVal || m_minDefault > m_maxDefault)
  76. {
  77. m_minDefault = m_minVal;
  78. m_maxDefault = m_maxVal;
  79. }
  80. m_cbnMin.SetCurSel(m_minDefault - m_minVal);
  81. m_cbnMax.SetCurSel(m_maxDefault - m_minVal);
  82. return TRUE;
  83. }
  84. virtual void OnOK()
  85. {
  86. CDialog::OnOK();
  87. m_minVal = static_cast<int>(m_cbnMin.GetItemData(m_cbnMin.GetCurSel()));
  88. m_maxVal = static_cast<int>(m_cbnMax.GetItemData(m_cbnMax.GetCurSel()));
  89. if(m_maxVal < m_minVal)
  90. std::swap(m_minVal, m_maxVal);
  91. }
  92. };
  93. BEGIN_MESSAGE_MAP(CFindReplaceTab, CPropertyPage)
  94. ON_CBN_SELCHANGE(IDC_COMBO1, &CFindReplaceTab::OnNoteChanged)
  95. ON_CBN_SELCHANGE(IDC_COMBO2, &CFindReplaceTab::OnInstrChanged)
  96. ON_CBN_SELCHANGE(IDC_COMBO3, &CFindReplaceTab::OnVolCmdChanged)
  97. ON_CBN_SELCHANGE(IDC_COMBO4, &CFindReplaceTab::OnVolumeChanged)
  98. ON_CBN_SELCHANGE(IDC_COMBO5, &CFindReplaceTab::OnEffectChanged)
  99. ON_CBN_SELCHANGE(IDC_COMBO6, &CFindReplaceTab::OnParamChanged)
  100. ON_CBN_SELCHANGE(IDC_COMBO7, &CFindReplaceTab::OnPCParamChanged)
  101. ON_CBN_EDITCHANGE(IDC_COMBO4, &CFindReplaceTab::OnVolumeChanged)
  102. ON_CBN_EDITCHANGE(IDC_COMBO6, &CFindReplaceTab::OnParamChanged)
  103. ON_COMMAND(IDC_CHECK1, &CFindReplaceTab::OnCheckNote)
  104. ON_COMMAND(IDC_CHECK2, &CFindReplaceTab::OnCheckInstr)
  105. ON_COMMAND(IDC_CHECK3, &CFindReplaceTab::OnCheckVolCmd)
  106. ON_COMMAND(IDC_CHECK4, &CFindReplaceTab::OnCheckVolume)
  107. ON_COMMAND(IDC_CHECK5, &CFindReplaceTab::OnCheckEffect)
  108. ON_COMMAND(IDC_CHECK6, &CFindReplaceTab::OnCheckParam)
  109. ON_COMMAND(IDC_CHECK7, &CFindReplaceTab::OnCheckChannelSearch)
  110. END_MESSAGE_MAP()
  111. void CFindReplaceTab::DoDataExchange(CDataExchange* pDX)
  112. {
  113. CDialog::DoDataExchange(pDX);
  114. DDX_Control(pDX, IDC_COMBO1, m_cbnNote);
  115. DDX_Control(pDX, IDC_COMBO2, m_cbnInstr);
  116. DDX_Control(pDX, IDC_COMBO3, m_cbnVolCmd);
  117. DDX_Control(pDX, IDC_COMBO4, m_cbnVolume);
  118. DDX_Control(pDX, IDC_COMBO5, m_cbnCommand);
  119. DDX_Control(pDX, IDC_COMBO6, m_cbnParam);
  120. DDX_Control(pDX, IDC_COMBO7, m_cbnPCParam);
  121. }
  122. BOOL CFindReplaceTab::OnInitDialog()
  123. {
  124. CString s;
  125. CPropertyPage::OnInitDialog();
  126. // Search flags
  127. FlagSet<FindReplace::Flags> flags = m_isReplaceTab ? m_settings.replaceFlags : m_settings.findFlags;
  128. COMBOBOXINFO info;
  129. info.cbSize = sizeof(info);
  130. if(m_cbnVolume.GetComboBoxInfo(&info))
  131. {
  132. ::SetWindowLong(info.hwndItem, GWL_STYLE, ::GetWindowLong(info.hwndItem, GWL_STYLE) | ES_NUMBER);
  133. ::SendMessage(info.hwndItem, EM_SETLIMITTEXT, 4, 0);
  134. }
  135. if(m_cbnParam.GetComboBoxInfo(&info))
  136. {
  137. // Might need to enter hex values
  138. //::SetWindowLong(info.hwndItem, GWL_STYLE, ::GetWindowLong(info.hwndItem, GWL_STYLE) | ES_NUMBER);
  139. ::SendMessage(info.hwndItem, EM_SETLIMITTEXT, 4, 0);
  140. }
  141. CheckDlgButton(IDC_CHECK1, flags[FindReplace::Note] ? BST_CHECKED : BST_UNCHECKED);
  142. CheckDlgButton(IDC_CHECK2, flags[FindReplace::Instr] ? BST_CHECKED : BST_UNCHECKED);
  143. CheckDlgButton(IDC_CHECK3, flags[FindReplace::VolCmd | FindReplace::PCParam] ? BST_CHECKED : BST_UNCHECKED);
  144. CheckDlgButton(IDC_CHECK4, flags[FindReplace::Volume | FindReplace::PCValue] ? BST_CHECKED : BST_UNCHECKED);
  145. CheckDlgButton(IDC_CHECK5, flags[FindReplace::Command] ? BST_CHECKED : BST_UNCHECKED);
  146. CheckDlgButton(IDC_CHECK6, flags[FindReplace::Param] ? BST_CHECKED : BST_UNCHECKED);
  147. if(m_isReplaceTab)
  148. {
  149. CheckDlgButton(IDC_CHECK7, flags[FindReplace::Replace] ? BST_CHECKED : BST_UNCHECKED);
  150. CheckDlgButton(IDC_CHECK8, flags[FindReplace::ReplaceAll] ? BST_CHECKED : BST_UNCHECKED);
  151. } else
  152. {
  153. CheckDlgButton(IDC_CHECK7, flags[FindReplace::InChannels] ? BST_CHECKED : BST_UNCHECKED);
  154. int nButton = IDC_RADIO1;
  155. if(flags[FindReplace::FullSearch])
  156. nButton = IDC_RADIO2;
  157. else if(flags[FindReplace::InPatSelection])
  158. nButton = IDC_RADIO3;
  159. CheckRadioButton(IDC_RADIO1, IDC_RADIO3, nButton);
  160. GetDlgItem(IDC_RADIO3)->EnableWindow(flags[FindReplace::InPatSelection] ? TRUE : FALSE);
  161. SetDlgItemInt(IDC_EDIT1, m_settings.findChnMin + 1);
  162. SetDlgItemInt(IDC_EDIT2, m_settings.findChnMax + 1);
  163. static_cast<CSpinButtonCtrl *>(GetDlgItem(IDC_SPIN1))->SetRange32(1, m_sndFile.GetNumChannels());
  164. static_cast<CSpinButtonCtrl *>(GetDlgItem(IDC_SPIN2))->SetRange32(1, m_sndFile.GetNumChannels());
  165. // Pre-fill with selected pattern data
  166. if(!flags[FindReplace::Note] && m_initialValues.note != NOTE_NONE)
  167. {
  168. m_settings.findNoteMin = m_settings.findNoteMax = m_initialValues.note;
  169. }
  170. if(!flags[FindReplace::Instr] && m_initialValues.instr != 0)
  171. {
  172. m_settings.findInstrMin = m_settings.findInstrMax = m_initialValues.instr;
  173. }
  174. if(IsPCEvent())
  175. {
  176. if(!flags[FindReplace::PCParam] && m_initialValues.GetValueVolCol() != 0)
  177. m_settings.findParamMin = m_settings.findParamMax = m_initialValues.GetValueVolCol();
  178. if(!flags[FindReplace::PCValue] && m_initialValues.GetValueEffectCol() != 0)
  179. m_settings.findVolumeMin = m_settings.findVolumeMax = m_initialValues.GetValueEffectCol();
  180. } else
  181. {
  182. if(!flags[FindReplace::VolCmd] && m_initialValues.volcmd != VOLCMD_NONE)
  183. m_settings.findVolCmd = m_initialValues.volcmd;
  184. if(!flags[FindReplace::Volume] && m_initialValues.volcmd != VOLCMD_NONE)
  185. m_settings.findVolumeMin = m_settings.findVolumeMax = m_initialValues.vol;
  186. if(!flags[FindReplace::Command] && m_initialValues.command != CMD_NONE)
  187. m_settings.findCommand = m_initialValues.command;
  188. if(!flags[FindReplace::Param] && m_initialValues.command != CMD_NONE)
  189. m_settings.findParamMin = m_settings.findParamMax = m_initialValues.param;
  190. }
  191. }
  192. // Note
  193. {
  194. int sel = -1;
  195. m_cbnNote.SetRedraw(FALSE);
  196. m_cbnNote.InitStorage(150, 6);
  197. m_cbnNote.SetItemData(m_cbnNote.AddString(_T("...")), NOTE_NONE);
  198. if (m_isReplaceTab)
  199. {
  200. m_cbnNote.SetItemData(m_cbnNote.AddString(_T("note -1")), kReplaceNoteMinusOne);
  201. m_cbnNote.SetItemData(m_cbnNote.AddString(_T("note +1")), kReplaceNotePlusOne);
  202. m_cbnNote.SetItemData(m_cbnNote.AddString(_T("-1 oct")), kReplaceNoteMinusOctave);
  203. m_cbnNote.SetItemData(m_cbnNote.AddString(_T("+1 oct")), kReplaceNotePlusOctave);
  204. m_cbnNote.SetItemData(m_cbnNote.AddString(_T("Transpose...")), kReplaceRelative);
  205. if(m_settings.replaceNoteAction == FindReplace::ReplaceRelative)
  206. {
  207. switch(m_settings.replaceNote)
  208. {
  209. case -1: sel = 1; break;
  210. case 1: sel = 2; break;
  211. case FindReplace::ReplaceOctaveDown: sel = 3; break;
  212. case FindReplace::ReplaceOctaveUp : sel = 4; break;
  213. default: sel = 5; break;
  214. }
  215. }
  216. } else
  217. {
  218. m_cbnNote.SetItemData(m_cbnNote.AddString(_T("any")), kFindAny);
  219. m_cbnNote.SetItemData(m_cbnNote.AddString(_T("Range...")), kFindRange);
  220. if(m_settings.findNoteMin == NOTE_MIN && m_settings.findNoteMax == NOTE_MAX)
  221. sel = 1;
  222. else if(m_settings.findNoteMin < m_settings.findNoteMax)
  223. sel = 2;
  224. }
  225. AppendNotesToControlEx(m_cbnNote, m_sndFile);
  226. if(sel == -1)
  227. {
  228. DWORD_PTR searchNote = m_isReplaceTab ? m_settings.replaceNote : m_settings.findNoteMin;
  229. int ncount = m_cbnNote.GetCount();
  230. for(int i = 0; i < ncount; i++) if(searchNote == m_cbnNote.GetItemData(i))
  231. {
  232. sel = i;
  233. break;
  234. }
  235. }
  236. m_cbnNote.SetCurSel(sel);
  237. m_cbnNote.SetRedraw(TRUE);
  238. }
  239. // Volume Command
  240. m_cbnVolCmd.SetRedraw(FALSE);
  241. m_cbnVolCmd.InitStorage(m_effectInfo.GetNumVolCmds(), 15);
  242. m_cbnVolCmd.SetItemData(m_cbnVolCmd.AddString(_T(" None")), (DWORD_PTR)-1);
  243. UINT count = m_effectInfo.GetNumVolCmds();
  244. for (UINT n=0; n<count; n++)
  245. {
  246. if(m_effectInfo.GetVolCmdInfo(n, &s) && !s.IsEmpty())
  247. {
  248. m_cbnVolCmd.SetItemData(m_cbnVolCmd.AddString(s), n);
  249. }
  250. }
  251. m_cbnVolCmd.SetCurSel(0);
  252. UINT fxndx = m_effectInfo.GetIndexFromVolCmd(m_isReplaceTab ? m_settings.replaceVolCmd : m_settings.findVolCmd);
  253. for (UINT i=0; i<=count; i++) if (fxndx == m_cbnVolCmd.GetItemData(i))
  254. {
  255. m_cbnVolCmd.SetCurSel(i);
  256. break;
  257. }
  258. m_cbnVolCmd.SetRedraw(TRUE);
  259. m_cbnVolCmd.ShowWindow(SW_SHOW);
  260. m_cbnPCParam.ShowWindow(SW_HIDE);
  261. // Command
  262. {
  263. m_cbnCommand.SetRedraw(FALSE);
  264. m_cbnCommand.InitStorage(m_effectInfo.GetNumEffects(), 20);
  265. m_cbnCommand.SetItemData(m_cbnCommand.AddString(_T(" None")), (DWORD_PTR)-1);
  266. count = m_effectInfo.GetNumEffects();
  267. for (UINT n=0; n<count; n++)
  268. {
  269. if(m_effectInfo.GetEffectInfo(n, &s, true) && !s.IsEmpty())
  270. {
  271. m_cbnCommand.SetItemData(m_cbnCommand.AddString(s), n);
  272. }
  273. }
  274. m_cbnCommand.SetCurSel(0);
  275. fxndx = m_effectInfo.GetIndexFromEffect(m_isReplaceTab ? m_settings.replaceCommand : m_settings.findCommand, static_cast<ModCommand::PARAM>(m_isReplaceTab ? m_settings.replaceParam : m_settings.findParamMin));
  276. for (UINT i=0; i<=count; i++) if (fxndx == m_cbnCommand.GetItemData(i))
  277. {
  278. m_cbnCommand.SetCurSel(i);
  279. break;
  280. }
  281. m_cbnCommand.SetRedraw(TRUE);
  282. }
  283. UpdateInstrumentList();
  284. UpdateVolumeList();
  285. UpdateParamList();
  286. OnCheckChannelSearch();
  287. return TRUE;
  288. }
  289. bool CFindReplaceTab::IsPCEvent() const
  290. {
  291. if(m_isReplaceTab)
  292. {
  293. if(ModCommand::IsPcNote(static_cast<ModCommand::NOTE>(m_settings.replaceNote)))
  294. return true;
  295. else if(m_settings.replaceFlags[FindReplace::Note])
  296. return false;
  297. // If we don't replace the note, still show the PC-related settings if we search for PC events.
  298. }
  299. return ModCommand::IsPcNote(m_settings.findNoteMin);
  300. }
  301. void CFindReplaceTab::UpdateInstrumentList()
  302. {
  303. const bool isPCEvent = IsPCEvent();
  304. if(m_cbnInstr.GetCount() != 0 && !!GetWindowLongPtr(m_cbnInstr.m_hWnd, GWLP_USERDATA) == isPCEvent)
  305. return;
  306. SetWindowLongPtr(m_cbnInstr.m_hWnd, GWLP_USERDATA, isPCEvent);
  307. int oldSelection = (m_isReplaceTab ? m_settings.replaceInstr : m_settings.findInstrMin);
  308. int sel = (oldSelection == 0) ? 0 : -1;
  309. m_cbnInstr.SetRedraw(FALSE);
  310. m_cbnInstr.ResetContent();
  311. m_cbnInstr.InitStorage((isPCEvent ? MAX_MIXPLUGINS : MAX_INSTRUMENTS) + 3, 32);
  312. m_cbnInstr.SetItemData(m_cbnInstr.AddString(_T("..")), 0);
  313. if (m_isReplaceTab)
  314. {
  315. m_cbnInstr.SetItemData(m_cbnInstr.AddString(isPCEvent ? _T("Plugin -1") : _T("Instrument -1")), kReplaceInstrumentMinusOne);
  316. m_cbnInstr.SetItemData(m_cbnInstr.AddString(isPCEvent ? _T("Plugin +1") : _T("Instrument +1")), kReplaceInstrumentPlusOne);
  317. m_cbnInstr.SetItemData(m_cbnInstr.AddString(_T("Other...")), kReplaceRelative);
  318. if(m_settings.replaceInstrAction == FindReplace::ReplaceRelative)
  319. {
  320. switch(m_settings.replaceInstr)
  321. {
  322. case -1: sel = 1; break;
  323. case 1: sel = 2; break;
  324. default: sel = 3; break;
  325. }
  326. }
  327. } else
  328. {
  329. m_cbnInstr.SetItemData(m_cbnInstr.AddString(_T("Range...")), kFindRange);
  330. if(m_settings.findInstrMin < m_settings.findInstrMax)
  331. sel = 1;
  332. }
  333. if(sel == -1)
  334. sel = m_cbnInstr.GetCount() + oldSelection - 1;
  335. if(isPCEvent)
  336. {
  337. AddPluginNamesToCombobox(m_cbnInstr, m_sndFile.m_MixPlugins, false);
  338. } else
  339. {
  340. CString s;
  341. for(INSTRUMENTINDEX n = 1; n < MAX_INSTRUMENTS; n++)
  342. {
  343. s.Format(_T("%03d:"), n);
  344. if(m_sndFile.GetNumInstruments())
  345. s += mpt::ToCString(m_sndFile.GetCharsetInternal(), m_sndFile.GetInstrumentName(n));
  346. else
  347. s += mpt::ToCString(m_sndFile.GetCharsetInternal(), m_sndFile.m_szNames[n]);
  348. m_cbnInstr.SetItemData(m_cbnInstr.AddString(s), n);
  349. }
  350. }
  351. m_cbnInstr.SetCurSel(sel);
  352. m_cbnInstr.SetRedraw(TRUE);
  353. m_cbnInstr.Invalidate(FALSE);
  354. }
  355. void CFindReplaceTab::UpdateParamList()
  356. {
  357. const bool isPCEvent = IsPCEvent();
  358. if(m_cbnInstr.GetCount() == 0 || !!GetWindowLongPtr(m_cbnInstr.m_hWnd, GWLP_USERDATA) != isPCEvent)
  359. {
  360. SetWindowLongPtr(m_cbnInstr.m_hWnd, GWLP_USERDATA, isPCEvent);
  361. }
  362. int effectIndex = static_cast<int>(m_cbnCommand.GetItemData(m_cbnCommand.GetCurSel()));
  363. ModCommand::PARAM n = 0; // unused parameter adjustment
  364. ModCommand::COMMAND cmd = m_effectInfo.GetEffectFromIndex(effectIndex, n);
  365. const UINT mask = m_effectInfo.GetEffectMaskFromIndex(effectIndex);
  366. if(m_isReplaceTab)
  367. m_settings.replaceCommand = cmd;
  368. else
  369. m_settings.findCommand = cmd;
  370. // Update Param range
  371. const bool isExtended = m_effectInfo.IsExtendedEffect(effectIndex);
  372. int sel = -1;
  373. int oldcount = m_cbnParam.GetCount();
  374. int newcount = isExtended ? 16 : 256;
  375. if(oldcount)
  376. oldcount -= m_isReplaceTab ? 2 : 1;
  377. auto findParam = m_isReplaceTab ? m_settings.replaceParam : m_settings.findParamMin;
  378. if(isExtended)
  379. {
  380. findParam &= 0x0F;
  381. if(!m_isReplaceTab && !IsDlgButtonChecked(IDC_CHECK6))
  382. {
  383. m_settings.findParamMin = (m_settings.findParamMin & 0x0F) | mask;
  384. m_settings.findParamMax = (m_settings.findParamMax & 0x0F) | mask;
  385. } else if(m_isReplaceTab)
  386. {
  387. m_settings.replaceParam |= mask;
  388. }
  389. }
  390. if(oldcount != newcount)
  391. {
  392. TCHAR s[16];
  393. int newpos;
  394. if(oldcount && m_cbnParam.GetCurSel() != CB_ERR)
  395. newpos = static_cast<int>(m_cbnParam.GetItemData(m_cbnParam.GetCurSel()));
  396. else
  397. newpos = findParam;
  398. Limit(newpos, 0, newcount - 1);
  399. m_cbnParam.SetRedraw(FALSE);
  400. m_cbnParam.ResetContent();
  401. m_cbnParam.InitStorage(newcount + 2, 4);
  402. if(m_isReplaceTab)
  403. {
  404. wsprintf(s, _T("+ %d"), m_settings.replaceParam);
  405. m_cbnParam.SetItemData(m_cbnParam.AddString(s), kReplaceRelative);
  406. wsprintf(s, _T("* %d%%"), m_settings.replaceParam);
  407. m_cbnParam.SetItemData(m_cbnParam.AddString(s), kReplaceMultiply);
  408. if(m_settings.replaceParamAction == FindReplace::ReplaceRelative)
  409. sel = 0;
  410. else if(m_settings.replaceParamAction == FindReplace::ReplaceMultiply)
  411. sel = 1;
  412. m_settings.replaceParam = newpos;
  413. if(isExtended)
  414. {
  415. m_settings.replaceParam = (m_settings.replaceParam & 0x0F) | mask;
  416. }
  417. } else
  418. {
  419. m_cbnParam.SetItemData(m_cbnParam.AddString(_T("Range")), kFindRange);
  420. if(m_settings.findParamMin < m_settings.findParamMax)
  421. sel = 0;
  422. }
  423. if(sel == -1)
  424. sel = m_cbnParam.GetCount() + newpos;
  425. for(int param = 0; param < newcount; param++)
  426. {
  427. wsprintf(s, (newcount == 256) ? _T("%02X") : _T("%X"), param);
  428. int i = m_cbnParam.AddString(s);
  429. m_cbnParam.SetItemData(i, param);
  430. }
  431. m_cbnParam.SetCurSel(sel);
  432. m_cbnParam.SetRedraw(TRUE);
  433. m_cbnParam.Invalidate(FALSE);
  434. }
  435. }
  436. void CFindReplaceTab::UpdateVolumeList()
  437. {
  438. TCHAR s[256];
  439. const bool isPCEvent = IsPCEvent();
  440. BOOL enable = isPCEvent ? FALSE : TRUE;
  441. GetDlgItem(IDC_CHECK5)->EnableWindow(enable);
  442. GetDlgItem(IDC_CHECK6)->EnableWindow(enable);
  443. m_cbnCommand.EnableWindow(enable);
  444. m_cbnParam.EnableWindow(enable);
  445. // Update plugin parameter list
  446. int plug = static_cast<int>(m_cbnInstr.GetItemData(m_cbnInstr.GetCurSel()));
  447. if(isPCEvent && (m_cbnPCParam.GetCount() == 0 || GetWindowLongPtr(m_cbnPCParam.m_hWnd, GWLP_USERDATA) != plug))
  448. {
  449. SetWindowLongPtr(m_cbnPCParam.m_hWnd, GWLP_USERDATA, plug);
  450. CheckDlgButton(IDC_CHECK5, BST_UNCHECKED);
  451. CheckDlgButton(IDC_CHECK6, BST_UNCHECKED);
  452. int sel = m_isReplaceTab ? m_settings.replaceParam : m_settings.findParamMin;
  453. plug--;
  454. m_cbnPCParam.SetRedraw(FALSE);
  455. m_cbnPCParam.ResetContent();
  456. if(plug >= 0 && plug < MAX_MIXPLUGINS && m_sndFile.m_MixPlugins[plug].pMixPlugin != nullptr)
  457. {
  458. AddPluginParameternamesToCombobox(m_cbnPCParam, *m_sndFile.m_MixPlugins[plug].pMixPlugin);
  459. } else
  460. {
  461. m_cbnPCParam.InitStorage(ModCommand::maxColumnValue, 20);
  462. for(int i = 0; i < ModCommand::maxColumnValue; i++)
  463. {
  464. wsprintf(s, _T("%02u: Parameter %02u"), static_cast<unsigned int>(i), static_cast<unsigned int>(i));
  465. m_cbnPCParam.SetItemData(m_cbnPCParam.AddString(s), i);
  466. }
  467. }
  468. m_cbnPCParam.SetCurSel(sel);
  469. m_cbnPCParam.SetRedraw(TRUE);
  470. m_cbnPCParam.Invalidate(FALSE);
  471. }
  472. m_cbnVolCmd.ShowWindow(isPCEvent ? SW_HIDE : SW_SHOW);
  473. m_cbnPCParam.ShowWindow(isPCEvent ? SW_SHOW : SW_HIDE);
  474. int rangeMin, rangeMax, curVal;
  475. if(isPCEvent)
  476. {
  477. rangeMin = 0;
  478. rangeMax = ModCommand::maxColumnValue;
  479. curVal = (m_isReplaceTab ? m_settings.replaceVolume : m_settings.findVolumeMin);
  480. } else
  481. {
  482. int effectIndex = static_cast<int>(m_cbnVolCmd.GetItemData(m_cbnVolCmd.GetCurSel()));
  483. ModCommand::VOLCMD cmd = m_effectInfo.GetVolCmdFromIndex(effectIndex);
  484. if(m_isReplaceTab)
  485. m_settings.replaceVolCmd = cmd;
  486. else
  487. m_settings.findVolCmd = cmd;
  488. // Update Param range
  489. ModCommand::VOL volMin, volMax;
  490. if(!m_effectInfo.GetVolCmdInfo(effectIndex, nullptr, &volMin, &volMax))
  491. {
  492. volMin = 0;
  493. volMax = 64;
  494. }
  495. rangeMin = volMin;
  496. rangeMax = volMax;
  497. curVal = (m_isReplaceTab ? m_settings.replaceVolume : m_settings.findVolumeMin);
  498. }
  499. int oldcount = m_cbnVolume.GetCount();
  500. int newcount = rangeMax - rangeMin + 1;
  501. if (oldcount != newcount)
  502. {
  503. int sel = -1;
  504. int newpos;
  505. if (oldcount)
  506. newpos = static_cast<int>(m_cbnVolume.GetItemData(m_cbnVolume.GetCurSel()));
  507. else
  508. newpos = curVal;
  509. Limit(newpos, 0, newcount - 1);
  510. m_cbnVolume.SetRedraw(FALSE);
  511. m_cbnVolume.ResetContent();
  512. m_cbnVolume.InitStorage(newcount + 2, 4);
  513. if(m_isReplaceTab)
  514. {
  515. wsprintf(s, _T("+ %d"), m_settings.replaceVolume);
  516. m_cbnVolume.SetItemData(m_cbnVolume.AddString(s), kReplaceRelative);
  517. wsprintf(s, _T("* %d%%"), m_settings.replaceVolume);
  518. m_cbnVolume.SetItemData(m_cbnVolume.AddString(s), kReplaceMultiply);
  519. if(m_settings.replaceVolumeAction == FindReplace::ReplaceRelative)
  520. sel = 0;
  521. else if(m_settings.replaceVolumeAction == FindReplace::ReplaceMultiply)
  522. sel = 1;
  523. } else
  524. {
  525. m_cbnVolume.SetItemData(m_cbnVolume.AddString(_T("Range...")), kFindRange);
  526. if(m_settings.findVolumeMin < m_settings.findVolumeMax)
  527. sel = 0;
  528. }
  529. if(sel == -1)
  530. sel = m_cbnVolume.GetCount() + newpos - rangeMin;
  531. for (int vol = rangeMin; vol <= rangeMax; vol++)
  532. {
  533. wsprintf(s, (rangeMax < 10 || rangeMax > 99) ? _T("%d") : _T("%02d"), vol);
  534. int i = m_cbnVolume.AddString(s);
  535. m_cbnVolume.SetItemData(i, vol);
  536. }
  537. m_cbnVolume.SetCurSel(sel);
  538. m_cbnVolume.SetRedraw(TRUE);
  539. m_cbnVolume.Invalidate(FALSE);
  540. }
  541. }
  542. void CFindReplaceTab::OnNoteChanged()
  543. {
  544. CheckOnChange(IDC_CHECK1);
  545. int item = static_cast<int>(m_cbnNote.GetItemData(m_cbnNote.GetCurSel()));
  546. if(m_isReplaceTab)
  547. {
  548. m_settings.replaceNoteAction = FindReplace::ReplaceRelative;
  549. switch(item)
  550. {
  551. case kReplaceNoteMinusOne: m_settings.replaceNote = -1; break;
  552. case kReplaceNotePlusOne: m_settings.replaceNote = 1; break;
  553. case kReplaceNoteMinusOctave: m_settings.replaceNote = FindReplace::ReplaceOctaveDown; break;
  554. case kReplaceNotePlusOctave: m_settings.replaceNote = FindReplace::ReplaceOctaveUp; break;
  555. case kReplaceRelative:
  556. {
  557. CInputDlg dlg(this, _T("Custom Transpose Amount:"), -120, 120, m_settings.replaceNote);
  558. if(dlg.DoModal() == IDOK)
  559. {
  560. m_settings.replaceNote = dlg.resultAsInt;
  561. } else
  562. {
  563. // TODO undo selection
  564. }
  565. }
  566. break;
  567. default:
  568. m_settings.replaceNote = item;
  569. m_settings.replaceNoteAction = FindReplace::ReplaceValue;
  570. }
  571. } else
  572. {
  573. if(item == kFindRange)
  574. {
  575. CFindRangeDlg dlg(this, NOTE_MIN, m_settings.findNoteMin, NOTE_MAX, m_settings.findNoteMax, CFindRangeDlg::kNotes);
  576. if(dlg.DoModal() == IDOK)
  577. {
  578. m_settings.findNoteMin = static_cast<ModCommand::NOTE>(dlg.GetMinVal());
  579. m_settings.findNoteMax = static_cast<ModCommand::NOTE>(dlg.GetMaxVal());
  580. }
  581. } else if(item == kFindAny)
  582. {
  583. m_settings.findNoteMin = NOTE_MIN;
  584. m_settings.findNoteMax = NOTE_MAX;
  585. } else
  586. {
  587. m_settings.findNoteMin = m_settings.findNoteMax = static_cast<ModCommand::NOTE>(item);
  588. }
  589. }
  590. UpdateInstrumentList();
  591. UpdateVolumeList();
  592. }
  593. void CFindReplaceTab::OnInstrChanged()
  594. {
  595. CheckOnChange(IDC_CHECK2);
  596. int item = static_cast<int>(m_cbnInstr.GetItemData(m_cbnInstr.GetCurSel()));
  597. if(m_isReplaceTab)
  598. {
  599. m_settings.replaceInstrAction = FindReplace::ReplaceRelative;
  600. switch(item)
  601. {
  602. case kReplaceInstrumentMinusOne: m_settings.replaceInstr = -1; break;
  603. case kReplaceInstrumentPlusOne: m_settings.replaceInstr = 1; break;
  604. case kReplaceRelative:
  605. {
  606. CInputDlg dlg(this, _T("Custom Replacement Amount:"), -255, 255, m_settings.replaceInstr);
  607. if(dlg.DoModal() == IDOK)
  608. {
  609. m_settings.replaceInstrAction = FindReplace::ReplaceRelative;
  610. m_settings.replaceInstr = dlg.resultAsInt;
  611. } else
  612. {
  613. // TODO undo selection
  614. }
  615. }
  616. break;
  617. default:
  618. m_settings.replaceInstrAction = FindReplace::ReplaceValue;
  619. m_settings.replaceInstr = item;
  620. break;
  621. }
  622. } else
  623. {
  624. if(item == kFindRange)
  625. {
  626. CFindRangeDlg dlg(this, 1, m_settings.findInstrMin, MAX_INSTRUMENTS - 1, m_settings.findInstrMax, CFindRangeDlg::kDecimal);
  627. if(dlg.DoModal() == IDOK)
  628. {
  629. m_settings.findInstrMin = static_cast<ModCommand::INSTR>(dlg.GetMinVal());
  630. m_settings.findInstrMax = static_cast<ModCommand::INSTR>(dlg.GetMaxVal());
  631. }
  632. } else
  633. {
  634. m_settings.findInstrMin = m_settings.findInstrMax = static_cast<ModCommand::INSTR>(item);
  635. }
  636. }
  637. if(IsPCEvent())
  638. UpdateVolumeList();
  639. }
  640. void CFindReplaceTab::RelativeOrMultiplyPrompt(CComboBox &comboBox, FindReplace::ReplaceMode &action, int &value, int range, bool isHex)
  641. {
  642. int sel = comboBox.GetCurSel();
  643. int item = static_cast<int>(comboBox.GetItemData(sel));
  644. if(sel == CB_ERR)
  645. {
  646. item = 0;
  647. CString s;
  648. comboBox.GetWindowText(s);
  649. s.TrimLeft();
  650. if(s.GetLength() >= 1)
  651. {
  652. TCHAR first = s[0];
  653. if(first == _T('+'))
  654. {
  655. item = kReplaceRelative;
  656. sel = 0;
  657. } else if(first == _T('*'))
  658. {
  659. item = kReplaceMultiply;
  660. sel = 1;
  661. }
  662. }
  663. if(!item)
  664. {
  665. if(isHex)
  666. {
  667. int len = ::GetWindowTextLengthA(m_cbnParam);
  668. std::string sHex(len, 0);
  669. ::GetWindowTextA(m_cbnParam, &sHex[0], len + 1);
  670. item = mpt::String::Parse::HexToUnsignedInt(sHex);
  671. } else
  672. {
  673. item = ConvertStrTo<int>(s);
  674. }
  675. }
  676. }
  677. if(item == kReplaceRelative || item == kReplaceMultiply)
  678. {
  679. const TCHAR *prompt, *format;
  680. FindReplace::ReplaceMode act;
  681. if(item == kReplaceRelative)
  682. {
  683. act = FindReplace::ReplaceRelative;
  684. prompt = _T("Amount to add or subtract:");
  685. format = _T("+ %d");
  686. } else
  687. {
  688. act = FindReplace::ReplaceMultiply;
  689. prompt = _T("Multiply by percentage:");
  690. format = _T("* %d%%");
  691. }
  692. range *= 100;
  693. CInputDlg dlg(this, prompt, -range, range, value);
  694. if(dlg.DoModal() == IDOK)
  695. {
  696. value = dlg.resultAsInt;
  697. action = act;
  698. TCHAR s[32];
  699. wsprintf(s, format, value);
  700. comboBox.DeleteString(sel);
  701. comboBox.InsertString(sel, s);
  702. comboBox.SetItemData(sel, item);
  703. comboBox.SetCurSel(sel);
  704. } else
  705. {
  706. // TODO undo selection
  707. }
  708. } else
  709. {
  710. action = FindReplace::ReplaceValue;
  711. value = item;
  712. }
  713. }
  714. void CFindReplaceTab::OnVolumeChanged()
  715. {
  716. CheckOnChange(IDC_CHECK4);
  717. int item = m_cbnVolume.GetCurSel();
  718. if(item != CB_ERR)
  719. item = static_cast<int>(m_cbnVolume.GetItemData(item));
  720. else
  721. item = GetDlgItemInt(IDC_COMBO4);
  722. int rangeMax = IsPCEvent() ? ModCommand::maxColumnValue : 64;
  723. if(m_isReplaceTab)
  724. {
  725. RelativeOrMultiplyPrompt(m_cbnVolume, m_settings.replaceVolumeAction, m_settings.replaceVolume, rangeMax, false);
  726. } else
  727. {
  728. if(item == kFindRange)
  729. {
  730. CFindRangeDlg dlg(this, 0, m_settings.findVolumeMin, rangeMax, m_settings.findVolumeMax, CFindRangeDlg::kDecimal);
  731. if(dlg.DoModal() == IDOK)
  732. {
  733. m_settings.findVolumeMin = dlg.GetMinVal();
  734. m_settings.findVolumeMax = dlg.GetMaxVal();
  735. } else
  736. {
  737. // TODO undo selection
  738. }
  739. } else
  740. {
  741. m_settings.findVolumeMin = m_settings.findVolumeMax = item;
  742. }
  743. }
  744. }
  745. void CFindReplaceTab::OnParamChanged()
  746. {
  747. CheckOnChange(IDC_CHECK6);
  748. int item = m_cbnParam.GetCurSel();
  749. if(item != CB_ERR)
  750. {
  751. item = static_cast<int>(m_cbnParam.GetItemData(item));
  752. } else
  753. {
  754. int len = ::GetWindowTextLengthA(m_cbnParam);
  755. std::string s(len, 0);
  756. ::GetWindowTextA(m_cbnParam, &s[0], len + 1);
  757. item = mpt::String::Parse::HexToUnsignedInt(s);
  758. }
  759. // Apply parameter value mask if required (e.g. SDx has mask D0).
  760. int effectIndex = static_cast<int>(m_cbnCommand.GetItemData(m_cbnCommand.GetCurSel()));
  761. UINT mask = (effectIndex > -1) ? m_effectInfo.GetEffectMaskFromIndex(effectIndex) : 0;
  762. if(m_isReplaceTab)
  763. {
  764. RelativeOrMultiplyPrompt(m_cbnParam, m_settings.replaceParamAction, m_settings.replaceParam, 256, true);
  765. if(m_settings.replaceParamAction == FindReplace::ReplaceValue && effectIndex > -1)
  766. {
  767. m_settings.replaceParam |= mask;
  768. }
  769. } else
  770. {
  771. if(item == kFindRange)
  772. {
  773. CFindRangeDlg dlg(this, 0, m_settings.findParamMin & ~mask, m_cbnParam.GetCount() - 2, m_settings.findParamMax & ~mask, CFindRangeDlg::kHex);
  774. if(dlg.DoModal() == IDOK)
  775. {
  776. m_settings.findParamMin = dlg.GetMinVal() | mask;
  777. m_settings.findParamMax = dlg.GetMaxVal() | mask;
  778. } else
  779. {
  780. // TODO undo selection
  781. }
  782. } else
  783. {
  784. m_settings.findParamMin = m_settings.findParamMax = (item | mask);
  785. }
  786. }
  787. }
  788. void CFindReplaceTab::OnPCParamChanged()
  789. {
  790. CheckOnChange(IDC_CHECK3);
  791. int item = static_cast<int>(m_cbnPCParam.GetItemData(m_cbnPCParam.GetCurSel()));
  792. if(m_isReplaceTab)
  793. {
  794. RelativeOrMultiplyPrompt(m_cbnPCParam, m_settings.replaceParamAction, m_settings.replaceParam, 256, false);
  795. } else
  796. {
  797. if(item == kFindRange)
  798. {
  799. CFindRangeDlg dlg(this, 0, m_settings.findParamMin, ModCommand::maxColumnValue, m_settings.findParamMax, CFindRangeDlg::kDecimal);
  800. if(dlg.DoModal() == IDOK)
  801. {
  802. m_settings.findParamMin = dlg.GetMinVal();
  803. m_settings.findParamMax = dlg.GetMaxVal();
  804. } else
  805. {
  806. // TODO undo selection
  807. }
  808. } else
  809. {
  810. m_settings.findParamMin = m_settings.findParamMax = item;
  811. }
  812. }
  813. }
  814. void CFindReplaceTab::OnCheckChannelSearch()
  815. {
  816. if (!m_isReplaceTab)
  817. {
  818. BOOL b = IsDlgButtonChecked(IDC_CHECK7);
  819. GetDlgItem(IDC_EDIT1)->EnableWindow(b);
  820. GetDlgItem(IDC_SPIN1)->EnableWindow(b);
  821. GetDlgItem(IDC_EDIT2)->EnableWindow(b);
  822. GetDlgItem(IDC_SPIN2)->EnableWindow(b);
  823. }
  824. }
  825. void CFindReplaceTab::OnOK()
  826. {
  827. // Search flags
  828. FlagSet<FindReplace::Flags> &flags = m_isReplaceTab ? m_settings.replaceFlags : m_settings.findFlags;
  829. flags.reset();
  830. flags.set(FindReplace::Note, !!IsDlgButtonChecked(IDC_CHECK1));
  831. flags.set(FindReplace::Instr, !!IsDlgButtonChecked(IDC_CHECK2));
  832. if(IsPCEvent())
  833. {
  834. flags.set(FindReplace::PCParam, !!IsDlgButtonChecked(IDC_CHECK3));
  835. flags.set(FindReplace::PCValue, !!IsDlgButtonChecked(IDC_CHECK4));
  836. } else
  837. {
  838. flags.set(FindReplace::VolCmd, !!IsDlgButtonChecked(IDC_CHECK3));
  839. flags.set(FindReplace::Volume, !!IsDlgButtonChecked(IDC_CHECK4));
  840. flags.set(FindReplace::Command, !!IsDlgButtonChecked(IDC_CHECK5));
  841. flags.set(FindReplace::Param, !!IsDlgButtonChecked(IDC_CHECK6));
  842. }
  843. if(m_isReplaceTab)
  844. {
  845. flags.set(FindReplace::Replace, !!IsDlgButtonChecked(IDC_CHECK7));
  846. flags.set(FindReplace::ReplaceAll, !!IsDlgButtonChecked(IDC_CHECK8));
  847. } else
  848. {
  849. flags.set(FindReplace::InChannels, !!IsDlgButtonChecked(IDC_CHECK7));
  850. flags.set(FindReplace::FullSearch, !!IsDlgButtonChecked(IDC_RADIO2));
  851. flags.set(FindReplace::InPatSelection, !!IsDlgButtonChecked(IDC_RADIO3));
  852. }
  853. // Min/Max channels
  854. if (!m_isReplaceTab)
  855. {
  856. m_settings.findChnMin = static_cast<CHANNELINDEX>(GetDlgItemInt(IDC_EDIT1) - 1);
  857. m_settings.findChnMax = static_cast<CHANNELINDEX>(GetDlgItemInt(IDC_EDIT2) - 1);
  858. if (m_settings.findChnMax < m_settings.findChnMin)
  859. {
  860. std::swap(m_settings.findChnMin, m_settings.findChnMax);
  861. }
  862. }
  863. CPropertyPage::OnOK();
  864. }
  865. OPENMPT_NAMESPACE_END