source-engine/hammer/texturebox.cpp

473 lines
11 KiB
C++
Raw Permalink Normal View History

2020-04-23 00:56:21 +08:00
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Implements an owner-draw combo box containing the names and thumbnail
// images of textures. The textures are gotten from the global texture
// manager object, and are filtered by texture format.
//
//=============================================================================
#include "stdafx.h"
#include "GameConfig.h"
#include "IEditorTexture.h"
#include "TextureBox.h"
#include "TextureSystem.h"
#include "hammer.h"
// memdbgon must be the last include file in a .cpp file!!!
#include <tier0/memdbgon.h>
BEGIN_MESSAGE_MAP(CTextureBox, CComboBox)
//{{AFX_MSG_MAP(CTextureBox)
ON_WM_ERASEBKGND()
ON_MESSAGE(CB_SELECTSTRING, OnSelectString)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CTextureBox::CTextureBox(void)
{
bFirstMeasure = TRUE;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CTextureBox::~CTextureBox(void)
{
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : lpCompareItemStruct -
// Output : int
//-----------------------------------------------------------------------------
int CTextureBox::CompareItem(LPCOMPAREITEMSTRUCT lpCompareItemStruct)
{
return 0;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : lpDeleteItemStruct -
//-----------------------------------------------------------------------------
void CTextureBox::DeleteItem(LPDELETEITEMSTRUCT lpDeleteItemStruct)
{
CComboBox::DeleteItem(lpDeleteItemStruct);
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : lpDrawItemStruct -
//-----------------------------------------------------------------------------
void CTextureBox::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
// if(!pGD)
// return;
CDC dc;
dc.Attach(lpDrawItemStruct->hDC);
dc.SaveDC();
RECT& r = lpDrawItemStruct->rcItem;
int iFontHeight = dc.GetTextExtent("J", 1).cy;
if (lpDrawItemStruct->itemID != -1)
{
IEditorTexture *pTex = (IEditorTexture *)GetItemDataPtr(lpDrawItemStruct->itemID);
dc.SetROP2(R2_COPYPEN);
CPalette *pOldPalette = NULL;
if (pTex != NULL)
{
pTex->Load();
pOldPalette = dc.SelectPalette(pTex->HasPalette() ? pTex->GetPalette() : g_pGameConfig->Palette, FALSE);
dc.RealizePalette();
}
COLORREF dwBackColor = RGB(255,255,255);
COLORREF dwForeColor = RGB(0,0,0);
if (lpDrawItemStruct->itemState & ODS_SELECTED)
{
dwBackColor = GetSysColor(COLOR_HIGHLIGHT);
dwForeColor = GetSysColor(COLOR_HIGHLIGHTTEXT);
}
// draw background
CBrush brush;
brush.CreateSolidBrush(dwBackColor);
dc.FillRect(&r, &brush);
if (pTex == NULL)
{
// separator
dc.SelectStockObject(BLACK_PEN);
dc.MoveTo(r.left, r.top+5);
dc.LineTo(r.right, r.top+5);
}
else
{
char szName[MAX_PATH];
int iLen = pTex->GetShortName(szName);
// when we get here, we are drawing a regular graphic. we
// check the size of the rectangle - if it's > 32 (just
// a nice number), we're drawing an item in the drop list.
if ((r.bottom - r.top) > 32)
{
DrawTexData_t DrawTexData;
DrawTexData.nFlags = 0;
// draw graphic
CRect r2(r);
r2.InflateRect(-4, -4);
r2.right = r2.left + 64;
pTex->Draw(&dc, r2, 0, 0, DrawTexData);
// draw name
dc.SetTextColor(dwForeColor);
dc.SetBkMode(TRANSPARENT);
dc.TextOut(r2.right + 4, r2.top + 4, szName, iLen);
// draw size
sprintf(szName, "%dx%d", pTex->GetWidth(), pTex->GetHeight());
dc.TextOut(r2.right + 4, r2.top + 4 + iFontHeight, szName, strlen(szName));
}
// if it's < 32, we're drawing the item in the "closed"
// combo box, so just draw the name of the texture
else
{
// just draw name -
dc.SetTextColor(dwForeColor);
dc.SetBkMode(TRANSPARENT);
dc.TextOut(r.left + 4, r.top + 2, szName, iLen);
}
}
if (pOldPalette)
{
dc.SelectPalette(pOldPalette, FALSE);
}
}
else if (lpDrawItemStruct->itemState & ODS_FOCUS)
{
dc.DrawFocusRect(&r);
}
dc.RestoreDC(-1);
dc.Detach();
}
//-----------------------------------------------------------------------------
// Purpose: Adds the given texture to the MRU for this texture list.
// Input : pTex - Texture to add. If NULL, MRU is rebuilt from scratch.
//-----------------------------------------------------------------------------
void CTextureBox::AddMRU(IEditorTexture *pTex)
{
if (pTex != NULL)
{
//
// Add the texture to the MRU set.
//
g_Textures.AddMRU(pTex);
//
// Update the list contents based on the new MRU set.
//
RebuildMRU();
//
// Select the newly added texture, which should be at index 0.
//
SetCurSel(0);
Invalidate();
}
}
//-----------------------------------------------------------------------------
// Purpose: Rebuilds the MRU for this texture combo box.
//-----------------------------------------------------------------------------
void CTextureBox::RebuildMRU(void)
{
SetRedraw(FALSE);
int nCurSel = GetCurSel();
//
// Delete current MRUs from list.
//
int nItems = GetCount();
int nDelimiterIndex = 0;
while (nDelimiterIndex < nItems)
{
//
// The first item with a NULL item data pointer is the MRU delimiter.
//
if (GetItemDataPtr(nDelimiterIndex) == NULL)
{
break;
}
nDelimiterIndex++;
}
//
// If the MRU delimiter was found, delete everything before it.
//
if (nDelimiterIndex != nItems)
{
do
{
DeleteString(0);
} while(nDelimiterIndex--);
}
//
// Add each texture from the graphics MRU to this list's MRU.
//
int nStrCount = 0;
int nMRUCount = g_Textures.MRUGetCount();
for (int nMRU = 0; nMRU < nMRUCount; nMRU++)
{
IEditorTexture *pTex = g_Textures.MRUGet(nMRU);
if (pTex != NULL)
{
char szBuf[MAX_PATH];
pTex->GetShortName(szBuf);
int nIndex = InsertString(nStrCount, szBuf);
SetItemDataPtr(nIndex, pTex);
nStrCount++;
}
}
//
// Add the MRU seperator to the list, unless the MRU was empty.
//
if (nStrCount > 0)
{
int nIndex = InsertString(nStrCount, "");
SetItemDataPtr(nIndex, NULL);
}
//
// Restore the original selection.
//
SetCurSel(nCurSel);
SetRedraw(TRUE);
Invalidate();
}
void CTextureBox::NotifyNewMaterial( IEditorTexture *pTex )
{
char szStr[MAX_PATH];
pTex->GetShortName( szStr );
int iItem = AddString( szStr );
if ( iItem != CB_ERR )
{
SetItemDataPtr( iItem, (void *)pTex );
}
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : lpMeasureItemStruct -
//-----------------------------------------------------------------------------
void CTextureBox::MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct)
{
lpMeasureItemStruct->itemWidth = 64;
//
// If the item data is NULL or points to an empty string, it's the separator.
//
char *pszText = (char *)lpMeasureItemStruct->itemData;
if ((pszText == NULL) || (*pszText == '\0'))
{
lpMeasureItemStruct->itemHeight = 9;
}
else
{
lpMeasureItemStruct->itemHeight = 64 + 8;
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CTextureBox::LoadGraphicList(void)
{
if (g_pGameConfig->GetTextureFormat() == tfNone)
{
return;
}
SetRedraw(FALSE);
ResetContent();
InitStorage(g_Textures.GetActiveTextureCount() + 32, sizeof(PVOID));
//
// Add the MRU textures to the list.
//
int nStrCount = 0;
int nMRUCount = g_Textures.MRUGetCount();
for (int nMRU = 0; nMRU < nMRUCount; nMRU++)
{
IEditorTexture *pTex = g_Textures.MRUGet(nMRU);
if (pTex != NULL)
{
char szStr[MAX_PATH];
pTex->GetShortName(szStr);
AddString(szStr);
SetItemDataPtr(nStrCount, (void *)pTex);
nStrCount++;
}
}
//
// Add the MRU seperator to the list, unless the MRU was empty.
//
if (nStrCount > 0)
{
AddString("");
SetItemDataPtr(nStrCount, NULL);
nStrCount++;
}
//
// Add the rest of the textures to the list.
//
int nIndex = 0;
IEditorTexture *pTex = g_Textures.EnumActiveTextures(&nIndex, g_pGameConfig->GetTextureFormat());
while (pTex != NULL)
{
char szStr[MAX_PATH];
pTex->GetShortName(szStr);
int err = AddString(szStr);
Assert( (err != CB_ERR) && (err != CB_ERRSPACE) );
SetItemDataPtr(nStrCount, (void *)pTex);
nStrCount++;
pTex = g_Textures.EnumActiveTextures(&nIndex, g_pGameConfig->GetTextureFormat());
}
//
// Hack: Select one that doesn't start with '+', '!', or '*', and doesn't have "door" in it.
//
SetCurSel(0);
int nSel = GetCount();
for (int i = 0; i < nSel; i++)
{
IEditorTexture *pTexSearch = (IEditorTexture *)GetItemDataPtr(i);
if (pTexSearch != NULL)
{
char szName[MAX_PATH];
pTexSearch->GetShortName(szName);
if ((szName[0] != 0) && (szName[0] != '*') && (szName[0] != '+') && (szName[0] != '!') && (strstr(szName, "door") == NULL))
{
// this one is ok
SetCurSel(i);
break;
}
}
}
SetRedraw(TRUE);
Invalidate();
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : dwStyle -
// rect -
// pParentWnd -
// nID -
// Output : Returns TRUE on success, FALSE on failure.
//-----------------------------------------------------------------------------
BOOL CTextureBox::Create(DWORD dwStyle, const RECT &rect, CWnd *pParentWnd, UINT nID)
{
static BOOL bInitClass = TRUE;
static LPCTSTR pszTextureBoxClass = "TextureBox";
if(bInitClass)
{
bInitClass = FALSE;
// get default class provided by MFC
WNDCLASS wndclass;
GetClassInfo(AfxGetInstanceHandle(), _T("COMBOBOX"), &wndclass);
wndclass.hbrBackground = NULL;
wndclass.lpszClassName = pszTextureBoxClass;
AfxRegisterClass(&wndclass);
}
return CWnd::Create(pszTextureBoxClass, NULL, dwStyle, rect, pParentWnd, nID);
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : wParam -
// lParam -
// Output : LRESULT
//-----------------------------------------------------------------------------
LRESULT CTextureBox::OnSelectString(WPARAM wParam, LPARAM lParam)
{
LPCTSTR pszSelect = LPCTSTR(lParam);
int nCount = GetCount();
IEditorTexture *pTex;
for(int i = wParam + 1; i < nCount; i++)
{
pTex = (IEditorTexture *)GetItemDataPtr(i);
if (pTex != NULL)
{
char szName[MAX_PATH];
pTex->GetShortName(szName);
if (!stricmp(szName, pszSelect))
{
SetCurSel(i);
return i;
}
}
}
return LB_ERR;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : pDC -
// Output : Returns TRUE on success, FALSE on failure.
//-----------------------------------------------------------------------------
BOOL CTextureBox::OnEraseBkgnd(CDC *pDC)
{
CRect r;
GetUpdateRect(r);
pDC->SetROP2(R2_COPYPEN);
FillRect(pDC->m_hDC, r, HBRUSH(GetStockObject(BLACK_BRUSH)));
return TRUE;
}