Skip to content

Commit 0449cf5

Browse files
authored
Merge pull request #1944 from yunline/frect
Implement FRect
2 parents 1c60bf9 + b04dc1f commit 0449cf5

18 files changed

+3809
-2091
lines changed

buildconfig/Setup.Android.SDL2.in

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ display src_c/display.c $(SDL) $(DEBUG)
4949
event src_c/event.c $(SDL) $(DEBUG)
5050
key src_c/key.c $(SDL) $(DEBUG)
5151
mouse src_c/mouse.c $(SDL) $(DEBUG)
52-
rect src_c/rect.c $(SDL) $(DEBUG)
52+
rect src_c/rect.c src_c/pgcompat_rect.c $(SDL) $(DEBUG)
5353
rwobject src_c/rwobject.c $(SDL) $(DEBUG)
5454
surface src_c/surface.c src_c/alphablit.c src_c/surface_fill.c $(SDL) $(DEBUG)
5555
surflock src_c/surflock.c $(SDL) $(DEBUG)

buildconfig/Setup.SDL2.in

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ display src_c/display.c $(SDL) $(DEBUG)
5959
event src_c/event.c $(SDL) $(DEBUG)
6060
key src_c/key.c $(SDL) $(DEBUG)
6161
mouse src_c/mouse.c $(SDL) $(DEBUG)
62-
rect src_c/rect.c $(SDL) $(DEBUG)
62+
rect src_c/rect.c src_c/pgcompat_rect.c $(SDL) $(DEBUG)
6363
rwobject src_c/rwobject.c $(SDL) $(DEBUG)
6464
surface src_c/simd_blitters_sse2.c src_c/simd_blitters_avx2.c src_c/surface.c src_c/alphablit.c src_c/surface_fill.c $(SDL) $(DEBUG)
6565
surflock src_c/surflock.c $(SDL) $(DEBUG)

buildconfig/stubs/gen_stubs.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@
5454

5555
# pygame classes that are autoimported into main namespace are kept in this dict
5656
PG_AUTOIMPORT_CLASSES = {
57-
"rect": ["Rect"],
57+
"rect": ["Rect", "FRect"],
5858
"surface": ["Surface", "SurfaceType"],
5959
"color": ["Color"],
6060
"pixelarray": ["PixelArray"],

buildconfig/stubs/pygame/__init__.pyi

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ from pygame import (
4444
system as system,
4545
)
4646

47-
from .rect import Rect as Rect
47+
from .rect import Rect as Rect, FRect as FRect
4848
from .surface import Surface as Surface, SurfaceType as SurfaceType
4949
from .color import Color as Color
5050
from .pixelarray import PixelArray as PixelArray

buildconfig/stubs/pygame/_common.pyi

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ from typing_extensions import Protocol
66

77
from pygame.color import Color
88
from pygame.math import Vector2
9-
from pygame.rect import Rect
9+
from pygame.rect import Rect, FRect
1010

1111
# For functions that take a file name
1212
AnyPath = Union[str, bytes, PathLike[str], PathLike[bytes]]
@@ -23,9 +23,12 @@ ColorValue = Union[Color, int, str, Tuple[int, int, int], RGBAOutput, Sequence[i
2323

2424
_CanBeRect = Union[
2525
Rect,
26+
FRect,
2627
Tuple[int, int, int, int],
28+
Tuple[float, float, float, float],
2729
Tuple[Coordinate, Coordinate],
2830
Sequence[int],
31+
Sequence[float],
2932
Sequence[Coordinate],
3033
]
3134

buildconfig/stubs/pygame/rect.pyi

Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,4 +197,177 @@ class Rect(Collection[int]):
197197
self, rect_dict: Dict[_K, "Rect"], values: bool
198198
) -> List[Tuple[_K, "Rect"]]: ...
199199

200+
class FRect(Collection[float]):
201+
x: float
202+
y: float
203+
top: float
204+
left: float
205+
bottom: float
206+
right: float
207+
topleft: Tuple[float, float]
208+
bottomleft: Tuple[float, float]
209+
topright: Tuple[float, float]
210+
bottomright: Tuple[float, float]
211+
midtop: Tuple[float, float]
212+
midleft: Tuple[float, float]
213+
midbottom: Tuple[float, float]
214+
midright: Tuple[float, float]
215+
center: Tuple[float, float]
216+
centerx: float
217+
centery: float
218+
size: Tuple[float, float]
219+
width: float
220+
height: float
221+
w: float
222+
h: float
223+
__hash__: None # type: ignore
224+
__safe_for_unpickling__: Literal[True]
225+
@overload
226+
def __init__(
227+
self, left: float, top: float, width: float, height: float
228+
) -> None: ...
229+
@overload
230+
def __init__(self, left_top: Coordinate, width_height: Coordinate) -> None: ...
231+
@overload
232+
def __init__(self, single_arg: RectValue) -> None: ...
233+
def __len__(self) -> Literal[4]: ...
234+
def __iter__(self) -> Iterator[float]: ...
235+
@overload
236+
def __getitem__(self, i: int) -> float: ...
237+
@overload
238+
def __getitem__(self, s: slice) -> List[float]: ...
239+
@overload
240+
def __setitem__(self, key: int, value: float) -> None: ...
241+
@overload
242+
def __setitem__(self, key: slice, value: Union[float, FRect]) -> None: ...
243+
def __copy__(self) -> FRect: ...
244+
copy = __copy__
245+
@overload
246+
def move(self, x: float, y: float) -> FRect: ...
247+
@overload
248+
def move(self, move_by: Coordinate) -> FRect: ...
249+
@overload
250+
def move_ip(self, x: float, y: float) -> None: ...
251+
@overload
252+
def move_ip(self, move_by: Coordinate) -> None: ...
253+
@overload
254+
def inflate(self, x: float, y: float) -> FRect: ...
255+
@overload
256+
def inflate(self, inflate_by: Coordinate) -> FRect: ...
257+
@overload
258+
def inflate_ip(self, x: float, y: float) -> None: ...
259+
@overload
260+
def inflate_ip(self, inflate_by: Coordinate) -> None: ...
261+
@overload
262+
def update(self, left: float, top: float, width: float, height: float) -> None: ...
263+
@overload
264+
def update(self, left_top: Coordinate, width_height: Coordinate) -> None: ...
265+
@overload
266+
def update(self, single_arg: RectValue) -> None: ...
267+
@overload
268+
def clamp(self, rect: RectValue) -> FRect: ...
269+
@overload
270+
def clamp(self, left_top: Coordinate, width_height: Coordinate) -> FRect: ...
271+
@overload
272+
def clamp(self, left: float, top: float, width: float, height: float) -> FRect: ...
273+
@overload
274+
def clamp_ip(self, rect: RectValue) -> None: ...
275+
@overload
276+
def clamp_ip(self, left_top: Coordinate, width_height: Coordinate) -> None: ...
277+
@overload
278+
def clamp_ip(
279+
self, left: float, top: float, width: float, height: float
280+
) -> None: ...
281+
@overload
282+
def clip(self, rect: RectValue) -> FRect: ...
283+
@overload
284+
def clip(self, left_top: Coordinate, width_height: Coordinate) -> FRect: ...
285+
@overload
286+
def clip(self, left: float, top: float, width: float, height: float) -> FRect: ...
287+
@overload
288+
def clipline(
289+
self, x1: float, x2: float, x3: float, x4: float
290+
) -> Union[Tuple[Tuple[float, float], Tuple[float, float]], Tuple[()]]: ...
291+
@overload
292+
def clipline(
293+
self, first_coordinate: Coordinate, second_coordinate: Coordinate
294+
) -> Union[Tuple[Tuple[float, float], Tuple[float, float]], Tuple[()]]: ...
295+
@overload
296+
def clipline(
297+
self, rect_arg: RectValue
298+
) -> Union[Tuple[Tuple[float, float], Tuple[float, float]], Tuple[()]]: ...
299+
@overload
300+
def union(self, rect: RectValue) -> FRect: ...
301+
@overload
302+
def union(self, left_top: Coordinate, width_height: Coordinate) -> FRect: ...
303+
@overload
304+
def union(self, left: float, top: float, width: float, height: float) -> FRect: ...
305+
@overload
306+
def union_ip(self, rect: RectValue) -> None: ...
307+
@overload
308+
def union_ip(self, left_top: Coordinate, width_height: Coordinate) -> None: ...
309+
@overload
310+
def union_ip(
311+
self, left: float, top: float, width: float, height: float
312+
) -> None: ...
313+
def unionall(self, rect: Sequence[RectValue]) -> FRect: ...
314+
def unionall_ip(self, rect_sequence: Sequence[RectValue]) -> None: ...
315+
@overload
316+
def fit(self, rect: RectValue) -> FRect: ...
317+
@overload
318+
def fit(self, left_top: Coordinate, width_height: Coordinate) -> FRect: ...
319+
@overload
320+
def fit(self, left: float, top: float, width: float, height: float) -> FRect: ...
321+
def normalize(self) -> None: ...
322+
def __contains__(self, rect: Union[RectValue, float]) -> bool: ... # type: ignore[override]
323+
@overload
324+
def contains(self, rect: RectValue) -> bool: ...
325+
@overload
326+
def contains(self, left_top: Coordinate, width_height: Coordinate) -> bool: ...
327+
@overload
328+
def contains(
329+
self, left: float, top: float, width: float, height: float
330+
) -> bool: ...
331+
@overload
332+
def collidepoint(self, x: float, y: float) -> bool: ...
333+
@overload
334+
def collidepoint(self, x_y: Coordinate) -> bool: ...
335+
@overload
336+
def colliderect(self, rect: RectValue) -> bool: ...
337+
@overload
338+
def colliderect(self, left_top: Coordinate, width_height: Coordinate) -> bool: ...
339+
@overload
340+
def colliderect(
341+
self, left: float, top: float, width: float, height: float
342+
) -> bool: ...
343+
def collidelist(self, rect_list: Sequence[RectValue]) -> float: ...
344+
def collidelistall(self, rect_list: Sequence[RectValue]) -> List[float]: ...
345+
def collideobjectsall(
346+
self, objects: Sequence[_T], key: Optional[Callable[[_T], RectValue]] = None
347+
) -> List[_T]: ...
348+
def collideobjects(
349+
self, objects: Sequence[_T], key: Optional[Callable[[_T], RectValue]] = None
350+
) -> Optional[_T]: ...
351+
# Also undocumented: the dict collision methods take a 'values' argument
352+
# that defaults to False. If it is False, the keys in rect_dict must be
353+
# Rect-like; otherwise, the values must be Rects.
354+
@overload
355+
def collidedict(
356+
self, rect_dict: Dict[RectValue, _V], values: bool = ...
357+
) -> Tuple[RectValue, _V]: ...
358+
@overload
359+
def collidedict(
360+
self, rect_dict: Dict[_K, "FRect"], values: bool
361+
) -> Tuple[_K, "FRect"]: ...
362+
@overload
363+
def collidedictall(
364+
self, rect_dict: Dict[RectValue, _V], values: bool = ...
365+
) -> List[Tuple[RectValue, _V]]: ...
366+
@overload
367+
def collidedictall(
368+
self, rect_dict: Dict[_K, "FRect"], values: bool
369+
) -> List[Tuple[_K, "FRect"]]: ...
370+
200371
RectType = Rect
372+
FRectType = FRect
373+

docs/reST/c_api/rect.rst

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
src_c/rect.c
1010
============
1111

12-
This extension module defines Python type :py:class:`pygame.Rect`.
12+
This extension module defines Python type :py:class:`pygame.Rect` & :py:class:`pygame.FRect`.
1313

1414
Header file: src_c/include/pygame.h
1515

@@ -19,25 +19,50 @@ Header file: src_c/include/pygame.h
1919
2020
The Pygame rectangle type instance.
2121

22+
.. c:type:: pgFRectObject
23+
24+
.. c:member:: SDL_FRect r
25+
26+
The Pygame rectangle type instance.
27+
2228
.. c:var:: PyTypeObject *pgRect_Type
2329
2430
The Pygame rectangle object type pygame.Rect.
2531

32+
.. c:var:: PyTypeObject *pgRFect_Type
33+
34+
The Pygame rectangle object type pygame.FRect.
35+
2636
.. c:function:: SDL_Rect pgRect_AsRect(PyObject *obj)
2737
2838
A macro to access the SDL_Rect field of a :py:class:`pygame.Rect` instance.
2939
40+
.. c:function:: SDL_FRect pgFRect_AsRect(PyObject *obj)
41+
42+
A macro to access the SDL_FRect field of a :py:class:`pygame.FRect` instance.
43+
3044
.. c:function:: PyObject* pgRect_New(SDL_Rect *r)
3145
3246
Return a new :py:class:`pygame.Rect` instance from the SDL_Rect *r*.
3347
On failure, raise a Python exception and return *NULL*.
3448
49+
.. c:function:: PyObject* pgRFect_New(SDL_FRect *r)
50+
51+
Return a new :py:class:`pygame.FRect` instance from the SDL_FRect *r*.
52+
On failure, raise a Python exception and return *NULL*.
53+
3554
.. c:function:: PyObject* pgRect_New4(int x, int y, int w, int h)
3655
3756
Return a new pygame.Rect instance with position (*x*, *y*) and
3857
size (*w*, *h*).
3958
On failure raise a Python exception and return *NULL*.
4059
60+
.. c:function:: PyObject* pgFRect_New4(float x, float y, float w, float h)
61+
62+
Return a new pygame.FRect instance with position (*x*, *y*) and
63+
size (*w*, *h*).
64+
On failure raise a Python exception and return *NULL*.
65+
4166
.. c:function:: SDL_Rect* pgRect_FromObject(PyObject *obj, SDL_Rect *temp)
4267
4368
Translate a Python rectangle representation as a Pygame :c:type:`SDL_Rect`.
@@ -51,7 +76,25 @@ Header file: src_c/include/pygame.h
5176
of the rectangle, else return *NULL*.
5277
No Python exceptions are raised.
5378
79+
.. c:function:: SDL_FRect* pgFRect_FromObject(PyObject *obj, SDL_FRect *temp)
80+
81+
Translate a Python rectangle representation as a Pygame :c:type:`SDL_FRect`.
82+
A rectangle can be a length 4 sequence floats (x, y, w, h),
83+
or a length 2 sequence of position (x, y) and size (w, h),
84+
or a length 1 tuple containing a rectangle representation,
85+
or have a method *rect* that returns a rectangle.
86+
Pass a pointer to a locally declared :c:type:`SDL_FRect` as *temp*.
87+
Do not rely on this being filled in; use the function's return value instead.
88+
On success, return a pointer to a :c:type:`SDL_FRect` representation
89+
of the rectangle, else return *NULL*.
90+
No Python exceptions are raised.
91+
5492
.. c:function:: void pgRect_Normalize(SDL_Rect *rect)
5593
5694
Normalize the given rect. A rect with a negative size (negative width and/or
5795
height) will be adjusted to have a positive size.
96+
97+
.. c:function:: void pgFRect_Normalize(SDL_FRect *rect)
98+
99+
Normalize the given rect. A rect with a negative size (negative width and/or
100+
height) will be adjusted to have a positive size.

docs/reST/ref/rect.rst

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,11 @@
1111
| :sg:`Rect(left, top, width, height) -> Rect`
1212
| :sg:`Rect((left, top), (width, height)) -> Rect`
1313
| :sg:`Rect(object) -> Rect`
14+
| :sg:`FRect(left, top, width, height) -> FRect`
15+
| :sg:`FRect((left, top), (width, height)) -> FRect`
16+
| :sg:`FRect(object) -> FRect`
17+
18+
.. versionchanged:: 2.2 Since version 2.2 there is another class called FRect that serves the same purpose as as `Rect` but it can hold floats instead of integers.
1419

1520
Pygame uses Rect objects to store and manipulate rectangular areas. A Rect
1621
can be created from a combination of left, top, width, and height values.
@@ -557,4 +562,4 @@
557562
558563
.. ## Rect.collidedictall ##
559564
560-
.. ## pygame.Rect ##
565+
.. ## pygame.Rect ##

src_c/_pygame.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -330,7 +330,7 @@ struct pgColorObject {
330330
* Remember to keep these constants up to date.
331331
*/
332332

333-
#define PYGAMEAPI_RECT_NUMSLOTS 5
333+
#define PYGAMEAPI_RECT_NUMSLOTS 10
334334
#define PYGAMEAPI_JOYSTICK_NUMSLOTS 2
335335
#define PYGAMEAPI_DISPLAY_NUMSLOTS 2
336336
#define PYGAMEAPI_SURFACE_NUMSLOTS 4

src_c/doc/rect_doc.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/* Auto generated file: with makeref.py . Docs go in docs/reST/ref/ . */
2-
#define DOC_RECT "Rect(left, top, width, height) -> Rect\nRect((left, top), (width, height)) -> Rect\nRect(object) -> Rect\npygame object for storing rectangular coordinates"
2+
#define DOC_RECT "Rect(left, top, width, height) -> Rect\nRect((left, top), (width, height)) -> Rect\nRect(object) -> Rect\nFRect(left, top, width, height) -> FRect\nFRect((left, top), (width, height)) -> FRect\nFRect(object) -> FRect\npygame object for storing rectangular coordinates"
33
#define DOC_RECT_COPY "copy() -> Rect\ncopy the rectangle"
44
#define DOC_RECT_MOVE "move(x, y) -> Rect\nmoves the rectangle"
55
#define DOC_RECT_MOVEIP "move_ip(x, y) -> None\nmoves the rectangle, in place"

src_c/include/_pygame.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,13 @@ typedef struct {
167167
PyObject *weakreflist;
168168
} pgRectObject;
169169

170+
typedef struct {
171+
PyObject_HEAD SDL_FRect r;
172+
PyObject *weakreflist;
173+
} pgFRectObject;
174+
170175
#define pgRect_AsRect(x) (((pgRectObject *)x)->r)
176+
#define pgFRect_AsRect(x) (((pgFRectObject *)x)->r)
171177
#ifndef PYGAMEAPI_RECT_INTERNAL
172178
#define pgRect_Type (*(PyTypeObject *)PYGAMEAPI_GET_SLOT(rect, 0))
173179

@@ -182,6 +188,20 @@ typedef struct {
182188

183189
#define pgRect_Normalize (*(void (*)(SDL_Rect *))PYGAMEAPI_GET_SLOT(rect, 4))
184190

191+
#define pgFRect_Type (*(PyTypeObject *)PYGAMEAPI_GET_SLOT(rect, 5))
192+
193+
#define pgFRect_Check(x) ((x)->ob_type == &pgFRect_Type)
194+
#define pgFRect_New \
195+
(*(PyObject * (*)(SDL_FRect *)) PYGAMEAPI_GET_SLOT(rect, 6))
196+
197+
#define pgFRect_New4 \
198+
(*(PyObject * (*)(float, float, float, float)) PYGAMEAPI_GET_SLOT(rect, 7))
199+
200+
#define pgFRect_FromObject \
201+
(*(SDL_FRect * (*)(PyObject *, SDL_FRect *)) PYGAMEAPI_GET_SLOT(rect, 8))
202+
203+
#define pgFRect_Normalize (*(void (*)(SDL_FRect *))PYGAMEAPI_GET_SLOT(rect, 9))
204+
185205
#define import_pygame_rect() IMPORT_PYGAME_MODULE(rect)
186206
#endif /* ~PYGAMEAPI_RECT_INTERNAL */
187207

0 commit comments

Comments
 (0)