QZoomView.cpp
上传用户:xp9161
上传日期:2009-12-21
资源大小:70k
文件大小:11k
源码类别:

Windows编程

开发平台:

Visual C++

  1. //===============================
  2. // QZoomView.cpp
  3. //
  4. // Version 1.1, October 8, 2003
  5. // Buggy behaviour with MM_TEXT repaired.
  6. // Erroneous assert when no cursors are set corrected.
  7. // Spurious loupe cursor problem fixed.
  8. //
  9. // Version 1.0, August 29, 2003
  10. // (c) Sjaak Priester, Amsterdam
  11. // www.sjaakpriester.nl
  12. //
  13. // Freeware. Use at your own risk. Comments welcome.
  14. #include "stdafx.h"
  15. #include "QZoomView.h"
  16. #include "QSelectTracker.h"
  17. #define ZOOM_MIN .05f
  18. #define ZOOM_MAX 20.0f
  19. #ifndef MM_NONE
  20. #define MM_NONE 0
  21. #endif
  22. //===========================================
  23. // QZoomView
  24. // Preset zoom factors
  25. float QZoomView::m_DefaultPresets[] =
  26. {
  27. 0.125f, 1.0f/6.0f, 0.25f, 1.0f/3.0f, 0.5f, 2.0f/3.0f, 1.0f,
  28. 1.5f, 2.0f, 3.0f, 4.0f, 6.0f, 8.0f
  29. };
  30. #define INDEX_100PERCENT 6
  31. HCURSOR QZoomView::m_Cursors[5] = { 0 };
  32. IMPLEMENT_DYNAMIC(QZoomView, CScrollView)
  33. BEGIN_MESSAGE_MAP(QZoomView, CScrollView)
  34. ON_WM_LBUTTONDOWN()
  35. ON_WM_SETCURSOR()
  36. ON_WM_KEYUP()
  37. ON_WM_KEYDOWN()
  38. ON_WM_MOUSEWHEEL()
  39. END_MESSAGE_MAP()
  40. QZoomView::QZoomView()
  41. : m_PresetCount(0)
  42. , m_Presets(0)
  43. , m_Mode(ZoomViewOff)
  44. , m_Zoom(1.0f)
  45. , m_PresetIndex(INDEX_100PERCENT)
  46. , m_WheelDelta(0)
  47. , m_MessageBeep(MB_ICONHAND)
  48. {
  49. SetPresets(m_DefaultPresets, sizeof(m_DefaultPresets)/sizeof(float));
  50. }
  51. QZoomView::~QZoomView()
  52. {
  53. delete m_Presets;
  54. }
  55. // QZoomView initializing
  56. BOOL QZoomView::SetPresets(const float * pPresets, int count)
  57. {
  58. if (! pPresets || ! count) return FALSE;
  59. if (pPresets[0] < ZOOM_MIN) return FALSE;
  60. if (pPresets[count - 1] > ZOOM_MAX) return FALSE;
  61. for (int i = 1; i < count; i++)
  62. if (pPresets[i] <= pPresets[i - 1]) return FALSE;
  63. delete m_Presets;
  64. m_Presets = new float[count];
  65. if (m_Presets) ::CopyMemory(m_Presets, pPresets, count * sizeof(float));
  66. m_PresetCount = count;
  67. m_PresetIndex = -1;
  68. for (i = 0; i < count; i++)
  69. if (pPresets[i] == 1.0f)
  70. {
  71. m_PresetIndex = i;
  72. break;
  73. }
  74. return TRUE;
  75. }
  76. float QZoomView::ZoomTo(float zoom)
  77. {
  78. #ifdef _DEBUG
  79. if (m_nMapMode == MM_NONE)
  80. {
  81. TRACE(_T("Error: must call SetScrollSizes() before calling ZoomTo.n"));
  82. ASSERT(FALSE);
  83. return 1.0f;
  84. }
  85. #endif //_DEBUG
  86. if (zoom < ZOOM_MIN) zoom = ZOOM_MIN;
  87. else if (zoom > ZOOM_MAX) zoom = ZOOM_MAX;
  88. TRACE1(_T("Zoom factor = %fn"), zoom);
  89. float prevZoom = m_Zoom;
  90. if (m_Zoom != zoom)
  91. {
  92. m_Zoom = zoom;
  93. CClientDC dc(this);
  94. OnPrepareDC(& dc);
  95. m_totalDev = m_totalLog;
  96. dc.LPtoDP(& m_totalDev);
  97. m_pageDev.cx = m_totalDev.cx / 10;
  98. m_pageDev.cy = m_totalDev.cy / 10;
  99. m_lineDev.cx = m_pageDev.cx / 10;
  100. m_lineDev.cy = m_pageDev.cy / 10;
  101. UpdateBars();
  102. OnZoom(zoom, prevZoom);
  103. Invalidate();
  104. }
  105. m_WheelDelta = 0;
  106. return prevZoom;
  107. }
  108. void QZoomView::ZoomToPreset(int index, const LPPOINT center /* = NULL */)
  109. {
  110. #ifdef _DEBUG
  111. if (m_nMapMode == MM_NONE)
  112. {
  113. TRACE(_T("Error: must call SetScrollSizes() before calling SetZoomIndex.n"));
  114. ASSERT(FALSE);
  115. return;
  116. }
  117. #endif //_DEBUG
  118. ASSERT(index >= 0);
  119. if (index >= m_PresetCount) return;
  120. CPoint pntCenter;
  121. if (center) pntCenter = * center;
  122. else
  123. {
  124. CClientDC dc(this);
  125. OnPrepareDC(& dc);
  126. CRect rcClient;
  127. GetClientRect(rcClient);
  128. pntCenter = rcClient.CenterPoint();
  129. dc.DPtoLP(& pntCenter);
  130. }
  131. m_PresetIndex = index;
  132. ZoomTo(m_Presets[index]);
  133. ScrollToCenter(pntCenter);
  134. }
  135. void QZoomView::ZoomToRectangle(CRect logRect)
  136. {
  137. CRect rcClient;
  138. GetClientRect(rcClient);
  139. // Compensate for scrollbars after zooming
  140. DWORD dwStyle = GetStyle();
  141. CSize szSB;
  142. GetScrollBarSizes(szSB);
  143. if(!(dwStyle & WS_VSCROLL))
  144. rcClient.right -= szSB.cx;
  145. if(!(dwStyle & WS_HSCROLL))
  146. rcClient.bottom -= szSB.cy;
  147. CRect devRect(logRect);
  148. // Original mapmode gives 100% zoom
  149. CClientDC dc(this);
  150. dc.SetMapMode(m_nMapMode);
  151. // Rect for 100% zoom in device coordinates:
  152. dc.LPtoDP(devRect);
  153. devRect.NormalizeRect();
  154. // We need to compare devRect.Width()/rcClient.right to devRect.Height()/rcClient.bottom.
  155. // Give them common denominators and compare just the numerators (assume all
  156. // numbers are positive):
  157. int nx = devRect.Width() * rcClient.bottom;
  158. int ny = devRect.Height() * rcClient.right;
  159. float zoom;
  160. if (nx < ny)
  161. {
  162. if (devRect.Width() < rcClient.right)
  163. rcClient.bottom += szSB.cy;
  164. // We probably don't need a horizontal scrollbar,
  165. // but we can't be sure.
  166. // -1 compensates for roundof errors
  167. zoom = (float)(rcClient.bottom - 1) /(float)devRect.Height();
  168. }
  169. else
  170. {
  171. if (devRect.Height() < rcClient.bottom)
  172. rcClient.right += szSB.cx;
  173. zoom = (float)(rcClient.right - 1) / (float)devRect.Width();
  174. }
  175. ZoomTo(zoom);
  176. m_PresetIndex = -1;
  177. ScrollToCenter(logRect.CenterPoint());
  178. }
  179. BOOL QZoomView::ZoomIn(const LPPOINT pPoint /* = NULL */)
  180. {
  181. if (! m_Presets) return FALSE;
  182. for (int i = 0; i < m_PresetCount; i++) if (m_Presets[i] > m_Zoom) break;
  183. if (i < m_PresetCount)
  184. {
  185. ZoomToPreset(i, pPoint);
  186. return TRUE;
  187. }
  188. else
  189. {
  190. if (m_MessageBeep != NoBeep) MessageBeep(m_MessageBeep);
  191. return FALSE;
  192. }
  193. }
  194. BOOL QZoomView::ZoomOut(const LPPOINT pPoint /* = NULL */)
  195. {
  196. if (! m_Presets) return FALSE;
  197. for (int i = m_PresetCount; --i >= 0;) if (m_Presets[i] < m_Zoom) break;
  198. if (i >= 0)
  199. {
  200. ZoomToPreset(i, pPoint);
  201. return TRUE;
  202. }
  203. else
  204. {
  205. if (m_MessageBeep != NoBeep) MessageBeep(m_MessageBeep);
  206. return FALSE;
  207. }
  208. }
  209. void QZoomView::ZoomToWindow(void)
  210. {
  211. CRect rc(CPoint(0, 0), GetTotalSize());
  212. ZoomToRectangle(rc);
  213. }
  214. BOOL QZoomView::ScrollToCenter(CPoint logCenter)
  215. {
  216. CClientDC dc(this);
  217. OnPrepareDC(& dc);
  218. dc.LPtoDP(& logCenter);
  219. CRect rcClient;
  220. GetClientRect(rcClient);
  221. return OnScrollBy(logCenter - rcClient.CenterPoint());
  222. }
  223. // Added in version 1.1
  224. CRect QZoomView::VisibleRect(void)
  225. {
  226. CRect rcDoc(0, 0, m_totalLog.cx, m_totalLog.cy);
  227. rcDoc.NormalizeRect();
  228. CRect rcClient;
  229. GetClientRect(rcClient);
  230. CClientDC dc(this);
  231. OnPrepareDC(& dc);
  232. dc.DPtoLP(rcClient);
  233. rcClient.NormalizeRect();
  234. rcClient &= rcDoc;
  235. return rcClient;
  236. }
  237. // QZoomView message handlers
  238. void QZoomView::OnLButtonDown(UINT nFlags, CPoint point)
  239. {
  240. int mode = m_Mode;
  241. if (::GetKeyState(VK_SPACE) < 0) mode = ZoomViewDrag;
  242. if (mode == ZoomViewZoomIn || mode == ZoomViewZoomOut)
  243. {
  244. CClientDC dc(this);
  245. OnPrepareDC(& dc);
  246. dc.DPtoLP(& point);
  247. QSelectTracker tracker(this);
  248. tracker.m_CenterSize = 0;
  249. HCURSOR hOldCursor = 0;
  250. HCURSOR hNewCursor = m_Cursors[CursorLoupe];
  251. if (hNewCursor) hOldCursor = ::SetCursor(hNewCursor);
  252. int r = tracker.Track(& dc, nFlags, point);
  253. TRACE1(_T("tracker returns %dn"), r);
  254. if (hOldCursor) ::SetCursor(hOldCursor);
  255. if (r == QTracker::TrackNoMove) // no mouse movement, zoom to point
  256. {
  257. if (::GetKeyState(VK_CONTROL) < 0) mode ^= 3;
  258. if (mode == ZoomViewZoomIn) ZoomIn(& point);
  259. else ZoomOut(& point);
  260. }
  261. else if (r > 0) ZoomToRectangle(tracker.GetRect());
  262. }
  263. else if (mode == ZoomViewDrag)
  264. {
  265. Dragger dragger(this);
  266. HCURSOR hOldCursor = 0;
  267. HCURSOR hNewCursor = m_Cursors[CursorGripClosed];
  268. if (hNewCursor) hOldCursor = ::SetCursor(hNewCursor);
  269. dragger.Track(point);
  270. if (hOldCursor) ::SetCursor(hOldCursor);
  271. }
  272. CScrollView::OnLButtonDown(nFlags, point);
  273. }
  274. BOOL QZoomView::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt)
  275. {
  276. if (nFlags & MK_CONTROL)
  277. {
  278. m_WheelDelta += zDelta;
  279. if (m_WheelDelta >= 120) ZoomOut();
  280. else if (m_WheelDelta <= -120) ZoomIn();
  281. return TRUE;
  282. }
  283. return CScrollView::OnMouseWheel(nFlags, zDelta, pt);
  284. }
  285. BOOL QZoomView::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
  286. {
  287. if (nHitTest != HTCLIENT || m_Mode == ZoomViewOff)
  288. return CScrollView::OnSetCursor(pWnd, nHitTest, message);
  289. SetCursor();
  290. return TRUE;
  291. }
  292. void QZoomView::OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags)
  293. {
  294. if (nChar == VK_CONTROL || nChar == VK_SPACE) SetCursor();
  295. CScrollView::OnKeyUp(nChar, nRepCnt, nFlags);
  296. }
  297. void QZoomView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
  298. {
  299. if (nChar == VK_CONTROL || nChar == VK_SPACE) SetCursor();
  300. CScrollView::OnKeyDown(nChar, nRepCnt, nFlags);
  301. }
  302. void QZoomView::SetCursor(void)
  303. {
  304. int mode = m_Mode;
  305. if (::GetKeyState(VK_SPACE) < 0) mode = ZoomViewDrag;
  306. if ((mode == ZoomViewZoomIn || mode == ZoomViewZoomOut)
  307. && ::GetKeyState(VK_CONTROL) < 0) mode ^= 3;
  308. int iCursor(-1);
  309. switch (mode)
  310. {
  311. case ZoomViewZoomIn:
  312. iCursor = CursorLoupePlus;
  313. break;
  314. case ZoomViewZoomOut:
  315. iCursor = CursorLoupeMinus;
  316. break;
  317. case ZoomViewDrag:
  318. iCursor = CursorGripOpen;
  319. break;
  320. default:
  321. ASSERT(mode == ZoomViewOff); // No other mode allowed
  322. break;
  323. }
  324. HCURSOR h = NULL;
  325. if (iCursor >= 0) h = m_Cursors[iCursor];
  326. if (h) ::SetCursor(h);
  327. }
  328. void QZoomView::OnPrepareDC(CDC* pDC, CPrintInfo* pInfo)
  329. {
  330. CScrollView::OnPrepareDC(pDC, pInfo);
  331. if (!pDC->IsPrinting())
  332. {
  333. ASSERT(m_Zoom > 0.0f);
  334. int denom(1000);
  335. int num((int)(m_Zoom * (float)denom));
  336. // Added in version 1.1
  337. if (pDC->GetMapMode() == MM_TEXT)
  338. {
  339. // MM_TEXT has WindowExt and ViewportExt of (1 x 1),
  340. // so ScaleViewportExt doesn't work properly.
  341. // We compensate by scaling both the WindowExt and ViewportExt.
  342. // (Thanks to Almut Branner)
  343. pDC->SetMapMode(MM_ANISOTROPIC);
  344. pDC->ScaleWindowExt(denom, 1, denom, 1);
  345. num *= denom;
  346. }
  347. else pDC->SetMapMode(MM_ANISOTROPIC);
  348. pDC->ScaleViewportExt(num, denom, num, denom);
  349. CRect rect;
  350. GetClientRect(&rect);
  351. CPoint pntVO = pDC->GetViewportOrg();
  352. // Center in window if small enough
  353. if (m_totalDev.cx < rect.Width())
  354. pntVO.x = (rect.Width() - m_totalDev.cx) / 2;
  355. if (m_totalDev.cy < rect.Height())
  356. pntVO.y = (rect.Height() - m_totalDev.cy) / 2;
  357. pDC->SetViewportOrg(pntVO);
  358. }
  359. }
  360. // Overrideable
  361. // Called when zoom factor is changed, before window is redrawn. Default does nothing.
  362. void QZoomView::OnZoom(float Zoom, float PreviousZoom)
  363. {
  364. }
  365. /* static */
  366. BOOL QZoomView::LoadCursor(CursorType type, UINT nResourceID, HINSTANCE hInst /* = NULL */)
  367. {
  368. ASSERT(type >= 0 && type < 5);
  369. HCURSOR h(0);
  370. if (nResourceID)
  371. {
  372. if (hInst) h = ::LoadCursor(hInst, MAKEINTRESOURCE(nResourceID));
  373. else h = ::AfxGetApp()->LoadCursor(nResourceID);
  374. }
  375. m_Cursors[type] = h;
  376. return h != 0;
  377. }
  378. // QZoomView diagnostics
  379. #ifdef _DEBUG
  380. void QZoomView::AssertValid() const
  381. {
  382. CScrollView::AssertValid();
  383. }
  384. void QZoomView::Dump(CDumpContext& dc) const
  385. {
  386. CScrollView::Dump(dc);
  387. dc << _T("Zoom factor = ") << m_Zoom << _T("n");
  388. }
  389. #endif //_DEBUG
  390. // ==========================
  391. // QZoomView::Dragger
  392. int QZoomView::Dragger::OnMouseMessage(UINT msg, UINT nFlags, CPoint point)
  393. {
  394. ASSERT_KINDOF(CView, m_pWnd);
  395. CSize szScroll = m_PreviousPoint - point;
  396. ((CView *) m_pWnd)->OnScrollBy(szScroll);
  397. return QTracker::OnMouseMessage(msg, nFlags, point);
  398. }