@@ -230,7 +230,9 @@ pub struct Font {
230230
231231#[ pymethods]
232232impl Font {
233- /// Query variable font axes. Returns list of dicts: {tag, min, max, default}.
233+ /// Query variable font axes.
234+ ///
235+ /// Returns a list of `(tag, min, max, default)` tuples.
234236 pub fn variations ( & self ) -> PyResult < Vec < ( String , f32 , f32 , f32 ) > > {
235237 font_variations ( self . entity )
236238 . map ( |axes| {
@@ -241,14 +243,46 @@ impl Font {
241243 . map_err ( |e| PyRuntimeError :: new_err ( format ! ( "{e}" ) ) )
242244 }
243245
244- /// Query font metadata. Returns dict with family, style, weight, width, is_variable.
246+ /// Query font metadata.
247+ ///
248+ /// Returns a `(family, style, weight, width, is_variable)` tuple.
245249 pub fn metadata ( & self ) -> PyResult < ( String , String , f32 , f32 , bool ) > {
246250 font_metadata ( self . entity )
247251 . map ( |m| ( m. family , m. style , m. weight , m. width , m. is_variable ) )
248252 . map_err ( |e| PyRuntimeError :: new_err ( format ! ( "{e}" ) ) )
249253 }
250254}
251255
256+ /// Convert glyph outline data into per-glyph (or per-contour) lists of Python
257+ /// tuples. Each command is a variable-length tuple tagged by a single letter:
258+ /// `("M", x, y)`, `("L", x, y)`, `("Q", cx, cy, x, y)`,
259+ /// `("C", cx1, cy1, cx2, cy2, x, y)`, or `("Z",)`.
260+ fn path_commands_to_py (
261+ py : Python < ' _ > ,
262+ groups : Vec < Vec < processing_render:: render:: primitive:: text:: PathCommand > > ,
263+ ) -> Vec < Vec < Py < PyAny > > > {
264+ use processing_render:: render:: primitive:: text:: PathCommand ;
265+
266+ let to_py = |cmd : PathCommand | -> Py < PyAny > {
267+ match cmd {
268+ PathCommand :: MoveTo ( x, y) => ( "M" , x, y) . into_pyobject ( py) . unwrap ( ) . into_any ( ) . unbind ( ) ,
269+ PathCommand :: LineTo ( x, y) => ( "L" , x, y) . into_pyobject ( py) . unwrap ( ) . into_any ( ) . unbind ( ) ,
270+ PathCommand :: QuadTo { cx, cy, x, y } => {
271+ ( "Q" , cx, cy, x, y) . into_pyobject ( py) . unwrap ( ) . into_any ( ) . unbind ( )
272+ }
273+ PathCommand :: CubicTo { cx1, cy1, cx2, cy2, x, y } => {
274+ ( "C" , cx1, cy1, cx2, cy2, x, y) . into_pyobject ( py) . unwrap ( ) . into_any ( ) . unbind ( )
275+ }
276+ PathCommand :: Close => ( "Z" , ) . into_pyobject ( py) . unwrap ( ) . into_any ( ) . unbind ( ) ,
277+ }
278+ } ;
279+
280+ groups
281+ . into_iter ( )
282+ . map ( |group| group. into_iter ( ) . map ( to_py) . collect ( ) )
283+ . collect ( )
284+ }
285+
252286#[ pyclass]
253287#[ derive( Debug ) ]
254288pub struct Image {
@@ -1081,60 +1115,23 @@ impl Graphics {
10811115 x : f32 ,
10821116 y : f32 ,
10831117 ) -> PyResult < Vec < Vec < Py < PyAny > > > > {
1084- use processing_render:: render:: primitive:: text:: PathCommand ;
1085-
10861118 let paths = graphics_text_to_paths ( self . entity , content, x, y)
10871119 . map_err ( |e| PyRuntimeError :: new_err ( format ! ( "{e}" ) ) ) ?;
1088-
1089- Python :: attach ( |py| {
1090- Ok ( paths
1091- . into_iter ( )
1092- . map ( |glyph| {
1093- glyph
1094- . into_iter ( )
1095- . map ( |cmd| match cmd {
1096- PathCommand :: MoveTo ( x, y) => ( "M" , x, y, 0.0 , 0.0 , 0.0 , 0.0 ) . into_pyobject ( py) . unwrap ( ) . into_any ( ) . unbind ( ) ,
1097- PathCommand :: LineTo ( x, y) => ( "L" , x, y, 0.0 , 0.0 , 0.0 , 0.0 ) . into_pyobject ( py) . unwrap ( ) . into_any ( ) . unbind ( ) ,
1098- PathCommand :: QuadTo { cx, cy, x, y } => ( "Q" , cx, cy, x, y, 0.0 , 0.0 ) . into_pyobject ( py) . unwrap ( ) . into_any ( ) . unbind ( ) ,
1099- PathCommand :: CubicTo { cx1, cy1, cx2, cy2, x, y } => ( "C" , cx1, cy1, cx2, cy2, x, y) . into_pyobject ( py) . unwrap ( ) . into_any ( ) . unbind ( ) ,
1100- PathCommand :: Close => ( "Z" , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 ) . into_pyobject ( py) . unwrap ( ) . into_any ( ) . unbind ( ) ,
1101- } )
1102- . collect ( )
1103- } )
1104- . collect ( ) )
1105- } )
1120+ Python :: attach ( |py| Ok ( path_commands_to_py ( py, paths) ) )
11061121 }
11071122
11081123 /// Extract glyph outlines as per-contour path commands.
11091124 /// Each contour (MoveTo...Close sequence) is a separate list.
1125+ /// Commands use the same tuple shapes as `text_to_paths`.
11101126 pub fn text_to_contours (
11111127 & self ,
11121128 content : & str ,
11131129 x : f32 ,
11141130 y : f32 ,
11151131 ) -> PyResult < Vec < Vec < Py < PyAny > > > > {
1116- use processing_render:: render:: primitive:: text:: PathCommand ;
1117-
11181132 let contours = graphics_text_to_contours ( self . entity , content, x, y)
11191133 . map_err ( |e| PyRuntimeError :: new_err ( format ! ( "{e}" ) ) ) ?;
1120-
1121- Python :: attach ( |py| {
1122- Ok ( contours
1123- . into_iter ( )
1124- . map ( |contour| {
1125- contour
1126- . into_iter ( )
1127- . map ( |cmd| match cmd {
1128- PathCommand :: MoveTo ( x, y) => ( "M" , x, y, 0.0 , 0.0 , 0.0 , 0.0 ) . into_pyobject ( py) . unwrap ( ) . into_any ( ) . unbind ( ) ,
1129- PathCommand :: LineTo ( x, y) => ( "L" , x, y, 0.0 , 0.0 , 0.0 , 0.0 ) . into_pyobject ( py) . unwrap ( ) . into_any ( ) . unbind ( ) ,
1130- PathCommand :: QuadTo { cx, cy, x, y } => ( "Q" , cx, cy, x, y, 0.0 , 0.0 ) . into_pyobject ( py) . unwrap ( ) . into_any ( ) . unbind ( ) ,
1131- PathCommand :: CubicTo { cx1, cy1, cx2, cy2, x, y } => ( "C" , cx1, cy1, cx2, cy2, x, y) . into_pyobject ( py) . unwrap ( ) . into_any ( ) . unbind ( ) ,
1132- PathCommand :: Close => ( "Z" , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 ) . into_pyobject ( py) . unwrap ( ) . into_any ( ) . unbind ( ) ,
1133- } )
1134- . collect ( )
1135- } )
1136- . collect ( ) )
1137- } )
1134+ Python :: attach ( |py| Ok ( path_commands_to_py ( py, contours) ) )
11381135 }
11391136
11401137 /// Sample points along text outlines.
@@ -1167,12 +1164,11 @@ impl Graphics {
11671164 }
11681165
11691166 /// Set per-glyph colors for the next text() call.
1170- /// colors: list of (r, g, b) or (r, g, b, a) tuples with values 0-255.
1171- pub fn text_glyph_colors ( & self , colors : Vec < ( f32 , f32 , f32 , f32 ) > ) -> PyResult < ( ) > {
1172- let colors: Vec < bevy:: color:: Color > = colors
1173- . into_iter ( )
1174- . map ( |( r, g, b, a) | bevy:: color:: Color :: srgba ( r, g, b, a) )
1175- . collect ( ) ;
1167+ ///
1168+ /// `colors` is a list of color objects (as built by `color(...)`); they are
1169+ /// cycled across the glyphs of the next `text()` call.
1170+ pub fn text_glyph_colors ( & self , colors : Vec < PyRef < crate :: color:: PyColor > > ) -> PyResult < ( ) > {
1171+ let colors: Vec < bevy:: color:: Color > = colors. iter ( ) . map ( |c| c. 0 ) . collect ( ) ;
11761172 graphics_text_glyph_colors ( self . entity , colors)
11771173 . map_err ( |e| PyRuntimeError :: new_err ( format ! ( "{e}" ) ) )
11781174 }
@@ -1200,12 +1196,6 @@ impl Graphics {
12001196 . map_err ( |e| PyRuntimeError :: new_err ( format ! ( "{e}" ) ) )
12011197 }
12021198
1203- /// Set text direction. 0=AUTO, 1=LTR, 2=RTL
1204- pub fn text_direction ( & self , dir : u8 ) -> PyResult < ( ) > {
1205- graphics_text_direction ( self . entity , dir)
1206- . map_err ( |e| PyRuntimeError :: new_err ( format ! ( "{e}" ) ) )
1207- }
1208-
12091199 pub fn text_wrap ( & self , mode : u8 ) -> PyResult < ( ) > {
12101200 use processing:: prelude:: TextWrapMode ;
12111201 graphics_record_command ( self . entity , DrawCommand :: TextWrap ( TextWrapMode :: from ( mode) ) )
0 commit comments