$search
00001 00002 // Name: common/pseudodc.cpp 00003 // Purpose: Implementation of the wxPseudoDC Class 00004 // Author: Paul Lanier 00005 // Modified by: 00006 // Created: 05/25/06 00007 // RCS-ID: $Id: pseudodc.cpp,v 1.3 2006/10/21 01:22:11 RD Exp $ 00008 // Copyright: (c) wxWidgets team 00009 // Licence: wxWindows licence 00011 00012 // For compilers that support precompilation, includes "wx.h". 00013 //include "wx/wxprec.h" 00014 00015 #undef DEBUG 00016 #include <Python.h> 00017 #include "wx/wxPython/wxPython.h" 00018 #include "wx/wxPython/pseudodc.h" 00019 00020 // wxList based class definitions 00021 #include <wx/listimpl.cpp> 00022 WX_DEFINE_LIST(pdcOpList); 00023 WX_DEFINE_LIST(pdcObjectList); 00024 00025 //---------------------------------------------------------------------------- 00026 // Helper functions used for drawing greyed out versions of objects 00027 //---------------------------------------------------------------------------- 00028 wxColour &MakeColourGrey(const wxColour &c) 00029 { 00030 static wxColour rval; 00031 rval.Set(byte((230-c.Red())*0.7+c.Red()), 00032 byte((230-c.Green())*0.7+c.Green()), 00033 byte((230-c.Blue())*0.7+c.Blue())); 00034 return rval; 00035 } 00036 wxBrush &GetGreyBrush(wxBrush &brush) 00037 { 00038 static wxBrush b; 00039 wxColour c; 00040 b = brush; 00041 c = MakeColourGrey(brush.GetColour()); 00042 b.SetColour(c); 00043 return b; 00044 } 00045 00046 wxPen &GetGreyPen(wxPen &pen) 00047 { 00048 static wxPen p; 00049 wxColour c; 00050 p = pen; 00051 c = MakeColourGrey(pen.GetColour()); 00052 p.SetColour(c); 00053 return p; 00054 } 00055 00056 void GreyOutImage(wxImage &img) 00057 { 00058 unsigned char *data = img.GetData(); 00059 unsigned char r,g,b; 00060 unsigned char mr,mg,mb; 00061 int i, tst; 00062 int len = img.GetHeight()*img.GetWidth()*3; 00063 if (img.HasMask()) 00064 { 00065 mr = img.GetMaskRed(); 00066 mg = img.GetMaskGreen(); 00067 mb = img.GetMaskBlue(); 00068 } 00069 tst=0; 00070 for (i=0;i<len;i+=3) 00071 { 00072 r=data[i]; g=data[i+1]; b=data[i+2]; 00073 if (!img.HasMask() || 00074 r!=mr || g!=mg || b!=mb) 00075 { 00076 if (!tst) 00077 { 00078 tst=1; 00079 } 00080 r = (unsigned char)((230.0-r)*0.7+r); 00081 g = (unsigned char)((230.0-g)*0.7+g); 00082 b = (unsigned char)((230.0-b)*0.7+b); 00083 data[i]=r; data[i+1]=g; data[i+2]=b; 00084 } 00085 } 00086 } 00087 00088 wxIcon &GetGreyIcon(wxIcon &icon) 00089 { 00090 wxBitmap bmp; 00091 bmp.CopyFromIcon(icon); 00092 wxImage img = bmp.ConvertToImage(); 00093 GreyOutImage(img); 00094 wxBitmap bmp2(img,32); 00095 static wxIcon rval; 00096 rval.CopyFromBitmap(bmp2); 00097 return rval; 00098 } 00099 00100 wxBitmap &GetGreyBitmap(wxBitmap &bmp) 00101 { 00102 wxImage img = bmp.ConvertToImage(); 00103 GreyOutImage(img); 00104 static wxBitmap rval(img,32); 00105 return rval; 00106 } 00107 00108 // ============================================================================ 00109 // various pdcOp class implementation methods 00110 // ============================================================================ 00111 00112 // ---------------------------------------------------------------------------- 00113 // pdcDrawPolyPolygonOp constructor 00114 // ---------------------------------------------------------------------------- 00115 pdcDrawPolyPolygonOp::pdcDrawPolyPolygonOp(int n, int count[], wxPoint points[], 00116 wxCoord xoffset, wxCoord yoffset, int fillStyle) 00117 { 00118 m_n=n; m_xoffset=xoffset; m_yoffset=yoffset; m_fillStyle=fillStyle; 00119 int total_n=0; 00120 if (n) 00121 { 00122 m_count = new int[n]; 00123 for(int i=0; i<n; i++) 00124 { 00125 total_n+=count[i]; 00126 m_count[i]=count[i]; 00127 } 00128 if (total_n) 00129 { 00130 m_points = new wxPoint[total_n]; 00131 for(int j=0; j<total_n; j++) 00132 m_points[j] = points[j]; 00133 } 00134 else m_points=NULL; 00135 } 00136 else 00137 { 00138 m_points=NULL; 00139 m_count=NULL; 00140 } 00141 m_totaln = total_n; 00142 } 00143 00144 // ---------------------------------------------------------------------------- 00145 // pdcDrawPolyPolygonOp destructor 00146 // ---------------------------------------------------------------------------- 00147 pdcDrawPolyPolygonOp::~pdcDrawPolyPolygonOp() 00148 { 00149 if (m_points) delete m_points; 00150 if (m_count) delete m_count; 00151 m_points=NULL; 00152 m_count=NULL; 00153 } 00154 00155 // ---------------------------------------------------------------------------- 00156 // pdcDrawLinesOp constructor 00157 // ---------------------------------------------------------------------------- 00158 pdcDrawLinesOp::pdcDrawLinesOp(int n, wxPoint points[], 00159 wxCoord xoffset, wxCoord yoffset) 00160 { 00161 m_n=n; m_xoffset=xoffset; m_yoffset=yoffset; 00162 if (n) 00163 { 00164 m_points = new wxPoint[n]; 00165 for (int i=0; i<n; i++) 00166 m_points[i] = points[i]; 00167 } 00168 else m_points=NULL; 00169 } 00170 00171 // ---------------------------------------------------------------------------- 00172 // pdcDrawLinesOp destructor 00173 // ---------------------------------------------------------------------------- 00174 pdcDrawLinesOp::~pdcDrawLinesOp() 00175 { 00176 if (m_points) delete m_points; 00177 m_points=NULL; 00178 } 00179 00180 // ---------------------------------------------------------------------------- 00181 // pdcDrawPolygonOp constructor 00182 // ---------------------------------------------------------------------------- 00183 pdcDrawPolygonOp::pdcDrawPolygonOp(int n, wxPoint points[], 00184 wxCoord xoffset, wxCoord yoffset, int fillStyle) 00185 { 00186 m_n=n; m_xoffset=xoffset; m_yoffset=yoffset; m_fillStyle=fillStyle; 00187 if (n) 00188 { 00189 m_points = new wxPoint[n]; 00190 for (int i=0; i<n; i++) 00191 m_points[i] = points[i]; 00192 } 00193 else m_points=NULL; 00194 } 00195 00196 // ---------------------------------------------------------------------------- 00197 // pdcDrawPolygonOp destructor 00198 // ---------------------------------------------------------------------------- 00199 pdcDrawPolygonOp::~pdcDrawPolygonOp() 00200 { 00201 if (m_points) delete m_points; 00202 m_points=NULL; 00203 } 00204 00205 #if wxUSE_SPLINES 00206 // ---------------------------------------------------------------------------- 00207 // pdcDrawSplineOp constructor 00208 // ---------------------------------------------------------------------------- 00209 pdcDrawSplineOp::pdcDrawSplineOp(int n, wxPoint points[]) 00210 { 00211 m_n=n; 00212 if (n) 00213 { 00214 m_points = new wxPoint[n]; 00215 for(int i=0; i<n; i++) 00216 m_points[i] = points[i]; 00217 } 00218 else m_points=NULL; 00219 } 00220 00221 // ---------------------------------------------------------------------------- 00222 // pdcDrawSplineOp destructor 00223 // ---------------------------------------------------------------------------- 00224 pdcDrawSplineOp::~pdcDrawSplineOp() 00225 { 00226 if (m_points) delete m_points; 00227 m_points=NULL; 00228 } 00229 #endif // wxUSE_SPLINES 00230 00231 // ============================================================================ 00232 // pdcObject implementation 00233 // ============================================================================ 00234 // ---------------------------------------------------------------------------- 00235 // DrawToDC - play back the op list to the DC 00236 // ---------------------------------------------------------------------------- 00237 void pdcObject::DrawToDC(wxDC *dc) 00238 { 00239 pdcOpList::Node *node = m_oplist.GetFirst(); 00240 while(node) 00241 { 00242 node->GetData()->DrawToDC(dc, m_greyedout); 00243 node = node->GetNext(); 00244 } 00245 } 00246 00247 // ---------------------------------------------------------------------------- 00248 // Translate - translate all the operations by some dx,dy 00249 // ---------------------------------------------------------------------------- 00250 void pdcObject::Translate(wxCoord dx, wxCoord dy) 00251 { 00252 pdcOpList::Node *node = m_oplist.GetFirst(); 00253 while(node) 00254 { 00255 node->GetData()->Translate(dx,dy); 00256 node = node->GetNext(); 00257 } 00258 if (m_bounded) 00259 { 00260 m_bounds.x += dx; 00261 m_bounds.y += dy; 00262 } 00263 } 00264 00265 // ---------------------------------------------------------------------------- 00266 // SetGreyedOut - set the greyout member and cache grey versions of everything 00267 // if greyout is true 00268 // ---------------------------------------------------------------------------- 00269 void pdcObject::SetGreyedOut(bool greyout) 00270 { 00271 m_greyedout=greyout; 00272 if (greyout) 00273 { 00274 pdcOpList::Node *node = m_oplist.GetFirst(); 00275 pdcOp *obj; 00276 while(node) 00277 { 00278 00279 obj = node->GetData(); 00280 obj->CacheGrey(); 00281 node = node->GetNext(); 00282 } 00283 } 00284 } 00285 00286 // ============================================================================ 00287 // wxPseudoDC implementation 00288 // ============================================================================ 00289 00290 // ---------------------------------------------------------------------------- 00291 // Destructor 00292 // ---------------------------------------------------------------------------- 00293 wxPseudoDC::~wxPseudoDC() 00294 { 00295 // delete all the nodes in the list 00296 RemoveAll(); 00297 00298 } 00299 00300 // ---------------------------------------------------------------------------- 00301 // ClearAll - remove all nodes from list 00302 // ---------------------------------------------------------------------------- 00303 void wxPseudoDC::RemoveAll(void) 00304 { 00305 m_objectlist.Clear(); 00306 m_currId = -1; 00307 m_lastObjNode = NULL; 00308 } 00309 00310 // ---------------------------------------------------------------------------- 00311 // GetLen - return the number of operations in the current op list 00312 // ---------------------------------------------------------------------------- 00313 int wxPseudoDC::GetLen(void) 00314 { 00315 pdcObjectList::Node *pt = m_objectlist.GetFirst(); 00316 int len=0; 00317 while (pt) 00318 { 00319 len += pt->GetData()->GetLen(); 00320 pt = pt->GetNext(); 00321 } 00322 return len; 00323 } 00324 00325 // ---------------------------------------------------------------------------- 00326 // FindObjNode - find and return an object node by id. If node doesn't exist 00327 // and create is true then create one and return it. Otherwise 00328 // return NULL. 00329 // ---------------------------------------------------------------------------- 00330 pdcObjectList::Node *wxPseudoDC::FindObjNode(int id, bool create) 00331 { 00332 // see if last operation was for same id 00333 if (m_lastObjNode && m_lastObjNode->GetData()->GetId() == id) 00334 return m_lastObjNode; 00335 // if not then search for it 00336 pdcObjectList::Node *pt = m_objectlist.GetFirst(); 00337 while (pt) 00338 { 00339 if (pt->GetData()->GetId() == id) 00340 { 00341 00342 // cache this node for future operations 00343 m_lastObjNode = pt; 00344 return pt; 00345 } 00346 pt = pt->GetNext(); 00347 } 00348 // if create then create and return a new node 00349 if (create) 00350 { 00351 // cache this node for future operations 00352 m_lastObjNode = m_objectlist.Append(new pdcObject(id)); 00353 return m_lastObjNode; 00354 } 00355 // otherwise just return NULL 00356 return NULL; 00357 } 00358 00359 // ---------------------------------------------------------------------------- 00360 // AddToList - Add a node to the list at the end (preserve draw order) 00361 // ---------------------------------------------------------------------------- 00362 void wxPseudoDC::AddToList(pdcOp *newOp) 00363 { 00364 pdcObjectList::Node *pt = FindObjNode(m_currId, true); 00365 pt->GetData()->AddOp(newOp); 00366 } 00367 00368 // ---------------------------------------------------------------------------- 00369 // ClearID - remove all the operations associated with a single ID 00370 // ---------------------------------------------------------------------------- 00371 void wxPseudoDC::ClearId(int id) 00372 { 00373 pdcObjectList::Node *pt = FindObjNode(id); 00374 if (pt) pt->GetData()->Clear(); 00375 } 00376 00377 // ---------------------------------------------------------------------------- 00378 // RemoveID - Remove the object node (and all operations) associated with an id 00379 // ---------------------------------------------------------------------------- 00380 void wxPseudoDC::RemoveId(int id) 00381 { 00382 pdcObjectList::Node *pt = FindObjNode(id); 00383 if (pt) 00384 { 00385 if (m_lastObjNode == pt) 00386 m_lastObjNode = NULL; 00387 m_objectlist.DeleteNode(pt); 00388 } 00389 } 00390 00391 // ---------------------------------------------------------------------------- 00392 // SetIdBounds - Set the bounding rect for a given id 00393 // ---------------------------------------------------------------------------- 00394 void wxPseudoDC::SetIdBounds(int id, wxRect& rect) 00395 { 00396 pdcObjectList::Node *pt = FindObjNode(id, true); 00397 pt->GetData()->SetBounds(rect); 00398 } 00399 00400 // ---------------------------------------------------------------------------- 00401 // GetIdBounds - Get the bounding rect for a given id 00402 // ---------------------------------------------------------------------------- 00403 void wxPseudoDC::GetIdBounds(int id, wxRect& rect) 00404 { 00405 pdcObjectList::Node *pt = FindObjNode(id); 00406 if (pt && pt->GetData()->IsBounded()) 00407 rect = pt->GetData()->GetBounds(); 00408 else 00409 rect.x = rect.y = rect.width = rect.height = 0; 00410 } 00411 00412 // ---------------------------------------------------------------------------- 00413 // TranslateId - Translate all the operations of a single id 00414 // ---------------------------------------------------------------------------- 00415 void wxPseudoDC::TranslateId(int id, wxCoord dx, wxCoord dy) 00416 { 00417 pdcObjectList::Node *pt = FindObjNode(id); 00418 if (pt) pt->GetData()->Translate(dx,dy); 00419 } 00420 00421 // ---------------------------------------------------------------------------- 00422 // DrawIdToDC - Draw a specific id to the dc passed in 00423 // ---------------------------------------------------------------------------- 00424 void wxPseudoDC::DrawIdToDC(int id, wxDC *dc) 00425 { 00426 pdcObjectList::Node *pt = FindObjNode(id); 00427 if (pt) pt->GetData()->DrawToDC(dc); 00428 } 00429 00430 // ---------------------------------------------------------------------------- 00431 // SetIdGreyedOut - Set the greyedout member of id 00432 // ---------------------------------------------------------------------------- 00433 void wxPseudoDC::SetIdGreyedOut(int id, bool greyout) 00434 { 00435 pdcObjectList::Node *pt = FindObjNode(id); 00436 if (pt) pt->GetData()->SetGreyedOut(greyout); 00437 } 00438 00439 // ---------------------------------------------------------------------------- 00440 // GetIdGreyedOut - Get the greyedout member of id 00441 // ---------------------------------------------------------------------------- 00442 bool wxPseudoDC::GetIdGreyedOut(int id) 00443 { 00444 pdcObjectList::Node *pt = FindObjNode(id); 00445 if (pt) return pt->GetData()->GetGreyedOut(); 00446 else return false; 00447 } 00448 00449 // ---------------------------------------------------------------------------- 00450 // FindObjectsByBBox - Return a list of all the ids whose bounding boxes 00451 // contain (x,y) 00452 // ---------------------------------------------------------------------------- 00453 PyObject *wxPseudoDC::FindObjectsByBBox(wxCoord x, wxCoord y) 00454 { 00455 //wxPyBlock_t blocked = wxPyBeginBlockThreads(); 00456 pdcObjectList::Node *pt = m_objectlist.GetFirst(); 00457 pdcObject *obj; 00458 PyObject* pyList = NULL; 00459 pyList = PyList_New(0); 00460 wxRect r; 00461 while (pt) 00462 { 00463 obj = pt->GetData(); 00464 r = obj->GetBounds(); 00465 if (obj->IsBounded() && r.Contains(x,y)) 00466 { 00467 PyObject* pyObj = PyInt_FromLong((long)obj->GetId()); 00468 PyList_Insert(pyList, 0, pyObj); 00469 Py_DECREF(pyObj); 00470 } 00471 pt = pt->GetNext(); 00472 } 00473 //wxPyEndBlockThreads(blocked); 00474 return pyList; 00475 } 00476 00477 // ---------------------------------------------------------------------------- 00478 // FindObjects - Return a list of all the ids that draw to (x,y) 00479 // ---------------------------------------------------------------------------- 00480 PyObject *wxPseudoDC::FindObjects(wxCoord x, wxCoord y, 00481 wxCoord radius, const wxColor& bg) 00482 { 00483 //wxPyBlock_t blocked = wxPyBeginBlockThreads(); 00484 pdcObjectList::Node *pt = m_objectlist.GetFirst(); 00485 pdcObject *obj; 00486 PyObject* pyList = NULL; 00487 pyList = PyList_New(0); 00488 wxBrush bgbrush(bg); 00489 wxPen bgpen(bg); 00490 // special case radius = 0 00491 if (radius == 0) 00492 { 00493 wxBitmap bmp(4,4,24); 00494 wxMemoryDC memdc; 00495 wxColor pix; 00496 wxRect viewrect(x-2,y-2,4,4); 00497 // setup the memdc for rendering 00498 memdc.SelectObject(bmp); 00499 memdc.SetBackground(bgbrush); 00500 memdc.Clear(); 00501 memdc.SetDeviceOrigin(2-x,2-y); 00502 while (pt) 00503 { 00504 obj = pt->GetData(); 00505 if (obj->IsBounded() && obj->GetBounds().Contains(x,y)) 00506 { 00507 // start clean 00508 memdc.SetBrush(bgbrush); 00509 memdc.SetPen(bgpen); 00510 memdc.DrawRectangle(viewrect); 00511 // draw the object 00512 obj->DrawToDC(&memdc); 00513 memdc.GetPixel(x,y,&pix); 00514 // clear and update rgn2 00515 if (pix != bg) 00516 { 00517 PyObject* pyObj = PyInt_FromLong((long)obj->GetId()); 00518 PyList_Insert(pyList, 0, pyObj); 00519 Py_DECREF(pyObj); 00520 } 00521 } 00522 pt = pt->GetNext(); 00523 } 00524 memdc.SelectObject(wxNullBitmap); 00525 } 00526 else 00527 { 00528 wxRect viewrect(x-radius,y-radius,2*radius,2*radius); 00529 wxBitmap maskbmp(2*radius,2*radius,24); 00530 wxMemoryDC maskdc; 00531 // create bitmap with circle for masking 00532 maskdc.SelectObject(maskbmp); 00533 maskdc.SetBackground(*wxBLACK_BRUSH); 00534 maskdc.Clear(); 00535 maskdc.SetBrush(*wxWHITE_BRUSH); 00536 maskdc.SetPen(*wxWHITE_PEN); 00537 maskdc.DrawCircle(radius,radius,radius); 00538 // now setup a memdc for rendering our object 00539 wxBitmap bmp(2*radius,2*radius,24); 00540 wxMemoryDC memdc; 00541 memdc.SelectObject(bmp); 00542 // set the origin so (x,y) is in the bmp center 00543 memdc.SetDeviceOrigin(radius-x,radius-y); 00544 // a region will be used to see if the result is empty 00545 wxRegion rgn2; 00546 while (pt) 00547 { 00548 obj = pt->GetData(); 00549 if (obj->IsBounded() && viewrect.Intersects(obj->GetBounds())) 00550 { 00551 // start clean 00552 //memdc.Clear(); 00553 memdc.SetBrush(bgbrush); 00554 memdc.SetPen(bgpen); 00555 memdc.DrawRectangle(viewrect); 00556 // draw the object 00557 obj->DrawToDC(&memdc); 00558 // remove background color 00559 memdc.SetLogicalFunction(wxXOR); 00560 memdc.SetBrush(bgbrush); 00561 memdc.SetPen(bgpen); 00562 memdc.DrawRectangle(viewrect); 00563 memdc.SetLogicalFunction(wxCOPY); 00564 #ifdef __WXMAC__ 00565 // wxAND is not supported on wxMac, but it doesn't seem to 00566 // hurt anything to use wxCOPY instead... 00567 memdc.Blit(x-radius,y-radius,2*radius,2*radius,&maskdc,0,0,wxCOPY); 00568 #else 00569 // AND with circle bitmap 00570 memdc.Blit(x-radius,y-radius,2*radius,2*radius,&maskdc,0,0,wxAND); 00571 #endif 00572 // clear and update rgn2 00573 memdc.SelectObject(wxNullBitmap); 00574 rgn2.Clear(); 00575 rgn2.Union(bmp, *wxBLACK); 00576 //rgn2.Intersect(rgn); 00577 memdc.SelectObject(bmp); 00578 if (!rgn2.IsEmpty()) 00579 { 00580 PyObject* pyObj = PyInt_FromLong((long)obj->GetId()); 00581 PyList_Insert(pyList, 0, pyObj); 00582 Py_DECREF(pyObj); 00583 } 00584 } 00585 pt = pt->GetNext(); 00586 } 00587 maskdc.SelectObject(wxNullBitmap); 00588 memdc.SelectObject(wxNullBitmap); 00589 } 00590 //wxPyEndBlockThreads(blocked); 00591 return pyList; 00592 } 00593 00594 // ---------------------------------------------------------------------------- 00595 // DrawToDCClipped - play back the op list to the DC but clip any objects 00596 // known to be not in rect. This is a coarse level of 00597 // clipping to speed things up when lots of objects are off 00598 // screen and doesn't affect the dc level clipping 00599 // ---------------------------------------------------------------------------- 00600 void wxPseudoDC::DrawToDCClipped(wxDC *dc, const wxRect& rect) 00601 { 00602 pdcObjectList::Node *pt = m_objectlist.GetFirst(); 00603 pdcObject *obj; 00604 while (pt) 00605 { 00606 obj = pt->GetData(); 00607 if (!obj->IsBounded() || rect.Intersects(obj->GetBounds())) 00608 obj->DrawToDC(dc); 00609 pt = pt->GetNext(); 00610 } 00611 } 00612 void wxPseudoDC::DrawToDCClippedRgn(wxDC *dc, const wxRegion& region) 00613 { 00614 pdcObjectList::Node *pt = m_objectlist.GetFirst(); 00615 pdcObject *obj; 00616 while (pt) 00617 { 00618 obj = pt->GetData(); 00619 if (!obj->IsBounded() || 00620 (region.Contains(obj->GetBounds()) != wxOutRegion)) 00621 obj->DrawToDC(dc); 00622 pt = pt->GetNext(); 00623 } 00624 } 00625 00626 // ---------------------------------------------------------------------------- 00627 // DrawToDC - play back the op list to the DC 00628 // ---------------------------------------------------------------------------- 00629 void wxPseudoDC::DrawToDC(wxDC *dc) 00630 { 00631 pdcObjectList::Node *pt = m_objectlist.GetFirst(); 00632 while (pt) 00633 { 00634 pt->GetData()->DrawToDC(dc); 00635 pt = pt->GetNext(); 00636 } 00637 } 00638