// Choice.cpp : Implementation of cChoice #include "stdafx.h" #include "DecalControls.h" #include "Choice.h" #include "ChoicePopup.h" #include "ChoiceDropDown.h" ///////////////////////////////////////////////////////////////////////////// // cChoice cChoice::cChoice() : m_nSelected( -1 ), m_nHotSelect( -1 ), m_nDropLines( 8 ), m_bPopup( false ), m_bMouseDown( false ), m_bMouseOver( false ) { } void cChoice::setPopup( bool bPopup ) { // Always reset hot select m_bPopup = bPopup; m_nHotSelect = -1; if( bPopup ) { long nID; m_pSite->get_ID( &nID ); Fire_DropDown( nID ); m_pPopup->put_Popup( VARIANT_TRUE ); } // Redraw everything m_pSite->Reformat(); m_pSite->Invalidate(); } void cChoice::onCreate() { CComPtr< IPluginSite > pPluginSite; m_pSite->get_PluginSite( &pPluginSite ); // Create the image info pPluginSite->LoadBitmapPortal( 0x06001276, &m_pInactive ); BSTR bstrFontName; pPluginSite->get_FontName(&bstrFontName); pPluginSite->CreateFont( bstrFontName /*_bstr_t( _T( "Times New Roman" ) )*/, 14, 0, &m_pFont ); // Create the dropdown CComObject< cChoiceDropDown > *pDropDown; CComObject< cChoiceDropDown >::CreateInstance( &pDropDown ); pDropDown->m_pChoice = this; LayerParams lp = { 0, { -1, -1, 0, 0 }, 0 }; m_pSite->CreateChild( &lp, pDropDown ); m_pPopup = pDropDown->m_pSite; // Create the scroller CComPtr< ILayer > pScrollerLayer; HRESULT hRes = ::CoCreateInstance( CLSID_Scroller, NULL, CLSCTX_INPROC_SERVER, IID_ILayer, reinterpret_cast< void ** >( &pScrollerLayer ) ); _ASSERTE( SUCCEEDED( hRes ) ); pScrollerLayer->QueryInterface( &m_pScroller ); // Create the scroller object LayerParams lpScroller = { 0, { 0, 0, 0, 0 }, eRenderClipped }; m_pPopup->CreateChild( &lpScroller, pScrollerLayer ); // Configure the scroller SIZE szLine = { 18, 1 }; m_pScroller->put_Increments( &szLine ); // Create the popup window CComObject< cChoicePopup > *pPopup; CComObject< cChoicePopup >::CreateInstance( &pPopup ); pPopup->m_pChoice = this; m_pScroller->CreateClient( pPopup ); m_pPopup->put_Transparent( VARIANT_FALSE ); m_pSite->put_Transparent( VARIANT_FALSE ); } void cChoice::onDestroy() { m_pPopup.Release(); m_pFont.Release(); m_pInactive.Release(); } STDMETHODIMP cChoice::MouseUp(MouseState *) { m_bMouseDown = false; if( m_bMouseOver ) { setPopup( !m_bPopup ); if( !m_bPopup ) m_pPopup->put_Popup( VARIANT_FALSE ); } return S_OK; } #define RENDER_LEFTSTRETCH 10 #define RENDER_RIGHTSTRETCH 7 #define ROW_HEIGHT 18 #define ICON_WIDTH 20 #define ICON_HEIGHT 19 STDMETHODIMP cChoice::Render(ICanvas *pCanvas) { // First draw the background RECT rcPos; m_pSite->get_Position( &rcPos ); SIZE szImage; m_pInactive->get_Size( &szImage ); static POINT ptBack = { 0, 0 }; m_pInactive->StretchBlt( pCanvas, &ptBack, rcPos.right - rcPos.left, RENDER_LEFTSTRETCH, szImage.cx - RENDER_RIGHTSTRETCH ); if( m_nSelected != -1 ) { // Draw the selected text static POINT ptText = { 12, 2 }; m_pFont->DrawTextEx( &ptText, m_options[ m_nSelected ].m_strText, 0, 0, eAA, pCanvas ); } // Draw the up/down icon CComPtr< IPluginSite > pPluginSite; m_pSite->get_PluginSite( &pPluginSite ); SIZE szIcon = { ICON_WIDTH, ICON_HEIGHT }; CComPtr< IIconCache > pIconCache; pPluginSite->GetIconCache( &szIcon, &pIconCache ); POINT ptIcon = { rcPos.right - rcPos.left - ICON_WIDTH, 0 }; pIconCache->DrawIcon( &ptIcon, ( ( m_bMouseDown && m_bMouseOver ) ? !m_bPopup : m_bPopup ) ? 0x06001275 : 0x06001274, 0, pCanvas ); return S_OK; } STDMETHODIMP cChoice::Reformat() { if( !m_bPopup || m_options.size() == 0 ) { // If it's hidden great, hide it well static RECT rcHidden = { -1, -1, 0, 0 }; m_pPopup->put_Position( &rcHidden ); return S_OK; } // Calculate the correct position RECT rc; m_pSite->get_ScreenPosition( &rc ); // Two modes, with scroll bar and without if( m_options.size() > m_nDropLines ) { // With a scroller RECT rcPopup = { rc.left, rc.bottom, rc.right - ICON_WIDTH + 16, rc.bottom + ROW_HEIGHT * m_nDropLines }; m_pPopup->put_Position( &rcPopup ); m_pScroller->put_VerticalEnabled( VARIANT_TRUE ); SIZE szArea = { rc.right - ICON_WIDTH, ROW_HEIGHT * m_options.size() }; m_pScroller->put_Area( &szArea ); } else { RECT rcPopup = { rc.left, rc.bottom, rc.right - ICON_WIDTH, rc.bottom + ROW_HEIGHT * m_options.size() }; m_pPopup->put_Position( &rcPopup ); POINT ptOffset = { 0, 0 }; m_pScroller->put_Offset( &ptOffset ); m_pScroller->put_VerticalEnabled( VARIANT_FALSE ); SIZE szArea = { rc.right - ICON_WIDTH, ROW_HEIGHT * m_options.size() }; m_pScroller->put_Area( &szArea ); } return S_OK; } STDMETHODIMP cChoice::SchemaLoad(IView *pView, IUnknown *pSchema) { // Load the data from the schema MSXML::IXMLDOMElementPtr pElement = pSchema; MSXML::IXMLDOMElementPtr pRow; for( MSXML::IXMLDOMNodeListPtr pRows = pElement->selectNodes( _T( "option" ) ); ( pRow = pRows->nextNode() ).GetInterfacePtr() != NULL; ) { _variant_t vRow = pRow->getAttribute( _T( "text" ) ), vData = pRow->getAttribute( _T( "data" ) ); _ASSERTE( vRow.vt == VT_BSTR ); cOption o; o.m_strText = vRow; o.m_value = vData; m_options.push_back( o ); } _variant_t vDropRows = pElement->getAttribute( "droplines" ), vSelected = pElement->getAttribute( "selected" ); if( vDropRows.vt != VT_NULL ) { try { m_nDropLines = static_cast< long >( vDropRows ); _ASSERTE( m_nDropLines > 0 ); } catch( ... ) { // Type conversion error _ASSERTE( FALSE ); } } if( vSelected.vt != VT_NULL ) { try { m_nSelected = static_cast< long >( vSelected ); _ASSERTE( m_nSelected >= 0 ); } catch( ... ) { // Type conversion error _ASSERTE( FALSE ); } } return S_OK; } STDMETHODIMP cChoice::AddChoice(BSTR strDisplay, VARIANT vData) { cOption o; o.m_strText = strDisplay; o.m_value = vData; m_options.push_back( o ); m_pSite->Reformat(); return S_OK; } STDMETHODIMP cChoice::get_ChoiceCount(long *pVal) { _ASSERTE( pVal != NULL ); *pVal = m_options.size(); return S_OK; } STDMETHODIMP cChoice::get_Data(long nIndex, VARIANT *pVal) { if( pVal == NULL ) return E_POINTER; if( nIndex < 0 || nIndex > m_options.size() ) { pVal->lVal = -1; pVal->vt = VT_I4; } else ::VariantCopy( pVal, &m_options[ nIndex ].m_value ); return S_OK; } STDMETHODIMP cChoice::put_Data(long nIndex, VARIANT newVal) { _ASSERTE( nIndex >= 0 ); _ASSERTE( nIndex < m_options.size() ); ::VariantCopy( &m_options[ nIndex ].m_value, &newVal ); return S_OK; } STDMETHODIMP cChoice::get_Text(long nIndex, BSTR *pVal) { USES_CONVERSION; _ASSERTE( nIndex >= 0 ); _ASSERTE( nIndex < m_options.size() ); _ASSERTE( pVal != NULL ); *pVal = OLE2BSTR( m_options[ nIndex ].m_strText ); return S_OK; } STDMETHODIMP cChoice::put_Text(long nIndex, BSTR newVal) { _ASSERTE( nIndex >= 0 ); _ASSERTE( nIndex < m_options.size() ); _ASSERTE( newVal != NULL ); m_options[ nIndex ].m_strText = newVal; m_pPopup->Invalidate(); return S_OK; } STDMETHODIMP cChoice::RemoveChoice(long nIndex) { _ASSERTE( nIndex >= 0 ); _ASSERTE( nIndex < m_options.size() ); m_options.erase( m_options.begin() + nIndex ); if( m_nSelected >= m_options.size() ) m_nSelected = m_options.size() - 1; long nID; m_pSite->get_ID( &nID ); Fire_Change( nID, m_nSelected ); // Redraw the concerned m_pSite->Reformat(); m_pPopup->Invalidate(); return S_OK; } STDMETHODIMP cChoice::get_Dropped(VARIANT_BOOL *pVal) { _ASSERTE( pVal != NULL ); *pVal = ( m_bPopup ) ? VARIANT_TRUE : VARIANT_FALSE; return S_OK; } STDMETHODIMP cChoice::put_Dropped(VARIANT_BOOL newVal) { if( !!newVal != m_bPopup ) setPopup( !!newVal ); return S_OK; } STDMETHODIMP cChoice::get_Selected(long *pVal) { _ASSERTE( pVal != NULL ); *pVal = m_nSelected; return S_OK; } STDMETHODIMP cChoice::put_Selected(long newVal) { _ASSERTE( newVal >= -1 ); //_ASSERTE( newVal < m_options.size() ); //back out if out of bounds, don't error to prevent breaking vb plugs //this should fix the crash on display bug if (newVal >= m_options.size()) return S_OK; if( newVal == m_nSelected ) return S_OK; m_nSelected = newVal; long nID; m_pSite->get_ID( &nID ); Fire_Change( nID, m_nSelected ); // Redraw the concerned m_pSite->Invalidate(); m_pPopup->Invalidate(); return S_OK; } STDMETHODIMP cChoice::get_DropLines(long *pVal) { _ASSERTE( pVal != NULL ); *pVal = m_nDropLines; return S_OK; } STDMETHODIMP cChoice::put_DropLines(long newVal) { _ASSERTE( newVal > 0 ); m_nDropLines = newVal; m_pSite->Reformat(); return S_OK; } STDMETHODIMP cChoice::Clear() { m_options.clear(); m_nSelected = -1; long nID; m_pSite->get_ID( &nID ); Fire_Change( nID, m_nSelected ); m_pSite->Reformat(); return S_OK; }