home *** CD-ROM | disk | FTP | other *** search
- /*----------------------------------------------------------------------
- Copyright (c) Gipsysoft. All Rights Reserved.
- File: DialogSizer_Set.cpp
- Web site: http://gipsysoft.com
-
- This software is provided 'as-is', without any express or implied warranty.
-
- In no event will the author be held liable for any damages arising from the
- use of this software.
-
- Permission is granted to anyone to use this software for any purpose, including
- commercial applications, and to alter it and redistribute it freely, subject
- to the following restrictions:
-
- 1) The origin of this software must not be misrepresented; you must not claim
- that you wrote the original software. If you use this software in a product,
- an acknowledgment in the product documentation is requested but not required.
- 2) Altered source versions must be plainly marked as such, and must not be
- misrepresented as being the original software. Altered source is encouraged
- to be submitted back to the original author so it can be shared with the
- community. Please share your changes.
- 3) This notice may not be removed or altered from any source distribution.
-
- Owner: russf@gipsysoft.com
- Purpose: Main functionality for sizeable dialogs
-
- Store a local copy of the user settings
- Subclass the window
- Respond to various messages withinn the subclassed window.
-
- ----------------------------------------------------------------------*/
- #include "stdafx.h"
- #include "VBA.h"
- #include "ResizeDlg.h"
- #undef ASSERT
- #include "WinHelper.h"
-
- // moved functions to this file to reduce number of files
-
- struct RegistryData
- {
- WINDOWPLACEMENT m_wpl;
- };
-
-
- struct DialogData // dd
- {
- HKEY hkRootSave;
- LPCTSTR pcszName;
-
- //
- // The number of items contained in the psd member.
- // Used in the DeferWindowPos structure and in allocating memory
- int nItemCount;
- DialogSizerSizingItem *psd;
-
- //
- // We need the smallest to respond to the WM_GETMINMAXINFO message
- POINT m_ptSmallest;
-
- //
- // We don't strictly speaking need to say how big the biggest can be but
- POINT m_ptLargest;
- bool m_bLargestSet;
-
- //
- // we need this to decide how much the window has changed size when we get a WM_SIZE message
- SIZE m_sizeClient;
-
- //
- // Draw the sizing grip...or not
- bool m_bMaximised;
- BOOL m_bShowSizingGrip;
-
- WinHelper::CRect m_rcGrip;
- };
-
- extern bool regEnabled;
- extern const char *regGetINIPath();
-
- void AssertFailed(char *file, int line, char *exp)
- {
- char buffer[1024];
-
- sprintf(buffer, "File %s\nLine %d\nExpression %s\nPress Retry to debug",
- file, line, exp);
- int res = MessageBox(*theApp.m_pMainWnd, buffer, "Assertion failed!",
- MB_ICONHAND | MB_SETFOREGROUND | MB_TASKMODAL |
- MB_ABORTRETRYIGNORE);
-
- if(res == IDRETRY) {
- __asm int 3;
- } else if(res == IDABORT)
- SendMessage(*theApp.m_pMainWnd, WM_QUIT, 0, 0);
- }
-
- void ApiFailure(char *pcszFilename, int nLine, char *pcszExpression )
- {
- const DWORD dwLastError = ::GetLastError();
- LPCTSTR lpMsgBuf;
- (void)::FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER |
- FORMAT_MESSAGE_FROM_SYSTEM |
- FORMAT_MESSAGE_IGNORE_INSERTS,
- NULL, dwLastError,
- MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
- (LPTSTR) &lpMsgBuf, 0, NULL );
-
- char szExeName[ MAX_PATH ];
-
- if( !GetModuleFileName( NULL, szExeName, countof( szExeName ) ) )
- strcpy( szExeName, "<No Program Name>" );
-
-
- char szMessage[ 1024 ];
- _snprintf( szMessage, countof( szMessage )
- , "API VERIFY Failure!"
- "\nProgram: %s"
- "\n"
- "\nFile %s"
- "\nLine %d"
- "\n"
- "\nExpression %s"
- "\n"
- "\nLast Error %d"
- "\n %s"
- "\n\nPress Retry to debug the application"
- , szExeName
- , pcszFilename
- , nLine
- , pcszExpression
- , dwLastError
- , lpMsgBuf
- );
-
- (void)LocalFree( (LPVOID)lpMsgBuf );
- HWND hwndParent = ::GetActiveWindow();
- hwndParent = ::GetLastActivePopup( hwndParent );
- int nCode = ::MessageBoxA( hwndParent,
- szMessage,
- "Debug Helper",
- MB_TASKMODAL | MB_ICONHAND | MB_ABORTRETRYIGNORE |
- MB_SETFOREGROUND );
- if(nCode == IDABORT) {
- ::SendMessage(*theApp.m_pMainWnd, WM_QUIT, 0, 0);
- } else if(nCode == IDRETRY)
- __asm int 3;
- }
-
- long FASTCALL RegQueryValueExRecursive( HKEY hKey, LPCTSTR lpValueName, LPDWORD lpReserved, LPDWORD lpType, LPBYTE lpData, LPDWORD lpcbData )
- {
- TCHAR szBuffer[ 256 ];
- R_ASSERT( lstrlen( lpValueName ) < countof( szBuffer ) );
- (void)lstrcpy( szBuffer, lpValueName );
-
- LPTSTR pszBuffer = szBuffer;
- LPTSTR pszLast = szBuffer;
- while( *pszBuffer )
- {
- if( *pszBuffer == _T('\\') || *pszBuffer == _T('/') )
- {
- pszLast = pszBuffer;
- lpValueName = pszLast + 1;
- }
- pszBuffer++;
- }
-
- if(!regEnabled) {
- if(GetPrivateProfileStruct("Viewer",
- lpValueName,
- lpData,
- *lpcbData,
- regGetINIPath())) {
- *lpType = REG_BINARY;
- return ERROR_SUCCESS;
- }
- return -1;
- }
-
- bool m_bNeedToCloseKey = false;
- if( pszLast != szBuffer )
- {
- *pszLast = _T('\000');
- HKEY hkeyTemp;
- long lRet = RegOpenKey( hKey, szBuffer, &hkeyTemp );
- if( lRet != ERROR_SUCCESS )
- {
- return lRet;
- }
- hKey = hkeyTemp;
- m_bNeedToCloseKey = true;
- }
-
- long lRet = RegQueryValueEx( hKey, lpValueName, lpReserved, lpType, lpData, lpcbData );
- if( m_bNeedToCloseKey )
- {
- R_VERIFY( RegCloseKey( hKey ) == ERROR_SUCCESS );
- }
- return lRet;
- }
-
- long FASTCALL RegSetValueExRecursive( HKEY hKey, LPCTSTR lpValueName, DWORD Reserved, DWORD dwType, CONST BYTE* lpData, DWORD cbData )
- {
- TCHAR szBuffer[ 256 ];
- R_ASSERT( lstrlen( lpValueName ) < countof( szBuffer ) );
- (void)lstrcpy( szBuffer, lpValueName );
-
- LPTSTR pszBuffer = szBuffer;
- LPTSTR pszLast = szBuffer;
- while( *pszBuffer )
- {
- if( *pszBuffer == _T('\\') || *pszBuffer == _T('/') )
- {
- pszLast = pszBuffer;
- lpValueName = pszLast + 1;
- }
- pszBuffer++;
- }
-
- if(!regEnabled) {
- if(WritePrivateProfileStruct("Viewer",
- lpValueName,
- (LPVOID)lpData,
- cbData,
- regGetINIPath())) {
- return ERROR_SUCCESS;
- }
- return -1;
- }
-
- bool m_bNeedToCloseKey = false;
- if( pszLast != szBuffer )
- {
- *pszLast = _T('\000');
- HKEY hkeyTemp;
- long lRet = RegOpenKey( hKey, szBuffer, &hkeyTemp );
- if( lRet != ERROR_SUCCESS )
- {
- lRet = RegCreateKey( hKey, szBuffer, &hkeyTemp );
- if( lRet != ERROR_SUCCESS )
- return lRet;
- }
- hKey = hkeyTemp;
- m_bNeedToCloseKey = true;
- }
-
- long lRet = RegSetValueEx( hKey, lpValueName, Reserved, dwType, lpData, cbData );
- if( m_bNeedToCloseKey )
- {
- R_VERIFY( RegCloseKey( hKey ) == ERROR_SUCCESS );
- }
- return lRet;
- }
-
-
- int ResizeDlgGetItemCount(const DialogSizerSizingItem *psd)
- {
- R_ASSERT( psd );
- int nCount = 0;
- while( psd->uSizeInfo != 0xFFFFFFFF )
- {
- nCount++;
- psd++;
- }
- return nCount;
- }
-
- void ResizeDlgUpdateGripperRect( const int cx, const int cy, WinHelper::CRect &rcGrip )
- {
- const int nGripWidth = GetSystemMetrics( SM_CYVSCROLL );
- const int nGripHeight = GetSystemMetrics( SM_CXVSCROLL );
- rcGrip.left = cx - nGripWidth;
- rcGrip.top = cy - nGripHeight;
- rcGrip.right = cx;
- rcGrip.bottom = cy;
- }
-
- void ResizeDlgUpdateGripper( HWND hwnd, DialogData *pdd )
- {
- if( pdd->m_bShowSizingGrip )
- {
- WinHelper::CRect rcOld( pdd->m_rcGrip );
-
- ResizeDlgUpdateGripperRect( pdd->m_sizeClient.cx, pdd->m_sizeClient.cy, pdd->m_rcGrip );
-
- //
- // We also need to invalidate the combined area of the old and new rectangles
- // otherwise we would have trail of grippers when we sized the dialog larger
- // in any axis
- (void)UnionRect( &rcOld, &rcOld, &pdd->m_rcGrip );
- (void)InvalidateRect( hwnd, &rcOld, TRUE );
- }
- }
-
- void ResizeDlgCopyItems( DialogSizerSizingItem *psdDest, const DialogSizerSizingItem *psdSource )
- //
- // Will copy all of the items in psdSource into psdDest.
- {
- //
- // Loop til we reach the end
- while( psdSource->uSizeInfo != 0xFFFFFFFF )
- {
- *psdDest = *psdSource;
- psdDest++;
- psdSource++;
- }
- // And when we do copy the last item
- *psdDest = *psdSource;
- }
-
-
- ResizeDlg::ResizeDlg(UINT id, CWnd *parent)
- : CDialog(id, parent)
- {
- dd = NULL;
- }
-
- void *ResizeDlg::AddDialogData()
- //
- // Firstly determine if the data already exists, if it does then return that, if not then we will
- // create and initialise a brand new structure.
- {
- DialogData *pdd = (DialogData*)dd;
- if( !pdd ) {
- pdd = (DialogData *)calloc(1, sizeof(DialogData));
- }
-
- if( pdd ) {
- //
- // Store some sizes etc. for later.
- CRect rc;
- GetWindowRect( rc );
- pdd->m_ptSmallest.x = rc.Width();
- pdd->m_ptSmallest.y = rc.Height();
-
-
- GetClientRect( rc );
- pdd->m_sizeClient = rc.Size();
- dd = pdd;
- ResizeDlgUpdateGripperRect( pdd->m_sizeClient.cx, pdd->m_sizeClient.cy, pdd->m_rcGrip );
- }
- return pdd;
- }
-
- BOOL ResizeDlg::SetData(const DialogSizerSizingItem *psd,
- BOOL bShowSizingGrip,
- HKEY hkRootSave,
- LPCTSTR pcszName,
- SIZE *psizeMax)
- //
- // Setting a dialog sizeable involves subclassing the window and handling it's
- // WM_SIZE messages, if we have a hkRootSave and pcszName then we will also be loading/saving
- // the size and position of the window from the registry. We load from the registry when we
- // subclass the window and we save to the registry when we get a WM_DESTROY.
- //
- // It will return non-zero for success and zero if it fails
- {
- R_ASSERT( psd );
- R_ASSERT( ( hkRootSave != NULL && pcszName != NULL )
- || ( hkRootSave == NULL && pcszName == NULL ) );
- //
- // Make sure all of the parameters are valid.
- if( ::IsWindow( *this )
- && psd
- && ( ( hkRootSave != NULL && pcszName != NULL &&
- !IsBadStringPtr( pcszName, 0xFFFF ) ) ||
- ( hkRootSave == NULL && pcszName == NULL ) )
- && ( psizeMax == NULL || !IsBadReadPtr( psizeMax, sizeof( SIZE ) ) )
- ) {
- DialogData *pdd = (DialogData *)AddDialogData();
- if( pdd ) {
- pdd->hkRootSave = hkRootSave;
- pdd->pcszName = pcszName;
- pdd->m_bShowSizingGrip = bShowSizingGrip;
- pdd->nItemCount = ResizeDlgGetItemCount( psd ) + 1;
- pdd->psd = (DialogSizerSizingItem *)
- calloc(pdd->nItemCount,
- sizeof(DialogSizerSizingItem ));
- if( pdd->psd ) {
- //
- // Copy all of the user controls etc. for later, this way the user can quite happily
- // let the structure go out of scope.
- ResizeDlgCopyItems( pdd->psd, psd );
- if( psizeMax ) {
- pdd->m_ptLargest.x = psizeMax->cx;
- pdd->m_ptLargest.y = psizeMax->cy;
- pdd->m_bLargestSet = true;
- }
-
- //
- // If the there was save info passed in then we need to make damn good use of it
- // by attempting to load the RegistryData structure
- if( hkRootSave && pcszName ) {
- RegistryData rd;
- DWORD dwSize = sizeof( RegistryData );
- DWORD dwType = REG_BINARY;
- if( RegQueryValueExRecursive( hkRootSave, pcszName, NULL, &dwType, reinterpret_cast<LPBYTE>( &rd ), &dwSize ) == ERROR_SUCCESS && dwSize == sizeof( rd ) ) {
- if( !(GetWindowLong( *this, GWL_STYLE ) & WS_VISIBLE) )
- rd.m_wpl.showCmd = SW_HIDE;
-
- VAPI( SetWindowPlacement( &rd.m_wpl ) );
- }
- }
- return TRUE;
- } else {
- free(pdd);
- }
- }
- }
- return FALSE;
- }
-
- void ResizeDlg::UpdateWindowSize(const int cx, const int cy, HWND hwnd)
- {
- DialogData *pdd = (DialogData*)dd;
- if( pdd ) {
- const int nDeltaX = cx - pdd->m_sizeClient.cx;
- const int nDeltaY = cy - pdd->m_sizeClient.cy;
- WinHelper::CDeferWindowPos def( pdd->nItemCount );
- WinHelper::CRect rc;
- const DialogSizerSizingItem *psd = pdd->psd;
- while( psd->uSizeInfo != 0xFFFFFFFF ) {
- HWND hwndChild = ::GetDlgItem( *this, psd->uControlID );
- if( ::IsWindow( hwndChild ) ) {
- VAPI( ::GetWindowRect( hwndChild, rc ) );
- (void)::MapWindowPoints( ::GetDesktopWindow(), hwnd,
- (LPPOINT)&rc, 2 );
-
- //
- // Adjust the window horizontally
- if( psd->uSizeInfo & DS_MoveX ) {
- rc.left += nDeltaX;
- rc.right += nDeltaX;
- }
-
- //
- // Adjust the window vertically
- if( psd->uSizeInfo & DS_MoveY ) {
- rc.top += nDeltaY;
- rc.bottom += nDeltaY;
- }
-
- //
- // Size the window horizontally
- if( psd->uSizeInfo & DS_SizeX ) {
- rc.right += nDeltaX;
- }
-
- //
- // Size the window vertically
- if( psd->uSizeInfo & DS_SizeY ) {
- rc.bottom += nDeltaY;
- }
-
- (void)def.DeferWindowPos( hwndChild, NULL, rc,
- SWP_NOACTIVATE | SWP_NOZORDER );
- }
- psd++;
- }
-
- pdd->m_sizeClient.cx = cx;
- pdd->m_sizeClient.cy = cy;
-
- //
- // If we have a sizing grip enabled then adjust it's position
- ResizeDlgUpdateGripper( hwnd, pdd );
- }
- }
-
- BOOL ResizeDlg::OnWndMsg(UINT msg, WPARAM wParam, LPARAM lParam, LRESULT *res )
- // Actual window procedure that will handle saving window size/position and moving
- // the controls whilst the window sizes.
- {
- if(dd == NULL) {
- return CDialog::OnWndMsg(msg, wParam, lParam, res);
- }
- switch( msg ) {
- case WM_ERASEBKGND:
- {
- BOOL r = CDialog::OnWndMsg(msg, wParam, lParam, res);
- DialogData *pdd = (DialogData*)dd;
- if( pdd && pdd->m_bShowSizingGrip && !pdd->m_bMaximised ) {
- VAPI( ::DrawFrameControl( reinterpret_cast<HDC>( wParam ),
- pdd->m_rcGrip,
- DFC_SCROLL, DFCS_SCROLLSIZEGRIP ) );
- }
- return r;
- }
- case WM_SIZE:
- {
- DialogData *pdd = (DialogData*)dd;
- if( pdd && wParam != SIZE_MINIMIZED ) {
- pdd->m_bMaximised = ( wParam == SIZE_MAXIMIZED ? true : false );
- UpdateWindowSize( LOWORD( lParam ), HIWORD( lParam ), *this);
- }
- }
- break;
- case WM_NCHITTEST:
- {
- //
- // If the gripper is enabled then perform a simple hit test on our gripper area.
- DialogData *pdd = (DialogData*)dd;
- if( pdd && pdd->m_bShowSizingGrip ) {
- POINT pt = { LOWORD(lParam), HIWORD(lParam) };
- (void)ScreenToClient( &pt );
- if( PtInRect( pdd->m_rcGrip, pt ) )
- return (BOOL)HTBOTTOMRIGHT;
- }
- }
- break;
- case WM_GETMINMAXINFO:
- {
- //
- // Our opportunity to say that we do not want the dialog to grow or shrink any more.
- DialogData *pdd = (DialogData*)dd;
- LPMINMAXINFO lpmmi = reinterpret_cast<LPMINMAXINFO>( lParam );
- lpmmi->ptMinTrackSize = pdd->m_ptSmallest;
- if( pdd->m_bLargestSet ) {
- lpmmi->ptMaxTrackSize = pdd->m_ptLargest;
- }
- }
- return (BOOL)0;
- case WM_NOTIFY:
- {
- if( reinterpret_cast<LPNMHDR>(lParam)->code == PSN_SETACTIVE ) {
- CRect rc;
- VAPI( ::GetClientRect( *GetParent( ), &rc ) );
- UpdateWindowSize( rc.Width(), rc.Height(), *GetParent( ) );
- }
- }
- break;
- case WM_DESTROY:
- {
- //
- // Our opportunty for cleanup.
- // Simply acquire all of our objects, free the appropriate memory and remove the
- // properties from the window. If we do not remove the properties then they will constitute
- // a resource leak.
- DialogData *pdd = (DialogData*)dd;
- if( pdd ) {
- RegistryData rd;
- rd.m_wpl.length = sizeof( rd.m_wpl );
- VAPI( GetWindowPlacement( &rd.m_wpl ) );
-
- if( pdd->hkRootSave && pdd->pcszName ) {
- (void)RegSetValueExRecursive( pdd->hkRootSave, pdd->pcszName,
- NULL, REG_BINARY,
- reinterpret_cast<LPBYTE>( &rd ),
- sizeof( rd ) );
- }
-
- if( pdd->psd ) {
- free(pdd->psd);
- }
- free(pdd);
- }
-
- }
- break;
- }
- return CDialog::OnWndMsg(msg, wParam, lParam, res);
- }
-