/************************************************* * osbview.cpp * * * * Copyright (C) 1995-1999 Microsoft Inc. * * * *************************************************/ // osbview.cpp : implementation of the COSBView class // #include "stdafx.h" #include "cblocks.h" #include "dib.h" #include "dibpal.h" #include "osbview.h" #ifdef _DEBUG #undef THIS_FILE static char BASED_CODE THIS_FILE[] = __FILE__; #endif ///////////////////////////////////////////////////////////////////////////// // COSBView IMPLEMENT_DYNCREATE(COSBView, CScrollView) BEGIN_MESSAGE_MAP(COSBView, CScrollView) //{{AFX_MSG_MAP(COSBView) ON_WM_PALETTECHANGED() ON_WM_QUERYNEWPALETTE() //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // COSBView construction/destruction COSBView::COSBView() { m_pDIB = NULL; m_pPal = NULL; m_pOneToOneClrTab = NULL; m_hbmSection = NULL; // try to get the CreateDIBSection proc. addr. } COSBView::~COSBView() { if (m_pDIB) delete m_pDIB; if (m_pPal) delete m_pPal; if (m_pOneToOneClrTab) free(m_pOneToOneClrTab); if (m_hbmSection) ::DeleteObject(m_hbmSection); EmptyDirtyList(); } // Create a new buffer, tables and palette to match a supplied DIB BOOL COSBView::Create(CDIB *pDIB) { // Create the 1:1 palette index table if (m_pOneToOneClrTab) free(m_pOneToOneClrTab); m_pOneToOneClrTab = (LPBITMAPINFO) malloc(sizeof(BITMAPINFOHEADER) + 256 * sizeof(WORD)); if (!m_pOneToOneClrTab) { TRACE("Failed to create color table"); return FALSE; } // Set up the table header to match the DIB // by copying the header and then constructing the 1:1 // index translation table memcpy(m_pOneToOneClrTab, pDIB->GetBitmapInfoAddress(), sizeof(BITMAPINFOHEADER)); WORD *pIndex; pIndex = (LPWORD)((LPBYTE)m_pOneToOneClrTab + sizeof(BITMAPINFOHEADER)); for (int i = 0; i < 256; i++) { *pIndex++ = (WORD) i; } // Create a palette from the DIB we can use to do screen drawing if (m_pPal) delete m_pPal; m_pPal = new CDIBPal; ASSERT(m_pPal); if (!m_pPal->Create(pDIB)) { TRACE("Failed to create palette"); delete m_pPal; m_pPal = NULL; return FALSE; } else { // map the colors so we get an identity palette m_pPal->SetSysPalColors(); } // delete any existing DIB and create a new one if (m_pDIB) delete m_pDIB; m_pDIB = new CDIB; BOOL bResult = FALSE; if (m_hbmSection) ::DeleteObject(m_hbmSection); CDC *pDC = GetDC(); CPalette *pPalOld = pDC->SelectPalette(m_pPal, FALSE); pDC->RealizePalette(); BYTE *pBits = NULL; m_hbmSection = CreateDIBSection(pDC->GetSafeHdc(), m_pOneToOneClrTab, DIB_PAL_COLORS, (VOID **) &pBits, NULL, 0); pDC->SelectPalette(pPalOld, FALSE); ASSERT(m_hbmSection); ASSERT(pBits); ReleaseDC(pDC); bResult = m_pDIB->Create(pDIB->GetBitmapInfoAddress(), pBits); if (!bResult) { TRACE("Failed to create os dib"); delete m_pDIB; m_pDIB = NULL; return FALSE; } CSize sizeTotal; sizeTotal.cx = m_pDIB->GetWidth(); sizeTotal.cy = m_pDIB->GetHeight(); SetScrollSizes(MM_TEXT, sizeTotal); return TRUE; } ///////////////////////////////////////////////////////////////////////////// // COSBView drawing void COSBView::OnInitialUpdate() { CSize sizeTotal; if (m_pDIB) { sizeTotal.cx = m_pDIB->GetWidth(); sizeTotal.cy = m_pDIB->GetHeight(); } else { sizeTotal.cx = 640; sizeTotal.cy = 480; } SetScrollSizes(MM_TEXT, sizeTotal); } void COSBView::OnDraw(CDC* pDC) { Draw(); UNREFERENCED_PARAMETER(pDC); } ///////////////////////////////////////////////////////////////////////////// // COSBView diagnostics #ifdef _DEBUG void COSBView::AssertValid() const { CScrollView::AssertValid(); } void COSBView::Dump(CDumpContext& dc) const { CScrollView::Dump(dc); } CDocument* COSBView::GetDocument() // non-debug version is inline { return m_pDocument; } #endif //_DEBUG ///////////////////////////////////////////////////////////////////////////// // COSBView message handlers // Draw a section of the off-screen image buffer to the screen. void COSBView::Draw(CRect* pRect) { CClientDC dc(this); CRect rcDraw; // make sure we have what we need to do a paint if (!m_pDIB || !m_pOneToOneClrTab) { TRACE("No DIB or clr tab to paint from"); return; } // see if a clip rect was supplied and use the client area if not if (pRect) { rcDraw = *pRect; } else { GetClientRect(rcDraw); } // Get the clip box CRect rcClip; dc.GetClipBox(rcClip); // Create a rect for the DIB CRect rcDIB; rcDIB.left = rcDIB.top = 0; rcDIB.right = m_pDIB->GetWidth() - 1; rcDIB.bottom = m_pDIB->GetHeight() - 1; // Find a rectangle that describes the intersection of the draw // rect, clip rect and dib rect CRect rcBlt = rcDraw & rcClip & rcDIB; // Copy the update rectangle from the off-screen DC to the // window DC. Note that DIB origin is lower left corner. int w, h, xs, xd, yd, ys; w = rcBlt.right - rcBlt.left; h = rcBlt.bottom - rcBlt.top; xs = xd = rcBlt.left; yd = rcBlt.top; ys = rcBlt.top; // if we have a palette, select and realize it CPalette *ppalOld = NULL; if(m_pPal) { ppalOld = dc.SelectPalette(m_pPal, 0); dc.RealizePalette(); } HDC dcMem = ::CreateCompatibleDC(dc.GetSafeHdc()); if ( dcMem != NULL ) { HBITMAP hbmOld = (HBITMAP) ::SelectObject(dcMem, m_hbmSection); ::BitBlt(dc.GetSafeHdc(), xd, yd, w, h, dcMem, xs, ys, SRCCOPY); ::SelectObject(dcMem, hbmOld); ::DeleteDC(dcMem); } if (ppalOld) dc.SelectPalette(ppalOld, 0); } void COSBView::OnPaletteChanged(CWnd* pFocusWnd) { // See if the change was caused by us and ignore it if not if (pFocusWnd != this) { OnQueryNewPalette(); } } // Note: Windows actually ignores the return value BOOL COSBView::OnQueryNewPalette() { // We are going active so realize our palette if (m_pPal) { CDC* pdc = GetDC(); CPalette *poldpal = pdc->SelectPalette(m_pPal, FALSE); UINT u = pdc->RealizePalette(); ReleaseDC(pdc); if (u != 0) { // some colors changed so we need to do a repaint InvalidateRect(NULL, TRUE); // repaint the lot return TRUE; // say we did something } } return FALSE; // say we did nothing } // Add a region to the dirty list void COSBView::AddDirtyRegion(CRect* prcNew) { // get the rectangle currently at the top of the list POSITION pos = m_DirtyList.GetHeadPosition(); if (pos) { CRect* prcTop = (CRect*)m_DirtyList.GetNext(pos); CRect rcTest; // If the new one intersects the top one merge them if (rcTest.IntersectRect(prcTop, prcNew)) { prcTop->UnionRect(prcTop, prcNew); return; } } // list is empty or there was no intersection CRect *prc = new CRect; *prc = *prcNew; // copy the data // add a new rectangle to the list m_DirtyList.AddHead((CObject*)prc); } // Render and draw all the dirty regions void COSBView::RenderAndDrawDirtyList() { POSITION pos = m_DirtyList.GetHeadPosition(); // Render all the dirty regions while (pos) { // get the next region CRect* pRect = (CRect*)m_DirtyList.GetNext(pos); // render it Render(pRect); } // Draw all the dirty regions to the screen while (!m_DirtyList.IsEmpty()) { // get the next region CRect* pRect = (CRect*)m_DirtyList.RemoveHead(); Draw(pRect); // done with it delete pRect; } } // Empty the dirty list void COSBView::EmptyDirtyList() { while (!m_DirtyList.IsEmpty()) { CRect* prc = (CRect*)m_DirtyList.RemoveHead(); delete prc; } } // Update the view to reflect some change in the doc void COSBView::OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint) { // Render and draw everything Render(); Draw(); UNREFERENCED_PARAMETER(pSender); UNREFERENCED_PARAMETER(lHint); UNREFERENCED_PARAMETER(pHint); } void COSBView::Resize(BOOL bShrinkOnly) { // adjust parent rect so client rect is appropriate size // determine current size of the client area as if no scrollbars present CRect rectClient; GetWindowRect(rectClient); CRect rect = rectClient; CalcWindowRect(rect); rectClient.left += rectClient.left - rect.left; rectClient.top += rectClient.top - rect.top; rectClient.right -= rect.right - rectClient.right; rectClient.bottom -= rect.bottom - rectClient.bottom; rectClient.OffsetRect(-rectClient.left, -rectClient.top); ASSERT(rectClient.left == 0 && rectClient.top == 0); // determine desired size of the view CRect rectView(0, 0, m_totalDev.cx, m_totalDev.cy); if (bShrinkOnly) { if (rectClient.right <= m_totalDev.cx) rectView.right = rectClient.right; if (rectClient.bottom <= m_totalDev.cy) rectView.bottom = rectClient.bottom; } CalcWindowRect(rectView, CWnd::adjustOutside); if (bShrinkOnly) { if (rectClient.right <= m_totalDev.cx) rectView.right = rectClient.right; if (rectClient.bottom <= m_totalDev.cy) rectView.bottom = rectClient.bottom; } CRect rectFrame; CFrameWnd* pFrame = GetParentFrame(); ASSERT_VALID(pFrame); pFrame->GetWindowRect(rectFrame); CSize size = rectFrame.Size(); size.cx += rectView.right - rectClient.right+2; size.cy += rectView.bottom - rectClient.bottom+2; pFrame->SetWindowPos(NULL, 0, 0, size.cx, size.cy, SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE); }