mirror of
https://github.com/lvgl/lvgl.git
synced 2026-03-23 14:03:13 +08:00
feat(gdb): extract style constants to auto-generated lv_style_consts.py
This commit is contained in:
@@ -1,7 +1,11 @@
|
||||
from .lv_ll import LVList
|
||||
from .lv_style import (
|
||||
LVStyle, StyleEntry,
|
||||
dump_style_info, style_prop_name, decode_selector, format_style_value,
|
||||
LVStyle,
|
||||
StyleEntry,
|
||||
dump_style_info,
|
||||
style_prop_name,
|
||||
decode_selector,
|
||||
format_style_value,
|
||||
)
|
||||
from .lv_rb import LVRedBlackTree, dump_rb_info
|
||||
from .lv_cache import LVCache, dump_cache_info
|
||||
|
||||
@@ -4,200 +4,18 @@ from typing import Iterator
|
||||
import gdb
|
||||
from prettytable import PrettyTable
|
||||
from lvglgdb.value import Value
|
||||
|
||||
# Style property ID to name mapping (from lv_style.h enum)
|
||||
_STYLE_PROP_NAMES = {
|
||||
1: "WIDTH",
|
||||
2: "HEIGHT",
|
||||
3: "LENGTH",
|
||||
4: "TRANSFORM_WIDTH",
|
||||
5: "TRANSFORM_HEIGHT",
|
||||
8: "MIN_WIDTH",
|
||||
9: "MAX_WIDTH",
|
||||
10: "MIN_HEIGHT",
|
||||
11: "MAX_HEIGHT",
|
||||
12: "TRANSLATE_X",
|
||||
13: "TRANSLATE_Y",
|
||||
14: "RADIAL_OFFSET",
|
||||
16: "X",
|
||||
17: "Y",
|
||||
18: "ALIGN",
|
||||
24: "PAD_TOP",
|
||||
25: "PAD_BOTTOM",
|
||||
26: "PAD_LEFT",
|
||||
27: "PAD_RIGHT",
|
||||
28: "PAD_RADIAL",
|
||||
29: "PAD_ROW",
|
||||
30: "PAD_COLUMN",
|
||||
32: "MARGIN_TOP",
|
||||
33: "MARGIN_BOTTOM",
|
||||
34: "MARGIN_LEFT",
|
||||
35: "MARGIN_RIGHT",
|
||||
40: "BG_GRAD",
|
||||
41: "BG_GRAD_DIR",
|
||||
42: "BG_MAIN_OPA",
|
||||
43: "BG_GRAD_OPA",
|
||||
44: "BG_GRAD_COLOR",
|
||||
45: "BG_MAIN_STOP",
|
||||
46: "BG_GRAD_STOP",
|
||||
48: "BG_IMAGE_SRC",
|
||||
49: "BG_IMAGE_OPA",
|
||||
50: "BG_IMAGE_RECOLOR_OPA",
|
||||
51: "BG_IMAGE_TILED",
|
||||
52: "BG_IMAGE_RECOLOR",
|
||||
56: "BORDER_WIDTH",
|
||||
57: "BORDER_COLOR",
|
||||
58: "BORDER_OPA",
|
||||
59: "BORDER_POST",
|
||||
60: "BORDER_SIDE",
|
||||
64: "OUTLINE_WIDTH",
|
||||
65: "OUTLINE_COLOR",
|
||||
66: "OUTLINE_OPA",
|
||||
67: "OUTLINE_PAD",
|
||||
72: "BG_OPA",
|
||||
73: "BG_COLOR",
|
||||
74: "SHADOW_WIDTH",
|
||||
75: "LINE_WIDTH",
|
||||
76: "ARC_WIDTH",
|
||||
77: "TEXT_FONT",
|
||||
78: "IMAGE_RECOLOR_OPA",
|
||||
80: "IMAGE_OPA",
|
||||
81: "SHADOW_OPA",
|
||||
82: "LINE_OPA",
|
||||
83: "ARC_OPA",
|
||||
84: "TEXT_OPA",
|
||||
88: "SHADOW_COLOR",
|
||||
89: "IMAGE_RECOLOR",
|
||||
90: "LINE_COLOR",
|
||||
91: "ARC_COLOR",
|
||||
92: "TEXT_COLOR",
|
||||
96: "ARC_IMAGE_SRC",
|
||||
97: "SHADOW_OFFSET_X",
|
||||
98: "SHADOW_OFFSET_Y",
|
||||
99: "SHADOW_SPREAD",
|
||||
100: "LINE_DASH_WIDTH",
|
||||
101: "TEXT_ALIGN",
|
||||
102: "TEXT_LETTER_SPACE",
|
||||
103: "TEXT_LINE_SPACE",
|
||||
104: "LINE_DASH_GAP",
|
||||
105: "LINE_ROUNDED",
|
||||
106: "IMAGE_COLORKEY",
|
||||
107: "TEXT_OUTLINE_STROKE_WIDTH",
|
||||
108: "TEXT_OUTLINE_STROKE_OPA",
|
||||
109: "TEXT_OUTLINE_STROKE_COLOR",
|
||||
110: "TEXT_DECOR",
|
||||
111: "ARC_ROUNDED",
|
||||
112: "OPA",
|
||||
113: "OPA_LAYERED",
|
||||
114: "COLOR_FILTER_DSC",
|
||||
115: "COLOR_FILTER_OPA",
|
||||
116: "ANIM",
|
||||
117: "ANIM_DURATION",
|
||||
118: "TRANSITION",
|
||||
120: "RADIUS",
|
||||
121: "BITMAP_MASK_SRC",
|
||||
122: "BLEND_MODE",
|
||||
123: "ROTARY_SENSITIVITY",
|
||||
124: "TRANSLATE_RADIAL",
|
||||
128: "CLIP_CORNER",
|
||||
129: "BASE_DIR",
|
||||
130: "RECOLOR",
|
||||
131: "RECOLOR_OPA",
|
||||
132: "LAYOUT",
|
||||
136: "BLUR_RADIUS",
|
||||
137: "BLUR_BACKDROP",
|
||||
138: "BLUR_QUALITY",
|
||||
144: "DROP_SHADOW_RADIUS",
|
||||
145: "DROP_SHADOW_OFFSET_X",
|
||||
146: "DROP_SHADOW_OFFSET_Y",
|
||||
147: "DROP_SHADOW_COLOR",
|
||||
148: "DROP_SHADOW_OPA",
|
||||
149: "DROP_SHADOW_QUALITY",
|
||||
152: "TRANSFORM_SCALE_X",
|
||||
153: "TRANSFORM_SCALE_Y",
|
||||
154: "TRANSFORM_PIVOT_X",
|
||||
155: "TRANSFORM_PIVOT_Y",
|
||||
156: "TRANSFORM_ROTATION",
|
||||
157: "TRANSFORM_SKEW_X",
|
||||
158: "TRANSFORM_SKEW_Y",
|
||||
160: "FLEX_FLOW",
|
||||
161: "FLEX_MAIN_PLACE",
|
||||
162: "FLEX_CROSS_PLACE",
|
||||
163: "FLEX_TRACK_PLACE",
|
||||
164: "FLEX_GROW",
|
||||
165: "GRID_COLUMN_DSC_ARRAY",
|
||||
166: "GRID_ROW_DSC_ARRAY",
|
||||
168: "GRID_COLUMN_ALIGN",
|
||||
169: "GRID_ROW_ALIGN",
|
||||
170: "GRID_CELL_COLUMN_POS",
|
||||
171: "GRID_CELL_COLUMN_SPAN",
|
||||
172: "GRID_CELL_X_ALIGN",
|
||||
173: "GRID_CELL_ROW_POS",
|
||||
174: "GRID_CELL_ROW_SPAN",
|
||||
175: "GRID_CELL_Y_ALIGN",
|
||||
}
|
||||
|
||||
_PART_NAMES = {
|
||||
0x00: "MAIN",
|
||||
0x01: "SCROLLBAR",
|
||||
0x02: "INDICATOR",
|
||||
0x03: "KNOB",
|
||||
0x04: "SELECTED",
|
||||
0x05: "ITEMS",
|
||||
0x06: "CURSOR",
|
||||
0x08: "CUSTOM_FIRST",
|
||||
0x0F: "ANY",
|
||||
}
|
||||
|
||||
_STATE_FLAGS = {
|
||||
0x0001: "ALT",
|
||||
0x0004: "CHECKED",
|
||||
0x0008: "FOCUSED",
|
||||
0x0010: "FOCUS_KEY",
|
||||
0x0020: "EDITED",
|
||||
0x0040: "HOVERED",
|
||||
0x0080: "PRESSED",
|
||||
0x0100: "SCROLLED",
|
||||
0x0200: "DISABLED",
|
||||
0x1000: "USER_1",
|
||||
0x2000: "USER_2",
|
||||
0x4000: "USER_3",
|
||||
0x8000: "USER_4",
|
||||
}
|
||||
|
||||
_COLOR_PROPS = {
|
||||
44,
|
||||
52,
|
||||
57,
|
||||
65,
|
||||
73,
|
||||
88,
|
||||
89,
|
||||
90,
|
||||
91,
|
||||
92,
|
||||
109,
|
||||
130,
|
||||
147,
|
||||
}
|
||||
|
||||
_POINTER_PROPS = {
|
||||
40,
|
||||
48,
|
||||
77,
|
||||
96,
|
||||
114,
|
||||
116,
|
||||
118,
|
||||
121,
|
||||
165,
|
||||
166,
|
||||
}
|
||||
from .lv_style_consts import (
|
||||
STYLE_PROP_NAMES,
|
||||
PART_NAMES,
|
||||
STATE_FLAGS,
|
||||
COLOR_PROPS,
|
||||
POINTER_PROPS,
|
||||
)
|
||||
|
||||
|
||||
def style_prop_name(prop_id: int) -> str:
|
||||
"""Resolve style property ID to human-readable name."""
|
||||
return _STYLE_PROP_NAMES.get(prop_id, f"UNKNOWN({prop_id})")
|
||||
return STYLE_PROP_NAMES.get(prop_id, f"UNKNOWN({prop_id})")
|
||||
|
||||
|
||||
def decode_selector(selector: int) -> str:
|
||||
@@ -205,14 +23,14 @@ def decode_selector(selector: int) -> str:
|
||||
part_val = (selector >> 16) & 0xFF
|
||||
state_val = selector & 0xFFFF
|
||||
|
||||
part_str = _PART_NAMES.get(part_val, f"PART({part_val:#x})")
|
||||
part_str = PART_NAMES.get(part_val, f"PART({part_val:#x})")
|
||||
|
||||
if state_val == 0:
|
||||
state_str = "DEFAULT"
|
||||
elif state_val == 0xFFFF:
|
||||
state_str = "ANY"
|
||||
else:
|
||||
flags = [name for bit, name in _STATE_FLAGS.items() if state_val & bit]
|
||||
flags = [name for bit, name in STATE_FLAGS.items() if state_val & bit]
|
||||
state_str = "|".join(flags) if flags else f"STATE({state_val:#x})"
|
||||
|
||||
return f"{part_str}|{state_str}"
|
||||
@@ -221,14 +39,14 @@ def decode_selector(selector: int) -> str:
|
||||
def format_style_value(prop_id: int, value: Value) -> str:
|
||||
"""Format a style value based on property type."""
|
||||
try:
|
||||
if prop_id in _COLOR_PROPS:
|
||||
if prop_id in COLOR_PROPS:
|
||||
color = value.color
|
||||
r = int(color.red) & 0xFF
|
||||
g = int(color.green) & 0xFF
|
||||
b = int(color.blue) & 0xFF
|
||||
block = f"\033[48;2;{r};{g};{b}m \033[0m"
|
||||
return f"#{r:02x}{g:02x}{b:02x} {block}"
|
||||
elif prop_id in _POINTER_PROPS:
|
||||
elif prop_id in POINTER_PROPS:
|
||||
ptr = int(value.ptr)
|
||||
return f"{ptr:#x}" if ptr else "NULL"
|
||||
else:
|
||||
|
||||
193
scripts/gdb/lvglgdb/lvgl/misc/lv_style_consts.py
Normal file
193
scripts/gdb/lvglgdb/lvgl/misc/lv_style_consts.py
Normal file
@@ -0,0 +1,193 @@
|
||||
"""
|
||||
Auto-generated style constants from LVGL headers.
|
||||
|
||||
Do not edit manually. Regenerate with:
|
||||
python3 scripts/gen_style_consts.py
|
||||
"""
|
||||
|
||||
STYLE_PROP_NAMES = {
|
||||
1: "WIDTH",
|
||||
2: "HEIGHT",
|
||||
3: "LENGTH",
|
||||
4: "TRANSFORM_WIDTH",
|
||||
5: "TRANSFORM_HEIGHT",
|
||||
8: "MIN_WIDTH",
|
||||
9: "MAX_WIDTH",
|
||||
10: "MIN_HEIGHT",
|
||||
11: "MAX_HEIGHT",
|
||||
12: "TRANSLATE_X",
|
||||
13: "TRANSLATE_Y",
|
||||
14: "RADIAL_OFFSET",
|
||||
16: "X",
|
||||
17: "Y",
|
||||
18: "ALIGN",
|
||||
24: "PAD_TOP",
|
||||
25: "PAD_BOTTOM",
|
||||
26: "PAD_LEFT",
|
||||
27: "PAD_RIGHT",
|
||||
28: "PAD_RADIAL",
|
||||
29: "PAD_ROW",
|
||||
30: "PAD_COLUMN",
|
||||
32: "MARGIN_TOP",
|
||||
33: "MARGIN_BOTTOM",
|
||||
34: "MARGIN_LEFT",
|
||||
35: "MARGIN_RIGHT",
|
||||
40: "BG_GRAD",
|
||||
41: "BG_GRAD_DIR",
|
||||
42: "BG_MAIN_OPA",
|
||||
43: "BG_GRAD_OPA",
|
||||
44: "BG_GRAD_COLOR",
|
||||
45: "BG_MAIN_STOP",
|
||||
46: "BG_GRAD_STOP",
|
||||
48: "BG_IMAGE_SRC",
|
||||
49: "BG_IMAGE_OPA",
|
||||
50: "BG_IMAGE_RECOLOR_OPA",
|
||||
51: "BG_IMAGE_TILED",
|
||||
52: "BG_IMAGE_RECOLOR",
|
||||
56: "BORDER_WIDTH",
|
||||
57: "BORDER_COLOR",
|
||||
58: "BORDER_OPA",
|
||||
59: "BORDER_POST",
|
||||
60: "BORDER_SIDE",
|
||||
64: "OUTLINE_WIDTH",
|
||||
65: "OUTLINE_COLOR",
|
||||
66: "OUTLINE_OPA",
|
||||
67: "OUTLINE_PAD",
|
||||
72: "BG_OPA",
|
||||
73: "BG_COLOR",
|
||||
74: "SHADOW_WIDTH",
|
||||
75: "LINE_WIDTH",
|
||||
76: "ARC_WIDTH",
|
||||
77: "TEXT_FONT",
|
||||
78: "IMAGE_RECOLOR_OPA",
|
||||
80: "IMAGE_OPA",
|
||||
81: "SHADOW_OPA",
|
||||
82: "LINE_OPA",
|
||||
83: "ARC_OPA",
|
||||
84: "TEXT_OPA",
|
||||
88: "SHADOW_COLOR",
|
||||
89: "IMAGE_RECOLOR",
|
||||
90: "LINE_COLOR",
|
||||
91: "ARC_COLOR",
|
||||
92: "TEXT_COLOR",
|
||||
96: "ARC_IMAGE_SRC",
|
||||
97: "SHADOW_OFFSET_X",
|
||||
98: "SHADOW_OFFSET_Y",
|
||||
99: "SHADOW_SPREAD",
|
||||
100: "LINE_DASH_WIDTH",
|
||||
101: "TEXT_ALIGN",
|
||||
102: "TEXT_LETTER_SPACE",
|
||||
103: "TEXT_LINE_SPACE",
|
||||
104: "LINE_DASH_GAP",
|
||||
105: "LINE_ROUNDED",
|
||||
106: "IMAGE_COLORKEY",
|
||||
107: "TEXT_OUTLINE_STROKE_WIDTH",
|
||||
108: "TEXT_OUTLINE_STROKE_OPA",
|
||||
109: "TEXT_OUTLINE_STROKE_COLOR",
|
||||
110: "TEXT_DECOR",
|
||||
111: "ARC_ROUNDED",
|
||||
112: "OPA",
|
||||
113: "OPA_LAYERED",
|
||||
114: "COLOR_FILTER_DSC",
|
||||
115: "COLOR_FILTER_OPA",
|
||||
116: "ANIM",
|
||||
117: "ANIM_DURATION",
|
||||
118: "TRANSITION",
|
||||
120: "RADIUS",
|
||||
121: "BITMAP_MASK_SRC",
|
||||
122: "BLEND_MODE",
|
||||
123: "ROTARY_SENSITIVITY",
|
||||
124: "TRANSLATE_RADIAL",
|
||||
128: "CLIP_CORNER",
|
||||
129: "BASE_DIR",
|
||||
130: "RECOLOR",
|
||||
131: "RECOLOR_OPA",
|
||||
132: "LAYOUT",
|
||||
136: "BLUR_RADIUS",
|
||||
137: "BLUR_BACKDROP",
|
||||
138: "BLUR_QUALITY",
|
||||
144: "DROP_SHADOW_RADIUS",
|
||||
145: "DROP_SHADOW_OFFSET_X",
|
||||
146: "DROP_SHADOW_OFFSET_Y",
|
||||
147: "DROP_SHADOW_COLOR",
|
||||
148: "DROP_SHADOW_OPA",
|
||||
149: "DROP_SHADOW_QUALITY",
|
||||
152: "TRANSFORM_SCALE_X",
|
||||
153: "TRANSFORM_SCALE_Y",
|
||||
154: "TRANSFORM_PIVOT_X",
|
||||
155: "TRANSFORM_PIVOT_Y",
|
||||
156: "TRANSFORM_ROTATION",
|
||||
157: "TRANSFORM_SKEW_X",
|
||||
158: "TRANSFORM_SKEW_Y",
|
||||
160: "FLEX_FLOW",
|
||||
161: "FLEX_MAIN_PLACE",
|
||||
162: "FLEX_CROSS_PLACE",
|
||||
163: "FLEX_TRACK_PLACE",
|
||||
164: "FLEX_GROW",
|
||||
165: "GRID_COLUMN_DSC_ARRAY",
|
||||
166: "GRID_ROW_DSC_ARRAY",
|
||||
168: "GRID_COLUMN_ALIGN",
|
||||
169: "GRID_ROW_ALIGN",
|
||||
170: "GRID_CELL_COLUMN_POS",
|
||||
171: "GRID_CELL_COLUMN_SPAN",
|
||||
172: "GRID_CELL_X_ALIGN",
|
||||
173: "GRID_CELL_ROW_POS",
|
||||
174: "GRID_CELL_ROW_SPAN",
|
||||
175: "GRID_CELL_Y_ALIGN",
|
||||
}
|
||||
|
||||
PART_NAMES = {
|
||||
0x00: "MAIN",
|
||||
0x01: "SCROLLBAR",
|
||||
0x02: "INDICATOR",
|
||||
0x03: "KNOB",
|
||||
0x04: "SELECTED",
|
||||
0x05: "ITEMS",
|
||||
0x06: "CURSOR",
|
||||
0x08: "CUSTOM_FIRST",
|
||||
0x0F: "ANY",
|
||||
}
|
||||
|
||||
STATE_FLAGS = {
|
||||
0x0001: "ALT",
|
||||
0x0004: "CHECKED",
|
||||
0x0008: "FOCUSED",
|
||||
0x0010: "FOCUS_KEY",
|
||||
0x0020: "EDITED",
|
||||
0x0040: "HOVERED",
|
||||
0x0080: "PRESSED",
|
||||
0x0100: "SCROLLED",
|
||||
0x0200: "DISABLED",
|
||||
0x1000: "USER_1",
|
||||
0x2000: "USER_2",
|
||||
0x4000: "USER_3",
|
||||
0x8000: "USER_4",
|
||||
}
|
||||
|
||||
COLOR_PROPS = {
|
||||
44, # BG_GRAD_COLOR
|
||||
52, # BG_IMAGE_RECOLOR
|
||||
57, # BORDER_COLOR
|
||||
65, # OUTLINE_COLOR
|
||||
73, # BG_COLOR
|
||||
88, # SHADOW_COLOR
|
||||
89, # IMAGE_RECOLOR
|
||||
90, # LINE_COLOR
|
||||
91, # ARC_COLOR
|
||||
92, # TEXT_COLOR
|
||||
109, # TEXT_OUTLINE_STROKE_COLOR
|
||||
130, # RECOLOR
|
||||
147, # DROP_SHADOW_COLOR
|
||||
}
|
||||
|
||||
POINTER_PROPS = {
|
||||
40, # BG_GRAD
|
||||
48, # BG_IMAGE_SRC
|
||||
77, # TEXT_FONT
|
||||
96, # ARC_IMAGE_SRC
|
||||
106, # IMAGE_COLORKEY
|
||||
114, # COLOR_FILTER_DSC
|
||||
116, # ANIM
|
||||
118, # TRANSITION
|
||||
121, # BITMAP_MASK_SRC
|
||||
}
|
||||
248
scripts/gdb/scripts/gen_style_consts.py
Normal file
248
scripts/gdb/scripts/gen_style_consts.py
Normal file
@@ -0,0 +1,248 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Generate style constant tables from LVGL header files.
|
||||
|
||||
Parses lv_style.h, lv_obj_style.h, and lv_style_gen.h to produce
|
||||
lv_style_consts.py used by the lvglgdb GDB plugin.
|
||||
|
||||
Usage:
|
||||
python3 scripts/gen_style_consts.py
|
||||
"""
|
||||
|
||||
import re
|
||||
from pathlib import Path
|
||||
|
||||
SCRIPT_DIR = Path(__file__).parent
|
||||
GDB_ROOT = SCRIPT_DIR.parent
|
||||
LVGL_SRC = GDB_ROOT.parent.parent / "src"
|
||||
OUTPUT = GDB_ROOT / "lvglgdb" / "lvgl" / "misc" / "lv_style_consts.py"
|
||||
|
||||
STYLE_H = LVGL_SRC / "misc" / "lv_style.h"
|
||||
OBJ_STYLE_H = LVGL_SRC / "core" / "lv_obj_style.h"
|
||||
STYLE_GEN_H = LVGL_SRC / "misc" / "lv_style_gen.h"
|
||||
|
||||
|
||||
def parse_style_props(path: Path) -> dict[int, str]:
|
||||
"""Parse _lv_style_id_t enum from lv_style.h."""
|
||||
text = path.read_text()
|
||||
|
||||
# Extract enum block
|
||||
m = re.search(r"enum\s+_lv_style_id_t\s*\{(.*?)\}", text, re.DOTALL)
|
||||
if not m:
|
||||
raise RuntimeError("Cannot find _lv_style_id_t enum")
|
||||
|
||||
props = {}
|
||||
current_val = 0
|
||||
for line in m.group(1).splitlines():
|
||||
line = line.strip().rstrip(",")
|
||||
if (
|
||||
not line
|
||||
or line.startswith("/*")
|
||||
or line.startswith("//")
|
||||
or line.startswith("*")
|
||||
):
|
||||
continue
|
||||
|
||||
# Match: LV_STYLE_XXX = value or LV_STYLE_XXX (auto-increment)
|
||||
match = re.match(r"(LV_STYLE_\w+)\s*=\s*(0x[\da-fA-F]+|\d+)", line)
|
||||
if match:
|
||||
name = match.group(1)
|
||||
val_str = match.group(2)
|
||||
current_val = int(val_str, 0)
|
||||
else:
|
||||
match = re.match(r"(LV_STYLE_\w+)", line)
|
||||
if not match:
|
||||
continue
|
||||
name = match.group(1)
|
||||
|
||||
# Skip meta entries
|
||||
if name in (
|
||||
"LV_STYLE_PROP_INV",
|
||||
"LV_STYLE_PROP_ANY",
|
||||
"LV_STYLE_PROP_CONST",
|
||||
"LV_STYLE_LAST_BUILT_IN_PROP",
|
||||
"LV_STYLE_NUM_BUILT_IN_PROPS",
|
||||
):
|
||||
current_val += 1
|
||||
continue
|
||||
|
||||
short = name.removeprefix("LV_STYLE_")
|
||||
props[current_val] = short
|
||||
current_val += 1
|
||||
|
||||
return props
|
||||
|
||||
|
||||
def parse_parts(path: Path) -> dict[int, str]:
|
||||
"""Parse lv_part_t enum from lv_obj_style.h."""
|
||||
text = path.read_text()
|
||||
m = re.search(r"typedef\s+enum\s*\{(.*?)\}\s*lv_part_t", text, re.DOTALL)
|
||||
if not m:
|
||||
raise RuntimeError("Cannot find lv_part_t enum")
|
||||
|
||||
parts = {}
|
||||
for line in m.group(1).splitlines():
|
||||
match = re.match(r"\s*(LV_PART_\w+)\s*=\s*(0x[\da-fA-F]+|\d+)", line)
|
||||
if not match:
|
||||
continue
|
||||
name = match.group(1)
|
||||
val = int(match.group(2), 0)
|
||||
short = name.removeprefix("LV_PART_")
|
||||
# Selector uses bits [23:16], shift down to get the key
|
||||
parts[val >> 16] = short
|
||||
|
||||
return parts
|
||||
|
||||
|
||||
def _parse_int_expr(expr: str) -> int | None:
|
||||
"""Parse a C integer expression: decimal, hex, or '1 << N'."""
|
||||
expr = expr.strip()
|
||||
m = re.match(r"^(0x[\da-fA-F]+|\d+)$", expr)
|
||||
if m:
|
||||
return int(m.group(1), 0)
|
||||
m = re.match(r"^(\d+)\s*<<\s*(\d+)$", expr)
|
||||
if m:
|
||||
return int(m.group(1)) << int(m.group(2))
|
||||
return None
|
||||
|
||||
|
||||
def parse_states(path: Path) -> dict[int, str]:
|
||||
"""Parse lv_state_t enum from lv_obj_style.h."""
|
||||
text = path.read_text()
|
||||
m = re.search(r"typedef\s+enum\s*\{(.*?)\}\s*lv_state_t", text, re.DOTALL)
|
||||
if not m:
|
||||
raise RuntimeError("Cannot find lv_state_t enum")
|
||||
|
||||
states = {}
|
||||
for line in m.group(1).splitlines():
|
||||
match = re.match(r"\s*(LV_STATE_\w+)\s*=\s*(.+?)(?:,|/)", line)
|
||||
if not match:
|
||||
continue
|
||||
name = match.group(1)
|
||||
expr = match.group(2).strip()
|
||||
|
||||
# Skip DEFAULT (0) and ANY (0xFFFF)
|
||||
if name in ("LV_STATE_DEFAULT", "LV_STATE_ANY"):
|
||||
continue
|
||||
|
||||
val = _parse_int_expr(expr)
|
||||
if val is None:
|
||||
continue
|
||||
short = name.removeprefix("LV_STATE_")
|
||||
states[val] = short
|
||||
|
||||
return states
|
||||
|
||||
|
||||
def parse_color_props(style_gen_h: Path, prop_map: dict[int, str]) -> set[int]:
|
||||
"""Identify color properties from lv_style_gen.h setter signatures."""
|
||||
text = style_gen_h.read_text()
|
||||
name_to_id = {v: k for k, v in prop_map.items()}
|
||||
|
||||
color_ids = set()
|
||||
for match in re.finditer(
|
||||
r"void\s+lv_style_set_(\w+)\s*\([^,]+,\s*lv_color_t", text
|
||||
):
|
||||
prop_name = match.group(1).upper()
|
||||
if prop_name in name_to_id:
|
||||
color_ids.add(name_to_id[prop_name])
|
||||
|
||||
return color_ids
|
||||
|
||||
|
||||
def parse_pointer_props(style_gen_h: Path, prop_map: dict[int, str]) -> set[int]:
|
||||
"""Identify pointer properties from lv_style_gen.h setter signatures."""
|
||||
text = style_gen_h.read_text()
|
||||
name_to_id = {v: k for k, v in prop_map.items()}
|
||||
|
||||
ptr_ids = set()
|
||||
for match in re.finditer(
|
||||
r"void\s+lv_style_set_(\w+)\s*\([^,]+,\s*(?:const\s+)?(?:void|lv_\w+)\s*\*",
|
||||
text,
|
||||
):
|
||||
prop_name = match.group(1).upper()
|
||||
if prop_name in name_to_id:
|
||||
ptr_ids.add(name_to_id[prop_name])
|
||||
|
||||
return ptr_ids
|
||||
|
||||
|
||||
def generate(
|
||||
props: dict[int, str],
|
||||
parts: dict[int, str],
|
||||
states: dict[int, str],
|
||||
color_ids: set[int],
|
||||
pointer_ids: set[int],
|
||||
) -> str:
|
||||
"""Generate Python source for the constants module."""
|
||||
lines = [
|
||||
'"""',
|
||||
"Auto-generated style constants from LVGL headers.",
|
||||
"",
|
||||
"Do not edit manually. Regenerate with:",
|
||||
" python3 scripts/gen_style_consts.py",
|
||||
'"""',
|
||||
"",
|
||||
]
|
||||
|
||||
# STYLE_PROP_NAMES
|
||||
lines.append("STYLE_PROP_NAMES = {")
|
||||
for k in sorted(props):
|
||||
lines.append(f' {k}: "{props[k]}",')
|
||||
lines.append("}")
|
||||
lines.append("")
|
||||
|
||||
# PART_NAMES
|
||||
lines.append("PART_NAMES = {")
|
||||
for k in sorted(parts):
|
||||
lines.append(f' 0x{k:02X}: "{parts[k]}",')
|
||||
lines.append("}")
|
||||
lines.append("")
|
||||
|
||||
# STATE_FLAGS
|
||||
lines.append("STATE_FLAGS = {")
|
||||
for k in sorted(states):
|
||||
lines.append(f' 0x{k:04X}: "{states[k]}",')
|
||||
lines.append("}")
|
||||
lines.append("")
|
||||
|
||||
# COLOR_PROPS
|
||||
if color_ids:
|
||||
lines.append("COLOR_PROPS = {")
|
||||
for v in sorted(color_ids):
|
||||
lines.append(f" {v}, # {props.get(v, '?')}")
|
||||
lines.append("}")
|
||||
else:
|
||||
lines.append("COLOR_PROPS = set()")
|
||||
lines.append("")
|
||||
|
||||
# POINTER_PROPS
|
||||
if pointer_ids:
|
||||
lines.append("POINTER_PROPS = {")
|
||||
for v in sorted(pointer_ids):
|
||||
lines.append(f" {v}, # {props.get(v, '?')}")
|
||||
lines.append("}")
|
||||
else:
|
||||
lines.append("POINTER_PROPS = set()")
|
||||
lines.append("")
|
||||
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
def main():
|
||||
props = parse_style_props(STYLE_H)
|
||||
parts = parse_parts(OBJ_STYLE_H)
|
||||
states = parse_states(OBJ_STYLE_H)
|
||||
color_ids = parse_color_props(STYLE_GEN_H, props)
|
||||
pointer_ids = parse_pointer_props(STYLE_GEN_H, props)
|
||||
|
||||
src = generate(props, parts, states, color_ids, pointer_ids)
|
||||
OUTPUT.write_text(src)
|
||||
print(
|
||||
f"Generated {OUTPUT} ({len(props)} props, {len(parts)} parts, "
|
||||
f"{len(states)} states, {len(color_ids)} color, {len(pointer_ids)} pointer)"
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user