From 29ec34be77216cdab02ef78eb98a5a9e1aa949c9 Mon Sep 17 00:00:00 2001 From: Uli Raich Date: Wed, 21 Sep 2022 11:21:36 +0200 Subject: [PATCH] examples(micropython): add a few missing MP examples (#3672) --- .../keypad_encoder/lv_demo_keypad_encoder.py | 156 ++++++++++++++++ examples/assets/emoji/F617.png | Bin 0 -> 4460 bytes examples/event/lv_example_event_4.py | 52 ++++++ .../others/gridnav/lv_example_gridnav_1.py | 63 +++++++ .../others/gridnav/lv_example_gridnav_2.py | 32 ++++ .../others/gridnav/lv_example_gridnav_3.py | 84 +++++++++ .../others/gridnav/lv_example_gridnav_4.py | 36 ++++ .../others/ime/lv_example_ime_pinyin_1.py | 50 +++++ .../others/ime/lv_example_ime_pinyin_2.py | 52 ++++++ .../others/imgfont/lv_example_imgfont_1.py | 40 ++++ examples/others/msg/lv_example_msg_2.py | 142 ++++++++++++++ examples/others/msg/lv_example_msg_3.py | 122 ++++++++++++ examples/widgets/chart/lv_example_chart_4.py | 65 ++++--- .../widgets/checkbox/lv_example_checkbox_2.py | 83 +++++++++ .../widgets/keyboard/lv_example_keyboard_2.py | 26 +++ examples/widgets/menu/lv_example_menu_5.py | 175 ++++++++++++++++++ 16 files changed, 1151 insertions(+), 27 deletions(-) create mode 100644 demos/keypad_encoder/lv_demo_keypad_encoder.py create mode 100644 examples/assets/emoji/F617.png create mode 100644 examples/event/lv_example_event_4.py create mode 100644 examples/others/gridnav/lv_example_gridnav_1.py create mode 100644 examples/others/gridnav/lv_example_gridnav_2.py create mode 100644 examples/others/gridnav/lv_example_gridnav_3.py create mode 100644 examples/others/gridnav/lv_example_gridnav_4.py create mode 100644 examples/others/ime/lv_example_ime_pinyin_1.py create mode 100644 examples/others/ime/lv_example_ime_pinyin_2.py create mode 100644 examples/others/imgfont/lv_example_imgfont_1.py create mode 100644 examples/others/msg/lv_example_msg_2.py create mode 100644 examples/others/msg/lv_example_msg_3.py create mode 100644 examples/widgets/checkbox/lv_example_checkbox_2.py create mode 100644 examples/widgets/keyboard/lv_example_keyboard_2.py create mode 100644 examples/widgets/menu/lv_example_menu_5.py diff --git a/demos/keypad_encoder/lv_demo_keypad_encoder.py b/demos/keypad_encoder/lv_demo_keypad_encoder.py new file mode 100644 index 0000000000..2070ac9776 --- /dev/null +++ b/demos/keypad_encoder/lv_demo_keypad_encoder.py @@ -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() diff --git a/examples/assets/emoji/F617.png b/examples/assets/emoji/F617.png new file mode 100644 index 0000000000000000000000000000000000000000..2013382daf4759575a68eda24a4651633495004d GIT binary patch literal 4460 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 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() diff --git a/examples/others/msg/lv_example_msg_2.py b/examples/others/msg/lv_example_msg_2.py new file mode 100644 index 0000000000..d16b053497 --- /dev/null +++ b/examples/others/msg/lv_example_msg_2.py @@ -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) + diff --git a/examples/others/msg/lv_example_msg_3.py b/examples/others/msg/lv_example_msg_3.py new file mode 100644 index 0000000000..444d49633c --- /dev/null +++ b/examples/others/msg/lv_example_msg_3.py @@ -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() + diff --git a/examples/widgets/chart/lv_example_chart_4.py b/examples/widgets/chart/lv_example_chart_4.py index f1a759f476..fbace6b291 100644 --- a/examples/widgets/chart/lv_example_chart_4.py +++ b/examples/widgets/chart/lv_example_chart_4.py @@ -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)) diff --git a/examples/widgets/checkbox/lv_example_checkbox_2.py b/examples/widgets/checkbox/lv_example_checkbox_2.py new file mode 100644 index 0000000000..9901ad274c --- /dev/null +++ b/examples/widgets/checkbox/lv_example_checkbox_2.py @@ -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() diff --git a/examples/widgets/keyboard/lv_example_keyboard_2.py b/examples/widgets/keyboard/lv_example_keyboard_2.py new file mode 100644 index 0000000000..1bcac0d055 --- /dev/null +++ b/examples/widgets/keyboard/lv_example_keyboard_2.py @@ -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) + diff --git a/examples/widgets/menu/lv_example_menu_5.py b/examples/widgets/menu/lv_example_menu_5.py new file mode 100644 index 0000000000..3a180a9b75 --- /dev/null +++ b/examples/widgets/menu/lv_example_menu_5.py @@ -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) + + + +