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.

459 lines
11 KiB

  1. #include "stdafx.h"
  2. #include "global.h"
  3. #include "sprite.h"
  4. #ifdef _DEBUG
  5. #undef THIS_FILE
  6. static CHAR BASED_CODE THIS_FILE[] = __FILE__;
  7. #endif
  8. #ifdef _DEBUG
  9. IMPLEMENT_DYNAMIC( CDragger, CObject )
  10. IMPLEMENT_DYNAMIC( CMultiDragger, CDragger )
  11. IMPLEMENT_DYNAMIC(CSprite, CDragger)
  12. #endif
  13. #include "memtrace.h"
  14. extern BOOL moduleInit;
  15. /**********************************************************************/
  16. /* CDragger Implementation */
  17. /**********************************************************************/
  18. /*
  19. * OPTIMIZATION
  20. *
  21. * At the moment, draggers get a new DC whenever they need to draw or
  22. * erase. We could cut that in half easily by merging the draw/erase
  23. * code, and achieve even better wins by allocating a single DC for a
  24. * multiple selection draw/erase.
  25. */
  26. CDragger::CDragger( CWnd* pWnd, CRect* pRect )
  27. {
  28. ASSERT(pWnd != NULL);
  29. m_pWnd = pWnd;
  30. m_state = hidden;
  31. m_rect.SetRect(0,0,0,0);
  32. if (pRect != NULL)
  33. m_rect = *pRect;
  34. }
  35. CDragger::~CDragger()
  36. {
  37. if (m_pWnd->m_hWnd != NULL && m_state != hidden)
  38. Hide();
  39. }
  40. /* CDragger::Draw
  41. *
  42. * This is a specialized Draw to draw our drag rectangles; drag
  43. * rectangles are the dotted rectangles which we draw when the user is
  44. * dragging a tracker to move or resize a control.
  45. */
  46. void CDragger::Draw()
  47. {
  48. ASSERT( m_pWnd != NULL );
  49. CRect rect = m_rect;
  50. /*
  51. * This gets complex -- hold on to your hat. The m_rect is
  52. * measured in client coordinates of the window, but since we
  53. * need to use GetWindowDC rather than GetDC (to avoid having
  54. * the m_rect clipped by the dialog's children) we must map
  55. * these coordinates to window coords. We do this by mapping
  56. * them into screen coordinates, computing the offset from the
  57. * upper left corner of the dialog's WindowRect, and mapping
  58. * them back. It's the most efficient way I can think to do
  59. * it; other suggestions are welcome.
  60. */
  61. CRect parentRect;
  62. m_pWnd->GetWindowRect( &parentRect );
  63. m_pWnd->ClientToScreen( &rect );
  64. rect.OffsetRect( -parentRect.left, -parentRect.top );
  65. // now we've got "rect" in the coordinates of the thing we
  66. // want to draw on.
  67. int dx = (rect.right - rect.left) - 1;
  68. int dy = (rect.bottom - rect.top) - 1;
  69. CDC* dc = m_pWnd->GetWindowDC();
  70. ASSERT( dc != NULL );
  71. CBrush* oldBrush = dc->SelectObject( GetHalftoneBrush() );
  72. dc->PatBlt( rect.left , rect.top , dx, 1 , PATINVERT );
  73. dc->PatBlt( rect.left , rect.bottom - 1, dx, 1 , PATINVERT );
  74. dc->PatBlt( rect.left , rect.top , 1 , dy, PATINVERT );
  75. dc->PatBlt( rect.right - 1, rect.top , 1 , dy, PATINVERT );
  76. dc->SelectObject( oldBrush );
  77. m_pWnd->ReleaseDC( dc );
  78. }
  79. /* CDragger::Erase
  80. *
  81. * Since the default draw uses XOR, we can just Draw again to erase!
  82. */
  83. void CDragger::Erase()
  84. {
  85. Draw();
  86. }
  87. /* CDragger::Show, Hide
  88. *
  89. * The "drag rectangle" is the dotted rectangle which we draw when the
  90. * user is moving or resizing a control by dragging it with the mouse.
  91. * These functions erase and draw the drag rectangle, respectively.
  92. */
  93. void CDragger::Hide()
  94. {
  95. if (m_state != shown)
  96. return;
  97. m_state = hidden;
  98. Erase();
  99. }
  100. void CDragger::Show()
  101. {
  102. if (m_state != hidden)
  103. return;
  104. m_state = shown;
  105. Draw();
  106. }
  107. void CDragger::Obscure( BOOL bObscure )
  108. {
  109. if (bObscure)
  110. {
  111. if (m_state != shown)
  112. return;
  113. Hide();
  114. m_state = obscured;
  115. }
  116. else
  117. {
  118. if (m_state != obscured)
  119. return;
  120. m_state = hidden;
  121. Show();
  122. }
  123. }
  124. /* CDragger::Move
  125. *
  126. * Since nearly every single occurance of "CDragger->Show" occurred in
  127. * the context "Hide, m_rect = foo, Show", I decided to merge this
  128. * functionality into a single C++ function.
  129. */
  130. void CDragger::Move(const CRect& newRect, BOOL bForceShow)
  131. {
  132. if ((m_rect == newRect) && !bForceShow)
  133. return;
  134. BOOL fShow = bForceShow || m_state == shown;
  135. Hide();
  136. m_rect = newRect;
  137. if (fShow)
  138. Show();
  139. }
  140. void CDragger::MoveBy(int cx, int cy, BOOL bForceShow)
  141. {
  142. CSize offset (cx, cy);
  143. CPoint newTopLeft = m_rect.TopLeft() + offset;
  144. Move(newTopLeft, bForceShow);
  145. }
  146. CRect CDragger::GetRect() const
  147. {
  148. return m_rect;
  149. }
  150. void CDragger::Move(const CPoint& newTopLeft, BOOL bForceShow)
  151. {
  152. Move(m_rect - m_rect.TopLeft() + newTopLeft, bForceShow);
  153. }
  154. void CDragger::SetSize(const CSize& newSize, BOOL bForceShow)
  155. {
  156. CRect newRect = m_rect;
  157. newRect.right = newRect.left + newSize.cx;
  158. newRect.bottom = newRect.top + newSize.cy;
  159. Move(newRect, bForceShow);
  160. }
  161. CMultiDragger::CMultiDragger() : m_draggerList()
  162. {
  163. ASSERT( m_draggerList.IsEmpty() );
  164. }
  165. CMultiDragger::CMultiDragger(CWnd *pWnd) : CDragger(pWnd), m_draggerList()
  166. {
  167. ASSERT(m_draggerList.IsEmpty());
  168. }
  169. CMultiDragger::~CMultiDragger()
  170. {
  171. POSITION pos = m_draggerList.GetHeadPosition();
  172. while (pos != NULL)
  173. {
  174. CDragger *pDragger = (CDragger*) m_draggerList.GetNext(pos);
  175. delete pDragger;
  176. }
  177. }
  178. CRect CMultiDragger::GetRect() const
  179. {
  180. // accumulate the bounding rectangle for the group
  181. POSITION pos = m_draggerList.GetHeadPosition();
  182. CRect boundRect (32767, 32767, -32767, -32767);
  183. while (pos != NULL)
  184. {
  185. CDragger *pDragger = (CDragger*) m_draggerList.GetNext(pos);
  186. boundRect.left = min (boundRect.left, pDragger->m_rect.left);
  187. boundRect.right = max (boundRect.right, pDragger->m_rect.right);
  188. boundRect.top = min (boundRect.top, pDragger->m_rect.top);
  189. boundRect.bottom= max (boundRect.bottom, pDragger->m_rect.bottom);
  190. }
  191. return boundRect;
  192. }
  193. void CMultiDragger::Hide()
  194. {
  195. // hide each dragger on the list
  196. POSITION pos = m_draggerList.GetHeadPosition();
  197. while (pos != NULL)
  198. {
  199. CDragger* pDragger = (CDragger*) m_draggerList.GetNext(pos);
  200. pDragger->Hide();
  201. }
  202. }
  203. void CMultiDragger::Show()
  204. {
  205. // show each dragger on the list
  206. POSITION pos = m_draggerList.GetHeadPosition();
  207. while (pos != NULL)
  208. {
  209. CDragger* pDragger = (CDragger*) m_draggerList.GetNext(pos);
  210. pDragger->Show();
  211. }
  212. }
  213. void CMultiDragger::Draw()
  214. {
  215. // draw each dragger on the list
  216. POSITION pos = m_draggerList.GetHeadPosition();
  217. while (pos != NULL)
  218. {
  219. CDragger* pDragger = (CDragger*) m_draggerList.GetNext(pos);
  220. pDragger->Draw();
  221. }
  222. }
  223. void CMultiDragger::Erase()
  224. {
  225. // erase each dragger on the list
  226. POSITION pos = m_draggerList.GetHeadPosition();
  227. while (pos != NULL)
  228. {
  229. CDragger* pDragger = (CDragger*) m_draggerList.GetNext(pos);
  230. pDragger->Erase();
  231. }
  232. }
  233. void CMultiDragger::Move(const CPoint& newTopLeft, BOOL bForceShow)
  234. {
  235. // move each dragger to the new top left
  236. // first go through the list and find the current topmost leftmost
  237. // point
  238. CPoint topLeft (32767, 32767);
  239. POSITION pos = m_draggerList.GetHeadPosition();
  240. while (pos != NULL)
  241. {
  242. CDragger* pDragger = (CDragger*) m_draggerList.GetNext(pos);
  243. CRect draggerRect = pDragger->GetRect();
  244. if (draggerRect.left < topLeft.x)
  245. topLeft.x= draggerRect.left;
  246. if (draggerRect.top < topLeft.y)
  247. topLeft.y= draggerRect.top;
  248. }
  249. // now find the offset and move each dragger
  250. CSize offset = newTopLeft - topLeft;
  251. pos = m_draggerList.GetHeadPosition();
  252. while (pos != NULL)
  253. {
  254. CDragger* pDragger = (CDragger*) m_draggerList.GetNext(pos);
  255. pDragger->MoveBy(offset.cx, offset.cy, bForceShow);
  256. }
  257. }
  258. void CMultiDragger::Add(CDragger *pDragger)
  259. {
  260. // add the dragger to the list
  261. ASSERT(pDragger != NULL);
  262. m_draggerList.AddTail(pDragger);
  263. }
  264. void CMultiDragger::Remove(CDragger *pDragger)
  265. {
  266. // remove the dragger from the list
  267. ASSERT(pDragger != NULL);
  268. POSITION pos = m_draggerList.Find(pDragger);
  269. if (pos != NULL)
  270. m_draggerList.RemoveAt(pos);
  271. }
  272. CSprite::CSprite() : m_saveBits()
  273. {
  274. m_state = hidden;
  275. m_pWnd = NULL;
  276. }
  277. CSprite::CSprite(CWnd* pWnd, CRect* pRect)
  278. : CDragger(pWnd, pRect), m_saveBits()
  279. {
  280. m_state = hidden;
  281. m_pWnd = pWnd;
  282. }
  283. CSprite::~CSprite()
  284. {
  285. if (m_pWnd->m_hWnd != NULL && m_state != hidden)
  286. Hide();
  287. }
  288. void CSprite::Move(const CRect& newRect, BOOL bForceShow)
  289. {
  290. CRect rect = newRect;
  291. if ((rect == m_rect) && !bForceShow)
  292. return;
  293. STATE oldState = m_state;
  294. Hide();
  295. if (newRect.Size() != m_rect.Size())
  296. m_saveBits.DeleteObject();
  297. m_rect = rect;
  298. if (bForceShow || oldState == shown)
  299. Show();
  300. }
  301. void CSprite::SaveBits()
  302. {
  303. CClientDC dcWnd(m_pWnd);
  304. CDC dcSave;
  305. CBitmap* pOldBitmap;
  306. dcSave.CreateCompatibleDC(&dcWnd);
  307. if (m_saveBits.m_hObject == NULL)
  308. {
  309. m_saveBits.CreateCompatibleBitmap(&dcWnd, m_rect.Width(),
  310. m_rect.Height());
  311. }
  312. pOldBitmap = dcSave.SelectObject(&m_saveBits);
  313. dcSave.BitBlt(0, 0, m_rect.Width(), m_rect.Height(),
  314. &dcWnd, m_rect.left, m_rect.top, SRCCOPY);
  315. dcSave.SelectObject(pOldBitmap);
  316. }
  317. void CSprite::Erase()
  318. {
  319. if (m_saveBits.m_hObject == NULL)
  320. return;
  321. LONG dwStyle = ::GetWindowLong(m_pWnd->m_hWnd, GWL_STYLE);
  322. ::SetWindowLong(m_pWnd->m_hWnd, GWL_STYLE, dwStyle & ~WS_CLIPCHILDREN);
  323. CClientDC dcWnd(m_pWnd);
  324. CDC dcSave;
  325. CBitmap* pOldBitmap;
  326. dcSave.CreateCompatibleDC(&dcWnd);
  327. pOldBitmap = dcSave.SelectObject(&m_saveBits);
  328. dcWnd.ExcludeUpdateRgn(m_pWnd);
  329. dcWnd.BitBlt(m_rect.left, m_rect.top, m_rect.Width(), m_rect.Height(),
  330. &dcSave, 0, 0, SRCCOPY);
  331. dcSave.SelectObject(pOldBitmap);
  332. ::SetWindowLong(m_pWnd->m_hWnd, GWL_STYLE, dwStyle);
  333. }
  334. CHighlight::CHighlight()
  335. {
  336. m_bdrSize = 2;
  337. }
  338. CHighlight::CHighlight(CWnd *pWnd, CRect *pRect, int bdrSize)
  339. : CDragger(pWnd, pRect)
  340. {
  341. m_bdrSize = bdrSize;
  342. m_rect.InflateRect(m_bdrSize, m_bdrSize);
  343. }
  344. CHighlight::~CHighlight()
  345. {
  346. if (m_pWnd->m_hWnd != NULL && m_state != hidden)
  347. Hide();
  348. }
  349. void CHighlight::Draw()
  350. {
  351. m_pWnd->UpdateWindow();
  352. CClientDC dc(m_pWnd);
  353. CBrush *pOldBrush = dc.SelectObject(GetSysBrush(COLOR_HIGHLIGHT));
  354. // draw the top, right, bottom and left sides
  355. dc.PatBlt(m_rect.left + m_bdrSize, m_rect.top ,
  356. m_rect.Width() - m_bdrSize, m_bdrSize , PATCOPY);
  357. dc.PatBlt(m_rect.right - m_bdrSize , m_rect.top + m_bdrSize ,
  358. m_bdrSize , m_rect.Height() - m_bdrSize, PATCOPY);
  359. dc.PatBlt(m_rect.left , m_rect.bottom - m_bdrSize ,
  360. m_rect.Width() - m_bdrSize, m_bdrSize , PATCOPY);
  361. dc.PatBlt(m_rect.left , m_rect.top ,
  362. m_bdrSize , m_rect.Height() - m_bdrSize, PATCOPY);
  363. // restore the state of the DC
  364. dc.SelectObject(pOldBrush);
  365. }
  366. void CHighlight::Erase()
  367. {
  368. m_pWnd->InvalidateRect(&m_rect);
  369. m_pWnd->UpdateWindow();
  370. }