diff --git a/.github/workflows/build_micropython.yml b/.github/workflows/build_micropython.yml index 7a861490f..9fc157756 100644 --- a/.github/workflows/build_micropython.yml +++ b/.github/workflows/build_micropython.yml @@ -66,10 +66,19 @@ jobs: # Unix port - name: Build Unix port if: matrix.port == 'unix' - run: make -j $(nproc) -C ports/unix DEBUG=1 + run: make -j $(nproc) -C ports/unix DEBUG=1 LV_CFLAGS="-DMICROPY_LV_USE_LOG=0" + - name: Install requirements for the test + run: | + python3 -m pip install pillow + mkdir lib/lv_bindings/lvgl/tests/micropy_test/artifacts - name: Run tests if: success() && matrix.port == 'unix' run: | export XDG_RUNTIME_DIR=/tmp - lib/lv_bindings/tests/run.sh + python3 lib/lv_bindings/lvgl/tests/micropy_test/__init__.py --artifact-path=lib/lv_bindings/lvgl/tests/micropy_test/artifacts --mpy-path=ports/unix/build-standard/micropython + - name: Upload Artifacts + uses: actions/upload-artifact@v3 + with: + name: test-artifacts + path: lib/lv_bindings/lvgl/tests/micropy_test/artifacts diff --git a/src/libs/bin_decoder/lv_bin_decoder.c b/src/libs/bin_decoder/lv_bin_decoder.c index 7610fc259..f2db7ff42 100644 --- a/src/libs/bin_decoder/lv_bin_decoder.c +++ b/src/libs/bin_decoder/lv_bin_decoder.c @@ -956,10 +956,9 @@ static lv_result_t decompress_image(lv_image_decoder_dsc_t * dsc, const lv_image } uint8_t * img_data; + uint32_t out_len = compressed->decompressed_size; uint32_t input_len = compressed->compressed_size; LV_UNUSED(input_len); - uint32_t out_len = compressed->decompressed_size; - lv_draw_buf_t * decompressed = lv_draw_buf_create(dsc->header.w, dsc->header.h, dsc->header.cf, dsc->header.stride); if(decompressed == NULL) { diff --git a/tests/micropy_test/__init__.py b/tests/micropy_test/__init__.py new file mode 100644 index 000000000..ef5b6b35c --- /dev/null +++ b/tests/micropy_test/__init__.py @@ -0,0 +1,370 @@ +""" +The test script will only run the one test on microptyhon. It is not a +framework that can be used for other tests. This has a reduced code footprint. +entrypoint API is almost the same as the framework. + + +Requirements +Python >= 3.10 + +pillow library + +add the following to the CI prior to the test running + +python3 -m pip install pillow + +Example command line to run the test. I suggest doing this from the root of the +binding directory. It is just a simple location to do it from. + +Paths that are passed in MUST be relitive to the current working directory. +python3 lib/lv_bindings/lvgl/tests/micropy_test/__init__.py --artifact-path=lib/lv_bindings/lvgl/tests/micropy_test/artifacts --mpy-path=ports/unix/build-standard/micropython + +""" +import os +import time +import signal +import argparse +import binascii +import unittest +import threading +import subprocess + +from PIL import Image as Image + + +DEBUG = 0 + +debug_log = None + + +def log(*args): + args = ' '.join(repr(arg) for arg in args) + debug_log.write(args + '\n') + + if DEBUG: + sys.stdout.write('\033[31;1m' + args + '\033[0m\n') + sys.stdout.flush() + + +BASE_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__))) +TEST_PATH = os.path.join(BASE_PATH, 'micropy.py') +IMG_PATH = os.path.join(BASE_PATH, '../ref_imgs/binding.png') + +CTRL_C = b'\x03' # 2 times to exit any running code +CTRL_D = b'\x04' # exit paste mode committing and running what has been pasted +CTRL_E = b'\x05' # enter paste mode + +PASTE_PROMPT = b'===' +REPL_PROMPT = b'>>>' + +os.environ['MICROPYINSPECT'] = '1' + + +class TestData: + + def __init__(self): + self.watchdog_timer = time.time() + self.result = None + self.error_data = '' + self.event = threading.Event() + + +class MicroPython_Test(unittest.TestCase): + # these are here simply to make an IDE happy. Their values get dynamically + # set when the class gets constructed + process: subprocess.Popen = None + exit_event: threading.Event = None + + @classmethod + def send(cls, cmd): + if cls.process is None: + return + + log('<---', cmd) + cls.process.stdin.write(cmd) + cls.process.stdin.flush() + + @classmethod + def read_until(cls, marker): + micropy_data = b'' + error_data = b'' + + log('MARKER', marker) + + logged = False + + while ( + not micropy_data.endswith(marker) and + not cls.exit_event.is_set() + ): + try: + char = cls.process.stdout.read(1) + except: # NOQA + break + + if char: + micropy_data += char + logged = False + else: + logged = True + log('--->', micropy_data) + + if micropy_data.endswith(b'\nERROR END\n'): + error_data = micropy_data.split(b'\nERROR START\n')[-1].split(b'\nERROR END\n')[0] + micropy_data = b'' + log('---> ERROR: ', error_data) + logged = True + break + + if not logged: + log('--->', micropy_data) + + if cls.exit_event.is_set(): + log('--EXIT EVENT SET') + + if micropy_data: + return micropy_data.replace(marker, b''), error_data + + return micropy_data, error_data + + @classmethod + def setUpClass(cls): + os.chdir(os.path.dirname(__file__)) + cls.exit_event = threading.Event() + + log(f'--SETTING UP') + cls.process = subprocess.Popen( + ['bash'], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + stdin=subprocess.PIPE, + env=os.environ, + shell=True, + preexec_fn=os.setsid + ) + log(f'--RUNNING MICROPYTHON ({MICROPYTHON_PATH})') + + cls.send(b'cd ' + os.path.dirname(__file__).encode('utf-8') + b'\n') + cls.send(MICROPYTHON_PATH.encode('utf-8') + b'\n') + _, error_data = cls.read_until(b'>>>') + + if error_data: + raise RuntimeError(error_data) + + log('--MICROPYTHON STARTED') + + @classmethod + def tearDownClass(cls): + log('--TEARDOWN STARTED') + + if cls.process is not None: + cls.send(CTRL_C) + cls.send(CTRL_C) + cls.send(CTRL_D) + + if not cls.process.stdin.closed: + cls.process.stdin.close() + + os.killpg(os.getpgid(cls.process.pid), signal.SIGTERM) + + cls.process.wait() + + if not cls.process.stdout.closed: + cls.process.stdout.close() + + if not cls.process.stderr.closed: + cls.process.stderr.close() + + cls.process = None + + log(f'--TEARDOWN FINISHED') + + def test_1_image_compare(self): + image = Image.open(IMG_PATH) + res_img = image.convert('RGB') + image.close() + res_data = list(res_img.getdata()) + res_img.close() + + with open(TEST_PATH, 'rb') as f: + test_code = f.read() + + log(f'--RUNNING TEST ({TEST_PATH})') + + test_code = test_code.strip() + + if self.__class__.process is None: + self.fail('MicroPython failure.') + + self.send(CTRL_E) + + _, error_data = self.read_until(PASTE_PROMPT) + if error_data: + self.fail(error_data) + + test_code = test_code.split(b'\r\n') + + for i, line in enumerate(test_code): + self.send(line + b'\n') + _, error_data = self.read_until(b'\n') + + if error_data: + self.fail(error_data) + + time.sleep(0.002) + + # self.read_until(b'# end\n') + + def _do(td: TestData): + self.send(CTRL_D) + td.error_data = b'' + td.watchdog_timer = time.time() + + td.result = [] + + try: + _, td.error_data = self.read_until(b'FRAME START\n') + td.watchdog_timer = time.time() + + lne, td.error_data = self.read_until(b'\n') + + while ( + b'FRAME END' not in lne and + not td.error_data and + not self.__class__.exit_event.is_set() + ): + td.watchdog_timer = time.time() + td.result.append(lne) + lne, td.error_data = self.read_until(b'\n') + + if td.error_data: + return + + if self.__class__.exit_event.is_set(): + return + + except: # NOQA + import traceback + + traceback.print_exc() + + td.error_data = traceback.format_exc() + return + + td.event.set() + + test_data = TestData() + + t = threading.Thread( + target=_do, + args=(test_data,) + ) + t.daemon = True + test_data.watchdog_timer = time.time() + + t.start() + + while ( + (time.time() - test_data.watchdog_timer) * 1000 <= 20000 and + not test_data.event.is_set() + ): + test_data.event.wait(0.05) + + if not test_data.event.is_set(): + self.__class__.exit_event.set() + # self.read_until(REPL_PROMPT) + + self.send(CTRL_C) + self.send(CTRL_C) + + width = 800 + height = 480 + + if test_data.error_data: + self.fail(test_data.error_data) + + try: + frame = bytearray( + b''.join(binascii.unhexlify(lne) for lne in test_data.result) + ) + + # I don't exactly know why the byte order is backwards but it is + frame = bytes(bytearray([ + item for j in range(0, len(frame), 3) + for item in [frame[j + 2], frame[j + 1], frame[j]] + ])) + + image = Image.new('RGB', (width, height)) + image.frombytes(frame) + img = image.convert('RGB') + image.close() + + byte_data = list(img.getdata()) + img.save(os.path.join(ARTIFACT_PATH, f'frame.png'), 'PNG') + img.close() + + with open(os.path.join(ARTIFACT_PATH, f'frame.bin'), 'wb') as f: + # have to flatten the data and remove the alpha + # from the PIL image it is formatted as + # [(r, g, b), (r, g, b)] + f.write(bytes(bytearray([ + item for sublist in byte_data + for item in sublist + ]))) + + except: # NOQA + import traceback + + self.fail(traceback.format_exc()) + + self.assertEqual(res_data, byte_data, 'Frames do not match') + + +cwd = os.path.abspath(os.getcwd()) + +ARTIFACT_PATH = os.path.join(cwd, 'artifacts') +MICROPYTHON_PATH = os.path.join(cwd, 'micropython') + + +if __name__ == '__main__': + import sys + + arg_parser = argparse.ArgumentParser() + arg_parser.add_argument( + '--artifact-path', + dest='artifact_path', + help='path to save artifacts to', + action='store' + ) + arg_parser.add_argument( + '--mpy-path', + dest='mpy_path', + help='path to micropython', + action='store' + ) + arg_parser.add_argument( + '--debug', + dest='debug', + help='debug output', + action='store_true' + ) + + args = arg_parser.parse_args() + + ARTIFACT_PATH = os.path.join(cwd, args.artifact_path) + MICROPYTHON_PATH = os.path.join(cwd, args.mpy_path) + DEBUG = args.debug + + if not os.path.exists(ARTIFACT_PATH): + raise RuntimeError(f'Artifact path does not exist ({ARTIFACT_PATH})') + + if not os.path.exists(MICROPYTHON_PATH): + raise RuntimeError(f'MicroPython binary not found ({MICROPYTHON_PATH})') + + debug_log_path = os.path.join(ARTIFACT_PATH, 'debug.log') + debug_log = open(debug_log_path, 'w') + + unittest.main(argv=[sys.argv[0], '-v']) + + debug_log.close() + print(f'View the debug output in "{debug_log_path}"') diff --git a/tests/micropy_test/font_montserrat_24.ttf b/tests/micropy_test/font_montserrat_24.ttf new file mode 100644 index 000000000..f4a266dd3 Binary files /dev/null and b/tests/micropy_test/font_montserrat_24.ttf differ diff --git a/tests/micropy_test/image_compare.png b/tests/micropy_test/image_compare.png new file mode 100644 index 000000000..0415210d9 Binary files /dev/null and b/tests/micropy_test/image_compare.png differ diff --git a/tests/micropy_test/micropy.py b/tests/micropy_test/micropy.py new file mode 100644 index 000000000..5f7b9799f --- /dev/null +++ b/tests/micropy_test/micropy.py @@ -0,0 +1,432 @@ +import io + +import lvgl as lv +import ubinascii +import fs_driver +import sys + + +if not lv.is_initialized(): + lv.init() + +try: + lv.log_register_print_cb # NOQA + + raise RuntimeError('Logging in LVGL MUST be disabled to run the tests.') +except AttributeError: + pass +except RuntimeError as exc: + buf = io.StringIO() + sys.print_exception(exc, buf) + + print('ERROR START') + print(buf.getvalue()) + print('ERROR END') + raise + +fs_drv = lv.fs_drv_t() +fs_driver.fs_register(fs_drv, 'A') + +WIDTH = 800 +HEIGHT = 480 + + +def test_func_wrapper(func): + def _wrapper(*args, **kwargs): + try: + return func(*args, **kwargs) + except Exception as exc: + buf = io.StringIO() + sys.print_exception(exc, buf) + + print('ERROR START') + print(buf.getvalue()) + print('ERROR END') + + return _wrapper + + +CAPTURE_FRAME = False + + +@test_func_wrapper +def flush(disp, area, color_p): + + x1 = area.x1 + x2 = area.x2 + y1 = area.y1 + y2 = area.y2 + + size = (x2 - x1 + 1) * (y2 - y1 + 1) * lv.color_format_get_size( + disp.get_color_format() + ) + data_view = color_p.__dereference__(size) + byte_count = 0 + + print('FRAME START') + sys.stdout.flush() + + while byte_count != size: + chunk_size = min(size - byte_count, 512) + chunk = data_view[byte_count:chunk_size + byte_count] + byte_count += chunk_size + print(ubinascii.hexlify(bytes(chunk)).decode('utf-8')) + sys.stdout.flush() + + print('FRAME END') + sys.stdout.flush() + + disp.flush_ready() + + +disp_drv = lv.display_create(WIDTH, HEIGHT) +disp_drv.set_flush_cb(flush) +disp_drv.set_color_format(lv.COLOR_FORMAT.RGB888) + +color_size = lv.color_format_get_size(disp_drv.get_color_format()) + +buf = bytearray(WIDTH * HEIGHT * color_size) +disp_drv.set_draw_buffers( + buf, + None, + WIDTH * HEIGHT * color_size, + lv.DISPLAY_RENDER_MODE.FULL + ) + + +@test_func_wrapper +def GRID_FR(x): + return lv.COORD.MAX - 100 + x + + +@test_func_wrapper +def CANVAS_BUF_SIZE(w, h, bpp, stride): + return ((((w * bpp + 7) >> 3) + stride - 1) & ~( + stride - 1)) * h + lv.DRAW_BUF_ALIGN + + +@test_func_wrapper +def create_ui(): + # Create a colors + c1 = lv.color_hex(0xff0000) + c2 = lv.palette_darken(lv.PALETTE.BLUE, 2) + c3 = c1.mix(c2, lv.OPA._60) + + # Create a style + style_big_font = lv.style_t() + style_big_font.init() + + # Try to load as built in font and if not load it using tiny TTF + try: + font_montserrat_24 = lv.font_montserrat_24 + except AttributeError: + font_montserrat_24 = lv.font_t() + lv.tiny_ttf_create_file(font_montserrat_24, 'A:font_montserrat_24.ttf', 32) + + style_big_font.set_text_font(font_montserrat_24) + + # Get the active screen + scr = lv.screen_active() + + # Declare static array of integers, and test grid setting options + gird_cols = [300, GRID_FR(3), GRID_FR(2), lv.GRID_TEMPLATE_LAST] + gird_rows = [100, GRID_FR(1), lv.GRID_CONTENT, lv.GRID_TEMPLATE_LAST] + scr.set_grid_dsc_array(gird_cols, gird_rows) + + chart_type_subject = lv.subject_t() + chart_type_subject.init_int(0) + + # Create a widget + dropdown = lv.dropdown(scr) + + # Pass a string as argument + dropdown.set_options("Lines\nBars") + + # Use grid align options + dropdown.set_grid_cell( + lv.GRID_ALIGN.CENTER, + 0, + 1, + lv.GRID_ALIGN.CENTER, + 0, + 1 + ) + + # Bind to a subject + dropdown.bind_value(chart_type_subject) + + # Create a chart with an external array of points + chart = lv.chart(lv.screen_active()) + chart.set_grid_cell(lv.GRID_ALIGN.STRETCH, 0, 1, lv.GRID_ALIGN.CENTER, 1, 1) + + series = chart.add_series(c3, lv.chart.AXIS.PRIMARY_X) + + chart_y_array = [10, 25, 50, 40, 30, 35, 60, 65, 70, 75] + + chart.set_ext_y_array(series, chart_y_array) + + # Add custom observer callback + chart_type_subject.add_observer_obj( + lambda _, __: chart_type_observer_cb(chart, chart_type_subject), + chart, + None + ) + + # Manually set the subject's value + chart_type_subject.set_int(1) + + label = lv.label(scr) + label.set_grid_cell(lv.GRID_ALIGN.START, 1, 1, lv.GRID_ALIGN.CENTER, 0, 1) + + # Apply styles on main part and default state + label.set_style_bg_opa(lv.OPA._70, 0) + label.set_style_bg_color(c1, 0) + label.set_style_text_color(c2, 0) + label.add_style(style_big_font, 0) + + # Declare an array of strings + btnmatrix_options = ["First", "Second", "\n", "Third", ""] + + btnmatrix_ctrl = [lv.buttonmatrix.CTRL.DISABLED, + 2 | lv.buttonmatrix.CTRL.CHECKED, 1] + + btnmatrix = lv.buttonmatrix(scr) + btnmatrix.set_grid_cell( + lv.GRID_ALIGN.STRETCH, + 1, + 1, + lv.GRID_ALIGN.STRETCH, + 1, + 1 + ) + # Pass string and enum arrays + btnmatrix.set_map(btnmatrix_options) + btnmatrix.set_ctrl_map(btnmatrix_ctrl) + # Add style to non main part and non default state + btnmatrix.add_style(style_big_font, lv.PART.ITEMS | lv.STATE.CHECKED) + + btnmatrix.set_selected_button(1) + btnmatrix.add_event_cb( + lambda _: buttonmatrix_event_cb(btnmatrix, label), + lv.EVENT.VALUE_CHANGED, + None + ) + btnmatrix.send_event(lv.EVENT.VALUE_CHANGED, None) + + # Create a base object + cont = lv.obj(scr) + # Span 2 rows + cont.set_grid_cell(lv.GRID_ALIGN.STRETCH, 2, 1, lv.GRID_ALIGN.STRETCH, 0, 2) + + # Apply flex layout + cont.set_flex_flow(lv.FLEX_FLOW.COLUMN) + + btn1 = list_button_create(cont) + btn2 = list_button_create(cont) + btn3 = list_button_create(cont) + btn4 = list_button_create(cont) + btn5 = list_button_create(cont) + btn6 = list_button_create(cont) + btn7 = list_button_create(cont) + btn8 = list_button_create(cont) + btn9 = list_button_create(cont) + btn10 = list_button_create(cont) + + a = lv.anim_t() + a.init() + a.set_var(btn1) + a.set_values(lv.OPA.COVER, lv.OPA._50) + a.set_custom_exec_cb(lambda _, v: opa_anim_cb(btn1, v)) # Pass a callback + a.set_time(300) + a.set_path_cb(lv.anim_t.path_ease_out) + a.start() + + btn2.add_flag(lv.obj.FLAG.HIDDEN) + + btn_label = btn3.get_child(0) + btn_label.set_text("A multi-line text with a ° symbol") + btn_label.set_width(lv.pct(100)) + + a = lv.anim_t() + a.init() + a.set_var(btn4) + a.set_values(lv.OPA.COVER, lv.OPA._50) + a.set_custom_exec_cb(lambda _, v: opa_anim_cb(btn4, v)) # Pass a callback + a.set_path_cb(lv.anim_t.path_ease_out) + a.set_time(300) + a.set_repeat_count(lv.ANIM_REPEAT_INFINITE) + a.start() + + # Wait and delete the button with the animation + + cont.get_child(3).delete() + # Large byte array + + canvas_buf = bytearray(CANVAS_BUF_SIZE(400, 100, 16, 1)) + + canvas = lv.canvas(scr) + canvas.set_grid_cell(lv.GRID_ALIGN.START, 0, 2, lv.GRID_ALIGN.START, 2, 1) + # Test RGB565 rendering + canvas.set_buffer( + lv.draw_buf_align(canvas_buf, lv.COLOR_FORMAT.RGB565), + 400, + 100, + lv.COLOR_FORMAT.RGB565 + ) + canvas.fill_bg(c2, lv.OPA.COVER) + draw_to_canvas(canvas) + + test_img_lvgl_logo_jpg_data = ( + b'\xFF\xD8\xFF\xE0\x00\x10\x4A\x46\x49\x46\x00\x01\x01\x01\x01\x2C\x01\x2C\x00\x00\xFF\xFE\x00\x13\x43\x72\x65\x61\x74\x65\x64\x20\x77\x69\x74\x68\x20\x47\x49\x4D\x50\xFF\xDB\x00\x43\x00\x08\x06\x06\x07\x06\x05\x08\x07\x07\x07\x09\x09\x08\x0A\x0C\x15\x0E\x0C\x0B\x0B\x0C\x19\x12\x13\x0F\x15\x1E\x1B\x20\x1F\x1E\x1B\x1D\x1D\x21\x25\x30\x29\x21\x23\x2D\x24\x1D\x1D\x2A\x39\x2A\x2D\x31\x33\x36\x36\x36\x20\x28\x3B\x3F\x3A\x34\x3E\x30\x35\x36\x33\xFF\xDB\x00\x43\x01\x09\x09\x09\x0C\x0B\x0C\x18\x0E\x0E\x18\x33\x22\x1D\x22\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33' + b'\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33\xFF\xC0\x00\x11\x08\x00\x21\x00\x69\x03\x01\x11\x00\x02\x11\x01\x03\x11\x01\xFF\xC4\x00\x1F\x00\x00\x01\x05\x01\x01\x01\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\xFF\xC4\x00\xB5\x10\x00\x02\x01\x03\x03\x02\x04\x03\x05\x05\x04\x04\x00\x00\x01\x7D\x01\x02\x03\x00\x04\x11\x05\x12\x21\x31\x41\x06\x13\x51\x61\x07\x22\x71\x14\x32\x81\x91\xA1\x08\x23\x42\xB1\xC1\x15\x52\xD1\xF0\x24\x33\x62\x72\x82\x09\x0A\x16\x17\x18\x19\x1A\x25\x26\x27\x28\x29\x2A\x34\x35\x36\x37\x38\x39\x3A\x43\x44\x45\x46\x47\x48\x49\x4A\x53\x54\x55' + b'\x56\x57\x58\x59\x5A\x63\x64\x65\x66\x67\x68\x69\x6A\x73\x74\x75\x76\x77\x78\x79\x7A\x83\x84\x85\x86\x87\x88\x89\x8A\x92\x93\x94\x95\x96\x97\x98\x99\x9A\xA2\xA3\xA4\xA5\xA6\xA7\xA8\xA9\xAA\xB2\xB3\xB4\xB5\xB6\xB7\xB8\xB9\xBA\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xD2\xD3\xD4\xD5\xD6\xD7\xD8\xD9\xDA\xE1\xE2\xE3\xE4\xE5\xE6\xE7\xE8\xE9\xEA\xF1\xF2\xF3\xF4\xF5\xF6\xF7\xF8\xF9\xFA\xFF\xC4\x00\x1F\x01\x00\x03\x01\x01\x01\x01\x01\x01\x01\x01\x01\x00\x00\x00\x00\x00\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\xFF\xC4\x00\xB5\x11\x00\x02\x01\x02\x04\x04\x03\x04\x07\x05\x04\x04\x00\x01\x02\x77\x00\x01\x02\x03\x11\x04\x05\x21\x31\x06\x12\x41' + b'\x51\x07\x61\x71\x13\x22\x32\x81\x08\x14\x42\x91\xA1\xB1\xC1\x09\x23\x33\x52\xF0\x15\x62\x72\xD1\x0A\x16\x24\x34\xE1\x25\xF1\x17\x18\x19\x1A\x26\x27\x28\x29\x2A\x35\x36\x37\x38\x39\x3A\x43\x44\x45\x46\x47\x48\x49\x4A\x53\x54\x55\x56\x57\x58\x59\x5A\x63\x64\x65\x66\x67\x68\x69\x6A\x73\x74\x75\x76\x77\x78\x79\x7A\x82\x83\x84\x85\x86\x87\x88\x89\x8A\x92\x93\x94\x95\x96\x97\x98\x99\x9A\xA2\xA3\xA4\xA5\xA6\xA7\xA8\xA9\xAA\xB2\xB3\xB4\xB5\xB6\xB7\xB8\xB9\xBA\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xD2\xD3\xD4\xD5\xD6\xD7\xD8\xD9\xDA\xE2\xE3\xE4\xE5\xE6\xE7\xE8\xE9\xEA\xF2\xF3\xF4\xF5\xF6\xF7\xF8\xF9\xFA\xFF\xDA\x00\x0C\x03\x01\x00\x02\x11\x03' + b'\x11\x00\x3F\x00\x4F\x11\xFC\x6B\xF1\x25\x8F\x89\x35\x2B\x2B\x2B\x7B\x04\xB7\xB6\xB9\x78\x50\x49\x13\x33\x10\xAC\x57\x24\xEE\x1D\x71\x9A\x00\xCB\xFF\x00\x85\xEB\xE2\xEF\xF9\xE7\xA6\xFF\x00\xDF\x86\xFF\x00\xE2\xA9\x88\xD7\xF0\xE7\xC5\x5F\x1B\xF8\x9B\x57\x5D\x36\xD6\x4D\x0E\x09\x59\x19\xC3\xDC\xC6\xC8\xB8\x03\x3D\x77\x1E\x69\x0C\xF5\x4F\x87\xFE\x25\xBB\xF1\x4F\x84\xE3\xD4\x6F\xA3\x85\x2E\x44\xAF\x14\x9E\x47\xDC\x62\xA7\x19\x1C\x9A\x00\xD7\xD0\xB5\xBB\x5F\x11\x69\x11\x6A\x56\x42\x41\x04\x8C\xCA\xA2\x45\xC3\x65\x58\xA9\xE3\xEA\x0D\x00\x26\xB9\xAE\xDA\x78\x7A\xCE\x2B\xBB\xE1\x20\xB7\x79\xD2\x16\x91\x14\x11\x19\x63\x80\xCD\xCF\x0B\x9C\x73' + b'\xEF\x40\x1A\x74\x01\x43\x5A\xD6\x2D\x34\x0D\x22\xE3\x53\xBE\x66\x10\x42\x01\x21\x46\x59\x89\x38\x00\x0E\xE4\x92\x00\x14\x00\xEB\xCD\x56\xCF\x4D\xD3\x0E\xA3\xA8\xCE\xB6\x76\xEA\xA1\x9D\xA7\x21\x76\xE7\xB1\xF7\xF6\x14\x01\xCE\xAF\xC4\x0B\x69\xD7\xCD\xB4\xD0\x7C\x43\x75\x6D\xD4\x5C\x45\xA7\xB6\xC2\x3D\x40\x24\x12\x3E\x82\x80\x36\xB4\x4F\x11\xE9\x7E\x21\x8A\x47\xD3\xEE\x0B\x3C\x27\x6C\xD0\xC8\x86\x39\x62\x3E\x8C\x8D\x82\x28\x01\xE9\xAD\xDA\xC9\xE2\x29\xB4\x35\x12\x7D\xAE\x2B\x65\xB9\x63\xB7\xE5\xD8\x58\xA8\xE7\xD7\x20\xD0\x06\x95\x00\x14\x01\xF3\x87\x88\x6F\x3C\x26\x3C\x49\xAA\x09\xFC\x20\x25\x98\x5D\xCA\x1E\x4F\xED\x29\x57\x7B\x6F\x39' + b'\x38\x1C\x0C\x9E\x71\x5C\x13\xC6\xB8\xC9\xAB\x6C\x7D\x66\x1F\x86\x63\x56\x94\x6A\x7B\x4B\x5D\x27\xB7\x75\xEA\x72\x3E\x3C\xD2\xAC\xB4\x5F\x18\xDE\xD8\xE9\xD1\x34\x56\x88\x23\x68\xE3\x67\x2D\xB7\x74\x6A\xC4\x64\xF2\x79\x26\xBB\xD3\xBA\x3E\x52\x4B\x96\x4D\x1C\xE5\x32\x4F\xA6\x7E\x09\x7F\xC9\x37\x8F\xFE\xBE\x65\xFE\x62\x90\xCD\x4F\x85\x5F\xF2\x4F\x6C\x7F\xEB\xB4\xFF\x00\xFA\x39\xE8\x03\xA4\xD6\xB4\xAB\x7D\x73\x44\xBC\xD2\xEE\x86\x61\xBA\x89\xA3\x6F\x6C\xF4\x23\xDC\x1C\x1F\xC2\x80\x31\xBC\x05\xAA\xDC\x6A\x1E\x1C\x16\x97\xE7\xFE\x26\x7A\x64\x8D\x65\x76\x0F\x52\xE9\xC0\x6F\xF8\x12\xE0\xFE\x34\x01\x4F\x5C\xFF\x00\x8A\x8B\xC7\x3A\x66\x82\xBF' + b'\x35\x9E\x98\x06\xA1\x7D\xE8\x5F\xA4\x28\x7F\x1C\xB6\x3D\x85\x00\x45\x35\xB4\x7E\x27\xF8\x9F\x3D\xB5\xE8\x12\xD8\xE8\x16\xF1\x49\x1D\xBB\x0C\xAB\x5C\x49\x92\x1C\x8E\xFB\x54\x71\xE8\x4D\x00\x77\x34\x01\x02\x2D\xAA\xDE\x4A\xD1\xAC\x22\xE5\x95\x7C\xD2\xB8\xDE\x40\xE9\x9E\xF8\xE4\xE2\x80\x39\x3B\x5F\xF9\x2C\x7A\x87\xFD\x81\x61\xFF\x00\xD1\xAD\x40\x1D\x9D\x00\x14\x01\xF3\xC6\xBD\xFF\x00\x08\x5F\xFC\x24\x5A\x9F\xDA\x06\xBF\xE7\xFD\xAE\x5F\x33\xCB\x30\xED\xDD\xBC\xE7\x19\xE7\x19\xAF\x26\xA7\xB1\xE7\x77\xBF\xE0\x7E\x87\x83\xFE\xD2\xFA\xBD\x3E\x4E\x4B\x59\x5A\xFC\xD7\xB5\x89\xBC\x79\x61\xE0\xC9\xBC\x5D\x73\x26\xA0\x75\xE1\x72\x63\x8B\x7F\xD9' + b'\xCC\x3B\x31\xE5\xAE\x31\xBB\x9E\x98\xCF\xBD\x76\x4F\x15\x0A\x6F\x95\xA3\xE6\xB0\xD9\x0E\x23\x17\x4F\xDB\x46\x49\x27\x7E\xFD\xFD\x0E\x1B\xC6\x7A\x06\x9D\xA1\x5D\x69\xAD\xA5\xCD\x75\x25\xA5\xF5\x92\xDC\xA8\xBA\xDB\xBD\x72\xCC\x30\x76\xF1\xFC\x35\xD3\x09\x29\xC5\x49\x1E\x3E\x26\x84\xB0\xF5\x65\x4A\x5B\xA7\x63\xDC\xFE\x09\x7F\xC9\x37\x8F\xFE\xBE\x65\xFE\x62\x99\x89\xA1\xF0\xB2\x68\x93\xE1\xFD\x92\xB4\xA8\x0F\x9D\x3F\x05\x87\xFC\xF6\x7A\x00\xED\x16\x68\x9D\xB6\xAC\x88\xC7\xD0\x30\x34\x01\xC2\x6B\x97\x90\x78\x27\xC7\x2B\xAE\x5C\x37\x95\xA4\xEB\x10\x18\x6E\xDB\xB2\x4F\x1A\x96\x46\xFA\xB2\x82\xBF\x80\xA0\x0D\x3F\x00\xD9\x4E\x34\x79\xB5\xBB' + b'\xF4\x2B\xA8\x6B\x33\x1B\xB9\x41\xEA\x88\x78\x8D\x3F\xE0\x29\x8F\xCC\xD0\x05\x1D\x66\x56\xF0\x87\x8D\x9B\xC4\x73\x46\xCD\xA3\x6A\x50\x25\xBD\xF4\xA8\xA5\x8D\xBC\x88\x4E\xC9\x1B\x1F\xC2\x41\x20\x9E\xD4\x01\xD8\x5B\x6A\x36\x37\x96\xCB\x73\x6D\x79\x04\xD0\x30\xC8\x92\x39\x03\x29\x1F\x51\x40\x1C\x96\x83\x79\x6D\xA8\x7C\x4D\xF1\x0D\xC5\x9C\xF1\xDC\x40\x96\x56\xD1\x34\x91\x36\xE5\x0E\x0B\xE5\x72\x38\xC8\xC8\xE2\x80\x16\x09\x12\x3F\x8C\x5A\x81\x77\x55\x1F\xD8\xB0\xF5\x38\xFF\x00\x96\xAD\x40\x1D\x8F\xDA\x20\xFF\x00\x9E\xD1\xFF\x00\xDF\x42\x80\x1D\xBD\x3F\xBE\xBF\x9D\x00\x79\x46\xA9\xF0\x6A\x6D\x47\x56\xBC\xBD\x1A\xDA\x20\xB8\x9D\xE5\x08\x6D' + b'\x89\xDB\xB9\x89\xC6\x77\x7B\xD7\x04\xF0\x5C\xD2\x6F\x98\xFA\xCC\x3F\x13\x46\x95\x28\xD3\xF6\x57\xB2\x4B\x7E\xCB\xD0\xB7\xE2\x3F\x84\xD2\xEB\xDA\xDC\xBA\x82\xEB\x09\x08\x91\x11\x76\x1B\x72\xD8\xDA\x81\x7A\xEE\xF6\xAA\xAB\x84\xE7\x97\x35\xCC\x70\x3C\x42\xB0\xB4\x15\x2F\x67\x7B\x5F\xAF\x77\x7E\xC5\x4F\x12\x7C\x1A\x97\x5E\x8F\x49\x55\xD6\xD2\x13\x61\x64\xB6\xA4\x9B\x62\xDB\xF0\xCC\x77\x7D\xEE\x3E\xF7\x4A\xEA\xA7\x1E\x48\xA8\xF6\x3C\x1C\x5D\x7F\xAC\x57\x9D\x5B\x5B\x99\xDC\xEE\x3C\x15\xE1\x64\xF0\x7F\x86\x61\xD2\x16\xE4\xDC\x95\x66\x77\x94\xAE\xDD\xC5\x8F\x61\x93\x81\x56\x73\x91\x37\xC3\xCF\x08\x33\x16\x6F\x0F\x58\x12\x4E\x49\x31\x75\xA0' + b'\x0B\x7A\x6F\x83\xFC\x3B\xA3\xDE\xAD\xE6\x9D\xA3\xDA\x5A\xDC\xA8\x20\x49\x12\x60\x80\x7A\xD0\x05\xFD\x4F\x4A\xB0\xD6\x6C\xCD\xA6\xA5\x69\x15\xD5\xB9\x60\xC6\x39\x57\x23\x23\xA1\xA0\x0B\x6A\xA1\x54\x2A\x80\x00\x18\x00\x76\xA0\x01\x95\x5D\x4A\xB2\x86\x52\x30\x41\x19\x06\x80\x39\xB9\xBE\x1E\xF8\x42\x79\xCC\xD2\x78\x7A\xC3\x79\x39\x38\x88\x00\x4F\xD0\x71\x40\x1B\xB6\x56\x16\x9A\x6D\xAA\xDB\x58\xDA\xC3\x6D\x02\x7D\xD8\xE1\x40\x8A\x3F\x01\x40\x19\xDA\xA7\x84\xBC\x3F\xAD\xDD\x8B\xBD\x4F\x49\xB5\xBB\xB8\x0A\x10\x49\x2A\x64\xED\x1D\x07\xEA\x68\x02\x8F\xFC\x2B\xBF\x07\xFF\x00\xD0\xBB\x61\xFF\x00\x7E\xA8\x03\x73\xFB\x32\xCB\xFE\x7D\xD2\x80\x2D' + b'\xD0\x01\x40\x05\x00\x14\x00\x50\x01\x40\x05\x00\x14\x00\x50\x01\x40\x05\x00\x14\x00\x50\x01\x40\x1F\xFF\xD9' + ) + + test_img_lvgl_logo_jpg = lv.image_dsc_t( + dict( + header=dict(cf=lv.COLOR_FORMAT.RAW_ALPHA, w=105, h=33), + data_size=1947, + data=test_img_lvgl_logo_jpg_data + ) + ) + + img = lv.image(scr) + img.set_src(test_img_lvgl_logo_jpg) + img.align(lv.ALIGN.BOTTOM_RIGHT, -20, -20) + img.add_flag(lv.obj.FLAG.IGNORE_LAYOUT) + + img = lv.image(scr) + img.set_src("A:test_img_lvgl_logo.png") + img.set_pos(500, 420) + img.add_flag(lv.obj.FLAG.IGNORE_LAYOUT) + img.set_rotation(200) + img.set_scale_x(400) + + +@test_func_wrapper +def chart_type_observer_cb(chart, subject): + v = subject.get_int() + # chart = observer.get_target() + chart.set_type(lv.chart.TYPE.LINE if v == 0 else lv.chart.TYPE.BAR) + + +@test_func_wrapper +def buttonmatrix_event_cb(buttonmatrix, label): + # label = e.get_user_data() + # buttonmatrix = e.get_target() + idx = buttonmatrix.get_selected_button() + text = buttonmatrix.get_button_text(idx) + label.set_text(text) + + +@test_func_wrapper +def list_button_create(parent): + btn = lv.button(parent) + btn.set_size(lv.pct(100), lv.SIZE_CONTENT) + + # Get an integer + idx = btn.get_index() + + # Formatted string for label + label = lv.label(btn) + label.set_text(lv.SYMBOL.FILE + " Item %d" % idx) + + return btn + + +@test_func_wrapper +def opa_anim_cb(button, value): + try: + button.set_style_opa(value, 0) + except: # NOQA + pass + + +@test_func_wrapper +def draw_to_canvas(canvas): + layer = lv.layer_t() + canvas.init_layer(layer) + + # Use draw descriptors + + test_img_lvgl_logo_png_data = ( + b'\x89\x50\x4E\x47\x0D\x0A\x1A\x0A\x00\x00\x00\x0D\x49\x48\x44\x52\x00\x00\x00\x69\x00\x00\x00\x21\x08\x06\x00\x00\x00\xDA\x89\x85\x3B\x00\x00\x00\x06\x62\x4B\x47\x44\x00\x00\x00\x00\x00\x00\xF9\x43\xBB\x7F\x00\x00\x00\x09\x70\x48\x59\x73\x00\x00\x2E\x23\x00\x00\x2E\x23\x01\x78\xA5\x3F\x76\x00\x00\x00\x07\x74\x49\x4D\x45\x07\xE7\x09\x12\x12\x25\x07\x59\xA0\x4E\xA5\x00\x00\x00\x19\x74\x45\x58\x74\x43\x6F\x6D\x6D\x65\x6E\x74\x00\x43\x72\x65\x61\x74\x65\x64\x20\x77\x69\x74\x68\x20\x47\x49\x4D\x50\x57\x81\x0E\x17\x00\x00\x06\xB9\x49\x44\x41\x54\x68\xDE\xED\x9A\x7F\x8C\x5D\x45\x15\xC7\x3F\xE7\xBE\xF7\x76\xA9\x20\x18\x03\x9A\x6A\x77\xE6\xDD' + b'\xB7\x6B\x8A\x49\xC3\x1A\xB5\x25\x80\xB5\xE2\x6A\x2B\x0D\x46\x71\x89\x8A\xBF\x48\x4C\xD5\xD4\x46\x08\x58\x48\x10\xC5\xE8\x3F\xA6\x68\x6B\xE4\x0F\x85\x22\x68\x53\x6D\x9A\x40\x31\x40\xC0\x92\xB6\xD0\x62\x53\x4A\xAC\x44\xA2\xAD\xA4\x76\xF7\xDE\xB9\xAF\x3F\x0C\x0A\xD2\x96\x6D\xD9\xDD\xB7\xF7\xF8\xC7\x9B\xCA\x76\xF7\xFD\x5C\x77\xDD\xD7\xE4\x7D\x93\x97\x97\xB9\x33\x77\x66\xCE\xF9\xCE\x39\x73\xE6\xCC\x85\x36\xDA\x68\xE3\x7F\x87\x00\x98\x7C\xBE\x13\x95\xE5\x40\x0F\x5A\x7E\x36\x8D\x23\x0C\xA1\x6C\x4D\x92\x68\xA0\xAD\xEE\x29\xAA\xD0\x5A\x13\x28\x99\xCD\xC0\xF5\x67\x48\x9B\x01\x9C\x00\x96\x26\x2E\x7A\xBE\xAD\xF2\xE6\x91\x85\xCC\x42\xA0\x7F\x06' + b'\x08\x2A\x01\x81\xFF\x5D\x08\xDC\x02\x7C\x7E\x7C\x83\xAE\xAE\x82\x48\xA0\x9D\x80\x04\xA2\xC3\x71\x1C\xA7\xF5\x3A\x35\xB6\x90\x45\x35\x07\x68\x92\x44\x6F\x4C\x75\x72\xF3\xC2\x30\x08\x52\x3A\x01\x4D\x5C\xFD\x7E\xAC\x0D\x73\xAA\xBC\x05\xD1\x9C\x57\xD5\x88\xA2\xA7\x8B\x2E\x1E\x6D\x64\x3C\x6B\x0B\x19\x55\xED\x40\x34\x4D\x5C\x3C\xDC\xCC\x5C\x03\x85\x8B\xBD\x22\xA7\x13\x03\xC0\xE5\xC0\xA7\x80\xD3\xFE\xD9\x3B\x27\x99\xB1\xF0\x56\xE0\x79\xE0\x40\xAA\xD2\xDB\x58\xD7\xDA\x8B\xB0\x1F\xE1\xAF\xC6\x86\xF3\xA7\xEC\x42\x52\xBE\x08\xBC\x04\x3C\x62\xF2\x85\x6C\x45\x22\x4D\x3E\x6B\x6C\xF8\x31\x63\xC3\x5F\x2B\xBC\x88\x30\x08\x52\x04\x8A\xC0\xA0\x20\x7F' + b'\x36\x36\x7C\xC0\xD8\x70\x89\xC9\x87\x99\x9A\xB3\x46\xAF\x43\x78\x09\xE4\x31\x63\xC3\x6C\x53\x24\xCD\x90\x85\x3E\x9B\xB8\xE8\x05\xA1\xF4\x24\x70\xAC\xCE\xF8\xEF\x06\x8C\x22\xB9\x86\x28\x4A\xF5\x45\xE0\x35\xA0\x1B\x58\x31\x95\xC9\x19\x53\xC8\x08\x7C\x0B\x30\xC0\x13\x49\x3C\x58\x9A\x68\xE1\xC6\x86\x57\x07\x22\x7B\x80\x6D\xC0\x8D\xC0\x7C\x20\x07\xFC\xC3\xCB\x94\xF5\xCF\xBE\x0A\xEC\x44\x79\xDA\xD8\xB0\xD6\x42\x9B\xE3\xC7\x9B\xAB\xA2\xB4\x02\x49\xFD\xC6\x86\xB7\x2B\xD9\xB5\x80\x9D\xCE\x8E\x8B\xC5\xB8\x04\xFC\xD8\x17\x57\xD8\x7C\x78\x49\xB3\x7D\xA8\x68\x1F\xB0\x10\x38\x26\xE8\x86\xB3\x09\xCC\x8B\x04\x7A\x07\xF0\xD4\x99\x36\xC0\xF7\x80\x45' + b'\x88\xBE\x23\x71\x51\x98\xB8\xA8\xA0\xA2\x97\x80\xF6\x02\xB7\x01\x09\xF0\x61\xE0\x59\x63\xC3\x65\x33\xB0\x27\xCD\x08\x2E\x04\xD6\xCC\xD8\x4E\xAA\x3C\x86\x10\x03\x79\x55\xBE\x0C\xAC\x6B\xF4\x55\x6B\xC3\x40\xE1\x26\x5F\x7C\xD0\xB9\xF8\xF5\x71\xFB\x94\x90\xF2\x5D\xE0\x87\x80\x02\xBF\x50\xE1\x8E\x62\x1C\x1D\x9F\xB4\x58\xE2\x78\x14\xD8\x0F\xEC\x37\xA6\x70\x1F\xA2\x6B\x80\x65\x40\x34\xDD\xE2\x06\xC0\xCB\x40\xCA\x39\x84\x24\x89\x86\x80\xFB\x7D\x71\xA5\xB5\xB6\xA3\x71\x7E\xB9\xD4\x2B\xF3\x34\x70\xEF\x59\xCA\x48\xE9\x03\xEE\xF2\xC5\xEF\xA8\xE8\xAA\x4A\x04\x4D\x9E\xCF\xE0\x49\x90\x55\x22\xB2\x30\x71\xD1\xC1\x69\xB7\xA4\x4C\x90\xEE\x2B\x8D\x05' + b'\xBD\x12\xC8\xDC\x2A\x62\x65\x51\xBE\x06\x5C\xD7\x4A\x44\xA9\x72\x9F\x08\xAB\x81\x1E\x25\xB8\x1E\xD8\xD4\xE0\xAB\xAB\xBD\x07\xD9\x90\xB8\xE8\xF0\x9B\x51\xA3\xED\x04\xD6\xFA\xBA\x8D\x28\x6B\x8A\x2E\x6E\x78\xF3\x48\xDC\xA0\x02\xAF\xCE\x48\x08\xBE\x35\x72\x73\xB4\x1C\x89\x9D\x57\x79\xE1\xF1\xF8\x52\x1B\xFE\xC0\x47\x6A\x41\xAB\x90\x54\x4C\xA2\x57\x8C\x0D\x37\x03\x2B\x81\x6F\x74\xF7\xBC\x67\xF3\xC0\xA1\xBF\xA7\xB5\xC3\xF7\xF0\x5D\xFE\xB8\x51\x9A\x68\x45\x10\x7C\x04\xB8\x0C\x18\x42\xB9\x33\x49\x22\x6D\x15\x59\xB3\x0A\x4B\x80\x5F\xD6\x68\x93\x57\xD8\x20\x65\xC2\x5A\x0D\x3F\xF5\x11\xDE\xE2\xD1\x91\xD2\x95\xC0\xEE\x3A\xED\xBF\xEE\xF7\xCB\xA7' + b'\x12\x17\xED\x9B\x50\xF7\x05\xFF\xFF\x50\x92\x44\xC5\x56\x12\x32\x68\xC0\x3A\x02\x5A\x15\x2A\x87\x80\x47\x01\x41\xB8\x79\x5E\x97\x91\x1A\x01\xC3\x45\x9E\xA4\x14\xF8\xD9\xF8\xBA\x8B\xBB\x17\x08\xB0\xC8\x17\x9F\x6E\x35\x31\x5B\x97\x80\x86\x02\x88\x41\x05\x7E\xEE\xDD\xF2\xB5\x22\xD9\x7C\x8D\x80\xA1\x1F\x98\x0B\xFC\x2D\x95\x74\xFB\xF8\xBA\xF3\x4B\xA7\x2E\xA0\x7C\xA8\x4F\x81\x43\x6D\x92\xA6\x19\x63\xA3\x23\x3B\x81\xE7\x80\xF3\x44\xF4\x96\x4A\x6D\xBA\x0A\x61\xCE\x07\x0C\x00\x6B\x0F\xC7\xEE\xAC\x54\x4E\x0A\x19\xAF\x0B\x05\x86\xA7\x32\x0F\x63\xC3\x15\xC6\x86\x1B\x8D\x0D\xFB\xDB\x24\x4D\xC0\x91\xA3\x47\xC6\x5B\xD3\x0D\xC6\x16\xDE\x3E\x29\x05' + b'\x34\xC6\x32\x9F\x1D\x38\x2A\x2A\x5B\x26\xD6\x67\x44\x87\x81\x51\xAF\x8F\x8B\xA6\x38\x95\xCB\x81\x2F\xF9\xE0\xA3\x4D\xD2\x24\x12\x08\xB6\x00\xAE\xEC\xB2\xF4\xC6\x0A\x4D\x6E\xF2\xB2\xAE\x77\xC9\xE0\x89\x89\x95\x71\x1C\x9D\xF6\xEF\x0B\xB0\xA0\x15\xDD\x5D\xBD\x2C\xEE\x28\xC2\x49\x60\xA4\x55\x49\x72\x6E\xE0\x8D\x71\xC1\xC0\x2A\x6B\xED\x9C\x71\x6E\x68\x11\xF0\x51\xE0\x84\x0A\xEB\x6B\x74\xF3\x8C\xFF\xFF\x4C\xAB\xC9\x97\x55\x78\x46\xE0\x9A\x2A\xE7\xA4\x14\xF8\x83\xA0\xAF\x81\x5C\xA1\x10\x56\x5E\xC9\x04\x94\xEF\xA3\x6E\x98\xC5\x48\x6F\x13\xA2\xDF\x07\x0A\x4A\x70\x0D\xF0\xC8\x99\x8C\x04\xE5\x3D\x67\x4B\x31\x8E\x8E\xD5\x48\x45\xFC\x06\xE1\x56' + b'\x60\xB1\xB1\xE1\x92\xC4\x45\xBB\x5A\x86\xA4\x71\x7E\x78\x4E\x25\x92\x14\x3A\xB6\xC7\x71\x90\x96\x09\x7A\x5B\x95\x03\xEF\xAE\x3E\xD3\xBD\x2B\x23\x69\x3F\xD0\x31\x1B\x82\x24\xC9\xE0\xCB\xC6\x86\x0F\x00\xDF\x06\x6E\xEB\xE9\x9E\xFF\xBB\xE1\xD2\x48\x17\xE5\x3B\xAC\x12\xF0\x93\x9A\x2E\x25\xE0\x40\xAA\x3C\x01\x7C\x1A\xB8\xA7\xCB\x14\x16\x17\x2B\xB8\xC6\x59\x21\x49\xE0\x6A\x60\x73\x75\x7F\xCF\xDD\x29\xFC\x0A\x78\xD8\xAF\xC8\x4A\xD8\x74\xA4\x23\xB3\xD2\x8C\xA6\xB3\x9B\x03\x54\xD6\x23\x7C\x13\x58\x38\x52\x1A\xB9\x4A\xE0\x5A\xEF\x21\x9E\x94\xF2\xDD\x51\x55\xC4\x71\x94\x5A\x1B\xDE\xAC\x70\x25\x70\x99\x88\x3E\x64\x6C\xFE\xB3\x89\x8B\x8F\xCF\x36' + b'\x49\x41\x0D\xC5\xBF\x19\xFC\xD4\x6F\x93\x6D\x85\x15\x97\x24\xD1\x41\x60\xAB\x97\xE9\x76\xE0\x2B\xBE\xEA\x1E\xE7\xA2\xBA\x0B\xC8\xB9\x28\x01\x3E\x07\x9C\x04\x96\x82\x3C\x67\x6C\xD8\x67\x4C\x4F\xA6\x7A\xE8\x5D\x08\x8C\x0D\xDF\x0F\x7C\x68\x26\xDD\x5D\x4B\x04\x68\x82\x5E\x65\x6C\xBE\xD1\xBB\xA1\xE3\x89\x8B\x77\x57\xB1\xFC\x35\x5A\xCE\x33\x7E\xD2\x3F\xDA\x97\xCB\xE5\xB6\x37\x4C\xB4\x8B\x76\x1A\x1B\x2E\x05\x7E\x0B\xBC\x17\xD8\x86\x8C\xED\x35\x36\xFC\x3D\xC8\x1F\x11\x2D\xA2\xAA\xA8\xCC\x45\x78\x1F\xE8\xC7\x81\x3E\xAF\xCB\x18\x78\xBC\xCE\x10\x17\x88\xB2\xDC\xD8\xFC\x58\x63\xCE\x41\x0E\xB4\x0C\x49\xC0\xBA\x26\x3E\xB3\x78\x01\xF8\x40\x15\xA9' + b'\xFE\x84\xB0\x97\xB2\xDB\x02\xB8\x77\xE0\xD0\xC1\xB1\xA6\x2C\xD2\x45\x7B\x4D\x3E\xFC\x20\xCA\x6A\x9F\x4A\xBA\xA2\xFC\x53\x9F\xC1\x94\x89\x53\xFD\x27\x70\xBF\x90\xAE\x73\xCE\xBD\x52\xA7\xFB\x10\xE4\xD1\x26\x14\x73\x6B\x76\x76\xCD\x27\x1D\x51\x64\x23\x70\x7E\x93\xAF\x56\x4D\x80\xBA\x24\x2A\x19\x1B\xDE\xE5\xDD\x56\x49\x48\x37\x4D\xC9\x75\xC6\xD1\xBF\x81\x3B\x8D\xC9\xFF\x08\x91\x4F\x78\xA2\x7A\x7C\x90\x75\xE6\x5A\x62\x00\xD8\x13\x08\xDB\xE2\x38\x1A\xAA\x63\x12\x03\xC8\x7F\xEF\xC0\x9A\x59\xBD\x7F\xF9\x7F\x92\x94\x4C\xDE\x03\xE2\x53\x94\xBF\x22\x9A\xDE\x81\x5C\xB4\x03\xD8\x31\x3D\xFB\x5C\xFC\xBA\x0F\x9A\x1E\x9E\x37\x2F\x94\x20\x53\x3E\x99' + b'\x24\xCE\x69\x73\xFD\x44\x7B\x80\x3D\x53\xDD\x93\x4A\xF5\xD2\x63\x0A\xF5\xDC\x45\x89\x52\xA9\x04\x0C\x55\x39\x6F\x1D\x05\xEE\x3E\xD7\x33\x1B\x87\x0F\xCF\xCE\x1D\x93\x1C\x84\xCE\xB4\xBC\xC9\x76\x56\x39\x03\xED\x50\xF8\x97\xC0\x72\xCA\x77\x31\x95\xB0\xFB\x52\x70\xC6\xE4\x7B\x09\x64\xC1\x84\x1E\x4E\x29\xEC\x2A\xBA\xE8\x55\xDA\x68\xA3\x8D\x36\xDA\x68\xA3\x8D\x73\x1A\xFF\x01\xC1\xBA\x4F\x53\x6B\xDA\x6F\x58\x00\x00\x00\x00\x49\x45\x4E\x44\xAE\x42\x60\x82' + ) + + test_img_lvgl_logo_png = lv.image_dsc_t( + dict( + header=dict(cf=lv.COLOR_FORMAT.RAW_ALPHA, w=105, h=33), + data_size=1873, + data=test_img_lvgl_logo_png_data + ) + ) + + image_draw_dsc = lv.draw_image_dsc_t() + + image_draw_dsc.init() + image_draw_dsc.src = test_img_lvgl_logo_png + + coords = lv.area_t( + dict( + x1=10, + y1=10, + x2=10 + test_img_lvgl_logo_png.header.w - 1, + y2=10 + test_img_lvgl_logo_png.header.h - 1 + ) + ) + lv.draw_image(layer, image_draw_dsc, coords) + + # Reuse the draw descriptor + coords.move(40, 40) + image_draw_dsc.opa = lv.OPA._50 + lv.draw_image(layer, image_draw_dsc, coords) + + line_draw_dsc = lv.draw_line_dsc_t() + line_draw_dsc.init() + line_draw_dsc.color = lv.color_hex3(0xCA8) + line_draw_dsc.width = 8 + line_draw_dsc.round_end = 1 + line_draw_dsc.round_start = 1 + line_draw_dsc.p1.x = 150 + line_draw_dsc.p1.y = 30 + line_draw_dsc.p2.x = 350 + line_draw_dsc.p2.y = 55 + lv.draw_line(layer, line_draw_dsc) + + canvas.finish_layer(layer) + + c = lv.color_hex(0xff0000) + for i in range(50): + canvas.set_px(100 + i * 2, 10, c, lv.OPA.COVER) + + +@test_func_wrapper +def main(): + lv.tick_inc(300) + lv.refr_now(None) + + +create_ui() +main() +# end diff --git a/tests/micropy_test/test_img_lvgl_logo.png b/tests/micropy_test/test_img_lvgl_logo.png new file mode 100644 index 000000000..2484cf84a Binary files /dev/null and b/tests/micropy_test/test_img_lvgl_logo.png differ