--- /dev/null
+//////////////////////////////////////////////\r
+// View.cpp\r
+// Definitions for the CView class\r
+\r
+#include "stdafx.h"\r
+#include "view.h"\r
+#include "resource.h"\r
+\r
+\r
+CView::CView() : m_xCurrentScroll(0), m_yCurrentScroll(0)\r
+{\r
+}\r
+\r
+CView::~CView()\r
+{\r
+}\r
+\r
+BOOL CView::FileOpen(LPCTSTR szFilename)\r
+{\r
+ if (szFilename)\r
+ {\r
+ m_bmImage.LoadImage(szFilename, 0, 0, LR_LOADFROMFILE);\r
+ }\r
+ else\r
+ m_bmImage.DeleteObject();\r
+\r
+ return (BOOL)m_bmImage.GetHandle();\r
+}\r
+\r
+BOOL CView::FileSave(LPCTSTR pszFile)\r
+ {\r
+ CFile File;\r
+ BOOL bResult = FALSE;\r
+ if (File.Open(pszFile, OPEN_ALWAYS))\r
+ {\r
+ // Create our LPBITMAPINFO object\r
+ CBitmapInfoPtr pbmi(&m_bmImage);\r
+\r
+ // Create the reference DC for GetDIBits to use\r
+ CMemDC MemDC(NULL);\r
+\r
+ // Use GetDIBits to create a DIB from our DDB, and extract the colour data\r
+ MemDC.GetDIBits(&m_bmImage, 0, pbmi->bmiHeader.biHeight, NULL, pbmi, DIB_RGB_COLORS);\r
+ std::vector<byte> vBits(pbmi->bmiHeader.biSizeImage, 0);\r
+ byte* lpvBits = &vBits.front();\r
+\r
+ MemDC.GetDIBits(&m_bmImage, 0, pbmi->bmiHeader.biHeight, lpvBits, pbmi, DIB_RGB_COLORS);\r
+\r
+ LPBITMAPINFOHEADER pbmih = &pbmi->bmiHeader;\r
+ BITMAPFILEHEADER hdr = {0};\r
+ hdr.bfType = 0x4d42; // 0x42 = "B" 0x4d = "M"\r
+ hdr.bfSize = (DWORD) (sizeof(BITMAPFILEHEADER) + pbmih->biSize + pbmih->biClrUsed * sizeof(RGBQUAD) + pbmih->biSizeImage);\r
+ hdr.bfOffBits = (DWORD) sizeof(BITMAPFILEHEADER) + pbmih->biSize + pbmih->biClrUsed * sizeof (RGBQUAD);\r
+\r
+ File.Write((LPCVOID) &hdr, sizeof(BITMAPFILEHEADER));\r
+ File.Write((LPCVOID) pbmih, sizeof(BITMAPINFOHEADER) + pbmih->biClrUsed * sizeof (RGBQUAD));\r
+ File.Write((LPCVOID) lpvBits, (int) pbmih->biSizeImage);\r
+\r
+ if (File.GetLength() == sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + pbmih->biClrUsed * sizeof (RGBQUAD) + (int) pbmih->biSizeImage)\r
+ bResult = TRUE;\r
+ }\r
+\r
+ return bResult;\r
+}\r
+\r
+CRect CView::GetImageRect()\r
+{\r
+ BITMAP bm;\r
+ ::GetObject(m_bmImage, sizeof(BITMAP), &bm);\r
+\r
+ CRect rc;\r
+ rc.right = bm.bmWidth;\r
+ rc.bottom = bm.bmHeight;\r
+\r
+ return rc;\r
+}\r
+\r
+void CView::OnDraw(CDC* pDC)\r
+{\r
+ if (m_bmImage.GetHandle())\r
+ {\r
+ // We have an image, so display it\r
+ CMemDC memDC(pDC);\r
+ CRect rcView = GetClientRect();\r
+ CBitmap* pOldBitmap = memDC.SelectObject(&m_bmImage);\r
+ pDC->BitBlt(0, 0, rcView.Width(), rcView.Height(), &memDC, m_xCurrentScroll, m_yCurrentScroll, SRCCOPY);\r
+ memDC.SelectObject(pOldBitmap);\r
+ }\r
+ else\r
+ {\r
+ // There is no image, so display a hint to get one\r
+ CRect rc = GetClientRect();\r
+ pDC->DrawText(_T("Use the Menu or ToolBar to open a Bitmap File"), -1, rc, DT_CENTER | DT_VCENTER | DT_SINGLELINE);\r
+ }\r
+}\r
+\r
+void CView::OnInitialUpdate()\r
+{\r
+ // OnInitialUpdate is called immediately after the window is created\r
+ TRACE(_T("View window created\n"));\r
+\r
+ ShowScrollBar(SB_BOTH, FALSE);\r
+}\r
+\r
+void CView::OnHScroll(WPARAM wParam, LPARAM lParam)\r
+{\r
+ UNREFERENCED_PARAMETER(lParam);\r
+ int xNewPos;\r
+\r
+ switch (LOWORD(wParam))\r
+ {\r
+ case SB_PAGEUP: // User clicked the scroll bar shaft left of the scroll box.\r
+ xNewPos = m_xCurrentScroll - 50;\r
+ break;\r
+\r
+ case SB_PAGEDOWN: // User clicked the scroll bar shaft right of the scroll box.\r
+ xNewPos = m_xCurrentScroll + 50;\r
+ break;\r
+\r
+ case SB_LINEUP: // User clicked the left arrow.\r
+ xNewPos = m_xCurrentScroll - 5;\r
+ break;\r
+\r
+ case SB_LINEDOWN: // User clicked the right arrow.\r
+ xNewPos = m_xCurrentScroll + 5;\r
+ break;\r
+\r
+ case SB_THUMBPOSITION: // User dragged the scroll box.\r
+ xNewPos = HIWORD(wParam);\r
+ break;\r
+\r
+ case SB_THUMBTRACK: // User dragging the scroll box.\r
+ xNewPos = HIWORD(wParam);\r
+ break;\r
+\r
+ default:\r
+ xNewPos = m_xCurrentScroll;\r
+ }\r
+\r
+ // Scroll the window.\r
+ xNewPos = MAX(0, xNewPos);\r
+ xNewPos = MIN( xNewPos, GetImageRect().Width() - GetClientRect().Width() );\r
+ int xDelta = xNewPos - m_xCurrentScroll;\r
+ m_xCurrentScroll = xNewPos;\r
+ ScrollWindowEx(-xDelta, 0, NULL, NULL, NULL, NULL, SW_INVALIDATE);\r
+\r
+ // Reset the scroll bar.\r
+ SCROLLINFO si = {0};\r
+ si.cbSize = sizeof(si);\r
+ si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;\r
+ si.cbSize = sizeof(si);\r
+ si.fMask = SIF_POS;\r
+ si.nPos = m_xCurrentScroll;\r
+ SetScrollInfo(SB_HORZ, si, TRUE);\r
+}\r
+\r
+void CView::OnVScroll(WPARAM wParam, LPARAM lParam)\r
+{\r
+ UNREFERENCED_PARAMETER(lParam);\r
+ int yNewPos;\r
+\r
+ switch (LOWORD(wParam))\r
+ {\r
+ case SB_PAGEUP: // User clicked the scroll bar shaft above the scroll box.\r
+ yNewPos = m_yCurrentScroll - 50;\r
+ break;\r
+\r
+ case SB_PAGEDOWN: // User clicked the scroll bar shaft below the scroll box.\r
+ yNewPos = m_yCurrentScroll + 50;\r
+ break;\r
+\r
+ case SB_LINEUP: // User clicked the top arrow.\r
+ yNewPos = m_yCurrentScroll - 5;\r
+ break;\r
+\r
+ case SB_LINEDOWN: // User clicked the bottom arrow.\r
+ yNewPos = m_yCurrentScroll + 5;\r
+ break;\r
+\r
+ case SB_THUMBPOSITION: // User dragged the scroll box.\r
+ yNewPos = HIWORD(wParam);\r
+ break;\r
+\r
+ case SB_THUMBTRACK: // User dragging the scroll box.\r
+ yNewPos = HIWORD(wParam);\r
+ break;\r
+\r
+ default:\r
+ yNewPos = m_yCurrentScroll;\r
+ }\r
+\r
+ // Scroll the window.\r
+ yNewPos = MAX(0, yNewPos);\r
+ yNewPos = MIN( yNewPos, GetImageRect().Height() - GetClientRect().Height() );\r
+ int yDelta = yNewPos - m_yCurrentScroll;\r
+ m_yCurrentScroll = yNewPos;\r
+ ScrollWindowEx(0, -yDelta, NULL, NULL, NULL, NULL, SW_INVALIDATE);\r
+\r
+ // Reset the scroll bar.\r
+ SCROLLINFO si = {0};\r
+ si.cbSize = sizeof(si);\r
+ si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;\r
+ si.cbSize = sizeof(si);\r
+ si.fMask = SIF_POS;\r
+ si.nPos = m_yCurrentScroll;\r
+ SetScrollInfo(SB_VERT, si, TRUE);\r
+}\r
+\r
+void CView::OnWindowPosChanged(WPARAM wParam, LPARAM lParam)\r
+{\r
+ UNREFERENCED_PARAMETER(wParam);\r
+ UNREFERENCED_PARAMETER(lParam);\r
+\r
+ if (m_bmImage.GetHandle())\r
+ {\r
+ CRect rcImage = GetImageRect();\r
+ DWORD dwStyle = (DWORD)GetWindowLongPtr(GWL_STYLE);\r
+ DWORD dwExStyle = (DWORD)GetWindowLongPtr(GWL_EXSTYLE);\r
+ AdjustWindowRectEx(&rcImage, dwStyle, FALSE, dwExStyle);\r
+\r
+ CRect rcView = GetClientRect();\r
+ AdjustWindowRectEx(&rcView, dwStyle, FALSE, dwExStyle);\r
+\r
+ SCROLLINFO si = {0};\r
+ si.cbSize = sizeof(si);\r
+ si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;\r
+ si.nMin = 0;\r
+\r
+ if (rcView.Width() >= rcImage.Width())\r
+ {\r
+ m_xCurrentScroll = 0;\r
+ ShowScrollBar(SB_HORZ, FALSE);\r
+ }\r
+ else\r
+ {\r
+ si.nMax = rcImage.Width();\r
+ si.nPage = rcView.Width();\r
+ si.nPos = m_xCurrentScroll;\r
+ SetScrollInfo(SB_HORZ, si, TRUE);\r
+ ShowScrollBar(SB_HORZ, TRUE);\r
+ }\r
+\r
+ if (rcView.Height() >= rcImage.Height())\r
+ {\r
+ m_yCurrentScroll = 0;\r
+ ShowScrollBar(SB_VERT, FALSE);\r
+ }\r
+ else\r
+ {\r
+ si.nMax = rcImage.Height();\r
+ si.nPage = rcView.Height();\r
+ si.nPos = m_yCurrentScroll;\r
+ SetScrollInfo(SB_VERT, si, TRUE);\r
+ ShowScrollBar(SB_VERT, TRUE);\r
+ }\r
+\r
+ int xNewPos = MIN(m_xCurrentScroll, rcImage.Width() - rcView.Width());\r
+ xNewPos = MAX(xNewPos, 0);\r
+ int xDelta = xNewPos - m_xCurrentScroll;\r
+\r
+ int yNewPos = MIN(m_yCurrentScroll, rcImage.Height() - rcView.Height());\r
+ yNewPos = MAX(yNewPos, 0);\r
+ int yDelta = yNewPos - m_yCurrentScroll;\r
+\r
+ ScrollWindowEx(-xDelta, -yDelta, NULL, NULL, NULL, NULL, SW_INVALIDATE);\r
+ m_xCurrentScroll = xNewPos;\r
+ m_yCurrentScroll = yNewPos;\r
+ }\r
+ else\r
+ Invalidate(); // Keep the text centered in the window\r
+}\r
+\r
+void CView::PreCreate(CREATESTRUCT &cs)\r
+{\r
+ // Set the Window Class name\r
+ cs.lpszClass = _T("View");\r
+\r
+ cs.style = WS_CHILD | WS_HSCROLL | WS_VSCROLL ;\r
+\r
+ // Set the extended style\r
+ cs.dwExStyle = WS_EX_CLIENTEDGE;\r
+}\r
+\r
+LRESULT CView::WndProc(UINT uMsg, WPARAM wParam, LPARAM lParam)\r
+{\r
+ switch (uMsg)\r
+ {\r
+ case WM_WINDOWPOSCHANGED:\r
+ OnWindowPosChanged(wParam, lParam);\r
+ break;\r
+\r
+ case WM_HSCROLL:\r
+ OnHScroll(wParam, lParam);\r
+ break;\r
+\r
+ case WM_VSCROLL:\r
+ OnVScroll(wParam, lParam);\r
+ break;\r
+ }\r
+\r
+ // Pass unhandled messages on for default processing\r
+ return WndProcDefault(uMsg, wParam, lParam);\r
+}\r
+\r