150 lines
14 KiB
Markdown
150 lines
14 KiB
Markdown
# GuiLite设计原理及代码注释
|
||
- [基本原理](#基本原理)
|
||
- [扩展方法](#扩展方法)
|
||
- [代码目录结构](#代码目录结构)
|
||
- [界面元素管理](#界面元素管理)
|
||
- [图形绘制](#图形绘制)
|
||
- [文件注释](#文件注释)
|
||
- [函数注释](#函数注释)
|
||
- [速成路线图](#速成路线图)
|
||
***
|
||
## 基本原理
|
||
GuiLite只做两个工作:界面元素管理和图形绘制。
|
||
|
||
界面管理包括:
|
||
- 添加/删除界面元素(例如:按钮,标签,对话框等控件),设置对应的文字及位置信息
|
||
- 用户输入消息传递:根据用户输入寻找受影响的界面元素,并回调响应的处理的处理函数
|
||
- 用户自定义消息传递:用户可以自定义消息响应函数,并自主产生消息;当消息产生时,对应的响应函数会被调用
|
||
|
||
图形绘制包括:
|
||
- 基本的点线绘制,例如:画点,矩形,横线,竖线等
|
||
- 设置绘制图层,如果需要多个图层,在基本点线绘制时,需要给出图层的索引值
|
||
- 图层处理,在图层界面发生变化的时候(例如:打开/关闭对话框),GuiLite将决定各个图层上的像素点,哪个会被最终显示在屏幕上
|
||
|
||
👉注意:图形绘制不依赖界面管理,可以独立的存在,例如,在资源有限的单片机环境,有时候不需要界面元素管理,而直接进行图形,文字的绘制。
|
||
|
||
## 扩展方法
|
||
GuiLite只给出了基本控件(例如:按钮,标签,键盘,选择框)的实现方法,旨在说明控件的实现方法。对于扩展控件,可以选择下面的方式:
|
||
- 如果开发者需要调整基本控件的细节,可以直接在源代码中修改
|
||
- 如果开发者需要构建全新的控件,可以参考基本控件的实现方法,重新实现
|
||
|
||
对于扩展绘制,例如:画圆,画曲线,可以直接在surface.cpp文件中添加响应的函数接口。
|
||
|
||
## 代码目录结构
|
||
core:
|
||
- 实现了底层绘制,图层管理和消息传递
|
||
- adapter实现了各个平台(例如:Windows, Linux,Android,iOS,macOS,未知OS或无OS)的封装。
|
||
|
||
widgets:
|
||
- 实现了各种常规控件(例如:按钮,标签,键盘,波形)及容器(例如:视窗,对话框,滑动页面),开发者可以根据自己的需要,直接在相应的代码上进行修改或重绘,开发出有自己风格,特色的界面
|
||
- 实现了用户的手势识别(例如:手指滑动,鼠标按下/释放)的消息传递,将用户的输入信息传递到整个GUI体系树中,并调用相应的响应回调函数;开发者可以根据自己的需要添加/修改响应回调函数。
|
||
|
||
## 界面元素管理
|
||
界面元素管理包括:对所有控件(button,spinbox, lable, keyboard),容器(dialog, view)管理;具体的管理方法是在用户调用connect函数时,会把所有的界面元素连接起来,从而实现对所有界面元素的遍历/添加/删除等操作。这些链接看起来像一棵树,对界面元素的遍历,就是对这棵树的遍历
|
||
|
||
比如:当你按下一个dialog的button时,手指的位置信息(x,y)会被传入树的根部(root),然后从root开始寻找,哪个dialog被点中,dialog的哪个button被点中,并调用buton被点中的回调函数,用于作相应处理(一般会进行button的状态修改及重绘工作)
|
||
|
||
### 界面元素如何创建
|
||
所有界面元素都继承自c_wnd类的对象,对象被实例化时,也就完成了界面元素的创建;但此时的界面元素是孤独的,与其他界面元素没有形成联系(没有父母,没有兄弟姐妹)
|
||
|
||
### 界面元素如何被管理
|
||
新创建的界面元素纳入管理的过程,就是为其添加父母,兄弟姐妹的过程。使用的函数接口为connect();从此该界面元素会跟其他界面元素一样,纳入一棵树中,并随之响应用户可能的点击操作。
|
||
|
||
当需要删掉该界面元素时,使用disconnect();从此该界面元素会断绝所有的父子关系,从树上摘下来,不再响应用户的触控操作;但对象本身不会被销毁。典型应用场景:软键盘的创建/退出。
|
||
|
||
## 图形绘制
|
||
图形绘制包括: 绘制方法和图层管理。
|
||
- 点绘制是线/面/位图绘制的基础,若干个点的绘制,形成点面及位图
|
||
- 图层管理,则是管理多个界面元素的遮挡关系,系统默认支持3层遮挡关系,这3个层次可以为:视图背景层,对话框层,keyboard/spinbox控件层。
|
||
|
||
### 绘制方法
|
||
请参看文件bitmap.cpp和surface.cpp中的draw_xxx()函数。
|
||
为了发挥GPU的加速功能,也可以通过改写draw_xxx/fill_xxx函数,使用GPU特性,来提升绘制效率。
|
||
|
||
### 图层管理
|
||
![Graphic layer](GraphicLayer.png)![GuiLiteGraphic](GuiLiteGraphic.gif)
|
||
- display层:该层对应了物理显存,display层决定了一个显示终端的最终显示效果;通常系统中至少有一个display层。
|
||
- surface层:该层属于display层的一个部分;它为左右滑动而存在,每一张滑动页面均对应了一个surface层;surface层决定了一个滑动页面的最终显示效果;通常1个display层会对应多个surface层。
|
||
- frame层:该层属于surface层的一个部分;它现实叠加界面元素而存在。
|
||
|
||
## 文件注释
|
||
| core 重要程度/文件名称 | 代码简介 | 推荐学习时间 |
|
||
| --- | --- | --- |
|
||
| ★★★ wnd.h | UI元素的基本类,定义所有的UI元素信息、绘制及管理办法 | 1.5小时 |
|
||
| ★★ display.h | 生成显示设备,设定surface的数目,一个surface对应一个滑动页面 | 0.5小时 |
|
||
| word.h | 显示文字 | < 1小时 |
|
||
| image.h | 绘制位图,支持16 bits和32 bits | < 0.5小时 |
|
||
| rect.h | UI元素的位置信息 | < 0.5小时 |
|
||
| api_linux.cpp | Linux适配层 | < 0.5小时 |
|
||
| api_win.cpp | Window适配层 | < 0.5小时 |
|
||
| api_unknow.cpp | 无OS或其他OS适配层 | < 0.5小时 |
|
||
***
|
||
| widgets 难度/文件名称 | 代码简介 | 推荐学习时间 |
|
||
| --- | --- | --- |
|
||
| label.h | 标签控件的绘制 | < 0.5小时 |
|
||
| button.h | 按钮控件的绘制及用户点击响应函数 | < 0.5小时 |
|
||
| table.h | Table控件的绘制 | < 0.5小时 |
|
||
| dialog.h | 对话框的绘制及管理方法 | < 0.5小时 |
|
||
| ★ keyboard.h | 键盘控件的绘制及用户点击响应函数 | 0.5小时 |
|
||
| ★★ list_box.h | List控件的绘制及用户点击响应函数 | 1.5小时 |
|
||
| ★★ spinbox.h | Spinbox控件的绘制及用户点击响应函数 | 1.5小时 |
|
||
| ★★ edit.h | Edit控件的绘制及用户点击响应函数 | 1.5小时 |
|
||
| ★ slide_group.h | 多屏GUI的实现,以及用来切换屏幕的划屏操作 | 1.5小时 |
|
||
| ★★★ wave_buffer.h | 波形数据的缓冲管理 | 1.5小时 |
|
||
| ★★★ wave_ctrl.h | 它通过波形数据,绘制实时的波形控件 | 1.5小时 |
|
||
|
||
## 函数注释
|
||
| 函数名称 | display.h::c_display 函数接口注释 |
|
||
| --- | --- |
|
||
| c_display | c_display构造函数。phy_fb:物理framebuffer指针;display_width:物理显示器宽度;display_height:物理显示器高度;surface_width:surface宽度;surface_height:surface高度;color_bytes:颜色深度;surface_cnt:surface个数/滑动页面的个数;gfx_op:外部绘制接口,用以适配非framebuffer的渲染方式,如果该值不为空,surface在作底层渲染的时候,会调用该接口 |
|
||
| alloc_surface | 分配surface/滑动页面。usr: 用户ID;max_zorder:该surface所拥有的图层数量|
|
||
| merge_surface | 横向组合两个surface,多用于滑动surface。s0:源surface 0;s1:源surface 1,x0:源surface 0的起始点x坐标;x1:源surface 1的起始点x坐标;y0:源surface 0的起始点y坐标;y1:源surface 1的起始点y坐标;offset:横向组合的偏移距离 |
|
||
| get_updated_fb | 获取该display的framebuffer指针,常用来将GUI显示在任意需要的地方。widght:用来获取framebuffer的宽度;height:用来获取framebuffer的高度;force_update:是否需要强制更新framebuffer的内容,如果不需要强制更新,且framebuffer没法发生变化,将返回NULL |
|
||
| snap_shot | 生成当前显示的快照,并输出到bitmap文件。file_name:快照文件的名称 |
|
||
***
|
||
| 函数名称 | display.h::c_surface 函数接口注释 |
|
||
| --- | --- |
|
||
| c_surface | c_surface构造函数。 display:surface所属于的display;width:surface的宽度;height:surface的高度;color_bytes:颜色深度|
|
||
| set_surface | 设置surface。wnd_root:使用者者ID,通常为root window,其子窗口自动获得该surface的使用权。 max_z_order:该surface拥有的图层数量 |
|
||
| draw_pixel | 渲染一个像素点。x:像素点坐标x;y:像素点坐标y;rgb:像素颜色;z_order:像素所在的图层 |
|
||
| draw_pixel_on_fb | 渲染一个像素点 - 底层渲染。x:像素点坐标x;y:像素点坐标y;rgb:像素颜色 |
|
||
| fill_rect | 填充一个矩形。 x0:矩形左上角的坐标x;y0:矩形左上角的坐标y;x1:矩形右下角的坐标x;y1:矩形右下角的坐标y;rgb:矩形的颜色;z_order:矩形所在的图层|
|
||
| fill_rect_on_fb | 填充一个矩形 - 底层渲染。 x0:矩形左上角的坐标x;y0:矩形左上角的坐标y;x1:矩形右下角的坐标x;y1:矩形右下角的坐标y;rgb:矩形的颜色 |
|
||
| get_pixel | 获取指定位置的像素点的颜色值。x:位置坐标x;y:位置坐标y;z_order:位置坐标z(图层坐标) |
|
||
| draw_hline | 渲染一条横线。x0:横线的左边起始坐标x;x1:横线的右边结尾坐标x;y:横线的纵向坐标y |
|
||
| draw_vline | 渲染一条竖线。x:竖线的横向坐标:x;y0:竖线的上起始坐标y;y1:竖线的下结尾坐标y |
|
||
| draw_line | 渲染普通直线。x1:直线左端点的坐标x;y1:直线左端点的坐标y;x2:直线右端点坐标x;y2:直线右端点坐标y |
|
||
| draw_rect | 渲染矩形。x0:矩形左上角的坐标x;y0:矩形左上角的坐标y;x1:矩形右下角的坐标x;y1:矩形右下角的坐标y |
|
||
| set_overlap_zone | 设置指定图层的可视区域(矩形),可视区域会根据图层优先级,自动进行上下叠加。rect:可视矩形的位置信息;z_order:图层的z坐标(图层坐标) |
|
||
| flush_screen | 将当前surface的指定矩形区域一次性刷在显示屏上。left:surface指定区域的左边界坐标;top:surface指定区域的上边界坐标;right:surface指定区域的右边界坐标;bottom:surface指定区域的下边界坐标 |
|
||
| is_valid | 判断给定位置的矩形,是否合理(是否在surface的范围内)。rect:矩形区域的坐标信息 |
|
||
***
|
||
| 函数名称 | wnd.cpp 函数接口注释 |
|
||
| --- | --- |
|
||
| c_wnd | c_wnd构造函数,进行基本初始化 |
|
||
| connect | 把自己(this)、自己的子窗口系列及父窗口连接起来,形成完整的UI窗口链条;连接完成后,自己就可以响应用户输入及各种UI消息。parent:父窗口;resour_id:窗口ID;str:自己的窗口标题字符串;x:自己相对父窗口的坐标x;y:自己相对父窗口的坐标y;width:窗口宽度;height:窗口高度;p_child_tree:子窗口系列 |
|
||
| load_child_wnd | 把一系列子窗口连接起来,形成完整的UI窗口链条;连接完成后,所有子窗口都可以响应用户输入及各种UI消息。p_child_tree:子窗口系列 |
|
||
| disconnect | 把自己(this)跟父窗口、子窗口脱离连接,切断自己与UI的联系,不在响应用户输入及各种UI消息。 |
|
||
| get_wnd_ptr | 获得指定窗口ID的窗口指针。id:窗口ID |
|
||
| set_attr | 设置窗口属性,包括:普通、失效、可见。attr:属性值 |
|
||
| is_focus_wnd | 判断自己(this)是否可以获得焦点 |
|
||
| set_wnd_pos | 设置自己(this)相对于父窗口的窗口位置。x:窗口左上角坐标x;y:窗口左上角坐标y;width:窗口宽度;height:窗口高度 |
|
||
| get_wnd_rect | 获取自己(this)相对于父窗口的位置信息。rect:用于输出位置信息 |
|
||
| get_screen_rect | 获取自己(this)相对于UI系统的绝对位置信息。rect:用于输出位置信息 |
|
||
| set_child_focus | 将自己(this)的一个子窗口设置为获得讲点状态。 focus_child:获得焦点的子窗口|
|
||
| add_child_2_tail | 把一个子窗口添加到自己(this)的子窗口链表的尾部。child:被添加的子窗口 |
|
||
| get_last_child | 获得自己(this)子窗口链表尾部的子窗口指针。 |
|
||
| unlink_child | 将自己(this)的子窗口从子窗口链表中脱离出来。child:被脱链的子窗口 |
|
||
| show_window | 渲染自己(this)及自己的子窗口 |
|
||
| on_touch | 响应用户的触控消息。x:用户触控点的坐标x;y:用户触控点的坐标y;action:用户的触控类型,包括:按下,释放 |
|
||
| on_key | 响应用户的按键消息。key:用户点击的按键键值。 |
|
||
| notify_parent | 传递UI消息给自己(this)的父窗口,并调用父窗口对应的响应函数。msg_id:消息ID;ctrl_id:自己的资源ID,param:消息的参数 |
|
||
|
||
## 速成路线图
|
||
1. 精读源文件wnd.cpp中的connect, on_touch, on_key函数,理解界面元素的串联办法;理解响应触控操作的基本原理;理解响应硬按键的基本原理
|
||
2. 快速浏览surface.cpp中用于绘制的draw_xxx函数,熟悉基本的绘制接口;精读c_surface构造函数,理解c_surface类的各种成员关系
|
||
3. 精读button.cpp文件,初步掌握界面元素的基本开发方法
|
||
4. - 快速浏览HelloStar实例的BuildLinux/main.cpp,理解构建一般Linux应用的办法
|
||
- 快速浏览HelloStar实例的BuildMFC/HelloStarDlg.cpp,理解构建一般Windows应用的办法
|
||
- 快速浏览HelloStar实例的BuildSTM32F103-Keil/USER/main.c,理解构建一般单片机系统的办法
|