pseudodc.cpp 20 KB

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