Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

382 lines
10 KiB

  1. /*************************************************
  2. * osbview.cpp *
  3. * *
  4. * Copyright (C) 1995-1999 Microsoft Inc. *
  5. * *
  6. *************************************************/
  7. // osbview.cpp : implementation of the COSBView class
  8. //
  9. #include "stdafx.h"
  10. #include "cblocks.h"
  11. #include "dib.h"
  12. #include "dibpal.h"
  13. #include "osbview.h"
  14. #ifdef _DEBUG
  15. #undef THIS_FILE
  16. static char BASED_CODE THIS_FILE[] = __FILE__;
  17. #endif
  18. /////////////////////////////////////////////////////////////////////////////
  19. // COSBView
  20. IMPLEMENT_DYNCREATE(COSBView, CScrollView)
  21. BEGIN_MESSAGE_MAP(COSBView, CScrollView)
  22. //{{AFX_MSG_MAP(COSBView)
  23. ON_WM_PALETTECHANGED()
  24. ON_WM_QUERYNEWPALETTE()
  25. //}}AFX_MSG_MAP
  26. END_MESSAGE_MAP()
  27. /////////////////////////////////////////////////////////////////////////////
  28. // COSBView construction/destruction
  29. COSBView::COSBView()
  30. {
  31. m_pDIB = NULL;
  32. m_pPal = NULL;
  33. m_pOneToOneClrTab = NULL;
  34. m_hbmSection = NULL;
  35. // try to get the CreateDIBSection proc. addr.
  36. }
  37. COSBView::~COSBView()
  38. {
  39. if (m_pDIB) delete m_pDIB;
  40. if (m_pPal) delete m_pPal;
  41. if (m_pOneToOneClrTab) free(m_pOneToOneClrTab);
  42. if (m_hbmSection) ::DeleteObject(m_hbmSection);
  43. EmptyDirtyList();
  44. }
  45. // Create a new buffer, tables and palette to match a supplied DIB
  46. BOOL COSBView::Create(CDIB *pDIB)
  47. {
  48. // Create the 1:1 palette index table
  49. if (m_pOneToOneClrTab) free(m_pOneToOneClrTab);
  50. m_pOneToOneClrTab =
  51. (LPBITMAPINFO) malloc(sizeof(BITMAPINFOHEADER)
  52. + 256 * sizeof(WORD));
  53. if (!m_pOneToOneClrTab) {
  54. TRACE("Failed to create color table");
  55. return FALSE;
  56. }
  57. // Set up the table header to match the DIB
  58. // by copying the header and then constructing the 1:1
  59. // index translation table
  60. memcpy(m_pOneToOneClrTab,
  61. pDIB->GetBitmapInfoAddress(),
  62. sizeof(BITMAPINFOHEADER));
  63. WORD *pIndex;
  64. pIndex = (LPWORD)((LPBYTE)m_pOneToOneClrTab + sizeof(BITMAPINFOHEADER));
  65. for (int i = 0; i < 256; i++) {
  66. *pIndex++ = (WORD) i;
  67. }
  68. // Create a palette from the DIB we can use to do screen drawing
  69. if (m_pPal) delete m_pPal;
  70. m_pPal = new CDIBPal;
  71. ASSERT(m_pPal);
  72. if (!m_pPal->Create(pDIB)) {
  73. TRACE("Failed to create palette");
  74. delete m_pPal;
  75. m_pPal = NULL;
  76. return FALSE;
  77. } else {
  78. // map the colors so we get an identity palette
  79. m_pPal->SetSysPalColors();
  80. }
  81. // delete any existing DIB and create a new one
  82. if (m_pDIB) delete m_pDIB;
  83. m_pDIB = new CDIB;
  84. BOOL bResult = FALSE;
  85. if (m_hbmSection)
  86. ::DeleteObject(m_hbmSection);
  87. CDC *pDC = GetDC();
  88. CPalette *pPalOld = pDC->SelectPalette(m_pPal, FALSE);
  89. pDC->RealizePalette();
  90. BYTE *pBits = NULL;
  91. m_hbmSection = CreateDIBSection(pDC->GetSafeHdc(),
  92. m_pOneToOneClrTab,
  93. DIB_PAL_COLORS,
  94. (VOID **) &pBits,
  95. NULL,
  96. 0);
  97. pDC->SelectPalette(pPalOld, FALSE);
  98. ASSERT(m_hbmSection);
  99. ASSERT(pBits);
  100. ReleaseDC(pDC);
  101. bResult = m_pDIB->Create(pDIB->GetBitmapInfoAddress(), pBits);
  102. if (!bResult)
  103. {
  104. TRACE("Failed to create os dib");
  105. delete m_pDIB;
  106. m_pDIB = NULL;
  107. return FALSE;
  108. }
  109. CSize sizeTotal;
  110. sizeTotal.cx = m_pDIB->GetWidth();
  111. sizeTotal.cy = m_pDIB->GetHeight();
  112. SetScrollSizes(MM_TEXT, sizeTotal);
  113. return TRUE;
  114. }
  115. /////////////////////////////////////////////////////////////////////////////
  116. // COSBView drawing
  117. void COSBView::OnInitialUpdate()
  118. {
  119. CSize sizeTotal;
  120. if (m_pDIB) {
  121. sizeTotal.cx = m_pDIB->GetWidth();
  122. sizeTotal.cy = m_pDIB->GetHeight();
  123. } else {
  124. sizeTotal.cx = 640;
  125. sizeTotal.cy = 480;
  126. }
  127. SetScrollSizes(MM_TEXT, sizeTotal);
  128. }
  129. void COSBView::OnDraw(CDC* pDC)
  130. {
  131. Draw();
  132. UNREFERENCED_PARAMETER(pDC);
  133. }
  134. /////////////////////////////////////////////////////////////////////////////
  135. // COSBView diagnostics
  136. #ifdef _DEBUG
  137. void COSBView::AssertValid() const
  138. {
  139. CScrollView::AssertValid();
  140. }
  141. void COSBView::Dump(CDumpContext& dc) const
  142. {
  143. CScrollView::Dump(dc);
  144. }
  145. CDocument* COSBView::GetDocument() // non-debug version is inline
  146. {
  147. return m_pDocument;
  148. }
  149. #endif //_DEBUG
  150. /////////////////////////////////////////////////////////////////////////////
  151. // COSBView message handlers
  152. // Draw a section of the off-screen image buffer to the screen.
  153. void COSBView::Draw(CRect* pRect)
  154. {
  155. CClientDC dc(this);
  156. CRect rcDraw;
  157. // make sure we have what we need to do a paint
  158. if (!m_pDIB || !m_pOneToOneClrTab) {
  159. TRACE("No DIB or clr tab to paint from");
  160. return;
  161. }
  162. // see if a clip rect was supplied and use the client area if not
  163. if (pRect) {
  164. rcDraw = *pRect;
  165. } else {
  166. GetClientRect(rcDraw);
  167. }
  168. // Get the clip box
  169. CRect rcClip;
  170. dc.GetClipBox(rcClip);
  171. // Create a rect for the DIB
  172. CRect rcDIB;
  173. rcDIB.left = rcDIB.top = 0;
  174. rcDIB.right = m_pDIB->GetWidth() - 1;
  175. rcDIB.bottom = m_pDIB->GetHeight() - 1;
  176. // Find a rectangle that describes the intersection of the draw
  177. // rect, clip rect and dib rect
  178. CRect rcBlt = rcDraw & rcClip & rcDIB;
  179. // Copy the update rectangle from the off-screen DC to the
  180. // window DC. Note that DIB origin is lower left corner.
  181. int w, h, xs, xd, yd, ys;
  182. w = rcBlt.right - rcBlt.left;
  183. h = rcBlt.bottom - rcBlt.top;
  184. xs = xd = rcBlt.left;
  185. yd = rcBlt.top;
  186. ys = rcBlt.top;
  187. // if we have a palette, select and realize it
  188. CPalette *ppalOld = NULL;
  189. if(m_pPal) {
  190. ppalOld = dc.SelectPalette(m_pPal, 0);
  191. dc.RealizePalette();
  192. }
  193. HDC dcMem = ::CreateCompatibleDC(dc.GetSafeHdc());
  194. if ( dcMem != NULL )
  195. {
  196. HBITMAP hbmOld = (HBITMAP) ::SelectObject(dcMem, m_hbmSection);
  197. ::BitBlt(dc.GetSafeHdc(),
  198. xd, yd,
  199. w, h,
  200. dcMem,
  201. xs, ys,
  202. SRCCOPY);
  203. ::SelectObject(dcMem, hbmOld);
  204. ::DeleteDC(dcMem);
  205. }
  206. if (ppalOld) dc.SelectPalette(ppalOld, 0);
  207. }
  208. void COSBView::OnPaletteChanged(CWnd* pFocusWnd)
  209. {
  210. // See if the change was caused by us and ignore it if not
  211. if (pFocusWnd != this) {
  212. OnQueryNewPalette();
  213. }
  214. }
  215. // Note: Windows actually ignores the return value
  216. BOOL COSBView::OnQueryNewPalette()
  217. {
  218. // We are going active so realize our palette
  219. if (m_pPal) {
  220. CDC* pdc = GetDC();
  221. CPalette *poldpal = pdc->SelectPalette(m_pPal, FALSE);
  222. UINT u = pdc->RealizePalette();
  223. ReleaseDC(pdc);
  224. if (u != 0) {
  225. // some colors changed so we need to do a repaint
  226. InvalidateRect(NULL, TRUE); // repaint the lot
  227. return TRUE; // say we did something
  228. }
  229. }
  230. return FALSE; // say we did nothing
  231. }
  232. // Add a region to the dirty list
  233. void COSBView::AddDirtyRegion(CRect* prcNew)
  234. {
  235. // get the rectangle currently at the top of the list
  236. POSITION pos = m_DirtyList.GetHeadPosition();
  237. if (pos) {
  238. CRect* prcTop = (CRect*)m_DirtyList.GetNext(pos);
  239. CRect rcTest;
  240. // If the new one intersects the top one merge them
  241. if (rcTest.IntersectRect(prcTop, prcNew)) {
  242. prcTop->UnionRect(prcTop, prcNew);
  243. return;
  244. }
  245. }
  246. // list is empty or there was no intersection
  247. CRect *prc = new CRect;
  248. *prc = *prcNew; // copy the data
  249. // add a new rectangle to the list
  250. m_DirtyList.AddHead((CObject*)prc);
  251. }
  252. // Render and draw all the dirty regions
  253. void COSBView::RenderAndDrawDirtyList()
  254. {
  255. POSITION pos = m_DirtyList.GetHeadPosition();
  256. // Render all the dirty regions
  257. while (pos) {
  258. // get the next region
  259. CRect* pRect = (CRect*)m_DirtyList.GetNext(pos);
  260. // render it
  261. Render(pRect);
  262. }
  263. // Draw all the dirty regions to the screen
  264. while (!m_DirtyList.IsEmpty()) {
  265. // get the next region
  266. CRect* pRect = (CRect*)m_DirtyList.RemoveHead();
  267. Draw(pRect);
  268. // done with it
  269. delete pRect;
  270. }
  271. }
  272. // Empty the dirty list
  273. void COSBView::EmptyDirtyList()
  274. {
  275. while (!m_DirtyList.IsEmpty()) {
  276. CRect* prc = (CRect*)m_DirtyList.RemoveHead();
  277. delete prc;
  278. }
  279. }
  280. // Update the view to reflect some change in the doc
  281. void COSBView::OnUpdate(CView* pSender,
  282. LPARAM lHint,
  283. CObject* pHint)
  284. {
  285. // Render and draw everything
  286. Render();
  287. Draw();
  288. UNREFERENCED_PARAMETER(pSender);
  289. UNREFERENCED_PARAMETER(lHint);
  290. UNREFERENCED_PARAMETER(pHint);
  291. }
  292. void COSBView::Resize(BOOL bShrinkOnly)
  293. {
  294. // adjust parent rect so client rect is appropriate size
  295. // determine current size of the client area as if no scrollbars present
  296. CRect rectClient;
  297. GetWindowRect(rectClient);
  298. CRect rect = rectClient;
  299. CalcWindowRect(rect);
  300. rectClient.left += rectClient.left - rect.left;
  301. rectClient.top += rectClient.top - rect.top;
  302. rectClient.right -= rect.right - rectClient.right;
  303. rectClient.bottom -= rect.bottom - rectClient.bottom;
  304. rectClient.OffsetRect(-rectClient.left, -rectClient.top);
  305. ASSERT(rectClient.left == 0 && rectClient.top == 0);
  306. // determine desired size of the view
  307. CRect rectView(0, 0, m_totalDev.cx, m_totalDev.cy);
  308. if (bShrinkOnly)
  309. {
  310. if (rectClient.right <= m_totalDev.cx)
  311. rectView.right = rectClient.right;
  312. if (rectClient.bottom <= m_totalDev.cy)
  313. rectView.bottom = rectClient.bottom;
  314. }
  315. CalcWindowRect(rectView, CWnd::adjustOutside);
  316. if (bShrinkOnly)
  317. {
  318. if (rectClient.right <= m_totalDev.cx)
  319. rectView.right = rectClient.right;
  320. if (rectClient.bottom <= m_totalDev.cy)
  321. rectView.bottom = rectClient.bottom;
  322. }
  323. CRect rectFrame;
  324. CFrameWnd* pFrame = GetParentFrame();
  325. ASSERT_VALID(pFrame);
  326. pFrame->GetWindowRect(rectFrame);
  327. CSize size = rectFrame.Size();
  328. size.cx += rectView.right - rectClient.right+2;
  329. size.cy += rectView.bottom - rectClient.bottom+2;
  330. pFrame->SetWindowPos(NULL, 0, 0, size.cx, size.cy,
  331. SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE);
  332. }