windows-nt/Source/XPSP1/NT/windows/feime/cht/cblocks/osbview.cpp
2020-09-26 16:20:57 +08:00

383 lines
10 KiB
C++

/*************************************************
* 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);
}