1
0
mirror of https://github.com/lvgl/lvgl.git synced 2025-01-28 07:03:00 +08:00

examples(micropython): add a few missing MP examples (#3672)

This commit is contained in:
Uli Raich 2022-09-21 11:21:36 +02:00 committed by GitHub
parent d5e6ffdd87
commit 29ec34be77
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 1151 additions and 27 deletions

View File

@ -0,0 +1,156 @@
class KeyboardEncoder:
def __init__(self):
self.LV_VER_RES = lv.scr_act().get_disp().driver.ver_res
print("vertial size: ",self.LV_VER_RES)
self.g = lv.group_create()
self.g.set_default()
cur_drv = lv.indev_t.__cast__(None)
while True:
cur_drv = cur_drv.get_next()
if not cur_drv :
break
if cur_drv.driver.type == lv.INDEV_TYPE.KEYPAD:
print("Found keypad")
cur_drv.set_group(self.g)
if cur_drv.driver.type == lv.INDEV_TYPE.ENCODER:
print("Found encoder")
cur_drv.set_group(self.g)
self.tv = lv.tabview(lv.scr_act(), lv.DIR.TOP, lv.DPI_DEF // 3)
self.t1 = self.tv.add_tab("Selectors")
self.t2 = self.tv.add_tab("Text input")
self.selectors_create(self.t1)
self.text_input_create(self.t2)
self.msgbox_create()
def selectors_create(self,parent):
parent.set_flex_flow(lv.FLEX_FLOW.COLUMN)
parent.set_flex_align(lv.FLEX_ALIGN.START, lv.FLEX_ALIGN.CENTER, lv.FLEX_ALIGN.CENTER)
obj = lv.table(parent)
obj.set_cell_value(0, 0, "00")
obj.set_cell_value(0, 1, "01")
obj.set_cell_value(1, 0, "10")
obj.set_cell_value(1, 1, "11")
obj.set_cell_value(2, 0, "20")
obj.set_cell_value(2, 1, "21")
obj.set_cell_value(3, 0, "30")
obj.set_cell_value(3, 1, "31")
obj.add_flag(lv.obj.FLAG.SCROLL_ON_FOCUS)
obj = lv.calendar(parent)
obj.add_flag(lv.obj.FLAG.SCROLL_ON_FOCUS)
obj = lv.btnmatrix(parent)
obj.add_flag(lv.obj.FLAG.SCROLL_ON_FOCUS)
obj = lv.checkbox(parent)
obj.add_flag(lv.obj.FLAG.SCROLL_ON_FOCUS);
obj = lv.slider(parent)
obj.set_range(0, 10)
obj.add_flag(lv.obj.FLAG.SCROLL_ON_FOCUS)
obj = lv.switch(parent)
obj.add_flag(lv.obj.FLAG.SCROLL_ON_FOCUS)
obj = lv.spinbox(parent)
obj.add_flag(lv.obj.FLAG.SCROLL_ON_FOCUS)
obj = lv.dropdown(parent)
obj.add_flag(lv.obj.FLAG.SCROLL_ON_FOCUS)
obj = lv.roller(parent)
obj.add_flag(lv.obj.FLAG.SCROLL_ON_FOCUS)
list = lv.list(parent)
list.update_layout()
if list.get_height() > parent.get_content_height() :
list.set_height(parent.get_content_height())
list.add_btn(lv.SYMBOL.OK, "Apply")
list.add_btn(lv.SYMBOL.CLOSE, "Close")
list.add_btn(lv.SYMBOL.EYE_OPEN, "Show")
list.add_btn(lv.SYMBOL.EYE_CLOSE, "Hide")
list.add_btn(lv.SYMBOL.TRASH, "Delete")
list.add_btn(lv.SYMBOL.COPY, "Copy")
list.add_btn(lv.SYMBOL.PASTE, "Paste")
def text_input_create(self,parent) :
parent.set_flex_flow(lv.FLEX_FLOW.COLUMN)
ta1 = lv.textarea(parent)
ta1.set_width(lv.pct(100))
ta1.set_one_line(True)
ta1.set_placeholder_text("Click with an encoder to show a keyboard")
ta2 = lv.textarea(parent)
ta2.set_width(lv.pct(100))
ta2.set_one_line(True)
ta2.set_placeholder_text("Type something")
self.kb = lv.keyboard(lv.scr_act())
self.kb.add_flag(lv.obj.FLAG.HIDDEN)
ta1.add_event_cb(self.ta_event_cb, lv.EVENT.ALL, None)
ta2.add_event_cb(self.ta_event_cb, lv.EVENT.ALL, None)
def msgbox_create(self):
btns = ["Ok", "Cancel", ""]
mbox = lv.msgbox(None, "Hi", "Welcome to the keyboard and encoder demo", btns, False)
mbox.add_event_cb(self.msgbox_event_cb, lv.EVENT.ALL, None)
lv.group_focus_obj(mbox.get_btns())
mbox.get_btns().add_state(lv.STATE.FOCUS_KEY)
self.g.focus_freeze(True)
mbox.align(lv.ALIGN.CENTER, 0, 0)
bg = mbox.get_parent()
bg.set_style_bg_opa(lv.OPA._70, 0)
bg.set_style_bg_color(lv.palette_main(lv.PALETTE.GREY), 0)
def msgbox_event_cb(self,e):
code = e.get_code();
msgbox = e.get_current_target()
if code == lv.EVENT.VALUE_CHANGED:
txt = msgbox.get_active_btn_text()
if txt:
msgbox.close()
self.g.focus_freeze(False)
lv.group_focus_obj(self.t1.get_child(0))
self.t1.scroll_to(0, 0, lv.ANIM.OFF)
def ta_event_cb(self,e) :
indev = lv.indev_get_act()
if indev == None :
return
indev_type = indev.get_type()
code = e.get_code()
ta = e.get_target()
if code == lv.EVENT.CLICKED and indev_type == lv.INDEV_TYPE.ENCODER:
self.kb.set_textarea(ta)
self.kb.clear_flag(lv.obj.FLAG.HIDDEN)
self.kb.group_focus_obj()
self.kb.get_group().set_editing()
self.tv.set_height(LV_VER_RES // 2)
lv_obj_align(kb, LV_ALIGN_BOTTOM_MID, 0, 0);
if code == lv.EVENT.READY or code == lv.EVENT.CANCEL:
self.kb.add_flag(lv.obj.FLAG.HIDDEN)
self.tv.set_height(self.LV_VER_RES)
keyboard_encoder = KeyboardEncoder()

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

View File

@ -0,0 +1,52 @@
class LV_Example_Event_4:
def __init__(self):
#
# Demonstrate the usage of draw event
#
self.size = 0
self.size_dec = False
self.cont = lv.obj(lv.scr_act())
self.cont.set_size(200, 200)
self.cont.center()
self.cont.add_event_cb(self.event_cb, lv.EVENT.DRAW_PART_END, None)
lv.timer_create(self.timer_cb, 30, None)
def timer_cb(self,timer) :
self.cont.invalidate()
if self.size_dec :
self.size -= 1
else :
self.size += 1
if self.size == 50 :
self.size_dec = True
elif self.size == 0:
self.size_dec = False
def event_cb(self,e) :
obj = e.get_target()
dsc = e.get_draw_part_dsc()
if dsc.class_p == lv.obj_class and dsc.part == lv.PART.MAIN :
draw_dsc = lv.draw_rect_dsc_t()
draw_dsc.init()
draw_dsc.bg_color = lv.color_hex(0xffaaaa)
draw_dsc.radius = lv.RADIUS_CIRCLE
draw_dsc.border_color = lv.color_hex(0xff5555)
draw_dsc.border_width = 2
draw_dsc.outline_color = lv.color_hex(0xff0000)
draw_dsc.outline_pad = 3
draw_dsc.outline_width = 2
a = lv.area_t()
a.x1 = 0
a.y1 = 0
a.x2 = self.size
a.y2 = self.size
coords = lv.area_t()
obj.get_coords(coords)
coords.align(a, lv.ALIGN.CENTER, 0, 0)
dsc.draw_ctx.rect(draw_dsc, a)
lv_example_event_4 = LV_Example_Event_4()

View File

@ -0,0 +1,63 @@
#
# Demonstrate a a basic grid navigation
#
# It's assumed that the default group is set and
# there is a keyboard indev
cont1 = lv.obj(lv.scr_act())
lv.gridnav_add(cont1, lv.GRIDNAV_CTRL.NONE)
# Use flex here, but works with grid or manually placed objects as well
cont1.set_flex_flow(lv.FLEX_FLOW.ROW_WRAP)
cont1.set_style_bg_color(lv.palette_lighten(lv.PALETTE.BLUE, 5), lv.STATE.FOCUSED)
cont1.set_size(lv.pct(50), lv.pct(100))
# Only the container needs to be in a group
lv.group_get_default().add_obj(cont1)
label = lv.label(cont1)
label.set_text("No rollover")
for i in range(10):
obj = lv.btn(cont1)
obj.set_size(70, lv.SIZE_CONTENT)
obj.add_flag(lv.obj.FLAG.CHECKABLE)
lv.group_remove_obj(obj) # Not needed, we use the gridnav instead
label = lv.label(obj)
label.set_text("{:d}".format(i))
label.center()
# Create a second container with rollover grid nav mode.
cont2 = lv.obj(lv.scr_act())
lv.gridnav_add(cont2,lv.GRIDNAV_CTRL.ROLLOVER)
cont2.set_style_bg_color(lv.palette_lighten(lv.PALETTE.BLUE, 5), lv.STATE.FOCUSED)
cont2.set_size(lv.pct(50), lv.pct(100))
cont2.align(lv.ALIGN.RIGHT_MID, 0, 0)
label = lv.label(cont2)
label.set_width(lv.pct(100))
label.set_text("Rollover\nUse tab to focus the other container")
# Only the container needs to be in a group
lv.group_get_default().add_obj(cont2)
# Add and place some children manually
ta = lv.textarea(cont2)
ta.set_size(lv.pct(100), 80)
ta.set_pos(0, 80);
lv.group_remove_obj(ta) # Not needed, we use the gridnav instead
cb = lv.checkbox(cont2)
cb.set_pos(0, 170)
lv.group_remove_obj(cb) # Not needed, we use the gridnav instead
sw1 = lv.switch(cont2)
sw1.set_pos(0, 200);
lv.group_remove_obj(sw1) # Not needed, we use the gridnav instead
sw2 = lv.switch(cont2)
sw2.set_pos(lv.pct(50), 200)
lv.group_remove_obj(sw2) # Not needed, we use the gridnav instead

View File

@ -0,0 +1,32 @@
#
# Grid navigation on a list
#
# It's assumed that the default group is set and
# there is a keyboard indev
list1 = lv.list(lv.scr_act())
lv.gridnav_add(list1, lv.GRIDNAV_CTRL.NONE)
list1.set_size(lv.pct(45), lv.pct(80))
list1.align(lv.ALIGN.LEFT_MID, 5, 0)
list1.set_style_bg_color(lv.palette_lighten(lv.PALETTE.BLUE, 5), lv.STATE.FOCUSED)
lv.group_get_default().add_obj(list1)
for i in range(15):
item_text = "File {:d}".format(i)
item = list1.add_btn(lv.SYMBOL.FILE, item_text)
item.set_style_bg_opa(0, 0)
lv.group_remove_obj(item) # Not needed, we use the gridnav instead
list2 = lv.list(lv.scr_act())
lv.gridnav_add(list2, lv.GRIDNAV_CTRL.ROLLOVER)
list2.set_size(lv.pct(45), lv.pct(80))
list2.align(lv.ALIGN.RIGHT_MID, -5, 0)
list2.set_style_bg_color(lv.palette_lighten(lv.PALETTE.BLUE, 5), lv.STATE.FOCUSED)
lv.group_get_default().add_obj(list2)
for i in range(15):
item_text = "Folder {:d}".format(i)
item = list2.add_btn(lv.SYMBOL.DIRECTORY, item_text)
item.set_style_bg_opa(0, 0)
lv.group_remove_obj(item)

View File

@ -0,0 +1,84 @@
def cont_sub_event_cb(e):
k = e.get_key()
obj = e.get_current_target()
if k == lv.KEY.ENTER:
lv.group_focus_obj(obj)
elif k == lv.KEY.ESC:
obj.get_group().focus_next()
#
# Nested grid navigations
#
# It's assumed that the default group is set and
# there is a keyboard indev*/
cont_main = lv.obj(lv.scr_act())
lv.gridnav_add(cont_main,lv.GRIDNAV_CTRL.ROLLOVER | lv.GRIDNAV_CTRL.SCROLL_FIRST)
# Only the container needs to be in a group
lv.group_get_default().add_obj(cont_main)
# Use flex here, but works with grid or manually placed objects as well
cont_main.set_flex_flow(lv.FLEX_FLOW.ROW_WRAP)
cont_main.set_style_bg_color(lv.palette_lighten(lv.PALETTE.BLUE, 5), lv.STATE.FOCUSED)
cont_main.set_size(lv.pct(80), lv.SIZE_CONTENT)
btn = lv.btn(cont_main)
lv.group_remove_obj(btn)
label = lv.label(btn)
label.set_text("Button 1")
btn = lv.btn(cont_main)
lv.group_remove_obj(btn)
label = lv.label(btn)
label.set_text("Button 2");
# Create an other container with long text to show how LV_GRIDNAV_CTRL_SCROLL_FIRST works
cont_sub1 = lv.obj(cont_main)
cont_sub1.set_size(lv.pct(100), 100)
label = lv.label(cont_sub1)
cont_sub1.set_style_bg_color(lv.palette_lighten(lv.PALETTE.RED, 5), lv.STATE.FOCUSED)
label.set_width(lv.pct(100));
label.set_text(
"""I'm a very long text which makes my container scrollable.
As LV_GRIDNAV_FLAG_SCROLL_FIRST is enabled arrows will scroll me first
and a new objects will be focused only when an edge is reached with the scrolling.\n
This is only some placeholder text to be sure the parent will be scrollable. \n
Hello world!
Hello world!
Hello world!
Hello world!
Hello world!
Hello world!
""")
# Create a third container that can be focused with ENTER and contains an other grid nav
cont_sub2 = lv.obj(cont_main)
lv.gridnav_add(cont_sub2, lv.GRIDNAV_CTRL.ROLLOVER)
#Only the container needs to be in a group
lv.group_get_default().add_obj(cont_sub2)
cont_sub2.add_event_cb(cont_sub_event_cb, lv.EVENT.KEY, None)
# Use flex here, but works with grid or manually placed objects as well
cont_sub2.set_flex_flow(lv.FLEX_FLOW.ROW_WRAP)
cont_sub2.set_style_bg_color(lv.palette_lighten(lv.PALETTE.RED, 5), lv.STATE.FOCUSED)
cont_sub2.set_size(lv.pct(100), lv.SIZE_CONTENT)
label = lv.label(cont_sub2)
label.set_text("Use ENTER/ESC to focus/defocus this container")
label.set_width(lv.pct(100))
btn = lv.btn(cont_sub2)
lv.group_remove_obj(btn)
label = lv.label(btn)
label.set_text("Button 3")
btn = lv.btn(cont_sub2)
lv.group_remove_obj(btn)
label = lv.label(btn)
label.set_text("Button 4")

View File

@ -0,0 +1,36 @@
def event_handler(e):
obj = e.get_target()
list = obj.get_parent()
print("Clicked: " + list.get_btn_text(obj))
#
# Simple navigation on a list widget
#
# It's assumed that the default group is set and
# there is a keyboard indev
list = lv.list(lv.scr_act())
lv.gridnav_add(list, lv.GRIDNAV_CTRL.ROLLOVER)
list.align(lv.ALIGN.LEFT_MID, 0, 10)
lv.group_get_default().add_obj(list)
for i in range(20):
# Add some separators too, they are not focusable by gridnav
if i % 5 == 0:
txt = "Section {:d}".format(i // 5 + 1)
# lv_snprintf(buf, sizeof(buf), "Section %d", i / 5 + 1);
list.add_text(txt)
txt = "File {:d}".format(i + 1)
#lv_snprintf(buf, sizeof(buf), "File %d", i + 1);
item = list.add_btn(lv.SYMBOL.FILE, txt)
item.add_event_cb(event_handler, lv.EVENT.CLICKED, None)
lv.group_remove_obj(item) # The default group adds it automatically
btn = lv.btn(lv.scr_act())
btn.align(lv.ALIGN.RIGHT_MID, 0, -10)
label = lv.label(btn)
label.set_text("Button")

View File

@ -0,0 +1,50 @@
import fs_driver
def ta_event_cb(e,kb):
code = e.get_code()
ta = e.get_target()
if code == lv.EVENT.FOCUSED:
if lv.indev_get_act() != None and lv.indev_get_act().get_type() != lv.INDEV_TYPE.KEYPAD :
kb.set_textarea(ta)
kb.clear_flag(lv.obj.FLAG.HIDDEN)
elif code == lv.EVENT.CANCEL:
kb.add_flag(lv.obj.FLAG.HIDDEN)
ta.clear_state(ta, LV_STATE_FOCUSED);
lv.indev_reset(None, ta) # To forget the last clicked object to make it focusable again
fs_drv = lv.fs_drv_t()
fs_driver.fs_register(fs_drv, 'S')
font_simsun_16_cjk = lv.font_load("S:../../assets/font/lv_font_simsun_16_cjk.fnt")
if font_simsun_16_cjk == None:
print("Error when loading chinese font")
pinyin_ime = lv.ime_pinyin(lv.scr_act())
pinyin_ime.set_style_text_font(font_simsun_16_cjk, 0)
# pinyin_ime.pinyin_set_dict(your_dict) # Use a custom dictionary. If it is not set, the built-in dictionary will be used.
# ta1
ta1 = lv.textarea(lv.scr_act())
ta1.set_one_line(True)
ta1.set_style_text_font(font_simsun_16_cjk, 0)
ta1.align(lv.ALIGN.TOP_LEFT, 0, 0)
# Create a keyboard and add it to ime_pinyin
kb = lv.keyboard(lv.scr_act())
pinyin_ime.pinyin_set_keyboard(kb)
kb.set_textarea(ta1)
ta1.add_event_cb(lambda evt: ta_event_cb(evt,kb), lv.EVENT.ALL, None)
# Get the cand_panel, and adjust its size and position
cand_panel = pinyin_ime.pinyin_get_cand_panel()
cand_panel.set_size(lv.pct(100), lv.pct(10))
cand_panel.align_to(kb, lv.ALIGN.OUT_TOP_MID, 0, 0)
# Try using ime_pinyin to output the Chinese below in the ta1 above
cz_label = lv.label(lv.scr_act())
cz_label.set_text("嵌入式系统Embedded System\n是一种嵌入机械或电气系统内部、具有专一功能和实时计算性能的计算机系统。")
cz_label.set_style_text_font(font_simsun_16_cjk, 0)
cz_label.set_width(310)
cz_label.align_to(ta1, lv.ALIGN.OUT_BOTTOM_LEFT, 0, 0)

View File

@ -0,0 +1,52 @@
import fs_driver
def ta_event_cb(e,kb):
code = e.get_code()
ta = e.get_target()
if code == lv.EVENT.FOCUSED:
if lv.indev_get_act() != None and lv.indev_get_act().get_type() != lv.INDEV_TYPE.KEYPAD :
kb.set_textarea(ta)
kb.clear_flag(lv.obj.FLAG.HIDDEN)
elif code == lv.EVENT.READY:
kb.add_flag(lv.obj.FLAG.HIDDEN)
ta.clear_state(ta, LV_STATE_FOCUSED);
lv.indev_reset(None, ta) # To forget the last clicked object to make it focusable again
fs_drv = lv.fs_drv_t()
fs_driver.fs_register(fs_drv, 'S')
font_simsun_16_cjk = lv.font_load("S:../../assets/font/lv_font_simsun_16_cjk.fnt")
if font_simsun_16_cjk == None:
print("Error when loading chinese font")
pinyin_ime = lv.ime_pinyin(lv.scr_act())
pinyin_ime.set_style_text_font(font_simsun_16_cjk, 0)
# pinyin_ime.pinyin_set_dict(your_dict) # Use a custom dictionary. If it is not set, the built-in dictionary will be used.
# ta1
ta1 = lv.textarea(lv.scr_act())
ta1.set_one_line(True)
ta1.set_style_text_font(font_simsun_16_cjk, 0)
ta1.align(lv.ALIGN.TOP_LEFT, 0, 0)
# Create a keyboard and add it to ime_pinyin
kb = lv.keyboard(lv.scr_act())
kb.set_textarea(ta1)
pinyin_ime.pinyin_set_keyboard(kb)
pinyin_ime.pinyin_set_mode(lv.ime_pinyin.PINYIN_MODE.K9) # Set to 9-key input mode. Default: 26-key input(k26) mode.
ta1.add_event_cb(lambda evt: ta_event_cb(evt,kb), lv.EVENT.ALL, None)
# Get the cand_panel, and adjust its size and position
cand_panel = pinyin_ime.pinyin_get_cand_panel()
cand_panel.set_size(lv.pct(100), lv.pct(10))
cand_panel.align_to(kb, lv.ALIGN.OUT_TOP_MID, 0, 0)
# Try using ime_pinyin to output the Chinese below in the ta1 above
cz_label = lv.label(lv.scr_act())
cz_label.set_text("嵌入式系统Embedded System\n是一种嵌入机械或电气系统内部、具有专一功能和实时计算性能的计算机系统。")
cz_label.set_style_text_font(font_simsun_16_cjk, 0)
cz_label.set_width(310)
cz_label.align_to(ta1, lv.ALIGN.OUT_BOTTOM_LEFT, 0, 0)

View File

@ -0,0 +1,40 @@
import fs_driver
import sys
# set LV_USE_FFMPEG to True if it is enabled in lv_conf.h
LV_USE_FFMPEG = True
LV_FONT_DEFAULT = lv.font_montserrat_14
fs_drv = lv.fs_drv_t()
fs_driver.fs_register(fs_drv, 'A')
# get the directory in which the script is running
try:
script_path = __file__[:__file__.rfind('/')] if __file__.find('/') >= 0 else '.'
except NameError:
script_path = ''
def get_imgfont_path(font, img_src, length, unicode, unicode_next,user_data) :
if unicode < 0xf600:
return
if LV_USE_FFMPEG:
path = bytes(script_path + "/../../assets/emoji/{:04X}.png".format(unicode) + "\0","ascii")
else:
path = bytes("A:"+ script_path + "/../../assets/emoji/{:04X}.png".format(unicode) + "\0","ascii")
# print("image path: ",path)
img_src.__dereference__(length)[0:len(path)] = path
return True
#
# draw img in label or span obj
#
imgfont = lv.imgfont_create(80, get_imgfont_path, None)
if imgfont == None:
print("imgfont init error")
imgfont.fallback = LV_FONT_DEFAULT
label1 = lv.label(lv.scr_act())
label1.set_text("12\uF600\uF617AB")
label1.set_style_text_font(imgfont, lv.PART.MAIN)
label1.center()

View File

@ -0,0 +1,142 @@
from micropython import const
# Define a message ID
MSG_LOGIN_ATTEMPT = const(1)
MSG_LOG_OUT = const(2)
MSG_LOGIN_ERROR = const(3)
MSG_LOGIN_OK = const(4)
# Define the object that will be sent as msg payload
class Message:
def __init__(self, value):
self.value = value
def message(self):
return self.value
def auth_manager(m,passwd):
payload = m.get_payload()
pin_act = payload.__cast__().message()
# print("pin act: ",pin_act,end="")
# print(", pin axpected: ",passwd)
pin_expected = passwd
if pin_act == pin_expected:
lv.msg_send(MSG_LOGIN_OK, None)
else:
lv.msg_send(MSG_LOGIN_ERROR, Message("Incorrect PIN"))
def textarea_event_cb(e):
ta = e.get_target()
code = e.get_code()
if code == lv.EVENT.READY:
passwd = Message(ta.get_text())
lv.msg_send(MSG_LOGIN_ATTEMPT, passwd)
elif code == lv.EVENT.MSG_RECEIVED:
m = e.get_msg()
id = m.get_id()
if id == MSG_LOGIN_ERROR:
# If there was an error, clean the text area
msg = m.get_payload().__cast__()
if len(msg.message()):
ta.set_text("")
elif id == MSG_LOGIN_OK:
ta.add_state(lv.STATE.DISABLED)
ta.clear_state(lv.STATE.FOCUSED | lv.STATE.FOCUS_KEY)
elif id == MSG_LOG_OUT:
ta.set_text("");
ta.clear_state(lv.STATE.DISABLED)
def log_out_event_cb(e):
code = e.get_code()
if code == lv.EVENT.CLICKED:
lv.msg_send(MSG_LOG_OUT, None)
elif code == lv.EVENT.MSG_RECEIVED:
m = e.get_msg()
btn = e.get_target()
id = m.get_id()
if id == MSG_LOGIN_OK:
btn.clear_state(lv.STATE.DISABLED)
elif id == MSG_LOG_OUT:
btn.add_state(lv.STATE.DISABLED)
def start_engine_msg_event_cb(e):
m = e.get_msg()
btn = e.get_target()
id = m.get_id()
if id == MSG_LOGIN_OK:
btn.clear_state(lv.STATE.DISABLED)
elif id == MSG_LOG_OUT:
btn.add_state(lv.STATE.DISABLED)
def info_label_msg_event_cb(e):
label = e.get_target()
m = e.get_msg()
id = m.get_id()
if id == MSG_LOGIN_ERROR:
payload = m.get_payload()
label.set_text(payload.__cast__().message())
label.set_style_text_color(lv.palette_main(lv.PALETTE.RED), 0)
elif id == MSG_LOGIN_OK:
label.set_text("Login successful")
label.set_style_text_color(lv.palette_main(lv.PALETTE.GREEN), 0)
elif id == MSG_LOG_OUT:
label.set_text("Logged out")
label.set_style_text_color(lv.palette_main(lv.PALETTE.GREY), 0)
def register_auth(msg_id,auth_msg):
lv.msg_subscribe(MSG_LOGIN_ATTEMPT, lambda m: auth_msg(m,"hello"), None)
#
# Simple PIN login screen.
# No global variables are used, all state changes are communicated via messages.
register_auth(MSG_LOGIN_ATTEMPT,auth_manager)
# lv.msg_subscribe_obj(MSG_LOGIN_ATTEMPT, auth_manager, "Hello")
# Create a slider in the center of the display
ta = lv.textarea(lv.scr_act())
ta.set_pos(10, 10)
ta.set_width(200)
ta.set_one_line(True)
ta.set_password_mode(True)
ta.set_placeholder_text("The password is: hello")
ta.add_event_cb(textarea_event_cb, lv.EVENT.ALL, None)
lv.msg_subscribe_obj(MSG_LOGIN_ERROR, ta, None)
lv.msg_subscribe_obj(MSG_LOGIN_OK, ta, None)
lv.msg_subscribe_obj(MSG_LOG_OUT, ta, None)
kb = lv.keyboard(lv.scr_act())
kb.set_textarea(ta)
# Create a log out button which will be active only when logged in
btn = lv.btn(lv.scr_act())
btn.set_pos(240, 10)
btn.add_event_cb(log_out_event_cb, lv.EVENT.ALL, None)
lv.msg_subscribe_obj(MSG_LOGIN_OK, btn, None)
lv.msg_subscribe_obj(MSG_LOG_OUT, btn, None)
label = lv.label(btn);
label.set_text("LOG OUT")
# Create a label to show info
label = lv.label(lv.scr_act());
label.set_text("")
label.add_event_cb(info_label_msg_event_cb, lv.EVENT.MSG_RECEIVED, None)
label.set_pos(10, 60)
lv.msg_subscribe_obj(MSG_LOGIN_ERROR, label, None)
lv.msg_subscribe_obj(MSG_LOGIN_OK, label, None)
lv.msg_subscribe_obj(MSG_LOG_OUT, label, None)
#Create button which will be active only when logged in
btn = lv.btn(lv.scr_act())
btn.set_pos(10, 80)
btn.add_event_cb(start_engine_msg_event_cb, lv.EVENT.MSG_RECEIVED, None)
btn.add_flag(lv.obj.FLAG.CHECKABLE)
lv.msg_subscribe_obj(MSG_LOGIN_OK, btn, None)
lv.msg_subscribe_obj(MSG_LOG_OUT, btn, None)
label = lv.label(btn)
label.set_text("START ENGINE")
lv.msg_send(MSG_LOG_OUT, None)

View File

@ -0,0 +1,122 @@
# Define a message ID
MSG_INC = 1
MSG_DEC = 2
MSG_SET = 3
MSG_UPDATE = 4
MSG_UPDATE_REQUEST = 5
# Define the object that will be sent as msg payload
class NewValue:
def __init__(self, value):
self.value = value
def __repr__(self):
return f"{self.value} %"
class LV_Example_Msg_2:
def __init__(self):
self.value = 10
lv.msg_subscribe(MSG_INC, self.value_handler, None)
lv.msg_subscribe(MSG_DEC, self.value_handler, None)
lv.msg_subscribe(MSG_SET, self.value_handler, None)
lv.msg_subscribe(MSG_UPDATE, self.value_handler, None)
lv.msg_subscribe(MSG_UPDATE_REQUEST, self.value_handler, None)
panel = lv.obj(lv.scr_act())
panel.set_size(250, lv.SIZE_CONTENT)
panel.center()
panel.set_flex_flow(lv.FLEX_FLOW.ROW)
panel.set_flex_align(lv.FLEX_ALIGN.SPACE_BETWEEN, lv.FLEX_ALIGN.CENTER, lv.FLEX_ALIGN.START)
# Up button
btn = lv.btn(panel)
btn.set_flex_grow(1)
btn.add_event_cb(self.btn_event_cb, lv.EVENT.ALL, None)
label = lv.label(btn)
label.set_text(lv.SYMBOL.LEFT)
label.center()
# Current value
label = lv.label(panel)
label.set_flex_grow(2)
label.set_style_text_align(lv.TEXT_ALIGN.CENTER, 0)
label.set_text("?")
lv.msg_subscribe_obj(MSG_UPDATE, label, None)
label.add_event_cb(self.label_event_cb, lv.EVENT.MSG_RECEIVED, None)
# Down button
btn = lv.btn(panel)
btn.set_flex_grow(1)
btn.add_event_cb(self.btn_event_cb, lv.EVENT.ALL, None)
label = lv.label(btn)
label.set_text(lv.SYMBOL.RIGHT)
label.center()
# Slider
slider = lv.slider(panel)
slider.set_flex_grow(1)
slider.add_flag(lv.OBJ_FLAG_FLEX_IN_NEW_TRACK)
slider.add_event_cb(self.slider_event_cb, lv.EVENT.ALL, None)
lv.msg_subscribe_obj(MSG_UPDATE, slider, None)
# As there are new UI elements that don't know the system's state
# send an UPDATE REQUEST message which will trigger an UPDATE message with the current value
lv.msg_send(MSG_UPDATE_REQUEST, None)
def value_handler(self,m):
old_value = self.value
id = m.get_id()
if id == MSG_INC:
if self.value < 100:
self.value +=1
elif id == MSG_DEC:
if self.value > 0:
self.value -=1
elif id == MSG_SET:
payload = m.get_payload()
new_value=payload.__cast__()
self.value = new_value.value
# print("value_handler: new value: {:d}".format(new_value.value))
elif id == MSG_UPDATE_REQUEST:
lv.msg_send(MSG_UPDATE, NewValue(self.value))
if self.value != old_value:
lv.msg_send(MSG_UPDATE, NewValue(self.value));
def btn_event_cb(self,e):
btn = e.get_target()
code = e.get_code()
if code == lv.EVENT.CLICKED or code == lv.EVENT.LONG_PRESSED_REPEAT:
if btn.get_index() == 0: # rst object is the dec. button
lv.msg_send(MSG_DEC, None)
else :
lv.msg_send(MSG_INC, None)
def label_event_cb(self,e):
label = e.get_target()
code = e.get_code()
if code == lv.EVENT.MSG_RECEIVED:
m = e.get_msg()
if m.get_id() == MSG_UPDATE:
payload = m.get_payload()
value=payload.__cast__()
# print("label_event_cb: " + str(value))
label.set_text(str(value))
def slider_event_cb(self,e):
slider = e.get_target()
code = e.get_code()
if code == lv.EVENT.VALUE_CHANGED:
v = slider.get_value()
# print("slider_event_cb: {:d}".format(v))
lv.msg_send(MSG_SET, NewValue(v))
elif code == lv.EVENT.MSG_RECEIVED:
m = e.get_msg()
if m.get_id() == MSG_UPDATE:
v = m.get_payload()
value = v.__cast__()
slider.set_value(value.value, lv.ANIM.OFF)
lv_example_msg_2 = LV_Example_Msg_2()

View File

@ -1,24 +1,38 @@
#!/opt/bin/lv_micropython -i
import lvgl as lv
import display_driver
def event_cb(e):
code = e.get_code()
chart = e.get_target()
if code == lv.EVENT.VALUE_CHANGED:
chart.invalidate()
if code == lv.EVENT.REFR_EXT_DRAW_SIZE:
# s = lv.coord_t.__cast__(e.get_param())
# print("s: {:d}".format(s))
e.set_ext_draw_size(20)
elif code == lv.EVENT.DRAW_POST_END:
id = lv.chart.get_pressed_point(chart)
if id == lv.CHART_POINT_NONE:
id = chart.get_pressed_point()
if id == lv.CHART_POINT_NONE :
return
# print("Selected point ", id)
for i in range(len(series)):
p = lv.point_t()
chart.get_point_pos_by_id(series[i], id, p)
value = series_points[i][id]
buf = lv.SYMBOL.DUMMY + "$" + str(value)
# print("Selected point {:d}".format(id))
ser = chart.get_series_next(None)
while(ser) :
p = lv.point_t()
chart.get_point_pos_by_id(ser, id, p)
# print("point coords: x: {:d}, y: {:d}".format(p.x,p.y))
y_array = chart.get_y_array(ser)
value = y_array[id]
buf = lv.SYMBOL.DUMMY + "{:2d}".format(value)
draw_rect_dsc = lv.draw_rect_dsc_t()
draw_rect_dsc.init()
draw_rect_dsc.bg_color = lv.color_black()
@ -26,23 +40,27 @@ def event_cb(e):
draw_rect_dsc.radius = 3
draw_rect_dsc.bg_img_src = buf
draw_rect_dsc.bg_img_recolor = lv.color_white()
a = lv.area_t()
coords = lv.area_t()
chart.get_coords(coords)
# print("coords: x1: {:d}, y1: {:d}".format(coords.x1, coords.y1))
a = lv.area_t()
a.x1 = coords.x1 + p.x - 20
a.x2 = coords.x1 + p.x + 20
a.y1 = coords.y1 + p.y - 30
a.y2 = coords.y1 + p.y - 10
clip_area = lv.area_t.__cast__(e.get_param())
lv.draw_rect(a, clip_area, draw_rect_dsc)
# print("a: x1: {:d}, x2: {:d}, y1: {:d}, y2: {:d}".format(a.x1,a.x2,a.y1,a.y2))
draw_ctx = e.get_draw_ctx()
draw_ctx.rect(draw_rect_dsc, a)
ser = chart.get_series_next(ser)
elif code == lv.EVENT.RELEASED:
chart.invalidate()
#
# Add ticks and labels to the axis and demonstrate scrolling
#
# Show the value of the pressed points
#
# Create a chart
@ -51,6 +69,7 @@ chart.set_size(200, 150)
chart.center()
chart.add_event_cb(event_cb, lv.EVENT.ALL, None)
chart.refresh_ext_draw_size()
# Zoom in a little in X
@ -59,15 +78,7 @@ chart.set_zoom_x(800)
# Add two data series
ser1 = chart.add_series(lv.palette_main(lv.PALETTE.RED), lv.chart.AXIS.PRIMARY_Y)
ser2 = chart.add_series(lv.palette_main(lv.PALETTE.GREEN), lv.chart.AXIS.PRIMARY_Y)
ser1_p = []
ser2_p = []
for i in range(10):
ser1_p.append(lv.rand(60,90))
ser2_p.append(lv.rand(10,40))
ser1.y_points = ser1_p
ser2.y_points = ser2_p
series = [ser1,ser2]
series_points=[ser1_p,ser2_p]
chart.set_next_value(ser1, lv.rand(60, 90))
chart.set_next_value(ser2, lv.rand(10, 40))

View File

@ -0,0 +1,83 @@
import time
class LV_Example_Checkbox_2:
def __init__(self):
#
# Checkboxes as radio buttons
#
# The idea is to enable `LV_OBJ_FLAG_EVENT_BUBBLE` on checkboxes and process the
#`LV.EVENT.CLICKED` on the container.
# Since user_data cannot be used to pass parameters in MicroPython I use an instance variable to
# keep the index of the active button
self.active_index_1 = 0
self.active_index_2 = 0
self.style_radio = lv.style_t()
self.style_radio.init()
self.style_radio.set_radius(lv.RADIUS_CIRCLE)
self.style_radio_chk = lv.style_t()
self.style_radio_chk.init()
self.style_radio_chk.init()
self.style_radio_chk.set_bg_img_src(None)
self.cont1 = lv.obj(lv.scr_act())
self.cont1.set_flex_flow(lv.FLEX_FLOW.COLUMN)
self.cont1.set_size(lv.pct(40), lv.pct(80))
self.cont1.add_event_cb(self.radio_event_handler, lv.EVENT.CLICKED, None)
for i in range(5):
txt = "A {:d}".format(i+1)
self.radiobutton_create(self.cont1,txt)
# Make the first checkbox checked
#lv_obj_add_state(lv_obj_get_child(self.cont1, 0), LV_STATE_CHECKED);
self.cont1.get_child(0).add_state(lv.STATE.CHECKED)
self.cont2 = lv.obj(lv.scr_act())
self.cont2.set_flex_flow(lv.FLEX_FLOW.COLUMN)
self.cont2.set_size(lv.pct(40), lv.pct(80))
self.cont2.set_x(lv.pct(50))
self.cont2.add_event_cb(self.radio_event_handler, lv.EVENT.CLICKED, None)
for i in range(3):
txt = "B {:d}".format(i+1)
self.radiobutton_create(self.cont2,txt)
# Make the first checkbox checked*/
self.cont2.get_child(0).add_state(lv.STATE.CHECKED)
def radio_event_handler(self,e):
cont = e.get_current_target()
act_cb = e.get_target()
if cont == self.cont1:
active_id = self.active_index_1
else:
active_id = self.active_index_2
old_cb = cont.get_child(active_id)
# Do nothing if the container was clicked
if act_cb == cont:
return
old_cb.clear_state(lv.STATE.CHECKED) # Uncheck the previous radio button
act_cb.add_state(lv.STATE.CHECKED) # Uncheck the current radio button
if cont == self.cont1:
self.active_index_1 = act_cb.get_index()
# print("active index 1: ", self.active_index_1)
else:
self.active_index_2 = act_cb.get_index()
# print("active index 2: ", self.active_index_2)
print("Selected radio buttons: {:d}, {:d}".format(self.active_index_1, self.active_index_2))
def radiobutton_create(self,parent, txt):
obj = lv.checkbox(parent)
obj.set_text(txt)
obj.add_flag(lv.obj.FLAG.EVENT_BUBBLE)
obj.add_style(self.style_radio, lv.PART.INDICATOR)
obj.add_style(self.style_radio_chk, lv.PART.INDICATOR | lv.STATE.CHECKED)
lv_example_checkbox_2 = LV_Example_Checkbox_2()

View File

@ -0,0 +1,26 @@
# Create an AZERTY keyboard map
kb_map = ["A", "Z", "E", "R", "T", "Y", "U", "I", "O", "P", lv.SYMBOL.BACKSPACE, "\n",
"Q", "S", "D", "F", "G", "J", "K", "L", "M", lv.SYMBOL.NEW_LINE, "\n",
"W", "X", "C", "V", "B", "N", ",", ".", ":", "!", "?", "\n",
lv.SYMBOL.CLOSE, " ", " ", " ", lv.SYMBOL.OK, None]
# Set the relative width of the buttons and other controls
kb_ctrl = [4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 6,
4, 4, 4, 4, 4, 4, 4, 4, 4, 6,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
2, lv.btnmatrix.CTRL.HIDDEN | 2, 6, lv.btnmatrix.CTRL.HIDDEN | 2, 2]
# Create a keyboard and add the new map as USER_1 mode
kb = lv.keyboard(lv.scr_act())
kb.set_map(lv.keyboard.MODE.USER_1, kb_map, kb_ctrl)
kb.set_mode(lv.keyboard.MODE.USER_1)
# Create a text area. The keyboard will write here
ta = lv.textarea(lv.scr_act())
ta.align(lv.ALIGN.TOP_MID, 0, 10)
ta.set_size(lv.pct(90), 80)
ta.add_state(lv.STATE.FOCUSED)
kb.set_textarea(ta)

View File

@ -0,0 +1,175 @@
from micropython import const
def create_text(parent, icon, txt, builder_variant):
obj = lv.menu_cont(parent)
img = None
label = None
if icon :
img = lv.img(obj)
img.set_src(icon)
if txt :
label = lv.label(obj)
label.set_text(txt)
label.set_long_mode(lv.label.LONG.SCROLL_CIRCULAR)
label.set_flex_grow(1)
if builder_variant == LV_MENU_ITEM_BUILDER_VARIANT_2 and icon and txt :
img.add_flag(lv.OBJ_FLAG_FLEX_IN_NEW_TRACK)
img.swap(label)
return obj
def create_slider(parent, icon, txt, min, max, val) :
obj = create_text(parent, icon, txt, LV_MENU_ITEM_BUILDER_VARIANT_2)
slider = lv.slider(obj)
slider.set_flex_grow(1)
slider.set_range(min, max)
slider.set_value(val, lv.ANIM.OFF)
if icon == None :
slider.add_flag(lv.obj.FLAG_FLEX.IN_NEW_TRACK)
return obj
def create_switch(parent, icon, txt, chk) :
obj = create_text(parent, icon, txt, LV_MENU_ITEM_BUILDER_VARIANT_1)
sw = lv.switch(obj)
if chk == lv.STATE.CHECKED:
sw.add_state(chk )
else:
sw.add_state(0)
return obj
def back_event_handler(e,menu):
obj = e.get_target()
# menu = lv_event_get_user_data(e);
if menu.back_btn_is_root(obj) :
mbox1 = lv.msgbox(None, "Hello", "Root back btn click.", None, True)
mbox1.center()
def switch_handler(e,menu):
code = e.get_code()
obj = e.get_target()
if code == lv.EVENT.VALUE_CHANGED :
if obj.has_state(lv.STATE.CHECKED) :
menu.set_page(None)
menu.set_sidebar_page(root_page)
# lv_event_send(lv_obj_get_child(lv_obj_get_child(lv_menu_get_cur_sidebar_page(menu), 0), 0), LV_EVENT_CLICKED, NULL);
lv.event_send(menu.get_cur_sidebar_page().get_child(0).get_child(0),lv.EVENT.CLICKED,None)
else :
menu.set_sidebar_page(None)
menu.clear_history() # Clear history because we will be showing the root page later
menu.set_page(root_page)
LV_MENU_ITEM_BUILDER_VARIANT_1 = const(0)
LV_MENU_ITEM_BUILDER_VARIANT_2 = const(1)
LV_HOR_RES = lv.scr_act().get_disp().driver.hor_res
LV_VER_RES = lv.scr_act().get_disp().driver.ver_res
menu = lv.menu(lv.scr_act())
bg_color = menu.get_style_bg_color(0)
if bg_color.color_brightness() > 127 :
menu.set_style_bg_color(menu.get_style_bg_color(0).color_darken(10),0)
else :
menu.set_style_bg_color(menu.get_style_bg_color(0).color_darken(50),0)
menu.set_mode_root_back_btn(lv.menu.ROOT_BACK_BTN.ENABLED)
menu.add_event_cb(lambda evt: back_event_handler(evt,menu), lv.EVENT.CLICKED, None)
menu.set_size(LV_HOR_RES, LV_VER_RES )
menu.center()
# Create sub pages
sub_mechanics_page = lv.menu_page(menu, None)
sub_mechanics_page.set_style_pad_hor(menu.get_main_header().get_style_pad_left(0),0)
lv.menu_separator(sub_mechanics_page)
section = lv.menu_section(sub_mechanics_page);
create_slider(section,lv.SYMBOL.SETTINGS, "Velocity", 0, 150, 120)
create_slider(section,lv.SYMBOL.SETTINGS, "Acceleration", 0, 150, 50)
create_slider(section,lv.SYMBOL.SETTINGS, "Weight limit", 0, 150, 80)
sub_sound_page = lv.menu_page(menu, None)
sub_sound_page.set_style_pad_hor(menu.get_main_header().get_style_pad_left(0),0)
lv.menu_separator(sub_sound_page)
section = lv.menu_section(sub_sound_page)
create_switch(section,lv.SYMBOL.AUDIO, "Sound", False)
sub_display_page = lv.menu_page(menu, None)
sub_display_page.set_style_pad_hor(menu.get_main_header().get_style_pad_left(0),0)
lv.menu_separator(sub_display_page)
section = lv.menu_section(sub_display_page)
create_slider(section,lv.SYMBOL.SETTINGS, "Brightness", 0, 150, 100)
sub_software_info_page = lv.menu_page(menu, None)
sub_software_info_page.set_style_pad_hor(menu.get_main_header().get_style_pad_left(0),0)
section = lv.menu_section(sub_software_info_page)
create_text(section,None, "Version 1.0", LV_MENU_ITEM_BUILDER_VARIANT_1)
sub_legal_info_page = lv.menu_page(menu, None)
sub_legal_info_page.set_style_pad_hor(menu.get_main_header().get_style_pad_left(0),0)
section = lv.menu_section(sub_legal_info_page)
for i in range(15):
create_text(section, None,
"This is a long long long long long long long long long text, if it is long enough it may scroll.",
LV_MENU_ITEM_BUILDER_VARIANT_1)
sub_about_page = lv.menu_page(menu, None)
sub_about_page.set_style_pad_hor(menu.get_main_header().get_style_pad_left(0),0)
lv.menu_separator(sub_about_page)
section = lv.menu_section(sub_about_page)
cont = create_text(section, None, "Software information", LV_MENU_ITEM_BUILDER_VARIANT_1);
menu.set_load_page_event(cont, sub_software_info_page);
cont = create_text(section, None, "Legal information", LV_MENU_ITEM_BUILDER_VARIANT_1);
menu.set_load_page_event(cont, sub_legal_info_page)
sub_menu_mode_page = lv.menu_page(menu, None)
sub_menu_mode_page.set_style_pad_hor(menu.get_main_header().get_style_pad_left(0),0)
lv.menu_separator(sub_menu_mode_page)
section = lv.menu_section(sub_menu_mode_page)
cont = create_switch(section, lv.SYMBOL.AUDIO, "Sidebar enable",True)
cont.get_child(2).add_event_cb(lambda evt: switch_handler(evt,menu), lv.EVENT.VALUE_CHANGED, None)
# Create a root page
root_page = lv.menu_page(menu, "Settings")
root_page.set_style_pad_hor(menu.get_main_header().get_style_pad_left(0),0)
section = lv.menu_section(root_page)
cont = create_text(section, lv.SYMBOL.SETTINGS, "Mechanics", LV_MENU_ITEM_BUILDER_VARIANT_1)
menu.set_load_page_event(cont, sub_mechanics_page);
cont = create_text(section, lv.SYMBOL.AUDIO, "Sound", LV_MENU_ITEM_BUILDER_VARIANT_1);
menu.set_load_page_event(cont, sub_sound_page)
cont = create_text(section, lv.SYMBOL.SETTINGS, "Display", LV_MENU_ITEM_BUILDER_VARIANT_1);
menu.set_load_page_event(cont, sub_display_page)
create_text(root_page, None, "Others", LV_MENU_ITEM_BUILDER_VARIANT_1);
section = lv.menu_section(root_page)
cont = create_text(section, None, "About", LV_MENU_ITEM_BUILDER_VARIANT_1);
menu.set_load_page_event(cont, sub_about_page)
cont = create_text(section, lv.SYMBOL.SETTINGS, "Menu mode", LV_MENU_ITEM_BUILDER_VARIANT_1);
menu.set_load_page_event(cont, sub_menu_mode_page)
menu.set_sidebar_page(root_page)
lv.event_send(menu.get_cur_sidebar_page().get_child(0).get_child(0),lv.EVENT.CLICKED,None)