@@ -72,13 +72,19 @@ def __init__(
72
72
color = 0xFFFFFF ,
73
73
background_color = None ,
74
74
line_spacing = 1.25 ,
75
+ background_tight = False ,
76
+ padding_top = 0 ,
77
+ padding_bottom = 0 ,
78
+ padding_left = 0 ,
79
+ padding_right = 0 ,
75
80
** kwargs
76
81
):
77
82
if not max_glyphs and not text :
78
83
raise RuntimeError ("Please provide a max size, or initial text" )
79
84
if not max_glyphs :
80
- max_glyphs = len (text )
85
+ max_glyphs = len (text ) + 1 # add one for the background bitmap tileGrid
81
86
super ().__init__ (max_size = max_glyphs , ** kwargs )
87
+
82
88
self .width = max_glyphs
83
89
self ._font = font
84
90
self ._text = None
@@ -87,28 +93,94 @@ def __init__(
87
93
self .y = y
88
94
89
95
self .palette = displayio .Palette (2 )
90
- if background_color is not None :
91
- self .palette [0 ] = background_color
92
- self .palette .make_opaque (0 )
93
- self ._transparent_background = False
94
- else :
95
- self .palette [0 ] = 0
96
- self .palette .make_transparent (0 )
97
- self ._transparent_background = True
96
+ self .palette [0 ] = 0
97
+ self .palette .make_transparent (0 )
98
98
self .palette [1 ] = color
99
99
100
- bounds = self ._font .get_bounding_box ()
101
- self .height = bounds [1 ]
100
+ self .height = self ._font .get_bounding_box ()[1 ]
102
101
self ._line_spacing = line_spacing
103
102
self ._boundingbox = None
104
103
104
+ self ._background_tight = (
105
+ background_tight # sets padding status for text background box
106
+ )
107
+
108
+ self ._background_color = background_color
109
+ self ._background_palette = displayio .Palette (1 )
110
+ self .append (
111
+ displayio .TileGrid (
112
+ displayio .Bitmap (0 , 0 , 1 ), pixel_shader = self ._background_palette
113
+ )
114
+ ) # initialize with a blank tilegrid placeholder for background
115
+
116
+ self ._padding_top = padding_top
117
+ self ._padding_bottom = padding_bottom
118
+ self ._padding_left = padding_left
119
+ self ._padding_right = padding_right
120
+
105
121
if text is not None :
106
122
self ._update_text (str (text ))
107
123
124
+ def _create_background_box (self , lines , y_offset ):
125
+
126
+ left = self ._boundingbox [0 ]
127
+
128
+ if self ._background_tight : # draw a tight bounding box
129
+ box_width = self ._boundingbox [2 ]
130
+ box_height = self ._boundingbox [3 ]
131
+ x_box_offset = 0
132
+ y_box_offset = self ._boundingbox [1 ]
133
+
134
+ else : # draw a "loose" bounding box to include any ascenders/descenders.
135
+
136
+ # check a few glyphs for maximum ascender and descender height
137
+ # Enhancement: it would be preferred to access the font "FONT_ASCENT" and
138
+ # "FONT_DESCENT" in the imported BDF file
139
+ glyphs = "M j'" # choose glyphs with highest ascender and lowest
140
+ # descender, will depend upon font used
141
+ ascender_max = descender_max = 0
142
+ for char in glyphs :
143
+ this_glyph = self ._font .get_glyph (ord (char ))
144
+ ascender_max = max (ascender_max , this_glyph .height + this_glyph .dy )
145
+ descender_max = max (descender_max , - this_glyph .dy )
146
+
147
+ box_width = self ._boundingbox [2 ] + self ._padding_left + self ._padding_right
148
+ x_box_offset = - self ._padding_left
149
+ box_height = (
150
+ (ascender_max + descender_max )
151
+ + int ((lines - 1 ) * self .height * self ._line_spacing )
152
+ + self ._padding_top
153
+ + self ._padding_bottom
154
+ )
155
+ y_box_offset = - ascender_max + y_offset - self ._padding_top
156
+
157
+ self ._update_background_color (self ._background_color )
158
+ box_width = max (0 , box_width ) # remove any negative values
159
+ box_height = max (0 , box_height ) # remove any negative values
160
+
161
+ background_bitmap = displayio .Bitmap (box_width , box_height , 1 )
162
+ tile_grid = displayio .TileGrid (
163
+ background_bitmap ,
164
+ pixel_shader = self ._background_palette ,
165
+ x = left + x_box_offset ,
166
+ y = y_box_offset ,
167
+ )
168
+
169
+ return tile_grid
170
+
171
+ def _update_background_color (self , new_color ):
172
+
173
+ if new_color is None :
174
+ self ._background_palette .make_transparent (0 )
175
+ else :
176
+ self ._background_palette .make_opaque (0 )
177
+ self ._background_palette [0 ] = new_color
178
+ self ._background_color = new_color
179
+
108
180
def _update_text (self , new_text ): # pylint: disable=too-many-locals
109
181
x = 0
110
182
y = 0
111
- i = 0
183
+ i = 1
112
184
old_c = 0
113
185
y_offset = int (
114
186
(
@@ -118,17 +190,19 @@ def _update_text(self, new_text): # pylint: disable=too-many-locals
118
190
/ 2
119
191
)
120
192
left = right = top = bottom = 0
193
+ lines = 1
121
194
for character in new_text :
122
195
if character == "\n " :
123
196
y += int (self .height * self ._line_spacing )
124
197
x = 0
198
+ lines += 1
125
199
continue
126
200
glyph = self ._font .get_glyph (ord (character ))
127
201
if not glyph :
128
202
continue
129
- right = max (right , x + glyph .width + glyph . shift_x )
203
+ right = max (right , x + glyph .shift_x )
130
204
if y == 0 : # first line, find the Ascender height
131
- top = min (top , - glyph .height + y_offset )
205
+ top = min (top , - glyph .height - glyph . dy + y_offset )
132
206
bottom = max (bottom , y - glyph .dy + y_offset )
133
207
position_y = y - glyph .height - glyph .dy + y_offset
134
208
position_x = x + glyph .dx
@@ -161,14 +235,14 @@ def _update_text(self, new_text): # pylint: disable=too-many-locals
161
235
else :
162
236
self .append (face )
163
237
elif self ._text and character == self ._text [old_c ]:
238
+
164
239
try :
165
240
self [i ].position = (position_x , position_y )
166
241
except AttributeError :
167
242
self [i ].x = position_x
168
243
self [i ].y = position_y
169
244
170
245
x += glyph .shift_x
171
-
172
246
# TODO skip this for control sequences or non-printables.
173
247
i += 1
174
248
old_c += 1
@@ -187,6 +261,7 @@ def _update_text(self, new_text): # pylint: disable=too-many-locals
187
261
self .pop ()
188
262
self ._text = new_text
189
263
self ._boundingbox = (left , top , left + right , bottom - top )
264
+ self [0 ] = self ._create_background_box (lines , y_offset )
190
265
191
266
@property
192
267
def bounding_box (self ):
@@ -216,20 +291,11 @@ def color(self, new_color):
216
291
@property
217
292
def background_color (self ):
218
293
"""Color of the background as an RGB hex number."""
219
- if not self ._transparent_background :
220
- return self .palette [0 ]
221
- return None
294
+ return self ._background_color
222
295
223
296
@background_color .setter
224
297
def background_color (self , new_color ):
225
- if new_color is not None :
226
- self .palette [0 ] = new_color
227
- self .palette .make_opaque (0 )
228
- self ._transparent_background = False
229
- else :
230
- self .palette [0 ] = 0
231
- self .palette .make_transparent (0 )
232
- self ._transparent_background = True
298
+ self ._update_background_color (new_color )
233
299
234
300
@property
235
301
def text (self ):
@@ -256,8 +322,7 @@ def font(self, new_font):
256
322
current_anchored_position = self .anchored_position
257
323
self ._text = ""
258
324
self ._font = new_font
259
- bounds = self ._font .get_bounding_box ()
260
- self .height = bounds [1 ]
325
+ self .height = self ._font .get_bounding_box ()[1 ]
261
326
self ._update_text (str (old_text ))
262
327
self .anchored_position = current_anchored_position
263
328
0 commit comments