CARPLAY版本整理

This commit is contained in:
2025-01-21 16:49:37 +08:00
commit f0fb64e4e6
26542 changed files with 13719676 additions and 0 deletions

View File

@ -0,0 +1,121 @@
# 文档
### 0. 参考手册
* [参考手册](manual.md)
* [参考手册 (chm)](https://github.com/zlgopen/awtk-docs/tree/master/AWTK-API%E6%89%8B%E5%86%8C)
* [开发实践](https://github.com/zlgopen/awtk-docs/blob/master/AWTK%E5%BC%80%E5%8F%91%E5%AE%9E%E8%B7%B5)
### 1. 使用文档
* [避坑指南](trap_list.md)
* [AWTK 控件的布局参数介绍](layout.md)
* [AWTK 界面描述文件介绍](ui_desc.md)
* [AWTK 中的图片显示方式](image_draw_type.md)
* [AWTK 中的矢量图绘图函数](vgcanvas.md)
* [AWTK 中的事件处理函数](event_listener.md)
* [AWTK 中的国际化之字符串翻译](locale.md)
* [AWTK 中的窗体样式](theme.md)
* [AWTK 中的 system\_bar 使用方法](system_bar.md)
* [AWTK 中的资源管理器](assets_manager.md)
* [AWTK 中的窗口动画](window_animator.md)
* [AWTK 中的控件动画](widget_animator.md)
* [LCD 旋转(横屏与竖屏)](lcd_rotation.md)
* [AWTK 中的输入法](input_method.md)
* [AWTK 硬件资源需求评估](hardware_req.md)
* [AWTK 中的一些惯例](conventions.md)
* [对话框高亮策略](dialog_highlight.md)
* [控件焦点相关问题](widget_focus.md)
* [AWTK 中的颜色格式](color_format.md)
* [AWTK 输入事件处理流程](input_event_flow.md)
* [内存耗尽处理流程](out_of_memory.md)
* [实时切换主题](theme_switch.md)
* [键值映射](map_key.md)
* [应用程序的入口函数](awtk_main.md)
* [资源打包](assets_zip.md)
* [LCD 密度与图片的对应关系](../design/default/images/README.md)
* [slide_view/pages 各个页面缺省的焦点控件](pages_slide_view_default_focused_child_for_each_page.md)
* [输入事件记录与重放](event_recorder_player.md)
* [API 注释格式](api_doc.md)
* [自定义控件规范](custom_widget_rules.md)
* [动态库与静态库](shared_static.md)
* [窗口之间如何通信](https://github.com/zlgopen/awtk-inter-win-communication)
* [为 512K Flash 优化空间](how_to_optimize_for_512K_flash.md)
* [如何绘制旋转文字](how_to_draw_rotate_text.md)
* [如何修改 Windows 下应用程序的图标](how_set_app_icon.md)
* [项目描述文件 project.json 介绍](awtk_project_description_file.md)
* [利用 app_helper 编写 SConstruct](app_helper_usage.md)
* [自定义控件支持脚本绑定](binding_custom_widget.md)
* [编写跨平台的代码](cross_platform_programming.md)
* [应用程序的类型](app_type.md)
* [如何引用第三方库](how_to_use_3rd_libs.md)
* [在 windows 下使用 gcc 编译 AWTK](mingw.md)
### 2.HowTos
* [AWTK 调试技巧](debug_tips.md)
* [AWTK 优化技巧](optimation.md)
* [如何使用离线画布](how_to_use_canvas_offline.md)
* [如何加入中文输入法](chinese_ime.md)
* [如何在 Visual Studio 中调试 AWTK](vs_debug.md)
* [如何在非 GUI 线程操作 GUI 控件](how_to_non_gui_thread_operate_widget.md)
* [如何启用鼠标指针](how_to_enable_mouse_cursor.md)
* [如何启用屏保](screen_saver.md)
* [如何设置字体的全局缩放比例](how_to_scale_font.md)
* [如何实现"back"键和"home"键](how_to_impl_back_and_home_key.md)
* [如何实现自定义的软键盘](how_to_impl_custom_soft_keyboard.md)
* [如何编译 Windows 32 位版本](how_to_build_windows_32bit_version.md)
* [如何支持单色 LCD](how_to_support_mono_lcd.md)
* [如何使用 mutable_image 控件](how_to_use_mutable_image.md)
* [如何让文本滚动起来](how_to_scroll_you_text.md)
* [如何在窗体样式文件中写控件布局参数](how_to_write_layout_params_in_style.md)
* [如何开启按键音](how_to_enable_key_touch_sound.md)
* [如何更新拼音输入法数据](how_to_update_gpinyin_data.md)
* [如何用 valgrind 查找内存相关问题](how_to_use_valgrind_detect_memory_bugs.md)
* [如何定制 combo_box 控件中按钮的风格和大小](how_to_customize_combo_boxox_button.md)
[如何访问控件的属性](how_to_access_widget_props.md)
* [如何集成第三方库](docs/how_to_use_3rd_libs.md)
* [如何使用对话框](how_toto_use_dialog.md)
* [如何使用软键盘上的 action 按钮](how_to_use_action_text.md)
* [如何存取应用程序的配置信息](how_to_use_app_conf.md)
* [如何实现弹出菜单](how_to_impl_popup_menu.md)
* [如何用 edit 控件编辑日期](how_to_edit_date.md)
* [如何用 edit 控件编辑时间](how_to_edit_time.md)
* [如何用 edit 控件编辑 IP 地址](how_to_edit_ip_addr.md)
* [如何支持 unicode bidirectional algorithm](how_to_enable_bidi.md)
* [如何续期使用 AWTK Designer](how_to_renewal_awtk_designer.md)
* [如何将生成的可执行文件和资源打包](how_to_release_app.md)
* [如何使用多点触控手势算法](how_to_use_multi_gesture.md)
* [如何隐藏滚动条的上下按钮](how_to_hide_up_down_button_of_scrollbar.md)
* [如何使用 packed 图](how_to_use_packed_image.md)
* [如何根据实际分辨率自动调整窗口中子控件的位置大小](how_to_auto_scale_children.md)
* [如何修改 stb\_truetype 获取字模时申请的缓冲区大小](how_to_modify_stb_truetype_buffer_size.md)
* [如何让内存管理器支持管理多块不连续的内存](how_to_support_multi_mem_block.md)
* [如何使用keil的AC6工具链编译](how_to_build_with_keil_ac6.md)
* [如何支持极简键盘 (3 键键盘、5 键键盘和旋转按钮)](docs/how_to_support_5keys_3keys.md)
### 3. 内部原理
* [AWTK 脚本绑定原理](script_binding.md)
* [AWTK 内存分配器](mem_alloactor.md)
* [优化 freetype 解析矢量字体的显示效果](optimation_freetype_gray_font.md)
* [优化 stb\_truetype 在 mono 模式下的字体显示效果](optimation_stb_truetype_mono_font.md)
### 4. 移植文档
* [嵌入式平台移植注意事项](porting_common.md)
* [将 AWTK 移植到 STM32f103ze 裸系统](porting_to_stm32f103ze.md)
* [将 AWTK 移植到 STM32f429igtx 裸系统](porting_to_stm32f429igtx.md)
* [将 AWTK 移植到 AWorksOS 平台](porting_to_awtk_aworks_rt1052.md)
* [将 AWTK 移植到 TencentOS 平台](https://github.com/zlgopen/awtk-stm32f103ze-tencentos/blob/master/docs/tos-port.md)
* [将 AWTK 移植到 RT-Thread 平台](https://github.com/zlgopen/awtk-stm32f103ze-rtthread/blob/master/docs/rtt-port.md)
* [将 AWTK 移植到 LPC1867 裸系统(推荐)](https://github.com/zlgopen/awtk-lpc1768-raw/blob/master/docs/lpc1768_port.md)
* [将 AWTK 移植到 STM32H743(TencentOS) 平台(推荐)](https://github.com/zlgopen/awtk-stm32h743iitx-tencentos/blob/master/docs/stm32h743iitx_port.md)
### 5. 技术笔记
* [LCD 接口的几种实现方式](lcd.md)
* [FrameBuffer 的几种使用方式](framebuffer.md)
### 6. 其它
* [常见问题解答](faq.md)
* [修改 AWTK 的代码风格](code_style.md)
* [AWTK 是如何保证代码质量的](qa.md)
### 7. 第三方文档
* [AWTK 编译与调试 环境搭建指南](https://github.com/hk-mars/Blog-Article/blob/master/IoT/AWTK%20%E7%BC%96%E8%AF%91%E4%B8%8E%E8%B0%83%E8%AF%95%20%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA%E6%8C%87%E5%8D%97.md)

View File

@ -0,0 +1,165 @@
## API 注释格式
AWTK 中的 API 注释,除了作为 API 的文档之外,还有以下用途:
* 提取 JSON 格式的 IDL用于生成各种语言的绑定代码。
* 用于设计器 (designer) 获取各个控件的元信息。
* 生成动态库的导出符号表。
这里采用了类似于 [jsduck](https://github.com/senchalabs/jsduck) 的 API 注释格式,但是 jsduck 并不支持 C 语言的数据类型,所以没有办法完全兼容 jsduck 的格式。
### 一、类的注释
@class 表示类定义。
示例:
```
/**
* @class progress_bar_t
* @parent widget_t
* @annotation ["scriptable"]
* 进度条控件。
*/
```
里面说明了类的名称、基类的名称和该类型是否可以脚本化。对于类annotation 的取值有:
* scriptable 该类可以被脚本化。
* fake 该类是 fake 的,并不真实存在。
* widget 表示该类是 widget 的子类。
* window 表示该类是窗口的子类。
* design 表示可以在 UI 设计器中使用。
### 二、属性注释
@property 表示属性定义。
示例:
```
/**
* @property {uint8_t} value
* @annotation ["set_prop","get_prop","readable","persitent","design","scriptable"]
* 进度条的值 [0-100]。
*/
```
里面说明了成员变量的类型、名称和是否只读等信息。对于 propertyannotation 的取值有:
* set\_prop 是否可以通过 widget\_set\_prop 来设置该属性。
* get\_prop 是否可以通过 widget\_get\_prop 来获取该属性。
* readable 该属性是否可以直接读取。
* writable 该属性是否可以直接修改。
* persitent 该属性是否需要持久化。
* design 该属性可以在设计器中设置。
* scriptable 该属性是否支持脚本化。
### 三、函数的注释
@method 表示函数定义。
示例:
```
/**
* @method progress_bar_create
* @annotation ["constructor", "scriptable"]
* 创建 progress_bar 对象
* @param {widget_t*} parent 父控件
* @param {xy_t} x x 坐标
* @param {xy_t} y y 坐标
* @param {wh_t} w 宽度
* @param {wh_t} h 高度
*
* @return {widget_t*} 对象。
*/
widget_t* progress_bar_create(widget_t* parent, xy_t x, xy_t y, wh_t w, wh_t h);
/**
* @method progress_bar_cast
* 转换为 progress_bar 对象(供脚本语言使用)。
* @annotation ["cast", "scriptable"]
* @param {widget_t*} widget progress_bar 对象。
*
* @return {widget_t*} progress_bar 对象。
*/
widget_t* progress_bar_cast(widget_t* widget);
/**
* @method progress_bar_set_value
* 设置进度条的进度。
* @annotation ["scriptable"]
* @param {widget_t*} widget 控件对象。
* @param {uint8_t} value 进度
*
* @return {ret_t} 返回 RET_OK 表示成功,否则表示失败。
*/
ret_t progress_bar_set_value(widget_t* widget, uint8_t value);
```
里面说明了函数的名称、参数和返回值。对于 propertyannotation 的取值有:
* global 是否是全局函数。除了指明为全局函数,函数是当前类的成员函数。
* cast 类型转换函数。
* constructor 构造函数
* deconstructor 析构函数
* scriptable 是否可以脚本化。对于特殊函数(通常有回调函数作为参数)不方便直接产生代码,可以指定为 scriptable:custom使用定制的绑定代码。
### 四、枚举的注释
@enum 表示枚举定义。
示例:
```
/**
* @enum align_v_t
* @annotation ["scriptable"]
* 垂直对齐的常量定义。
*/
typedef enum _align_v_t {
/**
* @const ALIGN_V_NONE
* 无效对齐方式。
*/
ALIGN_V_NONE= 0,
/**
* @const ALIGN_V_MIDDLE
* 居中对齐。
*/
ALIGN_V_MIDDLE,
/**
* @const ALIGN_V_TOP
* 顶部对齐。
*/
ALIGN_V_TOP,
/**
* @const ALIGN_V_BOTTOM
* 底部对齐。
*/
ALIGN_V_BOTTOM
}align_v_t;
```
里面定义了枚举的名称和各个枚举值。对于枚举annotation 的取值有:
* scriptable 该类可以被脚本化。
### 五、事件的注释
@event 表示事件定义。
示例:
```c
/**
* @event {pointer_event_t} EVT_CLICK
* 点击事件。
*/
/**
* @event {pointer_event_t} EVT_LONG_PRESS
* 长按事件。
*/
```

View File

@ -0,0 +1,105 @@
# 利用 app_helper 编写 SConstruct
编写 SConstruct 是一件繁琐的事情。我们把一些公共的功能,提取到 app\_helper 中,让 SConstruct 稍微简化一点:
## 一、示例
```python
import os
import scripts.app_helper as app
helper = app.Helper(ARGUMENTS);
helper.add_libs(['sqlite3']).add_cpppath([os.path.join(helper.APP_ROOT, '3rd')]).call(DefaultEnvironment)
helper.SConscript(['src/SConscript', '3rd/sqlite3/SConscript'])
```
## 二、helper API 介绍
* use\_std\_cxx 指定 C++ 编译器的版本。
```
helper.use_std_cxx(17)
```
* add\_deps 增加依赖的第三方库
```python
DEPENDS_LIBS = [
{
"root" : '../awtk-restful-httpd',
'shared_libs': ['httpd'],
'static_libs': []
}
]
helper.add_deps(DEPENDS_LIBS)
```
* add\_libs 增加依赖的库。
```
helper.add_libs(['sqlite3'])
```
* set\_dll\_def 设置动态库的 def 文件名。
```
helper.set_dll_def('src/table_view.def')
```
* add\_cpppath 增加头文件搜索路径。
```
helper.add_cpppath([os.path.join(helper.APP_ROOT, '3rd')])
```
* add\_libpath 增加库的搜索路径。
* add\_cxxflags 增加 C++预处理参数。
* add\_ccflags 增加 C 预处理参数。
* add\_linkflags 增加链接参数。
* add\_platform\_libs 增加特定平台的需要的库。
```
helper.add_platform_libs('Windows', ['ws2_32'])
```
* add\_platform\_cpppath 增加特定平台的需要的头文件搜索路径。
* add\_platform\_libpath 增加特定平台的需要的库搜索路径。
* add\_platform\_ccflags 增加特定平台的需要的 C 预处理参数。
* add\_platform\_cxxflags 增加特定平台的需要的 C++预处理参数。
* add\_platform\_linkflags 增加特定平台的需要的链接参数。
> 所有路径均为列表(数组)格式。
## 三、注意事项
* 平台相关的函数plat 的取值:
* Windows 表示 Windows
* Linux 表示 Linux
* Darwin 表示 MacOS
* helper 支持链式调用call 函数需要放到最后。
```
helper.add_libs(['sqlite3']).add_cpppath([os.path.join(helper.APP_ROOT, '3rd')]).call(DefaultEnvironment)
```
## 四、参考
* [如何引用第三方库](how_to_use_3rd_libs.md)
* [编写跨平台的代码](cross_platform_programming.md)
* https://github.com/zlgopen/awtk-hello/blob/master/SConstruct
* https://github.com/zlgopen/awtk-mvvm-c-hello/blob/master/SConstruct
* https://github.com/zlgopen/awtk-widget-table-view/blob/master/SConstruct

View File

@ -0,0 +1,76 @@
## 应用程序的类型
在 AWTK 中,应用程序有以下类型:
```c
/**
* @enum app_type_t
* @prefix APP_
* @annotation ["scriptable"]
* 应用程序类型。
*/
typedef enum _app_type_t {
/**
* @const APP_MOBILE
* 嵌入式或移动 APP
*/
APP_MOBILE = 0,
/**
* @const APP_SIMULATOR
* 模拟器。
*/
APP_SIMULATOR,
/**
* @const APP_DESKTOP
* 桌面应用程序。
*/
APP_DESKTOP
} app_type_t;
```
### APP_SIMULATOR
> 默认运行方式,有以下特点:
* 使用 AWTK 的输入法
* 使用 AWTK 的剪切板
* 在 PC 上运行时,窗口不可调整大小。
### APP_DESKTOP
> 用于开发 PC 软件,有以下特点:
* 使用系统的输入法
* 使用系统的剪切板
* 窗口可以调整大小。
### APP_MOBILE
> 在 Android/iOS 上:
* 使用系统的输入法
* 使用系统的剪切板
* 窗口自动调整大小。
> 在嵌入式系统:
* 使用 AWTK 的输入法
* 使用 AWTK 的剪切板
* 窗口自动调整大小。
### 使用方法
建议使用 awtk_main.inc。
对于 PC 软件,需要 APP\_TYPE 为 APP\_DESKTOP其它情况保持默认即可编译时会自动判断。
> 示例(demos/demo_desktop.c)
```c
#define LCD_WIDTH 400
#define LCD_HEGHT 400
#define APP_TYPE APP_DESKTOP
#ifdef WITH_FS_RES
#define APP_DEFAULT_FONT "default_full"
#endif /*WITH_FS_RES*/
#include "awtk_main.inc"
```

View File

@ -0,0 +1,39 @@
# 资源目录变更通知
为了支持多个主题在运行时实时切换,我们对目录结构做了一些调整: 在资源目录下增加主题子目录。
如:
* 旧的目录结果如下:
```
assets
inc
raw
```
* 新的目录结果如下:
```
assets
default
inc
raw
```
资源更新脚本也需要做相应改动:
旧的 scripts/update\_res.py
```
common.init(AWTK_ROOT, ASSETS_ROOT, ASSET_C);
common.updateRes()
```
新的 scripts/update\_res.py
```
common.init(AWTK_ROOT, ASSETS_ROOT, 'default', ASSET_C);
common.updateRes()
```

View File

@ -0,0 +1,206 @@
#AWTK 中的资源管理
## 基本架构
这里的资源管理器并非 Windows 下的文件浏览器,而是负责对各种资源,比如字体、窗体样式、图片、界面数据、字符串和其它数据的进行集中管理的组件。引入资源管理器的目的有以下几个:
* 让上层不需要了解存储的方式。在没有文件系统时或者内存紧缺时,把资源转成常量数组直接编译到代码中。在有文件系统而且内存充足时,资源放在文件系统中。在有网络时,资源也可以存放在服务器上(暂未实现)。资源管理器为上层提供统一的接口,让上层而不用关心底层的存储方式。
* 让上层不需要了解资源的具体格式。比如一个名为 earth 的图片,没有文件系统或内存紧缺,图片直接用位图数据格式存在 ROM 中,而有文件系统时,则用 PNG 格式存放在文件系统中。资源管理器让上层不需要关心图片的格式,访问时指定图片的名称即可(不用指定扩展名)。
* 让上层不需要了解屏幕的密度。不同的屏幕密度下需要加载不同的图片,比如 MacPro 的 Retina 屏就需要用双倍解析度的图片,否则就出现界面模糊。资源管理器需要为此提供支持,让上层不需关心屏幕的密度。
* 对资源进行内存缓存。不同类型的资源使用方式是不一样的比如字体和窗体样式加载之后会一直使用UI 文件在生成界面之后就暂时不需要了PNG 文件解码之后就只需要保留解码的位图数据即可。资源管理器配合图片管理器等其它组件实现资源的自动缓存。
负责资源管理器和资源管理相关的组件如下图所示:
![](images/assets_manager.png)
> 网络加载暂未实现。
## 资源的生成
AWTK 中的资源需要进行格式转换才能使用:
* 在没有文件系统时或者内存紧缺时,需要把资源转成常量数组直接编译到代码中。
* XML 格式的 UI 文件需要转换成二进制的格式。
* XML 格式的窗体样式文件需要转换成二进制的格式。
* TTF 可以根据需要转换成位图字体。
* PNG 可以根据需要转换成位图图片。
相关工具:
* bin/fontgen 位图字体生成工具
* bin/imagegen 位图图片生成工具
* bin/resgen 二进制文件生成资源常量数组
* bin/themegen XML 窗体样式转换成二进制的窗体样式
* bin/xml\_to\_ui XML 的界面描述格式转换二进制的界面描述格式
* ./scripts/update\_res.py 批量转换整个项目的资源
## 一、初始化
将资源生成常量数组直接编译到代码中时,其初始化过程为:
* 1. 包含相应的数据文件。
```
#include "assets/inc/fonts/ap.data"
#include "assets/inc/fonts/default.data"
#include "assets/inc/fonts/default_ttf.data"
#include "assets/inc/images/bricks.data"
#include "assets/inc/images/checked.data"
...
```
* 2. 将资源增加到资源管理器中。
```
assets_manager_add(rm, font_ap);
assets_manager_add(rm, font_default);
assets_manager_add(rm, font_default_ttf);
assets_manager_add(rm, image_bricks);
assets_manager_add(rm, image_checked);
...
```
将资源放在文件系统中时,一般不需要特殊处理,不过可以用 assets\_manager\_load 预加载资源。如:
```
assets_manager_load(rm, ASSET_TYPE_THEME, "default");
assets_manager_load(rm, ASSET_TYPE_FONT, "default_ttf");
```
> 参考demos/assets.c
## 二、使用方法
* 加载图片图片
使用 image\_manager\_load指定图片的名称即可。
```
bitmap_t img;
image_manager_load(image_manager(), "earth", &img);
```
> 或者通过更上层 widget 的函数去加载图片:
```
bitmap_t bitmap;
widget_load_image(widget, "myimage", &bitmap);
```
* 使用 UI 数据
使用 window\_open指定资源的名称即可。如
```
widget_t* win = window_open(name);
```
* 使用字体
一般在窗体样式文件中指定字体即可。
* 使用窗体样式
一般在界面描述文件中指定 style 即可。
## 三、资源的名称
资源名称一般就是资源的文件名,不带文件扩展名。比如图片名为 test.png那资源名称就是 test如果因为某种原因把 test.png 换成了 test.jpg对代码并无影响。
> 对于 DATA 类型的资源,由于其扩展名不固定,所以需要带扩展名才能访问。
>
> 比如资源文件名为"app.json",不能用"app"访问,而是用"app.json"才能访问。
对于图片和 UI 资源名称AWTK 还支持一种高级用法。想想下面几种情况:
* 需要支持不同的分辨率。而在不同分辨率里,要使用不同的背景图片。
* 需要支持竖屏和横屏。而有的界面自动排版不能满足需求,需要为竖屏和横屏个写一个 XML 文件。
* 需要支持不同的语言。而在不同的语言里,有的图片是语言相关的。
为了应对这些情况AWTK 提供了名称表达式:
* 名称中可以带变量和表达式。变量用${xxx}表示xxx 将被替换成实际的值。
* 可以指定多个名称,依次匹配,直到找到的为止。多个名称之间用逗号分隔。
示例 1
```
<style name="sky">
<normal bg_image="bg_${device_orientation}_1"/>
</style>
```
在竖屏下,相当于:
```
<style name="sky">
<normal bg_image="bg_portrait_1"/>
</style>
```
在横屏下,相当于:
```
<style name="sky">
<normal bg_image="bg_landscape_1"/>
</style>
```
示例 2:
```
<image image="flag_${country},flag_none" x="c" y="m:-80" w="80" h="80"/>
```
在 locale 为 zh\_CN 时,相当于:
```
<image image="flag_CN,flag_none" x="c" y="m:-80" w="80" h="80"/>
```
依次查找 flag\_CN 和 flag\_none 两个图片。
在 locale 为 en\_US 时,相当于:
```
<image image="flag_US,flag_none" x="c" y="m:-80" w="80" h="80"/>
```
依次查找 flag\_US 和 flag\_none 两个图片。
> 变量名可以使用 [system\_info 中的成员变量](https://github.com/zlgopen/awtk/blob/master/docs/manual/system_info_t.md)
## 四、扩展用法
有时候在嵌入式平台开发项目中会出现一种情况,项目的资源分为两部分,一部分是基本上不会修改的资源(例如字库资源等),一部分会根据开发过程中会进行修改或者更换资源(例如图片资源等)。
这个时候需要把不会修改的资源烧写指定的地方flash 或者 其他的存储设备中),然后再通过特定的方法加载到 awtk 中。
#### 示例:
```
#include "base/assets_manager.h"
/* 字体文件资源烧写到 0x60520000 的地址中 */
#define FONT_FULL_ADD 0x60520000
/* 字体文件资源大小长度 */
#define FONT_FULL_LEN 0x00220000
ret_t assets_init(void) {
assets_manager_t* am = assets_manager();
/*
* 把字体文件资源 data 数据直接加载到 awtk 中
* 并且该字体文件资源的名字为 "default_full"
* 程序内部可以通过 "default_full" 名字来使用该字体资源
*/
assets_manager_add_data(am, "default_full", ASSET_TYPE_FONT, ASSET_TYPE_FONT_TTF, (const uint8_t*)FONT_FULL_ADD, FONT_FULL_LEN);
```
> 备注assets_manager_add_data 函数传入的资源 data 数组,会拷贝一份在 awtk 内部,所以如果资源 data 数组是通过 malloc 等方法创建出来的话,就需要自行释放资源 data 数组。

View File

@ -0,0 +1,34 @@
# AWTK 资源打包
在支持文件系统的时候AWTK 的资源缺省是以独立文件的形式放在指定目录里的。但在有的情况下,把全部资源文件放到一个 zip 文件中,是更好的或唯一的选择。比如:
* 开发 PC 应用程序。
* 在没有文件系统的情况下,把资源放到外部 flash。
* 开发 IOS 应用程序(通过 cmake 创建 Xcode 项目时,似乎没有办法让资源保持原有的目录结构)。
## 一、生成 zip 文件
在 bash 下,可以使用 scripts/create_assets_zip.sh 脚本完成以上工作。
如:
```
../awtk/scripts/create_assets_zip.sh
```
> 假设当前在应用程序的根目录,应用程序和 awtk 并列在同一个目录中,生成的 zip 文件名为 assets.zip。
## 二、启用从 zip 文件中加载资源
实际使用时,只需要在包含 awtk_main.inc 之前,定义 ASSETS_ZIP 即可。如:
```c
#define ASSETS_ZIP "./assets.zip"
#include "awtk_main.inc"
```
> [asset\_loader\_zip](https://github.com/zlgopen/awtk/blob/master/src/base/asset_loader_zip.h) 支持从 zip 文件加载,也支持从抽象的 [data reader](https://github.com/zlgopen/awtk/blob/master/src/tkc/data_reader.h) 接口加载。希望从外部 flash 中加载,可以把读取 flash 的功能包装成 data reader 的接口。

View File

@ -0,0 +1,233 @@
[![banner](images/awtk_ecology_banner.jpg)](awtk_ecology_intro.md)
如果您针对某个芯片或平台移植过 AWTK或者为 AWTK 扩展过炫酷的控件,并希望共享这个适配代码,可以联系我们开源到 GitHub 上,我们愿意在 AWTK 技术上对您提供进一步的支持服务,大家可以一起把这个适配做稳做好,构建 AWTK 良好的生态。
[进一步了解我们的 AWTK 生态共建计划](awtk_ecology_intro.md)
## 索引
- [操作系统适配](#操作系统适配)
- [MCU芯片适配](#MCU芯片适配)
- [扩展控件](#扩展控件)
- [编程语言绑定](#编程语言绑定)
- [编译构建工具](#编译构建工具)
- [商业应用案例](#商业应用案例)
## 操作系统适配
- #### 桌面操作系统
| 操作系统 | 下载地址 | 作者 |
| -------- | ------------------------------- | ------------------------ |
| Windows | https://github.com/zlgopen/awtk | [ZLG](http://www.zlg.cn) |
| Linux | https://github.com/zlgopen/awtk | [ZLG](http://www.zlg.cn) |
| macOS | https://github.com/zlgopen/awtk | [ZLG](http://www.zlg.cn) |
- #### 嵌入式操作系统
| 操作系统 | 下载地址 | 作者 |
| ------------ | --------------------------------------- | ------------------------ |
| AWorksOS | [MCU芯片适配](#MCU芯片适配) | |
| 嵌入式 Linux | [MCU芯片适配](#MCU芯片适配) | |
| RT-Thread | [MCU芯片适配](#MCU芯片适配) | |
| TencentOS | [MCU芯片适配](#MCU芯片适配) | |
| FreeRTOS | [MCU芯片适配](#MCU芯片适配) | |
| SylixOS | https://github.com/zlgopen/awtk-sylixos | [ZLG](http://www.zlg.cn) |
| ms-rtos | https://github.com/ms-rtos/awtk | [翼辉](http://www.acoinfo.com/)|
- #### 软件框架和软件平台
| 操作系统 | 下载地址 | 作者 |
| --------- | -------------------------------------------------- | --------------------------------------------- |
| 海思Linux | https://github.com/zlgopen/awtk-linux-fb/issues/28 | [kent52712](https://github.com/kent52712) |
| VSF平台 | https://github.com/vsfteam/vsf | [vsfteam](https://github.com/vsfteam)【原厂】 |
| Wayland | https://github.com/zjm1060/awtk-wayland | [zjm1060](https://github.com/zjm1060) |
| Web | https://github.com/zlgopen/awtk-web | [ZLG](http://www.zlg.cn) |
| Android | https://github.com/zlgopen/awtk-android | [ZLG](http://www.zlg.cn) |
| iOS | https://github.com/zlgopen/awtk-ios | [ZLG](http://www.zlg.cn) |
## MCU芯片适配
以下按芯片厂商名字字母排序
- #### Anyka
| 芯片 | 操作系统 | 下载地址 | 作者 |
| ------- | ------------------- | ---------- | ---------------------------------- |
| AK376xD | RT-Thread | 请联系作者 | [Anyka](http://www.anyka.com)【原厂】 |
| AK376xD | Linux | 请联系作者 | [Anyka](http://www.anyka.com)【原厂】 |
- #### Espressif
| 芯片 | 操作系统 | 下载地址 | 作者 |
| ----- | -------- | --------------------------------------- | ----------------------------------------- |
| ESP32 | FreeRTOS | https://github.com/jason-mao/esp32-awtk | [jason-mao](https://github.com/jason-mao) |
- #### GigaDevice
| 芯片 | 操作系统 | 下载地址 | 作者 |
| -------- | -------- | ---------- | ------------------------ |
| GD32450Z | 无 | 请联系作者 | [ZLG](http://www.zlg.cn) |
- #### Ingenic
| 芯片 | 操作系统 | 下载地址 | 作者 |
| ----- | -------- | -------------------------------------------- | -------------------------------------------- |
| M200 | Linux | https://github.com/zlgopen/awtk-port-ingenic | [Ingenic](http://www.ingenic.com.cn)【原厂】 |
| X1000 | Linux | https://github.com/zlgopen/awtk-port-ingenic | [Ingenic](http://www.ingenic.com.cn)【原厂】 |
| X1830 | Linux | https://github.com/zlgopen/awtk-port-ingenic | [Ingenic](http://www.ingenic.com.cn)【原厂】 |
- #### MindMotion
| 芯片 | 操作系统 | 下载地址 | 作者 |
| ------------ | -------- | ---------- | -------------------------------------------------- |
| MM32F103RET6 | 无 | 请联系作者 | [MindMotion](http://www.mindmotion.com.cn)【原厂】 |
- #### Nordic
| 芯片 | 操作系统 | 下载地址 | 作者 |
| -------- | -------- | ---------- | ------------------------------------------------- |
| NRF52840 | FreeRTOS | 请联系作者 | [jimmywong2003](https://github.com/jimmywong2003) |
- #### NXP
| 芯片 | 操作系统 | 下载地址 | 作者 |
| --------------- | -------- | -------------------------------------------------- | ------------------------------------- |
| RT1052 | AWorksOS | https://github.com/zlgopen/awtk-aworks-rt1052 | [ZLG](http://www.zlg.cn) |
| RT1052 | 无 | https://github.com/zlgopen/awtk-easyarm-rt1052-raw | [ZLG](http://www.zlg.cn) |
| RT1052 | FreeRTOS | https://github.com/chinachuli/awtk-imxrt1052-raw | [褚立](https://github.com/chinachuli) |
| RT1020 | 无 | 请联系作者 | [ZLG](http://www.zlg.cn) |
| RT1011 | 无 | 请联系作者 | [ZLG](http://www.zlg.cn) |
| RT1176 | FreeRTOS | 请联系作者 | [ZLG](http://www.zlg.cn) |
| RT500 | FreeRTOS | 请联系作者 | [ZLG](http://www.zlg.cn) |
| i.MX6 Cortex-A7 | AWorksOS | 请联系作者 | [ZLG](http://www.zlg.cn) |
| i.MX6 Cortex-A7 | Linux | https://github.com/zlgopen/awtk-linux-fb | [ZLG](http://www.zlg.cn) |
| i.MX6 Cortex-A9 | Linux | https://github.com/zlgopen/awtk-linux-fb | [ZLG](http://www.zlg.cn) |
| i.MX283 | Linux | https://github.com/zlgopen/awtk-linux-fb | [ZLG](http://www.zlg.cn) |
| LPC54608 | 无 | 请联系作者 | [ZLG](http://www.zlg.cn) |
| LPC54018 | 无 | 请联系作者 | [ZLG](http://www.zlg.cn) |
| LPC1768 | 无 | https://github.com/zlgopen/awtk-lpc1768-raw | [ZLG](http://www.zlg.cn) |
- #### ST
| 芯片 | 操作系统 | 下载地址 | 作者 |
| --------- | --------- | ----------------------------------------------------- | ---------------------------------- |
| STM32F103 | 无 | https://github.com/zlgopen/awtk-stm32f103ze-raw | [ZLG](http://www.zlg.cn) |
| STM32F103 | RT-Thread | https://github.com/zlgopen/awtk-stm32f103ze-rtthread | [ZLG](http://www.zlg.cn) |
| STM32F103 | TencentOS | https://github.com/zlgopen/awtk-stm32f103ze-tencentos | [ZLG](http://www.zlg.cn) |
| STM32H743 | TencentOS | https://github.com/zlgopen/awtk-stm32h743iitx-tencentos | [ZLG](http://www.zlg.cn) |
| STM32H743 | FreeRTOS | https://github.com/zlgopen/awtk-stm32h743iitx-freertos | [ZLG](http://www.zlg.cn) |
| STM32F429 | 无 | https://github.com/zlgopen/awtk-stm32f429igtx-raw | [ZLG](http://www.zlg.cn) |
| STM32F767 | 无 | https://github.com/zlgopen/awtk-stm32f767igtx-raw | [ZLG](http://www.zlg.cn) |
| STM32F769 | FreeRTOS | https://github.com/wpmyj/awtk-stm32f769-freertos | [王培明](https://github.com/wpmyj) |
- #### SigmaStar
| 芯片 | 操作系统 | 下载地址 | 作者 |
| ------- | -------- | ---------- | ------------------------------------------------------------ |
| SSD201 | Linux | 请联系作者 | [SigmaStar](http://www.comake.online/index.php?p=products_list&lanmu=2)【原厂】 |
| SSD202D | Linux | 请联系作者 | [SigmaStar](http://www.comake.online/index.php?p=products_list&lanmu=2)【原厂】 |
| SSD212 | Linux | 请联系作者 | [SigmaStar](http://www.comake.online/index.php?p=products_list&lanmu=2)【原厂】 |
| SSD210 | Linux | 请联系作者 | [SigmaStar](http://www.comake.online/index.php?p=products_list&lanmu=2)【原厂】 |
| SSD222 | Linux | 请联系作者 | [SigmaStar](http://www.comake.online/index.php?p=products_list&lanmu=2)【原厂】 |
| SSD268G | Linux | 请联系作者 | [SigmaStar](http://www.comake.online/index.php?p=products_list&lanmu=2)【原厂】 |
> 以上信息如果有误,或需要补充的,请联系 chentan@zlg.cn 修正
>
## 扩展控件
- #### 基础控件
| 控件名称 | 下载地址 | 作者 |
| -------- | ----------------------------------------------- | -------------------------------------------------- |
| 二维码 | https://github.com/zlgopen/awtk-widget-store | [ZLG](http://www.zlg.cn) |
| 下拉按钮 | https://github.com/zlgopen/awtk-widget-store | [ZLG](http://www.zlg.cn) |
| 日期选择 | https://github.com/zlgopen/awtk-widget-store | [ZLG](http://www.zlg.cn) |
| 旋转文本 | https://github.com/zlgopen/awtk-widget-store | [ZLG](http://www.zlg.cn) |
| 数字显示 | https://github.com/zlgopen/awtk-widget-store | [ZLG](http://www.zlg.cn) |
| 蒙板视图 | https://github.com/zlgopen/awtk-widget-store | [ZLG](http://www.zlg.cn) |
| 圆形滑块 | https://github.com/longyuwlz/awtk_slider_circle | [longyuwlz](http://github.com/longyuwlz) |
- #### 图表控件
| 控件名称 | 下载地址 | 作者 |
| -------- | -------------------------------------------- | ------------------------ |
| 饼图 | https://github.com/zlgopen/awtk-widget-store | [ZLG](http://www.zlg.cn) |
| 柱状图 | https://github.com/zlgopen/awtk-widget-store | [ZLG](http://www.zlg.cn) |
| 曲线图 | https://github.com/zlgopen/awtk-widget-store | [ZLG](http://www.zlg.cn) |
| 表格视图 | https://github.com/zlgopen/awtk-widget-store | [ZLG](http://www.zlg.cn) |
- #### 多媒体控件
| 控件名称 | 下载地址 | 作者 |
| -------- | -------------------------------------------- | ------------------------ |
| 摄像头 | https://github.com/zlgopen/awtk-widget-store | [ZLG](http://www.zlg.cn) |
| 视频动画 | https://github.com/zlgopen/awtk-widget-store | [ZLG](http://www.zlg.cn) |
## 编程语言绑定
- #### C
| 解析引擎 | 下载地址 | 作者 |
| -------- | ------------------------------- | ------------------------ |
| C99 | https://github.com/zlgopen/awtk | [ZLG](http://www.zlg.cn) |
- #### JavaScript
| 解析引擎 | 下载地址 | 作者 |
| ----------- | ------------------------------------------- | ------------------------ |
| JerryScript | https://github.com/zlgopen/awtk-jerryscript | [ZLG](http://www.zlg.cn) |
| QuickJS | https://github.com/zlgopen/awtk-quickjs | [ZLG](http://www.zlg.cn) |
| Node.js | 请联系作者 | [ZLG](http://www.zlg.cn) |
- #### Lua
| 解析引擎 | 下载地址 | 作者 |
| -------- | ----------------------------------- | ------------------------ |
| Lua | https://github.com/zlgopen/awtk-lua | [ZLG](http://www.zlg.cn) |
- #### C++
| 解析引擎 | 下载地址 | 作者 |
| -------- | ----------------------------------- | ------------------------ |
| C++98 | https://github.com/zlgopen/awtk-cpp | [ZLG](http://www.zlg.cn) |
- #### Java
| 解析引擎 | 下载地址 | 作者 |
| -------- | ------------------------------------ | ------------------------ |
| JDK | https://github.com/zlgopen/awtk-java | [ZLG](http://www.zlg.cn) |
## 编译构建工具
| 构建工具 | 编译平台 | 下载地址 | 作者 |
| -------- | -------- | ------------------------------------------- | --------------------------------------- |
| SCons | PC ALL | https://github.com/zlgopen/awtk | [ZLG](http://www.zlg.cn) |
| SCons | ARMCC | https://github.com/zlgopen/awtk-scons-armcc | [ZLG](http://www.zlg.cn) |
| SCons | MinGW | https://github.com/zlgopen/awtk-scons-mingw | [ZLG](http://www.zlg.cn) |
| CMake | MSVC | https://github.com/zlgopen/awtk-msvc | [ZLG](http://www.zlg.cn) |
| CMake | macOS | https://github.com/oskycar/awtktest_cmake | [allenyang](https://github.com/oskycar) |
## 商业应用案例
- #### 智能家居
- #### 智能穿戴
- #### 汽车电子
- #### 医疗电子
- #### 工业控制

View File

@ -0,0 +1,52 @@
## AWTK 生态共建计划
各位关注和使用 AWTK 的开发者,你们好!
如果您针对某个芯片或平台移植过 AWTK或者为 AWTK 扩展过炫酷的控件,并希望共享这个适配代码,可以联系我们开源到 GitHub 上,我们愿意在 AWTK 技术上对您提供进一步的支持服务,大家可以一起把这个适配做稳做好,构建 AWTK 良好的生态。
### 您可以获得
- 在 AWTK 官方页面上,加入您的相关链接
- 更进一步的 AWTK 技术支持服务
- 更多的资源和信息共享,与我们一起共建共赢嵌入式开发生态
### 联系方式
发送邮件到 chentan@zlg.cn标题写 AWTK 生态共建;
或添加小Z微信zlgmcu-888备注写 AWTK 生态共建,申请加入 AWTK 生态共建交流群
##### 您需要提供
需要给我们提供一些基本信息:
1. 项目的名称
2. 适配的平台:包括 MCU 型号、Flash 和 RAM 大小、屏幕分辨率及颜色位数、操作系统等
3. 您的姓名和联系方式
4. 项目在 GitHub 上的地址
5. 公司名称(个人项目可以不填)
### 如何上传代码
我们期待与芯片原厂和操作系统原厂的合作,同时也欢迎个人项目的参与
针对原厂和个人的项目有不同的上传方式:
##### 如果是原厂合作的项目
1. 我们将会在 GitHub 创建一个专属的仓库 zlgopen/awtk-port-公司名,并在 AWTK 官方页面加上链接
2. 请您在 GitHub 上注册一个维护账号,我们会将这个账号加入该仓库的上传权限
3. 您可以将公司介绍、项目说明和项目代码 push 到该仓库
4. 我们将为您建立专项支持微信群,提供更进一步的 AWTK 技术支持服务
##### 如果是个人的项目
1. 需要您把项目上传到 GitHub 的个人仓库中,然后把仓库地址发给我们
2. 我们审核完之后会在 AWTK 官方页面加上链接
3. 我们会邀请您加入 AWTK 生态共建交流群,并提供更优先的技术支持服务
> 2019/11/8

View File

@ -0,0 +1,89 @@
# AWTK 应用程序的入口
## 一、背景
虽然 main 函数是 C 语言的标准入口,但是不同平台的入口函数仍然有多种不同的形式。比如:
* 嵌入式系统用 gui\_app\_start
* ios/android 用 SDL\_main
* Linux/MacOS 用 main
* Windows 用 wWinMain
如果希望开发的程序要在多个平台上运行就需要处理多种入口函数。为了简化这个过程AWTK 把入口函数的处理封装到 awtk_main.inc 中,开发者只需要 include 进来即可。
## 二、基本用法
* 实现 application_init 函数
```c
ret_t application_init() {
/*do sth.*/
return RET_OK;
}
```
* 实现 application_exit 函数
```c
ret_t application_exit() {
log_debug("application_exit\n");
return RET_OK;
}
```
* 包含 awtk_main.inc
```c
#include "awtk_main.inc"
```
> 请参考[完整的例子](https://github.com/zlgopen/awtk-c-demos/blob/master/demos/button.c)
## 三、高级用法
* 指定APP TYPE和窗口大小
```c
#define LCD_WIDTH 800
#define LCD_HEGHT 600
#define AWTK_APP_TYPE APP_DESKTOP
#include "awtk_main.inc"
```
> 请参考[完整的例子](https://github.com/zlgopen/awtk/blob/master/demos/demo_desktop.c)
* 处理命令行参数
```c
static ret_t on_cmd_line(int argc, char* argv[]) {
script_file = argc == 2 ? argv[1] : "./demos/demoui.js";
return RET_OK;
}
#define ON_CMD_LINE on_cmd_line
#include "awtk_main.inc"
```
> 请参考[完整的例子](https://github.com/zlgopen/awtk-jerryscript/blob/master/src/c/main.c)
* 指定应用程序的名称
```c
#define APP_NAME "AWTK-JS"
#include "awtk_main.inc"
```
* 指定缺省字体
```c
#define APP_DEFAULT_FONT "default_full"
#include "awtk_main.inc"
```
> 请参考[完整的例子](https://github.com/zlgopen/awtk-jerryscript/blob/master/src/c/main.c)

View File

@ -0,0 +1,242 @@
# AWTK 项目描述文件
AWTK Designer下面简称 Designer创建的项目均有一个项目描述文件 project.json。该文件是一个JSON格式的文件是每个项目必须的主要描述了项目的名称、类型、启动页面、资源配置等。Designer 通过该文件来获取项目信息并识别项目是否可以打开。
如:
```json
{
"name": "project_name",
"version": "1.0.0",
"date": "2020-07-04",
"team": "AWTK Develop Team",
"author": "XXXX <xxxx@zlg.cn>",
"desc": "使用 XML(UI文件)描述用户界面 和 C/C++ 实现业务逻辑的应用程序",
"copyright": "Guangzhou ZHIYUAN Electronics Co.,Ltd.",
"type": "PROJECT_WIDGETS_APPLICATION",
"subType": "",
"entry": "main",
"assets": {
"activedTheme": "default",
"outputDir": "res",
"loadFrom": "any",
"const": "resource_data",
"screenDPR": "x1",
"defaultLanguage": "zh",
"defaultCountry": "CN",
"themes": {
"default": {
"activedSystemBar": "system_bar",
"activedBottomSystemBar": "system_bar_b",
"packaged": true,
"fonts": {
"default": {
"text": " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~,。?!确定取消",
"18": " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~,。?!确定取消"
}
},
"lcd": {
"width": "800",
"height": "480",
"colorDepth": "16bit",
"colorFormat": "BGR(A)"
}
}
}
},
"creator": {
"name": "AWTK Designer",
"version": "1.0.0"
},
"awtkRoot": "${DesignerPath}/SDK/awtk",
"usesSdk": {
"awtk:minSdkVersion": "20070",
"awtk:maxSdkVersion": "20090",
"awtk:targetSdkVersion": "20090"
}
}
```
## 1. name
name 是必须的,表示项目的名称。
> 注意:对于自定义控件库项目,该名称必须是全小写英文字母,单词之间用下划线连接。
## 2. version
version 是可选的表示项目的版本号缺省为“1.0.0”。
## 3. date
date 是可选的,表示项目创建的日期。
## 4. team
team 是可选的,表示项目开发团队的名称。
## 5. author
author 是可选的,表示作者、联系方式。
## 6. desc
desc 是可选的,表示项目简介或者功能描述。
## 7. copyright
copyright 是可选的,表示版权声明。
## 8. type
type 是可选的表示项目类型缺省为“PROJECT_WIDGETS_APPLICATION”。
目前有如下几种项目类型:
* PROJECT_WIDGETS_APPLICATION 表示使用 XML(UI文件)描述用户界面 和 C/C++ 实现业务逻辑的应用程序,在代码中可通过 AWTK API 直接访问 Widget
* PROJECT_CUSTOM_WIDGET 表示自定义控件库,可导入 Designer安装到项目后可以像内置控件一样编辑并实时预览显示效果
* PROJECT_THEME 表示应用程序主题,可导入 Designer 并应用到不同的项目;
* PROJECT_UI_SNIPPET 表示界面片段,可导入 Designer 并应用到不同的项目。
## 9. subType
subType 是可选的。
对于PROJECT_UI_SNIPPET类型的项目目前有system_bar系统栏、keyboard软键盘两种。
## 10. entry
entry 是必须的,表示应用程序或者示例程序的启动页面。
## 11. assets
assets 是必须的,是应用程序或者示例程序的资源配置。主要参数有:
#### 11.1 activedTheme
activedTheme 表示Designer当前激活的主题也是应用程序或者示例程序的默认主题。
#### 11.2 outputDir
outputDir 表示资源打包时的输出目录。默认为项目的res目录。
#### 11.3 loadFrom
loadFrom 表示资源的打包方式,有 2 个选项:
* any 表示文件+常量,即同时生成用于文件系统的资源和可直接编译到代码中的常量资源(以常量数组的形式存在);
* fs 表示为仅文件,即仅生成用于文件系统的资源。
#### 11.4 const
const 表示资源的常量格式,主要指字体、图片打包时生成的常量资源的格式,有 2 种格式:
* resource_data 表示原始数据即常量数组中缓存的是原始的文件数据比如PNG 图片的原始数据为 PNG 数据);
* bitmap_data 表示位图数据,即常量数组中缓存的是 Bitmap 数据。
* all_data 表示同时生成上述两种类型的数据。
#### 11.5 screenDPR
screenDPR 表示LCD的设备像素比DPR影响打包生成常量资源时应包含哪些图片资源有 3 个选项:
* x1 表示包含 x1、xx、svg
* x2 表示包含 x2、xx、svg
* x3 表示包含 x3、xx、svg。
#### 11.6 defaultLanguage
defaultLanguage 表示应用程序默认使用的语言默认为中文zh
#### 11.7 defaultCountry
defaultCountry 表示应用程序默认使用的语言所属的国家或地区默认为中国CN
#### 11.8 themes
themes 表示应用程序使用的主题主题可以有多个缺省为default。
主题的参数有:
* activedSystemBar 表示正在使用的顶部系统栏
* activedBottomSystemBar 表示正在使用的底部系统栏
* packaged 表示资源打包时是否打包该主题
* fonts 表示该主题使用到的字体及其设置
比如名称为 default 的字体,可以设置:
text 表示裁剪 TTF 文件时需要保留的字符;
18 表示生成 18 字号的 Bitmap 字体时需要保留的字符,这里数值表示字体的字号。
* lcd 表示 目标 LCD 的参数
主要的参数有:
width 表示 LCD 的宽度
height 表示 LCD 的高度
colorDepth 表示 LCD 的颜色深度
colorFormat 表示 LCD 的颜色格式
其中LCD 的颜色深度和颜色格式决定了 LCD Frame Buffer 的格式。
> 颜色深度为 1bit 时,颜色格式固定为 MONO表示 Frame Buffer 为 MONO
> 颜色深度为 16bit 且颜色格式为 RGB(A),表示 Frame Buffer 为 RGB565
> 颜色深度为 32bit 且颜色格式为 RGB(A),表示 Frame Buffer 为 RGB8888
> 颜色深度为 16bit 且颜色格式为 BGR(A),表示 Frame Buffer 为 BGR565
> 颜色深度为 32bit 且颜色格式为 BGR(A),表示 Frame Buffer 为 BGR8888。
而 LCD Frame Buffer 的格式又决定打包生成的字体位图数据(也就是字模数据)和图片位图数据的格式。
> 对于字体:
> Frame Buffer 为 MONO 时,字模的 alpha 通道为 1bit否则为 8bit。
> 对于图片:
> Frame Buffer 为 MONO 时,无论图片的颜色通道是什么格式,统一转为 1bit原颜色灰度>10 时 为 1表示白色否则为 0表示黑色
> Frame Buffer 为 565 格式时,没有 alpha 通道的图片会转为 565 格式的位图数据,但有 alpha 通道
的图片则仍会转为 8888 格式的位图数据(运行时经过半透混合会转成 565 格式);
> Frame Buffer 为 8888 格式时,则全部转为 8888 格式的位图数据。
> 需要注意的是,对于控件样式(比如背景颜色、文本颜色等):
> 由于运行时计算灰度会影响效率,因此,当 Frame Buffer 为 MONO 时AWTK 认为颜色的 R 通道为 0 时表示黑色,否则为白色。建议 MONO 模式下,样式里的颜色均显式地设为黑色或白色。
## 12. creator
creator 是必须的,表示项目的创建者,主要的参数有:
* name 表示创建者的名称固定为“AWTK Designer”
* version 表示创建者的版本号比如“0.1.6”。
## 13. usesSdk
usesSdk 是可选的表示项目依赖的SDK的信息。
比如项目依赖的AWTK有如下参数
* 参数 awtk:minSdkVersion 是可选的,表示兼容的最低版本。
* 参数 awtk:maxSdkVersion 是可选的,表示兼容的最高版本。
* 参数 awtk:targetSdkVersion 是可选的,表示最佳版本。
> 上述版本号对应发布的 AWTK 中 component.json 文件中的 "release_id"
> 注意:如果没有显式设置,则认为兼容所有版本。
## 14. awtkRoot
对于1.0.0以上版本的DesignerawtkRoot 是必须的,用于指定项目编译时(即点击 Designer 工具栏上的编译按钮启动编译时)依赖的 AWTK 的路径。
默认为 “${DesignerPath}/SDK/awtk”。
其中, “${DesignerPath}” 表示 Designer 的安装目录。
> 使用 scons 进行编译时,可以通过 AWTK_ROOT 参数手动设置 AWTK 的路径,比如:
```cmd
scons AWTK_ROOT=c:/AWTK/SDK/awtk
```

View File

@ -0,0 +1,69 @@
# 自定义控件支持脚本绑定
本文 [二维码控件](https://github.com/zlgopen/awtk-widget-qr.git) 为例,介绍一下如何让自定义控件支持脚本绑定。
> 本文前提:
* 安装 node.js
* 安装 python 3.x
* awtk 编译环境
* 在 bash 中运行
## 1. 获取自定义控件的源码
```
git clone https://github.com/zlgopen/awtk-widget-qr.git
```
## 2. 把自定义控件的源码拷贝到 AWTK 的 ext_widgets 目录下
```
cp -rf awtk-widget-qr/src/qr awtk/src/ext_widgets/qr
cp -rf awtk-widget-qr/src/qr_register.* awtk/src/ext_widgets/
```
## 3. 注册控件
修改 awtk/src/ext\_widgets/ext\_widgets.c
```c
#include "qr_register.h"
ret_t tk_ext_widgets_init(void) {
...
qr_register();
...
}
```
## 4. 编译 awtk
```
cd awtk
scons -j2
cd -
```
### 5. 更新绑定代码
```
git clone https://github.com/zlgopen/awtk-binding
cd awtk-binding
./gen.sh
cd -
```
### 6. 同步绑定代码到需要的语言
```
git clone https://github.com/zlgopen/awtk-jerryscript
cd awtk-jerryscript
./sync.sh
scons
```
### 7. 注意
* 开发应用程序时记得拷贝自定义控件的 style 到资源中。
* 如果代码下载太慢,可以从 fastgit 下载。

View File

@ -0,0 +1,170 @@
# 特殊平台编译配置
有些平台编译比较特殊,不能使用 scons 编译,也不能使用 keil 编译。我们用一个配置文件描述项目,然后用脚本来编译或生成项目模板。目前有 web、ios 和 android 版本使用这种方式。
配置文件采用 JSON 格式,位置放在项目的根目录下,推荐命名为 build.json。
## 一、通用选项
* name 应用程序名称(不支持中文和特殊符号)。
* version 版本号。
* assets 资源所在的目录相对于配置文件所在的目录android/ios 一般使用"res/assets", web 一般使用 design
* sources 源文件列表(相对于配置文件所在的目录)。文件名支持通配符如*.c。只要添加应用程序本身和使用的第三方库的源码即可AWTK 本身用到的代码会自动添加。
* includes 头文件搜索路径列表(相对于配置文件所在的目录)。
> sources 虽然是通用选项,但是不同平台,包含的源文件可能并不相同,此时应该放到具体平台之下。
## 二、web 平台选项
web 平台选项放在 web 子键下面,目前支持以下选项:
* app_type 目前可选择的值有。"c"表示用 C 语言开发的应用程序,"js"表示用 Javascript 开发的应用程序。
* config 用于指定一些运行参数。
* width 如果应用开发时没有做自适应性布局,可以用 width 参数指定画布的宽度。
* height 如果应用开发时没有做自适应性布局,可以用 height 参数指定画布的高度。
* defaultFont 缺省字体。缺省为"sans"。
* fontScale 字体的缩放比例。缺省为 1。
> config 中的参数也可以直接在 URL 中指定。如:
```
http://192.168.1.117:8080/demoui/index.html?width=480&height=800&fontScale=0.8&defaultFont=serif
```
如:
用 C 语言写的 demoui 的配置文件:
```
"web": {
"app_type": "c",
"assets": "design",
"sources": [
"demos/assets.c",
"demos/demo_ui_app.c"
],
"config": {
"fontScale": "0.8",
"defaultFont": "sans"
}
},
```
用 Javascript 写的 demoui 的配置文件:
```
{
"name":"demouijs",
"version":"1.0",
"app_type":"js",
"assets": "design",
"sources":["./design/default/scripts/basic.js"]
}
```
## 三、android 平台选项
android 平台选项放在 android 子键下面,目前支持以下选项:
* app_name 应用程序的完整名称。如org.zlgopen.demoui
* cflags C 代码额外的编译参数。
* cppflags C++代码额外的编译参数。
* features 平台专用特性。目前支持:
* fullscreen 是否全屏。true 表示全屏false 表示不全屏。
示例:
```
"android": {
"features": {
"fullscreen":true
},
"app_name": "org.zlgopen.demoui",
"sources": [
"demos/assets.c",
"demos/demo_ui_app.c",
"demos/vg_common.inc",
"res/assets.inc",
"res/assets/__assets_default.inc"
]
},
```
## 四、 ios 平台选项
* app_name 应用程序的完整名称。如org.zlgopen.demoui
* defines 宏定义。ios 和 android 定义方式有些不同,宏定义要放到 defines 中,而不能放到 cflags 和 cppflags。格式也有些不同
```
"defines":" HAVE_CONFIG_H=1 BUILDING_LIBCURL=1 WITH_CURL=1 ",
```
```
"ios": {
"app_name": "org.zlgopen.demoui",
"sources": [
"demos/assets.c",
"demos/demo_ui_app.c",
"demos/vg_common.inc",
"res/assets.inc",
"res/assets/__assets_default.inc"
]
}
```
## 五、完整示例
下面是 demoui 的完整示例
```
{
"name": "demoui",
"version": "1.0",
"assets": "res/assets",
"author": "xianjimli@hotmail.com",
"copyright": "Guangzhou ZHIYUAN Electronics Co.,Ltd.",
"web": {
"app_type": "c",
"assets": "design",
"sources": [
"demos/assets.c",
"demos/demo_ui_app.c"
],
"config": {
"fontScale": "0.8",
"defaultFont": "sans"
}
},
"android": {
"app_name": "org.zlgopen.demoui",
"sources": [
"demos/assets.c",
"demos/demo_ui_app.c",
"demos/vg_common.inc",
"res/assets.inc",
"res/assets/__assets_default.inc"
]
},
"ios": {
"app_name": "org.zlgopen.demoui",
"sources": [
"demos/assets.c",
"demos/demo_ui_app.c",
"demos/vg_common.inc",
"res/assets.inc",
"res/assets/__assets_default.inc"
]
}
}
```
## 六、示例与参考
* [awtk-http-client 的配置文件](https://github.com/zlgopen/awtk-http-client/blob/master/build.json)
* [awtk-hello 的配置文件](https://github.com/zlgopen/awtk-hello/blob/master/build.json)
* [Android/IOS 插件的配置文件](https://github.com/zlgopen/awtk-mobile-plugins/blob/master/build.json)
* [awtk-web-js 的配置文件](https://github.com/zlgopen/awtk-jerryscript/blob/master/build_web.json)

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,280 @@
# 缺省子控件的布局器
## 一、语法
子控件布局器统一使用 children_layout 属性指定,其语法为:
```
缺省子控件布局器 => default '(' PARAM_LIST ')'
PARAM_LIST => PARAM | PARAM ',' PARAM_LIST
```
示例:
```
<view x="0" y="0" w="100%" h="100%" children_layout="default(c=2,r=8,m=5,s=5)">
```
## 二、参数
缺省子控件的布局器提供了下列参数:
| 参数 | 简写 | 说明 |
|----------------|:------:|:--------------|
| rows | r | 行数 |
| cols | c | 列数 |
| width | w | 子控件的宽度,可以用来计算列数,与 cols 互斥 |
| height | h | 子控件的高度,可以用来计算行数,与 rows 互斥 |
| x\_margin | xm | 水平方向的边距 |
| y\_margin | ym | 垂直方向的边距 |
| spacing | s | 子控件之间的间距 |
| keep_invisible | ki | 是否给不可见的控件留位置(缺省否)|
| keep_disable | kd | 是否给不用的控件留位置(缺省是)|
| aligh_h | a | 用于 hbox 的情况 (col=0,row=1), 子控件整体水平对齐的方式。
在代码中,可以通过 widget\_set\_children\_layout 函数启用子控件布局器:
```
/**
* @method widget_set_children_layout
* 设置子控件的布局参数。
* @annotation ["scriptable"]
* @param {widget_t*} widget 控件对象。
* @param {const char*} params 布局参数。
*
* @return {ret_t} 返回 RET_OK 表示成功,否则表示失败。
*/
ret_t widget_set_children_layout(widget_t* widget, const char* params);
```
示例:
```
widget_set_children_layout(w, "default(r=2,c=2)");
```
在 XML 中,可以通过 children\_layout 属性设置:
```
<column x="20" y="160" w="50%" h="60" children_layout="default(r=2,c=1,ym=2,s=10)" >
<check_button name="c1" text="Book"/>
<check_button name="c2" text="Food"/>
</column>
```
## 三、使用方法
下面我们看看,如何调整 rows/cols 两个参数,来实现不同的布局方式。
### 0. 缺省
在没有设置子控件布局参数时,采用缺省的布局方式,父控件啥事也不做,完全由子控件自己的布局参数决定。
### 1. hbox 水平布局
当 rows=1,cols=0 时,所有子控件在水平方向排成一行,可以实现水平布局功能。子控件的参数:
* x 从左到右排列,由布局参数计算而出。
* y 为 y\_margin
* w 由子控件自己决定。
* h 为父控件的高度-2*y\_margin
> 子控件需要自己决定宽度。
> aligh_h 参数可以控制整体对齐方式。
示例:
```
<window>
<view x="c" y="m" w="300" h="30" children_layout="default(r=1,c=0,s=5)">
<button text="1" w="20%"/>
<button text="2" w="30%"/>
<button text="3" w="30%"/>
<button text="4" w="20%"/>
</view>
</window>
```
例如,将文件保存当前目录的 t.xml 文件,可用 preview_ui在 awtk\bin 目录下)预览效果如下图,命令如下:
```
bin\preview_ui.exe t.xml
```
![水平布局](images/layout_hbox.png)
### 2. vbox 垂直布局
当 cols=1,rows=0 时,所有子控件在垂直方向排成一列,可以实现垂直布局功能。子控件的参数:
* x 为 x\_margin
* y 从上到下排列,由布局参数计算而出。
* w 为父控件的宽度-2*x\_margin
* h 由子控件自己决定。
> 子控件需要自己决定高度。
示例:
```
<window>
<view x="c" y="m" w="80" h="200" children_layout="default(r=0,c=1,s=5)">
<button text="1" h="20%"/>
<button text="2" h="30%"/>
<button text="3" h="30%"/>
<button text="4" h="20%"/>
</view>
</window>
```
例如,将文件保存当前目录的 t.xml 文件,可用 preview_ui在 awtk\bin 目录下)预览效果如下图,命令如下:
```
bin\preview_ui.exe t.xml
```
![垂直布局](images/layout_vbox.png)
### 3. listbox 列表布局
当 cols=1,rows=N 时,所有子控件在垂直方向排成一列,可以实现列表布局功能。子控件的参数:
* x 为 x\_margin
* y 从上到下排列,由布局参数计算而出。
* w 为父控件的宽度-2*x\_margin
* h 为父控件的高度(减去边距和间距)分成成 N 等分。
> 子控件无需指定 x/y/w/h 等参数
示例:
```
<window>
<view x="c" y="m" w="200" h="200" children_layout="default(r=4,c=1,s=5)">
<button text="1" />
<button text="2" />
<button text="3" />
<button text="4" />
</view>
</window>
```
例如,将文件保存当前目录的 t.xml 文件,可用 preview_ui在 awtk\bin 目录下)预览效果如下图,命令如下:
```
bin\preview_ui.exe t.xml
```
![列表布局](images/layout_list.png)
### 4. grid 网格布局
当 cols=M,rows=N 时,所有子控件放在 MxN 的网格中,可以实现网格布局功能。
> 子控件无需指定 x/y/w/h 等参数
示例:
```
<window>
<view x="c" y="m" w="200" h="200" children_layout="default(r=2,c=2,s=5)">
<button text="1" />
<button text="2" />
<button text="3" />
<button text="4" />
</view>
</window>
```
例如,将文件保存当前目录的 t.xml 文件,可用 preview_ui在 awtk\bin 目录下)预览效果如下图,命令如下:
```
bin\preview_ui.exe t.xml
```
![网格布局](images/layout_grid.png)
### 5. floating 浮动布局
如果子控件的 floating 属性设置为 true其不受 children\_layout 的限制:
示例:
```
<window>
<view x="c" y="m" w="200" h="200" children_layout="default(r=2,c=2,s=5)">
<label text="1" />
<label text="2" />
<label text="3" />
<label text="4" />
<button text="floating" floating="true" x="c" y="m" w="80" h="30"/>
</view>
</window>
```
例如,将文件保存当前目录的 t.xml 文件,可用 preview_ui在 awtk\bin 目录下)预览效果如下图,命令如下:
```
bin\preview_ui.exe t.xml
```
![浮动布局](images/layout_floating.png)
## 四、高级用法
### 1. 子控件布局器和子控件自身的布局参数结合。
为了更大的灵活性,缺省子控件布局器可以和子控件自身的参数结合起来。
示例:
```
<window>
<view x="c" y="m" w="200" h="200" children_layout="default(r=2,c=2,s=5)">
<button text="1" x="0" y="0" w="50%" h="50%"/>
<button text="2" x="r" y="m" w="60%" h="60%"/>
<button text="3" x="c" y="m" w="70%" h="70%"/>
<button text="4" x="c" y="m" w="80%" h="80%"/>
</view>
</window>
```
例如,将文件保存当前目录的 t.xml 文件,可用 preview_ui在 awtk\bin 目录下)预览效果如下图,命令如下:
```
bin\preview_ui.exe t.xml
```
![高级用法一](images/layout_adv1.png)
### 2. 子控件自身的布局参数 x/y/w/h 均为像素方式时,需要用 self\_layout 参数指定。
示例:
```
<window>
<view x="c" y="m" w="200" h="200" children_layout="default(r=2,c=2,s=5)">
<button text="1" self_layout="default(x=0,y=0,w=50,h=50)" />
<button text="2" x="r" y="m" w="60%" h="60%"/>
<button text="3" x="c" y="m" w="70%" h="70%"/>
<button text="4" x="c" y="m" w="80%" h="80%"/>
</view>
</window>
```
例如,将文件保存当前目录的 t.xml 文件,可用 preview_ui在 awtk\bin 目录下)预览效果如下图,命令如下:
```
bin\preview_ui.exe t.xml
```
![高级用法二](images/layout_adv2.png)
## 五、示例
demos/assets/raw/ui/中有演示各种布局参数的示例。
> 以上在运行预览命令时,假定 awtk 的根目录为当前目录。
>
> 在不同平台下,命令运行方式有细微差别,请自行调整。
>

View File

@ -0,0 +1,63 @@
# ListView 子控件的布局器
## 一、语法
子控件布局器统一使用 children_layout 属性指定,其语法为:
```
ListView 子控件布局器 => list_view '(' PARAM_LIST ')'
PARAM_LIST => PARAM | PARAM ',' PARAM_LIST
```
> ListView 子控件布局器只适用于 ListView 下的 ScrollView 控件,除非需要指定边距和间距,否则一般无需指定该参数。
示例:
```
<list_view x="0" y="30" w="100%" h="-80" item_height="60">
<scroll_view name="view" x="0" y="0" w="100%" h="100%" children_layout="list_view(m=10,s=15)">
```
## 二、参数
ListView 子控件的布局器提供了下列参数:
| 参数 | 简写 | 说明 |
|-----------------------|:------:|:--------------------------------------------------------- |
| item\_height | i | 行高(作用与 listview 的 item\_height 属性相同) |
| default\_item\_height | d | 缺省行高(作用与 listview 的 default\_item\_height 属性相同) |
| margin | m | 边距 |
| x\_margin | xm | 水平方向的边距 |
| y\_margin | ym | 垂直方向的边距 |
| spacing | s | 子控件之间的间距 |
| keep_invisible | ki | 是否给不可见的控件留位置(缺省否)|
| keep_disable | kd | 是否给不用的控件留位置(缺省是)|
在代码中,可以通过 widget\_set\_children\_layout 函数启用子控件布局器:
```
/**
* @method widget_set_children_layout
* 设置子控件的布局参数。
* @annotation ["scriptable"]
* @param {widget_t*} widget 控件对象。
* @param {const char*} params 布局参数。
*
* @return {ret_t} 返回 RET_OK 表示成功,否则表示失败。
*/
ret_t widget_set_children_layout(widget_t* widget, const char* params);
```
示例:
```
widget_set_children_layout(w, "list_view(m=10,s=15)");
```
在 XML 中,可以通过 children\_layout 属性设置:
```
<list_view x="0" y="30" w="100%" h="-80" item_height="60">
<scroll_view name="view" x="0" y="0" w="100%" h="100%" children_layout="list_view(m=10,s=15)">
```

View File

@ -0,0 +1,9 @@
# 如何加入中文输入法
在示例项目中,没有加入输入法,主要是开发板的 flash 不够。如果 flash 够大(不小于 4M 时),可以自行加入:
* 加入 3rd/gpinyin/src 中的代码。
* 加入 src/input\_engines/input\_engine\_pinyin.cpp。
* 去掉 src/input\_engines/input\_engine\_null.cpp。
* include 路径加入 3rd/gpinyin/include。
* 把 default\_full.ttf 拷贝到 default.tff重新生成资源并编译 (defualt.ttf 中没有汉字default\_full.ttf 里才有,所以需要切换字体,否则输入的字符无法显示)。

View File

@ -0,0 +1,17 @@
# Code Style
每个人都有自己喜欢的代码风格AWTK 采用的代码风格不可能让所有人喜欢,所以 AWTK 提供了一个配置文件。clang-format借助 clang-format 工具可以瞬间将 AWTK 的代码风格变成你喜欢的代码风格。
具体做法如下:
## 安装 clang-format 工具
请参考http://releases.llvm.org/download.html#7.0.0
## 修改 .clang-format
请参考http://clang.llvm.org/docs/index.html
## 更新
> 支持 bash 的平台运行。/format.sh 即可。Windows 平台可以在 git bash 里运行。

View File

@ -0,0 +1,176 @@
# 颜色格式
AWTK 目前支持以下颜色格式:
* 十六机制格式。
RGB 三个通道分别用两个十六进制的字符表示alpha 通道为 0xff即不透明。如
```
#ffeedd 表示 R、G、B 分别为 0xff、0xee、0xdd
```
* rgb(R,G,B) 格式。
括号中的 R、G、B 为 0 到 255 之间的十进制数alpha 通道为 0xff即不透明。如
```
rgb(100, 150, 200) 表示 R、G、B 分别为 100、150、200
```
* rgba(R,G,B,A) 格式。
这是唯一支持半透明颜色的方式。
括号中的 R、G、B 为 0 到 255 之间的十进制数A 的为 0 到 1 之间的小数。如:
```
rgba(100, 150, 200, 0.5) 表示 R、G、B, A 分别为 100、150、200、0.5
```
> 注意:半透明颜色填充相对于不透明颜色填充,要慢很多,请谨慎使用。
* 英文名称。目前支持的颜色名称有:
| 名称 | 颜色值 |
| ---------------- | --------- |
|aliceblue | #f0f8ff |
|antiquewhite | #faebd7 |
|aqua | #00ffff |
|aquamarine | #7fffd4 |
|azure | #f0ffff |
|beige | #f5f5dc |
|bisque | #ffe4c4 |
|black | #000000 |
|blanchedalmond | #ffebcd |
|blue | #0000ff |
|blueviolet | #8a2be2 |
|brown | #a52a2a |
|burlywood | #deb887 |
|cadetblue | #5f9ea0 |
|chartreuse | #7fff00 |
|chocolate | #d2691e |
|coral | #ff7f50 |
|cornflowerblue | #6495ed |
|cornsilk | #fff8dc |
|crimson | #dc143c |
|cyan | #00ffff |
|darkblue | #00008b |
|darkcyan | #008b8b |
|darkgoldenrod | #b8860b |
|darkgray | #a9a9a9 |
|darkgreen | #006400 |
|darkkhaki | #bdb76b |
|darkmagenta | #8b008b |
|darkolivegreen | #556b2f |
|darkorange | #ff8c00 |
|darkorchid | #9932cc |
|darkred | #8b0000 |
|darksalmon | #e9967a |
|darkseagreen | #8fbc8f |
|darkslateblue | #483d8b |
|darkslategray | #2f4f4f |
|darkturquoise | #00ced1 |
|darkviolet | #9400d3 |
|deeppink | #ff1493 |
|deepskyblue | #00bfff |
|dimgray | #696969 |
|dodgerblue | #1e90ff |
|firebrick | #b22222 |
|floralwhite | #fffaf0 |
|forestgreen | #228b22 |
|fuchsia | #ff00ff |
|gainsboro | #dcdcdc |
|ghostwhite | #f8f8ff |
|gold | #ffd700 |
|goldenrod | #daa520 |
|gray | #bebebe |
|green | #008000 |
|greenyellow | #adff2f |
|honeydew | #f0fff0 |
|hotpink | #ff69b4 |
|indianred | #cd5c5c |
|indigo | #4b0082 |
|ivory | #fffff0 |
|khaki | #f0d58c |
|lavender | #e6e6fa |
|lavenderblush | #fff0f5 |
|lawngreen | #7cfc00 |
|lemonchiffon | #fffacd |
|lightblue | #add8e6 |
|lightcoral | #f08080 |
|lightcyan | #e0ffff |
|lightgoldenrodyellow | #fafad2 |
|lightgreen | #90ee90 |
|lightgrey | #d3d3d3 |
|lightpink | #ffb6c1 |
|lightsalmon | #ffa07a |
|lightseagreen | #20b2aa |
|lightskyblue | #87cefa |
|lightslategray | #778899 |
|lightsteelblue | #b0c4de |
|lightyellow | #ffffe0 |
|lime | #00ff00 |
|limegreen | #32cd32 |
|linen | #faf0e6 |
|magenta | #ff00ff |
|maroon | #800000 |
|mediumaquamarine | #66cdaa |
|mediumblue | #0000cd |
|mediumorchid | #ba55d3 |
|mediumpurple | #9370db |
|mediumseagreen | #3cb371 |
|mediumslateblue | #7b68ee |
|mediumspringgreen | #00fa9a |
|mediumturquoise | #48d1cc |
|mediumvioletred | #c71585 |
|midnightblue | #191970 |
|mintcream | #f5fffa |
|mistyrose | #ffe4e1 |
|moccasin | #ffe4b5 |
|navajowhite | #ffdead |
|navy | #000080 |
|oldlace | #fdf5e6 |
|olive | #808000 |
|olivedrab | #6b8e23 |
|orange | #ffa500 |
|orangered | #ff4500 |
|orchid | #da70d6 |
|palegoldenrod | #eee8aa |
|palegreen | #98fb98 |
|paleturquoise | #afeeee |
|palevioletred | #db7093 |
|papayawhip | #ffefd5 |
|peachpuff | #ffdab9 |
|peru | #cd853f |
|pink | #ffc0cb |
|plum | #dda0dd |
|powderblue | #b0e0e6 |
|purple | #800080 |
|red | #ff0000 |
|rosybrown | #bc8f8f |
|royalblue | #4169e1 |
|saddlebrown | #8b4513 |
|salmon | #fa8072 |
|sandybrown | #f4a460 |
|seagreen | #2e8b57 |
|seashell | #fff5ee |
|sienna | #a0522d |
|silver | #c0c0c0 |
|skyblue | #87ceeb |
|slateblue | #6a5acd |
|slategray | #708090 |
|snow | #fffafa |
|springgreen | #00ff7f |
|steelblue | #4682b4 |
|tan | #d2b48c |
|teal | #008080 |
|thistle | #d8bfd8 |
|tomato | #ff6347 |
|turquoise | #40e0d0 |
|violet | #ee82ee |
|wheat | #f5deb3 |
|white | #ffffff |
|whitesmoke | #f5f5f5 |
|yellow | #ffff00 |
|yellowgreen | #9acd32 |

View File

@ -0,0 +1,29 @@
# AWTK 中的一些惯例
#### 1.pixel 格式:以各个通道在内存中存放的顺序,从低地址到高地址递增的方式命名。
>如:
>
>RGBA8888表示内存地址从低到高依次为 RGBA每个通道各占一字节 (8 位)。
>
>BGR565表示内存地址从低到高依次为 BGRBGR 三个通道分别占 5 位6 位和 5 位。
---
#### 2. 所有类的公开属性都是只读的,不要直接去修改它们。
---
#### 3. 所有类的公开属性都可以直接读取,不提供 get 函数。
---
#### 4.widget 及其子类的公开属性,如果在 annotation 中标明支持 set\_prop那么可以在界面描述文件中用同名属性为其指定的初始值。
---
#### 5. 除非特别说明,时间单位为毫秒。
---
#### 6. 除非特别说明,控件都是容器。你可以在按钮中放图片,也可以在图片中放按钮,通过组合形成更强大控件。

View File

@ -0,0 +1,152 @@
# 编写跨平台的代码
## 1. 尽量使用 tkc 中的函数
tkc 中提供了编码、时间、网络、串口、线程、互斥和文件系统等各种需要跨平台接口的封装,这些接口在各个平台都有实现。
## 2. 针对接口编程
如果需要的某个功能,在各个平台都有不同的实现,先研究各个平台提供的功能,再抽象一个统一的接口,针对各个平台实现一个适配器。应用程序使用统一的接口去访问这些功能,应用程序不但能够跨平台运行,代码也更具可读性。
## 3. 指定特定平台的库、头文件、预处理参数和链接参数
helper 提供了一组函数来处理不同平台的参数。平台名称的取值有:
* "Windows" Windows 平台
* "Linux" Linux 平台
* "Darwin" MacOS 平台
> Android 和 IOS 不使用 scons 编译,故不使用这种方式。
* 添加平台特有的库
示例:
```python
helper.add_platform_libs("Windows", ["ws2_32"])
helper.add_platform_libs("Linux", ["pthread", "dl", "readline", "m"])
helper.add_platform_libs("Darwin", ["pthread", "dl", "readline", "m"])
```
* 添加平台特有的库的搜索路径
```
add_platform_libpath(self, platform_name, APP_LIBPATH)
```
示例:
```
helper.add_platform_libpath("Linux", ["/usr/local/lib"])
```
> 注意这里的 APP_LIBPATH 是数组类型。
* 添加平台特有的头文件的搜索路径
```
add_platform_cpppath(self, platform_name, APP_CPPPATH)
```
示例:
```
helper.add_platform_libpath("Linux", ["/usr/local/include"])
```
> 注意这里的 APP_CPPPATH 是数组类型
* 添加平台特有的宏定义预处理参数
```
add_platform_ccflags(self, platform_name, APP_CCFLAGS)
```
示例:
```
helper.add_platform_ccflags("Linux", " -DSOME_MACRO=1 ")
```
> ccflags 是字符串格式不是数组
* 添加平台特有的C++文件的预处理参数
```
add_platform_cxxflags(self, platform_name, APP_CXXFLAGS)
```
示例:
```
helper.add_platform_cxxflags("Linux", " -DSOME_MACRO=1 ")
```
> cxxflags 是字符串格式不是数组
* 添加平台特有的链接参数
```
add_platform_linkflags(self, platform_name, APP_LINKFLAGS)
```
> linkflags 是字符串格式不是数组
## 4. 区分各个平台的宏
* WIN32 或 WINDOWS Windows 平台
* MINGW Windows 平台的 MinGW 编译。
* LINUX Linux 平台
* MACOS 或__APPLE__ Macos 平台
* ANDROID Android 平台
* IOS iOS 平台
> 这些宏虽然可以区分不同的平台,但是如果将这些宏分散在应用程序中,代码将会变得丑陋难读。建议先定义接口,在适配器中使用这些宏。
示例:
```
#ifdef ANDROID
#include "SDL.h"
#endif /*ANDROID*/
#if defined(__APPLE__) || defined(LINUX)
#include <unistd.h>
#include <dirent.h>
#include <sys/types.h>
#include <pwd.h>
#elif defined(WIN32)
#include <stdio.h>
#include <windows.h>
#include <io.h>
#include <direct.h>
#include <Shlobj.h>
#include <fileapi.h>
#define unlink _unlink
#define rename MoveFileA
#define ftruncate _chsize
#include "./dirent.inc"
#include "tkc/utf8.h"
#include "tkc/mem.h"
#endif
#if defined(__APPLE__)
#include <mach-o/dyld.h>
#endif /*__APPLE__*/
```
## 5. 添加平台特有的文件
有些文件是特定平台才需要的,可以根据平台的名称,来决定添加哪些文件。
示例:
```python
import platform;
OS_NAME=platform.system()
if OS_NAME == 'Windows':
sources=Glob('src/windows/*.c')
elif OS_NAME == 'Linux':
sources=Glob('src/linux/*.c')
```

View File

@ -0,0 +1,350 @@
# 自定义控件规范
为了自定义控件可以在 Designer 中使用,需要将自定义控件编译成动态库。
编译脚本请参考https://github.com/zlgopen/awtk-widget-number-label/blob/master/src/SConscript
## 1. 目录结构
* design 存放示例代码的原始资源,用 Designer 打开后可进行编辑。
* res 存放示例代码运行时需要的资源,由 Designer 打包 或者 scripts/update_res.py 脚本生成。
* bin 存放动态库和可执行文件。
* lib 存放静态库文件。
* demos 存放示例代码。
* idl 存放生成的 IDL 文件。
* scripts 存放资源生成的脚本文件。
* src 存放控件源码,每个控件放在独立的目录。
* tests 用于存放测试代码。
示例:
```
├─design
│ └─default
├─res
│ └─assets
│ └─default
├─bin
├─lib
├─demos
├─docs
├─idl
├─scripts
├─src
│ └─number_label
└─tests
```
> 完整示例参考 [number-label](https://github.com/zlgopen/awtk-widget-number-label)
## 2. 命名规范
### 2.1 控件类型名
控件类型名使用小写的英文单词,多个单词之间用下划线连接。
如:
```
#define WIDGET_TYPE_NUMBER_LABEL "number_label"
```
控件类型名用于注册控件,以便在 XML UI 文件中使用。
> 控件名要求能展示控件的功能。
### 2.2 子目录名
在 src 下的子目录名与控件类型名保持一致。
### 2.3 源文件名
* 头文件名:控件类型名 + ".h"
* 源文件名:控件类型名 + ".c"
### 2.4 类名
控件类型名 + "_t"
如:
```c
typedef struct _number_label_t {
widget_t widget;
...
} number_label_t;
```
> 自定义控件只能以 widget_t 作为父类。
### 2.2 函数名
成员函数以控件类型名为前缀,以下划线连接,全部使用小写单词。
如:
```
/**
* @method number_label_set_format
* 设置格式字符串(用于将浮点数转换为字符串)。
* @annotation ["scriptable"]
* @param {widget_t*} widget 控件对象。
* @param {const char*} format 格式字符串。
*
* @return {ret_t} 返回 RET_OK 表示成功,否则表示失败。
*/
ret_t number_label_set_format(widget_t* widget, const char* format);
```
### 2.3 属性名
属性名使用小写的英文单词,多个单词之间用下划线连接。
> 属性名必须与 XML UI 文件中的属性名保持一致。
示例
```c
/**
* @property {char*} format
* @annotation ["set_prop","get_prop","readable","persitent","design","scriptable"]
*
* 格式字符串。
*
*/
char* format;
```
> 如果修改某个属性会 EVT\_VALUE\_CHANGED 事件,请支持通过 WIDGET\_PROP\_VALUE 访问该属性。
比如,手势密码控件的 password 属性,是用户可以输入的,修改 password 触发 EVT\_VALUE\_CHANGED 事件,那么在 get_prop/set_prop 里要允许通过 WIDGET\_PROP\_VALUE 访问 password 属性。
```c
static ret_t gesture_lock_get_prop(widget_t* widget, const char* name, value_t* v) {
gesture_lock_t* gesture_lock = GESTURE_LOCK(widget);
return_value_if_fail(gesture_lock != NULL && name != NULL && v != NULL, RET_BAD_PARAMS);
ret_t ret = RET_NOT_FOUND;
if (tk_str_eq(name, GESTURE_LOCK_PROP_PASSWORD) || tk_str_eq(name, WIDGET_PROP_VALUE)) {
value_set_str(v, gesture_lock->password);
ret = RET_OK;
}
return ret;
}
```
### 2.4 事件名
如果控件有自定义的事件,事件名以"EVT"为前缀,使用大写的英文单词,单词之间用下划线连接。
如:
```c
/**
* @event {pointer_event_t} EVT_LONG_PRESS
* 长按事件。
*/
```
### 2.5 动态库名
如果动态库中只有一个控件,动态库的名称使用控件类型名。如果动态库中有多个控件,可以自行考虑名称。
### 2.6 控件注册函数名
控件注册函数负责注册动态库中的控件。
控件注册函数名必须以动态库名为前缀,加上"_register"。注册函数无参数,并返回 ret_t。
如:
```c
/**
* @method number_label_register
* 注册数值文本控件。
*
* @annotation ["global"]
*
* @return {ret_t} 返回 RET_OK 表示成功,否则表示失败。
*/
ret_t number_label_register(void);
```
### 2.7 获取支持的渲染模式的函数名
目前可选的渲染模式有 OpenGL、AGGE-BGR565、AGGE-BGRA8888、AGGE-MONO默认支持全部模式模式之间以“|”间隔,可根据实际情况修改。
获取支持的渲染模式的函数名必须以动态库名为前缀,加上"_supported_render_mode"。该函数无参数,并返回 const char*。
如:
```c
/**
* @method number_label_supported_render_mode
* 获取支持的渲染模式。
*
* @annotation ["global"]
*
* @return {const char*} 返回 RET_OK 表示成功,否则表示失败。
*/
const char* number_label_supported_render_mode(void);
```
## 3. 注释格式
自定义控件需要使用 AWTK 标准注释。请参考 [API 注释格式](api_doc.md)
## 4. 辅助工具
awtk 提供了一些工具用于生成 IDL 和动态库导出符号表。
* awtk/tools/idl\_gen/index.js 用于生成 IDL。
如:
```
node ../awtk/tools/idl_gen/index.js idl/idl.json src/
```
* awtk/tools/dll\_def\_gen/index.js 用于生成动态库导出符号表。
如:
```
node ../awtk/tools/dll_def_gen/index.js idl/idl.json src/number_label.def
```
> 使用这些工具需要安装 [nodejs](https://nodejs.org/zh-cn/)
## 5. 依赖的 AWTK 版本
可以在自定义控件项目的 project.json 文件中设置该动态库依赖的 AWTK 版本。
如:
```json
{
...
"usesSdk": {
"awtk:minSdkVersion": "20070",
"awtk:maxSdkVersion": "20090",
"awtk:targetSdkVersion": "20090"
}
...
}
```
* 参数 awtk:minSdkVersion 是可选的,表示兼容的最低版本。
* 参数 awtk:maxSdkVersion 是可选的,表示兼容的最高版本。
* 参数 awtk:targetSdkVersion 是可选的,表示最佳版本。
> 上述版本号对应发布的 AWTK 中 component.json 文件中的 "release_id"
> 注意:如果没有显式设置,则认为兼容所有版本。
## 6. Designer 新建控件的初始状态
默认情况下,从 Designer 的控件列表的自定义分组中拖出一个控件,其属性为控件 create 时的初值,样式为全透明。
如果需要指定新建控件的初始状态,可以在控件的 class 注释上补充如下格式的注释。
```c
/**
...
* ```xml
* <!-- ui -->
* 控件初始属性的 xml 描述(如果描述中包含子控件,会同时创建)
* ```
...
* ```xml
* <!-- style -->
* 控件默认样式的 xml 描述(如果描述中包含其它控件的样式,会同时添加到 default.xml 样式文件)
* ```
...
*/
```
如:
```c
/**
* @class number_label_t
* @parent widget_t
* @annotation ["scriptable","design","widget"]
* 数值文本控件。
*
* 在 xml 中使用"number\_label"标签创建数值文本控件。如:
*
* ```xml
* <!-- ui -->
* <number_label x="c" y="50" w="24" h="100" value="40" format="%.4lf" decimal_font_size_scale="0.5"/>
* ```
*
* 可用通过 style 来设置控件的显示风格,如字体的大小和颜色等等。如:
*
* ```xml
* <!-- style -->
* <number_label>
* <style name="default" font_size="32">
* <normal text_color="black" />
* </style>
* <style name="green" font_name="led" font_size="32">
* <normal text_color="green" />
* </style>
* </number_label>
* ```
*/
```
> Designer 新建控件时会根据上述描述初始化控件的属性及样式,但会忽略 x、y 属性。
## 7. Designer 中的图标
如果需要修改自定义控件在 Designer 中的图标,请将图标存放到指定位置。
### 7.1 库的图标
库的图标指在 Designer 的“选择模板”或者“模板管理”页面上用于标识自定义控件库或者描述其功能的图标,大小为 60*60 像素。
默认为自定义控件库的 docs/images/widget_preview.png。
> 如果不指定,则显示为空。
### 7.2 控件列表上的图标
控件列表上的图标指在 Designer 的控件列表上该控件的图标,大小为 48*48 像素。
默认为自定义控件库的 docs/images/widget_list.png。
> 如果不指定,则显示默认图标。
> 如果自定义控件库包含多个控件可以用“widget_list_”前缀 + 控件类型名的形式为控件单独指定图标比如“widget_list_number_label.png”。
### 7.3 对象浏览器上的图标
对象浏览器上的图标指在 Designer 的对象浏览器上该控件类型的对象左侧显示的图标,大小为 16*16 像素。
默认为自定义控件库的 docs/images/widget_obj.png。
> 如果不指定,则显示默认图标。
> 如果自定义控件库包含多个控件可以用“widget_obj_”前缀 + 控件类型名的形式为控件单独指定图标比如“widget_obj_number_label.png”。
## 8. src 目录中的源代码使用相对路径的方式 include 头文件
为了避免使用自定义控件库时需设置一遍编译时的 include 目录,提高用户体验,要求在源代码中 include 头文件时使用相对路径的形式。
比如number_label.h、number_label.c 在同一个目录,则在 number_label.c 中按如下方式 include
```c
...
#include "number_label.h"
...
```
> 如果不使用相对路径的方式,则请在自定义控件库的 README.md 文件中注明该库需要 include 的目录。

View File

@ -0,0 +1,38 @@
# AWTK 调试技巧
这里收集一些调试技巧,各种疑难杂症的解决方案。请大家把遇到的问题(包括已经解决的)发到 issues 上,我来收集整理。谢谢
## 一、输入设备相关问题
### 1. 指针设备问题的检查列表:
* 设备名称是否正确。
* 电阻屏是否校准。
* x/y 是否需要对调或其它变换。
## 二、显示相关问题
### 1. 图片颜色不正常的检查列表:
* LCD 的格式是否正确。
* 图片格式是否正确。
## 三、资源相关问题
## 四、内存问题
* 1. 内存出现莫名其妙的错误
> 通常是堆栈溢出,把栈空间修改大点试试。如果支持 jpg/png栈至少 32K如果支持 gif 栈至少 48K。
* 2. 内存泄露
> 如果定义宏了 ENABLE\_MEM\_LEAK\_CHECK每次内存分配都会记录分配的位置、大小和时间并在窗口打开和关闭时通过 log\_debug 显示当前未释放的内存块。根据块数的变化可以看出是否有内存泄露,并根据分配的位置可以定位泄露的位置。
## 五、性能问题
性能问题的检查列表:
* 1. 硬件加速是否启用。
* 2.memcpy 的速度是否正常。
* 3. 在 window\_manager\_paint\_normal 函数中查看 last\_paint\_cost 是否在合理的范围。

View File

@ -0,0 +1,73 @@
# 对话框高亮策略
## 一、介绍
在弹出除对话框时,通常希望让背景窗口变暗或者变模糊,以突显当前的对话框的重要性。我们把让背景窗口变暗或者变模糊的方法称为对话框高亮策略。并把对话框高亮策略抽象成接口,开发者可以自己实现特殊效果的高亮策略,也可以使用缺省的高亮策略。
缺省的对话框高亮策略是让背景窗口变暗,可以是静态的(固定 alpha),也可以是动态的。动态的高亮策略在对话框打开的动画过程中,背景窗口逐渐变暗,这有更好的视觉效果,但也需要更多的计算开销,开发者可以根据实际情况选用静态还是动态效果。
## 二、使用方法
通过对话框的 hightlight 属性来指定对话框的高亮策略,"default"表示缺省的对话框的高亮策略。如:
使用静态效果:
```
<dialog anim_hint="popdown" highlight="default(alpha=40)"
x="0" y="0" w="100%" h="160">
```
使用动态效果:
```
<dialog anim_hint="popup" highlight="default(start_alpha=0, end_alpha=80)"
x="0" y="bottom" w="100%" h="160">
```
## 三、参数说明
参数其格式为 [类似函数调用的参数格式](func_call_params_format.md)。 缺省的对话框高亮策略支持以下几个参数:
* start_alpha 起始 alpha 值 (0-255)。
* end_alpha 结束 alpha 值 (0-255)。
* alpha 相当于将 start\_alpha 和 end\_alpha 设置为同一个值。
> 当 alpha=0 时,显示效果没有变化,但相当于了缓存背景窗口的绘制到图片中,从而提高显示效率,在特殊情况下可以酌情使用。
## 四、自定义对话框高亮策略
开发者可以自定义高亮策略,自定义的高亮策略可以像内置高亮策略一样,可以用以上方法在 XML 文件中启用。
1. 实现 dialog\_highlighter\_t 接口。如:
```
static const dialog_highlighter_vtable_t s_dialog_highlighter_default_vt = {
.type = "dialog_highlighter_default_t",
.desc = "dialog_highlighter_default_t",
.size = sizeof(dialog_highlighter_default_t),
.prepare = dialog_highlighter_default_prepare,
.draw = dialog_highlighter_default_draw};
dialog_highlighter_t* dialog_highlighter_default_create(object_t* args) {
value_t v;
dialog_highlighter_t* h = dialog_highlighter_create(&s_dialog_highlighter_default_vt);
dialog_highlighter_default_t* dh = (dialog_highlighter_default_t*)h;
return_value_if_fail(h != NULL, NULL);
dh->end_alpha = 0;
dh->start_alpha = 0;
...
return h;
}
```
2. 注册到 dialog\_highlighter\_factory 工厂。如:
```
dialog_highlighter_factory_register(f, DIALOG_HIGHLIGHTER_DEFAULT,
dialog_highlighter_default_create);
```
> 完整示例请参考https://github.com/zlgopen/awtk/tree/master/src/dialog_highlighters

View File

@ -0,0 +1,26 @@
digraph G {
ratio = fill;
node [style=filled height=0.4 width=2 fontname="serif" ];
edge [fontname="serif" ];
rankdir="LR";
idl[color="0.408 0.498 1.000" label="JSON格式的IDL"];
comment[color="0.650 0.200 1.000" label="API 注释"];
quickjs[color="0.201 0.753 1.000" label="QuickJS 绑定"];
jerryscript[color="0.201 0.753 1.000" label="JerryScript 绑定"];
lua[color="0.201 0.753 1.000" label="LUA 绑定"];
web[color="0.201 0.753 1.000" label="WEB API"];
other[color="0.201 0.753 1.000" label="其它语言绑定"];
doc[color="0.650 0.700 0.700" label="文档"];
comment -> idl[label="注释提取工具" ]
idl -> jerryscript[label="jerryscript代码生成器"]
idl -> quickjs[label="quickjs代码生成器"]
idl -> lua[label="lua代码生成器"]
idl -> web[label="web代码生成器"]
idl -> other[label="其它代码生成器"]
idl -> doc[label="文档生成工具"]
}

View File

@ -0,0 +1,23 @@
digraph UML {
rankdir = TB
fontname = "Courier New"
fontsize = 10
node [ fontname = "Courier New", fontsize = 10, shape = "record" ];
edge [ fontname = "Courier New", fontsize = 10 ];
subgraph clusterAssetsManager {
asset_info_t[ label = "{asset_info_t|+name\l+data\l+size\l+type\l+subtype\l}" ];
assets_manager_t->asset_info_t[constraint=false arrowhead=none];
};
locale_info_t ->assets_manager_t[arrowhead=vee];
font_manager_t->assets_manager_t[arrowhead=vee];
image_manager_t->assets_manager_t[arrowhead=vee];
theme_t->assets_manager_t[arrowhead=vee];
ui_loader_t->assets_manager_t[arrowhead=vee];
assets_manager_t -> fs[arrowhead=vee];
assets_manager_t -> rom_data[arrowhead=vee];
assets_manager_t -> network[arrowhead=vee];
}

View File

@ -0,0 +1,30 @@
digraph G {
rankdir = BT
fontname = "Courier New"
fontsize = 12
node [
fontname = "Courier New"
fontsize = 12
shape = "record"
width = 0.4
]
subgraph clusterFontManager{
glyph_t[ label = "{glyph_t|+x\l+y\l+w\l+h\l+data\l}" ];
font_t[ label = "{font_t|+match(...)\l+find_glyph(...) : glyph_t\l}" ];
font_loader_t [ label = "{font_loader_t|+load(...) : font_t\l}" ];
font_manager_t [ label = "{font_manager_t|+get_font(...) : font_t\l}" ];
glyph_t -> font_t [constraint=false arrowhead = ediamond ]
font_t -> font_manager_t[arrowhead="none"];
font_loader_t -> font_manager_t[arrowhead="none"];
font_loader_t -> font_t [constraint=false arrowhead="vee" label="load"];
}
canvas_t -> font_manager_t[arrowhead="vee" label="get_font"];
font_loader_ft_t -> font_loader_t[arrowhead=empty style=dashed]
font_loader_stb_t -> font_loader_t[arrowhead=empty style=dashed]
font_loader_bitmap_t -> font_loader_t[arrowhead=empty style=dashed]
}

View File

@ -0,0 +1,11 @@
digraph UML {
rankdir = LR
fontname = "Courier New"
fontsize = 10
node [ fontname = "Courier New", fontsize = 10, shape = "record" ];
edge [ fontname = "Courier New", fontsize = 10 ];
idle_t -> idle_info_t[arrowhead=vee]
}

View File

@ -0,0 +1,20 @@
digraph UML {
rankdir = BT
fontname = "Courier New"
fontsize = 10
node [ fontname = "Courier New", fontsize = 10, shape = "record" ];
edge [ fontname = "Courier New", fontsize = 10 ];
subgraph clusterImageManager {
bitmap_t[ label = "{bitmap_t|+x\l+y\l+w\l+h\l+data\l}" ];
image_manager_t[ label = "{image_manager_t|+ get_bitmap(...)\l}" ];
image_loader_t[ label = "{image_loader_t|+ load(...)\l}" ];
image_manager_t->bitmap_t[constraint=false arrowhead=none];
image_loader_t->image_manager_t[arrowhead=vee ];
};
image_loader_stb_t->image_loader_t[arrowhead=empty style=dashed];
}

View File

@ -0,0 +1,24 @@
digraph UML {
rankdir = BT
fontname = "Courier New"
fontsize = 10
node [ fontname = "Courier New", fontsize = 10, shape = "record" ];
edge [ fontname = "Courier New", fontsize = 10 ];
input_method_t -> edit_t [arrowhead=none]
subgraph cluster_1 {
input_method_t -> input_engine_t [constraint=false arrowhead=vee style=dashed]
}
input_method_default_t -> input_method_t [arrowhead=empty style=dashed]
input_method_sdl_t -> input_method_t [arrowhead=empty style=dashed]
input_method_null_t -> input_method_t [arrowhead=empty style=dashed]
input_engine_pinyin_t -> input_engine_t[arrowhead=empty style=dashed]
input_engine_null_t -> input_engine_t[arrowhead=empty style=dashed]
keyboard_t ->input_method_default_t [arrowhead=none]
}

View File

@ -0,0 +1,23 @@
digraph G {
rankdir = BT
fontname = "Courier New"
fontsize = 12
node [
fontname = "Courier New"
fontsize = 12
shape = "record"
width = 0.4
]
subgraph clusterFontManager{
children_layouter_factory -> children_layouter[constraint=false arrowhead=normal]
}
children_layouter_default -> children_layouter[style=dashed arrowhead=empty]
children_layouter_list_view -> children_layouter[style=dashed arrowhead=empty]
children_layouter_flex -> children_layouter[style=dashed arrowhead=empty]
children_layouter_xxx -> children_layouter[style=dashed arrowhead=empty]
}

View File

@ -0,0 +1,17 @@
digraph G {
rankdir = RL
fontname = "Courier New"
fontsize = 12
node [
fontname = "Courier New"
fontsize = 12
shape = "record"
width = 0.4
]
self_layout -> widget_t[arrowhead = "ediamond"]
children_layout -> widget_t[arrowhead = "ediamond"]
}

View File

@ -0,0 +1,23 @@
digraph G {
rankdir = BT
fontname = "Courier New"
fontsize = 12
node [
fontname = "Courier New"
fontsize = 12
shape = "record"
width = 0.4
]
subgraph clusterFontManager{
self_layouter_default -> self_layouter[constraint=false arrowhead=normal]
}
self_layouter_default -> self_layouter[style=dashed arrowhead=empty]
self_layouter_menu -> self_layouter[style=dashed arrowhead=empty]
self_layouter_flex -> self_layouter[style=dashed arrowhead=empty]
self_layouter_menu -> self_layouter[style=dashed arrowhead=empty]
self_layouter_xxx -> self_layouter[style=dashed arrowhead=empty]
}

View File

@ -0,0 +1,20 @@
digraph G {
rankdir = BT
fontname = "Courier New"
fontsize = 12
node [
fontname = "Courier New"
fontsize = 12
shape = "record"
width = 0.4
]
lcd_mem_fragment_t -> lcd_t[arrowhead = "empty"]
lcd_mono_t -> lcd_t[arrowhead = "empty"]
lcd_mem_t -> lcd_t[arrowhead = "empty"]
lcd_vgcanvas_t -> lcd_t[arrowhead = "empty"]
lcd_profile_t -> lcd_t[arrowhead = "empty"]
lcd_mem_xxx -> lcd_mem_t[arrowhead = "none"]
lcd_mem_special -> lcd_mem_t[arrowhead = "none"]
}

View File

@ -0,0 +1,19 @@
digraph G {
rankdir = BT
fontname = "Courier New"
fontsize = 12
node [
fontname = "Courier New"
fontsize = 12
shape = "record"
width = 0.4
]
mem_allocator_simple_t -> mem_allocator_t[arrowhead = "empty"]
mem_allocator_std_t -> mem_allocator_t[arrowhead = "empty"]
mem_allocator_lock_t -> mem_allocator_t[arrowhead = "empty"]
mem_allocator_pool_t -> mem_allocator_t[arrowhead = "empty"]
mem_allocator_debug_t -> mem_allocator_t[arrowhead = "empty"]
mem_allocator_oom_t -> mem_allocator_t[arrowhead = "empty"]
}

View File

@ -0,0 +1,22 @@
digraph UML {
rankdir = BT
fontname = "Courier New"
fontsize = 10
node [ fontname = "Courier New", fontsize = 10, shape = "record" ];
edge [ fontname = "Courier New", fontsize = 10 ];
style_t->widget_t[arrowhead=none];
style_factory_t->widget_t[arrowhead=none];
subgraph cluster_0{
style_factory_t->style_t[constraint=false arrowhead=vee];
};
subgraph cluster_1{
style_const_t -> style_mutable_t[constraint=false arrowhead=ediamond]
};
style_const_t -> style_t[arrowhead=empty style=dashed]
style_mutable_t -> style_t[arrowhead=empty style=dashed]
theme_t -> style_const_t[arrowhead=none]
}

View File

@ -0,0 +1,11 @@
digraph UML {
rankdir = LR
fontname = "Courier New"
fontsize = 10
node [ fontname = "Courier New", fontsize = 10, shape = "record" ];
edge [ fontname = "Courier New", fontsize = 10 ];
timer_t -> timer_info_t[arrowhead=vee]
}

View File

@ -0,0 +1,24 @@
digraph UML {
rankdir = BT
fontname = "Courier New"
fontsize = 10
node [ fontname = "Courier New", fontsize = 10, shape = "record" ];
edge [ fontname = "Courier New", fontsize = 10 ];
subgraph cluster_1{
ui_builder_t[ label = "{ui_builder_t|+on_start(...)\l+on_widget_start(...)\l+on_widget_prop(...)\l+on_widget_end(...)\l+on_end(...)\l}" ];
ui_loader_t[ label = "{ui_loader_t|+load(...)\l}" ];
ui_loader_t -> ui_builder_t[constraint=false arrowhead=vee]
};
ui_loader_default_t -> ui_loader_t [arrowhead=empty style=dashed]
ui_loader_xml_t -> ui_loader_t [arrowhead=empty style=dashed]
ui_builder_default_t -> ui_builder_t [arrowhead=empty style=dashed]
ui_xml_writer_t -> ui_builder_t [arrowhead=empty style=dashed]
ui_binary_writer_t -> ui_builder_t [arrowhead=empty style=dashed]
}

View File

@ -0,0 +1,78 @@
digraph G {
rankdir = RL
fontname = "Courier New"
fontsize = 12
node [
fontname = "Courier New"
fontsize = 12
shape = "record"
width = 0.4
]
edit_t -> widget_t[arrowhead=empty]
image_base_t -> widget_t[arrowhead=empty]
window_base_t -> widget_t[arrowhead=empty]
label_t -> widget_t[arrowhead=empty]
button_t -> widget_t[arrowhead=empty]
color_tile_t -> widget_t[arrowhead=empty]
combo_box_item_t -> widget_t[arrowhead=empty]
slider_t -> widget_t[arrowhead=empty]
progress_bar_t -> widget_t[arrowhead=empty]
app_bar_t -> widget_t[arrowhead=empty]
row_t -> widget_t[arrowhead=empty]
column_t -> widget_t[arrowhead=empty]
grid_t -> widget_t[arrowhead=empty]
grid_item_t -> widget_t[arrowhead=empty]
group_box_t -> widget_t[arrowhead=empty]
view_t -> widget_t[arrowhead=empty]
button_group_t -> widget_t[arrowhead=empty]
dialog_title_t -> widget_t[arrowhead=empty]
dialog_client_t -> widget_t[arrowhead=empty]
window_t -> window_base_t[arrowhead=empty]
popup_t -> window_base_t[arrowhead=empty]
dialog_t -> window_base_t[arrowhead=empty]
calibration_win_t -> window_base_t[arrowhead=empty]
system_bar_t -> window_base_t[arrowhead=empty]
overlay_t -> window_base_t[arrowhead=empty]
image_t -> image_base_t[arrowhead=empty]
gif_image_t -> image_base_t[arrowhead=empty]
svg_image_t -> image_base_t[arrowhead=empty]
combo_box_t -> edit_t[arrowhead=empty]
spin_box_t -> edit_t[arrowhead=empty]
tab_control_t -> widget_t[arrowhead=empty]
tab_button_t -> widget_t[arrowhead=empty]
tab_button_group_t -> widget_t[arrowhead=empty]
group_box_t -> widget_t[arrowhead=empty]
app_bar_t -> widget_t[arrowhead=empty]
canvas_widget_t -> widget_t[arrowhead=empty]
color_picker_t -> widget_t[arrowhead=empty]
guage_t -> widget_t[arrowhead=empty]
guage_pointer_t -> widget_t[arrowhead=empty]
image_animation_t -> widget_t[arrowhead=empty]
image_value_t -> widget_t[arrowhead=empty]
keyboard_t -> widget_t[arrowhead=empty]
progress_circle_t -> widget_t[arrowhead=empty]
rich_text_t -> widget_t[arrowhead=empty]
slide_menu_t -> widget_t[arrowhead=empty]
slide_view_t -> widget_t[arrowhead=empty]
switch_t -> widget_t[arrowhead=empty]
text_selector_t -> widget_t[arrowhead=empty]
time_clock_t -> widget_t[arrowhead=empty]
digit_clock_t -> widget_t[arrowhead=empty]
list_view_t -> widget_t[arrowhead=empty]
list_view_h_t -> widget_t[arrowhead=empty]
list_item_t -> widget_t[arrowhead=empty]
scroll_bar_t -> widget_t[arrowhead=empty]
scroll_view_t -> widget_t[arrowhead=empty]
mledit_t -> widget_t[arrowhead=empty]
slide_indicator_t -> widget_t[arrowhead=empty]
line_number_t -> widget_t[arrowhead=empty]
}

View File

@ -0,0 +1,29 @@
### 插值算法名称(easing)
* linear
* quadratic\_in
* quadratic\_out
* quadratic\_inout
* cubic\_in
* cubic\_out
* sin\_in
* sin\_out
* sin\_inout
* pow\_in
* pow\_out
* pow\_inout
* circular\_in
* circular\_out
* circular\_inout
* elastic\_in
* elastic\_out
* elastic\_inout
* back\_in
* back\_out
* back\_inout
* bounce\_in
* bounce\_out
* bounce\_inout
具体效果,请参考:[tween.js](http://tweenjs.github.io/tween.js/examples/03_graphs.html)

View File

@ -0,0 +1,81 @@
# AWTK 中的事件处理函数
emitter 实现了通用的事件注册、注销和分发功能widget 对此做了进一步包装,使用起来非常方便。
## 一、注册控件事件的处理函数
使用 widget_on 来注册事件处理函数:
```
/**
* @method widget_on
* 注册指定事件的处理函数。
* @scriptable custom
* @param {widget_t*} widget 控件对象。
* @param {event_type_t} type 事件类型。
* @param {event_func_t} on_event 事件处理函数。
* @param {void*} ctx 事件处理函数上下文。
*
* @return {uint32_t} 返回 id用于 widget_off。
*/
uint32_t widget_on(widget_t* widget, event_type_t type, event_func_t on_event, void* ctx);
```
示例:
```
static ret_t on_inc(void* ctx, event_t* e) {
widget_t* progress_bar = (widget_t*)ctx;
uint8_t value = (PROGRESS_BAR(progress_bar)->value + 10) % 100;
progress_bar_set_value(progress_bar, value);
(void)e;
return RET_OK;
}
...
progress_bar = progress_bar_create(win, 10, 80, 168, 30);
widget_set_value(progress_bar, 40);
ok = button_create(win, 10, 5, 80, 30);
widget_set_text(ok, L"Inc");
widget_on(ok, EVT_CLICK, on_inc, progress_bar);
...
```
在上面这个例子中,我们创建了一个进度条和一个按钮,并为按钮的『点击』事件注册一个处理函数,当按钮被点击时,增加进度条的值。
## 二、注销控件事件的处理函数
由于窗口关闭时会销毁其中所有控件,所以一般不需要手工去注销。如果确实需要,可以使用 widget_off:
```
/**
* @method widget_off
* 注销指定事件的处理函数。
* @scriptable custom
* @param {widget_t*} widget 控件对象。
* @param {uint32_t} id widget_on 返回的 ID。
*
* @return {ret_t} 返回 RET_OK 表示成功,否则表示失败。
*/
ret_t widget_off(widget_t* widget, uint32_t id);
```
## 三、控件分发事件
一般只有在控件内部实现中,或者需要向控件注入事件时,才需要调用事件分发函数。如果需要分发事件,可以调用 widget_dispatch
```
/**
* @method widget_dispatch
* 分发一个事件。
* @private
* @param {widget_t*} widget 控件对象。
* @param {event_t*} e 事件。
*
* @return {ret_t} 返回 RET_OK 表示成功,否则表示失败。
*/
ret_t widget_dispatch(widget_t* widget, event_t* e);
```

View File

@ -0,0 +1,108 @@
# 输入事件记录与重放
## 1. 用途
输入事件记录与重放的常见用途有:
* 自动演示功能。
* 长时间运行进行压力测试。
* 辅助手工测试。有时出现崩溃的 BUG 时,往往忘记之前是如何操作的了,输入事件记录与重放可以精确重现问题。同时也可以减轻手工测试的工作量。
## 2.API
```c
/**
* @method event_recorder_player_start_record
* 开始事件记录。
* @annotation ["static"]
* @param {const char*} filename 用于保存事件的文件名。
*
* @return {ret_t} 返回 RET_OK 表示成功,否则表示失败。
*/
ret_t event_recorder_player_start_record(const char* filename);
/**
* @method event_recorder_player_start_play
* 开始事件重放。
* @annotation ["static"]
* @param {const char*} filename 存放事件的文件名。
* @param {uint32_t} times 循环播放的次数。
*
* @return {ret_t} 返回 RET_OK 表示成功,否则表示失败。
*/
ret_t event_recorder_player_start_play(const char* filename, uint32_t times);
/**
* @method event_recorder_player_stop_record
* 停止事件记录。
* @annotation ["static"]
*
* @return {ret_t} 返回 RET_OK 表示成功,否则表示失败。
*/
ret_t event_recorder_player_stop_record(void);
/**
* @method event_recorder_player_stop_play
* 停止事件重放。
* @annotation ["static"]
*
* @return {ret_t} 返回 RET_OK 表示成功,否则表示失败。
*/
ret_t event_recorder_player_stop_play(void);
```
## 3. 用法
一般有两种方式启用输入事件记录与重放:
* 通过命令行参数启动记录或重放功能(目前没有提供示例)。
* 通过快捷键启动记录和重放功能。这种方法更为灵活,可以随时启用和停止,可以随时记录和播放。
> 要定义宏 WITH|_EVENT\_RECORDER\_PLAYER 才能启用事件记录与重放功能PC 版本缺省是定义了该宏的。
demoui 中演示了通过快捷键启动记录和重放功能:
```c
#include "base/event_recorder_player.h"
...
static ret_t on_key_record_play_events(void* ctx, event_t* e) {
key_event_t* evt = (key_event_t*)e;
#ifdef WITH_EVENT_RECORDER_PLAYER
if (evt->key == TK_KEY_F5) {
event_recorder_player_start_record("event_log.bin");
return RET_STOP;
} else if (evt->key == TK_KEY_F6) {
event_recorder_player_stop_record();
return RET_STOP;
} else if (evt->key == TK_KEY_F7) {
event_recorder_player_start_play("event_log.bin", 0xffff);
return RET_STOP;
} else if (evt->key == TK_KEY_F8) {
event_recorder_player_stop_play();
return RET_STOP;
}
#endif /*WITH_EVENT_RECORDER_PLAYER*/
return RET_OK;
}
...
widget_on(wm, EVT_KEY_UP, on_key_record_play_events, wm);
```
在以上代码中:
* F5 键开始记录。
* F6 键停止记录。
* F7 键开始播放。
* F8 键停止播放。
## 4. 已知问题
* 如果想重复播放记录的事件,确保记录事件时,回到初始界面后才停止记录。
* 目前平台原生输入法的输入事件没有记录。

View File

@ -0,0 +1,311 @@
# FAQ
#### 1.return\_value\_if\_fail 作为 AWTK 中使用率排第一的宏,它的功能、优点和注意事项都有哪些?
**功能**
* 主要用于对函数的参数或函数的返回值进行检查(这是防御性编程的手段之一)。
> return\_value\_if\_fail 这个宏并非是 AWTK 原创,而是从 GTK+(或者说 glib) 里拿来的。
**优点**
* 以简洁的方式对函数的参数或函数的返回值进行检查。
* Release 模式和 Debug 模式可以做不同的处理。
> 在参数出现错误时,悄无声息的返回一个错误码,其实是对调用者的纵容,很容易把错误隐藏起来。所以在 Debug 模式我们可以打出一条警告信息,甚至直接 assert 掉,这对于定位 BUG 非常有效。
**注意事项**
* 内部函数 (static) 一般不需要对参数进行检查。
* 只对异常的情况进行判断,对于正常的失败或无效参数,请不要使用本宏。
* 如果在返回之前,有资源需要释放,请不要用本宏。可以用 goto\_error\_if\_fail 跳到 error 出,释放资源后再返回。
---
#### 2. 每次在绘制图片前,都要调用 image\_manager\_load 去加载图片,这样做会不会很慢?有什么优点?
* 不会慢。因为 image\_manager 中有缓存,不会每次都去解码。
**优点**
* 缓存有助于多个控件共享同一张图片。
* 外面不保存对 bitmap 的引用,缓存管理更加灵活。比如,可以清除最近没有被渲染的图片(即使某个隐藏的窗口还在使用该图片)。
---
#### 3. 使用矢量字体,速度会慢吗?
* 几乎没有影响。因为有缓存,所以只需要渲染一次,之后和位图字体的并无不同。
---
#### 4. 在 16 位 LCD 上显示 PNG 图片效果很差,有什么办法吗?
* 如果是不透明的图片,可以将 PNG 转换成 JPG 文件,转换过程中启用 dithering 算法做平滑处理。
可以用 imagemagic 转换:
```
convert bg.png -ordered-dither o8x8,32,64,32 bg.jpg
```
> 参考http://www.imagemagick.org/Usage/quantize/
#### 5. 如何获取控件值?
获取控件的值有以下几种方式:
* 用 widget\_get\_value 函数获取(仅支持整数类型)。
* 用 wiget\_get\_prop 函数获取。
* 直接访问控件的属性。控件的属性如果标记为 readable均可直接访问。如
```
widget_t* slider = widget_lookup(win, "slider", TRUE);
double value = SLIDER(slider)->value;
```
> 直接访问控件属性时,需要用对应的宏(如上面的 SLIDER) 进行类型转换。
#### 6.Ubuntu 14 上无法启动,有什么办法吗?
Ubuntu 14 上的 OpenGL 有问题,请使用 AGGE 软件渲染。修改 awtk\_config.py
```
NANOVG_BACKEND='AGGE'
```
#### 7. 如何实现半透明效果
* 在 style 中,使用 rgba 格式可以指定半透明填充颜色。如:
```xml
<normal bg_color="rgba(200,200,200,0.1)" />
```
* 图片半透明。在制作图片时,使用 PNG 格式,保留 alpha 通道。
* 整个控件(包括子控件)半透明。可以使用函数 widget\_set\_opacity 设置不透明度。
```c
/**
* @method widget_set_opacity
* 设置控件的不透明度。
*
*>在嵌入式平台,半透明效果会使性能大幅下降,请谨慎使用。
*
* @param {widget_t*} widget 控件对象。
* @param {uint8_t} opacity 不透明度(取值 0-2550 表示完全透明255 表示完全不透明)。
*
* @return {ret_t} 返回 RET_OK 表示成功,否则表示失败。
*/
ret_t widget_set_opacity(widget_t* widget, uint8_t opacity);
```
> opacity 会影响包括字体在内的全部元素,通常只适用于实现淡入淡出的动态效果。
#### 8. 如何定制缺省软键盘界面?
软键盘可以根据自己的情况进行调整,可以修改 design/default/ui/kb_default.xml。
* 修改 active 的值可以改变初始页面。
```xml
<pages x="0" y="bottom" w="100%" h="-28" active="4">
```
* 修改 s 的值可以调正按钮之间的间距,嵌入式系统 s=1 就好了。
```xml
children_layout="default(r=4,c=1,s=2,m=2)"
```
* 修改 h 的值可以调整键盘的高度
```xml
<keyboard theme="keyboard" x="0" y="bottom" w="100%" h="40%">
```
* 中英文按钮切换的图片最好自己设计一个。
修改之后,需要更新资源的脚本:
```
python scripts/update_res.py ui
```
#### 9. 如何查看应用程序占用了多少内存?
tk\_mem\_stat 函数可以获取内存的使用情况,也可以直接调用 tk\_mem\_dump 显示内存使用情况。
tk\_mem\_dump 函数的实现如下:
```c
void tk_mem_dump(void) {
mem_stat_t s = tk_mem_stat();
log_debug("used: %d bytes %d blocks\n", s.used_bytes, s.used_block_nr);
}
```
#### 10. 如何确定是否是内存不够导致运行速度变慢?
内存不够时系统确实有可能变慢,内存不够时会清除部分或全部解码的图片缓存,下次使用这些图片时会重新解码。
可以在 mem.c 中的函数 tk\_mem\_on\_out\_of\_memory 里设置断点,内存耗尽时会调用这个函数释放缓存。如果这个函数被调用,说明内存不够。
#### 11. 如何降低内存开销?
* 减少同时打开窗口的个数。
* 根据实际情况 (lcd 的格式) 定义 WITH\_BITMAP_BGR565/WITH\_BITMAP\_RGB565 把不透明的图片解码成 16 位。
#### 12. 如何关闭 log_debug 打印的调试信息。
log\_set\_log\_level 函数可设置 log 的级别,用它可以关闭低级别的 log 信息。
```c
/**
* @method log_set_log_level
*
* 设置 log 的级别。
*
* @param {log_level_t} log_level log 的级别。
*
* @return {ret_t} 返回 RET_OK 表示成功,否则表示失败。
*/
ret_t log_set_log_level(log_level_t log_level);
```
在 awtk_main.inc 中有如下代码:
```c
#ifdef NDEBUG
log_set_log_level(LOG_LEVEL_INFO);
#else
log_set_log_level(LOG_LEVEL_DEBUG);
#endif /*NDEBUG*/
```
如果使用 awtk_main.inc 作为应用程序的入口,定义 NDEBUG 也关闭 debug 级别的调试信息。
#### 13. 应用程序在 Windows 的手持设备中运行,如何去掉窗口的标题栏?
在 awtk\_config.py 中定义宏 NATIVE\_WINDOW\_BORDERLESS重新编译即可
```python
COMMON_CCFLAGS=COMMON_CCFLAGS+' -DNATIVE_WINDOW_BORDERLESS=1 '
```
#### 14. 子控件处理了事件,不希望父控件继续处理,怎么处理呢?
让事件处理函数返回 RET\_STOPAWTK 不再调用后续事件处理函数。
#### 15. 如何去掉不需要的控件,以节省 flash 空间
因为控件注册了,即使没有使用,编译器也会把相关代码编译进去。所以只有去掉控件的注册代码,才能优化掉不必要的代码。
* 去掉不必要的基本控件,可以编辑 src/widgets/widgets.c
比如去掉 overlay 窗口,可以注释掉下面的这行代码:
```
widget_factory_register(f, WIDGET_TYPE_OVERLAY, overlay_create);
```
* 去掉不必要的扩展控件,可以编辑 src/ext_widgets/ext_widgets.c
* 从 assets/default/raw/styles/default.xml 中去掉不必要的。
* 去掉不必要的图片。一些控件去掉了,相应的图片也没有必要了。
#### 16. 内存不够,内部 flash 不够,如何加载大字体文件?
请参考:[自定义字体加载器:加载部分字体](https://github.com/zlgopen/awtk-custom-font-loader)
#### 17. 如何在打开新窗口时关闭当前窗口?
使用下面的函数即可:
```c
/**
* @method window_open_and_close
* @annotation ["constructor", "scriptable"]
* 从资源文件中加载并创建 window 对象。本函数在 ui_loader/ui_builder_default 里实现。
* @param {const char*} name window 的名称。
* @param {widget_t*} to_close 关闭该窗口。
*
* @return {widget_t*} 对象。
*/
widget_t* window_open_and_close(const char* name, widget_t* to_close);
```
#### 18. 如何设置当前的语言?
使用下面的函数即可:
```c
/**
* @method locale_info_change
* 设置当前的国家和语言。
* @annotation ["scriptable"]
* @param {locale_info_t*} locale_info locale_info 对象。
* @param {char*} language 语言。
* @param {char*} country 国家或地区。
*
* @return {ret_t} 返回 RET_OK 表示成功,否则表示失败。
*/
ret_t locale_info_change(locale_info_t* locale_info, const char* language, const char* country)
```
#### 19. 如何将板子键盘的键值映射到 AWTK
请参考:
* [Linux 系统](https://github.com/zlgopen/awtk-linux-fb/blob/master/awtk-port/input_thread.c)
* [嵌入式系统](https://github.com/zlgopen/awtk-stm32h743iitx-mvvm/blob/master/docs/stm32h743iitx_port.md) 的 11 节。
#### 20. 如何定制软键盘/候选字的风格?
请修改下面的文件,并重新生成资源:
```
design/default/styles/keyboard.xml
```
#### 21. 如何处理Cannot find module 'glob'
一般来说,执行下面的命令即可:
```
npm install -g glob
```
在 Linux/MacOS 上,有时仍然出现错误,可以通过下面的命令,设置 NODE_PATH 环境变量:
```
export NODE_PATH="$(npm root -g)"
```
#### 22. 如何处理 ImportError: No module named PIL
这个需要安装 Pillow 模块 (python),运行下面的命令可以安装:
```
pip3 install Pillow
```
如果系统同时安装了 python2可以加个 alias。
```
alias python=python3
```
#### 23. 如何让用户不可以调整 desktop 应用程序的窗口大小。
在 awtk\_config.py 中定义宏 NATIVE\_WINDOW\_NOT\_RESIZABLE重新编译即可
```python
COMMON_CCFLAGS=COMMON_CCFLAGS+' -DNATIVE_WINDOW_NOT_RESIZABLE=1 '
```

View File

@ -0,0 +1,65 @@
## FrameBuffer 的几种使用方式
### 一、单 framebuffer。
系统中只有一个 framebufferLCD 使用该 framebuffer 进行显示GUI 使用该 framebuffer 进行绘制。
![1](images/fb1.png)
#### 优点:
* 只有一个 framebuffer内存需求减半。
* 无需额外内存拷贝,而且只需画变化的部分,所以性能很高耗电低。
#### 缺点
* GUI 绘制的同时 LCD 在显示,这很容易出现屏幕闪烁。为了避免闪烁,可以在 GUI 绘制前禁用 LCD 同步数据(需等待 LCD 刷完后再禁用),等绘制完成时再启用 LCD 同步数据。我在 stm32f429igtx 上测试,发现确实不闪烁了,但是在窗口动画时,颜色有些不正常。不知是不是 LCD 频繁启用/禁用LCD 时钟来不及稳定导致的。
> 如果硬件能够解决动画颜色不正常的问题或者不需要动画,这种方式是最好的选择。
### 二、双 framebuffer一个 online 一个 offline轮流切换显示。
* 1.GUI 在 offline 的 framebuffer 上绘制。
* 2.LCD 显示 online 的 framebuffer。
* 3.GUI 绘制完成后,交换两个 framebufferonline 变 offlineoffline 变 online。
![2](images/fb2.png)
#### 优点:
* 无需内存拷贝,切换 LCD 的 framebuffer 地址即可。
#### 缺点
* GUI 每次都需要进行完整的绘制,不能只绘制变化的部分。
### 三、双 framebuffer一个固定 online 供 LCD 显示,一个固定 offline 供 GUI 绘制。
![3](images/fb3.png)
#### 优点:
* 只需绘制变化的部分,绘制完成后,把变化的部分从 offline 的 framebuffer 拷贝到 online 的 framebuffer 即可。
#### 缺点:
* 窗口动画时,可能整个屏幕都在变化,所以拷贝的量比较大。优化方法:对于平移的动画,可以让 GUI 直接往 online 的 framebuffer 上绘制,减少一次内存拷贝,而且不会出现闪烁。
### 四、三个 framebuffer一个 online 供 LCD 显示,一个 offline 供 GUI 绘制,一个为下一个要显示的 framebuffer。
![4](images/fb4.png)
第二种方式的双缓冲切换方法有一个重要的性能问题:因为并不是在任意时刻都可以切换切换缓冲区,而是只有在当前帧显示完成后才能切换,否则就会出现刚显示一部分就切换到下一帧的情况,这会导致闪烁。所以每次切换都需要等待显示完成,按每秒刷新 60 帧算,这需要等待 16ms 左右,如果绘制本身需要 16ms那帧率就只有 30FPS 了。如果使三个 framebuffer就不用等待切换完成了帧率一下可以到达 60FPS 了。
* 1.GUI 选取不是 online 和 next 的 framebuffer 作为 offline 的 framebuffer在 offline 的 framebuffer 上绘制。
* 2.GUI 绘制完成后,把 offline 设置为 next 作为即将显示的 framebuffer。
* 3.LCD 在显示完成中断里,将 next 设置为 online 的 framebuffer并将 next 设置为空闲。
#### 优点:
* 显示速度大幅提升。
#### 缺点:
* 多一些内存开销。
> 以上方式各有优缺点,请根据具体情况进行选择,建议使用最后两种方式。

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,60 @@
## app_conf 扩展函数
获取 app\_conf 对象后,可以直接用 [object](fscript_object.md) 的接口访问 app\_conf。
### 1. app_conf
> 获取 app_conf 对象
----------------------------
#### 原型
```
app_conf() => object
```
#### 示例
```
assert(object_set(app_conf(), "timeout", 100))
```
### 2. app_conf_save
> 保存修改。
----------------------------
#### 原型
```
app_conf_save() => bool
```
#### 示例
```
assert(app_conf_save())
```
### 完整示例
```js
assert(object_set(app_conf(), "timeout", 100))
assert(object_set(app_conf(), "serial.device", "/dev/tty01"))
assert(object_set(app_conf(), "serial.baudrate", 115200))
assert(app_conf_save())
assert(object_get(app_conf(), "timeout") == 100)
assert(object_get(app_conf(), "serial.device") == "/dev/tty01")
assert(object_get(app_conf(), "serial.baudrate") == 115200)
assert(object_remove(app_conf(), "timeout"))
assert(object_remove(app_conf(), "serial"))
assert(object_get(app_conf(), "timeout", 10) == 10)
assert(object_get(app_conf(), "serial.device", "a") == "a")
assert(object_get(app_conf(), "serial.baudrate", 1000) == 1000)
assert(object_set(app_conf(), "timeout", 100))
assert(app_conf_save())
```

View File

@ -0,0 +1,362 @@
## array 扩展函数
array 是一个通用的数组,里面可以放混合数据类型的数据。
array 有以下属性:
* size 元素的个数
* capacity 元素的最大个数
### 1.array\_create
> 创建 array 对象。
----------------------------
#### 原型
```js
array_create() => object
```
### 2.array\_create\_with\_str
> 创建 array 对象。以指定的分隔符把字符串拆开,并转换为指定类型的数据,放入数组中。
----------------------------
#### 原型
```js
array_create_with_str(str, sep, type) => object
```
type 为可选参数,可选取值为:
* int 表示整数。
* double 表示浮点数。
* 其它或默认为字符串。
示例:
```
a = array_create_with_str("2,1,3", ",", "int");
a = array_create_with_str("a2,a1,a3", ",");
```
### 3.array\_create\_repeated
> 创建 array 对象。
----------------------------
#### 原型
```js
array_create_repeated(value, nr) => object
```
* value 为初始化的值。
* nr 为值的个数。
示例:
```
a = array_create_repeated(123, 3);
```
### 4.array\_dup
> 创建 array 对象。
----------------------------
#### 原型
```js
array_dup(arr, start, end) => object
```
start 为开始的位置,默认为 0。
end 为结束的位置(不包含)
示例:
```
a = array_create_with_str("2,1,3", ",", "int");
b = array_dup(a);
c = array_dup(a, 1);
d = array_dup(a, 1, 2);
```
### 5.array\_push
> 追加一个或多个数据。
----------------------------
#### 原型
```js
array_push(array, v, ...) => uint32_t
```
> 返回写入数据的个数
### 6.array\_pop
> 弹出最后一个元素
----------------------------
#### 原型
```js
array_pop(array) => value
```
### 7.array\_shift
> 弹出第一个元素
----------------------------
#### 原型
```js
array_shift(array) => value
```
### 8.array\_get
> 获取指定位置的元素
----------------------------
#### 原型
```js
array_get(array, index) => value
```
> index 为负数时,从后往前取。比如-1 表示最后一个元素。
>
> 此外,也可以通过 array.[index] 的方式访问数组元素。
### 9.array\_set
> 修改指定位置的元素
----------------------------
#### 原型
```js
array_set(array, index, value) => bool
```
> index 为负数时,从后往前取。比如-1 表示最后一个元素。
### 10.array\_insert
> 插入元素到指定位置
----------------------------
#### 原型
```js
array_insert(array, index, value) => bool
```
> index 为负数时,从后往前取。比如-1 表示最后一个元素。
### 11.array\_index\_of
> 获取元素首次出现的位置。
----------------------------
#### 原型
```js
array_index_of(array, value) => index
```
### 12.array\_last_index\_of
> 获取元素最后出现的位置。
----------------------------
#### 原型
```js
array_last_index_of(array, value) => index
```
### 13.array\_remove
> 删除指定位置的元素
----------------------------
#### 原型
```js
array_remove(array, index) => bool
```
> index 为负数时,从后往前取。比如-1 表示最后一个元素。
### 14.array\_get\_and\_remove(
> 删除指定位置的元素,并返回改元素。
----------------------------
#### 原型
```js
array_get_and_remove(array, index) => value
```
> index 为负数时,从后往前取。比如-1 表示最后一个元素。
### 15.array\_clear
> 删除全部元素
----------------------------
#### 原型
```js
array_clear(array) => bool
```
### 16.array\_join
> 连接全部元素成一个字符串。
----------------------------
#### 原型
```js
array_join(array, sep) => str
```
### 17.array\_sort
> 根据当前的数据类型排序,以第一个元素类型为准。
----------------------------
#### 原型
```js
array_sort(array, ascending, ignore_case) => bool
```
* ascending 是否为升序,默认是。
* ignore_case 是否忽略大小写,仅用于字符串,默认为否。
示例:
```
a = array_create_with_str("2,1,3", ",", "int");
assert(array_sort(a));
d = array_join(a, ":");
assert(d == "1:2:3")
assert(array_sort(a, false));
d = array_join(a, ":");
assert(d == "3:2:1")
```
### 18.array\_min
> 获取最小值。
----------------------------
#### 原型
```js
array_min(array) => double
```
### 19.array\_max
> 获取最大值。
----------------------------
#### 原型
```js
array_max(array) => double
```
### 20.array\_avg
> 求平均值。
----------------------------
#### 原型
```js
array_avg(array) => double
```
### 21.array\_sum
> 求和。
----------------------------
#### 原型
```js
array_sum(array) => double
```
### 22.array\_clone\_and\_sort
> clone一份数据根据当前的数据类型排序以第一个元素类型为准。
----------------------------
#### 原型
```js
array_clone_and_sort(array, ascending, ignore_case) => array
```
* ascending 是否为升序,默认是。
* ignore_case 是否忽略大小写,仅用于字符串,默认为否。
示例:
```
a = array_create_with_str("2,1,3", ",", "int");
b = array_clone_and_sort(a));
d = array_join(b, ":");
assert(d == "1:2:3")
```
### 更多示例
```js
a = array_create()
assert(array_push(a,1,2,3) == 3)
assert(array_push(a,"a","b","c") == 3)
assert(array_pop(a), "c")
assert(array_pop(a), "b")
assert(array_pop(a), "a")
assert(array_pop(a), "3")
assert(array_pop(a), "2")
assert(array_pop(a), "1")
assert(value_is_valid(array_pop(a)))
assert(array_clear(a))
assert(a.size == 0)
assert(array_insert(a, 0, 'a'))
assert(array_insert(a, 1, 'b'))
assert(array_insert(a, 2, 'c'))
assert(array_insert(a, 3, 'd'))
assert(a.size == 4)
assert(array_remove(a, 0))
assert(array_get(a, 0) == 'b')
assert(array_set(a, 0, 'bbb'))
assert(array_get(a, 0) == 'bbb')
assert(array_set(a, 0, 'b'))
assert(array_get(a, 1) == 'c')
assert(array_set(a, 1, 'ccc'))
assert(array_get(a, 1) == 'ccc')
assert(array_set(a, 1, 'c'))
assert(array_join(a, ',') == 'b,c,d')
print(a.size, a.capacity)
```

View File

@ -0,0 +1,195 @@
## 位操作扩展函数
### 1. &
> 位与运算。
----------------------------
#### 原型
```
n1 & n2
```
#### 示例
```
print(1 & 1)
```
### 2. |
> 位或运算。
----------------------------
#### 原型
```
n1 | n2
```
### 示例
```
print(|(1, 2))
```
### 3.~
> 按位取反运算。
----------------------------
#### 原型
```
~(n1)
```
#### 示例
```
print(~1)
```
### 4.^
> 异或运算。
----------------------------
#### 原型
```
n1^n2
```
#### 示例
```
print(n1^n2)
```
### 5. <<
> 左移
----------------------------
#### 原型
```
n1<<n2
```
#### 示例
```
print(n1<<n2)
```
### 6. >>
> 右移
----------------------------
#### 原型
```
n1>>n2
```
#### 示例
```
print(n1>>n2)
```
### 7. bit_get
> 获取指定的位
----------------------------
#### 原型
```
bit_get(n1, n2) => bool
```
#### 示例
```
print(bit_get(0b1010, 1))
```
### 8. bit_set
> 设置指定的位
----------------------------
#### 原型
```
bit_set(n1, n2) => value
```
#### 示例
```
print(bit_set(0b1010, 0))
```
### 9. bit_clear
> 清除指定的位
----------------------------
#### 原型
```
bit_clear(n1, n2) => value
```
#### 示例
```
print(bit_clear(0b1010, 1))
```
### 10. bit_toggle
> 取反指定的位
----------------------------
#### 原型
```
bit_toggle(n1, n2) => value
```
#### 示例
```
print(bit_toggle(0b1010, 1))
```
### 更多示例
```js
assert(bit_clear(0b0111, 1) == 0b0101)
assert(bit_clear(0b0111, 0) == 0b0110)
assert(bit_set(0b0, 0) == 0b1)
assert(bit_set(0b0, 1) == 0b10)
assert(bit_set(0b0, 2) == 0b100)
assert(bit_toggle(0b000, 0) == 0b1)
assert(bit_toggle(0b111, 1) == 0b101)
assert(bit_toggle(0b101, 2) == 0b1)
assert(bit_get(0b0111, 0))
assert(bit_get(0b0111, 1))
assert(!bit_get(0b0011, 2))
assert((1<<1) == 2)
assert((1<<2) == 4)
assert((1<<8) == 256)
assert(((0xf0112233 >> 24) & 0xff) == 0xf0)
```

View File

@ -0,0 +1,87 @@
## CRC 函数
Cyclic redundancy check
### 1.crc16
> crc16 函数。
----------------------------
#### 原型
```
crc16(str) => uint16_t
crc16(data, size) => uint16_t
crc16(binary) => uint16_t
```
#### 示例
```
crc16("hello")
```
### 2.crc32
> crc32 函数。
----------------------------
#### 原型
```
crc32(str) => uint32_t
crc32(data, size) => uint32_t
crc32(binary) => uint32_t
```
#### 示例
```
crc32("hello")
```
### 3.cksum
> cksum 函数。
----------------------------
#### 原型
```
cksum(str) => uint16_t
cksum(data, size) => uint16_t
cksum(binary) => uint16_t
```
#### 示例
```
cksum("hello")
```
### 4. 更多示例
```js
//test string
assert(crc16("123") == 40116)
assert(crc32("123") == u32(2286445522))
assert(cksum("123") == u16(65385))
//test binary
a=typed_array_create("i8", 10)
assert(typed_array_push(a, 1,2,3) == 3)
print(crc16(a.data, a.size))
print(crc32(a.data, a.size))
print(cksum(a.data, a.size))
unset(a);
//test binary
assert(file_write("test.bin", "hello", 5))
assert(file_exist("test.bin"))
a = file_read_binary("test.bin")
assert(crc16(a) == 13501)
assert(crc32(a) == 907060870)
assert(cksum(a)==65003)
assert(file_remove("test.bin"))
unset(a)
```

View File

@ -0,0 +1,147 @@
## 日期时间扩展函数
### 1.date\_time\_create
> 创建日期对象。
----------------------------
#### 原型
```
date_time_create() => object
```
日期对象有下列属性:
* year 年 (读写)
* month 月 (读写)
* day 日 (读写)
* hour 时 (读写)
* minute 分 (读写)
* second 秒 (读写)
* wday 周几 (只读)
### 2.date\_time\_to\_time
> 转成相对于 00:00:00 UTC on 1 January 1970 的秒数。
----------------------------
#### 原型
```
date_time_to_time(dt) => uint64_t
```
### 3.date\_time\_from\_time
> 将相对于 00:00:00 UTC on 1 January 1970 的秒数转成成 date time。
----------------------------
#### 原型
```
date_time_from_time(dt, time) => bool
```
### 4.date\_time\_set
> 把 date time 中的时间设置为系统时间。
----------------------------
#### 原型
```
date_time_set(dt) => bool
```
> 需要有设置系统时间的权限。
### 5.time_now
> 获取当前时间戳函数 (s)。
----------------------------
#### 原型
```
time_now() => uint64_t
```
### 6.time\_now\_ms
> 获取当前时间戳函数 (ms)。
----------------------------
#### 原型
```
time_now_ms() => uint64_t
```
### 7.time_now_us
> 获取当前时间戳函数 (us)。
----------------------------
#### 原型
```
time_now_us() => uint64_t
```
### 8.is\_leap\_year
> 判断指定年份是否是闰年。
----------------------------
#### 原型
```
is_leap_year(year) => bool
```
### 9.get\_days\_of\_month
> 获取指定年月的天数。
----------------------------
#### 原型
```
get_days_of_month(year, month) => uint32_t
```
### 更多示例
```js
dt = date_time_create()
print(dt.year, "-", dt.month, "-", dt.day, " ", dt.hour, ":", dt.minute, ":", dt.second, "(", dt.wday, ")")
dt.year = 2022
dt.month = 10
dt.day = 1
dt.hour = 2
dt.minute = 3
dt.second = 4
assert(dt.year == 2022)
assert(dt.month == 10)
assert(dt.day == 1)
assert(dt.hour == 2)
assert(dt.minute == 3)
assert(dt.second == 4)
print(dt.year, "-", dt.month, "-", dt.day, " ", dt.hour, ":", dt.minute, ":", dt.second, "(", dt.wday, ")")
assert(date_time_to_time(dt) == 1664560984)
assert(date_time_from_time(dt, 1664560985))
assert(dt.year == 2022)
assert(dt.month == 10)
assert(dt.day == 1)
assert(dt.hour == 2)
assert(dt.minute == 3)
assert(dt.second == 5)
print(time_now_us())
print(time_now_ms())
print(time_now_s())
```

View File

@ -0,0 +1,109 @@
## 大端小端扩展函数
### 1.is\_little
> 判断当前 CPU 是否是小端。
----------------------------
#### 原型
```js
is_little() => bool
```
### 2.htonl
> 将类型为 uint32_t 的整数,从主机字节顺序转成网络字节顺序。
----------------------------
#### 原型
```js
htonl(uint32_t) => uint32_t
```
### 3.ntohl
> 将类型为 uint32_t 的整数,从网络字节顺序转成主机字节顺序。
----------------------------
#### 原型
```js
ntohl(uint32_t) => uint32_t
```
### 4.htons
> 将类型为 uint16_t 的整数,从主机字节顺序转成网络字节顺序。
----------------------------
#### 原型
```js
htons(uint16_t) => uint16_t
```
### 5.ntohs
> 将类型为 uint16_t 的整数,从网络字节顺序转成主机字节顺序。
----------------------------
#### 原型
```js
ntohs(uint16_t) => uint16_t
```
### 6.htonf
> 将类型为单精度的浮点数,从主机字节顺序转成网络字节顺序。
----------------------------
#### 原型
```js
htonf(float) => float
```
### 7.ntohf
> 将类型为单精度的浮点数,从网络字节顺序转成主机字节顺序。
----------------------------
#### 原型
```js
ntohf(float) => float
```
### 8.htonll
> 将类型为 uint64_t 的整数,从主机字节顺序转成网络字节顺序。
----------------------------
#### 原型
```js
htonl(uint64_t) => uint64_t
```
### 9.ntohll
> 将类型为 uint64_t 的整数,从网络字节顺序转成主机字节顺序。
----------------------------
#### 原型
```js
ntohll(uint64_t) => uint64_t
```
### 更多示例
```js
assert(is_little())
assert(htonl(0x11223344) == 0x44332211)
assert(ntohl(0x11223344) == 0x44332211)
assert(htons(0x1122) == 0x2211)
assert(ntohs(0x1122) == 0x2211)
assert(htonll(0x1122334455667788)==0x8877665544332211)
assert(ntohll(0x1122334455667788)==0x8877665544332211)
```

View File

@ -0,0 +1,349 @@
## 文件系统扩展函数
### 1.file\_read\_text
> 读取文本文件。
----------------------------
#### 原型
```
file_read_text(filename) => str
```
### 2.file\_read\_binary
> 读取二进制文件。
----------------------------
#### 原型
```
file_read_binary(filename) => binary
```
### 3.file\_write
> 写入文件。
----------------------------
#### 原型
```
file_write(filename, str) => bool
file_write(filename, binary) => bool
file_write(filename, data, size) => bool
```
### 4.file\_write\_append
> 写入文件尾部(追加内容)。
----------------------------
#### 原型
```
file_write_append(filename, str) => bool
file_write_append(filename, binary) => bool
file_write_append(filename, data, size) => bool
```
### 5.file\_exist
> 检查文件是否存在。
----------------------------
#### 原型
```
file_exist(filename) => bool
```
### 6.file\_get\_size
> 获取文件大小。
----------------------------
#### 原型
```
file_get_size(filename) => int32_t
```
### 7.file\_remove
> 删除指定的文件。
----------------------------
#### 原型
```
file_remove(filename) => bool
```
### 8.file\_rename
> 文件重命名。
----------------------------
#### 原型
```
file_rename(filename, new_name) => bool
```
### 9.file\_copy
> 文件拷贝。
----------------------------
#### 原型
```
file_copy(filename, dst_name) => bool
```
### 10.file\_stat
> 获取文件信息。
----------------------------
#### 原型
```
file_stat(filename) => object
```
返回的文件信息对象包含以下属性:
| 属性名称 | 属性类型 | 说明 |
| ----------- | -------- | ---------------------- |
| dev | uint32_t | 文件系统设备 |
| ino | uint16_t | 文件序列号 |
| mode | uint16_t | 文件类型和权限信息 |
| nlink | int16_t | 文件的符号链接数量 |
| uid | int16_t | 用户id |
| gid | int16_t | 组id |
| rdev | uint32_t | 设备id |
| size | uint64_t | 文件大小(单位:字节) |
| atime | uint64_t | 最后访问时间 |
| mtime | uint64_t | 最后修改时间 |
| ctime | uint64_t | 创建时间 |
| is_dir | bool_t | 是否为目录 |
| is_link | bool_t | 是否为链接 |
| is_reg_file | bool_t | 是否为普通文件 |
### 11.path\_create
> 创建目录(递归创建不存在的父目录)。
----------------------------
#### 原型
```
path_create(path) => bool
```
### 12.path\_remove
> 删除目录(递归创建子目录和文件)。
----------------------------
#### 原型
```
path_remove(path) => bool
```
### 13.path\_exist
> 检查指定的目录是否存在。
----------------------------
#### 原型
```
path_exist(path) => bool
```
### 14.path\_rename
> 目录重命名。
----------------------------
#### 原型
```
path_rename(path, new_path) => bool
```
### 15.path\_list
> 获取指定目录下的子目录/文件列表。
----------------------------
#### 原型
```
path_list(path) => array
```
返回的列表数组中每个元素都是一个 object 对象,每个 object 对象中包含以下属性:
| 属性名称 | 属性类型 | 说明 |
| ----------- | -------- | -------------- |
| is_dir | bool_t | 是否是目录 |
| is_link | bool_t | 是否是符号链接 |
| is_reg_file | bool_t | 是否是普通文件 |
| name | str | 文件名称 |
### 16.path\_get\_exe
> 获取可执行文件所在目录。
----------------------------
#### 原型
```
path_get_exe() => str
```
### 17.path\_get\_cwd
> 获取当前所在目录。
----------------------------
#### 原型
```
path_get_cwd() => str
```
### 18.path\_get\_temp
> 获取临时目录的路径。
----------------------------
#### 原型
```
path_get_temp() => str
```
### 19.path\_get\_app\_root
> 获取应用程序根目录的路径。
----------------------------
#### 原型
```
path_get_app_root() => str
```
### 20.path\_get\_user\_storage\_root
> 获取用户目录或用户可以存储数据的目录的路径。
----------------------------
#### 原型
```
path_get_user_storage_root() => str
```
### 21.fs\_get\_disk\_info
> 获取文件系统信息。
----------------------------
#### 原型
```
fs_get_disk_info(path) => object
```
返回的文件系统信息对象包含以下属性:
| 属性名称 | 属性类型 | 说明 |
| ----------- | -------- | ---------------- |
| free_kb | int32_t | 空闲空间大小(KB) |
| total_kb | int32_t | 总共空间大小(KB) |
> 备注:该功能需适配 AWTK 通用文件系统fs.h中的 fs_get_disk_info 接口,目前 PC 上暂不支持。
### 更多示例
```js
assert(file_write("test.txt", "hello"))
assert(file_exist("test.txt"))
assert(file_get_size("test.txt")==5)
assert(file_read_text("test.txt") == "hello")
assert(file_write_append("test.txt","world"))
assert(file_read_text("test.txt") == "helloworld")
assert(file_rename("test.txt","rename.txt"))
assert(!file_exist("test.txt"))
assert(file_read_text("rename.txt") == "helloworld")
assert(file_copy("rename.txt","copy.txt"))
assert(file_read_text("copy.txt") == "helloworld")
assert(file_remove("copy.txt"))
assert(!file_exist("copy.txt"))
a = file_stat("rename.txt")
print(join(": ","dev",a.dev))
print(join(": ","ino",a.ino))
print(join(": ","mode",a.mode))
print(join(": ","nlink",a.nlink))
print(join(": ","uid",a.uid))
print(join(": ","rdev",a.rdev))
print(join(": ","size",a.size))
print(join(": ","atime",a.atime))
print(join(": ","mtime",a.mtime))
print(join(": ","ctime",a.ctime))
print(join(": ","is_dir",a.is_dir))
print(join(": ","is_link",a.is_link))
print(join(": ","is_reg_file",a.is_reg_file))
assert(file_remove("rename.txt"))
assert(!file_exist("rename.txt"))
assert(file_write("test.bin", "hello", 5))
assert(file_exist("test.bin"))
assert(file_get_size("test.bin")==5)
a = file_read_binary("test.bin")
assert(value_get_binary_size(a) == 5)
assert(file_remove("test.bin"))
assert(!file_exist("test.bin"))
assert(file_write("test.bin", a))
assert(file_exist("test.bin"))
assert(file_get_size("test.bin")==5)
assert(file_remove("test.bin"))
assert(path_create("a/b/c"))
assert(path_exist("a/b/c"))
assert(path_remove("a/b/c"))
assert(!path_exist("a/b/c"))
assert(path_rename("a/b","a/bbb"))
assert(!path_exist("a/b"))
assert(path_exist("a/bbb"))
assert(file_write("a/test.txt", "hello"))
a = path_list("a")
assert(a.size==2)
b = array_get(a,0)
c = array_get(a,1)
assert(b.name=="bbb")
assert(c.name=="test.txt")
assert(path_remove("a"))
assert(!path_exist("a"))
print(path_get_exe())
print(path_get_cwd())
print(path_get_temp())
print(path_get_app_root())
print(path_get_user_storage_root())
unset(a)
unset(b)
unset(c)
```

View File

@ -0,0 +1,45 @@
## iostream 扩展函数
### 1.iostream\_get\_istream
> 获取输入流对象。
----------------------------
#### 原型
```
iostream_get_istream(iostream) => object
```
### 2.iostream\_get\_ostream
> 获取输出流对象。
----------------------------
#### 原型
```
iostream _get_ostream(iostream) => object
```
### 更多示例
```js
//
// start serial echo server first
// ./bin/serial_recv 4000
//
a = iostream_serial_create("/dev/ttys001", 0)
b = iostream_get_ostream(a)
c = iostream_get_istream(a)
assert(ostream_write_uint32(b, 6) == 4)
assert(ostream_write_string(b, "hello\n") == 6)
assert(istream_read_uint32(c, 3000) == 6)
assert(istream_read_string(c, 6, 3000) == "hello\n")
unset(c)
unset(b)
unset(a)
```

View File

@ -0,0 +1,87 @@
## 文件流扩展函数
### 1.istream\_file\_create
> 创建文件输入流对象。
----------------------------
#### 原型
```js
istream_file_create(filename, mode) => object
```
### 2.ostream\_file\_create
> 创建文件输出流对象。
----------------------------
#### 原型
```js
ostream_file_create(filename, mode) => object
```
### 完整示例
```js
a = ostream_file_create("test.bin", "wb+")
assert(ostream_write_uint8(a, 1) == 1)
assert(ostream_write_int8(a, -1) == 1)
assert(ostream_tell(a), 2)
assert(ostream_write_uint16(a, 2) == 2)
assert(ostream_write_int16(a, -2) == 2)
assert(ostream_tell(a), 6)
assert(ostream_write_uint32(a, 3) == 4)
assert(ostream_write_int32(a, -3) == 4)
assert(ostream_tell(a), 14)
assert(ostream_write_uint64(a, 4) == 8)
assert(ostream_write_int64(a, -4) == 8)
assert(ostream_tell(a), 30)
assert(ostream_write_float(a, 5) == 4)
assert(ostream_write_double(a, -5) == 8)
assert(ostream_tell(a), 42)
assert(ostream_write_string(a, "hello") == 5)
assert(ostream_write_binary(a, "world", 5) == 5)
assert(ostream_tell(a), 52)
assert(ostream_flush(a))
a = istream_file_create("test.bin", "rb")
assert(istream_read_uint8(a)==1)
assert(istream_read_int8(a)==-1)
assert(istream_tell(a), 2)
assert(istream_read_uint16(a)==2)
assert(istream_read_int16(a)==-2)
assert(istream_tell(a), 6)
assert(istream_read_uint32(a)==3)
assert(istream_read_int32(a)==-3)
assert(istream_tell(a), 14)
assert(istream_read_uint64(a)==4)
assert(istream_read_int64(a)==-4)
assert(istream_tell(a), 30)
assert(istream_read_float(a)==5)
assert(istream_read_double(a)==-5)
assert(istream_tell(a), 42)
assert(istream_read_string(a, 5)=="hello")
assert(istream_tell(a), 47)
istream_read_binary(a, 5)
assert(istream_tell(a), 52)
assert(istream_seek(a, 0))
assert(istream_read_uint8(a)==1)
assert(istream_read_int8(a)==-1)
assert(istream_tell(a) == 2)
unset(a)
```

View File

@ -0,0 +1,87 @@
## TCP/UDP 客户端扩展函数
### 1.iostream\_tcp\_create
> 创建 TCP 客户端输入输出流对象。
----------------------------
#### 原型
```js
iostream_tcp_create(host, port) => object
```
### 2.iostream\_udp\_create
> 创建 UDP 客户端输入输出流对象。
----------------------------
#### 原型
```js
iostream_udp_create(host, port) => object
```
### 完整示例
```js
//
//start tcp echo server first
//socat -v tcp-l:1234,fork exec:'/bin/cat'
//
a = iostream_tcp_create("localhost", 1234)
b = iostream_get_ostream(a)
c = iostream_get_istream(a)
assert(ostream_write_uint8(b, 1) == 1)
assert(ostream_write_uint16(b, 2)== 2)
assert(ostream_write_uint32(b, 3) == 4)
assert(ostream_write_uint64(b, 4) == 8)
assert(ostream_write_float(b, 5) == 4)
assert(ostream_write_double(b, 6) == 8)
assert(ostream_write_string(b, "hello\n") == 6)
assert(istream_read_uint8(c) == 1)
assert(istream_read_uint16(c) == 2)
assert(istream_read_uint32(c) == 3)
assert(istream_read_uint64(c) == 4)
assert(istream_read_float(c) == 5)
assert(istream_read_double(c) == 6)
assert(istream_read_string(c, 6) == "hello\n")
unset(c)
unset(b)
unset(a)
```
```js
//
// start udp echo server first
// ./bin/udp_recv 4000
//
a = iostream_udp_create("localhost", 4000)
b = iostream_get_ostream(a)
c = iostream_get_istream(a)
assert(ostream_write_uint8(b, 1) == 1)
assert(ostream_write_uint16(b, 2)== 2)
assert(ostream_write_uint32(b, 3) == 4)
assert(ostream_write_uint64(b, 4) == 8)
assert(ostream_write_float(b, 5) == 4)
assert(ostream_write_double(b, 6) == 8)
assert(ostream_write_string(b, "hello\n") == 6)
assert(istream_read_uint8(c) == 1)
assert(istream_read_uint16(c) == 2)
assert(istream_read_uint32(c) == 3)
assert(istream_read_uint64(c) == 4)
assert(istream_read_float(c) == 5)
assert(istream_read_double(c) == 6)
assert(istream_read_string(c, 6) == "hello\n")
unset(c)
unset(b)
unset(a)
```

View File

@ -0,0 +1,35 @@
## 串口扩展函数
### 1.iostream\_serial\_create
> 创建串口输入输出流对象。
----------------------------
#### 原型
```js
istream_file_create(device, baudrate) => object
```
### 完整示例
```js
//
// start serial echo server first
// ./bin/serial_recv 4000
//
a = iostream_serial_create("/dev/ttys001", 0)
b = iostream_get_ostream(a)
c = iostream_get_istream(a)
assert(ostream_write_uint32(b, 6) == 4)
assert(ostream_write_string(b, "hello\n") == 6)
assert(istream_read_uint32(c, 3000) == 6)
assert(istream_read_string(c, 6, 3000) == "hello\n")
unset(c)
unset(b)
unset(a)
```

View File

@ -0,0 +1,218 @@
## istream 扩展函数
### 1.istream\_seek
> 定位到指定的偏移量。
----------------------------
#### 原型
```js
istream_seek(istream, offset) => bool
```
> 仅当输入流支持 seek 才能调用本函数。
### 2.istream\_tell
> 获取当前的偏移量。
----------------------------
#### 原型
```js
istream_tell(istream) => uint32_t
```
> 仅当输入流支持 tell 才能调用本函数。
### 3.istream\_read\_uint8
> 读取 uint8_t 类型的数据。
----------------------------
#### 原型
```js
istream_read_uint8(istream) => uint8_t
```
### 4.istream\_read\_uint16
> 读取 uint16_t 类型的数据。
----------------------------
#### 原型
```js
istream_read_uint16(istream) => uint16_t
```
### 5.istream\_read\_uint32
> 读取 uint32_t 类型的数据。
----------------------------
#### 原型
```js
istream_read_uint32(istream) => uint32_t
```
### 6.istream\_read\_uint64
> 读取 uint64_t 类型的数据。
----------------------------
#### 原型
```js
istream_read_uint64(istream) => uint64_t
```
### 7.istream\_read\_int8
> 读取 int8_t 类型的数据。
----------------------------
#### 原型
```js
istream_read_int8(istream) => int8_t
```
### 8.istream\_read\_int16
> 读取 int16_t 类型的数据。
----------------------------
#### 原型
```js
istream_read_int16(istream) => int16_t
```
### 9.istream\_read\_int32
> 读取 int32_t 类型的数据。
----------------------------
#### 原型
```js
istream_read_int32(istream) => int32_t
```
### 10.istream\_read\_int64
> 读取 int64_t 类型的数据。
----------------------------
#### 原型
```js
istream_read_int64(istream) => int64_t
```
### 11.istream\_read\_float
> 读取 float 类型的数据。
----------------------------
#### 原型
```js
istream_read_float(istream) => float
```
### 12.istream\_read\_double
> 读取 double 类型的数据。
----------------------------
#### 原型
```js
istream_read_double(istream) => double
```
### 13.istream\_read\_string
> 读取指定长度的字符串。
----------------------------
#### 原型
```js
istream_read_string(istream, size) => str
```
### 14.istream\_read\_binary
> 读取指定长度的二进制数据。
----------------------------
#### 原型
```js
istream_read_binary(istream, size) => binary
```
### 15.istream\_read\_line
> 读取一行的字符串。
----------------------------
#### 原型
```js
istream_read_line(istream, size) => str
```
### 16.istream\_is\_eos
> 判读数据是否读完。
----------------------------
#### 原型
```js
istream_is_eos(istream) => bool
```
### 更多示例
```js
a = istream_file_create("test.bin", "rb")
assert(istream_read_uint8(a)==1)
assert(istream_read_int8(a)==-1)
assert(istream_tell(a), 2)
assert(istream_read_uint16(a)==2)
assert(istream_read_int16(a)==-2)
assert(istream_tell(a), 6)
assert(istream_read_uint32(a)==3)
assert(istream_read_int32(a)==-3)
assert(istream_tell(a), 14)
assert(istream_read_uint64(a)==4)
assert(istream_read_int64(a)==-4)
assert(istream_tell(a), 30)
assert(istream_read_float(a)==5)
assert(istream_read_double(a)==-5)
assert(istream_tell(a), 42)
assert(istream_read_string(a, 5)=="hello")
assert(istream_tell(a), 47)
istream_read_binary(a, 5)
assert(istream_tell(a), 52)
assert(istream_seek(a, 0))
assert(istream_read_uint8(a)==1)
assert(istream_read_int8(a)==-1)
assert(istream_tell(a) == 2)
unset(a)
```

View File

@ -0,0 +1,100 @@
## JSON 扩展函数
### 1.json\_load
> 加载 json 数据。
----------------------------
#### 原型
```js
json_load(str) => object
json_load(binary) => object
json_load(data, size) => object
```
### 2.json\_save
> 将对象保存为 json 数据。
----------------------------
#### 原型
```js
json_save(obj) => binary
```
### 3.json\_save\_to\_string
> 将对象保存为字符串数据。
----------------------------
#### 原型
```js
json_save_to_string(obj) => string
```
### 4.ubjson\_load
> 加载 ubjson 数据。
----------------------------
#### 原型
```js
ubjson_load(binary) => object
ubjson_load(data, size) => object
```
### 5.ubjson\_save
> 将对象保存为 ubjson 数据。
----------------------------
#### 原型
```js
ubjson_save(obj) => binary
```
### 完整示例
```js
//load from string
str='{
"name" : "fscript",
"age" : 100
}'
a=json_load(str)
assert(object_get(a, "name")=="fscript");
assert(object_get(a, "age")==100);
//save to file
b=json_save(a)
assert(file_write("test.json", b))
//json obj to string
c=json_save_to_string(a)
assert(c==str);
//load from file as text
a = json_load(file_read_text("test.json"))
assert(object_get(a, "name")=="fscript");
assert(object_get(a, "age")==100);
//load from file as binary
a = json_load(file_read_binary("test.json"))
assert(file_remove("test.json"))
assert(object_get(a, "name")=="fscript");
assert(object_get(a, "age")==100);
assert(file_remove("test.json"))
unset(a)
unset(b)
unset(c)
unset(str)
```

View File

@ -0,0 +1,222 @@
### 扩展数学函数
#### 1.sin
> sin 函数。
----------------------------
##### 原型
```
sin(a) => double
```
##### 示例
```
sin(0)
```
#### 2.cos
> cos 函数。
----------------------------
##### 原型
```
cos(a) => double
```
##### 示例
```
cos(0)
```
#### 3.tan
> tan 函数。
----------------------------
##### 原型
```
tan(a) => double
```
##### 示例
```
tan(1)
```
#### 4.asin
> asin 函数。
----------------------------
##### 原型
```
asin(a) => double
```
##### 示例
```
asin(1)
```
#### 5.acos
> acos 函数。
----------------------------
##### 原型
```
acos(a) => double
```
##### 示例
```
acos(1)
```
#### 6.atan
> atan 函数。
----------------------------
##### 原型
```
atan(a) => double
```
##### 示例
```
atan(1)
```
#### 7.pow
> pow 函数。
----------------------------
##### 原型
```
pow(a, b) => double
```
##### 示例
```
pow(2, 3)
```
#### 8.atan2
> atan2 函数。
----------------------------
##### 原型
```
atan2(a, b) => double
```
##### 示例
```
atan2(2, 3)
```
#### 9.log
> log 函数。
----------------------------
##### 原型
```
log(a) => double
```
##### 示例
```
log(0)
```
#### 10.is_prime
> 判断一个整数是否是质数。
----------------------------
##### 原型
```
is_prime(a) => bool
```
##### 示例
```
is_prime(7)
```
#### 11.exp
> exp 函数
----------------------------
##### 原型
```
exp(a) => double
```
##### 示例
```
exp(7)
```
#### 12.d2r
> 将角度转换成幅度。
----------------------------
##### 原型
```
d2r(a) => double
```
##### 示例
```
d2r(7)
```
#### 13.r2d
> 将幅度转换成角度。
----------------------------
##### 原型
```
r2d(a) => double
```
##### 示例
```
r2d(7)
```

View File

@ -0,0 +1,174 @@
## object 扩展函数
object 适用于 app\_conf、typed\_array 和 array 等各种对象。
### 1. object\_create
> 创建缺省的 object 对象,可以当一个 map 使用。
----------------------------
#### 原型
```
object_create() => object
```
#### 示例
```
a = object_create()
```
### 2. object\_get
> 获取对象的属性。
可以通过 value\_is\_valid 来判断返回值是否有效。
----------------------------
#### 原型
```
object_get(o, key) => value
object_get(o, key, defval) => value
```
也可以直接访问对象的属性:
```
print(o.key)
```
#### 示例
```
print(object_get(a, "age"))
print(a.age)
```
### 3. object\_set
> 设置对象的属性。
----------------------------
#### 原型
```
object_set(obj, key, value) => bool
```
#### 示例
```
object_set(a, "age", 123);
```
### 4. object\_remove
> 删除对象的属性。
----------------------------
#### 原型
```
object_remove(obj, key) => bool
```
#### 示例
```
object_remove(a, "age")
```
### 5. object\_ref
> 引用计数加1。
----------------------------
#### 原型
```
object_ref(obj) => object
```
#### 示例
```
object_ref(a)
```
### 5. object\_unref
> 引用计数减1。引用计数为0时销毁对象。
----------------------------
#### 原型
```
object_unref(obj)
```
#### 示例
```
object_ref(a)
```
### 6. object\_forward\_events
> 将源对象的事件转发目标对象。
----------------------------
目前支持以下事件的转发:
* EVT_PROP_CHANGED对象中的属性改变事件。
* EVT_PROPS_CHANGED对象中的属性改变事件。
* EVT_ITEMS_CHANGED集合对象中的项目改变事件
#### 原型
```
object_forward_events(src_obj, dst_obj)
```
#### 示例
```
global = object_create()
global.arr = array_create()
object_forward_events(global.arr, global)
```
### 完整示例
```js
a = object_create()
assert(!value_is_null(a))
assert(object_set(a, "age", 123))
assert(a.age == 123)
assert(object_set(a, "name", "awtk"))
assert(a.name == "awtk")
assert(object_get(a, "age") == 123)
print(object_get(a, "age"))
assert(object_remove(a, "age"))
assert(!value_is_valid(object_get(a, "age")))
unset(a)
person = object_create()
assert(!value_is_null(person))
assert(object_set(person, "age", 123))
assert(person.age == 123)
assert(object_set(person, "name", "awtk"))
assert(person.name == "awtk")
global = object_create()
global.arr = array_create()
object_forward_events(global.arr, global)
unset(person)
unset(global)
```

View File

@ -0,0 +1,219 @@
## ostream 扩展函数
### 1.ostream\_seek
> 定位到指定的偏移量。
----------------------------
#### 原型
```js
ostream_seek(ostream, offset) => bool
```
### 2.ostream\_tell
> 获取当前的偏移量。
----------------------------
#### 原型
```js
ostream_tell(ostream) => bool
```
> 仅当输入流支持 tell 才能调用本函数。
### 3.ostream\_flush
> 刷新缓冲区。
----------------------------
#### 原型
```js
ostream_flush(ostream) => bool
```
### 4.ostream\_write\_uint8
> 写入 uint8_t 类型的数据。
----------------------------
#### 原型
```js
ostream_write_uint8(ostream, v, ...) => int32_t
```
> 返回写入数据的长度(字节数)。
### 5.ostream\_write\_uint16
> 写入 uint16_t 类型的数据。
----------------------------
#### 原型
```js
ostream_write_uint16(ostream, v, ...) => int32_t
```
> 返回写入数据的长度(字节数)。
### 6.ostream\_write\_uint32
> 写入 uint32_t 类型的数据。
----------------------------
#### 原型
```js
ostream_write_uint32(ostream, v, ...) => int32_t
```
> 返回写入数据的长度(字节数)。
### 7.ostream\_write\_uint64
> 写入 uint64_t 类型的数据。
----------------------------
#### 原型
```js
ostream_write_uint64(ostream, v, ...) => int32_t
```
> 返回写入数据的长度(字节数)。
### 8.ostream\_write\_int8
> 写入 int8_t 类型的数据。
----------------------------
#### 原型
```js
ostream_write_int8(ostream, v, ...) => int32_t
```
> 返回写入数据的长度(字节数)。
### 9.ostream\_write\_int16
> 写入 int16_t 类型的数据。
----------------------------
#### 原型
```js
ostream_write_int16(ostream, v, ...) => int32_t
```
> 返回写入数据的长度(字节数)。
### 10.ostream\_write\_int32
> 写入 int32_t 类型的数据。
----------------------------
#### 原型
```js
ostream_write_int32(ostream, v, ...) => int32_t
```
> 返回写入数据的长度(字节数)。
### 11.ostream\_write\_int64
> 写入 int64_t 类型的数据。
----------------------------
#### 原型
```js
ostream_write_int64(ostream, v, ...) => int32_t
```
> 返回写入数据的长度(字节数)。
### 12.ostream\_write\_float
> 写入 float 类型的数据。
----------------------------
#### 原型
```js
ostream_write_float(ostream, v, ...) => int32_t
```
> 返回写入数据的长度(字节数)。
### 13.ostream\_write\_double
> 写入 double 类型的数据。
----------------------------
#### 原型
```js
ostream_write_double(ostream, v, ...) => int32_t
```
> 返回写入数据的长度(字节数)。
### 14.ostream\_write\_string
> 写入 字符串 类型的数据。
----------------------------
#### 原型
```js
ostream_write_string(ostream, v, [size]) => int32_t
```
> size为长度(可选),超过字符串长度时取字符串的长度。
> 返回写入数据的长度(字节数)。
### 15.ostream\_write\_binary
> 写入 二进制 类型的数据。
----------------------------
#### 原型
```js
ostream_write_binary(ostream, v, [size]) => int32_t
```
> size为长度在v是binary时可选为POINTER时则是必选。
> 返回写入数据的长度(字节数)。
### 更多示例
```js
a = ostream_file_create("test.bin", "wb+")
assert(ostream_write_uint8(a, 1) == 1)
assert(ostream_write_int8(a, -1) == 1)
assert(ostream_tell(a), 2)
assert(ostream_write_uint16(a, 2) == 2)
assert(ostream_write_int16(a, -2) == 2)
assert(ostream_tell(a), 6)
assert(ostream_write_uint32(a, 3) == 4)
assert(ostream_write_int32(a, -3) == 4)
assert(ostream_tell(a), 14)
assert(ostream_write_uint64(a, 4) == 8)
assert(ostream_write_int64(a, -4) == 8)
assert(ostream_tell(a), 30)
assert(ostream_write_float(a, 5) == 4)
assert(ostream_write_double(a, -5) == 8)
assert(ostream_tell(a), 42)
assert(ostream_write_string(a, "hello") == 5)
assert(ostream_write_binary(a, "world", 5) == 5)
assert(ostream_tell(a), 52)
assert(ostream_flush(a))
```

View File

@ -0,0 +1,241 @@
## 读缓冲区扩展函数
rbuffer 有以下属性:
* data 缓冲区的指针
* cursor 当前读的位置
* capacity 最大容量
### 1.rbuffer\_create
> 创建 rbuffer 对象。
----------------------------
#### 原型
```js
rbuffer_create(str) => object
rbuffer_create(binary) => object
rbuffer_create(data, size) => object
```
### 2.rbuffer\_skip
> 跳过指定长度的数据。
----------------------------
#### 原型
```js
rbuffer_skip(rbuffer, size) => bool
```
### 3.rbuffer\_rewind
> 重置读取指针到 0。
----------------------------
#### 原型
```js
rbuffer_rewind(rbuffer) => bool
```
### 4.rbuffer\_read\_uint8
> 读取 uint8_t 类型的数据。
----------------------------
#### 原型
```js
rbuffer_read_uint8(rbuffer) => uint8_t
```
### 5.rbuffer\_read\_uint16
> 读取 uint16_t 类型的数据。
----------------------------
#### 原型
```js
rbuffer_read_uint16(rbuffer) => uint16_t
```
### 6.rbuffer\_read\_uint32
> 读取 uint32_t 类型的数据。
----------------------------
#### 原型
```js
rbuffer_read_uint32(rbuffer) => uint32_t
```
### 7.rbuffer\_read\_uint64
> 读取 uint64_t 类型的数据。
----------------------------
#### 原型
```js
rbuffer_read_uint64(rbuffer) => uint64_t
```
### 8.rbuffer\_read\_int8
> 读取 int8_t 类型的数据。
----------------------------
#### 原型
```js
rbuffer_read_int8(rbuffer) => int8_t
```
### 9.rbuffer\_read\_int16
> 读取 int16_t 类型的数据。
----------------------------
#### 原型
```js
rbuffer_read_int16(rbuffer) => int16_t
```
### 10.rbuffer\_read\_int32
> 读取 int32_t 类型的数据。
----------------------------
#### 原型
```js
rbuffer_read_int32(rbuffer) => int32_t
```
### 11.rbuffer\_read\_int64
> 读取 int64_t 类型的数据。
----------------------------
#### 原型
```js
rbuffer_read_int64(rbuffer) => int64_t
```
### 12.rbuffer\_read\_float
> 读取 float 类型的数据。
----------------------------
#### 原型
```js
rbuffer_read_float(rbuffer) => float
```
### 13.rbuffer\_read\_double
> 读取 double 类型的数据。
----------------------------
#### 原型
```js
rbuffer_read_double(rbuffer) => double
```
### 14.rbuffer\_read\_string
> 读取字符串。
----------------------------
#### 原型
```js
rbuffer_read_string(rbuffer) => str
```
### 15.rbuffer\_read\_binary
> 读取指定长度的二进制数据。
----------------------------
#### 原型
```js
rbuffer_read_binary(rbuffer, size) => binary
```
### 16.rbuffer\_get\_data
> 获取 buffer 的指针。
----------------------------
#### 原型
```js
rbuffer_get_data(rbuffer) => pointer
```
### 17.rbuffer\_get\_cursor
> 获取 buffer 当前的读取位置。
----------------------------
#### 原型
```js
rbuffer_get_cursor(rbuffer) => uint32_t
```
### 18.rbuffer\_get\_capacity
> 获取 buffer 的容量。
----------------------------
#### 原型
```js
rbuffer_get_capacity(rbuffer) => uint32_t
```
### 更多示例
```js
...
b=rbuffer_create(wbuffer_get_data(a), wbuffer_get_cursor(a))
assert(rbuffer_get_cursor(b)==0)
assert(rbuffer_read_int8(b)== -10)
assert(rbuffer_get_cursor(b)==1)
assert(rbuffer_read_int16(b)==-1122)
assert(rbuffer_get_cursor(b)==3)
assert(rbuffer_read_int32(b)==-11223344)
assert(rbuffer_get_cursor(b)==7)
assert(rbuffer_read_int64(b)==-1122334455667788)
assert(rbuffer_get_cursor(b)==15)
assert(rbuffer_read_string(b)=="hello")
assert(rbuffer_get_cursor(b)==21)
c = rbuffer_read_binary(b, 6)
assert(rbuffer_get_cursor(b)==27)
wbuffer_rewind(a)
assert(wbuffer_get_cursor(a)==0)
wbuffer_write_binary(a, c)
assert(wbuffer_get_cursor(a)==6)
unset(a)
unset(b)
```

View File

@ -0,0 +1,162 @@
## 字符串扩展函数
### 1. ulen
> 获取 unicode 字符个数。
----------------------------
#### 原型
```
ulen(str) => int
```
#### 示例
```
print(ulen('致远电子'))
```
### 2. char\_at
> 获取指定位置的字符。
----------------------------
#### 原型
```
char_at(str, index) => str
```
> index 为负数时,从后往前取。比如-1 表示最后一个元素。
#### 示例
```
print(char_at('致远电子', 1))
print(char_at('ZLG', 1))
```
### 3. index\_of
> 查找指定子串的位置,如果没有找到返回-1。
----------------------------
#### 原型
```
index_of(str, substr) => int
```
#### 示例
```
print(index_of('hello AWTK and AWTK', 'AWTK'))
```
### 4. last\_index\_of
> 反向查找指定子串的位置,如果没有找到返回-1。
----------------------------
#### 原型
```
last_index_of(str, substr) => int
```
#### 示例
```
print(last_index_of('hello AWTK and AWTK', 'AWTK'))
```
### 5. trim\_left
> 去掉字符串左边的空白字符。
----------------------------
#### 原型
```
trim_left(str) => str
```
#### 示例
```
print(trim_left(' AWTK '))
```
### 6. trim\_right
> 去掉字符串右边的空白字符。
----------------------------
#### 原型
```
trim_right(str) => str
```
#### 示例
```
print(trim_right(' AWTK ') + "1234")
```
#### 7.totitle
> 将字符串中单词的首字母转换成大写。
----------------------------
##### 原型
```
totitle(str) => str
```
#### 示例
```
print(totitle("it is ok!"))
```
#### 8.prompt
> 在控制台提示用户输入字符串。
> 仅当定义了 HAS\_STIOD 时有效。
----------------------------
##### 原型
```
prompt(tips) => str
```
#### 示例
```
a = prompt('input a number:');
print(int(a)+100);
```
### 9. usubstr
> 取子字符串(unicode)。
----------------------------
#### 原型
```
usubstr(str, start, end) => str
```
> * 不包括end
> * start 为负数时,从后往前取。比如-1 表示最后一个元素。
> * end 为负数时,从后往前取。比如-1 表示最后一个元素。
> * end 省略表示到最后全部元素。

View File

@ -0,0 +1,153 @@
## typed array 扩展函数
typed\_array是一个单一类型的动态数组里面只能放相同类型的元素。
typed\_array 有以下属性:
* data 缓冲区的指针
* size 元素的个数
* capacity 元素的最大个数
* size\_in\_bytes 元素的个数 * 元素的大小
* capacity\_in\_bytes 元素的最大个数 * 元素的大小
### 1.typed\_array\_create
> 创建 typed\_array 对象。
----------------------------
#### 原型
```js
typed_array_create() => object
```
### 2.typed\_array\_push
> 追加一个或多个数据。
----------------------------
#### 原型
```js
typed_array_push(array, v, ...) => uint32_t
```
> 返回写入数据的个数
### 3.typed\_array\_pop
> 弹出最后一个元素
----------------------------
#### 原型
```js
typed_array_pop(array) => value
```
### 4.typed\_array\_get
> 获取指定位置的元素
----------------------------
#### 原型
```js
typed_array_get(array, index) => value
```
### 5.typed\_array\_set
> 修改指定位置的元素
----------------------------
#### 原型
```js
typed_array_set(array, index, value) => bool
```
### 6.typed\_array\_insert
> 插入元素到指定位置
----------------------------
#### 原型
```js
typed_array_insert(array, index, value) => bool
```
### 7.typed\_array\_remove
> 删除指定位置的元素
----------------------------
#### 原型
```js
typed_array_remove(array, index) => bool
```
### 8.typed\_array\_clear
> 删除全部元素
----------------------------
#### 原型
```js
typed_array_clear(array) => bool
```
### 9.typed\_array\_join
> 连接全部元素成一个字符串。
----------------------------
#### 原型
```js
typed_array_join(array, sep) => str
```
### 更多示例
```js
a=typed_array_create("i32", 10)
assert(typed_array_push(a, 1) == 1)
assert(a.size, 1);
assert(a.bytes, 4);
assert(typed_array_push(a, 2, 3) == 2)
assert(a.size, 3);
assert(a.bytes, 12);
assert(typed_array_get(a, 0)==1)
assert(typed_array_get(a, 1)==2)
assert(typed_array_get(a, 2)==3)
assert(typed_array_set(a, 0, 11))
assert(typed_array_set(a, 1, 22))
assert(typed_array_set(a, 2, 33))
assert(typed_array_get(a, 0)==11)
assert(typed_array_get(a, 1)==22)
assert(typed_array_get(a, 2)==33)
assert(typed_array_pop(a), 33);
assert(typed_array_pop(a), 22);
assert(typed_array_pop(a), 11);
assert(a.size == 0);
assert(typed_array_push(a,1, 2, 3) == 3)
assert(typed_array_remove(a, 0))
assert(a.size == 2);
assert(typed_array_remove(a, 1))
assert(typed_array_remove(a, 0))
assert(a.size == 0);
assert(typed_array_push(a,1, 2, 3) == 3)
print(typed_array_join(a, ',') == '1,2,3')
unset(a);
```

View File

@ -0,0 +1,75 @@
## value 扩展函数
value 相关的辅助函数。
### 1. value_is_valid
> 判断 value 是否有效。
----------------------------
#### 原型
```
value_is_valid(v) => bool
```
#### 示例
```
a = object_create()
print(value_is_valid(a))
```
### 2. value_is_null
> 判断 value 是否为 null。
----------------------------
#### 原型
```
value_is_null(v) => bool
```
#### 示例
```
a = object_create()
print(value_is_null(a))
```
### 3. value_get_binary_data
> 获取 binary 的数据指针。
----------------------------
#### 原型
```
value_get_binary_data(v) => pointer_t
```
#### 示例
```
print(value_get_binary_data(a))
```
### 4. value_get_binary_size
> 获取 binary 的数据长度。
----------------------------
#### 原型
```
value_get_binary_size(v) => uint32_t
```
#### 示例
```
a = file_read_binary("test.bin")
assert(value_get_binary_size(a) == 5)
```

View File

@ -0,0 +1,249 @@
## 写缓冲扩展函数
wbuffer 有以下属性:
* data 缓冲区的指针
* cursor 当前写的位置
* capacity 最大容量
### 1.wbuffer\_create
> 创建 wbuffer 对象。
----------------------------
#### 原型
```js
wbuffer_create() => object
```
### 2.wbuffer\_attach
> 创建 wbuffer 对象,并附加到指定的数据上。
----------------------------
#### 原型
```js
wbuffer_attach(str) => object
wbuffer_attach(binary) => object
wbuffer_attach(data, size) => object
```
### 3.wbuffer\_skip
> 跳过指定长度的数据。
----------------------------
#### 原型
```js
wbuffer_skip(wbuffer, size) => bool
```
### 4.wbuffer\_write\_uint8
> 写入 uint8_t 类型的数据。
----------------------------
#### 原型
```js
wbuffer_write_uint8(wbuffer, v, ...) => int32_t
```
> 返回写入数据的长度(字节数)。
### 5.wbuffer\_write\_uint16
> 写入 uint16_t 类型的数据。
----------------------------
#### 原型
```js
wbuffer_write_uint16(wbuffer, v, ...) => int32_t
```
> 返回写入数据的长度(字节数)。
### 6.wbuffer\_write\_uint32
> 写入 uint32_t 类型的数据。
----------------------------
#### 原型
```js
wbuffer_write_uint32(wbuffer, v, ...) => int32_t
```
> 返回写入数据的长度(字节数)。
### 7.wbuffer\_write\_uint64
> 写入 uint64_t 类型的数据。
----------------------------
#### 原型
```js
wbuffer_write_uint64(wbuffer, v, ...) => int32_t
```
> 返回写入数据的长度(字节数)。
### 8.wbuffer\_write\_int8
> 写入 int8_t 类型的数据。
----------------------------
#### 原型
```js
wbuffer_write_int8(wbuffer, v, ...) => int32_t
```
> 返回写入数据的长度(字节数)。
### 9.wbuffer\_write\_int16
> 写入 int16_t 类型的数据。
----------------------------
#### 原型
```js
wbuffer_write_int16(wbuffer, v, ...) => int32_t
```
> 返回写入数据的长度(字节数)。
### 10.wbuffer\_write\_int32
> 写入 int32_t 类型的数据。
----------------------------
#### 原型
```js
wbuffer_write_int32(wbuffer, v, ...) => int32_t
```
> 返回写入数据的长度(字节数)。
### 11.wbuffer\_write\_int64
> 写入 int64_t 类型的数据。
----------------------------
#### 原型
```js
wbuffer_write_int64(wbuffer, v, ...) => int32_t
```
> 返回写入数据的长度(字节数)。
### 12.wbuffer\_write\_float
> 写入 float 类型的数据。
----------------------------
#### 原型
```js
wbuffer_write_float(wbuffer, v, ...) => int32_t
```
> 返回写入数据的长度(字节数)。
### 13.wbuffer\_write\_double
> 写入 double 类型的数据。
----------------------------
#### 原型
```js
wbuffer_write_double(wbuffer, v, ...) => int32_t
```
> 返回写入数据的长度(字节数)。
### 14.wbuffer\_write\_string
> 写入 字符串 类型的数据。
----------------------------
#### 原型
```js
wbuffer_write_string(wbuffer, v, ...) => int32_t
```
> 返回写入数据的长度(字节数)。
### 15.wbuffer\_write\_binary
> 写入 二进制 类型的数据。
----------------------------
#### 原型
```js
wbuffer_write_binary(wbuffer, v, ...) => int32_t
```
> 返回写入数据的长度(字节数)。
### 4.wbuffer\_rewind
> 重置读取指针到 0。
----------------------------
#### 原型
```js
rbuffer_rewind(rbuffer) => bool
```
### 17.wbuffer\_get\_data
> 获取 buffer 的指针。
----------------------------
#### 原型
```js
rbuffer_get_data(rbuffer) => pointer
```
### 18.wbuffer\_get\_cursor
> 获取 buffer 当前的读取位置。
----------------------------
#### 原型
```js
rbuffer_get_cursor(rbuffer) => uint32_t
```
### 19.wbuffer\_get\_capacity
> 获取 buffer 的容量。
----------------------------
#### 原型
```js
rbuffer_get_capacity(rbuffer) => uint32_t
```
### 更多示例
```js
a=wbuffer_create()
wbuffer_write_int8(a, -10)
assert(wbuffer_get_cursor(a)==1)
wbuffer_write_int16(a, -1122)
assert(wbuffer_get_cursor(a)==3)
wbuffer_write_int32(a, -11223344)
assert(wbuffer_get_cursor(a)==7)
wbuffer_write_int64(a, -1122334455667788)
assert(wbuffer_get_cursor(a)==15)
wbuffer_write_string(a, "hello")
assert(wbuffer_get_cursor(a)==21)
wbuffer_write_binary(a, "wolrd", 6)
assert(wbuffer_get_cursor(a)==27)
```

View File

@ -0,0 +1,695 @@
# fscript 的 widget 扩展函数
## 1. 介绍
[fscript](fscript.md) 的 widget 扩展函数只能在 widget 的事件处理函数中使用,包括传统的 AWTK 应用程序和 AWTK-MVVM 应用程序的事件处理函数。
fscript 和其它主流脚本 (lua/js) 相比,最大的优势就是体积小巧,而且 AWTK 本身依赖于 fscript所以使用 fscript 增加额外代码可以忽略不计数。
fscript 并不是要取代 C 或 JS 来开发 AWTK 应用程序,而是一个有益的补充,加快应用程序的开发,在 AWTK 的 UI 文件中直接嵌入 fscript, 有如下优势:
* 1. 在特定情况下,可以极大简化程序的实现。
>比如下面的代码,点击按钮时打开指定的窗口就非常简洁。
```xml
<button focusable="true" focused="true" on:click="open('basic')" text="Basic" />
```
>比如下面的代码,点击按钮时关闭当前的窗口也非常简洁。
```xml
<button focusable="true" on:click="close()" text="Close" />
```
* 2. 方便工具(如 designer) 生成向导代码。
> 一般的 IDE 都有简单的代码生成功能,比如按钮的事件处理函数可以选择打开或关闭窗口等简单的功能。不排除 designer 以后增加类似的功能。
* 3. 让 MVVM 应用程序有机会去操作界面。
> 理论上模型是不能操作界面的但在特殊情况下确实有操作界面的需求。在保持视图和模型独立的前提下fscript 让操作界面成为可能。
* 4. 方便生成自定义的组件。很多情况下,需要对现有的控件进行改进和组合,生成新的控件。
比如,我们需要用 text selector 生成一个日期选择控件,用三个 text selector 控件组合成日期选择控件,分别选择年月日。但是 text selector 之间是独立的,而年月和日则是有依赖关系,比如 1 月的天数是 31 天2 月的天数与年份有关。当然我们可以用 C 代码来建立三者的关系,而用 fscript不但实现要简单一些而且由于 xml 和代码在一起,发布和重用也非常方便。
```xml
<row x="10" y="30" w="100%" h="150" children_layout="default(row=1,col=3)">
<text_selector name="year" options="2000-2050" selected_index="9">
<property name="on:value_changed">
<![CDATA[
a = get_days_of_month(widget_get('parent.year', 'value'), widget_get('parent.month', 'value'))
widget_set('parent.day', 'options', iformat( '1-%d', a) + '%02d')
]]>
</property>
</text_selector>
<text_selector name="month" options="1-12-%02d" selected_index="8" loop_options="true">
<property name="on:value_changed">
<![CDATA[
a = get_days_of_month(widget_get('parent.year', 'value'), widget_get('parent.month', 'value'))
widget_set('parent.day', 'options', iformat( '1-%d', a) + '%02d')
]]>
</property>
</text_selector>
<text_selector name="day" options="1-31-%02d" selected_index="9" />
</row>
```
* 5. 不需要重新编译代码。如果资源文件是在文件系统中,直接更新资源即可,而无需编译和下载固件。
## 2. 事件处理函数
添加事件处理函数,实际上是增加一些自定义的属性,属性名以 on: 开头,紧跟事件名称。如:
```xml
<button focusable="true" on:click="close()" text="Close" />
```
为了方便编辑和阅读,对于比较复杂的脚本,可以把事件处理函数独立出来,放到 property 里,并用 CDATA 包装起来。
```xml
<button name="timer" focusable="true" on:click="start_timer(100)" text="Start Timer">
<property name="on:timer"><![CDATA[
a = widget_lookup('window', 'bar', true)
b = widget_get(a, 'value')
if(b < 100) {
widget_set(a, 'value', b + 1)
} else {
widget_set(a, 'value', 0)
stop_timer()
}
]]></property>
</button>
```
> 如果处理逻辑太复杂,请不要用 fscript 实现,否则不好调试。要善用 fscript 的优点而回避它的缺点。
## 3. 目前支持的事件
* global\_key\_up
* global\_key\_down
* global\_key\_long\_press
* key\_up
* key\_down
* key\_long\_press
* key\_down\_before\_children
* key\_up\_before\_children
> 按键事件处理函数可以从 key 变量获取当前的键值。可以从 alt, ctrl, cmd 和 menu 变量中获取相应控制键的状态。如:
```xml
<property name="on:global_key_down">
print("global keydown:", key, "alt=", alt, "ctrl=", ctrl, "cmd=", cmd, "menu=", menu);
</property>
<property name="on:global_key_up">
print("global keyup:", key, "alt=", alt, "ctrl=", ctrl, "cmd=", cmd, "menu=", menu);
</property>
<property name="on:global_key_long_press">
print("global key_long_press:", key, "alt=", alt, "ctrl=", ctrl, "cmd=", cmd, "menu=", menu);
</property>
<property name="on:key_down">
print("keydown:", key, "alt=", alt, "ctrl=", ctrl, "cmd=", cmd, "menu=", menu);
</property>
<property name="on:key_up">
print("keyup:", key, "alt=", alt, "ctrl=", ctrl, "cmd=", cmd, "menu=", menu);
</property>
<property name="on:key_long_press">
print("keyup:", key, "alt=", alt, "ctrl=", ctrl, "cmd=", cmd, "menu=", menu);
</property>
```
* pointer\_up
* pointer\_down
* pointer\_move
* click
> 指针事件处理函数可以从 x/y 变量获取当前指针的位置。可以从 alt, ctrl, cmd 和 menu 变量中获取相应控制键的状态。如:
```xml
<property name="on:pointer_down">
print("pointerdown:", x, y, "alt=", alt, "ctrl=", ctrl, "cmd=", cmd, "menu=", menu);
</property>
<property name="on:pointer_up">
print("pointerup:", x, y, "alt=", alt, "ctrl=", ctrl, "cmd=", cmd, "menu=", menu);
</property>
<property name="on:click">
print("click:", x, y, "alt=", alt, "ctrl=", ctrl, "cmd=", cmd, "menu=", menu);
</property>
```
* timer
示例:
```xml
<button name="timer" focusable="true" on:click="start_timer(100)" text="Start Timer">
<property name="on:timer"><![CDATA[
a = widget_lookup('window', 'bar', true)
b = widget_get(a, 'value')
if(b < 100) {
widget_set(a, 'value', b + 1)
} else {
widget_set(a, 'value', 0)
stop_timer()
}
]]></property>
</button>
```
* window\_close
* window\_open
* window\_will\_open
> 窗口事件只适用于窗口。
```xml
<property name="on:window_open">
print("window_open")
</property>
<property name="on:window_will_open">
print("window_will_open")
</property>
<property name="on:window_close">
print("window_close")
</property>
```
* value\_changed
```xml
<progress_bar name="bar" text="" value="10" on:value_changed="print(widget_get('self', 'value'))"/>
```
* focus
* blur
示例:
```
<edit name="edit" tips="text edit" on:focus="print(focus)" on:blur="print('blur', widget_get('self', 'value'))"/>
```
* value\_changed\_by\_ui (仅 MVVM 支持)
> 在 MVVM 中,除了支持以上方式编写 fscript也可以通过 v-on: 和 v-data: 的方式使用 fscript请参考 MVVM 的文档。
## 4. 事件的返回值
* 事件缺省返回 RET\_OK。
* 如果需要在执行完成后移除事件处理函数,可以设置 RET\_REMOVE 为 true。
```
RET_REMOVE=true
```
* 如果需要在执行完成后停止后续事件处理,可以设置 RET\_STOP 为 true。
```
RET_STOP=true
```
## 5. widget 相关的扩展函数
### 5.1 open
> 打开窗口。
----------------------------
#### 原型
```js
open(name, close_current, switch_to_if_exist)
```
* name 窗口的资源名称(字符串)
* close\_current 可选。为 true 时关闭当前窗口。
* switch\_to\_if\_exist 可选。为 true 时,如果同名窗口存在,直接切换到指定窗口。
### 示例
```xml
<button text="Open" focusable="true" focus="true" on:click="open('test_fscript')"/>
<button text="Close" focusable="true" on:click="open('test_fscript', true)"/>
<button text="Switch TO" focusable="true" on:click="open('test_fscript', false, true)"/>
```
### 5.2 close
> 关闭窗口。
----------------------------
#### 原型
```js
close(name)
```
* name 窗口的名称(字符串),可选。缺省关闭当前窗口。
### 示例
```xml
<button focusable="true" on:click="close()" text="Close" />
```
### 5.3 back
> 退到前一个窗口
----------------------------
#### 原型
```js
back()
```
### 示例
```xml
<button focusable="true" on:click="back()" text="back" />
```
### 5.4 back_to_home
> 退到主窗口
----------------------------
#### 原型
```js
back_to_home()
```
### 示例
```xml
<button focusable="true" on:click="back_to_home()" text="home" />
```
### 5.5 quit
> 退出应用程序
----------------------------
#### 原型
```js
quit()
```
### 示例
```xml
<button focusable="true" on:click="quit()" text="quit" />
```
### 5.6 tr
> 翻译指定字符串
----------------------------
#### 原型
```js
tr(str)
```
### 示例
```xml
<button focusable="true" on:click="print(tr('OK'))" text="tr" />
```
### 5.7 widget_lookup
> 查找指定的控件
----------------------------
#### 原型
```js
widget_lookup(widget, path)
widget_lookup(widget, name, recursive)
```
* widget 用作锚点,后面的路径相对于该 widget。'self' 表示当前控件,'parent' 表示当前控件的父控件,'window' 表示当前的窗口,'window\_manager' 表示窗口管理器。
### 示例
> 查找窗口下名为 view 控件下的名为 bar 的控件。
```js
a = widget_lookup('window', 'view.bar')
```
> 递归查找窗口下名为 bar 的控件。
```js
a = widget_lookup('window', 'bar', true)
```
> 递归查找当前控件下名为 bar 的控件。
```js
a = widget_lookup('self', 'bar', true)
```
> 递归查找当前控件的父控件下名为 bar 的控件。
```js
a = widget_lookup('self', 'bar', true)
```
### 5.8 widget_get
> 获取控件的属性
----------------------------
#### 原型
```js
widget_get(widget, prop)
widget_get(widget, path.prop)
```
* widget 用作锚点,后面的路径相对于该 widget。'self' 表示当前控件,'parent' 表示当前控件的父控件,'window' 表示当前的窗口,'window\_manager' 表示窗口管理器。
* prop 可以是简单的属性命名,也可以是 widget 路径+属性名。
* 支持 widget.prop 方式访问控件属性。
### 示例
> 获取当前控件的 value
```
widget_get('self', 'value')
```
> 获取当前控件下名为 bar 控件的 value
```
widget_get('self', 'bar.value')
```
> 获取当前控件的父控件下名为 bar 控件的 value
```
widget_get('self', 'bar.value')
```
> 获取当前控件的父控件下名为 bar 控件的 value
```
widget_get('parent', 'bar.value')
```
> 获取当前窗口下名为 bar 控件的 value
```
widget_get('window', 'bar.value')
```
> 获取当前窗口下名为 view 控件下名为 bar 控件的 value
```
widget_get('window', 'view.bar.value')
```
>对于控件对象,可以直接访问其属性
```
a = widget_lookup('window', 'bar', true)
if(a.value <= 90) {
a.value = a.value + 10
}
```
### 5.9 widget_set
> 设置控件的属性
----------------------------
#### 原型
```js
widget_set(widget, prop, value)
widget_set(widget, path.prop, value)
```
* widget 用作锚点,后面的路径相对于该 widget。'self' 表示当前控件,'parent' 表示当前控件的父控件,'window' 表示当前的窗口,'window\_manager' 表示窗口管理器。
* prop 可以是简单的属性命名,也可以是 widget 路径+属性名。
* 支持 widget.prop 方式设置控件属性。
### 示例
> 设置当前控件的 value
```
widget_set('self', 'value', 12)
```
> 设置当前控件下名为 bar 控件的 value
```
widget_set('self', 'bar.value', 12)
```
> 设置当前控件的父控件下名为 bar 控件的 value
```
widget_set('parent', 'bar.value', 1.2)
```
> 设置当前窗口下名为 bar 控件的 value
```
widget_set('window', 'bar.value', 'hello')
```
> 设置当前窗口下名为 view 控件下名为 bar 控件的 value
```
widget_set('window', 'view.bar.value', 12)
```
>对于控件对象,可以直接访问其属性
```
a = widget_lookup('window', 'bar', true)
if(a.value <= 90) {
a.value = a.value + 10
}
```
### 5.10 widget_create
> 创建控件
----------------------------
#### 原型
```js
widget_create(type, parent, x, y, w, h)
```
* type 为控件的字符串名称。
* parent 为父控件。可以是 widget 对象,也可以是 widget 的路径。
### 示例
```js
a = widget_lookup('window', 'foobar', true)
if(value_is_null(a)) {
a = widget_create('label', 'window.view', 0, 0, 0, 0)
assert(!value_is_null(a))
widget_set(a, 'text', 'Dynamic created')
assert(widget_get(a, 'text') == 'Dynamic created')
widget_set(a, 'name', 'foobar')
assert(widget_get(a, 'name') == 'foobar')
} else {
print("foobar exist");
}
```
### 5.10 widget_destroy
> 销毁控件
----------------------------
#### 原型
```js
widget_destroy(widget)
```
* widget 可以是 widget 对象,也可以是 widget 的路径。
### 示例
```js
a = widget_lookup('window', 'foobar', true)
if(!value_is_null(a)) {
widget_destroy(a)
} else {
print('not found foobar');
}
```
```
widget_destroy('self.bar')
widget_destroy('window.view.bar')
```
### 5.11 start_timer
> 开启一个定时器
----------------------------
#### 原型
```js
start_timer(duration)
```
* duration 为定时器时间间隔。
* 一个控件只能开启一个定时器,如果定时器存在,自动先移除之前的定时器。
* 定时器时间到了之后,会触发控件的 timer 事件,所以对应的控件需要处理 timer 事件。
### 示例
```xml
<button name="timer" focusable="true" on:click="start_timer(100)" text="Start Timer">
<property name="on:timer">
<![CDATA[
a = widget_lookup('window', 'bar', true)
b = widget_get(a, 'value')
if(b < 100) {
widget_set(a, 'value', b + 1)
} else {
widget_set(a, 'value', 0)
stop_timer()
}
]]>
</property>
</button>
```
### 5.12 stop_timer
> 停止指定控件的定时器
----------------------------
#### 原型
```js
stop_timer()
stop_timer(widget)
```
* 不指定 widget 是停止当前控件的定时。
* widget 可以是 widget 对象,也可以是 widget 的路径。
### 示例
```js
stop_timer('parent.timer')
```
### 5.13 send_key
> 向指定控件发生按键事件
----------------------------
#### 原型
```js
send_key(widget, key_name)
```
* widget 可以是 widget 对象,也可以是 widget 的路径。
### 示例
```js
<button text="Backspace" on:click="send_key('window.edit', 'backspace')"/>
<button text="Char" on:click="send_key('window.edit', 'a')"/>
```
### 5.14 widget\_eval
> 有时几个事件处理函数的代码是重复的我们可以把代码放到控件的属性中通过widget\_eval来执行。
----------------------------
#### 原型
```js
widget_eval(path.prop)
widget_eval(widget, prop)
widget_eval(widget, path.prop)
```
* widget 用作锚点,后面的路径相对于该 widget。'self' 表示当前控件,'parent' 表示当前控件的父控件,'window' 表示当前的窗口,'window\_manager' 表示窗口管理器。
* prop 可以是简单的属性命名,也可以是 widget 路径+属性名。
### 示例
下面两个事件处理函数的代码是相同。
```xml
<row x="10" y="30" w="100%" h="150" children_layout="default(row=1,col=3)">
<text_selector name="year" options="2000-2050" selected_index="9">
<property name="on:value_changed">
<![CDATA[
a = get_days_of_month(widget_get('parent.year', 'value'), widget_get('parent.month', 'value'))
widget_set('parent.day', 'options', iformat( '1-%d', a) + '%02d')
]]>
</property>
</text_selector>
<text_selector name="month" options="1-12-%02d" selected_index="8" loop_options="true">
<property name="on:value_changed">
<![CDATA[
a = get_days_of_month(widget_get('parent.year', 'value'), widget_get('parent.month', 'value'))
widget_set('parent.day', 'options', iformat( '1-%d', a) + '%02d')
]]>
</property>
</text_selector>
<text_selector name="day" options="1-31-%02d" selected_index="9" />
</row>
```
我们可以改造成这样:
```xml
<row x="10" y="bottom" w="100%" h="150" children_layout="default(row=1,col=3)">
<property name="handle_value_changed">
<![CDATA[
a = get_days_of_month(widget_get('parent.year', 'value'), widget_get('parent.month', 'value'))
widget_set('parent.day', 'options', iformat( '1-%d', a) + '%02d')
]]>
</property>
<text_selector name="year" options="2000-2050" selected_index="9"
on:value_changed="widget_eval('parent.handle_value_changed')" />
<text_selector name="month" options="1-12-%02d" selected_index="8" loop_options="true"
on:value_changed="widget_eval('parent.handle_value_changed')" />
<text_selector name="day" options="1-31-%02d" selected_index="9" />
</row>
```
### 示例参考
* https://github.com/zlgopen/awtk/blob/master/design/default/ui/main_fscript.xml
* https://github.com/zlgopen/awtk/blob/master/design/default/ui/text_selector_fscript.xml
* https://github.com/zlgopen/awtk/blob/master/design/default/ui/button_fscript.xml
* https://github.com/zlgopen/awtk/blob/master/design/default/ui/test_fscript.xml
* https://github.com/zlgopen/awtk/blob/master/design/default/ui/basic_fscript.xml
> 可以用 preview_ui 直接运行。如:
```
./bin/preview_ui.exe design/default/ui/main_fscript.xml
```

View File

@ -0,0 +1,36 @@
# 类似函数调用的参数格式
在AWTK的XML UI中不少地方使用了类似函数调用的参数格式常见用途有
* 控件动画。如:
```
<progress_bar name="value" x="center" y="middle" w="90%" h="40"
animation="value(from=50, to=100, yoyo_times=1000, duration=1000, delay=4000)"/>
```
* 窗口动画。如:
```
<dialog anim_hint="popup" highlight="default(start_alpha=0, end_alpha=80)"
```
* 布局参数。如:
```
<row x="10" y="bottom:30" w="100%" h="90" children_layout="default(row=1,col=3)">
```
**基本格式为:**
**函数名**后跟一对括号,括号中有一个或多个**参数****参数**之间用英文','分隔,**参数名**和**参数值**之间用'='分隔。如果没有**参数**可以只写**函数名**。
用不太正规的语法描述为:
```
func_call => func_name '(' params_list ')' | func_name
params_list => params_list ',' param | param
param => name '=' value
```

View File

@ -0,0 +1,6 @@
dot dots/* -Tpng -O
mv dots/*.png images
dot dots/* -Tsvg -O
mv dots/*.svg images

View File

@ -0,0 +1,60 @@
## 渐变色
渐变色在设计漂亮美观的界面时十分实用相较于纯色渐变色看起来更有质感也更新潮一些。目前AWTK 中支持将控件的背景色和前景色设置为渐变色。
### 一、主要限制
AWTK 的渐变色设置格式参考了 [HTML CSS 的格式](https://developer.mozilla.org/en-US/docs/Web/CSS/gradient/linear-gradient()),但是目前只实现了它的一个子集。主要有以下限制:
1. 只支持 180 度的 linear-gradient也就是垂直从上到下的线性渐变。
2. 只支持两种颜色的渐变,也就是从某一种颜色渐变到另一种颜色。
需要注意的是,目前 AWTK 只支持将控件风格(样式)中的 bg\_color 属性和 fg\_color 属性设置为渐变色,即只允许控件背景色和前景色为渐变色。
> 备注AWTK 中已实现渐变色的填充,后续会不断优化完善,支持更多的渐变色设置格式并让更多控件风格支持设置渐变色。
### 二、示例用法
#### 2.1 窗体样式文件中设置渐变色
例如,此处在窗体样式文件中创建名为 gradient_button 的按钮样式,设置其不同状态下的背景色为渐变色:
```xml
<button>
...
<style name="gradient_button" border_color="#a0a0a0" text_color="black" >
<normal bg_color="linear-gradient(180deg, red 60%, cyan);" />
<over bg_color="linear-gradient(180deg, orange 60%, red);" />
<pressed bg_color="linear-gradient(180deg, orange 60%, blue);" />
<focused bg_color="linear-gradient(180deg, orange 60%, green);" />
</style>
</button>
```
上面按钮样式中 normal 状态的 bg_color 属性设置表示如下:
* **linear-gradient**: 表示线性渐变;
* **180deg**: 表示垂直从上到下的渐变;
* **red 60%, cyan**: 表示从高度为 60% 的位置开始红色渐变最后以为蓝绿色结束。
不填写开始高度,则默认从 0% 的位置开始,例如直接从红色垂直渐变为蓝色,代码如下:
```xml
<normal bg_color="linear-gradient(180deg, red, cyan);" />
```
并且,开始和结束的颜色可通过颜色编码表示,代码如下:
```xml
<normal bg_color="linear-gradient(180deg, #FF0000, #0000FF);" />
```
#### 2.2 代码中设置渐变色
在 C 代码中设置控件背景色为渐变色只需调用 widget\_set\_style\_str 接口即可,代码如下:
```c
widget_set_style_str(button, "normal:bg_color", "linear-gradient(180deg, red, blue);");
```
> 备注:调用 widget\_set\_style\_xxx 接口在代码中设置的样式为 inline style会占用额外的内存具体详见 [theme.md](theme.md)。

View File

@ -0,0 +1,111 @@
#AWTK 硬件资源需求评估
## 一、CPU
CPU 的要求与 LCD 的尺寸关系很大如果不启用动画对于320x240x16的 LCD52M的32位CPU应该够用。
目前我们测试过的最低硬件配置是STM32F103(Cortex-M3内核 CPU 72 MH)更低的CPU只能支持更低尺寸的LCD了。
## 二、Flash 的需求
AWTK 基本代码(包括常用控件),在 STM32上编译之后大概 150K。字体、图片和输入法要看具体的应用了。
一般来说,至少要 256K FLASH不包括裸系统和输入法以及图片字体等资源
下列模块为 AWTK 可增加模块STM32F103等低端平台会禁止下列模块故无此FLASH开销
| 模块名称 | FLASH大小 | 备注 |
| :------------------------: | :---------: | :--------------------------: |
| PNGJPG 和 GIF 图片解码器 | 大约57.64KB | |
| Truetype 字体解码器 | 大约27.3KB | |
| 标准的 UNICODE 换行算法 | 大约49.4KB | |
| Google 拼音输入法 | 大约1.15MB | |
| 加载文件系统资源模块 | 大约7.1KB | |
| 启用 AGGE 作为矢量画布 | 大约21KB | |
| 窗口动画 | 大约9.42KB | 窗口动画需要矢量画布功能支持 |
## 三、内存需求评估指南
假设:
* LCD的宽度为LCD\_W
* LCD的高度为LCD\_H
* LCD的每像素占用的字节数为BPP
### 1.Framebuffer
* 单 framebuffer 需要LCD\_W * LCD\_H * BPP
* 双 framebuffer 需要2 * LCD\_W * LCD\_H * BPP
* 三 framebuffer 需要3 * LCD\_W * LCD\_H * BPP
> STM32F103等低端平台无需Framebuffer故无此内存开销。
>
### 2.窗口动画
- 如果启用窗口动画,需要两个 framebuffer 大小的内存2 * LCD\_W * LCD\_H * BPP
- 窗口动画需要开启矢量画布功能
> STM32F103等低端平台禁用窗口动画故无此内存开销。
### 3.图片解码
* 图片解码器解码的时候大约占用 2 * 图片宽* 图片高 * BPP 的内存。
* 一般带 alpha 通道的图片解码后每像素占用4字节。
* 不带 alpha 通道的图片解码后,如果定义 WITH\_BITMAP\_BGR565每像素占用2字节否则占用4字节。
> STM32F103等低端平台直接使用位图编译到常量中故无此内存开销。
### 4.输入法
- 配套的控件
- Google 拼音输入大约占用700KB。
> STM32F103等低端平台不启用输入法故无此内存开销。
### 5.字体
* 字体文件本身大小。
* 字体解码器大约200B
* 长度为256的字体图片缓冲区的大约占用4.2KB。
* 字体图片缓存大小(字体图片的大小会根据字号和字体形状来决定一个字体图片的内存大小)。
> STM32F103等低端平台直接使用位图字体编译到常量中故无此内存开销。
### 6.控件
一般控件占用100B左右(64位系统会多一些)一般复杂度的应用程序控件占用内存的峰值小余100K。
对于低端平台,可以简化界面,关闭后台窗口,以减少内存的需求。
### 7.AGGE矢量画布
- nanovg 作为前端大约占用18.3KB左右的缓冲区(64位系统会多一些)。
- AGGE 作为后端大约占用300B左右。
- AGGE 在计算时候会根据不同的效果会创建一些大小不等的缓冲区和临时变量具体需要看效果来决定一般效果峰值小于10K
> STM32F103等低端平台不启用矢量画布故无此内存开销。
## 四、附录
### 1. AWTK 对应模块内存表:
| 功能名称 | 宏 | ROM | RAM | 说明 |
| --------------------------- | -------------------------------------------------------- | :---------- | :----------------------- | :----------------------------------------------------------- |
| PNG JPG 和 GIF 图片解码器 | WITH_STB_IMAGE | 大约57.64KB | 大于2 * 255KB + 16KB | 一张16位色分辨率为480 * 272的图片内存为255KB |
| Truetype 字体解码器 | WITH_STB_FONT | 大约27.3KB | 4.2KB+18.5KB | 100个方正水云的18号字的内存大约为18.5KB长度为256的字体图片缓冲区的大约占用4.2KB |
| 标准的 UNICODE 换行算法 | WITH_UNICODE_BREAK | 大约49.4KB | 大于1.39KB | |
| Google 拼音输入法 | 取消定义 WITHOUT_INPUT_METHOD 或者取消定义 WITH_NULL_IM | 大约1.15MB | 大于700KB | |
| 加载文件系统资源模块 | WITH_FS_RES | 大约7.1KB | 0B | |
| 启用 AGGE 作为矢量画布 | WITH_NANOVG_AGGE | 大约21KB | 大于18.4KB + 10KB | AGGE 计算时候开辟内存保守估计峰值为10KB |
| 窗口动画 | WITHOUT_WINDOW_ANIMATORS | 大约9.42KB | 大于2 * 255KB | 一块16位色分辨率为480 * 272的 framebuffer 为255KB |
| 裁剪布局算法 | WITHOUT_LAYOUT | 大约3.64KB | 0B | |
| 裁剪控件动画 | WITHOUT_WIDGET_ANIMATORS | 大约1.3KB | 0B | |
| 裁剪剪切板算法 | WITHOUT_CLIPBOARD | 472B | 0B | |
| 裁剪对话框高亮策略代码 | WITHOUT_DIALOG_HIGHLIGHTER | 大约1.46KB | 0B | |

View File

@ -0,0 +1,16 @@
# 如何设置应用程序的图标
## Windows
### 将应用程序的资源放到应用程序目录下的下列位置:
```
win32_res/awtk.res
```
### 资源的生成方法
可以在awtk/win32\_res基础之上修改也可以完全自己制作。
### 参考
* [如何修改 Windows 下应用程序的图标](https://github.com/zlgopen/awtk/blob/master/win32_res/README.md)

View File

@ -0,0 +1,133 @@
# 如何访问控件的属性
## 1.修改控件的属性
控件所有的公开属性,都提供了相应的 set 函数,用它可以修改对应的属性。如:
```c
/**
* @method check_button_set_value
* 设置控件的值。
* @annotation ["scriptable"]
* @param {widget_t*} widget check_button 对象。
* @param {bool_t} value 值
*
* @return {ret_t} 返回 RET_OK 表示成功,否则表示失败。
*/
ret_t check_button_set_value(widget_t* widget, bool_t value);
```
## 2.读取控件的属性
控件都提供了一个宏,将其由 widget 类型转换成实际的类型,然后可以直接读取它的属性。如:
```c
bool_t checked = CHECK_BUTTON(button)->value;
```
## 3.通过 widget 的函数访问控件的属性
widget 提供了 widget\_get\_prop/widget\_set\_prop 系列函数,也可以用来访问控件的属性。
```c
/**
* @method widget_get_prop
* 获取控件指定属性的值。
* @param {widget_t*} widget 控件对象。
* @param {const char*} name 属性的名称。
* @param {value_t*} v 返回属性的值。
*
* @return {ret_t} 返回 RET_OK 表示成功,否则表示失败。
*/
ret_t widget_get_prop(widget_t* widget, const char* name, value_t* v);
/**
* @method widget_set_prop
* 设置控件指定属性的值。
* @param {widget_t*} widget 控件对象。
* @param {const char*} name 属性的名称。
* @param {value_t*} v 属性的值。
*
* @return {ret_t} 返回 RET_OK 表示成功,否则表示失败。
*/
ret_t widget_set_prop(widget_t* widget, const char* name, const value_t* v);
```
## 4.访问 text 属性
```
/**
* @method widget_get_text
* 获取控件的文本。
* 只是对 widget\_get\_prop 的包装,文本的意义由子类控件决定。
*
* 如果希望获取 UTF8 格式的文本,可以参考下面的代码:
*
* ```c
* str_t str;
* str_init(&str, 0);
* str_from_wstr(&str, widget_get_text(target));
* log_debug("%s: %s\n", target->name, str.str);
* str_reset(&str);
* ```
*
* @annotation ["scriptable"]
* @param {widget_t*} widget 控件对象。
*
* @return {const wchar_t*} 返回文本。
*/
const wchar_t* widget_get_text(widget_t* widget);
/**
* @method widget_set_text
* 设置控件的文本。
* 只是对 widget\_set\_prop 的包装,文本的意义由子类控件决定。
* @param {widget_t*} widget 控件对象。
* @param {const wchar_t*} text 文本。
*
* @return {ret_t} 返回 RET_OK 表示成功,否则表示失败。
*/
ret_t widget_set_text(widget_t* widget, const wchar_t* text)
/**
* @method widget_set_text_utf8
* 设置控件的文本。
* 只是对 widget\_set\_prop 的包装,文本的意义由子类控件决定。
* @annotation ["scriptable"]
* @alias set_text
* @param {widget_t*} widget 控件对象。
* @param {const char*} text 文本。
*
* @return {ret_t} 返回 RET_OK 表示成功,否则表示失败。
*/
ret_t widget_set_text_utf8(widget_t* widget, const char* text);
```
## 5.访问 value 属性
> 仅使用与 int/bool 类型的属性
```
/**
* @method widget_set_value
* 设置控件的值。
* 只是对 widget\_set\_prop 的包装,值的意义由子类控件决定。
* @annotation ["scriptable"]
* @param {widget_t*} widget 控件对象。
* @param {int32_t} value 值。
*
* @return {ret_t} 返回 RET_OK 表示成功,否则表示失败。
*/
ret_t widget_set_value(widget_t* widget, int32_t value)
/**
* @method widget_get_value
* 获取控件的值。只是对 widget\_get\_prop 的包装,值的意义由子类控件决定。
* @annotation ["scriptable"]
* @param {widget_t*} widget 控件对象。
*
* @return {int32_t} 返回值。
*/
int32_t widget_get_value(widget_t* widget);
```

View File

@ -0,0 +1,92 @@
# 如何根据实际分辨率自动调整窗口中子控件的位置大小
## 1. 介绍
一般来说,我们希望设计的界面在不同分辨率的设备上都能正常显示,此时应该使用 [layout 参数](layout.md),而不要使用固定坐标和大小。
在有的情况下,设计时的分辨率与运行时的分辨率差不大,或者宽高之比的比例相近。比如手机,用 AWTK 开发的应用程序在手机上运行时,可以使用一种简便的方法,让 AWTK 自动调整子控件的坐标和大小(或者辅以 layout 参数进行微调)。
通过指定窗口下面这些属性,可以实现自动调整控件的坐标和大小。
```c
/**
* @property {uint16_t} design_w
* @annotation ["set_prop","get_prop","readable","persitent","design","scriptable"]
* 设计时宽度。
*/
uint16_t design_w;
/**
* @property {uint16_t} design_h
* @annotation ["set_prop","get_prop","readable","persitent","design","scriptable"]
* 设计时高度。
*/
uint16_t design_h;
/**
* @property {bool_t} auto_scale_children_x
* @annotation ["set_prop","get_prop","readable","persitent","design","scriptable"]
* 窗口大小与设计时大小不同时,是否自动调整子控件的 x 坐标。
*/
uint16_t auto_scale_children_x : 1;
/**
* @property {bool_t} auto_scale_children_y
* @annotation ["set_prop","get_prop","readable","persitent","design","scriptable"]
* 窗口大小与设计时大小不同时,是否自动调整子控件的 y 坐标。
*/
uint16_t auto_scale_children_y : 1;
/**
* @property {bool_t} auto_scale_children_w
* @annotation ["set_prop","get_prop","readable","persitent","design","scriptable"]
* 窗口大小与设计时大小不同时,是否自动调整子控件的宽度。
*/
uint16_t auto_scale_children_w : 1;
/**
* @property {bool_t} auto_scale_children_h
* @annotation ["set_prop","get_prop","readable","persitent","design","scriptable"]
* 窗口大小与设计时大小不同时,是否自动调整子控件的高度。
*/
uint16_t auto_scale_children_h : 1;
```
> 如果子控件具有 self\_layout 参数或者所在容器具有 children\_layout 参数,则不使用自动调整功能。
## 2. 通过 XML 指定参数
示例:
```xml
<window
design_w="320" design_h="480"
auto_scale_children_x="true" auto_scale_children_y="true"
auto_scale_children_w="true" auto_scale_children_h="true" >
<button text="Hello" x="120" w="80" y="220" h="40" />
</window>
```
## 3. 通过代码指定参数
在代码中,可以使用下面这个函数自动调整控件的坐标和大小:
```c
/**
* @method window_set_auto_scale_children
* 当设计分辨率和实际分辨率不一致时,自动调整子控件的位置和大小。
*
* > 当子控件有 self_layout 参数或者子控件的父控件有 children_layout 参数时,不会自动调整。
*
* @annotation ["scriptable"]
* @param {widget_t*} widget window 对象。
* @param {uint32_t} design_w 设计时宽度。
* @param {uint32_t} design_h 设计时高度。
*
* @return {ret_t} 返回 RET_OK 表示成功,否则表示失败。
*/
ret_t window_set_auto_scale_children(widget_t* widget, uint32_t design_w, uint32_t design_h);
```
示例:
```c
widget_t* win = window_open("foobar");
window_set_auto_scale_children(win, 320, 480);
```

View File

@ -0,0 +1,37 @@
# 如何编译Windows 32位版本
* 1.在文件awtk\_config.py中设置TARGET\_ARCH为'x86'
将:
```
#TARGET_ARCH='x86'
```
修改为:
```
TARGET_ARCH='x86'
```
* 2.对于XP如果OpenGL渲染不正常。可以使用AGGE(或BGFX)试试。
将:
```
#NANOVG_BACKEND='AGGE'
```
修改为:
```
NANOVG_BACKEND='AGGE'
```
* 3.编译32位版本需要重新生成资源。
```
scripts/update_res.py clean
scripts/update_res.py all
```

View File

@ -0,0 +1,9 @@
## 如何使用keil的AC6工具链编译
有些平台必须使用AC6工具链编译但是使用AC6编译会有些问题请先做下列修改
1. 在C/C++(AC6)设置中指定Language C为gnu99
2. 在C/C++(AC6)设置中从Misc Controls中去掉 --gnu
3. 选中.cpp的文件右键打开"Options for file xxx.cpp"菜单File Type选择“C++ Source file”
4. 在AC6中有些语法变化比如__attribute__((at(0x08041000)))是无效的,请改成 __attribute__((section(".ARM.__AT_0x08041000")))。

View File

@ -0,0 +1,26 @@
# 如何定制 combo_box 控件中按钮的风格和大小
## 定制 combo_box 控件中按钮的风格
打开 style 文件,找到按钮的 style修改名为 combobox_down 的 style 即可。
```xml
<button>
<style name="combobox_down" border_color="#a0a0a0">
<normal bg_color="#f0f0f0" icon="arrow_down_n"/>
<pressed bg_color="#c0c0c0" icon="arrow_down_p"/>
<over bg_color="#e0e0e0" icon="arrow_down_o"/>
</style>
</button>
```
## 定制 combo_box 控件中按钮的大小
此时需要在 combo_box 控件中,增加一个按钮子控件,可以设置它的大小、位置和 style 的名称。
```xml
<combo_box left_margin="6" x="10" y="5" w="200" h="30" text="left" options="left;center;right;">
<button style="combobox_down" x="right:5" y="middle" w="20" h="20"/>
</combo_box>
```

View File

@ -0,0 +1,88 @@
# 如何绘制旋转文字
要旋转文字只能用 [vgcanvas](https://github.com/zlgopen/awtk/blob/master/docs/manual/vgcanvas_t.md) 绘制文字。在不同的情况下AWTK 底层采用不同的 [vgcanvas](https://github.com/zlgopen/awtk/blob/master/docs/manual/vgcanvas_t.md) 引擎,遗憾的是部分 [vgcanvas](https://github.com/zlgopen/awtk/blob/master/docs/manual/vgcanvas_t.md) 引擎并不支持绘制文字。事实上只能在用 OpenGL 的情况下,才支持绘制文字。
不过没有关系,毕竟在嵌入式平台,旋转文字的需求不多,如果确实需要,也是有解决方案的。本文介绍一种跨平台的绘制旋转的文字方法。
字体引擎(比如 stb/freetype) 会把矢量字体转换成一种特殊位图,这个位图只有透明通道 (alpha) 信息,在 AWTK 中用 glyph\_t 表示。[vgcanvas](https://github.com/zlgopen/awtk/blob/master/docs/manual/vgcanvas_t.md) 引擎都支持贴图功能,只要把 glyph\_t 转换成正常 bitmap\_t 对象,就可以利用 vgcanvas 各种变换效果了。
下面这个函数可以把字符串对应的 glyph 转换成位图对象(拿去用就好了):
```c
static bitmap_t* bitmap_from_str(canvas_t* canvas, wchar_t* str, color_t tc) {
glyph_t g;
uint32_t x = 0;
uint32_t y = 0;
uint32_t i = 0;
uint32_t w = 0;
uint32_t h = 0;
uint32_t ox = 0;
font_vmetrics_t vm;
uint32_t* p = NULL;
uint32_t baseline = 0;
bitmap_t* bitmap = NULL;
uint32_t font_size = canvas->font_size;
font_manager_t* fm = canvas->font_manager;
font_t* font = font_manager_get_font(fm, canvas->font_name, font_size);
return_value_if_fail(font != NULL, NULL);
vm = font_get_vmetrics(font, font_size);
h = vm.ascent - vm.descent;
return_value_if_fail(h > 0, NULL);
baseline = vm.ascent;
for (i = 0; str[i]; i++) {
return_value_if_fail(font_get_glyph(font, str[i], font_size, &g) == RET_OK, NULL);
w += g.advance + 1;
}
bitmap = bitmap_create_ex(w, h, 0, BITMAP_FMT_RGBA8888);
return_value_if_fail(bitmap != NULL, NULL);
p = (uint32_t*)bitmap_lock_buffer_for_write(bitmap);
memset(p, 0x00, w * h * 4);
for (i = 0; str[i]; i++) {
return_value_if_fail(font_get_glyph(font, str[i], font_size, &g) == RET_OK, NULL);
for (y = 0; y < g.h; y++) {
for (x = 0; x < g.w; x++) {
int32_t dx = ox + g.x + x;
int32_t dy = baseline + g.y + y;
uint32_t* d = p + dy * w + dx;
const uint8_t* s = g.data + y * g.w + x;
tc.rgba.a = *s;
*d = tc.color;
}
}
ox += g.advance + 1;
}
bitmap_unlock_buffer(bitmap);
bitmap->flags |= BITMAP_FLAG_CHANGED;
return bitmap;
}
```
然后?然后就和画图一样了:
```c
vgcanvas_save(vg);
vgcanvas_translate(vg, c->ox, c->oy);
vgcanvas_translate(vg, cx, cy);
vgcanvas_rotate(vg, info->rotation);
vgcanvas_scale(vg, info->scale, info->scale);
vgcanvas_translate(vg, -cx, -cy);
canvas_widget_draw_image_center(widget, vg, text_img);
vgcanvas_restore(vg);
```
完整代码请参考:[vgcanvas_draw_text](https://github.com/zlgopen/awtk-c-demos/blob/master/demos/vgcanvas_draw_text.c)
vgcanvas 的 API 基本上是参考 [HTML5 Canvas API](https://www.w3schools.com/tags/ref_canvas.asp) 定义的,这个 API 是我见过最好的 2D 绘图 API。不过[vgcanvas](https://github.com/zlgopen/awtk/blob/master/docs/manual/vgcanvas_t.md) 在没有 GPU 的情况下,性能远远不如 [canvas](https://github.com/zlgopen/awtk/blob/master/docs/manual/canvas_t.md),除非有旋转之类的特殊需求,尽量使用 [canvas](https://github.com/zlgopen/awtk/blob/master/docs/manual/canvas_t.md) 的 API。

View File

@ -0,0 +1,22 @@
# 如何用 edit 控件编辑日期
用 edit 控件编辑日期,将 edit 的 input\_type 指定为"date"即可。
* 基本用法
示例:
```xml
<edit w="70%" text="2020/10/10" tips="date" input_type="date"/
```
* 启用自动修正功能
示例:
```xml
<edit w="70%" text="" tips="date autofix" input_type="date" auto_fix="true"/>
```
参考:[input type](manual/input_type_t.md)

View File

@ -0,0 +1,22 @@
# 如何用 edit 控件编辑 IP 地址
用 edit 控件编辑 IP 地址,将 edit 的 input\_type 指定为"ipv4"即可。
* 基本用法
示例:
```xml
<edit w="70%" text="192.168.1.1" tips="ipv4" input_type="ipv4"/>
```
* 启用自动修正功能
示例:
```xml
<edit w="70%" text="192.168.1.1" tips="ipv4 autofix" input_type="ipv4" auto_fix="true"/>
```
参考:[input type](manual/input_type_t.md)

View File

@ -0,0 +1,24 @@
# 如何用 edit 控件编辑时间
用 edit 控件编辑时间,将 edit 的 input\_type 指定为"time"即可。
* 基本用法
示例:
```xml
<edit w="70%" text="12:16" tips="time" input_type="time"/>
```
* 启用自动修正功能
示例:
```xml
<edit w="70%" text="" tips="time autofix" input_type="time" auto_fix="true"/>
```
> time 只能输入时分,要输入时分秒请用 time\_full。
参考:[input type](manual/input_type_t.md)

View File

@ -0,0 +1,55 @@
# 如何启用文本双向排版 (Unicode Bidirectional Algorithm)
## 1. 启用文本双向排版算法
定义宏 WITH\_TEXT\_BIDI 即可,嵌入式版本请修改 awtk_config.h:
```c
/**
* 如果希望支持文字双向排版算法(如阿拉伯语言),请定义本宏。
*
* #define WITH_TEXT_BIDI 1
*
*/
```
>PC 版本默认已经定义。
### 2. 加入相关文件
```
3rd/fribidi/fribidi-arabic.c
3rd/fribidi/fribidi-bidi-types.c
3rd/fribidi/fribidi-bidi.c
3rd/fribidi/fribidi-brackets.c
3rd/fribidi/fribidi-deprecated.c
3rd/fribidi/fribidi-joining-types.c
3rd/fribidi/fribidi-joining.c
3rd/fribidi/fribidi-mirroring.c
3rd/fribidi/fribidi-run.c
3rd/fribidi/fribidi-shape.c
3rd/fribidi/fribidi.c
src/base/bidi.c
```
>PC 版本默认已经加。
### 3. 控件的 bidi 属性
默认情况下,文字的方向自动确定,如果在某些情况下,需要自己指定,可以通过 bidi 属性来实现。
示例:
```xml
<label text="1. جامعة كولومبيا عام." style:font_size="30" style:font_name="trado" bidi="lro"/>
```
bidi 的可选值有:
* rtl Right-To-Left letter。
* ltr Left-To-Right letter。
* auto Auto Detection
* wrtl Weak Right To Left paragraph。
* wltr Weak Left To Right paragraph。
* lro Left-To-Right letter Override。
* rlo Right-To-Left letter Override。

View File

@ -0,0 +1,34 @@
# 如何开启按键音
在有的应用程序中,按键和触屏时,需要给用户提供某种反馈:
* 反馈的方式通常是声音或震动。
* 声音的类型可能与当前的按键有关。比如拨号界面,按下不同的数字会播放不同的声音。
* 在同一个应用,不同场景的需求也可能不一样,所以需要全局开启或关闭反馈。
由于AWTK 本身没有提供震动和声音的接口,所以 AWTK 提供了一个 ui_feedback 接口,开发者可以设置回调函数,去播放声音或震动。
回调函数的原型和初始化函数如下:
```
typedef ret_t (*ui_on_feedback_t)(void* ctx, widget_t* widget, event_t* evt);
/**
* @method ui_feedback_init
* 初始化。
* 设置实际的处理函数。
*
* @annotation ["static"]
* @param {ui_on_feedback_t} on_feedback 实际的处理函数。
* @param {void*} ctx 回调函数的上下文。
*
* @return {ret_t} 返回RET_OK表示成功否则表示失败。
*/
ret_t ui_feedback_init(ui_on_feedback_t on_feedback, void* ctx);
```
通常只是部分控件需要提供反馈因此控件缺省情况下不提供反馈功能。需要把控件的feedback属性设置为TRUE当有按键(按下和弹起)和触屏事件(按下和弹起)发生在该控件上时,才会调用开发者设置的回调函数。
在回调函数中,开发者可以根据事件的类型、当前设置和控件的其它属性,来决定如何反馈。

View File

@ -0,0 +1,72 @@
# 如何启用鼠标指针
## 1. 启用鼠标指针
启用鼠标指针,需要定义宏 ENABLE\_CURSOR。
## 2. 控件的缺省鼠标指针
控件的缺省鼠标指针由 vtable 的 pointer_cursor 属性指定。如 edit 的鼠标指针:
```c
TK_DECL_VTABLE(edit) = {.size = sizeof(edit_t),
.type = WIDGET_TYPE_EDIT,
.focusable = TRUE,
.inputable = TRUE,
.pointer_cursor = WIDGET_CURSOR_EDIT,
.clone_properties = s_edit_properties,
.persistent_properties = s_edit_properties,
.parent = TK_PARENT_VTABLE(widget),
.create = edit_create,
.on_re_translate = edit_on_re_translate,
.on_paint_self = edit_on_paint_self,
.set_prop = edit_set_prop,
.get_prop = edit_get_prop,
.on_destroy = edit_on_destroy,
.on_copy = edit_on_copy,
.on_event = edit_on_event}
```
> 控件的缺省鼠标指针在 AWTK 内部写定了,开发者可以换图片来改变鼠标指针的形状。
## 3. 为单个控件指定鼠标指针。
为单个控件指定鼠标指针,只需要指定控件的 pointer_cursor 属性即可。如:
```xml
<label x="0" y="0" w="100%" h="100%" text="up/down key change focus" pointer_cursor="cursor_hand"/>
```
## 4. 等待状态的鼠标指针
下列两个函数用于开始和结束等待鼠标指针。
开始等待鼠标指针后:
* 如果 ignore\_user\_input 为 TRUE窗口忽略所有输入事件。
* 鼠标移动时不再自动切换鼠标指针。
```c
/**
* @method widget_begin_wait_pointer_cursor
* 开始等待鼠标指针。
* @param {widget_t*} widget 控件对象。
* @param {bool_t} ignore_user_input 是否忽略用户输入。
*
* @return {ret_t} 返回 RET_OK 表示成功,否则表示失败。
*/
ret_t widget_begin_wait_pointer_cursor(widget_t* widget, bool_t ignore_user_input);
/**
* @method widget_end_wait_pointer_cursor
* 结束等待鼠标指针。
* @param {widget_t*} widget 控件对象。
*
* @return {ret_t} 返回 RET_OK 表示成功,否则表示失败。
*/
ret_t widget_begin_end_pointer_cursor(widget_t* widget);
```
[完整实例](https://github.com/zlgopen/awtk-c-demos/blob/master/demos/wait_cursor.c)

View File

@ -0,0 +1,17 @@
# 如何隐藏滚动条的上下按钮
在 design/default/styles/default.xml 中,去掉 scroll\_down/scroll\_up 按钮的 style 即可:
```xml
<style name="scroll_down" border_color="#a0a0a0">
<normal bg_color="#f0f0f0" icon="arrow_down_n"/>
<pressed bg_color="#c0c0c0" icon="arrow_down_p"/>
<over bg_color="#e0e0e0" icon="arrow_down_o"/>
</style>
<style name="scroll_up" border_color="#a0a0a0">
<normal bg_color="#f0f0f0" icon="arrow_up_n"/>
<pressed bg_color="#c0c0c0" icon="arrow_up_p"/>
<over bg_color="#e0e0e0" icon="arrow_up_o"/>
</style>
```

View File

@ -0,0 +1,36 @@
# 如何实现"back"键和"home"键
* **back 键** 关闭当前窗口,回到上一级窗口。
* **home 键** 回到第一个主窗口,并关闭之上的全部窗口。
1. 编写事件处理函数。
```
static ret_t on_key_back_or_back_to_home(void* ctx, event_t* e) {
key_event_t* evt = (key_event_t*)e;
if (evt->key == TK_KEY_F2) {
window_manager_back(WIDGET(ctx));
} else if (evt->key == TK_KEY_F3) {
window_manager_back_to_home(WIDGET(ctx));
}
return RET_OK;
}
```
2. 注册窗口管理器的按键事件处理函数:
```
widget_t* wm = window_manager();
widget_on(wm, EVT_KEY_DOWN, on_key_back_or_back_to_home, wm);
```
3. 把主窗口设置为不可关闭:
```
widget_set_prop_str(win, WIDGET_PROP_CLOSABLE, "no");
```
请参考完整示例:[multi_windows.c](https://github.com/zlgopen/awtk-c-demos/blob/master/demos/multi_windows.c)
如果在关闭窗口前,需要用户确认,请参考:[system_bar.md](https://github.com/zlgopen/awtk/blob/master/docs/system_bar.md)

View File

@ -0,0 +1,66 @@
# 如何实现自定义的软键盘
有时需要把软键盘嵌入到窗口内部(比如计算器和密码输入等),这时可以使用自定义软键盘。
### 一、编辑器设置 input_type 为"custom"(它会禁止内置的软键盘)。
```
<edit x="c" y="10" w="90%" h="30" focused="true" input_type="custom" text="" />
```
> 如果希望初始化时编辑器自动获的焦点,可以设置 focused 为 true。
### 二、软键盘的按钮放入一个 view任何容器控件均可并将 view 的 is\_keyboard 设置为 true。
```
<view y="60" x="c" w="90%" h="-60" is_keyboard="true"
children_layout="default(r=4,c=4,m=5,s=5)" >
<button name="key" text="0" />
<button name="key" text="1" />
<button name="key" text="2" />
<button name="key" text="3" />
<button name="key" text="4" />
<button name="key" text="5" />
<button name="key" text="6" />
<button name="key" text="7" />
<button name="key" text="8" />
<button name="key" text="9" />
<button name="key" text="#" />
<button name="backspace" text="<=" />
</view>
```
### 三、处理按钮事件
#### 1. 处理正常按键
```
static ret_t on_send_key(void* ctx, event_t* e) {
widget_t* button = WIDGET(e->target);
char text[2];
text[0] = (char)button->text.str[0];
text[1] = '\0';
input_method_commit_text(input_method(), text);
return RET_OK;
}
```
#### 2. 处理删除键
```
static ret_t on_backspace(void* ctx, event_t* e) {
input_method_dispatch_key(input_method(), TK_KEY_BACKSPACE);
return RET_OK;
}
```
>如果你不希望出现编辑器的光标,可以使用 label 控件代替 edit 控件,输入和删除时直接操作 label 的 text。
参考:
* [demo\_ui\_app.c](https://github.com/zlgopen/awtk/blob/master/demos/demo_ui_app.c)
* [soft\_keyboard.xml](https://github.com/zlgopen/awtk/blob/master/design/default/ui/soft_keyboard.xml)

View File

@ -0,0 +1,5 @@
# 如何实现弹出菜单
弹出菜单就是一个 popup 窗口,只是需要用 [menu 自身布局器](https://github.com/zlgopen/awtk/blob/master/docs/self_layouter_menu.md) 指定窗口弹出的位置。
完整示例请参考:[popup_menu](https://github.com/zlgopen/awtk-c-demos/blob/master/demos/popup_menu.c)

View File

@ -0,0 +1,25 @@
# 如何修改 stb\_truetype 获取字模时申请的缓冲区大小
stb\_truetype 是一个用来解析 ttf 字体文件的开源库,功能强大,体积小巧。
在 AWTK 中,使用 AGGE 渲染模式时,默认采用 stb\_truetype 解析 ttf 字体文件(实际上由宏 WITH\_STB\_FONT 决定)。
stb\_truetype 在获取字模时,会 malloc 一块缓冲区保存字模位图中每行像素的变化信息生成字模后该缓冲区被释放由于频繁申请释放内存容易产生内存碎片因此AWTK 默认设置该缓冲区大小约为 11 KB。
若由于内存不足 stb\_truetype 获取字模失败,则会打印以下提示信息:
```
STBTT get glyph failed : Cannot allocate memory!
```
此时,用户可通过定义宏 STBTT\_MAX\_SCANLINE\_EDGES 来设置缓冲区大小,该宏表示字模位图中每行像素的变化信息的最大数量,比如一个宽为 1000 像素的字模,如果它的某一行每个像素点都在变化,那么最大值则为 1000此时可设置该宏为 1000代码如下
```c
#define STBTT_MAX_SCANLINE_EDGES 1000 //缓冲区大小约为 1000 * 28 字节(约 27KB
```
当设置宏 STBTT\_MAX\_SCANLINE\_EDGES 为 0 时stb\_truetype 的缓冲区将动态扩张,但容易产生内存碎片,代码如下:
```c
#define STBTT_MAX_SCANLINE_EDGES 0 //缓冲区将动态扩张
```

View File

@ -0,0 +1,125 @@
## 如何在非 GUI 线程操作 GUI 控件
GUI 控件只能在 GUI 线程进行操作,非 GUI 线程想操作 GUI 控件,必须用以下函数进行串行化。
### 1. idle\_queue
idle\_queue 向主循环的事件队列提交一个增加 idle 的请求GUI 线程的主循环在处理事件队列时,会把该 idle 函数放到 idle 管理器中,在分发 idle 时,该 idle 函数在 GUI 线程执行。
```c
/**
* @method idle_queue
* 用于非 GUI 线程增加一个 idle本函数向主循环的事件队列中发送一个增加 idle 的请求。
* @annotation ["static"]
* @param {idle_func_t} on_idle idle 回调函数。
* @param {void*} ctx idle 回调函数的上下文。
*
* @return {ret_t} 返回 RET_OK 表示成功,否则表示失败。
*/
ret_t idle_queue(idle_func_t on_idle, void* ctx);
```
> on\_idle 函数返回 RET\_REPEAT 时,将重复执行。
### 2. timer\_queue
timer\_queue 向主循环的事件队列提交一个增加 timer 的请求GUI 线程的主循环在处理事件队列时,会把该 timer 函数放到 timer 管理器中,在分发 timer 时,该 timer 函数在 GUI 线程执行。
```c
/**
* @method timer_queue
* 用于非 GUI 线程增加一个 timer本函数向主循环的事件队列中发送一个增加 timer 的请求。
* @annotation ["static"]
* @param {timer_func_t} on_timer
* timer 回调函数,回调函数返回 RET_REPEAT则下次继续执行否则自动移出。
* @param {void*} ctx timer 回调函数的上下文。
* @param {uint32_t} duration 时间。
*
* @return {ret_t} 返回 RET_OK 表示成功,否则表示失败。
*/
ret_t timer_queue(timer_func_t on_timer, void* ctx, uint32_t duration);
```
> on\_timer 函数返回 RET\_REPEAT 时,将重复执行。
### 3. tk\_run\_in\_ui\_thread
tk\_run\_in\_ui\_thread 让后台线程在 UI 线程执行指定的函数,它是对 idle\_queue 的包装,支持等待调用完成。
```c
/**
* @method tk_run_in_ui_thread
* 后台线程在 UI 线程执行指定的函数。
*
* @param {tk_callback_t} func 函数。
* @param {void*} ctx 回调函数的上下文。
* @param {bool_t} wait_until_done 是否等待完成。
*
* @return {ret_t} 返回 RET_OK 表示成功,否则表示失败。
*/
ret_t tk_run_in_ui_thread(tk_callback_t func, void* ctx, bool_t wait_until_done)
```
> 如果 wait\_until\_done 为 FALSEfunc 函数返回 RET\_REPEAT 时,将重复执行。
> 注意:以上是少数几个可以在非 GUI 线程安全调用的函数,请不要在非 GUI 线程调用其它 widget 相关的函数。
### 示例:
```c
void* test_thread1(void* args) {
int nr = 500000;
while ((nr-- > 0) && (!s_app_quit)) {
tk_run_in_ui_thread((tk_callback_t)update_progress_bar, args, TRUE);
sleep_ms(30);
}
return NULL;
}
void* test_thread2(void* args) {
int nr = 500000;
while ((nr-- > 0) && (!s_app_quit)) {
tk_run_in_ui_thread((tk_callback_t)update_progress_bar, args, FALSE);
sleep_ms(30);
}
return NULL;
}
static ret_t on_idle(const idle_info_t* idle) {
return update_progress_bar(WIDGET(idle->ctx));
}
void* test_thread3(void* args) {
int nr = 500000;
while ((nr-- > 0) && (!s_app_quit)) {
idle_queue(on_idle, args);
sleep_ms(30);
}
return NULL;
}
static ret_t on_timer(const timer_info_t* timer) {
return update_progress_bar(WIDGET(timer->ctx));
}
void* test_thread4(void* args) {
int nr = 500000;
while ((nr-- > 0) && (!s_app_quit)) {
timer_queue(on_timer, args, 30);
sleep_ms(30);
}
return NULL;
}
```
### 参考
> demos/demo\_thread\_app.c
### 注意事项
* 在 idle 函数执行的时候,窗口可能已经被关闭,控件已经处于无效状态。为了避免出现也指针的问题,在 idle 函数中,应该检查目标窗口和控件是否存在。

View File

@ -0,0 +1,70 @@
# 为 512K Flash 优化空间
## 背景
* 缺省情况下demo1 在 STMF103 上的空间占用情况如下。
```
Program Size: Code=222780 RO-data=232212 RW-data=720 ZI-data=53440
```
对于只用 512K Flash 的平台来说,给应用程序留下的空间就比较少了,这里介绍一下进一步优化空间方法:
## AWTK 优化
* 1. 将编译器的优化级别提高一级 (O1):
可以优化掉 30K 左右的空间:
```
Program Size: Code=193658 RO-data=232214 RW-data=720 ZI-data=53440
```
* 2. 去掉 Unicode 换行算法的支持。
修改 awtk\_config.h 文件,去掉 WITH\_UNICODE\_BREAK 的定义。
```c
//#define WITH_UNICODE_BREAK 1
```
可以优化掉 50K 左右的空间:
```
Program Size: Code=190338 RO-data=186674 RW-data=400 ZI-data=53440
```
* 3. 去掉不必要的 bitmap 格式
对于 BGR565 格式的 LCD修改 awtk\_config.h 文件,增加下面的宏定义
```c
/**
* 对于只有 512K flash 的平台,而且 LCD 格式是 BGR565。如果希望进一步优化空间去掉多余的 bitmap 格式支持代码。请定义本宏。
* 其它 LCD 格式可以自行修改src/blend/soft_g2d.c 保留需要的格式即可。
*
*/
#define LCD_BGR565_LITE 1
```
可以优化掉 30K 左右的空间:
```
Program Size: Code=163602 RO-data=186498 RW-data=400 ZI-data=53440
```
* 4. 将编译器的优化级别提高一级 (O2):
可以优化掉 10K 左右的空间:
```
Program Size: Code=149510 RO-data=186494 RW-data=400 ZI-data=53440
```
* 5. 去掉不需要的控件:
最多可以优化掉 20K 左右的空间
## APP 优化
* 设计界面时不要使用 inline 样式。使用共享样式,可以减少 RAM 和 Flash 的空间。

View File

@ -0,0 +1,13 @@
# 如何将生成的可执行文件和资源打包
在开发完成后通常需要将可执行文件和运行时需要的资源拷贝出来发给客户或放到板子上运行。AWTK 提供了一个脚本 scripts/release.py将可执行文件和运行时需要的资源拷贝出来放到当前目录的 release 子目录下。用法如下:
假如当前项目是 awtk-hello在 awtk-hello 目录中运行下面的命令:
```
python ../awtk/scripts/release.py hello_awtk.exe
```
> Linux/MacOS/LinuxFB 不能带 .exe 扩展名。
> 本脚本适用于 Linux、Windows、MacOS、Linux_FB不适用于其它嵌入式系统。对于其它嵌入式系统本脚本可以将运行时需要的资源拷贝出来放到开发板的 T 卡上,自己删除 release/bin 目录即可。

View File

@ -0,0 +1,22 @@
# 如何续期使用 AWTK Designer
因 AWTK Designer 许可证有使用期限,如果许可证到期了,将无法继续使用 AWTK Designer。如需继续使用 AWTK Designer可按下面步骤完成许可证续期
##### 1、登录 AWTK 云平台: https://awtk.zlg.cn 。
##### 2、完善个人信息。
在 AWTK 云平台的 “个人信息” 页面绑定好邮箱,并完整填写真实有效的公司信息,通过管理员审核后将有机会定期获赠 Designer 续期卡券,获得卡券后可以对 Designer 进行许可证续期。
![](images/awtk_cloud_platform_info_page.png)
##### 3、点击 “许可管理” 页面中的 “续期” 按钮,完成续期。
![](images/awtk_cloud_platform_license_page.png)
> 欲了解更多信息请参阅AWTK Designer 安装目录、Docs 文件夹下的文档:
> - 《AWTK Designer 快速安装指南。pdf》
> - 《AWTK Designer 快速使用指南。pdf》
> - 《AWTK Designer 用户手册。pdf》

View File

@ -0,0 +1,13 @@
# 如何设置字体的全局缩放比例
有时需要支持 Accessibility要求对字体进行全局缩放以便实现"大字体"和"小字体"的选项。在 AWTK 中,可以调用函数 system\_info\_set\_font\_scale 来实现。
```
system_info_set_font_scale(system_info(), font_scale);
```
font\_scale 的取值:
* 1 表示正常大小。
* 大于 1 表示放大。
* 小于 1 表示缩小。

View File

@ -0,0 +1,80 @@
# 如何让文本滚动起来
在很多时候,特别是在小屏幕的硬件上,控件比较小而要显示的文本比较长。
此时,我们需要在控件获得焦点时/或点击时,让文本滚动起来,以便让用户看到完整的信息。
AWTK 提供了 hscroll\_label\_t 控件,可以轻松满足文本滚动的需求。
## 一、基本用法
示例:
```
<window anim_hint="htranslate" text="hscroll_label" children_layout="default(c=1,h=30,xm=10,s=5)">
<hscroll_label text="炫酷的 GUI 引擎。" />
<hscroll_label text="炫酷的 GUI 引擎。" style="right"/>
<hscroll_label
lull="1000"
loop="true"
yoyo="true"
ellipses="true"
focusable="true"
text="(always ellipses loop yoyo) 为用户提供一个功能强大、高效可靠、简单易用、可轻松做出炫酷效果的 GUI 引擎。" />
<hscroll_label
focusable="true"
only_focus="true"
text="(only_focus noloop) 为用户提供一个功能强大、高效可靠、简单易用、可轻松做出炫酷效果的 GUI 引擎。" />
<hscroll_label
loop="true"
ellipses="true"
focusable="true"
only_focus="true"
text="(only_focus ellipses loop) 为用户提供一个功能强大、高效可靠、简单易用、可轻松做出炫酷效果的 GUI 引擎。" />
<hscroll_label
style="green"
loop="true"
yoyo="true"
ellipses="true"
focusable="true"
only_focus="true"
text="(only_focus ellipses loop yoyo) 为用户提供一个功能强大、高效可靠、简单易用、可轻松做出炫酷效果的 GUI 引擎。" />
</window>
```
## 二、扩展用法
但有时用的不是单纯的文本控件,而是列表项、多选按钮、单选按钮或其它功能的控件,那该怎么办呢?
其实也很简单,把 hscroll\_label 作为该控件的子控件,并指定 only\_parent\_focus 属性为 true 即可。
示例:
```
<window anim_hint="htranslate" move_focus_prev_key="up" move_focus_next_key="down" text="Basic Controls">
<row x="0" y="180" w="-50" h="90" children_layout="default(r=1,c=2,m=2)">
<column children_layout="default(r=3,c=1,ym=2,s=10)" >
<check_button name="r1" focusable="true" >
<hscroll_label style="green" only_parent_focus="true" x="right" y="middle" w="-30" h="100%"
text="1.AWTK 为用户提供一个功能强大、高效可靠、简单易用、可轻松做出炫酷效果的 GUI 引擎。" />
</check_button>
<check_button name="r2" focusable="true">
<hscroll_label style="green" only_parent_focus="true" x="right" y="middle" w="-30" h="100%"
text="2.AWTK 为用户提供一个功能强大、高效可靠、简单易用、可轻松做出炫酷效果的 GUI 引擎。" />
</check_button>
<check_button name="r3" value="true" focusable="true">
<hscroll_label style="green" only_parent_focus="true" x="right" y="middle" w="-30" h="100%"
text="3.AWTK 为用户提供一个功能强大、高效可靠、简单易用、可轻松做出炫酷效果的 GUI 引擎。" />
</check_button>
</column>
</row>
</window>
```

View File

@ -0,0 +1,68 @@
# 如何支持极简键盘 (3 键键盘、5 键键盘和旋转按钮)
## 背景
在有的硬件上,没有触摸/鼠标等指针设备,只有极简的键盘,典型情况如下
* 3 键键盘(回车键+上下键),旋转按钮也可以归为此类,左右旋转映射成上下键。有些变种带有数字键和功能键也归于此类。
* 5 键键盘(回车键+上下左右键)。有些变种带有数字键和功能键也归于此类。
对于上面的情况,方向键既要用于导航(切换焦点),又要用于控件输入数据,所以需要引入一种状态(或称为模式):
* 在移动焦点的状态:方向键用于切换焦点。
* 在非移动焦点的状态:方向键用于修改控件的值。
回车的作用:
* 在按钮等支持用回车键激活的控件上,用于激活按钮,相当于点击事件。
* 在编辑器等控件上,用于切换状态,用于改变方向键的作用。
## 用法
AWTK 对此做了内置的支持,使用方法如下,在初始化时指定键盘的类型即可。
```c
ret_t application_init() {
system_info_set_keyboard_type(system_info(), KEYBOARD_5KEYS);
return RET_OK;
}
```
键盘类型的定义:
```c
/**
* @enum keyboard_type_t
* 键盘的类型
*/
typedef enum _keyboard_type_t {
/**
* @const KEYBOARD_NONE
* 无键盘。
*/
KEYBOARD_NONE = 0,
/**
* @const KEYBOARD_NORMAL
* 正常键盘。
*/
KEYBOARD_NORMAL,
/**
* @const KEYBOARD_3KEYS
* 3 键 (RETURN+上下键,附加数字键等)。
* > RETURN 键用于切换模式:焦点模式下,上下键用于切换焦点,非焦点模式下,上下键用于切修改控件的值。
*/
KEYBOARD_3KEYS,
/**
* @const KEYBOARD_5KEYS
* 5 键 (RETURN+上下左右键,附加数字键等)。
* > RETURN 键用于切换模式:焦点模式下,上下键用于切换焦点,非焦点模式下,上下键用于切修改控件的值。
*/
KEYBOARD_5KEYS
} keyboard_type_t;
```

View File

@ -0,0 +1,75 @@
# 支持单色 LCD
## lcd_mono 实现
src/lcd/lcd_mono.c 提供单色 LCD 的 framebuffer每个像素占用一个比特实现了 LCD 的基本绘制函数,在使用时调用者需要提供 flush 函数,负责把脏矩形内的像素提交到 LCD 硬件。
## 模拟器
在 awtk_config.py 中可以打开单色 LCD 的配置。
```
LCD='SDL_FB_MONO'
```
## 单色字体生成
字体生成工具 fontgen 支持生成单色字体,加上可选参数 mono 即可。
```
fontgen.exe ttf_filename str_filename out_filename font_size [mono]
```
## 单色图片生成
图片生成工具 imagegen 支持生成单色图片,加上可选参数 mono 即可。
```
imagegen.exe in_filename out_filename (bgra|bgr565|mono)
```
> 由于单色图片只有两种颜色,所以在设计图片上只能使用白色 (#ffffff) 和黑色 (#000000),否则转换出来的效果不是期望的。
## 窗体样式配置
窗体样式中只能使用白色 (#ffffff) 和黑色 (#000000) 两种颜色。
## 资源生成
生成资源时需要加上 mono 参数,该参数会被传递给 fontgen 和 imagegen。
```
python scripts/update_res.py all x1 mono
```
## 应用程序
应用程序 UI 设计请考虑单色 LCD 的特殊性。
> demoui 没有考虑单色 LCD在单色 LCD 上运行效果不佳。
## 预览 mono test 查看运行效果
```
./bin/preview_ui design/default/ui/mono_test.xml
```
## 其它
* 嵌入式系统,请在 awtk\_config.h 中定义下面的宏。
```
#define WITH_LCD_MONO 1
```
* awtk-linux-fb请在 awtk\_config.py 中定义下面的宏。
```
COMMON_CCFLAGS = COMMON_CCFLAGS + ' -DWITH_LCD_MONO=1 '
```
## 参考:
* [免费像素字体](https://www.uisdc.com/25-pixel-fonts)
* [Unifont 点阵黑:一款超大字符集免费商用像素字体](https://www.maoken.com/freefonts/3747.html)

View File

@ -0,0 +1,41 @@
# AWTK 内存分配器支持多块不连续的内存。
在嵌入式系统中可能有多块不连续的内存。AWTK 最新版本支持管理多个不连续的内存块。使用方法如下:
* 定义内存块数目
> 在 awtk\_config.h 中定义:
```c
#define TK_MAX_MEM_BLOCK_NR 3
```
* 初始化内存
> 需要使用 tk\_mem\_init\_ex 代替 tk\_mem\_init 初始化内存。一般将大块放到前面,小块放到后面。也可以将速度快的内存放到前面,将速度慢的放到后面。
```c
/**
* @method tk_mem_init_ex
* @export none
* 初始化内存,支持多块不连续的内存。
* >最后一个参数必须为NULL。
*
* 示例:
* ```c
* tk_mem_init_ex(mem1, sizeof(mem1), mem2, sizeof(mem2), mem3, sizeof(mem3), NULL);
* ```
*
* @param {void*} buffer 内存地址。
* @param {uint32_t} size 内存长度。
*
* @return {ret_t} 返回RET_OK表示成功否则表示失败。
*/
ret_t tk_mem_init_ex(void* buffer, uint32_t size, ...);
```
示例:
```c
tk_mem_init_ex(mem1, sizeof(mem1), mem2, sizeof(mem2), mem3, sizeof(mem3), NULL);
```

View File

@ -0,0 +1,35 @@
# 如何更新拼音输入法字典和联想字库
有的情况下,可能需要自己更新拼音输入法字典和联想词库。比如:
* 使用更好的字典数据。
* 去掉一些不需要的汉字。
* 使用更完善的联想字库。
## 1.更新拼音输入法字典
### 1.1 根据自己的需要编辑下列文件:
* 3rd/gpinyin/data/rawdict\_utf16\_65105\_freq.txt
* 3rd/gpinyin/data/valid\_utf16.txt
### 1.2 重新生成数据
```
./bin/gpinyingen
```
### 1.3 拷贝3rd/gpinyin/data/gpinyin.dat到资源目录的data目录。
```
cp 3rd/gpinyin/data/gpinyin.dat design/default/data/gpinyin.dat
```
## 2.更新联想词库
联想词库是抓取网页通过分词工具自动生成的。请参考tools/word_gen/README.md

View File

@ -0,0 +1,78 @@
# 如何引用第三方库
使用第三方库时,在应用程序的 SConstruct 中描述依赖关系即可。具体方式为:先定义依赖描述,再调用 set_deps 将依赖描述设置到 helper 里。
示例:
```python
DEPENDS_LIBS = [
{
"root" : '../awtk-mvvm',
'shared_libs': ['mvvm'],
'static_libs': []
},
{
"root" : '../awtk-restful-httpd',
'shared_libs': ['httpd'],
'static_libs': []
}
]
helper.set_deps(DEPENDS_LIBS)
```
> 注意helper.set\_deps 一定要在 helper.call 之前调用。
## 依赖描述内容
* root 第三方库的根目录。建议使用相对于应用程序的相对路径。
如:
```
"root" : '../awtk-mvvm',
```
* shared_libs 第三方库提供的共享库列表(数组),不带扩展名和 lib 前缀。
如:
```
"shared_libs" : ["a","b","c"]
```
* static_libs 第三方库提供的静态库库列表(数组),不带扩展名和 lib 前缀。
如:
```
"static_libs" : ["a","b","c"]
```
* libpath 库所在的路径,相对于前面指定的 root 路径。缺省为:["lib", "bin"]
如:
```
"libpath" : ["libs", "bin"]
```
* cpppath 头文件所在的路径,相对于前面指定的 root 路径。缺省为:["src"]
如:
```
"cpppath" : ["includes", "src"]
```
* cflags C 语言的 flags 定义(可选)。
如:
```
"cflags" : " -DNDEBUG=1 "
```
* cxxflags C++语言的 flags 定义(可选)。
* ccflags C/C++语言的 flags 定义(可选)。
## 完整示例
* [awtk-mvvm-c-hello](https://github.com/zlgopen/awtk-mvvm-c-hello/blob/master/SConstruct)

Some files were not shown because too many files have changed in this diff Show More