diff options
Diffstat (limited to 'Src/external_dependencies/openmpt-trunk/mptrack/Mainbar.cpp')
-rw-r--r-- | Src/external_dependencies/openmpt-trunk/mptrack/Mainbar.cpp | 1410 |
1 files changed, 1410 insertions, 0 deletions
diff --git a/Src/external_dependencies/openmpt-trunk/mptrack/Mainbar.cpp b/Src/external_dependencies/openmpt-trunk/mptrack/Mainbar.cpp new file mode 100644 index 00000000..462109b2 --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/mptrack/Mainbar.cpp @@ -0,0 +1,1410 @@ +/* + * Mainbar.cpp + * ----------- + * Purpose: Implementation of OpenMPT's window toolbar. + * Notes : (currently none) + * Authors: OpenMPT Devs + * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. + */ + + +#include "stdafx.h" +#include "Mptrack.h" +#include "Mainfrm.h" +#include "InputHandler.h" +#include "View_tre.h" +#include "ImageLists.h" +#include "Moddoc.h" +#include "../soundlib/mod_specifications.h" +#include "../common/mptStringBuffer.h" + + +OPENMPT_NAMESPACE_BEGIN + + +///////////////////////////////////////////////////////////////////// +// CToolBarEx: custom toolbar base class + +void CToolBarEx::SetHorizontal() +{ + m_bVertical = false; + SetBarStyle(GetBarStyle() | CBRS_ALIGN_TOP); +} + + +void CToolBarEx::SetVertical() +{ + m_bVertical = true; +} + + +CSize CToolBarEx::CalcDynamicLayout(int nLength, DWORD dwMode) +{ + CSize sizeResult; + // if we're committing set the buttons appropriately + if(dwMode & LM_COMMIT) + { + if(dwMode & LM_VERTDOCK) + { + if(!m_bVertical) + SetVertical(); + } else + { + if(m_bVertical) + SetHorizontal(); + } + sizeResult = CToolBar::CalcDynamicLayout(nLength, dwMode); + } else + { + const bool wasVertical = m_bVertical; + const bool doSwitch = (dwMode & LM_HORZ) ? wasVertical : !wasVertical; + + if(doSwitch) + { + if(wasVertical) + SetHorizontal(); + else + SetVertical(); + } + + sizeResult = CToolBar::CalcDynamicLayout(nLength, dwMode); + + if(doSwitch) + { + if(wasVertical) + SetHorizontal(); + else + SetVertical(); + } + } + + return sizeResult; +} + + +BOOL CToolBarEx::EnableControl(CWnd &wnd, UINT nIndex, UINT nHeight) +{ + if(wnd.m_hWnd != NULL) + { + CRect rect; + GetItemRect(nIndex, rect); + if(nHeight) + { + int n = (rect.bottom + rect.top - nHeight) / 2; + if(n > rect.top) rect.top = n; + } + wnd.SetWindowPos(NULL, rect.left, rect.top, 0, 0, SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOSIZE|SWP_NOCOPYBITS); + wnd.ShowWindow(SW_SHOW); + } + return TRUE; +} + + +void CToolBarEx::ChangeCtrlStyle(LONG lStyle, BOOL bSetStyle) +{ + if(m_hWnd) + { + LONG lStyleOld = GetWindowLong(m_hWnd, GWL_STYLE); + if(bSetStyle) + lStyleOld |= lStyle; + else + lStyleOld &= ~lStyle; + SetWindowLong(m_hWnd, GWL_STYLE, lStyleOld); + SetWindowPos(NULL, 0, 0, 0, 0, SWP_NOZORDER | SWP_NOMOVE | SWP_NOSIZE); + Invalidate(); + } +} + + +void CToolBarEx::EnableFlatButtons(BOOL bFlat) +{ + m_bFlatButtons = bFlat ? true : false; + ChangeCtrlStyle(TBSTYLE_FLAT, bFlat); +} + + +///////////////////////////////////////////////////////////////////// +// CMainToolBar + +#define SCALEWIDTH(x) (Util::ScalePixels(x, m_hWnd)) +#define SCALEHEIGHT(x) (Util::ScalePixels(x, m_hWnd)) + +// Play Command +#define PLAYCMD_INDEX 10 +#define TOOLBAR_IMAGE_PAUSE 8 +#define TOOLBAR_IMAGE_PLAY 13 +// Base octave +#define EDITOCTAVE_INDEX 13 +#define EDITOCTAVE_WIDTH SCALEWIDTH(55) +#define EDITOCTAVE_HEIGHT SCALEHEIGHT(20) +#define SPINOCTAVE_INDEX (EDITOCTAVE_INDEX+1) +#define SPINOCTAVE_WIDTH SCALEWIDTH(16) +#define SPINOCTAVE_HEIGHT (EDITOCTAVE_HEIGHT) +// Static "Tempo:" +#define TEMPOTEXT_INDEX 16 +#define TEMPOTEXT_WIDTH SCALEWIDTH(45) +#define TEMPOTEXT_HEIGHT SCALEHEIGHT(20) +// Edit Tempo +#define EDITTEMPO_INDEX (TEMPOTEXT_INDEX+1) +#define EDITTEMPO_WIDTH SCALEWIDTH(48) +#define EDITTEMPO_HEIGHT SCALEHEIGHT(20) +// Spin Tempo +#define SPINTEMPO_INDEX (EDITTEMPO_INDEX+1) +#define SPINTEMPO_WIDTH SCALEWIDTH(16) +#define SPINTEMPO_HEIGHT (EDITTEMPO_HEIGHT) +// Static "Speed:" +#define SPEEDTEXT_INDEX 20 +#define SPEEDTEXT_WIDTH SCALEWIDTH(57) +#define SPEEDTEXT_HEIGHT (TEMPOTEXT_HEIGHT) +// Edit Speed +#define EDITSPEED_INDEX (SPEEDTEXT_INDEX+1) +#define EDITSPEED_WIDTH SCALEWIDTH(28) +#define EDITSPEED_HEIGHT (EDITTEMPO_HEIGHT) +// Spin Speed +#define SPINSPEED_INDEX (EDITSPEED_INDEX+1) +#define SPINSPEED_WIDTH SCALEWIDTH(16) +#define SPINSPEED_HEIGHT (EDITSPEED_HEIGHT) +// Static "Rows/Beat:" +#define RPBTEXT_INDEX 24 +#define RPBTEXT_WIDTH SCALEWIDTH(63) +#define RPBTEXT_HEIGHT (TEMPOTEXT_HEIGHT) +// Edit Speed +#define EDITRPB_INDEX (RPBTEXT_INDEX+1) +#define EDITRPB_WIDTH SCALEWIDTH(28) +#define EDITRPB_HEIGHT (EDITTEMPO_HEIGHT) +// Spin Speed +#define SPINRPB_INDEX (EDITRPB_INDEX+1) +#define SPINRPB_WIDTH SCALEWIDTH(16) +#define SPINRPB_HEIGHT (EDITRPB_HEIGHT) +// VU Meters +#define VUMETER_INDEX (SPINRPB_INDEX+6) +#define VUMETER_WIDTH SCALEWIDTH(255) +#define VUMETER_HEIGHT SCALEHEIGHT(19) + +static UINT MainButtons[] = +{ + // same order as in the bitmap 'mainbar.bmp' + ID_FILE_NEW, + ID_FILE_OPEN, + ID_FILE_SAVE, + ID_SEPARATOR, + ID_EDIT_CUT, + ID_EDIT_COPY, + ID_EDIT_PASTE, + ID_SEPARATOR, + ID_MIDI_RECORD, + ID_PLAYER_STOP, + ID_PLAYER_PAUSE, + ID_PLAYER_PLAYFROMSTART, + ID_SEPARATOR, + ID_SEPARATOR, + ID_SEPARATOR, + ID_SEPARATOR, + ID_SEPARATOR, + ID_SEPARATOR, + ID_SEPARATOR, + ID_SEPARATOR, + ID_SEPARATOR, + ID_SEPARATOR, + ID_SEPARATOR, + ID_SEPARATOR, + + ID_SEPARATOR, + ID_SEPARATOR, + ID_SEPARATOR, + ID_SEPARATOR, + ID_VIEW_OPTIONS, + ID_PANIC, + ID_UPDATE_AVAILABLE, + ID_SEPARATOR, + ID_SEPARATOR, // VU Meter +}; + + +enum { MAX_MIDI_DEVICES = 256 }; + +BEGIN_MESSAGE_MAP(CMainToolBar, CToolBarEx) + ON_WM_VSCROLL() + ON_NOTIFY_EX_RANGE(TTN_NEEDTEXT, 0, 0xFFFF, &CMainToolBar::OnToolTipText) + ON_NOTIFY_REFLECT(TBN_DROPDOWN, &CMainToolBar::OnTbnDropDownToolBar) + ON_COMMAND_RANGE(ID_SELECT_MIDI_DEVICE, ID_SELECT_MIDI_DEVICE + MAX_MIDI_DEVICES, &CMainToolBar::OnSelectMIDIDevice) +END_MESSAGE_MAP() + + +template<typename TWnd> +static bool CreateTextWnd(TWnd &wnd, const TCHAR *text, DWORD style, CWnd *parent, UINT id) +{ + auto dc = parent->GetDC(); + auto oldFont = dc->SelectObject(CMainFrame::GetGUIFont()); + const auto size = dc->GetTextExtent(text); + dc->SelectObject(oldFont); + parent->ReleaseDC(dc); + 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))}; + return wnd.Create(text, style, rect, parent, id) != FALSE; +} + +BOOL CMainToolBar::Create(CWnd *parent) +{ + CRect rect; + DWORD dwStyle = WS_CHILD | WS_VISIBLE | CBRS_TOP | CBRS_SIZE_DYNAMIC | CBRS_TOOLTIPS | CBRS_FLYBY; + + if(!CToolBar::Create(parent, dwStyle)) + return FALSE; + + CDC *dc = GetDC(); + const auto hFont = reinterpret_cast<WPARAM>(CMainFrame::GetGUIFont()); + const double scaling = Util::GetDPIx(m_hWnd) / 96.0; + const int imgSize = mpt::saturate_round<int>(16 * scaling), btnSizeX = mpt::saturate_round<int>(23 * scaling), btnSizeY = mpt::saturate_round<int>(22 * scaling); + m_ImageList.Create(IDB_MAINBAR, 16, 16, IMGLIST_NUMIMAGES, 1, dc, scaling, false); + m_ImageListDisabled.Create(IDB_MAINBAR, 16, 16, IMGLIST_NUMIMAGES, 1, dc, scaling, true); + ReleaseDC(dc); + GetToolBarCtrl().SetBitmapSize(CSize(imgSize, imgSize)); + GetToolBarCtrl().SetButtonSize(CSize(btnSizeX, btnSizeY)); + GetToolBarCtrl().SetImageList(&m_ImageList); + GetToolBarCtrl().SetDisabledImageList(&m_ImageListDisabled); + SendMessage(WM_SETFONT, hFont, TRUE); + + if(!SetButtons(MainButtons, mpt::saturate_cast<int>(std::size(MainButtons)))) return FALSE; + + CRect temp; + GetItemRect(0, temp); + SetSizes(CSize(temp.Width(), temp.Height()), CSize(imgSize, imgSize)); + + // Dropdown menus for New and MIDI buttons + LPARAM dwExStyle = GetToolBarCtrl().SendMessage(TB_GETEXTENDEDSTYLE) | TBSTYLE_EX_DRAWDDARROWS; + GetToolBarCtrl().SendMessage(TB_SETEXTENDEDSTYLE, 0, dwExStyle); + SetButtonStyle(CommandToIndex(ID_FILE_NEW), GetButtonStyle(CommandToIndex(ID_FILE_NEW)) | TBSTYLE_DROPDOWN); + SetButtonStyle(CommandToIndex(ID_MIDI_RECORD), GetButtonStyle(CommandToIndex(ID_MIDI_RECORD)) | TBSTYLE_DROPDOWN); + + nCurrentSpeed = 6; + nCurrentTempo.Set(125); + nCurrentRowsPerBeat = 4; + nCurrentOctave = -1; + + // Octave Edit Box + if(!CreateTextWnd(m_EditOctave, _T("Octave 9"), WS_CHILD | WS_BORDER | SS_LEFT | SS_CENTERIMAGE, this, IDC_EDIT_BASEOCTAVE)) return FALSE; + rect.SetRect(0, 0, SPINOCTAVE_WIDTH, SPINOCTAVE_HEIGHT); + m_SpinOctave.Create(WS_CHILD | UDS_ALIGNRIGHT, rect, this, IDC_SPIN_BASEOCTAVE); + + // Tempo Text + if(!CreateTextWnd(m_StaticTempo, _T("Tempo:"), WS_CHILD | SS_CENTER | SS_CENTERIMAGE, this, IDC_TEXT_CURRENTTEMPO)) return FALSE; + // Tempo EditBox + if(!CreateTextWnd(m_EditTempo, _T("999.999"), WS_CHILD | WS_BORDER | SS_LEFT | SS_CENTERIMAGE , this, IDC_EDIT_CURRENTTEMPO)) return FALSE; + // Tempo Spin + rect.SetRect(0, 0, SPINTEMPO_WIDTH, SPINTEMPO_HEIGHT); + m_SpinTempo.Create(WS_CHILD | UDS_ALIGNRIGHT, rect, this, IDC_SPIN_CURRENTTEMPO); + + // Speed Text + if(!CreateTextWnd(m_StaticSpeed, _T("Ticks/Row:"), WS_CHILD | SS_CENTER | SS_CENTERIMAGE, this, IDC_TEXT_CURRENTSPEED)) return FALSE; + // Speed EditBox + if(!CreateTextWnd(m_EditSpeed, _T("999"), WS_CHILD | WS_BORDER | SS_LEFT | SS_CENTERIMAGE , this, IDC_EDIT_CURRENTSPEED)) return FALSE; + // Speed Spin + rect.SetRect(0, 0, SPINSPEED_WIDTH, SPINSPEED_HEIGHT); + m_SpinSpeed.Create(WS_CHILD | UDS_ALIGNRIGHT, rect, this, IDC_SPIN_CURRENTSPEED); + + // Rows per Beat Text + if(!CreateTextWnd(m_StaticRowsPerBeat, _T("Rows/Beat:"), WS_CHILD | SS_CENTER | SS_CENTERIMAGE, this, IDC_TEXT_RPB)) return FALSE; + // Rows per Beat EditBox + if(!CreateTextWnd(m_EditRowsPerBeat, _T("9999"), WS_CHILD | WS_BORDER | SS_LEFT | SS_CENTERIMAGE , this, IDC_EDIT_RPB)) return FALSE; + // Rows per Beat Spin + rect.SetRect(0, 0, SPINRPB_WIDTH, SPINRPB_HEIGHT); + m_SpinRowsPerBeat.Create(WS_CHILD | UDS_ALIGNRIGHT, rect, this, IDC_SPIN_RPB); + + // VU Meter + rect.SetRect(0, 0, VUMETER_WIDTH, VUMETER_HEIGHT); + //m_VuMeter.CreateEx(WS_EX_STATICEDGE, "STATIC", "", WS_CHILD | WS_BORDER | SS_NOTIFY, rect, this, IDC_VUMETER); + m_VuMeter.Create(_T(""), WS_CHILD | WS_BORDER | SS_NOTIFY, rect, this, IDC_VUMETER); + + // Adjust control styles + m_EditOctave.SendMessage(WM_SETFONT, hFont); + m_EditOctave.ModifyStyleEx(0, WS_EX_STATICEDGE, SWP_NOACTIVATE); + m_StaticTempo.SendMessage(WM_SETFONT, hFont); + m_EditTempo.SendMessage(WM_SETFONT, hFont); + m_EditTempo.ModifyStyleEx(0, WS_EX_STATICEDGE, SWP_NOACTIVATE); + m_StaticSpeed.SendMessage(WM_SETFONT, hFont); + m_EditSpeed.SendMessage(WM_SETFONT, hFont); + m_EditSpeed.ModifyStyleEx(0, WS_EX_STATICEDGE, SWP_NOACTIVATE); + m_StaticRowsPerBeat.SendMessage(WM_SETFONT, hFont); + m_EditRowsPerBeat.SendMessage(WM_SETFONT, hFont); + m_EditRowsPerBeat.ModifyStyleEx(0, WS_EX_STATICEDGE, SWP_NOACTIVATE); + m_SpinOctave.SetRange(MIN_BASEOCTAVE, MAX_BASEOCTAVE); + m_SpinOctave.SetPos(4); + m_SpinTempo.SetRange(-1, 1); + m_SpinTempo.SetPos(0); + m_SpinSpeed.SetRange(-1, 1); + m_SpinSpeed.SetPos(0); + m_SpinRowsPerBeat.SetRange(-1, 1); + m_SpinRowsPerBeat.SetPos(0); + // Display everything + SetWindowText(_T("Main")); + SetBaseOctave(4); + SetCurrentSong(nullptr); + EnableDocking(CBRS_ALIGN_ANY); + + GetToolBarCtrl().SetState(ID_UPDATE_AVAILABLE, TBSTATE_HIDDEN); + + return TRUE; +} + + +void CMainToolBar::Init(CMainFrame *pMainFrm) +{ + EnableFlatButtons(TrackerSettings::Instance().m_dwPatternSetup & PATTERN_FLATBUTTONS); + SetHorizontal(); + pMainFrm->DockControlBar(this); +} + + +static int GetWndWidth(const CWnd &wnd) +{ + CRect rect; + wnd.GetClientRect(rect); + return rect.right; +} + + +void CMainToolBar::SetHorizontal() +{ + CToolBarEx::SetHorizontal(); + m_VuMeter.SetOrientation(true); + SetButtonInfo(EDITOCTAVE_INDEX, IDC_EDIT_BASEOCTAVE, TBBS_SEPARATOR, GetWndWidth(m_EditOctave)); + SetButtonInfo(SPINOCTAVE_INDEX, IDC_SPIN_BASEOCTAVE, TBBS_SEPARATOR, SPINOCTAVE_WIDTH); + SetButtonInfo(TEMPOTEXT_INDEX, IDC_TEXT_CURRENTTEMPO, TBBS_SEPARATOR, GetWndWidth(m_StaticTempo)); + SetButtonInfo(EDITTEMPO_INDEX, IDC_EDIT_CURRENTTEMPO, TBBS_SEPARATOR, GetWndWidth(m_EditTempo)); + SetButtonInfo(SPINTEMPO_INDEX, IDC_SPIN_CURRENTTEMPO, TBBS_SEPARATOR, SPINTEMPO_WIDTH); + SetButtonInfo(SPEEDTEXT_INDEX, IDC_TEXT_CURRENTSPEED, TBBS_SEPARATOR, GetWndWidth(m_StaticSpeed)); + SetButtonInfo(EDITSPEED_INDEX, IDC_EDIT_CURRENTSPEED, TBBS_SEPARATOR, GetWndWidth(m_EditSpeed)); + SetButtonInfo(SPINSPEED_INDEX, IDC_SPIN_CURRENTSPEED, TBBS_SEPARATOR, SPINSPEED_WIDTH); + SetButtonInfo(RPBTEXT_INDEX, IDC_TEXT_RPB, TBBS_SEPARATOR, GetWndWidth(m_StaticRowsPerBeat)); + SetButtonInfo(EDITRPB_INDEX, IDC_EDIT_RPB, TBBS_SEPARATOR, GetWndWidth(m_EditRowsPerBeat)); + SetButtonInfo(SPINRPB_INDEX, IDC_SPIN_RPB, TBBS_SEPARATOR, SPINRPB_WIDTH); + SetButtonInfo(VUMETER_INDEX, IDC_VUMETER, TBBS_SEPARATOR, VUMETER_WIDTH); + + //SetButtonInfo(SPINSPEED_INDEX+1, IDC_TEXT_BPM, TBBS_SEPARATOR, SPEEDTEXT_WIDTH); + // Octave Box + EnableControl(m_EditOctave, EDITOCTAVE_INDEX); + EnableControl(m_SpinOctave, SPINOCTAVE_INDEX); + // Tempo + EnableControl(m_StaticTempo, TEMPOTEXT_INDEX, TEMPOTEXT_HEIGHT); + EnableControl(m_EditTempo, EDITTEMPO_INDEX, EDITTEMPO_HEIGHT); + EnableControl(m_SpinTempo, SPINTEMPO_INDEX, SPINTEMPO_HEIGHT); + // Speed + EnableControl(m_StaticSpeed, SPEEDTEXT_INDEX, SPEEDTEXT_HEIGHT); + EnableControl(m_EditSpeed, EDITSPEED_INDEX, EDITSPEED_HEIGHT); + EnableControl(m_SpinSpeed, SPINSPEED_INDEX, SPINSPEED_HEIGHT); + // Rows per Beat + EnableControl(m_StaticRowsPerBeat, RPBTEXT_INDEX, RPBTEXT_HEIGHT); + EnableControl(m_EditRowsPerBeat, EDITRPB_INDEX, EDITRPB_HEIGHT); + EnableControl(m_SpinRowsPerBeat, SPINRPB_INDEX, SPINRPB_HEIGHT); + EnableControl(m_VuMeter, VUMETER_INDEX, VUMETER_HEIGHT); +} + + +void CMainToolBar::SetVertical() +{ + CToolBarEx::SetVertical(); + m_VuMeter.SetOrientation(false); + // Change Buttons + SetButtonInfo(EDITOCTAVE_INDEX, ID_SEPARATOR, TBBS_SEPARATOR, 1); + SetButtonInfo(SPINOCTAVE_INDEX, ID_SEPARATOR, TBBS_SEPARATOR, 1); + SetButtonInfo(TEMPOTEXT_INDEX, ID_SEPARATOR, TBBS_SEPARATOR, 1); + SetButtonInfo(EDITTEMPO_INDEX, ID_SEPARATOR, TBBS_SEPARATOR, 1); + SetButtonInfo(SPINTEMPO_INDEX, ID_SEPARATOR, TBBS_SEPARATOR, 1); + SetButtonInfo(SPEEDTEXT_INDEX, ID_SEPARATOR, TBBS_SEPARATOR, 1); + SetButtonInfo(EDITSPEED_INDEX, ID_SEPARATOR, TBBS_SEPARATOR, 1); + SetButtonInfo(SPINSPEED_INDEX, ID_SEPARATOR, TBBS_SEPARATOR, 1); + SetButtonInfo(RPBTEXT_INDEX, ID_SEPARATOR, TBBS_SEPARATOR, 1); + SetButtonInfo(EDITRPB_INDEX, ID_SEPARATOR, TBBS_SEPARATOR, 1); + SetButtonInfo(SPINRPB_INDEX, ID_SEPARATOR, TBBS_SEPARATOR, 1); + SetButtonInfo(VUMETER_INDEX, IDC_VUMETER, TBBS_SEPARATOR, VUMETER_HEIGHT); + + // Hide Controls + if(m_EditOctave.m_hWnd) m_EditOctave.ShowWindow(SW_HIDE); + if(m_SpinOctave.m_hWnd) m_SpinOctave.ShowWindow(SW_HIDE); + if(m_StaticTempo.m_hWnd) m_StaticTempo.ShowWindow(SW_HIDE); + if(m_EditTempo.m_hWnd) m_EditTempo.ShowWindow(SW_HIDE); + if(m_SpinTempo.m_hWnd) m_SpinTempo.ShowWindow(SW_HIDE); + if(m_StaticSpeed.m_hWnd) m_StaticSpeed.ShowWindow(SW_HIDE); + if(m_EditSpeed.m_hWnd) m_EditSpeed.ShowWindow(SW_HIDE); + if(m_SpinSpeed.m_hWnd) m_SpinSpeed.ShowWindow(SW_HIDE); + if(m_StaticRowsPerBeat.m_hWnd) m_StaticRowsPerBeat.ShowWindow(SW_HIDE); + if(m_EditRowsPerBeat.m_hWnd) m_EditRowsPerBeat.ShowWindow(SW_HIDE); + if(m_SpinRowsPerBeat.m_hWnd) m_SpinRowsPerBeat.ShowWindow(SW_HIDE); + EnableControl(m_VuMeter, VUMETER_INDEX, VUMETER_HEIGHT); + //if(m_StaticBPM.m_hWnd) m_StaticBPM.ShowWindow(SW_HIDE); +} + + +UINT CMainToolBar::GetBaseOctave() const +{ + if(nCurrentOctave >= MIN_BASEOCTAVE) return (UINT)nCurrentOctave; + return 4; +} + + +BOOL CMainToolBar::SetBaseOctave(UINT nOctave) +{ + TCHAR s[64]; + + if((nOctave < MIN_BASEOCTAVE) || (nOctave > MAX_BASEOCTAVE)) return FALSE; + if(nOctave != (UINT)nCurrentOctave) + { + nCurrentOctave = nOctave; + wsprintf(s, _T(" Octave %d"), nOctave); + m_EditOctave.SetWindowText(s); + m_SpinOctave.SetPos(nOctave); + } + return TRUE; +} + + +bool CMainToolBar::ShowUpdateInfo(const CString &newVersion, const CString &infoURL, bool showHighLight) +{ + GetToolBarCtrl().SetState(ID_UPDATE_AVAILABLE, TBSTATE_ENABLED); + if(m_bVertical) + SetVertical(); + else + SetHorizontal(); + + CRect rect; + GetToolBarCtrl().GetRect(ID_UPDATE_AVAILABLE, &rect); + CPoint pt = rect.CenterPoint(); + ClientToScreen(&pt); + CMainFrame::GetMainFrame()->GetWindowRect(rect); + LimitMax(pt.x, rect.right); + + if(showHighLight) + { + return m_tooltip.ShowUpdate(*this, newVersion, infoURL, rect, pt, ID_UPDATE_AVAILABLE); + } else + { + return true; + } +} + + +void CMainToolBar::RemoveUpdateInfo() +{ + if(m_tooltip) + m_tooltip.Pop(); + GetToolBarCtrl().SetState(ID_UPDATE_AVAILABLE, TBSTATE_HIDDEN); +} + + +BOOL CMainToolBar::SetCurrentSong(CSoundFile *pSndFile) +{ + static CSoundFile *sndFile = nullptr; + if(pSndFile != sndFile) + { + sndFile = pSndFile; + } + + // Update Info + if(pSndFile) + { + TCHAR s[32]; + // Update play/pause button + if(nCurrentTempo == TEMPO(0, 0)) SetButtonInfo(PLAYCMD_INDEX, ID_PLAYER_PAUSE, TBBS_BUTTON, TOOLBAR_IMAGE_PAUSE); + // Update Speed + int nSpeed = pSndFile->m_PlayState.m_nMusicSpeed; + if(nSpeed != nCurrentSpeed) + { + CModDoc *modDoc = pSndFile->GetpModDoc(); + if(modDoc != nullptr) + { + // Update envelope views if speed has changed + modDoc->UpdateAllViews(InstrumentHint().Envelope()); + } + + if(nCurrentSpeed < 0) m_SpinSpeed.EnableWindow(TRUE); + nCurrentSpeed = nSpeed; + wsprintf(s, _T("%u"), static_cast<unsigned int>(nCurrentSpeed)); + m_EditSpeed.SetWindowText(s); + } + TEMPO nTempo = pSndFile->m_PlayState.m_nMusicTempo; + if(nTempo != nCurrentTempo) + { + if(nCurrentTempo <= TEMPO(0, 0)) m_SpinTempo.EnableWindow(TRUE); + nCurrentTempo = nTempo; + if(nCurrentTempo.GetFract() == 0) + _stprintf(s, _T("%u"), nCurrentTempo.GetInt()); + else + _stprintf(s, _T("%.4f"), nCurrentTempo.ToDouble()); + m_EditTempo.SetWindowText(s); + } + int nRowsPerBeat = pSndFile->m_PlayState.m_nCurrentRowsPerBeat; + if(nRowsPerBeat != nCurrentRowsPerBeat) + { + if(nCurrentRowsPerBeat < 0) m_SpinRowsPerBeat.EnableWindow(TRUE); + nCurrentRowsPerBeat = nRowsPerBeat; + wsprintf(s, _T("%u"), static_cast<unsigned int>(nCurrentRowsPerBeat)); + m_EditRowsPerBeat.SetWindowText(s); + } + } else + { + if(nCurrentTempo > TEMPO(0, 0)) + { + nCurrentTempo.Set(0); + m_EditTempo.SetWindowText(_T("---")); + m_SpinTempo.EnableWindow(FALSE); + SetButtonInfo(PLAYCMD_INDEX, ID_PLAYER_PLAY, TBBS_BUTTON, TOOLBAR_IMAGE_PLAY); + } + if(nCurrentSpeed != -1) + { + nCurrentSpeed = -1; + m_EditSpeed.SetWindowText(_T("---")); + m_SpinSpeed.EnableWindow(FALSE); + } + if(nCurrentRowsPerBeat != -1) + { + nCurrentRowsPerBeat = -1; + m_EditRowsPerBeat.SetWindowText(_T("---")); + m_SpinRowsPerBeat.EnableWindow(FALSE); + } + } + return TRUE; +} + + +void CMainToolBar::OnVScroll(UINT nCode, UINT nPos, CScrollBar *pScrollBar) +{ + CMainFrame *pMainFrm; + + CToolBarEx::OnVScroll(nCode, nPos, pScrollBar); + short int oct = (short int)m_SpinOctave.GetPos(); + if((oct >= MIN_BASEOCTAVE) && ((int)oct != nCurrentOctave)) + { + SetBaseOctave(oct); + } + if((nCurrentSpeed < 0) || (nCurrentTempo <= TEMPO(0, 0))) return; + if((pMainFrm = CMainFrame::GetMainFrame()) != nullptr) + { + CSoundFile *pSndFile = pMainFrm->GetSoundFilePlaying(); + if(pSndFile) + { + const auto &specs = pSndFile->GetModSpecifications(); + int n; + if((n = mpt::signum(m_SpinTempo.GetPos32())) != 0) + { + TEMPO newTempo; + if(specs.hasFractionalTempo) + { + n *= TEMPO::fractFact; + if(CMainFrame::GetMainFrame()->GetInputHandler()->CtrlPressed()) + n /= 100; + else + n /= 10; + newTempo.SetRaw(n); + } else + { + newTempo = TEMPO(n, 0); + } + newTempo += nCurrentTempo; + pSndFile->SetTempo(Clamp(newTempo, specs.GetTempoMin(), specs.GetTempoMax()), true); + m_SpinTempo.SetPos(0); + } + if((n = mpt::signum(m_SpinSpeed.GetPos32())) != 0) + { + pSndFile->m_PlayState.m_nMusicSpeed = Clamp(uint32(nCurrentSpeed + n), specs.speedMin, specs.speedMax); + m_SpinSpeed.SetPos(0); + } + if((n = m_SpinRowsPerBeat.GetPos32()) != 0) + { + if(n < 0) + { + if(nCurrentRowsPerBeat > 1) + SetRowsPerBeat(nCurrentRowsPerBeat - 1); + } else if(static_cast<ROWINDEX>(nCurrentRowsPerBeat) < pSndFile->m_PlayState.m_nCurrentRowsPerMeasure) + { + SetRowsPerBeat(nCurrentRowsPerBeat + 1); + } + m_SpinRowsPerBeat.SetPos(0); + + // Update pattern editor + pMainFrm->PostMessage(WM_MOD_INVALIDATEPATTERNS, HINT_MPTOPTIONS); + } + + SetCurrentSong(pSndFile); + } + } +} + + +void CMainToolBar::OnTbnDropDownToolBar(NMHDR *pNMHDR, LRESULT *pResult) +{ + NMTOOLBAR *pToolBar = reinterpret_cast<NMTOOLBAR *>(pNMHDR); + ClientToScreen(&(pToolBar->rcButton)); + + switch(pToolBar->iItem) + { + case ID_FILE_NEW: + CMainFrame::GetMainFrame()->GetFileMenu()->GetSubMenu(0)->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, pToolBar->rcButton.left, pToolBar->rcButton.bottom, this); + break; + case ID_MIDI_RECORD: + // Show a list of MIDI devices + { + HMENU hMenu = ::CreatePopupMenu(); + MIDIINCAPS mic; + UINT numDevs = midiInGetNumDevs(); + if(numDevs > MAX_MIDI_DEVICES) numDevs = MAX_MIDI_DEVICES; + UINT current = TrackerSettings::Instance().GetCurrentMIDIDevice(); + for(UINT i = 0; i < numDevs; i++) + { + mic.szPname[0] = 0; + if(midiInGetDevCaps(i, &mic, sizeof(mic)) == MMSYSERR_NOERROR) + { + ::AppendMenu(hMenu, MF_STRING | (i == current ? MF_CHECKED : 0), ID_SELECT_MIDI_DEVICE + i, theApp.GetFriendlyMIDIPortName(mpt::String::ReadCStringBuf(mic.szPname), true)); + } + } + if(!numDevs) + { + ::AppendMenu(hMenu, MF_STRING | MF_GRAYED, 0, _T("No MIDI input devices found")); + } + ::TrackPopupMenu(hMenu, TPM_LEFTALIGN | TPM_RIGHTBUTTON, pToolBar->rcButton.left, pToolBar->rcButton.bottom, 0, m_hWnd, NULL); + ::DestroyMenu(hMenu); + } + break; + } + + *pResult = 0; +} + + +void CMainToolBar::OnSelectMIDIDevice(UINT id) +{ + CMainFrame::GetMainFrame()->midiCloseDevice(); + TrackerSettings::Instance().SetMIDIDevice(id - ID_SELECT_MIDI_DEVICE); + CMainFrame::GetMainFrame()->midiOpenDevice(); +} + + +void CMainToolBar::SetRowsPerBeat(ROWINDEX nNewRPB) +{ + CMainFrame *pMainFrm = CMainFrame::GetMainFrame(); + if(pMainFrm == nullptr) + return; + CModDoc *pModDoc = pMainFrm->GetModPlaying(); + CSoundFile *pSndFile = pMainFrm->GetSoundFilePlaying(); + if(pModDoc == nullptr || pSndFile == nullptr) + return; + + pSndFile->m_PlayState.m_nCurrentRowsPerBeat = nNewRPB; + PATTERNINDEX nPat = pSndFile->GetCurrentPattern(); + if(pSndFile->Patterns[nPat].GetOverrideSignature()) + { + if(nNewRPB <= pSndFile->Patterns[nPat].GetRowsPerMeasure()) + { + pSndFile->Patterns[nPat].SetSignature(nNewRPB, pSndFile->Patterns[nPat].GetRowsPerMeasure()); + TempoSwing swing = pSndFile->Patterns[nPat].GetTempoSwing(); + if(!swing.empty()) + { + swing.resize(nNewRPB); + pSndFile->Patterns[nPat].SetTempoSwing(swing); + } + pModDoc->SetModified(); + } + } else + { + if(nNewRPB <= pSndFile->m_nDefaultRowsPerMeasure) + { + pSndFile->m_nDefaultRowsPerBeat = nNewRPB; + if(!pSndFile->m_tempoSwing.empty()) pSndFile->m_tempoSwing.resize(nNewRPB); + pModDoc->SetModified(); + } + } +} + + +BOOL CMainToolBar::OnToolTipText(UINT, NMHDR* pNMHDR, LRESULT* pResult) +{ + auto pTTT = reinterpret_cast<TOOLTIPTEXT *>(pNMHDR); + UINT_PTR id = pNMHDR->idFrom; + if(pTTT->uFlags & TTF_IDISHWND) + { + // idFrom is actually the HWND of the tool + id = (UINT_PTR)::GetDlgCtrlID((HWND)id); + } + + const TCHAR *s = nullptr; + CommandID cmd = kcNull; + switch(id) + { + case ID_FILE_NEW: s = _T("New"); cmd = kcFileNew; break; + case ID_FILE_OPEN: s = _T("Open"); cmd = kcFileOpen; break; + case ID_FILE_SAVE: s = _T("Save"); cmd = kcFileSave; break; + case ID_EDIT_CUT: s = _T("Cut"); cmd = kcEditCut; break; + case ID_EDIT_COPY: s = _T("Copy"); cmd = kcEditCopy; break; + case ID_EDIT_PASTE: s = _T("Paste"); cmd = kcEditPaste; break; + case ID_MIDI_RECORD: s = _T("MIDI Record"); cmd = kcMidiRecord; break; + case ID_PLAYER_STOP: s = _T("Stop"); cmd = kcStopSong; break; + case ID_PLAYER_PLAY: s = _T("Play"); cmd = kcPlayPauseSong; break; + case ID_PLAYER_PAUSE: s = _T("Pause"); cmd = kcPlayPauseSong; break; + case ID_PLAYER_PLAYFROMSTART: s = _T("Play From Start"); cmd = kcPlaySongFromStart; break; + case ID_VIEW_OPTIONS: s = _T("Setup"); cmd = kcViewOptions; break; + case ID_PANIC: s = _T("Stop all hanging plugin and sample voices"); cmd = kcPanic; break; + case ID_UPDATE_AVAILABLE: s = _T("A new update is available."); break; + } + + if(s == nullptr) + return FALSE; + + mpt::tstring fmt = s; + if(cmd != kcNull) + { + auto keyText = CMainFrame::GetInputHandler()->m_activeCommandSet->GetKeyTextFromCommand(cmd, 0); + if(!keyText.IsEmpty()) + fmt += MPT_TFORMAT(" ({})")(keyText); + } + mpt::String::WriteWinBuf(pTTT->szText) = fmt; + *pResult = 0; + + // bring the tooltip window above other popup windows + ::SetWindowPos(pNMHDR->hwndFrom, HWND_TOP, 0, 0, 0, 0, + SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOMOVE | SWP_NOOWNERZORDER); + + return TRUE; // message was handled +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// CModTreeBar + +BEGIN_MESSAGE_MAP(CModTreeBar, CDialogBar) + //{{AFX_MSG_MAP(CModTreeBar) + ON_WM_NCCALCSIZE() + ON_WM_NCPAINT() + ON_WM_NCHITTEST() + ON_WM_SIZE() + ON_WM_NCMOUSEMOVE() + ON_WM_MOUSEMOVE() + ON_WM_LBUTTONDOWN() + ON_WM_NCLBUTTONDOWN() + ON_WM_LBUTTONUP() + ON_WM_NCLBUTTONUP() + ON_MESSAGE(WM_INITDIALOG, &CModTreeBar::OnInitDialog) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + + +CModTreeBar::CModTreeBar() +{ + m_nTreeSplitRatio = TrackerSettings::Instance().glTreeSplitRatio; +} + + +LRESULT CModTreeBar::OnInitDialog(WPARAM wParam, LPARAM lParam) +{ + LRESULT l = CDialogBar::HandleInitDialog(wParam, lParam); + m_pModTreeData = new CModTree(nullptr); + if(m_pModTreeData) m_pModTreeData->SubclassDlgItem(IDC_TREEDATA, this); + m_pModTree = new CModTree(m_pModTreeData); + if(m_pModTree) m_pModTree->SubclassDlgItem(IDC_TREEVIEW, this); + m_dwStatus = 0; + m_sizeDefault.cx = Util::ScalePixels(TrackerSettings::Instance().glTreeWindowWidth, m_hWnd) + 3; + m_sizeDefault.cy = 32767; + return l; +} + + +CModTreeBar::~CModTreeBar() +{ + if(m_pModTree) + { + delete m_pModTree; + m_pModTree = nullptr; + } + if(m_pModTreeData) + { + delete m_pModTreeData; + m_pModTreeData = nullptr; + } +} + + +void CModTreeBar::Init() +{ + m_nTreeSplitRatio = TrackerSettings::Instance().glTreeSplitRatio; + if(m_pModTree) + { + m_pModTreeData->Init(); + m_pModTree->Init(); + } +} + + +void CModTreeBar::RefreshDlsBanks() +{ + if(m_pModTree) m_pModTree->RefreshDlsBanks(); +} + + +void CModTreeBar::RefreshMidiLibrary() +{ + if(m_pModTree) m_pModTree->RefreshMidiLibrary(); +} + + +void CModTreeBar::OnOptionsChanged() +{ + if(m_pModTree) m_pModTree->OnOptionsChanged(); +} + + +void CModTreeBar::RecalcLayout() +{ + CRect rect; + + if((m_pModTree) && (m_pModTreeData)) + { + int cytree, cydata, cyavail; + + GetClientRect(&rect); + cyavail = rect.Height() - 3; + if(cyavail < 0) cyavail = 0; + cytree = (cyavail * m_nTreeSplitRatio) >> 8; + cydata = cyavail - cytree; + m_pModTree->SetWindowPos(NULL, 0,0, rect.Width(), cytree, SWP_NOZORDER|SWP_NOACTIVATE); + m_pModTreeData->SetWindowPos(NULL, 0,cytree+3, rect.Width(), cydata, SWP_NOZORDER|SWP_NOACTIVATE); + } +} + + +CSize CModTreeBar::CalcFixedLayout(BOOL, BOOL) +{ + int width = Util::ScalePixels(TrackerSettings::Instance().glTreeWindowWidth, m_hWnd); + CSize sz; + m_sizeDefault.cx = width; + m_sizeDefault.cy = 32767; + sz.cx = width + 3; + if(sz.cx < 4) sz.cx = 4; + sz.cy = 32767; + return sz; +} + + +void CModTreeBar::DoMouseMove(CPoint pt) +{ + CRect rect; + + if((m_dwStatus & (MTB_CAPTURE|MTB_DRAGGING)) && (::GetCapture() != m_hWnd)) + { + CancelTracking(); + } + if(m_dwStatus & MTB_DRAGGING) + { + if(m_dwStatus & MTB_VERTICAL) + { + if(m_pModTree) + { + m_pModTree->GetWindowRect(&rect); + pt.y += rect.Height(); + } + GetClientRect(&rect); + pt.y -= ptDragging.y; + if(pt.y < 0) pt.y = 0; + if(pt.y > rect.Height()) pt.y = rect.Height(); + if((!(m_dwStatus & MTB_TRACKER)) || (pt.y != (int)m_nTrackPos)) + { + if(m_dwStatus & MTB_TRACKER) OnInvertTracker(m_nTrackPos); + m_nTrackPos = pt.y; + OnInvertTracker(m_nTrackPos); + m_dwStatus |= MTB_TRACKER; + } + } else + { + pt.x -= ptDragging.x - m_cxOriginal + 3; + if(pt.x < 0) pt.x = 0; + if((!(m_dwStatus & MTB_TRACKER)) || (pt.x != (int)m_nTrackPos)) + { + if(m_dwStatus & MTB_TRACKER) OnInvertTracker(m_nTrackPos); + m_nTrackPos = pt.x; + OnInvertTracker(m_nTrackPos); + m_dwStatus |= MTB_TRACKER; + } + } + } else + { + UINT nCursor = 0; + + GetClientRect(&rect); + rect.left = rect.right - 2; + rect.right = rect.left + 5; + if(rect.PtInRect(pt)) + { + nCursor = AFX_IDC_HSPLITBAR; + } else + if(m_pModTree) + { + m_pModTree->GetWindowRect(&rect); + rect.right = rect.Width(); + rect.left = 0; + rect.top = rect.Height()-1; + rect.bottom = rect.top + 5; + if(rect.PtInRect(pt)) + { + nCursor = AFX_IDC_VSPLITBAR; + } + } + if(nCursor) + { + UINT nDir = (nCursor == AFX_IDC_VSPLITBAR) ? MTB_VERTICAL : 0; + BOOL bLoad = FALSE; + if(!(m_dwStatus & MTB_CAPTURE)) + { + m_dwStatus |= MTB_CAPTURE; + SetCapture(); + bLoad = TRUE; + } else + { + if(nDir != (m_dwStatus & MTB_VERTICAL)) bLoad = TRUE; + } + m_dwStatus &= ~MTB_VERTICAL; + m_dwStatus |= nDir; + if(bLoad) SetCursor(theApp.LoadCursor(nCursor)); + } else + { + if(m_dwStatus & MTB_CAPTURE) + { + m_dwStatus &= ~MTB_CAPTURE; + ReleaseCapture(); + SetCursor(LoadCursor(NULL, IDC_ARROW)); + } + } + } +} + + +void CModTreeBar::DoLButtonDown(CPoint pt) +{ + if((m_dwStatus & MTB_CAPTURE) && (!(m_dwStatus & MTB_DRAGGING))) + { + CRect rect; + GetWindowRect(&rect); + m_cxOriginal = rect.Width(); + m_cyOriginal = rect.Height(); + ptDragging = pt; + m_dwStatus |= MTB_DRAGGING; + DoMouseMove(pt); + } +} + + +void CModTreeBar::DoLButtonUp() +{ + if(m_dwStatus & MTB_DRAGGING) + { + CRect rect; + + m_dwStatus &= ~MTB_DRAGGING; + if(m_dwStatus & MTB_TRACKER) + { + OnInvertTracker(m_nTrackPos); + m_dwStatus &= ~MTB_TRACKER; + } + if(m_dwStatus & MTB_VERTICAL) + { + GetClientRect(&rect); + int cyavail = rect.Height() - 3; + if(cyavail < 4) cyavail = 4; + int ratio = (m_nTrackPos << 8) / cyavail; + if(ratio < 0) ratio = 0; + if(ratio > 256) ratio = 256; + m_nTreeSplitRatio = ratio; + TrackerSettings::Instance().glTreeSplitRatio = ratio; + RecalcLayout(); + } else + { + GetWindowRect(&rect); + m_nTrackPos += 3; + if(m_nTrackPos < 4) m_nTrackPos = 4; + CMainFrame *pMainFrm = CMainFrame::GetMainFrame(); + if((m_nTrackPos != (UINT)rect.Width()) && (pMainFrm)) + { + TrackerSettings::Instance().glTreeWindowWidth = Util::ScalePixelsInv(m_nTrackPos - 3, m_hWnd); + m_sizeDefault.cx = m_nTrackPos; + m_sizeDefault.cy = 32767; + pMainFrm->RecalcLayout(); + } + } + } +} + + +void CModTreeBar::CancelTracking() +{ + if(m_dwStatus & MTB_TRACKER) + { + OnInvertTracker(m_nTrackPos); + m_dwStatus &= ~MTB_TRACKER; + } + m_dwStatus &= ~MTB_DRAGGING; + if(m_dwStatus & MTB_CAPTURE) + { + m_dwStatus &= ~MTB_CAPTURE; + ReleaseCapture(); + } +} + + +void CModTreeBar::OnInvertTracker(UINT x) +{ + CMainFrame *pMainFrm = CMainFrame::GetMainFrame(); + + if(pMainFrm) + { + CRect rect; + + GetClientRect(&rect); + if(m_dwStatus & MTB_VERTICAL) + { + rect.top = x; + rect.bottom = rect.top + 4; + } else + { + rect.left = x; + rect.right = rect.left + 4; + } + ClientToScreen(&rect); + pMainFrm->ScreenToClient(&rect); + + // pat-blt without clip children on + CDC* pDC = pMainFrm->GetDC(); + // invert the brush pattern (looks just like frame window sizing) + CBrush* pBrush = CDC::GetHalftoneBrush(); + HBRUSH hOldBrush = NULL; + if(pBrush != NULL) + hOldBrush = (HBRUSH)SelectObject(pDC->m_hDC, pBrush->m_hObject); + pDC->PatBlt(rect.left, rect.top, rect.Width(), rect.Height(), PATINVERT); + if(hOldBrush != NULL) + SelectObject(pDC->m_hDC, hOldBrush); + ReleaseDC(pDC); + } +} + + +void CModTreeBar::OnDocumentCreated(CModDoc *pModDoc) +{ + if(m_pModTree && pModDoc) m_pModTree->AddDocument(*pModDoc); +} + + +void CModTreeBar::OnDocumentClosed(CModDoc *pModDoc) +{ + if(m_pModTree && pModDoc) m_pModTree->RemoveDocument(*pModDoc); +} + + +void CModTreeBar::OnUpdate(CModDoc *pModDoc, UpdateHint hint, CObject *pHint) +{ + if(m_pModTree) m_pModTree->OnUpdate(pModDoc, hint, pHint); +} + + +void CModTreeBar::UpdatePlayPos(CModDoc *pModDoc, Notification *pNotify) +{ + if(m_pModTree && pModDoc) m_pModTree->UpdatePlayPos(*pModDoc, pNotify); +} + + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// CModTreeBar message handlers + +void CModTreeBar::OnNcCalcSize(BOOL bCalcValidRects, NCCALCSIZE_PARAMS* lpncsp) +{ + CDialogBar::OnNcCalcSize(bCalcValidRects, lpncsp); + if(lpncsp) + { + lpncsp->rgrc[0].right -= 3; + if(lpncsp->rgrc[0].right < lpncsp->rgrc[0].left) lpncsp->rgrc[0].right = lpncsp->rgrc[0].left; + } +} + + +LRESULT CModTreeBar::OnNcHitTest(CPoint point) +{ + CRect rect; + + GetWindowRect(&rect); + rect.DeflateRect(1,1); + rect.right -= 3; + if(!rect.PtInRect(point)) return HTBORDER; + return CDialogBar::OnNcHitTest(point); +} + + +void CModTreeBar::OnNcPaint() +{ + RECT rect; + CDialogBar::OnNcPaint(); + + GetWindowRect(&rect); + // Assumes there is no other non-client items + rect.right -= rect.left; + rect.bottom -= rect.top; + rect.top = 0; + rect.left = rect.right - 3; + if((rect.left < rect.right) && (rect.top < rect.bottom)) + { + CDC *pDC = GetWindowDC(); + HDC hdc = pDC->m_hDC; + FillRect(hdc, &rect, GetSysColorBrush(COLOR_BTNFACE)); + ReleaseDC(pDC); + } +} + + +void CModTreeBar::OnSize(UINT nType, int cx, int cy) +{ + CDialogBar::OnSize(nType, cx, cy); + RecalcLayout(); +} + + +void CModTreeBar::OnNcMouseMove(UINT, CPoint point) +{ + CRect rect; + CPoint pt = point; + + GetWindowRect(&rect); + pt.x -= rect.left; + pt.y -= rect.top; + DoMouseMove(pt); +} + + +void CModTreeBar::OnMouseMove(UINT, CPoint point) +{ + DoMouseMove(point); +} + + +void CModTreeBar::OnNcLButtonDown(UINT, CPoint point) +{ + CRect rect; + CPoint pt = point; + + GetWindowRect(&rect); + pt.x -= rect.left; + pt.y -= rect.top; + DoLButtonDown(pt); +} + + +void CModTreeBar::OnLButtonDown(UINT, CPoint point) +{ + DoLButtonDown(point); +} + + +void CModTreeBar::OnNcLButtonUp(UINT, CPoint) +{ + DoLButtonUp(); +} + + +void CModTreeBar::OnLButtonUp(UINT, CPoint) +{ + DoLButtonUp(); +} + + +HWND CModTreeBar::GetModTreeHWND() +{ + return m_pModTree->m_hWnd; +} + + +LRESULT CModTreeBar::SendMessageToModTree(UINT cmdID, WPARAM wParam, LPARAM lParam) +{ + if(::GetFocus() == m_pModTree->m_hWnd) + return m_pModTree->SendMessage(cmdID, wParam, lParam); + if(::GetFocus() == m_pModTreeData->m_hWnd) + return m_pModTreeData->SendMessage(cmdID, wParam, lParam); + return 0; +} + + +bool CModTreeBar::SetTreeSoundfile(FileReader &file) +{ + return m_pModTree->SetSoundFile(file); +} + + + + +//////////////////////////////////////////////////////////////////////////////// +// +// Stereo VU Meter for toolbar +// + +BEGIN_MESSAGE_MAP(CStereoVU, CStatic) + ON_WM_PAINT() + ON_WM_LBUTTONDOWN() +END_MESSAGE_MAP() + + +void CStereoVU::OnPaint() +{ + CRect rect; + CPaintDC dc(this); + DrawVuMeters(dc, true); +} + + +void CStereoVU::SetVuMeter(uint8 validChannels, const uint32 channels[4], bool force) +{ + bool changed = false; + if(validChannels == 0) + { + // reset + validChannels = numChannels; + } else if(validChannels != numChannels) + { + changed = true; + force = true; + numChannels = validChannels; + allowRightToLeft = (numChannels > 2); + } + for(uint8 c = 0; c < validChannels; ++c) + { + if(vuMeter[c] != channels[c]) + { + changed = true; + } + } + if(changed) + { + DWORD curTime = timeGetTime(); + if(curTime - lastVuUpdateTime >= TrackerSettings::Instance().VuMeterUpdateInterval || force) + { + for(uint8 c = 0; c < validChannels; ++c) + { + vuMeter[c] = channels[c]; + } + CClientDC dc(this); + DrawVuMeters(dc, force); + lastVuUpdateTime = curTime; + } + } +} + + +// Draw stereo VU +void CStereoVU::DrawVuMeters(CDC &dc, bool redraw) +{ + CRect rect; + GetClientRect(&rect); + + if(redraw) + { + dc.FillSolidRect(rect.left, rect.top, rect.Width(), rect.Height(), RGB(0,0,0)); + } + + for(uint8 channel = 0; channel < numChannels; ++channel) + { + CRect chanrect = rect; + if(horizontal) + { + if(allowRightToLeft) + { + const int col = channel % 2; + const int row = channel / 2; + + float width = (rect.Width() - 2.0f) / 2.0f; + float height = rect.Height() / float(numChannels/2); + + chanrect.top = mpt::saturate_round<int32>(rect.top + height * row); + chanrect.bottom = mpt::saturate_round<int32>(chanrect.top + height) - 1; + + chanrect.left = mpt::saturate_round<int32>(rect.left + width * col) + ((col == 1) ? 2 : 0); + chanrect.right = mpt::saturate_round<int32>(chanrect.left + width) - 1; + + } else + { + float height = rect.Height() / float(numChannels); + chanrect.top = mpt::saturate_round<int32>(rect.top + height * channel); + chanrect.bottom = mpt::saturate_round<int32>(chanrect.top + height) - 1; + } + } else + { + float width = rect.Width() / float(numChannels); + chanrect.left = mpt::saturate_round<int32>(rect.left + width * channel); + chanrect.right = mpt::saturate_round<int32>(chanrect.left + width) - 1; + } + DrawVuMeter(dc, chanrect, channel, redraw); + } + +} + + +// Draw a single VU Meter +void CStereoVU::DrawVuMeter(CDC &dc, const CRect &rect, int index, bool redraw) +{ + uint32 vu = vuMeter[index]; + + if(CMainFrame::GetMainFrame()->GetSoundFilePlaying() == nullptr) + { + vu = 0; + } + + const bool clip = (vu & Notification::ClipVU) != 0; + vu = (vu & (~Notification::ClipVU)) >> 8; + + if(horizontal) + { + const bool rtl = allowRightToLeft && ((index % 2) == 0); + + const int cx = std::max(1, rect.Width()); + int v = (vu * cx) >> 8; + + for(int x = 0; x <= cx; x += 2) + { + int pen = Clamp((x * NUM_VUMETER_PENS) / cx, 0, NUM_VUMETER_PENS - 1); + const bool last = (x == (cx & ~0x1)); + + // Darken everything above volume, unless it's the clip indicator + if(v <= x && (!last || !clip)) + pen += NUM_VUMETER_PENS; + + bool draw = redraw || (v < lastV[index] && v<=x && x<=lastV[index]) || (lastV[index] < v && lastV[index]<=x && x<=v); + draw = draw || (last && clip != lastClip[index]); + if(draw) dc.FillSolidRect( + ((!rtl) ? (rect.left + x) : (rect.right - x)), + rect.top, 1, rect.Height(), CMainFrame::gcolrefVuMeter[pen]); + if(last) lastClip[index] = clip; + } + lastV[index] = v; + } else + { + const int cy = std::max(1, rect.Height()); + int v = (vu * cy) >> 8; + + for(int ry = rect.bottom - 1; ry > rect.top; ry -= 2) + { + const int y0 = rect.bottom - ry; + int pen = Clamp((y0 * NUM_VUMETER_PENS) / cy, 0, NUM_VUMETER_PENS - 1); + const bool last = (ry == rect.top + 1); + + // Darken everything above volume, unless it's the clip indicator + if(v <= y0 && (!last || !clip)) + pen += NUM_VUMETER_PENS; + + bool draw = redraw || (v < lastV[index] && v<=ry && ry<=lastV[index]) || (lastV[index] < v && lastV[index]<=ry && ry<=v); + draw = draw || (last && clip != lastClip[index]); + if(draw) dc.FillSolidRect(rect.left, ry, rect.Width(), 1, CMainFrame::gcolrefVuMeter[pen]); + if(last) lastClip[index] = clip; + } + lastV[index] = v; + } +} + + +void CStereoVU::OnLButtonDown(UINT, CPoint) +{ + // Reset clip indicator. + CMainFrame::GetMainFrame()->m_VUMeterInput.ResetClipped(); + CMainFrame::GetMainFrame()->m_VUMeterOutput.ResetClipped(); +} + + +OPENMPT_NAMESPACE_END |