698 lines
20 KiB
C++
698 lines
20 KiB
C++
|
/*
|
||
|
* view_com.cpp
|
||
|
* ------------
|
||
|
* Purpose: Song comments tab, lower panel.
|
||
|
* Notes : (currently none)
|
||
|
* Authors: Olivier Lapicque
|
||
|
* 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 "Childfrm.h"
|
||
|
#include "Clipboard.h"
|
||
|
#include "ImageLists.h"
|
||
|
#include "Moddoc.h"
|
||
|
#include "Globals.h"
|
||
|
#include "Ctrl_com.h"
|
||
|
#include "ChannelManagerDlg.h"
|
||
|
#include "../common/mptStringBuffer.h"
|
||
|
#include "view_com.h"
|
||
|
#include "../soundlib/mod_specifications.h"
|
||
|
|
||
|
|
||
|
OPENMPT_NAMESPACE_BEGIN
|
||
|
|
||
|
|
||
|
#define DETAILS_TOOLBAR_CY Util::ScalePixels(28, m_hWnd)
|
||
|
|
||
|
enum
|
||
|
{
|
||
|
SMPLIST_SAMPLENAME = 0,
|
||
|
SMPLIST_SAMPLENO,
|
||
|
SMPLIST_SIZE,
|
||
|
SMPLIST_TYPE,
|
||
|
SMPLIST_MIDDLEC,
|
||
|
SMPLIST_INSTR,
|
||
|
SMPLIST_FILENAME,
|
||
|
SMPLIST_PATH,
|
||
|
SMPLIST_COLUMNS
|
||
|
};
|
||
|
|
||
|
|
||
|
enum
|
||
|
{
|
||
|
INSLIST_INSTRUMENTNAME = 0,
|
||
|
INSLIST_INSTRUMENTNO,
|
||
|
INSLIST_SAMPLES,
|
||
|
INSLIST_ENVELOPES,
|
||
|
INSLIST_FILENAME,
|
||
|
INSLIST_PLUGIN,
|
||
|
INSLIST_COLUMNS
|
||
|
};
|
||
|
|
||
|
|
||
|
const CListCtrlEx::Header gSampleHeaders[SMPLIST_COLUMNS] =
|
||
|
{
|
||
|
{ _T("Sample Name"), 192, LVCFMT_LEFT },
|
||
|
{ _T("Num"), 45, LVCFMT_RIGHT },
|
||
|
{ _T("Size"), 72, LVCFMT_RIGHT },
|
||
|
{ _T("Type"), 45, LVCFMT_RIGHT },
|
||
|
{ _T("C-5 Freq"), 80, LVCFMT_RIGHT },
|
||
|
{ _T("Instr"), 64, LVCFMT_RIGHT },
|
||
|
{ _T("File Name"), 128, LVCFMT_RIGHT },
|
||
|
{ _T("Path"), 256, LVCFMT_LEFT },
|
||
|
};
|
||
|
|
||
|
const CListCtrlEx::Header gInstrumentHeaders[INSLIST_COLUMNS] =
|
||
|
{
|
||
|
{ _T("Instrument Name"), 192, LVCFMT_LEFT },
|
||
|
{ _T("Num"), 45, LVCFMT_RIGHT },
|
||
|
{ _T("Samples"), 64, LVCFMT_RIGHT },
|
||
|
{ _T("Envelopes"), 128, LVCFMT_RIGHT },
|
||
|
{ _T("File Name"), 128, LVCFMT_RIGHT },
|
||
|
{ _T("Plugin"), 128, LVCFMT_RIGHT },
|
||
|
};
|
||
|
|
||
|
|
||
|
IMPLEMENT_SERIAL(CViewComments, CModScrollView, 0)
|
||
|
|
||
|
BEGIN_MESSAGE_MAP(CViewComments, CModScrollView)
|
||
|
//{{AFX_MSG_MAP(CViewComments)
|
||
|
ON_WM_SIZE()
|
||
|
ON_WM_DESTROY()
|
||
|
ON_MESSAGE(WM_MOD_KEYCOMMAND, &CViewComments::OnCustomKeyMsg)
|
||
|
ON_MESSAGE(WM_MOD_MIDIMSG, &CViewComments::OnMidiMsg)
|
||
|
ON_COMMAND(IDC_LIST_SAMPLES, &CViewComments::OnShowSamples)
|
||
|
ON_COMMAND(IDC_LIST_INSTRUMENTS, &CViewComments::OnShowInstruments)
|
||
|
ON_COMMAND(IDC_LIST_PATTERNS, &CViewComments::OnShowPatterns)
|
||
|
ON_COMMAND(ID_COPY_ALL_NAMES, &CViewComments::OnCopyNames)
|
||
|
ON_NOTIFY(LVN_ENDLABELEDIT, IDC_LIST_DETAILS, &CViewComments::OnEndLabelEdit)
|
||
|
ON_NOTIFY(LVN_BEGINLABELEDIT, IDC_LIST_DETAILS, &CViewComments::OnBeginLabelEdit)
|
||
|
ON_NOTIFY(NM_DBLCLK, IDC_LIST_DETAILS, &CViewComments::OnDblClickListItem)
|
||
|
ON_NOTIFY(NM_RCLICK, IDC_LIST_DETAILS, &CViewComments::OnRClickListItem)
|
||
|
//}}AFX_MSG_MAP
|
||
|
END_MESSAGE_MAP()
|
||
|
|
||
|
|
||
|
void CViewComments::OnInitialUpdate()
|
||
|
{
|
||
|
CModScrollView::OnInitialUpdate();
|
||
|
if(m_nListId == 0)
|
||
|
{
|
||
|
m_nListId = IDC_LIST_SAMPLES;
|
||
|
|
||
|
// For XM, set the instrument list as the default list
|
||
|
const CModDoc *pModDoc = GetDocument();
|
||
|
if(pModDoc && pModDoc->GetSoundFile().GetMessageHeuristic() == ModMessageHeuristicOrder::InstrumentsSamples && pModDoc->GetNumInstruments() > 0)
|
||
|
{
|
||
|
m_nListId = IDC_LIST_INSTRUMENTS;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
CChildFrame *pFrame = (CChildFrame *)GetParentFrame();
|
||
|
CRect rect;
|
||
|
|
||
|
if (pFrame)
|
||
|
{
|
||
|
COMMENTVIEWSTATE &commentState = pFrame->GetCommentViewState();
|
||
|
if (commentState.initialized)
|
||
|
{
|
||
|
m_nListId = commentState.nId;
|
||
|
}
|
||
|
}
|
||
|
GetClientRect(&rect);
|
||
|
m_ToolBar.Create(WS_CHILD|WS_VISIBLE|CCS_NOPARENTALIGN, rect, this, IDC_TOOLBAR_DETAILS);
|
||
|
m_ToolBar.Init(CMainFrame::GetMainFrame()->m_MiscIcons, CMainFrame::GetMainFrame()->m_MiscIconsDisabled);
|
||
|
m_ItemList.Create(WS_CHILD | WS_VISIBLE | LVS_REPORT | LVS_SINGLESEL | LVS_EDITLABELS | LVS_NOSORTHEADER, rect, this, IDC_LIST_DETAILS);
|
||
|
m_ItemList.ModifyStyleEx(0, WS_EX_STATICEDGE);
|
||
|
// Add ToolBar Buttons
|
||
|
m_ToolBar.AddButton(IDC_LIST_SAMPLES, IMAGE_SAMPLES);
|
||
|
m_ToolBar.AddButton(IDC_LIST_INSTRUMENTS, IMAGE_INSTRUMENTS);
|
||
|
//m_ToolBar.AddButton(IDC_LIST_PATTERNS, TIMAGE_TAB_PATTERNS);
|
||
|
m_ToolBar.SetIndent(4);
|
||
|
UpdateButtonState();
|
||
|
UpdateView(UpdateHint().ModType());
|
||
|
}
|
||
|
|
||
|
|
||
|
void CViewComments::OnDestroy()
|
||
|
{
|
||
|
if(m_lastNote != NOTE_NONE)
|
||
|
GetDocument()->NoteOff(m_lastNote, true, m_noteInstr, m_noteChannel);
|
||
|
|
||
|
CChildFrame *pFrame = (CChildFrame *)GetParentFrame();
|
||
|
if (pFrame)
|
||
|
{
|
||
|
COMMENTVIEWSTATE &commentState = pFrame->GetCommentViewState();
|
||
|
commentState.initialized = true;
|
||
|
commentState.nId = m_nListId;
|
||
|
}
|
||
|
CModScrollView::OnDestroy();
|
||
|
}
|
||
|
|
||
|
|
||
|
LRESULT CViewComments::OnModViewMsg(WPARAM wParam, LPARAM lParam)
|
||
|
{
|
||
|
switch(wParam)
|
||
|
{
|
||
|
case VIEWMSG_SETFOCUS:
|
||
|
case VIEWMSG_SETACTIVE:
|
||
|
GetParentFrame()->SetActiveView(this);
|
||
|
m_ItemList.SetFocus();
|
||
|
return 0;
|
||
|
default:
|
||
|
return CModScrollView::OnModViewMsg(wParam, lParam);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
LRESULT CViewComments::OnMidiMsg(WPARAM midiData_, LPARAM)
|
||
|
{
|
||
|
uint32 midiData = static_cast<uint32>(midiData_);
|
||
|
// Handle MIDI messages assigned to shortcuts
|
||
|
CInputHandler *ih = CMainFrame::GetInputHandler();
|
||
|
ih->HandleMIDIMessage(kCtxViewComments, midiData) != kcNull
|
||
|
|| ih->HandleMIDIMessage(kCtxAllContexts, midiData) != kcNull;
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
|
||
|
LRESULT CViewComments::OnCustomKeyMsg(WPARAM wParam, LPARAM)
|
||
|
{
|
||
|
const int item = m_ItemList.GetSelectionMark() + 1;
|
||
|
if(item == 0)
|
||
|
return kcNull;
|
||
|
|
||
|
auto modDoc = GetDocument();
|
||
|
if(wParam >= kcCommentsStartNotes && wParam <= kcCommentsEndNotes)
|
||
|
{
|
||
|
const auto lastInstr = m_noteInstr;
|
||
|
m_noteInstr = (m_nListId == IDC_LIST_SAMPLES) ? INSTRUMENTINDEX_INVALID : static_cast<INSTRUMENTINDEX>(item);
|
||
|
const auto note = modDoc->GetNoteWithBaseOctave(static_cast<int>(wParam - kcCommentsStartNotes), m_noteInstr);
|
||
|
PlayNoteParam params(note);
|
||
|
if(m_nListId == IDC_LIST_SAMPLES)
|
||
|
params.Sample(static_cast<SAMPLEINDEX>(item));
|
||
|
else if(m_nListId == IDC_LIST_INSTRUMENTS)
|
||
|
params.Instrument(m_noteInstr);
|
||
|
else
|
||
|
return kcNull;
|
||
|
if(m_lastNote != NOTE_NONE)
|
||
|
modDoc->NoteOff(m_lastNote, true, lastInstr, m_noteChannel);
|
||
|
m_noteChannel = modDoc->PlayNote(params);
|
||
|
m_lastNote = note;
|
||
|
return wParam;
|
||
|
} else if(wParam >= kcCommentsStartNoteStops && wParam <= kcCommentsEndNoteStops)
|
||
|
{
|
||
|
const auto note = modDoc->GetNoteWithBaseOctave(static_cast<int>(wParam - kcCommentsStartNoteStops), m_noteInstr);
|
||
|
modDoc->NoteOff(note, false, m_noteInstr, m_noteChannel);
|
||
|
return wParam;
|
||
|
} else if(wParam == kcToggleSmpInsList)
|
||
|
{
|
||
|
bool ok = SwitchToList(m_nListId == IDC_LIST_SAMPLES ? IDC_LIST_INSTRUMENTS : IDC_LIST_SAMPLES);
|
||
|
if(ok)
|
||
|
{
|
||
|
int newItem = 0;
|
||
|
switch(m_nListId)
|
||
|
{
|
||
|
case IDC_LIST_SAMPLES:
|
||
|
// Switch to a sample belonging to previously selected instrument
|
||
|
if(SAMPLEINDEX smp = modDoc->FindInstrumentChild(static_cast<INSTRUMENTINDEX>(item)); smp != 0 && smp != SAMPLEINDEX_INVALID)
|
||
|
newItem = smp - 1;
|
||
|
break;
|
||
|
|
||
|
case IDC_LIST_INSTRUMENTS:
|
||
|
// Switch to parent instrument of previously selected sample
|
||
|
if(INSTRUMENTINDEX ins = modDoc->FindSampleParent(static_cast<SAMPLEINDEX>(item)); ins != 0 && ins != INSTRUMENTINDEX_INVALID)
|
||
|
newItem = ins - 1;
|
||
|
break;
|
||
|
}
|
||
|
m_ItemList.SetItemState(newItem, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED);
|
||
|
m_ItemList.SetSelectionMark(newItem);
|
||
|
m_ItemList.EnsureVisible(newItem, FALSE);
|
||
|
m_ItemList.SetFocus();
|
||
|
}
|
||
|
return wParam;
|
||
|
} else if(wParam == kcExecuteSmpInsListItem)
|
||
|
{
|
||
|
OnDblClickListItem(nullptr, nullptr);
|
||
|
return wParam;
|
||
|
} else if(wParam == kcRenameSmpInsListItem)
|
||
|
{
|
||
|
m_ItemList.EditLabel(item - 1);
|
||
|
return wParam;
|
||
|
}
|
||
|
return kcNull;
|
||
|
}
|
||
|
|
||
|
|
||
|
BOOL CViewComments::PreTranslateMessage(MSG *pMsg)
|
||
|
{
|
||
|
if(pMsg)
|
||
|
{
|
||
|
if((pMsg->message == WM_SYSKEYUP) || (pMsg->message == WM_KEYUP)
|
||
|
|| (pMsg->message == WM_SYSKEYDOWN) || (pMsg->message == WM_KEYDOWN))
|
||
|
{
|
||
|
CInputHandler *ih = CMainFrame::GetInputHandler();
|
||
|
|
||
|
//Translate message manually
|
||
|
UINT nChar = static_cast<UINT>(pMsg->wParam);
|
||
|
UINT nRepCnt = LOWORD(pMsg->lParam);
|
||
|
UINT nFlags = HIWORD(pMsg->lParam);
|
||
|
KeyEventType kT = ih->GetKeyEventType(nFlags);
|
||
|
if(!ih->IsBypassed() && ih->KeyEvent(kCtxViewComments, nChar, nRepCnt, nFlags, kT) != kcNull)
|
||
|
{
|
||
|
return TRUE; // Mapped to a command, no need to pass message on.
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return CModScrollView::PreTranslateMessage(pMsg);
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////
|
||
|
// CViewComments drawing
|
||
|
|
||
|
void CViewComments::UpdateView(UpdateHint hint, CObject *)
|
||
|
{
|
||
|
const CModDoc *pModDoc = GetDocument();
|
||
|
|
||
|
if ((!pModDoc) || (!(m_ItemList.m_hWnd))) return;
|
||
|
const FlagSet<HintType> hintType = hint.GetType();
|
||
|
if (hintType[HINT_MPTOPTIONS])
|
||
|
{
|
||
|
m_ToolBar.UpdateStyle();
|
||
|
}
|
||
|
const SampleHint sampleHint = hint.ToType<SampleHint>();
|
||
|
const InstrumentHint instrHint = hint.ToType<InstrumentHint>();
|
||
|
const bool updateSamples = sampleHint.GetType()[HINT_SMPNAMES | HINT_SAMPLEINFO];
|
||
|
const bool updateInstr = instrHint.GetType()[HINT_INSNAMES|HINT_INSTRUMENT];
|
||
|
bool updateAll = hintType[HINT_MODTYPE];
|
||
|
|
||
|
if(!updateSamples && !updateInstr && !updateAll) return;
|
||
|
|
||
|
const CSoundFile &sndFile = pModDoc->GetSoundFile();
|
||
|
|
||
|
m_ToolBar.ChangeBitmap(IDC_LIST_INSTRUMENTS, sndFile.GetNumInstruments() ? IMAGE_INSTRUMENTS : IMAGE_INSTRMUTE);
|
||
|
|
||
|
CString s;
|
||
|
LV_ITEM lvi, lvi2;
|
||
|
|
||
|
m_ItemList.SetRedraw(FALSE);
|
||
|
// Add sample headers
|
||
|
if (m_nListId != m_nCurrentListId || updateAll)
|
||
|
{
|
||
|
UINT ichk = 0;
|
||
|
m_ItemList.DeleteAllItems();
|
||
|
while ((m_ItemList.DeleteColumn(0)) && (ichk < 25)) ichk++;
|
||
|
m_nCurrentListId = m_nListId;
|
||
|
if (m_nCurrentListId == IDC_LIST_SAMPLES)
|
||
|
{
|
||
|
// Add Sample Headers
|
||
|
m_ItemList.SetHeaders(gSampleHeaders);
|
||
|
} else if (m_nCurrentListId == IDC_LIST_INSTRUMENTS)
|
||
|
{
|
||
|
// Add Instrument Headers
|
||
|
m_ItemList.SetHeaders(gInstrumentHeaders);
|
||
|
} else
|
||
|
updateAll = true;
|
||
|
}
|
||
|
// Add Items
|
||
|
UINT nCount = m_ItemList.GetItemCount();
|
||
|
// Add Samples
|
||
|
if (m_nCurrentListId == IDC_LIST_SAMPLES && (updateAll || updateSamples))
|
||
|
{
|
||
|
SAMPLEINDEX nMax = static_cast<SAMPLEINDEX>(nCount);
|
||
|
if (nMax < sndFile.GetNumSamples()) nMax = sndFile.GetNumSamples();
|
||
|
for (SAMPLEINDEX iSmp = 0; iSmp < nMax; iSmp++)
|
||
|
{
|
||
|
if (iSmp < sndFile.GetNumSamples())
|
||
|
{
|
||
|
UINT nCol = 0;
|
||
|
for (UINT iCol=0; iCol<SMPLIST_COLUMNS; iCol++)
|
||
|
{
|
||
|
const ModSample &sample = sndFile.GetSample(iSmp + 1);
|
||
|
s.Empty();
|
||
|
switch(iCol)
|
||
|
{
|
||
|
case SMPLIST_SAMPLENAME:
|
||
|
s = mpt::ToCString(sndFile.GetCharsetInternal(), sndFile.m_szNames[iSmp + 1]);
|
||
|
break;
|
||
|
case SMPLIST_SAMPLENO:
|
||
|
s = mpt::cfmt::dec0<2>(iSmp + 1);
|
||
|
break;
|
||
|
case SMPLIST_SIZE:
|
||
|
if(sample.nLength && !sample.uFlags[CHN_ADLIB])
|
||
|
{
|
||
|
auto size = sample.GetSampleSizeInBytes();
|
||
|
if(size >= 1024)
|
||
|
s.Format(_T("%u KB"), size >> 10);
|
||
|
else
|
||
|
s.Format(_T("%u B"), size);
|
||
|
}
|
||
|
break;
|
||
|
case SMPLIST_TYPE:
|
||
|
if(sample.uFlags[CHN_ADLIB])
|
||
|
s = _T("OPL");
|
||
|
else if(sample.HasSampleData())
|
||
|
s = MPT_CFORMAT("{} Bit")(sample.GetElementarySampleSize() * 8);
|
||
|
break;
|
||
|
case SMPLIST_INSTR:
|
||
|
if (sndFile.GetNumInstruments())
|
||
|
{
|
||
|
bool first = true;
|
||
|
for (INSTRUMENTINDEX i = 1; i <= sndFile.GetNumInstruments(); i++)
|
||
|
{
|
||
|
if (sndFile.IsSampleReferencedByInstrument(iSmp + 1, i))
|
||
|
{
|
||
|
if (!first) s.AppendChar(_T(','));
|
||
|
first = false;
|
||
|
|
||
|
s.AppendFormat(_T("%u"), i);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
case SMPLIST_MIDDLEC:
|
||
|
if (sample.nLength)
|
||
|
{
|
||
|
s.Format(_T("%u Hz"), sample.GetSampleRate(sndFile.GetType()));
|
||
|
}
|
||
|
break;
|
||
|
case SMPLIST_FILENAME:
|
||
|
s = mpt::ToCString(sndFile.GetCharsetInternal(), sample.filename);
|
||
|
break;
|
||
|
case SMPLIST_PATH:
|
||
|
s = sndFile.GetSamplePath(iSmp + 1).ToCString();
|
||
|
break;
|
||
|
}
|
||
|
lvi.mask = LVIF_TEXT;
|
||
|
lvi.iItem = iSmp;
|
||
|
lvi.iSubItem = nCol;
|
||
|
lvi.pszText = const_cast<TCHAR *>(s.GetString());
|
||
|
if ((iCol) || (iSmp < nCount))
|
||
|
{
|
||
|
bool update = true;
|
||
|
if (iSmp < nCount)
|
||
|
{
|
||
|
TCHAR stmp[512];
|
||
|
lvi2 = lvi;
|
||
|
lvi2.pszText = stmp;
|
||
|
lvi2.cchTextMax = mpt::saturate_cast<int>(std::size(stmp));
|
||
|
stmp[0] = 0;
|
||
|
m_ItemList.GetItem(&lvi2);
|
||
|
if (s == stmp) update = false;
|
||
|
}
|
||
|
if (update) m_ItemList.SetItem(&lvi);
|
||
|
} else
|
||
|
{
|
||
|
m_ItemList.InsertItem(&lvi);
|
||
|
}
|
||
|
nCol++;
|
||
|
}
|
||
|
} else
|
||
|
{
|
||
|
m_ItemList.DeleteItem(iSmp);
|
||
|
}
|
||
|
}
|
||
|
} else
|
||
|
// Add Instruments
|
||
|
if ((m_nCurrentListId == IDC_LIST_INSTRUMENTS) && (updateAll || updateInstr))
|
||
|
{
|
||
|
INSTRUMENTINDEX nMax = static_cast<INSTRUMENTINDEX>(nCount);
|
||
|
if (nMax < sndFile.GetNumInstruments()) nMax = sndFile.GetNumInstruments();
|
||
|
for (INSTRUMENTINDEX iIns = 0; iIns < nMax; iIns++)
|
||
|
{
|
||
|
if (iIns < sndFile.GetNumInstruments())
|
||
|
{
|
||
|
UINT nCol = 0;
|
||
|
for (UINT iCol=0; iCol<INSLIST_COLUMNS; iCol++)
|
||
|
{
|
||
|
ModInstrument *pIns = sndFile.Instruments[iIns+1];
|
||
|
s.Empty();
|
||
|
switch(iCol)
|
||
|
{
|
||
|
case INSLIST_INSTRUMENTNAME:
|
||
|
if (pIns) s = mpt::ToCString(sndFile.GetCharsetInternal(), pIns->name);
|
||
|
break;
|
||
|
case INSLIST_INSTRUMENTNO:
|
||
|
s = mpt::cfmt::dec0<2>(iIns + 1);
|
||
|
break;
|
||
|
case INSLIST_SAMPLES:
|
||
|
if (pIns)
|
||
|
{
|
||
|
bool first = true;
|
||
|
for(auto sample : pIns->GetSamples())
|
||
|
{
|
||
|
if(!first) s.AppendChar(_T(','));
|
||
|
first = false;
|
||
|
s.AppendFormat(_T("%u"), sample);
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
case INSLIST_ENVELOPES:
|
||
|
if (pIns)
|
||
|
{
|
||
|
if (pIns->VolEnv.dwFlags[ENV_ENABLED]) s += _T("Vol");
|
||
|
if (pIns->PanEnv.dwFlags[ENV_ENABLED]) { if (!s.IsEmpty()) s += _T(", "); s += _T("Pan"); }
|
||
|
if (pIns->PitchEnv.dwFlags[ENV_ENABLED]) { if (!s.IsEmpty()) s += _T(", "); s += (pIns->PitchEnv.dwFlags[ENV_FILTER] ? _T("Filter") : _T("Pitch")); }
|
||
|
}
|
||
|
break;
|
||
|
case INSLIST_FILENAME:
|
||
|
if (pIns)
|
||
|
{
|
||
|
s = mpt::ToCString(sndFile.GetCharsetInternal(), pIns->filename);
|
||
|
}
|
||
|
break;
|
||
|
case INSLIST_PLUGIN:
|
||
|
if (pIns != nullptr && pIns->nMixPlug > 0 && sndFile.m_MixPlugins[pIns->nMixPlug - 1].IsValidPlugin())
|
||
|
{
|
||
|
s.Format(_T("FX%02u: "), pIns->nMixPlug);
|
||
|
s += mpt::ToCString(sndFile.m_MixPlugins[pIns->nMixPlug - 1].GetLibraryName());
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
lvi.mask = LVIF_TEXT;
|
||
|
lvi.iItem = iIns;
|
||
|
lvi.iSubItem = nCol;
|
||
|
lvi.pszText = const_cast<TCHAR *>(s.GetString());
|
||
|
if ((iCol) || (iIns < nCount))
|
||
|
{
|
||
|
bool update = true;
|
||
|
if (iIns < nCount)
|
||
|
{
|
||
|
TCHAR stmp[512];
|
||
|
lvi2 = lvi;
|
||
|
lvi2.pszText = stmp;
|
||
|
lvi2.cchTextMax = mpt::saturate_cast<int>(std::size(stmp));
|
||
|
stmp[0] = 0;
|
||
|
m_ItemList.GetItem(&lvi2);
|
||
|
if (s == stmp) update = false;
|
||
|
}
|
||
|
if (update) m_ItemList.SetItem(&lvi);
|
||
|
} else
|
||
|
{
|
||
|
m_ItemList.InsertItem(&lvi);
|
||
|
}
|
||
|
nCol++;
|
||
|
}
|
||
|
} else
|
||
|
{
|
||
|
m_ItemList.DeleteItem(iIns);
|
||
|
}
|
||
|
}
|
||
|
} else
|
||
|
// Add Patterns
|
||
|
//if ((m_nCurrentListId == IDC_LIST_PATTERNS) && (hintType & (HINT_MODTYPE|HINT_PATNAMES|HINT_PATTERNROW)))
|
||
|
{
|
||
|
}
|
||
|
m_ItemList.SetRedraw(TRUE);
|
||
|
}
|
||
|
|
||
|
|
||
|
void CViewComments::RecalcLayout()
|
||
|
{
|
||
|
CRect rect;
|
||
|
|
||
|
if (!m_hWnd) return;
|
||
|
GetClientRect(&rect);
|
||
|
m_ToolBar.SetWindowPos(NULL, 0, 0, rect.Width(), DETAILS_TOOLBAR_CY, SWP_NOZORDER|SWP_NOACTIVATE);
|
||
|
m_ItemList.SetWindowPos(NULL, -1, DETAILS_TOOLBAR_CY, rect.Width()+2, rect.Height() - DETAILS_TOOLBAR_CY + 1, SWP_NOZORDER|SWP_NOACTIVATE);
|
||
|
}
|
||
|
|
||
|
|
||
|
void CViewComments::UpdateButtonState()
|
||
|
{
|
||
|
const CModDoc *pModDoc = GetDocument();
|
||
|
if (pModDoc)
|
||
|
{
|
||
|
m_ToolBar.SetState(IDC_LIST_SAMPLES, ((m_nListId == IDC_LIST_SAMPLES) ? TBSTATE_CHECKED : 0)|TBSTATE_ENABLED);
|
||
|
m_ToolBar.SetState(IDC_LIST_INSTRUMENTS, ((m_nListId == IDC_LIST_INSTRUMENTS) ? TBSTATE_CHECKED : 0)|TBSTATE_ENABLED);
|
||
|
m_ToolBar.SetState(IDC_LIST_PATTERNS, ((m_nListId == IDC_LIST_PATTERNS) ? TBSTATE_CHECKED : 0)|TBSTATE_ENABLED);
|
||
|
m_ToolBar.EnableButton(IDC_LIST_INSTRUMENTS, (pModDoc->GetNumInstruments()) ? TRUE : FALSE);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
void CViewComments::OnBeginLabelEdit(LPNMHDR, LRESULT *)
|
||
|
{
|
||
|
CEdit *editCtrl = m_ItemList.GetEditControl();
|
||
|
if(editCtrl)
|
||
|
{
|
||
|
const CModSpecifications &specs = GetDocument()->GetSoundFile().GetModSpecifications();
|
||
|
const auto maxStrLen = (m_nListId == IDC_LIST_SAMPLES) ? specs.sampleNameLengthMax : specs.instrNameLengthMax;
|
||
|
editCtrl->LimitText(maxStrLen);
|
||
|
CMainFrame::GetInputHandler()->Bypass(true);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
void CViewComments::OnEndLabelEdit(LPNMHDR pnmhdr, LRESULT *)
|
||
|
{
|
||
|
CMainFrame::GetInputHandler()->Bypass(false);
|
||
|
LV_DISPINFO *plvDispInfo = (LV_DISPINFO *)pnmhdr;
|
||
|
LV_ITEM &lvItem = plvDispInfo->item;
|
||
|
CModDoc *pModDoc = GetDocument();
|
||
|
|
||
|
if(lvItem.pszText != nullptr && !lvItem.iSubItem && pModDoc)
|
||
|
{
|
||
|
UINT iItem = lvItem.iItem;
|
||
|
CSoundFile &sndFile = pModDoc->GetSoundFile();
|
||
|
|
||
|
if(m_nListId == IDC_LIST_SAMPLES)
|
||
|
{
|
||
|
if(iItem < sndFile.GetNumSamples())
|
||
|
{
|
||
|
sndFile.m_szNames[iItem + 1] = mpt::ToCharset(sndFile.GetCharsetInternal(), CString(lvItem.pszText));
|
||
|
pModDoc->UpdateAllViews(this, SampleHint(static_cast<SAMPLEINDEX>(iItem + 1)).Info().Names(), this);
|
||
|
pModDoc->SetModified();
|
||
|
}
|
||
|
} else if(m_nListId == IDC_LIST_INSTRUMENTS)
|
||
|
{
|
||
|
if((iItem < sndFile.GetNumInstruments()) && (sndFile.Instruments[iItem + 1]))
|
||
|
{
|
||
|
ModInstrument *pIns = sndFile.Instruments[iItem + 1];
|
||
|
pIns->name = mpt::ToCharset(sndFile.GetCharsetInternal(), CString(lvItem.pszText));
|
||
|
pModDoc->UpdateAllViews(this, InstrumentHint(static_cast<INSTRUMENTINDEX>(iItem + 1)).Info().Names(), this);
|
||
|
pModDoc->SetModified();
|
||
|
}
|
||
|
} else
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
m_ItemList.SetItemText(iItem, lvItem.iSubItem, lvItem.pszText);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////
|
||
|
// CViewComments messages
|
||
|
|
||
|
|
||
|
void CViewComments::OnSize(UINT nType, int cx, int cy)
|
||
|
{
|
||
|
CModScrollView::OnSize(nType, cx, cy);
|
||
|
if (((nType == SIZE_RESTORED) || (nType == SIZE_MAXIMIZED)) && (cx > 0) && (cy > 0) && (m_hWnd))
|
||
|
{
|
||
|
RecalcLayout();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
bool CViewComments::SwitchToList(int list)
|
||
|
{
|
||
|
if(list == m_nListId)
|
||
|
return false;
|
||
|
|
||
|
if(list == IDC_LIST_SAMPLES)
|
||
|
{
|
||
|
m_nListId = IDC_LIST_SAMPLES;
|
||
|
UpdateButtonState();
|
||
|
UpdateView(UpdateHint().ModType());
|
||
|
} else if(list == IDC_LIST_INSTRUMENTS)
|
||
|
{
|
||
|
const CModDoc *modDoc = GetDocument();
|
||
|
if(!modDoc || !modDoc->GetNumInstruments())
|
||
|
return false;
|
||
|
|
||
|
m_nListId = IDC_LIST_INSTRUMENTS;
|
||
|
UpdateButtonState();
|
||
|
UpdateView(UpdateHint().ModType());
|
||
|
/*} else if(list == IDC_LIST_PATTERNS)
|
||
|
{
|
||
|
m_nListId = IDC_LIST_PATTERNS;
|
||
|
UpdateButtonState();
|
||
|
UpdateView(UpdateHint().ModType());*/
|
||
|
} else
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
|
||
|
void CViewComments::OnDblClickListItem(NMHDR *, LRESULT *)
|
||
|
{
|
||
|
// Double click -> switch to instrument or sample tab
|
||
|
int nItem = m_ItemList.GetSelectionMark();
|
||
|
if(nItem == -1) return;
|
||
|
CModDoc *pModDoc = GetDocument();
|
||
|
if(!pModDoc) return;
|
||
|
nItem++;
|
||
|
|
||
|
switch(m_nListId)
|
||
|
{
|
||
|
case IDC_LIST_SAMPLES:
|
||
|
pModDoc->ViewSample(nItem);
|
||
|
break;
|
||
|
case IDC_LIST_INSTRUMENTS:
|
||
|
pModDoc->ViewInstrument(nItem);
|
||
|
break;
|
||
|
case IDC_LIST_PATTERNS:
|
||
|
pModDoc->ViewPattern(nItem, 0);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
void CViewComments::OnRClickListItem(NMHDR *, LRESULT *)
|
||
|
{
|
||
|
HMENU menu = ::CreatePopupMenu();
|
||
|
::AppendMenu(menu, MF_STRING, ID_COPY_ALL_NAMES, _T("&Copy Names"));
|
||
|
CPoint pt;
|
||
|
::GetCursorPos(&pt);
|
||
|
::TrackPopupMenu(menu, TPM_LEFTALIGN | TPM_RIGHTBUTTON, pt.x, pt.y, 0, m_hWnd, NULL);
|
||
|
::DestroyMenu(menu);
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
void CViewComments::OnCopyNames()
|
||
|
{
|
||
|
std::wstring names;
|
||
|
const CSoundFile &sndFile = GetDocument()->GetSoundFile();
|
||
|
if(m_nListId == IDC_LIST_SAMPLES)
|
||
|
{
|
||
|
for(SAMPLEINDEX i = 1; i <= sndFile.GetNumSamples(); i++)
|
||
|
names += mpt::ToWide(sndFile.GetCharsetInternal(), sndFile.GetSampleName(i)) + L"\r\n";
|
||
|
} else if(m_nListId == IDC_LIST_INSTRUMENTS)
|
||
|
{
|
||
|
for(INSTRUMENTINDEX i = 1; i <= sndFile.GetNumInstruments(); i++)
|
||
|
names += mpt::ToWide(sndFile.GetCharsetInternal(), sndFile.GetInstrumentName(i)) + L"\r\n";
|
||
|
}
|
||
|
const size_t sizeBytes = (names.length() + 1) * sizeof(wchar_t);
|
||
|
Clipboard clipboard(CF_UNICODETEXT, sizeBytes);
|
||
|
if(auto dst = clipboard.Get(); dst.data())
|
||
|
{
|
||
|
std::memcpy(dst.data(), names.c_str(), sizeBytes);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
OPENMPT_NAMESPACE_END
|