Skip to content

Instantly share code, notes, and snippets.

@jdtsmith
Last active October 19, 2021 00:14
Show Gist options
  • Save jdtsmith/76f7e7dd7adea768a284140fe2c81e59 to your computer and use it in GitHub Desktop.
Save jdtsmith/76f7e7dd7adea768a284140fe2c81e59 to your computer and use it in GitHub Desktop.
LVGL MicroPython custom set_attribute
import lvgl as lv
import display
fontBase = 'font_montserrat'
# Colors (+ BLACK and WHITE, NONE = black)
# AMBER BLUE BLUE_GREY BROWN
# CYAN DEEP_ORANGE DEEP_PURPLE GREEN
# GREY INDIGO LIGHT_BLUE LIGHT_GREEN
# LIME NONE ORANGE PINK
# PURPLE RED TEAL YELLOW
def color(col):
shift = 0
if isinstance(col, (list, tuple)):
col, shift = col
col = col.upper()
if col in ("BLACK","WHITE"):
col = getattr(lv,"color_"+col.lower())()
else:
col = getattr(lv.PALETTE,col)
if shift>0:
col=lv.palette_lighten(col,shift)
elif shift<0:
col=lv.palette_darken(col,-shift)
else:
col=lv.palette_main(col)
return col
def opa(opa):
return max(0,min(255,round(opa*255)))
def size(value):
if value == "full": # String full/content/percentage width/heigth
value = lv.pct(100)
elif value == "content":
value = lv.SIZE.CONTENT
elif value.endswith("%"):
value = lv.pct(int(value[:-1]))
return value
class LVGLObj:
attr_priority = dict(x=1, y=1,
text_align=2, scroll=2,
size=3, width=3, height=3)
def __init__(self, lvo, **kwds):
self._lvo = lvo
#print(f"GOT LVO: {self._lvo}")
self.set(**kwds)
def __del__(self, extra = None):
objs=[self]
if extra is not None:
if isinstance(extra, (tuple, list)):
objs.extend(extra)
else:
objs.append(extra)
for obj in objs:
if not obj: continue
try:
obj.delete()
except lv.LvReferenceError:
pass # perhaps was already deleted!
def set(self, **kwds):
didPause = display.pause()
for k,v in sorted(kwds.items(),
key=lambda x: self.attr_priority.get(x[0]) or 0):
setattr(self, k, v)
if didPause: display.resume()
# fontSize's: 8, 14, 16, 20, 24, 28, 32, 36, 40, "large"
@property
def fontSize(self):
return self._fontSize
@fontSize.setter
def fontSize(self, fs):
"""Set font to a given size in points, or the special value "large"."""
self._fontSize = fs
if fs == "large":
font = display.largeFont
elif fs==8:
font=lv.font_unscii_8
else:
font = getattr(lv,f'{fontBase}_{fs}')
self.text_font = font
def __getattr__(self, attr, lvobj = None):
"""Generic getter for get{_style}_{attr} and obj.FLAG/lv.STATE values."""
# runs *after* actual object attributes are looked up, so
# avoid name collisions and use _attribute
if attr == "lvo": return self._lvo
lvobj = lvobj or self._lvo
if hasattr(lvobj, attr): # priority 1: likely a method to call
return getattr(lvobj, attr)
elif hasattr(lvobj, f'get_{attr}'): # get_x()
return getattr(lvobj, f'get_{attr}')()
elif hasattr(lvobj, f'get_style_{attr}'): # get_style_x()
return getattr(lvobj, f'get_style_{attr}')(lv.PART.MAIN)
elif lvobj and hasattr(lv.obj.FLAG, attr): # o.FLAG.x
return getattr(lvobj.FLAG, attr)
elif lvobj and hasattr(lv.STATE, attr): # o.STATE
return lvobj.state & getattr(lv.STATE, attr)
else:
raise AttributeError(f"No such attribute: {attr}")
def __setattr__(self, attr, value, lvobj = None):
"""Generic setter for set{_style}_{attr}, and obj.FLAG values.
Handles tuples/lists, and pre-processes, color (string color
or (string color, integer shift) tuple), opacity (float 0-1),
alignment (string from lv.ALIGN or lv.TEXT_ALIGN), and
width/height/size ("content", "full", or "xxx%", tuple
permitted for size). All internal variables starting with "_"
are assigned as attributes on the object itself.
"""
if attr.startswith("_"): # Special case: internal variables
object.__setattr__(self, attr, value)
return
lvobj = lvobj or self._lvo
#print(f"Setting {self}.{attr} to {value}")
if attr.endswith("_color"):
value = color(value) # String or tuple for color
elif attr.endswith("opa"):
value = opa(value) # Percentage opacity
elif attr in ("width","height","x","y") and isinstance(value, str):
value = size(value)
elif attr == "align":
value = getattr(lv.ALIGN, value) # String alignment
elif attr == "text_align":
value = getattr(lv.TEXT_ALIGN, value) # String text alignment
elif attr == "size":
if isinstance(value, str):
value = (size(value),) *2
elif isinstance(value, (tuple, list)):
value = tuple(size(x) if isinstance(x, str) else x for x in value)
# On textareas, set_align sets text alignment and is deprecated. Use
# set_style_align there instead.
if (hasattr(lvobj, f'set_{attr}') and # set_x
not (attr == "align" and isinstance(lvobj, lv.textarea))):
if isinstance(value, (tuple, list)):
getattr(lvobj, f'set_{attr}')(*value)
else:
getattr(lvobj, f'set_{attr}')(value)
elif hasattr(lvobj,f'set_style_{attr}'): # set_style_x
getattr(lvobj,f'set_style_{attr}')(value, 0)
elif lvobj and hasattr(lv.obj.FLAG, attr): # add|clear_flag(x)
flag = getattr(lv.obj.FLAG, attr)
if value:
lvobj.add_flag(flag)
else:
lvobj.clear_flag(flag)
elif lvobj and hasattr(lv.STATE, attr): # add|clear_state(x)
flag = getattr(lv.STATE, attr)
if value:
lvobj.add_state(flag)
else:
lvobj.clear_state(flag)
else: # Just assign a regular object attribute
object.__setattr__(self, attr, value)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment