Files
FC1/Editor/Music/MusicEditorDialog.cpp
romkazvo 34d6c5d489 123
2023-08-07 19:29:24 +08:00

2113 lines
56 KiB
C++

////////////////////////////////////////////////////////////////////////////
//
// Crytek Engine Source File.
// Copyright (C), Crytek Studios, 2002.
// -------------------------------------------------------------------------
// File name: MaterialDialog.cpp
// Version: v1.00
// Created: 22/1/2003 by Timur.
// Compilers: Visual Studio.NET
// Description:
// -------------------------------------------------------------------------
// History:
//
////////////////////////////////////////////////////////////////////////////
#include "StdAfx.h"
#include "MusicEditorDialog.h"
#include "StringDlg.h"
#include "NumberDlg.h"
#include "MusicManager.h"
#include "MusicThemeLibrary.h"
#include "MusicThemeLibItem.h"
#include "ViewManager.h"
#include "Clipboard.h"
#include <Isound.h>
#include "MusicEditorUI.h"
#define IDC_TREE_CTRL AFX_IDW_PANE_FIRST
#define IDC_FILE_TREE_CTRL AFX_IDW_PANE_FIRST + 1*16
#define IMAGE_THEME 0
#define IMAGE_MOOD 1
#define IMAGE_PATTERN_SET 2
#define IMAGE_LAYER 3
#define IMAGE_PATTERN 4
//////////////////////////////////////////////////////////////////////////
static CMusicEditorUI_Theme sMusicUI_Theme;
static CMusicEditorUI_Mood sMusicUI_Mood;
static CMusicEditorUI_PatternSet sMusicUI_PatternSet;
static CMusicEditorUI_Layer sMusicUI_Layer;
static CMusicEditorUI_Pattern sMusicUI_Pattern;
IMPLEMENT_DYNAMIC(CMusicEditorDialog,CBaseLibraryDialog);
//////////////////////////////////////////////////////////////////////////
// CMusicEditorDialog implementation.
//////////////////////////////////////////////////////////////////////////
CMusicEditorDialog::CMusicEditorDialog( CWnd *pParent )
: CBaseLibraryDialog(IDD_DB_ENTITY, pParent)
{
m_pMusicManager = GetIEditor()->GetMusicManager();
m_pMusicData = m_pMusicManager->GetMusicData();
m_pItemManager = m_pMusicManager;
m_hDropItem = NULL;
m_hDraggedItem = NULL;
m_pSound = 0;
m_bPlaying = false;
m_bHandleDeleteItem = false;
m_lastItemType = (ETreeItemType)-1;
m_musicFilesPath = "Music";
m_pMusicSystem = GetIEditor()->GetSystem()->GetIMusicSystem();
// Immidiatly create dialog.
Create( IDD_DB_ENTITY,pParent );
}
CMusicEditorDialog::~CMusicEditorDialog()
{
}
void CMusicEditorDialog::DoDataExchange(CDataExchange* pDX)
{
CBaseLibraryDialog::DoDataExchange(pDX);
}
BEGIN_MESSAGE_MAP(CMusicEditorDialog, CBaseLibraryDialog)
ON_COMMAND( ID_DB_ADD,OnAddItem )
ON_UPDATE_COMMAND_UI( ID_DB_PLAY,OnUpdatePlay )
ON_COMMAND( ID_DB_MTL_ADDSUBMTL,OnAddSubItem )
ON_COMMAND( ID_DB_PLAY,OnPlay )
ON_COMMAND( ID_DB_STOP,OnStop )
ON_COMMAND( ID_DB_MUSIC_LOADFROMLUA,OnLoadFromLua )
ON_COMMAND( ID_DB_CUT,OnCut )
ON_COMMAND( ID_DB_COPY,OnCopy )
ON_COMMAND( ID_DB_PASTE,OnPaste )
ON_COMMAND( ID_DB_CLONE,OnClone )
ON_COMMAND( ID_DB_MUSIC_RELOADFILES,OnRealodMusicFiles )
ON_NOTIFY(TVN_SELCHANGED, IDC_TREE_CTRL, OnSelChangedItemTree)
ON_NOTIFY(TVN_BEGINDRAG, IDC_TREE_CTRL, OnBeginDrag)
ON_NOTIFY(TVN_BEGINLABELEDIT, IDC_TREE_CTRL, OnBeginLabelEdit)
ON_NOTIFY(TVN_ENDLABELEDIT, IDC_TREE_CTRL, OnEndLabelEdit)
ON_NOTIFY(TVN_DELETEITEM, IDC_TREE_CTRL, OnTreeDeleteItem )
ON_NOTIFY(NM_RCLICK , IDC_TREE_CTRL, OnNotifyTreeRClick)
ON_NOTIFY(NM_DBLCLK , IDC_TREE_CTRL, OnNotifyTreeDblClick)
//////////////////////////////////////////////////////////////////////////
// File tree.
ON_NOTIFY(NM_CLICK , IDC_FILE_TREE_CTRL, OnNotifyFileTreeClick)
ON_NOTIFY(TVN_SELCHANGED, IDC_FILE_TREE_CTRL, OnSelectFileTree)
ON_NOTIFY(TVN_BEGINDRAG, IDC_FILE_TREE_CTRL, OnFilesBeginDrag)
ON_NOTIFY(NM_KILLFOCUS, IDC_FILE_TREE_CTRL, OnFileTreeKillFocus)
ON_WM_SIZE()
ON_WM_DESTROY()
ON_WM_MOUSEMOVE()
ON_WM_LBUTTONUP()
END_MESSAGE_MAP()
//////////////////////////////////////////////////////////////////////////
void CMusicEditorDialog::OnDestroy()
{
int temp;
int HSplitter,VSplitter;
m_wndHSplitter.GetRowInfo( 0,HSplitter,temp );
m_wndVSplitter.GetColumnInfo( 0,VSplitter,temp );
AfxGetApp()->WriteProfileInt("Dialogs\\MusicEditor","HSplitter",HSplitter );
AfxGetApp()->WriteProfileInt("Dialogs\\MusicEditor","VSplitter",VSplitter );
CBaseLibraryDialog::OnDestroy();
}
// CTVSelectKeyDialog message handlers
BOOL CMusicEditorDialog::OnInitDialog()
{
CBaseLibraryDialog::OnInitDialog();
m_pMusicSystem = GetIEditor()->GetSystem()->GetIMusicSystem();
InitToolbar();
CRect rc;
GetClientRect(rc);
//int h2 = rc.Height()/2;
int h2 = 200;
int VSplitter = AfxGetApp()->GetProfileInt("Dialogs\\MusicEditor","VSplitter",300 );
int HSplitter = AfxGetApp()->GetProfileInt("Dialogs\\MusicEditor","HSplitter",100 );
//m_imageList.Create(IDB_MUSIC_TREE, 16, 1, RGB (255, 0, 255));
CMFCUtils::LoadTrueColorImageList( m_imageList,IDB_MUSIC_TREE,16,RGB(255,0,255) );
m_wndVSplitter.CreateStatic( this,1,2,WS_CHILD|WS_VISIBLE );
m_wndHSplitter.CreateStatic( &m_wndVSplitter,2,1,WS_CHILD|WS_VISIBLE );
// TreeCtrl must be already created.
//m_treeCtrl.EnableMultiSelect(TRUE);
m_treeCtrl.ModifyStyle( 0,TVS_EDITLABELS );
m_treeCtrl.SetParent( &m_wndVSplitter );
m_treeCtrl.SetImageList(&m_imageList,TVSIL_NORMAL);
m_propsCtrl.Create( WS_VISIBLE|WS_CHILD|WS_BORDER,rc,&m_wndVSplitter,1 );
//m_vars = gMatVars.CreateVars();
//m_propsCtrl.AddVarBlock( m_vars );
m_propsCtrl.EnableWindow(FALSE);
//////////////////////////////////////////////////////////////////////////
// Attach it to the control
m_filesImageList.Create(IDB_SOUND_FILES, 16, 1, RGB (255, 0, 255));
m_filesTreeCtrl.Create( WS_VISIBLE|WS_CHILD|WS_TABSTOP|WS_BORDER|TVS_HASBUTTONS|TVS_LINESATROOT|TVS_HASLINES,CRect(),this,IDC_FILE_TREE_CTRL );
m_filesTreeCtrl.SetParent( &m_wndHSplitter );
m_filesTreeCtrl.SetImageList(&m_filesImageList,TVSIL_NORMAL);
//////////////////////////////////////////////////////////////////////////
m_wndHSplitter.SetPane( 0,0,&m_propsCtrl,CSize(100,HSplitter) );
m_wndHSplitter.SetPane( 1,0,&m_filesTreeCtrl,CSize(100,HSplitter) );
m_wndVSplitter.SetPane( 0,0,&m_treeCtrl,CSize(VSplitter,100) );
m_wndVSplitter.SetPane( 0,1,&m_wndHSplitter,CSize(VSplitter,100) );
RecalcLayout();
return TRUE; // return TRUE unless you set the focus to a control
// EXCEPTION: OCX Property Pages should return FALSE
}
//////////////////////////////////////////////////////////////////////////
UINT CMusicEditorDialog::GetDialogMenuID()
{
return IDR_DB_ENTITY;
};
//////////////////////////////////////////////////////////////////////////
// Create the toolbar
void CMusicEditorDialog::InitToolbar()
{
VERIFY( m_toolbar.CreateEx(this, TBSTYLE_FLAT|TBSTYLE_WRAPABLE,
WS_CHILD|WS_VISIBLE|CBRS_TOP|CBRS_TOOLTIPS|CBRS_FLYBY|CBRS_SIZE_DYNAMIC) );
VERIFY( m_toolbar.LoadToolBar24(IDR_DB_MUSIC_BAR) );
// Resize the toolbar
CRect rc;
GetClientRect(rc);
m_toolbar.SetWindowPos(NULL, 0, 0, rc.right, 70, SWP_NOZORDER);
CSize sz = m_toolbar.CalcDynamicLayout(TRUE,TRUE);
//m_toolbar.SetButtonStyle( m_toolbar.CommandToIndex(ID_DB_PLAY),TBBS_CHECKBOX );
CBaseLibraryDialog::InitToolbar();
}
//////////////////////////////////////////////////////////////////////////
void CMusicEditorDialog::OnSize(UINT nType, int cx, int cy)
{
// resize splitter window.
if (m_wndVSplitter.m_hWnd)
{
CRect rc;
GetClientRect(rc);
m_wndVSplitter.MoveWindow(rc,FALSE);
}
CBaseLibraryDialog::OnSize(nType, cx, cy);
}
//////////////////////////////////////////////////////////////////////////
void CMusicEditorDialog::OnNewDocument()
{
//////////////////////////////////////////////////////////////////////////
CBaseLibraryDialog::OnNewDocument();
if (m_pSound)
m_pSound->Stop();
m_pSound = 0;
if (m_pMusicSystem) // [marco] crashes in previewer
m_pMusicSystem->SetData( m_pMusicData,true );
};
//////////////////////////////////////////////////////////////////////////
void CMusicEditorDialog::OnLoadDocument()
{
CBaseLibraryDialog::OnLoadDocument();
if (m_pSound)
m_pSound->Stop();
m_pSound = 0;
}
//////////////////////////////////////////////////////////////////////////
void CMusicEditorDialog::OnCloseDocument()
{
CBaseLibraryDialog::OnCloseDocument();
if (m_pSound)
m_pSound->Stop();
m_pSound = 0;
}
//////////////////////////////////////////////////////////////////////////
HTREEITEM CMusicEditorDialog::InsertItemToTree( CBaseLibraryItem *pItem,HTREEITEM hParent )
{
/*
CMusicThemeLibItem *pMtl = (CMusicThemeLibItem*)pItem;
if (pMtl->GetParent())
{
if (!hParent || hParent == TVI_ROOT || m_treeCtrl.GetItemData(hParent) == 0)
return 0;
}
HTREEITEM hMtlItem = CBaseLibraryDialog::InsertItemToTree( pItem,hParent );
for (int i = 0; i < pMtl->GetSubMaterialCount(); i++)
{
CMusicThemeLibItem *pSubMtl = pMtl->GetSubMaterial(i);
CBaseLibraryDialog::InsertItemToTree( pSubMtl,hMtlItem );
}
return hMtlItem;
*/
return 0;
}
//////////////////////////////////////////////////////////////////////////
void CMusicEditorDialog::SelectItem( CBaseLibraryItem *item,bool bForceReload )
{
/*
bool bChanged = item != m_pCurrentItem || bForceReload;
CBaseLibraryDialog::SelectItem( item,bForceReload );
if (!bChanged)
return;
// Empty preview control.
m_previewCtrl.SetEntity(0);
m_pMatManager->SetCurrentMaterial( (CMusicThemeLibItem*)item );
if (!item)
{
m_propsCtrl.EnableWindow(FALSE);
return;
}
if (!m_pEntityRender)
{
LoadGeometry( m_geometryFile );
}
if (m_pEntityRender)
m_previewCtrl.SetEntity( m_pEntityRender );
m_propsCtrl.EnableWindow(TRUE);
m_propsCtrl.EnableUpdateCallback(false);
// Render preview geometry with current material
CMusicThemeLibItem *mtl = GetSelectedMaterial();
AssignMtlToGeometry();
// Update variables.
m_propsCtrl.EnableUpdateCallback(false);
gMatVars.SetFromMaterial( mtl );
m_propsCtrl.EnableUpdateCallback(true);
//gMatVars.m_onSetCallback = functor(*this,OnUpdateProperties);
if (m_publicVarsItems)
{
m_propsCtrl.DeleteItem( m_publicVarsItems );
m_publicVarsItems = 0;
}
m_publicVars = mtl->GetPublicVars();
if (m_publicVars)
{
m_publicVarsItems = m_propsCtrl.AddVarBlock( m_publicVars,"Shader Params" );
}
m_propsCtrl.ExpandAllChilds( m_propsCtrl.GetRootItem(),false );
m_propsCtrl.SetUpdateCallback( functor(*this,OnUpdateProperties) );
m_propsCtrl.EnableUpdateCallback(true);
*/
}
//////////////////////////////////////////////////////////////////////////
void CMusicEditorDialog::Update()
{
}
//////////////////////////////////////////////////////////////////////////
void CMusicEditorDialog::OnUpdateProperties( IVariable *var )
{
ItemDesc *pItemDesc = GetCurrentItem();
switch (pItemDesc->type)
{
case EITEM_THEME:
sMusicUI_Theme.Get( pItemDesc->m_pTheme );
break;
case EITEM_MOOD:
sMusicUI_Mood.Get( pItemDesc->m_pMood );
break;
case EITEM_PATTERN_SET:
sMusicUI_PatternSet.Get( pItemDesc->m_pPatternSet );
break;
case EITEM_LAYER:
sMusicUI_Layer.Get( pItemDesc->m_pPatternSet,pItemDesc->layerType );
break;
case EITEM_PATTERN:
{
sMusicUI_Pattern.Get( pItemDesc->m_pPattern );
// Update total probabilities.
SMusicPatternSet *pPatternSet = pItemDesc->m_pPatternSet;
CalcProbabilities( pPatternSet );
// Update pattern description in Music.
m_pMusicSystem->UpdatePattern( pItemDesc->m_pPattern );
}
break;
};
SetModified();
/*
CMusicThemeLibItem *mtl = GetSelectedMaterial();
if (!mtl)
return;
bool bLightingOnChanged = &gMatVars.bLighting == var;
bool bShaderChanged = (var == &gMatVars.shader);
// Assign new public vars to material.
if (m_publicVarsItems != NULL && m_publicVars != NULL)
{
if (!bShaderChanged)
{
// No need to change public vars.
mtl->SetPublicVars( m_publicVars );
}
}
gMatVars.SetToMaterial( mtl );
if (bShaderChanged || bLightingOnChanged)
{
gMatVars.SetFromMaterial( mtl );
}
gMatVars.SetTextureNames( mtl );
AssignMtlToGeometry();
// When shader changed.
if (bShaderChanged)
{
// Delete old public params and add new ones.
if (m_publicVarsItems)
{
m_propsCtrl.DeleteItem( m_publicVarsItems );
m_publicVarsItems = 0;
}
m_publicVars = mtl->GetPublicVars();
if (m_publicVars)
{
m_publicVarsItems = m_propsCtrl.AddVarBlock( m_publicVars,"Shader Params" );
}
}
if (bLightingOnChanged)
m_propsCtrl.Invalidate();
*/
}
//////////////////////////////////////////////////////////////////////////
void CMusicEditorDialog::OnPlay()
{
m_bPlaying = true;
m_pMusicSystem->Pause(false);
ItemDesc *pItem = GetCurrentItem();
if (pItem)
{
if (m_bPlaying)
{
if (pItem->type == EITEM_PATTERN)
{
m_pMusicSystem->PlayPattern( pItem->m_pPattern->sName.c_str(),false );
}
else
{
if (pItem->m_pTheme)
m_pMusicSystem->SetTheme( pItem->m_pTheme->sName.c_str() );
if (pItem->m_pMood)
m_pMusicSystem->SetMood( pItem->m_pMood->sName.c_str() );
}
}
}
}
//////////////////////////////////////////////////////////////////////////
void CMusicEditorDialog::OnUpdatePlay( CCmdUI* pCmdUI )
{
if (m_bPlaying)
pCmdUI->SetCheck(TRUE);
else
pCmdUI->SetCheck(FALSE);
}
//////////////////////////////////////////////////////////////////////////
void CMusicEditorDialog::OnStop()
{
m_pMusicSystem->Silence();
m_pMusicSystem->Pause(true);
m_bPlaying = false;
}
//////////////////////////////////////////////////////////////////////////
void CMusicEditorDialog::OnBeginDrag(NMHDR* pNMHDR, LRESULT* pResult)
{
/*
NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
HTREEITEM hItem = pNMTreeView->itemNew.hItem;
CMusicThemeLibItem* pMtl = (CMusicThemeLibItem*)m_treeCtrl.GetItemData(hItem);
if (!pMtl)
return;
m_treeCtrl.Select( hItem,TVGN_CARET );
m_hDropItem = 0;
m_dragImage = m_treeCtrl.CreateDragImage( hItem );
if (m_dragImage)
{
m_hDraggedItem = hItem;
m_hDropItem = hItem;
m_dragImage->BeginDrag(0, CPoint(-10, -10));
CRect rc;
AfxGetMainWnd()->GetWindowRect( rc );
CPoint p = pNMTreeView->ptDrag;
ClientToScreen( &p );
p.x -= rc.left;
p.y -= rc.top;
m_dragImage->DragEnter( AfxGetMainWnd(),p );
SetCapture();
GetIEditor()->EnableUpdate( false );
}
*/
*pResult = 0;
}
//////////////////////////////////////////////////////////////////////////
void CMusicEditorDialog::OnMouseMove(UINT nFlags, CPoint point)
{
if (m_dragImage)
{
CPoint p;
p = point;
ClientToScreen( &p );
m_treeCtrl.ScreenToClient( &p );
TVHITTESTINFO hit;
ZeroStruct(hit);
hit.pt = p;
HTREEITEM hHitItem = m_treeCtrl.HitTest( &hit );
if (m_hDropItem != hHitItem)
{
if (m_hDropItem)
{
m_treeCtrl.SetItem( m_hDropItem,TVIF_STATE,0,0,0,0,TVIS_DROPHILITED,0 );
m_treeCtrl.Invalidate();
}
}
if (hHitItem)
{
if (m_hDropItem != hHitItem)
{
m_hDropItem = 0;
ItemDesc *pItemDesc = (ItemDesc*)m_treeCtrl.GetItemData(hHitItem);
if (pItemDesc && (pItemDesc->type == EITEM_PATTERN || pItemDesc->type == EITEM_LAYER))
{
// Set state of this item to drop target.
m_treeCtrl.SetItem( hHitItem,TVIF_STATE,0,0,0,TVIS_DROPHILITED,TVIS_DROPHILITED,0 );
m_treeCtrl.Invalidate();
m_hDropItem = hHitItem;
}
}
}
CRect rc;
AfxGetMainWnd()->GetWindowRect( rc );
p = point;
ClientToScreen( &p );
p.x -= rc.left;
p.y -= rc.top;
m_dragImage->DragMove( p );
}
CBaseLibraryDialog::OnMouseMove(nFlags, point);
}
//////////////////////////////////////////////////////////////////////////
void CMusicEditorDialog::OnLButtonUp(UINT nFlags, CPoint point)
{
//CXTResizeDialog::OnLButtonUp(nFlags, point);
if (m_hDropItem)
{
m_treeCtrl.SetItem( m_hDropItem,TVIF_STATE,0,0,0,0,TVIS_DROPHILITED,0 );
m_hDropItem = 0;
}
if (m_dragImage)
{
CPoint p;
GetCursorPos( &p );
GetIEditor()->EnableUpdate( true );
m_dragImage->DragLeave( AfxGetMainWnd() );
m_dragImage->EndDrag();
delete m_dragImage;
m_dragImage = 0;
ReleaseCapture();
CPoint treepoint = p;
m_treeCtrl.ScreenToClient( &treepoint );
TVHITTESTINFO hit;
ZeroStruct(hit);
hit.pt = treepoint;
HTREEITEM hHitItem = m_treeCtrl.HitTest( &hit );
if (hHitItem)
{
DropToItem( hHitItem,m_hDraggedItem );
m_hDraggedItem = 0;
return;
}
}
m_hDraggedItem = 0;
CBaseLibraryDialog::OnLButtonUp(nFlags, point);
}
//////////////////////////////////////////////////////////////////////////
void CMusicEditorDialog::OnNotifyTreeRClick(NMHDR* pNMHDR, LRESULT* pResult)
{
*pResult = 0;
// Show helper menu.
CPoint point;
ItemDesc *pItemDesc = 0;
// Find node under mouse.
GetCursorPos( &point );
m_treeCtrl.ScreenToClient( &point );
// Select the item that is at the point myPoint.
UINT uFlags;
HTREEITEM hItem = m_treeCtrl.HitTest(point,&uFlags);
if ((hItem != NULL) && (TVHT_ONITEM & uFlags))
{
pItemDesc = (ItemDesc*)m_treeCtrl.GetItemData(hItem);
}
m_treeCtrl.Select( hItem,TVGN_CARET );
// Create pop up menu.
CMenu menu;
menu.CreatePopupMenu();
CString pasteStr = "Paste";
CClipboard clipboard;
bool bNoPaste = clipboard.IsEmpty();
int pasteFlags = 0;
if (bNoPaste)
pasteFlags |= MF_GRAYED;
else
{
pasteStr = pasteStr + " " + clipboard.GetTitle();
}
if (pItemDesc)
{
switch (pItemDesc->type)
{
case EITEM_THEME:
menu.AppendMenu( MF_STRING,ID_DB_PLAY,"Play Theme" );
menu.AppendMenu( MF_STRING,ID_DB_ADD,"New Theme" );
menu.AppendMenu( MF_STRING,ID_DB_MTL_ADDSUBMTL,"New Mood" );
menu.AppendMenu( MF_STRING,ID_DB_MTL_ADDSUBMTL,"New Bridge" );
menu.AppendMenu( MF_SEPARATOR,0,"" );
break;
case EITEM_MOOD:
menu.AppendMenu( MF_STRING,ID_DB_PLAY,"Play Mood" );
//menu.AppendMenu( MF_STRING,ID_DB_PLAY,"Play As Default Mood" );
menu.AppendMenu( MF_STRING,ID_DB_ADD,"New Mood" );
menu.AppendMenu( MF_STRING,ID_DB_MTL_ADDSUBMTL,"New Pattern Set" );
menu.AppendMenu( MF_SEPARATOR,0,"" );
break;
case EITEM_PATTERN_SET:
menu.AppendMenu( MF_STRING,ID_DB_PLAY,"Play Mood" );
menu.AppendMenu( MF_STRING,ID_DB_ADD,"New Pattern Set" );
menu.AppendMenu( MF_SEPARATOR,0,"" );
break;
case EITEM_LAYER:
menu.AppendMenu( MF_STRING,ID_DB_PLAY,"Play Mood" );
menu.AppendMenu( MF_STRING,ID_DB_ADD,"New Pattern" );
menu.AppendMenu( MF_SEPARATOR,0,"" );
break;
case EITEM_PATTERN:
menu.AppendMenu( MF_STRING,ID_DB_PLAY,"Play Pattern" );
menu.AppendMenu( MF_STRING,ID_DB_ADD,"New Pattern" );
menu.AppendMenu( MF_SEPARATOR,0,"" );
break;
};
if (pItemDesc->type != EITEM_LAYER)
{
menu.AppendMenu( MF_STRING,ID_DB_CUT,"Cut" );
menu.AppendMenu( MF_STRING,ID_DB_COPY,"Copy" );
menu.AppendMenu( MF_STRING|pasteFlags,ID_DB_PASTE,pasteStr );
menu.AppendMenu( MF_STRING,ID_DB_CLONE,"Clone" );
menu.AppendMenu( MF_SEPARATOR,0,"" );
menu.AppendMenu( MF_STRING,ID_DB_RENAME,"Rename" );
menu.AppendMenu( MF_STRING,ID_DB_REMOVE,"Delete" );
}
else
{
menu.AppendMenu( MF_STRING|pasteFlags,ID_DB_PASTE,pasteStr );
menu.AppendMenu( MF_SEPARATOR,0,"" );
menu.AppendMenu( MF_STRING,ID_DB_REMOVE,"Delete Patterns" );
}
}
else
{
// No items.
menu.AppendMenu( MF_STRING,ID_DB_ADD,"New Theme" );
menu.AppendMenu( MF_SEPARATOR,0,"" );
menu.AppendMenu( MF_STRING|pasteFlags,ID_DB_PASTE,pasteStr );
}
GetCursorPos( &point );
menu.TrackPopupMenu( TPM_LEFTALIGN|TPM_LEFTBUTTON,point.x,point.y,this );
}
//////////////////////////////////////////////////////////////////////////
void CMusicEditorDialog::OnNotifyTreeDblClick(NMHDR* pNMHDR, LRESULT* pResult)
{
*pResult = 0;
// Show helper menu.
CPoint point;
ItemDesc *pItemDesc = 0;
// Find node under mouse.
GetCursorPos( &point );
m_treeCtrl.ScreenToClient( &point );
// Select the item that is at the point myPoint.
UINT uFlags;
HTREEITEM hItem = m_treeCtrl.HitTest(point,&uFlags);
if ((hItem != NULL) && (TVHT_ONITEM & uFlags))
{
pItemDesc = (ItemDesc*)m_treeCtrl.GetItemData(hItem);
}
if (!pItemDesc)
return;
m_treeCtrl.Select( hItem,TVGN_CARET );
/*
if (pItemDesc->type == EITEM_PATTERN)
{
bool bExclusive = !m_bPlaying;
m_pMusicSystem->PlayPattern( pItemDesc->m_pPattern->sName.c_str(),bExclusive );
if (bExclusive)
m_bPlaying = false;
}
else
*/
if (m_bPlaying)
OnPlay();
}
//////////////////////////////////////////////////////////////////////////
void CMusicEditorDialog::OnCopy()
{
CClipboard clipboard;
ItemDesc *pItemDesc = GetCurrentItem();
if (!pItemDesc)
return;
switch (pItemDesc->type)
{
case EITEM_THEME:
// Copy Theme.
{
XmlNodeRef node = new CXmlNode( "Theme" );
CBaseLibraryItem::SerializeContext ctx( node,false );
ctx.bCopyPaste = true;
((CMusicThemeLibItem*)(pItemDesc->pItem))->Serialize( ctx );
clipboard.Put( node );
}
break;
case EITEM_MOOD:
// Copy Mood.
{
XmlNodeRef node = new CXmlNode( "Mood" );
CBaseLibraryItem::SerializeContext ctx( node,false );
ctx.bCopyPaste = true;
CMusicThemeLibItem::SerializeMood( ctx,pItemDesc->m_pMood );
clipboard.Put( node );
}
break;
case EITEM_PATTERN_SET:
// Copy pattern set.
{
XmlNodeRef node = new CXmlNode( "PatternSet" );
CBaseLibraryItem::SerializeContext ctx( node,false );
ctx.bCopyPaste = true;
CMusicThemeLibItem::SerializePatternSet( ctx,pItemDesc->m_pPatternSet );
clipboard.Put( node );
}
break;
case EITEM_LAYER:
break;
case EITEM_PATTERN:
{
XmlNodeRef node = new CXmlNode( "Pattern" );
CBaseLibraryItem::SerializeContext ctx( node,false );
ctx.bCopyPaste = true;
CMusicThemeLibItem::SerializePattern( ctx,pItemDesc->m_pPattern );
clipboard.Put( node );
}
break;
};
}
//////////////////////////////////////////////////////////////////////////
void CMusicEditorDialog::OnPaste()
{
if (!m_pLibrary)
return;
CClipboard clipboard;
if (clipboard.IsEmpty())
return;
XmlNodeRef node = clipboard.Get();
if (!node)
return;
ItemDesc *pItemDesc = GetCurrentItem();
if (node->isTag("Pattern"))
{
if (pItemDesc && pItemDesc->m_pPatternSet)
NewPattern( pItemDesc->m_pPatternSet,pItemDesc->layerType,NULL,node );
}
else if (node->isTag("PatternSet"))
{
if (pItemDesc && pItemDesc->m_pMood)
PastePatternSet( pItemDesc->m_pMood,node );
}
else if (node->isTag("Mood"))
{
if (pItemDesc && pItemDesc->m_pTheme)
PasteMood( pItemDesc->m_pTheme,node );
}
else if (node->isTag("Theme"))
{
PasteTheme( node );
}
}
//////////////////////////////////////////////////////////////////////////
void CMusicEditorDialog::DropToItem( HTREEITEM hItem,HTREEITEM hSrcItem )
{
if (m_pLibrary)
{
m_pLibrary->SetModified();
}
CString filename = stl::find_in_map( m_musicFilesMap,hSrcItem,"" );
if (!filename.IsEmpty())
{
ItemDesc *pItemDesc = (ItemDesc*)m_treeCtrl.GetItemData(hItem);
if (pItemDesc)
{
switch(pItemDesc->type) {
case EITEM_LAYER:
{
CString fname = Path::GetFileName(filename);
SPatternDef *pPattern = NewPattern( pItemDesc->m_pPatternSet,pItemDesc->layerType,fname );
pPattern->sFilename = (const char*)filename;
m_pMusicSystem->UpdatePattern( pPattern );
}
break;
case EITEM_PATTERN:
pItemDesc->m_pPattern->sFilename = (const char*)filename;
m_pMusicSystem->UpdatePattern( pItemDesc->m_pPattern );
break;
}
if (GetCurrentItem() == pItemDesc)
SelectItem( pItemDesc );
}
}
SetModified();
}
//////////////////////////////////////////////////////////////////////////
HTREEITEM CMusicEditorDialog::InsertItem_Theme( CMusicThemeLibItem *pItem )
{
SMusicTheme *pTheme = pItem->GetTheme();
HTREEITEM hItem = m_treeCtrl.InsertItem( pTheme->sName.c_str(),IMAGE_THEME,IMAGE_THEME,TVI_ROOT );
ItemDesc *pItemDesc = new ItemDesc;
pItemDesc->type = EITEM_THEME;
pItemDesc->pItem = pItem;
pItemDesc->m_pTheme = pTheme;
m_treeCtrl.SetItemData( hItem,(DWORD_PTR)pItemDesc );
m_ThemeToItemMap[pTheme] = hItem;
for (TMoodMap::iterator it = pTheme->mapMoods.begin(); it != pTheme->mapMoods.end(); ++it)
{
InsertItem_Mood( pItemDesc,it->second,hItem );
}
return hItem;
}
//////////////////////////////////////////////////////////////////////////
HTREEITEM CMusicEditorDialog::InsertItem_Mood( ItemDesc *pParent,SMusicMood *pMood,HTREEITEM parentItem )
{
if (!parentItem)
{
parentItem = stl::find_in_map( m_ThemeToItemMap,pParent->m_pTheme, (HTREEITEM)0 );
if (!parentItem)
parentItem = TVI_ROOT;
}
HTREEITEM hItem = m_treeCtrl.InsertItem( pMood->sName.c_str(),IMAGE_MOOD,IMAGE_MOOD,parentItem );
ItemDesc *pItemDesc = new ItemDesc( *pParent );
pItemDesc->type = EITEM_MOOD;
pItemDesc->m_pMood = pMood;
m_treeCtrl.SetItemData( hItem,(DWORD_PTR)pItemDesc );
m_MoodToItemMap[pMood] = hItem;
for (int i = 0; i < pMood->vecPatternSets.size();i++)
{
InsertItem_PatternSet( pItemDesc,pMood->vecPatternSets[i],hItem );
}
return hItem;
}
//////////////////////////////////////////////////////////////////////////
HTREEITEM CMusicEditorDialog::InsertItem_PatternSet( ItemDesc *pParent,SMusicPatternSet *pPatterns,HTREEITEM parentItem )
{
if (!parentItem)
{
parentItem = stl::find_in_map( m_MoodToItemMap,pParent->m_pMood, (HTREEITEM)0 );
if (!parentItem)
parentItem = TVI_ROOT;
}
HTREEITEM hItem = m_treeCtrl.InsertItem( "Pattern Set",IMAGE_PATTERN_SET,IMAGE_PATTERN_SET,parentItem );
ItemDesc *pItemDesc = new ItemDesc( *pParent );
pItemDesc->type = EITEM_PATTERN_SET;
pItemDesc->m_pPatternSet = pPatterns;
m_treeCtrl.SetItemData( hItem,(DWORD_PTR)pItemDesc );
m_PatternSetToItemMap[pPatterns] = hItem;
// Add 3 pattern layers.
HTREEITEM hMainLayer = m_treeCtrl.InsertItem( "Main Layer",IMAGE_LAYER,IMAGE_LAYER,hItem );
HTREEITEM hRhythmicLayer = m_treeCtrl.InsertItem( "Rhytmic Layer",IMAGE_LAYER,IMAGE_LAYER,hItem );
HTREEITEM hIncidentalLayer = m_treeCtrl.InsertItem( "Incidental Layer",IMAGE_LAYER,IMAGE_LAYER,hItem );
ItemDesc *pItemDesc1 = new ItemDesc(*pItemDesc,ELAYER_MAIN);
ItemDesc *pItemDesc2 = new ItemDesc(*pItemDesc,ELAYER_RHYTHMIC);
ItemDesc *pItemDesc3 = new ItemDesc(*pItemDesc,ELAYER_INCIDENTAL);
m_treeCtrl.SetItemData( hMainLayer,(DWORD_PTR)(pItemDesc1) );
m_treeCtrl.SetItemData( hRhythmicLayer,(DWORD_PTR)(pItemDesc2) );
m_treeCtrl.SetItemData( hIncidentalLayer,(DWORD_PTR)(pItemDesc3) );
int i;
for (i = 0; i < pPatterns->vecMainPatterns.size();i++)
{
InsertItem_Pattern( pItemDesc1,pPatterns->vecMainPatterns[i],hMainLayer );
}
for (i = 0; i < pPatterns->vecRhythmicPatterns.size();i++)
{
InsertItem_Pattern( pItemDesc2,pPatterns->vecRhythmicPatterns[i],hRhythmicLayer );
}
for (i = 0; i < pPatterns->vecIncidentalPatterns.size();i++)
{
InsertItem_Pattern( pItemDesc3,pPatterns->vecIncidentalPatterns[i],hIncidentalLayer );
}
return hItem;
}
//////////////////////////////////////////////////////////////////////////
HTREEITEM CMusicEditorDialog::InsertItem_Pattern( ItemDesc *pParent,SPatternDef *pPattern,HTREEITEM parentItem )
{
if (!parentItem)
{
if (!parentItem)
parentItem = TVI_ROOT;
}
// Find this pattern.
//m_pMusicData->vecPatternDef
HTREEITEM hItem = m_treeCtrl.InsertItem( pPattern->sName.c_str(),IMAGE_PATTERN,IMAGE_PATTERN,parentItem );
ItemDesc *pItemDesc = new ItemDesc( *pParent );
pItemDesc->type = EITEM_PATTERN;
pItemDesc->m_pPattern = pPattern;
m_treeCtrl.SetItemData( hItem,(DWORD_PTR)pItemDesc );
m_PatternToItemMap[pPattern] = hItem;
return hItem;
}
//////////////////////////////////////////////////////////////////////////
void CMusicEditorDialog::ReloadItems()
{
m_bIgnoreSelectionChange = true;
m_pCurrentItem = 0;
m_itemsToTree.clear();
m_treeCtrl.DeleteAllItems();
m_bIgnoreSelectionChange = false;
if (!m_pLibrary)
return;
m_bIgnoreSelectionChange = true;
m_treeCtrl.SetRedraw(FALSE);
m_treeCtrl.DeleteAllItems();
// Clear all maps.
m_PatternsMap.clear();
// Clear all maps.
m_ThemeToItemMap.clear();
m_MoodToItemMap.clear();
m_PatternSetToItemMap.clear();
m_PatternToItemMap.clear();
if (!m_pMusicData)
return;
for (int i = 0; i < m_pMusicData->vecPatternDef.size(); i++)
{
SPatternDef *pPattern = m_pMusicData->vecPatternDef[i];
m_PatternsMap[pPattern->sName.c_str()] = pPattern;
}
//////////////////////////////////////////////////////////////////////////
HTREEITEM hLibItem = TVI_ROOT;
for (int i = 0; i < m_pLibrary->GetItemCount(); i++)
{
CMusicThemeLibItem *pItem = (CMusicThemeLibItem*)m_pLibrary->GetItem(i);
InsertItem_Theme( pItem );
}
//////////////////////////////////////////////////////////////////////////
m_treeCtrl.SetRedraw(TRUE);
m_bIgnoreSelectionChange = false;
}
//////////////////////////////////////////////////////////////////////////
void CMusicEditorDialog::OnSelChangedItemTree(NMHDR* pNMHDR, LRESULT* pResult)
{
if (m_bIgnoreSelectionChange)
return;
LPNMTREEVIEW pNMTreeView = reinterpret_cast<LPNMTREEVIEW>(pNMHDR);
if (m_pSound)
m_pSound->Stop();
m_pSound = 0;
m_pCurrentItem = 0;
if (m_treeCtrl)
{
HTREEITEM hItem = pNMTreeView->itemNew.hItem;
if (hItem != 0 && hItem != TVI_ROOT)
{
// Change currently selected item.
ItemDesc *desc = (ItemDesc*)m_treeCtrl.GetItemData(hItem);
assert(desc);
SelectItem( desc );
}
}
*pResult = 0;
}
//////////////////////////////////////////////////////////////////////////
void CMusicEditorDialog::SelectItem( ItemDesc *pItemDesc )
{
assert(pItemDesc);
m_propsCtrl.EnableUpdateCallback(false);
if (m_lastItemType != pItemDesc->type)
{
m_lastItemType = pItemDesc->type;
// Recreate UI variables.
m_propsCtrl.DeleteAllItems();
m_vars = 0;
switch (pItemDesc->type)
{
case EITEM_THEME:
m_vars = sMusicUI_Theme.CreateVars();
break;
case EITEM_MOOD:
m_vars = sMusicUI_Mood.CreateVars();
break;
case EITEM_PATTERN_SET:
m_vars = sMusicUI_PatternSet.CreateVars();
break;
case EITEM_LAYER:
m_vars = sMusicUI_Layer.CreateVars();
break;
case EITEM_PATTERN:
m_vars = sMusicUI_Pattern.CreateVars();
break;
}
if (m_vars)
{
m_propsCtrl.AddVarBlock( m_vars );
m_propsCtrl.ExpandAll();
m_propsCtrl.EnableWindow(TRUE);
}
else
m_propsCtrl.EnableWindow(FALSE);
}
switch (pItemDesc->type)
{
case EITEM_THEME:
if (m_vars)
{
m_propsCtrl.DeleteAllItems();
sMusicUI_Theme.Set( pItemDesc->m_pTheme );
m_propsCtrl.AddVarBlock( m_vars );
m_propsCtrl.ExpandAll();
}
break;
case EITEM_MOOD:
sMusicUI_Mood.Set( pItemDesc->m_pMood );
break;
case EITEM_PATTERN_SET:
sMusicUI_PatternSet.Set( pItemDesc->m_pPatternSet );
break;
case EITEM_LAYER:
sMusicUI_Layer.Set( pItemDesc->m_pPatternSet,pItemDesc->layerType );
break;
case EITEM_PATTERN:
sMusicUI_Pattern.Set( pItemDesc->m_pPattern );
break;
}
m_propsCtrl.SetUpdateCallback( functor(*this, &CMusicEditorDialog::OnUpdateProperties) );
m_propsCtrl.EnableUpdateCallback(true);
}
//////////////////////////////////////////////////////////////////////////
void CMusicEditorDialog::OnBeginLabelEdit(NMHDR* pNMHDR, LRESULT* pResult)
{
NMTVDISPINFO *pNM = (NMTVDISPINFO*)pNMHDR;
*pResult = 0;
ItemDesc *pItemDesc = (ItemDesc*)m_treeCtrl.GetItemData( pNM->item.hItem );
if (!pItemDesc)
{
*pResult = TRUE;
return;
}
switch (pItemDesc->type)
{
case EITEM_LAYER:
case EITEM_PATTERN_SET:
*pResult = TRUE;
break;
}
}
//////////////////////////////////////////////////////////////////////////
void CMusicEditorDialog::OnEndLabelEdit(NMHDR* pNMHDR, LRESULT* pResult)
{
NMTVDISPINFO *pNM = (NMTVDISPINFO*)pNMHDR;
*pResult = 0;
const char *sText = pNM->item.pszText;
if (!sText)
return;
ItemDesc *pItemDesc = (ItemDesc*)m_treeCtrl.GetItemData( pNM->item.hItem );
if (!pItemDesc)
return;
switch (pItemDesc->type)
{
case EITEM_THEME:
m_pMusicData->mapThemes.erase( pItemDesc->m_pTheme->sName.c_str() );
m_pMusicData->mapThemes[sText] = pItemDesc->m_pTheme;
pItemDesc->m_pTheme->sName = sText;
m_treeCtrl.SetItemText( pNM->item.hItem,sText );
pItemDesc->pItem->SetName( sText );
m_pMusicSystem->UpdateTheme( pItemDesc->m_pTheme );
break;
case EITEM_MOOD:
pItemDesc->m_pTheme->mapMoods.erase( pItemDesc->m_pMood->sName );
pItemDesc->m_pMood->sName = sText;
pItemDesc->m_pTheme->mapMoods[sText] = pItemDesc->m_pMood;
m_treeCtrl.SetItemText( pNM->item.hItem,sText );
m_pMusicSystem->UpdateMood( pItemDesc->m_pMood );
break;
case EITEM_PATTERN_SET:
//pItemDesc->m_pPatternSet->s
break;
case EITEM_PATTERN:
// New name must be unique.
if (m_PatternsMap.find(sText) == m_PatternsMap.end())
{
// Rename pattern.
m_pMusicSystem->RenamePattern( pItemDesc->m_pPattern->sName.c_str(),sText );
m_PatternsMap.erase(pItemDesc->m_pPattern->sName.c_str() ); // Old remove from map.
m_PatternsMap[sText] = pItemDesc->m_pPattern; // New add to map.
pItemDesc->m_pPattern->sName = sText;
m_treeCtrl.SetItemText( pNM->item.hItem,sText );
}
break;
}
SetModified();
}
//////////////////////////////////////////////////////////////////////////
void CMusicEditorDialog::SetModified()
{
if (m_pLibrary)
m_pLibrary->SetModified();
GetIEditor()->SetModifiedFlag();
}
//////////////////////////////////////////////////////////////////////////
CMusicEditorDialog::ItemDesc* CMusicEditorDialog::GetCurrentItem()
{
//if (m_treeCtrl.GetSelectedCount() != 1)
//return 0;
HTREEITEM hItem = m_treeCtrl.GetSelectedItem();
if (!hItem)
return 0;
ItemDesc *pItemDesc = (ItemDesc*)m_treeCtrl.GetItemData( hItem );
return pItemDesc;
}
SMusicTheme* CMusicEditorDialog::NewTheme( const char *sBaseName )
{
SMusicTheme *pTheme = new SMusicTheme;
if (!sBaseName || strlen(sBaseName) == 0)
sBaseName = "Theme0";
pTheme->sName = MakeUniqThemeName(sBaseName);
pTheme->fDefaultMoodTimeout = 0;
m_pMusicData->mapThemes[pTheme->sName] = pTheme;
CMusicThemeLibItem *pItem = (CMusicThemeLibItem*)m_pMusicManager->CreateItem( m_pLibrary );
pItem->SetTheme( pTheme );
m_treeCtrl.SetRedraw(FALSE);
HTREEITEM hNewItem = InsertItem_Theme( pItem );
m_treeCtrl.Select( hNewItem,TVGN_CARET );
m_treeCtrl.SetRedraw(TRUE);
m_pMusicSystem->UpdateTheme( pTheme );
return pTheme;
}
//////////////////////////////////////////////////////////////////////////
SMusicMood* CMusicEditorDialog::NewMood( SMusicTheme *pTheme,const char *sBaseName,bool bNewPatternSet )
{
SMusicMood *pMood = new SMusicMood;
if (!sBaseName)
sBaseName = "Mood0";
pMood->sName = MakeUniqMoodName(pTheme,sBaseName);
pMood->nPriority = 0;
pMood->fFadeOutTime = DEFAULT_CROSSFADE_TIME;
pMood->bPlaySingle = false;
pMood->pCurrPatternSet = 0;
pTheme->mapMoods[pMood->sName] = pMood;
m_treeCtrl.SetRedraw(FALSE);
//////////////////////////////////////////////////////////////////////////
// Add item to tree.
//////////////////////////////////////////////////////////////////////////
HTREEITEM hTheme = stl::find_in_map( m_ThemeToItemMap,pTheme, (HTREEITEM)0 );
if (hTheme)
{
ItemDesc *pThemeItemDesc = (ItemDesc*)m_treeCtrl.GetItemData(hTheme);
if (pThemeItemDesc)
{
HTREEITEM hNewItem = InsertItem_Mood( pThemeItemDesc,pMood,hTheme );
m_treeCtrl.Select( hNewItem,TVGN_CARET );
}
}
// Make one pattern set in this mood.
if (bNewPatternSet)
NewPatternSet( pMood );
m_treeCtrl.SetRedraw(TRUE);
return pMood;
}
//////////////////////////////////////////////////////////////////////////
void CMusicEditorDialog::CalcProbabilities( SMusicPatternSet *pPatternSet )
{
assert(pPatternSet);
pPatternSet->fTotalMainPatternProbability = 0.0f;
pPatternSet->fTotalRhythmicPatternProbability = 0.0f;
pPatternSet->fTotalIncidentalPatternProbability = 0.0f;
for (int j = 0; j < pPatternSet->vecMainPatterns.size(); j++)
{
pPatternSet->fTotalMainPatternProbability += pPatternSet->vecMainPatterns[j]->fProbability;
}
for (int j = 0; j < pPatternSet->vecRhythmicPatterns.size(); j++)
{
pPatternSet->fTotalRhythmicPatternProbability += pPatternSet->vecRhythmicPatterns[j]->fProbability;
}
for (int j = 0; j < pPatternSet->vecIncidentalPatterns.size(); j++)
{
pPatternSet->fTotalIncidentalPatternProbability += pPatternSet->vecIncidentalPatterns[j]->fProbability;
}
}
//////////////////////////////////////////////////////////////////////////
void CMusicEditorDialog::PasteTheme( XmlNodeRef &node )
{
const char *sBaseName = node->getAttr( "Name" );
SMusicTheme *pTheme = NewTheme(sBaseName);
pTheme->sDefaultMood = node->getAttr( "DefaultMood" );
node->getAttr( "DefaultMoodTimeout",pTheme->fDefaultMoodTimeout );
// Load moods.
XmlNodeRef nodeMoods = node->findChild("Moods");
if (nodeMoods)
{
for (int i = 0; i < nodeMoods->getChildCount(); i++)
{
XmlNodeRef moodNode = nodeMoods->getChild(i);
SMusicMood *pMood = PasteMood( pTheme,moodNode );
pTheme->mapMoods.erase( pMood->sName.c_str() ); // Erase uniq mood name.
pMood->sName = moodNode->getAttr("Name"); // Load name from xml node.
pTheme->mapMoods[pMood->sName.c_str()] = pMood; // Assign xml node name.
}
}
// Load bridges.
XmlNodeRef nodeBridges = node->findChild( "Bridges" );
if (nodeBridges)
{
for (int i = 0; i < nodeBridges->getChildCount(); i++)
{
XmlNodeRef nodeBridge = nodeBridges->getChild(i);
CString sPattern;
if (nodeBridge->getAttr( "Pattern",sPattern))
{
pTheme->mapBridges[nodeBridges->getTag()] = (const char*)sPattern;
}
}
}
}
//////////////////////////////////////////////////////////////////////////
SMusicMood* CMusicEditorDialog::PasteMood( SMusicTheme *pTheme,XmlNodeRef &node )
{
// Loading.
CString sBaseName = node->getAttr( "Name" );
SMusicMood *pMood = NewMood( pTheme,sBaseName,false );
node->getAttr( "PlaySingle",pMood->bPlaySingle );
node->getAttr( "Priority",pMood->nPriority );
node->getAttr( "FadeOutTime",pMood->fFadeOutTime );
if (node->getChildCount() > 0)
{
// Load pattern sets.
for (int i = 0; i < node->getChildCount(); i++)
{
PastePatternSet( pMood,node->getChild(i) );
}
}
return pMood;
}
//////////////////////////////////////////////////////////////////////////
void CMusicEditorDialog::PastePatternSet( SMusicMood *pMood,XmlNodeRef &nodePtrnSet )
{
SMusicPatternSet *pPatternSet = NewPatternSet( pMood );
nodePtrnSet->getAttr( "MaxTimeout",pPatternSet->fMaxTimeout );
nodePtrnSet->getAttr( "MinTimeout",pPatternSet->fMinTimeout );
nodePtrnSet->getAttr( "IncidentalLayerProbability",pPatternSet->fIncidentalLayerProbability );
nodePtrnSet->getAttr( "RhythmicLayerProbability",pPatternSet->fRhythmicLayerProbability );
nodePtrnSet->getAttr( "MaxSimultaneousIncidentalPatterns",pPatternSet->nMaxSimultaneousIncidentalPatterns );
nodePtrnSet->getAttr( "MaxSimultaneousRhythmicPatterns",pPatternSet->nMaxSimultaneousRhythmicPatterns );
// Save patterns.
XmlNodeRef nodeMainLayer = nodePtrnSet->findChild( "MainLayer" );
XmlNodeRef nodeRhythmicLayer = nodePtrnSet->findChild( "RhythmicLayer" );
XmlNodeRef nodeIncidentalLayer = nodePtrnSet->findChild( "IncidentalLayer" );
if (nodeMainLayer)
{
for (int j = 0; j < nodeMainLayer->getChildCount(); j++)
{
NewPattern( pPatternSet,ELAYER_MAIN,NULL,nodeMainLayer->getChild(j) );
}
}
if (nodeRhythmicLayer)
{
for (int j = 0; j < nodeRhythmicLayer->getChildCount(); j++)
{
NewPattern( pPatternSet,ELAYER_RHYTHMIC,NULL,nodeRhythmicLayer->getChild(j) );
}
}
if (nodeIncidentalLayer)
{
for (int j = 0; j < nodeIncidentalLayer->getChildCount(); j++)
{
NewPattern( pPatternSet,ELAYER_INCIDENTAL,NULL,nodeIncidentalLayer->getChild(j) );
}
}
CalcProbabilities(pPatternSet);
}
//////////////////////////////////////////////////////////////////////////
SMusicPatternSet* CMusicEditorDialog::NewPatternSet( SMusicMood *pMood )
{
SMusicPatternSet *pPatternSet = new SMusicPatternSet;
pMood->vecPatternSets.push_back( pPatternSet );
pPatternSet->fMinTimeout = 60;
pPatternSet->fMaxTimeout = 120;
pPatternSet->fTotalMainPatternProbability = 0;
//TPatternInfoVec vecMainPatterns;
pPatternSet->nMaxSimultaneousRhythmicPatterns = 1;
pPatternSet->fRhythmicLayerProbability = 100;
pPatternSet->fTotalRhythmicPatternProbability = 0;
//TPatternInfoVec vecRhythmicPatterns;
pPatternSet->nMaxSimultaneousIncidentalPatterns = 1;
pPatternSet->fIncidentalLayerProbability = 100;
pPatternSet->fTotalIncidentalPatternProbability = 0;
//TPatternInfoVec vecIncidentalPatterns;
//////////////////////////////////////////////////////////////////////////
// Add item to tree.
//////////////////////////////////////////////////////////////////////////
HTREEITEM hMood = stl::find_in_map( m_MoodToItemMap,pMood,(HTREEITEM)0 );
if (hMood)
{
ItemDesc *pMoodItemDesc = (ItemDesc*)m_treeCtrl.GetItemData(hMood);
if (pMoodItemDesc)
{
HTREEITEM hNewItem = InsertItem_PatternSet( pMoodItemDesc,pPatternSet,hMood );
m_treeCtrl.Select( hNewItem,TVGN_CARET );
}
}
return pPatternSet;
}
//////////////////////////////////////////////////////////////////////////
SPatternDef* CMusicEditorDialog::NewPattern( SMusicPatternSet *pPatternSet,ELayerType layer,const char *sBaseName,XmlNodeRef &node )
{
SPatternDef *pPattern = new SPatternDef;
if (!sBaseName)
sBaseName = "Pattern0";
if (node)
{
sBaseName = node->getAttr( "Name" );
// If paste from node.
CBaseLibraryItem::SerializeContext ctx( node,true );
ctx.bCopyPaste = true;
CMusicThemeLibItem::SerializePattern( ctx,pPattern );
}
else
{
pPattern->nLayeringVolume = 255; // Max volume.
}
CString uniqName = MakeUniqPatternName( sBaseName );
pPattern->sName = (const char*)uniqName;
m_PatternsMap[uniqName] = pPattern;
m_pMusicData->vecPatternDef.push_back(pPattern);
if (layer == ELAYER_MAIN)
pPatternSet->vecMainPatterns.push_back( pPattern );
else if (layer == ELAYER_RHYTHMIC)
pPatternSet->vecRhythmicPatterns.push_back( pPattern );
else if (layer == ELAYER_INCIDENTAL)
pPatternSet->vecIncidentalPatterns.push_back( pPattern );
CalcProbabilities( pPatternSet );
m_pMusicSystem->UpdatePattern( pPattern );
//////////////////////////////////////////////////////////////////////////
// Insert item to tree.
//////////////////////////////////////////////////////////////////////////
HTREEITEM hPatternSet = stl::find_in_map( m_PatternSetToItemMap,pPatternSet,(HTREEITEM)0 );
if (hPatternSet)
{
ItemDesc *pItemDesc = (ItemDesc*)m_treeCtrl.GetItemData(hPatternSet);
if (pItemDesc)
{
HTREEITEM hLayer = m_treeCtrl.GetNextItem(hPatternSet,TVGN_CHILD);
for (int i = 0; i < layer && hLayer; i++)
{
hLayer = m_treeCtrl.GetNextItem(hLayer,TVGN_NEXT);
}
if (hLayer)
{
ItemDesc *pLayerDesc = (ItemDesc*)m_treeCtrl.GetItemData(hLayer);
if (pLayerDesc)
{
HTREEITEM hNewItem = InsertItem_Pattern( pLayerDesc,pPattern,hLayer );
m_treeCtrl.Select( hNewItem,TVGN_CARET );
}
}
}
}
return pPattern;
}
//////////////////////////////////////////////////////////////////////////
CString CMusicEditorDialog::MakeUniqPatternName( const CString &baseName )
{
if (m_PatternsMap.find(baseName) == m_PatternsMap.end())
return baseName;
// Remove all numbers from the end of name.
CString typeName = baseName;
int len = typeName.GetLength();
while (len > 0 && isdigit(typeName[len-1]))
len--;
typeName = typeName.Left(len);
CString tpName = typeName;
int num = 0;
for (int i = 0; i < m_pMusicData->vecPatternDef.size(); i++)
{
SPatternDef *pPattern = m_pMusicData->vecPatternDef[i];
const char *name = pPattern->sName.c_str();
if (strncmp(name,tpName,len) == 0)
{
int n = atoi(name+len) + 1;
num = MAX( num,n );
}
}
CString str;
str.Format( "%s%d",(const char*)typeName,num );
return str;
}
//////////////////////////////////////////////////////////////////////////
CString CMusicEditorDialog::MakeUniqThemeName( const CString &baseName )
{
if (m_pMusicData->mapThemes.find((const char*)baseName) == m_pMusicData->mapThemes.end())
return baseName;
// Remove all numbers from the end of name.
CString typeName = baseName;
int len = typeName.GetLength();
while (len > 0 && isdigit(typeName[len-1]))
len--;
typeName = typeName.Left(len);
CString tpName = typeName;
int num = 0;
for (TThemeMap::iterator it = m_pMusicData->mapThemes.begin(); it != m_pMusicData->mapThemes.end(); ++it)
{
SMusicTheme *pTheme = it->second;
const char *name = pTheme->sName.c_str();
if (strncmp(name,tpName,len) == 0)
{
int n = atoi(name+len) + 1;
num = MAX( num,n );
}
}
CString str;
str.Format( "%s%d",(const char*)typeName,num );
return str;
}
//////////////////////////////////////////////////////////////////////////
CString CMusicEditorDialog::MakeUniqMoodName( SMusicTheme *pTheme,const CString &baseName )
{
if (pTheme->mapMoods.find((const char*)baseName) == pTheme->mapMoods.end())
return baseName;
// Remove all numbers from the end of name.
CString typeName = baseName;
int len = typeName.GetLength();
while (len > 0 && isdigit(typeName[len-1]))
len--;
typeName = typeName.Left(len);
CString tpName = typeName;
int num = 0;
for (TMoodMap::iterator it = pTheme->mapMoods.begin(); it != pTheme->mapMoods.end(); ++it)
{
SMusicMood *pMood = it->second;
const char *name = pMood->sName.c_str();
if (strncmp(name,tpName,len) == 0)
{
int n = atoi(name+len) + 1;
num = MAX( num,n );
}
}
CString str;
str.Format( "%s%d",(const char*)typeName,num );
return str;
}
//////////////////////////////////////////////////////////////////////////
void CMusicEditorDialog::OnAddItem()
{
ItemDesc *pItemDesc = GetCurrentItem();
if (!pItemDesc)
{
// Add Theme.
NewTheme();
return;
}
HTREEITEM hItem = m_treeCtrl.GetSelectedItem();
if (!hItem)
return;
switch (pItemDesc->type)
{
case EITEM_THEME:
NewTheme();
break;
case EITEM_MOOD:
NewMood( pItemDesc->m_pTheme );
break;
case EITEM_PATTERN_SET:
NewPatternSet( pItemDesc->m_pMood );
break;
case EITEM_LAYER:
NewPattern( pItemDesc->m_pPatternSet,pItemDesc->layerType );
break;
case EITEM_PATTERN:
NewPattern( pItemDesc->m_pPatternSet,pItemDesc->layerType,pItemDesc->m_pPattern->sName.c_str() );
break;
}
}
//////////////////////////////////////////////////////////////////////////
void CMusicEditorDialog::OnAddSubItem()
{
ItemDesc *pItemDesc = GetCurrentItem();
if (!pItemDesc)
return;
HTREEITEM hItem = m_treeCtrl.GetSelectedItem();
if (!hItem)
return;
switch (pItemDesc->type)
{
case EITEM_THEME:
// Add mood
NewMood( pItemDesc->m_pTheme );
break;
case EITEM_MOOD:
// Add pattern set.
NewPatternSet( pItemDesc->m_pMood );
break;
case EITEM_PATTERN_SET:
break;
case EITEM_LAYER:
// Add Pattern
NewPattern( pItemDesc->m_pPatternSet,pItemDesc->layerType );
break;
}
SetModified();
}
//////////////////////////////////////////////////////////////////////////
void CMusicEditorDialog::DeletePattern( ItemDesc *pItemDesc )
{
SPatternDef *def = pItemDesc->m_pPattern;
m_PatternToItemMap.erase(def);
// Delete item.
SMusicPatternSet *pPatternSet = pItemDesc->m_pPatternSet;
switch (pItemDesc->layerType)
{
case ELAYER_MAIN:
stl::find_and_erase( pPatternSet->vecMainPatterns,def );
break;
case ELAYER_RHYTHMIC:
stl::find_and_erase( pPatternSet->vecRhythmicPatterns,def );
break;
case ELAYER_INCIDENTAL:
stl::find_and_erase( pPatternSet->vecIncidentalPatterns,def );
break;
}
CalcProbabilities( pPatternSet );
// Delete pattern from music.
m_pMusicSystem->DeletePattern( def->sName.c_str() );
// Delete from music.
stl::find_and_erase( m_pMusicData->vecPatternDef,def );
delete def;
SetModified();
}
//////////////////////////////////////////////////////////////////////////
void CMusicEditorDialog::DeletePatternSet( ItemDesc *pItemDesc )
{
SMusicPatternSet *pPatternSet = pItemDesc->m_pPatternSet;
stl::find_and_erase( pItemDesc->m_pMood->vecPatternSets,pPatternSet );
m_PatternSetToItemMap.erase( pPatternSet );
delete pPatternSet;
SetModified();
}
//////////////////////////////////////////////////////////////////////////
void CMusicEditorDialog::DeleteMood( ItemDesc *pItemDesc )
{
SMusicMood *pMood = pItemDesc->m_pMood;
pItemDesc->m_pTheme->mapMoods.erase( pMood->sName );
m_MoodToItemMap.erase( pMood );
delete pMood;
SetModified();
}
//////////////////////////////////////////////////////////////////////////
void CMusicEditorDialog::DeleteTheme( ItemDesc *pItemDesc )
{
DeleteItem( pItemDesc->pItem );
SMusicTheme *pTheme = pItemDesc->m_pTheme;
m_pMusicData->mapThemes.erase( pTheme->sName );
m_ThemeToItemMap.erase( pTheme );
delete pTheme;
m_pMusicSystem->UpdateTheme( NULL ); // Get newer themes, data.
SetModified();
}
//////////////////////////////////////////////////////////////////////////
void CMusicEditorDialog::OnTreeDeleteItem(NMHDR* pNMHDR, LRESULT* pResult)
{
*pResult = 0;
if (!m_bHandleDeleteItem)
return;
NMTREEVIEW *pNMTREEVIEW = (NMTREEVIEW*)pNMHDR;
HTREEITEM hItem = pNMTREEVIEW->itemOld.hItem;
ItemDesc *pItemDesc = (ItemDesc*)pNMTREEVIEW->itemOld.lParam;
if (!pItemDesc)
return;
//m_treeCtrl.SetItemData( hItem,0 );
switch (pItemDesc->type)
{
case EITEM_THEME:
DeleteTheme( pItemDesc );
break;
case EITEM_MOOD:
DeleteMood( pItemDesc );
break;
case EITEM_PATTERN_SET:
DeletePatternSet( pItemDesc );
break;
case EITEM_LAYER:
break;
case EITEM_PATTERN:
DeletePattern( pItemDesc );
break;
};
delete pItemDesc;
}
//////////////////////////////////////////////////////////////////////////
void CMusicEditorDialog::OnRemoveItem()
{
ItemDesc *pItemDesc = GetCurrentItem();
if (!pItemDesc)
return;
HTREEITEM hItem = m_treeCtrl.GetSelectedItem();
if (!hItem)
return;
m_bHandleDeleteItem = true;
m_treeCtrl.SetRedraw(FALSE);
switch (pItemDesc->type)
{
case EITEM_THEME:
if (AfxMessageBox( _T("Delete this Theme?"),MB_YESNO ) == IDYES)
m_treeCtrl.DeleteItem(hItem);
break;
case EITEM_MOOD:
if (AfxMessageBox( _T("Delete this Mood?"),MB_YESNO ) == IDYES)
m_treeCtrl.DeleteItem(hItem);
break;
case EITEM_PATTERN_SET:
{
// Check if next item is also pattern set.
/*
bool bLastSet = true;
ItemDesc *pParentItem = (ItemDesc*)m_treeCtrl.GetItemData( m_treeCtrl.GetParentItem(hItem) );
if (pParentItem)
{
if (pParentItem->m_pMood->vecPatternSets.size() > 1) // more then 1 pattern in mood.
bLastSet = false;
}
if (bLastSet)
*/
{
if (AfxMessageBox( _T("Delete this Pattern Set?"),MB_YESNO ) == IDYES)
m_treeCtrl.DeleteItem(hItem);
}
}
break;
case EITEM_LAYER:
// Delete all items in this layer.
{
if (AfxMessageBox( _T("Delete all paterns in this Layer?"),MB_YESNO ) == IDYES)
{
// Delete all of the children of hmyItem.
if (m_treeCtrl.ItemHasChildren(hItem))
{
HTREEITEM hNextItem;
HTREEITEM hChildItem = m_treeCtrl.GetChildItem(hItem);
while (hChildItem != NULL)
{
hNextItem = m_treeCtrl.GetNextItem(hChildItem, TVGN_NEXT);
m_treeCtrl.DeleteItem(hChildItem);
hChildItem = hNextItem;
}
}
}
}
break;
case EITEM_PATTERN:
{
if (AfxMessageBox( _T("Delete this Pattern?"),MB_YESNO ) == IDYES)
m_treeCtrl.DeleteItem(hItem);
}
break;
};
m_treeCtrl.SetFocus();
m_treeCtrl.SetRedraw(TRUE);
m_bHandleDeleteItem = false;
SetModified();
}
//////////////////////////////////////////////////////////////////////////
void CMusicEditorDialog::OnRenameItem()
{
HTREEITEM hItem = m_treeCtrl.GetSelectedItem();
if (!hItem)
return;
m_treeCtrl.SetFocus();
m_treeCtrl.EditLabel(hItem);
}
//////////////////////////////////////////////////////////////////////////
void CMusicEditorDialog::OnLoadFromLua()
{
if (AfxMessageBox( "Load Music Data from Lua?",MB_YESNO|MB_ICONQUESTION ) != IDYES)
return;
CWaitCursor wait;
m_pMusicManager->LoadFromLua( m_pLibrary );
ReloadItems();
SetModified();
}
//////////////////////////////////////////////////////////////////////////
void CMusicEditorDialog::OnLoadLibrary()
{
CBaseLibrary *pPrevLib = m_pLibrary;
CBaseLibraryDialog::OnLoadLibrary();
if (m_pLibrary != pPrevLib)
{
// Library changed.
GetIEditor()->GetSystem()->GetIMusicSystem()->SetData( m_pMusicData,true );
}
}
//////////////////////////////////////////////////////////////////////////
void CMusicEditorDialog::OnRealodMusicFiles()
{
FillFileTree();
}
//////////////////////////////////////////////////////////////////////////
void CMusicEditorDialog::LoadMusicFiles( std::vector<CString> &musicFiles )
{
CString fileSpec = "*.ogg;*.mp3";
CString currFileSpec;
static CFileUtil::FileArray files;
files.clear();
// Reserve many files.
files.resize(0);
files.reserve( 2000 );
// Split file spec with ';'
while (!fileSpec.IsEmpty())
{
int splitpos = fileSpec.Find(';');
if (splitpos < 0)
{
currFileSpec = fileSpec;
CFileUtil::ScanDirectory( m_musicFilesPath,currFileSpec,files,true );
break;
}
CString currFileSpec = fileSpec.Mid(0,splitpos);
CFileUtil::ScanDirectory( m_musicFilesPath,currFileSpec,files,true );
fileSpec = fileSpec.Mid(splitpos+1);
}
musicFiles.resize(0);
musicFiles.reserve( files.size() );
for (int i = 0; i < files.size(); i++)
{
musicFiles.push_back( files[i].filename );
}
std::sort( musicFiles.begin(),musicFiles.end() );
}
//////////////////////////////////////////////////////////////////////////
void CMusicEditorDialog::FillFileTree()
{
CWaitCursor wait;
std::vector<CString> files;
LoadMusicFiles( files );
m_filesTreeCtrl.SetRedraw( FALSE );
m_musicFilesMap.clear();
m_filesTreeCtrl.DeleteAllItems();
CString filename,ext,path;
std::map<CString,HTREEITEM> pathmap;
for (int i = 0; i < files.size(); i++)
{
Path::Split( files[i],path,filename,ext );
HTREEITEM hGroup = TVI_ROOT;
if (!path.IsEmpty())
{
hGroup = stl::find_in_map( pathmap,path,(HTREEITEM)0 );
if (!hGroup)
{
hGroup = TVI_ROOT;
int startPos = 0;
int prevPos = 0;
CString subpath;
while (startPos < path.GetLength())
{
prevPos = startPos;
int pos = path.Find( '\\',startPos );
if (pos >= 0)
{
startPos = pos+1;
}
else
startPos = path.GetLength();
subpath = path.Mid(0,pos);
HTREEITEM hItem = stl::find_in_map( pathmap,subpath,(HTREEITEM)0 );
if (!hItem)
{
CString subGroupName = path.Mid(prevPos,startPos-prevPos-1);
hGroup = m_filesTreeCtrl.InsertItem( subGroupName,0,0,hGroup );
pathmap[subpath] = hGroup;
}
else
hGroup = hItem;
}
}
}
int nImage = 1;
HTREEITEM hNewItem = m_filesTreeCtrl.InsertItem( filename, nImage, nImage, hGroup );
//m_tree.SetItemState(hNewItem, TVIS_BOLD, TVIS_BOLD);
CString filename = Path::AddBackslash(m_musicFilesPath) + files[i];
filename.Replace( '\\','/' );
m_musicFilesMap[hNewItem] = filename;
}
m_filesTreeCtrl.SetRedraw( TRUE );
}
//////////////////////////////////////////////////////////////////////////
void CMusicEditorDialog::SetActive( bool bActive )
{
CBaseLibraryDialog::SetActive( bActive );
if (bActive && m_musicFilesMap.empty())
{
FillFileTree();
}
}
//////////////////////////////////////////////////////////////////////////
void CMusicEditorDialog::PlaySound( const CString &filename )
{
if (m_pSound)
m_pSound->Stop();
m_pSound = 0;
if (m_bPlaying)
{
ISoundSystem *pSoundSystem = GetIEditor()->GetSystem()->GetISoundSystem();
if (pSoundSystem)
{
m_pSound = pSoundSystem->LoadSound( filename,FLAG_SOUND_2D|FLAG_SOUND_STEREO|FLAG_SOUND_16BITS|FLAG_SOUND_LOAD_SYNCHRONOUSLY );
if (m_pSound)
m_pSound->Play();
}
}
}
//////////////////////////////////////////////////////////////////////////
void CMusicEditorDialog::OnNotifyFileTreeClick(NMHDR* pNMHDR, LRESULT* pResult)
{
pResult = 0;
if (m_bIgnoreSelectionChange)
return;
// Find item under mouse.
CPoint point;
GetCursorPos( &point );
m_filesTreeCtrl.ScreenToClient( &point );
UINT uFlags;
HTREEITEM hItem = m_filesTreeCtrl.HitTest(point,&uFlags);
CString filename = stl::find_in_map( m_musicFilesMap,hItem,"" );
if (!filename.IsEmpty())
{
// Play sound.
PlaySound( filename );
}
else
{
if (m_pSound)
m_pSound->Stop();
m_pSound = 0;
}
}
//////////////////////////////////////////////////////////////////////////
void CMusicEditorDialog::OnSelectFileTree(NMHDR* pNMHDR, LRESULT* pResult)
{
pResult = 0;
if (m_bIgnoreSelectionChange)
return;
LPNMTREEVIEW pNMTreeView = reinterpret_cast<LPNMTREEVIEW>(pNMHDR);
if (m_pSound)
m_pSound->Stop();
m_pSound = 0;
if (m_filesTreeCtrl)
{
HTREEITEM hItem = pNMTreeView->itemNew.hItem;
CString filename = stl::find_in_map( m_musicFilesMap,hItem,"" );
if (!filename.IsEmpty())
{
// Play sound.
PlaySound( filename );
}
}
}
//////////////////////////////////////////////////////////////////////////
void CMusicEditorDialog::OnFileTreeKillFocus(NMHDR* pNMHDR, LRESULT* pResult)
{
*pResult = 0;
if (m_pSound)
m_pSound->Stop();
m_pSound = 0;
}
//////////////////////////////////////////////////////////////////////////
void CMusicEditorDialog::OnFilesBeginDrag(NMHDR* pNMHDR, LRESULT* pResult)
{
NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
HTREEITEM hItem = pNMTreeView->itemNew.hItem;
CString filename = stl::find_in_map( m_musicFilesMap,hItem,"" );
if (!filename.IsEmpty())
{
m_filesTreeCtrl.Select( hItem,TVGN_CARET );
m_hDropItem = 0;
m_dragImage = m_filesTreeCtrl.CreateDragImage( hItem );
if (m_dragImage)
{
m_hDraggedItem = hItem;
m_dragImage->BeginDrag(0, CPoint(-10, -10));
CRect rc;
AfxGetMainWnd()->GetWindowRect( rc );
CPoint p = pNMTreeView->ptDrag;
ClientToScreen( &p );
p.x -= rc.left;
p.y -= rc.top;
m_dragImage->DragEnter( AfxGetMainWnd(),p );
SetCapture();
GetIEditor()->EnableUpdate( false );
}
}
*pResult = 0;
}