mirror of
https://github.com/arendst/Tasmota.git
synced 2025-07-07 10:56:29 +00:00
561 lines
19 KiB
Python
561 lines
19 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
LVGL Header Preprocessor
|
|
|
|
Extracts function signatures and enums from LVGL header files.
|
|
Generates mapping files for Berry scripting integration.
|
|
"""
|
|
|
|
import re
|
|
import sys
|
|
import glob
|
|
import argparse
|
|
from pathlib import Path
|
|
from typing import List, Set, Tuple, Optional
|
|
import logging
|
|
|
|
# Configure logging
|
|
logging.basicConfig(level=logging.INFO, format='%(levelname)s: %(message)s')
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
class LVGLPreprocessor:
|
|
"""Main preprocessor class for LVGL headers."""
|
|
|
|
def __init__(self, lv_src_prefix: str = "../../lvgl/src/"):
|
|
self.lv_src_prefix = Path(lv_src_prefix)
|
|
self.headers_exclude_suffix = {
|
|
"_private.h",
|
|
"lv_lottie.h",
|
|
"lv_obj_property.h",
|
|
"lv_obj_property_names.h",
|
|
"lv_style_properties.h",
|
|
"lv_3dtexture.h",
|
|
}
|
|
|
|
# Function exclusion patterns
|
|
self.function_exclude_patterns = [
|
|
r"^_", # skip if function name starts with '_'
|
|
r"^lv_debug", # all debug functions
|
|
r"^lv_init", r"^lv_deinit",
|
|
r"^lv_templ_",
|
|
r"^lv_imagebutton_get_src_", # LV_IMGBTN_TILED == 0
|
|
r"^lv_imagebitton_set_src_tiled", # !LV_IMGBTN_TILED
|
|
r"^lv_refr_get_fps_", # no LV_USE_PERF_MONITOR
|
|
r"^lv_image_cache_",
|
|
r"^lv_image_decoder_",
|
|
r"^lv_image_cf_",
|
|
r"^lv_image_buf_",
|
|
r"^lv_indev_scroll_",
|
|
r"^lv_pow",
|
|
r"^lv_keyboard_def_event_cb", # need to fix conditional include
|
|
r"^lv_refr_reset_fps_counter",
|
|
r"^lv_refr_get_fps_avg",
|
|
r"^lv_anim_path_", # callbacks for animation are moved to constants
|
|
r"^lv_obj_set_property", # LV_USE_OBJ_PROPERTY 0
|
|
r"^lv_obj_set_properties",
|
|
r"^lv_obj_get_property",
|
|
r"^lv_win_",
|
|
r"^lv_obj.*name", # we don't enable #if LV_USE_OBJ_NAME
|
|
]
|
|
|
|
# Enum exclusion patterns
|
|
self.enum_exclude_prefixes = {
|
|
"_", "LV_BIDI_DIR_", "LV_FONT_", "LV_SIGNAL_", "LV_TEMPL_",
|
|
"LV_TASK_PRIO_", "LV_THEME_", "LV_LRU_", "LV_VECTOR_",
|
|
"LV_KEYBOARD_MODE_TEXT_ARABIC", "LV_DRAW_TASK_TYPE_3D",
|
|
"LV_DRAW_TASK_TYPE_VECTOR",
|
|
}
|
|
|
|
def comment_remover(self, text: str) -> str:
|
|
"""Remove C/C++ style comments from source code."""
|
|
def replacer(match):
|
|
s = match.group(0)
|
|
return " " if s.startswith('/') else s
|
|
|
|
pattern = re.compile(
|
|
r'//.*?$|/\*.*?\*/|\'(?:\\.|[^\\\'])*\'|"(?:\\.|[^\\"])*"',
|
|
re.DOTALL | re.MULTILINE
|
|
)
|
|
return re.sub(pattern, replacer, text)
|
|
|
|
def list_files(self, prefix: Path, glob_patterns: List[str]) -> List[Path]:
|
|
"""Compute a sorted list of files from a prefix and glob patterns."""
|
|
files = []
|
|
for pattern in glob_patterns:
|
|
files.extend(Path(prefix).glob(pattern))
|
|
return sorted(files)
|
|
|
|
def clean_source(self, raw: str) -> str:
|
|
"""Clean source code by removing comments, preprocessor directives, etc."""
|
|
raw = self.comment_remover(raw)
|
|
|
|
# Normalize line endings
|
|
raw = re.sub(r'\r\n', '\n', raw)
|
|
raw = re.sub(r'\r', '\n', raw)
|
|
|
|
# Handle line continuations
|
|
raw = re.sub(r'\\\n', ' ', raw)
|
|
|
|
# Remove preprocessor directives
|
|
raw = re.sub(r'\n[ \t]*#[^\n]*(?=\n)', '', raw)
|
|
raw = re.sub(r'^[ \t]*#[^\n]*\n', '', raw)
|
|
raw = re.sub(r'\n[ \t]*#[^\n]*$', '', raw)
|
|
|
|
# Remove extern "C" blocks
|
|
raw = re.sub(r'extern\s+"C"\s+{(.*)}', r'\1', raw, flags=re.DOTALL)
|
|
|
|
# Remove empty lines
|
|
raw = re.sub(r'\n[ \t]*(?=\n)', '', raw)
|
|
raw = re.sub(r'^[ \t]*\n', '', raw)
|
|
raw = re.sub(r'\n[ \t]*$', '', raw)
|
|
|
|
return raw
|
|
|
|
def extract_functions(self, source: str) -> List[str]:
|
|
"""Extract function signatures from cleaned source code."""
|
|
# Remove content within braces
|
|
while True:
|
|
source, repl_count = re.subn(r'\{[^{]*?\}', ';', source, flags=re.DOTALL)
|
|
if repl_count == 0:
|
|
break
|
|
|
|
# Find function signatures
|
|
pattern = r'(^|;|})\s*([^;{}]+\(.*?\))\s*(?=(;|{))'
|
|
matches = re.findall(pattern, source, flags=re.DOTALL)
|
|
|
|
functions = []
|
|
for match in matches:
|
|
func_def = match[1]
|
|
# Clean up whitespace
|
|
func_def = re.sub(r'[ \t\r\n]+', ' ', func_def)
|
|
|
|
# Remove LVGL-specific attributes
|
|
func_def = re.sub(r'LV_ATTRIBUTE_FAST_MEM ', '', func_def)
|
|
func_def = re.sub(r'LV_ATTRIBUTE_TIMER_HANDLER ', '', func_def)
|
|
func_def = re.sub(r'extern ', '', func_def)
|
|
|
|
# Skip excluded function types
|
|
if any(func_def.startswith(prefix) for prefix in ["typedef", "_LV_", "LV_"]):
|
|
continue
|
|
|
|
# Extract function name
|
|
name_match = re.search(r'\s(\w+)\([^\(]*$', func_def)
|
|
if not name_match:
|
|
continue
|
|
|
|
func_name = name_match.group(1)
|
|
|
|
# Check exclusion patterns
|
|
if any(re.search(pattern, func_name) for pattern in self.function_exclude_patterns):
|
|
continue
|
|
|
|
functions.append(func_def)
|
|
|
|
return functions
|
|
|
|
def extract_enums(self, source: str) -> Set[str]:
|
|
"""Extract enum values from cleaned source code."""
|
|
enum_values = set()
|
|
|
|
# Find enum definitions
|
|
enum_matches = re.findall(r'enum\s+\w*\s*{(.*?)}', source, flags=re.DOTALL)
|
|
|
|
for enum_content in enum_matches:
|
|
# Skip LV_PROPERTY_ID enums (disabled feature)
|
|
if 'LV_PROPERTY_ID' in enum_content:
|
|
continue
|
|
|
|
# Remove macro-defined enums
|
|
enum_content = re.sub(r'\S+\((.*?),.*?\),', r'\1,', enum_content)
|
|
|
|
# Split by commas and clean up
|
|
for item in enum_content.split(','):
|
|
item = re.sub(r'[ \t\n]', '', item) # Remove whitespace
|
|
item = re.sub(r'=.*$', '', item) # Remove assignment
|
|
|
|
if not item: # Skip empty items
|
|
continue
|
|
|
|
# Check exclusion patterns
|
|
if any(item.startswith(prefix) for prefix in self.enum_exclude_prefixes):
|
|
continue
|
|
|
|
enum_values.add(item)
|
|
|
|
# Extract LV_EXPORT_CONST_INT constants
|
|
const_ints = re.findall(r'LV_EXPORT_CONST_INT\((\w+)\)', source, flags=re.DOTALL)
|
|
enum_values.update(const_ints)
|
|
|
|
return enum_values
|
|
|
|
def get_function_headers(self) -> List[Path]:
|
|
"""Get list of header files for function extraction."""
|
|
patterns = [
|
|
"lv_api*.h",
|
|
"widgets/*/*.h",
|
|
"libs/qrcode/lv_qrcode.h",
|
|
"core/*.h",
|
|
"indev/lv_indev.h",
|
|
"layouts/*/*.h",
|
|
"themes/lv_theme.h",
|
|
"draw/lv_draw_arc.h",
|
|
"draw/lv_draw_label.h",
|
|
"draw/lv_draw_line.h",
|
|
"draw/lv_draw_mask.h",
|
|
"draw/lv_draw_rect.h",
|
|
"draw/lv_draw_triangle.h",
|
|
"draw/lv_draw.h",
|
|
"display/*.h",
|
|
"misc/lv_anim.h",
|
|
"misc/lv_area.h",
|
|
"misc/lv_color.h",
|
|
"misc/lv_color_op.h",
|
|
"misc/lv_palette.h",
|
|
"misc/lv_event.h",
|
|
"misc/lv_style_gen.h",
|
|
"misc/lv_style.h",
|
|
"misc/lv_timer.h",
|
|
"misc/lv_text.h",
|
|
"font/lv_font.h",
|
|
"../lvgl.h",
|
|
]
|
|
|
|
headers = self.list_files(self.lv_src_prefix, patterns)
|
|
|
|
# Add additional headers
|
|
additional_paths = [
|
|
Path("../../LVGL_assets/src/lv_theme_haspmota.h"),
|
|
Path("../src/lv_berry.h"),
|
|
Path("../src/lv_colorwheel.h"),
|
|
]
|
|
|
|
for path in additional_paths:
|
|
if path.exists():
|
|
headers.append(path)
|
|
|
|
# Filter out excluded files
|
|
return [h for h in headers if not any(str(h).endswith(suffix) for suffix in self.headers_exclude_suffix)]
|
|
|
|
def get_enum_headers(self) -> List[Path]:
|
|
"""Get list of header files for enum extraction."""
|
|
patterns = [
|
|
"core/*.h",
|
|
"draw/*.h",
|
|
"hal/*.h",
|
|
"misc/*.h",
|
|
"widgets/*/*.h",
|
|
"display/lv_display.h",
|
|
"layouts/**/*.h",
|
|
]
|
|
|
|
headers = self.list_files(self.lv_src_prefix, patterns)
|
|
return [h for h in headers if not any(str(h).endswith(suffix) for suffix in self.headers_exclude_suffix)]
|
|
|
|
def generate_functions_header(self, output_path: Path):
|
|
"""Generate the functions header file."""
|
|
logger.info(f"Generating functions header: {output_path}")
|
|
|
|
headers = self.get_function_headers()
|
|
|
|
with open(output_path, 'w', encoding='utf-8') as f:
|
|
f.write("""
|
|
// Automatically generated from LVGL source with `python3 preprocessor.py`
|
|
// Extract function signatures from LVGL APIs in headers
|
|
|
|
// Custom Tasmota functions
|
|
lv_ts_calibration_t * lv_get_ts_calibration(void);
|
|
|
|
// ======================================================================
|
|
// LV top level functions
|
|
// ======================================================================
|
|
|
|
// resolution
|
|
lv_coord_t lv_get_hor_res(void);
|
|
lv_coord_t lv_get_ver_res(void);
|
|
|
|
// ======================================================================
|
|
// Generated from headers
|
|
// ======================================================================
|
|
|
|
""")
|
|
|
|
for header_path in headers:
|
|
try:
|
|
with open(header_path, encoding='utf-8-sig') as header_file:
|
|
f.write(f"// {header_path}\n")
|
|
|
|
raw_content = self.clean_source(header_file.read())
|
|
functions = self.extract_functions(raw_content)
|
|
|
|
for func in functions:
|
|
f.write(f"{func}\n")
|
|
f.write("\n")
|
|
|
|
except Exception as e:
|
|
logger.error(f"Error processing {header_path}: {e}")
|
|
|
|
def generate_enums_header(self, output_path: Path):
|
|
"""Generate the enums header file."""
|
|
logger.info(f"Generating enums header: {output_path}")
|
|
|
|
headers = self.get_enum_headers()
|
|
|
|
with open(output_path, 'w', encoding='utf-8') as f:
|
|
# Write the static content first
|
|
f.write(self._get_static_enum_content())
|
|
|
|
# Process headers for dynamic enums
|
|
for header_path in headers:
|
|
try:
|
|
with open(header_path, encoding='utf-8-sig') as header_file:
|
|
f.write(f"// File: {header_path}\n")
|
|
|
|
raw_content = self.clean_source(header_file.read())
|
|
enum_values = self.extract_enums(raw_content)
|
|
|
|
for enum_value in sorted(enum_values):
|
|
f.write(f"{enum_value}\n")
|
|
f.write("\n")
|
|
|
|
except Exception as e:
|
|
logger.error(f"Error processing {header_path}: {e}")
|
|
|
|
def _get_static_enum_content(self) -> str:
|
|
"""Get the static content for enum header."""
|
|
return """// ======================================================================
|
|
// Functions
|
|
// ======================================================================
|
|
|
|
load_font=@lv0_load_font
|
|
|
|
// lv_anim_path_functions
|
|
anim_path_bounce=&lv_anim_path_bounce
|
|
anim_path_ease_in=&lv_anim_path_ease_in
|
|
anim_path_ease_in_out=&lv_anim_path_ease_in_out
|
|
anim_path_ease_out=&lv_anim_path_ease_out
|
|
anim_path_linear=&lv_anim_path_linear
|
|
anim_path_overshoot=&lv_anim_path_overshoot
|
|
anim_path_step=&lv_anim_path_step
|
|
LV_LAYOUT_GRID=>be_LV_LAYOUT_GRID
|
|
LV_LAYOUT_FLEX=>be_LV_LAYOUT_FLEX
|
|
|
|
// ======================================================================
|
|
// Colors
|
|
// ======================================================================
|
|
// LV Colors - we store in 24 bits format and will convert at runtime
|
|
// This is specific treatment because we keep colors in 24 bits format
|
|
COLOR_WHITE=0xFFFFFF
|
|
COLOR_SILVER=0xC0C0C0
|
|
COLOR_GRAY=0x808080
|
|
COLOR_GREY=0x808080 // OpenHASP
|
|
COLOR_BLACK=0x000000
|
|
COLOR_RED=0xFF0000
|
|
COLOR_MAROON=0x800000
|
|
COLOR_YELLOW=0xFFFF00
|
|
COLOR_OLIVE=0x808000
|
|
COLOR_LIME=0x00FF00
|
|
COLOR_GREEN=0x008000
|
|
COLOR_CYAN=0x00FFFF
|
|
COLOR_AQUA=0x00FFFF
|
|
COLOR_TEAL=0x008080
|
|
COLOR_BLUE=0x0000FF
|
|
COLOR_NAVY=0x000080
|
|
COLOR_MAGENTA=0xFF00FF
|
|
COLOR_FUCHSIA=0xFF00FF // OpenHASP
|
|
COLOR_ORANGE=0xFFA500 // OpenHASP
|
|
COLOR_PURPLE=0x800080
|
|
// Below are OpenHASP additions
|
|
COLOR_PERU=0xCD853F
|
|
COLOR_SIENNA=0xA0522D
|
|
COLOR_BROWN=0xA52A2A
|
|
COLOR_SNOW=0xFFFAFA
|
|
COLOR_IVORY=0xFFFFF0
|
|
COLOR_LINEN=0xFAF0E6
|
|
COLOR_BEIGE=0xF5F5DC
|
|
COLOR_AZURE=0xF0FFFF
|
|
COLOR_PINK=0xFFC0CB
|
|
COLOR_PLUM=0xDDA0DD
|
|
COLOR_ORCHID=0xDA70D6
|
|
COLOR_VIOLET=0xEE82EE
|
|
COLOR_INDIGO=0x4B0082
|
|
COLOR_BLUSH=0xB00000
|
|
COLOR_TOMATO=0xFF6347
|
|
COLOR_SALMON=0xFA8072
|
|
COLOR_CORAL=0xFF7F50
|
|
COLOR_GOLD=0xFFD700
|
|
COLOR_KHAKI=0xF0E68C
|
|
COLOR_BISQUE=0xFFE4C4
|
|
COLOR_WHEAT=0xF5DEB3
|
|
COLOR_TAN=0xD2B48C
|
|
|
|
// Freetype
|
|
FT_FONT_STYLE_NORMAL=FT_FONT_STYLE_NORMAL
|
|
FT_FONT_STYLE_ITALIC=FT_FONT_STYLE_ITALIC
|
|
FT_FONT_STYLE_BOLD=FT_FONT_STYLE_BOLD
|
|
|
|
// following are #define, not enum
|
|
LV_GRID_FR=LV_GRID_FR(0)
|
|
|
|
// ======================================================================
|
|
// Symbols
|
|
// ======================================================================
|
|
|
|
SYMBOL_AUDIO="\\xef\\x80\\x81"
|
|
SYMBOL_VIDEO="\\xef\\x80\\x88"
|
|
SYMBOL_LIST="\\xef\\x80\\x8b"
|
|
SYMBOL_OK="\\xef\\x80\\x8c"
|
|
SYMBOL_CLOSE="\\xef\\x80\\x8d"
|
|
SYMBOL_POWER="\\xef\\x80\\x91"
|
|
SYMBOL_SETTINGS="\\xef\\x80\\x93"
|
|
SYMBOL_HOME="\\xef\\x80\\x95"
|
|
SYMBOL_DOWNLOAD="\\xef\\x80\\x99"
|
|
SYMBOL_DRIVE="\\xef\\x80\\x9c"
|
|
SYMBOL_REFRESH="\\xef\\x80\\xa1"
|
|
SYMBOL_MUTE="\\xef\\x80\\xa6"
|
|
SYMBOL_VOLUME_MID="\\xef\\x80\\xa7"
|
|
SYMBOL_VOLUME_MAX="\\xef\\x80\\xa8"
|
|
SYMBOL_IMAGE="\\xef\\x80\\xbe"
|
|
SYMBOL_EDIT="\\xef\\x8C\\x84"
|
|
SYMBOL_PREV="\\xef\\x81\\x88"
|
|
SYMBOL_PLAY="\\xef\\x81\\x8b"
|
|
SYMBOL_PAUSE="\\xef\\x81\\x8c"
|
|
SYMBOL_STOP="\\xef\\x81\\x8d"
|
|
SYMBOL_NEXT="\\xef\\x81\\x91"
|
|
SYMBOL_EJECT="\\xef\\x81\\x92"
|
|
SYMBOL_LEFT="\\xef\\x81\\x93"
|
|
SYMBOL_RIGHT="\\xef\\x81\\x94"
|
|
SYMBOL_PLUS="\\xef\\x81\\xa7"
|
|
SYMBOL_MINUS="\\xef\\x81\\xa8"
|
|
SYMBOL_EYE_OPEN="\\xef\\x81\\xae"
|
|
SYMBOL_EYE_CLOSE="\\xef\\x81\\xb0"
|
|
SYMBOL_WARNING="\\xef\\x81\\xb1"
|
|
SYMBOL_SHUFFLE="\\xef\\x81\\xb4"
|
|
SYMBOL_UP="\\xef\\x81\\xb7"
|
|
SYMBOL_DOWN="\\xef\\x81\\xb8"
|
|
SYMBOL_LOOP="\\xef\\x81\\xb9"
|
|
SYMBOL_DIRECTORY="\\xef\\x81\\xbb"
|
|
SYMBOL_UPLOAD="\\xef\\x82\\x93"
|
|
SYMBOL_CALL="\\xef\\x82\\x95"
|
|
SYMBOL_CUT="\\xef\\x83\\x84"
|
|
SYMBOL_COPY="\\xef\\x83\\x85"
|
|
SYMBOL_SAVE="\\xef\\x83\\x87"
|
|
SYMBOL_CHARGE="\\xef\\x83\\xa7"
|
|
SYMBOL_PASTE="\\xef\\x83\\xAA"
|
|
SYMBOL_BELL="\\xef\\x83\\xb3"
|
|
SYMBOL_KEYBOARD="\\xef\\x84\\x9c"
|
|
SYMBOL_GPS="\\xef\\x84\\xa4"
|
|
SYMBOL_FILE="\\xef\\x85\\x9b"
|
|
SYMBOL_WIFI="\\xef\\x87\\xab"
|
|
SYMBOL_BATTERY_FULL="\\xef\\x89\\x80"
|
|
SYMBOL_BATTERY_3="\\xef\\x89\\x81"
|
|
SYMBOL_BATTERY_2="\\xef\\x89\\x82"
|
|
SYMBOL_BATTERY_1="\\xef\\x89\\x83"
|
|
SYMBOL_BATTERY_EMPTY="\\xef\\x89\\x84"
|
|
SYMBOL_USB="\\xef\\x8a\\x87"
|
|
SYMBOL_BLUETOOTH="\\xef\\x8a\\x93"
|
|
SYMBOL_TRASH="\\xef\\x8B\\xAD"
|
|
SYMBOL_BACKSPACE="\\xef\\x95\\x9A"
|
|
SYMBOL_SD_CARD="\\xef\\x9F\\x82"
|
|
SYMBOL_NEW_LINE="\\xef\\xA2\\xA2"
|
|
|
|
SYMBOL_DUMMY="\\xEF\\xA3\\xBF"
|
|
|
|
SYMBOL_BULLET="\\xE2\\x80\\xA2"
|
|
|
|
// LVGL 8 to 9 compatibility
|
|
|
|
LV_DISP_ROTATION_0=LV_DISPLAY_ROTATION_0
|
|
LV_DISP_ROTATION_90=LV_DISPLAY_ROTATION_90
|
|
LV_DISP_ROTATION_180=LV_DISPLAY_ROTATION_180
|
|
LV_DISP_ROTATION_270=LV_DISPLAY_ROTATION_270
|
|
|
|
LV_DISP_RENDER_MODE_PARTIAL=LV_DISPLAY_RENDER_MODE_PARTIAL
|
|
LV_DISP_RENDER_MODE_DIRECT=LV_DISPLAY_RENDER_MODE_DIRECT
|
|
LV_DISP_RENDER_MODE_FULL=LV_DISPLAY_RENDER_MODE_FULL
|
|
|
|
LV_BTNMATRIX_BTN_NONE=LV_BUTTONMATRIX_BUTTON_NONE
|
|
|
|
LV_BTNMATRIX_CTRL_HIDDEN=LV_BUTTONMATRIX_CTRL_HIDDEN
|
|
LV_BTNMATRIX_CTRL_NO_REPEAT=LV_BUTTONMATRIX_CTRL_NO_REPEAT
|
|
LV_BTNMATRIX_CTRL_DISABLED=LV_BUTTONMATRIX_CTRL_DISABLED
|
|
LV_BTNMATRIX_CTRL_CHECKABLE=LV_BUTTONMATRIX_CTRL_CHECKABLE
|
|
LV_BTNMATRIX_CTRL_CHECKED=LV_BUTTONMATRIX_CTRL_CHECKED
|
|
LV_BTNMATRIX_CTRL_CLICK_TRIG=LV_BUTTONMATRIX_CTRL_CLICK_TRIG
|
|
LV_BTNMATRIX_CTRL_POPOVER=LV_BUTTONMATRIX_CTRL_POPOVER
|
|
LV_BTNMATRIX_CTRL_CUSTOM_1=LV_BUTTONMATRIX_CTRL_CUSTOM_1
|
|
LV_BTNMATRIX_CTRL_CUSTOM_2=LV_BUTTONMATRIX_CTRL_CUSTOM_2
|
|
|
|
LV_RES_OK=LV_RESULT_OK
|
|
LV_RES_INV=LV_RESULT_INVALID
|
|
|
|
LV_INDEV_STATE_PR=LV_INDEV_STATE_PRESSED
|
|
LV_INDEV_STATE_REL=LV_INDEV_STATE_RELEASED
|
|
|
|
LV_STYLE_ANIM_TIME=LV_STYLE_ANIM_DURATION
|
|
LV_STYLE_IMG_OPA=LV_STYLE_IMAGE_OPA
|
|
LV_STYLE_IMG_RECOLOR=LV_STYLE_IMAGE_RECOLOR
|
|
LV_STYLE_IMG_RECOLOR_OPA=LV_STYLE_IMAGE_RECOLOR_OPA
|
|
LV_STYLE_SHADOW_OFS_X=LV_STYLE_SHADOW_OFFSET_X
|
|
LV_STYLE_SHADOW_OFS_Y=LV_STYLE_SHADOW_OFFSET_Y
|
|
LV_STYLE_TRANSFORM_ANGLE=LV_STYLE_TRANSFORM_ROTATION
|
|
|
|
LV_ZOOM_NONE=LV_SCALE_NONE
|
|
|
|
// LVGL 9.3
|
|
LV_LABEL_LONG_WRAP=LV_LABEL_LONG_MODE_WRAP
|
|
LV_LABEL_LONG_DOT=LV_LABEL_LONG_MODE_DOTS
|
|
LV_LABEL_LONG_SCROLL=LV_LABEL_LONG_MODE_SCROLL
|
|
LV_LABEL_LONG_SCROLL_CIRCULAR=LV_LABEL_LONG_MODE_SCROLL_CIRCULAR
|
|
LV_LABEL_LONG_CLIP=LV_LABEL_LONG_MODE_CLIP
|
|
|
|
// ======================================================================
|
|
// Generated from headers
|
|
// ======================================================================
|
|
"""
|
|
|
|
def run(self, functions_output: str = "../mapping/lv_funcs.h",
|
|
enums_output: str = "../mapping/lv_enum.h"):
|
|
"""Run the complete preprocessing pipeline."""
|
|
functions_path = Path(functions_output)
|
|
enums_path = Path(enums_output)
|
|
|
|
# Create output directories if they don't exist
|
|
functions_path.parent.mkdir(parents=True, exist_ok=True)
|
|
enums_path.parent.mkdir(parents=True, exist_ok=True)
|
|
|
|
# Generate both files
|
|
self.generate_functions_header(functions_path)
|
|
self.generate_enums_header(enums_path)
|
|
|
|
logger.info("Preprocessing complete!")
|
|
|
|
|
|
def main():
|
|
"""Main entry point with command line argument parsing."""
|
|
parser = argparse.ArgumentParser(description="LVGL Header Preprocessor")
|
|
parser.add_argument("--lv-src", default="../../lvgl/src/",
|
|
help="Path to LVGL source directory")
|
|
parser.add_argument("--functions-output", default="../mapping/lv_funcs.h",
|
|
help="Output path for functions header")
|
|
parser.add_argument("--enums-output", default="../mapping/lv_enum.h",
|
|
help="Output path for enums header")
|
|
parser.add_argument("--verbose", "-v", action="store_true",
|
|
help="Enable verbose logging")
|
|
|
|
args = parser.parse_args()
|
|
|
|
if args.verbose:
|
|
logging.getLogger().setLevel(logging.DEBUG)
|
|
|
|
try:
|
|
preprocessor = LVGLPreprocessor(args.lv_src)
|
|
preprocessor.run(args.functions_output, args.enums_output)
|
|
except Exception as e:
|
|
logger.error(f"Preprocessing failed: {e}")
|
|
sys.exit(1)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|