This commit is contained in:
jim 2018-03-12 21:24:24 +08:00
parent 73b8e1a3d0
commit 79cde3f835
7 changed files with 216 additions and 27 deletions

View File

@ -78,6 +78,7 @@ demos\demo1
## 文档
* [LFTK脚本绑定的实现原理 - lua绑定](docs/binding_lua.md)
* [LFTK控件的布局参数介绍](docs/layout.md)
## 任务完成情况
[TODO.md](TODO.md)

176
docs/layout.md Normal file
View File

@ -0,0 +1,176 @@
# LFTK控件的布局参数
## 一、为什么需要布局参数
如果界面上元素是预先知道的,而且窗口的大小也是固定的,通过可视化的工具,以所见即所得的方式,去创建界面是最轻松的方式。但是在下列情况下,使用布局参数却是更好的选择。
* 窗口的大小可以动态调整的。
* 需要适应不同大小的屏幕。
* 界面上的元素是动态的,需要用程序创建界面。
[LFTK](https://github.com/xianjimli/lftk)提供了简单而又强大的布局参数。
## 二、控件自身的布局参数
### 0. 像素
直接指定控件的x/y/w/h的像素值这是缺省的方式也是最缺乏灵活性的方式。
示例:
* 在XML界面描述文件中
```
<button x="10" y="5" w="80" h="30" text="ok"/>
```
* 在代码中:
```
widget_move_resize(btn, 10, 5, 80, 30);
```
### 1. 百分比
* x/w的值如果包含"%",则自动换算成相对其父控件宽度的百分比。
* y/h的值如果包含"%",则自动换算成相对其父控件高度的百分比。
示例:
* 在XML界面描述文件中
```
<button x="10%" y="10" w="50%" h="30" text="ok"/>
```
* 在代码中(看起来要麻烦一点)
```
widget_set_self_layout_params(btn, "10%", "10", "50%", "30");
widget_layout(btn);
```
> 在代码中设置控件的布局参数,方法类似,后面就不再举例子了。
### 2. 水平居中
让控件在水平方向上居中只需要将x的值设置成"c"或者"center"即可。
示例:
```
<button x="center" y="10" w="50%" h="30" text="ok"/>
```
### 3. 垂直居中
让控件在垂直方向上居中只需要将y的值设置成"m"或者"middle"即可。
示例:
```
<button x="center" y="middle" w="50%" h="30" text="ok"/>
```
### 4. 位于右边
让控件位于父控件的右侧只需要将x的值设置成"right"即可。
示例:
```
<button x="right" y="10" w="50%" h="30" text="ok"/>
```
如果还想离右侧有一定距离可以在right后指定距离的像素。
示例:
```
<button x="right:20" y="10" w="50%" h="30" text="ok"/>
```
### 5. 位于底部
让控件位于父控件的底部只需要将y的值设置成"bottom"即可。
示例:
```
<button x="10" y="bottom" w="50%" h="30" text="ok"/>
```
如果还想离底部有一定距离可以在bottom后指定距离的像素。
示例:
```
<button x="10" y="bottom:20" w="50%" h="30" text="ok"/>
```
## 三、子控件的布局参数
为了方便父控件布局子控件LFTK提供了下面4个参数
* rows 行数
* cols 列数
* margin 边距
* cell_spacing 子控件之间的间距
在代码中,可以通过下面的函数设置这几个参数:
```
ret_t widget_set_children_layout_params(widget_t* widget, uint8_t rows, uint8_t cols, uint8_t margin, uint8_t cell_spacing);
```
在XML中可以通过layout设置这几个参数:
```
<group_box x="0" y="140" w="100%" h="90" layout="2 2 10 5">
<button x="0" y="0" w="0" h="0" text="button"/>
<button x="0" y="0" w="0" h="0" text="button"/>
<button x="0" y="0" w="0" h="0" text="button"/>
<button x="0" y="0" w="0" h="0" text="button"/>
</group_box>
```
下面我们看看如何调整rows/cols两个参数来实现不同的布局方式。
### 0. 缺省
在没有设置子控件布局参数或者rows/cols都为0时采用缺省的布局方式父控件啥事也不做完全有子控件自己的布局参数决定。
### 1. hbox
当rows=1,cols=0时所有子控件在水平方向排成一行可以实现其它GUI中hbox的功能。子控件的参数
* x 从左到右排列,由布局参数计算而出。
* y 为margin
* w 由子控件自己决定。
* h 为父控件的高度-2*margin
### 2. vbox
当cols=1,rows=0时所有子控件在垂直方向排成一列可以实现其它GUI中vbox的功能。子控件的参数
* x 为margin
* y 从上到下排列,由布局参数计算而出。
* w 为父控件的宽度-2*margin
* h 由子控件自己决定。
### 3. listbox
当cols=1,rows=N时所有子控件在垂直方向排成一列可以实现其它GUI中listbox的功能。子控件的参数
* x 为margin
* y 从上到下排列,由布局参数计算而出。
* w 为父控件的宽度-2*margin
* h 为父控件的高度(减去边距和间距)分成成N等分。
### 4. grid
当cols=N,rows=N时所有子控件放在NxN的网格中可以实现其它GUI中grid的功能。
> demos/layouts中有演示各种布局参数的示例可以用下面的命令运行起来看看
```
./demos/prefix_xml_ui demos/layouts/demo2.xml
```

7
docs/optimation.md Normal file
View File

@ -0,0 +1,7 @@
## LFTK中显示优化技术
### 一、裁剪
### 二、脏矩形
### 三、极速模式

View File

@ -158,7 +158,7 @@ ret_t widget_layout_calc(const widget_layout_t* layout, rect_t* r, wh_t parent_w
return RET_OK;
}
ret_t widget_set_self_layout_params(widget_t* widget, const widget_layout_t* layout) {
ret_t widget_set_parsed_self_layout_params(widget_t* widget, const widget_layout_t* layout) {
return_value_if_fail(widget != NULL && layout != NULL, RET_BAD_PARAMS);
if (widget->layout_params == NULL) {
widget->layout_params = MEM_ZALLOC(layout_params_t);
@ -169,6 +169,14 @@ ret_t widget_set_self_layout_params(widget_t* widget, const widget_layout_t* lay
return RET_OK;
}
ret_t widget_set_self_layout_params(widget_t* widget, const char* x, const char* y, const char* w, const char* h) {
widget_layout_t layout;
return_value_if_fail(widget != NULL && x != NULL && y != NULL && w != NULL && h!= NULL, RET_BAD_PARAMS);
widget_layout_parse(&layout, x, y, w, h);
return widget_set_parsed_self_layout_params(widget, &layout);
}
ret_t widget_set_children_layout_params(widget_t* widget, uint8_t rows, uint8_t cols,
uint8_t margin,
uint8_t cell_spacing) {

View File

@ -32,7 +32,8 @@ ret_t widget_layout_calc(const widget_layout_t* layout, rect_t* r, wh_t parent_w
widget_layout_t* widget_layout_parse(widget_layout_t* layout, const char* x, const char* y, const char* w, const char* h);
children_layout_t* children_layout_parser(children_layout_t* layout, const char* params);
ret_t widget_set_self_layout_params(widget_t* widget, const widget_layout_t* layout);
ret_t widget_set_parsed_self_layout_params(widget_t* widget, const widget_layout_t* layout);
ret_t widget_set_self_layout_params(widget_t* widget, const char* x, const char* y, const char* w, const char* h);
ret_t widget_set_children_layout_params(widget_t* widget, uint8_t rows, uint8_t cols, uint8_t margin, uint8_t cell_spacing);
ret_t widget_layout(widget_t* widget);

View File

@ -93,7 +93,7 @@ static ret_t ui_builder_default_on_widget_start(ui_builder_t* b, const widget_de
}
if(layout->x_attr != X_ATTR_DEFAULT || layout->y_attr != Y_ATTR_DEFAULT || layout->w_attr == W_ATTR_PIXEL || layout->h_attr == H_ATTR_PIXEL) {
widget_set_self_layout_params(widget, layout);
widget_set_parsed_self_layout_params(widget, layout);
}
b->widget = widget;

View File

@ -23,7 +23,6 @@ TEST(Layuout, basic) {
}
TEST(Layuout, fill) {
rect_t r;
widget_layout_t layout;
ASSERT_EQ(widget_layout_parse(&layout, "1", "2", "fill", "fill"), &layout);
ASSERT_EQ(layout.w_attr, W_ATTR_FILL);
@ -121,23 +120,23 @@ TEST(Layuout, layout_children_null) {
widget_t* g2 = group_box_create(win, 0, 0, 0, 0);
widget_t* g3 = group_box_create(win, 0, 0, 0, 0);
widget_set_self_layout_params(g1, widget_layout_parse(&layout, "1", "2", "3", "4"));
widget_set_parsed_self_layout_params(g1, widget_layout_parse(&layout, "1", "2", "3", "4"));
widget_layout(win);
ASSERT_EQ(g1->x, 1);
ASSERT_EQ(g1->y, 2);
ASSERT_EQ(g1->w, 3);
ASSERT_EQ(g1->h, 4);
widget_set_self_layout_params(g1, widget_layout_parse(&layout, "0", "0", "10", "4"));
widget_set_self_layout_params(g2, widget_layout_parse(&layout, "0", "0", "fill", "4"));
widget_set_self_layout_params(g3, widget_layout_parse(&layout, "100", "0", "3", "4"));
widget_set_parsed_self_layout_params(g1, widget_layout_parse(&layout, "0", "0", "10", "4"));
widget_set_parsed_self_layout_params(g2, widget_layout_parse(&layout, "0", "0", "fill", "4"));
widget_set_parsed_self_layout_params(g3, widget_layout_parse(&layout, "100", "0", "3", "4"));
widget_layout(win);
ASSERT_EQ(g2->x, 10);
ASSERT_EQ(g2->w, 90);
widget_set_self_layout_params(g1, widget_layout_parse(&layout, "0", "0", "10", "20"));
widget_set_self_layout_params(g2, widget_layout_parse(&layout, "0", "0", "4", "fill"));
widget_set_self_layout_params(g3, widget_layout_parse(&layout, "100", "160", "3", "4"));
widget_set_parsed_self_layout_params(g1, widget_layout_parse(&layout, "0", "0", "10", "20"));
widget_set_parsed_self_layout_params(g2, widget_layout_parse(&layout, "0", "0", "4", "fill"));
widget_set_parsed_self_layout_params(g3, widget_layout_parse(&layout, "100", "160", "3", "4"));
widget_layout(win);
ASSERT_EQ(g2->y, 20);
ASSERT_EQ(g2->h, 140);
@ -153,16 +152,16 @@ TEST(Layuout, layout_children_00) {
widget_t* g3 = group_box_create(win, 0, 0, 0, 0);
widget_set_children_layout_params(win, 0, 0, 10, 10);
widget_set_self_layout_params(g1, widget_layout_parse(&layout, "0", "0", "10", "4"));
widget_set_self_layout_params(g2, widget_layout_parse(&layout, "0", "0", "fill", "4"));
widget_set_self_layout_params(g3, widget_layout_parse(&layout, "100", "0", "3", "4"));
widget_set_parsed_self_layout_params(g1, widget_layout_parse(&layout, "0", "0", "10", "4"));
widget_set_parsed_self_layout_params(g2, widget_layout_parse(&layout, "0", "0", "fill", "4"));
widget_set_parsed_self_layout_params(g3, widget_layout_parse(&layout, "100", "0", "3", "4"));
widget_layout(win);
ASSERT_EQ(g2->x, 20);
ASSERT_EQ(g2->w, 70);
widget_set_self_layout_params(g1, widget_layout_parse(&layout, "0", "0", "10", "20"));
widget_set_self_layout_params(g2, widget_layout_parse(&layout, "0", "0", "4", "fill"));
widget_set_self_layout_params(g3, widget_layout_parse(&layout, "100", "160", "3", "4"));
widget_set_parsed_self_layout_params(g1, widget_layout_parse(&layout, "0", "0", "10", "20"));
widget_set_parsed_self_layout_params(g2, widget_layout_parse(&layout, "0", "0", "4", "fill"));
widget_set_parsed_self_layout_params(g3, widget_layout_parse(&layout, "100", "160", "3", "4"));
widget_layout(win);
ASSERT_EQ(g2->y, 30);
ASSERT_EQ(g2->h, 120);
@ -178,9 +177,9 @@ TEST(Layuout, layout_children_10) {
widget_t* g3 = group_box_create(win, 0, 0, 0, 0);
widget_set_children_layout_params(win, 1, 0, 10, 5);
widget_set_self_layout_params(g1, widget_layout_parse(&layout, "0", "0", "20", "4"));
widget_set_self_layout_params(g2, widget_layout_parse(&layout, "0", "0", "30", "4"));
widget_set_self_layout_params(g3, widget_layout_parse(&layout, "100", "0", "20%", "4"));
widget_set_parsed_self_layout_params(g1, widget_layout_parse(&layout, "0", "0", "20", "4"));
widget_set_parsed_self_layout_params(g2, widget_layout_parse(&layout, "0", "0", "30", "4"));
widget_set_parsed_self_layout_params(g3, widget_layout_parse(&layout, "100", "0", "20%", "4"));
widget_layout(win);
ASSERT_EQ(g1->x, 10);
ASSERT_EQ(g1->y, 10);
@ -208,9 +207,9 @@ TEST(Layuout, layout_children_01) {
widget_t* g3 = group_box_create(win, 0, 0, 0, 0);
widget_set_children_layout_params(win, 0, 1, 10, 10);
widget_set_self_layout_params(g1, widget_layout_parse(&layout, "0", "0", "20", "20"));
widget_set_self_layout_params(g2, widget_layout_parse(&layout, "0", "0", "30", "30"));
widget_set_self_layout_params(g3, widget_layout_parse(&layout, "100", "100", "20%", "20%"));
widget_set_parsed_self_layout_params(g1, widget_layout_parse(&layout, "0", "0", "20", "20"));
widget_set_parsed_self_layout_params(g2, widget_layout_parse(&layout, "0", "0", "30", "30"));
widget_set_parsed_self_layout_params(g3, widget_layout_parse(&layout, "100", "100", "20%", "20%"));
widget_layout(win);
ASSERT_EQ(g1->x, 10);
ASSERT_EQ(g1->y, 10);
@ -236,7 +235,7 @@ TEST(Layuout, layout_children_11) {
widget_t* g1 = group_box_create(win, 0, 0, 0, 0);
widget_set_children_layout_params(win, 1, 1, 10, 5);
widget_set_self_layout_params(g1, widget_layout_parse(&layout, "0", "0", "20%", "20%"));
widget_set_parsed_self_layout_params(g1, widget_layout_parse(&layout, "0", "0", "20%", "20%"));
widget_layout(win);
ASSERT_EQ(g1->x, 10);
ASSERT_EQ(g1->y, 10);
@ -247,7 +246,6 @@ TEST(Layuout, layout_children_11) {
}
TEST(Layuout, layout_children_14) {
widget_layout_t layout;
widget_t* win = group_box_create(NULL, 0, 0, 200, 200);
widget_t* g1 = group_box_create(win, 0, 0, 0, 0);
widget_t* g2 = group_box_create(win, 0, 0, 0, 0);
@ -280,7 +278,6 @@ TEST(Layuout, layout_children_14) {
}
TEST(Layuout, layout_children_41) {
widget_layout_t layout;
widget_t* win = group_box_create(NULL, 0, 0, 200, 200);
widget_t* g1 = group_box_create(win, 0, 0, 0, 0);
widget_t* g2 = group_box_create(win, 0, 0, 0, 0);
@ -313,7 +310,6 @@ TEST(Layuout, layout_children_41) {
}
TEST(Layuout, layout_children_22) {
widget_layout_t layout;
widget_t* win = group_box_create(NULL, 0, 0, 200, 200);
widget_t* g1 = group_box_create(win, 0, 0, 0, 0);
widget_t* g2 = group_box_create(win, 0, 0, 0, 0);