//////////////////////////////////////////////////////////////////////////// // // 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 #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(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 &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 files; LoadMusicFiles( files ); m_filesTreeCtrl.SetRedraw( FALSE ); m_musicFilesMap.clear(); m_filesTreeCtrl.DeleteAllItems(); CString filename,ext,path; std::map 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(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; }