pseudodc.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634
  1. /////////////////////////////////////////////////////////////////////////////
  2. // Name: pseudodc.cpp
  3. // Purpose: Implementation of the gwxPseudoDC Class
  4. // Author: Paul Lanier
  5. // Modified by: Glynn Clements 2009-01-14
  6. // Created: 05/25/06
  7. // RCS-ID: $Id: pseudodc.cpp 51090 2008-01-08 04:36:23Z RD $
  8. // Copyright: (c) wxWidgets team
  9. // Licence: wxWindows licence
  10. /////////////////////////////////////////////////////////////////////////////
  11. // For compilers that support precompilation, includes "wx.h".
  12. //include "wx/wxprec.h"
  13. #undef DEBUG
  14. #include <Python.h>
  15. #include <wx/wxPython/wxPython.h>
  16. #include "pseudodc.h"
  17. // wxList based class definitions
  18. #include <wx/listimpl.cpp>
  19. WX_DEFINE_LIST(gpdcOpList);
  20. WX_DEFINE_LIST(gpdcObjectList);
  21. //----------------------------------------------------------------------------
  22. // Helper functions used for drawing greyed out versions of objects
  23. //----------------------------------------------------------------------------
  24. wxColour &gwxMakeColourGrey(const wxColour &c)
  25. {
  26. static wxColour rval;
  27. rval.Set(byte((230-c.Red())*0.7+c.Red()),
  28. byte((230-c.Green())*0.7+c.Green()),
  29. byte((230-c.Blue())*0.7+c.Blue()));
  30. return rval;
  31. }
  32. wxBrush &gwxGetGreyBrush(wxBrush &brush)
  33. {
  34. static wxBrush b;
  35. wxColour c;
  36. b = brush;
  37. c = gwxMakeColourGrey(brush.GetColour());
  38. b.SetColour(c);
  39. return b;
  40. }
  41. wxPen &gwxGetGreyPen(wxPen &pen)
  42. {
  43. static wxPen p;
  44. wxColour c;
  45. p = pen;
  46. c = gwxMakeColourGrey(pen.GetColour());
  47. p.SetColour(c);
  48. return p;
  49. }
  50. void gwxGreyOutImage(wxImage &img)
  51. {
  52. unsigned char *data = img.GetData();
  53. unsigned char r,g,b;
  54. unsigned char mr,mg,mb;
  55. int i, tst;
  56. int len = img.GetHeight()*img.GetWidth()*3;
  57. if (img.HasMask())
  58. {
  59. mr = img.GetMaskRed();
  60. mg = img.GetMaskGreen();
  61. mb = img.GetMaskBlue();
  62. }
  63. tst=0;
  64. for (i=0;i<len;i+=3)
  65. {
  66. r=data[i]; g=data[i+1]; b=data[i+2];
  67. if (!img.HasMask() ||
  68. r!=mr || g!=mg || b!=mb)
  69. {
  70. if (!tst)
  71. {
  72. tst=1;
  73. }
  74. r = (unsigned char)((230.0-r)*0.7+r);
  75. g = (unsigned char)((230.0-g)*0.7+g);
  76. b = (unsigned char)((230.0-b)*0.7+b);
  77. data[i]=r; data[i+1]=g; data[i+2]=b;
  78. }
  79. }
  80. }
  81. wxIcon &gwxGetGreyIcon(wxIcon &icon)
  82. {
  83. wxBitmap bmp;
  84. bmp.CopyFromIcon(icon);
  85. wxImage img = bmp.ConvertToImage();
  86. gwxGreyOutImage(img);
  87. wxBitmap bmp2(img,32);
  88. static wxIcon rval;
  89. rval.CopyFromBitmap(bmp2);
  90. return rval;
  91. }
  92. wxBitmap &gwxGetGreyBitmap(wxBitmap &bmp)
  93. {
  94. wxImage img = bmp.ConvertToImage();
  95. gwxGreyOutImage(img);
  96. static wxBitmap rval(img,32);
  97. return rval;
  98. }
  99. // ============================================================================
  100. // various gpdcOp class implementation methods
  101. // ============================================================================
  102. // ----------------------------------------------------------------------------
  103. // gpdcDrawPolyPolygonOp constructor
  104. // ----------------------------------------------------------------------------
  105. gpdcDrawPolyPolygonOp::gpdcDrawPolyPolygonOp(int n, int count[], wxPoint points[],
  106. wxCoord xoffset, wxCoord yoffset, int fillStyle)
  107. {
  108. m_n=n; m_xoffset=xoffset; m_yoffset=yoffset; m_fillStyle=fillStyle;
  109. int total_n=0;
  110. if (n)
  111. {
  112. m_count = new int[n];
  113. for(int i=0; i<n; i++)
  114. {
  115. total_n+=count[i];
  116. m_count[i]=count[i];
  117. }
  118. if (total_n)
  119. {
  120. m_points = new wxPoint[total_n];
  121. for(int j=0; j<total_n; j++)
  122. m_points[j] = points[j];
  123. }
  124. else m_points=NULL;
  125. }
  126. else
  127. {
  128. m_points=NULL;
  129. m_count=NULL;
  130. }
  131. m_totaln = total_n;
  132. }
  133. // ----------------------------------------------------------------------------
  134. // gpdcDrawPolyPolygonOp destructor
  135. // ----------------------------------------------------------------------------
  136. gpdcDrawPolyPolygonOp::~gpdcDrawPolyPolygonOp()
  137. {
  138. if (m_points) delete m_points;
  139. if (m_count) delete m_count;
  140. m_points=NULL;
  141. m_count=NULL;
  142. }
  143. // ----------------------------------------------------------------------------
  144. // gpdcDrawLinesOp constructor
  145. // ----------------------------------------------------------------------------
  146. gpdcDrawLinesOp::gpdcDrawLinesOp(int n, wxPoint points[],
  147. wxCoord xoffset, wxCoord yoffset)
  148. {
  149. m_n=n; m_xoffset=xoffset; m_yoffset=yoffset;
  150. if (n)
  151. {
  152. m_points = new wxPoint[n];
  153. for (int i=0; i<n; i++)
  154. m_points[i] = points[i];
  155. }
  156. else m_points=NULL;
  157. }
  158. // ----------------------------------------------------------------------------
  159. // gpdcDrawLinesOp destructor
  160. // ----------------------------------------------------------------------------
  161. gpdcDrawLinesOp::~gpdcDrawLinesOp()
  162. {
  163. if (m_points) delete m_points;
  164. m_points=NULL;
  165. }
  166. // ----------------------------------------------------------------------------
  167. // gpdcDrawPolygonOp constructor
  168. // ----------------------------------------------------------------------------
  169. gpdcDrawPolygonOp::gpdcDrawPolygonOp(int n, wxPoint points[],
  170. wxCoord xoffset, wxCoord yoffset, int fillStyle)
  171. {
  172. m_n=n; m_xoffset=xoffset; m_yoffset=yoffset; m_fillStyle=fillStyle;
  173. if (n)
  174. {
  175. m_points = new wxPoint[n];
  176. for (int i=0; i<n; i++)
  177. m_points[i] = points[i];
  178. }
  179. else m_points=NULL;
  180. }
  181. // ----------------------------------------------------------------------------
  182. // gpdcDrawPolygonOp destructor
  183. // ----------------------------------------------------------------------------
  184. gpdcDrawPolygonOp::~gpdcDrawPolygonOp()
  185. {
  186. if (m_points) delete m_points;
  187. m_points=NULL;
  188. }
  189. #if wxUSE_SPLINES
  190. // ----------------------------------------------------------------------------
  191. // gpdcDrawSplineOp constructor
  192. // ----------------------------------------------------------------------------
  193. gpdcDrawSplineOp::gpdcDrawSplineOp(int n, wxPoint points[])
  194. {
  195. m_n=n;
  196. if (n)
  197. {
  198. m_points = new wxPoint[n];
  199. for(int i=0; i<n; i++)
  200. m_points[i] = points[i];
  201. }
  202. else m_points=NULL;
  203. }
  204. // ----------------------------------------------------------------------------
  205. // gpdcDrawSplineOp destructor
  206. // ----------------------------------------------------------------------------
  207. gpdcDrawSplineOp::~gpdcDrawSplineOp()
  208. {
  209. if (m_points) delete m_points;
  210. m_points=NULL;
  211. }
  212. #endif // wxUSE_SPLINES
  213. // ============================================================================
  214. // gpdcObject implementation
  215. // ============================================================================
  216. // ----------------------------------------------------------------------------
  217. // DrawToDC - play back the op list to the DC
  218. // ----------------------------------------------------------------------------
  219. void gpdcObject::DrawToDC(wxDC *dc)
  220. {
  221. gpdcOpList::compatibility_iterator node = m_oplist.GetFirst();
  222. while(node)
  223. {
  224. node->GetData()->DrawToDC(dc, m_greyedout);
  225. node = node->GetNext();
  226. }
  227. }
  228. // ----------------------------------------------------------------------------
  229. // Translate - translate all the operations by some dx,dy
  230. // ----------------------------------------------------------------------------
  231. void gpdcObject::Translate(wxCoord dx, wxCoord dy)
  232. {
  233. gpdcOpList::compatibility_iterator node = m_oplist.GetFirst();
  234. while(node)
  235. {
  236. node->GetData()->Translate(dx,dy);
  237. node = node->GetNext();
  238. }
  239. if (m_bounded)
  240. {
  241. m_bounds.x += dx;
  242. m_bounds.y += dy;
  243. }
  244. }
  245. // ----------------------------------------------------------------------------
  246. // SetGreyedOut - set the greyout member and cache grey versions of everything
  247. // if greyout is true
  248. // ----------------------------------------------------------------------------
  249. void gpdcObject::SetGreyedOut(bool greyout)
  250. {
  251. m_greyedout=greyout;
  252. if (greyout)
  253. {
  254. gpdcOpList::compatibility_iterator node = m_oplist.GetFirst();
  255. gpdcOp *obj;
  256. while(node)
  257. {
  258. obj = node->GetData();
  259. obj->CacheGrey();
  260. node = node->GetNext();
  261. }
  262. }
  263. }
  264. // ============================================================================
  265. // gwxPseudoDC implementation
  266. // ============================================================================
  267. // ----------------------------------------------------------------------------
  268. // Destructor
  269. // ----------------------------------------------------------------------------
  270. gwxPseudoDC::~gwxPseudoDC()
  271. {
  272. // delete all the nodes in the list
  273. RemoveAll();
  274. }
  275. // ----------------------------------------------------------------------------
  276. // ClearAll - remove all nodes from list
  277. // ----------------------------------------------------------------------------
  278. void gwxPseudoDC::RemoveAll(void)
  279. {
  280. m_objectlist.Clear();
  281. m_objectIndex.clear();
  282. m_currId = -1;
  283. m_lastObject = NULL;
  284. }
  285. // ----------------------------------------------------------------------------
  286. // GetLen - return the number of operations in the current op list
  287. // ----------------------------------------------------------------------------
  288. int gwxPseudoDC::GetLen(void)
  289. {
  290. gpdcObjectList::compatibility_iterator pt = m_objectlist.GetFirst();
  291. int len=0;
  292. while (pt)
  293. {
  294. len += pt->GetData()->GetLen();
  295. pt = pt->GetNext();
  296. }
  297. return len;
  298. }
  299. // ----------------------------------------------------------------------------
  300. // FindObject - find and return an object node by id. If node doesn't exist
  301. // and create is true then create one and return it. Otherwise
  302. // return NULL.
  303. // ----------------------------------------------------------------------------
  304. gpdcObject *gwxPseudoDC::FindObject(int id, bool create)
  305. {
  306. // see if last operation was for same id
  307. //~ if (m_lastObject && m_lastObject->GetId() == id)
  308. //~ return m_lastObject;
  309. // if not then search for it
  310. gpdcObjectHash::iterator lookup = m_objectIndex.find(id);
  311. if (lookup == m_objectIndex.end()) {//not found
  312. if (create) {
  313. m_lastObject = new gpdcObject(id);
  314. m_objectlist.Append(m_lastObject);
  315. gpdcObjectHash::value_type insert(id, m_lastObject);
  316. m_objectIndex.insert(insert);
  317. return m_lastObject;
  318. } else {
  319. return NULL;
  320. }
  321. } else { //found
  322. return lookup->second;
  323. }
  324. }
  325. // ----------------------------------------------------------------------------
  326. // AddToList - Add a node to the list at the end (preserve draw order)
  327. // ----------------------------------------------------------------------------
  328. void gwxPseudoDC::AddToList(gpdcOp *newOp)
  329. {
  330. gpdcObject *obj = FindObject(m_currId, true);
  331. obj->AddOp(newOp);
  332. }
  333. // ----------------------------------------------------------------------------
  334. // ClearID - remove all the operations associated with a single ID
  335. // ----------------------------------------------------------------------------
  336. void gwxPseudoDC::ClearId(int id)
  337. {
  338. gpdcObject *obj = FindObject(id);
  339. if (obj) obj->Clear();
  340. }
  341. // ----------------------------------------------------------------------------
  342. // RemoveID - Remove the object node (and all operations) associated with an id
  343. // ----------------------------------------------------------------------------
  344. void gwxPseudoDC::RemoveId(int id)
  345. {
  346. gpdcObject *obj = FindObject(id);
  347. if (obj)
  348. {
  349. if (m_lastObject == obj)
  350. m_lastObject = obj;
  351. m_objectlist.DeleteObject(obj);
  352. }
  353. m_objectIndex.erase(id);
  354. }
  355. // ----------------------------------------------------------------------------
  356. // SetIdBounds - Set the bounding rect for a given id
  357. // ----------------------------------------------------------------------------
  358. void gwxPseudoDC::SetIdBounds(int id, wxRect& rect)
  359. {
  360. gpdcObject *obj = FindObject(id, true);
  361. obj->SetBounds(rect);
  362. }
  363. // ----------------------------------------------------------------------------
  364. // GetIdBounds - Get the bounding rect for a given id
  365. // ----------------------------------------------------------------------------
  366. void gwxPseudoDC::GetIdBounds(int id, wxRect& rect)
  367. {
  368. gpdcObject *obj = FindObject(id);
  369. if (obj && obj->IsBounded())
  370. rect = obj->GetBounds();
  371. else
  372. rect.x = rect.y = rect.width = rect.height = 0;
  373. }
  374. // ----------------------------------------------------------------------------
  375. // TranslateId - Translate all the operations of a single id
  376. // ----------------------------------------------------------------------------
  377. void gwxPseudoDC::TranslateId(int id, wxCoord dx, wxCoord dy)
  378. {
  379. gpdcObject *obj = FindObject(id);
  380. if (obj) obj->Translate(dx,dy);
  381. }
  382. // ----------------------------------------------------------------------------
  383. // DrawIdToDC - Draw a specific id to the dc passed in
  384. // ----------------------------------------------------------------------------
  385. void gwxPseudoDC::DrawIdToDC(int id, wxDC *dc)
  386. {
  387. gpdcObject *obj = FindObject(id);
  388. if (obj) obj->DrawToDC(dc);
  389. }
  390. // ----------------------------------------------------------------------------
  391. // SetIdGreyedOut - Set the greyedout member of id
  392. // ----------------------------------------------------------------------------
  393. void gwxPseudoDC::SetIdGreyedOut(int id, bool greyout)
  394. {
  395. gpdcObject *obj = FindObject(id);
  396. if (obj) obj->SetGreyedOut(greyout);
  397. }
  398. // ----------------------------------------------------------------------------
  399. // GetIdGreyedOut - Get the greyedout member of id
  400. // ----------------------------------------------------------------------------
  401. bool gwxPseudoDC::GetIdGreyedOut(int id)
  402. {
  403. gpdcObject *obj = FindObject(id);
  404. if (obj) return obj->GetGreyedOut();
  405. else return false;
  406. }
  407. // ----------------------------------------------------------------------------
  408. // FindObjectsByBBox - Return a list of all the ids whose bounding boxes
  409. // contain (x,y)
  410. // ----------------------------------------------------------------------------
  411. PyObject *gwxPseudoDC::FindObjectsByBBox(wxCoord x, wxCoord y)
  412. {
  413. //wxPyBlock_t blocked = wxPyBeginBlockThreads();
  414. gpdcObjectList::compatibility_iterator pt = m_objectlist.GetFirst();
  415. gpdcObject *obj;
  416. PyObject* pyList = NULL;
  417. pyList = PyList_New(0);
  418. wxRect r;
  419. while (pt)
  420. {
  421. obj = pt->GetData();
  422. r = obj->GetBounds();
  423. if (obj->IsBounded() && r.Contains(x,y))
  424. {
  425. PyObject* pyObj = PyInt_FromLong((long)obj->GetId());
  426. PyList_Insert(pyList, 0, pyObj);
  427. Py_DECREF(pyObj);
  428. }
  429. pt = pt->GetNext();
  430. }
  431. //wxPyEndBlockThreads(blocked);
  432. return pyList;
  433. }
  434. // ----------------------------------------------------------------------------
  435. // FindObjects - Return a list of all the ids that draw to (x,y)
  436. // ----------------------------------------------------------------------------
  437. PyObject *gwxPseudoDC::FindObjects(wxCoord x, wxCoord y,
  438. wxCoord radius, const wxColor& bg)
  439. {
  440. //wxPyBlock_t blocked = wxPyBeginBlockThreads();
  441. gpdcObjectList::compatibility_iterator pt = m_objectlist.GetFirst();
  442. gpdcObject *obj;
  443. PyObject* pyList = NULL;
  444. pyList = PyList_New(0);
  445. wxBrush bgbrush(bg);
  446. wxPen bgpen(bg);
  447. // special case radius = 0
  448. if (radius == 0)
  449. {
  450. wxBitmap bmp(4,4,24);
  451. wxMemoryDC memdc;
  452. wxColor pix;
  453. wxRect viewrect(x-2,y-2,4,4);
  454. // setup the memdc for rendering
  455. memdc.SelectObject(bmp);
  456. memdc.SetBackground(bgbrush);
  457. memdc.Clear();
  458. memdc.SetDeviceOrigin(2-x,2-y);
  459. while (pt)
  460. {
  461. obj = pt->GetData();
  462. if (obj->IsBounded() && obj->GetBounds().Contains(x,y))
  463. {
  464. // start clean
  465. memdc.SetBrush(bgbrush);
  466. memdc.SetPen(bgpen);
  467. memdc.DrawRectangle(viewrect);
  468. // draw the object
  469. obj->DrawToDC(&memdc);
  470. memdc.GetPixel(x,y,&pix);
  471. // clear and update rgn2
  472. if (pix != bg)
  473. {
  474. PyObject* pyObj = PyInt_FromLong((long)obj->GetId());
  475. PyList_Insert(pyList, 0, pyObj);
  476. Py_DECREF(pyObj);
  477. }
  478. }
  479. pt = pt->GetNext();
  480. }
  481. memdc.SelectObject(wxNullBitmap);
  482. }
  483. else
  484. {
  485. wxRect viewrect(x-radius,y-radius,2*radius,2*radius);
  486. wxBitmap maskbmp(2*radius,2*radius,24);
  487. wxMemoryDC maskdc;
  488. // create bitmap with circle for masking
  489. maskdc.SelectObject(maskbmp);
  490. maskdc.SetBackground(*wxBLACK_BRUSH);
  491. maskdc.Clear();
  492. maskdc.SetBrush(*wxWHITE_BRUSH);
  493. maskdc.SetPen(*wxWHITE_PEN);
  494. maskdc.DrawCircle(radius,radius,radius);
  495. // now setup a memdc for rendering our object
  496. wxBitmap bmp(2*radius,2*radius,24);
  497. wxMemoryDC memdc;
  498. memdc.SelectObject(bmp);
  499. // set the origin so (x,y) is in the bmp center
  500. memdc.SetDeviceOrigin(radius-x,radius-y);
  501. // a region will be used to see if the result is empty
  502. wxRegion rgn2;
  503. while (pt)
  504. {
  505. obj = pt->GetData();
  506. if (obj->IsBounded() && viewrect.Intersects(obj->GetBounds()))
  507. {
  508. // start clean
  509. //memdc.Clear();
  510. memdc.SetBrush(bgbrush);
  511. memdc.SetPen(bgpen);
  512. memdc.DrawRectangle(viewrect);
  513. // draw the object
  514. obj->DrawToDC(&memdc);
  515. // remove background color
  516. memdc.SetLogicalFunction(wxXOR);
  517. memdc.SetBrush(bgbrush);
  518. memdc.SetPen(bgpen);
  519. memdc.DrawRectangle(viewrect);
  520. memdc.SetLogicalFunction(wxCOPY);
  521. #ifdef __WXMAC__
  522. // wxAND is not supported on wxMac, but it doesn't seem to
  523. // hurt anything to use wxCOPY instead...
  524. memdc.Blit(x-radius,y-radius,2*radius,2*radius,&maskdc,0,0,wxCOPY);
  525. #else
  526. // AND with circle bitmap
  527. memdc.Blit(x-radius,y-radius,2*radius,2*radius,&maskdc,0,0,wxAND);
  528. #endif
  529. // clear and update rgn2
  530. memdc.SelectObject(wxNullBitmap);
  531. rgn2.Clear();
  532. rgn2.Union(bmp, *wxBLACK);
  533. //rgn2.Intersect(rgn);
  534. memdc.SelectObject(bmp);
  535. if (!rgn2.IsEmpty())
  536. {
  537. PyObject* pyObj = PyInt_FromLong((long)obj->GetId());
  538. PyList_Insert(pyList, 0, pyObj);
  539. Py_DECREF(pyObj);
  540. }
  541. }
  542. pt = pt->GetNext();
  543. }
  544. maskdc.SelectObject(wxNullBitmap);
  545. memdc.SelectObject(wxNullBitmap);
  546. }
  547. //wxPyEndBlockThreads(blocked);
  548. return pyList;
  549. }
  550. // ----------------------------------------------------------------------------
  551. // DrawToDCClipped - play back the op list to the DC but clip any objects
  552. // known to be not in rect. This is a coarse level of
  553. // clipping to speed things up when lots of objects are off
  554. // screen and doesn't affect the dc level clipping
  555. // ----------------------------------------------------------------------------
  556. void gwxPseudoDC::DrawToDCClipped(wxDC *dc, const wxRect& rect)
  557. {
  558. gpdcObjectList::compatibility_iterator pt = m_objectlist.GetFirst();
  559. gpdcObject *obj;
  560. while (pt)
  561. {
  562. obj = pt->GetData();
  563. if (!obj->IsBounded() || rect.Intersects(obj->GetBounds()))
  564. obj->DrawToDC(dc);
  565. pt = pt->GetNext();
  566. }
  567. }
  568. void gwxPseudoDC::DrawToDCClippedRgn(wxDC *dc, const wxRegion& region)
  569. {
  570. gpdcObjectList::compatibility_iterator pt = m_objectlist.GetFirst();
  571. gpdcObject *obj;
  572. while (pt)
  573. {
  574. obj = pt->GetData();
  575. if (!obj->IsBounded() ||
  576. (region.Contains(obj->GetBounds()) != wxOutRegion))
  577. obj->DrawToDC(dc);
  578. pt = pt->GetNext();
  579. }
  580. }
  581. // ----------------------------------------------------------------------------
  582. // DrawToDC - play back the op list to the DC
  583. // ----------------------------------------------------------------------------
  584. void gwxPseudoDC::DrawToDC(wxDC *dc)
  585. {
  586. gpdcObjectList::compatibility_iterator pt = m_objectlist.GetFirst();
  587. while (pt)
  588. {
  589. pt->GetData()->DrawToDC(dc);
  590. pt = pt->GetNext();
  591. }
  592. }