UI 工程与资源生成工具
AC82N SDK 中用于设计和生成 UI 资源的 PC 端工具链,包含 Qt 界面编辑工具(QtToolBin / QTToolJson)、资源编译器(ResBuilder)以及支撑两者的控件定义与类型映射配置体系,最终产出固件可消费的资源包和版本头文件。
Purpose and Scope
本页覆盖 doc/软件工具/图片资源生成工具/UI工程/UITools/ 目录下的完整工具链:
- UI 工程编辑器:
QtToolBin.exe、QTToolJson 1.1.exe - 资源生成器:
ResBuilder.exe、Resbuilder.dat - 控件定义体系:
control/control.json与control/ex/*.json(扩展控件) - 类型 ID 映射:
config/ini/option.ini - 生成产物:
res_ver.h(资源版本头文件) - 工程配置:
Application Data/ui-config、backgrounds/slider.json
本页不覆盖以下兄弟主题(由其他目录页负责):
- 显示引擎运行时(
display-ui相关目录):资源包在固件中的解析、渲染与交互机制 - 资源制作规范(如 Photoshop 切图、
背景/背景图制作流程):本页聚焦工具与配置本身 - 其他软件工具(
doc/软件工具/下与图片资源无关的工具)
注意:仓库中仅提供工具的二进制文件(
.exe/.dat)与配置文件,工具的 C++/Qt 源码不在本仓库内。因此本页对工具内部算法的描述以配置文件与生成产物的可验证行为为准,二进制内部实现细节标注为"仓库中未提供源码"。
Overview
AC82N 系列芯片面向带屏 MCU 产品(如运动手环、手表等)。其 UI 开发采用典型的"工程-资源分离"流水线:
- 设计期:UI 设计者在 PC 上用 Qt 工具(
QtToolBin.exe)打开/创建 UI 工程,通过拖拽控件(按钮、图片列表、电池、时间、进度条等)编排页面,控件的外观与行为由control.json中声明的属性模板驱动(即"所见即所得"的元数据驱动编辑器)。 - 生成期:设计完成后,由
ResBuilder.exe(配套Resbuilder.dat数据文件)将工程编译为固件可烧录的二进制资源包,并输出res_ver.h版本头文件——其中的IMAGE_VERION/STRING_VERION宏供固件代码校验资源版本,防止固件与资源包不匹配。 - 运行期:固件将资源包烧入 Flash,由显示引擎按控件 ID 与类型 ID 解析并渲染。
该设计的关键意图:
- 元数据驱动:控件模板(JSON)与类型 ID(INI)与工具二进制解耦,新增控件只需添加模板文件 + 分配 ID,无需改动工具本体——这正是
control/ex/扩展机制存在的意义。 - 版本可校验:资源包携带哈希版本号,固件启动时可据此检测资源缺失/过期,这是嵌入式场景下资源与代码频繁迭代时的重要安全网。
- 中英双语映射:
option.ini中同时存在英文与中文控件名,说明工具界面支持多语言,且类型 ID 是唯一稳定标识(同一控件的中英文名映射到同一个 ID)。
Architecture
flowchart TD
subgraph sg_Editor["设计期(PC 工具)"]
QtTool["QtToolBin.exe<br/>QTToolJson 1.1.exe"]
UIConfig["Application Data/ui-config<br/>背景 backgrounds/slider.json"]
QtTool -->|"打开/编辑工程"| UIConfig
end
subgraph sg_Defs["控件定义层(元数据)"]
CtrlJson["control/control.json<br/>内置控件模板"]
CtrlEx["control/ex/*.json<br/>扩展控件模板"]
OptionIni["config/ini/option.ini<br/>控件类型 ID 映射"]
end
subgraph sg_Gen["生成期(资源编译器)"]
ResBuilder["ResBuilder.exe + Resbuilder.dat"]
ResVerH["res_ver.h<br/>IMAGE_VERION / STRING_VERION"]
ResPack["资源包(烧录到 Flash)"]
end
subgraph sg_Run["运行期(固件)"]
DisplayEngine["显示引擎<br/>(见 display-ui 页面)"]
end
CtrlJson --> QtTool
CtrlEx --> QtTool
OptionIni --> QtTool
QtTool -->|"导出工程/数据"| ResBuilder
CtrlJson --> ResBuilder
CtrlEx --> ResBuilder
OptionIni --> ResBuilder
ResBuilder --> ResVerH
ResBuilder --> ResPack
ResPack --> DisplayEngine
ResVerH -->|"版本校验宏"| DisplayEngine
架构解读:
- 控件定义层是工具链的"契约":
control.json(内置控件)与control/ex/*.json(扩展控件)同时被编辑器和资源生成器消费,保证"编辑器里看到的样子"与"生成器编译的结果"一致;option.ini则把控件名映射为稳定的整数类型 ID,作为编辑器、生成器、固件三者之间传递的紧凑标识。 - 生成器是设计期到运行期的桥梁:
ResBuilder.exe把 UI 工程(页面布局、控件属性、图片引用)编译为二进制资源包,并同步产出res_ver.h——固件通过它校验资源版本。 - 运行时引擎是消费端:资源包的解析、渲染、事件分发属于显示引擎(本仓库
display-ui相关目录)的职责,不在本页展开。
工具链组成与分工
| 文件 | 角色 | 形态 |
|---|---|---|
QtToolBin.exe | UI 工程编辑器(Qt 桌面程序) | 二进制,无源码 |
QTToolJson 1.1.exe | JSON 版 UI 工程编辑器 | 二进制,无源码 |
ResBuilder.exe | 资源生成器(编译 UI 工程为资源包) | 二进制,无源码 |
Resbuilder.dat | 资源生成器的数据/规则文件 | 二进制数据 |
control/control.json | 内置控件属性模板(Battery、ImageList、Text 等) | JSON |
control/ex/*.json | 扩展控件模板(progressbar、slider、watch 等) | JSON |
config/ini/option.ini | 控件名 → 类型 ID 映射、图片格式 ID | INI |
Application Data/ui-config | UI 工程工程级配置 | 文本(键值) |
backgrounds/slider.json | 背景控件(滑杆)默认模板 | JSON + PNG |
res_ver.h | 生成产物:资源版本头文件 | C 头文件(自动生成) |
设计意图:工具以数据驱动方式工作——控件的外观属性、事件、默认值全部外置在 JSON 模板中,工具二进制只负责渲染与编译;这样即使工具本体不随 SDK 发布源码,用户仍可通过模板完全控制编辑器行为,并为固件团队提供了可审计的"生成规则"。
控件定义体系(control.json)
control/control.json 是编辑器的控件模板库,以 compoents 数组形式声明每个控件的元数据。每个控件条目包含:-class(基类)、-name/-type(标识名)、caption(中文显示名)、icon(工具栏图标)、property(属性列表)、tip、version、widget。
以 Battery(电池电量)控件为例,其声明结构如下:
{
"compoents": [
{
"-class": "NewFrame",
"-name": "Battery",
"-type": "Battery",
"caption": "电池电量",
"icon": "config\\images\\POR_dark4.png",
"property": [
{
"-name": "id",
"-type": "id",
"caption": "唯一ID号"
},
{
"-name": "element_css",
"-type": "struct",
"caption": "CSS元素",
"struct": [
{
"-name": "align",
"-type": "enum",
"caption": "对齐方式",
"default": "ALIGN_CENTER",
"enum": [
{ "ALIGN_LEFT": 0 },
{ "ALIGN_CENTER": 1 },
{ "ALIGN_RIGHT": 2 }
]
},
{
"-name": "rect",
"-type": "rect",
"caption": "坐标",
"rect": { "height": 25, "width": 75, "x": 0, "y": 0 }
}
]
},
{
"-name": "image",
"-type": "piclist",
"caption": "电量图片列表",
"default": "config\\images\\battery0.png",
"list": [
"config\\images\\battery0.png",
"config\\images\\battery4.png",
"config\\images\\battery1.png",
"config\\images\\battery2.png",
"config\\images\\battery3.png"
],
"maxlength": 0
},
{
"-name": "action",
"-type": "action",
"caption": "事件属性",
"action": [
{
"-name": "event",
"-type": "enum",
"caption": "事件",
"default": "KEY_OK",
"enum": [
{ "KEY_OK": 13 },
{ "KEY_CANCLE": 14 },
{ "KEY_MENU": 15 },
{ "KEY_MODE": 16 },
{ "KEY_LEFT": 37 },
{ "KEY_UP": 38 },
{ "KEY_RIGHT": 39 },
{ "KEY_DOWN": 40 },
{ "TOUCH_DOWN": 129 },
{ "TOUCH_UP": 130 },
{ "TOUCH_MOVE": 131 },
{ "TOUCH_HOLD": 132 },
{ "TOUCH_CLICK": 133 },
{ "TOUCH_DOUBLE_CLICK": 134 },
{ "ON_CHANGE_INIT": 151 },
{ "ENUM_KEY": 1 }
]
},
{
"-name": "action",
"-type": "enum",
"caption": "动作",
"default": "SHOW",
"enum": [
{ "SHOW": 0 },
{ "HIDE": 1 }
]
}
]
}
],
"tip": "",
"version": "1",
"widget": []
}
]
}
Source: control.json
属性类型(-type)语义
从上述模板可归纳出编辑器支持的属性类型体系:
| 类型 | 含义 | 典型用途 |
|---|---|---|
id | 控件唯一 ID | 每个控件必备,固件按 ID 索引 |
struct | 结构体属性(可嵌套) | element_css:CSS 风格样式(对齐、隐藏、标志、坐标、背景、边框) |
enum | 枚举选择 | 对齐方式、事件类型、动作等 |
rect | 矩形坐标 {x, y, width, height} | 控件位置与尺寸 |
background-color | 背景色(如 #368FEE) | 纯色背景 |
background-image | 背景图片 | 位图背景 |
border | 边框 {top,left,right,bottom} + 灰阶色 | 描边样式 |
piclist | 图片列表(多帧图) | 电量 5 帧图、充电图 |
action | 事件-动作绑定 | 按键/触摸事件 → SHOW/HIDE 等动作 |
text-str | 字符串参数 | action 的 object/args |
事件编码的关键观察
action.event 的枚举值与固件输入事件一一对应:KEY_OK=13、KEY_CANCLE=14、KEY_MENU=15、KEY_MODE=16 为实体按键;KEY_LEFT=37 至 KEY_DOWN=40 为方向键(与 PC 扫描码一致);TOUCH_DOWN=129 至 TOUCH_DOUBLE_CLICK=134 为触摸事件;ON_CHANGE_INIT=151 为初始化回调事件。这些数值就是固件显示引擎 KEY_EVENT/TOUCH_EVENT 的协议值——编辑器生成的工程文件在编译后直接以这些数值写入资源包,运行时不需再做字符串解析,这是嵌入式资源紧凑化设计的体现。
扩展控件机制(control/ex/)
内置控件之外,工具通过 control/ex/*.json 提供扩展控件模板,每个扩展控件同时附带一张预览图(.png)。仓库中已包含:
| 扩展控件文件 | 控件 | 相关类型 ID(见 option.ini) |
|---|---|---|
multiprogressbar.json | 多段进度条 | multiprogressbar=22、multiprogressbar_highlight=23 |
progressbar.json | 进度条 | progressbar=20、progressbar_highlight=21 |
slider.json | 横向滑杆 | slider=28、right_pic=29、left_pic=30、slider_pic=31、slider_text=32 |
vslider.json | 纵向滑杆 | vslider=33、vslider_right_pic=34、vslider_left_pic=35、vslider_pic=36、vslider_text=37 |
watch.json | 表盘 | watch=24、watch_hour=25、watch_min=26、watch_sec=27 |
设计意图:复杂控件(滑杆、表盘)由多个部件(子图/子文本)组合而成,因此一个控件会占用一组连续的类型 ID。例如 slider 占 28~32 共 5 个 ID(控件本体 + 右图 + 左图 + 滑块图 + 文本),watch 占 24~27 共 4 个 ID(表盘 + 时针 + 分针 + 秒针)。这种"ID 段"分配方式让固件端可以按 ID 区间批量注册子元素,同时保持每个部件独立可寻址。
扩展控件的 JSON 结构与 control.json 中内置控件一致(同为 -class/-name/-type/property 模式),backgrounds/slider.json 则表明背景同样可作为可配置对象(带默认 PNG 预览)。
控件类型 ID 映射(option.ini)
config/ini/option.ini 是工具链的类型 ID 中枢,分 [Control] 与 [Picture] 两段:
[Control]
window=1
project=1
ScenesScreen=2
page=2
NewLayout=3
NewLayer=4
NewGrid=5
VerticalList=5
HorizontalList=5
Button=7
ImageList=8
Battery=9
Time=10
Camera=11
Text=12
animation=13
player=14
number=15
窗口=1
工程=1
页面=2
布局=3
图层=4
表格控件=5
垂直列表=5
水平列表=5
按钮=7
图片=8
电池电量=9
时间=10
文字=12
动画=13
播放器=14
数字=15
progressbar = 20
progressbar_highlight = 21
multiprogressbar = 22
multiprogressbar_highlight = 23
watch=24
watch_hour=25
watch_min=26
watch_sec=27
slider=28
right_pic=29
left_pic=30
slider_pic=31
slider_text=32
vslider=33
vslider_right_pic=34
vslider_left_pic=35
vslider_pic=36
vslider_text=37
[Picture]
png=233
Source: option.ini
要点:
- 多对一映射:同一类型 ID 可有多个名称——
window与工程(中文)都映射到 1;ScenesScreen、page、页面都映射到 2;NewGrid、VerticalList、HorizontalList、表格控件、垂直列表、水平列表都映射到 5。这说明 5 表示"容器/列表"这一类控件,编辑器按语境选择显示名,但生成的类型 ID 统一。 - ID 区间规划:1~15 为内置基础控件;20 起为扩展控件及其部件(见上节);ID 是资源包的协议字段,固件显示引擎按此 ID 区分控件类型进行渲染。
- 图片格式 ID:
[Picture] png=233将 PNG 格式映射为格式 ID 233,指示资源生成器以该格式压缩/编码图片资源。
资源版本头文件(res_ver.h)
res_ver.h 是 ResBuilder 的生成产物,供固件代码包含以校验资源版本:
#ifndef __RES_VER_H__
#define __RES_VER_H__
/* Generated By ResBuilder In 2020-01-07 15:16:30 */
#define IMAGE_VERION 0xd9ba4727
#define STRING_VERION 0x0c1b27ae
#endif
Source: res_ver.h
要点:
- 文件头注释记录生成工具与时间戳(
Generated By ResBuilder In 2020-01-07 15:16:30),便于追溯资源包由哪个版本的工具在何时生成。 IMAGE_VERION(注意拼写为 VERION,非 VERSION,属工具原始命名,固件端需保持一致)是图片资源的哈希版本;STRING_VERION是字符串资源(多语言文本)的哈希版本。两者独立,因为图片与字符串通常独立打包、独立更新。- 版本值(如
0xd9ba4727)由 ResBuilder 根据资源内容计算,固件在启动/挂载资源时比对,不一致则提示或回退,防止"固件新、资源旧"导致的渲染错乱——这是嵌入式 UI 迭代中常见的故障源。
核心流程:从 UI 工程到资源包
sequenceDiagram
participant D as UI 设计者
participant Q as QtToolBin / QTToolJson
participant T as 控件模板<br/>control.json + ex/*.json + option.ini
participant R as ResBuilder.exe<br/>+ Resbuilder.dat
participant H as res_ver.h
participant F as 固件显示引擎
D->>Q: 新建/打开 UI 工程(ui-config)
Q->>T: 加载控件模板与类型 ID
Q->>Q: 拖拽控件、设置属性(坐标/图片/事件)
D->>Q: 保存工程(页面/控件数据 + 图片引用)
Q->>R: 导出工程数据
R->>T: 读取控件定义与类型映射
R->>R: 编码图片(PNG→格式ID 233)<br/>编译控件/页面为二进制资源
R->>H: 生成版本头文件<br/>IMAGE_VERION / STRING_VERION
R-->>F: 输出资源包(烧录 Flash)
F->>H: 启动时比对资源版本
F->>F: 按类型 ID 解析控件并渲染
流程说明:
- 工程编辑:设计者用
QtToolBin.exe(或 JSON 版QTToolJson 1.1.exe)创建 UI 工程,工程级配置保存在Application Data/ui-config;编辑器依据control.json与control/ex/*.json渲染控件面板,依据option.ini为每个控件分配类型 ID。 - 数据导出:设计完成后导出工程数据(页面树、控件属性、图片路径),交由
ResBuilder.exe编译。 - 资源编译:
ResBuilder以Resbuilder.dat为规则数据,把 PNG 图片按格式 ID 233 编码、把控件树/事件按类型 ID 序列化,产出紧凑的二进制资源包;同时把资源内容的哈希写入res_ver.h。 - 烧录与校验:资源包随固件烧入 Flash;显示引擎启动时读取
res_ver.h中的版本宏与资源包内嵌版本比对,一致才挂载,从而避免资源与固件版本错配。
使用示例
示例 1:为扩展控件分配类型 ID(option.ini)
新增扩展控件时,先在 option.ini 的 [Control] 段为其本体与各部件分配连续 ID。仓库中 slider 的分配如下:
slider=28
right_pic=29
left_pic=30
slider_pic=31
slider_text=32
vslider=33
vslider_right_pic=34
vslider_left_pic=35
vslider_pic=36
vslider_text=37
Source: option.ini
滑杆被拆分为"本体 + 右图 + 左图 + 滑块图 + 文本"五个可独立寻址的部件,便于运行时分别更新状态(如随音量/进度移动滑块图)。
示例 2:控件模板中的属性声明(control.json)
模板中的每个属性决定编辑器属性面板的展示方式与默认值。Battery 控件的电量图片列表使用 piclist 类型,声明了 5 帧电量图(battery0~battery4)与充电图:
{
"-name": "image",
"-type": "piclist",
"caption": "电量图片列表",
"default": "config\\images\\battery0.png",
"list": [
"config\\images\\battery0.png",
"config\\images\\battery4.png",
"config\\images\\battery1.png",
"config\\images\\battery2.png",
"config\\images\\battery3.png"
],
"maxlength": 0
}
Source: control.json
maxlength: 0 表示帧数不限制;固件端 Battery 控件按"当前电量百分比 → 帧索引"的映射显示对应帧。注意 default 与 list 中的图片路径使用反斜杠相对路径(config\images\...),说明模板默认图存放于工具安装目录的 config/images/ 下,实际工程中应替换为工程图片。
示例 3:消费生成产物(res_ver.h)
固件代码包含生成的头文件即可获得资源版本宏(VERION 为工具原始命名,使用时应保持一致):
/* Generated By ResBuilder In 2020-01-07 15:16:30 */
#define IMAGE_VERION 0xd9ba4727
#define STRING_VERION 0x0c1b27ae
Source: res_ver.h
固件侧典型用法:将 IMAGE_VERION 与资源包头部的版本字段比对,不一致时拒绝挂载或提示升级,防止新旧资源混用导致 UI 错乱。
配置选项
option.ini — [Control] 段(控件类型 ID)
| 键(英文/中文) | 值(类型 ID) | 说明 |
|---|---|---|
window / 工程 | 1 | 工程/窗口根对象 |
ScenesScreen / page / 页面 | 2 | 页面(场景屏幕) |
NewLayout / 布局 | 3 | 布局容器 |
NewLayer / 图层 | 4 | 图层 |
NewGrid / VerticalList / HorizontalList / 表格控件 / 垂直列表 / 水平列表 | 5 | 表格/列表容器(多名称共用) |
Button / 按钮 | 7 | 按钮 |
ImageList / 图片 | 8 | 图片控件 |
Battery / 电池电量 | 9 | 电池电量控件 |
Time / 时间 | 10 | 时间控件 |
Camera | 11 | 摄像头控件 |
Text / 文字 | 12 | 文本控件 |
animation / 动画 | 13 | 动画控件 |
player / 播放器 | 14 | 播放器控件 |
number / 数字 | 15 | 数字控件 |
progressbar / progressbar_highlight | 20 / 21 | 进度条(本体/高亮) |
multiprogressbar / multiprogressbar_highlight | 22 / 23 | 多段进度条(本体/高亮) |
watch / watch_hour / watch_min / watch_sec | 24~27 | 表盘/时针/分针/秒针 |
slider / right_pic / left_pic / slider_pic / slider_text | 28~32 | 横向滑杆及其部件 |
vslider 及 vslider_* 部件 | 33~37 | 纵向滑杆及其部件 |
option.ini — [Picture] 段(图片格式 ID)
| 键 | 值 | 说明 |
|---|---|---|
png | 233 | PNG 图片编码格式 ID |
控件模板字段(control.json 条目级)
| 字段 | 类型 | 说明 |
|---|---|---|
-class | string | 基类名(如 NewFrame) |
-name / -type | string | 控件标识名(如 Battery) |
caption | string | 编辑器显示名(中文) |
icon | string | 工具栏图标相对路径 |
property | array | 属性定义数组 |
tip / version / widget | - | 提示文本 / 模板版本 / 附加控件数据 |
属性字段(property 条目级)
| 字段 | 类型 | 说明 |
|---|---|---|
-name | string | 属性名(固件序列化字段名) |
-type | string | 属性类型:id/struct/enum/rect/piclist/action/text-str/background-color/background-image/border |
caption | string | 属性中文名 |
default | mixed | 默认值 |
enum / list / rect / action / struct | mixed | 按类型携带的取值/结构定义 |
失败模式与边界情况
以下失败模式部分可从配置文件直接推断,部分属于该工作流的固有风险(工具二进制无源码,内部处理不可验证,特此说明):
- 资源版本不匹配:
res_ver.h的IMAGE_VERION/STRING_VERION与资源包内嵌版本不一致时,显示引擎可能渲染错乱或拒绝挂载。缓解:烧录时保证固件与资源包同步发布,用生成时间戳(Generated By ResBuilder In ...)辅助追溯。 - 扩展控件缺少类型 ID:在
control/ex/新增模板但未在option.ini分配 ID,或 ID 与已有控件冲突,会导致生成器序列化错误或运行时控件类型识别错误。缓解:遵循"连续 ID 段"分配约定(见扩展控件章节)。 - 图片路径失效:模板中
default/list使用工具相对路径(config\images\...);工程迁移后若图片未随工程携带,生成器将找不到图源。缓解:将图片随工程目录一起管理,避免绝对路径。 - ID 复用歧义:类型 ID 5 同时映射表格/垂直列表/水平列表,若固件端仅按 ID 区分控件而忽略子类型字段,可能出现容器行为不一致。缓解:固件端按 ID + 子类型联合解析。
- 工具版本漂移:
QtToolBin.exe、QTToolJson 1.1.exe与ResBuilder.exe为独立二进制,版本不一致可能产生 ResBuilder 无法解析的工程文件。缓解:统一使用配套版本(QTToolJson 1.1与 ResBuilder 协同)。 - 并发/多实例:工具为单机 PC 程序,仓库未提供多实例与并发写保护信息;建议同一工程同一时刻仅由一个编辑器实例打开,避免
ui-config与生成物互相覆盖。
性能与运维注意事项
- 资源紧凑化:
[Picture] png=233表明生成器按固定格式 ID 编码 PNG;图片帧数(maxlength)与尺寸影响资源包体积与 Flash 占用,量产前应控制图片总量。 - 哈希版本成本:每次资源变更后 ResBuilder 重算
IMAGE_VERION/STRING_VERION,固件比对为 O(1) 常量操作,对启动时间无实质影响。 - 可追溯性:
res_ver.h头部时间戳与工具签名使资源包可审计,建议在 CI/发布流程中保留每次生成的头文件作为版本档案。
扩展点:如何新增一个 UI 控件
基于元数据驱动架构,新增控件无需修改工具二进制,只需三步:
- 在
control/ex/下新建mywidget.json,按control.json的条目结构声明-class/-name/-type/caption/icon/property,并放置同名.png预览图。 - 在
option.ini的[Control]段为其分配类型 ID(复杂控件使用连续 ID 段,参考slider=28~32模式)。 - 在固件显示引擎侧实现对应类型 ID 的解析与渲染(属于
display-ui目录的职责,见相关链接)。
测试与验证
仓库内未包含针对工具的自动化测试用例(工具以二进制发布)。可验证的行为包括:
- 用
ResBuilder.exe重新生成资源后,res_ver.h中的哈希值应随资源内容变化而改变,内容不变则哈希不变。 - 修改
option.ini中扩展控件 ID 后重新生成,资源包内对应控件类型字段应同步更新。 QTToolJson 1.1.exe打开/保存工程后,ui-config与页面 JSON 应保持一致(JSON 版工具的可读性便于 diff 审查)。
Related Links
- 显示引擎运行时(资源解析/渲染/事件分发):见
display-ui目录相关页面 - 图片资源制作规范(切图、背景图):见
doc/软件工具/图片资源生成工具下其他文档 - 工具目录:doc/软件工具/图片资源生成工具/UI工程/UITools
- 控件模板:control.json
- 扩展控件目录:control/ex
- 类型映射:option.ini
- 生成产物示例:res_ver.h