Code/Resource
Windows Develop
Linux-Unix program
Internet-Socket-Network
Web Server
Browser Client
Ftp Server
Ftp Client
Browser Plugins
Proxy Server
Email Server
Email Client
WEB Mail
Firewall-Security
Telnet Server
Telnet Client
ICQ-IM-Chat
Search Engine
Sniffer Package capture
Remote Control
xml-soap-webservice
P2P
WEB(ASP,PHP,...)
TCP/IP Stack
SNMP
Grid Computing
SilverLight
DNS
Cluster Service
Network Security
Communication-Mobile
Game Program
Editor
Multimedia program
Graph program
Compiler program
Compress-Decompress algrithms
Crypt_Decrypt algrithms
Mathimatics-Numerical algorithms
MultiLanguage
Disk/Storage
Java Develop
assembly language
Applications
Other systems
Database system
Embeded-SCM Develop
FlashMX/Flex
source in ebook
Delphi VCL
OS Develop
MiddleWare
MPI
MacOS develop
LabView
ELanguage
Software/Tools
E-Books
Artical/Document
linkwnd.cpp
Package: shell.rar [view]
Upload User: xhy777
Upload Date: 2007-02-14
Package Size: 24088k
Code Size: 95k
Category:
Windows Kernel
Development Platform:
Visual C++
- //-------------------------------------------------------------------------//
- // linkwnd.cpp - implementation of CLinkWindow
- //
- // [scotthan] - created 10/7/98
- #include "shellprv.h"
- #include "ids.h"
- #include <oleacc.h>
- //-------------------------------------------------------------------------//
- #define IS_LINK(pBlock) ((pBlock) && (pBlock)->iLink != INVALID_LINK_INDEX)
- #ifndef ARRAYSIZE
- #define ARRAYSIZE(a) (sizeof(a)/sizeof(*a))
- #endif
- #ifndef POINTSPERRECT
- #define POINTSPERRECT (sizeof(RECT)/sizeof(POINT))
- #endif
- #ifndef RECTWIDTH
- #define RECTWIDTH(prc) ((prc)->right - (prc)->left)
- #endif
- #ifndef RECTHEIGHT
- #define RECTHEIGHT(prc) ((prc)->bottom - (prc)->top)
- #endif
- #define TESTKEYSTATE(vk) ((GetKeyState(vk) & 0x8000)!=0)
- #define LINKCOLOR_BKGND COLOR_WINDOW
- #define LINKCOLOR_ENABLED GetSysColor( GetCOLOR_HOTLIGHT() )
- #define LINKCOLOR_DISABLED GetSysColor( COLOR_GRAYTEXT )
- #define CF_SETCAPTURE 0x0001
- #define CF_SETFOCUS 0x0002
- // KEYBOARDCUES helpes
- #ifdef KEYBOARDCUES
- void _InitializeUISTATE( IN HWND hwnd, IN OUT UINT* puFlags );
- BOOL _HandleWM_UPDATEUISTATE( IN WPARAM wParam, IN LPARAM lParam, IN OUT UINT* puFlags );
- #endif
- //-------------------------------------------------------------------------//
- // class CAccessibleBase
- //
- // common IAccessible implementation.
- //
- class CAccessibleBase : public IAccessible, public IOleWindow
- //-------------------------------------------------------------------------//
- {
- public:
- CAccessibleBase( const HWND& hwnd )
- : _cRef(1), _ptiAcc(NULL), _hwnd(hwnd)
- {
- DllAddRef();
- }
- virtual ~CAccessibleBase()
- {
- ATOMICRELEASE(_ptiAcc);
- }
- // IUnknown
- STDMETHODIMP QueryInterface( REFIID riid, void** ppvObj );
- STDMETHODIMP_(ULONG) AddRef();
- STDMETHODIMP_(ULONG) Release();
- // IOleWindow
- STDMETHODIMP GetWindow( HWND* phwnd );
- STDMETHODIMP ContextSensitiveHelp( BOOL fEnterMode ) { return E_NOTIMPL; }
- // IDispatch
- STDMETHODIMP GetTypeInfoCount( UINT * pctinfo );
- STDMETHODIMP GetTypeInfo( UINT itinfo, LCID lcid, ITypeInfo** pptinfo );
- STDMETHODIMP GetIDsOfNames( REFIID riid, OLECHAR** rgszNames, UINT cNames,
- LCID lcid, DISPID * rgdispid );
- STDMETHODIMP Invoke( DISPID dispidMember, REFIID riid, LCID lcid, WORD wFlags,
- DISPPARAMS * pdispparams, VARIANT * pvarResult,
- EXCEPINFO * pexcepinfo, UINT * puArgErr );
- // IAccessible
- STDMETHODIMP get_accParent( IDispatch ** ppdispParent);
- STDMETHODIMP get_accChildCount( long * pcChildren );
- STDMETHODIMP get_accChild( VARIANT varChildIndex, IDispatch ** ppdispChild);
- STDMETHODIMP get_accValue( VARIANT varChild, BSTR* pbstrValue);
- STDMETHODIMP get_accDescription( VARIANT varChild, BSTR * pbstrDescription);
- STDMETHODIMP get_accRole( VARIANT varChild, VARIANT *pvarRole );
- STDMETHODIMP get_accState( VARIANT varChild, VARIANT *pvarState );
- STDMETHODIMP get_accHelp( VARIANT varChild, BSTR* pbstrHelp );
- STDMETHODIMP get_accHelpTopic( BSTR* pbstrHelpFile, VARIANT varChild, long* pidTopic );
- STDMETHODIMP get_accKeyboardShortcut( VARIANT varChild, BSTR* pbstrKeyboardShortcut );
- STDMETHODIMP get_accFocus( VARIANT FAR * pvarFocusChild );
- STDMETHODIMP get_accSelection( VARIANT FAR * pvarSelectedChildren );
- STDMETHODIMP get_accDefaultAction( VARIANT varChild, BSTR* pbstrDefaultAction );
- STDMETHODIMP accSelect( long flagsSelect, VARIANT varChild );
- STDMETHODIMP accLocation( long* pxLeft, long* pyTop, long* pcxWidth, long* pcyHeight, VARIANT varChild );
- STDMETHODIMP accNavigate( long navDir, VARIANT varStart, VARIANT * pvarEndUpAt );
- STDMETHODIMP accHitTest( long xLeft, long yTop, VARIANT * pvarChildAtPoint );
- STDMETHODIMP put_accName( VARIANT varChild, BSTR bstrName );
- STDMETHODIMP put_accValue( VARIANT varChild, BSTR bstrValue );
- protected:
- virtual UINT GetDefaultActionStringID() const = 0;
- private:
- ULONG _cRef;
- ITypeInfo* _ptiAcc;
- const HWND& _hwnd;
- // Thunked OLEACC defs from winuser.h
- #ifndef OBJID_WINDOW
- #define OBJID_WINDOW 0x00000000
- #endif//OBJID_WINDOW
- #ifndef OBJID_TITLEBAR
- #define OBJID_TITLEBAR 0xFFFFFFFE
- #endif//OBJID_TITLEBAR
- #ifndef OBJID_CLIENT
- #define OBJID_CLIENT 0xFFFFFFFC
- #endif//OBJID_CLIENT
- #ifndef CHILDID_SELF
- #define CHILDID_SELF 0
- #endif//CHILDID_SELF
- #define VALIDATEACCCHILD( varChild, idChild, hrFail )
- if( !(VT_I4 == varChild.vt && idChild == varChild.lVal) ) {return hrFail;}
- } ;
- //-------------------------------------------------------------------------//
- #define TEST_CAPTURE(fTest) ((_fCapture & fTest) != 0)
- #define MODIFY_CAPTURE(fSet, fRemove) {if(fSet){_fCapture |= fSet;} if(fRemove){_fCapture &= ~fRemove;}}
- #define RESET_CAPTURE() {_fCapture=0;}
- //-------------------------------------------------------------------------//
- // class CLinkWindow
- class CLinkWindow : public CAccessibleBase
- //-------------------------------------------------------------------------//
- {
- public:
- CLinkWindow();
- virtual ~CLinkWindow();
- // IAccessible specialization
- STDMETHODIMP get_accName( VARIANT varChild, BSTR* pbstrName);
- STDMETHODIMP accDoDefaultAction( VARIANT varChild );
- private:
- // CAccessibleBase overrides
- UINT GetDefaultActionStringID() const { return IDS_LINKWINDOW_DEFAULTACTION; }
- // Private types
- struct RECTLISTENTRY // rect list member
- {
- RECT rc;
- RECTLISTENTRY* next;
- };
- struct TEXTBLOCK // text segment data
- {
- int iLink; // index of link (INVALID_LINK_INDEX if static text)
- DWORD state; // state bits
- TCHAR szID[MAX_LINKID_TEXT]; // link identifier.
- TEXTBLOCK* next; // next block
- RECTLISTENTRY* rgrle; // list of bounding rectangle(s)
- TCHAR* pszText; // text
- TCHAR* pszUrl; // URL.
- TEXTBLOCK();
- ~TEXTBLOCK();
- void AddRect( const RECT& rc );
- void FreeRects();
- };
- // Utility methods
- BOOL CreateFonts( BOOL bRecreate = FALSE );
- void DestroyFonts();
- HCURSOR GetLinkCursor();
- void Parse( LPCTSTR pszText = NULL );
- BOOL Add( TEXTBLOCK* pAdd );
- TEXTBLOCK* FindLink( int iLink ) const;
- void FreeBlocks();
- void SetText( LPCTSTR pszText );
- int GetText( BOOL bForParsing, LPTSTR pszText, int cchText ) const;
- int GetTextW( BOOL bForParsing, LPWSTR pwszText, int cchText ) const;
- int GetTextLength( BOOL bForParsing ) const;
- void Paint( HDC hdc, IN OPTIONAL LPCRECT prcClient = NULL, LPCRECT prcClip = NULL );
- int CalcIdealHeight( int cx );
- int HitTest( const POINT& pt ) const;
- BOOL WantTab( BOOL* biFocus = NULL ) const;
- void AssignTabFocus( int nDirection );
- int GetNextEnabledLink( int iStart, int nDir ) const;
- int StateCount( DWORD dwStateMask, DWORD dwState ) const;
- LONG EnableNotifications( BOOL bEnable );
- static TEXTBLOCK* CreateBlock( LPCTSTR pszStart, LPCTSTR pszEnd, int iLink );
- // Message handlers
- static LRESULT WINAPI WndProc( HWND, UINT, WPARAM, LPARAM );
- void OnButtonDown( WPARAM fwKeys, const POINT& pt );
- void OnButtonUp( WPARAM fwKeys, const POINT& pt );
- void OnCaptureLost( HWND hwndNew ) {RESET_CAPTURE();}
- LRESULT OnFocus( HWND hwndPrev );
- void OnKeyDown( UINT virtKey );
- LRESULT SendNotify( UINT nCode, int iLink, LPCTSTR pszLinkID = NULL ) const;
- LRESULT GetItem( OUT LWITEM* pItem );
- LRESULT SetItem( IN LWITEM* pItem );
- // Data
- TEXTBLOCK* _rgBlocks; // linked list of text blocks
- int _cBlocks; // block count
- int _cLinks; // link count
- int _iFocus; // index of focus link
- int _cyIdeal;
- LPTSTR _pszCaption;
- HWND _hwnd;
- HFONT _hfStatic,
- _hfLink;
- UINT _fCapture;
- UINT _fKeyboardCues;
- POINT _ptCapture;
- HCURSOR _hcurHand;
- LONG _cNotifyLocks;
- friend BOOL LinkWindow_RegisterClass();
- };
- //-------------------------------------------------------------------------//
- LPTSTR _AllocAndCopy( LPTSTR& pszDest, LPCTSTR pszSrc )
- {
- if( pszDest )
- {
- delete [] pszDest;
- pszDest = NULL;
- }
- if( pszSrc && (pszDest = new TCHAR[lstrlen(pszSrc)+1]) != NULL )
- lstrcpy( pszDest, pszSrc );
- return pszDest;
- }
- BOOL _AssignBit( const DWORD dwBit, DWORD& dwDest, const DWORD dwSrc ) // returns TRUE if changed
- {
- if( ((dwSrc & dwBit) != 0) != ((dwDest & dwBit) != 0) )
- {
- if( ((dwSrc & dwBit) != 0) )
- dwDest |= dwBit;
- else
- dwDest &= ~dwBit;
- return TRUE;
- }
- return FALSE;
- }
- //-------------------------------------------------------------------------//
- BOOL WINAPI LinkWindow_RegisterClass()
- {
- WNDCLASSEX wc;
- ZeroMemory( &wc, sizeof(wc) );
- wc.cbSize = sizeof(wc);
- wc.style = CS_GLOBALCLASS;
- wc.lpfnWndProc = CLinkWindow::WndProc;
- wc.hInstance = HINST_THISDLL;
- wc.hIcon = NULL;
- wc.hCursor = LoadCursor( NULL, IDC_ARROW );
- wc.hbrBackground = (HBRUSH)(LINKCOLOR_BKGND+1);
- wc.lpszClassName = LINKWINDOW_CLASS;
- return ::RegisterClassEx( &wc ) != 0 ||
- GetLastError() == ERROR_CLASS_ALREADY_EXISTS;
- }
- //-------------------------------------------------------------------------//
- BOOL WINAPI LinkWindow_UnregisterClass( HINSTANCE hInst )
- {
- return ::UnregisterClass( LINKWINDOW_CLASS, hInst );
- }
- //-------------------------------------------------------------------------//
- CLinkWindow::CLinkWindow()
- : CAccessibleBase( _hwnd ),
- _rgBlocks(NULL),
- _cBlocks(0),
- _cLinks(0),
- _cyIdeal(0),
- _hwnd(NULL),
- _hfStatic(NULL),
- _hfLink(NULL),
- _iFocus(INVALID_LINK_INDEX),
- _fCapture(0),
- _pszCaption(NULL),
- _fKeyboardCues(0),
- _hcurHand(NULL),
- _cNotifyLocks(0)
- {
- _ptCapture.x = _ptCapture.y = 0;
- }
- //-------------------------------------------------------------------------//
- CLinkWindow::~CLinkWindow()
- {
- FreeBlocks();
- DestroyFonts();
- SetText( NULL );
- }
- //-------------------------------------------------------------------------//
- // CLinkWindow IAccessible impl
- //
- // Note: Currently, this IAccessible implementation does not supports only
- // single links; multiple links are not supported. All child delegation
- // is to/from self. This allows us to blow off the IEnumVARIANT and IDispatch
- // implementations.
- //
- // To shore this up the implementation, we need to implement each link
- // as a child IAccessible object and delegate accordingly.
- //
- STDMETHODIMP CLinkWindow::get_accName( VARIANT varChild, BSTR* pbstrName)
- {
- VALIDATEACCCHILD( varChild, CHILDID_SELF, E_INVALIDARG );
- if( NULL == pbstrName )
- return E_POINTER;
- *pbstrName = 0;
- int cch = GetTextLength( FALSE );
- if( (*pbstrName = SysAllocStringLen(NULL, cch + 1)) != NULL )
- {
- GetTextW( FALSE, *pbstrName, cch + 1 );
- return S_OK;
- }
- return E_OUTOFMEMORY;
- }
- STDMETHODIMP CLinkWindow::accDoDefaultAction( VARIANT varChild )
- {
- VALIDATEACCCHILD( varChild, CHILDID_SELF, E_INVALIDARG );
- SendNotify( NM_RETURN, _iFocus );
- return S_OK;
- }
- //-------------------------------------------------------------------------//
- // CLinkWindow window implementation
- //-------------------------------------------------------------------------//
- //-------------------------------------------------------------------------//
- void CLinkWindow::FreeBlocks()
- {
- for( TEXTBLOCK* pBlock = _rgBlocks; pBlock; )
- {
- TEXTBLOCK* pNext = pBlock->next;
- delete pBlock;
- pBlock = pNext;
- }
- _rgBlocks = NULL;
- _cBlocks = _cLinks = 0;
- }
- //-------------------------------------------------------------------------//
- CLinkWindow::TEXTBLOCK* CLinkWindow::CreateBlock( LPCTSTR pszStart, LPCTSTR pszEnd, int iLink )
- {
- TEXTBLOCK* pBlock = NULL;
- int cch = (int)(pszEnd - pszStart) + 1;
- if( cch > 0 )
- {
- if( (pBlock = new TEXTBLOCK) != NULL )
- {
- if( (pBlock->pszText = new TCHAR[cch]) == NULL )
- {
- delete pBlock;
- pBlock = NULL;
- }
- else
- {
- lstrcpyn( pBlock->pszText, pszStart, cch );
- pBlock->iLink = iLink;
- }
- }
- }
- return pBlock;
- }
- //-------------------------------------------------------------------------//
- BOOL CLinkWindow::CreateFonts( BOOL bRecreate )
- {
- if( _hfStatic && _hfLink && !bRecreate )
- return TRUE;
- BOOL bRet = FALSE;
- HFONT hfStatic = NULL;
- for( HWND hwnd = _hwnd; NULL == hfStatic && hwnd != NULL; hwnd = GetParent(hwnd) )
- hfStatic = (HFONT)::SendMessage( hwnd, WM_GETFONT, 0, 0L );
- if( hfStatic )
- {
- DestroyFonts();
- LOGFONT lf;
- if( GetObject( hfStatic, sizeof(lf), &lf ) )
- {
- // static text has no underline
- lf.lfUnderline = FALSE;
- _hfStatic = CreateFontIndirect( &lf );
- // link text has underline
- lf.lfUnderline = TRUE;
- _hfLink = CreateFontIndirect( &lf );
- bRet = _hfLink != NULL && _hfStatic != NULL;
- }
- }
- return bRet;
- }
- //-------------------------------------------------------------------------//
- HCURSOR CLinkWindow::GetLinkCursor()
- {
- if( !_hcurHand )
- _hcurHand = LoadHandCursor(0);
- return _hcurHand;
- }
- //-------------------------------------------------------------------------//
- void CLinkWindow::DestroyFonts()
- {
- if( _hfStatic )
- {
- DeleteObject( _hfStatic );
- _hfStatic = NULL;
- }
- if( _hfLink )
- {
- DeleteObject( _hfLink );
- _hfLink = NULL;
- }
- }
- //-------------------------------------------------------------------------//
- void CLinkWindow::Parse( LPCTSTR pszText )
- {
- TEXTBLOCK* pBlock;
- int cBlocks = 0, cLinks = 0;
- LPCTSTR psz1, psz2, pszBlock;
- LPTSTR pszBuf = NULL;
- FreeBlocks(); // free existing blocks
- if( !pszText )
- {
- int cch = GetWindowTextLength( _hwnd )+1;
- if( cch <= 0 ||
- (pszBuf = new TCHAR[cch+1]) == NULL )
- goto exit;
- GetWindowText( _hwnd, pszBuf, cch );
- }
- else
- pszBuf = (LPTSTR)pszText;
- if( !(pszBuf && *pszBuf) )
- goto exit;
- #define LINKTAG1L TEXT("<a>")
- #define LINKTAG1U TEXT("<A>")
- #define cchLINKTAG1 3
- #define LINKTAG2L TEXT("</a>")
- #define LINKTAG2U TEXT("</A>")
- #define cchLINKTAG2 4
- for( pszBlock = pszBuf; pszBlock && *pszBlock; )
- {
- // Search for "<a>" tag
- if( ((psz1 = StrStrI( pszBlock, LINKTAG1L )) != NULL ||
- (psz1 = StrStrI( pszBlock, LINKTAG1U )) != NULL) )
- {
- // Add run between psz1 and pszBlock as static text
- if( psz1 > pszBlock )
- {
- if( (pBlock = CreateBlock( pszBlock, psz1, INVALID_LINK_INDEX )) != NULL )
- {
- Add( pBlock );
- cBlocks++;
- }
- }
- // safe-skip over tag
- for( int i = 0; i < cchLINKTAG1 && psz1 && *psz1;
- i++, psz1 = CharNext(psz1) );
- pszBlock = psz1;
- if( psz1 && *psz1 )
- {
- if( (psz2 = StrStrI( pszBlock, LINKTAG2L )) != NULL ||
- (psz2 = StrStrI( pszBlock, LINKTAG2U )) != NULL )
- {
- if( (pBlock = CreateBlock( psz1, psz2, cLinks )) != NULL )
- {
- Add( pBlock );
- cBlocks++;
- cLinks++;
- }
- // safe-skip over tag
- for( int i = 0;
- i < cchLINKTAG2 && psz2 && *psz2;
- i++, psz2 = CharNext(psz2) );
- pszBlock = psz2;
- }
- else // syntax error; mark trailing run is static text.
- {
- psz2 = pszBlock + lstrlen( pszBlock );
- if( (pBlock = CreateBlock( psz1, psz2, INVALID_LINK_INDEX )) != NULL )
- {
- Add( pBlock );
- cBlocks++;
- }
- pszBlock = psz2;
- }
- }
- }
- else // no more tags. Mark the last run of static text
- {
- psz2 = pszBlock + lstrlen( pszBlock );
- if( (pBlock = CreateBlock( pszBlock, psz2, INVALID_LINK_INDEX )) != NULL )
- {
- Add( pBlock );
- cBlocks++;
- }
- pszBlock = psz2;
- }
- }
- ASSERT( cBlocks == _cBlocks );
- ASSERT( cLinks == _cLinks );
- exit:
- if( !pszText && pszBuf ) // delete text buffer if we had alloc'd it.
- delete [] pszBuf;
- }
- //-------------------------------------------------------------------------//
- BOOL CLinkWindow::Add( TEXTBLOCK* pAdd )
- {
- BOOL bAdded = FALSE;
- pAdd->next = NULL;
- if( !_rgBlocks ) {
- _rgBlocks = pAdd;
- bAdded = TRUE;
- }
- else {
- for( TEXTBLOCK* pBlock = _rgBlocks; pBlock && !bAdded; pBlock = pBlock->next ) {
- if( !pBlock->next ) {
- pBlock->next = pAdd;
- bAdded = TRUE;
- }
- }
- }
- if( bAdded ) {
- _cBlocks++;
- if( IS_LINK( pAdd ) )
- _cLinks++;
- }
- return bAdded;
- }
- //-------------------------------------------------------------------------//
- CLinkWindow::TEXTBLOCK* CLinkWindow::FindLink( int iLink ) const
- {
- if( iLink == INVALID_LINK_INDEX )
- return NULL;
- for( TEXTBLOCK* pBlock = _rgBlocks; pBlock; pBlock = pBlock->next )
- {
- if( IS_LINK( pBlock ) && pBlock->iLink == iLink )
- return pBlock;
- }
- return NULL;
- }
- //-------------------------------------------------------------------------//
- int _IsLineBreakChar( LPCTSTR psz, int ich, TCHAR chBreak, OUT BOOL* pbRemove )
- {
- LPTSTR pch;
- *pbRemove = FALSE;
- ASSERT( psz != NULL )
- ASSERT( psz[ich] != 0 );
- // Try caller-provided break character (assumed a 'remove' break char).
- if( psz[ich] == chBreak )
- {
- *pbRemove = TRUE;
- return ich;
- }
- #define MAX_LINEBREAK_RESOURCE 128
- static TCHAR _szBreakRemove [MAX_LINEBREAK_RESOURCE] = {0};
- static TCHAR _szBreakPreserve [MAX_LINEBREAK_RESOURCE] = {0};
- #define LOAD_BREAKCHAR_RESOURCE( nIDS, buff )
- if(0==*buff) { LoadString(HINST_THISDLL, nIDS, buff, ARRAYSIZE(buff)); }
- // Try 'remove' break chars
- LOAD_BREAKCHAR_RESOURCE( IDS_LINEBREAK_REMOVE, _szBreakRemove );
- for( pch = _szBreakRemove; *pch; pch = CharNext(pch) )
- {
- if( psz[ich] == *pch )
- {
- *pbRemove = TRUE;
- return ich;
- }
- }
- // Try 'preserve prior' break chars:
- LOAD_BREAKCHAR_RESOURCE( IDS_LINEBREAK_PRESERVE, _szBreakPreserve );
- for( pch = _szBreakPreserve; *pch; pch = CharNext(pch) )
- {
- if( psz[ich] == *pch )
- return ++ich;
- }
- return -1;
- }
- //-------------------------------------------------------------------------//
- BOOL _FindLastBreakChar(
- IN LPCTSTR pszText,
- IN int cchText,
- IN TCHAR chBreak, // official break char (from TEXTMETRIC).
- OUT int* piLast,
- OUT BOOL* pbRemove )
- {
- *piLast = 0;
- *pbRemove = FALSE;
- for( int i = cchText-1; i >= 0; i-- )
- {
- #ifndef UNICODE
- if( IsDBCSLeadByte( pszText[i] ) )
- continue;
- #endif
- int ich = _IsLineBreakChar( pszText, i, chBreak, pbRemove );
- if( ich >= 0 )
- {
- *piLast = ich;
- return TRUE;
- }
- }
- return FALSE;
- }
- //-------------------------------------------------------------------------//
- int CLinkWindow::CalcIdealHeight( int cx )
- {
- int cyRet = -1;
- HDC hdc;
- RECT rc;
- SIZE sizeDC;
- if( NULL == _rgBlocks || 0 == _cBlocks )
- return -1;
- GetClientRect( _hwnd, &rc );
- if( cx <= 0 )
- cx = RECTWIDTH( &rc );
- else
- rc.right = cx;
- if( cx <= 0 )
- return -1;
- // Come up with a conservative estimate for the new height.
- sizeDC.cy = MulDiv( RECTHEIGHT( &rc ), cx, RECTWIDTH( &rc ) ) * 2;
- sizeDC.cx = cx;
- if( (hdc = GetDC( _hwnd )) != NULL )
- {
- // prepare memory DC
- HDC hdcMem;
- if( (hdcMem = CreateCompatibleDC( hdc )) )
- {
- // [scotthan]: BUGBUG - Probably don't need anything but a monochrome DC
- // but should test before removing the code.
- HBITMAP hbm = CreateCompatibleBitmap( hdc, sizeDC.cx, sizeDC.cy );
- HBITMAP hbmPrev = (HBITMAP)SelectObject( hdcMem, hbm );
- int cyPrev = _cyIdeal; // push ideal
- // paint into memory DC to determine height
- SetRect( &rc, 0, 0, sizeDC.cx, sizeDC.cy );
- Paint( hdcMem, &rc );
- cyRet = _cyIdeal;
- _cyIdeal = cyPrev; // pop ideal
- SelectObject( hdcMem, hbmPrev );
- DeleteObject( hbm );
- DeleteDC( hdcMem );
- }
- ReleaseDC( _hwnd, hdc );
- }
- return cyRet;
- }
- //-------------------------------------------------------------------------//
- void CLinkWindow::Paint( HDC hdcClient, LPCRECT prcClient, LPCRECT prcClip )
- {
- RECT rcClient;
- if( !prcClient )
- {
- GetClientRect( _hwnd, &rcClient );
- prcClient = &rcClient;
- }
- if( RECTWIDTH( prcClient )<=0 ||RECTHEIGHT( prcClient )<=0 )
- return;
- HDC hdc = hdcClient ? hdcClient : GetDC( _hwnd );
- TEXTBLOCK* pBlock;
- TEXTMETRIC tm;
- int iLine = 0, // current line index
- cyLine = 0, // line height.
- cyLeading = 0; // internal leading
- COLORREF rgbOld = GetTextColor( hdc ); // save text color
- RECT rcFill,
- rcDraw = *prcClient; // initialize line rect
- const ULONG dwFlags = DT_TOP|DT_LEFT;
- BOOL fFocus = GetFocus()==_hwnd;
- // initialize background
- SendMessage( GetParent( _hwnd ), WM_CTLCOLORSTATIC,
- (WPARAM)hdc, (LPARAM)_hwnd );
- SetBkMode( hdc, OPAQUE );
- _cyIdeal = 0;
- // For each block of text...
- for( pBlock = _rgBlocks; pBlock; pBlock = pBlock->next )
- {
- BOOL bLink = IS_LINK(pBlock);
- SelectObject( hdc, bLink ? _hfLink : _hfStatic );
- int cchDraw = lstrlen( pBlock->pszText ), // chars to draw, this block
- cchDrawn = 0; // chars to draw, this block
- LPTSTR pszText = &pBlock->pszText[cchDrawn];
- pBlock->FreeRects(); // free hit/focus rects; we're going to recompute.
- // Get font metrics
- GetTextMetrics( hdc, &tm );
- if( tm.tmExternalLeading > cyLeading )
- cyLeading = tm.tmExternalLeading;
- // initialize foreground color
- if( bLink )
- {
- BOOL bEnabled = pBlock->state & LWIS_ENABLED;
- SetTextColor( hdc, bEnabled ? LINKCOLOR_ENABLED : LINKCOLOR_DISABLED );
- }
- else
- SetTextColor( hdc, GetSysColor( COLOR_WINDOWTEXT ) );
- // while text remains...
- while( cchDraw > 0 )
- {
- // compute line height and maximum text width to rcBlock
- RECT rcBlock;
- BOOL bShy = FALSE;
- int cchTry = cchDraw;
- int cchFit = 0;
- SIZE sizeFit;
- BOOL bRemoveBreak = FALSE;
- for(;;)
- {
- if( !GetTextExtentExPoint( hdc, pszText, cchTry, RECTWIDTH(&rcDraw),
- &cchFit, NULL, &sizeFit ) )
- {
- cchTry--;
- continue;
- }
- else if( cchFit < cchTry )
- {
- BOOL fBreak = _FindLastBreakChar( pszText, cchFit, tm.tmBreakChar, &cchTry, &bRemoveBreak );
- if( 0 == cchTry )
- {
- if( !fBreak && (0 == rcDraw.left /* nothing drawn on this line*/) )
- cchTry = cchFit; // no break character found, so force a break.
- }
- else
- {
- GetTextExtentExPoint( hdc, pszText, cchTry, RECTWIDTH(&rcDraw),
- &cchFit, NULL, &sizeFit );
- }
- break;
- }
- else
- break;
- }
- cyLine = sizeFit.cy;
- SetRect( &rcBlock, 0, 0, sizeFit.cx, sizeFit.cy );
- OffsetRect( &rcBlock, rcDraw.left - rcBlock.left, 0 );
- // initialize drawing rectangle
- rcDraw.right = min( rcDraw.left + RECTWIDTH(&rcBlock), prcClient->right );
- rcDraw.bottom = rcDraw.top + cyLine;
- // draw the text
- ExtTextOut( hdc, rcDraw.left, rcDraw.top, ETO_OPAQUE|ETO_CLIPPED,
- &rcDraw, pszText, cchTry, NULL );
- // Add rectangle to block's list
- if( bLink && cchTry )
- pBlock->AddRect( rcDraw );
- cchDrawn = cchTry;
- if( cchTry < cchDraw ) // we got clipped
- {
- // fill line to right boundary
- SetRect( &rcFill, rcDraw.right, rcDraw.top, prcClient->right, rcDraw.bottom );
- ExtTextOut( hdc, rcFill.left, rcFill.top, ETO_OPAQUE,
- &rcFill, NULL, 0, NULL );
- // adjust text
- if( bRemoveBreak )
- cchDrawn++;
- pszText += cchDrawn;
- // advance to next line
- iLine++;
- rcDraw.left = 0;
- rcDraw.top = iLine * cyLine;
- rcDraw.bottom = rcDraw.top + cyLine + cyLeading;
- rcDraw.right = prcClient->right;
- }
- else // we were able to draw the entire text
- {
- // adjust drawing rectangle
- rcDraw.left += RECTWIDTH(&rcBlock);
- rcDraw.right = prcClient->right;
- // if this is the last block of text, fill line to right boundary
- if( pBlock->next == NULL )
- {
- rcFill = rcDraw;
- rcFill.right = prcClient->right;
- ExtTextOut( hdc, rcFill.left, rcFill.top, ETO_OPAQUE,
- &rcFill, NULL, 0, NULL );
- }
- }
- _cyIdeal = rcDraw.bottom;
- cchDraw -= cchDrawn;
- }
- // Draw focus rect(s)
- #ifdef KEYBOARDCUES
- if( 0 == (_fKeyboardCues & UISF_HIDEFOCUS) )
- #endif
- {
- if( fFocus && pBlock->iLink == _iFocus )
- {
- HBRUSH hbr, hbrOld;
- COLORREF rgbBkgnd = GetBkColor( hdc );
- if( (hbr = CreateSolidBrush( rgbBkgnd )) )
- {
- hbrOld = (HBRUSH)SelectObject( hdc, hbr );
- for( RECTLISTENTRY* prce = pBlock->rgrle; prce && hbr; prce = prce->next )
- {
- RECT rc = prce->rc;
- FrameRect( hdc, &rc, hbr );
- SetTextColor( hdc, rgbOld );
- DrawFocusRect( hdc, &rc );
- }
- SelectObject( hdc, hbrOld );
- DeleteObject( hbr );
- }
- }
- }
- }
- // Fill remainder of client rect.
- RECT rcX;
- rcFill = *prcClient;
- rcFill.top = rcDraw.top + cyLine;
- if( prcClip == NULL )
- {
- ExtTextOut( hdc, rcFill.left, rcFill.right, ETO_OPAQUE,
- &rcFill, NULL, 0, NULL );
- }
- else if( IntersectRect( &rcX, prcClip, &rcFill ) )
- {
- ExtTextOut( hdc, rcX.left, rcX.right, ETO_OPAQUE,
- &rcX, NULL, 0, NULL );
- }
- SetTextColor( hdc, rgbOld ); // restore text color
- if( NULL == hdcClient && hdc ) // release DC if we acquired it.
- ReleaseDC( _hwnd, hdc );
- }
- //-------------------------------------------------------------------------//
- int CLinkWindow::HitTest( const POINT& pt ) const
- {
- // Walk blocks until we find a link rect that contains the point
- TEXTBLOCK* pBlock;
- for( pBlock = _rgBlocks; pBlock; pBlock = pBlock->next )
- {
- if( IS_LINK(pBlock) && (pBlock->state & LWIS_ENABLED)!=0 )
- {
- RECTLISTENTRY* prce;
- for( prce = pBlock->rgrle; prce; prce = prce->next )
- {
- if( PtInRect( &prce->rc, pt ) )
- {
- return pBlock->iLink;
- }
- }
- }
- }
- return INVALID_LINK_INDEX;
- }
- //-------------------------------------------------------------------------//
- LRESULT CLinkWindow::SetItem( IN LWITEM* pItem )
- {
- TEXTBLOCK* pBlock;
- BOOL bRedraw = FALSE;
- LRESULT lRet = 0L;
- if( NULL == pItem || 0 == (pItem->mask & LWIF_ITEMINDEX) )
- return lRet; //BUGBUG: need to open up search keys to LWIF_ITEMID and LWIF_URL.
- if( (pBlock = FindLink( pItem->iLink )) != NULL )
- {
- if( pItem->mask & LWIF_STATE )
- {
- if( pItem->stateMask & LWIS_ENABLED )
- {
- bRedraw |= _AssignBit( LWIS_ENABLED, pBlock->state, pItem->state );
- BOOL bEnabled = IsWindowEnabled( _hwnd );
- int cEnabledLinks = StateCount( LWIS_ENABLED, LWIS_ENABLED );
- if( bEnabled )
- {
- if( bEnabled && 0 == cEnabledLinks )
- EnableWindow( _hwnd, FALSE );
- else if( !bEnabled && cEnabledLinks!=0 )
- EnableWindow( _hwnd, TRUE );
- }
- }
- if( pItem->stateMask & LWIS_VISITED )
- bRedraw |= _AssignBit( LWIS_VISITED, pBlock->state, pItem->state );
- if( pItem->stateMask & LWIS_FOCUSED )
- {
- // Focus assignment is handled differently;
- // one and only one link can have focus...
- if( pItem->state & LWIS_FOCUSED )
- {
- bRedraw |= (_iFocus != pItem->iLink);
- _iFocus = pItem->iLink;
- }
- else
- {
- bRedraw |= (_iFocus == pItem->iLink);
- _iFocus = INVALID_LINK_INDEX;
- }
- }
- }
- if( pItem->mask & LWIF_ITEMID )
- {
- lstrcpyn( pBlock->szID, pItem->szID, sizeof(pBlock->szID) );
- lRet = 1L;
- }
- if( pItem->mask & LWIF_URL )
- {
- _AllocAndCopy( pBlock->pszUrl, pItem->szUrl );
- lRet = 1L;
- }
- }
- if( bRedraw )
- {
- InvalidateRect( _hwnd, NULL, TRUE );
- UpdateWindow( _hwnd );
- }
- return lRet;
- }
- //-------------------------------------------------------------------------//
- LRESULT CLinkWindow::GetItem( OUT LWITEM* pItem )
- {
- TEXTBLOCK* pBlock;
- LRESULT lRet = 0L;
- if( NULL == pItem || 0 == (pItem->mask & LWIF_ITEMINDEX) )
- return lRet; //BUGBUG: need to open up search keys to LWIF_ITEMID and LWIF_URL.
- if( (pBlock = FindLink( pItem->iLink )) != NULL )
- {
- if( pItem->mask & LWIF_STATE )
- {
- pItem->state = 0L;
- if( pItem->stateMask & LWIS_FOCUSED )
- {
- if( _iFocus == pItem->iLink )
- pItem->state |= LWIS_FOCUSED;
- }
- if( pItem->stateMask & LWIS_ENABLED )
- {
- if( pBlock->state & LWIS_ENABLED )
- pItem->state |= LWIS_ENABLED;
- }
- if( pItem->stateMask & LWIS_VISITED )
- {
- if( pBlock->state & LWIS_VISITED )
- pItem->state |= LWIS_VISITED;
- }
- }
- if( pItem->mask & LWIF_ITEMID )
- {
- lstrcpyn( pItem->szID, pBlock->szID, sizeof(pBlock->szID) );
- lRet = 1L;
- }
- if( pItem->mask & LWIF_URL )
- {
- *pItem->szUrl = 0;
- if( pBlock->pszUrl )
- lstrcpyn( pItem->szUrl, pBlock->pszUrl, sizeof(pItem->szUrl) );
- lRet = 1L;
- }
- }
- return lRet;
- }
- //-------------------------------------------------------------------------//
- void CLinkWindow::OnButtonDown( WPARAM fwKeys, const POINT& pt )
- {
- int iLink;
- if( (iLink = HitTest( pt )) != INVALID_LINK_INDEX )
- {
- SetCursor( GetLinkCursor() );
- _iFocus = iLink;
- MODIFY_CAPTURE( CF_SETCAPTURE, 0 );
- _ptCapture = pt;
- if( GetFocus() != _hwnd )
- {
- MODIFY_CAPTURE( CF_SETFOCUS, 0 );
- EnableNotifications( FALSE ); // so the host doesn't reposition the link.
- SetFocus( _hwnd );
- EnableNotifications( TRUE );
- }
- InvalidateRect( _hwnd, NULL, FALSE );
- SetCapture( _hwnd );
- }
- }
- //-------------------------------------------------------------------------//
- void CLinkWindow::OnButtonUp( WPARAM fwKeys, const POINT& pt )
- {
- if( TEST_CAPTURE(CF_SETCAPTURE) )
- {
- ReleaseCapture();
- MODIFY_CAPTURE( 0, CF_SETCAPTURE );
- // if the focus link contains the point, we can
- // notify the parent window of a click event.
- TEXTBLOCK* pBlock;
- if( (pBlock = FindLink( _iFocus )) != NULL &&
- (pBlock->state & LWIS_ENABLED) != 0 &&
- _iFocus == HitTest( pt ) )
- {
- SendNotify( NM_CLICK, _iFocus );
- }
- }
- if( TEST_CAPTURE(CF_SETFOCUS) )
- {
- MODIFY_CAPTURE( 0, CF_SETFOCUS );
- if( GetFocus() == _hwnd ) // if we still have the focus...
- SendNotify( NM_SETFOCUS, _iFocus );
- }
- }
- //-------------------------------------------------------------------------//
- // WM_SETTEXT handler
- void CLinkWindow::SetText( LPCTSTR pszText )
- {
- if( pszText && _pszCaption && 0 == lstrcmp( pszText, _pszCaption ) )
- return; // nothing to do.
- if( _pszCaption )
- {
- delete [] _pszCaption;
- _pszCaption = NULL;
- }
- if( pszText && *pszText )
- {
- int cch = lstrlen( pszText );
- if( (_pszCaption = new TCHAR[cch+1]) != NULL )
- lstrcpy( _pszCaption, pszText );
- }
- }
- //-------------------------------------------------------------------------//
- // WM_GETTEXT handler
- int CLinkWindow::GetText( BOOL bForParsing, LPTSTR pszText, int cchText ) const
- {
- int cchRet = 0;
- if( pszText && cchText )
- {
- *pszText = 0;
- if( bForParsing )
- {
- if( _pszCaption && *_pszCaption &&
- lstrcpyn( pszText, _pszCaption, cchText ) )
- return lstrlen( pszText ) + 1;
- }
- else
- {
- TEXTBLOCK* pBlock;
- for( pBlock = _rgBlocks; cchText > 0 && pBlock; pBlock = pBlock->next )
- {
- if( pBlock->pszText )
- {
- int cchBlock = lstrlen( pBlock->pszText );
- StrNCat( pszText, pBlock->pszText, min( cchBlock + 1, cchText ) );
- cchRet += min( cchBlock, cchText );
- cchText -= min( cchBlock, cchText );
- }
- }
- if( cchRet )
- cchRet++; // terminating NULL
- }
- }
- return cchRet;
- }
- //-------------------------------------------------------------------------//
- // WM_GETTEXT handler
- int CLinkWindow::GetTextW( BOOL bForParsing, LPWSTR pwszText, int cchText ) const
- {
- #ifdef UNICODE
- return GetText( bForParsing, pwszText, cchText );
- #else UNICODE
- int cchRet = 0;
- LPSTR pszText = new CHAR[cchText];
- if( pszText )
- {
- cchRet = GetText( bForParsing, pszText, cchText );
- if( cchRet )
- {
- SHAnsiToUnicode( pszText, pwszText, cchText );
- }
- delete [] pszText;
- }
- return cchRet;
- #endif UNICODE
- }
- //-------------------------------------------------------------------------//
- // WM_GETTEXTLENGTH handler
- int CLinkWindow::GetTextLength( BOOL bForParsing ) const
- {
- int cnt = 0;
- if( bForParsing )
- cnt = (_pszCaption && *_pszCaption) ? lstrlen(_pszCaption) : 0;
- else
- {
- TEXTBLOCK* pBlock;
- for( pBlock = _rgBlocks; pBlock; pBlock = pBlock->next )
- {
- cnt += (pBlock->pszText && *pBlock->pszText) ? lstrlen(pBlock->pszText) : 0;
- }
- }
- return cnt;
- }
- //-------------------------------------------------------------------------//
- LONG CLinkWindow::EnableNotifications( BOOL bEnable )
- {
- if( bEnable )
- {
- if( _cNotifyLocks > 0 )
- _cNotifyLocks--;
- }
- else
- _cNotifyLocks++;
- return _cNotifyLocks;
- }
- //-------------------------------------------------------------------------//
- LRESULT CLinkWindow::SendNotify( UINT nCode, int iLink, LPCTSTR pszLinkID ) const
- {
- if( 0 == _cNotifyLocks )
- {
- NMLINKWND nm;
- ZeroMemory( &nm, sizeof(nm) );
- nm.hdr.hwndFrom = _hwnd;
- nm.hdr.idFrom = (UINT_PTR)GetWindowLong( _hwnd, GWL_ID );
- nm.hdr.code = nCode;
- nm.item.iLink = iLink;
- if( pszLinkID && *pszLinkID )
- lstrcpyn( nm.item.szID, pszLinkID, ARRAYSIZE(nm.item.szID) );
- return SendMessage( GetParent( _hwnd ), WM_NOTIFY, nm.hdr.idFrom, (LPARAM)&nm );
- }
- return 0L;
- }
- //-------------------------------------------------------------------------//
- inline void MakePoint( LPARAM lParam, OUT LPPOINT ppt )
- {
- POINTS pts = MAKEPOINTS( lParam );
- ppt->x = pts.x;
- ppt->y = pts.y;
- }
- //-------------------------------------------------------------------------//
- int CLinkWindow::GetNextEnabledLink( int iStart, int nDir ) const
- {
- ASSERT( -1 == nDir || 1 == nDir );
- if( _cLinks > 0 )
- {
- if( INVALID_LINK_INDEX == iStart )
- iStart = nDir > 0 ? -1 : _cLinks;
- for( iStart += nDir; iStart >= 0; iStart += nDir )
- {
- TEXTBLOCK* pBlock;
- if( NULL == (pBlock = FindLink( iStart )) )
- return INVALID_LINK_INDEX;
- if( pBlock->state & LWIS_ENABLED )
- {
- ASSERT( iStart == pBlock->iLink );
- return iStart;
- }
- }
- }
- return INVALID_LINK_INDEX;
- }
- //-------------------------------------------------------------------------//
- int CLinkWindow::StateCount( DWORD dwStateMask, DWORD dwState ) const
- {
- TEXTBLOCK* pBlock;
- int cnt = 0;
- for( pBlock = _rgBlocks; pBlock; pBlock = pBlock->next )
- {
- if( IS_LINK(pBlock) &&
- (pBlock->state & dwStateMask) == dwState )
- cnt++;
- }
- return cnt;
- }
- //-------------------------------------------------------------------------//
- BOOL CLinkWindow::WantTab( BOOL* biFocus ) const
- {
- int nDir = TESTKEYSTATE( VK_SHIFT ) ? -1 : 1;
- int iFocus = GetNextEnabledLink( _iFocus, nDir );
- if( INVALID_LINK_INDEX != iFocus )
- {
- if( biFocus )
- *biFocus = iFocus;
- return TRUE;
- }
- return FALSE;
- }
- //-------------------------------------------------------------------------//
- // WM_SETFOCUS handler
- LRESULT CLinkWindow::OnFocus( HWND hwndPrev )
- {
- if( !TEST_CAPTURE(CF_SETCAPTURE) ) // if we got focus by something other than a mouse click
- {
- int nDir = 0;
- if( TESTKEYSTATE( VK_TAB ) )
- nDir = TESTKEYSTATE( VK_SHIFT ) ? -1 : 1;
- AssignTabFocus( nDir ); // move internal focus
- }
- InvalidateRect( _hwnd, NULL, FALSE );
- SendNotify( NM_SETFOCUS, _iFocus ); // notify parent
- return 0L;
- }
- //-------------------------------------------------------------------------//
- void CLinkWindow::AssignTabFocus( int nDirection )
- {
- if( _cLinks )
- {
- if( 0 == nDirection )
- {
- if( INVALID_LINK_INDEX != _iFocus )
- return;
- nDirection = 1;
- }
- _iFocus = GetNextEnabledLink( _iFocus, nDirection );
- }
- }
- //-------------------------------------------------------------------------//
- // WM_KEYDOWN handler
- void CLinkWindow::OnKeyDown( UINT virtKey )
- {
- switch( virtKey )
- {
- case VK_TAB:
- if( WantTab( &_iFocus ) )
- InvalidateRect( _hwnd, NULL, FALSE );
- break;
- case VK_RETURN:
- case VK_SPACE:
- if( FindLink( _iFocus ) )
- SendNotify( NM_RETURN, _iFocus );
- break;
- }
- }
- //-------------------------------------------------------------------------//
- LRESULT WINAPI CLinkWindow::WndProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
- {
- LRESULT lRet = 0L;
- CLinkWindow* pThis = NULL;
- if( uMsg == WM_NCCREATE )
- {
- pThis = new CLinkWindow;
- if( NULL == pThis )
- {
- ASSERT( pThis );
- return FALSE;
- }
- pThis->_hwnd = hwnd;
- SetWindowPtr( hwnd, GWLP_USERDATA, pThis );
- return TRUE;
- }
- else
- {
- pThis = (CLinkWindow*)GetWindowPtr( hwnd, GWLP_USERDATA );
- ASSERT( pThis );
- ASSERT( pThis->_hwnd == hwnd );
- }
- switch( uMsg )
- {
- case WM_NCHITTEST:
- {
- POINT pt;
- MakePoint( lParam, &pt );
- MapWindowPoints( HWND_DESKTOP, hwnd, &pt, 1 );
- if( pThis->HitTest( pt ) != INVALID_LINK_INDEX )
- return HTCLIENT;
- return HTTRANSPARENT;
- }
- case WM_PAINT:
- {
- PAINTSTRUCT ps;
- HDC hdc;
- if( (hdc = BeginPaint( pThis->_hwnd, &ps )) != NULL )
- {
- pThis->Paint( hdc );
- EndPaint( pThis->_hwnd, &ps );
- }
- return lRet;
- }
- case WM_WINDOWPOSCHANGING:
- {
- WINDOWPOS* pwp = (WINDOWPOS*)lParam;
- RECT rc;
- GetClientRect( pThis->_hwnd, &rc );
- if( 0 == (pwp->flags & SWP_NOSIZE) &&
- !( pwp->cx == RECTWIDTH(&rc) &&
- pwp->cy == RECTHEIGHT(&rc) ) )
- {
- // BUGBUG: implement LWS_AUTOHEIGHT style by
- // calling CalcIdealHeight() to compute the height for
- // the given width.
- }
- break;
- }
- case WM_SIZE:
- {
- pThis->Paint( NULL );
- break;
- }
- case WM_CREATE:
- {
- if( (lRet = DefWindowProc( hwnd, uMsg, wParam, lParam )) == 0 )
- {
- CREATESTRUCT* pcs = (CREATESTRUCT*)lParam;
- #ifdef KEYBOARDCUES
- _InitializeUISTATE( hwnd, &pThis->_fKeyboardCues );
- #endif//KEYBOARDCUES
- pThis->CreateFonts();
- pThis->SetText( pcs->lpszName );
- pThis->Parse( pThis->_pszCaption );
- }
- return lRet;
- }
- case WM_SETTEXT:
- pThis->SetText( (LPCTSTR)lParam );
- pThis->Parse( pThis->_pszCaption );
- InvalidateRect( pThis->_hwnd, NULL, FALSE );
- break;
- case WM_GETTEXT:
- return pThis->GetText( TRUE, (LPTSTR)lParam, (int)wParam );
- case WM_GETTEXTLENGTH:
- return pThis->GetTextLength( TRUE );
- case WM_SETFOCUS:
- return pThis->OnFocus( (HWND)wParam );
- case WM_KILLFOCUS:
- pThis->SendNotify( NM_KILLFOCUS, pThis->_iFocus );
- pThis->_iFocus = INVALID_LINK_INDEX;
- InvalidateRect( pThis->_hwnd, NULL, FALSE );
- return lRet;
- case WM_LBUTTONDOWN:
- {
- POINT pt;
- MakePoint( lParam, &pt );
- pThis->OnButtonDown( wParam, pt );
- break;
- }
- case WM_LBUTTONUP:
- {
- POINT pt;
- MakePoint( lParam, &pt );
- pThis->OnButtonUp( wParam, pt );
- break;
- }
- case WM_MOUSEMOVE:
- {
- POINT pt;
- MakePoint( lParam, &pt );
- if( pThis->HitTest( pt ) != INVALID_LINK_INDEX )
- SetCursor( pThis->GetLinkCursor() );
- break;
- }
- case WM_CAPTURECHANGED:
- if( lParam /* NULL if we called ReleaseCapture() */ )
- pThis->OnCaptureLost( (HWND)lParam );
- break;
- case LWM_HITTEST: // wParam: n/a, lparam: LPLWITEM, ret: BOOL
- {
- LWHITTESTINFO* phti = (LWHITTESTINFO*)lParam;
- if( phti )
- {
- TEXTBLOCK* pBlock;
- *phti->item.szID = 0;
- if( (phti->item.iLink = pThis->HitTest( phti->pt )) != INVALID_LINK_INDEX &&
- (pBlock = pThis->FindLink( phti->item.iLink )) != NULL )
- {
- lstrcpyn( phti->item.szID, pBlock->szID, ARRAYSIZE(phti->item.szID) );
- return TRUE;
- }
- }
- return lRet;
- }
- case LWM_SETITEM:
- return pThis->SetItem( (LWITEM*)lParam );
- case LWM_GETITEM:
- return pThis->GetItem( (LWITEM*)lParam );
- case LWM_GETIDEALHEIGHT: // wParam: cx, lparam: n/a, ret: cy
- // force a recalc if we've never done so
- return pThis->CalcIdealHeight( (int)wParam );
- case WM_NCDESTROY:
- {
- lRet = DefWindowProc( hwnd, uMsg, wParam, lParam );
- SetWindowPtr( hwnd, GWLP_USERDATA, 0 );
- pThis->_hwnd = NULL;
- pThis->Release();
- return lRet;
- }
- case WM_GETDLGCODE:
- {
- MSG* pmsg;
- lRet = DLGC_BUTTON|DLGC_UNDEFPUSHBUTTON;
- if( (pmsg = (MSG*)lParam) )
- {
- if( (WM_KEYDOWN == pmsg->message || WM_KEYUP == pmsg->message) )
- {
- switch( pmsg->wParam )
- {
- case VK_TAB:
- if( pThis->WantTab() )
- lRet |= DLGC_WANTTAB;
- break;
- case VK_RETURN:
- case VK_SPACE:
- lRet |= DLGC_WANTALLKEYS;
- break;
- }
- }
- else if( WM_CHAR == pmsg->message && VK_RETURN == pmsg->wParam )
- {
- // Eat VK_RETURN WM_CHARs; we don't want
- // Dialog manager to beep when IsDialogMessage gets it.
- return lRet |= DLGC_WANTMESSAGE;
- }
- }
- return lRet;
- }
- case WM_KEYDOWN:
- pThis->OnKeyDown( (UINT)wParam );
- case WM_KEYUP:
- case WM_CHAR:
- return lRet;
- #ifdef KEYBOARDCUES
- case WM_UPDATEUISTATE:
- if( _HandleWM_UPDATEUISTATE( wParam, lParam, &pThis->_fKeyboardCues ) )
- RedrawWindow( hwnd, NULL, NULL,
- RDW_ERASE | RDW_INVALIDATE | RDW_UPDATENOW );
- break;
- #endif
- default:
- // oleacc defs thunked for WINVER < 0x0500
- if( IsWM_GETOBJECT( uMsg ) && OBJID_CLIENT == lParam )
- return LresultFromObject( IID_IAccessible, wParam, SAFECAST(pThis, IAccessible*) );
- break;
- }
- return DefWindowProc( hwnd, uMsg, wParam, lParam );
- }
- //-------------------------------------------------------------------------//
- CLinkWindow::TEXTBLOCK::TEXTBLOCK()
- : iLink(INVALID_LINK_INDEX),
- next(NULL),
- state(LWIS_ENABLED),
- pszText(NULL),
- pszUrl(NULL),
- rgrle(NULL)
- {
- *szID = 0;
- }
- //-------------------------------------------------------------------------//
- CLinkWindow::TEXTBLOCK::~TEXTBLOCK()
- {
- // free block text
- _AllocAndCopy( pszText, NULL );
- _AllocAndCopy( pszUrl, NULL );
- // free rectangle(s)
- FreeRects();
- }
- //-------------------------------------------------------------------------//
- void CLinkWindow::TEXTBLOCK::AddRect( const RECT& rc )
- {
- RECTLISTENTRY* prce;
- if( (prce = new RECTLISTENTRY) != NULL )
- {
- prce->rc = rc;
- prce->next = NULL;
- }
- if( rgrle == NULL )
- rgrle = prce;
- else
- {
- for( RECTLISTENTRY* p = rgrle; p; p = p->next )
- {
- if( p->next == NULL )
- {
- p->next = prce;
- break;
- }
- }
- }
- }
- //-------------------------------------------------------------------------//
- void CLinkWindow::TEXTBLOCK::FreeRects()
- {
- for( RECTLISTENTRY* p = rgrle; p; )
- {
- RECTLISTENTRY* next = p->next;
- delete p;
- p = next;
- }
- rgrle = NULL;
- }
- //-------------------------------------------------------------------------//
- #define GROUPBTN_BKCOLOR COLOR_WINDOW
- #define CAPTION_VPADDING 3
- #define CAPTION_HPADDING 2
- #define GBM_SENDNOTIFY (GBM_LAST + 1)
- //-------------------------------------------------------------------------//
- // class CGroupBtn
- class CGroupBtn : public CAccessibleBase
- //-------------------------------------------------------------------------//
- { // all members private:
- CGroupBtn( HWND hwnd );
- ~CGroupBtn();
- // IAccessible specialization
- STDMETHODIMP get_accName( VARIANT varChild, BSTR* pbstrName);
- STDMETHODIMP accDoDefaultAction( VARIANT varChild );
- // CAccessibleBase overrides
- UINT GetDefaultActionStringID() const { return IDS_GROUPBTN_DEFAULTACTION; }
- // window procedures
- static LRESULT WINAPI WndProc( HWND, UINT, WPARAM, LPARAM );
- static LRESULT WINAPI BuddyProc( HWND, UINT, WPARAM, LPARAM );
- // message handlers
- BOOL NcCreate( LPCREATESTRUCT lpcs );
- LRESULT NcCalcSize( BOOL, LPNCCALCSIZE_PARAMS );
- void NcPaint( HRGN );
- LRESULT NcMouseMove( WPARAM, LONG, LONG );
- LRESULT NcHitTest( LONG, LONG );
- LRESULT NcButtonDown( UINT nMsg, WPARAM nHittest, const POINTS& pts );
- LRESULT NcDblClick( UINT nMsg, WPARAM nHittest, LPARAM lParam );
- LRESULT ButtonUp( UINT nMsg, WPARAM nHittest, const POINTS& pts );
- void OnCaptureLost( HWND hwndNew ) {RESET_CAPTURE();}
- LRESULT WindowPosChanging( LPWINDOWPOS );
- LRESULT OnSize( WPARAM, LONG, LONG);
- BOOL SetPlacement( PGBPLACEMENT );
- BOOL SetBuddy( HWND, ULONG );
- BOOL SetDropState( BOOL );
- void SetText( LPCTSTR );
- int GetText( LPTSTR, int );
- int GetTextW( LPWSTR, int );
- int GetTextLength();
- void SetFont( HFONT );
- HFONT GetFont();
- // utility methods
- static void _MapWindowRect( HWND hwnd, HWND hwndRelative, OUT LPRECT prcWindow );
- void _MapWindowRect( HWND hwndRelative, OUT LPRECT prcWindow );
- HCURSOR GetHandCursor();
- void CalcCaptionSize();
- BOOL CalcClientRect( IN OPTIONAL LPCRECT prcWindow, OUT LPRECT prcClient );
- BOOL CalcWindowSizeForClient( IN OPTIONAL LPCRECT prcClient,
- IN OPTIONAL LPCRECT prcWindow,
- IN LPCRECT prcNewClient,
- OUT LPSIZE psizeWindow );
- void DoLayout( BOOL bNewBuddy = FALSE );
- LONG EnableNotifications( BOOL bEnable );
- LRESULT SendNotify( int nCode, IN OPTIONAL NMHDR* pnmh = NULL );
- void PostNotify( int nCode );
- // instance and static data
- HWND _hwnd;
- HWND _hwndBuddy;
- WNDPROC _pfnBuddy;
- ULONG _dwBuddyFlags;
- SIZE _sizeBuddyMargin;
- HFONT _hf;
- static ATOM _atom;
- LPTSTR _pszCaption;
- SIZE _sizeCaption;
- int _yDrop;
- BOOL _fDropped : 1,
- _fInLayout : 1;
- UINT _fCapture;
- UINT _fKeyboardCues;
- HCURSOR _hcurHand;
- LONG _cNotifyLocks;
- friend ATOM GroupButton_RegisterClass();
- friend HWND CreateGroupBtn( DWORD, LPCTSTR, DWORD,
- int x, int y, HWND hwndParent, UINT nID );
- };
- //-------------------------------------------------------------------------//
- ATOM GroupButton_RegisterClass()
- {
- if( CGroupBtn::_atom != 0 )
- return CGroupBtn::_atom;
- WNDCLASSEX wc;
- ZeroMemory( &wc, sizeof(wc) );
- wc.cbSize = sizeof(wc);
- wc.style = CS_GLOBALCLASS;
- wc.lpfnWndProc = CGroupBtn::WndProc;
- wc.hInstance = HINST_THISDLL;
- wc.hCursor = LoadCursor( NULL, IDC_ARROW );
- wc.hbrBackground = (HBRUSH)(GROUPBTN_BKCOLOR+1);
- wc.lpszClassName = GROUPBUTTON_CLASS;
- //wc.lpszMenuName
- //wc.hIcon
- //wc.hIconSm
- return (CGroupBtn::_atom = RegisterClassEx( &wc ));
- }
- //-------------------------------------------------------------------------//
- BOOL GroupButton_UnregisterClass()
- {
- return UnregisterClass( GROUPBUTTON_CLASS, HINST_THISDLL );
- }
- //-------------------------------------------------------------------------//
- CGroupBtn::CGroupBtn( HWND hwnd )
- : CAccessibleBase( _hwnd ),
- _hwnd(hwnd),
- _hwndBuddy(NULL),
- _pfnBuddy(NULL),
- _dwBuddyFlags(GBBF_HRESIZE|GBBF_VRESIZE),
- _fInLayout(FALSE),
- _hf(NULL),
- _pszCaption(NULL),
- _fDropped(TRUE),
- _fKeyboardCues(0),
- _yDrop(0),
- _fCapture(0),
- _hcurHand(NULL),
- _cNotifyLocks(0)
- {
- _sizeCaption.cx = _sizeCaption.cy = 0;
- _sizeBuddyMargin.cx = _sizeBuddyMargin.cy = 0;
- }
- ATOM CGroupBtn::_atom = 0;
- //-------------------------------------------------------------------------//
- CGroupBtn::~CGroupBtn()
- {
- SetFont( NULL );
- SetText( NULL );
- }
- //-------------------------------------------------------------------------//
- // CGroupBtn IAccessible impl
- STDMETHODIMP CGroupBtn::get_accName( VARIANT varChild, BSTR* pbstrName)
- {
- VALIDATEACCCHILD( varChild, CHILDID_SELF, E_INVALIDARG );
- if( NULL == pbstrName )
- return E_POINTER;
- *pbstrName = 0;
- int cch = GetTextLength();
- if( (*pbstrName = SysAllocStringLen(NULL, cch + 1)) != NULL )
- {
- GetTextW( *pbstrName, cch + 1 );
- return S_OK;
- }
- return E_OUTOFMEMORY;
- }
- STDMETHODIMP CGroupBtn::accDoDefaultAction( VARIANT varChild )
- {
- VALIDATEACCCHILD( varChild, CHILDID_SELF, E_INVALIDARG );
- SendNotify( NM_RETURN );
- return S_OK;
- }
- //-------------------------------------------------------------------------//
- // CGroupBtn window impl
- //-------------------------------------------------------------------------//
- //-------------------------------------------------------------------------//
- // WM_SETTEXT handler
- void CGroupBtn::SetText( LPCTSTR pszText )
- {
- if( _pszCaption )
- {
- if( pszText && 0==lstrcmp( _pszCaption, pszText ) )
- return;
- delete [] _pszCaption;
- _pszCaption = NULL;
- }
- if( pszText && *pszText )
- {
- if( (_pszCaption = new TCHAR[lstrlen(pszText)+1]) != NULL )
- lstrcpy( _pszCaption, pszText );
- }
- if( IsWindow( _hwnd ) )
- CalcCaptionSize();
- }
- //-------------------------------------------------------------------------//
- // WM_GETTEXT handler
- int CGroupBtn::GetText( LPTSTR pszText, int cchText )
- {
- int cch = 0;
- if( pszText && cchText > 0 )
- {
- *pszText = 0;
- if( _pszCaption && lstrcpyn( pszText, _pszCaption, cchText ) )
- cch = min( lstrlen( _pszCaption ), cchText );
- }
- return cch;
- }
- //-------------------------------------------------------------------------//
- int CGroupBtn::GetTextW( LPWSTR pwszText, int cchText )
- {
- #ifdef UNICODE
- return GetText( pwszText, cchText );
- #else //UNICODE
- int cchRet = 0;
- LPSTR pszText = new CHAR[cchText];
- if( pszText )
- {
- cchRet = GetText( pszText, cchText );
- if( cchRet )
- {
- SHAnsiToUnicode( pszText, pwszText, cchText );
- }
- delete [] pszText;
- }
- return cchRet;
- #endif //UNICODE
- }
- //-------------------------------------------------------------------------//
- // WM_GETTEXTLENGTH handler
- int CGroupBtn::GetTextLength()
- {
- return (_pszCaption && *_pszCaption) ? lstrlen( _pszCaption ) : 0 ;
- }
- //-------------------------------------------------------------------------//
- // WM_SETFONT handler
- void CGroupBtn::SetFont( HFONT hf )
- {
- if( _hf )
- {
- DeleteObject( _hf );
- _hf = NULL;
- }
- _hf = hf;
- }
- //-------------------------------------------------------------------------//
- // WM_GETFONT handler
- HFONT CGroupBtn::GetFont()
- {
- if( _hf == NULL )
- {
- // if we don't have a font, use the parent's font
- HFONT hfParent = (HFONT)SendMessage( GetParent( _hwnd ), WM_GETFONT, 0, 0L );
- if( hfParent )
- {
- LOGFONT lf;
- if( GetObject( hfParent, sizeof(LOGFONT), &lf ) >0 )
- _hf = CreateFontIndirect( &lf );
- }
- }
- return _hf;
- }
- //-------------------------------------------------------------------------//
- // Hand cursor load
- HCURSOR CGroupBtn::GetHandCursor()
- {
- if( !_hcurHand )
- _hcurHand = LoadHandCursor(0);
- return _hcurHand;
- }
- //-------------------------------------------------------------------------//
- // Retrieves the window rect in relative coords.
- void CGroupBtn::_MapWindowRect( HWND hwnd, HWND hwndRelative, OUT LPRECT prcWindow )
- {
- ASSERT( IsWindow( hwnd ) );
- GetWindowRect( hwnd, prcWindow );
- MapWindowPoints( HWND_DESKTOP, hwndRelative, (LPPOINT)prcWindow, 2 );
- }
- //-------------------------------------------------------------------------//
- // Retrieves the window rect in relative coords.
- inline void CGroupBtn::_MapWindowRect( HWND hwndRelative, OUT LPRECT prcWindow )
- {
- _MapWindowRect( _hwnd, hwndRelative, prcWindow );
- }
- //-------------------------------------------------------------------------//
- // Caches the size of the caption 'bar'.
- void CGroupBtn::CalcCaptionSize()
- {
- SIZE sizeCaption = {0,0};
- LPCTSTR pszCaption = (_pszCaption && *_pszCaption) ? _pszCaption : TEXT("|");
- HDC hdc;
- // compute caption size based on window text:
- if( (hdc = GetDC( _hwnd )) )
- {
- HFONT hf = GetFont(),
- hfPrev = (HFONT)SelectObject( hdc, hf );
- if( GetTextExtentPoint32( hdc, pszCaption, lstrlen( pszCaption ),
- &sizeCaption ) )
- sizeCaption.cy += CAPTION_VPADDING; // add some vertical padding
- SelectObject( hdc, hfPrev );
- ReleaseDC( _hwnd, hdc );
- }
- _sizeCaption = sizeCaption;
- }
- //-------------------------------------------------------------------------//
- // Computes the size and position of the client area
- BOOL CGroupBtn::CalcClientRect( IN OPTIONAL LPCRECT prcWindow, OUT LPRECT prcClient )
- {
- DWORD dwStyle = GetWindowLong( _hwnd, GWL_STYLE );
- RECT rcWindow;
- if( !prcWindow )
- {
- // Get parent-relative coords
- _MapWindowRect( GetParent( _hwnd ), &rcWindow );
- prcWindow = &rcWindow;
- }
- *prcClient = *prcWindow;
- // compute client rectangle:
- // allow for border
- if( dwStyle & WS_BORDER )
- InflateRect( prcClient, -1, -1 );
- // allow for caption 'bar'
- prcClient->top += _sizeCaption.cy;
- // Normalize for NULL rect.
- if( RECTWIDTH(prcWindow) <=0 )
- prcClient->left = prcClient->right = prcWindow->left;
- if( RECTHEIGHT(prcWindow) <=0 )
- prcClient->bottom = prcClient->top = prcWindow->top;
- return TRUE;
- }
- //-------------------------------------------------------------------------//
- BOOL CGroupBtn::CalcWindowSizeForClient(
- IN OPTIONAL LPCRECT prcClient,
- IN OPTIONAL LPCRECT prcWindow,
- IN LPCRECT prcNewClient,
- OUT LPSIZE psizeWindow )
- {
- if( !(prcNewClient && psizeWindow ) )
- {
- ASSERT(FALSE);
- return FALSE;
- }
- RECT rcWindow, rcClient;
- if( NULL == prcWindow )
- {
- GetWindowRect( _hwnd, &rcWindow );
- prcWindow = &rcWindow;
- }
- if( NULL == prcClient )
- {
- GetClientRect( _hwnd, &rcClient );
- prcClient = &rcClient;
- }
- SIZE sizeDelta;
- sizeDelta.cx = RECTWIDTH(prcWindow) - RECTWIDTH(prcClient);
- sizeDelta.cy = RECTHEIGHT(prcWindow) - RECTHEIGHT(prcClient);
- psizeWindow->cx = RECTWIDTH(prcNewClient) + sizeDelta.cx;
- psizeWindow->cy = RECTHEIGHT(prcNewClient) + sizeDelta.cy;
- return TRUE;
- }
- //-------------------------------------------------------------------------//
- // WM_WINDOWPOSCHANGING handler
- LRESULT CGroupBtn::WindowPosChanging( LPWINDOWPOS pwp )
- {
- if( pwp->flags & SWP_NOSIZE )
- return DefWindowProc( _hwnd, WM_WINDOWPOSCHANGING, 0, (LPARAM)pwp );
- // disallow sizing in buddy slave dimension(s).
- if( IsWindow( _hwndBuddy ) && _dwBuddyFlags & (GBBF_HSLAVE|GBBF_VSLAVE) && !_fInLayout )
- {
- RECT rcWindow, rcClient;
- BOOL fResizeBuddy = FALSE;
- GetWindowRect( _hwnd, &rcWindow );
- GetClientRect( _hwnd, &rcClient );
- // Prepare a buddy size data block
- GBNQUERYBUDDYSIZE qbs;
- qbs.cy = pwp->cy - (RECTHEIGHT(&rcWindow) - RECTHEIGHT(&rcClient));
- qbs.cx = pwp->cx - (RECTWIDTH(&rcWindow) - RECTWIDTH(&rcClient));
- if( _dwBuddyFlags & GBBF_HSLAVE ) // prevent external horz resizing
- {
- pwp->cx = RECTWIDTH( &rcWindow );
- // If we're being resized in the vert dir, query for
- // optimal buddy width for this height and adjust
- if( _dwBuddyFlags & GBBF_VRESIZE && RECTHEIGHT( &rcWindow ) != pwp->cy )
- {
- if( SendNotify( GBN_QUERYBUDDYWIDTH, (NMHDR*)&qbs ) && qbs.cx >= 0 )
- {
- // if the owner wants the buddy width to change, do it now.
- LONG cxNew = qbs.cx + (RECTWIDTH( &rcWindow ) - RECTWIDTH( &rcClient ));
- fResizeBuddy = cxNew != pwp->cx;
- pwp->cx = cxNew;
- }
- }
- }
- if( _dwBuddyFlags & GBBF_VSLAVE ) // prevent external vert resizing
- {
- pwp->cy = RECTHEIGHT( &rcWindow );
- // If we're being resized in the horz dir, query for
- // optimal buddy height for this horizontal and adjust
- if( _dwBuddyFlags & GBBF_HRESIZE && RECTWIDTH( &rcWindow ) != pwp->cx )
- {
- if( SendNotify( GBN_QUERYBUDDYHEIGHT, (NMHDR*)&qbs ) && qbs.cy >= 0 )
- {
- LONG cyNew = qbs.cy + (RECTHEIGHT( &rcWindow ) - RECTHEIGHT( &rcClient ));
- fResizeBuddy = cyNew != pwp->cy;
- pwp->cy = cyNew;
- }
- }
- }
- if( fResizeBuddy )
- {
- _fInLayout = TRUE;
- SetWindowPos( _hwndBuddy, NULL, 0, 0, qbs.cx, qbs.cy,
- SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE );
- _fInLayout = FALSE;
- }
- }
- // enforce minimum height:
- if( pwp->cy < _sizeCaption.cy )
- pwp->cy = _sizeCaption.cy;
- return 0L;
- }
- //-------------------------------------------------------------------------//
- LRESULT CGroupBtn::OnSize( WPARAM flags, LONG cx, LONG cy )
- {
- DoLayout();
- return 0L;
- }
- //-------------------------------------------------------------------------//
- void CGroupBtn::DoLayout( BOOL bNewBuddy )
- {
- if( !_fInLayout && IsWindow( _hwndBuddy ) )
- {
- RECT rcWindow, rcThis, rcBuddy;
- DWORD dwSwpBuddy = SWP_NOACTIVATE,
- dwSwpThis = SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE;
- BOOL fReposThis = FALSE;
- SIZE sizeNew;
- GetClientRect( _hwnd, &rcThis );
- GetWindowRect( _hwnd, &rcWindow );
- // get rectangles in parent coords
- MapWindowPoints( _hwnd, GetParent( _hwnd ), (LPPOINT)&rcThis, POINTSPERRECT );
- MapWindowPoints( HWND_DESKTOP, GetParent( _hwnd ), (LPPOINT)&rcWindow, POINTSPERRECT );
- _MapWindowRect( _hwndBuddy, GetParent( _hwnd ), &rcBuddy );
- // If we need to reposition ourself to the buddy,
- // calculate the new size now.
- if( _dwBuddyFlags & (GBBF_HSLAVE|GBBF_VSLAVE) )
- CalcWindowSizeForClient( &rcThis, &rcWindow, &rcBuddy, &sizeNew );
- // Resize buddy according to size.
- if( _dwBuddyFlags & GBBF_HRESIZE )
- {
- rcBuddy.right = rcBuddy.left + RECTWIDTH(&rcThis);
- if( bNewBuddy && 0 == (_dwBuddyFlags & GBBF_VRESIZE) )
- {
- // query height
- GBNQUERYBUDDYSIZE qbs;
- qbs.cx = RECTWIDTH( &rcThis );
- qbs.cy = -1;
- if( SendNotify( GBN_QUERYBUDDYHEIGHT, (NMHDR*)&qbs ) && qbs.cy >= 0 )
- rcBuddy.bottom = rcBuddy.top + qbs.cy;
- }
- }
- else if( _dwBuddyFlags & GBBF_HSLAVE )
- {
- rcWindow.right = rcWindow.left + sizeNew.cx;
- fReposThis = TRUE;
- }
- if( _dwBuddyFlags & GBBF_VRESIZE )
- {
- rcBuddy.bottom = rcBuddy.top + RECTHEIGHT(&rcThis);
- if( bNewBuddy && 0 == (_dwBuddyFlags & GBBF_HRESIZE) )
- {
- // query width
- GBNQUERYBUDDYSIZE qbs;
- qbs.cx = -1;
- qbs.cy = RECTHEIGHT( &rcThis );
- if( SendNotify( GBN_QUERYBUDDYWIDTH, (NMHDR*)&qbs ) && qbs.cx >= 0 )
- rcBuddy.right = rcBuddy.left + qbs.cx;
- }
- }
- else if( _dwBuddyFlags & GBBF_VSLAVE )
- {
- rcWindow.bottom = rcWindow.top + sizeNew.cy;
- fReposThis = TRUE;
- }
- if( _dwBuddyFlags & GBBF_HSCROLL )
- {
- /* not implemented */
- }
- if( _dwBuddyFlags & GBBF_VSCROLL )
- {
- /* not implemented */
- }
- // reposition ourself and update our client rect.
- if( fReposThis )
- {
- _fInLayout = TRUE;
- SetWindowPos( _hwnd, NULL, 0, 0,
- RECTWIDTH( &rcWindow ), RECTHEIGHT( &rcWindow ), dwSwpThis );
- _fInLayout = FALSE;
- GetClientRect( _hwnd, &rcThis );
- MapWindowPoints( _hwnd, GetParent( _hwnd ), (LPPOINT)&rcThis, POINTSPERRECT );
- }
- // slide buddy into client area and reposition
- OffsetRect( &rcBuddy, rcThis.left - rcBuddy.left, rcThis.top - rcBuddy.top );
- _fInLayout = TRUE;
- SetWindowPos( _hwndBuddy, _hwnd, rcBuddy.left, rcBuddy.top,
- RECTWIDTH( &rcBuddy ), RECTHEIGHT( &rcBuddy ), dwSwpBuddy );
- _fInLayout = FALSE;
- }
- }
- //-------------------------------------------------------------------------//
- // GBM_SETPLACEMENT handler
- BOOL CGroupBtn::SetPlacement( PGBPLACEMENT pgbp )
- {
- RECT rcWindow, rcClient;
- SIZE sizeDelta;
- DWORD dwFlags = SWP_NOZORDER|SWP_NOACTIVATE;
- ZeroMemory( &sizeDelta, sizeof(sizeDelta) );
- _MapWindowRect( GetParent( _hwnd ), &rcWindow );
- CalcClientRect( &rcWindow, &rcClient );
- // establish whether we need to resize
- if( (pgbp->x < 0 || pgbp->x == rcWindow.left) &&
- (pgbp->y < 0 || pgbp->y == rcWindow.top) )
- dwFlags |= SWP_NOMOVE;
- // compute horizontal placement
- if( pgbp->x >= 0 ) // fixed horz origin requested
- OffsetRect( &rcWindow, pgbp->x - rcWindow.left, 0 );
- if( pgbp->cx >= 0 ) // fixed width requested
- rcWindow.right = rcWindow.left + pgbp->cx;
- else
- {
- if( pgbp->cxBuddy >= 0 ) // client width requested
- sizeDelta.cx = pgbp->cxBuddy - RECTWIDTH(&rcClient);
- rcWindow.right += sizeDelta.cx;
- }
- // compute vertical placement
- if( pgbp->y >= 0 ) // fixed vert origin requested
- OffsetRect( &rcWindow, 0, pgbp->y - rcWindow.top );
- if( pgbp->cy >= 0 ) // fixed height requested
- rcWindow.bottom = rcWindow.top + pgbp->cy;
- else
- {
- if( pgbp->cyBuddy >= 0 ) // client height requested
- sizeDelta.cy = pgbp->cyBuddy - RECTHEIGHT(&rcClient);
- rcWindow.bottom += sizeDelta.cy;
- }
- if( pgbp->hdwp && (-1 != (LONG_PTR)pgbp->hdwp) )
- DeferWindowPos( pgbp->hdwp, _hwnd, NULL, rcWindow.left, rcWindow.top,
- RECTWIDTH( &rcWindow ), RECTHEIGHT( &rcWindow ),
- dwFlags );
- else
- SetWindowPos( _hwnd, NULL, rcWindow.left, rcWindow.top,
- RECTWIDTH( &rcWindow ), RECTHEIGHT( &rcWindow ),
- dwFlags );
- // stuff resulting rects
- pgbp->rcWindow = rcWindow;
- return CalcClientRect( &rcWindow, &pgbp->rcBuddy );
- }
- //-------------------------------------------------------------------------//
- BOOL CGroupBtn::SetBuddy( HWND hwnd, ULONG dwFlags )
- {
- if( !IsWindow( hwnd ) )
- hwnd = NULL;
- if( hwnd && (dwFlags & (GBBF_HSLAVE|GBBF_VSLAVE)) )
- {
- // subclass the buddy
- _pfnBuddy = (WNDPROC)SetWindowLongPtr( hwnd, GWLP_WNDPROC, (LONG_PTR)BuddyProc );
- SetWindowLongPtr( hwnd, GWLP_USERDATA, (LONG_PTR)this );
- }
- else if( IsWindow( _hwndBuddy ) && _pfnBuddy )
- {
- SetWindowLongPtr( hwnd, GWLP_USERDATA, (LONG_PTR)NULL );
- SetWindowLongPtr( hwnd, GWLP_WNDPROC, (LONG_PTR)_pfnBuddy );
- _pfnBuddy = NULL;
- }
- _hwndBuddy = hwnd;
- _dwBuddyFlags = dwFlags;
- DoLayout( TRUE );
- return TRUE;
- }
- //-------------------------------------------------------------------------//
- BOOL CGroupBtn::SetDropState( BOOL bDropped )
- {
- _fDropped = bDropped;
- return TRUE;
- }
- //-------------------------------------------------------------------------//
- // WM_NCCREATE handler
- BOOL CGroupBtn::NcCreate( LPCREATESTRUCT lpcs )
- {
- // assign user data
- SetWindowLongPtr( _hwnd, GWLP_USERDATA, (LONG_PTR)this );
- // enforce window style bits
- lpcs->style |= WS_CLIPCHILDREN|WS_CLIPSIBLINGS;
- lpcs->dwExStyle |= WS_EX_TRANSPARENT;
- SetWindowLong( _hwnd, GWL_STYLE, lpcs->style );
- SetWindowLong( _hwnd, GWL_EXSTYLE, lpcs->dwExStyle );
- // enforce min height
- SetText( lpcs->lpszName );
- if( lpcs->cy < _sizeCaption.cy )
- {
- lpcs->cy = _sizeCaption.cy;
- SetWindowPos( _hwnd, NULL, 0,0, lpcs->cx, lpcs->cy,
- SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE );
- }
- return TRUE;
- }
- //-------------------------------------------------------------------------//
- // WM_NCCALCSIZE handler
- LRESULT CGroupBtn::NcCalcSize( BOOL fCalcValidRects, LPNCCALCSIZE_PARAMS pnccs )
- {
- LRESULT lRet = FALSE;
- RECT rcClient;
- if( fCalcValidRects && CalcClientRect( &pnccs->rgrc[0], &rcClient ) )
- {
- pnccs->rgrc[1] = pnccs->rgrc[2];
- pnccs->rgrc[0] = pnccs->rgrc[2] = rcClient;
- return WVR_VALIDRECTS;
- }
- return lRet;
- }
- //-------------------------------------------------------------------------//
- // WM_NCPAINT handler
- void CGroupBtn::NcPaint( HRGN hrgn )
- {
- RECT rcWindow;
- DWORD dwStyle = GetWindowLong( _hwnd, GWL_STYLE );
- HDC hdc;
- GetWindowRect( _hwnd, &rcWindow );
- OffsetRect( &rcWindow, -rcWindow.left, -rcWindow.top );
- if( (hdc = GetWindowDC( _hwnd )) != NULL )
- {
- if( dwStyle & WS_BORDER )
- {
- HBRUSH hbr = CreateSolidBrush( COLOR_WINDOWFRAME );
- FrameRect( hdc, &rcWindow, hbr );
- DeleteObject( hbr );
- }
- rcWindow.bottom = rcWindow.top + _sizeCaption.cy;
- SetBkColor( hdc, GetSysColor( COLOR_HIGHLIGHT ) );
- SetTextColor( hdc, GetSysColor( COLOR_HIGHLIGHTTEXT ) );
- ExtTextOut( hdc, rcWindow.left, rcWindow.top,
- ETO_OPAQUE, &rcWindow, NULL, 0, NULL );
- InflateRect( &rcWindow, -CAPTION_HPADDING, -(CAPTION_VPADDING/2) );
- HFONT hfPrev = (HFONT)SelectObject( hdc, GetFont() );
- ExtTextOut( hdc, rcWindow.left, rcWindow.top,
- ETO_OPAQUE, &rcWindow, _pszCaption,
- _pszCaption ? lstrlen(_pszCaption) : 0, NULL );
- SelectObject( hdc, hfPrev );
- #ifdef KEYBOARDCUES
- if( 0 == (_fKeyboardCues & UISF_HIDEFOCUS) )
- #endif
- {
- if( GetFocus() == _hwnd )
- {
- rcWindow.right = rcWindow.left + _sizeCaption.cx + 1;
- InflateRect( &rcWindow, 1, 0 );
- DrawFocusRect( hdc, &rcWindow );
- }
- }
- ReleaseDC( _hwnd, hdc );
- }
- }
- //-------------------------------------------------------------------------//
- // WM_NCMOUSEMOVE handler
- //-------------------------------------------------------------------------//
- LRESULT CGroupBtn::NcMouseMove( WPARAM nHittest, LONG x, LONG y )
- {
- if( HTCAPTION == nHittest )
- {
- RECT rc;
- POINT pt;
- GetWindowRect( _hwnd, &rc );
- rc.bottom = rc.top + _sizeCaption.cy;
- rc.right = rc.left + _sizeCaption.cx;
- InflateRect( &rc, 0, -(CAPTION_VPADDING/2) );
- pt.x = x;
- pt.y = y;
- if( PtInRect( &rc, pt ) )
- {
- HCURSOR hc = GetHandCursor();
- if( hc != NULL )
- {
- SetCursor( hc );
- return 0L;
- }
- }
- }
- return DefWindowProc( _hwnd, WM_NCMOUSEMOVE, nHittest, MAKELPARAM( x, y ) );
- }
- //-------------------------------------------------------------------------//
- // WM_NCHITTEST handler
- LRESULT CGroupBtn::NcHitTest( LONG x, LONG y )
- {
- POINT pt;
- RECT rc, rcClient;
- DWORD dwStyle = GetWindowLong( _hwnd, GWL_STYLE );
- pt.x = x;
- pt.y = y;
- GetWindowRect( _hwnd, &rc );
- CalcClientRect( &rc, &rcClient );
- if( PtInRect( &rcClient, pt ) )
- return HTTRANSPARENT;
- if( PtInRect( &rc, pt ) )
- {
- if( dwStyle & WS_BORDER )
- {
- if( pt.x == rc.left ||
- pt.x == rc.right ||
- pt.y == rc.bottom )
- return HTBORDER;
- }
- return HTCAPTION;
- }
- return HTNOWHERE;
- }
- //-------------------------------------------------------------------------//
- LRESULT CGroupBtn::NcButtonDown( UINT nMsg, WPARAM nHittest, const POINTS& pts )
- {
- LRESULT lRet = 0L;
- if( HTCAPTION == nHittest )
- {
- SetCursor( GetHandCursor() );
- MODIFY_CAPTURE( CF_SETCAPTURE, 0 );
- if( GetFocus() != _hwnd )
- {
- MODIFY_CAPTURE( CF_SETFOCUS, 0 );
- EnableNotifications( FALSE ); // so the host doesn't reposition the link.
- SetFocus( _hwnd );
- EnableNotifications( TRUE );
- }
- SetCapture( _hwnd );
- }
- else
- lRet = DefWindowProc( _hwnd, nMsg, nHittest, MAKELONG(pts.x, pts.y) );
- return lRet;
- }
- //-------------------------------------------------------------------------//
- LRESULT CGroupBtn::ButtonUp( UINT nMsg, WPARAM nHittest, const POINTS& pts )
- {
- if( TEST_CAPTURE(CF_SETCAPTURE) )
- {
- ReleaseCapture();
- MODIFY_CAPTURE( 0, CF_SETCAPTURE );
- POINT ptScrn;
- ptScrn.x = pts.x;
- ptScrn.y = pts.y;
- MapWindowPoints( _hwnd, HWND_DESKTOP, &ptScrn, 1 );
- LRESULT nHittest = SendMessage( _hwnd, WM_NCHITTEST, 0, MAKELONG( ptScrn.x, ptScrn.y ) );
- if( HTCAPTION == nHittest )
- {
- switch( nMsg )
- {
- case WM_LBUTTONUP:
- SendNotify( NM_CLICK );
- break;
- case WM_RBUTTONUP:
- SendNotify( NM_RCLICK );
- break;
- }
- }
- }
- if( TEST_CAPTURE(CF_SETFOCUS) )
- {
- MODIFY_CAPTURE( 0, CF_SETFOCUS );
- if( GetFocus() == _hwnd ) // if we still have the focus...
- SendNotify( NM_SETFOCUS );
- }
- return 0L;
- }
- //-------------------------------------------------------------------------//
- // Non-client mouse click/dblclk handler
- LRESULT CGroupBtn::NcDblClick( UINT nMsg, WPARAM nHittest, LPARAM lParam )
- {
- LRESULT lRet = 0L;
- if( HTCAPTION == nHittest )
- {
- SetFocus( _hwnd );
- lRet = DefWindowProc( _hwnd, nMsg, HTCLIENT, lParam );
- switch( nMsg )
- {
- case WM_NCLBUTTONDBLCLK:
- SendNotify( NM_DBLCLK );
- break;
- case WM_NCRBUTTONDBLCLK:
- SendNotify( NM_RDBLCLK );
- break;
- }
- }
- else
- lRet = DefWindowProc( _hwnd, nMsg, nHittest, lParam );
- return lRet;
- }
- //-------------------------------------------------------------------------//
- LONG CGroupBtn::EnableNotifications( BOOL bEnable )
- {
- if( bEnable )
- {
- if( _cNotifyLocks > 0 )
- _cNotifyLocks--;
- }
- else
- _cNotifyLocks++;
- return _cNotifyLocks;
- }
- //-------------------------------------------------------------------------//
- // WM_NOTIFY transmit helper
- LRESULT CGroupBtn::SendNotify( int nCode, IN OPTIONAL NMHDR* pnmh )
- {
- if( 0 == _cNotifyLocks )
- {
- NMHDR hdr;
- if( NULL == pnmh )
- pnmh = &hdr;
- pnmh->hwndFrom = _hwnd;
- pnmh->idFrom = GetDlgCtrlID( _hwnd );
- pnmh->code = nCode;
- return SendMessage( GetParent( _hwnd ), WM_NOTIFY, hdr.idFrom, (LPARAM)pnmh );
- }
- return 0;
- }
- //-------------------------------------------------------------------------//
- // WM_NOTIFY transmit helper
- void CGroupBtn::PostNotify( int nCode )
- {
- if( 0 == _cNotifyLocks )
- PostMessage( _hwnd, GBM_SENDNOTIFY, nCode, 0L );
- }
- //-------------------------------------------------------------------------//
- LRESULT CGroupBtn::WndProc( HWND hwnd, UINT nMsg, WPARAM wParam, LPARAM lParam )
- {
- CGroupBtn *pThis = (CGroupBtn*)GetWindowLongPtr( hwnd, GWLP_USERDATA );
- LRESULT lRet = 0;
- switch( nMsg )
- {
- case WM_NCHITTEST:
- {
- POINTS pts = MAKEPOINTS( lParam );
- return pThis->NcHitTest( pts.x, pts.y );
- }
- case WM_NCMOUSEMOVE:
- {
- POINTS pts = MAKEPOINTS( lParam );
- return pThis->NcMouseMove( wParam, pts.x, pts.y );
- }
- case WM_NCCALCSIZE:
- return pThis->NcCalcSize( (BOOL)wParam, (LPNCCALCSIZE_PARAMS)lParam );
- case WM_NCPAINT:
- pThis->NcPaint( (HRGN)wParam );
- return 0;
- case WM_WINDOWPOSCHANGING:
- return pThis->WindowPosChanging( (LPWINDOWPOS)lParam );
- case WM_SIZE:
- {
- POINTS pts = MAKEPOINTS( lParam );
- return pThis->OnSize( wParam, pts.x, pts.y );
- }
- case WM_DESTROY:
- if( IsWindow( pThis->_hwndBuddy ) )
- DestroyWindow( pThis->_hwndBuddy );
- break;
- case WM_ERASEBKGND:
- return TRUE; // transparent: no erase bkgnd
- case WM_NCLBUTTONDOWN:
- case WM_NCRBUTTONDOWN:
- {
- POINTS pts = MAKEPOINTS(lParam);
- return pThis->NcButtonDown( nMsg, wParam, pts );
- }
- case WM_LBUTTONUP:
- case WM_RBUTTONUP:
- {
- POINTS pts = MAKEPOINTS(lParam);
- return pThis->ButtonUp( nMsg, wParam, pts );
- }
- case WM_NCLBUTTONDBLCLK:
- case WM_NCRBUTTONDBLCLK:
- return pThis->NcDblClick( nMsg, wParam, lParam );
- case WM_SHOWWINDOW:
- if( IsWindow( pThis->_hwndBuddy ) )
- ShowWindow( pThis->_hwndBuddy, wParam ? SW_SHOW : SW_HIDE );
- break;
- case WM_SETTEXT:
- pThis->SetText( (LPCTSTR)lParam );
- return TRUE;
- case WM_GETTEXT:
- return pThis->GetText( (LPTSTR)lParam, (int)wParam );
- case WM_SETFONT:
- pThis->SetFont( (HFONT)wParam );
- if( lParam /* fRedraw */)
- InvalidateRect( hwnd, NULL, TRUE );
- break;
- case WM_CAPTURECHANGED:
- if( lParam /* NULL if we called ReleaseCapture() */)
- pThis->OnCaptureLost( (HWND)lParam );
- break;
- case WM_SETFOCUS:
- pThis->NcPaint( (HRGN)1 );
- pThis->SendNotify( NM_SETFOCUS );
- break;
- case WM_KILLFOCUS:
- pThis->NcPaint( (HRGN)1 );
- pThis->SendNotify( NM_KILLFOCUS );
- break;
- case WM_GETDLGCODE:
- {
- MSG* pmsg;
- lRet = DLGC_BUTTON|DLGC_UNDEFPUSHBUTTON;
- if( (pmsg = (MSG*)lParam) )
- {
- if( (WM_KEYDOWN == pmsg->message || WM_KEYUP == pmsg->message) )
- {
- switch( pmsg->wParam )
- {
- case VK_RETURN:
- case VK_SPACE:
- lRet |= DLGC_WANTALLKEYS;
- break;
- }
- }
- else if( WM_CHAR == pmsg->message && VK_RETURN == pmsg->wParam )
- {
- // Eat VK_RETURN WM_CHARs; we don't want
- // Dialog manager to beep when IsDialogMessage gets it.
- return lRet |= DLGC_WANTMESSAGE;
- }
- }
- return lRet;
- }
- case WM_KEYDOWN:
- case WM_KEYUP:
- case WM_CHAR:
- switch( wParam )
- {
- case VK_RETURN:
- case VK_SPACE:
- if( WM_KEYDOWN == nMsg )
- pThis->SendNotify( NM_RETURN );
- return 0L;
- }
- break;
- #ifdef KEYBOARDCUES
- case WM_UPDATEUISTATE:
- if( _HandleWM_UPDATEUISTATE( wParam, lParam, &pThis->_fKeyboardCues ) )
- SendMessage( hwnd, WM_NCPAINT, 1, 0L );
- break;
- #endif
- case GBM_SETPLACEMENT:
- if( lParam )
- return pThis->SetPlacement( (PGBPLACEMENT)lParam );
- return 0L;
- case GBM_SETDROPSTATE: // WPARAM: BOOL fDropped, LPARAM: n/a, return: BOOL
- return 0L;
- case GBM_GETDROPSTATE: // WPARAM: n/a, LPARAM: n/a, return: BOOL fDropped
- return 0L;
- case GBM_SENDNOTIFY:
- pThis->SendNotify( (int)wParam );
- break;
- case WM_NCCREATE:
- {
- LPCREATESTRUCT lpcs = (LPCREATESTRUCT)lParam;
- if( (pThis = new CGroupBtn(hwnd) ) == NULL )
- break;
- if( !pThis->NcCreate( (LPCREATESTRUCT)lParam ) )
- return FALSE;
- break;
- }
- case WM_NCDESTROY:
- lRet = DefWindowProc( hwnd, nMsg, wParam, lParam );
- SetWindowPtr( hwnd, GWLP_USERDATA, NULL );
- pThis->_hwnd = NULL;
- pThis->Release();
- return lRet;
- case WM_CREATE:
- #ifdef KEYBOARDCUES
- _InitializeUISTATE( hwnd, &pThis->_fKeyboardCues );
- #endif//KEYBOARDCUES
- pThis->SetText( ((LPCREATESTRUCT)lParam)->lpszName );
- break;
- case GBM_SETBUDDY: // WPARAM: HWND hwndBuddy, LPARAM: MAKELPARAM(cxMargin, cyMargin), return: BOOL
- return pThis->SetBuddy( (HWND)wParam, (ULONG)lParam );
- case GBM_GETBUDDY: // WPARAM: n/a, LPARAM: n/a, return: HWND
- return (LRESULT)pThis->_hwndBuddy;
- default:
- // oleacc defs thunked for WINVER < 0x0500
- if( IsWM_GETOBJECT( nMsg ) && (OBJID_CLIENT == lParam || OBJID_TITLEBAR == lParam) )
- return LresultFromObject( IID_IAccessible, wParam, SAFECAST(pThis, IAccessible*) );
- break;
- }
- return DefWindowProc( hwnd, nMsg, wParam, lParam );
- }
- //-------------------------------------------------------------------------//
- LRESULT CGroupBtn::BuddyProc( HWND hwnd, UINT nMsg, WPARAM wParam, LPARAM lParam )
- {
- CGroupBtn *pBtn = (CGroupBtn*)GetWindowLongPtr( hwnd, GWLP_USERDATA );
- ASSERT( pBtn );
- switch( nMsg )
- {
- case WM_SIZE:
- {
- LRESULT lRet = CallWindowProc( pBtn->_pfnBuddy, hwnd, nMsg, wParam, lParam );
- if( !pBtn->_fInLayout )
- pBtn->DoLayout();
- return lRet;
- }
- case WM_DESTROY:
- {
- WNDPROC pfn = pBtn->_pfnBuddy;
- pBtn->SetBuddy( NULL, 0 );
- return CallWindowProc( pfn, hwnd, nMsg, wParam, lParam );
- }
- break;
- }
- return pBtn->_pfnBuddy ? CallWindowProc( pBtn->_pfnBuddy, hwnd, nMsg, wParam, lParam ) :
- 0L;
- }
- //-------------------------------------------------------------------------//
- // CAccessibleBase IUnknown impl
- STDMETHODIMP CAccessibleBase::QueryInterface( REFIID riid, void** ppvObj )
- {
- HRESULT hres;
- static const QITAB qit[] =
- {
- QITABENT(CAccessibleBase, IDispatch),
- QITABENT(CAccessibleBase, IAccessible),
- QITABENT(CAccessibleBase, IOleWindow),
- { 0 },
- };
- hres = QISearch(this, (LPCQITAB)qit, riid, ppvObj);
- return hres;
- }
- STDMETHODIMP_(ULONG) CAccessibleBase::AddRef()
- {
- return InterlockedIncrement( (LONG*)&_cRef );
- }
- STDMETHODIMP_(ULONG) CAccessibleBase::Release()
- {
- ULONG cRef = InterlockedDecrement( (LONG*)&_cRef );
- if( cRef <= 0 )
- {
- DllRelease();
- delete this;
- }
- return cRef;
- }
- //-------------------------------------------------------------------------//
- // CAccessibleBase IOleWindow impl
- STDMETHODIMP CAccessibleBase::GetWindow( HWND* phwnd )
- {
- *phwnd = _hwnd;
- return IsWindow( _hwnd ) ? S_OK : S_FALSE;
- }
- //-------------------------------------------------------------------------//
- // CAccessibleBase IDispatch impl
- //-------------------------------------------------------------------------//
- static BOOL _accLoadTypeInfo( ITypeInfo** ppti )
- {
- ITypeLib* ptl;
- HRESULT hr = LoadTypeLib(L"oleacc.dll", &ptl);
- if( SUCCEEDED( hr ) )
- {
- hr = ptl->GetTypeInfoOfGuid( IID_IAccessible, ppti );
- ATOMICRELEASE( ptl );
- }
- return hr;
- }
- STDMETHODIMP CAccessibleBase::GetTypeInfoCount( UINT * pctinfo )
- {
- *pctinfo = 1;
- return S_OK;
- }
- STDMETHODIMP CAccessibleBase::GetTypeInfo( UINT itinfo, LCID lcid, ITypeInfo** pptinfo )
- {
- HRESULT hr = E_FAIL;
- if( NULL == _ptiAcc && FAILED( (hr = _accLoadTypeInfo( &_ptiAcc )) ) )
- return hr;
- *pptinfo = _ptiAcc;
- (*pptinfo)->AddRef();
- return S_OK;
- }
- STDMETHODIMP CAccessibleBase::GetIDsOfNames(
- REFIID riid,
- OLECHAR** rgszNames,
- UINT cNames,
- LCID lcid, DISPID * rgdispid )
- {
- HRESULT hr = E_FAIL;
- if( IID_NULL != riid && IID_IAccessible != riid )
- return DISP_E_UNKNOWNINTERFACE;
- if( NULL == _ptiAcc && FAILED( (hr = _accLoadTypeInfo( &_ptiAcc )) ) )
- return hr;
- return _ptiAcc->GetIDsOfNames( rgszNames, cNames, rgdispid );
- }
- STDMETHODIMP CAccessibleBase::Invoke(
- DISPID dispidMember,
- REFIID riid,
- LCID lcid,
- WORD wFlags,
- DISPPARAMS * pdispparams,
- VARIANT * pvarResult,
- EXCEPINFO * pexcepinfo,
- UINT * puArgErr )
- {
- HRESULT hr = E_FAIL;
- if( IID_NULL != riid && IID_IAccessible != riid )
- return DISP_E_UNKNOWNINTERFACE;
- if( NULL == _ptiAcc && FAILED( (hr = _accLoadTypeInfo( &_ptiAcc )) ) )
- return hr;
- return _ptiAcc->Invoke( this, dispidMember, wFlags, pdispparams,
- pvarResult, pexcepinfo, puArgErr );
- }
- STDMETHODIMP CAccessibleBase::get_accParent( IDispatch ** ppdispParent )
- {
- *ppdispParent = NULL;
- if( IsWindow(_hwnd) )
- return AccessibleObjectFromWindow( _hwnd, OBJID_WINDOW,
- IID_IDispatch, (void **)ppdispParent );
- return S_FALSE;
- }
- STDMETHODIMP CAccessibleBase::get_accChildCount( long * pcChildren )
- {
- *pcChildren = 0;
- return S_OK;
- }
- STDMETHODIMP CAccessibleBase::get_accChild( VARIANT varChildIndex, IDispatch ** ppdispChild)
- {
- *ppdispChild = NULL;
- return S_FALSE;
- }
- STDMETHODIMP CAccessibleBase::get_accValue( VARIANT varChild, BSTR* pbstrValue)
- {
- VALIDATEACCCHILD( varChild, CHILDID_SELF, E_INVALIDARG );
- *pbstrValue = NULL;
- return S_FALSE;
- }
- STDMETHODIMP CAccessibleBase::get_accDescription( VARIANT varChild, BSTR * pbstrDescription)
- {
- VALIDATEACCCHILD( varChild, CHILDID_SELF, E_INVALIDARG );
- *pbstrDescription = NULL;
- return S_FALSE;
- }
- STDMETHODIMP CAccessibleBase::get_accRole( VARIANT varChild, VARIANT *pvarRole )
- {
- VALIDATEACCCHILD( varChild, CHILDID_SELF, E_INVALIDARG );
- pvarRole->vt = VT_I4;
- pvarRole->lVal = ROLE_SYSTEM_LINK;
- return S_OK;
- }
- STDMETHODIMP CAccessibleBase::get_accState( VARIANT varChild, VARIANT *pvarState )
- {
- VALIDATEACCCHILD( varChild, CHILDID_SELF, E_INVALIDARG );
- pvarState->vt = VT_I4;
- pvarState->lVal = STATE_SYSTEM_DEFAULT ;
- if( GetFocus() == _hwnd )
- pvarState->lVal |= STATE_SYSTEM_FOCUSED;
- else if( IsWindowEnabled( _hwnd ) )
- pvarState->lVal |= STATE_SYSTEM_FOCUSABLE;
- if( !IsWindowVisible( _hwnd ) )
- pvarState->lVal |= STATE_SYSTEM_INVISIBLE;
- return S_OK;
- }
- STDMETHODIMP CAccessibleBase::get_accHelp( VARIANT varChild, BSTR* pbstrHelp )
- {
- VALIDATEACCCHILD( varChild, CHILDID_SELF, E_INVALIDARG );
- *pbstrHelp = NULL;
- return S_FALSE;
- }
- STDMETHODIMP CAccessibleBase::get_accHelpTopic( BSTR* pbstrHelpFile, VARIANT varChild, long* pidTopic )
- {
- VALIDATEACCCHILD( varChild, CHILDID_SELF, E_INVALIDARG );
- *pbstrHelpFile = NULL;
- *pidTopic = -1;
- return S_FALSE;
- }
- STDMETHODIMP CAccessibleBase::get_accKeyboardShortcut( VARIANT varChild, BSTR* pbstrKeyboardShortcut )
- {
- VALIDATEACCCHILD( varChild, CHILDID_SELF, E_INVALIDARG );
- *pbstrKeyboardShortcut = NULL;
- return S_FALSE;
- }
- STDMETHODIMP CAccessibleBase::get_accFocus( VARIANT FAR * pvarFocusChild )
- {
- HWND hwndFocus;
- if( (hwndFocus = GetFocus()) == _hwnd || IsChild( _hwnd, hwndFocus ) )
- {
- pvarFocusChild->vt = VT_I4;
- pvarFocusChild->lVal = CHILDID_SELF;
- return S_OK;
- }
- return S_FALSE;
- }
- STDMETHODIMP CAccessibleBase::get_accSelection( VARIANT FAR * pvarSelectedChildren )
- {
- return get_accFocus( pvarSelectedChildren ); // implemented same as focus.
- }
- STDMETHODIMP CAccessibleBase::get_accDefaultAction( VARIANT varChild, BSTR* pbstrDefaultAction )
- {
- VALIDATEACCCHILD( varChild, CHILDID_SELF, E_INVALIDARG );
- WCHAR wsz[128];
- if( LoadStringW( HINST_THISDLL, GetDefaultActionStringID(), wsz, ARRAYSIZE(wsz) ) )
- {
- if( NULL == (*pbstrDefaultAction = SysAllocString( wsz )) )
- return E_OUTOFMEMORY;
- return S_OK;
- }
- return E_FAIL;
- }
- STDMETHODIMP CAccessibleBase::accSelect( long flagsSelect, VARIANT varChild )
- {
- VALIDATEACCCHILD( varChild, CHILDID_SELF, E_INVALIDARG );
- if( flagsSelect & SELFLAG_TAKEFOCUS )
- {
- SetFocus( _hwnd );
- return S_OK;
- }
- return S_FALSE;
- }
- STDMETHODIMP CAccessibleBase::accLocation( long* pxLeft, long* pyTop, long* pcxWidth, long* pcyHeight, VARIANT varChild )
- {
- RECT rc;
- GetWindowRect( _hwnd, &rc );
- *pxLeft = rc.left;
- *pyTop = rc.top;
- *pcxWidth = RECTWIDTH(&rc);
- *pcyHeight = RECTHEIGHT(&rc);
- varChild.vt = VT_I4;
- varChild.lVal = CHILDID_SELF;
- return S_OK;
- }
- STDMETHODIMP CAccessibleBase::accNavigate( long navDir, VARIANT varStart, VARIANT * pvarEndUpAt )
- {
- return S_FALSE;
- }
- STDMETHODIMP CAccessibleBase::accHitTest( long xLeft, long yTop, VARIANT * pvarChildAtPoint )
- {
- pvarChildAtPoint->vt = VT_I4;
- pvarChildAtPoint->lVal = CHILDID_SELF;
- return S_OK;
- }
- STDMETHODIMP CAccessibleBase::put_accName( VARIANT varChild, BSTR bstrName )
- {
- VALIDATEACCCHILD( varChild, CHILDID_SELF, E_INVALIDARG );
- return S_FALSE;
- }
- STDMETHODIMP CAccessibleBase::put_accValue( VARIANT varChild, BSTR bstrValue )
- {
- VALIDATEACCCHILD( varChild, CHILDID_SELF, E_INVALIDARG );
- return S_FALSE;
- }
- #ifdef KEYBOARDCUES
- //-------------------------------------------------------------------------//
- // KEYBOARDCUES helpes
- BOOL _HandleWM_UPDATEUISTATE(
- IN WPARAM wParam,
- IN LPARAM lParam,
- IN OUT UINT* puFlags )
- {
- UINT uFlags = *puFlags;
- switch( LOWORD(wParam) )
- {
- case UIS_CLEAR:
- *puFlags &= ~(HIWORD(wParam));
- break;
- case UIS_SET:
- *puFlags |= HIWORD(wParam);
- break;
- }
- return uFlags != *puFlags;
- }
- void _InitializeUISTATE( IN HWND hwnd, IN OUT UINT* puFlags )
- {
- HWND hwndParent = GetParent( hwnd );
- *puFlags = (UINT)SendMessage( hwndParent, WM_QUERYUISTATE, 0, 0L );
- }
- #endif//KEYBOARDCUES