/* Copyright (c) 2002-2012 Croteam Ltd. This program is free software; you can redistribute it and/or modify it under the terms of version 2 of the GNU General Public License as published by the Free Software Foundation This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ // BrowseWindow.cpp : implementation file // #include "stdafx.h" #include "BrowseWindow.h" #include #include #include #ifdef _DEBUG #undef new #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif INDEX _iLastHittedItem = -1; static CTFileName _fnRightClickedItemFileName; static BOOL _bRightClickedIsSelected; ///////////////////////////////////////////////////////////////////////////// // CBrowseWindow CBrowseWindow::CBrowseWindow() { m_pDrawPort = NULL; m_pViewPort = NULL; m_iLastHittedItem = 0; m_bDirectoryOpen = FALSE; } CBrowseWindow::~CBrowseWindow() { if( m_pViewPort != NULL) { _pGfx->DestroyWindowCanvas( m_pViewPort); m_pViewPort = NULL; } } BEGIN_MESSAGE_MAP(CBrowseWindow, CWnd) //{{AFX_MSG_MAP(CBrowseWindow) ON_WM_VSCROLL() ON_WM_PAINT() ON_WM_DROPFILES() ON_WM_SIZE() ON_COMMAND(ID_INSERT_ITEMS, OnInsertItems) ON_WM_LBUTTONDOWN() ON_COMMAND(ID_DELETE_ITEMS, OnDeleteItems) ON_COMMAND(ID_BIG_ICONS, OnBigIcons) ON_COMMAND(ID_MEDIUM_ICONS, OnMediumIcons) ON_COMMAND(ID_SMALL_ICONS, OnSmallIcons) ON_COMMAND(ID_SHOW_DESCRIPTION, OnShowDescription) ON_COMMAND(ID_SHOW_FILENAME, OnShowFilename) ON_WM_LBUTTONDBLCLK() ON_COMMAND(ID_RECREATE_TEXTURE, OnRecreateTexture) ON_COMMAND(ID_CREATE_AND_ADD_TEXTURE, OnCreateAndAddTexture) ON_COMMAND(ID_SELECT_BY_TEXTURE_IN_SELECTED_SECTORS, OnSelectByTextureInSelectedSectors) ON_COMMAND(ID_SELECT_BY_TEXTURE_IN_WORLD, OnSelectByTextureInWorld) ON_COMMAND(ID_SELECT_FOR_DROP_MARKER, OnSelectForDropMarker) ON_COMMAND(ID_SET_AS_CURRENT_TEXTURE, OnSetAsCurrentTexture) ON_COMMAND(ID_CONVERT_CLASS, OnConvertClass) ON_WM_MOUSEMOVE() ON_COMMAND(ID_MICRO_ICONS, OnMicroIcons) ON_COMMAND(ID_SELECT_EXCEPT_TEXTURES, OnSelectExceptTextures) ON_COMMAND(ID_ADD_TEXTURES_FROM_WORLD, OnAddTexturesFromWorld) ON_COMMAND(ID_SHOW_TREE_SHORTCUTS, OnShowTreeShortcuts) ON_COMMAND(ID_EXPORT_TEXTURE, OnExportTexture) ON_COMMAND(ID_BROWSER_CONTEXT_HELP, OnBrowserContextHelp) //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CBrowseWindow message handlers BOOL CBrowseWindow::AttachToControl( CWnd *pwndParent) { BOOL bResult = TRUE; bResult = Create( NULL, NULL, WS_BORDER|WS_VISIBLE|WS_VSCROLL, CRect(0,0,10,10), pwndParent, IDW_BROWSER); if( bResult) { DragAcceptFiles(); } SetFocus(); EnableToolTips( TRUE); return bResult; } void CBrowseWindow::SetBrowserPtr( CBrowser *pBrowser) { m_pBrowser = pBrowser; } void CBrowseWindow::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) { int iPosition = GetScrollPos(SB_VERT); int intMin, intMax; GetScrollRange( SB_VERT, &intMin, &intMax); INDEX iMin = intMin; INDEX iMax = intMax; switch( nSBCode ) { case SB_THUMBTRACK: case SB_THUMBPOSITION: { SetScrollPos(SB_VERT, nPos); break; } case SB_LINEDOWN: { iPosition = Clamp( iPosition+m_IconHeight, iMin, iMax); SetScrollPos(SB_VERT, iPosition); break; } case SB_PAGEDOWN: { iPosition = Clamp( iPosition+m_IconsInColumn*m_IconHeight, iMin, iMax); SetScrollPos(SB_VERT, iPosition); break; } case SB_LINEUP: { iPosition = Clamp( iPosition-m_IconHeight, iMin, iMax); SetScrollPos(SB_VERT, iPosition); break; } case SB_PAGEUP: { iPosition = Clamp( iPosition-m_IconsInColumn*m_IconHeight, iMin, iMax); SetScrollPos(SB_VERT, iPosition); break; } } CWnd::OnVScroll(nSBCode, nPos, pScrollBar); Invalidate(FALSE); } #define BOX( dp, xs, ys, w, h, color, type) \ dp->DrawLine( xs, ys, xs, ys+h, color, type); \ dp->DrawLine( xs, ys+h, xs+w, ys+h, color, type); \ dp->DrawLine( xs+w, ys+h, xs+w, ys, color, type); \ dp->DrawLine( xs+w, ys, xs, ys, color, type); #define ICONS_TRAY_WIDTH 16 #define ICONS_TRAY_HEIGHT 16 void CBrowseWindow::OnPaint() { { CPaintDC dc(this); // device context for painting (does BeginPaint()/EndPaint()!) } CWorldEditorApp *pApp = (CWorldEditorApp *)AfxGetApp(); PIXaabbox2D rectPict; INDEX i; if (m_pDrawPort==NULL || !m_pDrawPort->Lock()) { return; } // To write description m_pDrawPort->SetFont( theApp.m_pfntSystem); m_pDrawPort->SetTextAspect( 1.0f); // clear browsing window m_pDrawPort->FillZBuffer( ZBUF_BACK); m_pDrawPort->Fill( C_BLACK | CT_OPAQUE); CVirtualTreeNode *pVTNDir = m_pBrowser->GetSelectedDirectory(); if (pVTNDir==NULL) { m_pDrawPort->Unlock(); return; } if(m_bDirectoryOpen) { INDEX iYOffset = GetScrollPos( SB_VERT); INDEX iLineVisible = iYOffset/m_IconHeight; PIX pixStart = iYOffset%m_IconHeight; for( i=0; ivtn_bmBrowsingMode) { case BM_ICONS_MICRO: case BM_ICONS_SMALL: case BM_ICONS_MEDIUM: case BM_ICONS_LARGE: { PIX pixIconWidth = m_IconWidth; PIX pixIconHeight = m_IconHeight; // if we are browsing large icons, leave some space for icon text if( pVTNDir->vtn_bmBrowsingMode == BM_ICONS_LARGE) { pixIconHeight -= STRING_HEIGHT; } // set error texture CTextureData *ptdIcon = pApp->m_ptdError; if( pVTN->vtn_pTextureData != NULL) { ptdIcon = pVTN->vtn_pTextureData; } // get texture width and height PIX pixTextureWidth = ptdIcon->GetWidth(); PIX pixTextureHeight= ptdIcon->GetHeight(); // apply texture aspect ratio to icon if( pixTextureWidth>pixTextureHeight) { pixIconHeight /= pixTextureWidth/pixTextureHeight; } else { pixIconWidth /= pixTextureHeight/pixTextureWidth; } // if we have large icons if( pVTNDir->vtn_bmBrowsingMode == BM_ICONS_LARGE) { // rectangle for texture polygon is smaller because of subtitling info text rectPict = PIXaabbox2D( PIX2D(x+m_IconWidth/2-pixIconWidth/2+1, y+m_IconHeight/2-pixIconHeight/2+1), PIX2D(x+m_IconWidth/2+pixIconWidth/2-2, y+m_IconHeight/2+pixIconHeight/2-2-STRING_HEIGHT)); } else { // texture box covers maximum space rectPict = PIXaabbox2D( PIX2D(x+m_IconWidth/2-pixIconWidth/2+1, y+m_IconHeight/2-pixIconHeight/2+1), PIX2D(x+m_IconWidth/2+pixIconWidth/2-2, y+m_IconHeight/2+pixIconHeight/2-2)); } // draw icon CTextureObject toIcon; toIcon.SetData( ptdIcon); m_pDrawPort->PutTexture( &toIcon, rectPict); // if we have large icons if( pVTNDir->vtn_bmBrowsingMode == BM_ICONS_LARGE) { // type info text if( pVTN->vtn_fnItem.FileExt() == ".tex") { m_pDrawPort->PutText( pVTN->vtn_fnItem.FileName(), x, y + m_IconHeight-2-STRING_HEIGHT); } else { m_pDrawPort->PutText( pVTN->vtn_strName, x, y + m_IconHeight-2-STRING_HEIGHT); } } if( pVTN->vtn_bSelected) { BOX( m_pDrawPort, x, y, m_IconWidth-1, m_IconHeight-1, C_WHITE|CT_OPAQUE, _FULL_); BOX( m_pDrawPort, x, y, m_IconWidth-1, m_IconHeight-1, C_lRED|CT_OPAQUE, _POINT_); } break; } case BM_DESCRIPTION: case BM_FILENAME: { // First paint little icon rectPict = PIXaabbox2D( PIX2D(x, y), PIX2D(x+STRING_HEIGHT, y+STRING_HEIGHT)); if( pVTN->vtn_pTextureData != NULL) { CTextureObject toIcon; toIcon.SetData( pVTN->vtn_pTextureData); m_pDrawPort->PutTexture( &toIcon, rectPict); } else { m_pDrawPort->PutTexture( pApp->m_ptoError, rectPict); } // if we are using descriptive name if( pVTNDir->vtn_bmBrowsingMode == BM_DESCRIPTION) { if( pVTN->vtn_fnItem.FileExt() == ".tex") { m_pDrawPort->PutText( pVTN->vtn_fnItem.FileName(), x + STRING_HEIGHT, y); } else { m_pDrawPort->PutText( pVTN->vtn_strName, x + STRING_HEIGHT, y); } } // if we are using file name else { m_pDrawPort->PutText( pVTN->vtn_fnItem, x + STRING_HEIGHT, y); } if( pVTN->vtn_bSelected) { BOX( m_pDrawPort, x, y, m_IconWidth-1, m_IconHeight-1, C_WHITE|CT_OPAQUE, _FULL_); BOX( m_pDrawPort, x, y, m_IconWidth-1, m_IconHeight-1, C_lRED|CT_OPAQUE, _POINT_); } break; } default: { ASSERTALWAYS( "Unrecognizible browsing type found !"); } } } } // draw icons tray CTextureObject to; to.SetData(theApp.m_ptdIconsTray); INDEX iSelected=0; switch( pVTNDir->vtn_bmBrowsingMode) { case BM_ICONS_MICRO: iSelected = 0; break; case BM_ICONS_SMALL: iSelected = 1; break; case BM_ICONS_MEDIUM: iSelected = 2; break; case BM_ICONS_LARGE: iSelected = 3; break; case BM_DESCRIPTION: iSelected = 4; break; case BM_FILENAME: iSelected = 5; break; } FLOAT fRatio = theApp.m_ptdIconsTray->GetWidth()/theApp.m_ptdIconsTray->GetPixWidth(); MEX2D mex2dStart = MEX2D(0, MEX(iSelected*16*fRatio)); MEX2D mex2dEnd = MEX2D(MEX(16*8*fRatio), MEX((iSelected*16+16)*fRatio)); MEXaabbox2D boxTexture = MEXaabbox2D( mex2dStart, mex2dEnd); PIXaabbox2D boxScreen = PIXaabbox2D( PIX2D(0, 0), PIX2D(8*16, 16)); m_pDrawPort->Fill( 0, 0, m_pDrawPort->GetWidth(), 17, C_BLACK|CT_OPAQUE); m_pDrawPort->PutTexture( &to, boxScreen, boxTexture); m_pDrawPort->Unlock(); m_pViewPort->SwapBuffers(); } void CBrowseWindow::OnContextMenu( CPoint point) { CVirtualTreeNode *pVTNDir = m_pBrowser->GetSelectedDirectory(); if( pVTNDir == NULL) { AfxMessageBox( L"Virtual tree doesn't yet exists. Create at least one virtual directory " L"to be able to insert items into it."); return; } CWorldEditorDoc *pDoc = theApp.GetDocument(); // convert coordinates from screen to client CPoint ptClientCoordinates = point; ScreenToClient( &ptClientCoordinates); // Add hit icon to selection FLOAT fDummyX, fDummyY; INDEX iHittedItem = HitItem( ptClientCoordinates, fDummyX, fDummyY); _fnRightClickedItemFileName = CTString(""); if( iHittedItem != -1) { CVirtualTreeNode *pVTN = GetItem( iHittedItem); ASSERT( pVTN != NULL); _fnRightClickedItemFileName = pVTN->vtn_fnItem; _bRightClickedIsSelected = pVTN->vtn_bSelected; } CMenu menu; if( menu.LoadMenu(IDR_BROWSERPOPUP)) { CMenu* pPopup = menu.GetSubMenu(0); UINT iRecreateTextureCommandState = MF_DISABLED|MF_GRAYED; if( _fnRightClickedItemFileName.FileExt()==CTString(".tex") || _fnRightClickedItemFileName.FileExt()==CTString(".tbn") ) { iRecreateTextureCommandState = MF_ENABLED; } // enable recreate texture and set as current texture commands if texture right-clicked pPopup->EnableMenuItem(ID_RECREATE_TEXTURE, iRecreateTextureCommandState); pPopup->EnableMenuItem(ID_SET_AS_CURRENT_TEXTURE, iRecreateTextureCommandState); pPopup->EnableMenuItem(ID_EXPORT_TEXTURE, iRecreateTextureCommandState); UINT iSelectForDropMarkerCommandState = MF_DISABLED|MF_GRAYED; if( _fnRightClickedItemFileName.FileExt()==CTString(".ecl")) { iSelectForDropMarkerCommandState = MF_ENABLED; } // enable recreate texture command if texture right-clicked pPopup->EnableMenuItem(ID_SELECT_FOR_DROP_MARKER, iSelectForDropMarkerCommandState); if( pDoc == NULL) { pPopup->EnableMenuItem(ID_ADD_TEXTURES_FROM_WORLD, MF_DISABLED|MF_GRAYED); pPopup->EnableMenuItem(ID_SELECT_EXCEPT_TEXTURES, MF_DISABLED|MF_GRAYED); } // enable select by texture commands only if texture is right-clicked and document exists UINT iSelectByTextureCommandState = MF_DISABLED|MF_GRAYED; if( (_fnRightClickedItemFileName.FileExt()==CTString(".tex")) && (pDoc!=NULL)) { iSelectByTextureCommandState = MF_ENABLED; } UINT iConvertClassCommandState = MF_DISABLED|MF_GRAYED; if( (_fnRightClickedItemFileName.FileExt()==CTString(".ecl")) && (pDoc!=NULL) && (pDoc->m_selEntitySelection.Count() != 0) && (pDoc->m_iMode == ENTITY_MODE) ) { iConvertClassCommandState = MF_ENABLED; } pPopup->EnableMenuItem(ID_SELECT_BY_TEXTURE_IN_SELECTED_SECTORS, iSelectByTextureCommandState); pPopup->EnableMenuItem(ID_SELECT_BY_TEXTURE_IN_WORLD, iSelectByTextureCommandState); pPopup->EnableMenuItem(ID_CONVERT_CLASS, iConvertClassCommandState); UINT iClassHelp = MF_DISABLED|MF_GRAYED; if( _fnRightClickedItemFileName.FileExt()==CTString(".ecl")) { iClassHelp = MF_ENABLED; } pPopup->EnableMenuItem(ID_BROWSER_CONTEXT_HELP, iClassHelp); pPopup->TrackPopupMenu(TPM_LEFTBUTTON | TPM_RIGHTBUTTON | TPM_LEFTALIGN, point.x, point.y, this); } } INDEX CBrowseWindow::HitItem( CPoint point, FLOAT &fHitXOffset, FLOAT &fHitYOffset) const { PIXaabbox2D rectItem; PIXaabbox2D boxPoint; INDEX i; INDEX iYOffset = GetScrollPos( SB_VERT); INDEX iLineVisible = iYOffset/m_IconHeight; PIX pixStart = iYOffset%m_IconHeight; for( i=0; ipFiles = sizeof(DROPFILES); // filename does not contain wide characters pDropFiles->fWide = FALSE; // we want drop point's coordinates in client area pDropFiles->fNC = FALSE; strcpy(pchDropFileName, (const char *)fnFullToDrag); // final null terminator as per CF_HDROP Format specs. pchDropFileName[strlen(pchDropFileName)+1]=0; GlobalUnlock(hGlobal); return hGlobal; } void CBrowseWindow::OnLButtonDown(UINT nFlags, CPoint point) { CVirtualTreeNode *pVTNDir = m_pBrowser->GetSelectedDirectory(); if( pVTNDir == NULL) return; // if we hitted icons tray if( (point.x < ICONS_TRAY_WIDTH*6) && (point.y < (ICONS_TRAY_HEIGHT + 1)) ) { INDEX iSelected = point.x/ICONS_TRAY_WIDTH; switch( iSelected) { case 0: pVTNDir->vtn_bmBrowsingMode = BM_ICONS_MICRO; break; case 1: pVTNDir->vtn_bmBrowsingMode = BM_ICONS_SMALL; break; case 2: pVTNDir->vtn_bmBrowsingMode = BM_ICONS_MEDIUM; break; case 3: pVTNDir->vtn_bmBrowsingMode = BM_ICONS_LARGE; break; case 4: pVTNDir->vtn_bmBrowsingMode = BM_DESCRIPTION; break; case 5: pVTNDir->vtn_bmBrowsingMode = BM_FILENAME; break; } Refresh(); return; } // toggle hitted icon selection status FLOAT fDummyX, fDummyY; INDEX iHittedItem = HitItem( point, fDummyX, fDummyY); if( iHittedItem == -1) return; BOOL bShift = (nFlags & MK_SHIFT); BOOL bCtrl = (nFlags & MK_CONTROL); if( !bCtrl) { FOREACHINLIST( CVirtualTreeNode, vtn_lnInDirectory, pVTNDir->vtn_lhChildren, it) { it->vtn_bSelected = FALSE; } } INDEX ctItems = 0; {FOREACHINLIST( CVirtualTreeNode, vtn_lnInDirectory, pVTNDir->vtn_lhChildren, it) { if( !it->vtn_bIsDirectory) ctItems++; }} INDEX iMin = iHittedItem; INDEX iMax = iHittedItem; if( bShift) { iMin = ClampDn( Min( m_iLastHittedItem, iHittedItem), (INDEX)0); iMax = ClampUp( Max( m_iLastHittedItem, iHittedItem), ctItems); } INDEX iCurrent = 0; FOREACHINLIST( CVirtualTreeNode, vtn_lnInDirectory, pVTNDir->vtn_lhChildren, it) { CVirtualTreeNode &vtn = *it; if( !vtn.vtn_bIsDirectory) { if( (iCurrent >= iMin) && (iCurrent <= iMax) ) { if( bCtrl&&!bShift) { vtn.vtn_bSelected = !vtn.vtn_bSelected; } else { vtn.vtn_bSelected = TRUE; } } iCurrent++; } } if( !bShift) m_iLastHittedItem = iHittedItem; CVirtualTreeNode *pVTNHit = GetItem( iHittedItem); HGLOBAL hglobal = CreateHDrop( pVTNHit->vtn_fnItem); m_DataSource.CacheGlobalData( CF_HDROP, hglobal); m_DataSource.DoDragDrop( DROPEFFECT_COPY); Invalidate( FALSE); } void CBrowseWindow::OnDropFiles(HDROP hDropInfo) { CMainFrame* pMainFrame = STATIC_DOWNCAST(CMainFrame, AfxGetMainWnd()); INDEX iNoOfFiles = DragQueryFile( hDropInfo, 0xFFFFFFFF, NULL, 0); char chrFile[ 256]; // get dropped coordinates CPoint point; DragQueryPoint( hDropInfo, &point); CVirtualTreeNode *pVTN = m_pBrowser->GetSelectedDirectory(); if( pVTN != NULL) { CloseDirectory( pVTN); for( INDEX i=0; iGetSelectedDirectory(); if( pVTNDir == NULL) { return NULL; } INDEX ct=0; FOREACHINLIST( CVirtualTreeNode, vtn_lnInDirectory, pVTNDir->vtn_lhChildren, it) { // if( !it->vtn_bIsDirectory) { if( ct == iItem) { return( &it.Current()); } ct++; } } return NULL; } INDEX CBrowseWindow::GetItemNo( CVirtualTreeNode *pVTN) { CVirtualTreeNode *pVTNDir = m_pBrowser->GetSelectedDirectory(); if( pVTNDir == NULL) { return -1; } if( pVTNDir->vtn_lhChildren.IsEmpty()) { return -1; } INDEX ct=0; FOREACHINLIST( CVirtualTreeNode, vtn_lnInDirectory, pVTNDir->vtn_lhChildren, it) { if( !it->vtn_bIsDirectory) { if( &it.Current() == pVTN) { return( ct); } ct++; } } return -1; } void CBrowseWindow::InsertItem( CTFileName fnItem, CPoint pt) { CVirtualTreeNode *pVTNDir = m_pBrowser->GetSelectedDirectory(); if( pVTNDir == NULL) { return; } FLOAT fHitXRatio; FLOAT fHitYRatio; INDEX iHittedItem = HitItem( pt, fHitXRatio, fHitYRatio); CVirtualTreeNode *pVTNHit = NULL; if( iHittedItem != -1) { pVTNHit = GetItem( iHittedItem); } CVirtualTreeNode *pvtnToRemove = NULL; // check for all items in current virtual tree directory FOREACHINLIST( CVirtualTreeNode, vtn_lnInDirectory, pVTNDir->vtn_lhChildren, it) { // if it isn't directory means that it is item if( !it->vtn_bIsDirectory) { // don't allow inserting same item twice if( it->vtn_fnItem == fnItem) { if( pt.x == -1) return; pvtnToRemove = &it.Current(); } } } if( (pVTNHit == pvtnToRemove) && (pVTNHit != NULL) ) return; if( pvtnToRemove != NULL) { pvtnToRemove->vtn_lnInDirectory.Remove(); if( pvtnToRemove->vtn_pTextureData != NULL) { _pTextureStock->Release( pvtnToRemove->vtn_pTextureData); } delete pvtnToRemove; } // if item is texture if( fnItem.FileExt() == ".tex") { CTextureData *ptdTexture; // try to try { // obtain texture ptdTexture = _pTextureStock->Obtain_t( fnItem); } // catch and catch( char *err_str) { // report errors AfxMessageBox( CString(err_str)); return; } // now it must be valid ASSERT( ptdTexture != NULL); // get texture dimensions MEX mexWidth = ptdTexture->GetWidth(); MEX mexHeight = ptdTexture->GetHeight(); // release texture, we don't need it any more _pTextureStock->Release( ptdTexture); // mark both dimensions as incorrect BOOL bWidthOk = FALSE; BOOL bHeightOk = FALSE; // see if both width and height are potentions of 2 for( INDEX i=0; i<32; i++) { // check width, mark if correct if( (1L << i) == mexWidth) bWidthOk = TRUE; if( (1L << i) == mexHeight) bHeightOk = TRUE; } // if width or height are not potentios of 2 if( !bWidthOk || !bHeightOk) { char err_str[ 256]; sprintf( err_str, "Dropped texture \"%s\" has incorrect dimensions %.2f x %.2f." "All textures must have dimensions that are potentions of 2.", (CTString&)fnItem, METERS_MEX( mexWidth), METERS_MEX( mexHeight)); AfxMessageBox( CString(err_str)); return; } } else if( fnItem.FileExt() == ".ecl") { // obtain class CEntityClass *pec = _pEntityClassStock->Obtain_t( fnItem); // get thumbnail file name from the class CTFileName fnThumbnail = CTString(pec->ec_pdecDLLClass->dec_strIconFileName); // release class _pEntityClassStock->Release( pec); // if thumbnail's name is "", don't add this item if( fnThumbnail == CTString("") ) { return; } } CMainFrame* pMainFrame = STATIC_DOWNCAST(CMainFrame, AfxGetMainWnd()); CVirtualTreeNode *pVTN = new CVirtualTreeNode; pVTN->vtn_fnItem = fnItem; pVTN->vtn_bIsDirectory = FALSE; pVTN->vtn_strName = fnItem.FileName(); if( pVTNDir->vtn_lhChildren.Count() == 0) { pVTN->vtn_bSelected = TRUE; } if( pt.x == -1) { pVTNDir->vtn_lhChildren.AddTail( pVTN->vtn_lnInDirectory); } else { if( iHittedItem == -1) { pVTNDir->vtn_lhChildren.AddTail( pVTN->vtn_lnInDirectory); } else if( ((m_IconsInLine != 1) && (fHitXRatio < 0.5f)) || ((m_IconsInLine == 1) && (fHitYRatio < 0.5f)) ) { ASSERT( pVTNHit != NULL); pVTNHit->vtn_lnInDirectory.AddBefore( pVTN->vtn_lnInDirectory); } else { ASSERT( pVTNHit != NULL); pVTNHit->vtn_lnInDirectory.AddAfter( pVTN->vtn_lnInDirectory); } } m_pBrowser->m_bVirtualTreeChanged = TRUE; Invalidate(FALSE); } void CBrowseWindow::DeleteSelectedItems() { CVirtualTreeNode *pVTNDir = m_pBrowser->GetSelectedDirectory(); if( pVTNDir == NULL) { return; } FORDELETELIST( CVirtualTreeNode, vtn_lnInDirectory, pVTNDir->vtn_lhChildren, it) { if( !it->vtn_bIsDirectory) { if( it->vtn_bSelected) { it->vtn_lnInDirectory.Remove(); if( it->vtn_pTextureData != NULL) { _pTextureStock->Release( it->vtn_pTextureData); } delete &it.Current(); } } } m_pBrowser->m_bVirtualTreeChanged = TRUE; Invalidate(FALSE); } void CBrowseWindow::Refresh(void) { CVirtualTreeNode *pVTNDir = m_pBrowser->GetSelectedDirectory(); if( (pVTNDir == NULL) || (!m_bDirectoryOpen) ) { return; } switch( pVTNDir->vtn_bmBrowsingMode) { case BM_ICONS_MICRO: { m_IconWidth = 16; m_IconHeight = 16; break; } case BM_ICONS_SMALL: { m_IconWidth = 32; m_IconHeight = 32; break; } case BM_ICONS_MEDIUM: { m_IconWidth = 64; m_IconHeight = 64; break; } case BM_ICONS_LARGE: { m_IconWidth = 128; // allow some space for text m_IconHeight = 128 + STRING_HEIGHT; break; } case BM_DESCRIPTION: case BM_FILENAME: { m_IconWidth = m_BrowseWndWidth - 8; m_IconHeight = STRING_HEIGHT; break; } default: { ASSERTALWAYS( "Unrecognizible browsing type found !"); } } m_IconsInLine = m_BrowseWndWidth/m_IconWidth; if( m_IconsInLine == 0) { m_IconsInLine = 1; } m_IconsInColumn = m_BrowseWndHeight/m_IconHeight + 1; m_IconsVisible = m_IconsInLine * m_IconsInColumn; INDEX iItemsCt = -1; if( !pVTNDir->vtn_lhChildren.IsEmpty()) { iItemsCt = GetItemNo( LIST_TAIL( pVTNDir->vtn_lhChildren, CVirtualTreeNode, vtn_lnInDirectory) ); } INDEX ctLines = iItemsCt/m_IconsInLine; SetScrollRange( SB_VERT, 0, ctLines*m_IconHeight); Invalidate(FALSE); } void CBrowseWindow::OpenDirectory( CVirtualTreeNode *pVTNDir) { CWorldEditorApp *pApp = (CWorldEditorApp *)AfxGetApp(); CMainFrame* pMainFrame = STATIC_DOWNCAST(CMainFrame, AfxGetMainWnd()); if(m_bDirectoryOpen || pVTNDir==NULL) { return; } ASSERT( pVTNDir != NULL); // remember name of last opened virtual tree theApp.m_strOpenedVTDirectory = theApp.GetNameForVirtualTreeNode( pVTNDir); wchar_t achrOpenedDirectoryMessage[ 256]; swprintf( achrOpenedDirectoryMessage, L"Opened directory: \"%s\"", CString(theApp.m_strOpenedVTDirectory)); // put selected directory name into status line pMainFrame->m_wndStatusBar.SetPaneText( STATUS_LINE_PANE, achrOpenedDirectoryMessage, TRUE); FOREACHINLIST( CVirtualTreeNode, vtn_lnInDirectory, pVTNDir->vtn_lhChildren, it) { try { // if not directory if( !it->vtn_bIsDirectory) { CTFileName fnThumbnail; // thumbnail's file name // if texture if( it->vtn_fnItem.FileExt() == ".tex") { // use same texture for thumbnail fnThumbnail = it->vtn_fnItem; } // if world else if ( it->vtn_fnItem.FileExt() == ".wld") { // use file name with extension .tbn for thumbnail fnThumbnail = it->vtn_fnItem.FileDir() + it->vtn_fnItem.FileName() + ".tbn"; // use base name for description it->vtn_strName = it->vtn_fnItem.FileName(); } // if class else if ( it->vtn_fnItem.FileExt() == ".ecl") { // obtain class CEntityClass *pec = _pEntityClassStock->Obtain_t( it->vtn_fnItem); // get thumbnail file name from the class fnThumbnail = CTString(pec->ec_pdecDLLClass->dec_strIconFileName); // get description name from the class it->vtn_strName = pec->ec_pdecDLLClass->dec_strName; // release class _pEntityClassStock->Release( pec); } // if unknown extension else { // use no thumbnail fnThumbnail = CTString(""); } // if no thumbnail if( fnThumbnail == "") { it->vtn_pTextureData = NULL; } // if there is valid thumbnail file name else { // obtain thumbnail it->vtn_pTextureData = _pTextureStock->Obtain_t( fnThumbnail); // must be valid ASSERT( it->vtn_pTextureData != NULL); // if it is really texture, type full info if( it->vtn_fnItem.FileExt() == ".tex") { // use base name and dimension for desription it->vtn_strName = (CTString&)it->vtn_fnItem+" "+it->vtn_pTextureData->GetDescription(); } // else description is just item's file name else { it->vtn_strName = it->vtn_fnItem.FileName(); } } } } catch( char *error) { // ingnore errors (void) error; it->vtn_pTextureData = NULL; } } SetScrollPos(SB_VERT, 0); m_bDirectoryOpen = TRUE; Refresh(); Invalidate(FALSE); } void CBrowseWindow::CloseDirectory( CVirtualTreeNode *pVTN) { if( !m_bDirectoryOpen) { return; } ASSERT( pVTN != NULL); FOREACHINLIST( CVirtualTreeNode, vtn_lnInDirectory, pVTN->vtn_lhChildren, it) { if( !it->vtn_bIsDirectory) { if( it->vtn_pTextureData != NULL) { _pTextureStock->Release( it->vtn_pTextureData); it->vtn_pTextureData = NULL; } } } m_bDirectoryOpen = FALSE; } void CBrowseWindow::OnSize(UINT nType, int cx, int cy) { CWnd::OnSize(nType, cx, cy); // if window canvas is valid if( m_pViewPort!=NULL) { // resize it m_pViewPort->Resize(); Refresh(); } } void CBrowseWindow::OnInsertItems() { CVirtualTreeNode *pVTNDir = m_pBrowser->GetSelectedDirectory(); if( pVTNDir == NULL) { AfxMessageBox( L"ERROR: Virtual tree doesn't exist."); return; } char *pFilters = "Items (*.tex, *.wld, *.ecl)\0*.tex;*.wld;*.ecl\0" "World Files (*.wld)\0*.wld\0" "Texture files (*.tex)\0*.tex\0" "Class files (*.ecl)\0*.ecl\0" "All files (*.*)\0*.*\0\0"; // call file requester for opening textures CDynamicArray afnItems; _EngineGUI.FileRequester( "Insert items", pFilters, KEY_NAME_CREATE_TEXTURE_DIR, "Textures\\", "", &afnItems); if( afnItems.Count() == 0) return; // insert items FOREACHINDYNAMICARRAY( afnItems, CTFileName, itItem) { try { InsertItem( *itItem, CPoint(-1, -1)); } catch( char *err_str) { AfxMessageBox( CString(err_str)); } } CloseDirectory( pVTNDir); OpenDirectory( pVTNDir); } void CBrowseWindow::OnDeleteItems() { DeleteSelectedItems(); } void CBrowseWindow::OnBigIcons() { CVirtualTreeNode *pVTNDir = m_pBrowser->GetSelectedDirectory(); ASSERT( pVTNDir != NULL); pVTNDir->vtn_bmBrowsingMode = BM_ICONS_LARGE; Refresh(); } void CBrowseWindow::OnMediumIcons() { CVirtualTreeNode *pVTNDir = m_pBrowser->GetSelectedDirectory(); ASSERT( pVTNDir != NULL); pVTNDir->vtn_bmBrowsingMode = BM_ICONS_MEDIUM; Refresh(); } void CBrowseWindow::OnMicroIcons() { CVirtualTreeNode *pVTNDir = m_pBrowser->GetSelectedDirectory(); ASSERT( pVTNDir != NULL); pVTNDir->vtn_bmBrowsingMode = BM_ICONS_MICRO; Refresh(); } void CBrowseWindow::OnSmallIcons() { CVirtualTreeNode *pVTNDir = m_pBrowser->GetSelectedDirectory(); ASSERT( pVTNDir != NULL); pVTNDir->vtn_bmBrowsingMode = BM_ICONS_SMALL; Refresh(); } void CBrowseWindow::OnShowDescription() { CVirtualTreeNode *pVTNDir = m_pBrowser->GetSelectedDirectory(); ASSERT( pVTNDir != NULL); pVTNDir->vtn_bmBrowsingMode = BM_DESCRIPTION; Refresh(); } void CBrowseWindow::OnShowFilename() { CVirtualTreeNode *pVTNDir = m_pBrowser->GetSelectedDirectory(); ASSERT( pVTNDir != NULL); pVTNDir->vtn_bmBrowsingMode = BM_FILENAME; Refresh(); } void CBrowseWindow::OnLButtonDblClk(UINT nFlags, CPoint point) { CMainFrame* pMainFrame = STATIC_DOWNCAST(CMainFrame, AfxGetMainWnd()); // get hitted item's index FLOAT fDummyX, fDummyY; INDEX iHittedItem = HitItem( point, fDummyX, fDummyY); // if hit none reported, return if( iHittedItem == -1) { return; } // get item object from hitted index CVirtualTreeNode *pVTN = GetItem( iHittedItem); // must not be null ASSERT( pVTN != NULL); // get item's file name CTFileName fnItem = pVTN->vtn_fnItem; // if it is texture if( fnItem.FileExt() == ".tex") { CWorldEditorDoc *pDoc = theApp.GetDocument(); if(pDoc!=NULL && pDoc->GetEditingMode()==TERRAIN_MODE) { CTerrainLayer *ptlLayer=GetLayer(); CTerrain *ptTerrain=GetTerrain(); if(ptlLayer!=NULL && ptTerrain!=NULL) { try { ptlLayer->SetLayerTexture_t(fnItem); theApp.m_ctTerrainPageCanvas.MarkChanged(); ptTerrain->RefreshTerrain(); } catch(char *strError) { (void) strError; } } } else { // set it as new primitive's material default texture theApp.SetNewActiveTexture( _fnmApplicationPath + fnItem); // paste new active texture over polygon selection theApp.TexturizeSelection(); } } // if it is world (template) else if( fnItem.FileExt() == ".wld") { // open document with item's file name theApp.m_pDocTemplate->OpenDocumentFile( CString(_fnmApplicationPath + fnItem)); } } void CBrowseWindow::OnRecreateTexture() { if( _bRightClickedIsSelected) { CVirtualTreeNode *pVTNDir = m_pBrowser->GetSelectedDirectory(); ASSERT( pVTNDir != NULL); FOREACHINLIST( CVirtualTreeNode, vtn_lnInDirectory, pVTNDir->vtn_lhChildren, it) { if( it->vtn_bSelected && it->vtn_fnItem.FileExt()==CTString(".tex") ) { _EngineGUI.CreateTexture( it->vtn_fnItem); } } } else if( _fnRightClickedItemFileName.FileExt()==CTString(".tex")) { _EngineGUI.CreateTexture( _fnRightClickedItemFileName); } Refresh(); CWorldEditorDoc *pDoc = theApp.GetDocument(); if( pDoc != NULL) pDoc->UpdateAllViews( NULL); } void CBrowseWindow::OnSelectByTextureInSelectedSectors() { SelectByTextures( TRUE, FALSE); } void CBrowseWindow::OnCreateAndAddTexture() { CDynamicArray afnCreatedTextures; CTFileName fnCreatedTexture = _EngineGUI.CreateTexture( CTString(""), &afnCreatedTextures); if( afnCreatedTextures.Count() != 0) { CVirtualTreeNode *pVTNDir = m_pBrowser->GetSelectedDirectory(); if( pVTNDir != NULL) { CloseDirectory( pVTNDir); } // insert created textures FOREACHINDYNAMICARRAY( afnCreatedTextures, CTFileName, itTexture) { CTFileName &fn=*itTexture; InsertItem( fn, CPoint(-1, -1)); } if( pVTNDir != NULL) { OpenDirectory( pVTNDir); } } } void CBrowseWindow::OnSelectForDropMarker() { theApp.m_fnClassForDropMarker = _fnRightClickedItemFileName; } void CBrowseWindow::OnSetAsCurrentTexture() { // set it as new primitive's material default texture theApp.SetNewActiveTexture( _fnmApplicationPath + _fnRightClickedItemFileName); } void CBrowseWindow::OnConvertClass() { if( _fnRightClickedItemFileName.FileExt()!=CTString(".ecl")) { WarningMessage( "Only classes can be used for converting classe"); return; } try { CWorldEditorDoc *pDoc = theApp.GetDocument(); FOREACHINDYNAMICCONTAINER(pDoc->m_selEntitySelection, CEntity, iten) { // create the entity of requested class CEntity *penNewClass; penNewClass = pDoc->m_woWorld.CreateEntity_t( iten->GetPlacement(), _fnRightClickedItemFileName); // try to copy entity properties CDLLEntityClass *pdecDLLClassNew = penNewClass->GetClass()->ec_pdecDLLClass; for(;pdecDLLClassNew!=NULL; pdecDLLClassNew = pdecDLLClassNew->dec_pdecBase) { for(INDEX iPropertyNew=0; iPropertyNewdec_ctProperties; iPropertyNew++) { CEntityProperty &epPropertyNew = pdecDLLClassNew->dec_aepProperties[iPropertyNew]; CDLLEntityClass *pdecDLLClassOld = iten->GetClass()->ec_pdecDLLClass; for(;pdecDLLClassOld!=NULL; pdecDLLClassOld = pdecDLLClassOld->dec_pdecBase) { for(INDEX iPropertyOld=0; iPropertyOlddec_ctProperties; iPropertyOld++) { CEntityProperty &epPropertyOld = pdecDLLClassOld->dec_aepProperties[iPropertyOld]; if( (CTString(epPropertyNew.ep_strName) == epPropertyOld.ep_strName) && (epPropertyNew.ep_eptType == epPropertyOld.ep_eptType) ) { penNewClass->CopyOneProperty( epPropertyOld, epPropertyNew, *iten, FALSE); } } } } } // prepare the entity penNewClass->Initialize(); } CWorldEditorView *pWorldEditorView = theApp.GetActiveView(); if( pWorldEditorView != NULL) { pWorldEditorView->OnDeleteEntities(); } } catch( char *err_str) { AfxMessageBox( CString(err_str)); } } static void GetToolTipText(void *pBrowser, char *pToolTipText) { CBrowseWindow *pBrowseWindow = (CBrowseWindow *) pBrowser; pBrowseWindow->GetToolTipText( pToolTipText); } void CBrowseWindow::GetToolTipText( char *pToolTipText) { CPoint point; ::GetCursorPos(&point); ScreenToClient(&point); // get hitted item's index FLOAT fDummyX, fDummyY; INDEX iHittedItem = HitItem( point, fDummyX, fDummyY); // if hit none reported, return if( iHittedItem == -1) { strcpy( pToolTipText, ""); return; } // get item object from hitted index CVirtualTreeNode *pVTN = GetItem( iHittedItem); strcpy(pToolTipText, pVTN->vtn_strName); } void CBrowseWindow::OnMouseMove(UINT nFlags, CPoint point) { theApp.m_cttToolTips.MouseMoveNotify( m_hWnd, 500, &::GetToolTipText, this); CWnd::OnMouseMove(nFlags, point); } void CBrowseWindow::OnSelectByTextureInWorld() { SelectByTextures( FALSE, FALSE); } void CBrowseWindow::OnSelectExceptTextures( void) { SelectByTextures( FALSE, TRUE); } void CBrowseWindow::SelectByTextures( BOOL bInSelectedSectors, BOOL bExceptSelected) { CVirtualTreeNode *pVTNDir = m_pBrowser->GetSelectedDirectory(); CWorldEditorDoc *pDoc = theApp.GetDocument(); if( pDoc == NULL) return; // for each entity in the world FOREACHINDYNAMICCONTAINER(pDoc->m_woWorld.wo_cenEntities, CEntity, iten) { // if it is brush entity if (iten->en_RenderType == CEntity::RT_BRUSH) { // for each mip in its brush FOREACHINLIST(CBrushMip, bm_lnInBrush, iten->en_pbrBrush->br_lhBrushMips, itbm) { // for all sectors in this mip FOREACHINDYNAMICARRAY(itbm->bm_abscSectors, CBrushSector, itbsc) { // if sector is selected if( !bInSelectedSectors || itbsc->IsSelected(BSCF_SELECTED)) { // for all polygons in sector FOREACHINSTATICARRAY(itbsc->bsc_abpoPolygons, CBrushPolygon, itbpo) { // if it is not non translucent portal and is not selected and has same texture if ( /*(!(itbpo->bpo_ulFlags&BPOF_PORTAL) || (itbpo->bpo_ulFlags&BPOF_TRANSLUCENT) || (itbpo->bpo_bppProperties.bpp_uwPretenderDistance!=0) ) &&*/ !itbpo->IsSelected(BPOF_SELECTED) && (itbpo->bpo_abptTextures[pDoc->m_iTexture].bpt_toTexture.GetData() != NULL) ) { CTFileName fnTexture = itbpo->bpo_abptTextures[pDoc->m_iTexture].bpt_toTexture.GetData()->GetName(); BOOL bSelect = bExceptSelected; FOREACHINLIST( CVirtualTreeNode, vtn_lnInDirectory, pVTNDir->vtn_lhChildren, it) { if( _bRightClickedIsSelected) { if(it->vtn_bSelected && it->vtn_fnItem.FileExt()==CTString(".tex") && fnTexture == it->vtn_fnItem) { bSelect = !bExceptSelected; break; } } else if( fnTexture == _fnRightClickedItemFileName) { bSelect = !bExceptSelected; break; } } if( bSelect) pDoc->m_selPolygonSelection.Select(*itbpo); } } } } } } } pDoc->SetEditingMode( POLYGON_MODE); pDoc->m_chSelections.MarkChanged(); pDoc->UpdateAllViews( NULL); } void CBrowseWindow::OnAddTexturesFromWorld() { CVirtualTreeNode *pVTNDir = m_pBrowser->GetSelectedDirectory(); CWorldEditorDoc *pDoc = theApp.GetDocument(); if (pDoc == NULL) return; CloseDirectory( pVTNDir); // for each entity in the world FOREACHINDYNAMICCONTAINER(pDoc->m_woWorld.wo_cenEntities, CEntity, iten) { // if it is brush entity if (iten->en_RenderType == CEntity::RT_BRUSH) { // for each mip in its brush FOREACHINLIST(CBrushMip, bm_lnInBrush, iten->en_pbrBrush->br_lhBrushMips, itbm) { // for all sectors in this mip FOREACHINDYNAMICARRAY(itbm->bm_abscSectors, CBrushSector, itbsc) { // for all polygons in sector FOREACHINSTATICARRAY(itbsc->bsc_abpoPolygons, CBrushPolygon, itbpo) { try { CTextureObject &to1 = itbpo->bpo_abptTextures[0].bpt_toTexture; if(to1.GetData() != NULL) InsertItem( to1.GetData()->GetName(), CPoint(-1, -1)); CTextureObject &to2 = itbpo->bpo_abptTextures[1].bpt_toTexture; if(to2.GetData() != NULL) InsertItem( to2.GetData()->GetName(), CPoint(-1, -1)); CTextureObject &to3 = itbpo->bpo_abptTextures[2].bpt_toTexture; if(to3.GetData() != NULL) InsertItem( to3.GetData()->GetName(), CPoint(-1, -1)); } catch( char *err_str) { AfxMessageBox( CString(err_str)); } } } } } } OpenDirectory( pVTNDir); } void CBrowseWindow::OnShowTreeShortcuts() { CMainFrame* pMainFrame = STATIC_DOWNCAST(CMainFrame, AfxGetMainWnd()); pMainFrame->OnShowTreeShortcuts(); } void ExportTexture( CTFileName fnTexture) { CTextureData *ptd; CImageInfo ii; try { ptd = _pTextureStock->Obtain_t( fnTexture); for( INDEX iFrame=0; iFrametd_ctFrames; iFrame++) { ptd->Export_t( ii, iFrame); // obtain name for export file CTFileName fnFrame; if( ptd->td_ctFrames == 1) { fnFrame = fnTexture.NoExt()+".tga"; } else { fnFrame.PrintF("%s%03d.tga", (const char *)fnTexture.NoExt(), iFrame); } // if file exists, ask for substitution name if( FileExists( fnFrame) && iFrame==0 ) { CTString strDefaultDir = fnFrame.FileDir(); CTString strDefaultFile = fnFrame.FileName()+fnFrame.FileExt(); // invoke "Save as" dialog fnFrame = _EngineGUI.FileRequester( "Save As", FILTER_TGA FILTER_END, "Export texture directory", strDefaultDir, strDefaultFile, NULL, FALSE); } if( fnFrame != "") { ii.SaveTGA_t(fnFrame); ii.Clear(); } } } catch( char *strError) { AfxMessageBox( CString(strError)); ii.Clear(); } } void CBrowseWindow::OnExportTexture() { if( _bRightClickedIsSelected) { CVirtualTreeNode *pVTNDir = m_pBrowser->GetSelectedDirectory(); ASSERT( pVTNDir != NULL); FOREACHINLIST( CVirtualTreeNode, vtn_lnInDirectory, pVTNDir->vtn_lhChildren, it) { if( it->vtn_bSelected && it->vtn_fnItem.FileExt()==CTString(".tex") || it->vtn_bSelected && it->vtn_fnItem.FileExt()==CTString(".tbn") ) { ExportTexture( it->vtn_fnItem); } } } else if( _fnRightClickedItemFileName.FileExt()==CTString(".tex") || _fnRightClickedItemFileName.FileExt()==CTString(".tbn") ) { ExportTexture( _fnRightClickedItemFileName); } } void CBrowseWindow::OnBrowserContextHelp() { if( _fnRightClickedItemFileName.FileExt()==CTString(".ecl")) { theApp.DisplayHelp(_fnRightClickedItemFileName, HH_DISPLAY_TOPIC, NULL); } }