Mainbar.cpp 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410
  1. /*
  2. * Mainbar.cpp
  3. * -----------
  4. * Purpose: Implementation of OpenMPT's window toolbar.
  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 "Mptrack.h"
  11. #include "Mainfrm.h"
  12. #include "InputHandler.h"
  13. #include "View_tre.h"
  14. #include "ImageLists.h"
  15. #include "Moddoc.h"
  16. #include "../soundlib/mod_specifications.h"
  17. #include "../common/mptStringBuffer.h"
  18. OPENMPT_NAMESPACE_BEGIN
  19. /////////////////////////////////////////////////////////////////////
  20. // CToolBarEx: custom toolbar base class
  21. void CToolBarEx::SetHorizontal()
  22. {
  23. m_bVertical = false;
  24. SetBarStyle(GetBarStyle() | CBRS_ALIGN_TOP);
  25. }
  26. void CToolBarEx::SetVertical()
  27. {
  28. m_bVertical = true;
  29. }
  30. CSize CToolBarEx::CalcDynamicLayout(int nLength, DWORD dwMode)
  31. {
  32. CSize sizeResult;
  33. // if we're committing set the buttons appropriately
  34. if(dwMode & LM_COMMIT)
  35. {
  36. if(dwMode & LM_VERTDOCK)
  37. {
  38. if(!m_bVertical)
  39. SetVertical();
  40. } else
  41. {
  42. if(m_bVertical)
  43. SetHorizontal();
  44. }
  45. sizeResult = CToolBar::CalcDynamicLayout(nLength, dwMode);
  46. } else
  47. {
  48. const bool wasVertical = m_bVertical;
  49. const bool doSwitch = (dwMode & LM_HORZ) ? wasVertical : !wasVertical;
  50. if(doSwitch)
  51. {
  52. if(wasVertical)
  53. SetHorizontal();
  54. else
  55. SetVertical();
  56. }
  57. sizeResult = CToolBar::CalcDynamicLayout(nLength, dwMode);
  58. if(doSwitch)
  59. {
  60. if(wasVertical)
  61. SetHorizontal();
  62. else
  63. SetVertical();
  64. }
  65. }
  66. return sizeResult;
  67. }
  68. BOOL CToolBarEx::EnableControl(CWnd &wnd, UINT nIndex, UINT nHeight)
  69. {
  70. if(wnd.m_hWnd != NULL)
  71. {
  72. CRect rect;
  73. GetItemRect(nIndex, rect);
  74. if(nHeight)
  75. {
  76. int n = (rect.bottom + rect.top - nHeight) / 2;
  77. if(n > rect.top) rect.top = n;
  78. }
  79. wnd.SetWindowPos(NULL, rect.left, rect.top, 0, 0, SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOCOPYBITS);
  80. wnd.ShowWindow(SW_SHOW);
  81. }
  82. return TRUE;
  83. }
  84. void CToolBarEx::ChangeCtrlStyle(LONG lStyle, BOOL bSetStyle)
  85. {
  86. if(m_hWnd)
  87. {
  88. LONG lStyleOld = GetWindowLong(m_hWnd, GWL_STYLE);
  89. if(bSetStyle)
  90. lStyleOld |= lStyle;
  91. else
  92. lStyleOld &= ~lStyle;
  93. SetWindowLong(m_hWnd, GWL_STYLE, lStyleOld);
  94. SetWindowPos(NULL, 0, 0, 0, 0, SWP_NOZORDER | SWP_NOMOVE | SWP_NOSIZE);
  95. Invalidate();
  96. }
  97. }
  98. void CToolBarEx::EnableFlatButtons(BOOL bFlat)
  99. {
  100. m_bFlatButtons = bFlat ? true : false;
  101. ChangeCtrlStyle(TBSTYLE_FLAT, bFlat);
  102. }
  103. /////////////////////////////////////////////////////////////////////
  104. // CMainToolBar
  105. #define SCALEWIDTH(x) (Util::ScalePixels(x, m_hWnd))
  106. #define SCALEHEIGHT(x) (Util::ScalePixels(x, m_hWnd))
  107. // Play Command
  108. #define PLAYCMD_INDEX 10
  109. #define TOOLBAR_IMAGE_PAUSE 8
  110. #define TOOLBAR_IMAGE_PLAY 13
  111. // Base octave
  112. #define EDITOCTAVE_INDEX 13
  113. #define EDITOCTAVE_WIDTH SCALEWIDTH(55)
  114. #define EDITOCTAVE_HEIGHT SCALEHEIGHT(20)
  115. #define SPINOCTAVE_INDEX (EDITOCTAVE_INDEX+1)
  116. #define SPINOCTAVE_WIDTH SCALEWIDTH(16)
  117. #define SPINOCTAVE_HEIGHT (EDITOCTAVE_HEIGHT)
  118. // Static "Tempo:"
  119. #define TEMPOTEXT_INDEX 16
  120. #define TEMPOTEXT_WIDTH SCALEWIDTH(45)
  121. #define TEMPOTEXT_HEIGHT SCALEHEIGHT(20)
  122. // Edit Tempo
  123. #define EDITTEMPO_INDEX (TEMPOTEXT_INDEX+1)
  124. #define EDITTEMPO_WIDTH SCALEWIDTH(48)
  125. #define EDITTEMPO_HEIGHT SCALEHEIGHT(20)
  126. // Spin Tempo
  127. #define SPINTEMPO_INDEX (EDITTEMPO_INDEX+1)
  128. #define SPINTEMPO_WIDTH SCALEWIDTH(16)
  129. #define SPINTEMPO_HEIGHT (EDITTEMPO_HEIGHT)
  130. // Static "Speed:"
  131. #define SPEEDTEXT_INDEX 20
  132. #define SPEEDTEXT_WIDTH SCALEWIDTH(57)
  133. #define SPEEDTEXT_HEIGHT (TEMPOTEXT_HEIGHT)
  134. // Edit Speed
  135. #define EDITSPEED_INDEX (SPEEDTEXT_INDEX+1)
  136. #define EDITSPEED_WIDTH SCALEWIDTH(28)
  137. #define EDITSPEED_HEIGHT (EDITTEMPO_HEIGHT)
  138. // Spin Speed
  139. #define SPINSPEED_INDEX (EDITSPEED_INDEX+1)
  140. #define SPINSPEED_WIDTH SCALEWIDTH(16)
  141. #define SPINSPEED_HEIGHT (EDITSPEED_HEIGHT)
  142. // Static "Rows/Beat:"
  143. #define RPBTEXT_INDEX 24
  144. #define RPBTEXT_WIDTH SCALEWIDTH(63)
  145. #define RPBTEXT_HEIGHT (TEMPOTEXT_HEIGHT)
  146. // Edit Speed
  147. #define EDITRPB_INDEX (RPBTEXT_INDEX+1)
  148. #define EDITRPB_WIDTH SCALEWIDTH(28)
  149. #define EDITRPB_HEIGHT (EDITTEMPO_HEIGHT)
  150. // Spin Speed
  151. #define SPINRPB_INDEX (EDITRPB_INDEX+1)
  152. #define SPINRPB_WIDTH SCALEWIDTH(16)
  153. #define SPINRPB_HEIGHT (EDITRPB_HEIGHT)
  154. // VU Meters
  155. #define VUMETER_INDEX (SPINRPB_INDEX+6)
  156. #define VUMETER_WIDTH SCALEWIDTH(255)
  157. #define VUMETER_HEIGHT SCALEHEIGHT(19)
  158. static UINT MainButtons[] =
  159. {
  160. // same order as in the bitmap 'mainbar.bmp'
  161. ID_FILE_NEW,
  162. ID_FILE_OPEN,
  163. ID_FILE_SAVE,
  164. ID_SEPARATOR,
  165. ID_EDIT_CUT,
  166. ID_EDIT_COPY,
  167. ID_EDIT_PASTE,
  168. ID_SEPARATOR,
  169. ID_MIDI_RECORD,
  170. ID_PLAYER_STOP,
  171. ID_PLAYER_PAUSE,
  172. ID_PLAYER_PLAYFROMSTART,
  173. ID_SEPARATOR,
  174. ID_SEPARATOR,
  175. ID_SEPARATOR,
  176. ID_SEPARATOR,
  177. ID_SEPARATOR,
  178. ID_SEPARATOR,
  179. ID_SEPARATOR,
  180. ID_SEPARATOR,
  181. ID_SEPARATOR,
  182. ID_SEPARATOR,
  183. ID_SEPARATOR,
  184. ID_SEPARATOR,
  185. ID_SEPARATOR,
  186. ID_SEPARATOR,
  187. ID_SEPARATOR,
  188. ID_SEPARATOR,
  189. ID_VIEW_OPTIONS,
  190. ID_PANIC,
  191. ID_UPDATE_AVAILABLE,
  192. ID_SEPARATOR,
  193. ID_SEPARATOR, // VU Meter
  194. };
  195. enum { MAX_MIDI_DEVICES = 256 };
  196. BEGIN_MESSAGE_MAP(CMainToolBar, CToolBarEx)
  197. ON_WM_VSCROLL()
  198. ON_NOTIFY_EX_RANGE(TTN_NEEDTEXT, 0, 0xFFFF, &CMainToolBar::OnToolTipText)
  199. ON_NOTIFY_REFLECT(TBN_DROPDOWN, &CMainToolBar::OnTbnDropDownToolBar)
  200. ON_COMMAND_RANGE(ID_SELECT_MIDI_DEVICE, ID_SELECT_MIDI_DEVICE + MAX_MIDI_DEVICES, &CMainToolBar::OnSelectMIDIDevice)
  201. END_MESSAGE_MAP()
  202. template<typename TWnd>
  203. static bool CreateTextWnd(TWnd &wnd, const TCHAR *text, DWORD style, CWnd *parent, UINT id)
  204. {
  205. auto dc = parent->GetDC();
  206. auto oldFont = dc->SelectObject(CMainFrame::GetGUIFont());
  207. const auto size = dc->GetTextExtent(text);
  208. dc->SelectObject(oldFont);
  209. parent->ReleaseDC(dc);
  210. CRect rect{0, 0, size.cx + Util::ScalePixels(10, *parent), std::max(static_cast<int>(size.cy) + Util::ScalePixels(4, *parent), Util::ScalePixels(20, *parent))};
  211. return wnd.Create(text, style, rect, parent, id) != FALSE;
  212. }
  213. BOOL CMainToolBar::Create(CWnd *parent)
  214. {
  215. CRect rect;
  216. DWORD dwStyle = WS_CHILD | WS_VISIBLE | CBRS_TOP | CBRS_SIZE_DYNAMIC | CBRS_TOOLTIPS | CBRS_FLYBY;
  217. if(!CToolBar::Create(parent, dwStyle))
  218. return FALSE;
  219. CDC *dc = GetDC();
  220. const auto hFont = reinterpret_cast<WPARAM>(CMainFrame::GetGUIFont());
  221. const double scaling = Util::GetDPIx(m_hWnd) / 96.0;
  222. const int imgSize = mpt::saturate_round<int>(16 * scaling), btnSizeX = mpt::saturate_round<int>(23 * scaling), btnSizeY = mpt::saturate_round<int>(22 * scaling);
  223. m_ImageList.Create(IDB_MAINBAR, 16, 16, IMGLIST_NUMIMAGES, 1, dc, scaling, false);
  224. m_ImageListDisabled.Create(IDB_MAINBAR, 16, 16, IMGLIST_NUMIMAGES, 1, dc, scaling, true);
  225. ReleaseDC(dc);
  226. GetToolBarCtrl().SetBitmapSize(CSize(imgSize, imgSize));
  227. GetToolBarCtrl().SetButtonSize(CSize(btnSizeX, btnSizeY));
  228. GetToolBarCtrl().SetImageList(&m_ImageList);
  229. GetToolBarCtrl().SetDisabledImageList(&m_ImageListDisabled);
  230. SendMessage(WM_SETFONT, hFont, TRUE);
  231. if(!SetButtons(MainButtons, mpt::saturate_cast<int>(std::size(MainButtons)))) return FALSE;
  232. CRect temp;
  233. GetItemRect(0, temp);
  234. SetSizes(CSize(temp.Width(), temp.Height()), CSize(imgSize, imgSize));
  235. // Dropdown menus for New and MIDI buttons
  236. LPARAM dwExStyle = GetToolBarCtrl().SendMessage(TB_GETEXTENDEDSTYLE) | TBSTYLE_EX_DRAWDDARROWS;
  237. GetToolBarCtrl().SendMessage(TB_SETEXTENDEDSTYLE, 0, dwExStyle);
  238. SetButtonStyle(CommandToIndex(ID_FILE_NEW), GetButtonStyle(CommandToIndex(ID_FILE_NEW)) | TBSTYLE_DROPDOWN);
  239. SetButtonStyle(CommandToIndex(ID_MIDI_RECORD), GetButtonStyle(CommandToIndex(ID_MIDI_RECORD)) | TBSTYLE_DROPDOWN);
  240. nCurrentSpeed = 6;
  241. nCurrentTempo.Set(125);
  242. nCurrentRowsPerBeat = 4;
  243. nCurrentOctave = -1;
  244. // Octave Edit Box
  245. if(!CreateTextWnd(m_EditOctave, _T("Octave 9"), WS_CHILD | WS_BORDER | SS_LEFT | SS_CENTERIMAGE, this, IDC_EDIT_BASEOCTAVE)) return FALSE;
  246. rect.SetRect(0, 0, SPINOCTAVE_WIDTH, SPINOCTAVE_HEIGHT);
  247. m_SpinOctave.Create(WS_CHILD | UDS_ALIGNRIGHT, rect, this, IDC_SPIN_BASEOCTAVE);
  248. // Tempo Text
  249. if(!CreateTextWnd(m_StaticTempo, _T("Tempo:"), WS_CHILD | SS_CENTER | SS_CENTERIMAGE, this, IDC_TEXT_CURRENTTEMPO)) return FALSE;
  250. // Tempo EditBox
  251. if(!CreateTextWnd(m_EditTempo, _T("999.999"), WS_CHILD | WS_BORDER | SS_LEFT | SS_CENTERIMAGE , this, IDC_EDIT_CURRENTTEMPO)) return FALSE;
  252. // Tempo Spin
  253. rect.SetRect(0, 0, SPINTEMPO_WIDTH, SPINTEMPO_HEIGHT);
  254. m_SpinTempo.Create(WS_CHILD | UDS_ALIGNRIGHT, rect, this, IDC_SPIN_CURRENTTEMPO);
  255. // Speed Text
  256. if(!CreateTextWnd(m_StaticSpeed, _T("Ticks/Row:"), WS_CHILD | SS_CENTER | SS_CENTERIMAGE, this, IDC_TEXT_CURRENTSPEED)) return FALSE;
  257. // Speed EditBox
  258. if(!CreateTextWnd(m_EditSpeed, _T("999"), WS_CHILD | WS_BORDER | SS_LEFT | SS_CENTERIMAGE , this, IDC_EDIT_CURRENTSPEED)) return FALSE;
  259. // Speed Spin
  260. rect.SetRect(0, 0, SPINSPEED_WIDTH, SPINSPEED_HEIGHT);
  261. m_SpinSpeed.Create(WS_CHILD | UDS_ALIGNRIGHT, rect, this, IDC_SPIN_CURRENTSPEED);
  262. // Rows per Beat Text
  263. if(!CreateTextWnd(m_StaticRowsPerBeat, _T("Rows/Beat:"), WS_CHILD | SS_CENTER | SS_CENTERIMAGE, this, IDC_TEXT_RPB)) return FALSE;
  264. // Rows per Beat EditBox
  265. if(!CreateTextWnd(m_EditRowsPerBeat, _T("9999"), WS_CHILD | WS_BORDER | SS_LEFT | SS_CENTERIMAGE , this, IDC_EDIT_RPB)) return FALSE;
  266. // Rows per Beat Spin
  267. rect.SetRect(0, 0, SPINRPB_WIDTH, SPINRPB_HEIGHT);
  268. m_SpinRowsPerBeat.Create(WS_CHILD | UDS_ALIGNRIGHT, rect, this, IDC_SPIN_RPB);
  269. // VU Meter
  270. rect.SetRect(0, 0, VUMETER_WIDTH, VUMETER_HEIGHT);
  271. //m_VuMeter.CreateEx(WS_EX_STATICEDGE, "STATIC", "", WS_CHILD | WS_BORDER | SS_NOTIFY, rect, this, IDC_VUMETER);
  272. m_VuMeter.Create(_T(""), WS_CHILD | WS_BORDER | SS_NOTIFY, rect, this, IDC_VUMETER);
  273. // Adjust control styles
  274. m_EditOctave.SendMessage(WM_SETFONT, hFont);
  275. m_EditOctave.ModifyStyleEx(0, WS_EX_STATICEDGE, SWP_NOACTIVATE);
  276. m_StaticTempo.SendMessage(WM_SETFONT, hFont);
  277. m_EditTempo.SendMessage(WM_SETFONT, hFont);
  278. m_EditTempo.ModifyStyleEx(0, WS_EX_STATICEDGE, SWP_NOACTIVATE);
  279. m_StaticSpeed.SendMessage(WM_SETFONT, hFont);
  280. m_EditSpeed.SendMessage(WM_SETFONT, hFont);
  281. m_EditSpeed.ModifyStyleEx(0, WS_EX_STATICEDGE, SWP_NOACTIVATE);
  282. m_StaticRowsPerBeat.SendMessage(WM_SETFONT, hFont);
  283. m_EditRowsPerBeat.SendMessage(WM_SETFONT, hFont);
  284. m_EditRowsPerBeat.ModifyStyleEx(0, WS_EX_STATICEDGE, SWP_NOACTIVATE);
  285. m_SpinOctave.SetRange(MIN_BASEOCTAVE, MAX_BASEOCTAVE);
  286. m_SpinOctave.SetPos(4);
  287. m_SpinTempo.SetRange(-1, 1);
  288. m_SpinTempo.SetPos(0);
  289. m_SpinSpeed.SetRange(-1, 1);
  290. m_SpinSpeed.SetPos(0);
  291. m_SpinRowsPerBeat.SetRange(-1, 1);
  292. m_SpinRowsPerBeat.SetPos(0);
  293. // Display everything
  294. SetWindowText(_T("Main"));
  295. SetBaseOctave(4);
  296. SetCurrentSong(nullptr);
  297. EnableDocking(CBRS_ALIGN_ANY);
  298. GetToolBarCtrl().SetState(ID_UPDATE_AVAILABLE, TBSTATE_HIDDEN);
  299. return TRUE;
  300. }
  301. void CMainToolBar::Init(CMainFrame *pMainFrm)
  302. {
  303. EnableFlatButtons(TrackerSettings::Instance().m_dwPatternSetup & PATTERN_FLATBUTTONS);
  304. SetHorizontal();
  305. pMainFrm->DockControlBar(this);
  306. }
  307. static int GetWndWidth(const CWnd &wnd)
  308. {
  309. CRect rect;
  310. wnd.GetClientRect(rect);
  311. return rect.right;
  312. }
  313. void CMainToolBar::SetHorizontal()
  314. {
  315. CToolBarEx::SetHorizontal();
  316. m_VuMeter.SetOrientation(true);
  317. SetButtonInfo(EDITOCTAVE_INDEX, IDC_EDIT_BASEOCTAVE, TBBS_SEPARATOR, GetWndWidth(m_EditOctave));
  318. SetButtonInfo(SPINOCTAVE_INDEX, IDC_SPIN_BASEOCTAVE, TBBS_SEPARATOR, SPINOCTAVE_WIDTH);
  319. SetButtonInfo(TEMPOTEXT_INDEX, IDC_TEXT_CURRENTTEMPO, TBBS_SEPARATOR, GetWndWidth(m_StaticTempo));
  320. SetButtonInfo(EDITTEMPO_INDEX, IDC_EDIT_CURRENTTEMPO, TBBS_SEPARATOR, GetWndWidth(m_EditTempo));
  321. SetButtonInfo(SPINTEMPO_INDEX, IDC_SPIN_CURRENTTEMPO, TBBS_SEPARATOR, SPINTEMPO_WIDTH);
  322. SetButtonInfo(SPEEDTEXT_INDEX, IDC_TEXT_CURRENTSPEED, TBBS_SEPARATOR, GetWndWidth(m_StaticSpeed));
  323. SetButtonInfo(EDITSPEED_INDEX, IDC_EDIT_CURRENTSPEED, TBBS_SEPARATOR, GetWndWidth(m_EditSpeed));
  324. SetButtonInfo(SPINSPEED_INDEX, IDC_SPIN_CURRENTSPEED, TBBS_SEPARATOR, SPINSPEED_WIDTH);
  325. SetButtonInfo(RPBTEXT_INDEX, IDC_TEXT_RPB, TBBS_SEPARATOR, GetWndWidth(m_StaticRowsPerBeat));
  326. SetButtonInfo(EDITRPB_INDEX, IDC_EDIT_RPB, TBBS_SEPARATOR, GetWndWidth(m_EditRowsPerBeat));
  327. SetButtonInfo(SPINRPB_INDEX, IDC_SPIN_RPB, TBBS_SEPARATOR, SPINRPB_WIDTH);
  328. SetButtonInfo(VUMETER_INDEX, IDC_VUMETER, TBBS_SEPARATOR, VUMETER_WIDTH);
  329. //SetButtonInfo(SPINSPEED_INDEX+1, IDC_TEXT_BPM, TBBS_SEPARATOR, SPEEDTEXT_WIDTH);
  330. // Octave Box
  331. EnableControl(m_EditOctave, EDITOCTAVE_INDEX);
  332. EnableControl(m_SpinOctave, SPINOCTAVE_INDEX);
  333. // Tempo
  334. EnableControl(m_StaticTempo, TEMPOTEXT_INDEX, TEMPOTEXT_HEIGHT);
  335. EnableControl(m_EditTempo, EDITTEMPO_INDEX, EDITTEMPO_HEIGHT);
  336. EnableControl(m_SpinTempo, SPINTEMPO_INDEX, SPINTEMPO_HEIGHT);
  337. // Speed
  338. EnableControl(m_StaticSpeed, SPEEDTEXT_INDEX, SPEEDTEXT_HEIGHT);
  339. EnableControl(m_EditSpeed, EDITSPEED_INDEX, EDITSPEED_HEIGHT);
  340. EnableControl(m_SpinSpeed, SPINSPEED_INDEX, SPINSPEED_HEIGHT);
  341. // Rows per Beat
  342. EnableControl(m_StaticRowsPerBeat, RPBTEXT_INDEX, RPBTEXT_HEIGHT);
  343. EnableControl(m_EditRowsPerBeat, EDITRPB_INDEX, EDITRPB_HEIGHT);
  344. EnableControl(m_SpinRowsPerBeat, SPINRPB_INDEX, SPINRPB_HEIGHT);
  345. EnableControl(m_VuMeter, VUMETER_INDEX, VUMETER_HEIGHT);
  346. }
  347. void CMainToolBar::SetVertical()
  348. {
  349. CToolBarEx::SetVertical();
  350. m_VuMeter.SetOrientation(false);
  351. // Change Buttons
  352. SetButtonInfo(EDITOCTAVE_INDEX, ID_SEPARATOR, TBBS_SEPARATOR, 1);
  353. SetButtonInfo(SPINOCTAVE_INDEX, ID_SEPARATOR, TBBS_SEPARATOR, 1);
  354. SetButtonInfo(TEMPOTEXT_INDEX, ID_SEPARATOR, TBBS_SEPARATOR, 1);
  355. SetButtonInfo(EDITTEMPO_INDEX, ID_SEPARATOR, TBBS_SEPARATOR, 1);
  356. SetButtonInfo(SPINTEMPO_INDEX, ID_SEPARATOR, TBBS_SEPARATOR, 1);
  357. SetButtonInfo(SPEEDTEXT_INDEX, ID_SEPARATOR, TBBS_SEPARATOR, 1);
  358. SetButtonInfo(EDITSPEED_INDEX, ID_SEPARATOR, TBBS_SEPARATOR, 1);
  359. SetButtonInfo(SPINSPEED_INDEX, ID_SEPARATOR, TBBS_SEPARATOR, 1);
  360. SetButtonInfo(RPBTEXT_INDEX, ID_SEPARATOR, TBBS_SEPARATOR, 1);
  361. SetButtonInfo(EDITRPB_INDEX, ID_SEPARATOR, TBBS_SEPARATOR, 1);
  362. SetButtonInfo(SPINRPB_INDEX, ID_SEPARATOR, TBBS_SEPARATOR, 1);
  363. SetButtonInfo(VUMETER_INDEX, IDC_VUMETER, TBBS_SEPARATOR, VUMETER_HEIGHT);
  364. // Hide Controls
  365. if(m_EditOctave.m_hWnd) m_EditOctave.ShowWindow(SW_HIDE);
  366. if(m_SpinOctave.m_hWnd) m_SpinOctave.ShowWindow(SW_HIDE);
  367. if(m_StaticTempo.m_hWnd) m_StaticTempo.ShowWindow(SW_HIDE);
  368. if(m_EditTempo.m_hWnd) m_EditTempo.ShowWindow(SW_HIDE);
  369. if(m_SpinTempo.m_hWnd) m_SpinTempo.ShowWindow(SW_HIDE);
  370. if(m_StaticSpeed.m_hWnd) m_StaticSpeed.ShowWindow(SW_HIDE);
  371. if(m_EditSpeed.m_hWnd) m_EditSpeed.ShowWindow(SW_HIDE);
  372. if(m_SpinSpeed.m_hWnd) m_SpinSpeed.ShowWindow(SW_HIDE);
  373. if(m_StaticRowsPerBeat.m_hWnd) m_StaticRowsPerBeat.ShowWindow(SW_HIDE);
  374. if(m_EditRowsPerBeat.m_hWnd) m_EditRowsPerBeat.ShowWindow(SW_HIDE);
  375. if(m_SpinRowsPerBeat.m_hWnd) m_SpinRowsPerBeat.ShowWindow(SW_HIDE);
  376. EnableControl(m_VuMeter, VUMETER_INDEX, VUMETER_HEIGHT);
  377. //if(m_StaticBPM.m_hWnd) m_StaticBPM.ShowWindow(SW_HIDE);
  378. }
  379. UINT CMainToolBar::GetBaseOctave() const
  380. {
  381. if(nCurrentOctave >= MIN_BASEOCTAVE) return (UINT)nCurrentOctave;
  382. return 4;
  383. }
  384. BOOL CMainToolBar::SetBaseOctave(UINT nOctave)
  385. {
  386. TCHAR s[64];
  387. if((nOctave < MIN_BASEOCTAVE) || (nOctave > MAX_BASEOCTAVE)) return FALSE;
  388. if(nOctave != (UINT)nCurrentOctave)
  389. {
  390. nCurrentOctave = nOctave;
  391. wsprintf(s, _T(" Octave %d"), nOctave);
  392. m_EditOctave.SetWindowText(s);
  393. m_SpinOctave.SetPos(nOctave);
  394. }
  395. return TRUE;
  396. }
  397. bool CMainToolBar::ShowUpdateInfo(const CString &newVersion, const CString &infoURL, bool showHighLight)
  398. {
  399. GetToolBarCtrl().SetState(ID_UPDATE_AVAILABLE, TBSTATE_ENABLED);
  400. if(m_bVertical)
  401. SetVertical();
  402. else
  403. SetHorizontal();
  404. CRect rect;
  405. GetToolBarCtrl().GetRect(ID_UPDATE_AVAILABLE, &rect);
  406. CPoint pt = rect.CenterPoint();
  407. ClientToScreen(&pt);
  408. CMainFrame::GetMainFrame()->GetWindowRect(rect);
  409. LimitMax(pt.x, rect.right);
  410. if(showHighLight)
  411. {
  412. return m_tooltip.ShowUpdate(*this, newVersion, infoURL, rect, pt, ID_UPDATE_AVAILABLE);
  413. } else
  414. {
  415. return true;
  416. }
  417. }
  418. void CMainToolBar::RemoveUpdateInfo()
  419. {
  420. if(m_tooltip)
  421. m_tooltip.Pop();
  422. GetToolBarCtrl().SetState(ID_UPDATE_AVAILABLE, TBSTATE_HIDDEN);
  423. }
  424. BOOL CMainToolBar::SetCurrentSong(CSoundFile *pSndFile)
  425. {
  426. static CSoundFile *sndFile = nullptr;
  427. if(pSndFile != sndFile)
  428. {
  429. sndFile = pSndFile;
  430. }
  431. // Update Info
  432. if(pSndFile)
  433. {
  434. TCHAR s[32];
  435. // Update play/pause button
  436. if(nCurrentTempo == TEMPO(0, 0)) SetButtonInfo(PLAYCMD_INDEX, ID_PLAYER_PAUSE, TBBS_BUTTON, TOOLBAR_IMAGE_PAUSE);
  437. // Update Speed
  438. int nSpeed = pSndFile->m_PlayState.m_nMusicSpeed;
  439. if(nSpeed != nCurrentSpeed)
  440. {
  441. CModDoc *modDoc = pSndFile->GetpModDoc();
  442. if(modDoc != nullptr)
  443. {
  444. // Update envelope views if speed has changed
  445. modDoc->UpdateAllViews(InstrumentHint().Envelope());
  446. }
  447. if(nCurrentSpeed < 0) m_SpinSpeed.EnableWindow(TRUE);
  448. nCurrentSpeed = nSpeed;
  449. wsprintf(s, _T("%u"), static_cast<unsigned int>(nCurrentSpeed));
  450. m_EditSpeed.SetWindowText(s);
  451. }
  452. TEMPO nTempo = pSndFile->m_PlayState.m_nMusicTempo;
  453. if(nTempo != nCurrentTempo)
  454. {
  455. if(nCurrentTempo <= TEMPO(0, 0)) m_SpinTempo.EnableWindow(TRUE);
  456. nCurrentTempo = nTempo;
  457. if(nCurrentTempo.GetFract() == 0)
  458. _stprintf(s, _T("%u"), nCurrentTempo.GetInt());
  459. else
  460. _stprintf(s, _T("%.4f"), nCurrentTempo.ToDouble());
  461. m_EditTempo.SetWindowText(s);
  462. }
  463. int nRowsPerBeat = pSndFile->m_PlayState.m_nCurrentRowsPerBeat;
  464. if(nRowsPerBeat != nCurrentRowsPerBeat)
  465. {
  466. if(nCurrentRowsPerBeat < 0) m_SpinRowsPerBeat.EnableWindow(TRUE);
  467. nCurrentRowsPerBeat = nRowsPerBeat;
  468. wsprintf(s, _T("%u"), static_cast<unsigned int>(nCurrentRowsPerBeat));
  469. m_EditRowsPerBeat.SetWindowText(s);
  470. }
  471. } else
  472. {
  473. if(nCurrentTempo > TEMPO(0, 0))
  474. {
  475. nCurrentTempo.Set(0);
  476. m_EditTempo.SetWindowText(_T("---"));
  477. m_SpinTempo.EnableWindow(FALSE);
  478. SetButtonInfo(PLAYCMD_INDEX, ID_PLAYER_PLAY, TBBS_BUTTON, TOOLBAR_IMAGE_PLAY);
  479. }
  480. if(nCurrentSpeed != -1)
  481. {
  482. nCurrentSpeed = -1;
  483. m_EditSpeed.SetWindowText(_T("---"));
  484. m_SpinSpeed.EnableWindow(FALSE);
  485. }
  486. if(nCurrentRowsPerBeat != -1)
  487. {
  488. nCurrentRowsPerBeat = -1;
  489. m_EditRowsPerBeat.SetWindowText(_T("---"));
  490. m_SpinRowsPerBeat.EnableWindow(FALSE);
  491. }
  492. }
  493. return TRUE;
  494. }
  495. void CMainToolBar::OnVScroll(UINT nCode, UINT nPos, CScrollBar *pScrollBar)
  496. {
  497. CMainFrame *pMainFrm;
  498. CToolBarEx::OnVScroll(nCode, nPos, pScrollBar);
  499. short int oct = (short int)m_SpinOctave.GetPos();
  500. if((oct >= MIN_BASEOCTAVE) && ((int)oct != nCurrentOctave))
  501. {
  502. SetBaseOctave(oct);
  503. }
  504. if((nCurrentSpeed < 0) || (nCurrentTempo <= TEMPO(0, 0))) return;
  505. if((pMainFrm = CMainFrame::GetMainFrame()) != nullptr)
  506. {
  507. CSoundFile *pSndFile = pMainFrm->GetSoundFilePlaying();
  508. if(pSndFile)
  509. {
  510. const auto &specs = pSndFile->GetModSpecifications();
  511. int n;
  512. if((n = mpt::signum(m_SpinTempo.GetPos32())) != 0)
  513. {
  514. TEMPO newTempo;
  515. if(specs.hasFractionalTempo)
  516. {
  517. n *= TEMPO::fractFact;
  518. if(CMainFrame::GetMainFrame()->GetInputHandler()->CtrlPressed())
  519. n /= 100;
  520. else
  521. n /= 10;
  522. newTempo.SetRaw(n);
  523. } else
  524. {
  525. newTempo = TEMPO(n, 0);
  526. }
  527. newTempo += nCurrentTempo;
  528. pSndFile->SetTempo(Clamp(newTempo, specs.GetTempoMin(), specs.GetTempoMax()), true);
  529. m_SpinTempo.SetPos(0);
  530. }
  531. if((n = mpt::signum(m_SpinSpeed.GetPos32())) != 0)
  532. {
  533. pSndFile->m_PlayState.m_nMusicSpeed = Clamp(uint32(nCurrentSpeed + n), specs.speedMin, specs.speedMax);
  534. m_SpinSpeed.SetPos(0);
  535. }
  536. if((n = m_SpinRowsPerBeat.GetPos32()) != 0)
  537. {
  538. if(n < 0)
  539. {
  540. if(nCurrentRowsPerBeat > 1)
  541. SetRowsPerBeat(nCurrentRowsPerBeat - 1);
  542. } else if(static_cast<ROWINDEX>(nCurrentRowsPerBeat) < pSndFile->m_PlayState.m_nCurrentRowsPerMeasure)
  543. {
  544. SetRowsPerBeat(nCurrentRowsPerBeat + 1);
  545. }
  546. m_SpinRowsPerBeat.SetPos(0);
  547. // Update pattern editor
  548. pMainFrm->PostMessage(WM_MOD_INVALIDATEPATTERNS, HINT_MPTOPTIONS);
  549. }
  550. SetCurrentSong(pSndFile);
  551. }
  552. }
  553. }
  554. void CMainToolBar::OnTbnDropDownToolBar(NMHDR *pNMHDR, LRESULT *pResult)
  555. {
  556. NMTOOLBAR *pToolBar = reinterpret_cast<NMTOOLBAR *>(pNMHDR);
  557. ClientToScreen(&(pToolBar->rcButton));
  558. switch(pToolBar->iItem)
  559. {
  560. case ID_FILE_NEW:
  561. CMainFrame::GetMainFrame()->GetFileMenu()->GetSubMenu(0)->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, pToolBar->rcButton.left, pToolBar->rcButton.bottom, this);
  562. break;
  563. case ID_MIDI_RECORD:
  564. // Show a list of MIDI devices
  565. {
  566. HMENU hMenu = ::CreatePopupMenu();
  567. MIDIINCAPS mic;
  568. UINT numDevs = midiInGetNumDevs();
  569. if(numDevs > MAX_MIDI_DEVICES) numDevs = MAX_MIDI_DEVICES;
  570. UINT current = TrackerSettings::Instance().GetCurrentMIDIDevice();
  571. for(UINT i = 0; i < numDevs; i++)
  572. {
  573. mic.szPname[0] = 0;
  574. if(midiInGetDevCaps(i, &mic, sizeof(mic)) == MMSYSERR_NOERROR)
  575. {
  576. ::AppendMenu(hMenu, MF_STRING | (i == current ? MF_CHECKED : 0), ID_SELECT_MIDI_DEVICE + i, theApp.GetFriendlyMIDIPortName(mpt::String::ReadCStringBuf(mic.szPname), true));
  577. }
  578. }
  579. if(!numDevs)
  580. {
  581. ::AppendMenu(hMenu, MF_STRING | MF_GRAYED, 0, _T("No MIDI input devices found"));
  582. }
  583. ::TrackPopupMenu(hMenu, TPM_LEFTALIGN | TPM_RIGHTBUTTON, pToolBar->rcButton.left, pToolBar->rcButton.bottom, 0, m_hWnd, NULL);
  584. ::DestroyMenu(hMenu);
  585. }
  586. break;
  587. }
  588. *pResult = 0;
  589. }
  590. void CMainToolBar::OnSelectMIDIDevice(UINT id)
  591. {
  592. CMainFrame::GetMainFrame()->midiCloseDevice();
  593. TrackerSettings::Instance().SetMIDIDevice(id - ID_SELECT_MIDI_DEVICE);
  594. CMainFrame::GetMainFrame()->midiOpenDevice();
  595. }
  596. void CMainToolBar::SetRowsPerBeat(ROWINDEX nNewRPB)
  597. {
  598. CMainFrame *pMainFrm = CMainFrame::GetMainFrame();
  599. if(pMainFrm == nullptr)
  600. return;
  601. CModDoc *pModDoc = pMainFrm->GetModPlaying();
  602. CSoundFile *pSndFile = pMainFrm->GetSoundFilePlaying();
  603. if(pModDoc == nullptr || pSndFile == nullptr)
  604. return;
  605. pSndFile->m_PlayState.m_nCurrentRowsPerBeat = nNewRPB;
  606. PATTERNINDEX nPat = pSndFile->GetCurrentPattern();
  607. if(pSndFile->Patterns[nPat].GetOverrideSignature())
  608. {
  609. if(nNewRPB <= pSndFile->Patterns[nPat].GetRowsPerMeasure())
  610. {
  611. pSndFile->Patterns[nPat].SetSignature(nNewRPB, pSndFile->Patterns[nPat].GetRowsPerMeasure());
  612. TempoSwing swing = pSndFile->Patterns[nPat].GetTempoSwing();
  613. if(!swing.empty())
  614. {
  615. swing.resize(nNewRPB);
  616. pSndFile->Patterns[nPat].SetTempoSwing(swing);
  617. }
  618. pModDoc->SetModified();
  619. }
  620. } else
  621. {
  622. if(nNewRPB <= pSndFile->m_nDefaultRowsPerMeasure)
  623. {
  624. pSndFile->m_nDefaultRowsPerBeat = nNewRPB;
  625. if(!pSndFile->m_tempoSwing.empty()) pSndFile->m_tempoSwing.resize(nNewRPB);
  626. pModDoc->SetModified();
  627. }
  628. }
  629. }
  630. BOOL CMainToolBar::OnToolTipText(UINT, NMHDR* pNMHDR, LRESULT* pResult)
  631. {
  632. auto pTTT = reinterpret_cast<TOOLTIPTEXT *>(pNMHDR);
  633. UINT_PTR id = pNMHDR->idFrom;
  634. if(pTTT->uFlags & TTF_IDISHWND)
  635. {
  636. // idFrom is actually the HWND of the tool
  637. id = (UINT_PTR)::GetDlgCtrlID((HWND)id);
  638. }
  639. const TCHAR *s = nullptr;
  640. CommandID cmd = kcNull;
  641. switch(id)
  642. {
  643. case ID_FILE_NEW: s = _T("New"); cmd = kcFileNew; break;
  644. case ID_FILE_OPEN: s = _T("Open"); cmd = kcFileOpen; break;
  645. case ID_FILE_SAVE: s = _T("Save"); cmd = kcFileSave; break;
  646. case ID_EDIT_CUT: s = _T("Cut"); cmd = kcEditCut; break;
  647. case ID_EDIT_COPY: s = _T("Copy"); cmd = kcEditCopy; break;
  648. case ID_EDIT_PASTE: s = _T("Paste"); cmd = kcEditPaste; break;
  649. case ID_MIDI_RECORD: s = _T("MIDI Record"); cmd = kcMidiRecord; break;
  650. case ID_PLAYER_STOP: s = _T("Stop"); cmd = kcStopSong; break;
  651. case ID_PLAYER_PLAY: s = _T("Play"); cmd = kcPlayPauseSong; break;
  652. case ID_PLAYER_PAUSE: s = _T("Pause"); cmd = kcPlayPauseSong; break;
  653. case ID_PLAYER_PLAYFROMSTART: s = _T("Play From Start"); cmd = kcPlaySongFromStart; break;
  654. case ID_VIEW_OPTIONS: s = _T("Setup"); cmd = kcViewOptions; break;
  655. case ID_PANIC: s = _T("Stop all hanging plugin and sample voices"); cmd = kcPanic; break;
  656. case ID_UPDATE_AVAILABLE: s = _T("A new update is available."); break;
  657. }
  658. if(s == nullptr)
  659. return FALSE;
  660. mpt::tstring fmt = s;
  661. if(cmd != kcNull)
  662. {
  663. auto keyText = CMainFrame::GetInputHandler()->m_activeCommandSet->GetKeyTextFromCommand(cmd, 0);
  664. if(!keyText.IsEmpty())
  665. fmt += MPT_TFORMAT(" ({})")(keyText);
  666. }
  667. mpt::String::WriteWinBuf(pTTT->szText) = fmt;
  668. *pResult = 0;
  669. // bring the tooltip window above other popup windows
  670. ::SetWindowPos(pNMHDR->hwndFrom, HWND_TOP, 0, 0, 0, 0,
  671. SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOMOVE | SWP_NOOWNERZORDER);
  672. return TRUE; // message was handled
  673. }
  674. ///////////////////////////////////////////////////////////////////////////////////////////////////
  675. // CModTreeBar
  676. BEGIN_MESSAGE_MAP(CModTreeBar, CDialogBar)
  677. //{{AFX_MSG_MAP(CModTreeBar)
  678. ON_WM_NCCALCSIZE()
  679. ON_WM_NCPAINT()
  680. ON_WM_NCHITTEST()
  681. ON_WM_SIZE()
  682. ON_WM_NCMOUSEMOVE()
  683. ON_WM_MOUSEMOVE()
  684. ON_WM_LBUTTONDOWN()
  685. ON_WM_NCLBUTTONDOWN()
  686. ON_WM_LBUTTONUP()
  687. ON_WM_NCLBUTTONUP()
  688. ON_MESSAGE(WM_INITDIALOG, &CModTreeBar::OnInitDialog)
  689. //}}AFX_MSG_MAP
  690. END_MESSAGE_MAP()
  691. CModTreeBar::CModTreeBar()
  692. {
  693. m_nTreeSplitRatio = TrackerSettings::Instance().glTreeSplitRatio;
  694. }
  695. LRESULT CModTreeBar::OnInitDialog(WPARAM wParam, LPARAM lParam)
  696. {
  697. LRESULT l = CDialogBar::HandleInitDialog(wParam, lParam);
  698. m_pModTreeData = new CModTree(nullptr);
  699. if(m_pModTreeData) m_pModTreeData->SubclassDlgItem(IDC_TREEDATA, this);
  700. m_pModTree = new CModTree(m_pModTreeData);
  701. if(m_pModTree) m_pModTree->SubclassDlgItem(IDC_TREEVIEW, this);
  702. m_dwStatus = 0;
  703. m_sizeDefault.cx = Util::ScalePixels(TrackerSettings::Instance().glTreeWindowWidth, m_hWnd) + 3;
  704. m_sizeDefault.cy = 32767;
  705. return l;
  706. }
  707. CModTreeBar::~CModTreeBar()
  708. {
  709. if(m_pModTree)
  710. {
  711. delete m_pModTree;
  712. m_pModTree = nullptr;
  713. }
  714. if(m_pModTreeData)
  715. {
  716. delete m_pModTreeData;
  717. m_pModTreeData = nullptr;
  718. }
  719. }
  720. void CModTreeBar::Init()
  721. {
  722. m_nTreeSplitRatio = TrackerSettings::Instance().glTreeSplitRatio;
  723. if(m_pModTree)
  724. {
  725. m_pModTreeData->Init();
  726. m_pModTree->Init();
  727. }
  728. }
  729. void CModTreeBar::RefreshDlsBanks()
  730. {
  731. if(m_pModTree) m_pModTree->RefreshDlsBanks();
  732. }
  733. void CModTreeBar::RefreshMidiLibrary()
  734. {
  735. if(m_pModTree) m_pModTree->RefreshMidiLibrary();
  736. }
  737. void CModTreeBar::OnOptionsChanged()
  738. {
  739. if(m_pModTree) m_pModTree->OnOptionsChanged();
  740. }
  741. void CModTreeBar::RecalcLayout()
  742. {
  743. CRect rect;
  744. if((m_pModTree) && (m_pModTreeData))
  745. {
  746. int cytree, cydata, cyavail;
  747. GetClientRect(&rect);
  748. cyavail = rect.Height() - 3;
  749. if(cyavail < 0) cyavail = 0;
  750. cytree = (cyavail * m_nTreeSplitRatio) >> 8;
  751. cydata = cyavail - cytree;
  752. m_pModTree->SetWindowPos(NULL, 0,0, rect.Width(), cytree, SWP_NOZORDER|SWP_NOACTIVATE);
  753. m_pModTreeData->SetWindowPos(NULL, 0,cytree+3, rect.Width(), cydata, SWP_NOZORDER|SWP_NOACTIVATE);
  754. }
  755. }
  756. CSize CModTreeBar::CalcFixedLayout(BOOL, BOOL)
  757. {
  758. int width = Util::ScalePixels(TrackerSettings::Instance().glTreeWindowWidth, m_hWnd);
  759. CSize sz;
  760. m_sizeDefault.cx = width;
  761. m_sizeDefault.cy = 32767;
  762. sz.cx = width + 3;
  763. if(sz.cx < 4) sz.cx = 4;
  764. sz.cy = 32767;
  765. return sz;
  766. }
  767. void CModTreeBar::DoMouseMove(CPoint pt)
  768. {
  769. CRect rect;
  770. if((m_dwStatus & (MTB_CAPTURE|MTB_DRAGGING)) && (::GetCapture() != m_hWnd))
  771. {
  772. CancelTracking();
  773. }
  774. if(m_dwStatus & MTB_DRAGGING)
  775. {
  776. if(m_dwStatus & MTB_VERTICAL)
  777. {
  778. if(m_pModTree)
  779. {
  780. m_pModTree->GetWindowRect(&rect);
  781. pt.y += rect.Height();
  782. }
  783. GetClientRect(&rect);
  784. pt.y -= ptDragging.y;
  785. if(pt.y < 0) pt.y = 0;
  786. if(pt.y > rect.Height()) pt.y = rect.Height();
  787. if((!(m_dwStatus & MTB_TRACKER)) || (pt.y != (int)m_nTrackPos))
  788. {
  789. if(m_dwStatus & MTB_TRACKER) OnInvertTracker(m_nTrackPos);
  790. m_nTrackPos = pt.y;
  791. OnInvertTracker(m_nTrackPos);
  792. m_dwStatus |= MTB_TRACKER;
  793. }
  794. } else
  795. {
  796. pt.x -= ptDragging.x - m_cxOriginal + 3;
  797. if(pt.x < 0) pt.x = 0;
  798. if((!(m_dwStatus & MTB_TRACKER)) || (pt.x != (int)m_nTrackPos))
  799. {
  800. if(m_dwStatus & MTB_TRACKER) OnInvertTracker(m_nTrackPos);
  801. m_nTrackPos = pt.x;
  802. OnInvertTracker(m_nTrackPos);
  803. m_dwStatus |= MTB_TRACKER;
  804. }
  805. }
  806. } else
  807. {
  808. UINT nCursor = 0;
  809. GetClientRect(&rect);
  810. rect.left = rect.right - 2;
  811. rect.right = rect.left + 5;
  812. if(rect.PtInRect(pt))
  813. {
  814. nCursor = AFX_IDC_HSPLITBAR;
  815. } else
  816. if(m_pModTree)
  817. {
  818. m_pModTree->GetWindowRect(&rect);
  819. rect.right = rect.Width();
  820. rect.left = 0;
  821. rect.top = rect.Height()-1;
  822. rect.bottom = rect.top + 5;
  823. if(rect.PtInRect(pt))
  824. {
  825. nCursor = AFX_IDC_VSPLITBAR;
  826. }
  827. }
  828. if(nCursor)
  829. {
  830. UINT nDir = (nCursor == AFX_IDC_VSPLITBAR) ? MTB_VERTICAL : 0;
  831. BOOL bLoad = FALSE;
  832. if(!(m_dwStatus & MTB_CAPTURE))
  833. {
  834. m_dwStatus |= MTB_CAPTURE;
  835. SetCapture();
  836. bLoad = TRUE;
  837. } else
  838. {
  839. if(nDir != (m_dwStatus & MTB_VERTICAL)) bLoad = TRUE;
  840. }
  841. m_dwStatus &= ~MTB_VERTICAL;
  842. m_dwStatus |= nDir;
  843. if(bLoad) SetCursor(theApp.LoadCursor(nCursor));
  844. } else
  845. {
  846. if(m_dwStatus & MTB_CAPTURE)
  847. {
  848. m_dwStatus &= ~MTB_CAPTURE;
  849. ReleaseCapture();
  850. SetCursor(LoadCursor(NULL, IDC_ARROW));
  851. }
  852. }
  853. }
  854. }
  855. void CModTreeBar::DoLButtonDown(CPoint pt)
  856. {
  857. if((m_dwStatus & MTB_CAPTURE) && (!(m_dwStatus & MTB_DRAGGING)))
  858. {
  859. CRect rect;
  860. GetWindowRect(&rect);
  861. m_cxOriginal = rect.Width();
  862. m_cyOriginal = rect.Height();
  863. ptDragging = pt;
  864. m_dwStatus |= MTB_DRAGGING;
  865. DoMouseMove(pt);
  866. }
  867. }
  868. void CModTreeBar::DoLButtonUp()
  869. {
  870. if(m_dwStatus & MTB_DRAGGING)
  871. {
  872. CRect rect;
  873. m_dwStatus &= ~MTB_DRAGGING;
  874. if(m_dwStatus & MTB_TRACKER)
  875. {
  876. OnInvertTracker(m_nTrackPos);
  877. m_dwStatus &= ~MTB_TRACKER;
  878. }
  879. if(m_dwStatus & MTB_VERTICAL)
  880. {
  881. GetClientRect(&rect);
  882. int cyavail = rect.Height() - 3;
  883. if(cyavail < 4) cyavail = 4;
  884. int ratio = (m_nTrackPos << 8) / cyavail;
  885. if(ratio < 0) ratio = 0;
  886. if(ratio > 256) ratio = 256;
  887. m_nTreeSplitRatio = ratio;
  888. TrackerSettings::Instance().glTreeSplitRatio = ratio;
  889. RecalcLayout();
  890. } else
  891. {
  892. GetWindowRect(&rect);
  893. m_nTrackPos += 3;
  894. if(m_nTrackPos < 4) m_nTrackPos = 4;
  895. CMainFrame *pMainFrm = CMainFrame::GetMainFrame();
  896. if((m_nTrackPos != (UINT)rect.Width()) && (pMainFrm))
  897. {
  898. TrackerSettings::Instance().glTreeWindowWidth = Util::ScalePixelsInv(m_nTrackPos - 3, m_hWnd);
  899. m_sizeDefault.cx = m_nTrackPos;
  900. m_sizeDefault.cy = 32767;
  901. pMainFrm->RecalcLayout();
  902. }
  903. }
  904. }
  905. }
  906. void CModTreeBar::CancelTracking()
  907. {
  908. if(m_dwStatus & MTB_TRACKER)
  909. {
  910. OnInvertTracker(m_nTrackPos);
  911. m_dwStatus &= ~MTB_TRACKER;
  912. }
  913. m_dwStatus &= ~MTB_DRAGGING;
  914. if(m_dwStatus & MTB_CAPTURE)
  915. {
  916. m_dwStatus &= ~MTB_CAPTURE;
  917. ReleaseCapture();
  918. }
  919. }
  920. void CModTreeBar::OnInvertTracker(UINT x)
  921. {
  922. CMainFrame *pMainFrm = CMainFrame::GetMainFrame();
  923. if(pMainFrm)
  924. {
  925. CRect rect;
  926. GetClientRect(&rect);
  927. if(m_dwStatus & MTB_VERTICAL)
  928. {
  929. rect.top = x;
  930. rect.bottom = rect.top + 4;
  931. } else
  932. {
  933. rect.left = x;
  934. rect.right = rect.left + 4;
  935. }
  936. ClientToScreen(&rect);
  937. pMainFrm->ScreenToClient(&rect);
  938. // pat-blt without clip children on
  939. CDC* pDC = pMainFrm->GetDC();
  940. // invert the brush pattern (looks just like frame window sizing)
  941. CBrush* pBrush = CDC::GetHalftoneBrush();
  942. HBRUSH hOldBrush = NULL;
  943. if(pBrush != NULL)
  944. hOldBrush = (HBRUSH)SelectObject(pDC->m_hDC, pBrush->m_hObject);
  945. pDC->PatBlt(rect.left, rect.top, rect.Width(), rect.Height(), PATINVERT);
  946. if(hOldBrush != NULL)
  947. SelectObject(pDC->m_hDC, hOldBrush);
  948. ReleaseDC(pDC);
  949. }
  950. }
  951. void CModTreeBar::OnDocumentCreated(CModDoc *pModDoc)
  952. {
  953. if(m_pModTree && pModDoc) m_pModTree->AddDocument(*pModDoc);
  954. }
  955. void CModTreeBar::OnDocumentClosed(CModDoc *pModDoc)
  956. {
  957. if(m_pModTree && pModDoc) m_pModTree->RemoveDocument(*pModDoc);
  958. }
  959. void CModTreeBar::OnUpdate(CModDoc *pModDoc, UpdateHint hint, CObject *pHint)
  960. {
  961. if(m_pModTree) m_pModTree->OnUpdate(pModDoc, hint, pHint);
  962. }
  963. void CModTreeBar::UpdatePlayPos(CModDoc *pModDoc, Notification *pNotify)
  964. {
  965. if(m_pModTree && pModDoc) m_pModTree->UpdatePlayPos(*pModDoc, pNotify);
  966. }
  967. ////////////////////////////////////////////////////////////////////////////////////////////////////
  968. // CModTreeBar message handlers
  969. void CModTreeBar::OnNcCalcSize(BOOL bCalcValidRects, NCCALCSIZE_PARAMS* lpncsp)
  970. {
  971. CDialogBar::OnNcCalcSize(bCalcValidRects, lpncsp);
  972. if(lpncsp)
  973. {
  974. lpncsp->rgrc[0].right -= 3;
  975. if(lpncsp->rgrc[0].right < lpncsp->rgrc[0].left) lpncsp->rgrc[0].right = lpncsp->rgrc[0].left;
  976. }
  977. }
  978. LRESULT CModTreeBar::OnNcHitTest(CPoint point)
  979. {
  980. CRect rect;
  981. GetWindowRect(&rect);
  982. rect.DeflateRect(1,1);
  983. rect.right -= 3;
  984. if(!rect.PtInRect(point)) return HTBORDER;
  985. return CDialogBar::OnNcHitTest(point);
  986. }
  987. void CModTreeBar::OnNcPaint()
  988. {
  989. RECT rect;
  990. CDialogBar::OnNcPaint();
  991. GetWindowRect(&rect);
  992. // Assumes there is no other non-client items
  993. rect.right -= rect.left;
  994. rect.bottom -= rect.top;
  995. rect.top = 0;
  996. rect.left = rect.right - 3;
  997. if((rect.left < rect.right) && (rect.top < rect.bottom))
  998. {
  999. CDC *pDC = GetWindowDC();
  1000. HDC hdc = pDC->m_hDC;
  1001. FillRect(hdc, &rect, GetSysColorBrush(COLOR_BTNFACE));
  1002. ReleaseDC(pDC);
  1003. }
  1004. }
  1005. void CModTreeBar::OnSize(UINT nType, int cx, int cy)
  1006. {
  1007. CDialogBar::OnSize(nType, cx, cy);
  1008. RecalcLayout();
  1009. }
  1010. void CModTreeBar::OnNcMouseMove(UINT, CPoint point)
  1011. {
  1012. CRect rect;
  1013. CPoint pt = point;
  1014. GetWindowRect(&rect);
  1015. pt.x -= rect.left;
  1016. pt.y -= rect.top;
  1017. DoMouseMove(pt);
  1018. }
  1019. void CModTreeBar::OnMouseMove(UINT, CPoint point)
  1020. {
  1021. DoMouseMove(point);
  1022. }
  1023. void CModTreeBar::OnNcLButtonDown(UINT, CPoint point)
  1024. {
  1025. CRect rect;
  1026. CPoint pt = point;
  1027. GetWindowRect(&rect);
  1028. pt.x -= rect.left;
  1029. pt.y -= rect.top;
  1030. DoLButtonDown(pt);
  1031. }
  1032. void CModTreeBar::OnLButtonDown(UINT, CPoint point)
  1033. {
  1034. DoLButtonDown(point);
  1035. }
  1036. void CModTreeBar::OnNcLButtonUp(UINT, CPoint)
  1037. {
  1038. DoLButtonUp();
  1039. }
  1040. void CModTreeBar::OnLButtonUp(UINT, CPoint)
  1041. {
  1042. DoLButtonUp();
  1043. }
  1044. HWND CModTreeBar::GetModTreeHWND()
  1045. {
  1046. return m_pModTree->m_hWnd;
  1047. }
  1048. LRESULT CModTreeBar::SendMessageToModTree(UINT cmdID, WPARAM wParam, LPARAM lParam)
  1049. {
  1050. if(::GetFocus() == m_pModTree->m_hWnd)
  1051. return m_pModTree->SendMessage(cmdID, wParam, lParam);
  1052. if(::GetFocus() == m_pModTreeData->m_hWnd)
  1053. return m_pModTreeData->SendMessage(cmdID, wParam, lParam);
  1054. return 0;
  1055. }
  1056. bool CModTreeBar::SetTreeSoundfile(FileReader &file)
  1057. {
  1058. return m_pModTree->SetSoundFile(file);
  1059. }
  1060. ////////////////////////////////////////////////////////////////////////////////
  1061. //
  1062. // Stereo VU Meter for toolbar
  1063. //
  1064. BEGIN_MESSAGE_MAP(CStereoVU, CStatic)
  1065. ON_WM_PAINT()
  1066. ON_WM_LBUTTONDOWN()
  1067. END_MESSAGE_MAP()
  1068. void CStereoVU::OnPaint()
  1069. {
  1070. CRect rect;
  1071. CPaintDC dc(this);
  1072. DrawVuMeters(dc, true);
  1073. }
  1074. void CStereoVU::SetVuMeter(uint8 validChannels, const uint32 channels[4], bool force)
  1075. {
  1076. bool changed = false;
  1077. if(validChannels == 0)
  1078. {
  1079. // reset
  1080. validChannels = numChannels;
  1081. } else if(validChannels != numChannels)
  1082. {
  1083. changed = true;
  1084. force = true;
  1085. numChannels = validChannels;
  1086. allowRightToLeft = (numChannels > 2);
  1087. }
  1088. for(uint8 c = 0; c < validChannels; ++c)
  1089. {
  1090. if(vuMeter[c] != channels[c])
  1091. {
  1092. changed = true;
  1093. }
  1094. }
  1095. if(changed)
  1096. {
  1097. DWORD curTime = timeGetTime();
  1098. if(curTime - lastVuUpdateTime >= TrackerSettings::Instance().VuMeterUpdateInterval || force)
  1099. {
  1100. for(uint8 c = 0; c < validChannels; ++c)
  1101. {
  1102. vuMeter[c] = channels[c];
  1103. }
  1104. CClientDC dc(this);
  1105. DrawVuMeters(dc, force);
  1106. lastVuUpdateTime = curTime;
  1107. }
  1108. }
  1109. }
  1110. // Draw stereo VU
  1111. void CStereoVU::DrawVuMeters(CDC &dc, bool redraw)
  1112. {
  1113. CRect rect;
  1114. GetClientRect(&rect);
  1115. if(redraw)
  1116. {
  1117. dc.FillSolidRect(rect.left, rect.top, rect.Width(), rect.Height(), RGB(0,0,0));
  1118. }
  1119. for(uint8 channel = 0; channel < numChannels; ++channel)
  1120. {
  1121. CRect chanrect = rect;
  1122. if(horizontal)
  1123. {
  1124. if(allowRightToLeft)
  1125. {
  1126. const int col = channel % 2;
  1127. const int row = channel / 2;
  1128. float width = (rect.Width() - 2.0f) / 2.0f;
  1129. float height = rect.Height() / float(numChannels/2);
  1130. chanrect.top = mpt::saturate_round<int32>(rect.top + height * row);
  1131. chanrect.bottom = mpt::saturate_round<int32>(chanrect.top + height) - 1;
  1132. chanrect.left = mpt::saturate_round<int32>(rect.left + width * col) + ((col == 1) ? 2 : 0);
  1133. chanrect.right = mpt::saturate_round<int32>(chanrect.left + width) - 1;
  1134. } else
  1135. {
  1136. float height = rect.Height() / float(numChannels);
  1137. chanrect.top = mpt::saturate_round<int32>(rect.top + height * channel);
  1138. chanrect.bottom = mpt::saturate_round<int32>(chanrect.top + height) - 1;
  1139. }
  1140. } else
  1141. {
  1142. float width = rect.Width() / float(numChannels);
  1143. chanrect.left = mpt::saturate_round<int32>(rect.left + width * channel);
  1144. chanrect.right = mpt::saturate_round<int32>(chanrect.left + width) - 1;
  1145. }
  1146. DrawVuMeter(dc, chanrect, channel, redraw);
  1147. }
  1148. }
  1149. // Draw a single VU Meter
  1150. void CStereoVU::DrawVuMeter(CDC &dc, const CRect &rect, int index, bool redraw)
  1151. {
  1152. uint32 vu = vuMeter[index];
  1153. if(CMainFrame::GetMainFrame()->GetSoundFilePlaying() == nullptr)
  1154. {
  1155. vu = 0;
  1156. }
  1157. const bool clip = (vu & Notification::ClipVU) != 0;
  1158. vu = (vu & (~Notification::ClipVU)) >> 8;
  1159. if(horizontal)
  1160. {
  1161. const bool rtl = allowRightToLeft && ((index % 2) == 0);
  1162. const int cx = std::max(1, rect.Width());
  1163. int v = (vu * cx) >> 8;
  1164. for(int x = 0; x <= cx; x += 2)
  1165. {
  1166. int pen = Clamp((x * NUM_VUMETER_PENS) / cx, 0, NUM_VUMETER_PENS - 1);
  1167. const bool last = (x == (cx & ~0x1));
  1168. // Darken everything above volume, unless it's the clip indicator
  1169. if(v <= x && (!last || !clip))
  1170. pen += NUM_VUMETER_PENS;
  1171. bool draw = redraw || (v < lastV[index] && v<=x && x<=lastV[index]) || (lastV[index] < v && lastV[index]<=x && x<=v);
  1172. draw = draw || (last && clip != lastClip[index]);
  1173. if(draw) dc.FillSolidRect(
  1174. ((!rtl) ? (rect.left + x) : (rect.right - x)),
  1175. rect.top, 1, rect.Height(), CMainFrame::gcolrefVuMeter[pen]);
  1176. if(last) lastClip[index] = clip;
  1177. }
  1178. lastV[index] = v;
  1179. } else
  1180. {
  1181. const int cy = std::max(1, rect.Height());
  1182. int v = (vu * cy) >> 8;
  1183. for(int ry = rect.bottom - 1; ry > rect.top; ry -= 2)
  1184. {
  1185. const int y0 = rect.bottom - ry;
  1186. int pen = Clamp((y0 * NUM_VUMETER_PENS) / cy, 0, NUM_VUMETER_PENS - 1);
  1187. const bool last = (ry == rect.top + 1);
  1188. // Darken everything above volume, unless it's the clip indicator
  1189. if(v <= y0 && (!last || !clip))
  1190. pen += NUM_VUMETER_PENS;
  1191. bool draw = redraw || (v < lastV[index] && v<=ry && ry<=lastV[index]) || (lastV[index] < v && lastV[index]<=ry && ry<=v);
  1192. draw = draw || (last && clip != lastClip[index]);
  1193. if(draw) dc.FillSolidRect(rect.left, ry, rect.Width(), 1, CMainFrame::gcolrefVuMeter[pen]);
  1194. if(last) lastClip[index] = clip;
  1195. }
  1196. lastV[index] = v;
  1197. }
  1198. }
  1199. void CStereoVU::OnLButtonDown(UINT, CPoint)
  1200. {
  1201. // Reset clip indicator.
  1202. CMainFrame::GetMainFrame()->m_VUMeterInput.ResetClipped();
  1203. CMainFrame::GetMainFrame()->m_VUMeterOutput.ResetClipped();
  1204. }
  1205. OPENMPT_NAMESPACE_END