| 1 | ///////////////////////////////////////////////////////////////////////////// |
| 2 | // Name: drawlist.cpp |
| 3 | // Purpose: Helper functions for optimized list drawing on a wxDC |
| 4 | // |
| 5 | // Author: Robin Dunn, Chris Barker |
| 6 | // |
| 7 | // Created: |
| 8 | // RCS-ID: $Id$ |
| 9 | // Copyright: (c) 2003 by Total Control Software |
| 10 | // Licence: wxWindows license |
| 11 | ///////////////////////////////////////////////////////////////////////////// |
| 12 | |
| 13 | |
| 14 | #undef DEBUG |
| 15 | #include <Python.h> |
| 16 | #include "wx/wxPython/wxPython.h" |
| 17 | #include "wx/wxPython/pydrawxxx.h" |
| 18 | |
| 19 | |
| 20 | //--------------------------------------------------------------------------- |
| 21 | |
| 22 | |
| 23 | // Called from _gdiinit so we can do the API import while the GIL is held |
| 24 | void wxPyDrawList_SetAPIPtr() |
| 25 | { |
| 26 | wxPyCoreAPI_IMPORT(); |
| 27 | } |
| 28 | |
| 29 | |
| 30 | PyObject* wxPyDrawXXXList(wxDC& dc, wxPyDrawListOp_t doDraw, |
| 31 | PyObject* pyCoords, PyObject* pyPens, PyObject* pyBrushes) |
| 32 | { |
| 33 | wxPyBlock_t blocked = wxPyBeginBlockThreads(); |
| 34 | |
| 35 | bool isFastSeq = PyList_Check(pyCoords) || PyTuple_Check(pyCoords); |
| 36 | bool isFastPens = PyList_Check(pyPens) || PyTuple_Check(pyPens); |
| 37 | bool isFastBrushes = PyList_Check(pyBrushes) || PyTuple_Check(pyBrushes); |
| 38 | int numObjs = 0; |
| 39 | int numPens = 0; |
| 40 | int numBrushes = 0; |
| 41 | wxPen* pen; |
| 42 | wxBrush* brush; |
| 43 | PyObject* obj; |
| 44 | PyObject* coords; |
| 45 | int i = 0; |
| 46 | PyObject* retval; |
| 47 | |
| 48 | if (!PySequence_Check(pyCoords)) { |
| 49 | goto err0; |
| 50 | } |
| 51 | if (!PySequence_Check(pyPens)) { |
| 52 | goto err1; |
| 53 | } |
| 54 | if (!PySequence_Check(pyBrushes)) { |
| 55 | goto err2; |
| 56 | } |
| 57 | numObjs = PySequence_Length(pyCoords); |
| 58 | numPens = PySequence_Length(pyPens); |
| 59 | numBrushes = PySequence_Length(pyBrushes); |
| 60 | for (i = 0; i < numObjs; i++) { |
| 61 | // Use a new pen? |
| 62 | if (i < numPens) { |
| 63 | if (isFastPens) { |
| 64 | obj = PySequence_Fast_GET_ITEM(pyPens, i); |
| 65 | } |
| 66 | else { |
| 67 | obj = PySequence_GetItem(pyPens, i); |
| 68 | } |
| 69 | if (! wxPyConvertSwigPtr(obj, (void **) &pen, wxT("wxPen"))) { |
| 70 | if (!isFastPens) |
| 71 | Py_DECREF(obj); |
| 72 | goto err1; |
| 73 | } |
| 74 | |
| 75 | dc.SetPen(*pen); |
| 76 | if (!isFastPens) |
| 77 | Py_DECREF(obj); |
| 78 | } |
| 79 | // Use a new brush? |
| 80 | if (i < numBrushes) { |
| 81 | if (isFastBrushes) { |
| 82 | obj = PySequence_Fast_GET_ITEM(pyBrushes, i); |
| 83 | } |
| 84 | else { |
| 85 | obj = PySequence_GetItem(pyBrushes, i); |
| 86 | } |
| 87 | if (!wxPyConvertSwigPtr(obj, (void **) &brush, wxT("wxBrush"))) { |
| 88 | if (!isFastBrushes) |
| 89 | Py_DECREF(obj); |
| 90 | goto err2; |
| 91 | } |
| 92 | |
| 93 | dc.SetBrush(*brush); |
| 94 | if (!isFastBrushes) |
| 95 | Py_DECREF(obj); |
| 96 | } |
| 97 | |
| 98 | // Get the Coordinates |
| 99 | if (isFastSeq) { |
| 100 | coords = PySequence_Fast_GET_ITEM(pyCoords, i); |
| 101 | } |
| 102 | else { |
| 103 | coords = PySequence_GetItem(pyCoords, i); |
| 104 | } |
| 105 | |
| 106 | |
| 107 | // call the drawOp |
| 108 | bool success = doDraw(dc, coords); |
| 109 | if (!isFastSeq) |
| 110 | Py_DECREF(coords); |
| 111 | |
| 112 | if (! success) { |
| 113 | retval = NULL; |
| 114 | goto exit; |
| 115 | } |
| 116 | |
| 117 | } // end of main for loop |
| 118 | |
| 119 | Py_INCREF(Py_None); |
| 120 | retval = Py_None; |
| 121 | goto exit; |
| 122 | |
| 123 | |
| 124 | err0: |
| 125 | PyErr_SetString(PyExc_TypeError, "Expected a sequence of coordinates"); |
| 126 | retval = NULL; |
| 127 | goto exit; |
| 128 | |
| 129 | err1: |
| 130 | PyErr_SetString(PyExc_TypeError, "Expected a sequence of wxPens"); |
| 131 | retval = NULL; |
| 132 | goto exit; |
| 133 | |
| 134 | err2: |
| 135 | PyErr_SetString(PyExc_TypeError, "Expected a sequence of wxBrushes"); |
| 136 | retval = NULL; |
| 137 | goto exit; |
| 138 | |
| 139 | |
| 140 | exit: |
| 141 | wxPyEndBlockThreads(blocked); |
| 142 | return retval; |
| 143 | } |
| 144 | |
| 145 | |
| 146 | |
| 147 | bool wxPyDrawXXXPoint(wxDC& dc, PyObject* coords) |
| 148 | { |
| 149 | int x, y; |
| 150 | |
| 151 | if (! wxPy2int_seq_helper(coords, &x, &y)) { |
| 152 | PyErr_SetString(PyExc_TypeError, "Expected a sequence of (x,y) sequences."); |
| 153 | return false; |
| 154 | } |
| 155 | dc.DrawPoint(x, y); |
| 156 | return true; |
| 157 | } |
| 158 | |
| 159 | bool wxPyDrawXXXLine(wxDC& dc, PyObject* coords) |
| 160 | { |
| 161 | int x1, y1, x2, y2; |
| 162 | |
| 163 | if (! wxPy4int_seq_helper(coords, &x1, &y1, &x2, &y2)) { |
| 164 | PyErr_SetString(PyExc_TypeError, "Expected a sequence of (x1,y1, x1,y2) sequences."); |
| 165 | return false; |
| 166 | } |
| 167 | dc.DrawLine(x1,y1, x2,y2); |
| 168 | return true; |
| 169 | } |
| 170 | |
| 171 | bool wxPyDrawXXXRectangle(wxDC& dc, PyObject* coords) |
| 172 | { |
| 173 | int x, y, w, h; |
| 174 | |
| 175 | if (! wxPy4int_seq_helper(coords, &x, &y, &w, &h)) { |
| 176 | PyErr_SetString(PyExc_TypeError, "Expected a sequence of (x,y, w,h) sequences."); |
| 177 | return false; |
| 178 | } |
| 179 | dc.DrawRectangle(x, y, w, h); |
| 180 | return true; |
| 181 | } |
| 182 | |
| 183 | bool wxPyDrawXXXEllipse(wxDC& dc, PyObject* coords) |
| 184 | { |
| 185 | int x, y, w, h; |
| 186 | |
| 187 | if (! wxPy4int_seq_helper(coords, &x, &y, &w, &h)) { |
| 188 | PyErr_SetString(PyExc_TypeError, "Expected a sequence of (x,y, w,h) sequences."); |
| 189 | return false; |
| 190 | } |
| 191 | dc.DrawEllipse(x, y, w, h); |
| 192 | return true; |
| 193 | } |
| 194 | |
| 195 | |
| 196 | bool wxPyDrawXXXPolygon(wxDC& dc, PyObject* coords) |
| 197 | { |
| 198 | wxPoint* points; |
| 199 | int numPoints; |
| 200 | |
| 201 | points = wxPoint_LIST_helper(coords, &numPoints); |
| 202 | if (! points) { |
| 203 | PyErr_SetString(PyExc_TypeError, "Expected a sequence of sequences of (x,y) sequences."); |
| 204 | return false; |
| 205 | } |
| 206 | dc.DrawPolygon(numPoints, points); |
| 207 | delete [] points; |
| 208 | return true; |
| 209 | } |
| 210 | |
| 211 | |
| 212 | //--------------------------------------------------------------------------- |
| 213 | |
| 214 | |
| 215 | |
| 216 | PyObject* wxPyDrawTextList(wxDC& dc, PyObject* textList, PyObject* pyPoints, PyObject* foregroundList, PyObject* backgroundList) |
| 217 | { |
| 218 | wxPyBlock_t blocked = wxPyBeginBlockThreads(); |
| 219 | |
| 220 | bool isFastSeq = PyList_Check(pyPoints) || PyTuple_Check(pyPoints); |
| 221 | bool isFastText = PyList_Check(textList) || PyTuple_Check(textList); |
| 222 | bool isFastForeground = PyList_Check(foregroundList) || PyTuple_Check(foregroundList); |
| 223 | bool isFastBackground = PyList_Check(backgroundList) || PyTuple_Check(backgroundList); |
| 224 | int numText = 0; |
| 225 | int numPoints = 0; |
| 226 | int numForeground = 0; |
| 227 | int numBackground = 0; |
| 228 | PyObject* obj; |
| 229 | int x1, y1; |
| 230 | int i = 0; |
| 231 | wxColor* color; |
| 232 | PyObject* retval; |
| 233 | wxString string; |
| 234 | |
| 235 | if (!PySequence_Check(pyPoints)) { |
| 236 | goto err0; |
| 237 | } |
| 238 | if (!PySequence_Check(textList)) { |
| 239 | goto err1; |
| 240 | } |
| 241 | if (!PySequence_Check(foregroundList)) { |
| 242 | goto err2; |
| 243 | } |
| 244 | if (!PySequence_Check(backgroundList)) { |
| 245 | goto err3; |
| 246 | } |
| 247 | numPoints = PySequence_Length(pyPoints); |
| 248 | numText = PySequence_Length(textList); |
| 249 | numForeground = PySequence_Length(foregroundList); |
| 250 | numBackground = PySequence_Length(backgroundList); |
| 251 | |
| 252 | for (i = 0; i < numPoints; i++) { |
| 253 | // Use a new string ? |
| 254 | if (i < numText) { |
| 255 | if ( isFastText ) { |
| 256 | obj = PySequence_Fast_GET_ITEM(textList, i); |
| 257 | } |
| 258 | else { |
| 259 | obj = PySequence_GetItem(textList, i); |
| 260 | } |
| 261 | if (! PyString_Check(obj) && !PyUnicode_Check(obj) ) { |
| 262 | Py_DECREF(obj); |
| 263 | goto err1; |
| 264 | } |
| 265 | string = Py2wxString(obj); |
| 266 | if ( !isFastText ) |
| 267 | Py_DECREF(obj); |
| 268 | } |
| 269 | |
| 270 | if (i < numForeground) { |
| 271 | // Use a new foreground ? |
| 272 | if ( isFastForeground ) { |
| 273 | obj = PySequence_Fast_GET_ITEM(foregroundList, i); |
| 274 | } |
| 275 | else { |
| 276 | obj = PySequence_GetItem(foregroundList, i); |
| 277 | } |
| 278 | if (! wxPyConvertSwigPtr(obj, (void **) &color, wxT("wxColour"))) { |
| 279 | if (!isFastForeground) |
| 280 | Py_DECREF(obj); |
| 281 | goto err2; |
| 282 | } |
| 283 | dc.SetTextForeground(*color); |
| 284 | if ( !isFastForeground ) |
| 285 | Py_DECREF(obj); |
| 286 | } |
| 287 | |
| 288 | if (i < numBackground) { |
| 289 | // Use a new background ? |
| 290 | if ( isFastBackground ) { |
| 291 | obj = PySequence_Fast_GET_ITEM(backgroundList, i); |
| 292 | } |
| 293 | else { |
| 294 | obj = PySequence_GetItem(backgroundList, i); |
| 295 | } |
| 296 | if (! wxPyConvertSwigPtr(obj, (void **) &color, wxT("wxColour"))) { |
| 297 | if (!isFastBackground) |
| 298 | Py_DECREF(obj); |
| 299 | goto err3; |
| 300 | } |
| 301 | dc.SetTextBackground(*color); |
| 302 | if ( !isFastBackground ) |
| 303 | Py_DECREF(obj); |
| 304 | } |
| 305 | |
| 306 | // Get the point coordinates |
| 307 | if (isFastSeq) { |
| 308 | obj = PySequence_Fast_GET_ITEM(pyPoints, i); |
| 309 | } |
| 310 | else { |
| 311 | obj = PySequence_GetItem(pyPoints, i); |
| 312 | } |
| 313 | if (! wxPy2int_seq_helper(obj, &x1, &y1)) { |
| 314 | if (! isFastSeq) |
| 315 | Py_DECREF(obj); |
| 316 | goto err0; |
| 317 | } |
| 318 | if (PyErr_Occurred()) { |
| 319 | retval = NULL; |
| 320 | if (!isFastSeq) |
| 321 | Py_DECREF(obj); |
| 322 | goto exit; |
| 323 | } |
| 324 | |
| 325 | |
| 326 | // Now draw the text |
| 327 | dc.DrawText(string, x1, y1); |
| 328 | |
| 329 | if (!isFastText) |
| 330 | Py_DECREF(obj); |
| 331 | } |
| 332 | |
| 333 | Py_INCREF(Py_None); |
| 334 | retval = Py_None; |
| 335 | goto exit; |
| 336 | |
| 337 | err0: |
| 338 | PyErr_SetString(PyExc_TypeError, "Expected a sequence of (x,y) sequences."); |
| 339 | retval = NULL; |
| 340 | goto exit; |
| 341 | err1: |
| 342 | PyErr_SetString(PyExc_TypeError, "Expected a sequence of strings"); |
| 343 | retval = NULL; |
| 344 | goto exit; |
| 345 | |
| 346 | err2: |
| 347 | PyErr_SetString(PyExc_TypeError, "Expected a sequence of wxColours for foregrounds"); |
| 348 | retval = NULL; |
| 349 | goto exit; |
| 350 | |
| 351 | err3: |
| 352 | PyErr_SetString(PyExc_TypeError, "Expected a sequence of wxColours for backgrounds"); |
| 353 | retval = NULL; |
| 354 | goto exit; |
| 355 | |
| 356 | exit: |
| 357 | wxPyEndBlockThreads(blocked); |
| 358 | return retval; |
| 359 | } |
| 360 | |
| 361 | |
| 362 | |
| 363 | //--------------------------------------------------------------------------- |