diff options
Diffstat (limited to 'samples/DX_APIUsage/DXUT/Optional/DXUTgui.cpp')
| -rw-r--r-- | samples/DX_APIUsage/DXUT/Optional/DXUTgui.cpp | 7293 |
1 files changed, 7293 insertions, 0 deletions
diff --git a/samples/DX_APIUsage/DXUT/Optional/DXUTgui.cpp b/samples/DX_APIUsage/DXUT/Optional/DXUTgui.cpp new file mode 100644 index 0000000..cb83fff --- /dev/null +++ b/samples/DX_APIUsage/DXUT/Optional/DXUTgui.cpp @@ -0,0 +1,7293 @@ +//-------------------------------------------------------------------------------------- +// File: DXUTgui.cpp +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//-------------------------------------------------------------------------------------- +#include "DXUT.h" +#include "DXUTgui.h" +#include "DXUTsettingsDlg.h" +#include "DXUTres.h" + +#include "SDKMisc.h" + +#undef min // use __min instead +#undef max // use __max instead + +#ifndef WM_XBUTTONDOWN +#define WM_XBUTTONDOWN 0x020B // (not always defined) +#endif +#ifndef WM_XBUTTONUP +#define WM_XBUTTONUP 0x020C // (not always defined) +#endif +#ifndef WM_MOUSEWHEEL +#define WM_MOUSEWHEEL 0x020A // (not always defined) +#endif +#ifndef WHEEL_DELTA +#define WHEEL_DELTA 120 // (not always defined) +#endif + +// Minimum scroll bar thumb size +#define SCROLLBAR_MINTHUMBSIZE 8 + +// Delay and repeat period when clicking on the scroll bar arrows +#define SCROLLBAR_ARROWCLICK_DELAY 0.33 +#define SCROLLBAR_ARROWCLICK_REPEAT 0.05 + +#define DXUT_NEAR_BUTTON_DEPTH 0.6f +#define DXUT_FAR_BUTTON_DEPTH 0.8f + +#define DXUT_MAX_GUI_SPRITES 500 + +D3DCOLORVALUE D3DCOLOR_TO_D3DCOLORVALUE( D3DCOLOR c ) +{ + D3DCOLORVALUE cv = + { + ( ( c >> 16 ) & 0xFF ) / 255.0f, + ( ( c >> 8 ) & 0xFF ) / 255.0f, + ( c & 0xFF ) / 255.0f, + ( ( c >> 24 ) & 0xFF ) / 255.0f + }; + return cv; +} + +#define UNISCRIBE_DLLNAME L"usp10.dll" + +#define GETPROCADDRESS( Module, APIName, Temp ) \ + Temp = GetProcAddress( Module, #APIName ); \ + if( Temp ) \ + *(FARPROC*)&_##APIName = Temp + +#define PLACEHOLDERPROC( APIName ) \ + _##APIName = Dummy_##APIName + +#define IMM32_DLLNAME L"imm32.dll" +#define VER_DLLNAME L"version.dll" + +CHAR g_strUIEffectFile[] = \ + "Texture2D g_Texture;"\ + ""\ + "SamplerState Sampler"\ + "{"\ + " Filter = MIN_MAG_MIP_LINEAR;"\ + " AddressU = Wrap;"\ + " AddressV = Wrap;"\ + "};"\ + ""\ + "BlendState UIBlend"\ + "{"\ + " AlphaToCoverageEnable = FALSE;"\ + " BlendEnable[0] = TRUE;"\ + " SrcBlend = SRC_ALPHA;"\ + " DestBlend = INV_SRC_ALPHA;"\ + " BlendOp = ADD;"\ + " SrcBlendAlpha = ONE;"\ + " DestBlendAlpha = ZERO;"\ + " BlendOpAlpha = ADD;"\ + " RenderTargetWriteMask[0] = 0x0F;"\ + "};"\ + ""\ + "BlendState NoBlending"\ + "{"\ + " BlendEnable[0] = FALSE;"\ + " RenderTargetWriteMask[0] = 0x0F;"\ + "};"\ + ""\ + "DepthStencilState DisableDepth"\ + "{"\ + " DepthEnable = false;"\ + "};"\ + "DepthStencilState EnableDepth"\ + "{"\ + " DepthEnable = true;"\ + "};"\ + "struct VS_OUTPUT"\ + "{"\ + " float4 Pos : POSITION;"\ + " float4 Dif : COLOR;"\ + " float2 Tex : TEXCOORD;"\ + "};"\ + ""\ + "VS_OUTPUT VS( float3 vPos : POSITION,"\ + " float4 Dif : COLOR,"\ + " float2 vTexCoord0 : TEXCOORD )"\ + "{"\ + " VS_OUTPUT Output;"\ + ""\ + " Output.Pos = float4( vPos, 1.0f );"\ + " Output.Dif = Dif;"\ + " Output.Tex = vTexCoord0;"\ + ""\ + " return Output;"\ + "}"\ + ""\ + "float4 PS( VS_OUTPUT In ) : SV_Target"\ + "{"\ + " return g_Texture.Sample( Sampler, In.Tex ) * In.Dif;"\ + "}"\ + ""\ + "float4 PSUntex( VS_OUTPUT In ) : SV_Target"\ + "{"\ + " return In.Dif;"\ + "}"\ + ""\ + "technique10 RenderUI"\ + "{"\ + " pass P0"\ + " {"\ + " SetVertexShader( CompileShader( vs_4_0, VS() ) );"\ + " SetGeometryShader( NULL );"\ + " SetPixelShader( CompileShader( ps_4_0, PS() ) );"\ + " SetDepthStencilState( DisableDepth, 0 );"\ + " SetBlendState( UIBlend, float4( 0.0f, 0.0f, 0.0f, 0.0f ), 0xFFFFFFFF );"\ + " }"\ + "}"\ + "technique10 RenderUIUntex"\ + "{"\ + " pass P0"\ + " {"\ + " SetVertexShader( CompileShader( vs_4_0, VS() ) );"\ + " SetGeometryShader( NULL );"\ + " SetPixelShader( CompileShader( ps_4_0, PSUntex() ) );"\ + " SetDepthStencilState( DisableDepth, 0 );"\ + " SetBlendState( UIBlend, float4( 0.0f, 0.0f, 0.0f, 0.0f ), 0xFFFFFFFF );"\ + " }"\ + "}"\ + "technique10 RestoreState"\ + "{"\ + " pass P0"\ + " {"\ + " SetDepthStencilState( EnableDepth, 0 );"\ + " SetBlendState( NoBlending, float4( 0.0f, 0.0f, 0.0f, 0.0f ), 0xFFFFFFFF );"\ + " }"\ + "}"; +const UINT g_uUIEffectFileSize = sizeof( g_strUIEffectFile ); + + +// DXUT_MAX_EDITBOXLENGTH is the maximum string length allowed in edit boxes, +// including the NULL terminator. +// +// Uniscribe does not support strings having bigger-than-16-bits length. +// This means that the string must be less than 65536 characters long, +// including the NULL terminator. +#define DXUT_MAX_EDITBOXLENGTH 0xFFFF + + +double CDXUTDialog::s_fTimeRefresh = 0.0f; +CDXUTControl* CDXUTDialog::s_pControlFocus = NULL; // The control which has focus +CDXUTControl* CDXUTDialog::s_pControlPressed = NULL; // The control currently pressed + + +struct DXUT_SCREEN_VERTEX +{ + float x, y, z, h; + D3DCOLOR color; + float tu, tv; + + static DWORD FVF; +}; +DWORD DXUT_SCREEN_VERTEX::FVF = D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX1; + + +struct DXUT_SCREEN_VERTEX_UNTEX +{ + float x, y, z, h; + D3DCOLOR color; + + static DWORD FVF; +}; +DWORD DXUT_SCREEN_VERTEX_UNTEX::FVF = D3DFVF_XYZRHW | D3DFVF_DIFFUSE; + + +struct DXUT_SCREEN_VERTEX_10 +{ + float x, y, z; + D3DCOLORVALUE color; + float tu, tv; +}; + + +inline int RectWidth( RECT& rc ) +{ + return ( ( rc ).right - ( rc ).left ); +} +inline int RectHeight( RECT& rc ) +{ + return ( ( rc ).bottom - ( rc ).top ); +} + + +HRESULT InitFont11( ID3D11Device* pd3d11Device, ID3D11InputLayout* pInputLayout ); +void EndFont11(); + +//-------------------------------------------------------------------------------------- +// CDXUTDialog class +//-------------------------------------------------------------------------------------- + +//-------------------------------------------------------------------------------------- +CDXUTDialog::CDXUTDialog() +{ + m_x = 0; + m_y = 0; + m_width = 0; + m_height = 0; + + m_pManager = NULL; + m_bVisible = true; + m_bCaption = false; + m_bMinimized = false; + m_bDrag = false; + m_wszCaption[0] = L'\0'; + m_nCaptionHeight = 18; + + m_colorTopLeft = 0; + m_colorTopRight = 0; + m_colorBottomLeft = 0; + m_colorBottomRight = 0; + + m_pCallbackEvent = NULL; + m_pCallbackEventUserContext = NULL; + + m_fTimeLastRefresh = 0; + + m_pControlMouseOver = NULL; + + m_pNextDialog = this; + m_pPrevDialog = this; + + m_nDefaultControlID = 0xffff; + m_bNonUserEvents = false; + m_bKeyboardInput = false; + m_bMouseInput = true; +} + + +//-------------------------------------------------------------------------------------- +CDXUTDialog::~CDXUTDialog() +{ + int i = 0; + + RemoveAllControls(); + + m_Fonts.RemoveAll(); + m_Textures.RemoveAll(); + + for( i = 0; i < m_DefaultElements.GetSize(); i++ ) + { + DXUTElementHolder* pElementHolder = m_DefaultElements.GetAt( i ); + SAFE_DELETE( pElementHolder ); + } + + m_DefaultElements.RemoveAll(); +} + + +//-------------------------------------------------------------------------------------- +void CDXUTDialog::Init( CDXUTDialogResourceManager* pManager, bool bRegisterDialog ) +{ + m_pManager = pManager; + if( bRegisterDialog ) + pManager->RegisterDialog( this ); + + SetTexture( 0, MAKEINTRESOURCE( 0xFFFF ), ( HMODULE )0xFFFF ); + InitDefaultElements(); +} + + +//-------------------------------------------------------------------------------------- +void CDXUTDialog::Init( CDXUTDialogResourceManager* pManager, bool bRegisterDialog, LPCWSTR pszControlTextureFilename ) +{ + m_pManager = pManager; + if( bRegisterDialog ) + pManager->RegisterDialog( this ); + SetTexture( 0, pszControlTextureFilename ); + InitDefaultElements(); +} + + +//-------------------------------------------------------------------------------------- +void CDXUTDialog::Init( CDXUTDialogResourceManager* pManager, bool bRegisterDialog, + LPCWSTR szControlTextureResourceName, HMODULE hControlTextureResourceModule ) +{ + m_pManager = pManager; + if( bRegisterDialog ) + pManager->RegisterDialog( this ); + + SetTexture( 0, szControlTextureResourceName, hControlTextureResourceModule ); + InitDefaultElements(); +} + + +//-------------------------------------------------------------------------------------- +void CDXUTDialog::SetCallback( PCALLBACKDXUTGUIEVENT pCallback, void* pUserContext ) +{ + // If this assert triggers, you need to call CDXUTDialog::Init() first. This change + // was made so that the DXUT's GUI could become seperate and optional from DXUT's core. The + // creation and interfacing with CDXUTDialogResourceManager is now the responsibility + // of the application if it wishes to use DXUT's GUI. + assert( m_pManager != NULL && L"To fix call CDXUTDialog::Init() first. See comments for details." ); + + m_pCallbackEvent = pCallback; + m_pCallbackEventUserContext = pUserContext; +} + + +//-------------------------------------------------------------------------------------- +void CDXUTDialog::RemoveControl( int ID ) +{ + for( int i = 0; i < m_Controls.GetSize(); i++ ) + { + CDXUTControl* pControl = m_Controls.GetAt( i ); + if( pControl->GetID() == ID ) + { + // Clean focus first + ClearFocus(); + + // Clear references to this control + if( s_pControlFocus == pControl ) + s_pControlFocus = NULL; + if( s_pControlPressed == pControl ) + s_pControlPressed = NULL; + if( m_pControlMouseOver == pControl ) + m_pControlMouseOver = NULL; + + SAFE_DELETE( pControl ); + m_Controls.Remove( i ); + + return; + } + } +} + + +//-------------------------------------------------------------------------------------- +void CDXUTDialog::RemoveAllControls() +{ + if( s_pControlFocus && s_pControlFocus->m_pDialog == this ) + s_pControlFocus = NULL; + if( s_pControlPressed && s_pControlPressed->m_pDialog == this ) + s_pControlPressed = NULL; + m_pControlMouseOver = NULL; + + for( int i = 0; i < m_Controls.GetSize(); i++ ) + { + CDXUTControl* pControl = m_Controls.GetAt( i ); + SAFE_DELETE( pControl ); + } + + m_Controls.RemoveAll(); +} + + +//-------------------------------------------------------------------------------------- +CDXUTDialogResourceManager::CDXUTDialogResourceManager() +{ + // Begin D3D9-specific + m_pd3d9Device = NULL; + m_pStateBlock = NULL; + m_pSprite = NULL; + + // Begin D3D11-specific + // Shaders + m_pVSRenderUI11 = NULL; + m_pPSRenderUI11 = NULL; + m_pPSRenderUIUntex11 = NULL; + + // States + m_pDepthStencilStateUI11 = NULL; + m_pRasterizerStateUI11 = NULL; + m_pBlendStateUI11 = NULL; + m_pSamplerStateUI11 = NULL; + m_pDepthStencilStateStored11 = NULL; + m_pRasterizerStateStored11 = NULL; + m_pBlendStateStored11 = NULL; + m_pSamplerStateStored11 = NULL; + + m_pInputLayout11 = NULL; + m_pVBScreenQuad11 = NULL; + m_pSpriteBuffer11 = NULL; +} + + +//-------------------------------------------------------------------------------------- +CDXUTDialogResourceManager::~CDXUTDialogResourceManager() +{ + int i; + for( i = 0; i < m_FontCache.GetSize(); i++ ) + { + DXUTFontNode* pFontNode = m_FontCache.GetAt( i ); + SAFE_DELETE( pFontNode ); + } + m_FontCache.RemoveAll(); + + for( i = 0; i < m_TextureCache.GetSize(); i++ ) + { + DXUTTextureNode* pTextureNode = m_TextureCache.GetAt( i ); + SAFE_DELETE( pTextureNode ); + } + m_TextureCache.RemoveAll(); + + CUniBuffer::Uninitialize(); +} + + +//-------------------------------------------------------------------------------------- +HRESULT CDXUTDialogResourceManager::OnD3D9CreateDevice( LPDIRECT3DDEVICE9 pd3dDevice ) +{ + HRESULT hr = S_OK; + int i = 0; + + m_pd3d9Device = pd3dDevice; + + for( i = 0; i < m_FontCache.GetSize(); i++ ) + { + hr = CreateFont9( i ); + if( FAILED( hr ) ) + return hr; + } + + for( i = 0; i < m_TextureCache.GetSize(); i++ ) + { + hr = CreateTexture9( i ); + if( FAILED( hr ) ) + return hr; + } + + hr = D3DXCreateSprite( pd3dDevice, &m_pSprite ); + if( FAILED( hr ) ) + return DXUT_ERR( L"D3DXCreateSprite", hr ); + + return S_OK; +} + + +//-------------------------------------------------------------------------------------- +HRESULT CDXUTDialogResourceManager::OnD3D9ResetDevice() +{ + HRESULT hr = S_OK; + + for( int i = 0; i < m_FontCache.GetSize(); i++ ) + { + DXUTFontNode* pFontNode = m_FontCache.GetAt( i ); + + if( pFontNode->pFont9 ) + pFontNode->pFont9->OnResetDevice(); + } + + if( m_pSprite ) + m_pSprite->OnResetDevice(); + + V_RETURN( m_pd3d9Device->CreateStateBlock( D3DSBT_ALL, &m_pStateBlock ) ); + + return S_OK; +} + +//-------------------------------------------------------------------------------------- +bool CDXUTDialogResourceManager::MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) +{ + return false; +} + + +//-------------------------------------------------------------------------------------- +void CDXUTDialogResourceManager::OnD3D9LostDevice() +{ + for( int i = 0; i < m_FontCache.GetSize(); i++ ) + { + DXUTFontNode* pFontNode = m_FontCache.GetAt( i ); + + if( pFontNode->pFont9 ) + pFontNode->pFont9->OnLostDevice(); + } + + if( m_pSprite ) + m_pSprite->OnLostDevice(); + + SAFE_RELEASE( m_pStateBlock ); +} + + +//-------------------------------------------------------------------------------------- +void CDXUTDialogResourceManager::OnD3D9DestroyDevice() +{ + int i = 0; + + m_pd3d9Device = NULL; + + // Release the resources but don't clear the cache, as these will need to be + // recreated if the device is recreated + for( i = 0; i < m_FontCache.GetSize(); i++ ) + { + DXUTFontNode* pFontNode = m_FontCache.GetAt( i ); + SAFE_RELEASE( pFontNode->pFont9 ); + } + + for( i = 0; i < m_TextureCache.GetSize(); i++ ) + { + DXUTTextureNode* pTextureNode = m_TextureCache.GetAt( i ); + SAFE_RELEASE( pTextureNode->pTexture9 ); + } + + SAFE_RELEASE( m_pSprite ); +} + + + +HRESULT CDXUTDialogResourceManager::OnD3D11CreateDevice( ID3D11Device* pd3dDevice, ID3D11DeviceContext* pd3d11DeviceContext ) +{ + m_pd3d11Device = pd3dDevice; + m_pd3d11DeviceContext = pd3d11DeviceContext; + + HRESULT hr = S_OK; + + // Compile Shaders + ID3DBlob* pVSBlob = NULL; + ID3DBlob* pPSBlob = NULL; + ID3DBlob* pPSUntexBlob = NULL; + V_RETURN( D3DCompile( g_strUIEffectFile, g_uUIEffectFileSize, "none", NULL, NULL, "VS", "vs_4_0_level_9_1", + D3D10_SHADER_ENABLE_BACKWARDS_COMPATIBILITY, 0, &pVSBlob, NULL ) ); + V_RETURN( D3DCompile( g_strUIEffectFile, g_uUIEffectFileSize, "none", NULL, NULL, "PS", "ps_4_0_level_9_1", + D3D10_SHADER_ENABLE_BACKWARDS_COMPATIBILITY, 0, &pPSBlob, NULL ) ); + V_RETURN( D3DCompile( g_strUIEffectFile, g_uUIEffectFileSize, "none", NULL, NULL, "PSUntex", "ps_4_0_level_9_1", + D3D10_SHADER_ENABLE_BACKWARDS_COMPATIBILITY, 0, &pPSUntexBlob, NULL ) ); + + // Create Shaders + V_RETURN( pd3dDevice->CreateVertexShader( pVSBlob->GetBufferPointer(), pVSBlob->GetBufferSize(), NULL, &m_pVSRenderUI11 ) ); + DXUT_SetDebugName( m_pVSRenderUI11, "CDXUTDialogResourceManager" ); + + V_RETURN( pd3dDevice->CreatePixelShader( pPSBlob->GetBufferPointer(), pPSBlob->GetBufferSize(), NULL, &m_pPSRenderUI11 ) ); + DXUT_SetDebugName( m_pPSRenderUI11, "CDXUTDialogResourceManager" ); + + V_RETURN( pd3dDevice->CreatePixelShader( pPSUntexBlob->GetBufferPointer(), pPSUntexBlob->GetBufferSize(), NULL, &m_pPSRenderUIUntex11 ) ); + DXUT_SetDebugName( m_pPSRenderUIUntex11, "CDXUTDialogResourceManager" ); + + // States + D3D11_DEPTH_STENCIL_DESC DSDesc; + ZeroMemory( &DSDesc, sizeof( D3D11_DEPTH_STENCIL_DESC ) ); + DSDesc.DepthEnable = FALSE; + DSDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL; + DSDesc.DepthFunc = D3D11_COMPARISON_LESS; + DSDesc.StencilEnable = FALSE; + V_RETURN( pd3dDevice->CreateDepthStencilState( &DSDesc, &m_pDepthStencilStateUI11 ) ); + DXUT_SetDebugName( m_pDepthStencilStateUI11, "CDXUTDialogResourceManager" ); + + D3D11_RASTERIZER_DESC RSDesc; + RSDesc.AntialiasedLineEnable = FALSE; + RSDesc.CullMode = D3D11_CULL_BACK; + RSDesc.DepthBias = 0; + RSDesc.DepthBiasClamp = 0.0f; + RSDesc.DepthClipEnable = TRUE; + RSDesc.FillMode = D3D11_FILL_SOLID; + RSDesc.FrontCounterClockwise = FALSE; + RSDesc.MultisampleEnable = TRUE; + RSDesc.ScissorEnable = FALSE; + RSDesc.SlopeScaledDepthBias = 0.0f; + V_RETURN( pd3dDevice->CreateRasterizerState( &RSDesc, &m_pRasterizerStateUI11 ) ); + DXUT_SetDebugName( m_pRasterizerStateUI11, "CDXUTDialogResourceManager" ); + + D3D11_BLEND_DESC BSDesc; + ZeroMemory( &BSDesc, sizeof( D3D11_BLEND_DESC ) ); + + BSDesc.RenderTarget[0].BlendEnable = TRUE; + BSDesc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA; + BSDesc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA; + BSDesc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD; + BSDesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE; + BSDesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO; + BSDesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD; + BSDesc.RenderTarget[0].RenderTargetWriteMask = 0x0F; + + V_RETURN( pd3dDevice->CreateBlendState( &BSDesc, &m_pBlendStateUI11 ) ); + DXUT_SetDebugName( m_pBlendStateUI11, "CDXUTDialogResourceManager" ); + + D3D11_SAMPLER_DESC SSDesc; + ZeroMemory( &SSDesc, sizeof( D3D11_SAMPLER_DESC ) ); + SSDesc.Filter = D3D11_FILTER_ANISOTROPIC ; + SSDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP; + SSDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP; + SSDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP; + SSDesc.ComparisonFunc = D3D11_COMPARISON_NEVER; + SSDesc.MaxAnisotropy = 16; + SSDesc.MinLOD = 0; + SSDesc.MaxLOD = D3D11_FLOAT32_MAX; + if ( pd3dDevice->GetFeatureLevel() < D3D_FEATURE_LEVEL_9_3 ) { + SSDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR; + SSDesc.MaxAnisotropy = 0; + } + V_RETURN( pd3dDevice->CreateSamplerState( &SSDesc, &m_pSamplerStateUI11 ) ); + DXUT_SetDebugName( m_pSamplerStateUI11, "CDXUTDialogResourceManager" ); + + // Create the font and texture objects in the cache arrays. + int i = 0; + for( i = 0; i < m_FontCache.GetSize(); i++ ) + { + hr = CreateFont11( i ); + if( FAILED( hr ) ) + return hr; + } + + for( i = 0; i < m_TextureCache.GetSize(); i++ ) + { + hr = CreateTexture11( i ); + if( FAILED( hr ) ) + return hr; + } + + // Create input layout + const D3D11_INPUT_ELEMENT_DESC layout[] = + { + { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }, + { "COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 }, + { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 28, D3D11_INPUT_PER_VERTEX_DATA, 0 }, + }; + + V_RETURN( pd3dDevice->CreateInputLayout( layout, ARRAYSIZE( layout ), pVSBlob->GetBufferPointer(), pVSBlob->GetBufferSize(), &m_pInputLayout11 ) ); + DXUT_SetDebugName( m_pInputLayout11, "CDXUTDialogResourceManager" ); + + // Release the blobs + SAFE_RELEASE( pVSBlob ); + SAFE_RELEASE( pPSBlob ); + SAFE_RELEASE( pPSUntexBlob ); + + // Create a vertex buffer quad for rendering later + D3D11_BUFFER_DESC BufDesc; + BufDesc.ByteWidth = sizeof( DXUT_SCREEN_VERTEX_10 ) * 4; + BufDesc.Usage = D3D11_USAGE_DYNAMIC; + BufDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; + BufDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + BufDesc.MiscFlags = 0; + V_RETURN( pd3dDevice->CreateBuffer( &BufDesc, NULL, &m_pVBScreenQuad11 ) ); + DXUT_SetDebugName( m_pVBScreenQuad11, "CDXUTDialogResourceManager" ); + + // Init the D3D11 font + InitFont11( pd3dDevice, m_pInputLayout11 ); + + return S_OK; +} + + +//-------------------------------------------------------------------------------------- +HRESULT CDXUTDialogResourceManager::OnD3D11ResizedSwapChain( ID3D11Device* pd3dDevice, + const DXGI_SURFACE_DESC* pBackBufferSurfaceDesc ) +{ + HRESULT hr = S_OK; + + m_nBackBufferWidth = pBackBufferSurfaceDesc->Width; + m_nBackBufferHeight = pBackBufferSurfaceDesc->Height; + + return hr; +} + + +//-------------------------------------------------------------------------------------- +void CDXUTDialogResourceManager::OnD3D11ReleasingSwapChain() +{ +} + + +//-------------------------------------------------------------------------------------- +void CDXUTDialogResourceManager::OnD3D11DestroyDevice() +{ + int i; + + // Release the resources but don't clear the cache, as these will need to be + // recreated if the device is recreated + + for( i = 0; i < m_TextureCache.GetSize(); i++ ) + { + DXUTTextureNode* pTextureNode = m_TextureCache.GetAt( i ); + SAFE_RELEASE( pTextureNode->pTexResView11 ); + SAFE_RELEASE( pTextureNode->pTexture11 ); + } + + // D3D11 + SAFE_RELEASE( m_pVBScreenQuad11 ); + SAFE_RELEASE( m_pSpriteBuffer11 ); + m_SpriteBufferBytes11 = 0; + SAFE_RELEASE( m_pInputLayout11 ); + + // Shaders + SAFE_RELEASE( m_pVSRenderUI11 ); + SAFE_RELEASE( m_pPSRenderUI11 ); + SAFE_RELEASE( m_pPSRenderUIUntex11 ); + + // States + SAFE_RELEASE( m_pDepthStencilStateUI11 ); + SAFE_RELEASE( m_pRasterizerStateUI11 ); + SAFE_RELEASE( m_pBlendStateUI11 ); + SAFE_RELEASE( m_pSamplerStateUI11 ); + + SAFE_RELEASE( m_pDepthStencilStateStored11 ); + SAFE_RELEASE( m_pRasterizerStateStored11 ); + SAFE_RELEASE( m_pBlendStateStored11 ); + SAFE_RELEASE( m_pSamplerStateStored11 ); + + EndFont11(); +} + +//-------------------------------------------------------------------------------------- +void CDXUTDialogResourceManager::StoreD3D11State( ID3D11DeviceContext* pd3dImmediateContext ) +{ + pd3dImmediateContext->OMGetDepthStencilState( &m_pDepthStencilStateStored11, &m_StencilRefStored11 ); + pd3dImmediateContext->RSGetState( &m_pRasterizerStateStored11 ); + pd3dImmediateContext->OMGetBlendState( &m_pBlendStateStored11, m_BlendFactorStored11, &m_SampleMaskStored11 ); + pd3dImmediateContext->PSGetSamplers( 0, 1, &m_pSamplerStateStored11 ); +} + +//-------------------------------------------------------------------------------------- +void CDXUTDialogResourceManager::RestoreD3D11State( ID3D11DeviceContext* pd3dImmediateContext ) +{ + pd3dImmediateContext->OMSetDepthStencilState( m_pDepthStencilStateStored11, m_StencilRefStored11 ); + pd3dImmediateContext->RSSetState( m_pRasterizerStateStored11 ); + pd3dImmediateContext->OMSetBlendState( m_pBlendStateStored11, m_BlendFactorStored11, m_SampleMaskStored11 ); + pd3dImmediateContext->PSSetSamplers( 0, 1, &m_pSamplerStateStored11 ); + + SAFE_RELEASE( m_pDepthStencilStateStored11 ); + SAFE_RELEASE( m_pRasterizerStateStored11 ); + SAFE_RELEASE( m_pBlendStateStored11 ); + SAFE_RELEASE( m_pSamplerStateStored11 ); +} + +//-------------------------------------------------------------------------------------- +void CDXUTDialogResourceManager::ApplyRenderUI11( ID3D11DeviceContext* pd3dImmediateContext ) +{ + // Shaders + pd3dImmediateContext->VSSetShader( m_pVSRenderUI11, NULL, 0 ); + pd3dImmediateContext->HSSetShader( NULL, NULL, 0 ); + pd3dImmediateContext->DSSetShader( NULL, NULL, 0 ); + pd3dImmediateContext->GSSetShader( NULL, NULL, 0 ); + pd3dImmediateContext->PSSetShader( m_pPSRenderUI11, NULL, 0 ); + + // States + pd3dImmediateContext->OMSetDepthStencilState( m_pDepthStencilStateUI11, 0 ); + pd3dImmediateContext->RSSetState( m_pRasterizerStateUI11 ); + float BlendFactor[4] = { 0, 0, 0, 0 }; + pd3dImmediateContext->OMSetBlendState( m_pBlendStateUI11, BlendFactor, 0xFFFFFFFF ); + pd3dImmediateContext->PSSetSamplers( 0, 1, &m_pSamplerStateUI11 ); +} + +//-------------------------------------------------------------------------------------- +void CDXUTDialogResourceManager::ApplyRenderUIUntex11( ID3D11DeviceContext* pd3dImmediateContext ) +{ + // Shaders + pd3dImmediateContext->VSSetShader( m_pVSRenderUI11, NULL, 0 ); + pd3dImmediateContext->HSSetShader( NULL, NULL, 0 ); + pd3dImmediateContext->DSSetShader( NULL, NULL, 0 ); + pd3dImmediateContext->GSSetShader( NULL, NULL, 0 ); + pd3dImmediateContext->PSSetShader( m_pPSRenderUIUntex11, NULL, 0 ); + + // States + pd3dImmediateContext->OMSetDepthStencilState( m_pDepthStencilStateUI11, 0 ); + pd3dImmediateContext->RSSetState( m_pRasterizerStateUI11 ); + float BlendFactor[4] = { 0, 0, 0, 0 }; + pd3dImmediateContext->OMSetBlendState( m_pBlendStateUI11, BlendFactor, 0xFFFFFFFF ); + pd3dImmediateContext->PSSetSamplers( 0, 1, &m_pSamplerStateUI11 ); +} + +//-------------------------------------------------------------------------------------- +void CDXUTDialogResourceManager::BeginSprites11( ) +{ + m_SpriteVertices.Reset(); +} + +//-------------------------------------------------------------------------------------- +void CDXUTDialogResourceManager::EndSprites11( ID3D11Device* pd3dDevice, ID3D11DeviceContext* pd3dImmediateContext ) +{ + + // ensure our buffer size can hold our sprites + UINT SpriteDataBytes = m_SpriteVertices.GetSize() * sizeof( DXUTSpriteVertex ); + if( m_SpriteBufferBytes11 < SpriteDataBytes ) + { + SAFE_RELEASE( m_pSpriteBuffer11 ); + m_SpriteBufferBytes11 = SpriteDataBytes; + + D3D11_BUFFER_DESC BufferDesc; + BufferDesc.ByteWidth = m_SpriteBufferBytes11; + BufferDesc.Usage = D3D11_USAGE_DYNAMIC; + BufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; + BufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + BufferDesc.MiscFlags = 0; + + pd3dDevice->CreateBuffer( &BufferDesc, NULL, &m_pSpriteBuffer11 ); + DXUT_SetDebugName( m_pSpriteBuffer11, "CDXUTDialogResourceManager" ); + } + + // Copy the sprites over + D3D11_BOX destRegion; + destRegion.left = 0; + destRegion.right = SpriteDataBytes; + destRegion.top = 0; + destRegion.bottom = 1; + destRegion.front = 0; + destRegion.back = 1; + D3D11_MAPPED_SUBRESOURCE MappedResource; + if ( S_OK == pd3dImmediateContext->Map( m_pSpriteBuffer11, 0, D3D11_MAP_WRITE_DISCARD, 0, &MappedResource ) ) { + CopyMemory( MappedResource.pData, (void*)m_SpriteVertices.GetData(), SpriteDataBytes ); + pd3dImmediateContext->Unmap(m_pSpriteBuffer11, 0); + } + + // Draw + UINT Stride = sizeof( DXUTSpriteVertex ); + UINT Offset = 0; + pd3dImmediateContext->IASetVertexBuffers( 0, 1, &m_pSpriteBuffer11, &Stride, &Offset ); + pd3dImmediateContext->IASetInputLayout( m_pInputLayout11 ); + pd3dImmediateContext->IASetPrimitiveTopology( D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST ); + pd3dImmediateContext->Draw( m_SpriteVertices.GetSize(), 0 ); + + m_SpriteVertices.Reset(); +} + +//-------------------------------------------------------------------------------------- +bool CDXUTDialogResourceManager::RegisterDialog( CDXUTDialog* pDialog ) +{ + // Check that the dialog isn't already registered. + for( int i = 0; i < m_Dialogs.GetSize(); ++i ) + if( m_Dialogs.GetAt( i ) == pDialog ) + return true; + + // Add to the list. + if( FAILED( m_Dialogs.Add( pDialog ) ) ) + return false; + + // Set up next and prev pointers. + if( m_Dialogs.GetSize() > 1 ) + m_Dialogs[m_Dialogs.GetSize() - 2]->SetNextDialog( pDialog ); + m_Dialogs[m_Dialogs.GetSize() - 1]->SetNextDialog( m_Dialogs[0] ); + + return true; +} + + +//-------------------------------------------------------------------------------------- +void CDXUTDialogResourceManager::UnregisterDialog( CDXUTDialog* pDialog ) +{ + // Search for the dialog in the list. + for( int i = 0; i < m_Dialogs.GetSize(); ++i ) + if( m_Dialogs.GetAt( i ) == pDialog ) + { + m_Dialogs.Remove( i ); + if( m_Dialogs.GetSize() > 0 ) + { + int l, r; + + if( 0 == i ) + l = m_Dialogs.GetSize() - 1; + else + l = i - 1; + + if( m_Dialogs.GetSize() == i ) + r = 0; + else + r = i; + + m_Dialogs[l]->SetNextDialog( m_Dialogs[r] ); + } + return; + } +} + + +//-------------------------------------------------------------------------------------- +void CDXUTDialogResourceManager::EnableKeyboardInputForAllDialogs() +{ + // Enable keyboard input for all registered dialogs + for( int i = 0; i < m_Dialogs.GetSize(); ++i ) + m_Dialogs[i]->EnableKeyboardInput( true ); +} + + +//-------------------------------------------------------------------------------------- +void CDXUTDialog::Refresh() +{ + if( s_pControlFocus ) + s_pControlFocus->OnFocusOut(); + + if( m_pControlMouseOver ) + m_pControlMouseOver->OnMouseLeave(); + + s_pControlFocus = NULL; + s_pControlPressed = NULL; + m_pControlMouseOver = NULL; + + for( int i = 0; i < m_Controls.GetSize(); i++ ) + { + CDXUTControl* pControl = m_Controls.GetAt( i ); + pControl->Refresh(); + } + + if( m_bKeyboardInput ) + FocusDefaultControl(); +} + + +//-------------------------------------------------------------------------------------- +HRESULT CDXUTDialog::OnRender( float fElapsedTime ) +{ + if( m_pManager->GetD3D9Device() ) + return OnRender9( fElapsedTime ); + else + return OnRender11( fElapsedTime ); +} + + +//-------------------------------------------------------------------------------------- +HRESULT CDXUTDialog::OnRender9( float fElapsedTime ) +{ + // If this assert triggers, you need to call CDXUTDialogResourceManager::On*Device() from inside + // the application's device callbacks. See the SDK samples for an example of how to do this. + assert( m_pManager->GetD3D9Device() && m_pManager->m_pStateBlock && + L"To fix hook up CDXUTDialogResourceManager to device callbacks. See comments for details" ); + + // See if the dialog needs to be refreshed + if( m_fTimeLastRefresh < s_fTimeRefresh ) + { + m_fTimeLastRefresh = DXUTGetTime(); + Refresh(); + } + + // For invisible dialog, out now. + if( !m_bVisible || + ( m_bMinimized && !m_bCaption ) ) + return S_OK; + + IDirect3DDevice9* pd3dDevice = m_pManager->GetD3D9Device(); + + // Set up a state block here and restore it when finished drawing all the controls + m_pManager->m_pStateBlock->Capture(); + + //pd3dDevice->SetSamplerState(0, D3DSAMP_SRGBTEXTURE, TRUE); + //pd3dDevice->SetRenderState( D3DRS_SRGBWRITEENABLE, TRUE ); + + pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE ); + pd3dDevice->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_SRCALPHA ); + pd3dDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA ); + pd3dDevice->SetRenderState( D3DRS_ALPHATESTENABLE, FALSE ); + pd3dDevice->SetRenderState( D3DRS_SEPARATEALPHABLENDENABLE, FALSE ); + pd3dDevice->SetRenderState( D3DRS_BLENDOP, D3DBLENDOP_ADD ); + pd3dDevice->SetRenderState( D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_ALPHA | D3DCOLORWRITEENABLE_BLUE | + D3DCOLORWRITEENABLE_GREEN | D3DCOLORWRITEENABLE_RED ); + pd3dDevice->SetRenderState( D3DRS_SHADEMODE, D3DSHADE_GOURAUD ); + pd3dDevice->SetRenderState( D3DRS_FOGENABLE, FALSE ); + pd3dDevice->SetRenderState( D3DRS_ZWRITEENABLE, FALSE ); + pd3dDevice->SetRenderState( D3DRS_FILLMODE, D3DFILL_SOLID ); + pd3dDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_CCW ); + + pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_SELECTARG2 ); + pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE ); + pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1 ); + pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_DIFFUSE ); + pd3dDevice->SetTextureStageState( 0, D3DTSS_RESULTARG, D3DTA_CURRENT ); + pd3dDevice->SetTextureStageState( 1, D3DTSS_COLOROP, D3DTOP_DISABLE ); + pd3dDevice->SetTextureStageState( 1, D3DTSS_ALPHAOP, D3DTOP_DISABLE ); + + BOOL bBackgroundIsVisible = ( m_colorTopLeft | m_colorTopRight | m_colorBottomRight | m_colorBottomLeft ) & + 0xff000000; + if( !m_bMinimized && bBackgroundIsVisible ) + { + DXUT_SCREEN_VERTEX_UNTEX vertices[4] = + { + ( float )m_x, ( float )m_y, 0.5f, 1.0f, m_colorTopLeft, + ( float )m_x + m_width, ( float )m_y, 0.5f, 1.0f, m_colorTopRight, + ( float )m_x + m_width, ( float )m_y + m_height, 0.5f, 1.0f, m_colorBottomRight, + ( float )m_x, ( float )m_y + m_height, 0.5f, 1.0f, m_colorBottomLeft, + }; + + pd3dDevice->SetVertexShader( NULL ); + pd3dDevice->SetPixelShader( NULL ); + + pd3dDevice->SetRenderState( D3DRS_ZENABLE, FALSE ); + + pd3dDevice->SetFVF( DXUT_SCREEN_VERTEX_UNTEX::FVF ); + pd3dDevice->DrawPrimitiveUP( D3DPT_TRIANGLEFAN, 2, vertices, sizeof( DXUT_SCREEN_VERTEX_UNTEX ) ); + } + + pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_MODULATE ); + pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE ); + pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE ); + + pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE ); + pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE ); + pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE ); + + pd3dDevice->SetSamplerState( 0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR ); + + DXUTTextureNode* pTextureNode = GetTexture( 0 ); + pd3dDevice->SetTexture( 0, pTextureNode->pTexture9 ); + + m_pManager->m_pSprite->Begin( D3DXSPRITE_DONOTSAVESTATE ); + + // Render the caption if it's enabled. + if( m_bCaption ) + { + // DrawSprite will offset the rect down by + // m_nCaptionHeight, so adjust the rect higher + // here to negate the effect. + RECT rc = + { + 0, -m_nCaptionHeight, m_width, 0 + }; + DrawSprite9( &m_CapElement, &rc ); + rc.left += 5; // Make a left margin + WCHAR wszOutput[256]; + wcscpy_s( wszOutput, 256, m_wszCaption ); + if( m_bMinimized ) + wcscat_s( wszOutput, 256, L" (Minimized)" ); + DrawText9( wszOutput, &m_CapElement, &rc, true ); + } + + // If the dialog is minimized, skip rendering + // its controls. + if( !m_bMinimized ) + { + for( int i = 0; i < m_Controls.GetSize(); i++ ) + { + CDXUTControl* pControl = m_Controls.GetAt( i ); + + // Focused control is drawn last + if( pControl == s_pControlFocus ) + continue; + + pControl->Render( fElapsedTime ); + } + + if( s_pControlFocus != NULL && s_pControlFocus->m_pDialog == this ) + s_pControlFocus->Render( fElapsedTime ); + } + + m_pManager->m_pSprite->End(); + + m_pManager->m_pStateBlock->Apply(); + + return S_OK; +} + + + +//-------------------------------------------------------------------------------------- +HRESULT CDXUTDialog::OnRender11( float fElapsedTime ) +{ + // If this assert triggers, you need to call CDXUTDialogResourceManager::On*Device() from inside + // the application's device callbacks. See the SDK samples for an example of how to do this. + assert( m_pManager->GetD3D11Device() && + L"To fix hook up CDXUTDialogResourceManager to device callbacks. See comments for details" ); + + // See if the dialog needs to be refreshed + if( m_fTimeLastRefresh < s_fTimeRefresh ) + { + m_fTimeLastRefresh = DXUTGetTime(); + Refresh(); + } + + // For invisible dialog, out now. + if( !m_bVisible || + ( m_bMinimized && !m_bCaption ) ) + return S_OK; + + ID3D11Device* pd3dDevice = m_pManager->GetD3D11Device(); + ID3D11DeviceContext* pd3dDeviceContext = m_pManager->GetD3D11DeviceContext(); + + // Set up a state block here and restore it when finished drawing all the controls + m_pManager->StoreD3D11State( pd3dDeviceContext ); + + BOOL bBackgroundIsVisible = ( m_colorTopLeft | m_colorTopRight | m_colorBottomRight | m_colorBottomLeft ) & + 0xff000000; + if( !m_bMinimized && bBackgroundIsVisible ) + { + // Convert the draw rectangle from screen coordinates to clip space coordinates. + float Left, Right, Top, Bottom; + Left = m_x * 2.0f / m_pManager->m_nBackBufferWidth - 1.0f; + Right = ( m_x + m_width ) * 2.0f / m_pManager->m_nBackBufferWidth - 1.0f; + Top = 1.0f - m_y * 2.0f / m_pManager->m_nBackBufferHeight; + Bottom = 1.0f - ( m_y + m_height ) * 2.0f / m_pManager->m_nBackBufferHeight; + + DXUT_SCREEN_VERTEX_10 vertices[4] = + { + Left, Top, 0.5f, D3DCOLOR_TO_D3DCOLORVALUE( m_colorTopLeft ), 0.0f, 0.0f, + Right, Top, 0.5f, D3DCOLOR_TO_D3DCOLORVALUE( m_colorTopRight ), 1.0f, 0.0f, + Left, Bottom, 0.5f, D3DCOLOR_TO_D3DCOLORVALUE( m_colorBottomLeft ), 0.0f, 1.0f, + Right, Bottom, 0.5f, D3DCOLOR_TO_D3DCOLORVALUE( m_colorBottomRight ), 1.0f, 1.0f, + }; + + //DXUT_SCREEN_VERTEX_10 *pVB; + D3D11_MAPPED_SUBRESOURCE MappedData; + if( SUCCEEDED( pd3dDeviceContext->Map( m_pManager->m_pVBScreenQuad11, 0, D3D11_MAP_WRITE_DISCARD, + 0, &MappedData ) ) ) + { + CopyMemory( MappedData.pData, vertices, sizeof( vertices ) ); + pd3dDeviceContext->Unmap( m_pManager->m_pVBScreenQuad11, 0 ); + } + + // Set the quad VB as current + UINT stride = sizeof( DXUT_SCREEN_VERTEX_10 ); + UINT offset = 0; + pd3dDeviceContext->IASetVertexBuffers( 0, 1, &m_pManager->m_pVBScreenQuad11, &stride, &offset ); + pd3dDeviceContext->IASetInputLayout( m_pManager->m_pInputLayout11 ); + pd3dDeviceContext->IASetPrimitiveTopology( D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP ); + + // Setup for rendering + m_pManager->ApplyRenderUIUntex11( pd3dDeviceContext ); + pd3dDeviceContext->Draw( 4, 0 ); + } + + DXUTTextureNode* pTextureNode = GetTexture( 0 ); + pd3dDeviceContext->PSSetShaderResources( 0, 1, &pTextureNode->pTexResView11 ); + + // Sort depth back to front + m_pManager->BeginSprites11(); + BeginText11(); + + m_pManager->ApplyRenderUI11( pd3dDeviceContext ); + + // Render the caption if it's enabled. + if( m_bCaption ) + { + // DrawSprite will offset the rect down by + // m_nCaptionHeight, so adjust the rect higher + // here to negate the effect. + RECT rc = { 0, -m_nCaptionHeight, m_width, 0 }; + DrawSprite11( &m_CapElement, &rc, 0.99f ); + rc.left += 5; // Make a left margin + WCHAR wszOutput[256]; + wcscpy_s( wszOutput, 256, m_wszCaption ); + if( m_bMinimized ) + wcscat_s( wszOutput, 256, L" (Minimized)" ); + DrawText11( pd3dDevice, pd3dDeviceContext, wszOutput, &m_CapElement, &rc, true ); + } + + // If the dialog is minimized, skip rendering + // its controls. + if( !m_bMinimized ) + { + for( int i = 0; i < m_Controls.GetSize(); i++ ) + { + CDXUTControl* pControl = m_Controls.GetAt( i ); + + // Focused control is drawn last + if( pControl == s_pControlFocus ) + continue; + + pControl->Render( fElapsedTime ); + } + + if( s_pControlFocus != NULL && s_pControlFocus->m_pDialog == this ) + s_pControlFocus->Render( fElapsedTime ); + } + + // End sprites + if( m_bCaption ) + { + m_pManager->EndSprites11( pd3dDevice, pd3dDeviceContext ); + EndText11( pd3dDevice, pd3dDeviceContext ); + } + m_pManager->RestoreD3D11State( pd3dDeviceContext ); + + return S_OK; +} + +//-------------------------------------------------------------------------------------- +VOID CDXUTDialog::SendEvent( UINT nEvent, bool bTriggeredByUser, CDXUTControl* pControl ) +{ + // If no callback has been registered there's nowhere to send the event to + if( m_pCallbackEvent == NULL ) + return; + + // Discard events triggered programatically if these types of events haven't been + // enabled + if( !bTriggeredByUser && !m_bNonUserEvents ) + return; + + m_pCallbackEvent( nEvent, pControl->GetID(), pControl, m_pCallbackEventUserContext ); +} + + +//-------------------------------------------------------------------------------------- +int CDXUTDialogResourceManager::AddFont( LPCWSTR strFaceName, LONG height, LONG weight ) +{ + // See if this font already exists + for( int i = 0; i < m_FontCache.GetSize(); i++ ) + { + DXUTFontNode* pFontNode = m_FontCache.GetAt( i ); + size_t nLen = 0; + nLen = wcsnlen( strFaceName, MAX_PATH); + if( 0 == _wcsnicmp( pFontNode->strFace, strFaceName, nLen ) && + pFontNode->nHeight == height && + pFontNode->nWeight == weight ) + { + return i; + } + } + + // Add a new font and try to create it + DXUTFontNode* pNewFontNode = new DXUTFontNode; + if( pNewFontNode == NULL ) + return -1; + + ZeroMemory( pNewFontNode, sizeof( DXUTFontNode ) ); + wcscpy_s( pNewFontNode->strFace, MAX_PATH, strFaceName ); + pNewFontNode->nHeight = height; + pNewFontNode->nWeight = weight; + m_FontCache.Add( pNewFontNode ); + + int iFont = m_FontCache.GetSize() - 1; + + // If a device is available, try to create immediately + if( m_pd3d9Device ) + CreateFont9( iFont ); + + return iFont; +} + + +//-------------------------------------------------------------------------------------- +HRESULT CDXUTDialog::SetFont( UINT index, LPCWSTR strFaceName, LONG height, LONG weight ) +{ + // If this assert triggers, you need to call CDXUTDialog::Init() first. This change + // was made so that the DXUT's GUI could become seperate and optional from DXUT's core. The + // creation and interfacing with CDXUTDialogResourceManager is now the responsibility + // of the application if it wishes to use DXUT's GUI. + assert( m_pManager != NULL && L"To fix call CDXUTDialog::Init() first. See comments for details." ); + + // Make sure the list is at least as large as the index being set + UINT i; + for( i = m_Fonts.GetSize(); i <= index; i++ ) + { + m_Fonts.Add( -1 ); + } + + int iFont = m_pManager->AddFont( strFaceName, height, weight ); + m_Fonts.SetAt( index, iFont ); + + return S_OK; +} + + +//-------------------------------------------------------------------------------------- +DXUTFontNode* CDXUTDialog::GetFont( UINT index ) +{ + if( NULL == m_pManager ) + return NULL; + return m_pManager->GetFontNode( m_Fonts.GetAt( index ) ); +} + + +//-------------------------------------------------------------------------------------- +int CDXUTDialogResourceManager::AddTexture( LPCWSTR strFilename ) +{ + // See if this texture already exists + for( int i = 0; i < m_TextureCache.GetSize(); i++ ) + { + DXUTTextureNode* pTextureNode = m_TextureCache.GetAt( i ); + size_t nLen = 0; + nLen = wcsnlen( strFilename, MAX_PATH); + if( pTextureNode->bFileSource && // Sources must match + 0 == _wcsnicmp( pTextureNode->strFilename, strFilename, nLen ) ) + { + return i; + } + } + + // Add a new texture and try to create it + DXUTTextureNode* pNewTextureNode = new DXUTTextureNode; + if( pNewTextureNode == NULL ) + return -1; + + ZeroMemory( pNewTextureNode, sizeof( DXUTTextureNode ) ); + pNewTextureNode->bFileSource = true; + wcscpy_s( pNewTextureNode->strFilename, MAX_PATH, strFilename ); + + m_TextureCache.Add( pNewTextureNode ); + + int iTexture = m_TextureCache.GetSize() - 1; + + // If a device is available, try to create immediately + if( m_pd3d9Device ) + CreateTexture9( iTexture ); + + return iTexture; +} + + +//-------------------------------------------------------------------------------------- +int CDXUTDialogResourceManager::AddTexture( LPCWSTR strResourceName, HMODULE hResourceModule ) +{ + // See if this texture already exists + for( int i = 0; i < m_TextureCache.GetSize(); i++ ) + { + DXUTTextureNode* pTextureNode = m_TextureCache.GetAt( i ); + if( !pTextureNode->bFileSource && // Sources must match + pTextureNode->hResourceModule == hResourceModule ) // Module handles must match + { + if( IS_INTRESOURCE( strResourceName ) ) + { + // Integer-based ID + if( ( INT_PTR )strResourceName == pTextureNode->nResourceID ) + return i; + } + else + { + // String-based ID + size_t nLen = 0; + nLen = wcsnlen ( strResourceName, MAX_PATH ); + if( 0 == _wcsnicmp( pTextureNode->strFilename, strResourceName, nLen ) ) + return i; + } + } + } + + // Add a new texture and try to create it + DXUTTextureNode* pNewTextureNode = new DXUTTextureNode; + if( pNewTextureNode == NULL ) + return -1; + + ZeroMemory( pNewTextureNode, sizeof( DXUTTextureNode ) ); + pNewTextureNode->hResourceModule = hResourceModule; + if( IS_INTRESOURCE( strResourceName ) ) + { + pNewTextureNode->nResourceID = ( int )( size_t )strResourceName; + } + else + { + pNewTextureNode->nResourceID = 0; + wcscpy_s( pNewTextureNode->strFilename, MAX_PATH, strResourceName ); + } + + m_TextureCache.Add( pNewTextureNode ); + + int iTexture = m_TextureCache.GetSize() - 1; + + // If a device is available, try to create immediately + if( m_pd3d9Device ) + CreateTexture9( iTexture ); + + return iTexture; +} + + +//-------------------------------------------------------------------------------------- +HRESULT CDXUTDialog::SetTexture( UINT index, LPCWSTR strFilename ) +{ + // If this assert triggers, you need to call CDXUTDialog::Init() first. This change + // was made so that the DXUT's GUI could become seperate and optional from DXUT's core. The + // creation and interfacing with CDXUTDialogResourceManager is now the responsibility + // of the application if it wishes to use DXUT's GUI. + assert( m_pManager != NULL && L"To fix this, call CDXUTDialog::Init() first. See comments for details." ); + + // Make sure the list is at least as large as the index being set + for( UINT i = m_Textures.GetSize(); i <= index; i++ ) + { + m_Textures.Add( -1 ); + } + + int iTexture = m_pManager->AddTexture( strFilename ); + + m_Textures.SetAt( index, iTexture ); + return S_OK; +} + + +//-------------------------------------------------------------------------------------- +HRESULT CDXUTDialog::SetTexture( UINT index, LPCWSTR strResourceName, HMODULE hResourceModule ) +{ + // If this assert triggers, you need to call CDXUTDialog::Init() first. This change + // was made so that the DXUT's GUI could become seperate and optional from DXUT's core. The + // creation and interfacing with CDXUTDialogResourceManager is now the responsibility + // of the application if it wishes to use DXUT's GUI. + assert( m_pManager != NULL && L"To fix this, call CDXUTDialog::Init() first. See comments for details." ); + + // Make sure the list is at least as large as the index being set + for( UINT i = m_Textures.GetSize(); i <= index; i++ ) + { + m_Textures.Add( -1 ); + } + + int iTexture = m_pManager->AddTexture( strResourceName, hResourceModule ); + + m_Textures.SetAt( index, iTexture ); + return S_OK; +} + + +//-------------------------------------------------------------------------------------- +DXUTTextureNode* CDXUTDialog::GetTexture( UINT index ) +{ + if( NULL == m_pManager ) + return NULL; + return m_pManager->GetTextureNode( m_Textures.GetAt( index ) ); +} + + + +//-------------------------------------------------------------------------------------- +bool CDXUTDialog::MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) +{ + bool bHandled = false; + + // For invisible dialog, do not handle anything. + if( !m_bVisible ) + return false; + + // If automation command-line switch is on, enable this dialog's keyboard input + // upon any key press or mouse click. + if( DXUTGetAutomation() && + ( WM_LBUTTONDOWN == uMsg || WM_LBUTTONDBLCLK == uMsg || WM_KEYDOWN == uMsg ) ) + { + m_pManager->EnableKeyboardInputForAllDialogs(); + } + + // If caption is enable, check for clicks in the caption area. + if( m_bCaption ) + { + if( uMsg == WM_LBUTTONDOWN || uMsg == WM_LBUTTONDBLCLK ) + { + POINT mousePoint = + { + short( LOWORD( lParam ) ), short( HIWORD( lParam ) ) + }; + + if( mousePoint.x >= m_x && mousePoint.x < m_x + m_width && + mousePoint.y >= m_y && mousePoint.y < m_y + m_nCaptionHeight ) + { + m_bDrag = true; + SetCapture( DXUTGetHWND() ); + return true; + } + } + else if( uMsg == WM_LBUTTONUP && m_bDrag ) + { + POINT mousePoint = + { + short( LOWORD( lParam ) ), short( HIWORD( lParam ) ) + }; + + if( mousePoint.x >= m_x && mousePoint.x < m_x + m_width && + mousePoint.y >= m_y && mousePoint.y < m_y + m_nCaptionHeight ) + { + ReleaseCapture(); + m_bDrag = false; + m_bMinimized = !m_bMinimized; + return true; + } + } + } + + // If the dialog is minimized, don't send any messages to controls. + if( m_bMinimized ) + return false; + + // If a control is in focus, it belongs to this dialog, and it's enabled, then give + // it the first chance at handling the message. + if( s_pControlFocus && + s_pControlFocus->m_pDialog == this && + s_pControlFocus->GetEnabled() ) + { + // If the control MsgProc handles it, then we don't. + if( s_pControlFocus->MsgProc( uMsg, wParam, lParam ) ) + return true; + } + + switch( uMsg ) + { + case WM_SIZE: + case WM_MOVE: + { + // Handle sizing and moving messages so that in case the mouse cursor is moved out + // of an UI control because of the window adjustment, we can properly + // unhighlight the highlighted control. + POINT pt = + { + -1, -1 + }; + OnMouseMove( pt ); + break; + } + + case WM_ACTIVATEAPP: + // Call OnFocusIn()/OnFocusOut() of the control that currently has the focus + // as the application is activated/deactivated. This matches the Windows + // behavior. + if( s_pControlFocus && + s_pControlFocus->m_pDialog == this && + s_pControlFocus->GetEnabled() ) + { + if( wParam ) + s_pControlFocus->OnFocusIn(); + else + s_pControlFocus->OnFocusOut(); + } + break; + + // Keyboard messages + case WM_KEYDOWN: + case WM_SYSKEYDOWN: + case WM_KEYUP: + case WM_SYSKEYUP: + { + // If a control is in focus, it belongs to this dialog, and it's enabled, then give + // it the first chance at handling the message. + if( s_pControlFocus && + s_pControlFocus->m_pDialog == this && + s_pControlFocus->GetEnabled() ) + { + if( s_pControlFocus->HandleKeyboard( uMsg, wParam, lParam ) ) + return true; + } + + // Not yet handled, see if this matches a control's hotkey + // Activate the hotkey if the focus doesn't belong to an + // edit box. + if( uMsg == WM_KEYDOWN && ( !s_pControlFocus || + ( s_pControlFocus->GetType() != DXUT_CONTROL_EDITBOX + && s_pControlFocus->GetType() != DXUT_CONTROL_IMEEDITBOX ) ) ) + { + for( int i = 0; i < m_Controls.GetSize(); i++ ) + { + CDXUTControl* pControl = m_Controls.GetAt( i ); + if( pControl->GetHotkey() == wParam ) + { + pControl->OnHotkey(); + return true; + } + } + } + + // Not yet handled, check for focus messages + if( uMsg == WM_KEYDOWN ) + { + // If keyboard input is not enabled, this message should be ignored + if( !m_bKeyboardInput ) + return false; + + switch( wParam ) + { + case VK_RIGHT: + case VK_DOWN: + if( s_pControlFocus != NULL ) + { + return OnCycleFocus( true ); + } + break; + + case VK_LEFT: + case VK_UP: + if( s_pControlFocus != NULL ) + { + return OnCycleFocus( false ); + } + break; + + case VK_TAB: + { + bool bShiftDown = ( ( GetKeyState( VK_SHIFT ) & 0x8000 ) != 0 ); + return OnCycleFocus( !bShiftDown ); + } + } + } + + break; + } + + + // Mouse messages + case WM_MOUSEMOVE: + case WM_LBUTTONDOWN: + case WM_LBUTTONUP: + case WM_MBUTTONDOWN: + case WM_MBUTTONUP: + case WM_RBUTTONDOWN: + case WM_RBUTTONUP: + case WM_XBUTTONDOWN: + case WM_XBUTTONUP: + case WM_LBUTTONDBLCLK: + case WM_MBUTTONDBLCLK: + case WM_RBUTTONDBLCLK: + case WM_XBUTTONDBLCLK: + case WM_MOUSEWHEEL: + { + // If not accepting mouse input, return false to indicate the message should still + // be handled by the application (usually to move the camera). + if( !m_bMouseInput ) + return false; + + POINT mousePoint = + { + short( LOWORD( lParam ) ), short( HIWORD( lParam ) ) + }; + mousePoint.x -= m_x; + mousePoint.y -= m_y; + + // If caption is enabled, offset the Y coordinate by the negative of its height. + if( m_bCaption ) + mousePoint.y -= m_nCaptionHeight; + + // If a control is in focus, it belongs to this dialog, and it's enabled, then give + // it the first chance at handling the message. + if( s_pControlFocus && + s_pControlFocus->m_pDialog == this && + s_pControlFocus->GetEnabled() ) + { + if( s_pControlFocus->HandleMouse( uMsg, mousePoint, wParam, lParam ) ) + return true; + } + + // Not yet handled, see if the mouse is over any controls + CDXUTControl* pControl = GetControlAtPoint( mousePoint ); + if( pControl != NULL && pControl->GetEnabled() ) + { + bHandled = pControl->HandleMouse( uMsg, mousePoint, wParam, lParam ); + if( bHandled ) + return true; + } + else + { + // Mouse not over any controls in this dialog, if there was a control + // which had focus it just lost it + if( uMsg == WM_LBUTTONDOWN && + s_pControlFocus && + s_pControlFocus->m_pDialog == this ) + { + s_pControlFocus->OnFocusOut(); + s_pControlFocus = NULL; + } + } + + // Still not handled, hand this off to the dialog. Return false to indicate the + // message should still be handled by the application (usually to move the camera). + switch( uMsg ) + { + case WM_MOUSEMOVE: + OnMouseMove( mousePoint ); + return false; + } + + break; + } + + case WM_CAPTURECHANGED: + { + // The application has lost mouse capture. + // The dialog object may not have received + // a WM_MOUSEUP when capture changed. Reset + // m_bDrag so that the dialog does not mistakenly + // think the mouse button is still held down. + if( ( HWND )lParam != hWnd ) + m_bDrag = false; + } + } + + return false; +} + +//-------------------------------------------------------------------------------------- +CDXUTControl* CDXUTDialog::GetControlAtPoint( POINT pt ) +{ + // Search through all child controls for the first one which + // contains the mouse point + for( int i = 0; i < m_Controls.GetSize(); i++ ) + { + CDXUTControl* pControl = m_Controls.GetAt( i ); + + if( pControl == NULL ) + { + continue; + } + + // We only return the current control if it is visible + // and enabled. Because GetControlAtPoint() is used to do mouse + // hittest, it makes sense to perform this filtering. + if( pControl->ContainsPoint( pt ) && pControl->GetEnabled() && pControl->GetVisible() ) + { + return pControl; + } + } + + return NULL; +} + + +//-------------------------------------------------------------------------------------- +bool CDXUTDialog::GetControlEnabled( int ID ) +{ + CDXUTControl* pControl = GetControl( ID ); + if( pControl == NULL ) + return false; + + return pControl->GetEnabled(); +} + + + +//-------------------------------------------------------------------------------------- +void CDXUTDialog::SetControlEnabled( int ID, bool bEnabled ) +{ + CDXUTControl* pControl = GetControl( ID ); + if( pControl == NULL ) + return; + + pControl->SetEnabled( bEnabled ); +} + + +//-------------------------------------------------------------------------------------- +void CDXUTDialog::OnMouseUp( POINT pt ) +{ + s_pControlPressed = NULL; + m_pControlMouseOver = NULL; +} + + +//-------------------------------------------------------------------------------------- +void CDXUTDialog::OnMouseMove( POINT pt ) +{ + // Figure out which control the mouse is over now + CDXUTControl* pControl = GetControlAtPoint( pt ); + + // If the mouse is still over the same control, nothing needs to be done + if( pControl == m_pControlMouseOver ) + return; + + // Handle mouse leaving the old control + if( m_pControlMouseOver ) + m_pControlMouseOver->OnMouseLeave(); + + // Handle mouse entering the new control + m_pControlMouseOver = pControl; + if( pControl != NULL ) + m_pControlMouseOver->OnMouseEnter(); +} + + +//-------------------------------------------------------------------------------------- +HRESULT CDXUTDialog::SetDefaultElement( UINT nControlType, UINT iElement, CDXUTElement* pElement ) +{ + // If this Element type already exist in the list, simply update the stored Element + for( int i = 0; i < m_DefaultElements.GetSize(); i++ ) + { + DXUTElementHolder* pElementHolder = m_DefaultElements.GetAt( i ); + + if( pElementHolder->nControlType == nControlType && + pElementHolder->iElement == iElement ) + { + pElementHolder->Element = *pElement; + return S_OK; + } + } + + // Otherwise, add a new entry + DXUTElementHolder* pNewHolder; + pNewHolder = new DXUTElementHolder; + if( pNewHolder == NULL ) + return E_OUTOFMEMORY; + + pNewHolder->nControlType = nControlType; + pNewHolder->iElement = iElement; + pNewHolder->Element = *pElement; + + HRESULT hr = m_DefaultElements.Add( pNewHolder ); + if( FAILED( hr ) ) + { + delete pNewHolder; + } + return hr; +} + + +//-------------------------------------------------------------------------------------- +CDXUTElement* CDXUTDialog::GetDefaultElement( UINT nControlType, UINT iElement ) +{ + for( int i = 0; i < m_DefaultElements.GetSize(); i++ ) + { + DXUTElementHolder* pElementHolder = m_DefaultElements.GetAt( i ); + + if( pElementHolder->nControlType == nControlType && + pElementHolder->iElement == iElement ) + { + return &pElementHolder->Element; + } + } + + return NULL; +} + + + +//-------------------------------------------------------------------------------------- +HRESULT CDXUTDialog::AddStatic( int ID, LPCWSTR strText, int x, int y, int width, int height, bool bIsDefault, + CDXUTStatic** ppCreated ) +{ + HRESULT hr = S_OK; + + CDXUTStatic* pStatic = new CDXUTStatic( this ); + + if( ppCreated != NULL ) + *ppCreated = pStatic; + + if( pStatic == NULL ) + return E_OUTOFMEMORY; + + hr = AddControl( pStatic ); + if( FAILED( hr ) ) + return hr; + + // Set the ID and list index + pStatic->SetID( ID ); + pStatic->SetText( strText ); + pStatic->SetLocation( x, y ); + pStatic->SetSize( width, height ); + pStatic->m_bIsDefault = bIsDefault; + + return S_OK; +} + + +//-------------------------------------------------------------------------------------- +HRESULT CDXUTDialog::AddButton( int ID, LPCWSTR strText, int x, int y, int width, int height, UINT nHotkey, + bool bIsDefault, CDXUTButton** ppCreated ) +{ + HRESULT hr = S_OK; + + CDXUTButton* pButton = new CDXUTButton( this ); + + if( ppCreated != NULL ) + *ppCreated = pButton; + + if( pButton == NULL ) + return E_OUTOFMEMORY; + + hr = AddControl( pButton ); + if( FAILED( hr ) ) + return hr; + + // Set the ID and list index + pButton->SetID( ID ); + pButton->SetText( strText ); + pButton->SetLocation( x, y ); + pButton->SetSize( width, height ); + pButton->SetHotkey( nHotkey ); + pButton->m_bIsDefault = bIsDefault; + + return S_OK; +} + +HRESULT CDXUTDialog::AddButtonCallback(std::function<void()> cb, LPCWSTR strText, int x, int y, int width, int height, UINT nHotkey, + bool bIsDefault, CDXUTButton** ppCreated) +{ + HRESULT hr = S_OK; + + CDXUTButton* pButton = new CDXUTButton(this); + + if (ppCreated != NULL) + *ppCreated = pButton; + + if (pButton == NULL) + return E_OUTOFMEMORY; + + hr = AddControl(pButton); + if (FAILED(hr)) + return hr; + + // Set the ID and list index + pButton->SetID(-1); + pButton->SetText(strText); + pButton->SetLocation(x, y); + pButton->SetSize(width, height); + pButton->SetHotkey(nHotkey); + pButton->m_bIsDefault = bIsDefault; + pButton->SetUserData(new std::function<void()>(cb)); + + return S_OK; +} + +//-------------------------------------------------------------------------------------- +HRESULT CDXUTDialog::AddCheckBox( int ID, LPCWSTR strText, int x, int y, int width, int height, bool bChecked, + UINT nHotkey, bool bIsDefault, CDXUTCheckBox** ppCreated ) +{ + HRESULT hr = S_OK; + + CDXUTCheckBox* pCheckBox = new CDXUTCheckBox( this ); + + if( ppCreated != NULL ) + *ppCreated = pCheckBox; + + if( pCheckBox == NULL ) + return E_OUTOFMEMORY; + + hr = AddControl( pCheckBox ); + if( FAILED( hr ) ) + return hr; + + // Set the ID and list index + pCheckBox->SetID( ID ); + pCheckBox->SetText( strText ); + pCheckBox->SetLocation( x, y ); + pCheckBox->SetSize( width, height ); + pCheckBox->SetHotkey( nHotkey ); + pCheckBox->m_bIsDefault = bIsDefault; + pCheckBox->SetChecked( bChecked ); + + return S_OK; +} + + + +//-------------------------------------------------------------------------------------- +HRESULT CDXUTDialog::AddRadioButton( int ID, UINT nButtonGroup, LPCWSTR strText, int x, int y, int width, int height, + bool bChecked, UINT nHotkey, bool bIsDefault, CDXUTRadioButton** ppCreated ) +{ + HRESULT hr = S_OK; + + CDXUTRadioButton* pRadioButton = new CDXUTRadioButton( this ); + + if( ppCreated != NULL ) + *ppCreated = pRadioButton; + + if( pRadioButton == NULL ) + return E_OUTOFMEMORY; + + hr = AddControl( pRadioButton ); + if( FAILED( hr ) ) + return hr; + + // Set the ID and list index + pRadioButton->SetID( ID ); + pRadioButton->SetText( strText ); + pRadioButton->SetButtonGroup( nButtonGroup ); + pRadioButton->SetLocation( x, y ); + pRadioButton->SetSize( width, height ); + pRadioButton->SetHotkey( nHotkey ); + pRadioButton->SetChecked( bChecked ); + pRadioButton->m_bIsDefault = bIsDefault; + pRadioButton->SetChecked( bChecked ); + + return S_OK; +} + + + + +//-------------------------------------------------------------------------------------- +HRESULT CDXUTDialog::AddComboBox( int ID, int x, int y, int width, int height, UINT nHotkey, bool bIsDefault, + CDXUTComboBox** ppCreated ) +{ + HRESULT hr = S_OK; + + CDXUTComboBox* pComboBox = new CDXUTComboBox( this ); + + if( ppCreated != NULL ) + *ppCreated = pComboBox; + + if( pComboBox == NULL ) + return E_OUTOFMEMORY; + + hr = AddControl( pComboBox ); + if( FAILED( hr ) ) + return hr; + + // Set the ID and list index + pComboBox->SetID( ID ); + pComboBox->SetLocation( x, y ); + pComboBox->SetSize( width, height ); + pComboBox->SetHotkey( nHotkey ); + pComboBox->m_bIsDefault = bIsDefault; + + return S_OK; +} + + + +//-------------------------------------------------------------------------------------- +HRESULT CDXUTDialog::AddSlider( int ID, int x, int y, int width, int height, int min, int max, int value, + bool bIsDefault, CDXUTSlider** ppCreated ) +{ + HRESULT hr = S_OK; + + CDXUTSlider* pSlider = new CDXUTSlider( this ); + + if( ppCreated != NULL ) + *ppCreated = pSlider; + + if( pSlider == NULL ) + return E_OUTOFMEMORY; + + hr = AddControl( pSlider ); + if( FAILED( hr ) ) + return hr; + + // Set the ID and list index + pSlider->SetID( ID ); + pSlider->SetLocation( x, y ); + pSlider->SetSize( width, height ); + pSlider->m_bIsDefault = bIsDefault; + pSlider->SetRange( min, max ); + pSlider->SetValue( value ); + pSlider->UpdateRects(); + + return S_OK; +} + + + +//-------------------------------------------------------------------------------------- +HRESULT CDXUTDialog::AddEditBox( int ID, LPCWSTR strText, int x, int y, int width, int height, bool bIsDefault, + CDXUTEditBox** ppCreated ) +{ + HRESULT hr = S_OK; + + CDXUTEditBox* pEditBox = new CDXUTEditBox( this ); + + if( ppCreated != NULL ) + *ppCreated = pEditBox; + + if( pEditBox == NULL ) + return E_OUTOFMEMORY; + + hr = AddControl( pEditBox ); + if( FAILED( hr ) ) + return hr; + + // Set the ID and position + pEditBox->SetID( ID ); + pEditBox->SetLocation( x, y ); + pEditBox->SetSize( width, height ); + pEditBox->m_bIsDefault = bIsDefault; + + if( strText ) + pEditBox->SetText( strText ); + + return S_OK; +} + + +//-------------------------------------------------------------------------------------- +HRESULT CDXUTDialog::AddListBox( int ID, int x, int y, int width, int height, DWORD dwStyle, CDXUTListBox** ppCreated ) +{ + HRESULT hr = S_OK; + CDXUTListBox* pListBox = new CDXUTListBox( this ); + + if( ppCreated != NULL ) + *ppCreated = pListBox; + + if( pListBox == NULL ) + return E_OUTOFMEMORY; + + hr = AddControl( pListBox ); + if( FAILED( hr ) ) + return hr; + + // Set the ID and position + pListBox->SetID( ID ); + pListBox->SetLocation( x, y ); + pListBox->SetSize( width, height ); + pListBox->SetStyle( dwStyle ); + + return S_OK; +} + + + +//-------------------------------------------------------------------------------------- +HRESULT CDXUTDialog::InitControl( CDXUTControl* pControl ) +{ + HRESULT hr; + + if( pControl == NULL ) + return E_INVALIDARG; + + pControl->m_Index = m_Controls.GetSize(); + + // Look for a default Element entries + for( int i = 0; i < m_DefaultElements.GetSize(); i++ ) + { + DXUTElementHolder* pElementHolder = m_DefaultElements.GetAt( i ); + if( pElementHolder->nControlType == pControl->GetType() ) + pControl->SetElement( pElementHolder->iElement, &pElementHolder->Element ); + } + + V_RETURN( pControl->OnInit() ); + + return S_OK; +} + + + +//-------------------------------------------------------------------------------------- +HRESULT CDXUTDialog::AddControl( CDXUTControl* pControl ) +{ + HRESULT hr = S_OK; + + hr = InitControl( pControl ); + if( FAILED( hr ) ) + return DXTRACE_ERR( L"CDXUTDialog::InitControl", hr ); + + // Add to the list + hr = m_Controls.Add( pControl ); + if( FAILED( hr ) ) + { + return DXTRACE_ERR( L"CGrowableArray::Add", hr ); + } + + return S_OK; +} + + +//-------------------------------------------------------------------------------------- +CDXUTControl* CDXUTDialog::GetControl( int ID ) +{ + // Try to find the control with the given ID + for( int i = 0; i < m_Controls.GetSize(); i++ ) + { + CDXUTControl* pControl = m_Controls.GetAt( i ); + + if( pControl->GetID() == ID ) + { + return pControl; + } + } + + // Not found + return NULL; +} + + + +//-------------------------------------------------------------------------------------- +CDXUTControl* CDXUTDialog::GetControl( int ID, UINT nControlType ) +{ + // Try to find the control with the given ID + for( int i = 0; i < m_Controls.GetSize(); i++ ) + { + CDXUTControl* pControl = m_Controls.GetAt( i ); + + if( pControl->GetID() == ID && pControl->GetType() == nControlType ) + { + return pControl; + } + } + + // Not found + return NULL; +} + + + +//-------------------------------------------------------------------------------------- +CDXUTControl* CDXUTDialog::GetNextControl( CDXUTControl* pControl ) +{ + int index = pControl->m_Index + 1; + + CDXUTDialog* pDialog = pControl->m_pDialog; + + // Cycle through dialogs in the loop to find the next control. Note + // that if only one control exists in all looped dialogs it will + // be the returned 'next' control. + while( index >= ( int )pDialog->m_Controls.GetSize() ) + { + pDialog = pDialog->m_pNextDialog; + index = 0; + } + + return pDialog->m_Controls.GetAt( index ); +} + +//-------------------------------------------------------------------------------------- +CDXUTControl* CDXUTDialog::GetPrevControl( CDXUTControl* pControl ) +{ + int index = pControl->m_Index - 1; + + CDXUTDialog* pDialog = pControl->m_pDialog; + + // Cycle through dialogs in the loop to find the next control. Note + // that if only one control exists in all looped dialogs it will + // be the returned 'previous' control. + while( index < 0 ) + { + pDialog = pDialog->m_pPrevDialog; + if( pDialog == NULL ) + pDialog = pControl->m_pDialog; + + index = pDialog->m_Controls.GetSize() - 1; + } + + return pDialog->m_Controls.GetAt( index ); +} + + +//-------------------------------------------------------------------------------------- +void CDXUTDialog::ClearRadioButtonGroup( UINT nButtonGroup ) +{ + // Find all radio buttons with the given group number + for( int i = 0; i < m_Controls.GetSize(); i++ ) + { + CDXUTControl* pControl = m_Controls.GetAt( i ); + + if( pControl->GetType() == DXUT_CONTROL_RADIOBUTTON ) + { + CDXUTRadioButton* pRadioButton = ( CDXUTRadioButton* )pControl; + + if( pRadioButton->GetButtonGroup() == nButtonGroup ) + pRadioButton->SetChecked( false, false ); + } + } +} + + + +//-------------------------------------------------------------------------------------- +void CDXUTDialog::ClearComboBox( int ID ) +{ + CDXUTComboBox* pComboBox = GetComboBox( ID ); + if( pComboBox == NULL ) + return; + + pComboBox->RemoveAllItems(); +} + + + + +//-------------------------------------------------------------------------------------- +void CDXUTDialog::RequestFocus( CDXUTControl* pControl ) +{ + if( s_pControlFocus == pControl ) + return; + + if( !pControl->CanHaveFocus() ) + return; + + if( s_pControlFocus ) + s_pControlFocus->OnFocusOut(); + + pControl->OnFocusIn(); + s_pControlFocus = pControl; +} + + +//-------------------------------------------------------------------------------------- +HRESULT CDXUTDialog::DrawRect( RECT* pRect, D3DCOLOR color ) +{ + if( m_pManager->GetD3D9Device() ) + return DrawRect9( pRect, color ); + return E_FAIL; +} + + +//-------------------------------------------------------------------------------------- +HRESULT CDXUTDialog::DrawRect9( RECT* pRect, D3DCOLOR color ) +{ + RECT rcScreen = *pRect; + OffsetRect( &rcScreen, m_x, m_y ); + + // If caption is enabled, offset the Y position by its height. + if( m_bCaption ) + OffsetRect( &rcScreen, 0, m_nCaptionHeight ); + + DXUT_SCREEN_VERTEX vertices[4] = + { + ( float )rcScreen.left - 0.5f, ( float )rcScreen.top - 0.5f, 0.5f, 1.0f, color, 0, 0, + ( float )rcScreen.right - 0.5f, ( float )rcScreen.top - 0.5f, 0.5f, 1.0f, color, 0, 0, + ( float )rcScreen.right - 0.5f, ( float )rcScreen.bottom - 0.5f, 0.5f, 1.0f, color, 0, 0, + ( float )rcScreen.left - 0.5f, ( float )rcScreen.bottom - 0.5f, 0.5f, 1.0f, color, 0, 0, + }; + + IDirect3DDevice9* pd3dDevice = m_pManager->GetD3D9Device(); + + // Since we're doing our own drawing here we need to flush the sprites + m_pManager->m_pSprite->Flush(); + IDirect3DVertexDeclaration9* pDecl = NULL; + pd3dDevice->GetVertexDeclaration( &pDecl ); // Preserve the sprite's current vertex decl + pd3dDevice->SetFVF( DXUT_SCREEN_VERTEX::FVF ); + + pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_SELECTARG2 ); + pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG2 ); + + pd3dDevice->DrawPrimitiveUP( D3DPT_TRIANGLEFAN, 2, vertices, sizeof( DXUT_SCREEN_VERTEX ) ); + + pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_MODULATE ); + pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE ); + + // Restore the vertex decl + pd3dDevice->SetVertexDeclaration( pDecl ); + pDecl->Release(); + + return S_OK; +} + + +//-------------------------------------------------------------------------------------- +HRESULT CDXUTDialog::DrawPolyLine( POINT* apPoints, UINT nNumPoints, D3DCOLOR color ) +{ + DXUT_SCREEN_VERTEX* vertices = new DXUT_SCREEN_VERTEX[ nNumPoints ]; + if( vertices == NULL ) + return E_OUTOFMEMORY; + + DXUT_SCREEN_VERTEX* pVertex = vertices; + POINT* pt = apPoints; + for( UINT i = 0; i < nNumPoints; i++ ) + { + pVertex->x = m_x + ( float )pt->x; + pVertex->y = m_y + ( float )pt->y; + pVertex->z = 0.5f; + pVertex->h = 1.0f; + pVertex->color = color; + pVertex->tu = 0.0f; + pVertex->tv = 0.0f; + + pVertex++; + pt++; + } + + IDirect3DDevice9* pd3dDevice = m_pManager->GetD3D9Device(); + + // Since we're doing our own drawing here we need to flush the sprites + m_pManager->m_pSprite->Flush(); + IDirect3DVertexDeclaration9* pDecl = NULL; + pd3dDevice->GetVertexDeclaration( &pDecl ); // Preserve the sprite's current vertex decl + pd3dDevice->SetFVF( DXUT_SCREEN_VERTEX::FVF ); + + pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_SELECTARG2 ); + pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG2 ); + + pd3dDevice->DrawPrimitiveUP( D3DPT_LINESTRIP, nNumPoints - 1, vertices, sizeof( DXUT_SCREEN_VERTEX ) ); + + pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_MODULATE ); + pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE ); + + // Restore the vertex decl + pd3dDevice->SetVertexDeclaration( pDecl ); + pDecl->Release(); + + SAFE_DELETE_ARRAY( vertices ); + return S_OK; +} + + +//-------------------------------------------------------------------------------------- +HRESULT CDXUTDialog::DrawSprite( CDXUTElement* pElement, RECT* prcDest, float fDepth ) +{ + if( m_pManager->GetD3D9Device() ) + return DrawSprite9( pElement, prcDest ); + else + return DrawSprite11( pElement, prcDest, fDepth ); +} + + +//-------------------------------------------------------------------------------------- +HRESULT CDXUTDialog::DrawSprite9( CDXUTElement* pElement, RECT* prcDest ) +{ + // No need to draw fully transparent layers + if( pElement->TextureColor.Current.a == 0 ) + return S_OK; + + RECT rcTexture = pElement->rcTexture; + + RECT rcScreen = *prcDest; + OffsetRect( &rcScreen, m_x, m_y ); + + // If caption is enabled, offset the Y position by its height. + if( m_bCaption ) + OffsetRect( &rcScreen, 0, m_nCaptionHeight ); + + DXUTTextureNode* pTextureNode = GetTexture( pElement->iTexture ); + if( pTextureNode == NULL ) + return E_FAIL; + + float fScaleX = ( float )RectWidth( rcScreen ) / RectWidth( rcTexture ); + float fScaleY = ( float )RectHeight( rcScreen ) / RectHeight( rcTexture ); + + D3DXMATRIXA16 matTransform; + D3DXMatrixScaling( &matTransform, fScaleX, fScaleY, 1.0f ); + + m_pManager->m_pSprite->SetTransform( &matTransform ); + + D3DXVECTOR3 vPos( ( float )rcScreen.left, ( float )rcScreen.top, 0.0f ); + + vPos.x /= fScaleX; + vPos.y /= fScaleY; + + return m_pManager->m_pSprite->Draw( pTextureNode->pTexture9, &rcTexture, NULL, &vPos, + pElement->TextureColor.Current ); +} + +//-------------------------------------------------------------------------------------- +HRESULT CDXUTDialog::DrawSprite11( CDXUTElement* pElement, RECT* prcDest, float fDepth ) +{ + // No need to draw fully transparent layers + if( pElement->TextureColor.Current.a == 0 ) + return S_OK; + + RECT rcTexture = pElement->rcTexture; + + RECT rcScreen = *prcDest; + OffsetRect( &rcScreen, m_x, m_y ); + + // If caption is enabled, offset the Y position by its height. + if( m_bCaption ) + OffsetRect( &rcScreen, 0, m_nCaptionHeight ); + + DXUTTextureNode* pTextureNode = GetTexture( pElement->iTexture ); + if( pTextureNode == NULL ) + return E_FAIL; + + float fBBWidth = ( float )m_pManager->m_nBackBufferWidth; + float fBBHeight = ( float )m_pManager->m_nBackBufferHeight; + float fTexWidth = ( float )pTextureNode->dwWidth; + float fTexHeight = ( float )pTextureNode->dwHeight; + + float fRectLeft = rcScreen.left / fBBWidth; + float fRectTop = 1.0f - rcScreen.top / fBBHeight; + float fRectRight = rcScreen.right / fBBWidth; + float fRectBottom = 1.0f - rcScreen.bottom / fBBHeight; + + fRectLeft = fRectLeft * 2.0f - 1.0f; + fRectTop = fRectTop * 2.0f - 1.0f; + fRectRight = fRectRight * 2.0f - 1.0f; + fRectBottom = fRectBottom * 2.0f - 1.0f; + + float fTexLeft = rcTexture.left / fTexWidth; + float fTexTop = rcTexture.top / fTexHeight; + float fTexRight = rcTexture.right / fTexWidth; + float fTexBottom = rcTexture.bottom / fTexHeight; + + // Add 6 sprite vertices + DXUTSpriteVertex SpriteVertex; + + // tri1 + SpriteVertex.vPos = D3DXVECTOR3( fRectLeft, fRectTop, fDepth ); + SpriteVertex.vTex = D3DXVECTOR2( fTexLeft, fTexTop ); + SpriteVertex.vColor = pElement->TextureColor.Current; + m_pManager->m_SpriteVertices.Add( SpriteVertex ); + + SpriteVertex.vPos = D3DXVECTOR3( fRectRight, fRectTop, fDepth ); + SpriteVertex.vTex = D3DXVECTOR2( fTexRight, fTexTop ); + SpriteVertex.vColor = pElement->TextureColor.Current; + m_pManager->m_SpriteVertices.Add( SpriteVertex ); + + SpriteVertex.vPos = D3DXVECTOR3( fRectLeft, fRectBottom, fDepth ); + SpriteVertex.vTex = D3DXVECTOR2( fTexLeft, fTexBottom ); + SpriteVertex.vColor = pElement->TextureColor.Current; + m_pManager->m_SpriteVertices.Add( SpriteVertex ); + + // tri2 + SpriteVertex.vPos = D3DXVECTOR3( fRectRight, fRectTop, fDepth ); + SpriteVertex.vTex = D3DXVECTOR2( fTexRight, fTexTop ); + SpriteVertex.vColor = pElement->TextureColor.Current; + m_pManager->m_SpriteVertices.Add( SpriteVertex ); + + SpriteVertex.vPos = D3DXVECTOR3( fRectRight, fRectBottom, fDepth ); + SpriteVertex.vTex = D3DXVECTOR2( fTexRight, fTexBottom ); + SpriteVertex.vColor = pElement->TextureColor.Current; + m_pManager->m_SpriteVertices.Add( SpriteVertex ); + + SpriteVertex.vPos = D3DXVECTOR3( fRectLeft, fRectBottom, fDepth ); + SpriteVertex.vTex = D3DXVECTOR2( fTexLeft, fTexBottom ); + SpriteVertex.vColor = pElement->TextureColor.Current; + m_pManager->m_SpriteVertices.Add( SpriteVertex ); + + // Why are we drawing the sprite every time? This is very inefficient, but the sprite workaround doesn't have support for sorting now, so we have to + // draw a sprite every time to keep the order correct between sprites and text. + m_pManager->EndSprites11( DXUTGetD3D11Device(), DXUTGetD3D11DeviceContext() ); + + return S_OK; +} + + +//-------------------------------------------------------------------------------------- +HRESULT CDXUTDialog::CalcTextRect( LPCWSTR strText, CDXUTElement* pElement, RECT* prcDest, int nCount ) +{ + HRESULT hr = S_OK; + + DXUTFontNode* pFontNode = GetFont( pElement->iFont ); + if( pFontNode == NULL ) + return E_FAIL; + + DWORD dwTextFormat = pElement->dwTextFormat | DT_CALCRECT; + // Since we are only computing the rectangle, we don't need a sprite. + if( pFontNode->pFont9 ) + { + hr = pFontNode->pFont9->DrawText( NULL, strText, nCount, prcDest, dwTextFormat, pElement->FontColor.Current ); + if( FAILED( hr ) ) + return hr; + } + + return S_OK; +} + + +//-------------------------------------------------------------------------------------- +HRESULT CDXUTDialog::DrawText( LPCWSTR strText, CDXUTElement* pElement, RECT* prcDest, bool bShadow, int nCount, bool bCenter ) +{ + if( m_pManager->GetD3D9Device() ) + return DrawText9( strText, pElement, prcDest, bShadow, nCount ); + else + return DrawText11( m_pManager->GetD3D11Device(), m_pManager->GetD3D11DeviceContext(), strText, pElement, prcDest, bShadow, nCount, bCenter ); +} + + +//-------------------------------------------------------------------------------------- +HRESULT CDXUTDialog::DrawText9( LPCWSTR strText, CDXUTElement* pElement, RECT* prcDest, bool bShadow, int nCount ) +{ + HRESULT hr = S_OK; + + // No need to draw fully transparent layers + if( pElement->FontColor.Current.a == 0 ) + return S_OK; + + RECT rcScreen = *prcDest; + OffsetRect( &rcScreen, m_x, m_y ); + + // If caption is enabled, offset the Y position by its height. + if( m_bCaption ) + OffsetRect( &rcScreen, 0, m_nCaptionHeight ); + + D3DXMATRIX matTransform; + D3DXMatrixIdentity( &matTransform ); + m_pManager->m_pSprite->SetTransform( &matTransform ); + + DXUTFontNode* pFontNode = GetFont( pElement->iFont ); + + if( bShadow ) + { + RECT rcShadow = rcScreen; + OffsetRect( &rcShadow, 1, 1 ); + hr = pFontNode->pFont9->DrawText( m_pManager->m_pSprite, strText, nCount, &rcShadow, pElement->dwTextFormat, + D3DCOLOR_ARGB( DWORD( pElement->FontColor.Current.a * 255 ), 0, 0, 0 ) ); + if( FAILED( hr ) ) + return hr; + } + + hr = pFontNode->pFont9->DrawText( m_pManager->m_pSprite, strText, nCount, &rcScreen, pElement->dwTextFormat, + pElement->FontColor.Current ); + if( FAILED( hr ) ) + return hr; + + return S_OK; +} + +ID3D11Buffer* g_pFontBuffer11 = NULL; +UINT g_FontBufferBytes11 = 0; +CGrowableArray<DXUTSpriteVertex> g_FontVertices; +ID3D11ShaderResourceView* g_pFont11 = NULL; +ID3D11InputLayout* g_pInputLayout11 = NULL; +HRESULT InitFont11( ID3D11Device* pd3d11Device, ID3D11InputLayout* pInputLayout ) +{ + HRESULT hr = S_OK; + WCHAR str[MAX_PATH]; + V_RETURN( DXUTFindDXSDKMediaFileCch( str, MAX_PATH, L"UI\\Font.dds" ) ); + + if (pd3d11Device->GetFeatureLevel() < D3D_FEATURE_LEVEL_10_0 ) { + + D3DX11_IMAGE_INFO dii; + D3DX11GetImageInfoFromFile( str, NULL, &dii, NULL ); + + D3DX11_IMAGE_LOAD_INFO dili; + dili.BindFlags = D3DX11_DEFAULT; + dili.CpuAccessFlags = D3DX11_DEFAULT; + dili.Depth = D3DX11_DEFAULT; + dili.Filter = D3DX11_DEFAULT; + dili.FirstMipLevel = 0; + dili.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + dili.Height = D3DX11_DEFAULT; + dili.MipFilter = D3DX11_DEFAULT; + dili.MipLevels = 1; + dili.MiscFlags = D3DX11_DEFAULT; + dili.pSrcInfo = &dii; + dili.Usage = D3D11_USAGE_DEFAULT ; + dili.Width = D3DX11_DEFAULT; + + V_RETURN( D3DX11CreateShaderResourceViewFromFile( pd3d11Device, str, &dili, NULL, &g_pFont11, &hr) ); + } + else + { + V_RETURN( D3DX11CreateShaderResourceViewFromFile( pd3d11Device, str, NULL, NULL, &g_pFont11, &hr) ); + } + +#if defined(PROFILE) || defined(DEBUG) + if (g_pFont11) + { + ID3D11Resource *pRes = NULL; + g_pFont11->GetResource( &pRes ); + DXUT_SetDebugName( pRes, "DXUT Text11" ); + SAFE_RELEASE( pRes ); + } + + DXUT_SetDebugName( g_pFont11, "DXUT Text11" ); +#endif + + g_pInputLayout11 = pInputLayout; + return hr; +} + +void EndFont11() +{ + SAFE_RELEASE( g_pFontBuffer11 ); + g_FontBufferBytes11 = 0; + SAFE_RELEASE( g_pFont11 ); +} + +void BeginText11() +{ + g_FontVertices.Reset(); +} + +void DrawText11DXUT( ID3D11Device* pd3dDevice, ID3D11DeviceContext* pd3d11DeviceContext, + LPCWSTR strText, RECT rcScreen, D3DXCOLOR vFontColor, + float fBBWidth, float fBBHeight, bool bCenter ) +{ + float fCharTexSizeX = 0.010526315f; + //float fGlyphSizeX = 14.0f / fBBWidth; + //float fGlyphSizeY = 32.0f / fBBHeight; + float fGlyphSizeX = 15.0f / fBBWidth; + float fGlyphSizeY = 42.0f / fBBHeight; + + + float fRectLeft = rcScreen.left / fBBWidth; + float fRectTop = 1.0f - rcScreen.top / fBBHeight; + + fRectLeft = fRectLeft * 2.0f - 1.0f; + fRectTop = fRectTop * 2.0f - 1.0f; + + int NumChars = (int)wcslen( strText ); + if (bCenter) { + float fRectRight = rcScreen.right / fBBWidth; + fRectRight = fRectRight * 2.0f - 1.0f; + float fRectBottom = 1.0f - rcScreen.bottom / fBBHeight; + fRectBottom = fRectBottom * 2.0f - 1.0f; + float fcenterx = ((fRectRight - fRectLeft) - (float)NumChars*fGlyphSizeX) *0.5f; + float fcentery = ((fRectTop - fRectBottom) - (float)1*fGlyphSizeY) *0.5f; + fRectLeft += fcenterx ; + fRectTop -= fcentery; + } + float fOriginalLeft = fRectLeft; + float fTexTop = 0.0f; + float fTexBottom = 1.0f; + + float fDepth = 0.5f; + for( int i=0; i<NumChars; i++ ) + { + if( strText[i] == '\n' ) + { + fRectLeft = fOriginalLeft; + fRectTop -= fGlyphSizeY; + + continue; + } + else if( strText[i] < 32 || strText[i] > 126 ) + { + continue; + } + + // Add 6 sprite vertices + DXUTSpriteVertex SpriteVertex; + float fRectRight = fRectLeft + fGlyphSizeX; + float fRectBottom = fRectTop - fGlyphSizeY; + float fTexLeft = ( strText[i] - 32 ) * fCharTexSizeX; + float fTexRight = fTexLeft + fCharTexSizeX; + + // tri1 + SpriteVertex.vPos = D3DXVECTOR3( fRectLeft, fRectTop, fDepth ); + SpriteVertex.vTex = D3DXVECTOR2( fTexLeft, fTexTop ); + SpriteVertex.vColor = vFontColor; + g_FontVertices.Add( SpriteVertex ); + + SpriteVertex.vPos = D3DXVECTOR3( fRectRight, fRectTop, fDepth ); + SpriteVertex.vTex = D3DXVECTOR2( fTexRight, fTexTop ); + SpriteVertex.vColor = vFontColor; + g_FontVertices.Add( SpriteVertex ); + + SpriteVertex.vPos = D3DXVECTOR3( fRectLeft, fRectBottom, fDepth ); + SpriteVertex.vTex = D3DXVECTOR2( fTexLeft, fTexBottom ); + SpriteVertex.vColor = vFontColor; + g_FontVertices.Add( SpriteVertex ); + + // tri2 + SpriteVertex.vPos = D3DXVECTOR3( fRectRight, fRectTop, fDepth ); + SpriteVertex.vTex = D3DXVECTOR2( fTexRight, fTexTop ); + SpriteVertex.vColor = vFontColor; + g_FontVertices.Add( SpriteVertex ); + + SpriteVertex.vPos = D3DXVECTOR3( fRectRight, fRectBottom, fDepth ); + SpriteVertex.vTex = D3DXVECTOR2( fTexRight, fTexBottom ); + SpriteVertex.vColor = vFontColor; + g_FontVertices.Add( SpriteVertex ); + + SpriteVertex.vPos = D3DXVECTOR3( fRectLeft, fRectBottom, fDepth ); + SpriteVertex.vTex = D3DXVECTOR2( fTexLeft, fTexBottom ); + SpriteVertex.vColor = vFontColor; + g_FontVertices.Add( SpriteVertex ); + + fRectLeft += fGlyphSizeX; + + } + + // We have to end text after every line so that rendering order between sprites and fonts is preserved + EndText11( pd3dDevice, pd3d11DeviceContext ); +} + +void EndText11( ID3D11Device* pd3dDevice, ID3D11DeviceContext* pd3d11DeviceContext ) +{ + + // ensure our buffer size can hold our sprites + UINT FontDataBytes = g_FontVertices.GetSize() * sizeof( DXUTSpriteVertex ); + if( g_FontBufferBytes11 < FontDataBytes ) + { + SAFE_RELEASE( g_pFontBuffer11 ); + g_FontBufferBytes11 = FontDataBytes; + + D3D11_BUFFER_DESC BufferDesc; + BufferDesc.ByteWidth = g_FontBufferBytes11; + BufferDesc.Usage = D3D11_USAGE_DYNAMIC; + BufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; + BufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + BufferDesc.MiscFlags = 0; + + pd3dDevice->CreateBuffer( &BufferDesc, NULL, &g_pFontBuffer11 ); + DXUT_SetDebugName( g_pFontBuffer11, "DXUT Text11" ); + } + + // Copy the sprites over + D3D11_BOX destRegion; + destRegion.left = 0; + destRegion.right = FontDataBytes; + destRegion.top = 0; + destRegion.bottom = 1; + destRegion.front = 0; + destRegion.back = 1; + D3D11_MAPPED_SUBRESOURCE MappedResource; + if ( S_OK == pd3d11DeviceContext->Map( g_pFontBuffer11, 0, D3D11_MAP_WRITE_DISCARD, 0, &MappedResource ) ) { + CopyMemory( MappedResource.pData, (void*)g_FontVertices.GetData(), FontDataBytes ); + pd3d11DeviceContext->Unmap(g_pFontBuffer11, 0); + } + + ID3D11ShaderResourceView* pOldTexture = NULL; + pd3d11DeviceContext->PSGetShaderResources( 0, 1, &pOldTexture ); + pd3d11DeviceContext->PSSetShaderResources( 0, 1, &g_pFont11 ); + + // Draw + UINT Stride = sizeof( DXUTSpriteVertex ); + UINT Offset = 0; + pd3d11DeviceContext->IASetVertexBuffers( 0, 1, &g_pFontBuffer11, &Stride, &Offset ); + pd3d11DeviceContext->IASetInputLayout( g_pInputLayout11 ); + pd3d11DeviceContext->IASetPrimitiveTopology( D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST ); + pd3d11DeviceContext->Draw( g_FontVertices.GetSize(), 0 ); + + pd3d11DeviceContext->PSSetShaderResources( 0, 1, &pOldTexture ); + SAFE_RELEASE( pOldTexture ); + + g_FontVertices.Reset(); +} + +//-------------------------------------------------------------------------------------- +HRESULT CDXUTDialog::DrawText11( ID3D11Device* pd3dDevice, ID3D11DeviceContext* pd3d11DeviceContext, + LPCWSTR strText, CDXUTElement* pElement, RECT* prcDest, bool bShadow, int nCount, bool bCenter ) +{ + //HRESULT hr = S_OK; + + // No need to draw fully transparent layers + if( pElement->FontColor.Current.a == 0 ) + return S_OK; + + RECT rcScreen = *prcDest; + OffsetRect( &rcScreen, m_x, m_y); + + // If caption is enabled, offset the Y position by its height. + if( m_bCaption ) + OffsetRect( &rcScreen, 0, m_nCaptionHeight ); + + float fBBWidth = ( float )m_pManager->m_nBackBufferWidth; + float fBBHeight = ( float )m_pManager->m_nBackBufferHeight; + + if( bShadow ) + { + RECT rcShadow = rcScreen; + OffsetRect( &rcShadow, 1, 1 ); + + D3DXCOLOR vShadowColor( 0,0,0, 1.0f ); + DrawText11DXUT( pd3dDevice, pd3d11DeviceContext, + strText, rcShadow, vShadowColor, + fBBWidth, fBBHeight, bCenter ); + + } + + D3DXCOLOR vFontColor( pElement->FontColor.Current.r, pElement->FontColor.Current.g, pElement->FontColor.Current.b, 1.0f ); + DrawText11DXUT( pd3dDevice, pd3d11DeviceContext, + strText, rcScreen, vFontColor, + fBBWidth, fBBHeight, bCenter ); + + return S_OK; +} + + +//-------------------------------------------------------------------------------------- +void CDXUTDialog::SetBackgroundColors( D3DCOLOR colorTopLeft, D3DCOLOR colorTopRight, D3DCOLOR colorBottomLeft, + D3DCOLOR colorBottomRight ) +{ + m_colorTopLeft = colorTopLeft; + m_colorTopRight = colorTopRight; + m_colorBottomLeft = colorBottomLeft; + m_colorBottomRight = colorBottomRight; +} + + +//-------------------------------------------------------------------------------------- +void CDXUTDialog::SetNextDialog( CDXUTDialog* pNextDialog ) +{ + if( pNextDialog == NULL ) + pNextDialog = this; + + m_pNextDialog = pNextDialog; + if( pNextDialog ) + m_pNextDialog->m_pPrevDialog = this; +} + + +//-------------------------------------------------------------------------------------- +void CDXUTDialog::ClearFocus() +{ + if( s_pControlFocus ) + { + s_pControlFocus->OnFocusOut(); + s_pControlFocus = NULL; + } + + ReleaseCapture(); +} + + +//-------------------------------------------------------------------------------------- +void CDXUTDialog::FocusDefaultControl() +{ + // Check for default control in this dialog + for( int i = 0; i < m_Controls.GetSize(); i++ ) + { + CDXUTControl* pControl = m_Controls.GetAt( i ); + if( pControl->m_bIsDefault ) + { + // Remove focus from the current control + ClearFocus(); + + // Give focus to the default control + s_pControlFocus = pControl; + s_pControlFocus->OnFocusIn(); + return; + } + } +} + + +//-------------------------------------------------------------------------------------- +bool CDXUTDialog::OnCycleFocus( bool bForward ) +{ + CDXUTControl* pControl = NULL; + CDXUTDialog* pDialog = NULL; // pDialog and pLastDialog are used to track wrapping of + CDXUTDialog* pLastDialog; // focus from first control to last or vice versa. + + if( s_pControlFocus == NULL ) + { + // If s_pControlFocus is NULL, we focus the first control of first dialog in + // the case that bForward is true, and focus the last control of last dialog when + // bForward is false. + // + if( bForward ) + { + // Search for the first control from the start of the dialog + // array. + for( int d = 0; d < m_pManager->m_Dialogs.GetSize(); ++d ) + { + pDialog = pLastDialog = m_pManager->m_Dialogs.GetAt( d ); + if( pDialog && pDialog->m_Controls.GetSize() > 0 ) + { + pControl = pDialog->m_Controls.GetAt( 0 ); + break; + } + } + + if( !pDialog || !pControl ) + { + // No dialog has been registered yet or no controls have been + // added to the dialogs. Cannot proceed. + return true; + } + } + else + { + // Search for the first control from the end of the dialog + // array. + for( int d = m_pManager->m_Dialogs.GetSize() - 1; d >= 0; --d ) + { + pDialog = pLastDialog = m_pManager->m_Dialogs.GetAt( d ); + if( pDialog && pDialog->m_Controls.GetSize() > 0 ) + { + pControl = pDialog->m_Controls.GetAt( pDialog->m_Controls.GetSize() - 1 ); + break; + } + } + + if( !pDialog || !pControl ) + { + // No dialog has been registered yet or no controls have been + // added to the dialogs. Cannot proceed. + return true; + } + } + } + else if( s_pControlFocus->m_pDialog != this ) + { + // If a control belonging to another dialog has focus, let that other + // dialog handle this event by returning false. + // + return false; + } + else + { + // Focused control belongs to this dialog. Cycle to the + // next/previous control. + pLastDialog = s_pControlFocus->m_pDialog; + pControl = ( bForward ) ? GetNextControl( s_pControlFocus ) : GetPrevControl( s_pControlFocus ); + pDialog = pControl->m_pDialog; + } + + for( int i = 0; i < 0xffff; i++ ) + { + // If we just wrapped from last control to first or vice versa, + // set the focused control to NULL. This state, where no control + // has focus, allows the camera to work. + int nLastDialogIndex = m_pManager->m_Dialogs.IndexOf( pLastDialog ); + int nDialogIndex = m_pManager->m_Dialogs.IndexOf( pDialog ); + if( ( !bForward && nLastDialogIndex < nDialogIndex ) || + ( bForward && nDialogIndex < nLastDialogIndex ) ) + { + if( s_pControlFocus ) + s_pControlFocus->OnFocusOut(); + s_pControlFocus = NULL; + return true; + } + + // If we've gone in a full circle then focus doesn't change + if( pControl == s_pControlFocus ) + return true; + + // If the dialog accepts keybord input and the control can have focus then + // move focus + if( pControl->m_pDialog->m_bKeyboardInput && pControl->CanHaveFocus() ) + { + if( s_pControlFocus ) + s_pControlFocus->OnFocusOut(); + s_pControlFocus = pControl; + s_pControlFocus->OnFocusIn(); + return true; + } + + pLastDialog = pDialog; + pControl = ( bForward ) ? GetNextControl( pControl ) : GetPrevControl( pControl ); + pDialog = pControl->m_pDialog; + } + + // If we reached this point, the chain of dialogs didn't form a complete loop + DXTRACE_ERR( L"CDXUTDialog: Multiple dialogs are improperly chained together", E_FAIL ); + return false; +} + + +//-------------------------------------------------------------------------------------- +HRESULT CDXUTDialogResourceManager::CreateFont9( UINT iFont ) +{ + HRESULT hr = S_OK; + + DXUTFontNode* pFontNode = m_FontCache.GetAt( iFont ); + + SAFE_RELEASE( pFontNode->pFont9 ); + + V_RETURN( D3DXCreateFont( m_pd3d9Device, pFontNode->nHeight, 0, pFontNode->nWeight, 1, FALSE, DEFAULT_CHARSET, + OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, + pFontNode->strFace, &pFontNode->pFont9 ) ); + + return S_OK; +} + + + +//-------------------------------------------------------------------------------------- +HRESULT CDXUTDialogResourceManager::CreateFont11( UINT iFont ) +{ + return S_OK; +} + + +//-------------------------------------------------------------------------------------- +HRESULT CDXUTDialogResourceManager::CreateTexture9( UINT iTexture ) +{ + HRESULT hr = S_OK; + + DXUTTextureNode* pTextureNode = m_TextureCache.GetAt( iTexture ); + + + D3DXIMAGE_INFO info; + + if( !pTextureNode->bFileSource ) + { + if( pTextureNode->nResourceID == 0xFFFF && pTextureNode->hResourceModule == ( HMODULE )0xFFFF ) + { + hr = DXUTCreateGUITextureFromInternalArray9( m_pd3d9Device, &pTextureNode->pTexture9, &info ); + if( FAILED( hr ) ) + return DXTRACE_ERR( L"D3DXCreateTextureFromFileInMemoryEx", hr ); + DXUT_SetDebugName( pTextureNode->pTexture9, "DXUT GUI Texture" ); + } + else + { + LPCWSTR pID = pTextureNode->nResourceID ? ( LPCWSTR )( size_t )pTextureNode->nResourceID : + pTextureNode->strFilename; + + // Create texture from resource + hr = D3DXCreateTextureFromResourceEx( m_pd3d9Device, pTextureNode->hResourceModule, pID, D3DX_DEFAULT, + D3DX_DEFAULT, + 1, 0, D3DFMT_UNKNOWN, D3DPOOL_MANAGED, + D3DX_DEFAULT, D3DX_DEFAULT, 0, + &info, NULL, &pTextureNode->pTexture9 ); + if( FAILED( hr ) ) + return DXTRACE_ERR( L"D3DXCreateTextureFromResourceEx", hr ); + } + } + else + { + // Make sure there's a texture to create + if( pTextureNode->strFilename[0] == 0 ) + return S_OK; + + // Create texture from file + hr = D3DXCreateTextureFromFileEx( m_pd3d9Device, pTextureNode->strFilename, D3DX_DEFAULT, D3DX_DEFAULT, + 1, 0, D3DFMT_UNKNOWN, D3DPOOL_MANAGED, + D3DX_DEFAULT, D3DX_DEFAULT, 0, + &info, NULL, &pTextureNode->pTexture9 ); + if( FAILED( hr ) ) + { + return DXTRACE_ERR( L"D3DXCreateTextureFromFileEx", hr ); + } + } + + // Store dimensions + pTextureNode->dwWidth = info.Width; + pTextureNode->dwHeight = info.Height; + + return S_OK; +} + + +//-------------------------------------------------------------------------------------- +HRESULT CDXUTDialogResourceManager::CreateTexture11( UINT iTexture ) +{ + HRESULT hr = S_OK; + + DXUTTextureNode* pTextureNode = m_TextureCache.GetAt( iTexture ); + + if( !pTextureNode->bFileSource ) + { + if( pTextureNode->nResourceID == 0xFFFF && pTextureNode->hResourceModule == ( HMODULE )0xFFFF ) + { + hr = DXUTCreateGUITextureFromInternalArray11( m_pd3d11Device, &pTextureNode->pTexture11, NULL ); + if( FAILED( hr ) ) + return DXTRACE_ERR( L"D3DX11CreateResourceFromFileInMemory", hr ); + DXUT_SetDebugName( pTextureNode->pTexture11, "DXUT GUI Texture" ); + } + //else + //{ + // LPCWSTR pID = pTextureNode->nResourceID ? ( LPCWSTR )( size_t )pTextureNode->nResourceID : + // pTextureNode->strFilename; + + // D3DX10_IMAGE_INFO SrcInfo; + // D3DX10GetImageInfoFromResource( NULL, pID, NULL, &SrcInfo, NULL ); + + // // Create texture from resource + // ID3D10Resource* pRes; + // D3DX10_IMAGE_LOAD_INFO loadInfo; + // loadInfo.Width = D3DX10_DEFAULT; + // loadInfo.Height = D3DX10_DEFAULT; + // loadInfo.Depth = D3DX10_DEFAULT; + // loadInfo.FirstMipLevel = 0; + // loadInfo.MipLevels = 1; + // loadInfo.Usage = D3D10_USAGE_DEFAULT; + // loadInfo.BindFlags = D3D10_BIND_SHADER_RESOURCE; + // loadInfo.CpuAccessFlags = 0; + // loadInfo.MiscFlags = 0; + // loadInfo.Format = MAKE_TYPELESS( SrcInfo.Format ); + // loadInfo.Filter = D3DX10_FILTER_NONE; + // loadInfo.MipFilter = D3DX10_FILTER_NONE; + // loadInfo.pSrcInfo = &SrcInfo; + + // hr = D3DX10CreateTextureFromResource( m_pd3d10Device, pTextureNode->hResourceModule, pID, &loadInfo, + // NULL, &pRes, NULL ); + // if( FAILED( hr ) ) + // return DXTRACE_ERR( L"D3DX10CreateResourceFromResource", hr ); + // hr = pRes->QueryInterface( __uuidof( ID3D10Texture2D ), ( LPVOID* )&pTextureNode->pTexture10 ); + // SAFE_RELEASE( pRes ); + // if( FAILED( hr ) ) + // return hr; + //} + } + else + { + // + //// Make sure there's a texture to create + //if( pTextureNode->strFilename[0] == 0 ) + // return S_OK; + + //D3DX10_IMAGE_INFO SrcInfo; + //D3DX10GetImageInfoFromFile( pTextureNode->strFilename, NULL, &SrcInfo, NULL ); + + //// Create texture from file + //ID3D10Resource* pRes; + //D3DX10_IMAGE_LOAD_INFO loadInfo; + //loadInfo.Width = D3DX10_DEFAULT; + //loadInfo.Height = D3DX10_DEFAULT; + //loadInfo.Depth = D3DX10_DEFAULT; + //loadInfo.FirstMipLevel = 0; + //loadInfo.MipLevels = 1; + //loadInfo.Usage = D3D10_USAGE_DEFAULT; + //loadInfo.BindFlags = D3D10_BIND_SHADER_RESOURCE; + //loadInfo.CpuAccessFlags = 0; + //loadInfo.MiscFlags = 0; + //loadInfo.Format = MAKE_TYPELESS( SrcInfo.Format ); + //loadInfo.Filter = D3DX10_FILTER_NONE; + //loadInfo.MipFilter = D3DX10_FILTER_NONE; + //loadInfo.pSrcInfo = &SrcInfo; + //hr = D3DX10CreateTextureFromFile( m_pd3d10Device, pTextureNode->strFilename, &loadInfo, NULL, &pRes, NULL ); + //if( FAILED( hr ) ) + //{ + // return DXTRACE_ERR( L"D3DX10CreateResourceFromFileEx", hr ); + //} + //hr = pRes->QueryInterface( __uuidof( ID3D10Texture2D ), ( LPVOID* )&pTextureNode->pTexture10 ); + //SAFE_RELEASE( pRes ); + //if( FAILED( hr ) ) + // return hr; + // + } + + // Store dimensions + D3D11_TEXTURE2D_DESC desc; + pTextureNode->pTexture11->GetDesc( &desc ); + pTextureNode->dwWidth = desc.Width; + pTextureNode->dwHeight = desc.Height; + + // Create resource view + D3D11_SHADER_RESOURCE_VIEW_DESC SRVDesc; + SRVDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; + SRVDesc.Format = MAKE_SRGB( desc.Format ); + SRVDesc.Texture2D.MipLevels = 1; + SRVDesc.Texture2D.MostDetailedMip = 0; + hr = m_pd3d11Device->CreateShaderResourceView( pTextureNode->pTexture11, &SRVDesc, &pTextureNode->pTexResView11 ); + DXUT_SetDebugName( pTextureNode->pTexResView11, "DXUT GUI Texture" ); + + return hr; +} + + +//-------------------------------------------------------------------------------------- +void CDXUTDialog::InitDefaultElements() +{ + SetFont( 0, L"Arial", 14, FW_NORMAL ); + + CDXUTElement Element; + RECT rcTexture; + + //------------------------------------- + // Element for the caption + //------------------------------------- + m_CapElement.SetFont( 0 ); + SetRect( &rcTexture, 17, 269, 241, 287 ); + m_CapElement.SetTexture( 0, &rcTexture ); + m_CapElement.TextureColor.States[ DXUT_STATE_NORMAL ] = D3DCOLOR_ARGB( 255, 255, 255, 255 ); + m_CapElement.FontColor.States[ DXUT_STATE_NORMAL ] = D3DCOLOR_ARGB( 255, 255, 255, 255 ); + m_CapElement.SetFont( 0, D3DCOLOR_ARGB( 255, 255, 255, 255 ), DT_LEFT | DT_VCENTER ); + // Pre-blend as we don't need to transition the state + m_CapElement.TextureColor.Blend( DXUT_STATE_NORMAL, 10.0f ); + m_CapElement.FontColor.Blend( DXUT_STATE_NORMAL, 10.0f ); + + //------------------------------------- + // CDXUTStatic + //------------------------------------- + Element.SetFont( 0 ); + Element.FontColor.States[ DXUT_STATE_DISABLED ] = D3DCOLOR_ARGB( 200, 200, 200, 200 ); + + // Assign the Element + SetDefaultElement( DXUT_CONTROL_STATIC, 0, &Element ); + + + //------------------------------------- + // CDXUTButton - Button + //------------------------------------- + SetRect( &rcTexture, 0, 0, 136, 54 ); + Element.SetTexture( 0, &rcTexture ); + Element.SetFont( 0 ); + Element.TextureColor.States[ DXUT_STATE_NORMAL ] = D3DCOLOR_ARGB( 150, 255, 255, 255 ); + Element.TextureColor.States[ DXUT_STATE_PRESSED ] = D3DCOLOR_ARGB( 200, 255, 255, 255 ); + Element.FontColor.States[ DXUT_STATE_MOUSEOVER ] = D3DCOLOR_ARGB( 255, 0, 0, 0 ); + + // Assign the Element + SetDefaultElement( DXUT_CONTROL_BUTTON, 0, &Element ); + + + //------------------------------------- + // CDXUTButton - Fill layer + //------------------------------------- + SetRect( &rcTexture, 136, 0, 252, 54 ); + Element.SetTexture( 0, &rcTexture, D3DCOLOR_ARGB( 0, 255, 255, 255 ) ); + Element.TextureColor.States[ DXUT_STATE_MOUSEOVER ] = D3DCOLOR_ARGB( 160, 255, 255, 255 ); + Element.TextureColor.States[ DXUT_STATE_PRESSED ] = D3DCOLOR_ARGB( 60, 0, 0, 0 ); + Element.TextureColor.States[ DXUT_STATE_FOCUS ] = D3DCOLOR_ARGB( 30, 255, 255, 255 ); + + + // Assign the Element + SetDefaultElement( DXUT_CONTROL_BUTTON, 1, &Element ); + + + //------------------------------------- + // CDXUTCheckBox - Box + //------------------------------------- + SetRect( &rcTexture, 0, 54, 27, 81 ); + Element.SetTexture( 0, &rcTexture ); + Element.SetFont( 0, D3DCOLOR_ARGB( 255, 255, 255, 255 ), DT_LEFT | DT_VCENTER ); + Element.FontColor.States[ DXUT_STATE_DISABLED ] = D3DCOLOR_ARGB( 200, 200, 200, 200 ); + Element.TextureColor.States[ DXUT_STATE_NORMAL ] = D3DCOLOR_ARGB( 150, 255, 255, 255 ); + Element.TextureColor.States[ DXUT_STATE_FOCUS ] = D3DCOLOR_ARGB( 200, 255, 255, 255 ); + Element.TextureColor.States[ DXUT_STATE_PRESSED ] = D3DCOLOR_ARGB( 255, 255, 255, 255 ); + + // Assign the Element + SetDefaultElement( DXUT_CONTROL_CHECKBOX, 0, &Element ); + + + //------------------------------------- + // CDXUTCheckBox - Check + //------------------------------------- + SetRect( &rcTexture, 27, 54, 54, 81 ); + Element.SetTexture( 0, &rcTexture ); + + // Assign the Element + SetDefaultElement( DXUT_CONTROL_CHECKBOX, 1, &Element ); + + + //------------------------------------- + // CDXUTRadioButton - Box + //------------------------------------- + SetRect( &rcTexture, 54, 54, 81, 81 ); + Element.SetTexture( 0, &rcTexture ); + Element.SetFont( 0, D3DCOLOR_ARGB( 255, 255, 255, 255 ), DT_LEFT | DT_VCENTER ); + Element.FontColor.States[ DXUT_STATE_DISABLED ] = D3DCOLOR_ARGB( 200, 200, 200, 200 ); + Element.TextureColor.States[ DXUT_STATE_NORMAL ] = D3DCOLOR_ARGB( 150, 255, 255, 255 ); + Element.TextureColor.States[ DXUT_STATE_FOCUS ] = D3DCOLOR_ARGB( 200, 255, 255, 255 ); + Element.TextureColor.States[ DXUT_STATE_PRESSED ] = D3DCOLOR_ARGB( 255, 255, 255, 255 ); + + // Assign the Element + SetDefaultElement( DXUT_CONTROL_RADIOBUTTON, 0, &Element ); + + + //------------------------------------- + // CDXUTRadioButton - Check + //------------------------------------- + SetRect( &rcTexture, 81, 54, 108, 81 ); + Element.SetTexture( 0, &rcTexture ); + + // Assign the Element + SetDefaultElement( DXUT_CONTROL_RADIOBUTTON, 1, &Element ); + + + //------------------------------------- + // CDXUTComboBox - Main + //------------------------------------- + SetRect( &rcTexture, 7, 81, 247, 123 ); + Element.SetTexture( 0, &rcTexture ); + Element.SetFont( 0 ); + Element.TextureColor.States[ DXUT_STATE_NORMAL ] = D3DCOLOR_ARGB( 150, 200, 200, 200 ); + Element.TextureColor.States[ DXUT_STATE_FOCUS ] = D3DCOLOR_ARGB( 170, 230, 230, 230 ); + Element.TextureColor.States[ DXUT_STATE_DISABLED ] = D3DCOLOR_ARGB( 70, 200, 200, 200 ); + Element.FontColor.States[ DXUT_STATE_MOUSEOVER ] = D3DCOLOR_ARGB( 255, 0, 0, 0 ); + Element.FontColor.States[ DXUT_STATE_PRESSED ] = D3DCOLOR_ARGB( 255, 0, 0, 0 ); + Element.FontColor.States[ DXUT_STATE_DISABLED ] = D3DCOLOR_ARGB( 200, 200, 200, 200 ); + + + // Assign the Element + SetDefaultElement( DXUT_CONTROL_COMBOBOX, 0, &Element ); + + + //------------------------------------- + // CDXUTComboBox - Button + //------------------------------------- + SetRect( &rcTexture, 98, 189, 151, 238 ); + Element.SetTexture( 0, &rcTexture ); + Element.TextureColor.States[ DXUT_STATE_NORMAL ] = D3DCOLOR_ARGB( 150, 255, 255, 255 ); + Element.TextureColor.States[ DXUT_STATE_PRESSED ] = D3DCOLOR_ARGB( 255, 150, 150, 150 ); + Element.TextureColor.States[ DXUT_STATE_FOCUS ] = D3DCOLOR_ARGB( 200, 255, 255, 255 ); + Element.TextureColor.States[ DXUT_STATE_DISABLED ] = D3DCOLOR_ARGB( 70, 255, 255, 255 ); + + // Assign the Element + SetDefaultElement( DXUT_CONTROL_COMBOBOX, 1, &Element ); + + + //------------------------------------- + // CDXUTComboBox - Dropdown + //------------------------------------- + SetRect( &rcTexture, 13, 123, 241, 160 ); + Element.SetTexture( 0, &rcTexture ); + Element.SetFont( 0, D3DCOLOR_ARGB( 255, 0, 0, 0 ), DT_LEFT | DT_TOP ); + + // Assign the Element + SetDefaultElement( DXUT_CONTROL_COMBOBOX, 2, &Element ); + + + //------------------------------------- + // CDXUTComboBox - Selection + //------------------------------------- + SetRect( &rcTexture, 12, 163, 239, 183 ); + Element.SetTexture( 0, &rcTexture ); + Element.SetFont( 0, D3DCOLOR_ARGB( 255, 255, 255, 255 ), DT_LEFT | DT_TOP ); + + // Assign the Element + SetDefaultElement( DXUT_CONTROL_COMBOBOX, 3, &Element ); + + + //------------------------------------- + // CDXUTSlider - Track + //------------------------------------- + SetRect( &rcTexture, 1, 187, 93, 228 ); + Element.SetTexture( 0, &rcTexture ); + Element.TextureColor.States[ DXUT_STATE_NORMAL ] = D3DCOLOR_ARGB( 150, 255, 255, 255 ); + Element.TextureColor.States[ DXUT_STATE_FOCUS ] = D3DCOLOR_ARGB( 200, 255, 255, 255 ); + Element.TextureColor.States[ DXUT_STATE_DISABLED ] = D3DCOLOR_ARGB( 70, 255, 255, 255 ); + + // Assign the Element + SetDefaultElement( DXUT_CONTROL_SLIDER, 0, &Element ); + + //------------------------------------- + // CDXUTSlider - Button + //------------------------------------- + SetRect( &rcTexture, 151, 193, 192, 234 ); + Element.SetTexture( 0, &rcTexture ); + + // Assign the Element + SetDefaultElement( DXUT_CONTROL_SLIDER, 1, &Element ); + + //------------------------------------- + // CDXUTScrollBar - Track + //------------------------------------- + int nScrollBarStartX = 196; + int nScrollBarStartY = 191; + SetRect( &rcTexture, nScrollBarStartX + 0, nScrollBarStartY + 21, nScrollBarStartX + 22, nScrollBarStartY + 32 ); + Element.SetTexture( 0, &rcTexture ); + Element.TextureColor.States[ DXUT_STATE_DISABLED ] = D3DCOLOR_ARGB( 255, 200, 200, 200 ); + + // Assign the Element + SetDefaultElement( DXUT_CONTROL_SCROLLBAR, 0, &Element ); + + //------------------------------------- + // CDXUTScrollBar - Up Arrow + //------------------------------------- + SetRect( &rcTexture, nScrollBarStartX + 0, nScrollBarStartY + 1, nScrollBarStartX + 22, nScrollBarStartY + 21 ); + Element.SetTexture( 0, &rcTexture ); + Element.TextureColor.States[ DXUT_STATE_DISABLED ] = D3DCOLOR_ARGB( 255, 200, 200, 200 ); + + + // Assign the Element + SetDefaultElement( DXUT_CONTROL_SCROLLBAR, 1, &Element ); + + //------------------------------------- + // CDXUTScrollBar - Down Arrow + //------------------------------------- + SetRect( &rcTexture, nScrollBarStartX + 0, nScrollBarStartY + 32, nScrollBarStartX + 22, nScrollBarStartY + 53 ); + Element.SetTexture( 0, &rcTexture ); + Element.TextureColor.States[ DXUT_STATE_DISABLED ] = D3DCOLOR_ARGB( 255, 200, 200, 200 ); + + + // Assign the Element + SetDefaultElement( DXUT_CONTROL_SCROLLBAR, 2, &Element ); + + //------------------------------------- + // CDXUTScrollBar - Button + //------------------------------------- + SetRect( &rcTexture, 220, 192, 238, 234 ); + Element.SetTexture( 0, &rcTexture ); + + // Assign the Element + SetDefaultElement( DXUT_CONTROL_SCROLLBAR, 3, &Element ); + + + //------------------------------------- + // CDXUTEditBox + //------------------------------------- + // Element assignment: + // 0 - text area + // 1 - top left border + // 2 - top border + // 3 - top right border + // 4 - left border + // 5 - right border + // 6 - lower left border + // 7 - lower border + // 8 - lower right border + + Element.SetFont( 0, D3DCOLOR_ARGB( 255, 0, 0, 0 ), DT_LEFT | DT_TOP ); + + // Assign the style + SetRect( &rcTexture, 14, 90, 241, 113 ); + Element.SetTexture( 0, &rcTexture ); + SetDefaultElement( DXUT_CONTROL_EDITBOX, 0, &Element ); + SetRect( &rcTexture, 8, 82, 14, 90 ); + Element.SetTexture( 0, &rcTexture ); + SetDefaultElement( DXUT_CONTROL_EDITBOX, 1, &Element ); + SetRect( &rcTexture, 14, 82, 241, 90 ); + Element.SetTexture( 0, &rcTexture ); + SetDefaultElement( DXUT_CONTROL_EDITBOX, 2, &Element ); + SetRect( &rcTexture, 241, 82, 246, 90 ); + Element.SetTexture( 0, &rcTexture ); + SetDefaultElement( DXUT_CONTROL_EDITBOX, 3, &Element ); + SetRect( &rcTexture, 8, 90, 14, 113 ); + Element.SetTexture( 0, &rcTexture ); + SetDefaultElement( DXUT_CONTROL_EDITBOX, 4, &Element ); + SetRect( &rcTexture, 241, 90, 246, 113 ); + Element.SetTexture( 0, &rcTexture ); + SetDefaultElement( DXUT_CONTROL_EDITBOX, 5, &Element ); + SetRect( &rcTexture, 8, 113, 14, 121 ); + Element.SetTexture( 0, &rcTexture ); + SetDefaultElement( DXUT_CONTROL_EDITBOX, 6, &Element ); + SetRect( &rcTexture, 14, 113, 241, 121 ); + Element.SetTexture( 0, &rcTexture ); + SetDefaultElement( DXUT_CONTROL_EDITBOX, 7, &Element ); + SetRect( &rcTexture, 241, 113, 246, 121 ); + Element.SetTexture( 0, &rcTexture ); + SetDefaultElement( DXUT_CONTROL_EDITBOX, 8, &Element ); + + //------------------------------------- + // CDXUTListBox - Main + //------------------------------------- + SetRect( &rcTexture, 13, 123, 241, 160 ); + Element.SetTexture( 0, &rcTexture ); + Element.SetFont( 0, D3DCOLOR_ARGB( 255, 0, 0, 0 ), DT_LEFT | DT_TOP ); + + // Assign the Element + SetDefaultElement( DXUT_CONTROL_LISTBOX, 0, &Element ); + + //------------------------------------- + // CDXUTListBox - Selection + //------------------------------------- + + SetRect( &rcTexture, 16, 166, 240, 183 ); + Element.SetTexture( 0, &rcTexture ); + Element.SetFont( 0, D3DCOLOR_ARGB( 255, 255, 255, 255 ), DT_LEFT | DT_TOP ); + + // Assign the Element + SetDefaultElement( DXUT_CONTROL_LISTBOX, 1, &Element ); +} + + + +//-------------------------------------------------------------------------------------- +// CDXUTControl class +//-------------------------------------------------------------------------------------- + +//-------------------------------------------------------------------------------------- +CDXUTControl::CDXUTControl( CDXUTDialog* pDialog ) +{ + m_Type = DXUT_CONTROL_BUTTON; + m_pDialog = pDialog; + m_ID = 0; + m_Index = 0; + m_pUserData = NULL; + + m_bEnabled = true; + m_bVisible = true; + m_bMouseOver = false; + m_bHasFocus = false; + m_bIsDefault = false; + + m_pDialog = NULL; + + m_x = 0; + m_y = 0; + m_width = 0; + m_height = 0; + + ZeroMemory( &m_rcBoundingBox, sizeof( m_rcBoundingBox ) ); +} + + +CDXUTControl::~CDXUTControl() +{ + for( int i = 0; i < m_Elements.GetSize(); ++i ) + { + delete m_Elements[i]; + } + m_Elements.RemoveAll(); +} + + +//-------------------------------------------------------------------------------------- +void CDXUTControl::SetTextColor( D3DCOLOR Color ) +{ + CDXUTElement* pElement = m_Elements.GetAt( 0 ); + + if( pElement ) + pElement->FontColor.States[DXUT_STATE_NORMAL] = Color; +} + + +//-------------------------------------------------------------------------------------- +HRESULT CDXUTControl::SetElement( UINT iElement, CDXUTElement* pElement ) +{ + HRESULT hr = S_OK; + + if( pElement == NULL ) + return E_INVALIDARG; + + // Make certain the array is this large + for( UINT i = m_Elements.GetSize(); i <= iElement; i++ ) + { + CDXUTElement* pNewElement = new CDXUTElement(); + if( pNewElement == NULL ) + return E_OUTOFMEMORY; + + hr = m_Elements.Add( pNewElement ); + if( FAILED( hr ) ) + { + SAFE_DELETE( pNewElement ); + return hr; + } + } + + // Update the data + CDXUTElement* pCurElement = m_Elements.GetAt( iElement ); + *pCurElement = *pElement; + + return S_OK; +} + + +//-------------------------------------------------------------------------------------- +void CDXUTControl::Refresh() +{ + m_bMouseOver = false; + m_bHasFocus = false; + + for( int i = 0; i < m_Elements.GetSize(); i++ ) + { + CDXUTElement* pElement = m_Elements.GetAt( i ); + pElement->Refresh(); + } +} + + +//-------------------------------------------------------------------------------------- +void CDXUTControl::UpdateRects() +{ + SetRect( &m_rcBoundingBox, m_x, m_y, m_x + m_width, m_y + m_height ); +} + + +//-------------------------------------------------------------------------------------- +// CDXUTStatic class +//-------------------------------------------------------------------------------------- + +//-------------------------------------------------------------------------------------- +CDXUTStatic::CDXUTStatic( CDXUTDialog* pDialog ) +{ + m_Type = DXUT_CONTROL_STATIC; + m_pDialog = pDialog; + + ZeroMemory( &m_strText, sizeof( m_strText ) ); + + for( int i = 0; i < m_Elements.GetSize(); i++ ) + { + CDXUTElement* pElement = m_Elements.GetAt( i ); + SAFE_DELETE( pElement ); + } + + m_Elements.RemoveAll(); +} + + +//-------------------------------------------------------------------------------------- +void CDXUTStatic::Render( float fElapsedTime ) +{ + if( m_bVisible == false ) + return; + + DXUT_CONTROL_STATE iState = DXUT_STATE_NORMAL; + + if( m_bEnabled == false ) + iState = DXUT_STATE_DISABLED; + + CDXUTElement* pElement = m_Elements.GetAt( 0 ); + + pElement->FontColor.Blend( iState, fElapsedTime ); + + m_pDialog->DrawText( m_strText, pElement, &m_rcBoundingBox, false, -1, false); +} + + +//-------------------------------------------------------------------------------------- +HRESULT CDXUTStatic::GetTextCopy( __out_ecount(bufferCount) LPWSTR strDest, + UINT bufferCount ) +{ + // Validate incoming parameters + if( strDest == NULL || bufferCount == 0 ) + { + return E_INVALIDARG; + } + + // Copy the window text + wcscpy_s( strDest, bufferCount, m_strText ); + + return S_OK; +} + + +//-------------------------------------------------------------------------------------- +HRESULT CDXUTStatic::SetText( LPCWSTR strText ) +{ + if( strText == NULL ) + { + m_strText[0] = 0; + return S_OK; + } + + wcscpy_s( m_strText, MAX_PATH, strText ); + return S_OK; +} + + +//-------------------------------------------------------------------------------------- +// CDXUTButton class +//-------------------------------------------------------------------------------------- + +//-------------------------------------------------------------------------------------- +CDXUTButton::CDXUTButton( CDXUTDialog* pDialog ) +{ + m_Type = DXUT_CONTROL_BUTTON; + m_pDialog = pDialog; + + m_bPressed = false; + m_nHotkey = 0; +} + +//-------------------------------------------------------------------------------------- +bool CDXUTButton::HandleKeyboard( UINT uMsg, WPARAM wParam, LPARAM lParam ) +{ + if( !m_bEnabled || !m_bVisible ) + return false; + + switch( uMsg ) + { + case WM_KEYDOWN: + { + switch( wParam ) + { + case VK_SPACE: + m_bPressed = true; + return true; + } + } + + case WM_KEYUP: + { + switch( wParam ) + { + case VK_SPACE: + if( m_bPressed == true ) + { + m_bPressed = false; + m_pDialog->SendEvent( EVENT_BUTTON_CLICKED, true, this ); + } + return true; + } + } + } + return false; +} + + +//-------------------------------------------------------------------------------------- +bool CDXUTButton::HandleMouse( UINT uMsg, POINT pt, WPARAM wParam, LPARAM lParam ) +{ + if( !m_bEnabled || !m_bVisible ) + return false; + + switch( uMsg ) + { + case WM_LBUTTONDOWN: + case WM_LBUTTONDBLCLK: + { + if( ContainsPoint( pt ) ) + { + // Pressed while inside the control + m_bPressed = true; + SetCapture( DXUTGetHWND() ); + + if( !m_bHasFocus ) + m_pDialog->RequestFocus( this ); + + return true; + } + + break; + } + + case WM_LBUTTONUP: + { + if( m_bPressed ) + { + m_bPressed = false; + ReleaseCapture(); + + if( !m_pDialog->m_bKeyboardInput ) + m_pDialog->ClearFocus(); + + // Button click + if( ContainsPoint( pt ) ) + m_pDialog->SendEvent( EVENT_BUTTON_CLICKED, true, this ); + + return true; + } + + break; + } + }; + + return false; +} + +//-------------------------------------------------------------------------------------- +void CDXUTButton::Render( float fElapsedTime ) +{ + if( m_bVisible == false ) + return; + + int nOffsetX = 0; + int nOffsetY = 0; + + DXUT_CONTROL_STATE iState = DXUT_STATE_NORMAL; + + if( m_bVisible == false ) + { + iState = DXUT_STATE_HIDDEN; + } + else if( m_bEnabled == false ) + { + iState = DXUT_STATE_DISABLED; + } + else if( m_bPressed ) + { + iState = DXUT_STATE_PRESSED; + + nOffsetX = 1; + nOffsetY = 2; + } + else if( m_bMouseOver ) + { + iState = DXUT_STATE_MOUSEOVER; + + nOffsetX = -1; + nOffsetY = -2; + } + else if( m_bHasFocus ) + { + iState = DXUT_STATE_FOCUS; + } + + // Background fill layer + CDXUTElement* pElement = m_Elements.GetAt( 0 ); + + float fBlendRate = ( iState == DXUT_STATE_PRESSED ) ? 0.0f : 0.8f; + + RECT rcWindow = m_rcBoundingBox; + OffsetRect( &rcWindow, nOffsetX, nOffsetY ); + + + // Blend current color + pElement->TextureColor.Blend( iState, fElapsedTime, fBlendRate ); + pElement->FontColor.Blend( iState, fElapsedTime, fBlendRate ); + + m_pDialog->DrawSprite( pElement, &rcWindow, DXUT_FAR_BUTTON_DEPTH ); + m_pDialog->DrawText( m_strText, pElement, &rcWindow, false, -1, true ); + + // Main button + pElement = m_Elements.GetAt( 1 ); + + // Blend current color + pElement->TextureColor.Blend( iState, fElapsedTime, fBlendRate ); + pElement->FontColor.Blend( iState, fElapsedTime, fBlendRate ); + + m_pDialog->DrawSprite( pElement, &rcWindow, DXUT_NEAR_BUTTON_DEPTH ); + m_pDialog->DrawText( m_strText, pElement, &rcWindow, false, -1, true ); +} + + + +//-------------------------------------------------------------------------------------- +// CDXUTCheckBox class +//-------------------------------------------------------------------------------------- + +//-------------------------------------------------------------------------------------- +CDXUTCheckBox::CDXUTCheckBox( CDXUTDialog* pDialog ) +{ + m_Type = DXUT_CONTROL_CHECKBOX; + m_pDialog = pDialog; + + m_bChecked = false; +} + + +//-------------------------------------------------------------------------------------- +bool CDXUTCheckBox::HandleKeyboard( UINT uMsg, WPARAM wParam, LPARAM lParam ) +{ + if( !m_bEnabled || !m_bVisible ) + return false; + + switch( uMsg ) + { + case WM_KEYDOWN: + { + switch( wParam ) + { + case VK_SPACE: + m_bPressed = true; + return true; + } + } + + case WM_KEYUP: + { + switch( wParam ) + { + case VK_SPACE: + if( m_bPressed == true ) + { + m_bPressed = false; + SetCheckedInternal( !m_bChecked, true ); + } + return true; + } + } + } + return false; +} + + +//-------------------------------------------------------------------------------------- +bool CDXUTCheckBox::HandleMouse( UINT uMsg, POINT pt, WPARAM wParam, LPARAM lParam ) +{ + if( !m_bEnabled || !m_bVisible ) + return false; + + switch( uMsg ) + { + case WM_LBUTTONDOWN: + case WM_LBUTTONDBLCLK: + { + if( ContainsPoint( pt ) ) + { + // Pressed while inside the control + m_bPressed = true; + SetCapture( DXUTGetHWND() ); + + if( !m_bHasFocus ) + m_pDialog->RequestFocus( this ); + + return true; + } + + break; + } + + case WM_LBUTTONUP: + { + if( m_bPressed ) + { + m_bPressed = false; + ReleaseCapture(); + + // Button click + if( ContainsPoint( pt ) ) + SetCheckedInternal( !m_bChecked, true ); + + return true; + } + + break; + } + }; + + return false; +} + + +//-------------------------------------------------------------------------------------- +void CDXUTCheckBox::SetCheckedInternal( bool bChecked, bool bFromInput ) +{ + m_bChecked = bChecked; + + m_pDialog->SendEvent( EVENT_CHECKBOX_CHANGED, bFromInput, this ); +} + + +//-------------------------------------------------------------------------------------- +BOOL CDXUTCheckBox::ContainsPoint( POINT pt ) +{ + return ( PtInRect( &m_rcBoundingBox, pt ) || + PtInRect( &m_rcButton, pt ) ); +} + + + +//-------------------------------------------------------------------------------------- +void CDXUTCheckBox::UpdateRects() +{ + CDXUTButton::UpdateRects(); + + m_rcButton = m_rcBoundingBox; + m_rcButton.right = m_rcButton.left + RectHeight( m_rcButton ); + + m_rcText = m_rcBoundingBox; + m_rcText.left += ( int )( 1.25f * RectWidth( m_rcButton ) ); +} + + + +//-------------------------------------------------------------------------------------- +void CDXUTCheckBox::Render( float fElapsedTime ) +{ + if( m_bVisible == false ) + return; + DXUT_CONTROL_STATE iState = DXUT_STATE_NORMAL; + + if( m_bVisible == false ) + iState = DXUT_STATE_HIDDEN; + else if( m_bEnabled == false ) + iState = DXUT_STATE_DISABLED; + else if( m_bPressed ) + iState = DXUT_STATE_PRESSED; + else if( m_bMouseOver ) + iState = DXUT_STATE_MOUSEOVER; + else if( m_bHasFocus ) + iState = DXUT_STATE_FOCUS; + + CDXUTElement* pElement = m_Elements.GetAt( 0 ); + + float fBlendRate = ( iState == DXUT_STATE_PRESSED ) ? 0.0f : 0.8f; + + pElement->TextureColor.Blend( iState, fElapsedTime, fBlendRate ); + pElement->FontColor.Blend( iState, fElapsedTime, fBlendRate ); + + m_pDialog->DrawSprite( pElement, &m_rcButton, DXUT_NEAR_BUTTON_DEPTH ); + m_pDialog->DrawText( m_strText, pElement, &m_rcText, false, -1, false ); + + if( !m_bChecked ) + iState = DXUT_STATE_HIDDEN; + + pElement = m_Elements.GetAt( 1 ); + + pElement->TextureColor.Blend( iState, fElapsedTime, fBlendRate ); + m_pDialog->DrawSprite( pElement, &m_rcButton, DXUT_FAR_BUTTON_DEPTH ); +} + + + + +//-------------------------------------------------------------------------------------- +// CDXUTRadioButton class +//-------------------------------------------------------------------------------------- + +//-------------------------------------------------------------------------------------- +CDXUTRadioButton::CDXUTRadioButton( CDXUTDialog* pDialog ) +{ + m_Type = DXUT_CONTROL_RADIOBUTTON; + m_pDialog = pDialog; +} + + + +//-------------------------------------------------------------------------------------- +bool CDXUTRadioButton::HandleKeyboard( UINT uMsg, WPARAM wParam, LPARAM lParam ) +{ + if( !m_bEnabled || !m_bVisible ) + return false; + + switch( uMsg ) + { + case WM_KEYDOWN: + { + switch( wParam ) + { + case VK_SPACE: + m_bPressed = true; + return true; + } + } + + case WM_KEYUP: + { + switch( wParam ) + { + case VK_SPACE: + if( m_bPressed == true ) + { + m_bPressed = false; + + m_pDialog->ClearRadioButtonGroup( m_nButtonGroup ); + m_bChecked = !m_bChecked; + + m_pDialog->SendEvent( EVENT_RADIOBUTTON_CHANGED, true, this ); + } + return true; + } + } + } + return false; +} + + +//-------------------------------------------------------------------------------------- +bool CDXUTRadioButton::HandleMouse( UINT uMsg, POINT pt, WPARAM wParam, LPARAM lParam ) +{ + if( !m_bEnabled || !m_bVisible ) + return false; + + switch( uMsg ) + { + case WM_LBUTTONDOWN: + case WM_LBUTTONDBLCLK: + { + if( ContainsPoint( pt ) ) + { + // Pressed while inside the control + m_bPressed = true; + SetCapture( DXUTGetHWND() ); + + if( !m_bHasFocus ) + m_pDialog->RequestFocus( this ); + + return true; + } + + break; + } + + case WM_LBUTTONUP: + { + if( m_bPressed ) + { + m_bPressed = false; + ReleaseCapture(); + + // Button click + if( ContainsPoint( pt ) ) + { + m_pDialog->ClearRadioButtonGroup( m_nButtonGroup ); + m_bChecked = !m_bChecked; + + m_pDialog->SendEvent( EVENT_RADIOBUTTON_CHANGED, true, this ); + } + + return true; + } + + break; + } + }; + + return false; +} + +//-------------------------------------------------------------------------------------- +void CDXUTRadioButton::SetCheckedInternal( bool bChecked, bool bClearGroup, bool bFromInput ) +{ + if( bChecked && bClearGroup ) + m_pDialog->ClearRadioButtonGroup( m_nButtonGroup ); + + m_bChecked = bChecked; + m_pDialog->SendEvent( EVENT_RADIOBUTTON_CHANGED, bFromInput, this ); +} + + + + +//-------------------------------------------------------------------------------------- +// CDXUTComboBox class +//-------------------------------------------------------------------------------------- + +//-------------------------------------------------------------------------------------- +CDXUTComboBox::CDXUTComboBox( CDXUTDialog* pDialog ) : m_ScrollBar( pDialog ) +{ + m_Type = DXUT_CONTROL_COMBOBOX; + m_pDialog = pDialog; + + m_nDropHeight = 100; + + m_nSBWidth = 16; + m_bOpened = false; + m_iSelected = -1; + m_iFocused = -1; +} + + +//-------------------------------------------------------------------------------------- +CDXUTComboBox::~CDXUTComboBox() +{ + RemoveAllItems(); +} + + +//-------------------------------------------------------------------------------------- +void CDXUTComboBox::SetTextColor( D3DCOLOR Color ) +{ + CDXUTElement* pElement = m_Elements.GetAt( 0 ); + + if( pElement ) + pElement->FontColor.States[DXUT_STATE_NORMAL] = Color; + + pElement = m_Elements.GetAt( 2 ); + + if( pElement ) + pElement->FontColor.States[DXUT_STATE_NORMAL] = Color; +} + + +//-------------------------------------------------------------------------------------- +void CDXUTComboBox::UpdateRects() +{ + + CDXUTButton::UpdateRects(); + + m_rcButton = m_rcBoundingBox; + m_rcButton.left = m_rcButton.right - RectHeight( m_rcButton ); + + m_rcText = m_rcBoundingBox; + m_rcText.right = m_rcButton.left; + + m_rcDropdown = m_rcText; + OffsetRect( &m_rcDropdown, 0, ( int )( 0.90f * RectHeight( m_rcText ) ) ); + m_rcDropdown.bottom += m_nDropHeight; + m_rcDropdown.right -= m_nSBWidth; + + m_rcDropdownText = m_rcDropdown; + m_rcDropdownText.left += ( int )( 0.1f * RectWidth( m_rcDropdown ) ); + m_rcDropdownText.right -= ( int )( 0.1f * RectWidth( m_rcDropdown ) ); + m_rcDropdownText.top += ( int )( 0.1f * RectHeight( m_rcDropdown ) ); + m_rcDropdownText.bottom -= ( int )( 0.1f * RectHeight( m_rcDropdown ) ); + + // Update the scrollbar's rects + m_ScrollBar.SetLocation( m_rcDropdown.right, m_rcDropdown.top + 2 ); + m_ScrollBar.SetSize( m_nSBWidth, RectHeight( m_rcDropdown ) - 2 ); + DXUTFontNode* pFontNode = m_pDialog->GetManager()->GetFontNode( m_Elements.GetAt( 2 )->iFont ); + if( pFontNode && pFontNode->nHeight ) + { + m_ScrollBar.SetPageSize( RectHeight( m_rcDropdownText ) / pFontNode->nHeight ); + + // The selected item may have been scrolled off the page. + // Ensure that it is in page again. + m_ScrollBar.ShowItem( m_iSelected ); + } +} + + +//-------------------------------------------------------------------------------------- +void CDXUTComboBox::OnFocusOut() +{ + CDXUTButton::OnFocusOut(); + + m_bOpened = false; +} + + +//-------------------------------------------------------------------------------------- +bool CDXUTComboBox::HandleKeyboard( UINT uMsg, WPARAM wParam, LPARAM lParam ) +{ + const DWORD REPEAT_MASK = ( 0x40000000 ); + + if( !m_bEnabled || !m_bVisible ) + return false; + + // Let the scroll bar have a chance to handle it first + if( m_ScrollBar.HandleKeyboard( uMsg, wParam, lParam ) ) + return true; + + switch( uMsg ) + { + case WM_KEYDOWN: + { + switch( wParam ) + { + case VK_RETURN: + if( m_bOpened ) + { + if( m_iSelected != m_iFocused ) + { + m_iSelected = m_iFocused; + m_pDialog->SendEvent( EVENT_COMBOBOX_SELECTION_CHANGED, true, this ); + } + m_bOpened = false; + + if( !m_pDialog->m_bKeyboardInput ) + m_pDialog->ClearFocus(); + + return true; + } + break; + + case VK_F4: + // Filter out auto-repeats + if( lParam & REPEAT_MASK ) + return true; + + m_bOpened = !m_bOpened; + + if( !m_bOpened ) + { + m_pDialog->SendEvent( EVENT_COMBOBOX_SELECTION_CHANGED, true, this ); + + if( !m_pDialog->m_bKeyboardInput ) + m_pDialog->ClearFocus(); + } + + return true; + + case VK_LEFT: + case VK_UP: + if( m_iFocused > 0 ) + { + m_iFocused--; + m_iSelected = m_iFocused; + + if( !m_bOpened ) + m_pDialog->SendEvent( EVENT_COMBOBOX_SELECTION_CHANGED, true, this ); + } + + return true; + + case VK_RIGHT: + case VK_DOWN: + if( m_iFocused + 1 < ( int )GetNumItems() ) + { + m_iFocused++; + m_iSelected = m_iFocused; + + if( !m_bOpened ) + m_pDialog->SendEvent( EVENT_COMBOBOX_SELECTION_CHANGED, true, this ); + } + + return true; + } + break; + } + } + + return false; +} + + +//-------------------------------------------------------------------------------------- +bool CDXUTComboBox::HandleMouse( UINT uMsg, POINT pt, WPARAM wParam, LPARAM lParam ) +{ + if( !m_bEnabled || !m_bVisible ) + return false; + + // Let the scroll bar handle it first. + if( m_ScrollBar.HandleMouse( uMsg, pt, wParam, lParam ) ) + return true; + + switch( uMsg ) + { + case WM_MOUSEMOVE: + { + if( m_bOpened && PtInRect( &m_rcDropdown, pt ) ) + { + // Determine which item has been selected + for( int i = 0; i < m_Items.GetSize(); i++ ) + { + DXUTComboBoxItem* pItem = m_Items.GetAt( i ); + if( pItem->bVisible && + PtInRect( &pItem->rcActive, pt ) ) + { + m_iFocused = i; + } + } + return true; + } + break; + } + + case WM_LBUTTONDOWN: + case WM_LBUTTONDBLCLK: + { + if( ContainsPoint( pt ) ) + { + // Pressed while inside the control + m_bPressed = true; + SetCapture( DXUTGetHWND() ); + + if( !m_bHasFocus ) + m_pDialog->RequestFocus( this ); + + // Toggle dropdown + if( m_bHasFocus ) + { + m_bOpened = !m_bOpened; + + if( !m_bOpened ) + { + if( !m_pDialog->m_bKeyboardInput ) + m_pDialog->ClearFocus(); + } + } + + return true; + } + + // Perhaps this click is within the dropdown + if( m_bOpened && PtInRect( &m_rcDropdown, pt ) ) + { + // Determine which item has been selected + for( int i = m_ScrollBar.GetTrackPos(); i < m_Items.GetSize(); i++ ) + { + DXUTComboBoxItem* pItem = m_Items.GetAt( i ); + if( pItem->bVisible && + PtInRect( &pItem->rcActive, pt ) ) + { + m_iFocused = m_iSelected = i; + m_pDialog->SendEvent( EVENT_COMBOBOX_SELECTION_CHANGED, true, this ); + m_bOpened = false; + + if( !m_pDialog->m_bKeyboardInput ) + m_pDialog->ClearFocus(); + + break; + } + } + + return true; + } + + // Mouse click not on main control or in dropdown, fire an event if needed + if( m_bOpened ) + { + m_iFocused = m_iSelected; + + m_pDialog->SendEvent( EVENT_COMBOBOX_SELECTION_CHANGED, true, this ); + m_bOpened = false; + } + + // Make sure the control is no longer in a pressed state + m_bPressed = false; + + // Release focus if appropriate + if( !m_pDialog->m_bKeyboardInput ) + { + m_pDialog->ClearFocus(); + } + + break; + } + + case WM_LBUTTONUP: + { + if( m_bPressed && ContainsPoint( pt ) ) + { + // Button click + m_bPressed = false; + ReleaseCapture(); + return true; + } + + break; + } + + case WM_MOUSEWHEEL: + { + int zDelta = ( short )HIWORD( wParam ) / WHEEL_DELTA; + if( m_bOpened ) + { + UINT uLines; + SystemParametersInfo( SPI_GETWHEELSCROLLLINES, 0, &uLines, 0 ); + m_ScrollBar.Scroll( -zDelta * uLines ); + } + else + { + if( zDelta > 0 ) + { + if( m_iFocused > 0 ) + { + m_iFocused--; + m_iSelected = m_iFocused; + + if( !m_bOpened ) + m_pDialog->SendEvent( EVENT_COMBOBOX_SELECTION_CHANGED, true, this ); + } + } + else + { + if( m_iFocused + 1 < ( int )GetNumItems() ) + { + m_iFocused++; + m_iSelected = m_iFocused; + + if( !m_bOpened ) + m_pDialog->SendEvent( EVENT_COMBOBOX_SELECTION_CHANGED, true, this ); + } + } + } + return true; + } + }; + + return false; +} + + +//-------------------------------------------------------------------------------------- +void CDXUTComboBox::OnHotkey() +{ + if( m_bOpened ) + return; + + if( m_iSelected == -1 ) + return; + + if( m_pDialog->IsKeyboardInputEnabled() ) + m_pDialog->RequestFocus( this ); + + m_iSelected++; + + if( m_iSelected >= ( int )m_Items.GetSize() ) + m_iSelected = 0; + + m_iFocused = m_iSelected; + m_pDialog->SendEvent( EVENT_COMBOBOX_SELECTION_CHANGED, true, this ); +} + + +//-------------------------------------------------------------------------------------- +void CDXUTComboBox::Render( float fElapsedTime ) +{ + if( m_bVisible == false ) + return; + DXUT_CONTROL_STATE iState = DXUT_STATE_NORMAL; + + if( !m_bOpened ) + iState = DXUT_STATE_HIDDEN; + + // Dropdown box + CDXUTElement* pElement = m_Elements.GetAt( 2 ); + + // If we have not initialized the scroll bar page size, + // do that now. + static bool bSBInit; + if( !bSBInit ) + { + // Update the page size of the scroll bar + if( m_pDialog->GetManager()->GetFontNode( pElement->iFont )->nHeight ) + m_ScrollBar.SetPageSize( RectHeight( m_rcDropdownText ) / + m_pDialog->GetManager()->GetFontNode( pElement->iFont )->nHeight ); + else + m_ScrollBar.SetPageSize( RectHeight( m_rcDropdownText ) ); + bSBInit = true; + } + + // Scroll bar + if( m_bOpened ) + m_ScrollBar.Render( fElapsedTime ); + + // Blend current color + pElement->TextureColor.Blend( iState, fElapsedTime ); + pElement->FontColor.Blend( iState, fElapsedTime ); + + m_pDialog->DrawSprite( pElement, &m_rcDropdown, DXUT_NEAR_BUTTON_DEPTH ); + + // Selection outline + CDXUTElement* pSelectionElement = m_Elements.GetAt( 3 ); + pSelectionElement->TextureColor.Current = pElement->TextureColor.Current; + pSelectionElement->FontColor.Current = pSelectionElement->FontColor.States[ DXUT_STATE_NORMAL ]; + + DXUTFontNode* pFont = m_pDialog->GetFont( pElement->iFont ); + if( pFont ) + { + int curY = m_rcDropdownText.top; + int nRemainingHeight = RectHeight( m_rcDropdownText ); + //WCHAR strDropdown[4096] = {0}; + + for( int i = m_ScrollBar.GetTrackPos(); i < m_Items.GetSize(); i++ ) + { + DXUTComboBoxItem* pItem = m_Items.GetAt( i ); + + // Make sure there's room left in the dropdown + nRemainingHeight -= pFont->nHeight; + if( nRemainingHeight < 0 ) + { + pItem->bVisible = false; + continue; + } + + SetRect( &pItem->rcActive, m_rcDropdownText.left, curY, m_rcDropdownText.right, curY + pFont->nHeight ); + curY += pFont->nHeight; + + //debug + //int blue = 50 * i; + //m_pDialog->DrawRect( &pItem->rcActive, 0xFFFF0000 | blue ); + + pItem->bVisible = true; + + if( m_bOpened ) + { + if( ( int )i == m_iFocused ) + { + RECT rc; + SetRect( &rc, m_rcDropdown.left, pItem->rcActive.top - 2, m_rcDropdown.right, + pItem->rcActive.bottom + 2 ); + m_pDialog->DrawSprite( pSelectionElement, &rc, DXUT_NEAR_BUTTON_DEPTH ); + m_pDialog->DrawText( pItem->strText, pSelectionElement, &pItem->rcActive ); + } + else + { + m_pDialog->DrawText( pItem->strText, pElement, &pItem->rcActive ); + } + } + } + } + + int nOffsetX = 0; + int nOffsetY = 0; + + iState = DXUT_STATE_NORMAL; + + if( m_bVisible == false ) + iState = DXUT_STATE_HIDDEN; + else if( m_bEnabled == false ) + iState = DXUT_STATE_DISABLED; + else if( m_bPressed ) + { + iState = DXUT_STATE_PRESSED; + + nOffsetX = 1; + nOffsetY = 2; + } + else if( m_bMouseOver ) + { + iState = DXUT_STATE_MOUSEOVER; + + nOffsetX = -1; + nOffsetY = -2; + } + else if( m_bHasFocus ) + iState = DXUT_STATE_FOCUS; + + float fBlendRate = ( iState == DXUT_STATE_PRESSED ) ? 0.0f : 0.8f; + + // Button + pElement = m_Elements.GetAt( 1 ); + + // Blend current color + pElement->TextureColor.Blend( iState, fElapsedTime, fBlendRate ); + + RECT rcWindow = m_rcButton; + OffsetRect( &rcWindow, nOffsetX, nOffsetY ); + m_pDialog->DrawSprite( pElement, &rcWindow, DXUT_FAR_BUTTON_DEPTH ); + + if( m_bOpened ) + iState = DXUT_STATE_PRESSED; + + // Main text box + pElement = m_Elements.GetAt( 0 ); + + // Blend current color + pElement->TextureColor.Blend( iState, fElapsedTime, fBlendRate ); + pElement->FontColor.Blend( iState, fElapsedTime, fBlendRate ); + + m_pDialog->DrawSprite( pElement, &m_rcText, DXUT_NEAR_BUTTON_DEPTH ); + + if( m_iSelected >= 0 && m_iSelected < ( int )m_Items.GetSize() ) + { + DXUTComboBoxItem* pItem = m_Items.GetAt( m_iSelected ); + if( pItem != NULL ) + { + m_pDialog->DrawText( pItem->strText, pElement, &m_rcText, false, -1, true ); + + } + } +} + + +//-------------------------------------------------------------------------------------- +HRESULT CDXUTComboBox::AddItem( const WCHAR* strText, void* pData ) +{ + // Validate parameters + if( strText == NULL ) + { + return E_INVALIDARG; + } + + // Create a new item and set the data + DXUTComboBoxItem* pItem = new DXUTComboBoxItem; + if( pItem == NULL ) + { + return DXTRACE_ERR_MSGBOX( L"new", E_OUTOFMEMORY ); + } + + ZeroMemory( pItem, sizeof( DXUTComboBoxItem ) ); + wcscpy_s( pItem->strText, 256, strText ); + pItem->pData = pData; + + m_Items.Add( pItem ); + + // Update the scroll bar with new range + m_ScrollBar.SetTrackRange( 0, m_Items.GetSize() ); + + // If this is the only item in the list, it's selected + if( GetNumItems() == 1 ) + { + m_iSelected = 0; + m_iFocused = 0; + m_pDialog->SendEvent( EVENT_COMBOBOX_SELECTION_CHANGED, false, this ); + } + + return S_OK; +} + + +//-------------------------------------------------------------------------------------- +void CDXUTComboBox::RemoveItem( UINT index ) +{ + DXUTComboBoxItem* pItem = m_Items.GetAt( index ); + SAFE_DELETE( pItem ); + m_Items.Remove( index ); + m_ScrollBar.SetTrackRange( 0, m_Items.GetSize() ); + if( m_iSelected >= m_Items.GetSize() ) + m_iSelected = m_Items.GetSize() - 1; +} + + +//-------------------------------------------------------------------------------------- +void CDXUTComboBox::RemoveAllItems() +{ + for( int i = 0; i < m_Items.GetSize(); i++ ) + { + DXUTComboBoxItem* pItem = m_Items.GetAt( i ); + SAFE_DELETE( pItem ); + } + + m_Items.RemoveAll(); + m_ScrollBar.SetTrackRange( 0, 1 ); + m_iFocused = m_iSelected = -1; +} + + + +//-------------------------------------------------------------------------------------- +bool CDXUTComboBox::ContainsItem( const WCHAR* strText, UINT iStart ) +{ + return ( -1 != FindItem( strText, iStart ) ); +} + + +//-------------------------------------------------------------------------------------- +int CDXUTComboBox::FindItem( const WCHAR* strText, UINT iStart ) +{ + if( strText == NULL ) + return -1; + + for( int i = iStart; i < m_Items.GetSize(); i++ ) + { + DXUTComboBoxItem* pItem = m_Items.GetAt( i ); + + if( 0 == wcscmp( pItem->strText, strText ) ) + { + return i; + } + } + + return -1; +} + + +//-------------------------------------------------------------------------------------- +void* CDXUTComboBox::GetSelectedData() +{ + if( m_iSelected < 0 ) + return NULL; + + DXUTComboBoxItem* pItem = m_Items.GetAt( m_iSelected ); + return pItem->pData; +} + + +//-------------------------------------------------------------------------------------- +DXUTComboBoxItem* CDXUTComboBox::GetSelectedItem() +{ + if( m_iSelected < 0 ) + return NULL; + + return m_Items.GetAt( m_iSelected ); +} + + +//-------------------------------------------------------------------------------------- +void* CDXUTComboBox::GetItemData( const WCHAR* strText ) +{ + int index = FindItem( strText ); + if( index == -1 ) + { + return NULL; + } + + DXUTComboBoxItem* pItem = m_Items.GetAt( index ); + if( pItem == NULL ) + { + DXTRACE_ERR( L"CGrowableArray::GetAt", E_FAIL ); + return NULL; + } + + return pItem->pData; +} + + +//-------------------------------------------------------------------------------------- +void* CDXUTComboBox::GetItemData( int nIndex ) +{ + if( nIndex < 0 || nIndex >= m_Items.GetSize() ) + return NULL; + + return m_Items.GetAt( nIndex )->pData; +} + + +//-------------------------------------------------------------------------------------- +HRESULT CDXUTComboBox::SetSelectedByIndex( UINT index ) +{ + if( index >= GetNumItems() ) + return E_INVALIDARG; + + m_iFocused = m_iSelected = index; + m_pDialog->SendEvent( EVENT_COMBOBOX_SELECTION_CHANGED, false, this ); + + return S_OK; +} + + + +//-------------------------------------------------------------------------------------- +HRESULT CDXUTComboBox::SetSelectedByText( const WCHAR* strText ) +{ + if( strText == NULL ) + return E_INVALIDARG; + + int index = FindItem( strText ); + if( index == -1 ) + return E_FAIL; + + m_iFocused = m_iSelected = index; + m_pDialog->SendEvent( EVENT_COMBOBOX_SELECTION_CHANGED, false, this ); + + return S_OK; +} + + + +//-------------------------------------------------------------------------------------- +HRESULT CDXUTComboBox::SetSelectedByData( void* pData ) +{ + for( int i = 0; i < m_Items.GetSize(); i++ ) + { + DXUTComboBoxItem* pItem = m_Items.GetAt( i ); + + if( pItem->pData == pData ) + { + m_iFocused = m_iSelected = i; + m_pDialog->SendEvent( EVENT_COMBOBOX_SELECTION_CHANGED, false, this ); + return S_OK; + } + } + + return E_FAIL; +} + + + +//-------------------------------------------------------------------------------------- +CDXUTSlider::CDXUTSlider( CDXUTDialog* pDialog ) +{ + m_Type = DXUT_CONTROL_SLIDER; + m_pDialog = pDialog; + + m_nMin = 0; + m_nMax = 100; + m_nValue = 50; + + m_bPressed = false; +} + + +//-------------------------------------------------------------------------------------- +BOOL CDXUTSlider::ContainsPoint( POINT pt ) +{ + return ( PtInRect( &m_rcBoundingBox, pt ) || + PtInRect( &m_rcButton, pt ) ); +} + + +//-------------------------------------------------------------------------------------- +void CDXUTSlider::UpdateRects() +{ + CDXUTControl::UpdateRects(); + + m_rcButton = m_rcBoundingBox; + m_rcButton.right = m_rcButton.left + RectHeight( m_rcButton ); + OffsetRect( &m_rcButton, -RectWidth( m_rcButton ) / 2, 0 ); + + m_nButtonX = ( int )( ( m_nValue - m_nMin ) * ( float )RectWidth( m_rcBoundingBox ) / ( m_nMax - m_nMin ) ); + OffsetRect( &m_rcButton, m_nButtonX, 0 ); +} + +int CDXUTSlider::ValueFromPos( int x ) +{ + float fValuePerPixel = ( float )( m_nMax - m_nMin ) / RectWidth( m_rcBoundingBox ); + return ( int )( 0.5f + m_nMin + fValuePerPixel * ( x - m_rcBoundingBox.left ) ); +} + +//-------------------------------------------------------------------------------------- +bool CDXUTSlider::HandleKeyboard( UINT uMsg, WPARAM wParam, LPARAM lParam ) +{ + if( !m_bEnabled || !m_bVisible ) + return false; + + switch( uMsg ) + { + case WM_KEYDOWN: + { + switch( wParam ) + { + case VK_HOME: + SetValueInternal( m_nMin, true ); + return true; + + case VK_END: + SetValueInternal( m_nMax, true ); + return true; + + case VK_LEFT: + case VK_DOWN: + SetValueInternal( m_nValue - 1, true ); + return true; + + case VK_RIGHT: + case VK_UP: + SetValueInternal( m_nValue + 1, true ); + return true; + + case VK_NEXT: + SetValueInternal( m_nValue - ( 10 > ( m_nMax - m_nMin ) / 10 ? 10 : ( m_nMax - m_nMin ) / 10 ), + true ); + return true; + + case VK_PRIOR: + SetValueInternal( m_nValue + ( 10 > ( m_nMax - m_nMin ) / 10 ? 10 : ( m_nMax - m_nMin ) / 10 ), + true ); + return true; + } + break; + } + } + + + return false; +} + + +//-------------------------------------------------------------------------------------- +bool CDXUTSlider::HandleMouse( UINT uMsg, POINT pt, WPARAM wParam, LPARAM lParam ) +{ + if( !m_bEnabled || !m_bVisible ) + return false; + + switch( uMsg ) + { + case WM_LBUTTONDOWN: + case WM_LBUTTONDBLCLK: + { + if( PtInRect( &m_rcButton, pt ) ) + { + // Pressed while inside the control + m_bPressed = true; + SetCapture( DXUTGetHWND() ); + + m_nDragX = pt.x; + //m_nDragY = pt.y; + m_nDragOffset = m_nButtonX - m_nDragX; + + //m_nDragValue = m_nValue; + + if( !m_bHasFocus ) + m_pDialog->RequestFocus( this ); + + return true; + } + + if( PtInRect( &m_rcBoundingBox, pt ) ) + { + m_nDragX = pt.x; + m_nDragOffset = 0; + m_bPressed = true; + + if( !m_bHasFocus ) + m_pDialog->RequestFocus( this ); + + if( pt.x > m_nButtonX + m_x ) + { + SetValueInternal( m_nValue + 1, true ); + return true; + } + + if( pt.x < m_nButtonX + m_x ) + { + SetValueInternal( m_nValue - 1, true ); + return true; + } + } + + break; + } + + case WM_LBUTTONUP: + { + if( m_bPressed ) + { + m_bPressed = false; + ReleaseCapture(); + m_pDialog->SendEvent( EVENT_SLIDER_VALUE_CHANGED_UP, true, this ); + + return true; + } + + break; + } + + case WM_MOUSEMOVE: + { + if( m_bPressed ) + { + SetValueInternal( ValueFromPos( m_x + pt.x + m_nDragOffset ), true ); + return true; + } + + break; + } + + case WM_MOUSEWHEEL: + { + int nScrollAmount = int( ( short )HIWORD( wParam ) ) / WHEEL_DELTA; + SetValueInternal( m_nValue - nScrollAmount, true ); + return true; + } + }; + + return false; +} + + +//-------------------------------------------------------------------------------------- +void CDXUTSlider::SetRange( int nMin, int nMax ) +{ + m_nMin = nMin; + m_nMax = nMax; + + SetValueInternal( m_nValue, false ); +} + + +//-------------------------------------------------------------------------------------- +void CDXUTSlider::SetValueInternal( int nValue, bool bFromInput ) +{ + // Clamp to range + nValue = __max( m_nMin, nValue ); + nValue = __min( m_nMax, nValue ); + + if( nValue == m_nValue ) + return; + + m_nValue = nValue; + UpdateRects(); + + m_pDialog->SendEvent( EVENT_SLIDER_VALUE_CHANGED, bFromInput, this ); +} + + +//-------------------------------------------------------------------------------------- +void CDXUTSlider::Render( float fElapsedTime ) +{ + if( m_bVisible == false ) + return; + + int nOffsetX = 0; + int nOffsetY = 0; + + DXUT_CONTROL_STATE iState = DXUT_STATE_NORMAL; + + if( m_bVisible == false ) + { + iState = DXUT_STATE_HIDDEN; + } + else if( m_bEnabled == false ) + { + iState = DXUT_STATE_DISABLED; + } + else if( m_bPressed ) + { + iState = DXUT_STATE_PRESSED; + + nOffsetX = 1; + nOffsetY = 2; + } + else if( m_bMouseOver ) + { + iState = DXUT_STATE_MOUSEOVER; + + nOffsetX = -1; + nOffsetY = -2; + } + else if( m_bHasFocus ) + { + iState = DXUT_STATE_FOCUS; + } + + float fBlendRate = ( iState == DXUT_STATE_PRESSED ) ? 0.0f : 0.8f; + + CDXUTElement* pElement = m_Elements.GetAt( 0 ); + + // Blend current color + pElement->TextureColor.Blend( iState, fElapsedTime, fBlendRate ); + m_pDialog->DrawSprite( pElement, &m_rcBoundingBox, DXUT_FAR_BUTTON_DEPTH ); + + pElement = m_Elements.GetAt( 1 ); + + // Blend current color + pElement->TextureColor.Blend( iState, fElapsedTime, fBlendRate ); + m_pDialog->DrawSprite( pElement, &m_rcButton, DXUT_NEAR_BUTTON_DEPTH ); +} + + +//-------------------------------------------------------------------------------------- +// CDXUTScrollBar class +//-------------------------------------------------------------------------------------- + +//-------------------------------------------------------------------------------------- +CDXUTScrollBar::CDXUTScrollBar( CDXUTDialog* pDialog ) +{ + m_Type = DXUT_CONTROL_SCROLLBAR; + m_pDialog = pDialog; + + m_bShowThumb = true; + m_bDrag = false; + + SetRect( &m_rcUpButton, 0, 0, 0, 0 ); + SetRect( &m_rcDownButton, 0, 0, 0, 0 ); + SetRect( &m_rcTrack, 0, 0, 0, 0 ); + SetRect( &m_rcThumb, 0, 0, 0, 0 ); + m_nPosition = 0; + m_nPageSize = 1; + m_nStart = 0; + m_nEnd = 1; + m_Arrow = CLEAR; + m_dArrowTS = 0.0; +} + + +//-------------------------------------------------------------------------------------- +CDXUTScrollBar::~CDXUTScrollBar() +{ +} + + +//-------------------------------------------------------------------------------------- +void CDXUTScrollBar::UpdateRects() +{ + CDXUTControl::UpdateRects(); + + // Make the buttons square + + SetRect( &m_rcUpButton, m_rcBoundingBox.left, m_rcBoundingBox.top, + m_rcBoundingBox.right, m_rcBoundingBox.top + RectWidth( m_rcBoundingBox ) ); + SetRect( &m_rcDownButton, m_rcBoundingBox.left, m_rcBoundingBox.bottom - RectWidth( m_rcBoundingBox ), + m_rcBoundingBox.right, m_rcBoundingBox.bottom ); + SetRect( &m_rcTrack, m_rcUpButton.left, m_rcUpButton.bottom, + m_rcDownButton.right, m_rcDownButton.top ); + m_rcThumb.left = m_rcUpButton.left; + m_rcThumb.right = m_rcUpButton.right; + + UpdateThumbRect(); +} + + +//-------------------------------------------------------------------------------------- +// Compute the dimension of the scroll thumb +void CDXUTScrollBar::UpdateThumbRect() +{ + if( m_nEnd - m_nStart > m_nPageSize ) + { + int nThumbHeight = __max( RectHeight( m_rcTrack ) * m_nPageSize / ( m_nEnd - m_nStart ), + SCROLLBAR_MINTHUMBSIZE ); + int nMaxPosition = m_nEnd - m_nStart - m_nPageSize; + m_rcThumb.top = m_rcTrack.top + ( m_nPosition - m_nStart ) * ( RectHeight( m_rcTrack ) - nThumbHeight ) + / nMaxPosition; + m_rcThumb.bottom = m_rcThumb.top + nThumbHeight; + m_bShowThumb = true; + + } + else + { + // No content to scroll + m_rcThumb.bottom = m_rcThumb.top; + m_bShowThumb = false; + } +} + + +//-------------------------------------------------------------------------------------- +// Scroll() scrolls by nDelta items. A positive value scrolls down, while a negative +// value scrolls up. +void CDXUTScrollBar::Scroll( int nDelta ) +{ + // Perform scroll + m_nPosition += nDelta; + + // Cap position + Cap(); + + // Update thumb position + UpdateThumbRect(); +} + + +//-------------------------------------------------------------------------------------- +void CDXUTScrollBar::ShowItem( int nIndex ) +{ + // Cap the index + + if( nIndex < 0 ) + nIndex = 0; + + if( nIndex >= m_nEnd ) + nIndex = m_nEnd - 1; + + // Adjust position + + if( m_nPosition > nIndex ) + m_nPosition = nIndex; + else if( m_nPosition + m_nPageSize <= nIndex ) + m_nPosition = nIndex - m_nPageSize + 1; + + UpdateThumbRect(); +} + + +//-------------------------------------------------------------------------------------- +bool CDXUTScrollBar::HandleKeyboard( UINT uMsg, WPARAM wParam, LPARAM lParam ) +{ + return false; +} + + +//-------------------------------------------------------------------------------------- +bool CDXUTScrollBar::HandleMouse( UINT uMsg, POINT pt, WPARAM wParam, LPARAM lParam ) +{ + static int ThumbOffsetY; + + m_LastMouse = pt; + switch( uMsg ) + { + case WM_LBUTTONDOWN: + case WM_LBUTTONDBLCLK: + { + // Check for click on up button + + if( PtInRect( &m_rcUpButton, pt ) ) + { + SetCapture( DXUTGetHWND() ); + if( m_nPosition > m_nStart ) + --m_nPosition; + UpdateThumbRect(); + m_Arrow = CLICKED_UP; + m_dArrowTS = DXUTGetTime(); + return true; + } + + // Check for click on down button + + if( PtInRect( &m_rcDownButton, pt ) ) + { + SetCapture( DXUTGetHWND() ); + if( m_nPosition + m_nPageSize <= m_nEnd ) + ++m_nPosition; + UpdateThumbRect(); + m_Arrow = CLICKED_DOWN; + m_dArrowTS = DXUTGetTime(); + return true; + } + + // Check for click on thumb + + if( PtInRect( &m_rcThumb, pt ) ) + { + SetCapture( DXUTGetHWND() ); + m_bDrag = true; + ThumbOffsetY = pt.y - m_rcThumb.top; + return true; + } + + // Check for click on track + + if( m_rcThumb.left <= pt.x && + m_rcThumb.right > pt.x ) + { + SetCapture( DXUTGetHWND() ); + if( m_rcThumb.top > pt.y && + m_rcTrack.top <= pt.y ) + { + Scroll( -( m_nPageSize - 1 ) ); + return true; + } + else if( m_rcThumb.bottom <= pt.y && + m_rcTrack.bottom > pt.y ) + { + Scroll( m_nPageSize - 1 ); + return true; + } + } + + break; + } + + case WM_LBUTTONUP: + { + m_bDrag = false; + ReleaseCapture(); + UpdateThumbRect(); + m_Arrow = CLEAR; + break; + } + + case WM_MOUSEMOVE: + { + if( m_bDrag ) + { + m_rcThumb.bottom += pt.y - ThumbOffsetY - m_rcThumb.top; + m_rcThumb.top = pt.y - ThumbOffsetY; + if( m_rcThumb.top < m_rcTrack.top ) + OffsetRect( &m_rcThumb, 0, m_rcTrack.top - m_rcThumb.top ); + else if( m_rcThumb.bottom > m_rcTrack.bottom ) + OffsetRect( &m_rcThumb, 0, m_rcTrack.bottom - m_rcThumb.bottom ); + + // Compute first item index based on thumb position + + int nMaxFirstItem = m_nEnd - m_nStart - m_nPageSize + 1; // Largest possible index for first item + int nMaxThumb = RectHeight( m_rcTrack ) - RectHeight( m_rcThumb ); // Largest possible thumb position from the top + + m_nPosition = m_nStart + + ( m_rcThumb.top - m_rcTrack.top + + nMaxThumb / ( nMaxFirstItem * 2 ) ) * // Shift by half a row to avoid last row covered by only one pixel + nMaxFirstItem / nMaxThumb; + + return true; + } + + break; + } + } + + return false; +} + + +//-------------------------------------------------------------------------------------- +bool CDXUTScrollBar::MsgProc( UINT uMsg, WPARAM wParam, LPARAM lParam ) +{ + if( WM_CAPTURECHANGED == uMsg ) + { + // The application just lost mouse capture. We may not have gotten + // the WM_MOUSEUP message, so reset m_bDrag here. + if( ( HWND )lParam != DXUTGetHWND() ) + m_bDrag = false; + } + + return false; +} + + +//-------------------------------------------------------------------------------------- +void CDXUTScrollBar::Render( float fElapsedTime ) +{ + if( m_bVisible == false ) + return; + + // Check if the arrow button has been held for a while. + // If so, update the thumb position to simulate repeated + // scroll. + if( m_Arrow != CLEAR ) + { + double dCurrTime = DXUTGetTime(); + if( PtInRect( &m_rcUpButton, m_LastMouse ) ) + { + switch( m_Arrow ) + { + case CLICKED_UP: + if( SCROLLBAR_ARROWCLICK_DELAY < dCurrTime - m_dArrowTS ) + { + Scroll( -1 ); + m_Arrow = HELD_UP; + m_dArrowTS = dCurrTime; + } + break; + case HELD_UP: + if( SCROLLBAR_ARROWCLICK_REPEAT < dCurrTime - m_dArrowTS ) + { + Scroll( -1 ); + m_dArrowTS = dCurrTime; + } + break; + } + } + else if( PtInRect( &m_rcDownButton, m_LastMouse ) ) + { + switch( m_Arrow ) + { + case CLICKED_DOWN: + if( SCROLLBAR_ARROWCLICK_DELAY < dCurrTime - m_dArrowTS ) + { + Scroll( 1 ); + m_Arrow = HELD_DOWN; + m_dArrowTS = dCurrTime; + } + break; + case HELD_DOWN: + if( SCROLLBAR_ARROWCLICK_REPEAT < dCurrTime - m_dArrowTS ) + { + Scroll( 1 ); + m_dArrowTS = dCurrTime; + } + break; + } + } + } + + DXUT_CONTROL_STATE iState = DXUT_STATE_NORMAL; + + if( m_bVisible == false ) + iState = DXUT_STATE_HIDDEN; + else if( m_bEnabled == false || m_bShowThumb == false ) + iState = DXUT_STATE_DISABLED; + else if( m_bMouseOver ) + iState = DXUT_STATE_MOUSEOVER; + else if( m_bHasFocus ) + iState = DXUT_STATE_FOCUS; + + + float fBlendRate = ( iState == DXUT_STATE_PRESSED ) ? 0.0f : 0.8f; + + // Background track layer + CDXUTElement* pElement = m_Elements.GetAt( 0 ); + + // Blend current color + pElement->TextureColor.Blend( iState, fElapsedTime, fBlendRate ); + m_pDialog->DrawSprite( pElement, &m_rcTrack, DXUT_FAR_BUTTON_DEPTH ); + + // Up Arrow + pElement = m_Elements.GetAt( 1 ); + + // Blend current color + pElement->TextureColor.Blend( iState, fElapsedTime, fBlendRate ); + m_pDialog->DrawSprite( pElement, &m_rcUpButton, DXUT_NEAR_BUTTON_DEPTH ); + + // Down Arrow + pElement = m_Elements.GetAt( 2 ); + + // Blend current color + pElement->TextureColor.Blend( iState, fElapsedTime, fBlendRate ); + m_pDialog->DrawSprite( pElement, &m_rcDownButton, DXUT_NEAR_BUTTON_DEPTH ); + + // Thumb button + pElement = m_Elements.GetAt( 3 ); + + // Blend current color + pElement->TextureColor.Blend( iState, fElapsedTime, fBlendRate ); + m_pDialog->DrawSprite( pElement, &m_rcThumb, DXUT_NEAR_BUTTON_DEPTH ); + +} + + +//-------------------------------------------------------------------------------------- +void CDXUTScrollBar::SetTrackRange( int nStart, int nEnd ) +{ + m_nStart = nStart; m_nEnd = nEnd; + Cap(); + UpdateThumbRect(); +} + + +//-------------------------------------------------------------------------------------- +void CDXUTScrollBar::Cap() // Clips position at boundaries. Ensures it stays within legal range. +{ + if( m_nPosition < m_nStart || + m_nEnd - m_nStart <= m_nPageSize ) + { + m_nPosition = m_nStart; + } + else if( m_nPosition + m_nPageSize > m_nEnd ) + m_nPosition = m_nEnd - m_nPageSize + 1; +} + +//-------------------------------------------------------------------------------------- +// CDXUTListBox class +//-------------------------------------------------------------------------------------- + +//-------------------------------------------------------------------------------------- +CDXUTListBox::CDXUTListBox( CDXUTDialog* pDialog ) : m_ScrollBar( pDialog ) +{ + m_Type = DXUT_CONTROL_LISTBOX; + m_pDialog = pDialog; + + m_dwStyle = 0; + m_nSBWidth = 16; + m_nSelected = -1; + m_nSelStart = 0; + m_bDrag = false; + m_nBorder = 6; + m_nMargin = 5; + m_nTextHeight = 0; +} + + +//-------------------------------------------------------------------------------------- +CDXUTListBox::~CDXUTListBox() +{ + RemoveAllItems(); +} + + +//-------------------------------------------------------------------------------------- +void CDXUTListBox::UpdateRects() +{ + CDXUTControl::UpdateRects(); + + m_rcSelection = m_rcBoundingBox; + m_rcSelection.right -= m_nSBWidth; + InflateRect( &m_rcSelection, -m_nBorder, -m_nBorder ); + m_rcText = m_rcSelection; + InflateRect( &m_rcText, -m_nMargin, 0 ); + + // Update the scrollbar's rects + m_ScrollBar.SetLocation( m_rcBoundingBox.right - m_nSBWidth, m_rcBoundingBox.top ); + m_ScrollBar.SetSize( m_nSBWidth, m_height ); + DXUTFontNode* pFontNode = m_pDialog->GetManager()->GetFontNode( m_Elements.GetAt( 0 )->iFont ); + if( pFontNode && pFontNode->nHeight ) + { + m_ScrollBar.SetPageSize( RectHeight( m_rcText ) / pFontNode->nHeight ); + + // The selected item may have been scrolled off the page. + // Ensure that it is in page again. + m_ScrollBar.ShowItem( m_nSelected ); + } +} + + +//-------------------------------------------------------------------------------------- +HRESULT CDXUTListBox::AddItem( const WCHAR* wszText, void* pData ) +{ + DXUTListBoxItem* pNewItem = new DXUTListBoxItem; + if( !pNewItem ) + return E_OUTOFMEMORY; + + wcscpy_s( pNewItem->strText, 256, wszText ); + pNewItem->pData = pData; + SetRect( &pNewItem->rcActive, 0, 0, 0, 0 ); + pNewItem->bSelected = false; + + HRESULT hr = m_Items.Add( pNewItem ); + if( FAILED( hr ) ) + { + SAFE_DELETE( pNewItem ); + } + else + { + m_ScrollBar.SetTrackRange( 0, m_Items.GetSize() ); + } + + return hr; +} + + +//-------------------------------------------------------------------------------------- +HRESULT CDXUTListBox::InsertItem( int nIndex, const WCHAR* wszText, void* pData ) +{ + DXUTListBoxItem* pNewItem = new DXUTListBoxItem; + if( !pNewItem ) + return E_OUTOFMEMORY; + + wcscpy_s( pNewItem->strText, 256, wszText ); + pNewItem->pData = pData; + SetRect( &pNewItem->rcActive, 0, 0, 0, 0 ); + pNewItem->bSelected = false; + + HRESULT hr = m_Items.Insert( nIndex, pNewItem ); + if( SUCCEEDED( hr ) ) + m_ScrollBar.SetTrackRange( 0, m_Items.GetSize() ); + else + SAFE_DELETE( pNewItem ); + + return hr; +} + + +//-------------------------------------------------------------------------------------- +void CDXUTListBox::RemoveItem( int nIndex ) +{ + if( nIndex < 0 || nIndex >= ( int )m_Items.GetSize() ) + return; + + DXUTListBoxItem* pItem = m_Items.GetAt( nIndex ); + + delete pItem; + m_Items.Remove( nIndex ); + m_ScrollBar.SetTrackRange( 0, m_Items.GetSize() ); + if( m_nSelected >= ( int )m_Items.GetSize() ) + m_nSelected = m_Items.GetSize() - 1; + + m_pDialog->SendEvent( EVENT_LISTBOX_SELECTION, true, this ); +} + + + + + +//-------------------------------------------------------------------------------------- +void CDXUTListBox::RemoveAllItems() +{ + for( int i = 0; i < m_Items.GetSize(); ++i ) + { + DXUTListBoxItem* pItem = m_Items.GetAt( i ); + delete pItem; + } + + m_Items.RemoveAll(); + m_ScrollBar.SetTrackRange( 0, 1 ); +} + + +//-------------------------------------------------------------------------------------- +DXUTListBoxItem* CDXUTListBox::GetItem( int nIndex ) +{ + if( nIndex < 0 || nIndex >= ( int )m_Items.GetSize() ) + return NULL; + + return m_Items[nIndex]; +} + + +//-------------------------------------------------------------------------------------- +// For single-selection listbox, returns the index of the selected item. +// For multi-selection, returns the first selected item after the nPreviousSelected position. +// To search for the first selected item, the app passes -1 for nPreviousSelected. For +// subsequent searches, the app passes the returned index back to GetSelectedIndex as. +// nPreviousSelected. +// Returns -1 on error or if no item is selected. +int CDXUTListBox::GetSelectedIndex( int nPreviousSelected ) +{ + if( nPreviousSelected < -1 ) + return -1; + + if( m_dwStyle & MULTISELECTION ) + { + // Multiple selection enabled. Search for the next item with the selected flag. + for( int i = nPreviousSelected + 1; i < ( int )m_Items.GetSize(); ++i ) + { + DXUTListBoxItem* pItem = m_Items.GetAt( i ); + + if( pItem->bSelected ) + return i; + } + + return -1; + } + else + { + // Single selection + return m_nSelected; + } +} + + +//-------------------------------------------------------------------------------------- +void CDXUTListBox::SelectItem( int nNewIndex ) +{ + // If no item exists, do nothing. + if( m_Items.GetSize() == 0 ) + return; + + int nOldSelected = m_nSelected; + + // Adjust m_nSelected + m_nSelected = nNewIndex; + + // Perform capping + if( m_nSelected < 0 ) + m_nSelected = 0; + if( m_nSelected >= ( int )m_Items.GetSize() ) + m_nSelected = m_Items.GetSize() - 1; + + if( nOldSelected != m_nSelected ) + { + if( m_dwStyle & MULTISELECTION ) + { + m_Items[m_nSelected]->bSelected = true; + } + + // Update selection start + m_nSelStart = m_nSelected; + + // Adjust scroll bar + m_ScrollBar.ShowItem( m_nSelected ); + } + + m_pDialog->SendEvent( EVENT_LISTBOX_SELECTION, true, this ); +} + + +//-------------------------------------------------------------------------------------- +bool CDXUTListBox::HandleKeyboard( UINT uMsg, WPARAM wParam, LPARAM lParam ) +{ + if( !m_bEnabled || !m_bVisible ) + return false; + + // Let the scroll bar have a chance to handle it first + if( m_ScrollBar.HandleKeyboard( uMsg, wParam, lParam ) ) + return true; + + switch( uMsg ) + { + case WM_KEYDOWN: + switch( wParam ) + { + case VK_UP: + case VK_DOWN: + case VK_NEXT: + case VK_PRIOR: + case VK_HOME: + case VK_END: + { + // If no item exists, do nothing. + if( m_Items.GetSize() == 0 ) + return true; + + int nOldSelected = m_nSelected; + + // Adjust m_nSelected + switch( wParam ) + { + case VK_UP: + --m_nSelected; break; + case VK_DOWN: + ++m_nSelected; break; + case VK_NEXT: + m_nSelected += m_ScrollBar.GetPageSize() - 1; break; + case VK_PRIOR: + m_nSelected -= m_ScrollBar.GetPageSize() - 1; break; + case VK_HOME: + m_nSelected = 0; break; + case VK_END: + m_nSelected = m_Items.GetSize() - 1; break; + } + + // Perform capping + if( m_nSelected < 0 ) + m_nSelected = 0; + if( m_nSelected >= ( int )m_Items.GetSize() ) + m_nSelected = m_Items.GetSize() - 1; + + if( nOldSelected != m_nSelected ) + { + if( m_dwStyle & MULTISELECTION ) + { + // Multiple selection + + // Clear all selection + for( int i = 0; i < ( int )m_Items.GetSize(); ++i ) + { + DXUTListBoxItem* pItem = m_Items[i]; + pItem->bSelected = false; + } + + if( GetKeyState( VK_SHIFT ) < 0 ) + { + // Select all items from m_nSelStart to + // m_nSelected + int nEnd = __max( m_nSelStart, m_nSelected ); + + for( int n = __min( m_nSelStart, m_nSelected ); n <= nEnd; ++n ) + m_Items[n]->bSelected = true; + } + else + { + m_Items[m_nSelected]->bSelected = true; + + // Update selection start + m_nSelStart = m_nSelected; + } + } + else + m_nSelStart = m_nSelected; + + // Adjust scroll bar + + m_ScrollBar.ShowItem( m_nSelected ); + + // Send notification + + m_pDialog->SendEvent( EVENT_LISTBOX_SELECTION, true, this ); + } + return true; + } + + // Space is the hotkey for double-clicking an item. + // + case VK_SPACE: + m_pDialog->SendEvent( EVENT_LISTBOX_ITEM_DBLCLK, true, this ); + return true; + } + break; + } + + return false; +} + + +//-------------------------------------------------------------------------------------- +bool CDXUTListBox::HandleMouse( UINT uMsg, POINT pt, WPARAM wParam, LPARAM lParam ) +{ + if( !m_bEnabled || !m_bVisible ) + return false; + + // First acquire focus + if( WM_LBUTTONDOWN == uMsg ) + if( !m_bHasFocus ) + m_pDialog->RequestFocus( this ); + + // Let the scroll bar handle it first. + if( m_ScrollBar.HandleMouse( uMsg, pt, wParam, lParam ) ) + return true; + + switch( uMsg ) + { + case WM_LBUTTONDOWN: + case WM_LBUTTONDBLCLK: + // Check for clicks in the text area + if( m_Items.GetSize() > 0 && PtInRect( &m_rcSelection, pt ) ) + { + // Compute the index of the clicked item + + int nClicked; + if( m_nTextHeight ) + nClicked = m_ScrollBar.GetTrackPos() + ( pt.y - m_rcText.top ) / m_nTextHeight; + else + nClicked = -1; + + // Only proceed if the click falls on top of an item. + + if( nClicked >= m_ScrollBar.GetTrackPos() && + nClicked < ( int )m_Items.GetSize() && + nClicked < m_ScrollBar.GetTrackPos() + m_ScrollBar.GetPageSize() ) + { + SetCapture( DXUTGetHWND() ); + m_bDrag = true; + + // If this is a double click, fire off an event and exit + // since the first click would have taken care of the selection + // updating. + if( uMsg == WM_LBUTTONDBLCLK ) + { + m_pDialog->SendEvent( EVENT_LISTBOX_ITEM_DBLCLK, true, this ); + return true; + } + + m_nSelected = nClicked; + if( !( wParam & MK_SHIFT ) ) + m_nSelStart = m_nSelected; + + // If this is a multi-selection listbox, update per-item + // selection data. + + if( m_dwStyle & MULTISELECTION ) + { + // Determine behavior based on the state of Shift and Ctrl + + DXUTListBoxItem* pSelItem = m_Items.GetAt( m_nSelected ); + if( ( wParam & ( MK_SHIFT | MK_CONTROL ) ) == MK_CONTROL ) + { + // Control click. Reverse the selection of this item. + + pSelItem->bSelected = !pSelItem->bSelected; + } + else if( ( wParam & ( MK_SHIFT | MK_CONTROL ) ) == MK_SHIFT ) + { + // Shift click. Set the selection for all items + // from last selected item to the current item. + // Clear everything else. + + int nBegin = __min( m_nSelStart, m_nSelected ); + int nEnd = __max( m_nSelStart, m_nSelected ); + + for( int i = 0; i < nBegin; ++i ) + { + DXUTListBoxItem* pItem = m_Items.GetAt( i ); + pItem->bSelected = false; + } + + for( int i = nEnd + 1; i < ( int )m_Items.GetSize(); ++i ) + { + DXUTListBoxItem* pItem = m_Items.GetAt( i ); + pItem->bSelected = false; + } + + for( int i = nBegin; i <= nEnd; ++i ) + { + DXUTListBoxItem* pItem = m_Items.GetAt( i ); + pItem->bSelected = true; + } + } + else if( ( wParam & ( MK_SHIFT | MK_CONTROL ) ) == ( MK_SHIFT | MK_CONTROL ) ) + { + // Control-Shift-click. + + // The behavior is: + // Set all items from m_nSelStart to m_nSelected to + // the same state as m_nSelStart, not including m_nSelected. + // Set m_nSelected to selected. + + int nBegin = __min( m_nSelStart, m_nSelected ); + int nEnd = __max( m_nSelStart, m_nSelected ); + + // The two ends do not need to be set here. + + bool bLastSelected = m_Items.GetAt( m_nSelStart )->bSelected; + for( int i = nBegin + 1; i < nEnd; ++i ) + { + DXUTListBoxItem* pItem = m_Items.GetAt( i ); + pItem->bSelected = bLastSelected; + } + + pSelItem->bSelected = true; + + // Restore m_nSelected to the previous value + // This matches the Windows behavior + + m_nSelected = m_nSelStart; + } + else + { + // Simple click. Clear all items and select the clicked + // item. + + + for( int i = 0; i < ( int )m_Items.GetSize(); ++i ) + { + DXUTListBoxItem* pItem = m_Items.GetAt( i ); + pItem->bSelected = false; + } + + pSelItem->bSelected = true; + } + } // End of multi-selection case + + m_pDialog->SendEvent( EVENT_LISTBOX_SELECTION, true, this ); + } + + return true; + } + break; + + case WM_LBUTTONUP: + { + ReleaseCapture(); + m_bDrag = false; + + if( m_nSelected != -1 ) + { + // Set all items between m_nSelStart and m_nSelected to + // the same state as m_nSelStart + int nEnd = __max( m_nSelStart, m_nSelected ); + + for( int n = __min( m_nSelStart, m_nSelected ) + 1; n < nEnd; ++n ) + m_Items[n]->bSelected = m_Items[m_nSelStart]->bSelected; + m_Items[m_nSelected]->bSelected = m_Items[m_nSelStart]->bSelected; + + // If m_nSelStart and m_nSelected are not the same, + // the user has dragged the mouse to make a selection. + // Notify the application of this. + if( m_nSelStart != m_nSelected ) + m_pDialog->SendEvent( EVENT_LISTBOX_SELECTION, true, this ); + + m_pDialog->SendEvent( EVENT_LISTBOX_SELECTION_END, true, this ); + } + return false; + } + + case WM_MOUSEMOVE: + if( m_bDrag ) + { + // Compute the index of the item below cursor + + int nItem; + if( m_nTextHeight ) + nItem = m_ScrollBar.GetTrackPos() + ( pt.y - m_rcText.top ) / m_nTextHeight; + else + nItem = -1; + + // Only proceed if the cursor is on top of an item. + + if( nItem >= ( int )m_ScrollBar.GetTrackPos() && + nItem < ( int )m_Items.GetSize() && + nItem < m_ScrollBar.GetTrackPos() + m_ScrollBar.GetPageSize() ) + { + m_nSelected = nItem; + m_pDialog->SendEvent( EVENT_LISTBOX_SELECTION, true, this ); + } + else if( nItem < ( int )m_ScrollBar.GetTrackPos() ) + { + // User drags the mouse above window top + m_ScrollBar.Scroll( -1 ); + m_nSelected = m_ScrollBar.GetTrackPos(); + m_pDialog->SendEvent( EVENT_LISTBOX_SELECTION, true, this ); + } + else if( nItem >= m_ScrollBar.GetTrackPos() + m_ScrollBar.GetPageSize() ) + { + // User drags the mouse below window bottom + m_ScrollBar.Scroll( 1 ); + m_nSelected = __min( ( int )m_Items.GetSize(), m_ScrollBar.GetTrackPos() + + m_ScrollBar.GetPageSize() ) - 1; + m_pDialog->SendEvent( EVENT_LISTBOX_SELECTION, true, this ); + } + } + break; + + case WM_MOUSEWHEEL: + { + UINT uLines; + SystemParametersInfo( SPI_GETWHEELSCROLLLINES, 0, &uLines, 0 ); + int nScrollAmount = int( ( short )HIWORD( wParam ) ) / WHEEL_DELTA * uLines; + m_ScrollBar.Scroll( -nScrollAmount ); + return true; + } + } + + return false; +} + + +//-------------------------------------------------------------------------------------- +bool CDXUTListBox::MsgProc( UINT uMsg, WPARAM wParam, LPARAM lParam ) +{ + if( WM_CAPTURECHANGED == uMsg ) + { + // The application just lost mouse capture. We may not have gotten + // the WM_MOUSEUP message, so reset m_bDrag here. + if( ( HWND )lParam != DXUTGetHWND() ) + m_bDrag = false; + } + + return false; +} + + +//-------------------------------------------------------------------------------------- +void CDXUTListBox::Render( float fElapsedTime ) +{ + if( m_bVisible == false ) + return; + + CDXUTElement* pElement = m_Elements.GetAt( 0 ); + pElement->TextureColor.Blend( DXUT_STATE_NORMAL, fElapsedTime ); + pElement->FontColor.Blend( DXUT_STATE_NORMAL, fElapsedTime ); + + CDXUTElement* pSelElement = m_Elements.GetAt( 1 ); + pSelElement->TextureColor.Blend( DXUT_STATE_NORMAL, fElapsedTime ); + pSelElement->FontColor.Blend( DXUT_STATE_NORMAL, fElapsedTime ); + + m_pDialog->DrawSprite( pElement, &m_rcBoundingBox, DXUT_FAR_BUTTON_DEPTH ); + + // Render the text + if( m_Items.GetSize() > 0 ) + { + // Find out the height of a single line of text + RECT rc = m_rcText; + RECT rcSel = m_rcSelection; + rc.bottom = rc.top + m_pDialog->GetManager()->GetFontNode( pElement->iFont )->nHeight; + + // Update the line height formation + m_nTextHeight = rc.bottom - rc.top; + + static bool bSBInit; + if( !bSBInit ) + { + // Update the page size of the scroll bar + if( m_nTextHeight ) + m_ScrollBar.SetPageSize( RectHeight( m_rcText ) / m_nTextHeight ); + else + m_ScrollBar.SetPageSize( RectHeight( m_rcText ) ); + bSBInit = true; + } + + rc.right = m_rcText.right; + for( int i = m_ScrollBar.GetTrackPos(); i < ( int )m_Items.GetSize(); ++i ) + { + if( rc.bottom > m_rcText.bottom ) + break; + + DXUTListBoxItem* pItem = m_Items.GetAt( i ); + + // Determine if we need to render this item with the + // selected element. + bool bSelectedStyle = false; + + if( !( m_dwStyle & MULTISELECTION ) && i == m_nSelected ) + bSelectedStyle = true; + else if( m_dwStyle & MULTISELECTION ) + { + if( m_bDrag && + ( ( i >= m_nSelected && i < m_nSelStart ) || + ( i <= m_nSelected && i > m_nSelStart ) ) ) + bSelectedStyle = m_Items[m_nSelStart]->bSelected; + else if( pItem->bSelected ) + bSelectedStyle = true; + } + + if( bSelectedStyle ) + { + rcSel.top = rc.top; rcSel.bottom = rc.bottom; + m_pDialog->DrawSprite( pSelElement, &rcSel, DXUT_NEAR_BUTTON_DEPTH ); + m_pDialog->DrawText( pItem->strText, pSelElement, &rc ); + } + else + m_pDialog->DrawText( pItem->strText, pElement, &rc ); + + OffsetRect( &rc, 0, m_nTextHeight ); + } + } + + // Render the scroll bar + + m_ScrollBar.Render( fElapsedTime ); +} + + +// Static member initialization +HINSTANCE CUniBuffer::s_hDll = NULL; +HRESULT ( WINAPI*CUniBuffer::_ScriptApplyDigitSubstitution )( const SCRIPT_DIGITSUBSTITUTE*, SCRIPT_CONTROL*, + SCRIPT_STATE* ) = Dummy_ScriptApplyDigitSubstitution; +HRESULT ( WINAPI*CUniBuffer::_ScriptStringAnalyse )( HDC, const void*, int, int, int, DWORD, int, SCRIPT_CONTROL*, + SCRIPT_STATE*, const int*, SCRIPT_TABDEF*, const BYTE*, + SCRIPT_STRING_ANALYSIS* ) = Dummy_ScriptStringAnalyse; +HRESULT ( WINAPI*CUniBuffer::_ScriptStringCPtoX )( SCRIPT_STRING_ANALYSIS, int, BOOL, int* ) = Dummy_ScriptStringCPtoX; +HRESULT ( WINAPI*CUniBuffer::_ScriptStringXtoCP )( SCRIPT_STRING_ANALYSIS, int, int*, int* ) = Dummy_ScriptStringXtoCP; +HRESULT ( WINAPI*CUniBuffer::_ScriptStringFree )( SCRIPT_STRING_ANALYSIS* ) = Dummy_ScriptStringFree; +const SCRIPT_LOGATTR* ( WINAPI*CUniBuffer::_ScriptString_pLogAttr )( SCRIPT_STRING_ANALYSIS ) = + Dummy_ScriptString_pLogAttr; +const int* ( WINAPI*CUniBuffer::_ScriptString_pcOutChars )( SCRIPT_STRING_ANALYSIS ) = + Dummy_ScriptString_pcOutChars; +bool CDXUTEditBox::s_bHideCaret; // If true, we don't render the caret. + + + +//-------------------------------------------------------------------------------------- +// CDXUTEditBox class +//-------------------------------------------------------------------------------------- + +// When scrolling, EDITBOX_SCROLLEXTENT is reciprocal of the amount to scroll. +// If EDITBOX_SCROLLEXTENT = 4, then we scroll 1/4 of the control each time. +#define EDITBOX_SCROLLEXTENT 4 + +//-------------------------------------------------------------------------------------- +CDXUTEditBox::CDXUTEditBox( CDXUTDialog* pDialog ) +{ + m_Type = DXUT_CONTROL_EDITBOX; + m_pDialog = pDialog; + + m_nBorder = 5; // Default border width + m_nSpacing = 4; // Default spacing + + m_bCaretOn = true; + m_dfBlink = GetCaretBlinkTime() * 0.001f; + m_dfLastBlink = DXUTGetGlobalTimer()->GetAbsoluteTime(); + s_bHideCaret = false; + m_nFirstVisible = 0; + m_TextColor = D3DCOLOR_ARGB( 255, 16, 16, 16 ); + m_SelTextColor = D3DCOLOR_ARGB( 255, 255, 255, 255 ); + m_SelBkColor = D3DCOLOR_ARGB( 255, 40, 50, 92 ); + m_CaretColor = D3DCOLOR_ARGB( 255, 0, 0, 0 ); + m_nCaret = m_nSelStart = 0; + m_bInsertMode = true; + + m_bMouseDrag = false; +} + + +//-------------------------------------------------------------------------------------- +CDXUTEditBox::~CDXUTEditBox() +{ +} + + +//-------------------------------------------------------------------------------------- +// PlaceCaret: Set the caret to a character position, and adjust the scrolling if +// necessary. +//-------------------------------------------------------------------------------------- +void CDXUTEditBox::PlaceCaret( int nCP ) +{ + assert( nCP >= 0 && nCP <= m_Buffer.GetTextSize() ); + m_nCaret = nCP; + + // Obtain the X offset of the character. + int nX1st, nX, nX2; + m_Buffer.CPtoX( m_nFirstVisible, FALSE, &nX1st ); // 1st visible char + m_Buffer.CPtoX( nCP, FALSE, &nX ); // LEAD + // If nCP is the NULL terminator, get the leading edge instead of trailing. + if( nCP == m_Buffer.GetTextSize() ) + nX2 = nX; + else + m_Buffer.CPtoX( nCP, TRUE, &nX2 ); // TRAIL + + // If the left edge of the char is smaller than the left edge of the 1st visible char, + // we need to scroll left until this char is visible. + if( nX < nX1st ) + { + // Simply make the first visible character the char at the new caret position. + m_nFirstVisible = nCP; + } + else // If the right of the character is bigger than the offset of the control's + // right edge, we need to scroll right to this character. + if( nX2 > nX1st + RectWidth( m_rcText ) ) + { + // Compute the X of the new left-most pixel + int nXNewLeft = nX2 - RectWidth( m_rcText ); + + // Compute the char position of this character + int nCPNew1st, nNewTrail; + m_Buffer.XtoCP( nXNewLeft, &nCPNew1st, &nNewTrail ); + + // If this coordinate is not on a character border, + // start from the next character so that the caret + // position does not fall outside the text rectangle. + int nXNew1st; + m_Buffer.CPtoX( nCPNew1st, FALSE, &nXNew1st ); + if( nXNew1st < nXNewLeft ) + ++nCPNew1st; + + m_nFirstVisible = nCPNew1st; + } +} + + +//-------------------------------------------------------------------------------------- +void CDXUTEditBox::ClearText() +{ + m_Buffer.Clear(); + m_nFirstVisible = 0; + PlaceCaret( 0 ); + m_nSelStart = 0; +} + + +//-------------------------------------------------------------------------------------- +void CDXUTEditBox::SetText( LPCWSTR wszText, bool bSelected ) +{ + assert( wszText != NULL ); + + m_Buffer.SetText( wszText ); + m_nFirstVisible = 0; + // Move the caret to the end of the text + PlaceCaret( m_Buffer.GetTextSize() ); + m_nSelStart = bSelected ? 0 : m_nCaret; +} + + +//-------------------------------------------------------------------------------------- +HRESULT CDXUTEditBox::GetTextCopy( __out_ecount(bufferCount) LPWSTR strDest, + UINT bufferCount ) +{ + assert( strDest ); + + wcscpy_s( strDest, bufferCount, m_Buffer.GetBuffer() ); + + return S_OK; +} + + +//-------------------------------------------------------------------------------------- +void CDXUTEditBox::DeleteSelectionText() +{ + int nFirst = __min( m_nCaret, m_nSelStart ); + int nLast = __max( m_nCaret, m_nSelStart ); + // Update caret and selection + PlaceCaret( nFirst ); + m_nSelStart = m_nCaret; + // Remove the characters + for( int i = nFirst; i < nLast; ++i ) + m_Buffer.RemoveChar( nFirst ); +} + + +//-------------------------------------------------------------------------------------- +void CDXUTEditBox::UpdateRects() +{ + CDXUTControl::UpdateRects(); + + // Update the text rectangle + m_rcText = m_rcBoundingBox; + // First inflate by m_nBorder to compute render rects + InflateRect( &m_rcText, -m_nBorder, -m_nBorder ); + + // Update the render rectangles + m_rcRender[0] = m_rcText; + SetRect( &m_rcRender[1], m_rcBoundingBox.left, m_rcBoundingBox.top, m_rcText.left, m_rcText.top ); + SetRect( &m_rcRender[2], m_rcText.left, m_rcBoundingBox.top, m_rcText.right, m_rcText.top ); + SetRect( &m_rcRender[3], m_rcText.right, m_rcBoundingBox.top, m_rcBoundingBox.right, m_rcText.top ); + SetRect( &m_rcRender[4], m_rcBoundingBox.left, m_rcText.top, m_rcText.left, m_rcText.bottom ); + SetRect( &m_rcRender[5], m_rcText.right, m_rcText.top, m_rcBoundingBox.right, m_rcText.bottom ); + SetRect( &m_rcRender[6], m_rcBoundingBox.left, m_rcText.bottom, m_rcText.left, m_rcBoundingBox.bottom ); + SetRect( &m_rcRender[7], m_rcText.left, m_rcText.bottom, m_rcText.right, m_rcBoundingBox.bottom ); + SetRect( &m_rcRender[8], m_rcText.right, m_rcText.bottom, m_rcBoundingBox.right, m_rcBoundingBox.bottom ); + + // Inflate further by m_nSpacing + InflateRect( &m_rcText, -m_nSpacing, -m_nSpacing ); +} + + +void CDXUTEditBox::CopyToClipboard() +{ + // Copy the selection text to the clipboard + if( m_nCaret != m_nSelStart && OpenClipboard( NULL ) ) + { + EmptyClipboard(); + + HGLOBAL hBlock = GlobalAlloc( GMEM_MOVEABLE, sizeof( WCHAR ) * ( m_Buffer.GetTextSize() + 1 ) ); + if( hBlock ) + { + WCHAR* pwszText = ( WCHAR* )GlobalLock( hBlock ); + if( pwszText ) + { + int nFirst = __min( m_nCaret, m_nSelStart ); + int nLast = __max( m_nCaret, m_nSelStart ); + if( nLast - nFirst > 0 ) + CopyMemory( pwszText, m_Buffer.GetBuffer() + nFirst, ( nLast - nFirst ) * sizeof( WCHAR ) ); + pwszText[nLast - nFirst] = L'\0'; // Terminate it + GlobalUnlock( hBlock ); + } + SetClipboardData( CF_UNICODETEXT, hBlock ); + } + CloseClipboard(); + // We must not free the object until CloseClipboard is called. + if( hBlock ) + GlobalFree( hBlock ); + } +} + + +void CDXUTEditBox::PasteFromClipboard() +{ + DeleteSelectionText(); + + if( OpenClipboard( NULL ) ) + { + HANDLE handle = GetClipboardData( CF_UNICODETEXT ); + if( handle ) + { + // Convert the ANSI string to Unicode, then + // insert to our buffer. + WCHAR* pwszText = ( WCHAR* )GlobalLock( handle ); + if( pwszText ) + { + // Copy all characters up to null. + if( m_Buffer.InsertString( m_nCaret, pwszText ) ) + PlaceCaret( m_nCaret + lstrlenW( pwszText ) ); + m_nSelStart = m_nCaret; + GlobalUnlock( handle ); + } + } + CloseClipboard(); + } +} + + +//-------------------------------------------------------------------------------------- +bool CDXUTEditBox::HandleKeyboard( UINT uMsg, WPARAM wParam, LPARAM lParam ) +{ + if( !m_bEnabled || !m_bVisible ) + return false; + + bool bHandled = false; + + switch( uMsg ) + { + case WM_KEYDOWN: + { + switch( wParam ) + { + case VK_TAB: + // We don't process Tab in case keyboard input is enabled and the user + // wishes to Tab to other controls. + break; + + case VK_HOME: + PlaceCaret( 0 ); + if( GetKeyState( VK_SHIFT ) >= 0 ) + // Shift is not down. Update selection + // start along with the caret. + m_nSelStart = m_nCaret; + ResetCaretBlink(); + bHandled = true; + break; + + case VK_END: + PlaceCaret( m_Buffer.GetTextSize() ); + if( GetKeyState( VK_SHIFT ) >= 0 ) + // Shift is not down. Update selection + // start along with the caret. + m_nSelStart = m_nCaret; + ResetCaretBlink(); + bHandled = true; + break; + + case VK_INSERT: + if( GetKeyState( VK_CONTROL ) < 0 ) + { + // Control Insert. Copy to clipboard + CopyToClipboard(); + } + else if( GetKeyState( VK_SHIFT ) < 0 ) + { + // Shift Insert. Paste from clipboard + PasteFromClipboard(); + } + else + { + // Toggle caret insert mode + m_bInsertMode = !m_bInsertMode; + } + break; + + case VK_DELETE: + // Check if there is a text selection. + if( m_nCaret != m_nSelStart ) + { + DeleteSelectionText(); + m_pDialog->SendEvent( EVENT_EDITBOX_CHANGE, true, this ); + } + else + { + // Deleting one character + if( m_Buffer.RemoveChar( m_nCaret ) ) + m_pDialog->SendEvent( EVENT_EDITBOX_CHANGE, true, this ); + } + ResetCaretBlink(); + bHandled = true; + break; + + case VK_LEFT: + if( GetKeyState( VK_CONTROL ) < 0 ) + { + // Control is down. Move the caret to a new item + // instead of a character. + m_Buffer.GetPriorItemPos( m_nCaret, &m_nCaret ); + PlaceCaret( m_nCaret ); + } + else if( m_nCaret > 0 ) + PlaceCaret( m_nCaret - 1 ); + if( GetKeyState( VK_SHIFT ) >= 0 ) + // Shift is not down. Update selection + // start along with the caret. + m_nSelStart = m_nCaret; + ResetCaretBlink(); + bHandled = true; + break; + + case VK_RIGHT: + if( GetKeyState( VK_CONTROL ) < 0 ) + { + // Control is down. Move the caret to a new item + // instead of a character. + m_Buffer.GetNextItemPos( m_nCaret, &m_nCaret ); + PlaceCaret( m_nCaret ); + } + else if( m_nCaret < m_Buffer.GetTextSize() ) + PlaceCaret( m_nCaret + 1 ); + if( GetKeyState( VK_SHIFT ) >= 0 ) + // Shift is not down. Update selection + // start along with the caret. + m_nSelStart = m_nCaret; + ResetCaretBlink(); + bHandled = true; + break; + + case VK_UP: + case VK_DOWN: + // Trap up and down arrows so that the dialog + // does not switch focus to another control. + bHandled = true; + break; + + default: + bHandled = wParam != VK_ESCAPE; // Let the application handle Esc. + } + } + } + return bHandled; +} + + +//-------------------------------------------------------------------------------------- +bool CDXUTEditBox::HandleMouse( UINT uMsg, POINT pt, WPARAM wParam, LPARAM lParam ) +{ + if( !m_bEnabled || !m_bVisible ) + return false; + + switch( uMsg ) + { + case WM_LBUTTONDOWN: + case WM_LBUTTONDBLCLK: + { + if( !m_bHasFocus ) + m_pDialog->RequestFocus( this ); + + if( !ContainsPoint( pt ) ) + return false; + + m_bMouseDrag = true; + SetCapture( DXUTGetHWND() ); + // Determine the character corresponding to the coordinates. + int nCP, nTrail, nX1st; + m_Buffer.CPtoX( m_nFirstVisible, FALSE, &nX1st ); // X offset of the 1st visible char + if( SUCCEEDED( m_Buffer.XtoCP( pt.x - m_rcText.left + nX1st, &nCP, &nTrail ) ) ) + { + // Cap at the NULL character. + if( nTrail && nCP < m_Buffer.GetTextSize() ) + PlaceCaret( nCP + 1 ); + else + PlaceCaret( nCP ); + m_nSelStart = m_nCaret; + ResetCaretBlink(); + } + return true; + } + + case WM_LBUTTONUP: + ReleaseCapture(); + m_bMouseDrag = false; + break; + + case WM_MOUSEMOVE: + if( m_bMouseDrag ) + { + // Determine the character corresponding to the coordinates. + int nCP, nTrail, nX1st; + m_Buffer.CPtoX( m_nFirstVisible, FALSE, &nX1st ); // X offset of the 1st visible char + if( SUCCEEDED( m_Buffer.XtoCP( pt.x - m_rcText.left + nX1st, &nCP, &nTrail ) ) ) + { + // Cap at the NULL character. + if( nTrail && nCP < m_Buffer.GetTextSize() ) + PlaceCaret( nCP + 1 ); + else + PlaceCaret( nCP ); + } + } + break; + } + + return false; +} + + +//-------------------------------------------------------------------------------------- +void CDXUTEditBox::OnFocusIn() +{ + CDXUTControl::OnFocusIn(); + + ResetCaretBlink(); +} + + +//-------------------------------------------------------------------------------------- +bool CDXUTEditBox::MsgProc( UINT uMsg, WPARAM wParam, LPARAM lParam ) +{ + if( !m_bEnabled || !m_bVisible ) + return false; + + switch( uMsg ) + { + // Make sure that while editing, the keyup and keydown messages associated with + // WM_CHAR messages don't go to any non-focused controls or cameras + case WM_KEYUP: + case WM_KEYDOWN: + return true; + + case WM_CHAR: + { + switch( ( WCHAR )wParam ) + { + // Backspace + case VK_BACK: + { + // If there's a selection, treat this + // like a delete key. + if( m_nCaret != m_nSelStart ) + { + DeleteSelectionText(); + m_pDialog->SendEvent( EVENT_EDITBOX_CHANGE, true, this ); + } + else if( m_nCaret > 0 ) + { + // Move the caret, then delete the char. + PlaceCaret( m_nCaret - 1 ); + m_nSelStart = m_nCaret; + m_Buffer.RemoveChar( m_nCaret ); + m_pDialog->SendEvent( EVENT_EDITBOX_CHANGE, true, this ); + } + ResetCaretBlink(); + break; + } + + case 24: // Ctrl-X Cut + case VK_CANCEL: // Ctrl-C Copy + { + CopyToClipboard(); + + // If the key is Ctrl-X, delete the selection too. + if( ( WCHAR )wParam == 24 ) + { + DeleteSelectionText(); + m_pDialog->SendEvent( EVENT_EDITBOX_CHANGE, true, this ); + } + + break; + } + + // Ctrl-V Paste + case 22: + { + PasteFromClipboard(); + m_pDialog->SendEvent( EVENT_EDITBOX_CHANGE, true, this ); + break; + } + + // Ctrl-A Select All + case 1: + if( m_nSelStart == m_nCaret ) + { + m_nSelStart = 0; + PlaceCaret( m_Buffer.GetTextSize() ); + } + break; + + case VK_RETURN: + // Invoke the callback when the user presses Enter. + m_pDialog->SendEvent( EVENT_EDITBOX_STRING, true, this ); + break; + + // Junk characters we don't want in the string + case 26: // Ctrl Z + case 2: // Ctrl B + case 14: // Ctrl N + case 19: // Ctrl S + case 4: // Ctrl D + case 6: // Ctrl F + case 7: // Ctrl G + case 10: // Ctrl J + case 11: // Ctrl K + case 12: // Ctrl L + case 17: // Ctrl Q + case 23: // Ctrl W + case 5: // Ctrl E + case 18: // Ctrl R + case 20: // Ctrl T + case 25: // Ctrl Y + case 21: // Ctrl U + case 9: // Ctrl I + case 15: // Ctrl O + case 16: // Ctrl P + case 27: // Ctrl [ + case 29: // Ctrl ] + case 28: // Ctrl \ + break; + + default: + { + // If there's a selection and the user + // starts to type, the selection should + // be deleted. + if( m_nCaret != m_nSelStart ) + DeleteSelectionText(); + + // If we are in overwrite mode and there is already + // a char at the caret's position, simply replace it. + // Otherwise, we insert the char as normal. + if( !m_bInsertMode && m_nCaret < m_Buffer.GetTextSize() ) + { + m_Buffer[m_nCaret] = ( WCHAR )wParam; + PlaceCaret( m_nCaret + 1 ); + m_nSelStart = m_nCaret; + } + else + { + // Insert the char + if( m_Buffer.InsertChar( m_nCaret, ( WCHAR )wParam ) ) + { + PlaceCaret( m_nCaret + 1 ); + m_nSelStart = m_nCaret; + } + } + ResetCaretBlink(); + m_pDialog->SendEvent( EVENT_EDITBOX_CHANGE, true, this ); + } + } + return true; + } + } + return false; +} + + +//-------------------------------------------------------------------------------------- +void CDXUTEditBox::Render( float fElapsedTime ) +{ + if( m_bVisible == false ) + return; + + HRESULT hr; + int nSelStartX = 0, nCaretX = 0; // Left and right X cordinates of the selection region + + CDXUTElement* pElement = GetElement( 0 ); + if( pElement ) + { + m_Buffer.SetFontNode( m_pDialog->GetFont( pElement->iFont ) ); + PlaceCaret( m_nCaret ); // Call PlaceCaret now that we have the font info (node), + // so that scrolling can be handled. + } + + // Render the control graphics + for( int e = 0; e < 9; ++e ) + { + pElement = m_Elements.GetAt( e ); + pElement->TextureColor.Blend( DXUT_STATE_NORMAL, fElapsedTime ); + + m_pDialog->DrawSprite( pElement, &m_rcRender[e], DXUT_FAR_BUTTON_DEPTH ); + } + + // + // Compute the X coordinates of the first visible character. + // + int nXFirst; + m_Buffer.CPtoX( m_nFirstVisible, FALSE, &nXFirst ); + + // + // Compute the X coordinates of the selection rectangle + // + hr = m_Buffer.CPtoX( m_nCaret, FALSE, &nCaretX ); + if( m_nCaret != m_nSelStart ) + hr = m_Buffer.CPtoX( m_nSelStart, FALSE, &nSelStartX ); + else + nSelStartX = nCaretX; + + // + // Render the selection rectangle + // + RECT rcSelection; // Make this available for rendering selected text + if( m_nCaret != m_nSelStart ) + { + int nSelLeftX = nCaretX, nSelRightX = nSelStartX; + // Swap if left is bigger than right + if( nSelLeftX > nSelRightX ) + { + int nTemp = nSelLeftX; nSelLeftX = nSelRightX; nSelRightX = nTemp; + } + + SetRect( &rcSelection, nSelLeftX, m_rcText.top, nSelRightX, m_rcText.bottom ); + OffsetRect( &rcSelection, m_rcText.left - nXFirst, 0 ); + IntersectRect( &rcSelection, &m_rcText, &rcSelection ); + + IDirect3DDevice9* pd3dDevice = m_pDialog->GetManager()->GetD3D9Device(); + if( pd3dDevice ) + pd3dDevice->SetRenderState( D3DRS_ZENABLE, FALSE ); + m_pDialog->DrawRect( &rcSelection, m_SelBkColor ); + if( pd3dDevice ) + pd3dDevice->SetRenderState( D3DRS_ZENABLE, TRUE ); + } + + // + // Render the text + // + // Element 0 for text + m_Elements.GetAt( 0 )->FontColor.Current = m_TextColor; + m_pDialog->DrawText( m_Buffer.GetBuffer() + m_nFirstVisible, m_Elements.GetAt( 0 ), &m_rcText ); + + // Render the selected text + if( m_nCaret != m_nSelStart ) + { + int nFirstToRender = __max( m_nFirstVisible, __min( m_nSelStart, m_nCaret ) ); + int nNumChatToRender = __max( m_nSelStart, m_nCaret ) - nFirstToRender; + m_Elements.GetAt( 0 )->FontColor.Current = m_SelTextColor; + m_pDialog->DrawText( m_Buffer.GetBuffer() + nFirstToRender, + m_Elements.GetAt( 0 ), &rcSelection, false, nNumChatToRender ); + } + + // + // Blink the caret + // + if( DXUTGetGlobalTimer()->GetAbsoluteTime() - m_dfLastBlink >= m_dfBlink ) + { + m_bCaretOn = !m_bCaretOn; + m_dfLastBlink = DXUTGetGlobalTimer()->GetAbsoluteTime(); + } + + // + // Render the caret if this control has the focus + // + if( m_bHasFocus && m_bCaretOn && !s_bHideCaret ) + { + // Start the rectangle with insert mode caret + RECT rcCaret = + { + m_rcText.left - nXFirst + nCaretX - 1, m_rcText.top, + m_rcText.left - nXFirst + nCaretX + 1, m_rcText.bottom + }; + + // If we are in overwrite mode, adjust the caret rectangle + // to fill the entire character. + if( !m_bInsertMode ) + { + // Obtain the right edge X coord of the current character + int nRightEdgeX; + m_Buffer.CPtoX( m_nCaret, TRUE, &nRightEdgeX ); + rcCaret.right = m_rcText.left - nXFirst + nRightEdgeX; + } + + m_pDialog->DrawRect( &rcCaret, m_CaretColor ); + } +} + + +#define IN_FLOAT_CHARSET( c ) \ + ( (c) == L'-' || (c) == L'.' || ( (c) >= L'0' && (c) <= L'9' ) ) + +void CDXUTEditBox::ParseFloatArray( float* pNumbers, int nCount ) +{ + int nWritten = 0; // Number of floats written + const WCHAR* pToken, *pEnd; + WCHAR wszToken[60]; + + pToken = m_Buffer.GetBuffer(); + while( nWritten < nCount && *pToken != L'\0' ) + { + // Skip leading spaces + while( *pToken == L' ' ) + ++pToken; + + if( *pToken == L'\0' ) + break; + + // Locate the end of number + pEnd = pToken; + while( IN_FLOAT_CHARSET( *pEnd ) ) + ++pEnd; + + // Copy the token to our buffer + int nTokenLen = __min( sizeof( wszToken ) / sizeof( wszToken[0] ) - 1, int( pEnd - pToken ) ); + wcscpy_s( wszToken, nTokenLen, pToken ); + *pNumbers = ( float )wcstod( wszToken, NULL ); + ++nWritten; + ++pNumbers; + pToken = pEnd; + } +} + + +void CDXUTEditBox::SetTextFloatArray( const float* pNumbers, int nCount ) +{ + WCHAR wszBuffer[512] = + { + 0 + }; + WCHAR wszTmp[64]; + + if( pNumbers == NULL ) + return; + + for( int i = 0; i < nCount; ++i ) + { + swprintf_s( wszTmp, 64, L"%.4f ", pNumbers[i] ); + wcscat_s( wszBuffer, 512, wszTmp ); + } + + // Don't want the last space + if( nCount > 0 && wcslen( wszBuffer ) > 0 ) + wszBuffer[wcslen( wszBuffer ) - 1] = 0; + + SetText( wszBuffer ); +} + + + + +//-------------------------------------------------------------------------------------- +void CUniBuffer::Initialize() +{ + if( s_hDll ) // Only need to do once + return; + + s_hDll = LoadLibrary( UNISCRIBE_DLLNAME ); + if( s_hDll ) + { + FARPROC Temp; + GETPROCADDRESS( s_hDll, ScriptApplyDigitSubstitution, Temp ); + GETPROCADDRESS( s_hDll, ScriptStringAnalyse, Temp ); + GETPROCADDRESS( s_hDll, ScriptStringCPtoX, Temp ); + GETPROCADDRESS( s_hDll, ScriptStringXtoCP, Temp ); + GETPROCADDRESS( s_hDll, ScriptStringFree, Temp ); + GETPROCADDRESS( s_hDll, ScriptString_pLogAttr, Temp ); + GETPROCADDRESS( s_hDll, ScriptString_pcOutChars, Temp ); + } +} + + +//-------------------------------------------------------------------------------------- +void CUniBuffer::Uninitialize() +{ + if( s_hDll ) + { + PLACEHOLDERPROC( ScriptApplyDigitSubstitution ); + PLACEHOLDERPROC( ScriptStringAnalyse ); + PLACEHOLDERPROC( ScriptStringCPtoX ); + PLACEHOLDERPROC( ScriptStringXtoCP ); + PLACEHOLDERPROC( ScriptStringFree ); + PLACEHOLDERPROC( ScriptString_pLogAttr ); + PLACEHOLDERPROC( ScriptString_pcOutChars ); + + FreeLibrary( s_hDll ); + s_hDll = NULL; + } +} + + +//-------------------------------------------------------------------------------------- +bool CUniBuffer::SetBufferSize( int nNewSize ) +{ + // If the current size is already the maximum allowed, + // we can't possibly allocate more. + if( m_nBufferSize == DXUT_MAX_EDITBOXLENGTH ) + return false; + + int nAllocateSize = ( nNewSize == -1 || nNewSize < m_nBufferSize * 2 ) ? ( m_nBufferSize ? m_nBufferSize * + 2 : 256 ) : nNewSize * 2; + + // Cap the buffer size at the maximum allowed. + if( nAllocateSize > DXUT_MAX_EDITBOXLENGTH ) + nAllocateSize = DXUT_MAX_EDITBOXLENGTH; + + WCHAR* pTempBuffer = new WCHAR[nAllocateSize]; + if( !pTempBuffer ) + return false; + + ZeroMemory( pTempBuffer, sizeof( WCHAR ) * nAllocateSize ); + + if( m_pwszBuffer ) + { + CopyMemory( pTempBuffer, m_pwszBuffer, m_nBufferSize * sizeof( WCHAR ) ); + delete[] m_pwszBuffer; + } + + m_pwszBuffer = pTempBuffer; + m_nBufferSize = nAllocateSize; + return true; +} + + +//-------------------------------------------------------------------------------------- +// Uniscribe -- Analyse() analyses the string in the buffer +//-------------------------------------------------------------------------------------- +HRESULT CUniBuffer::Analyse() +{ + if( m_Analysis ) + _ScriptStringFree( &m_Analysis ); + + SCRIPT_CONTROL ScriptControl; // For uniscribe + SCRIPT_STATE ScriptState; // For uniscribe + ZeroMemory( &ScriptControl, sizeof( ScriptControl ) ); + ZeroMemory( &ScriptState, sizeof( ScriptState ) ); + _ScriptApplyDigitSubstitution( NULL, &ScriptControl, &ScriptState ); + + if( !m_pFontNode ) + return E_FAIL; + + HDC hDC = + ( m_pFontNode->pFont9 ? m_pFontNode->pFont9->GetDC() : NULL ); + HRESULT hr = _ScriptStringAnalyse( hDC, + m_pwszBuffer, + lstrlenW( m_pwszBuffer ) + 1, // NULL is also analyzed. + lstrlenW( m_pwszBuffer ) * 3 / 2 + 16, + -1, + SSA_BREAK | SSA_GLYPHS | SSA_FALLBACK | SSA_LINK, + 0, + &ScriptControl, + &ScriptState, + NULL, + NULL, + NULL, + &m_Analysis ); + if( SUCCEEDED( hr ) ) + m_bAnalyseRequired = false; // Analysis is up-to-date + return hr; +} + + +//-------------------------------------------------------------------------------------- +CUniBuffer::CUniBuffer( int nInitialSize ) +{ + CUniBuffer::Initialize(); // ensure static vars are properly init'ed first + + m_nBufferSize = 0; + m_pwszBuffer = NULL; + m_bAnalyseRequired = true; + m_Analysis = NULL; + m_pFontNode = NULL; + + if( nInitialSize > 0 ) + SetBufferSize( nInitialSize ); +} + + +//-------------------------------------------------------------------------------------- +CUniBuffer::~CUniBuffer() +{ + delete[] m_pwszBuffer; + if( m_Analysis ) + _ScriptStringFree( &m_Analysis ); +} + + +//-------------------------------------------------------------------------------------- +WCHAR& CUniBuffer::operator[]( int n ) // No param checking +{ + // This version of operator[] is called only + // if we are asking for write access, so + // re-analysis is required. + m_bAnalyseRequired = true; + return m_pwszBuffer[n]; +} + + +//-------------------------------------------------------------------------------------- +void CUniBuffer::Clear() +{ + *m_pwszBuffer = L'\0'; + m_bAnalyseRequired = true; +} + + +//-------------------------------------------------------------------------------------- +// Inserts the char at specified index. +// If nIndex == -1, insert to the end. +//-------------------------------------------------------------------------------------- +bool CUniBuffer::InsertChar( int nIndex, WCHAR wChar ) +{ + assert( nIndex >= 0 ); + + if( nIndex < 0 || nIndex > lstrlenW( m_pwszBuffer ) ) + return false; // invalid index + + // Check for maximum length allowed + if( GetTextSize() + 1 >= DXUT_MAX_EDITBOXLENGTH ) + return false; + + if( lstrlenW( m_pwszBuffer ) + 1 >= m_nBufferSize ) + { + if( !SetBufferSize( -1 ) ) + return false; // out of memory + } + + assert( m_nBufferSize >= 2 ); + + // Shift the characters after the index, start by copying the null terminator + WCHAR* dest = m_pwszBuffer + lstrlenW( m_pwszBuffer ) + 1; + WCHAR* stop = m_pwszBuffer + nIndex; + WCHAR* src = dest - 1; + + while( dest > stop ) + { + *dest-- = *src--; + } + + // Set new character + m_pwszBuffer[ nIndex ] = wChar; + m_bAnalyseRequired = true; + + return true; +} + + +//-------------------------------------------------------------------------------------- +// Removes the char at specified index. +// If nIndex == -1, remove the last char. +//-------------------------------------------------------------------------------------- +bool CUniBuffer::RemoveChar( int nIndex ) +{ + if( !lstrlenW( m_pwszBuffer ) || nIndex < 0 || nIndex >= lstrlenW( m_pwszBuffer ) ) + return false; // Invalid index + + MoveMemory( m_pwszBuffer + nIndex, m_pwszBuffer + nIndex + 1, sizeof( WCHAR ) * + ( lstrlenW( m_pwszBuffer ) - nIndex ) ); + m_bAnalyseRequired = true; + return true; +} + + +//-------------------------------------------------------------------------------------- +// Inserts the first nCount characters of the string pStr at specified index. +// If nCount == -1, the entire string is inserted. +// If nIndex == -1, insert to the end. +//-------------------------------------------------------------------------------------- +bool CUniBuffer::InsertString( int nIndex, const WCHAR* pStr, int nCount ) +{ + assert( nIndex >= 0 ); + if( nIndex < 0 ) + return false; + + if( nIndex > lstrlenW( m_pwszBuffer ) ) + return false; // invalid index + + if( -1 == nCount ) + nCount = lstrlenW( pStr ); + + // Check for maximum length allowed + if( GetTextSize() + nCount >= DXUT_MAX_EDITBOXLENGTH ) + return false; + + if( lstrlenW( m_pwszBuffer ) + nCount >= m_nBufferSize ) + { + if( !SetBufferSize( lstrlenW( m_pwszBuffer ) + nCount + 1 ) ) + return false; // out of memory + } + + MoveMemory( m_pwszBuffer + nIndex + nCount, m_pwszBuffer + nIndex, sizeof( WCHAR ) * + ( lstrlenW( m_pwszBuffer ) - nIndex + 1 ) ); + CopyMemory( m_pwszBuffer + nIndex, pStr, nCount * sizeof( WCHAR ) ); + m_bAnalyseRequired = true; + + return true; +} + + +//-------------------------------------------------------------------------------------- +bool CUniBuffer::SetText( LPCWSTR wszText ) +{ + assert( wszText != NULL ); + + int nRequired = int( wcslen( wszText ) + 1 ); + + // Check for maximum length allowed + if( nRequired >= DXUT_MAX_EDITBOXLENGTH ) + return false; + + while( GetBufferSize() < nRequired ) + if( !SetBufferSize( -1 ) ) + break; + // Check again in case out of memory occurred inside while loop. + if( GetBufferSize() >= nRequired ) + { + wcscpy_s( m_pwszBuffer, GetBufferSize(), wszText ); + m_bAnalyseRequired = true; + return true; + } + else + return false; +} + + +//-------------------------------------------------------------------------------------- +HRESULT CUniBuffer::CPtoX( int nCP, BOOL bTrail, int* pX ) +{ + assert( pX ); + *pX = 0; // Default + + HRESULT hr = S_OK; + if( m_bAnalyseRequired ) + hr = Analyse(); + + if( SUCCEEDED( hr ) ) + hr = _ScriptStringCPtoX( m_Analysis, nCP, bTrail, pX ); + + return hr; +} + + +//-------------------------------------------------------------------------------------- +HRESULT CUniBuffer::XtoCP( int nX, int* pCP, int* pnTrail ) +{ + assert( pCP && pnTrail ); + *pCP = 0; *pnTrail = FALSE; // Default + + HRESULT hr = S_OK; + if( m_bAnalyseRequired ) + hr = Analyse(); + + if( SUCCEEDED( hr ) ) + hr = _ScriptStringXtoCP( m_Analysis, nX, pCP, pnTrail ); + + // If the coordinate falls outside the text region, we + // can get character positions that don't exist. We must + // filter them here and convert them to those that do exist. + if( *pCP == -1 && *pnTrail == TRUE ) + { + *pCP = 0; *pnTrail = FALSE; + } + else if( *pCP > lstrlenW( m_pwszBuffer ) && *pnTrail == FALSE ) + { + *pCP = lstrlenW( m_pwszBuffer ); *pnTrail = TRUE; + } + + return hr; +} + + +//-------------------------------------------------------------------------------------- +void CUniBuffer::GetPriorItemPos( int nCP, int* pPrior ) +{ + *pPrior = nCP; // Default is the char itself + + if( m_bAnalyseRequired ) + if( FAILED( Analyse() ) ) + return; + + const SCRIPT_LOGATTR* pLogAttr = _ScriptString_pLogAttr( m_Analysis ); + if( !pLogAttr ) + return; + + if( !_ScriptString_pcOutChars( m_Analysis ) ) + return; + int nInitial = *_ScriptString_pcOutChars( m_Analysis ); + if( nCP - 1 < nInitial ) + nInitial = nCP - 1; + for( int i = nInitial; i > 0; --i ) + if( pLogAttr[i].fWordStop || // Either the fWordStop flag is set + ( !pLogAttr[i].fWhiteSpace && // Or the previous char is whitespace but this isn't. + pLogAttr[i - 1].fWhiteSpace ) ) + { + *pPrior = i; + return; + } + // We have reached index 0. 0 is always a break point, so simply return it. + *pPrior = 0; +} + + +//-------------------------------------------------------------------------------------- +void CUniBuffer::GetNextItemPos( int nCP, int* pPrior ) +{ + *pPrior = nCP; // Default is the char itself + + HRESULT hr = S_OK; + if( m_bAnalyseRequired ) + hr = Analyse(); + if( FAILED( hr ) ) + return; + + const SCRIPT_LOGATTR* pLogAttr = _ScriptString_pLogAttr( m_Analysis ); + if( !pLogAttr ) + return; + + if( !_ScriptString_pcOutChars( m_Analysis ) ) + return; + int nInitial = *_ScriptString_pcOutChars( m_Analysis ); + if( nCP + 1 < nInitial ) + nInitial = nCP + 1; + + int i = nInitial; + int limit = *_ScriptString_pcOutChars( m_Analysis ); + while( limit > 0 && i < limit - 1 ) + { + if( pLogAttr[i].fWordStop ) // Either the fWordStop flag is set + { + *pPrior = i; + return; + } + else if( pLogAttr[i].fWhiteSpace && // Or this whitespace but the next char isn't. + !pLogAttr[i + 1].fWhiteSpace ) + { + *pPrior = i + 1; // The next char is a word stop + return; + } + + ++i; + limit = *_ScriptString_pcOutChars( m_Analysis ); + } + // We have reached the end. It's always a word stop, so simply return it. + *pPrior = *_ScriptString_pcOutChars( m_Analysis ) - 1; +} + + +//-------------------------------------------------------------------------------------- +void CDXUTEditBox::ResetCaretBlink() +{ + m_bCaretOn = true; + m_dfLastBlink = DXUTGetGlobalTimer()->GetAbsoluteTime(); +} + + +//-------------------------------------------------------------------------------------- +void DXUTBlendColor::Init( D3DCOLOR defaultColor, D3DCOLOR disabledColor, D3DCOLOR hiddenColor ) +{ + for( int i = 0; i < MAX_CONTROL_STATES; i++ ) + { + States[ i ] = defaultColor; + } + + States[ DXUT_STATE_DISABLED ] = disabledColor; + States[ DXUT_STATE_HIDDEN ] = hiddenColor; + Current = hiddenColor; +} + + +//-------------------------------------------------------------------------------------- +void DXUTBlendColor::Blend( UINT iState, float fElapsedTime, float fRate ) +{ + D3DXCOLOR destColor = States[ iState ]; + D3DXColorLerp( &Current, &Current, &destColor, 1.0f - powf( fRate, 30 * fElapsedTime ) ); +} + + + +//-------------------------------------------------------------------------------------- +void CDXUTElement::SetTexture( UINT iTexture, RECT* prcTexture, D3DCOLOR defaultTextureColor ) +{ + this->iTexture = iTexture; + + if( prcTexture ) + rcTexture = *prcTexture; + else + SetRectEmpty( &rcTexture ); + + TextureColor.Init( defaultTextureColor ); +} + + +//-------------------------------------------------------------------------------------- +void CDXUTElement::SetFont( UINT iFont, D3DCOLOR defaultFontColor, DWORD dwTextFormat ) +{ + this->iFont = iFont; + this->dwTextFormat = dwTextFormat; + + FontColor.Init( defaultFontColor ); +} + + +//-------------------------------------------------------------------------------------- +void CDXUTElement::Refresh() +{ + TextureColor.Current = TextureColor.States[ DXUT_STATE_HIDDEN ]; + FontColor.Current = FontColor.States[ DXUT_STATE_HIDDEN ]; +} + + |