3131import os
3232import mmap
3333import ctypes
34+ import ev3dev .fonts as fonts
35+ from PIL import Image , ImageDraw
3436from struct import pack
3537import fcntl
3638
@@ -179,14 +181,18 @@ def _map_fb_memory(fbfid, fix_info):
179181 )
180182
181183
182- class Screen (FbMem ):
184+ class Display (FbMem ):
183185 """
184186 A convenience wrapper for the FbMem class.
185187 Provides drawing functions from the python imaging library (PIL).
186188 """
187189
188- def __init__ (self ):
189- from PIL import Image , ImageDraw
190+ GRID_COLUMNS = 22
191+ GRID_COLUMN_PIXELS = 8
192+ GRID_ROWS = 12
193+ GRID_ROW_PIXELS = 10
194+
195+ def __init__ (self , desc = 'Display' ):
190196 FbMem .__init__ (self )
191197
192198 self ._img = Image .new (
@@ -195,6 +201,10 @@ def __init__(self):
195201 "white" )
196202
197203 self ._draw = ImageDraw .Draw (self ._img )
204+ self .desc = desc
205+
206+ def __str__ (self ):
207+ return self .desc
198208
199209 @property
200210 def xres (self ):
@@ -267,3 +277,120 @@ def update(self):
267277 self .mmap [:] = self ._img_to_rgb565_bytes ()
268278 else :
269279 raise Exception ("Not supported" )
280+
281+ def image_filename (self , filename , clear_screen = True , x1 = 0 , y1 = 0 , x2 = None , y2 = None ):
282+
283+ if clear_screen :
284+ self .clear ()
285+
286+ filename_im = Image .open (filename )
287+
288+ if x2 is not None and y2 is not None :
289+ return self ._img .paste (filename_im , (x1 , y1 , x2 , y2 ))
290+ else :
291+ return self ._img .paste (filename_im , (x1 , y1 ))
292+
293+ def line (self , clear_screen = True , x1 = 10 , y1 = 10 , x2 = 50 , y2 = 50 , line_color = 'black' , width = 1 ):
294+ """
295+ Draw a line from (x1, y1) to (x2, y2)
296+ """
297+
298+ if clear_screen :
299+ self .clear ()
300+
301+ return self .draw .line ((x1 , y1 , x2 , y2 ), fill = line_color , width = width )
302+
303+ def circle (self , clear_screen = True , x = 50 , y = 50 , radius = 40 , fill_color = 'black' , outline_color = 'black' ):
304+ """
305+ Draw a circle of 'radius' centered at (x, y)
306+ """
307+
308+ if clear_screen :
309+ self .clear ()
310+
311+ x1 = x - radius
312+ y1 = y - radius
313+ x2 = x + radius
314+ y2 = y + radius
315+
316+ return self .draw .ellipse ((x1 , y1 , x2 , y2 ), fill = fill_color , outline = outline_color )
317+
318+ def rectangle (self , clear_screen = True , x = 10 , y = 10 , width = 80 , height = 40 , fill_color = 'black' , outline_color = 'black' ):
319+ """
320+ Draw a rectangle 'width x height' where the top left corner is at (x, y)
321+ """
322+
323+ if clear_screen :
324+ self .clear ()
325+
326+ return self .draw .rectangle ((x , y , width , height ), fill = fill_color , outline = outline_color )
327+
328+ def point (self , clear_screen = True , x = 10 , y = 10 , point_color = 'black' ):
329+ """
330+ Draw a single pixel at (x, y)
331+ """
332+
333+ if clear_screen :
334+ self .clear ()
335+
336+ return self .draw .point ((x , y ), fill = point_color )
337+
338+ def text_pixels (self , text , clear_screen = True , x = 0 , y = 0 , text_color = 'black' , font = None ):
339+ """
340+ Display `text` starting at pixel (x, y).
341+
342+ The EV3 display is 178x128 pixels
343+ - (0, 0) would be the top left corner of the display
344+ - (89, 64) would be right in the middle of the display
345+
346+ 'text_color' : PIL says it supports "common HTML color names". There
347+ are 140 HTML color names listed here that are supported by all modern
348+ browsers. This is probably a good list to start with.
349+ https://www.w3schools.com/colors/colors_names.asp
350+
351+ 'font' : can be any font displayed here
352+ http://ev3dev-lang.readthedocs.io/projects/python-ev3dev/en/stable/other.html#bitmap-fonts
353+ """
354+
355+ if clear_screen :
356+ self .clear ()
357+
358+ if font is not None :
359+ assert font in fonts .available (), "%s is an invalid font" % font
360+ return self .draw .text ((x , y ), text , fill = text_color , font = fonts .load (font ))
361+ else :
362+ return self .draw .text ((x , y ), text , fill = text_color )
363+
364+ def text_grid (self , text , clear_screen = True , x = 0 , y = 0 , text_color = 'black' , font = None ):
365+ """
366+ Display 'text' starting at grid (x, y)
367+
368+ The EV3 display can be broken down in a grid that is 22 columns wide
369+ and 12 rows tall. Each column is 8 pixels wide and each row is 10
370+ pixels tall.
371+
372+ 'text_color' : PIL says it supports "common HTML color names". There
373+ are 140 HTML color names listed here that are supported by all modern
374+ browsers. This is probably a good list to start with.
375+ https://www.w3schools.com/colors/colors_names.asp
376+
377+ 'font' : can be any font displayed here
378+ http://ev3dev-lang.readthedocs.io/projects/python-ev3dev/en/stable/other.html#bitmap-fonts
379+ """
380+
381+ assert 0 <= x < Display .GRID_COLUMNS ,\
382+ "grid columns must be between 0 and %d, %d was requested" % \
383+ ((Display .GRID_COLUMNS - 1 , x ))
384+
385+ assert 0 <= y < Display .GRID_ROWS ,\
386+ "grid rows must be between 0 and %d, %d was requested" % \
387+ ((Display .GRID_ROWS - 1 ), y )
388+
389+ return self .text_pixels (text , clear_screen ,
390+ x * Display .GRID_COLUMN_PIXELS ,
391+ y * Display .GRID_ROW_PIXELS ,
392+ text_color , font )
393+
394+ def reset_screen (self ):
395+ self .clear ()
396+ self .update ()
0 commit comments