1#!/usr/bin/env python3 2import os 3import re 4import argparse 5from collections import defaultdict 6 7 8style_properties_type = { 9 "LV_STYLE_BG_COLOR": "LV_PROPERTY_TYPE_COLOR", 10 "LV_STYLE_BG_GRAD_COLOR": "LV_PROPERTY_TYPE_COLOR", 11 "LV_STYLE_BG_IMAGE_SRC": "LV_PROPERTY_TYPE_IMGSRC", 12 "LV_STYLE_BG_IMAGE_RECOLOR": "LV_PROPERTY_TYPE_COLOR", 13 "LV_STYLE_BORDER_COLOR": "LV_PROPERTY_TYPE_COLOR", 14 "LV_STYLE_OUTLINE_COLOR": "LV_PROPERTY_TYPE_COLOR", 15 "LV_STYLE_SHADOW_COLOR": "LV_PROPERTY_TYPE_COLOR", 16 "LV_STYLE_IMAGE_RECOLOR": "LV_PROPERTY_TYPE_COLOR", 17 "LV_STYLE_ARCH_IMAGE_SRC": "LV_PROPERTY_TYPE_IMGSRC", 18 "LV_STYLE_ARCH_COLOR": "LV_PROPERTY_TYPE_COLOR", 19 "LV_STYLE_TEXT_COLOR": "LV_PROPERTY_TYPE_COLOR", 20 "LV_STYLE_TEXT_FONT": "LV_PROPERTY_TYPE_FONT", 21 "LV_STYLE_LINE_COLOR": "LV_PROPERTY_TYPE_COLOR", 22} 23 24 25class Property: 26 def __init__(self, widget, name, type, index, id): 27 self.widget = widget 28 self.name = name 29 self.type = type 30 self.index = index 31 self.id = id 32 33 34def find_headers(directory): 35 if os.path.isfile(directory): 36 yield directory 37 return 38 39 for root, dirs, files in os.walk(directory): 40 for file in files: 41 if file.endswith('.h'): 42 yield os.path.join(root, file) 43 44 45def read_widget_properties(directory): 46 47 def match_properties(file_path): 48 pattern = r'^\s*LV_PROPERTY_ID2?\((\w+),\s*(\w+),\s*(\w+)(,\s*(\w+))?,\s*(\d+)\)' 49 with open(file_path, 'r') as file: 50 for line in file.readlines(): 51 match = re.match(pattern, line) 52 if match: 53 id = f"LV_PROPERTY_{match.group(1).upper()}_{match.group(2).upper()}" 54 yield Property( 55 match.group(1).lower(), 56 match.group(2).lower(), match.group(3), match.group(4), 57 id) 58 59 def match_styles(file_path): 60 pattern = r'^\s+LV_STYLE_(\w+)\s*=\s*(\d+),' 61 with open(file_path, 'r') as file: 62 for line in file.readlines(): 63 match = re.match(pattern, line) 64 if match: 65 name = match.group(1).upper() 66 id = f"LV_PROPERTY_STYLE_{name}" 67 yield Property("style", 68 match.group(1).lower(), "style", 69 match.group(2), id) 70 71 properties_by_widget = defaultdict(list) 72 for file_path in find_headers(directory): 73 for property in match_properties(file_path): 74 properties_by_widget[property.widget].append(property) 75 76 for property in match_styles(file_path): 77 properties_by_widget[property.widget].append(property) 78 79 for widget, properties in properties_by_widget.items(): 80 # sort properties by property name 81 properties.sort(key=lambda x: x.name) 82 properties_by_widget[widget] = properties 83 84 return properties_by_widget 85 86 87def write_widget_properties(output, properties_by_widget): 88 # Open header file for update. 89 with open(f'{output}/lv_obj_property_names.h', "w") as header: 90 header.write(f''' 91/** 92 * @file lv_obj_property_names.h 93 * GENERATED FILE, DO NOT EDIT IT! 94 */ 95#ifndef LV_OBJ_PROPERTY_NAMES_H 96#define LV_OBJ_PROPERTY_NAMES_H 97 98#include "../../misc/lv_types.h" 99 100#if LV_USE_OBJ_PROPERTY && LV_USE_OBJ_PROPERTY_NAME 101 102''') 103 104 for widget in sorted(properties_by_widget.keys()): 105 properties = properties_by_widget[widget] 106 file_name = f'lv_{widget}_properties.c' 107 output_file = f'{output}/{file_name}' 108 109 count = len(properties) 110 if widget == 'style': 111 include = "lv_style_properties.h" 112 guard = None 113 elif widget == "obj": 114 include = "../../core/lv_obj.h" 115 guard = None 116 else: 117 include = f'../{widget}/lv_{widget}.h' 118 guard = f"#if LV_USE_{widget.upper()}" 119 120 with open(output_file, 'w') as f: 121 f.write(f''' 122/** 123 * GENERATED FILE, DO NOT EDIT IT! 124 * @file {file_name} 125 */ 126 127#include "{include}" 128 129#if LV_USE_OBJ_PROPERTY && LV_USE_OBJ_PROPERTY_NAME 130 131{guard if guard else ""} 132/** 133 * {widget.capitalize() + ' widget' if widget != 'style' else 'Style'} property names, name must be in order. 134 * Generated code from properties.py 135 */ 136/* *INDENT-OFF* */ 137const lv_property_name_t lv_{widget}_property_names[{count}] = {{ 138''') 139 140 for property in properties: 141 name = property.name 142 name_str = '"' + name + '",' 143 f.write(f" {{{name_str :25} {property.id},}},\n") 144 145 f.write('};\n') 146 if guard: 147 f.write(f"#endif /*LV_USE_{widget.upper()}*/\n\n") 148 f.write("/* *INDENT-ON* */\n") 149 f.write('#endif\n') 150 header.write( 151 f' extern const lv_property_name_t lv_{widget}_property_names[{count}];\n' 152 ) 153 header.write('#endif\n') 154 header.write('#endif\n') 155 156 157def write_style_header(output, properties_by_widget): 158 properties = properties_by_widget['style'] 159 160 output_file = f'{output}/lv_style_properties.h' 161 162 with open(output_file, 'w') as f: 163 f.write(f''' 164/** 165 * GENERATED FILE, DO NOT EDIT IT! 166 * @file lv_style_properties.h 167 */ 168#ifndef LV_STYLE_PROPERTIES_H 169#define LV_STYLE_PROPERTIES_H 170 171#include "../../core/lv_obj_property.h" 172#if LV_USE_OBJ_PROPERTY 173 174 175/* *INDENT-OFF* */ 176enum {{ 177''') 178 179 for property in properties: 180 name = property.name 181 id_type = style_properties_type.get(f"LV_STYLE_{name.upper()}", 182 "LV_PROPERTY_TYPE_INT") 183 f.write( 184 f" LV_PROPERTY_ID(STYLE, {name.upper() + ',' :25} {id_type+',' :28} LV_STYLE_{name.upper()}),\n" 185 ) 186 187 f.write('};\n\n') 188 f.write('#endif\n') 189 f.write('#endif\n') 190 191 192def main(directory, output): 193 property = read_widget_properties(directory) 194 write_widget_properties(output, property) 195 write_style_header(output, property) 196 197 198if __name__ == "__main__": 199 parser = argparse.ArgumentParser( 200 description='Search files and filter lines.') 201 parser.add_argument('-d', '--directory', 202 help='Directory to lvgl root path') 203 parser.add_argument( 204 '-o', '--output', help='Folders to write generated properties for all widgets.') 205 args = parser.parse_args() 206 207 # default directory is the lvgl root path of where this script sits 208 if args.directory is None: 209 args.directory = os.path.join(os.path.dirname(__file__), "../") 210 211 if args.output is None: 212 args.output = os.path.join(args.directory, "src/widgets/property/") 213 214 # create output directory if it doesn't exist 215 os.makedirs(args.output, exist_ok=True) 216 217 main(args.directory, args.output) 218