GME  13
PanningButton.cpp
Go to the documentation of this file.
00001 // PannButton.cpp : implementation file
00002 //
00003 
00004 #include "stdafx.h"
00005 #include "PanningButton.h"
00006 #include "PanningViewCtrl.h"
00007 
00008 #ifdef _DEBUG
00009 #define new DEBUG_NEW
00010 #undef THIS_FILE
00011 static char THIS_FILE[] = __FILE__;
00012 #endif
00013 
00015 // CPanningButton
00016 
00017 CPanningButton::CPanningButton()
00018 {
00019         m_viewRectOnScreen      = CRect(0, 0, 0, 0);
00020         m_viewRectInMove        = CRect(0, 0, 0, 0);
00021         m_viewRectOnStored      = CRect(0, 0, 0, 0);
00022         m_bitmapDC                      = NULL;
00023         m_oldBmp                        = NULL;
00024         m_bitmapSizeStored      = CRect(0, 0, 0, 0);
00025         m_bitmapSizeOri         = CRect(0, 0, 0, 0);
00026         m_owner                         = NULL;
00027         m_backgorund            = RGB(255, 255, 255);
00028         m_sizeallh                      = NULL;
00029         m_arrowh                        = NULL;
00030         m_inMove                        = false;
00031         m_storedToScreenRx      = 0;
00032         m_storedToScreenRy      = 0;
00033         m_oriToStoredRx         = 0;
00034         m_oriToStoredRy         = 0;
00035 }
00036 
00037 CPanningButton::~CPanningButton()
00038 {
00039         if (m_bitmapDC != NULL)
00040                 DeleteDeviceContext(m_bitmapDC, m_oldBmp);
00041 }
00042 
00043 
00044 BEGIN_MESSAGE_MAP(CPanningButton, CWnd)
00045         //{{AFX_MSG_MAP(CPanningButton)
00046         ON_WM_PAINT()
00047         ON_WM_ERASEBKGND()
00048         ON_WM_MOUSEMOVE()
00049         ON_WM_LBUTTONDOWN()
00050         ON_WM_LBUTTONUP()
00051         //}}AFX_MSG_MAP
00052 END_MESSAGE_MAP()
00053 
00055 // CPanningButton message handlers
00056 
00057 bool CPanningButton::Create()
00058 {
00059         m_sizeallh = ::LoadCursor(NULL, IDC_SIZEALL);
00060         m_arrowh = ::LoadCursor(NULL, IDC_ARROW);
00061         return true;
00062 }
00063 
00064 void CPanningButton::SetBitmapDC(HWND owner, HDC bdc, HBITMAP oldBmp, CRect& orisize, CRect& actsize, COLORREF& bkgrnd) // may be empty
00065 {
00066         if (m_bitmapDC != NULL)
00067                 DeleteDeviceContext(m_bitmapDC, m_oldBmp);
00068         m_owner = owner;
00069         m_bitmapDC = bdc;
00070         m_oldBmp = oldBmp;
00071         m_bitmapSizeOri = orisize;
00072         m_bitmapSizeStored = actsize;
00073         m_backgorund = bkgrnd;
00074 
00075         Invalidate();
00076         UpdateWindow();
00077 }
00078 
00079 void CPanningButton::SetViewRect(CRect irect)
00080 {
00081         // the method can be called even if the panning window is not visible
00082         if (m_bitmapSizeOri.IsRectEmpty() || m_bitmapSizeStored.IsRectEmpty())
00083                 return;
00084         if (!::IsWindow(GetSafeHwnd()))
00085                 return;
00086 
00087         m_oriToStoredRx = (double)(m_bitmapSizeStored.Width()) / m_bitmapSizeOri.Width();
00088         m_oriToStoredRy = (double)(m_bitmapSizeStored.Height()) / m_bitmapSizeOri.Height();
00089         CRect newViewRectOnStored;
00090         newViewRectOnStored.left        = (int)(irect.left              * m_oriToStoredRx);
00091         newViewRectOnStored.right       = (int)(irect.right             * m_oriToStoredRx);
00092         newViewRectOnStored.top         = (int)(irect.top               * m_oriToStoredRy);
00093         newViewRectOnStored.bottom      = (int)(irect.bottom    * m_oriToStoredRy);
00094         if (m_viewRectOnStored.EqualRect(&newViewRectOnStored))
00095                 return;
00096         else
00097                 m_viewRectOnStored = newViewRectOnStored;
00098 
00099         CRect vRect(0, 0, 0, 0);
00100         CRect client;
00101         GetParent()->GetClientRect(&client);
00102 
00103         BmpToScreen(client);
00104         ViewRectToScreen(vRect);
00105 
00106         InvalidateRect(&m_viewRectOnScreen, FALSE);
00107         m_viewRectOnScreen = vRect;
00108         InvalidateRect(&vRect, FALSE);
00109         UpdateWindow();
00110 }
00111 
00112 void CPanningButton::BmpToScreen(CRect clientr)
00113 {
00114         double dx = (double)(clientr.Width()) / m_bitmapSizeStored.Width();
00115         double dy = (double)(clientr.Height()) / m_bitmapSizeStored.Height();
00116         double dd = (dx <= dy) ? dx: dy;
00117         dd = (dd < 1)? dd: 1;
00118 
00119         clientr.right = min(clientr.right, (LONG)(dd * m_bitmapSizeStored.Width()));
00120         clientr.bottom = min(clientr.bottom, (LONG)(dd * m_bitmapSizeStored.Height()));
00121         m_bitmapOnScreen = clientr;
00122 }
00123 
00124 void CPanningButton::ViewRectToScreen(CRect &vRect)
00125 {
00126         m_storedToScreenRx = (double)(m_bitmapOnScreen.Width()) / m_bitmapSizeStored.Width();
00127         m_storedToScreenRy = (double)(m_bitmapOnScreen.Height()) / m_bitmapSizeStored.Height();
00128         vRect = CRect(0, 0, 0, 0);
00129         vRect.left = (LONG)(m_viewRectOnStored.left * m_storedToScreenRx);
00130         vRect.right = (LONG)(m_viewRectOnStored.right * m_storedToScreenRx);
00131         vRect.top = (LONG)(m_viewRectOnStored.top * m_storedToScreenRy);
00132         vRect.bottom = (LONG)(m_viewRectOnStored.bottom * m_storedToScreenRy);
00133         vRect.right = min(vRect.right, m_bitmapOnScreen.right);
00134         vRect.bottom = min(vRect.bottom, m_bitmapOnScreen.bottom);
00135 }
00136 
00137 void CPanningButton::DeleteDeviceContext(HDC bDC, HBITMAP oldBmp)
00138 {
00139         HBITMAP hBmp = (HBITMAP)::SelectObject(bDC, (HBITMAP)oldBmp);
00140         BOOL succ = FALSE;
00141         if (hBmp != NULL) {
00142                 succ = ::DeleteObject(hBmp);
00143                 ASSERT(succ != FALSE);
00144         }
00145         succ = ::DeleteDC(bDC);
00146         ASSERT(succ != FALSE);
00147 }
00148 
00149 void CPanningButton::OnPaint()
00150 {
00151         CPaintDC dc(this); // device context for painting
00152         dc.SetMapMode(MM_TEXT);
00153 
00154         // clear it
00155         CRect clientr;
00156         GetParent()->GetClientRect(&clientr);
00157         CBrush brush;
00158         COLORREF col;
00159         if (m_bitmapDC == NULL) {
00160                 DWORD dw = ::GetSysColor(COLOR_3DFACE);
00161                 BYTE r = GetRValue(dw);
00162                 BYTE g = GetGValue(dw);
00163                 BYTE b = GetBValue(dw);
00164                 col = RGB(r,g,b);
00165         } else {
00166                 col = m_backgorund;
00167         }
00168         brush.CreateSolidBrush(col);
00169         dc.FillRect(&clientr, &brush);
00170 
00171         // no bitmap - return
00172         if (m_bitmapDC == NULL)
00173                 return;
00174 
00175         ::SetMapMode(m_bitmapDC, MM_TEXT);
00176 
00177         // transform bitmap to screen
00178         BmpToScreen(clientr);
00179         BOOL ret = ::StretchBlt(dc.m_hDC, 0, 0, m_bitmapOnScreen.Width(), m_bitmapOnScreen.Height(), m_bitmapDC,
00180                                                         0, 0, m_bitmapSizeStored.Width(), m_bitmapSizeStored.Height(), SRCCOPY);
00181         if (!ret)
00182                 return;
00183 
00184         CBrush brush1;
00185         DWORD dw1 = GetSysColor(COLOR_WINDOWTEXT);
00186         BYTE r1 = GetRValue(dw1);
00187         BYTE g1 = GetGValue(dw1);
00188         BYTE b1 = GetBValue(dw1);
00189         brush1.CreateSolidBrush(RGB(r1, g1, b1));
00190         if (!m_viewRectOnStored.IsRectEmpty() && m_viewRectOnScreen != m_bitmapOnScreen &&
00191                 !m_viewRectOnScreen.IsRectEmpty())
00192         {
00193                 if (!m_inMove) {
00194                         CRect vRect(0, 0, 0, 0);
00195                         ViewRectToScreen(vRect);
00196                         m_viewRectOnScreen = vRect;
00197                         dc.FrameRect(&m_viewRectOnScreen, &brush1);
00198                 } else {
00199                         dc.FrameRect(&m_viewRectInMove, &brush1);
00200                 }
00201         }
00202 }
00203 
00204 BOOL CPanningButton::OnEraseBkgnd(CDC* pDC)
00205 {
00206         return TRUE;
00207 }
00208 
00209 void CPanningButton::OnMouseMove(UINT nFlags, CPoint point)
00210 {
00211         if (m_viewRectOnScreen.PtInRect(point) || m_inMove)
00212                 SetCursor(m_sizeallh);
00213         else
00214                 SetCursor(m_arrowh);
00215 
00216         if (m_inMove) {
00217                 // move panning frame only
00218                 int dx = point.x - m_moveStartPoint.x;
00219                 int dy = point.y - m_moveStartPoint.y;
00220                 CRect trackRect = m_viewRectOnScreen;
00221                 trackRect.OffsetRect(dx, dy);
00222                 CRect shadow;
00223                 shadow.IntersectRect(&trackRect, &m_bitmapOnScreen);
00224                 if (shadow.Width() != trackRect.Width() && shadow.Height() != trackRect.Height())
00225                         return;
00226                 if (m_viewRectInMove.IsRectEmpty())
00227                         InvalidateRect(&m_viewRectOnScreen, FALSE);
00228                 else
00229                         InvalidateRect(&m_viewRectInMove, FALSE);
00230 
00231                 if (shadow.Width() != trackRect.Width()) {
00232                         if (trackRect.left < 0)
00233                                 trackRect.OffsetRect(-trackRect.left, 0);
00234                         else
00235                                 trackRect.OffsetRect(m_bitmapOnScreen.right - trackRect.right, 0);
00236                 } else if (shadow.Height() != trackRect.Height()) {
00237                         if (trackRect.top < 0)
00238                                 trackRect.OffsetRect(0, -trackRect.top);
00239                         else
00240                                 trackRect.OffsetRect(0, m_bitmapOnScreen.bottom - trackRect.bottom);
00241                 }
00242                 m_viewRectInMove = trackRect;
00243 
00244                 InvalidateRect(&m_viewRectInMove, FALSE);
00245                 UpdateWindow();
00246         }
00247         CWnd::OnMouseMove(nFlags, point);
00248 }
00249 
00250 void CPanningButton::OnLButtonDown(UINT nFlags, CPoint point) 
00251 {
00252         // TODO: Add your message handler code here and/or call default
00253         if (m_viewRectOnScreen.PtInRect(point)) {
00254                 SetCursor(m_sizeallh);
00255                 SetCapture();
00256                 m_inMove = true;
00257                 m_moveStartPoint = point;
00258                 m_moveStartRect = m_viewRectOnScreen;
00259         } else {
00260                 SetCursor(m_arrowh);
00261         }
00262         CWnd::OnLButtonDown(nFlags, point);
00263 }
00264 
00265 void CPanningButton::OnLButtonUp(UINT nFlags, CPoint point)
00266 {
00267         // TODO: Add your message handler code here and/or call default
00268         if (m_inMove) {
00269                 ReleaseCapture();
00270                 m_inMove = false;
00271 //              CWnd* mainw = AfxGetMainWnd();
00272                 if (m_owner) { // mainw)
00273                         double dx = point.x - m_moveStartPoint.x;
00274                         double dy = point.y - m_moveStartPoint.y;
00275                         // dx, dy in pann win screen coordinates
00276                         // calculate real screen coordinates
00277                         dx /= m_storedToScreenRx;
00278                         dy /= m_storedToScreenRy;
00279                         dx /= m_oriToStoredRx;
00280                         dy /= m_oriToStoredRy;
00281                         ::PostMessage(m_owner, WM_PANN_SCROLL, (WPARAM)(int)dx, (LPARAM)(int)dy);
00282                         Invalidate();
00283                 }
00284                 m_viewRectInMove = CRect(0, 0, 0, 0);
00285                 m_moveStartPoint = CPoint(0, 0);
00286                 m_moveStartRect = CRect(0, 0, 0, 0);
00287         }
00288 
00289         CWnd::OnLButtonUp(nFlags, point);
00290 }