winamp/Src/external_dependencies/openmpt-trunk/mptrack/Ctrl_pat.h
2024-09-24 14:54:57 +02:00

289 lines
10 KiB
C++

/*
* Ctrl_pat.h
* ----------
* Purpose: Pattern tab, upper panel.
* Notes : (currently none)
* Authors: Olivier Lapicque
* OpenMPT Devs
* The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
*/
#pragma once
#include "openmpt/all/BuildSettings.hpp"
#include "Globals.h"
#include "PatternCursor.h"
OPENMPT_NAMESPACE_BEGIN
class COrderList;
class CCtrlPatterns;
struct OrdSelection
{
ORDERINDEX firstOrd = 0, lastOrd = 0;
ORDERINDEX GetSelCount() const { return lastOrd - firstOrd + 1; }
};
class COrderList: public CWnd
{
friend class CCtrlPatterns;
protected:
HFONT m_hFont = nullptr;
int m_cxFont = 0, m_cyFont = 0;
//m_nXScroll : The order at the beginning of shown orderlist
//m_nScrollPos: The same as order
//m_nScrollPos2nd: 2nd selection point if multiple orders are selected
// (not neccessarily the higher order - GetCurSel() is taking care of that.)
ORDERINDEX m_nXScroll = 0, m_nScrollPos = 0, m_nScrollPos2nd = ORDERINDEX_INVALID, m_nDropPos, m_nMouseDownPos, m_playPos = ORDERINDEX_INVALID;
ORDERINDEX m_nDragOrder;
//To tell how many orders('orderboxes') to show at least
//on both sides of current order(when updating orderslist position).
int m_nOrderlistMargins;
CModDoc &m_modDoc;
CCtrlPatterns &m_pParent;
bool m_bScrolling = false, m_bDragging = false;
public:
COrderList(CCtrlPatterns &parent, CModDoc &document);
public:
BOOL Init(const CRect&, HFONT hFont);
void UpdateView(UpdateHint hint, CObject *pObj = nullptr);
void InvalidateSelection();
PATTERNINDEX GetCurrentPattern() const;
// make the current selection the secondary selection (used for keyboard orderlist navigation)
inline void SetCurSelTo2ndSel(bool isSelectionKeyPressed)
{
if(isSelectionKeyPressed && m_nScrollPos2nd == ORDERINDEX_INVALID) m_nScrollPos2nd = m_nScrollPos;
else if(!isSelectionKeyPressed && m_nScrollPos2nd != ORDERINDEX_INVALID) m_nScrollPos2nd = ORDERINDEX_INVALID;
};
void SetSelection(ORDERINDEX firstOrd, ORDERINDEX lastOrd = ORDERINDEX_INVALID);
// Why VC wants to inline this huge function is beyond my understanding...
MPT_NOINLINE bool SetCurSel(ORDERINDEX sel, bool setPlayPos = true, bool shiftClick = false, bool ignoreCurSel = false);
void UpdateScrollInfo();
void UpdateInfoText();
int GetFontWidth();
void QueuePattern(CPoint pt);
// Check if this module is currently playing
bool IsPlaying() const;
ORDERINDEX GetOrderFromPoint(const CPoint &pt) const;
CRect GetRectFromOrder(ORDERINDEX ord) const;
// Get the currently selected pattern(s).
// Set ignoreSelection to true if only the first selected point is important.
OrdSelection GetCurSel(bool ignoreSelection = false) const;
// Sets target margin value and returns the effective margin value.
ORDERINDEX SetMargins(int);
// Returns the effective margin value.
ORDERINDEX GetMargins() { return GetMargins(GetMarginsMax()); }
// Returns the effective margin value.
ORDERINDEX GetMargins(const ORDERINDEX maxMargins) const { return std::min(maxMargins, static_cast<ORDERINDEX>(m_nOrderlistMargins)); }
// Returns maximum margin value given current window width.
ORDERINDEX GetMarginsMax() { return GetMarginsMax(GetLength()); }
// Returns maximum margin value when shown sequence has nLength orders.
// For example: If length is 4 orders -> maxMargins = 4/2 - 1 = 1;
// if maximum is 5 -> maxMargins = (int)5/2 = 2
ORDERINDEX GetMarginsMax(const ORDERINDEX length) const { return (length > 0 && length % 2 == 0) ? length / 2 - 1 : length / 2; }
// Returns the number of sequence items visible in the list.
ORDERINDEX GetLength();
// Return true if given order is in margins given that first shown order
// is 'startOrder'. Begin part of the whole sequence
// is not interpreted to be in margins regardless of the margin value.
bool IsOrderInMargins(int order, int startOrder);
// Ensure that a given order index is visible in the orderlist view.
void EnsureVisible(ORDERINDEX order);
// Set given sqeuence and update orderlist display.
void SelectSequence(const SEQUENCEINDEX nSeq);
// Helper function for entering pattern number
void EnterPatternNum(int enterNum);
void OnCopy(bool onlyOrders);
// Update play state and order lock ranges after inserting order items.
void InsertUpdatePlaystate(ORDERINDEX first, ORDERINDEX last);
// Update play state and order lock ranges after deleting order items.
void DeleteUpdatePlaystate(ORDERINDEX first, ORDERINDEX last);
//{{AFX_VIRTUAL(COrderList)
BOOL PreTranslateMessage(MSG *pMsg) override;
INT_PTR OnToolHitTest(CPoint point, TOOLINFO* pTI) const override;
HRESULT get_accName(VARIANT varChild, BSTR *pszName) override;
//}}AFX_VIRTUAL
protected:
ModSequence& Order();
const ModSequence& Order() const;
void SetScrollPos(int pos);
int GetScrollPos(bool getTrackPos = false);
// Resizes the order list if the specified order is past the order list length
bool EnsureEditable(ORDERINDEX ord);
//{{AFX_MSG(COrderList)
afx_msg void OnPaint();
afx_msg BOOL OnEraseBkgnd(CDC *) { return TRUE; }
afx_msg void OnSetFocus(CWnd *);
afx_msg void OnKillFocus(CWnd *);
afx_msg void OnLButtonDown(UINT, CPoint);
afx_msg void OnLButtonDblClk(UINT, CPoint);
afx_msg void OnRButtonDown(UINT, CPoint);
afx_msg void OnLButtonUp(UINT, CPoint);
afx_msg void OnMButtonDown(UINT, CPoint);
afx_msg void OnMouseMove(UINT, CPoint);
afx_msg void OnHScroll(UINT nSBCode, UINT nPos, CScrollBar*);
afx_msg void OnSize(UINT nType, int cx, int cy);
afx_msg void OnSwitchToView();
afx_msg void OnInsertOrder();
afx_msg void OnInsertSeparatorPattern();
afx_msg void OnDeleteOrder();
afx_msg void OnRenderOrder();
afx_msg void OnPatternProperties();
afx_msg void OnPlayerPlay();
afx_msg void OnPlayerPause();
afx_msg void OnPlayerPlayFromStart();
afx_msg void OnPatternPlayFromStart();
afx_msg void OnCreateNewPattern();
afx_msg void OnDuplicatePattern();
afx_msg void OnMergePatterns();
afx_msg void OnPatternCopy();
afx_msg void OnPatternPaste();
afx_msg void OnSetRestartPos();
afx_msg void OnEditCopy() { OnCopy(false); }
afx_msg void OnEditCopyOrders() { OnCopy(true); }
afx_msg void OnEditCut();
afx_msg LRESULT OnDragonDropping(WPARAM bDoDrop, LPARAM lParam);
afx_msg LRESULT OnHelpHitTest(WPARAM, LPARAM lParam);
afx_msg void OnSelectSequence(UINT nid);
afx_msg LRESULT OnCustomKeyMsg(WPARAM, LPARAM);
afx_msg void OnLockPlayback();
afx_msg void OnUnlockPlayback();
afx_msg BOOL OnToolTipText(UINT, NMHDR *pNMHDR, LRESULT *pResult);
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
// CPatEdit: Edit control that switches back to the pattern view if Tab key is pressed.
class CPatEdit: public CEdit
{
protected:
CCtrlPatterns *m_pParent = nullptr;
public:
CPatEdit() = default;
void SetParent(CCtrlPatterns *parent) { m_pParent = parent; }
BOOL PreTranslateMessage(MSG *pMsg) override;
};
class CCtrlPatterns: public CModControlDlg
{
friend class COrderList;
protected:
COrderList m_OrderList;
CButton m_BtnPrev, m_BtnNext;
CComboBox m_CbnInstrument;
CPatEdit m_EditSpacing, m_EditPatName, m_EditSequence;
CSpinButtonCtrl m_SpinInstrument, m_SpinSpacing, m_SpinSequence;
CModControlBar m_ToolBar;
INSTRUMENTINDEX m_nInstrument = 0;
PatternCursor::Columns m_nDetailLevel = PatternCursor::lastColumn; // Visible Columns
bool m_bRecord = false, m_bVUMeters = false, m_bPluginNames = false;
public:
CCtrlPatterns(CModControlView &parent, CModDoc &document);
Setting<LONG> &GetSplitPosRef() override { return TrackerSettings::Instance().glPatternWindowHeight; }
public:
const ModSequence &Order() const;
ModSequence &Order();
void SetCurrentPattern(PATTERNINDEX nPat);
BOOL SetCurrentInstrument(UINT nIns);
BOOL GetFollowSong() { return IsDlgButtonChecked(IDC_PATTERN_FOLLOWSONG); }
BOOL GetLoopPattern() {return IsDlgButtonChecked(IDC_PATTERN_LOOP);}
COrderList &GetOrderList() { return m_OrderList; }
//{{AFX_VIRTUAL(CCtrlPatterns)
BOOL OnInitDialog() override;
void DoDataExchange(CDataExchange* pDX) override; // DDX/DDV support
void RecalcLayout() override;
void UpdateView(UpdateHint hint = UpdateHint(), CObject *pObj = nullptr) override;
CRuntimeClass *GetAssociatedViewClass() override;
LRESULT OnModCtrlMsg(WPARAM wParam, LPARAM lParam) override;
void OnActivatePage(LPARAM) override;
void OnDeactivatePage() override;
BOOL GetToolTipText(UINT, LPTSTR) override;
//}}AFX_VIRTUAL
protected:
//{{AFX_MSG(CCtrlPatterns)
afx_msg void OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar);
afx_msg void OnSequenceNext();
afx_msg void OnSequencePrev();
afx_msg void OnChannelManager();
afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags);
afx_msg void OnPlayerPause();
afx_msg void OnPatternNew();
afx_msg void OnPatternDuplicate();
afx_msg void OnPatternMerge();
afx_msg void OnPatternStop();
afx_msg void OnPatternPlay();
afx_msg void OnPatternPlayNoLoop();
afx_msg void OnPatternPlayRow();
afx_msg void OnPatternPlayFromStart();
afx_msg void OnPatternRecord();
afx_msg void OnPatternVUMeters();
afx_msg void OnPatternViewPlugNames();
afx_msg void OnPatternProperties();
afx_msg void OnPatternExpand();
afx_msg void OnPatternShrink();
afx_msg void OnPatternAmplify();
afx_msg void OnPatternCopy();
afx_msg void OnPatternPaste();
afx_msg void OnFollowSong();
afx_msg void OnChangeLoopStatus();
afx_msg void OnSwitchToView();
afx_msg void OnInstrumentChanged();
afx_msg void OnPrevInstrument();
afx_msg void OnNextInstrument();
afx_msg void OnSpacingChanged();
afx_msg void OnPatternNameChanged();
afx_msg void OnSequenceNameChanged();
afx_msg void OnChordEditor();
afx_msg void OnDetailLo();
afx_msg void OnDetailMed();
afx_msg void OnDetailHi();
afx_msg void OnEditUndo();
afx_msg void OnUpdateRecord(CCmdUI *pCmdUI);
afx_msg void TogglePluginEditor();
afx_msg void OnToggleOverflowPaste();
afx_msg void OnSequenceNumChanged();
afx_msg LRESULT OnCustomKeyMsg(WPARAM, LPARAM);
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
private:
bool HasValidPlug(INSTRUMENTINDEX instr) const;
public:
afx_msg BOOL OnMouseWheel(UINT nFlags, short zDelta, CPoint pt);
afx_msg void OnXButtonUp(UINT nFlags, UINT nButton, CPoint point);
afx_msg BOOL OnToolTip(UINT id, NMHDR *pTTTStruct, LRESULT *pResult);
};
OPENMPT_NAMESPACE_END