Skip to content

Commit 0a617b9

Browse files
committed
Re-implement outline with color and size properties.
1 parent edcb35f commit 0a617b9

File tree

6 files changed

+122
-27
lines changed

6 files changed

+122
-27
lines changed

buildconfig/stubs/pygame/font.pyi

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,9 +57,13 @@ class Font:
5757
@point_size.setter
5858
def point_size(self, value: int) -> None: ...
5959
@property
60-
def outline(self) -> int: ...
61-
@outline.setter
62-
def outline(self, value: int) -> None: ...
60+
def outline_size(self) -> int: ...
61+
@outline_size.setter
62+
def outline_size(self, value: int) -> None: ...
63+
@property
64+
def outline_color(self) -> ColorValue: ...
65+
@outline_color.setter
66+
def outline_color(self, value: ColorValue) -> None: ...
6367
def __init__(self, filename: Optional[FileArg] = None, size: int = 20) -> None: ...
6468
def render(
6569
self,

docs/reST/ref/font.rst

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -306,16 +306,27 @@ solves no longer exists, it will likely be removed in the future.
306306

307307
.. ## Font.point_size ##
308308
309-
.. attribute:: outline
309+
.. attribute:: outline_size
310310

311311
| :sl:`Gets or sets the font's outline size`
312-
| :sg:`outline -> int`
312+
| :sg:`outline_size -> int`
313313
314314
Returns the size of the outline.
315315

316316
.. versionadded:: 2.5.0
317317

318-
.. ## Font.outline ##
318+
.. ## Font.outline_size ##
319+
320+
.. attribute:: outline_color
321+
322+
| :sl:`Gets or sets the font's outline color`
323+
| :sg:`outline_size -> RGB`
324+
325+
Returns the color of the outline.
326+
327+
.. versionadded:: 2.5.0
328+
329+
.. ## Font.outline_color ##
319330
320331
.. method:: render
321332

src_c/doc/font_doc.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@
1717
#define DOC_FONT_FONT_STRIKETHROUGH "strikethrough -> bool\nGets or sets whether the font should be rendered with a strikethrough."
1818
#define DOC_FONT_FONT_ALIGN "align -> int\nSet how rendered text is aligned when given a wrap length."
1919
#define DOC_FONT_FONT_POINTSIZE "point_size -> int\nGets or sets the font's point size"
20-
#define DOC_FONT_FONT_OUTLINE "outline -> int\nGets or sets the font's outline size"
20+
#define DOC_FONT_FONT_OUTLINESIZE "outline_size -> int\nGets or sets the font's outline size"
21+
#define DOC_FONT_FONT_OUTLINECOLOR "outline_size -> RGB\nGets or sets the font's outline color"
2122
#define DOC_FONT_FONT_RENDER "render(text, antialias, color, bgcolor=None, wraplength=0) -> Surface\ndraw text on a new Surface"
2223
#define DOC_FONT_FONT_SIZE "size(text, /) -> (width, height)\ndetermine the amount of space needed to render text"
2324
#define DOC_FONT_FONT_SETUNDERLINE "set_underline(bool, /) -> None\ncontrol if text is rendered with an underline"

src_c/font.c

Lines changed: 71 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -829,34 +829,91 @@ font_getter_style_name(PyObject *self, void *closure)
829829
return PyUnicode_FromString(font_style_name ? font_style_name : "");
830830
}
831831

832+
static PyObject *
833+
font_getter_outline_size(PyFontObject *self, void *closure)
834+
{
835+
if (!PgFont_GenerationCheck(self))
836+
return RAISE_FONT_QUIT_ERROR();
837+
838+
#if SDL_TTF_VERSION_ATLEAST(2, 0, 12)
839+
return PyLong_FromLong(self->outline_size);
840+
#else
841+
return RAISE(pgExc_SDLError,
842+
"Incorrect SDL_TTF version (requires 2.0.12)");
843+
#endif
844+
}
845+
832846
static int
833-
font_setter_outline(PyObject *self, PyObject *value, void *closure)
847+
font_setter_outline_size(PyFontObject *self, PyObject *value, void *closure)
834848
{
835849
if (!PgFont_GenerationCheck(self)) {
836850
RAISE_FONT_QUIT_ERROR_RETURN(-1);
837851
}
838852

839-
TTF_Font *font = PyFont_AsFont(self);
840-
int val;
853+
#if SDL_TTF_VERSION_ATLEAST(2, 0, 12)
854+
int val = PyLong_AsLong(value);
841855

842-
DEL_ATTR_NOT_SUPPORTED_CHECK("outline", value);
856+
if (PyErr_Occurred() && val == -1)
857+
return -1;
843858

844-
val = PyLong_AsLong(value);
845-
if ((val == -1) && (PyErr_Occurred() != NULL))
859+
if (val < 0) {
860+
PyErr_SetString(PyExc_ValueError,
861+
"outline_size cannot be less than 0");
846862
return -1;
863+
}
864+
865+
self->outline_size = val;
847866

848-
TTF_SetFontOutline(font, val);
849867
return 0;
868+
#else
869+
PyErr_SetString(pgExc_SDLError,
870+
"Incorrect SDL_TTF version (requires 2.0.12)");
871+
return -1;
872+
#endif
850873
}
851874

852875
static PyObject *
853-
font_getter_outline(PyObject *self, void *closure)
876+
font_getter_outline_color(PyFontObject *self, void *closure)
854877
{
855-
if (!PgFont_GenerationCheck(self)) {
878+
if (!PgFont_GenerationCheck(self))
856879
return RAISE_FONT_QUIT_ERROR();
880+
881+
#if SDL_TTF_VERSION_ATLEAST(2, 0, 12)
882+
return Py_BuildValue("(bbbb)", self->outline_color.r,
883+
self->outline_color.g, self->outline_color.b,
884+
self->outline_color.a);
885+
#else
886+
return RAISE(pgExc_SDLError,
887+
"Incorrect SDL_TTF version (requires 2.0.12)");
888+
#endif
889+
}
890+
891+
static int
892+
font_setter_outline_color(PyFontObject *self, PyObject *value, void *closure)
893+
{
894+
Uint8 rgba[] = {0, 0, 0, 0};
895+
896+
if (!PgFont_GenerationCheck(self)) {
897+
RAISE_FONT_QUIT_ERROR_RETURN(-1);
857898
}
858899

859-
return PyLong_FromLong(TTF_GetFontOutline(PyFont_AsFont(self)));
900+
#if SDL_TTF_VERSION_ATLEAST(2, 0, 12)
901+
if (!pg_RGBAFromObjEx(value, rgba, PG_COLOR_HANDLE_ALL)) {
902+
return -1;
903+
}
904+
905+
if (PyErr_Occurred())
906+
return -1;
907+
908+
SDL_Color val = {rgba[0], rgba[1], rgba[2], SDL_ALPHA_OPAQUE};
909+
self->outline_color = val;
910+
911+
return 0;
912+
#else
913+
PyErr_SetString(pgExc_SDLError,
914+
"Incorrect SDL_TTF version (requires 2.0.12)");
915+
return -1;
916+
#endif
860917
}
861918

862919
static PyObject *
@@ -1088,8 +1145,10 @@ static PyGetSetDef font_getsets[] = {
10881145
DOC_FONT_FONT_ALIGN, NULL},
10891146
{"point_size", (getter)font_getter_point_size,
10901147
(setter)font_setter_point_size, DOC_FONT_FONT_POINTSIZE, NULL},
1091-
{"outline", (getter)font_getter_outline, (setter)font_setter_outline,
1092-
DOC_FONT_FONT_OUTLINE, NULL},
1148+
{"outline_color", (getter)font_getter_outline_color,
1149+
(setter)font_setter_outline_color, DOC_FONT_FONT_OUTLINECOLOR, NULL},
1150+
{"outline_size", (getter)font_getter_outline_size,
1151+
(setter)font_setter_outline_size, DOC_FONT_FONT_OUTLINESIZE, NULL},
10931152
{NULL, NULL, NULL, NULL, NULL}};
10941153

10951154
static PyMethodDef font_methods[] = {

src_c/include/pygame_font.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,10 @@ typedef struct {
2929
PyObject_HEAD TTF_Font *font;
3030
PyObject *weakreflist;
3131
int ptsize;
32+
33+
SDL_Color outline_color;
34+
int outline_size;
35+
3236
unsigned int ttf_init_generation;
3337
} PyFontObject;
3438
#define PyFont_AsFont(x) (((PyFontObject *)x)->font)

test/font_test.py

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -981,7 +981,8 @@ def test_font_property_should_raise_exception_after_quit(self):
981981
("italic", True),
982982
("underline", True),
983983
("strikethrough", True),
984-
("outline", 2),
984+
("outline_size", 2),
985+
("outline_color", (20, 0, 6)),
985986
]
986987
skip_properties = set()
987988
version = pygame.font.get_sdl_ttf_version()
@@ -1058,7 +1059,8 @@ def query(
10581059
underline=False,
10591060
strikethrough=False,
10601061
antialiase=False,
1061-
outline=2,
1062+
outline_size=2,
1063+
outline_color=(20, 0, 6),
10621064
):
10631065
if self.aborted:
10641066
return False
@@ -1069,7 +1071,15 @@ def query(
10691071
screen = self.screen
10701072
screen.fill((255, 255, 255))
10711073
pygame.display.flip()
1072-
if not (bold or italic or underline or strikethrough or antialiase or outline):
1074+
if not (
1075+
bold
1076+
or italic
1077+
or underline
1078+
or strikethrough
1079+
or antialiase
1080+
or outline_size
1081+
or outline_color
1082+
):
10731083
text = "normal"
10741084
else:
10751085
modes = []
@@ -1083,14 +1093,17 @@ def query(
10831093
modes.append("strikethrough")
10841094
if antialiase:
10851095
modes.append("antialiased")
1086-
if outline:
1087-
modes.append("outline")
1096+
if outline_size:
1097+
modes.append("outline_size")
1098+
if outline_color:
1099+
modes.append("outline_color")
10881100
text = f"{'-'.join(modes)} (y/n):"
10891101
f.set_bold(bold)
10901102
f.set_italic(italic)
10911103
f.set_underline(underline)
10921104
f.set_strikethrough(strikethrough)
1093-
f.outline = outline
1105+
f.outline_size = outline_size
1106+
f.outline_color = outline_color
10941107
s = f.render(text, antialiase, (0, 0, 0))
10951108
screen.blit(s, (offset, y))
10961109
y += s.get_size()[1] + spacing
@@ -1130,8 +1143,11 @@ def test_strikethrough(self):
11301143
def test_antialiase(self):
11311144
self.assertTrue(self.query(antialiase=True))
11321145

1133-
def test_outline(self):
1134-
self.assertTrue(self.query(outline=True))
1146+
def test_outline_size(self):
1147+
self.assertTrue(self.query(outline_size=2))
1148+
1149+
def test_outline_color(self):
1150+
self.assertTrue(self.query(outline_color=(20, 0, 6)))
11351151

11361152
def test_bold_antialiase(self):
11371153
self.assertTrue(self.query(bold=True, antialiase=True))

0 commit comments

Comments
 (0)