2
pygame - Python Game Library
3
Copyright (C) 2000-2001 Pete Shinners
5
This library is free software; you can redistribute it and/or
6
modify it under the terms of the GNU Library General Public
7
License as published by the Free Software Foundation; either
8
version 2 of the License, or (at your option) any later version.
10
This library is distributed in the hope that it will be useful,
11
but WITHOUT ANY WARRANTY; without even the implied warranty of
12
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
Library General Public License for more details.
15
You should have received a copy of the GNU Library General Public
16
License along with this library; if not, write to the Free
17
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24
* Python Rect Object -- useful 2d rectangle class
26
#define PYGAMEAPI_RECT_INTERNAL
30
staticforward PyTypeObject PyRect_Type;
31
#define PyRect_Check(x) ((x)->ob_type == &PyRect_Type)
35
GAME_Rect* GameRect_FromObject(PyObject* obj, GAME_Rect* temp)
40
return &((PyRectObject*)obj)->r;
42
if(PySequence_Check(obj))
44
if(PySequence_Length(obj) == 4)
46
if(!ShortFromObjIndex(obj, 0, &val)) return NULL; temp->x = val;
47
if(!ShortFromObjIndex(obj, 1, &val)) return NULL; temp->y = val;
48
if(!ShortFromObjIndex(obj, 2, &val)) return NULL; temp->w = val;
49
if(!ShortFromObjIndex(obj, 3, &val)) return NULL; temp->h = val;
52
if(PySequence_Length(obj) == 2)
54
PyObject* sub = PySequence_GetItem(obj, 0);
55
if(!sub || !PySequence_Check(sub) || PySequence_Length(sub)!=2)
56
{Py_XDECREF(sub); return NULL;}
57
if(!ShortFromObjIndex(sub, 0, &val)) {Py_DECREF(sub); return NULL;} temp->x = val;
58
if(!ShortFromObjIndex(sub, 1, &val)) {Py_DECREF(sub); return NULL;} temp->y = val;
60
sub = PySequence_GetItem(obj, 1);
61
if(!sub || !PySequence_Check(sub) || PySequence_Length(sub)!=2)
62
{Py_XDECREF(sub); return NULL;}
63
if(!ShortFromObjIndex(sub, 0, &val)) {Py_DECREF(sub); return NULL;} temp->w = val;
64
if(!ShortFromObjIndex(sub, 1, &val)) {Py_DECREF(sub); return NULL;} temp->h = val;
68
if(PyTuple_Check(obj) && PyTuple_Size(obj) == 1) /*looks like an arg?*/
70
PyObject* sub = PyTuple_GET_ITEM(obj, 0);
72
return GameRect_FromObject(sub, temp);
78
static int Rect_SetTop(GAME_Rect* r, short val)
83
static int Rect_SetBottom(GAME_Rect* r, short val)
88
static int Rect_SetLeft(GAME_Rect* r, short val)
93
static int Rect_SetRight(GAME_Rect* r, short val)
98
static int Rect_SetWidth(GAME_Rect* r, short val)
100
// r->x -= val - r->w;
104
static int Rect_SetHeight(GAME_Rect* r, short val)
106
// r->y -= val - r->h;
111
PyObject* PyRect_New(GAME_Rect* r)
113
PyRectObject* rect = PyObject_NEW(PyRectObject, &PyRect_Type);
122
return (PyObject*)rect;
125
PyObject* PyRect_New4(short x, short y, short w, short h)
127
PyRectObject* rect = PyObject_NEW(PyRectObject, &PyRect_Type);
136
return (PyObject*)rect;
139
static int DoRectsIntersect(GAME_Rect *A, GAME_Rect *B)
141
return ((A->x >= B->x && A->x < B->x+B->w) ||
142
(B->x >= A->x && B->x < A->x+A->w)) &&
143
((A->y >= B->y && A->y < B->y+B->h) ||
144
(B->y >= A->y && B->y < A->y+A->h));
149
/*DOC*/ static char doc_normalize[] =
150
/*DOC*/ "Rect.normalize() -> None\n"
151
/*DOC*/ "corrects negative sizes\n"
153
/*DOC*/ "If the rectangle has a a negative size in width or\n"
154
/*DOC*/ "height, this will flip that axis so the sizes are\n"
155
/*DOC*/ "positive, and the rectangle remains in the same\n"
159
static PyObject* rect_normalize(PyObject* oself, PyObject* args)
161
PyRectObject* self = (PyRectObject*)oself;
162
if(!PyArg_ParseTuple(args, ""))
165
if((short)self->r.w < 0)
167
self->r.x += self->r.w;
168
self->r.w = -self->r.w;
170
if((short)self->r.h < 0)
172
self->r.y += self->r.h;
173
self->r.h = -self->r.h;
180
/*DOC*/ static char doc_move[] =
181
/*DOC*/ "Rect.move(x, y) -> Rect\n"
182
/*DOC*/ "new rectangle with position changed\n"
184
/*DOC*/ "Returns a new rectangle which is the base\n"
185
/*DOC*/ "rectangle moved by the given amount.\n"
188
static PyObject* rect_move(PyObject* oself, PyObject* args)
190
PyRectObject* self = (PyRectObject*)oself;
193
if(!TwoShortsFromObj(args, &x, &y))
194
return RAISE(PyExc_TypeError, "argument must contain two numbers");
196
return PyRect_New4((short)(self->r.x+x), (short)(self->r.y+y), self->r.w, self->r.h);
199
/*DOC*/ static char doc_move_ip[] =
200
/*DOC*/ "Rect.move_ip(x, y) -> None\n"
201
/*DOC*/ "move the Rect by the given offset\n"
203
/*DOC*/ "Moves the rectangle which by the given amount.\n"
206
static PyObject* rect_move_ip(PyObject* oself, PyObject* args)
208
PyRectObject* self = (PyRectObject*)oself;
211
if(!TwoShortsFromObj(args, &x, &y))
212
return RAISE(PyExc_TypeError, "argument must contain two numbers");
221
/*DOC*/ static char doc_inflate[] =
222
/*DOC*/ "Rect.inflate(x, y) -> Rect\n"
223
/*DOC*/ "new rectangle with size changed\n"
225
/*DOC*/ "Returns a new rectangle which has the sizes\n"
226
/*DOC*/ "changed by the given amounts. The rectangle\n"
227
/*DOC*/ "shrinks and expands around the rectangle's center.\n"
228
/*DOC*/ "Negative values will shrink the rectangle.\n"
231
static PyObject* rect_inflate(PyObject* oself, PyObject* args)
233
PyRectObject* self = (PyRectObject*)oself;
236
if(!TwoShortsFromObj(args, &x, &y))
237
return RAISE(PyExc_TypeError, "argument must contain two numbers");
239
return PyRect_New4((short)(self->r.x-x/2), (short)(self->r.y-y/2), (short)(self->r.w+x), (short)(self->r.h+y));
243
/*DOC*/ static char doc_inflate_ip[] =
244
/*DOC*/ "Rect.inflate_ip(x, y) -> None\n"
245
/*DOC*/ "changes the Rect size\n"
247
/*DOC*/ "Changes the Rect by the given amounts. The rectangle\n"
248
/*DOC*/ "shrinks and expands around the rectangle's center.\n"
249
/*DOC*/ "Negative values will shrink the rectangle.\n"
252
static PyObject* rect_inflate_ip(PyObject* oself, PyObject* args)
254
PyRectObject* self = (PyRectObject*)oself;
257
if(!TwoShortsFromObj(args, &x, &y))
258
return RAISE(PyExc_TypeError, "argument must contain two numbers");
269
/*DOC*/ static char doc_union[] =
270
/*DOC*/ "Rect.union(rectstyle) -> Rect\n"
271
/*DOC*/ "makes new rectangle covering both inputs\n"
273
/*DOC*/ "Creates a new Rect to completely cover the\n"
274
/*DOC*/ "given input. There may be area inside the new\n"
275
/*DOC*/ "Rect that is not covered by either input.\n"
278
static PyObject* rect_union(PyObject* oself, PyObject* args)
280
PyRectObject* self = (PyRectObject*)oself;
281
GAME_Rect *argrect, temp;
283
if(!(argrect = GameRect_FromObject(args, &temp)))
284
return RAISE(PyExc_TypeError, "Argument must be rect style object");
286
x = min(self->r.x, argrect->x);
287
y = min(self->r.y, argrect->y);
288
w = max(self->r.x+self->r.w, argrect->x+argrect->w) - x;
289
h = max(self->r.y+self->r.h, argrect->y+argrect->h) - y;
290
return PyRect_New4(x, y, w, h);
296
/*DOC*/ static char doc_union_ip[] =
297
/*DOC*/ "Rect.union_ip(rectstyle) -> None\n"
298
/*DOC*/ "rectangle covering both input\n"
300
/*DOC*/ "Resizes the Rect to completely cover the\n"
301
/*DOC*/ "given input. There may be area inside the new\n"
302
/*DOC*/ "dimensions that is not covered by either input.\n"
305
static PyObject* rect_union_ip(PyObject* oself, PyObject* args)
307
PyRectObject* self = (PyRectObject*)oself;
308
GAME_Rect *argrect, temp;
310
if(!(argrect = GameRect_FromObject(args, &temp)))
311
return RAISE(PyExc_TypeError, "Argument must be rect style object");
313
x = min(self->r.x, argrect->x);
314
y = min(self->r.y, argrect->y);
315
w = max(self->r.x+self->r.w, argrect->x+argrect->w) - x;
316
h = max(self->r.y+self->r.h, argrect->y+argrect->h) - y;
325
/*DOC*/ static char doc_unionall[] =
326
/*DOC*/ "Rect.unionall(sequence_of_rectstyles) -> Rect\n"
327
/*DOC*/ "rectangle covering all inputs\n"
329
/*DOC*/ "Returns a new rectangle that completely covers all the\n"
330
/*DOC*/ "given inputs. There may be area inside the new\n"
331
/*DOC*/ "rectangle that is not covered by the inputs.\n"
334
static PyObject* rect_unionall(PyObject* oself, PyObject* args)
336
PyRectObject* self = (PyRectObject*)oself;
337
GAME_Rect *argrect, temp;
339
PyObject* list, *obj;
342
if(!PyArg_ParseTuple(args, "O", &list))
344
if(!PySequence_Check(list))
345
return RAISE(PyExc_TypeError, "Argument must be a sequence of rectstyle objects.");
349
r = self->r.x + self->r.w;
350
b = self->r.y + self->r.h;
352
size = PySequence_Length(list); /*warning, size could be -1 on error?*/
354
return PyRect_New4((short)l, (short)t, (short)(r-l), (short)(b-t));
356
for(loop = 0; loop < size; ++loop)
358
obj = PySequence_GetItem(list, loop);
359
if(!obj || !(argrect = GameRect_FromObject(obj, &temp)))
361
RAISE(PyExc_TypeError, "Argument must be a sequence of rectstyle objects.");
365
t = min(t, argrect->x);
366
l = min(l, argrect->y);
367
r = max(b, argrect->x+argrect->w);
368
b = max(b, argrect->y+argrect->h);
372
return PyRect_New4((short)l, (short)t, (short)(r-l), (short)(b-t));
376
/*DOC*/ static char doc_unionall_ip[] =
377
/*DOC*/ "Rect.unionall_ip(sequence_of_rectstyles) -> None\n"
378
/*DOC*/ "rectangle covering all inputs\n"
380
/*DOC*/ "Returns a new rectangle that completely covers all the\n"
381
/*DOC*/ "given inputs. There may be area inside the new\n"
382
/*DOC*/ "rectangle that is not covered by the inputs.\n"
385
static PyObject* rect_unionall_ip(PyObject* oself, PyObject* args)
387
PyRectObject* self = (PyRectObject*)oself;
388
GAME_Rect *argrect, temp;
390
PyObject* list, *obj;
393
if(!PyArg_ParseTuple(args, "O", &list))
395
if(!PySequence_Check(list))
396
return RAISE(PyExc_TypeError, "Argument must be a sequence of rectstyle objects.");
400
r = self->r.x + self->r.w;
401
b = self->r.y + self->r.h;
403
size = PySequence_Length(list); /*warning, size could be -1 on error?*/
405
return PyRect_New4((short)l, (short)t, (short)(r-l), (short)(b-t));
407
for(loop = 0; loop < size; ++loop)
409
obj = PySequence_GetItem(list, loop);
410
if(!obj || !(argrect = GameRect_FromObject(obj, &temp)))
412
RAISE(PyExc_TypeError, "Argument must be a sequence of rectstyle objects.");
416
t = min(t, argrect->x);
417
l = min(l, argrect->y);
418
r = max(b, argrect->x+argrect->w);
419
b = max(b, argrect->y+argrect->h);
431
/*DOC*/ static char doc_collidepoint[] =
432
/*DOC*/ "Rect.collidepoint(x, y) -> bool\n"
433
/*DOC*/ "point inside rectangle\n"
435
/*DOC*/ "Returns true if the given point position is inside\n"
436
/*DOC*/ "the rectangle. If a point is on the border, it is\n"
437
/*DOC*/ "counted as inside.\n"
440
static PyObject* rect_collidepoint(PyObject* oself, PyObject* args)
442
PyRectObject* self = (PyRectObject*)oself;
446
if(!TwoShortsFromObj(args, &x, &y))
447
return RAISE(PyExc_TypeError, "argument must contain two numbers");
449
inside = x>=self->r.x && x<self->r.x+self->r.w &&
450
y>=self->r.y && y<self->r.y+self->r.h;
452
return PyInt_FromLong(inside);
457
/*DOC*/ static char doc_colliderect[] =
458
/*DOC*/ "Rect.colliderect(rectstyle) -> bool\n"
459
/*DOC*/ "check overlapping rectangles\n"
461
/*DOC*/ "Returns true if any area of the two rectangles\n"
462
/*DOC*/ "overlaps.\n"
465
static PyObject* rect_colliderect(PyObject* oself, PyObject* args)
467
PyRectObject* self = (PyRectObject*)oself;
468
GAME_Rect *argrect, temp;
469
if(!(argrect = GameRect_FromObject(args, &temp)))
470
return RAISE(PyExc_TypeError, "Argument must be rect style object");
472
return PyInt_FromLong(DoRectsIntersect(&self->r, argrect));
477
/*DOC*/ static char doc_collidelist[] =
478
/*DOC*/ "Rect.collidelist(rectstyle list) -> int index\n"
479
/*DOC*/ "find overlapping rectangle\n"
481
/*DOC*/ "Returns the index of the first rectangle in the\n"
482
/*DOC*/ "list to overlap the base rectangle. Once an\n"
483
/*DOC*/ "overlap is found, this will stop checking the\n"
484
/*DOC*/ "remaining list. If no overlap is found, it will\n"
485
/*DOC*/ "return -1.\n"
488
static PyObject* rect_collidelist(PyObject* oself, PyObject* args)
490
PyRectObject* self = (PyRectObject*)oself;
491
GAME_Rect *argrect, temp;
493
PyObject* list, *obj;
494
PyObject* ret = NULL;
496
if(!PyArg_ParseTuple(args, "O", &list))
499
if(!PySequence_Check(list))
500
return RAISE(PyExc_TypeError, "Argument must be a sequence of rectstyle objects.");
502
size = PySequence_Length(list); /*warning, size could be -1 on error?*/
503
for(loop = 0; loop < size; ++loop)
505
obj = PySequence_GetItem(list, loop);
506
if(!obj || !(argrect = GameRect_FromObject(obj, &temp)))
508
RAISE(PyExc_TypeError, "Argument must be a sequence of rectstyle objects.");
512
if(DoRectsIntersect(&self->r, argrect))
514
ret = PyInt_FromLong(loop);
521
ret = PyInt_FromLong(-1);
527
/*DOC*/ static char doc_collidelistall[] =
528
/*DOC*/ "Rect.collidelistall(rectstyle list) -> int index\n"
529
/*DOC*/ "find all overlapping rectangles\n"
531
/*DOC*/ "Returns a list of the indexes that contain\n"
532
/*DOC*/ "rectangles overlapping the base rectangle. If no\n"
533
/*DOC*/ "overlap is found, it will return an empty\n"
534
/*DOC*/ "sequence.\n"
537
static PyObject* rect_collidelistall(PyObject* oself, PyObject* args)
539
PyRectObject* self = (PyRectObject*)oself;
540
GAME_Rect *argrect, temp;
542
PyObject* list, *obj;
543
PyObject* ret = NULL;
545
if(!PyArg_ParseTuple(args, "O", &list))
548
if(!PySequence_Check(list))
549
return RAISE(PyExc_TypeError, "Argument must be a sequence of rectstyle objects.");
555
size = PySequence_Length(list); /*warning, size could be -1?*/
556
for(loop = 0; loop < size; ++loop)
558
obj = PySequence_GetItem(list, loop);
560
if(!obj || !(argrect = GameRect_FromObject(obj, &temp)))
564
return RAISE(PyExc_TypeError, "Argument must be a sequence of rectstyle objects.");
567
if(DoRectsIntersect(&self->r, argrect))
569
PyObject* num = PyInt_FromLong(loop);
575
PyList_Append(ret, num);
586
/*DOC*/ static char doc_clip[] =
587
/*DOC*/ "Rect.clip(rectstyle) -> Rect\n"
588
/*DOC*/ "rectangle cropped inside another\n"
590
/*DOC*/ "Returns a new rectangle that is the given\n"
591
/*DOC*/ "rectangle cropped to the inside of the base\n"
592
/*DOC*/ "rectangle. If the two rectangles do not overlap to\n"
593
/*DOC*/ "begin with, you will get a rectangle with 0 size.\n"
596
static PyObject* rect_clip(PyObject* self, PyObject* args)
598
GAME_Rect *A, *B, temp;
601
A = &((PyRectObject*)self)->r;
602
if(!(B = GameRect_FromObject(args, &temp)))
603
return RAISE(PyExc_TypeError, "Argument must be rect style object");
606
if((A->x >= B->x) && (A->x < (B->x+B->w)))
608
else if((B->x >= A->x) && (B->x < (A->x+A->w)))
613
if(((A->x+A->w) > B->x) && ((A->x+A->w) <= (B->x+B->w)))
615
else if(((B->x+B->w) > A->x) && ((B->x+B->w) <= (A->x+A->w)))
621
if((A->y >= B->y) && (A->y < (B->y+B->h)))
623
else if((B->y >= A->y) && (B->y < (A->y+A->h)))
628
if (((A->y+A->h) > B->y) && ((A->y+A->h) <= (B->y+B->h)))
630
else if(((B->y+B->h) > A->y) && ((B->y+B->h) <= (A->y+A->h)))
635
return PyRect_New4(x, y, w, h);
638
return PyRect_New4(A->x, A->y, 0, 0);
642
/*DOC*/ static char doc_contains[] =
643
/*DOC*/ "Rect.contains(rectstyle) -> bool\n"
644
/*DOC*/ "check if rectangle fully inside another\n"
646
/*DOC*/ "Returns true when the given rectangle is entirely\n"
647
/*DOC*/ "inside the base rectangle.\n"
650
static PyObject* rect_contains(PyObject* oself, PyObject* args)
653
PyRectObject* self = (PyRectObject*)oself;
654
GAME_Rect *argrect, temp;
655
if(!(argrect = GameRect_FromObject(args, &temp)))
656
return RAISE(PyExc_TypeError, "Argument must be rect style object");
658
contained = (self->r.x <= argrect->x) && (self->r.y <= argrect->y) &&
659
(self->r.x + self->r.w >= argrect->x + argrect->w) &&
660
(self->r.y + self->r.h >= argrect->y + argrect->h) &&
661
(self->r.x + self->r.w > argrect->x) &&
662
(self->r.y + self->r.h > argrect->y);
664
return PyInt_FromLong(contained);
668
/*DOC*/ static char doc_clamp[] =
669
/*DOC*/ "Rect.clamp(rectstyle) -> Rect\n"
670
/*DOC*/ "move rectangle inside another\n"
672
/*DOC*/ "Returns a new rectangle that is moved to be\n"
673
/*DOC*/ "completely inside the argument rectangle. If the base\n"
674
/*DOC*/ "rectangle is too large for the argument rectangle in\n"
675
/*DOC*/ "an axis, it will be centered on that axis.\n"
678
static PyObject* rect_clamp(PyObject* oself, PyObject* args)
680
PyRectObject* self = (PyRectObject*)oself;
681
GAME_Rect *argrect, temp;
683
if(!(argrect = GameRect_FromObject(args, &temp)))
684
return RAISE(PyExc_TypeError, "Argument must be rect style object");
686
if(self->r.w >= argrect->w)
687
x = argrect->x + argrect->w / 2 - self->r.w / 2;
688
else if(self->r.x < argrect->x)
690
else if(self->r.x + self->r.w > argrect->x + argrect->w)
691
x = argrect->x + argrect->w - self->r.w;
695
if(self->r.h >= argrect->h)
696
y = argrect->y + argrect->h / 2 - self->r.h / 2;
697
else if(self->r.y < argrect->y)
699
else if(self->r.y + self->r.h > argrect->y + argrect->h)
700
y = argrect->y + argrect->h - self->r.h;
704
return PyRect_New4(x, y, self->r.w, self->r.h);
708
/*DOC*/ static char doc_clamp_ip[] =
709
/*DOC*/ "Rect.clamp_ip(rectstyle) -> None\n"
710
/*DOC*/ "moves the rectangle inside another\n"
712
/*DOC*/ "Moves the Rect to be\n"
713
/*DOC*/ "completely inside the argument rectangle. If the given\n"
714
/*DOC*/ "rectangle is too large for the argument rectangle in\n"
715
/*DOC*/ "an axis, it will be centered on that axis.\n"
718
static PyObject* rect_clamp_ip(PyObject* oself, PyObject* args)
720
PyRectObject* self = (PyRectObject*)oself;
721
GAME_Rect *argrect, temp;
723
if(!(argrect = GameRect_FromObject(args, &temp)))
724
return RAISE(PyExc_TypeError, "Argument must be rect style object");
726
if(self->r.w >= argrect->w)
727
x = argrect->x + argrect->w / 2 - self->r.w / 2;
728
else if(self->r.x < argrect->x)
730
else if(self->r.x + self->r.w > argrect->x + argrect->w)
731
x = argrect->x + argrect->w - self->r.w;
735
if(self->r.h >= argrect->h)
736
y = argrect->y + argrect->h / 2 - self->r.h / 2;
737
else if(self->r.y < argrect->y)
739
else if(self->r.y + self->r.h > argrect->y + argrect->h)
740
y = argrect->y + argrect->h - self->r.h;
750
static struct PyMethodDef rect_methods[] =
752
{"normalize", (PyCFunction)rect_normalize, 1, doc_normalize},
753
{"clip", (PyCFunction)rect_clip, 1, doc_clip},
754
{"clamp", (PyCFunction)rect_clamp, 1, doc_clamp},
755
{"clamp_ip", (PyCFunction)rect_clamp_ip, 1, doc_clamp_ip},
757
{"move", (PyCFunction)rect_move, 1, doc_move},
758
{"inflate", (PyCFunction)rect_inflate, 1, doc_inflate},
759
{"union", (PyCFunction)rect_union, 1, doc_union},
760
{"unionall", (PyCFunction)rect_unionall, 1, doc_unionall},
762
{"move_ip", (PyCFunction)rect_move_ip, 1, doc_move_ip},
763
{"inflate_ip", (PyCFunction)rect_inflate_ip, 1, doc_inflate_ip},
764
{"union_ip", (PyCFunction)rect_union_ip, 1, doc_union_ip},
765
{"unionall_ip", (PyCFunction)rect_unionall_ip, 1, doc_unionall_ip},
767
{"collidepoint", (PyCFunction)rect_collidepoint, 1, doc_collidepoint},
768
{"colliderect", (PyCFunction)rect_colliderect, 1, doc_colliderect},
769
{"collidelist", (PyCFunction)rect_collidelist, 1, doc_collidelist},
770
{"collidelistall", (PyCFunction)rect_collidelistall,1,doc_collidelistall},
771
{"contains", (PyCFunction)rect_contains, 1, doc_contains},
772
/* these are totally unwritten. volunteers? */
773
/* {"cleanup", (PyCFunction)rect_cleanup, 1, doc_cleanup}, */
774
/* {"remove", (PyCFunction)rect_remove, 1, doc_remove}, */
781
/* sequence functions */
783
static int rect_length(PyRectObject *self)
788
static PyObject* rect_item(PyRectObject *self, int i)
790
short* data = (short*)&self->r;
792
return RAISE(PyExc_IndexError, "Invalid rect Index");
794
return PyInt_FromLong(data[i]);
797
static int rect_ass_item(PyRectObject *self, int i, PyObject *v)
800
short* data = (short*)&self->r;
803
RAISE(PyExc_IndexError, "Invalid rect Index");
806
if(!ShortFromObj(v, &val))
808
RAISE(PyExc_TypeError, "Must assign numeric values");
811
data[i] = (short)val;
816
static PyObject* rect_slice(PyRectObject *self, int ilow, int ihigh)
819
short* data = (short*)&self->r;
820
int numitems, loop, l = 4;
822
if (ihigh < 0) ihigh += l;
823
if (ilow < 0) ilow += l;
824
if (ilow < 0) ilow = 0;
825
else if (ilow > l) ilow = l;
826
if (ihigh < 0) ihigh = 0;
827
else if (ihigh > l) ihigh = l;
828
if (ihigh < ilow) ihigh = ilow;
830
numitems = ihigh - ilow;
831
list = PyList_New(numitems);
832
for(loop = 0; loop < numitems; ++loop)
833
PyList_SET_ITEM(list, loop, PyInt_FromLong(data[loop+ilow]));
840
static int rect_ass_slice(PyRectObject *self, int ilow, int ihigh, PyObject *v)
842
short* data = (short*)&self->r;
843
int numitems, loop, l = 4;
846
if(!PySequence_Check(v))
848
RAISE(PyExc_TypeError, "Assigned slice must be a sequence");
852
if (ihigh < 0) ihigh += l;
853
if (ilow < 0) ilow += l;
854
if (ilow < 0) ilow = 0;
855
else if (ilow > l) ilow = l;
856
if (ihigh < 0) ihigh = 0;
857
else if (ihigh > l) ihigh = l;
858
if (ihigh < ilow) ihigh = ilow;
860
numitems = ihigh - ilow;
861
if(numitems != PySequence_Length(v))
863
RAISE(PyExc_ValueError, "Assigned slice must be same length");
867
for(loop = 0; loop < numitems; ++loop)
869
if(!ShortFromObjIndex(v, loop, &val)) return -1;
870
data[loop+ilow] = val;
876
static PySequenceMethods rect_as_sequence = {
877
(inquiry)rect_length, /*length*/
878
(binaryfunc)NULL, /*concat*/
879
(intargfunc)NULL, /*repeat*/
880
(intargfunc)rect_item, /*item*/
881
(intintargfunc)rect_slice, /*slice*/
882
(intobjargproc)rect_ass_item, /*ass_item*/
883
(intintobjargproc)rect_ass_slice, /*ass_slice*/
888
/* numeric functions */
890
static int rect_nonzero(PyRectObject *self)
892
return self->r.w != 0 && self->r.h != 0;
895
static int rect_coerce(PyObject** o1, PyObject** o2)
901
if(PyRect_Check(*o1))
906
else if((r = GameRect_FromObject(*o1, &temp)))
907
new1 = PyRect_New(r);
911
if(PyRect_Check(*o2))
916
else if((r = GameRect_FromObject(*o2, &temp)))
917
new2 = PyRect_New(r);
929
static PyNumberMethods rect_as_number = {
930
(binaryfunc)NULL, /*add*/
931
(binaryfunc)NULL, /*subtract*/
932
(binaryfunc)NULL, /*multiply*/
933
(binaryfunc)NULL, /*divide*/
934
(binaryfunc)NULL, /*remainder*/
935
(binaryfunc)NULL, /*divmod*/
936
(ternaryfunc)NULL, /*power*/
937
(unaryfunc)NULL, /*negative*/
938
(unaryfunc)NULL, /*pos*/
939
(unaryfunc)NULL, /*abs*/
940
(inquiry)rect_nonzero, /*nonzero*/
941
(unaryfunc)NULL, /*invert*/
942
(binaryfunc)NULL, /*lshift*/
943
(binaryfunc)NULL, /*rshift*/
944
(binaryfunc)NULL, /*and*/
945
(binaryfunc)NULL, /*xor*/
946
(binaryfunc)NULL, /*or*/
947
(coercion)rect_coerce, /*coerce*/
948
(unaryfunc)NULL, /*int*/
949
(unaryfunc)NULL, /*long*/
950
(unaryfunc)NULL, /*float*/
951
(unaryfunc)NULL, /*oct*/
952
(unaryfunc)NULL, /*hex*/
956
/* object type functions */
957
static void rect_dealloc(PyRectObject *self)
963
static PyObject *rect_repr(PyRectObject *self)
966
sprintf(string, "<rect(%d, %d, %d, %d)>", self->r.x, self->r.y, self->r.w, self->r.h);
967
return PyString_FromString(string);
971
static PyObject *rect_str(PyRectObject *self)
973
return rect_repr(self);
977
static int rect_compare(PyRectObject *self, PyObject *other)
979
GAME_Rect *orect, temp;
981
orect = GameRect_FromObject(other, &temp);
984
RAISE(PyExc_TypeError, "must compare rect with rect style object");
988
if(self->r.x != orect->x)
989
return self->r.x < orect->x ? -1 : 1;
990
if(self->r.y != orect->y)
991
return self->r.y < orect->y ? -1 : 1;
992
if(self->r.w != orect->w)
993
return self->r.w < orect->w ? -1 : 1;
994
if(self->r.h != orect->h)
995
return self->r.h < orect->h ? -1 : 1;
1001
static PyObject *rect_getattr(PyRectObject *self, char *name)
1003
PyObject *ret = NULL;
1004
GAME_Rect *r = &self->r;
1006
if(!strcmp(name, "top"))
1007
ret = PyInt_FromLong(r->y);
1008
else if(!strcmp(name, "bottom"))
1009
ret = PyInt_FromLong(r->y + r->h);
1010
else if(!strcmp(name, "left"))
1011
ret = PyInt_FromLong(r->x);
1012
else if(!strcmp(name, "right"))
1013
ret = PyInt_FromLong(r->x + r->w);
1014
else if(!strcmp(name, "width"))
1015
ret = PyInt_FromLong(r->w);
1016
else if(!strcmp(name, "height"))
1017
ret = PyInt_FromLong(r->h);
1018
else if(!strcmp(name, "centerx"))
1019
ret = PyInt_FromLong(r->x+r->w/2);
1020
else if(!strcmp(name, "centery"))
1021
ret = PyInt_FromLong(r->y+r->h/2);
1023
else if(!strcmp(name, "topleft"))
1024
ret = Py_BuildValue("(ii)", r->x, r->y);
1025
else if(!strcmp(name, "bottomleft"))
1026
ret = Py_BuildValue("(ii)", r->x, r->y + r->h);
1027
else if(!strcmp(name, "topright"))
1028
ret = Py_BuildValue("(ii)", r->x + r->w, r->y);
1029
else if(!strcmp(name, "bottomright"))
1030
ret = Py_BuildValue("(ii)", r->x + r->w, r->y + r->h);
1031
else if(!strcmp(name, "size"))
1032
ret = Py_BuildValue("(ii)", r->w, r->h);
1033
else if(!strcmp(name, "center"))
1034
ret = Py_BuildValue("(ii)", r->x + r->w / 2, r->y + r->h / 2);
1036
else if(!strcmp(name, "midleft"))
1037
ret = Py_BuildValue("(ii)", r->x, r->y + r->h / 2);
1038
else if(!strcmp(name, "midright"))
1039
ret = Py_BuildValue("(ii)", r->x + r->w, r->y + r->h / 2);
1040
else if(!strcmp(name, "midtop"))
1041
ret = Py_BuildValue("(ii)", r->x + r->w / 2, r->y);
1042
else if(!strcmp(name, "midbottom"))
1043
ret = Py_BuildValue("(ii)", r->x + r->w / 2, r->y + r->h);
1046
ret = Py_FindMethod(rect_methods, (PyObject *)self, name);
1051
static int rect_setattr(PyRectObject *self, char *name, PyObject *op)
1055
GAME_Rect *r = &self->r;
1057
if(!strcmp(name, "top"))
1059
if(ShortFromObj(op, &val1))
1060
ret = Rect_SetTop(r, val1);
1062
else if(!strcmp(name, "bottom"))
1064
if(ShortFromObj(op, &val1))
1065
ret = Rect_SetBottom(r, val1);
1067
else if(!strcmp(name, "left"))
1069
if(ShortFromObj(op, &val1))
1070
ret = Rect_SetLeft(r, val1);
1072
else if(!strcmp(name, "right"))
1074
if(ShortFromObj(op, &val1))
1075
ret = Rect_SetRight(r, val1);
1077
else if(!strcmp(name, "width"))
1079
if(ShortFromObj(op, &val1))
1080
ret = Rect_SetWidth(r, val1);
1082
else if(!strcmp(name, "height"))
1084
if(ShortFromObj(op, &val1))
1085
ret = Rect_SetHeight(r, val1);
1087
else if(!strcmp(name, "topleft"))
1089
if(TwoShortsFromObj(op, &val1, &val2))
1091
Rect_SetLeft(r, val1);
1092
ret = Rect_SetTop(r, val2);
1095
else if(!strcmp(name, "bottomleft"))
1097
if(TwoShortsFromObj(op, &val1, &val2))
1099
Rect_SetLeft(r, val1);
1100
ret = Rect_SetBottom(r, val2);
1103
else if(!strcmp(name, "topright"))
1105
if(TwoShortsFromObj(op, &val1, &val2))
1107
Rect_SetRight(r, val1);
1108
ret = Rect_SetTop(r, val2);
1111
else if(!strcmp(name, "bottomright"))
1113
if(TwoShortsFromObj(op, &val1, &val2))
1115
Rect_SetRight(r, val1);
1116
ret = Rect_SetBottom(r, val2);
1119
else if(!strcmp(name, "size"))
1121
if(TwoShortsFromObj(op, &val1, &val2))
1123
Rect_SetWidth(r, val1);
1124
ret = Rect_SetHeight(r, val2);
1127
else if(!strcmp(name, "center"))
1129
if(TwoShortsFromObj(op, &val1, &val2))
1131
r->x += val1 - (r->x + r->w / 2);
1132
r->y += val2 - (r->y + r->h / 2);
1136
else if(!strcmp(name, "centerx"))
1138
if(ShortFromObj(op, &val1))
1140
r->x += val1 - (r->x + r->w / 2);
1144
else if(!strcmp(name, "centery"))
1146
if(ShortFromObj(op, &val1))
1148
r->y += val1 - (r->y + r->h / 2);
1153
else if(!strcmp(name, "midleft"))
1155
if(TwoShortsFromObj(op, &val1, &val2))
1158
r->y += val2 - (r->y + r->h / 2);
1162
else if(!strcmp(name, "midright"))
1164
if(TwoShortsFromObj(op, &val1, &val2))
1167
r->y += val2 - (r->y + r->h / 2);
1171
else if(!strcmp(name, "midtop"))
1173
if(TwoShortsFromObj(op, &val1, &val2))
1175
r->x += val1 - (r->x + r->w / 2);
1180
else if(!strcmp(name, "midbottom"))
1182
if(TwoShortsFromObj(op, &val1, &val2))
1184
r->x += val1 - (r->x + r->w / 2);
1192
RAISE(PyExc_AttributeError, "Attribute cannot be modified");
1197
RAISE(PyExc_TypeError, "Unable to assign to rect attribute");
1203
/*DOC*/ static char doc_Rect_MODULE[] =
1204
/*DOC*/ "The rectangle object is a useful object\n"
1205
/*DOC*/ "representing a rectangle area. Rectangles are\n"
1206
/*DOC*/ "created from the pygame.Rect() function. This routine\n"
1207
/*DOC*/ "is also in the locals module, so importing the locals\n"
1208
/*DOC*/ "into your namespace allows you to just use Rect().\n"
1210
/*DOC*/ "Rect contains helpful methods, as well as a list of\n"
1211
/*DOC*/ "modifiable members:\n"
1212
/*DOC*/ "top, bottom, left, right, topleft, topright,\n"
1213
/*DOC*/ "bottomleft, bottomright, size, width, height,\n"
1214
/*DOC*/ "center, centerx, centery, midleft, midright, midtop,\n"
1215
/*DOC*/ "midbottom. When changing thesemembers, the rectangle\n"
1216
/*DOC*/ "will be moved to the given assignment. (except when\n"
1217
/*DOC*/ "changing the size, width, or height member, which will\n"
1218
/*DOC*/ "resize the rectangle from the topleft corner)\n"
1220
/*DOC*/ "The rectstyle arguments used frequently with the\n"
1221
/*DOC*/ "Rect object (and elsewhere in pygame) is one of\n"
1222
/*DOC*/ "the following things. First, an actual Rect\n"
1223
/*DOC*/ "object. Second, a sequence of [xpos, ypos, width,\n"
1224
/*DOC*/ "height]. Lastly, a pair of sequences, representing\n"
1225
/*DOC*/ "the position and size [[xpos, ypos], [width,\n"
1226
/*DOC*/ "height]]. Also, if a method takes a rectstyle\n"
1227
/*DOC*/ "argument as its only argument, you can simply pass\n"
1228
/*DOC*/ "four arguments representing xpos, ypos, width,\n"
1232
static PyTypeObject PyRect_Type = {
1233
PyObject_HEAD_INIT(0)
1236
sizeof(PyRectObject), /*basicsize*/
1239
(destructor)rect_dealloc, /*dealloc*/
1240
(printfunc)NULL, /*print*/
1241
(getattrfunc)rect_getattr, /*getattr*/
1242
(setattrfunc)rect_setattr, /*setattr*/
1243
(cmpfunc)rect_compare, /*compare*/
1244
(reprfunc)rect_repr, /*repr*/
1245
&rect_as_number, /*as_number*/
1246
&rect_as_sequence, /*as_sequence*/
1247
NULL, /*as_mapping*/
1248
(hashfunc)NULL, /*hash*/
1249
(ternaryfunc)NULL, /*call*/
1250
(reprfunc)rect_str, /*str*/
1252
/* Space for future expansion */
1254
doc_Rect_MODULE /* Documentation string */
1261
/*DOC*/ static char doc_Rect[] =
1262
/*DOC*/ "pygame.Rect(rectstyle) -> Rect\n"
1263
/*DOC*/ "create a new rectangle\n"
1265
/*DOC*/ "Creates a new rectangle object. The given\n"
1266
/*DOC*/ "rectstyle represents one of the various ways of\n"
1267
/*DOC*/ "representing rectangle data. This is usually a\n"
1268
/*DOC*/ "sequence of x and y position for the topleft\n"
1269
/*DOC*/ "corner, and the width and height.\n"
1271
/*DOC*/ "For some of the Rect methods there are two version.\n"
1272
/*DOC*/ "For example, there is move() and move_ip(). The methods\n"
1273
/*DOC*/ "witht the '_ip' suffix on the name are the 'in-place'\n"
1274
/*DOC*/ "version of those functions. They effect the actual\n"
1275
/*DOC*/ "source object, instead of returning a new Rect object.\n"
1278
static PyObject* RectInit(PyObject* self, PyObject* args)
1280
GAME_Rect *argrect, temp;
1281
if(!(argrect = GameRect_FromObject(args, &temp)))
1282
return RAISE(PyExc_TypeError, "Argument must be rect style object");
1284
return PyRect_New4(argrect->x, argrect->y, argrect->w, argrect->h);
1289
static PyMethodDef rect__builtins__[] =
1291
{ "Rect", RectInit, 1, doc_Rect },
1298
/*DOC*/ static char rectangle_doc[] =
1299
/*DOC*/ "Module for the rectangle object\n";
1304
PyObject *module, *dict, *apiobj;
1305
static void* c_api[PYGAMEAPI_RECT_NUMSLOTS];
1307
PyGAME_C_API[0] = PyGAME_C_API[0]; /*this cleans a compiler warning*/
1309
/* Create the module and add the functions */
1310
PyType_Init(PyRect_Type);
1313
module = Py_InitModule3("rect", rect__builtins__, rectangle_doc);
1314
dict = PyModule_GetDict(module);
1316
PyDict_SetItemString(dict, "RectType", (PyObject *)&PyRect_Type);
1318
/* export the c api */
1319
c_api[0] = &PyRect_Type;
1320
c_api[1] = PyRect_New;
1321
c_api[2] = PyRect_New4;
1322
c_api[3] = GameRect_FromObject;
1323
apiobj = PyCObject_FromVoidPtr(c_api, NULL);
1324
PyDict_SetItemString(dict, PYGAMEAPI_LOCAL_ENTRY, apiobj);
1327
/*imported needed apis*/
1328
import_pygame_base();