www.pudn.com > 44w.rar > resizer.h
#pragma once #include#include enum ANCHOR { ANCHOR_DEFAULT = 0, ANCHOR_LEFT = 1, ANCHOR_RIGHT = 2, ANCHOR_BOTH = 3, ANCHOR_TOP = ANCHOR_LEFT, ANCHOR_BOTTOM = ANCHOR_RIGHT, }; #define DEFER 1 class CResizer { HWND m_hDlg; // Handle to dialog window POINT m_origSize; // Size of dialog when first created (in template) POINT m_oldSize; // Most recent size of dialog POINT m_newSize; // Size as a result of resizing HDWP m_hdwp; // Deferred window position handle long m_horzPercent; // Horizontal breakpoint percentage long m_vertPercent; // Horizontal breakpoint percentage bool m_Enable; struct OVERRIDE { HWND hChild; ANCHOR horzAnchor; ANCHOR vertAnchor; } * m_OverrideList; // Overrides for default anchor points int m_OverrideCnt; OVERRIDE * FindOverride( HWND hChild, bool create ) { if ( hChild == NULL ) return NULL; for ( int i = 0; i < m_OverrideCnt; ++i ) if ( m_OverrideList[i].hChild == hChild ) return m_OverrideList + i; if ( ! create ) return NULL; // create item m_OverrideList = (OVERRIDE *)realloc( m_OverrideList, ++m_OverrideCnt*sizeof m_OverrideList[0] ); OVERRIDE * override = m_OverrideList + m_OverrideCnt - 1; override->hChild = hChild; override->horzAnchor = ANCHOR_DEFAULT; override->vertAnchor = ANCHOR_DEFAULT; return override; } static void inline UpdatePos( long & pos, long oldWidth, long newWidth ) { // anchor to right pos = newWidth - (oldWidth - pos); } static BOOL CALLBACK ResizeCallback( HWND hChild, LPARAM lParam ) { bool ResizeOkay = true; CResizer * This = (CResizer *) lParam; #if DEFER // Ensure child is a direct descendent of parent (mandatory for DeferWindowPos) if ( GetParent( hChild ) != This->m_hDlg ) return TRUE; #endif // Get child window location RECT rc; GetWindowRect( hChild, &rc ); ScreenToClient( This->m_hDlg, (POINT *)&rc.left ); ScreenToClient( This->m_hDlg, (POINT *)&rc.right ); // Select a "center" for dividing screen into quadrants int horzBreak = This->m_oldSize.x * This->m_horzPercent / 100; int vertBreak = This->m_oldSize.y * This->m_vertPercent / 100; // Compute default anchor points int horzAnchor = ANCHOR_DEFAULT, vertAnchor = ANCHOR_DEFAULT; if ( rc.left < horzBreak ) horzAnchor |= ANCHOR_LEFT; if ( rc.right >= horzBreak ) horzAnchor |= ANCHOR_RIGHT; if ( rc.top < vertBreak ) vertAnchor |= ANCHOR_TOP; if ( rc.bottom >= vertBreak ) vertAnchor |= ANCHOR_BOTTOM; // Apply window class override #if _DEBUG TCHAR Text[ MAX_PATH ] = TEXT(""); GetWindowText( hChild, Text, MAX_PATH ); #endif TCHAR Class[ MAX_PATH ] = TEXT(""); GetClassName( hChild, Class, MAX_PATH ); if ( _tcsicmp( Class, TEXT("Button") ) == 0 ) { DWORD Style = GetWindowLong( hChild, GWL_STYLE ); Style &= 0xF; if ( Style == BS_PUSHBUTTON || Style == BS_DEFPUSHBUTTON || Style == BS_OWNERDRAW || Style == BS_USERBUTTON ) ResizeOkay = false; } if ( ! ResizeOkay ) { // Not allowed to resize this control, so prevent the anchors from being BOTH if ( horzAnchor == ANCHOR_BOTH ) horzAnchor = horzBreak - rc.left >= rc.right - horzBreak ? ANCHOR_LEFT : ANCHOR_RIGHT; if ( vertAnchor == ANCHOR_BOTH ) vertAnchor = vertBreak - rc.top >= rc.bottom - vertBreak ? ANCHOR_TOP : ANCHOR_BOTTOM; } // Apply user override OVERRIDE * override = This->FindOverride( hChild, false ); if ( override ) { if ( override->horzAnchor != ANCHOR_DEFAULT ) horzAnchor = override->horzAnchor; if ( override->vertAnchor != ANCHOR_DEFAULT ) vertAnchor = override->vertAnchor; } // adjust size based on anchor points if ( horzAnchor == ANCHOR_RIGHT ) UpdatePos( rc.left, This->m_oldSize.x, This->m_newSize.x ); if ( horzAnchor & ANCHOR_RIGHT ) UpdatePos( rc.right, This->m_oldSize.x, This->m_newSize.x ); if ( vertAnchor == ANCHOR_BOTTOM ) UpdatePos( rc.top, This->m_oldSize.y, This->m_newSize.y ); if ( vertAnchor & ANCHOR_BOTTOM ) UpdatePos( rc.bottom, This->m_oldSize.y, This->m_newSize.y ); // Update position relative to parent, which may be different than dialog #if DEFER This->m_hdwp = DeferWindowPos( This->m_hdwp, hChild, NULL, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, SWP_NOZORDER ); #else MapWindowPoints( This->m_hDlg, GetParent(hChild), (POINT *)&rc, 2 ); MoveWindow( hChild, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, true ); #endif return TRUE; } void ResizeDialog() { if ( m_oldSize.y != m_newSize.y || m_oldSize.x != m_newSize.x ) { // move all windows #if DEFER m_hdwp = BeginDeferWindowPos( 20 ); #endif EnumChildWindows( m_hDlg, ResizeCallback, (LPARAM)this ); #if DEFER EndDeferWindowPos( m_hdwp ); #endif m_oldSize = m_newSize; } } public: CResizer( long horzPercent = 50, long vertPercent = 67 ) { m_horzPercent = horzPercent; m_vertPercent = vertPercent; m_OverrideList = NULL; m_OverrideCnt = 0; m_Enable = true; } void Reset() { // only called if resizer is being reused free( m_OverrideList ); m_OverrideList = NULL; m_OverrideCnt = 0; } ~CResizer() { Reset(); } // Called by WM_INITDIALOG handler void OnInitDialog( HWND hDlg ) { RECT rc; m_hDlg = hDlg; GetWindowRect( m_hDlg, &rc ); m_oldSize.x = rc.right - rc.left; m_oldSize.y = rc.bottom - rc.top; m_origSize = m_oldSize; } // Called by WM_GETMINMAXINFO handler void OnGetMinMaxInfo( WPARAM wParam, LPARAM lParam ) { MINMAXINFO * minmax = (MINMAXINFO *) lParam; minmax->ptMinTrackSize = m_origSize; } // Called by WM_SIZE handler void OnSize( WPARAM wParam, WPARAM lParam ) { if ( ! m_Enable ) return; if ( wParam == SIZE_MAXIMIZED || wParam == SIZE_RESTORED ) { RECT rc; if ( ! GetWindowRect( m_hDlg, &rc ) ) return; m_newSize.x = rc.right - rc.left; m_newSize.y = rc.bottom - rc.top; ResizeDialog(); } } // Called on WM_NCHITTEST (need for resize grip only) UINT OnNcHitTest( WPARAM wParam, LPARAM lParam ) { // check whether cursor is in size grip UINT ht = DefWindowProc( m_hDlg, WM_NCHITTEST, wParam, lParam ); if ( ht == HTCLIENT ) { if ( ! IsZoomed( m_hDlg ) ) { RECT rc; GetWindowRect( m_hDlg, &rc ); rc.left = rc.right - GetSystemMetrics( SM_CXHSCROLL ); rc.top = rc.bottom - GetSystemMetrics( SM_CYVSCROLL ); POINT pt = { GET_X_LPARAM ( lParam ), GET_Y_LPARAM( lParam ) }; if ( PtInRect( &rc, pt ) ) return HTBOTTOMRIGHT; } } return ht; } // Called on WM_PAINT (need for resize grip only) void OnPaint( WPARAM wParam, LPARAM lParam ) { if ( ! IsZoomed( m_hDlg ) ) { // Paint size grip PAINTSTRUCT ps; HDC hdc = BeginPaint( m_hDlg, &ps ); RECT rc; GetClientRect( m_hDlg, &rc ); rc.left = rc.right - GetSystemMetrics( SM_CXHSCROLL ); rc.top = rc.bottom - GetSystemMetrics( SM_CYVSCROLL ); DrawFrameControl( hdc, &rc, DFC_SCROLL, DFCS_SCROLLSIZEGRIP ); EndPaint( m_hDlg, &ps ); } } // If you're lazy just call this on every message bool OnMessage( HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam ) { switch ( message ) { case WM_INITDIALOG: OnInitDialog( hDlg ); return false; case WM_GETMINMAXINFO: OnGetMinMaxInfo( wParam, lParam ); return false; case WM_SIZE: OnSize( wParam, lParam ); InvalidateRect( hDlg, NULL, true ); return false; case WM_NCHITTEST: SetWindowLong( hDlg, DWL_MSGRESULT, OnNcHitTest( wParam, lParam ) ); return true; case WM_PAINT: OnPaint( wParam, lParam ); return false; default: return false; } } // If you're really lazy just call this on every message static bool OnMessageEx( HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam ) { CResizer * This = (CResizer *) GetWindowLong( hDlg, GWL_USERDATA ); switch ( message ) { case WM_INITDIALOG: This = new CResizer(); SetWindowLong( hDlg, GWL_USERDATA, (LONG)This ); break; case WM_DESTROY: delete This; SetWindowLong( hDlg, GWL_USERDATA, 0 ); break; case WM_COMMAND: switch ( wParam ) { case IDOK: case IDCANCEL: // If dialog is modal we won' receive WM_DESTORY, so assume these close the window delete This; SetWindowLong( hDlg, GWL_USERDATA, 0 ); break; } break; } return This ? This->OnMessage( hDlg, message, wParam, lParam ) : false; } // Called to manually resize the window POINT Resize( const POINT * pNewSize ) { if ( pNewSize == NULL ) // if size not specified use original size pNewSize = &m_origSize; POINT curSize = m_oldSize; SetWindowPos( m_hDlg, NULL, 0, 0, pNewSize->x, pNewSize->y, SWP_NOREDRAW|SWP_NOOWNERZORDER|SWP_NOZORDER|SWP_NOMOVE ); return curSize; } // Called to explicitly set the anchors for a child window void SetHorz( HWND hChild, ANCHOR horzAnchor ) { OVERRIDE * override = FindOverride( hChild, true ); override->horzAnchor = horzAnchor; } void SetVert( HWND hChild, ANCHOR vertAnchor ) { OVERRIDE * override = FindOverride( hChild, true ); override->vertAnchor = vertAnchor; } void SetBoth( HWND hChild, ANCHOR horzAnchor, ANCHOR vertAnchor ) { OVERRIDE * override = FindOverride( hChild, true ); override->horzAnchor = horzAnchor; override->vertAnchor = vertAnchor; } void Enable( bool enable ) { m_Enable = enable; } };