/*
 * globals.cpp
 * -----------
 * Purpose: Implementation of various views of the tracker interface.
 * 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 "Moddoc.h"
#include "Childfrm.h"
#include "Globals.h"
#include "Ctrl_gen.h"
#include "Ctrl_pat.h"
#include "Ctrl_smp.h"
#include "Ctrl_ins.h"
#include "Ctrl_com.h"
#include "ImageLists.h"
#include "../soundlib/mod_specifications.h"


OPENMPT_NAMESPACE_BEGIN


/////////////////////////////////////////////////////////////////////////////
// CModControlDlg

BEGIN_MESSAGE_MAP(CModControlDlg, CDialog)
	//{{AFX_MSG_MAP(CModControlDlg)
	ON_WM_SIZE()
#if !defined(MPT_BUILD_RETRO)
	ON_MESSAGE(WM_DPICHANGED, &CModControlDlg::OnDPIChanged)
#endif
	ON_MESSAGE(WM_MOD_UNLOCKCONTROLS,		&CModControlDlg::OnUnlockControls)
	ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTW, 0, 0xFFFF, &CModControlDlg::OnToolTipText)
	ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTA, 0, 0xFFFF, &CModControlDlg::OnToolTipText)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()


CModControlDlg::CModControlDlg(CModControlView &parent, CModDoc &document) : m_modDoc(document), m_sndFile(document.GetSoundFile()), m_parent(parent)
{
	m_bInitialized = FALSE;
	m_hWndView = NULL;
	m_nLockCount = 0;
}


CModControlDlg::~CModControlDlg()
{
	ASSERT(m_hWnd == NULL);
}


BOOL CModControlDlg::OnInitDialog()
{
	CDialog::OnInitDialog();
	m_nDPIx = Util::GetDPIx(m_hWnd);
	m_nDPIy = Util::GetDPIy(m_hWnd);
	EnableToolTips(TRUE);
	return TRUE;
}


LRESULT CModControlDlg::OnDPIChanged(WPARAM wParam, LPARAM)
{
	m_nDPIx = LOWORD(wParam);
	m_nDPIy = HIWORD(wParam);
	return 0;
}


void CModControlDlg::OnSize(UINT nType, int cx, int cy)
{
	CDialog::OnSize(nType, cx, cy);
	if (((nType == SIZE_RESTORED) || (nType == SIZE_MAXIMIZED)) && (cx > 0) && (cy > 0))
	{
		RecalcLayout();
	}
}


LRESULT CModControlDlg::OnModCtrlMsg(WPARAM wParam, LPARAM lParam)
{
	switch(wParam)
	{
	case CTRLMSG_SETVIEWWND:
		m_hWndView = (HWND)lParam;
		break;

	case CTRLMSG_ACTIVATEPAGE:
		OnActivatePage(lParam);
		break;

	case CTRLMSG_DEACTIVATEPAGE:
		OnDeactivatePage();
		break;

	case CTRLMSG_SETFOCUS:
		GetParentFrame()->SetActiveView(&m_parent);
		SetFocus();
		break;
	}
	return 0;
}


LRESULT CModControlDlg::SendViewMessage(UINT uMsg, LPARAM lParam) const
{
	if (m_hWndView)	return ::SendMessage(m_hWndView, WM_MOD_VIEWMSG, uMsg, lParam);
	return 0;
}


BOOL CModControlDlg::PostViewMessage(UINT uMsg, LPARAM lParam) const
{
	if (m_hWndView)	return ::PostMessage(m_hWndView, WM_MOD_VIEWMSG, uMsg, lParam);
	return FALSE;
}


INT_PTR CModControlDlg::OnToolHitTest(CPoint point, TOOLINFO* pTI) const
{
	INT_PTR nHit = CDialog::OnToolHitTest(point, pTI);
	if ((nHit >= 0) && (pTI))
	{
		if ((pTI->lpszText == LPSTR_TEXTCALLBACK) && (pTI->hwnd == m_hWnd))
		{
			CFrameWnd *pMDIParent = GetParentFrame();
			if (pMDIParent) pTI->hwnd = pMDIParent->m_hWnd;
		}
	}
	return nHit;
}


BOOL CModControlDlg::OnToolTipText(UINT nID, NMHDR* pNMHDR, LRESULT* pResult)
{
	CChildFrame *pChildFrm = (CChildFrame *)GetParentFrame();
	if (pChildFrm) return pChildFrm->OnToolTipText(nID, pNMHDR, pResult);
	if (pResult) *pResult = 0;
	return FALSE;
}


/////////////////////////////////////////////////////////////////////////////
// CModControlView

BOOL CModTabCtrl::Create(DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID)
{
	CMainFrame *pMainFrm = CMainFrame::GetMainFrame();
	if (!pMainFrm) return FALSE;
	if (!CTabCtrl::Create(dwStyle, rect, pParentWnd, nID)) return FALSE;
	SendMessage(WM_SETFONT, (WPARAM)pMainFrm->GetGUIFont());
	SetImageList(&pMainFrm->m_MiscIcons);
	return TRUE;
}


BOOL CModTabCtrl::InsertItem(int nIndex, LPCTSTR pszText, LPARAM lParam, int iImage)
{
	TC_ITEM tci;
	tci.mask = TCIF_TEXT | TCIF_PARAM | TCIF_IMAGE;
	tci.pszText = const_cast<LPTSTR>(pszText);
	tci.lParam = lParam;
	tci.iImage = iImage;
	return CTabCtrl::InsertItem(nIndex, &tci);
}


LPARAM CModTabCtrl::GetItemData(int nIndex)
{
	TC_ITEM tci;
	tci.mask = TCIF_PARAM;
	tci.lParam = 0;
	if (!GetItem(nIndex, &tci)) return 0;
	return tci.lParam;
}


/////////////////////////////////////////////////////////////////////////////////
// CModControlView

IMPLEMENT_DYNCREATE(CModControlView, CView)

BEGIN_MESSAGE_MAP(CModControlView, CView)
	//{{AFX_MSG_MAP(CModControlView)
	ON_WM_SIZE()
	ON_WM_DESTROY()
	ON_NOTIFY(TCN_SELCHANGE, IDC_TABCTRL1,	&CModControlView::OnTabSelchange)
	ON_MESSAGE(WM_MOD_ACTIVATEVIEW,			&CModControlView::OnActivateModView)
	ON_MESSAGE(WM_MOD_CTRLMSG,				&CModControlView::OnModCtrlMsg)
	ON_MESSAGE(WM_MOD_GETTOOLTIPTEXT,		&CModControlView::OnGetToolTipText)
	ON_COMMAND(ID_EDIT_CUT,					&CModControlView::OnEditCut)
	ON_COMMAND(ID_EDIT_COPY,				&CModControlView::OnEditCopy)
	ON_COMMAND(ID_EDIT_PASTE,				&CModControlView::OnEditPaste)
	ON_COMMAND(ID_EDIT_MIXPASTE,			&CModControlView::OnEditMixPaste)
	ON_COMMAND(ID_EDIT_MIXPASTE_ITSTYLE,	&CModControlView::OnEditMixPasteITStyle)
	ON_COMMAND(ID_EDIT_FIND,				&CModControlView::OnEditFind)
	ON_COMMAND(ID_EDIT_FINDNEXT,			&CModControlView::OnEditFindNext)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()


CModControlView::CModControlView()
{
	MemsetZero(m_Pages);
	m_nActiveDlg = -1;
	m_nInstrumentChanged = -1;
	m_hWndView = NULL;
	m_hWndMDI = NULL;
}


BOOL CModControlView::PreCreateWindow(CREATESTRUCT& cs)
{
	return CView::PreCreateWindow(cs);
}


void CModControlView::OnInitialUpdate() // called first time after construct
{
	CView::OnInitialUpdate();
	CRect rect;

	CChildFrame *pParentFrame = (CChildFrame *)GetParentFrame();
	if (pParentFrame) m_hWndView = pParentFrame->GetHwndView();
	GetClientRect(&rect);
	m_TabCtrl.Create(WS_CHILD|WS_VISIBLE|TCS_FOCUSNEVER|TCS_FORCELABELLEFT, rect, this, IDC_TABCTRL1);
	UpdateView(UpdateHint().ModType());
	SetActivePage(0);
}


void CModControlView::OnSize(UINT nType, int cx, int cy)
{
	CView::OnSize(nType, cx, cy);
	if (((nType == SIZE_RESTORED) || (nType == SIZE_MAXIMIZED)) && (cx > 0) && (cy > 0))
	{
		RecalcLayout();
	}
}


void CModControlView::RecalcLayout()
{
	CRect rcClient;

	if (m_TabCtrl.m_hWnd == NULL) return;
	GetClientRect(&rcClient);
	if ((m_nActiveDlg >= 0) && (m_nActiveDlg < MAX_PAGES) && (m_Pages[m_nActiveDlg]))
	{
		CWnd *pDlg = m_Pages[m_nActiveDlg];
		CRect rect = rcClient;
		m_TabCtrl.AdjustRect(FALSE, &rect);
		HDWP hdwp = BeginDeferWindowPos(2);
		DeferWindowPos(hdwp, m_TabCtrl.m_hWnd, NULL, rcClient.left, rcClient.top, rcClient.Width(), rcClient.Height(), SWP_NOZORDER);
		DeferWindowPos(hdwp, pDlg->m_hWnd, NULL, rect.left, rect.top, rect.Width(), rect.Height(), SWP_NOZORDER);
		EndDeferWindowPos(hdwp);
	} else
	{
		m_TabCtrl.MoveWindow(&rcClient);
	}
}


void CModControlView::OnUpdate(CView *, LPARAM lHint, CObject *pHint)
{
	UpdateView(UpdateHint::FromLPARAM(lHint), pHint);
}


void CModControlView::ForceRefresh()
{
	SetActivePage(GetActivePage());
}


BOOL CModControlView::SetActivePage(int nIndex, LPARAM lParam)
{
	CMainFrame *pMainFrm = CMainFrame::GetMainFrame();
	CModControlDlg *pDlg = NULL;


	if (nIndex == -1) nIndex = m_TabCtrl.GetCurSel();

	const UINT nID = static_cast<UINT>(m_TabCtrl.GetItemData(nIndex));
	if(nID == 0) return FALSE;

	switch(nID)
	{
		//rewbs.graph
		case IDD_CONTROL_GRAPH:
			nIndex = 5;
			break;
		//end rewbs.graph
		case IDD_CONTROL_COMMENTS:
			nIndex = 4;
			break;
		case IDD_CONTROL_GLOBALS:
			nIndex = 0;
			break;
		case IDD_CONTROL_PATTERNS:
			nIndex = 1;
			break;
		case IDD_CONTROL_SAMPLES:
			nIndex = 2;
			break;
		case IDD_CONTROL_INSTRUMENTS:
			nIndex = 3;
			break;
		default:
			return FALSE;
	}

	if ((nIndex < 0) || (nIndex >= MAX_PAGES) || (!pMainFrm)) return FALSE;

	if (m_Pages[m_nActiveDlg])
		m_Pages[m_nActiveDlg]->GetSplitPosRef() = ((CChildFrame *)GetParentFrame())->GetSplitterHeight();

	if (nIndex == m_nActiveDlg)
	{
		pDlg = m_Pages[m_nActiveDlg];
		PostMessage(WM_MOD_CTRLMSG, CTRLMSG_ACTIVATEPAGE, lParam);
		return TRUE;
	}
	if ((m_nActiveDlg >= 0) && (m_nActiveDlg < MAX_PAGES))
	{
		if (m_Pages[m_nActiveDlg])
		{
			OnModCtrlMsg(CTRLMSG_DEACTIVATEPAGE, 0);
			m_Pages[m_nActiveDlg]->ShowWindow(SW_HIDE);
		}
		m_nActiveDlg = -1;
	}
	if (m_Pages[nIndex]) //Ctrl window already created?
	{
		m_nActiveDlg = nIndex;
		pDlg = m_Pages[nIndex];
	} else //Ctrl window is not created yet - creating one.
	{
		MPT_ASSERT_ALWAYS(GetDocument() != nullptr);
		switch(nID)
		{
		//rewbs.graph
		case IDD_CONTROL_GRAPH:
			//pDlg = new CCtrlGraph();
			break;
		//end rewbs.graph
		case IDD_CONTROL_COMMENTS:
			pDlg = new CCtrlComments(*this, *GetDocument());
			break;
		case IDD_CONTROL_GLOBALS:
			pDlg = new CCtrlGeneral(*this, *GetDocument());
			break;
		case IDD_CONTROL_PATTERNS:
			pDlg = new CCtrlPatterns(*this, *GetDocument());
			break;
		case IDD_CONTROL_SAMPLES:
			pDlg = new CCtrlSamples(*this, *GetDocument());
			break;
		case IDD_CONTROL_INSTRUMENTS:
			pDlg = new CCtrlInstruments(*this, *GetDocument());
			break;
		default:
			return FALSE;
		}
		if (!pDlg) return FALSE;
		pDlg->SetViewWnd(m_hWndView);
		BOOL bStatus = pDlg->Create(nID, this);
		if(bStatus == 0) // Creation failed.
		{
			delete pDlg;
			return FALSE;
		}
		m_nActiveDlg = nIndex;
		m_Pages[nIndex] = pDlg;
	}
	RecalcLayout();
	pMainFrm->SetUserText(_T(""));
	pMainFrm->SetInfoText(_T(""));
	pMainFrm->SetXInfoText(_T("")); //rewbs.xinfo
	pDlg->ShowWindow(SW_SHOW);
	((CChildFrame *)GetParentFrame())->SetSplitterHeight(pDlg->GetSplitPosRef());
	if (m_hWndMDI) ::PostMessage(m_hWndMDI, WM_MOD_CHANGEVIEWCLASS, (WPARAM)lParam, (LPARAM)pDlg);
	return TRUE;
}


void CModControlView::OnDestroy()
{
	m_nActiveDlg = -1;
	for (UINT nIndex=0; nIndex<MAX_PAGES; nIndex++)
	{
		CModControlDlg *pDlg = m_Pages[nIndex];
		if (pDlg)
		{
			m_Pages[nIndex] = NULL;
			pDlg->DestroyWindow();
			delete pDlg;
		}
	}
	CView::OnDestroy();
}


void CModControlView::UpdateView(UpdateHint lHint, CObject *pObject)
{
	CWnd *pActiveDlg = NULL;
	CModDoc *pDoc = GetDocument();
	if (!pDoc) return;
	// Module type changed: update tabs
	if (lHint.GetType()[HINT_MODTYPE])
	{
		UINT nCount = 4;
		UINT mask = 1 | 2 | 4 | 16;

		if(pDoc->GetSoundFile().GetModSpecifications().instrumentsMax > 0 || pDoc->GetNumInstruments() > 0)
		{
			mask |= 8;
			//mask |= 32; //rewbs.graph
			nCount++;
		}
		if (nCount != (UINT)m_TabCtrl.GetItemCount())
		{
			UINT count = 0;
			if ((m_nActiveDlg >= 0) && (m_nActiveDlg < MAX_PAGES))
			{
				pActiveDlg = m_Pages[m_nActiveDlg];
				if (pActiveDlg) pActiveDlg->ShowWindow(SW_HIDE);
			}
			m_TabCtrl.DeleteAllItems();
			if (mask & 1) m_TabCtrl.InsertItem(count++, _T("General"), IDD_CONTROL_GLOBALS, IMAGE_GENERAL);
			if (mask & 2) m_TabCtrl.InsertItem(count++, _T("Patterns"), IDD_CONTROL_PATTERNS, IMAGE_PATTERNS);
			if (mask & 4) m_TabCtrl.InsertItem(count++, _T("Samples"), IDD_CONTROL_SAMPLES, IMAGE_SAMPLES);
			if (mask & 8) m_TabCtrl.InsertItem(count++, _T("Instruments"), IDD_CONTROL_INSTRUMENTS, IMAGE_INSTRUMENTS);
			//if (mask & 32) m_TabCtrl.InsertItem(count++, _T("Graph"), IDD_CONTROL_GRAPH, IMAGE_GRAPH); //rewbs.graph
			if (mask & 16) m_TabCtrl.InsertItem(count++, _T("Comments"), IDD_CONTROL_COMMENTS, IMAGE_COMMENTS);
		}
	}
	// Update child dialogs
	for (UINT nIndex=0; nIndex<MAX_PAGES; nIndex++)
	{
		CModControlDlg *pDlg = m_Pages[nIndex];
		if ((pDlg) && (pObject != pDlg)) pDlg->UpdateView(UpdateHint(lHint), pObject);
	}
	// Restore the displayed child dialog
	if (pActiveDlg) pActiveDlg->ShowWindow(SW_SHOW);
}


void CModControlView::OnTabSelchange(NMHDR*, LRESULT* pResult)
{
	SetActivePage(m_TabCtrl.GetCurSel());
	if (pResult) *pResult = 0;
}


LRESULT CModControlView::OnActivateModView(WPARAM nIndex, LPARAM lParam)
{
	if(::GetActiveWindow() != CMainFrame::GetMainFrame()->m_hWnd)
	{
		// If we are in a dialog (e.g. Amplify Sample), do not allow to switch to a different tab. Otherwise, watch the tracker crash!
		return 0;
	}

	if (m_TabCtrl.m_hWnd)
	{
		if (nIndex < 100)
		{
			m_TabCtrl.SetCurSel(static_cast<int>(nIndex));
			SetActivePage(static_cast<int>(nIndex), lParam);
		} else
		// Might be a dialog id IDD_XXXX
		{
			int nItems = m_TabCtrl.GetItemCount();
			for (int i=0; i<nItems; i++)
			{
				if ((WPARAM)m_TabCtrl.GetItemData(i) == nIndex)
				{
					m_TabCtrl.SetCurSel(i);
					SetActivePage(i, lParam);
					break;
				}
			}
		}
	}
	return 0;
}


LRESULT CModControlView::OnModCtrlMsg(WPARAM wParam, LPARAM lParam)
{
	if ((m_nActiveDlg >= 0) && (m_nActiveDlg < MAX_PAGES))
	{
		CModControlDlg *pActiveDlg = m_Pages[m_nActiveDlg];
		if (pActiveDlg)
		{
			switch(wParam)
			{
			case CTRLMSG_SETVIEWWND:
				{
					m_hWndView = (HWND)lParam;
					for (UINT i=0; i<MAX_PAGES; i++)
					{
						if (m_Pages[i]) m_Pages[i]->SetViewWnd(m_hWndView);
					}
				}
				break;
			}
			return pActiveDlg->OnModCtrlMsg(wParam, lParam);
		}
	}
	return 0;
}


LRESULT CModControlView::OnGetToolTipText(WPARAM uId, LPARAM pszText)
{
	if ((m_nActiveDlg >= 0) && (m_nActiveDlg < MAX_PAGES))
	{
		CModControlDlg *pActiveDlg = m_Pages[m_nActiveDlg];
		if (pActiveDlg) return (LRESULT)pActiveDlg->GetToolTipText(static_cast<UINT>(uId), (LPTSTR)pszText);
	}
	return 0;
}


void CModControlView::SampleChanged(SAMPLEINDEX smp)
{
	const CModDoc *modDoc = GetDocument();
	if(modDoc && modDoc->GetNumInstruments())
	{
		INSTRUMENTINDEX k = static_cast<INSTRUMENTINDEX>(GetInstrumentChange());
		if(!modDoc->IsChildSample(k, smp))
		{
			INSTRUMENTINDEX nins = modDoc->FindSampleParent(smp);
			if(nins != INSTRUMENTINDEX_INVALID)
			{
				InstrumentChanged(nins);
			}
		}
	} else
	{
		InstrumentChanged(smp);
	}
}


//////////////////////////////////////////////////////////////////
// CModScrollView

#ifndef WM_MOUSEHWHEEL
#define WM_MOUSEHWHEEL 0x20E // Only available on Vista and newer
#endif

IMPLEMENT_SERIAL(CModScrollView, CScrollView, 0)
BEGIN_MESSAGE_MAP(CModScrollView, CScrollView)
	//{{AFX_MSG_MAP(CModScrollView)
	ON_WM_DESTROY()
	ON_WM_MOUSEWHEEL()
	ON_WM_MOUSEHWHEEL()
#if !defined(MPT_BUILD_RETRO)
	ON_MESSAGE(WM_DPICHANGED, &CModScrollView::OnDPIChanged)
#endif
	ON_MESSAGE(WM_MOD_VIEWMSG,			&CModScrollView::OnReceiveModViewMsg)
	ON_MESSAGE(WM_MOD_DRAGONDROPPING,	&CModScrollView::OnDragonDropping)
	ON_MESSAGE(WM_MOD_UPDATEPOSITION,	&CModScrollView::OnUpdatePosition)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()


LRESULT CModScrollView::SendCtrlMessage(UINT uMsg, LPARAM lParam) const
{
	if (m_hWndCtrl)	return ::SendMessage(m_hWndCtrl, WM_MOD_CTRLMSG, uMsg, lParam);
	return 0;
}


void CModScrollView::SendCtrlCommand(int id) const
{
	::SendMessage(m_hWndCtrl, WM_COMMAND, id, 0);
}


BOOL CModScrollView::PostCtrlMessage(UINT uMsg, LPARAM lParam) const
{
	if (m_hWndCtrl)	return ::PostMessage(m_hWndCtrl, WM_MOD_CTRLMSG, uMsg, lParam);
	return FALSE;
}


LRESULT CModScrollView::OnReceiveModViewMsg(WPARAM wParam, LPARAM lParam)
{
	return OnModViewMsg(wParam, lParam);
}


void CModScrollView::OnUpdate(CView* pView, LPARAM lHint, CObject*pHint)
{
	if (pView != this) UpdateView(UpdateHint::FromLPARAM(lHint), pHint);
}


LRESULT CModScrollView::OnModViewMsg(WPARAM wParam, LPARAM lParam)
{
	switch(wParam)
	{
	case VIEWMSG_SETCTRLWND:
		m_hWndCtrl = (HWND)lParam;
		break;

	case VIEWMSG_SETFOCUS:
	case VIEWMSG_SETACTIVE:
		GetParentFrame()->SetActiveView(this);
		SetFocus();
		break;
	}
	return 0;
}


void CModScrollView::OnInitialUpdate()
{
	CScrollView::OnInitialUpdate();
	m_nDPIx = Util::GetDPIx(m_hWnd);
	m_nDPIy = Util::GetDPIy(m_hWnd);
}


LRESULT CModScrollView::OnDPIChanged(WPARAM wParam, LPARAM)
{
	m_nDPIx = LOWORD(wParam);
	m_nDPIy = HIWORD(wParam);
	return 0;
}


void CModScrollView::UpdateIndicator(LPCTSTR lpszText)
{
	CMainFrame *pMainFrm = CMainFrame::GetMainFrame();
	if (pMainFrm) pMainFrm->SetUserText((lpszText) ? lpszText : _T(""));
}


BOOL CModScrollView::OnMouseWheel(UINT fFlags, short zDelta, CPoint point)
{
	// we don't handle anything but scrolling just now
	if (fFlags & (MK_SHIFT | MK_CONTROL)) return FALSE;

	//if the parent is a splitter, it will handle the message
	//if (GetParentSplitter(this, TRUE)) return FALSE;

	// we can't get out of it--perform the scroll ourselves
	return DoMouseWheel(fFlags, zDelta, point);
}


void CModScrollView::OnMouseHWheel(UINT fFlags, short zDelta, CPoint point)
{
	// we don't handle anything but scrolling just now
	if (fFlags & (MK_SHIFT | MK_CONTROL))
	{
		CScrollView::OnMouseHWheel(fFlags, zDelta, point);
		return;
	}

	if (OnScrollBy(CSize(zDelta * m_lineDev.cx / WHEEL_DELTA, 0), TRUE))
		UpdateWindow();
}


void CModScrollView::OnDestroy()
{
	CModDoc *pModDoc = GetDocument();
	CMainFrame *pMainFrm = CMainFrame::GetMainFrame();
	if ((pMainFrm) && (pModDoc))
	{
		if (pMainFrm->GetFollowSong(pModDoc) == m_hWnd)
		{
			pModDoc->SetNotifications(Notification::Default);
			pModDoc->SetFollowWnd(NULL);
		}
		if (pMainFrm->GetMidiRecordWnd() == m_hWnd)
		{
			pMainFrm->SetMidiRecordWnd(NULL);
		}
	}
	CScrollView::OnDestroy();
}


LRESULT CModScrollView::OnUpdatePosition(WPARAM, LPARAM lParam)
{
	Notification *pnotify = (Notification *)lParam;
	if (pnotify) return OnPlayerNotify(pnotify);
	return 0;
}


BOOL CModScrollView::OnScroll(UINT nScrollCode, UINT nPos, BOOL bDoScroll)
{
	SCROLLINFO info;
	if(LOBYTE(nScrollCode) == SB_THUMBTRACK)
	{
		if(GetScrollInfo(SB_HORZ, &info, SIF_TRACKPOS))
			nPos = info.nTrackPos;
		m_nScrollPosX = nPos;
	} else if(HIBYTE(nScrollCode) == SB_THUMBTRACK)
	{
		if(GetScrollInfo(SB_VERT, &info, SIF_TRACKPOS))
			nPos = info.nTrackPos;
		m_nScrollPosY = nPos;
	}
	return CScrollView::OnScroll(nScrollCode, nPos, bDoScroll);
}


BOOL CModScrollView::OnScrollBy(CSize sizeScroll, BOOL bDoScroll)
{
	BOOL ret = CScrollView::OnScrollBy(sizeScroll, bDoScroll);
	if(ret)
	{
		SCROLLINFO info;
		if(sizeScroll.cx)
		{
			if(GetScrollInfo(SB_HORZ, &info, SIF_POS))
				m_nScrollPosX = info.nPos;
		}
		if(sizeScroll.cy)
		{
			if(GetScrollInfo(SB_VERT, &info, SIF_POS))
				m_nScrollPosY = info.nPos;
		}
	}
	return ret;
}


int CModScrollView::SetScrollPos(int nBar, int nPos, BOOL bRedraw)
{
	if(nBar == SB_HORZ)
		m_nScrollPosX = nPos;
	else if(nBar == SB_VERT)
		m_nScrollPosY = nPos;
	return CScrollView::SetScrollPos(nBar, nPos, bRedraw);
}


void CModScrollView::SetScrollSizes(int nMapMode, SIZE sizeTotal, const SIZE& sizePage, const SIZE& sizeLine)
{
	CScrollView::SetScrollSizes(nMapMode, sizeTotal, sizePage, sizeLine);
	// Fix scroll positions
	SCROLLINFO info;
	if(GetScrollInfo(SB_HORZ, &info, SIF_POS))
		m_nScrollPosX = info.nPos;
	if(GetScrollInfo(SB_VERT, &info, SIF_POS))
		m_nScrollPosY = info.nPos;
}


BOOL CModScrollView::OnGesturePan(CPoint ptFrom, CPoint ptTo)
{
	// On Windows 8 and later, panning with touch gestures does not generate sensible WM_*SCROLL messages.
	// OnScrollBy is only ever called with a size of 0/0 in this case.
	// WM_GESTURE on the other hand gives us sensible data to work with.
	OnScrollBy(ptTo - ptFrom, TRUE);
	return TRUE;
}


////////////////////////////////////////////////////////////////////////////
// 	CModControlBar

BEGIN_MESSAGE_MAP(CModControlBar, CToolBarCtrl)
	ON_MESSAGE(WM_HELPHITTEST,	&CModControlBar::OnHelpHitTest)
END_MESSAGE_MAP()


BOOL CModControlBar::Init(CImageList &icons, CImageList &disabledIcons)
{
	const int imgSize = Util::ScalePixels(16, m_hWnd), btnSizeX = Util::ScalePixels(26, m_hWnd), btnSizeY = Util::ScalePixels(24, m_hWnd);
	SetButtonStructSize(sizeof(TBBUTTON));
	SetBitmapSize(CSize(imgSize, imgSize));
	SetButtonSize(CSize(btnSizeX, btnSizeY));

	// Add bitmaps
	SetImageList(&icons);
	SetDisabledImageList(&disabledIcons);
	UpdateStyle();
	return TRUE;
}


BOOL CModControlBar::AddButton(UINT nID, int iImage, UINT nStyle, UINT nState)
{
	TBBUTTON btn;

	btn.iBitmap = iImage;
	btn.idCommand = nID;
	btn.fsStyle = (BYTE)nStyle;
	btn.fsState = (BYTE)nState;
	btn.dwData = 0;
	btn.iString = 0;
	return AddButtons(1, &btn);
}


void CModControlBar::UpdateStyle()
{
	if (m_hWnd)
	{
		LONG lStyleOld = GetWindowLong(m_hWnd, GWL_STYLE);
		if (TrackerSettings::Instance().m_dwPatternSetup & PATTERN_FLATBUTTONS)
			lStyleOld |= TBSTYLE_FLAT;
		else
			lStyleOld &= ~TBSTYLE_FLAT;
		lStyleOld |= CCS_NORESIZE | CCS_NOPARENTALIGN | CCS_NODIVIDER | TBSTYLE_TOOLTIPS;
		SetWindowLong(m_hWnd, GWL_STYLE, lStyleOld);
		Invalidate();
	}
}


LRESULT CModControlBar::OnHelpHitTest(WPARAM, LPARAM lParam)
{
	TBBUTTON tbbn;
	POINT point;
	point.x = GET_X_LPARAM(lParam);
	point.y = GET_Y_LPARAM(lParam);
	int ndx = HitTest(&point);
	if ((ndx >= 0) && (GetButton(ndx, &tbbn)))
	{
		return HID_BASE_COMMAND + tbbn.idCommand;
	}
	return 0;
}

OPENMPT_NAMESPACE_END