diff options
| author | Jason Maskell <[email protected]> | 2016-05-09 10:39:54 +0200 |
|---|---|---|
| committer | Jason Maskell <[email protected]> | 2016-05-09 10:39:54 +0200 |
| commit | 79b3462799c28af8ba586349bd671b1b56e72353 (patch) | |
| tree | 3b06e36c390254c0dc7f3733a0d32af213d87293 /test/d3d10/common/DXUTgui.cpp | |
| download | waveworks_archive-79b3462799c28af8ba586349bd671b1b56e72353.tar.xz waveworks_archive-79b3462799c28af8ba586349bd671b1b56e72353.zip | |
Initial commit with PS4 and XBone stuff trimmed.
Diffstat (limited to 'test/d3d10/common/DXUTgui.cpp')
| -rw-r--r-- | test/d3d10/common/DXUTgui.cpp | 6901 |
1 files changed, 6901 insertions, 0 deletions
diff --git a/test/d3d10/common/DXUTgui.cpp b/test/d3d10/common/DXUTgui.cpp new file mode 100644 index 0000000..eb83eda --- /dev/null +++ b/test/d3d10/common/DXUTgui.cpp @@ -0,0 +1,6901 @@ +// This code contains NVIDIA Confidential Information and is disclosed +// under the Mutual Non-Disclosure Agreement. +// +// Notice +// ALL NVIDIA DESIGN SPECIFICATIONS AND CODE ("MATERIALS") ARE PROVIDED "AS IS" NVIDIA MAKES +// NO REPRESENTATIONS, WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO +// THE MATERIALS, AND EXPRESSLY DISCLAIMS ANY IMPLIED WARRANTIES OF NONINFRINGEMENT, +// MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. +// +// NVIDIA Corporation assumes no responsibility for the consequences of use of such +// information or for any infringement of patents or other rights of third parties that may +// result from its use. No license is granted by implication or otherwise under any patent +// or patent rights of NVIDIA Corporation. No third party distribution is allowed unless +// expressly authorized by NVIDIA. Details are subject to change without notice. +// This code supersedes and replaces all information previously supplied. +// NVIDIA Corporation products are not authorized for use as critical +// components in life support devices or systems without express written approval of +// NVIDIA Corporation. +// +// Copyright � 2008- 2013 NVIDIA Corporation. All rights reserved. +// +// NVIDIA Corporation and its licensors retain all intellectual property and proprietary +// rights in and to this software and related documentation and any modifications thereto. +// Any use, reproduction, disclosure or distribution of this software and related +// documentation without an express license agreement from NVIDIA Corporation is +// strictly prohibited. +// + +//-------------------------------------------------------------------------------------- +// File: DXUTgui.cpp +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//-------------------------------------------------------------------------------------- +#include "dxstdafx.h" +#include "DXUT.h" +#include "DXUTgui.h" +#include "DXUTsettingsDlg.h" +#include "DXUTres.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 : SV_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 ); +} + + + +//-------------------------------------------------------------------------------------- +// 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; + // End D3D9-specific + + // Begin D3D10-specific + m_pd3d10Device = NULL; + m_pEffect10 = NULL; + m_pTechRenderUI10 = NULL; + m_pTechRenderUIUntex10 = NULL; + m_pFxTexture10 = NULL; + m_pInputLayout10 = NULL; + m_pVBScreenQuad10 = NULL; + m_pStateBlock10 = NULL; + m_pSprite10 = NULL; + m_nBackBufferWidth = m_nBackBufferHeight = 0; + + // End D3D10-specific +} + + +//-------------------------------------------------------------------------------------- +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::OnD3D10CreateDevice( ID3D10Device* pd3dDevice ) +{ + m_pd3d10Device = pd3dDevice; + + HRESULT hr = S_OK; + + // Create the UI effect object + V_RETURN( D3DX10CreateEffectFromMemory( g_strUIEffectFile, g_uUIEffectFileSize, NULL, NULL, + NULL, "fx_4_0", D3D10_SHADER_ENABLE_STRICTNESS, 0, + pd3dDevice, NULL, NULL, &m_pEffect10, NULL, NULL ) ); + + m_pTechRenderUI10 = m_pEffect10->GetTechniqueByName( "RenderUI" ); + m_pTechRenderUIUntex10 = m_pEffect10->GetTechniqueByName( "RenderUIUntex" ); + m_pFxTexture10 = m_pEffect10->GetVariableByName( "g_Texture" )->AsShaderResource(); + + // Create the font and texture objects in the cache arrays. + int i = 0; + for( i = 0; i < m_FontCache.GetSize(); i++ ) + { + hr = CreateFont10( i ); + if( FAILED( hr ) ) + return hr; + } + + for( i = 0; i < m_TextureCache.GetSize(); i++ ) + { + hr = CreateTexture10( i ); + if( FAILED( hr ) ) + return hr; + } + + // Create input layout + const D3D10_INPUT_ELEMENT_DESC layout[] = + { + { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D10_INPUT_PER_VERTEX_DATA, 0 }, + { "COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 12, D3D10_INPUT_PER_VERTEX_DATA, 0 }, + { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 28, D3D10_INPUT_PER_VERTEX_DATA, 0 }, + }; + + D3D10_PASS_DESC PassDesc; + V_RETURN( m_pTechRenderUI10->GetPassByIndex( 0 )->GetDesc( &PassDesc ) ); + V_RETURN( pd3dDevice->CreateInputLayout( layout, 3, PassDesc.pIAInputSignature, + PassDesc.IAInputSignatureSize, &m_pInputLayout10 ) ); + + // Create a vertex buffer quad for rendering later + D3D10_BUFFER_DESC BufDesc; + BufDesc.ByteWidth = sizeof( DXUT_SCREEN_VERTEX_10 ) * 4; + BufDesc.Usage = D3D10_USAGE_DYNAMIC; + BufDesc.BindFlags = D3D10_BIND_VERTEX_BUFFER; + BufDesc.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE; + BufDesc.MiscFlags = 0; + V_RETURN( pd3dDevice->CreateBuffer( &BufDesc, NULL, &m_pVBScreenQuad10 ) ); + + return S_OK; +} + + +//-------------------------------------------------------------------------------------- +HRESULT CDXUTDialogResourceManager::OnD3D10ResizedSwapChain( ID3D10Device* pd3dDevice, + const DXGI_SURFACE_DESC* pBackBufferSurfaceDesc ) +{ + HRESULT hr = S_OK; + + m_nBackBufferWidth = pBackBufferSurfaceDesc->Width; + m_nBackBufferHeight = pBackBufferSurfaceDesc->Height; + + hr = D3DX10CreateSprite( pd3dDevice, DXUT_MAX_GUI_SPRITES, &m_pSprite10 ); + if( FAILED( hr ) ) + return DXUT_ERR( L"D3DX10CreateSprite", hr ); + + D3D10_STATE_BLOCK_MASK StateBlockMask; + DXUT_Dynamic_D3D10StateBlockMaskEnableAll( &StateBlockMask ); + DXUT_Dynamic_D3D10StateBlockMaskDisableCapture( &StateBlockMask, D3D10_DST_OM_RENDER_TARGETS, 0, 1 ); + V_RETURN( DXUT_Dynamic_D3D10CreateStateBlock( pd3dDevice, &StateBlockMask, &m_pStateBlock10 ) ); + + return hr; +} + + +//-------------------------------------------------------------------------------------- +void CDXUTDialogResourceManager::OnD3D10ReleasingSwapChain() +{ + SAFE_RELEASE( m_pSprite10 ); + SAFE_RELEASE( m_pStateBlock10 ); +} + + +//-------------------------------------------------------------------------------------- +void CDXUTDialogResourceManager::OnD3D10DestroyDevice() +{ + int i; + + m_pd3d10Device = 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->pFont10 ); + } + + for( i = 0; i < m_TextureCache.GetSize(); i++ ) + { + DXUTTextureNode* pTextureNode = m_TextureCache.GetAt( i ); + SAFE_RELEASE( pTextureNode->pTexResView ); + SAFE_RELEASE( pTextureNode->pTexture10 ); + } + + SAFE_RELEASE( m_pVBScreenQuad10 ); + SAFE_RELEASE( m_pStateBlock10 ); + SAFE_RELEASE( m_pSprite10 ); + SAFE_RELEASE( m_pInputLayout10 ); + SAFE_RELEASE( m_pEffect10 ); +} + + +//-------------------------------------------------------------------------------------- +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 OnRender10( 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->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::OnRender10( 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->GetD3D10Device() && + 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; + + ID3D10Device* pd3dDevice = m_pManager->GetD3D10Device(); + + // Set up a state block here and restore it when finished drawing all the controls + m_pManager->m_pStateBlock10->Capture(); + + 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; + if( SUCCEEDED( m_pManager->m_pVBScreenQuad10->Map( D3D10_MAP_WRITE_DISCARD, 0, ( LPVOID* )&pVB ) ) ) + { + CopyMemory( pVB, vertices, sizeof( vertices ) ); + m_pManager->m_pVBScreenQuad10->Unmap(); + } + + // Set the quad VB as current + UINT stride = sizeof( DXUT_SCREEN_VERTEX_10 ); + UINT offset = 0; + pd3dDevice->IASetVertexBuffers( 0, 1, &m_pManager->m_pVBScreenQuad10, &stride, &offset ); + pd3dDevice->IASetInputLayout( m_pManager->m_pInputLayout10 ); + pd3dDevice->IASetPrimitiveTopology( D3D10_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP ); + + // Draw dialog background + D3D10_TECHNIQUE_DESC techDesc; + m_pManager->m_pTechRenderUIUntex10->GetDesc( &techDesc ); + for( UINT p = 0; p < techDesc.Passes; ++p ) + { + m_pManager->m_pTechRenderUIUntex10->GetPassByIndex( p )->Apply( 0 ); + pd3dDevice->Draw( 4, 0 ); + } + } + + DXUTTextureNode* pTextureNode = GetTexture( 0 ); + m_pManager->m_pFxTexture10->SetResource( pTextureNode->pTexResView ); + + // Sort depth back to front + m_pManager->m_pSprite10->Begin( 0 ); + + m_pManager->m_pTechRenderUI10->GetPassByIndex( 0 )->Apply( 0 ); + + // 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 }; + DrawSprite10( &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)" ); + DrawText10( 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_pSprite10->End(); + + m_pManager->m_pStateBlock10->Apply(); + // Restore depth stencil state + m_pManager->m_pEffect10->GetTechniqueByName( "RestoreState" )->GetPassByIndex( 0 )->Apply( 0 ); + + 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 = wcslen( strFaceName ); + 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 ); + if( m_pd3d10Device ) + CreateFont10( 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 = wcslen( strFilename ); + 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 = wcslen( strResourceName ); + 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::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 ); + else + return DrawRect10( pRect, color ); +} + + +//-------------------------------------------------------------------------------------- +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::DrawRect10( 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 ); + + ID3D10Device* pd3dDevice = m_pManager->GetD3D10Device(); + + // Convert the rect from screen coordinates to clip space coordinates. + float Left, Right, Top, Bottom; + Left = rcScreen.left * 2.0f / m_pManager->m_nBackBufferWidth - 1.0f; + Right = rcScreen.right * 2.0f / m_pManager->m_nBackBufferWidth - 1.0f; + Top = 1.0f - rcScreen.top * 2.0f / m_pManager->m_nBackBufferHeight; + Bottom = 1.0f - rcScreen.bottom * 2.0f / m_pManager->m_nBackBufferHeight; + DXUT_SCREEN_VERTEX_10 vertices[4] = + { + { Left, Top, 0.5f, D3DCOLOR_TO_D3DCOLORVALUE( color ), 0.0f, 0.0f }, + { Right, Top, 0.5f, D3DCOLOR_TO_D3DCOLORVALUE( color ), 1.0f, 0.0f }, + { Left, Bottom, 0.5f, D3DCOLOR_TO_D3DCOLORVALUE( color ), 0.0f, 1.0f }, + { Right, Bottom, 0.5f, D3DCOLOR_TO_D3DCOLORVALUE( color ), 1.0f, 1.0f }, + }; + DXUT_SCREEN_VERTEX_10* pVB; + if( SUCCEEDED( m_pManager->m_pVBScreenQuad10->Map( D3D10_MAP_WRITE_DISCARD, 0, ( LPVOID* )&pVB ) ) ) + { + CopyMemory( pVB, vertices, sizeof( vertices ) ); + m_pManager->m_pVBScreenQuad10->Unmap(); + } + + // Since we're doing our own drawing here we need to flush the sprites + m_pManager->m_pSprite10->Flush(); + + ID3D10InputLayout* pOldLayout; + D3D10_PRIMITIVE_TOPOLOGY OldTopology; + + pd3dDevice->IAGetInputLayout( &pOldLayout ); + pd3dDevice->IAGetPrimitiveTopology( &OldTopology ); + pd3dDevice->IASetInputLayout( m_pManager->m_pInputLayout10 ); + pd3dDevice->IASetPrimitiveTopology( D3D10_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP ); + + D3D10_TECHNIQUE_DESC techDesc; + m_pManager->m_pTechRenderUI10->GetDesc( &techDesc ); + for( UINT p = 0; p < techDesc.Passes; ++p ) + { + m_pManager->m_pTechRenderUI10->GetPassByIndex( p )->Apply( 0 ); + pd3dDevice->Draw( 4, 0 ); + } + + pd3dDevice->IASetInputLayout( pOldLayout ); + pd3dDevice->IASetPrimitiveTopology( OldTopology ); + SAFE_RELEASE( pOldLayout ); + + 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 DrawSprite10( 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::DrawSprite10( 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 ); + OffsetRect( &rcScreen, RectWidth( rcScreen ) / 2, RectHeight( rcScreen ) / 2 ); + + // 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 fScaleX = ( float )RectWidth( rcScreen ); + float fScaleY = ( float )RectHeight( rcScreen ); + + D3DXVECTOR3 vPos( ( float )rcScreen.left, ( float )rcScreen.top, fDepth ); + + D3DXMATRIXA16 matScaling; + D3DXMATRIXA16 matTranslation; + D3DXMatrixScaling( &matScaling, fScaleX, fScaleY, 1.0f ); + D3DXMatrixTranslation( &matTranslation, vPos.x, fBBHeight - vPos.y, vPos.z ); + + D3DXMATRIXA16 matProjection; + D3DXMatrixOrthoOffCenterLH( &matProjection, 0.0f, fBBWidth, 0.0f, fBBHeight, 0.1f, 10 ); + m_pManager->m_pSprite10->SetProjectionTransform( &matProjection ); + + D3DX10_SPRITE Sprite; + + Sprite.matWorld = matScaling * matTranslation; + Sprite.pTexture = pTextureNode->pTexResView; + float fTexWidth = ( float )pTextureNode->dwWidth; + float fTexHeight = ( float )pTextureNode->dwHeight; + Sprite.TexCoord.x = ( float )( rcTexture.left ) / fTexWidth; + Sprite.TexCoord.y = ( float )( rcTexture.top ) / fTexHeight; + Sprite.TexSize.x = ( float )( rcTexture.right - rcTexture.left ) / fTexWidth; + Sprite.TexSize.y = ( float )( rcTexture.bottom - rcTexture.top ) / fTexHeight; + Sprite.TextureIndex = 0; + Sprite.ColorModulate = pElement->TextureColor.Current; + + return m_pManager->m_pSprite10->DrawSpritesBuffered( &Sprite, 1 ); +} + + +//-------------------------------------------------------------------------------------- +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->pFont10 ) + { + hr = pFontNode->pFont10->DrawText( NULL, strText, nCount, prcDest, dwTextFormat, pElement->FontColor.Current ); + if( FAILED( hr ) ) + return hr; + } + else 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 ) +{ + if( m_pManager->GetD3D9Device() ) + return DrawText9( strText, pElement, prcDest, bShadow, nCount ); + else + return DrawText10( strText, pElement, prcDest, bShadow, nCount ); +} + + +//-------------------------------------------------------------------------------------- +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; +} + + +//-------------------------------------------------------------------------------------- +HRESULT CDXUTDialog::DrawText10( 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 ); + + float fBBWidth = ( float )m_pManager->m_nBackBufferWidth; + float fBBHeight = ( float )m_pManager->m_nBackBufferHeight; + + D3DXMATRIX matProjection; + D3DXMatrixOrthoOffCenterLH( &matProjection, 0.0f, fBBWidth, 0.0f, fBBHeight, 0.1f, 10 ); + m_pManager->m_pSprite10->SetProjectionTransform( &matProjection ); + + DXUTFontNode* pFontNode = GetFont( pElement->iFont ); + + if( bShadow ) + { + RECT rcShadow = rcScreen; + OffsetRect( &rcShadow, 1, 1 ); + hr = pFontNode->pFont10->DrawText( m_pManager->m_pSprite10, strText, nCount, &rcShadow, pElement->dwTextFormat, + D3DCOLOR_ARGB( DWORD( pElement->FontColor.Current.a * 255 ), 0, 0, 0 ) ); + if( FAILED( hr ) ) + return hr; + } + + hr = pFontNode->pFont10->DrawText( m_pManager->m_pSprite10, strText, nCount, &rcScreen, pElement->dwTextFormat, + pElement->FontColor.Current ); + if( FAILED( hr ) ) + return hr; + + 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::CreateFont10( UINT iFont ) +{ + HRESULT hr = S_OK; + + DXUTFontNode* pFontNode = m_FontCache.GetAt( iFont ); + + SAFE_RELEASE( pFontNode->pFont10 ); + + V_RETURN( D3DX10CreateFont( m_pd3d10Device, pFontNode->nHeight, 0, pFontNode->nWeight, 1, FALSE, DEFAULT_CHARSET, + OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, + pFontNode->strFace, &pFontNode->pFont10 ) ); + + 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 ); + } + 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::CreateTexture10( UINT iTexture ) +{ + HRESULT hr = S_OK; + + DXUTTextureNode* pTextureNode = m_TextureCache.GetAt( iTexture ); + + if( !pTextureNode->bFileSource ) + { + if( pTextureNode->nResourceID == 0xFFFF && pTextureNode->hResourceModule == ( HMODULE )0xFFFF ) + { + hr = DXUTCreateGUITextureFromInternalArray10( m_pd3d10Device, &pTextureNode->pTexture10, NULL ); + if( FAILED( hr ) ) + return DXTRACE_ERR( L"D3DX10CreateResourceFromFileInMemory", hr ); + } + 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 + D3D10_TEXTURE2D_DESC desc; + pTextureNode->pTexture10->GetDesc( &desc ); + pTextureNode->dwWidth = desc.Width; + pTextureNode->dwHeight = desc.Height; + + // Create resource view + D3D10_SHADER_RESOURCE_VIEW_DESC SRVDesc; + SRVDesc.ViewDimension = D3D10_SRV_DIMENSION_TEXTURE2D; + SRVDesc.Format = MAKE_SRGB( desc.Format ); + SRVDesc.Texture2D.MipLevels = 1; + SRVDesc.Texture2D.MostDetailedMip = 0; + hr = m_pd3d10Device->CreateShaderResourceView( pTextureNode->pTexture10, &SRVDesc, &pTextureNode->pTexResView ); + + 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, true ); +} + + +//-------------------------------------------------------------------------------------- +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 ) +{ + 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 + //TODO: remove magic numbers + 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 ); + + // 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 ); +} + + + +//-------------------------------------------------------------------------------------- +// 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 ) +{ + 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, true ); + + 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 ) +{ + 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 + //TODO: remove magic numbers + 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 ); + + } + } +} + + +//-------------------------------------------------------------------------------------- +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_FINALISED, 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 ) +{ + 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 ); + + //TODO: remove magic numbers + 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; // 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 ) +{ + // 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; +} + +//-------------------------------------------------------------------------------------- +// 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::RemoveItemByData( void* pData ) +{ +} + + +//-------------------------------------------------------------------------------------- +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->pFont10 ? m_pFontNode->pFont10->GetDC() : + ( 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 ]; +} + + |