zoomwnd.cpp
资源名称:shell.rar [点击查看]
上传用户:xhy777
上传日期:2007-02-14
资源大小:24088k
文件大小:31k
源码类别:
系统编程
开发平台:
Visual C++
- #include "precomp.h"
- #include "ZoomWnd.h"
- #include "resource.h"
- #define MIN(x,y) ((x<y)?x:y)
- #define MAX(x,y) ((x>y)?x:y)
- /////////////////////////////////////////////////////////////////////////////
- // CZoomWnd
- CZoomWnd::CZoomWnd()
- {
- m_modeDefault = MODE_ZOOMIN;
- m_fPanning = false;
- m_fCtrlDown = false;
- m_fShiftDown = false;
- m_bBestFit = true;
- m_cxImage = 1;
- m_cyImage = 1;
- m_cxCenter = 1;
- m_cyCenter = 1;
- m_hbitmap = 0;
- m_pImgCtx = NULL;
- m_cyHScroll = GetSystemMetrics( SM_CYHSCROLL );
- m_cxVScroll = GetSystemMetrics( SM_CXVSCROLL );
- m_iStrID = IDS_NOPREVIEW;
- m_hpal = NULL;
- m_fTransparent = false;
- }
- CZoomWnd::~CZoomWnd()
- {
- if ( m_pImgCtx )
- {
- // Do not disconnect, other zoom windows might be using this same interface
- m_pImgCtx->Release();
- }
- }
- // OnEraseBkgnd
- //
- // Handles WM_ERASEBKGND messages sent to the window
- LRESULT CZoomWnd::OnEraseBkgnd(UINT , WPARAM wParam, LPARAM , BOOL& )
- {
- #define COLOR_PREVIEWBKGND COLOR_WINDOW
- RECT rcFill; // rect to fill with background color
- HDC hdc = (HDC)wParam;
- if ( m_fTransparent )
- {
- // when we have a transparent image we are forced to erase the entire background.
- // This can lead to visual flicker when panning or zooming transparent images
- // but I don't know of any other way to handle this.
- rcFill.left = 0;
- rcFill.top = 0;
- rcFill.right = m_cxWindow;
- rcFill.bottom = m_cyWindow;
- FillRect( hdc, &rcFill, (HBRUSH)(COLOR_PREVIEWBKGND+1));
- }
- else
- {
- // There are four possible regions that might need to be erased:
- // +-----------------------+
- // | Erase Top |
- // +-------+-------+-------+
- // | | | |
- // | Erase | Image | Erase |
- // | Left | | Right |
- // +-------+-------+-------+
- // | Erase Bottom |
- // +-----------------------+
- // erase the left region
- rcFill.left = 0;
- rcFill.top = m_ptszDest.y;
- rcFill.right = m_ptszDest.x;
- rcFill.bottom = m_ptszDest.y + m_ptszDest.cy;
- if ( rcFill.right > rcFill.left )
- FillRect( hdc, &rcFill, (HBRUSH)(COLOR_PREVIEWBKGND+1));
- // erase the right region
- rcFill.left = m_ptszDest.x + m_ptszDest.cx;
- rcFill.right = m_cxWindow;
- if ( rcFill.right > rcFill.left )
- FillRect( hdc, &rcFill, (HBRUSH)(COLOR_PREVIEWBKGND+1));
- // erase the top region
- rcFill.left = 0;
- rcFill.top = 0;
- rcFill.right = m_cxWindow;
- rcFill.bottom = m_ptszDest.y;
- if ( rcFill.bottom > rcFill.top )
- FillRect( hdc, &rcFill, (HBRUSH)(COLOR_PREVIEWBKGND+1));
- // erase the bottom region
- rcFill.top = m_ptszDest.y + m_ptszDest.cy;
- rcFill.bottom = m_cyWindow;
- if ( rcFill.bottom > rcFill.top )
- FillRect( hdc, &rcFill, (HBRUSH)(COLOR_PREVIEWBKGND+1));
- }
- return TRUE;
- #undef COLOR_PREVIEWBKGND
- }
- // OnPaint
- //
- // Handles WM_PAINT messages sent to the window
- LRESULT CZoomWnd::OnPaint(UINT , WPARAM , LPARAM , BOOL& )
- {
- PAINTSTRUCT ps;
- HDC hdcDraw = BeginPaint( &ps );
- // setup the destination DC:
- SetMapMode( hdcDraw, MM_TEXT );
- SetStretchBltMode( hdcDraw, COLORONCOLOR );
- if ( m_hpal )
- {
- SelectPalette(hdcDraw, m_hpal, TRUE);
- RealizePalette(hdcDraw);
- }
- if ( m_pImgCtx )
- {
- m_pImgCtx->StretchBlt(
- hdcDraw,
- m_ptszDest.x,
- m_ptszDest.y,
- m_ptszDest.cx,
- m_ptszDest.cy,
- 0,0,
- m_cxImage,
- m_cyImage,
- SRCCOPY );
- }
- else if ( m_hbitmap)
- {
- // create the source DC:
- HDC hdcBitmap = CreateCompatibleDC( hdcDraw );
- SelectObject( hdcBitmap, m_hbitmap );
- // and blit using the destination rectangle info
- StretchBlt(
- hdcDraw,
- m_ptszDest.x,
- m_ptszDest.y,
- m_ptszDest.cx,
- m_ptszDest.cy,
- hdcBitmap,
- 0,0,
- m_cxImage,
- m_cyImage,
- SRCCOPY );
- DeleteDC( hdcBitmap );
- }
- else
- {
- RECT rc = { 0,0,m_cxWindow,m_cyWindow };
- TCHAR szBuf[80];
- LOGFONT lf;
- HFONT hFont;
- HFONT hFontOld;
- LoadString( _Module.GetModuleInstance(),
- m_iStrID,
- szBuf,
- sizeof(szBuf) );
- SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(lf), &lf, 0);
- hFont = CreateFontIndirect(&lf);
- hFontOld = (HFONT)SelectObject(hdcDraw, hFont);
- SetTextColor(hdcDraw, GetSysColor(COLOR_WINDOWTEXT));
- SetBkColor(hdcDraw, GetSysColor(COLOR_WINDOW));
- FillRect(hdcDraw, &rc, (HBRUSH)(COLOR_WINDOW+1));
- DrawText(hdcDraw, szBuf, -1, &rc, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
- SelectObject(hdcDraw, hFontOld);
- DeleteObject(hFont);
- }
- EndPaint( &ps );
- return 0;
- }
- // OnSetCursor
- //
- // Handles WM_SETCURSOR messages sent to the window.
- //
- // This function is a total HackMaster job. I have overloaded it's functionality to the point
- // of abserdity. Here's what the parameters mean:
- //
- // uMsg == WM_SETCURSOR
- // wParam Standard value sent during a WM_SETCURSOR messge.
- // lParam Standard value sent during a WM_SETCURSOR messge.
- //
- // uMsg == 0
- // wParam 0
- // lParam If this value is non-zero then it is a packed x,y cursor location.
- // If it's zero then we need to query the cursor location
- LRESULT CZoomWnd::OnSetCursor(UINT uMsg, WPARAM, LPARAM lParam, BOOL& bHandled)
- {
- // if this is a legitimate message but isn't intended for the client area, we ignore it.
- // we also ignore set cursor when we have no valid bitmap
- if ( ((WM_SETCURSOR == uMsg) && (HTCLIENT != LOWORD(lParam))) || (!m_hbitmap && !m_pImgCtx) )
- {
- bHandled = FALSE;
- return 0;
- }
- else if ( 0 == uMsg )
- {
- // Since this is one of our fake messages we need to do our own check to test for HTCLIENT.
- // we need to find the cursor location
- POINT pt;
- GetCursorPos( &pt );
- lParam = MAKELONG(pt.x, pt.y);
- if ( HTCLIENT != SendMessage( WM_NCHITTEST, 0, lParam ) )
- {
- bHandled = FALSE;
- return 0;
- }
- }
- WORD idCur;
- if ( m_fPanning )
- {
- idCur = IDC_CLOSEDHAND;
- }
- else if ( m_fCtrlDown )
- {
- idCur = IDC_OPENHAND;
- }
- else if ( (m_modeDefault == MODE_ZOOMIN) ^ m_fShiftDown )
- {
- idCur = IDC_ZOOMIN;
- }
- else
- {
- idCur = IDC_ZOOMOUT;
- }
- SetCursor( LoadCursor(_Module.GetModuleInstance(), MAKEINTRESOURCE(idCur)) );
- return TRUE;
- }
- // OnKeyUp
- //
- // Handles WM_KEYUP messages sent to the window
- LRESULT CZoomWnd::OnKeyUp(UINT , WPARAM wParam, LPARAM , BOOL& bHandled)
- {
- if ( VK_CONTROL == wParam )
- {
- m_fCtrlDown = false;
- OnSetCursor( 0,0,0, bHandled );
- }
- else if (VK_SHIFT == wParam)
- {
- m_fShiftDown = false;
- OnSetCursor( 0,0,0, bHandled );
- }
- bHandled = FALSE;
- return 0;
- }
- // OnKeyDown
- //
- // Handles WM_KEYDOWN messages sent to the window
- LRESULT CZoomWnd::OnKeyDown(UINT , WPARAM wParam, LPARAM , BOOL& bHandled)
- {
- // when we return, we want to call the DefWindowProc
- bHandled = false;
- switch ( wParam )
- {
- case VK_PRIOR:
- OnScroll(WM_VSCROLL, m_fCtrlDown?SB_TOP:SB_PAGEUP, 0, bHandled);
- break;
- case VK_NEXT:
- OnScroll(WM_VSCROLL, m_fCtrlDown?SB_BOTTOM:SB_PAGEDOWN, 0, bHandled);
- break;
- case VK_END:
- OnScroll(WM_HSCROLL, m_fCtrlDown?SB_BOTTOM:SB_PAGEDOWN, 0, bHandled);
- break;
- case VK_HOME:
- OnScroll(WM_HSCROLL, m_fCtrlDown?SB_TOP:SB_PAGEUP, 0, bHandled);
- break;
- case VK_CONTROL:
- case VK_SHIFT:
- // if m_fPanning is true then we are already in the middle of an operation so we
- // should maintain the cursor for that operation
- if ( !m_fPanning )
- {
- if ( VK_CONTROL == wParam )
- {
- m_fCtrlDown = true;
- }
- else if (VK_SHIFT == wParam)
- {
- m_fShiftDown = true;
- }
- // Update the cursor based on the key states set above only if we are over our window
- OnSetCursor( 0,0,0, bHandled );
- }
- break;
- default:
- // if in run screen preview mode any key other than Shift and Control will dismiss the window
- if ( NULL == GetParent() )
- {
- DestroyWindow();
- }
- return 1; // return non-zero to indicate unprocessed message
- }
- return 0;
- }
- // OnMouseUp
- //
- // Handles WM_LBUTTONUP messages sent to the window
- LRESULT CZoomWnd::OnMouseUp(UINT , WPARAM , LPARAM , BOOL& bHandled)
- {
- if ( m_fPanning )
- ReleaseCapture();
- m_fPanning = false;
- bHandled = FALSE;
- return 0;
- }
- // OnMouseDown
- //
- // Handles WM_LBUTTONDOWN and WM_MBUTTONDOWN messages sent to the window
- LRESULT CZoomWnd::OnMouseDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
- {
- m_xPosMouse = (short)LOWORD( lParam );
- m_yPosMouse = (short)HIWORD( lParam );
- ASSERT( m_fPanning == false );
- // Holding the CTRL key makes a pan into a zoom and vise-versa.
- // The middle mouse button always pans regardless of default mode and key state.
- if ( (wParam & MK_CONTROL) || (uMsg == WM_MBUTTONDOWN) )
- {
- // REVIEW: check for pan being valid here? Should be more efficient than all the checks
- // I have to do in OnMouseMove.
- m_fPanning = true;
- OnSetCursor(0,0,0,bHandled);
- SetCapture();
- }
- else
- {
- // Holding down the shift key turns a zoomin into a zoomout and vise-versa.
- // The "default" zoom mode is zoom in (if mode = pan and ctrl key is down we zoom in).
- bool bZoomIn = (m_modeDefault != MODE_ZOOMOUT) ^ ((wParam & MK_SHIFT)?1:0);
- // Find the point we want to stay centered on:
- m_cxCenter = MulDiv( m_xPosMouse-m_ptszDest.x, m_cxImage, m_ptszDest.cx);
- m_cyCenter = MulDiv( m_yPosMouse-m_ptszDest.y, m_cyImage, m_ptszDest.cy);
- bZoomIn?ZoomIn():ZoomOut();
- }
- bHandled = FALSE;
- return 0;
- }
- void CZoomWnd::Zoom( WPARAM wParam, LPARAM lParam )
- {
- switch (wParam&0xFF)
- {
- case IVZ_CENTER:
- break;
- case IVZ_POINT:
- {
- int x = LOWORD(lParam);
- int y = HIWORD(lParam);
- if ( x<0 ) x=0;
- else if ( x>=m_cxImage ) x = m_cxImage-1;
- if ( y<0 ) y=0;
- else if ( y>=m_cyImage ) y = m_cyImage-1;
- m_cxCenter = x;
- m_cyCenter = y;
- }
- break;
- case IVZ_RECT:
- {
- LPRECT prc = (LPRECT)lParam;
- int x = (prc->left+prc->right)/2;
- int y = (prc->top+prc->bottom)/2;
- if ( x<0 ) x=0;
- else if ( x>=m_cxImage ) x = m_cxImage-1;
- if ( y<0 ) y=0;
- else if ( y>=m_cyImage ) y = m_cyImage-1;
- m_cxCenter = x;
- m_cyCenter = y;
- // TODO: This should really completely adjust the dest rect but I have to
- // check for any assumptions about aspect ratio before I allow this absolute
- // aspect ignoring zoom mode.
- }
- break;
- }
- if ( wParam&IVZ_ZOOMOUT )
- ZoomOut();
- else
- ZoomIn();
- }
- void CZoomWnd::ZoomIn()
- {
- if ( m_pImgCtx || m_hbitmap )
- {
- m_bBestFit = false;
- // first, the height is adjusted by the amount the mouse cursor moved.
- m_ptszDest.cy = (LONG)/*ceil*/(m_ptszDest.cy*1.200); // ceil is required in order to zoom in
- // on 4px high or less image
- // we don't allow zooming beyond 16x the full size of the image
- if ( m_ptszDest.cy >= m_cyImage*16 )
- {
- m_ptszDest.cy = m_cyImage*16;
- }
- // next, a new width is calculated based on the original image dimentions and the new height
- m_ptszDest.cx = MulDiv( m_ptszDest.cy, m_cxImage, m_cyImage );
- AdjustRectPlacement();
- }
- }
- void CZoomWnd::ZoomOut()
- {
- if ( m_pImgCtx || m_hbitmap )
- {
- // if the destination rect already fits within the window, don't allow a zoom out.
- // This check is to prevent a redraw that would occure otherwise
- if ((m_ptszDest.cx <= MIN(m_cxWindow,m_cxImage)) &&
- (m_ptszDest.cy <= MIN(m_cyWindow,m_cyImage)))
- {
- m_bBestFit = true;
- return;
- }
- // first, the height is adjusted by the amount the mouse cursor moved.
- m_ptszDest.cy = (LONG)/*floor*/(m_ptszDest.cy*0.833); // floor is default behavior
- // next, a new width is calculated based on the original image dimentions and the new height
- m_ptszDest.cx = MulDiv( m_ptszDest.cy, m_cxImage, m_cyImage );
- AdjustRectPlacement();
- }
- }
- // OnMouseMove
- //
- // Handles WM_MOUSEMOVE messages sent to the control
- LRESULT CZoomWnd::OnMouseMove(UINT , WPARAM wParam, LPARAM lParam, BOOL& bHandled)
- {
- // This is something of a hack since I never recieve the keyboard focus
- if ( wParam & MK_CONTROL )
- m_fCtrlDown = true;
- else
- m_fCtrlDown = false;
- if ( wParam & MK_SHIFT )
- m_fShiftDown = true;
- else
- m_fShiftDown = false;
- // we only care about mouse move when the middle or left button is down
- // and we have a valid bitmap handle and we are panning
- if ( !(wParam & (MK_LBUTTON|MK_MBUTTON)) || !m_fPanning || (!m_hbitmap && !m_pImgCtx) )
- {
- bHandled = false;
- return TRUE;
- }
- // we know we are panning when we reach this point
- ASSERT( m_fPanning );
- POINTS pt = MAKEPOINTS( lParam );
- PTSZ ptszDest;
- ptszDest.cx = m_ptszDest.cx;
- ptszDest.cy = m_ptszDest.cy;
- // only allow side-to-side panning if it's needed
- if ( m_ptszDest.cx > m_cxWindow )
- {
- ptszDest.x = m_ptszDest.x + pt.x - m_xPosMouse;
- }
- else
- {
- ptszDest.x = m_ptszDest.x;
- }
- // only allow up-and-down panning if it's needed
- if ( m_ptszDest.cy > m_cyWindow )
- {
- ptszDest.y = m_ptszDest.y + pt.y - m_yPosMouse;
- }
- else
- {
- ptszDest.y = m_ptszDest.y;
- }
- // if the image is now smaller than the window, center it
- // if the image is now panned when it shouldn't be, adjust the possition
- if ( ptszDest.cx < m_cxWindow )
- ptszDest.x = (m_cxWindow-ptszDest.cx)/2;
- else
- {
- if ( ptszDest.x < (m_cxWindow - ptszDest.cx) )
- ptszDest.x = m_cxWindow - ptszDest.cx;
- if ( ptszDest.x > 0 )
- ptszDest.x = 0;
- }
- if ( ptszDest.cy < m_cyWindow )
- ptszDest.y = (m_cyWindow-ptszDest.cy)/2;
- else
- {
- if ( ptszDest.y < (m_cyWindow - ptszDest.cy) )
- ptszDest.y = m_cyWindow - ptszDest.cy;
- if ( ptszDest.y > 0 )
- ptszDest.y = 0;
- }
- m_xPosMouse = pt.x;
- m_yPosMouse = pt.y;
- // ensure the scroll bars are correct
- SetScrollBars();
- // if anything has changed, we must invalidate the window to force a repaint
- if ( (ptszDest.x != m_ptszDest.x) || (ptszDest.y != m_ptszDest.y) ||
- (ptszDest.cx != m_ptszDest.cx) || (ptszDest.y != m_ptszDest.y ))
- {
- // REVIEW: Is it worth it to calculate rcInvalid? Should I use NULL instead?
- RECT rcInvalid;
- rcInvalid.left = MIN( ptszDest.x, m_ptszDest.x );
- rcInvalid.top = MIN( ptszDest.y, m_ptszDest.y );
- rcInvalid.right = MAX( ptszDest.x + ptszDest.cx, m_ptszDest.x + m_ptszDest.cx );
- rcInvalid.bottom = MAX( ptszDest.y + ptszDest.cy, m_ptszDest.y + m_ptszDest.cy );
- m_ptszDest = ptszDest;
- InvalidateRect( &rcInvalid );
- }
- // Update m_cxCenter and m_cyCenter so that a zoom after a pan will zoom in
- // on the correct area. This is majorly annoying otherwise. We want the
- // new center to be whatever is in the center of the window after we pan.
- m_cxCenter = MulDiv( m_cxWindow/2-m_ptszDest.x, m_cxImage, m_ptszDest.cx);
- m_cyCenter = MulDiv( m_cyWindow/2-m_ptszDest.y, m_cyImage, m_ptszDest.cy);
- return TRUE;
- }
- // OnSize
- //
- // Handles WM_SIZE messages set to the window
- LRESULT CZoomWnd::OnSize(UINT , WPARAM , LPARAM lParam, BOOL& )
- {
- m_cxWindow = LOWORD(lParam);
- m_cyWindow = HIWORD(lParam);
- if ( m_bBestFit )
- {
- BestFit();
- }
- else
- {
- // The size of the rect doesn't change in this case, so just reposition
- AdjustRectPlacement();
- }
- return TRUE;
- }
- // SetMode
- //
- // Sets the current mouse mode to one of the values specified in the MODE enumeration.
- // Currently there are two modes, pan and zoom. The mode effects the default mouse
- // cursor when moving over the zoom window and the behavior of a click-and-drag with the
- // left mouse button. Holding the shift key effects the result of a click-and-drag but
- // does not effect m_mode, which is the default when the shift key isn't down.
- bool CZoomWnd::SetMode(MODE modeNew)
- {
- if ( m_modeDefault == modeNew )
- return false;
- m_modeDefault = modeNew;
- return true;
- }
- // ActualSize
- //
- // Displays image zoomed to its full size
- void CZoomWnd::ActualSize()
- {
- m_bBestFit = FALSE;
- // actual size means same sixe as the image
- m_ptszDest.cx = m_cxImage;
- m_ptszDest.cy = m_cyImage;
- // we center the image
- m_ptszDest.x = (m_cxWindow-m_cxImage)/2;
- m_ptszDest.y = (m_cyWindow-m_cyImage)/2;
- // Setting actual size is a zoom operation. Whenever we zoom we update our centerpoint.
- m_cxCenter = m_cxImage/2;
- m_cyCenter = m_cyImage/2;
- // turn scoll bars on/off as needed
- SetScrollBars();
- InvalidateRect( NULL );
- }
- // BestFit
- //
- // Computes the default location for the destination rectangle. This rectangle is a
- // best fit while maintaining aspect ratio within a window of the given width and height.
- // If the window is larger than the image, the image is centered, otherwise it is scaled
- // to fit within the window. The destination rectange is computed in the client coordinates
- // of the window whose width and height are passed as arguments (ie we assume the point 0,0
- // is the upper left corner of the window).
- //
- void CZoomWnd::BestFit()
- {
- m_bBestFit = true;
- // if scroll bars are on, adjust the client size to what it will be once they are off
- DWORD dwStyle = GetWindowLong(GWL_STYLE);
- if ( dwStyle & (WS_VSCROLL|WS_HSCROLL) )
- {
- m_cxWindow += (dwStyle&WS_VSCROLL)?m_cxVScroll:0;
- m_cyWindow += (dwStyle&WS_HSCROLL)?m_cyHScroll:0;
- }
- // Determine the limiting axis, if any.
- if ( m_cxImage <= m_cxWindow && m_cyImage <= m_cyWindow )
- {
- // item fits centered within window
- m_ptszDest.x = (m_cxWindow-m_cxImage)/2;
- m_ptszDest.y = (m_cyWindow-m_cyImage)/2;
- m_ptszDest.cx = m_cxImage;
- m_ptszDest.cy = m_cyImage;
- }
- else if ( m_cxImage * m_cyWindow < m_cxWindow * m_cyImage )
- {
- // height is the limiting factor
- int iNewWidth = MulDiv(m_cyWindow, m_cxImage, m_cyImage);
- m_ptszDest.x = (m_cxWindow-iNewWidth)/2;
- m_ptszDest.y = 0;
- m_ptszDest.cx = iNewWidth;
- m_ptszDest.cy = m_cyWindow;
- }
- else
- {
- // width is the limiting factor
- int iNewHeight = MulDiv(m_cxWindow, m_cyImage, m_cxImage);
- m_ptszDest.x = 0;
- m_ptszDest.y = (m_cyWindow-iNewHeight)/2;
- m_ptszDest.cx = m_cxWindow;
- m_ptszDest.cy = iNewHeight;
- }
- // this should turn off the scroll bars if they are on
- if ( dwStyle & (WS_VSCROLL|WS_HSCROLL) )
- {
- SetScrollBars();
- }
- // ensure the scroll bars are now off
- ASSERT( 0 == (GetWindowLong(GWL_STYLE)&(WS_VSCROLL|WS_HSCROLL)) );
- InvalidateRect( NULL );
- }
- // AdjustRectPlacement
- //
- // This function determines the optimal placement of the destination rectangle. This may
- // include resizing the destination rectangle if it is smaller than the "best fit" rectangle
- // but it is primarily intended for repossitioning the rectange due to a change in the window
- // size or destination rectangle size. The window is repositioned so that the centered point
- // remains in the center of the window.
- //
- void CZoomWnd::AdjustRectPlacement()
- {
- // if we have scroll bars ...
- DWORD dwStyle = GetWindowLong(GWL_STYLE);
- if ( dwStyle&(WS_VSCROLL|WS_HSCROLL) )
- {
- // .. and if removing scroll bars would allow the image to fit ...
- if ( (m_ptszDest.cx < (m_cxWindow + ((dwStyle&WS_VSCROLL)?m_cxVScroll:0))) &&
- (m_ptszDest.cy < (m_cyWindow + ((dwStyle&WS_HSCROLL)?m_cyHScroll:0))) )
- {
- // ... remove the scroll bars
- m_cxWindow += (dwStyle&WS_VSCROLL)?m_cxVScroll:0;
- m_cyWindow += (dwStyle&WS_HSCROLL)?m_cyHScroll:0;
- SetScrollBars();
- }
- }
- // If the dest rect is smaller than the window ...
- if ( (m_ptszDest.cx < m_cxWindow) && (m_ptszDest.cy < m_cyWindow) )
- {
- // ... then it must be larger than the image. Oterwise we switch
- // to "best fit" mode.
- if ( (m_ptszDest.cx < m_cxImage) && (m_ptszDest.cy < m_cyImage) )
- {
- BestFit();
- return;
- }
- }
- // given the window size, client area size, and dest rect size calculate the
- // dest rect position. This position is then restrained by the limits below.
- m_ptszDest.x = (m_cxWindow/2) - MulDiv( m_cxCenter, m_ptszDest.cx, m_cxImage);
- m_ptszDest.y = (m_cyWindow/2) - MulDiv( m_cyCenter, m_ptszDest.cy, m_cyImage);
- // if the image is now narrower than the window ...
- if ( m_ptszDest.cx < m_cxWindow )
- {
- // ... center the image
- m_ptszDest.x = (m_cxWindow-m_ptszDest.cx)/2;
- }
- else
- {
- // if the image is now panned when it shouldn't be, adjust the possition
- if ( m_ptszDest.x < (m_cxWindow - m_ptszDest.cx) )
- m_ptszDest.x = m_cxWindow - m_ptszDest.cx;
- if ( m_ptszDest.x > 0 )
- m_ptszDest.x = 0;
- }
- // if the image is now shorter than the window ...
- if ( m_ptszDest.cy < m_cyWindow )
- {
- // ... center the image
- m_ptszDest.y = (m_cyWindow-m_ptszDest.cy)/2;
- }
- else
- {
- // if the image is now panned when it shouldn't be, adjust the possition
- if ( m_ptszDest.y < (m_cyWindow - m_ptszDest.cy) )
- m_ptszDest.y = m_cyWindow - m_ptszDest.cy;
- if ( m_ptszDest.y > 0 )
- m_ptszDest.y = 0;
- }
- SetScrollBars();
- InvalidateRect( NULL );
- }
- // StatusUpdate
- //
- // Sent when the image generation status has changed, once when the image is first
- // being created and again if there is an error of any kind.
- void CZoomWnd::StatusUpdate( int iStatus )
- {
- if ( m_pImgCtx )
- {
- m_pImgCtx->Release();
- m_pImgCtx = 0;
- }
- m_hbitmap = 0;
- m_fTransparent = false;
- m_iStrID = iStatus;
- if ( m_hWnd )
- {
- InvalidateRect(NULL);
- }
- }
- // SetBitmap
- //
- // Called to pass in the handle to the bitmap we draw. We DO NOT own this bitmap, it
- // is a duplicate handle. We use it to paint only, it is freed by the parent window.
- //
- void CZoomWnd::SetBitmap(HBITMAP hbitmap)
- {
- if ( m_pImgCtx )
- {
- m_pImgCtx->Release();
- m_pImgCtx = 0;
- }
- m_fTransparent = false;
- m_hbitmap = hbitmap;
- if (m_hbitmap)
- {
- BITMAP bm;
- if (GetObject(m_hbitmap, sizeof(bm), &bm))
- {
- // this message indicates a successful result
- m_cxImage = bm.bmWidth;
- m_cyImage = bm.bmHeight;
- m_cxCenter = m_cxImage/2;
- m_cyCenter = m_cyImage/2;
- // this message could be recieved before the window is created.
- // Make sure m_hWnd is valid before calling BestFit or InvalidateRect
- if (m_hWnd)
- {
- BestFit();
- InvalidateRect(NULL);
- }
- return;
- }
- }
- m_iStrID = IDS_LOADFAILED;
- }
- // SetImgCtx
- //
- // Called to pass in the pointer to the IImgCtx we draw. We hold a reference to this
- // object so that we can use it to paint.
- //
- void CZoomWnd::SetImgCtx(IImgCtx * pImg)
- {
- m_hbitmap = 0;
- if ( m_pImgCtx )
- {
- m_pImgCtx->Release();
- }
- m_fTransparent = false;
- m_pImgCtx = pImg;
- if (m_pImgCtx)
- {
- SIZE size;
- DWORD fState;
- m_pImgCtx->AddRef();
- if ( SUCCEEDED(m_pImgCtx->GetStateInfo(&fState, &size, FALSE)) )
- {
- ASSERT( fState & IMGLOAD_COMPLETE );
- m_fTransparent = (0 == (fState & IMGTRANS_OPAQUE));
- m_cxImage = size.cx;
- m_cyImage = size.cy;
- m_cxCenter = m_cxImage/2;
- m_cyCenter = m_cyImage/2;
- if (m_hWnd)
- {
- BestFit();
- InvalidateRect(NULL);
- }
- }
- return;
- }
- m_iStrID = IDS_LOADFAILED;
- }
- void CZoomWnd::SetPalette( HPALETTE hpal )
- {
- m_hpal = hpal;
- }
- void CZoomWnd::SetScrollBars()
- {
- SCROLLINFO si;
- si.cbSize = sizeof(si);
- si.fMask = SIF_ALL;
- si.nMin = 0;
- si.nMax = m_ptszDest.cx;
- si.nPage = m_cxWindow+1;
- si.nPos = 0-m_ptszDest.x;
- si.nTrackPos = 0;
- SetScrollInfo( m_hWnd, SB_HORZ, &si, true );
- si.nMax = m_ptszDest.cy;
- si.nPage = m_cyWindow+1;
- si.nPos = 0-m_ptszDest.y;
- SetScrollInfo( m_hWnd, SB_VERT, &si, true );
- }
- LRESULT CZoomWnd::OnScroll(UINT uMsg, WPARAM wParam, LPARAM , BOOL& )
- {
- int iScrollBar;
- int iWindow; // width or height of the window
- LONG * piTL; // pointer to top or left point
- LONG iWH; // the width or height of the dest rect
- if ( (!m_hbitmap && !m_pImgCtx) )
- return 0;
- // handle both which direction we're scrolling
- if ( WM_HSCROLL==uMsg )
- {
- iScrollBar = SB_HORZ;
- iWindow = m_cxWindow;
- piTL = &m_ptszDest.x;
- iWH = m_ptszDest.cx;
- }
- else
- {
- iScrollBar = SB_VERT;
- iWindow = m_cyWindow;
- piTL = &m_ptszDest.y;
- iWH = m_ptszDest.cy;
- }
- // Using the keyboard we can get scroll messages when we don't have scroll bars.
- // Ignore these messages.
- if ( iWindow >= iWH )
- {
- // window is larger than the image, don't allow scrolling
- return 0;
- }
- // handle all possible scroll cases
- switch ( LOWORD(wParam) )
- {
- case SB_TOP:
- *piTL = 0;
- break;
- case SB_PAGEUP:
- *piTL += iWindow;
- break;
- case SB_LINEUP:
- (*piTL)++;
- break;
- case SB_LINEDOWN:
- (*piTL)--;
- break;
- case SB_PAGEDOWN:
- *piTL -= iWindow;
- break;
- case SB_BOTTOM:
- *piTL = iWindow-iWH;
- break;
- case SB_THUMBPOSITION:
- case SB_THUMBTRACK:
- *piTL = -HIWORD(wParam);
- break;
- case SB_ENDSCROLL:
- return 0;
- }
- // apply limits
- if ( 0 < *piTL )
- *piTL = 0;
- else if ( (iWindow-iWH) > *piTL )
- *piTL = iWindow-iWH;
- // adjust scrollbars
- SetScrollPos(iScrollBar, -(*piTL), true);
- // calculate new center point relative to image
- if ( WM_HSCROLL==uMsg )
- {
- m_cxCenter = MulDiv( (m_cxWindow/2)-m_ptszDest.x, m_cxImage, m_ptszDest.cx);
- }
- else
- {
- m_cyCenter = MulDiv( (m_cyWindow/2)-m_ptszDest.y, m_cyImage, m_ptszDest.cy);
- }
- InvalidateRect( NULL );
- return 0;
- }
- /*
- LRESULT CZoomWnd::OnHScroll(UINT , WPARAM wParam, LPARAM , BOOL& )
- {
- if ( !m_hbitmap )
- return 0;
- // handle all possible scroll cases
- switch ( LOWORD(wParam) )
- {
- case SB_TOP:
- m_ptszDest.x = 0;
- break;
- case SB_PAGEUP:
- m_ptszDest.x += m_cxWindow;
- break;
- case SB_LINEUP:
- m_ptszDest.x++;
- break;
- case SB_LINEDOWN:
- m_ptszDest.x--;
- break;
- case SB_PAGEDOWN:
- m_ptszDest.x -= m_cxWindow;
- break;
- case SB_BOTTOM:
- m_ptszDest.x = m_cxWindow-m_ptszDest.cx;
- break;
- case SB_THUMBPOSITION:
- case SB_THUMBTRACK:
- m_ptszDest.x = -HIWORD(wParam);
- break;
- case SB_ENDSCROLL:
- return 0;
- }
- // apply limits
- if ( 0 < m_ptszDest.x )
- m_ptszDest.x = 0;
- else if ( m_cxWindow-m_ptszDest.cx > m_ptszDest.x )
- m_ptszDest.x = m_cxWindow-m_ptszDest.cx;
- // adjust scrollbars
- SetScrollPos(SB_HORZ, -m_ptszDest.x, true);
- // calculate new center point relative to image
- m_cxCenter = MulDiv( (m_cxWindow/2)-m_ptszDest.x, m_cxImage, m_ptszDest.cx);
- // redraw
- InvalidateRect( NULL );
- return 0;
- }
- LRESULT CZoomWnd::OnVScroll(UINT , WPARAM wParam, LPARAM , BOOL& )
- {
- if ( !m_hbitmap )
- return 0;
- // handle all possible scroll cases
- switch ( LOWORD(wParam) )
- {
- case SB_TOP:
- m_ptszDest.y = 0;
- break;
- case SB_PAGEUP:
- m_ptszDest.y += m_cyWindow;
- break;
- case SB_LINEUP:
- m_ptszDest.y++;
- break;
- case SB_LINEDOWN:
- m_ptszDest.y--;
- break;
- case SB_PAGEDOWN:
- m_ptszDest.y -= m_cyWindow;
- break;
- case SB_BOTTOM:
- m_ptszDest.y = m_cyWindow-m_ptszDest.cy;
- break;
- case SB_THUMBPOSITION:
- case SB_THUMBTRACK:
- m_ptszDest.y = -HIWORD(wParam);
- break;
- case SB_ENDSCROLL:
- return 0;
- }
- // apply limits
- if ( 0 < m_ptszDest.y )
- m_ptszDest.y = 0;
- else if ( m_cyWindow-m_ptszDest.cy > m_ptszDest.y )
- m_ptszDest.y = m_cyWindow-m_ptszDest.cy;
- // adjust scrollbars
- SetScrollPos(SB_VERT, -m_ptszDest.y, true);
- // calculate new center point relative to image
- m_cyCenter = MulDiv( (m_cyWindow/2)-m_ptszDest.y, m_cyImage, m_ptszDest.cy);
- // redraw
- InvalidateRect( NULL );
- return 0;
- }
- */
- // OnWheelTurn
- //
- // Respondes to WM_MOUSEWHEEL messages sent to the parent window (then redirected here)
- LRESULT CZoomWnd::OnWheelTurn(UINT , WPARAM wParam, LPARAM , BOOL& )
- {
- bool bZoomIn = ((short)HIWORD(wParam) > 0);
- bZoomIn?ZoomIn():ZoomOut();
- return TRUE;
- }
- LRESULT CZoomWnd::OnSetFocus(UINT , WPARAM , LPARAM , BOOL& )
- {
- HWND hwndParent = GetParent();
- ::SetFocus( hwndParent );
- return 0;
- }
English
