@@ -66,7 +66,10 @@ class Label(LabelBase):
6666 This is helpful when two or more labels need to be aligned to the same baseline
6767 :param (int,str) tab_replacement: tuple with tab character replace information. When
6868 (4, " ") will indicate a tab replacement of 4 spaces, defaults to 4 spaces by
69- tab character"""
69+ tab character
70+ :param str label_direction: string defining the label text orientation. There are 5
71+ configurations possibles ``LTR``-Left-To-Right ``RTL``-Right-To-Left
72+ ``TTB``-Top-To-Bottom ``UPR``-Upwards ``DWR``-Downwards. It defaults to ``LTR``"""
7073
7174 # pylint: disable=too-many-instance-attributes, too-many-locals
7275 # This has a lot of getters/setters, maybe it needs cleanup.
@@ -122,6 +125,7 @@ def __init__(self, font, **kwargs) -> None:
122125 self ._padding_left = kwargs .get ("padding_left" , 0 )
123126 self ._padding_right = kwargs .get ("padding_right" , 0 )
124127 self .base_alignment = kwargs .get ("base_alignment" , False )
128+ self ._label_direction = kwargs .get ("label_direction" , "LTR" )
125129
126130 if text is not None :
127131 self ._update_text (str (text ))
@@ -136,7 +140,6 @@ def _create_background_box(self, lines: int, y_offset: int) -> None:
136140 :param y_offset: int y pixel bottom coordinate for the background_box"""
137141
138142 left = self ._bounding_box [0 ]
139-
140143 if self ._background_tight : # draw a tight bounding box
141144 box_width = self ._bounding_box [2 ]
142145 box_height = self ._bounding_box [3 ]
@@ -146,14 +149,33 @@ def _create_background_box(self, lines: int, y_offset: int) -> None:
146149 else : # draw a "loose" bounding box to include any ascenders/descenders.
147150 ascent , descent = self ._get_ascent_descent ()
148151
149- box_width = self ._bounding_box [2 ] + self ._padding_left + self ._padding_right
150- x_box_offset = - self ._padding_left
151- box_height = (
152- (ascent + descent )
153- + int ((lines - 1 ) * self .height * self ._line_spacing )
154- + self ._padding_top
155- + self ._padding_bottom
156- )
152+ if (
153+ self ._label_direction == "UPR"
154+ or self ._label_direction == "DWR"
155+ or self ._label_direction == "TTB"
156+ ):
157+ box_height = (
158+ self ._bounding_box [3 ] + self ._padding_top + self ._padding_bottom
159+ )
160+ x_box_offset = - self ._padding_bottom
161+ box_width = (
162+ (ascent + descent )
163+ + int ((lines - 1 ) * self .width * self ._line_spacing )
164+ + self ._padding_left
165+ + self ._padding_right
166+ )
167+ else :
168+ box_width = (
169+ self ._bounding_box [2 ] + self ._padding_left + self ._padding_right
170+ )
171+ x_box_offset = - self ._padding_left
172+ box_height = (
173+ (ascent + descent )
174+ + int ((lines - 1 ) * self .height * self ._line_spacing )
175+ + self ._padding_top
176+ + self ._padding_bottom
177+ )
178+
157179 if self .base_alignment :
158180 y_box_offset = - ascent - self ._padding_top
159181 else :
@@ -162,12 +184,25 @@ def _create_background_box(self, lines: int, y_offset: int) -> None:
162184 box_width = max (0 , box_width ) # remove any negative values
163185 box_height = max (0 , box_height ) # remove any negative values
164186
187+ if self ._label_direction == "UPR" :
188+ movx = left + x_box_offset
189+ movy = - box_height - x_box_offset
190+ elif self ._label_direction == "DWR" :
191+ movx = left + x_box_offset
192+ movy = x_box_offset
193+ elif self ._label_direction == "TTB" :
194+ movx = left + x_box_offset
195+ movy = x_box_offset
196+ else :
197+ movx = left + x_box_offset
198+ movy = y_box_offset
199+
165200 background_bitmap = displayio .Bitmap (box_width , box_height , 1 )
166201 tile_grid = displayio .TileGrid (
167202 background_bitmap ,
168203 pixel_shader = self ._background_palette ,
169- x = left + x_box_offset ,
170- y = y_box_offset ,
204+ x = movx ,
205+ y = movy ,
171206 )
172207
173208 return tile_grid
@@ -222,7 +257,7 @@ def _update_background_color(self, new_color: int) -> None:
222257 self ._bounding_box [3 ] + self ._padding_top + self ._padding_bottom > 0
223258 )
224259 ):
225- self .local_group [0 ] = self ._create_background_box (lines , y_offset )
260+ self .local_group [0 ] = self ._create_background_box (lines , self . _y_offset )
226261 else : # delete the existing bitmap
227262 self .local_group .pop (0 )
228263 self ._added_background_tilegrid = False
@@ -243,8 +278,15 @@ def _update_text(
243278 else :
244279 self ._y_offset = self ._get_ascent () // 2
245280
246- right = top = bottom = 0
247- left = None
281+ if self ._label_direction == "RTL" :
282+ left = top = bottom = 0
283+ right = None
284+ elif self ._label_direction == "LTR" :
285+ right = top = bottom = 0
286+ left = None
287+ else :
288+ top = right = left = 0
289+ bottom = 0
248290
249291 for character in new_text :
250292 if character == "\n " :
@@ -254,17 +296,74 @@ def _update_text(
254296 glyph = self ._font .get_glyph (ord (character ))
255297 if not glyph :
256298 continue
257- right = max (right , x + glyph .shift_x , x + glyph .width + glyph .dx )
258- if x == 0 :
259- if left is None :
260- left = glyph .dx
299+
300+ if self ._label_direction == "LTR" or self ._label_direction == "RTL" :
301+ bottom = max (bottom , y - glyph .dy + self ._y_offset )
302+ if y == 0 : # first line, find the Ascender height
303+ top = min (top , - glyph .height - glyph .dy + self ._y_offset )
304+ position_y = y - glyph .height - glyph .dy + self ._y_offset
305+
306+ if self ._label_direction == "LTR" :
307+ right = max (right , x + glyph .shift_x , x + glyph .width + glyph .dx )
308+ if x == 0 :
309+ if left is None :
310+ left = glyph .dx
311+ else :
312+ left = min (left , glyph .dx )
313+ position_x = x + glyph .dx
261314 else :
262- left = min (left , glyph .dx )
263- if y == 0 : # first line, find the Ascender height
264- top = min (top , - glyph .height - glyph .dy + self ._y_offset )
265- bottom = max (bottom , y - glyph .dy + self ._y_offset )
266- position_y = y - glyph .height - glyph .dy + self ._y_offset
267- position_x = x + glyph .dx
315+ left = max (
316+ left , abs (x ) + glyph .shift_x , abs (x ) + glyph .width + glyph .dx
317+ )
318+ if x == 0 :
319+ if right is None :
320+ right = glyph .dx
321+ else :
322+ right = max (right , glyph .dx )
323+ position_x = x - glyph .width
324+
325+ if self ._label_direction == "TTB" :
326+ if x == 0 :
327+ if left is None :
328+ left = glyph .dx
329+ else :
330+ left = min (left , glyph .dx )
331+ if y == 0 :
332+ top = min (top , - glyph .dy )
333+
334+ bottom = max (bottom , y + glyph .height , y + glyph .height + glyph .dy )
335+ right = max (
336+ right , x + glyph .width + glyph .dx , x + glyph .shift_x + glyph .dx
337+ )
338+ position_y = y + glyph .dy
339+ position_x = x - glyph .width // 2 + self ._y_offset
340+
341+ if self ._label_direction == "UPR" :
342+ if x == 0 :
343+ if bottom is None :
344+ bottom = - glyph .dx
345+
346+ if y == 0 : # first line, find the Ascender height
347+ bottom = min (bottom , - glyph .dy )
348+ left = min (left , x - glyph .height + self ._y_offset )
349+ top = min (top , y - glyph .width - glyph .dx , y - glyph .shift_x )
350+ right = max (right , x + glyph .height , x + glyph .height - glyph .dy )
351+ position_y = y - glyph .width - glyph .dx
352+ position_x = x - glyph .height - glyph .dy + self ._y_offset
353+
354+ if self ._label_direction == "DWR" :
355+ if y == 0 :
356+ if top is None :
357+ top = - glyph .dx
358+ top = min (top , - glyph .dx )
359+ if x == 0 :
360+ left = min (left , - glyph .dy )
361+ left = min (left , x , x - glyph .dy - self ._y_offset )
362+ bottom = max (bottom , y + glyph .width + glyph .dx , y + glyph .shift_x )
363+ right = max (right , x + glyph .height )
364+ position_y = y + glyph .dx
365+ position_x = x + glyph .dy - self ._y_offset
366+
268367 if glyph .width > 0 and glyph .height > 0 :
269368 try :
270369 # pylint: disable=unexpected-keyword-arg
@@ -286,22 +385,58 @@ def _update_text(
286385 x = position_x ,
287386 y = position_y ,
288387 )
388+
389+ if self ._label_direction == "UPR" :
390+ face .transpose_xy = True
391+ face .flip_x = True
392+ if self ._label_direction == "DWR" :
393+ face .transpose_xy = True
394+ face .flip_y = True
395+
289396 if tilegrid_count < len (self .local_group ):
290397 self .local_group [tilegrid_count ] = face
291398 else :
292399 self .local_group .append (face )
293400 tilegrid_count += 1
294- x += glyph .shift_x
401+
402+ if self ._label_direction == "RTL" :
403+ x = x - glyph .shift_x
404+ if self ._label_direction == "TTB" :
405+ if glyph .height < 2 :
406+ y = y + glyph .shift_x
407+ else :
408+ y = y + glyph .height + 1
409+ if self ._label_direction == "UPR" :
410+ y = y - glyph .shift_x
411+ if self ._label_direction == "DWR" :
412+ y = y + glyph .shift_x
413+ if self ._label_direction == "LTR" :
414+ x = x + glyph .shift_x
415+
295416 i += 1
296- # Remove the rest
297417
298- if left is None :
418+ if self . _label_direction == "LTR" and left is None :
299419 left = 0
420+ if self ._label_direction == "RTL" and right is None :
421+ right = 0
422+ if self ._label_direction == "TTB" and top is None :
423+ top = 0
300424
301425 while len (self .local_group ) > tilegrid_count : # i:
302426 self .local_group .pop ()
427+ # pylint: disable=invalid-unary-operand-type
428+ if self ._label_direction == "RTL" :
429+ self ._bounding_box = (- left , top , left - right , bottom - top )
430+ if self ._label_direction == "TTB" :
431+ self ._bounding_box = (left , top , right - left , bottom - top )
432+ if self ._label_direction == "UPR" :
433+ self ._bounding_box = (left , top , right , bottom - top )
434+ if self ._label_direction == "DWR" :
435+ self ._bounding_box = (left , top , right , bottom - top )
436+ if self ._label_direction == "LTR" :
437+ self ._bounding_box = (left , top , right - left , bottom - top )
438+
303439 self ._text = new_text
304- self ._bounding_box = (left , top , right - left , bottom - top )
305440
306441 if self .background_color is not None :
307442 self ._update_background_color (self ._background_color )
@@ -331,5 +466,10 @@ def _set_line_spacing(self, new_line_spacing: float) -> None:
331466 def _set_text (self , new_text : str , scale : int ) -> None :
332467 self ._reset_text (new_text )
333468
334- def _set_background_color (self , new_color ) :
469+ def _set_background_color (self , new_color : int ) -> None :
335470 self ._update_background_color (new_color )
471+
472+ def _set_label_direction (self , new_label_direction : str ) -> None :
473+ self ._label_direction = new_label_direction
474+ old_text = self ._text
475+ self ._update_text (str (old_text ))
0 commit comments