1515import math
1616
1717# --- Color constants (RGB tuples) ---
18- from steami_screen .colors import rgb_to_gray4
19-
2018# Grays map to exact SSD1327 levels: gray4 * 17 gives R=G=B
2119BLACK = (0 , 0 , 0 )
2220DARK = (102 , 102 , 102 ) # gray4=6
@@ -52,14 +50,6 @@ def __init__(self, display, width=None, height=None):
5250 self ._d = display
5351 self .width = width or getattr (display , 'width' , 128 )
5452 self .height = height or getattr (display , 'height' , 128 )
55- # Detect if the backend needs greyscale ints (SSD1327) or accepts RGB tuples
56- self ._needs_gray = not hasattr (display , 'fill_rect' ) or hasattr (display , 'framebuf' )
57-
58- def _c (self , color ):
59- """Convert color for the backend. Returns gray4 int for SSD1327, pass-through otherwise."""
60- if self ._needs_gray :
61- return rgb_to_gray4 (color )
62- return color
6353
6454 # --- Adaptive properties ---
6555
@@ -121,7 +111,7 @@ def _resolve(self, at, text_len=0, scale=1):
121111 def title (self , text , color = GRAY ):
122112 """Draw title text at the top (N)."""
123113 x , y = self ._resolve ("N" , len (text ))
124- self ._text (text , x , y , color )
114+ self ._d . text (text , x , y , color )
125115
126116 def value (self , val , unit = None , at = "CENTER" , label = None ,
127117 color = WHITE , scale = 2 , y_offset = 0 ):
@@ -156,7 +146,7 @@ def value(self, val, unit=None, at="CENTER", label=None,
156146 # Optional label above
157147 if label :
158148 lx = x + tw // 2 - len (label ) * self .CHAR_W // 2
159- self ._text (label , lx , y - self .CHAR_H - 4 , GRAY )
149+ self ._d . text (label , lx , y - self .CHAR_H - 4 , GRAY )
160150
161151 # Value (large)
162152 self ._draw_scaled_text (text , x , y , color , scale )
@@ -168,7 +158,7 @@ def value(self, val, unit=None, at="CENTER", label=None,
168158 if hasattr (self ._d , 'draw_medium_text' ):
169159 self ._d .draw_medium_text (unit , ux , unit_y , LIGHT )
170160 else :
171- self ._text (unit , ux , unit_y , LIGHT )
161+ self ._d . text (unit , ux , unit_y , LIGHT )
172162
173163 def subtitle (self , * lines , color = DARK ):
174164 """Draw subtitle text at the bottom (S). Accepts multiple lines."""
@@ -185,7 +175,7 @@ def subtitle(self, *lines, color=DARK):
185175 block_h = (n - 1 ) * line_h
186176 start_y = base_y - block_h // 2
187177
188- draw = getattr (self ._d , 'draw_small_text' , self ._text )
178+ draw = getattr (self ._d , 'draw_small_text' , self ._d . text )
189179 for i , line in enumerate (lines ):
190180 x , _ = self ._resolve ("S" , len (line ))
191181 y = start_y + i * line_h
@@ -246,7 +236,7 @@ def gauge(self, val, min_val=0, max_val=100, unit=None, color=LIGHT):
246236 if hasattr (self ._d , 'draw_medium_text' ):
247237 self ._d .draw_medium_text (unit , ux , uy , LIGHT )
248238 else :
249- self ._text (unit , ux , uy , LIGHT )
239+ self ._d . text (unit , ux , uy , LIGHT )
250240
251241 # Min/max labels at arc endpoints (slightly inward to stay visible)
252242 min_t = str (int (min_val ))
@@ -259,7 +249,7 @@ def gauge(self, val, min_val=0, max_val=100, unit=None, color=LIGHT):
259249 ly = int (cy + r_label * math .sin (angle_s ))
260250 rx = int (cx + r_label * math .cos (angle_e )) - len (max_t ) * self .CHAR_W // 2
261251 ry = int (cy + r_label * math .sin (angle_e ))
262- draw_sm = getattr (self ._d , 'draw_small_text' , self ._text )
252+ draw_sm = getattr (self ._d , 'draw_small_text' , self ._d . text )
263253 draw_sm (min_t , lx , ly , GRAY )
264254 draw_sm (max_t , rx , ry , GRAY )
265255
@@ -280,7 +270,7 @@ def graph(self, data, min_val=0, max_val=100, color=LIGHT):
280270 if data :
281271 text = str (int (data [- 1 ]))
282272 draw_fn = getattr (self ._d , 'draw_medium_text' ,
283- self ._text )
273+ self ._d . text )
284274 tw = len (text ) * self .CHAR_W
285275 vx = cx - tw // 2
286276 vy = 31
@@ -292,7 +282,7 @@ def _fmt(v):
292282 return str (int (v // 1000 )) + "k"
293283 return str (int (v ))
294284
295- draw_sm = getattr (self ._d , 'draw_small_text' , self ._text )
285+ draw_sm = getattr (self ._d , 'draw_small_text' , self ._d . text )
296286 mid_val = (min_val + max_val ) / 2
297287 for val , yp in [(max_val , gy ),
298288 (mid_val , gy + gh // 2 ),
@@ -349,9 +339,9 @@ def menu(self, items, selected=0, color=WHITE):
349339 iy = y + (i - start ) * item_h
350340 if i == selected :
351341 self ._fill_rect (15 , iy - 2 , self .width - 30 , item_h , DARK )
352- self ._text ("> " + items [i ], 18 , iy , color )
342+ self ._d . text ("> " + items [i ], 18 , iy , color )
353343 else :
354- self ._text (" " + items [i ], 18 , iy , GRAY )
344+ self ._d . text (" " + items [i ], 18 , iy , GRAY )
355345
356346 def compass (self , heading , color = LIGHT ):
357347 """Draw a compass with a rotating needle."""
@@ -367,7 +357,7 @@ def compass(self, heading, color=LIGHT):
367357 lx = cx + int ((r + 5 ) * math .sin (math .radians (angle )))
368358 ly = cy - int ((r + 5 ) * math .cos (math .radians (angle )))
369359 c = WHITE if label == "N" else GRAY
370- self ._text (label , lx - self .CHAR_W // 2 , ly - self .CHAR_H // 2 , c )
360+ self ._d . text (label , lx - self .CHAR_W // 2 , ly - self .CHAR_H // 2 , c )
371361
372362 # Tick marks (8 directions)
373363 for angle in range (0 , 360 , 45 ):
@@ -435,7 +425,7 @@ def watch(self, hours, minutes, seconds=0, color=LIGHT):
435425 lx = cx + int ((r - 15 ) * math .sin (rad ))
436426 ly = cy - int ((r - 15 ) * math .cos (rad ))
437427 tw = len (text ) * self .CHAR_W
438- self ._text (text , lx - tw // 2 , ly - self .CHAR_H // 2 , WHITE )
428+ self ._d . text (text , lx - tw // 2 , ly - self .CHAR_H // 2 , WHITE )
439429
440430 # Hour hand (short, thick)
441431 h_angle = (hours % 12 + minutes / 60 ) * 30
@@ -514,7 +504,7 @@ def text(self, text, at="CENTER", color=WHITE, scale=1):
514504 if scale > 1 :
515505 self ._draw_scaled_text (text , x , y , color , scale )
516506 else :
517- self ._text (text , x , y , color )
507+ self ._d . text (text , x , y , color )
518508
519509 def line (self , x1 , y1 , x2 , y2 , color = WHITE ):
520510 self ._line (x1 , y1 , x2 , y2 , color )
@@ -532,49 +522,37 @@ def rect(self, x, y, w, h, color=WHITE, fill=False):
532522 self ._rect (x , y , w , h , color )
533523
534524 def pixel (self , x , y , color = WHITE ):
535- self ._pixel (x , y , self . _c ( color ) )
525+ self ._d . pixel (x , y , color )
536526
537527 # --- Control ---
538528
539529 def clear (self , color = BLACK ):
540- self ._d .fill (self . _c ( color ) )
530+ self ._d .fill (color )
541531
542532 def show (self ):
543533 self ._d .show ()
544534
545535 # --- Internal drawing helpers ---
546536
547- def _text (self , text , x , y , c ):
548- self ._d .text (text , x , y , self ._c (c ))
549-
550- def _pixel (self , x , y , c ):
551- self ._d .pixel (x , y , self ._c (c ))
552-
553537 def _line (self , x1 , y1 , x2 , y2 , c ):
554- self ._d .line (x1 , y1 , x2 , y2 , self . _c ( c ) )
538+ self ._d .line (x1 , y1 , x2 , y2 , c )
555539
556540 def _hline (self , x , y , w , c ):
557- self ._d .line (x , y , x + w - 1 , y , self . _c ( c ) )
541+ self ._d .line (x , y , x + w - 1 , y , c )
558542
559543 def _vline (self , x , y , h , c ):
560- self ._d .line (x , y , x , y + h - 1 , self . _c ( c ) )
544+ self ._d .line (x , y , x , y + h - 1 , c )
561545
562546 def _fill_rect (self , x , y , w , h , c ):
563- cc = self ._c (c )
564547 if hasattr (self ._d , 'fill_rect' ):
565- self ._d .fill_rect (x , y , w , h , cc )
566- elif hasattr (self ._d , 'framebuf' ):
567- self ._d .framebuf .fill_rect (x , y , w , h , cc )
548+ self ._d .fill_rect (x , y , w , h , c )
568549 else :
569550 for row in range (h ):
570- self ._d .line (x , y + row , x + w - 1 , y + row , cc )
551+ self ._d .line (x , y + row , x + w - 1 , y + row , c )
571552
572553 def _rect (self , x , y , w , h , c ):
573- cc = self ._c (c )
574554 if hasattr (self ._d , 'rect' ):
575- self ._d .rect (x , y , w , h , cc )
576- elif hasattr (self ._d , 'framebuf' ):
577- self ._d .framebuf .rect (x , y , w , h , cc )
555+ self ._d .rect (x , y , w , h , c )
578556 else :
579557 self ._hline (x , y , w , c )
580558 self ._hline (x , y + h - 1 , w , c )
@@ -594,21 +572,21 @@ def _draw_scaled_text(self, text, x, y, color, scale):
594572 # On real hardware without scaled text support, draw at scale=1
595573 # centered at the same position (best effort)
596574 if not hasattr (self ._d , 'pixel' ):
597- self ._text (text , x , y , color )
575+ self ._d . text (text , x , y , color )
598576 return
599577 # Render at 1x to a temporary buffer, then scale up
600578 # For MicroPython: draw each character using the display's text method
601579 # but multiple times offset for a bold effect at scale 2
602580 if scale == 2 :
603581 for dx in range (2 ):
604582 for dy in range (2 ):
605- self ._text (text , x + dx , y + dy , color )
583+ self ._d . text (text , x + dx , y + dy , color )
606584 elif scale == 3 :
607585 for dx in range (3 ):
608586 for dy in range (3 ):
609- self ._text (text , x + dx , y + dy , color )
587+ self ._d . text (text , x + dx , y + dy , color )
610588 else :
611- self ._text (text , x , y , color )
589+ self ._d . text (text , x , y , color )
612590
613591 def _draw_arc (self , cx , cy , r , start_deg , sweep_deg , color , width = 3 ):
614592 """Draw a thick arc using individual pixels."""
@@ -623,7 +601,7 @@ def _draw_arc(self, cx, cy, r, start_deg, sweep_deg, color, width=3):
623601 x = int (cx + (r + dr ) * math .cos (angle ))
624602 y = int (cy + (r + dr ) * math .sin (angle ))
625603 if 0 <= x < self .width and 0 <= y < self .height :
626- self ._pixel (x , y , color )
604+ self ._d . pixel (x , y , color )
627605
628606 def _draw_circle (self , cx , cy , r , color ):
629607 """Bresenham circle."""
@@ -633,7 +611,7 @@ def _draw_circle(self, cx, cy, r, color):
633611 (x , - y ), (y , - x ), (- x , - y ), (- y , - x )):
634612 px , py = cx + sx , cy + sy
635613 if 0 <= px < self .width and 0 <= py < self .height :
636- self ._pixel (px , py , color )
614+ self ._d . pixel (px , py , color )
637615 y += 1
638616 if d < 0 :
639617 d += 2 * y + 1
0 commit comments