home *** CD-ROM | disk | FTP | other *** search
/ Chip 2004 July / CMCD0704.ISO / Software / Freeware / Utilitare / VisualBoyAdvance-1.7.2 / src / win32 / ResizeDlg.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2003-11-04  |  16.8 KB  |  562 lines

  1. /*----------------------------------------------------------------------
  2.   Copyright (c)  Gipsysoft. All Rights Reserved.
  3.   File:   DialogSizer_Set.cpp
  4.   Web site: http://gipsysoft.com
  5.  
  6.   This software is provided 'as-is', without any express or implied warranty.
  7.  
  8.   In no event will the author be held liable for any damages arising from the
  9.   use of this software.
  10.  
  11.   Permission is granted to anyone to use this software for any purpose, including
  12.   commercial applications, and to alter it and redistribute it freely, subject
  13.   to the following restrictions: 
  14.  
  15.   1) The origin of this software must not be misrepresented; you must not claim
  16.   that you wrote the original software. If you use this software in a product,
  17.   an acknowledgment in the product documentation is requested but not required. 
  18.   2) Altered source versions must be plainly marked as such, and must not be
  19.   misrepresented as being the original software. Altered source is encouraged
  20.   to be submitted back to the original author so it can be shared with the
  21.   community. Please share your changes.
  22.   3) This notice may not be removed or altered from any source distribution.
  23.  
  24.   Owner:  russf@gipsysoft.com
  25.   Purpose:        Main functionality for sizeable dialogs
  26.  
  27.   Store a local copy of the user settings
  28.   Subclass the window
  29.   Respond to various messages withinn the subclassed window.
  30.  
  31.   ----------------------------------------------------------------------*/
  32. #include "stdafx.h"
  33. #include "VBA.h"
  34. #include "ResizeDlg.h"
  35. #undef ASSERT
  36. #include "WinHelper.h"
  37.  
  38. // moved functions to this file to reduce number of files
  39.  
  40. struct RegistryData
  41. {
  42.   WINDOWPLACEMENT       m_wpl;
  43. };
  44.  
  45.  
  46. struct DialogData       //      dd
  47. {
  48.   HKEY hkRootSave;
  49.   LPCTSTR pcszName;
  50.  
  51.   //
  52.   //    The number of items contained in the psd member.
  53.   //    Used in the DeferWindowPos structure and in allocating memory
  54.   int nItemCount;
  55.   DialogSizerSizingItem *psd;
  56.  
  57.   //
  58.   //    We need the smallest to respond to the WM_GETMINMAXINFO message
  59.   POINT m_ptSmallest;
  60.  
  61.   //
  62.   //    We don't strictly speaking need to say how big the biggest can be but
  63.   POINT m_ptLargest;
  64.   bool m_bLargestSet;
  65.  
  66.   //
  67.   //    we need this to decide how much the window has changed size when we get a WM_SIZE message
  68.   SIZE m_sizeClient;
  69.  
  70.   //
  71.   //    Draw the sizing grip...or not
  72.   bool m_bMaximised;
  73.   BOOL m_bShowSizingGrip;
  74.  
  75.   WinHelper::CRect m_rcGrip;
  76. };
  77.  
  78. extern bool regEnabled;
  79. extern const char *regGetINIPath();
  80.  
  81. void AssertFailed(char *file, int line, char *exp)
  82. {
  83.   char buffer[1024];
  84.  
  85.   sprintf(buffer, "File %s\nLine %d\nExpression %s\nPress Retry to debug",
  86.           file, line, exp);
  87.   int res = MessageBox(*theApp.m_pMainWnd, buffer, "Assertion failed!",
  88.                        MB_ICONHAND | MB_SETFOREGROUND | MB_TASKMODAL |
  89.                        MB_ABORTRETRYIGNORE);
  90.  
  91.   if(res == IDRETRY) {
  92.     __asm int 3;
  93.   } else if(res == IDABORT)
  94.     SendMessage(*theApp.m_pMainWnd, WM_QUIT, 0, 0);
  95. }
  96.  
  97. void ApiFailure(char *pcszFilename, int nLine, char *pcszExpression )
  98. {
  99.   const DWORD dwLastError = ::GetLastError();
  100.   LPCTSTR lpMsgBuf;
  101.   (void)::FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER |
  102.                          FORMAT_MESSAGE_FROM_SYSTEM |
  103.                          FORMAT_MESSAGE_IGNORE_INSERTS,
  104.                          NULL, dwLastError,
  105.                          MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  106.                          (LPTSTR) &lpMsgBuf, 0, NULL );
  107.   
  108.   char szExeName[ MAX_PATH ];
  109.   
  110.   if( !GetModuleFileName( NULL, szExeName, countof( szExeName ) ) )
  111.     strcpy( szExeName, "<No Program Name>" );
  112.   
  113.   
  114.   char szMessage[ 1024 ];
  115.   _snprintf( szMessage, countof( szMessage )
  116.              , "API VERIFY Failure!"
  117.              "\nProgram: %s"
  118.              "\n"
  119.              "\nFile %s"
  120.              "\nLine %d"
  121.              "\n"
  122.              "\nExpression %s"
  123.              "\n"
  124.              "\nLast Error %d"
  125.              "\n           %s"
  126.              "\n\nPress Retry to debug the application"
  127.              , szExeName
  128.              , pcszFilename
  129.              , nLine
  130.              , pcszExpression
  131.              , dwLastError
  132.              , lpMsgBuf
  133.              );
  134.   
  135.   (void)LocalFree( (LPVOID)lpMsgBuf );
  136.   HWND hwndParent = ::GetActiveWindow();
  137.   hwndParent = ::GetLastActivePopup( hwndParent );
  138.   int nCode = ::MessageBoxA( hwndParent,
  139.                              szMessage,
  140.                              "Debug Helper",
  141.                              MB_TASKMODAL | MB_ICONHAND | MB_ABORTRETRYIGNORE |
  142.                              MB_SETFOREGROUND );
  143.   if(nCode == IDABORT) {
  144.     ::SendMessage(*theApp.m_pMainWnd, WM_QUIT, 0, 0);
  145.   } else if(nCode == IDRETRY)
  146.     __asm int 3;
  147. }
  148.  
  149. long FASTCALL RegQueryValueExRecursive( HKEY hKey, LPCTSTR lpValueName, LPDWORD lpReserved, LPDWORD lpType, LPBYTE lpData, LPDWORD lpcbData )
  150. {
  151.   TCHAR szBuffer[ 256 ];
  152.   R_ASSERT( lstrlen( lpValueName ) < countof( szBuffer ) );
  153.   (void)lstrcpy( szBuffer, lpValueName );
  154.   
  155.   LPTSTR pszBuffer = szBuffer;
  156.   LPTSTR pszLast = szBuffer;
  157.   while( *pszBuffer )
  158.     {
  159.       if( *pszBuffer == _T('\\') || *pszBuffer == _T('/') )
  160.         {
  161.           pszLast = pszBuffer;
  162.           lpValueName = pszLast + 1;
  163.         }
  164.       pszBuffer++;
  165.     }
  166.  
  167.   if(!regEnabled) {
  168.     if(GetPrivateProfileStruct("Viewer",
  169.                                lpValueName,
  170.                                lpData,
  171.                                *lpcbData,
  172.                                regGetINIPath())) {
  173.       *lpType = REG_BINARY;
  174.       return ERROR_SUCCESS;
  175.     }
  176.     return -1;
  177.   }
  178.   
  179.   bool m_bNeedToCloseKey = false;
  180.   if( pszLast != szBuffer )
  181.     {
  182.       *pszLast = _T('\000');
  183.       HKEY hkeyTemp;
  184.       long lRet = RegOpenKey( hKey, szBuffer, &hkeyTemp );
  185.       if( lRet != ERROR_SUCCESS )
  186.         {
  187.           return lRet;
  188.         }
  189.       hKey = hkeyTemp;
  190.       m_bNeedToCloseKey = true;
  191.     }
  192.   
  193.   long lRet = RegQueryValueEx( hKey, lpValueName, lpReserved, lpType, lpData, lpcbData );
  194.   if( m_bNeedToCloseKey )
  195.     {
  196.       R_VERIFY( RegCloseKey( hKey ) == ERROR_SUCCESS );
  197.     }
  198.   return lRet;
  199. }
  200.  
  201. long FASTCALL RegSetValueExRecursive( HKEY hKey, LPCTSTR lpValueName, DWORD Reserved, DWORD dwType, CONST BYTE* lpData, DWORD cbData )
  202. {
  203.   TCHAR szBuffer[ 256 ];
  204.   R_ASSERT( lstrlen( lpValueName ) < countof( szBuffer ) );
  205.   (void)lstrcpy( szBuffer, lpValueName );
  206.   
  207.   LPTSTR pszBuffer = szBuffer;
  208.   LPTSTR pszLast = szBuffer;
  209.   while( *pszBuffer )
  210.     {
  211.       if( *pszBuffer == _T('\\') || *pszBuffer == _T('/') )
  212.         {
  213.           pszLast = pszBuffer;
  214.           lpValueName = pszLast + 1;
  215.         }
  216.       pszBuffer++;
  217.     }
  218.  
  219.   if(!regEnabled) {
  220.     if(WritePrivateProfileStruct("Viewer",
  221.                                  lpValueName,
  222.                                  (LPVOID)lpData,
  223.                                  cbData,
  224.                                  regGetINIPath())) {
  225.       return ERROR_SUCCESS;
  226.     }
  227.     return -1;
  228.   }
  229.   
  230.   bool m_bNeedToCloseKey = false;
  231.   if( pszLast != szBuffer )
  232.     {
  233.       *pszLast = _T('\000');
  234.       HKEY hkeyTemp;
  235.       long lRet = RegOpenKey( hKey, szBuffer, &hkeyTemp );
  236.       if( lRet != ERROR_SUCCESS )
  237.         {
  238.           lRet = RegCreateKey( hKey, szBuffer, &hkeyTemp );
  239.           if( lRet != ERROR_SUCCESS )
  240.             return lRet;
  241.         }
  242.       hKey = hkeyTemp;
  243.       m_bNeedToCloseKey = true;
  244.     }
  245.   
  246.   long lRet = RegSetValueEx( hKey, lpValueName, Reserved, dwType, lpData, cbData );
  247.   if( m_bNeedToCloseKey )
  248.     {
  249.       R_VERIFY( RegCloseKey( hKey ) == ERROR_SUCCESS );
  250.     }
  251.   return lRet;
  252. }
  253.  
  254.  
  255. int ResizeDlgGetItemCount(const DialogSizerSizingItem *psd)
  256. {
  257.   R_ASSERT( psd );
  258.   int nCount = 0;
  259.   while( psd->uSizeInfo != 0xFFFFFFFF )
  260.     {
  261.       nCount++;
  262.       psd++;
  263.     }
  264.   return nCount;
  265. }
  266.  
  267. void ResizeDlgUpdateGripperRect( const int cx, const int cy, WinHelper::CRect &rcGrip )
  268. {
  269.   const int nGripWidth = GetSystemMetrics( SM_CYVSCROLL );
  270.   const int nGripHeight = GetSystemMetrics( SM_CXVSCROLL );
  271.   rcGrip.left = cx - nGripWidth;
  272.   rcGrip.top = cy - nGripHeight;
  273.   rcGrip.right = cx;
  274.   rcGrip.bottom = cy;
  275. }
  276.  
  277. void ResizeDlgUpdateGripper( HWND hwnd, DialogData *pdd )
  278. {
  279.   if( pdd->m_bShowSizingGrip )
  280.     {
  281.       WinHelper::CRect rcOld( pdd->m_rcGrip );
  282.       
  283.       ResizeDlgUpdateGripperRect( pdd->m_sizeClient.cx, pdd->m_sizeClient.cy, pdd->m_rcGrip );
  284.       
  285.       //
  286.       //        We also need to invalidate the combined area of the old and new rectangles
  287.       //        otherwise we would have trail of grippers when we sized the dialog larger
  288.       //        in any axis
  289.       (void)UnionRect( &rcOld, &rcOld, &pdd->m_rcGrip );
  290.       (void)InvalidateRect( hwnd, &rcOld, TRUE );
  291.     }
  292. }
  293.  
  294. void ResizeDlgCopyItems( DialogSizerSizingItem *psdDest, const DialogSizerSizingItem *psdSource )
  295.   //
  296.   //    Will copy all of the items in psdSource into psdDest.
  297. {
  298.   //
  299.   //    Loop til we reach the end
  300.   while( psdSource->uSizeInfo != 0xFFFFFFFF )
  301.     {
  302.       *psdDest = *psdSource;
  303.       psdDest++;
  304.       psdSource++;
  305.     }
  306.   //    And when we do copy the last item
  307.   *psdDest = *psdSource;
  308. }
  309.  
  310.  
  311. ResizeDlg::ResizeDlg(UINT id, CWnd *parent)
  312.   : CDialog(id, parent)
  313. {
  314.   dd = NULL;
  315. }
  316.  
  317. void *ResizeDlg::AddDialogData()
  318.   //
  319.   //    Firstly determine if the data already exists, if it does then return that, if not then we will
  320.   //    create and initialise a brand new structure.
  321. {
  322.   DialogData *pdd = (DialogData*)dd;
  323.   if( !pdd ) {
  324.     pdd = (DialogData *)calloc(1, sizeof(DialogData));
  325.   }
  326.   
  327.   if( pdd ) {
  328.     //
  329.     //  Store some sizes etc. for later.
  330.     CRect rc;
  331.     GetWindowRect( rc );
  332.     pdd->m_ptSmallest.x = rc.Width();
  333.     pdd->m_ptSmallest.y = rc.Height();
  334.     
  335.     
  336.     GetClientRect( rc );
  337.     pdd->m_sizeClient = rc.Size();
  338.     dd = pdd;
  339.     ResizeDlgUpdateGripperRect( pdd->m_sizeClient.cx, pdd->m_sizeClient.cy, pdd->m_rcGrip );
  340.   }
  341.   return pdd;
  342. }
  343.  
  344. BOOL ResizeDlg::SetData(const DialogSizerSizingItem *psd,
  345.                         BOOL bShowSizingGrip,
  346.                         HKEY hkRootSave,
  347.                         LPCTSTR pcszName,
  348.                         SIZE *psizeMax)
  349.   //
  350.   //    Setting a dialog sizeable involves subclassing the window and handling it's
  351.   //    WM_SIZE messages, if we have a hkRootSave and pcszName then we will also be loading/saving
  352.   //    the size and position of the window from the registry. We load from the registry when we 
  353.   //    subclass the window and we save to the registry when we get a WM_DESTROY.
  354.   //
  355.   //    It will return non-zero for success and zero if it fails
  356. {
  357.   R_ASSERT( psd );
  358.   R_ASSERT( ( hkRootSave != NULL && pcszName != NULL )
  359.             || ( hkRootSave == NULL && pcszName == NULL ) );
  360.   //
  361.   //    Make sure all of the parameters are valid.
  362.   if( ::IsWindow( *this )
  363.       && psd
  364.       && ( ( hkRootSave != NULL && pcszName != NULL &&
  365.              !IsBadStringPtr( pcszName, 0xFFFF ) ) ||
  366.            ( hkRootSave == NULL && pcszName == NULL ) )
  367.       && ( psizeMax == NULL || !IsBadReadPtr( psizeMax, sizeof( SIZE ) ) )
  368.       ) {
  369.     DialogData *pdd = (DialogData *)AddDialogData();
  370.     if( pdd ) {
  371.       pdd->hkRootSave = hkRootSave;
  372.       pdd->pcszName = pcszName;
  373.       pdd->m_bShowSizingGrip = bShowSizingGrip;
  374.       pdd->nItemCount = ResizeDlgGetItemCount( psd ) + 1;
  375.       pdd->psd = (DialogSizerSizingItem *)
  376.         calloc(pdd->nItemCount,
  377.                sizeof(DialogSizerSizingItem ));
  378.       if( pdd->psd ) {
  379.         //
  380.         //      Copy all of the user controls etc. for later, this way the user can quite happily
  381.         //      let the structure go out of scope.
  382.         ResizeDlgCopyItems( pdd->psd, psd );
  383.         if( psizeMax ) {
  384.           pdd->m_ptLargest.x = psizeMax->cx;
  385.           pdd->m_ptLargest.y = psizeMax->cy;
  386.           pdd->m_bLargestSet = true;
  387.         }
  388.         
  389.         //
  390.         //      If the there was save info passed in then we need to make damn good use of it
  391.         //      by attempting to load the RegistryData structure 
  392.         if( hkRootSave && pcszName ) {
  393.           RegistryData rd;
  394.           DWORD dwSize = sizeof( RegistryData );
  395.           DWORD dwType = REG_BINARY;
  396.           if( RegQueryValueExRecursive( hkRootSave, pcszName, NULL, &dwType, reinterpret_cast<LPBYTE>( &rd ), &dwSize ) == ERROR_SUCCESS && dwSize == sizeof( rd ) ) {
  397.             if( !(GetWindowLong( *this, GWL_STYLE ) & WS_VISIBLE) )
  398.               rd.m_wpl.showCmd = SW_HIDE;
  399.             
  400.             VAPI( SetWindowPlacement( &rd.m_wpl ) );
  401.           }
  402.         }
  403.         return TRUE;
  404.       } else {
  405.         free(pdd);
  406.       }
  407.     }
  408.   }
  409.   return FALSE;
  410. }
  411.  
  412. void ResizeDlg::UpdateWindowSize(const int cx, const int cy, HWND hwnd)
  413. {
  414.   DialogData *pdd = (DialogData*)dd;
  415.   if( pdd ) {
  416.     const int nDeltaX = cx - pdd->m_sizeClient.cx;
  417.     const int nDeltaY = cy - pdd->m_sizeClient.cy;
  418.     WinHelper::CDeferWindowPos def( pdd->nItemCount );
  419.     WinHelper::CRect rc;
  420.     const DialogSizerSizingItem *psd = pdd->psd;
  421.     while( psd->uSizeInfo != 0xFFFFFFFF ) {
  422.       HWND hwndChild = ::GetDlgItem( *this, psd->uControlID );
  423.       if( ::IsWindow( hwndChild ) ) {
  424.         VAPI( ::GetWindowRect( hwndChild, rc ) );
  425.         (void)::MapWindowPoints( ::GetDesktopWindow(),  hwnd,
  426.                                  (LPPOINT)&rc, 2 );
  427.         
  428.         //
  429.         //      Adjust the window horizontally
  430.         if( psd->uSizeInfo & DS_MoveX ) {
  431.           rc.left += nDeltaX;
  432.           rc.right += nDeltaX;
  433.         }
  434.         
  435.         //
  436.         //      Adjust the window vertically
  437.         if( psd->uSizeInfo & DS_MoveY ) {
  438.           rc.top += nDeltaY;
  439.           rc.bottom += nDeltaY;
  440.         }
  441.         
  442.         //
  443.         //      Size the window horizontally
  444.         if( psd->uSizeInfo & DS_SizeX ) {
  445.           rc.right += nDeltaX;
  446.         }
  447.         
  448.         //
  449.         //      Size the window vertically
  450.         if( psd->uSizeInfo & DS_SizeY ) {
  451.           rc.bottom += nDeltaY;
  452.         }
  453.         
  454.         (void)def.DeferWindowPos( hwndChild, NULL, rc,
  455.                                   SWP_NOACTIVATE | SWP_NOZORDER );
  456.       }
  457.       psd++;
  458.     }
  459.     
  460.     pdd->m_sizeClient.cx = cx;
  461.     pdd->m_sizeClient.cy = cy;
  462.     
  463.     //
  464.     //  If we have a sizing grip enabled then adjust it's position
  465.     ResizeDlgUpdateGripper( hwnd, pdd );
  466.   }
  467. }
  468.  
  469. BOOL ResizeDlg::OnWndMsg(UINT msg, WPARAM wParam, LPARAM lParam, LRESULT *res )
  470.   //    Actual window procedure that will handle saving window size/position and moving
  471.   //    the controls whilst the window sizes.
  472. {
  473.   if(dd == NULL) {
  474.     return CDialog::OnWndMsg(msg, wParam, lParam, res);
  475.   }
  476.   switch( msg ) {
  477.   case WM_ERASEBKGND:
  478.     {
  479.       BOOL r = CDialog::OnWndMsg(msg, wParam, lParam, res);
  480.       DialogData *pdd = (DialogData*)dd;
  481.       if( pdd && pdd->m_bShowSizingGrip && !pdd->m_bMaximised ) {
  482.         VAPI( ::DrawFrameControl( reinterpret_cast<HDC>( wParam ),
  483.                                   pdd->m_rcGrip,
  484.                                   DFC_SCROLL, DFCS_SCROLLSIZEGRIP ) );
  485.       }
  486.       return r;
  487.     }
  488.   case WM_SIZE:
  489.     {
  490.       DialogData *pdd = (DialogData*)dd;
  491.       if( pdd && wParam != SIZE_MINIMIZED ) {
  492.         pdd->m_bMaximised = ( wParam == SIZE_MAXIMIZED ? true : false );
  493.         UpdateWindowSize( LOWORD( lParam ), HIWORD( lParam ), *this);
  494.       }
  495.     }
  496.     break;
  497.   case WM_NCHITTEST:
  498.     {
  499.       //
  500.       //        If the gripper is enabled then perform a simple hit test on our gripper area.
  501.       DialogData *pdd = (DialogData*)dd;
  502.       if( pdd && pdd->m_bShowSizingGrip ) {
  503.         POINT pt = { LOWORD(lParam), HIWORD(lParam) };
  504.         (void)ScreenToClient( &pt );
  505.         if( PtInRect( pdd->m_rcGrip, pt ) )
  506.           return (BOOL)HTBOTTOMRIGHT;
  507.       }
  508.     }
  509.     break;
  510.   case WM_GETMINMAXINFO:
  511.     {
  512.       //
  513.       //        Our opportunity to say that we do not want the dialog to grow or shrink any more.
  514.       DialogData *pdd = (DialogData*)dd;
  515.       LPMINMAXINFO lpmmi = reinterpret_cast<LPMINMAXINFO>( lParam );
  516.       lpmmi->ptMinTrackSize = pdd->m_ptSmallest;
  517.       if( pdd->m_bLargestSet ) {
  518.         lpmmi->ptMaxTrackSize = pdd->m_ptLargest;
  519.       }
  520.     }
  521.     return (BOOL)0;
  522.   case WM_NOTIFY:
  523.     {
  524.       if( reinterpret_cast<LPNMHDR>(lParam)->code == PSN_SETACTIVE ) {
  525.         CRect rc;
  526.         VAPI( ::GetClientRect( *GetParent( ), &rc ) );
  527.         UpdateWindowSize( rc.Width(), rc.Height(), *GetParent( ) );
  528.       }
  529.     }
  530.     break;
  531.   case WM_DESTROY:
  532.     {
  533.       //
  534.       //        Our opportunty for cleanup.
  535.       //        Simply acquire all of our objects, free the appropriate memory and remove the 
  536.       //        properties from the window. If we do not remove the properties then they will constitute
  537.       //        a resource leak.
  538.       DialogData *pdd = (DialogData*)dd;
  539.       if( pdd ) {
  540.         RegistryData rd;
  541.         rd.m_wpl.length = sizeof( rd.m_wpl );
  542.         VAPI( GetWindowPlacement( &rd.m_wpl ) );
  543.         
  544.         if( pdd->hkRootSave && pdd->pcszName ) {
  545.           (void)RegSetValueExRecursive( pdd->hkRootSave, pdd->pcszName,
  546.                                         NULL, REG_BINARY,
  547.                                         reinterpret_cast<LPBYTE>( &rd ),
  548.                                         sizeof( rd ) );
  549.         }
  550.         
  551.         if( pdd->psd ) {
  552.           free(pdd->psd);
  553.         }
  554.         free(pdd);
  555.       }
  556.       
  557.     }
  558.     break;
  559.   }
  560.   return CDialog::OnWndMsg(msg, wParam, lParam, res);
  561. }
  562.