LCUI 0.13.0 开发日志

发表于2012年12月17日

2012-12-17

现在先写下这次版本更新中需要实现的东西:
能够够直接读取图片的信息,之前的版本,都是先读取图片数据,再从图片数据中获取图片信息。
实现部件的圆角边框绘制,阴影绘制。
文本框添加占位符功能,文本框为空并未处于焦点状态时,显示占位符。
图形处理上,为LCUI_Graph结构体添加auto_attr属性(attr是attribute的缩写),用于指示是否在每次修改图形数据后,自动更新该图形的属性;
解除每次操作图形时的加锁和解锁操作,因为有时频繁修改图形时,这加锁和解锁的操作,以及图形属性的自动更新,会浪费很多时间。
队列处理上,也一样,解除每次操作队列时的加锁和解锁操作,需要加锁时直接调用Queue_Lock或Queue_Using函数即可。
以后需要移植到windows上,那么,如何避免与windows的函数库内的函数同名?例如:RGB函数。
要么,重新调整函数名,加个LCUI前缀名,再用宏定义,将目前使用简写的函数名替换成原本的函数名,这个以后再考虑,现在懒得纠结。
其它的功能,在开发过程中再考虑。

有个想法:
部件的样式能够像html网页那样用css来定义网页元素的样式,贴个示例代码:

char wnd_css[]= {
".my_style {"
"width:320px;"
"height: 240px;"
"align:middle-center;"
"title-text:测试窗口;"
}
CSSLib_Add_New( wnd_css );
Set_Widget_Class( window, "my_style" );

调用CSSLib_Add_New函数把这个样式载入至样式库,然后调用Set_Widget_Class函数将库中的my_style类样式应用到window部件上。
CSSLib_Add_New函数是CSSLib模块里的,而Set_Widget_Class函数通过该模块的函数获取相应的样式,并应用到window部件上。
每种部件应该关联一个函数,用于处理这些样式。

2012-12-21

整理了一下头文件,部件的源文件和头文件,文件名都改成小写,并去掉LCUI_前缀名,部件的头文件,都转移至include/LCUI/widget/目录下。

LCUI_Font.h头文件也做了修改,一个头文件包含多个源文件中的函数声明、结构体定义、宏定义,维护起来有点麻烦,我把它缩减了。

textlayer.c、charset.c、bitmapfont.c等都有自己的头文件,而LCUI_Font.h只是#include这些头文件,它们的头文件都存放在include/LCUI/font/目录下。

从textlayer.c中分离出了textstyle.c,主要分离了TextStyle相关的结构体和函数,打算再从textlayer.c中分离出文件样式标签处理模块,转移到textstyle.c里。

git居然能够知道我更改了文件名,不错不错,本以为它会把更名后的文件当新文件对待。

2012-12-23

圆形边框绘制有点棘手,写了个测试网页,以下是效果图:

div的样式为:“width:100px; height: 100px; border-left:5px solid #000;border-top-left-radius:45px;"
宽高都为100px,左边框的大小为5px,实线,黑色,左上角的圆角半径为45px。
从左边框开始,线条逐渐变细,直到上边框的左端为止,这是怎么绘制的?

完成了左上角的圆角绘制,效果如图所示:

只是绘制线条而已,边框以外的图形并未进行透明处理;这线条并不是连续的,不像一个圆滑的曲线,有锯齿。
要使绘制出来的线条抗锯齿的话,那就在该点周围添加点,像素点的坐标越是接近计算出来的xy的值,那么,该像素的的颜色越深,反之,越淡。
说是这样说的,有待继续实验。

2012-12-25

上图中,从左下角到右上角,点的密度会越来越低,从y轴上看,每一行最多2个点;从x轴上看,有的列却没有一个点。

圆需要绘制2次,一次是根据y轴计算各点的x轴坐标并填充点,一次是根据x轴计算各点的y轴坐标并填充点;前面一次,每1行最多两个点;而后一次,每1列最多两个点,这样,这些点就能补全整个圆。

2012-12-28

在实现x轴的各点填充时出现问题,点是乱的,后来发现,是由于没有将double型y轴坐标转换成int型,导致运算结果异常。

经过一番优化后,已经实现圆的绘制,具体如下图所示:

可到这里查看圆的绘制代码,其实在绘制1/4圆的同时,就可以绘制剩下的3/4圆。

接下来就是添加区域有效性处理,绘制的圆可能会超出目标图层的范围,应该确保在绘制圆的时候不超出范围,以避免内存访问越界。

圆角绘制已经完成,如下图所示:

这是修改后的代码,圆角边框的线条粗细不能调整,有待完善,圆外的区域透明处理还算比较简单。

不同粗细的圆角边框线条绘制,可以根据粗细程度,绘制相应数量的圆,例如:线条宽度为5px,那么,需要绘制5个同心圆,它们的半径分别为:5、4、3、2、1,这样就组成了一个线条宽度为5px的圆了。

自定义线条宽度的圆角绘制已经实现,可到这里查看修改后的代码,以下是效果图:

边框线条宽度为20px,圆角线条里还有一些点没有被填充,看来真的需要实现之前说的那个 圆的抗锯齿处理了。

2012-12-30

同心圆方法不可行,加了简单的抗锯齿,未填充颜色的点被模糊了,效果不好。

2012-12-31

改用了另一种方法,这是初始效果图:

右半圆比较正常,和之前贴的网页的圆角效果相似,而左半圆有点问题,后来发现是计算公式有问题,纠正后的效果如下图所示:

可以看出,线条中间部分较细,到这里可查看代码修改情况,但直接绘制线条宽50px、半径为50px的圆,效果有问题,如下图所示:

还是计算问题,现已纠正,以下是现在的效果:

2013-1-1

改了一下代码,各个边的圆角化还是分开处理,让圆绘制在有效区域内还真有点麻烦,以下是左上角的绘制效果:

是不是和之前贴的网页圆角边框绘制效果图一样?只不过浏览器多了抗锯齿处理,可到这里查看修改后的代码,其它角的圆角绘制代码,和这个类似,有待继续添加。

我也大致能够猜到浏览器是如何绘制网页元素的边框了,4个边框,要绘制8次圆角,就以左上角圆角边框为例:先根据左边框的宽度,确定线条宽度,从左边框的上端开始,到上边框的左端结束,绘制一条圆角线;然后根据上边框的宽度,从上边框的左端开始,到左边框的上端结束,绘制一条圆角线;这种方法,是为了能够在边框各边的尺寸不统一的情况下,也能绘制相应宽度的圆角线。

2013-1-3

完成了左下角和右下角的圆角绘制,代码是复制粘贴左上角和右上角的圆角绘制代码的,只做了一点修改,重复代码较多,以后有空再精简一下,以下是效果图:

还剩下上左角、上右角、下左角和下右角的,有待继续完善。

2013-1-4

下左角的圆角绘制存在数据访问越界的问题。

是计算出了问题,一位坐标超出了范围,已经纠正,以下是目前的效果图:

需要加入抗锯齿处理,以使圆角润滑。

有个想法:从LCUI_Widget.c分离出一个模块,名字就这三个:LCUI_Surface.c LCUI_Layer.c LCUI_GraphLayer.c,具体用哪个,有待考虑。反正就是用于处理图层堆叠、显示之类的,而LCUI_Widget.c只用于对widget的图层的位置、尺寸、图形内容等数据进行修改。

2013-1-6

写了个图片转代码的程序,之前的图片转代码的程序是windows版的,它是由论坛上的一位网友根据我写的代码写出来的。

更新了复选框和单选框的图形样式,图形截取自QQ2013的单选框和复选框。

修改了队列处理模块,对队列的操作不再自动设置锁,需要开发者按需对队列手动设置锁,改了后还没出现什么问题。

查了一下软考初级成绩,这成绩应该及格了,撸这么久的代码还算没有白撸,下午题的代码,题目说明文字太多,都没仔细看就直接撸代码,幸好还是及格了。

2013-1-8

看了DirectFB源码目录中inputdrivers/keyboard/keyboard.c文件,发现里面的函数都是static的,其中driver_get_available、driver_close_device、driver_get_info这三个函数引起了我的注意,还有开头处的DFB_INPUT_DRIVER( keyboard )这个宏,个人猜测,这三个函数是一个驱动模块必须的函数,由DFB_INPUT_DRIVER宏来注册这个驱动模块。

keyboard.c的源代码看起来不太困难,没有太多外部模块的函数调用,只需要专注浏览该模块内的代码即可,这就是高内聚低耦合好处,方便了代码阅读,不必在多个模块间切换阅读代码,维护起来也很容易。

DirectFB的键盘驱动模块是在一个线程上运行的,keyboardEventThread函数中,通过循环读取/dev/tty0设备的数据来获取按键输入,之前看到这段代码:
evt.type = ((buf[i] & 0x80) ? DIET_KEYRELEASE : DIET_KEYPRESS);
本以为它可以判断按键是“按下”状态还是“释放”状态,参考了源代码,自己写了个测试程序,在终端上运行,结果表明的确可以获取按键的状态,可是,按ctrl+alt+F1切换到字符控制台模式后运行它,却只能获取键值,按键状态没法正常获取,一直是0。

GitHub.com网页有改动,具体如下图所示:

以前是显示直方图以表示项目变动状态,网页改动后,这个图更加直观了,用绿方块表示活跃度,方块颜色越绿,活跃度越高。

发现BUG,鼠标移动时会有残余图形,刷新区域的添加需要手动对队列上锁,以确保刷新区域的正常添加,已经纠正。

2013-1-9

需要在src目录下添加kernel目录,分割LCUI_Main.c中的源代码,把分割出来的代码保存至相应新文件里,例如:定时器模块的代码保存至timer.c里。

部件功能模块需要修改:
部件状态有normal、disable、hover、active、focus,其中focus状态能和其它状态并存。
可以为这几种部件状态关联样式类和函数指针,LCUI在处理部件时,会根据关联的样式预先绘制部件,然后,将剩下的工作交给关联的回调函数,对部件进行后期处理。
这样的话,有些预置部件就只能修改样式,不能修改默认关联的回调函数了,否则部件无法工作。

2013-1-10

源代码的分割已经完成,LCUI_Main.c分割成main.c device.c timer.c,并保存在kernel目录,添加了相应头文件,其它源文件和头文件也做了相应修改,LCUI.h中的部分结构体声明做了转移。

2013-1-11

focus状态就不用了,可通过判断widget的focus属性即可知道该部件是否获得焦点。

2013-1-12

从LCUI_Widget.c中分离出LCUI_GraphLayer.c模块的话,图层之间的关系需要父图层指针+子图层队列保存,因为图层的容器功能、显示顺序需要队列来记录,而子部件从容器A转移至容器B需要用一个指向父图层的指针,从父图层中的队列中移除子图层记录。而部件之间的父子关系也需要父部件指针+子部件队列保存,部件的鼠标、按键事件的响应需要用到。

百度搜索时,发现Qt有个函数:widgetAt(),用它可以得到指定点上存在哪个窗口部件,LCUI中同功能的函数是Get_Cursor_Overlay_Widget(),感觉有多余的下划线,函数名太长,可以考虑更名。

添加了LCUI_GraphLayer.c模块,只设计了一部分函数接口,具体实现代码有待继续编写。

2013-1-14

正纠结是否需要为LCUI_GraphLayer.c模块添加一个缓冲队列,和widget数据更新处理一样,这是避免频繁因更新数据(坐标、尺寸等)而导致处理耗时变长、数据冗余的问题,举个例子:一个图层要在1秒内从坐标(0,0)匀速移动至坐标(300,0),图层在屏幕上绘制需要时间,而这个时间无法预估,目前的做法是,自己手动确定1秒内更新的帧数,然后计算好每次更新画面时移动的距离,假设为60帧/秒,那么移动速度就是5像素/帧,如果是要让每一帧画面全部显示出来,那么,耗时可能不止1秒,机器配置越低,耗时越长;如果是尽量让该图层的位置移动的耗时接近1秒,那么,需要做“跳帧”处理,若前一次的坐标还未更新,那么这次的新坐标将覆盖前一次。除了坐标外,还有尺寸变更、图形重绘。

做了些修改,结构体中的int型的x、y,改用LCUI_Pos类型,而成员变量z改名为z_index,反正结构体内已经用了LCUI_Graph、LCUI_Queue结构体,再用个LCUI_Pos结构体也无妨。

LCUI_GraphLayer.c模块应该不需要这个,因为它主要是被LCUI_Widget.c模块调用,而LCUI_Widget.c模块已经实现了数据更新缓冲处理,如果还有其它模块需要使用LCUI_GraphLayer.c模块,且需要考虑上述问题,那到时候再来纠结吧。

那些3D游戏中的FPS是怎么计算的?如果要我的LCUI实现这个的话,那么就设2个变量:count和fps,分别用于计数和保存FPS,每次对所有部件数据及图形进行更新时,让count自增,再设个定时器,每隔一秒将frame_count赋值给fps,再重置count为0。

2013-1-15

这是以前提到的simsun.ttc字体的问题:

12px至16px的汉字显示有问题,不知如何解决。

在写GraphLayer_GetValidRect函数的实现代码时,发现一个问题,图层是否需要添加padding属性支持?不添加该支持的话,虽然用widget可以实现,也就是加个子部件,把所有子部件放进这个子部件,通过调整这个子部件的位置及尺寸,就能实现部件内边距了。但感觉这个有些麻烦,多了几级父子部件关系。

哦对了,不用部件,用图层就可以了,一个部件有两个图层:A和B,A作为部件主图层,而B作为主图层的子图层,为部件添加子部件,那就直接将子部件的主图层添加至父部件的B图层内,而父子图层关系的解除操作 需要稍微修改一下。

添加了GraphLayer_GetGraph函数的实现代码以及相关的函数,修改了结构体,点击这里可查看目前的源代码。

2013-1-16

写了个测试程序,在测试过程中,发现了一些细节上存在的BUG,现在已经解决,以下是测试程序输出的图片内容:

白色的是根图层,图层A是红色,图层B是绿色,图层C是蓝色,图层A和B是根图层的子图层,而图层C是图层B的子图层。

点击这里可以查看测试程序的源代码,也可以查看图层的尺寸和坐标。

接下来就是修改LCUI_Widget.c模块里的代码,改结构体和相关函数代码。

2013-1-17

纠结了一下,LCUI_GraphLayer不需要记录无效区域,因为图层是在内存中的,图层的位置移动、尺寸改变等,只是改数据,并没改屏幕上显示的内容,没多大关系的东西还是从LCUI_GraphLayer.c模块里分离出去好些。

修改了一番,已初步完成,能够显示鼠标游标,但不能显示图形界面,有待继续修改。

2013-1-18

停了一整天的电,用手机看SDL的源代码,在它的html文档中看见union这个词,SDL_Event是个共用体,里面有个type成员变量和其它事件类型结构体,而其它事件类结构体中也有type成员变量,直接对共用体中的type成员变量赋值,该共用体内的其它事件类型的结构体里的type成员变量也会改变,因为它们都是同一块内存空间。

LCUI的event还是要改一下,各种类型的事件的结构体,改用一个LCUI_Event共用体来包含它们,相关函数需要更名。

部件的client图层高度有问题,经过一番排查后发现问题原因是 -= 写成了 =,导致client图层高度计算错误。

2013-1-19

部件图形能正常显示了,还存在一点问题,例如:helloworld程序运行后一直在刷新屏幕区域,理论上显示后,界面没改动就不会更新屏幕区域,应该是哪里出了点问题。

问题出在Set_Widget_Padding函数,它会调用Update_Widget函数应用这次更新,而window部件的更新处理中,也调用了Set_Widget_Padding函数,就这样一直循环下去。

看来,应该考虑制定一个规则了:在调用Set_Widget_Padding之类的函数设定部件属性时,需要开发者自己手动调用Update_Widget函数以应用部件属性变化。

还有一种解决方法,设置部件内边距后,需要调整部件client图层的位置及尺寸,而这个操作在Widget_ExecUpdate函数里执行,那么,撤销Set_Widget_Padding函数里的Update_Widget函数调用,把那个调整client图层的代码剪切粘贴到Set_Widget_Padding函数里,这样就Set_Widget_Padding函数就不会调用Update_Widget函数了。

添加了FPS计算功能,用定时器,每秒更新一次FPS。

运行 矩形裁剪功能的测试程序,看看FPS是多少,结果,平均FPS在90左右,也发现了部件移动后的区域刷新有问题。

2013-1-20

区域刷新问题已经解决,原因是没有将内边距计算在内。

鼠标游标移动至按钮区域内,有一部分区域,移过去后按钮不会高亮,估计是获取指定坐标上的部件时出了点问题,看了代码,问题原因和上面的一样。

部件的堆叠顺序处理和图层堆叠顺序处理不一致,需要修改。

鼠标单击子窗口的标题栏时,窗口会向左上方向移动一定距离,需要修改。

纠正了部件的全局坐标 和 坐标转换中存在的计算错误

部件图层的堆叠顺序问题已经解决,如果图层已经前置,就不会移动它的位置。之前的算法,忽略了图层自己,直接和其它图层对比z_index的值,导致前置图层又被移至它后面的图层的位置上。

窗口第一次显示时,默认居中显示,由于之前是用Exec_Move_Widget函数直接移动部件位置,而窗口的初始位置更新还在队列中等待处理,导致窗口居中显示后不久位置又变为(0,0),改用Move_Widget函数即可

2013-1-22

完成了基本的样式字符串的解析功能,有待继续完善。

2013-1-23

部件更新的处理顺序有问题,本来是先改变部件坐标、后刷新部件区域内的图形显示,处理时却颠倒了顺序,窗口理论上会居中显示,结果,显示时会先显示在左上角,再居中显示。

做了一次修改,解决窗口第一次显示时不居中显示的问题,之前那个Exec_Move_Widget函数改Move_Widget函数的修改,现在又改回来了,子窗口第一次显示时是居中显示的,但是,在调用Update_Widget_Pos函数时,又把子窗口的位置改为了(0,0),于是决定修改这个函数的代码,加了个条件:只有在部件对齐方式不为ALIGN_NONE,或者计算的坐标不为(0,0)时才更新部件的位置;部件对齐方式为ALIGN_NONE时,不由LCUI自动更新它的位置,而后面的“计算的坐标不为(0,0)”这个条件,是考虑到部件坐标的单位为百分比的情况。

添加了CodingStyle.zh-cn.md文件,主要描述LCUI目前采用的代码风格,看来还需要修改老代码中的代码风格,比如:LCUI_Widget.c里的代码。

2013-1-25

准备完善一下事件机制,原先定义的LCUI_Event结构体,主要是用于储存与指定事件关联的回调函数数据,现在更名为LCUI_EventSlot,重新添加新的LCUI_Event结构体,LCUI_Event与LCUI_EventSlot的关系,就像信号(singal)与信号槽(singal slot)。

代码已经初步修改完,需要进一步完善。

经过一番纠结,决定将EventLoop放在单独的线程上跑,而程序的MainLoop主要用于处理部件的事件,调用已预先注册的回调函数。

鼠标的事件处理已经修改,除了拖动部件时有问题外,其余都正常,有待继续完善。

这么一改,感觉项目的源代码还需要重新规划一下。

2013-1-26

鼠标事件的修改已经完成,拖动部件移动时,鼠标移动变慢,看来这种方法不行。

改成以往的方式,用事件和事件槽,鼠标发生移动,就将已注册关联该事件的事件槽中的回调函数,转为任务,添加至任务队列,队列中的同类任务可以被覆盖,这样就能抛弃旧任务去及时处理新的任务。

这种方式改动较大,应该在添加事件时,对事件队列中已存在的同类未处理事件进行覆盖。

按上述进行修改,结果,没多大改善。之前是将鼠标的移动事件转为任务添加至程序任务队列,怀疑正常的鼠标移动速度是不是因为任务队列的添加操作导致的,但看了之前的代码,处理鼠标事件时,是直接调用Send_Task_To_App函数将任务追加至任务队列末尾,那么,就排除这个可能了。

纠结了一番,最后发现是因为鼠标游标位置没有及时更新而导致的,在计算新的鼠标游标位置时,都要调用Get_Cursor_Pos函数获取当前鼠标游标位置,然后加上相对距离,得出新的坐标,但没有及时调用Set_Cursor_Pos函数应用新的坐标,导致下次处理鼠标移动时,获取的函数未更新的游标位置,导致游标移动速度减慢。

代码已纠正,主要是将LCUI_HandleMouseMotion函数里的Set_Cursor_Pos函数调用,转移至src/input/mouse.c里的proc_mouse函数中。

2013-1-27

又修改了一番事件机制的代码,与事件关联的回调函数,在处理事件时就会调用,该调用会阻塞整个事件循环。而部件事件的处理,是将回调函数以任务的形式添加至程序任务队列,等待处理。

与系统相关的事件处理代码,放在event.c里,而与部件相关的事件处理代码,放在LCUI_Work.c里。

接下来需要完善部件的鼠标事件处理。

LCUI_Widget结构体需要进行修改。

这是修改后的LCUI_Widget结构体,相关函数代码到后面再改。

部件属性改动太大,其它代码修改量也很大,还是改回来算了,只改动部分,以后按需再修改个别属性。

2013-1-28

保存部件状态的变量名改用status还是state?百度了一番这两个单词的区别,最后还是用state。

精简了一下鼠标事件处理代码,中午纠结了个把小时的处理方法,纠结不出,在晚上撸代码时才决定改代码,算是改完了,只花了十几二十分钟的时间。

这次修改,主要完善了部件的鼠标响应,之前的效果是只有一个部件能够根据鼠标事件进行状态变化,例如:鼠标点击部件时的ACTIVE状态,鼠标覆盖在部件上面时的OVERLAY状态。完善后,该部件的状态变化会应用到上级所有父部件。

这是代码修改情况,处理方法用语言无法描述清楚,相关的函数名和注释写得也不准确。

2013-1-29

只是修改了LCUI_Widget.c里的函数命名风格,接下来会完善部件背景处理功能。

2013-1-30

设定背景图像时,是该保存图像副本,还是引用源图像?保存副本的话,会占用更多内存,即使源图像被销毁,副本依然可用。引用源图像(用指针保存源LCUI_Graph变量的地址),虽然减少了内存开销,但如果用一个局部LCUI_Graph变量保存图像数据,函数退出后,这个局部变量就无效了,那引用的数据也是无效的。

决定还是用另一种方法:保存源LCUI_Graph变量,也就是这个变量赋值给另一个LCUI_Graph副本,虽然销毁源数据后这个副本也会无效,因为图形的像素数据地址是一样的,但节省内存,也不用当心局部LCUI_Graph变量的生存周期问题。

圆角绘制有问题,仔细看之前的圆角绘制图,右下角的圆角有一个像素点没有透明化。

2013-1-31

试着在嵌入式设备上编译,gcc编译器不是新版本的,编译LCUI时报错,头文件中的数据结构定义有问题。

修改了一下头文件

修改了部件的背景图绘制方式,绘制部件前,会先对部件进行更新,然后绘制部件。

修改了button部件和window部件的代码

打算添加 消息框、颜色选择器这两个对话框。

这是初始版本的消息框的效果图:

看来,窗口右上角的关闭按钮需要改了,不能是点击后直接关闭整个程序。

需要主循环能够处理任务,但主循环已经在点击按钮后调用MessageBox函数时被阻塞,应该让LCUI支持创建新的主循环,MessageBox函数里继续执行主循环,这样,循环退出后,MessageBox函数就能通过返回值返回按钮编号,虽然不以返回值形式返回按钮编号也可以,但是,MessageBox函数参数是多个函数指针的话,调用起来也麻烦,还要写回调函数,打乱了代码。

2013-2-1

修改了一下主循环代码,添加了LCUI_MainLoop_New、LCUI_MainLoop_Level、LCUI_MainLoop_Run、LCUI_MainLoop_Quit这几个公共函数.

在写主循环队列的排序函数时,参考了定时器列表的排序代码,发现一个BUG,具体可看这里,在交换两个位置上的元素后,a_timer指针还是指向原来的元素,而不是交换后的新元素,因此,加了段代码:a_timer = b_timer;更新指针的指向。

2013-2-2

试着在消息框代码里添加主循环,结果有问题,点击窗口的关闭按钮,退出的不是当前主循环。主循环的列表排序有问题。

开始添加部件销毁操作,用Widget_Destroy函数记录需进行销毁操作的部件,在处理该操作时,调用Widget_ExecDestroy函数执行销毁。

销毁出现问题,部件的main_glayer和client_glayer指针都为NULL,调用Widget_Destroy函数时可不是NULL,目测是队列处理出了问题。

队列处理问题已经解决,问题原因是调用析构函数前就调用memset函数对该队列成员的空间置零,导致调用析构函数销毁队列成员时,成员数据异常。

修改了button部件的图形自定义函数,直接将LCUI_Graph结构体参数赋值过去,而不是调用Graph_Copy函数进行拷贝,删除了button部件的析构函数,因为没什么指针需要手动释放。

window部件代码做了修改,设定按钮图形后,不会调用Graph_Free函数进行释放了,否则,这会导致在绘制按钮图形时图形数据访问越界的问题。

2个以上的窗口处理有问题,明明是点前面的窗口,响应的却是背面的窗口。

消息框有多个的话,该怎么处理?MessageBox函数是阻塞调用,它的返回值用于表示点击的按钮,假设弹出了消息框A和B,进入了两层消息框的主循环,那么,我关闭消息框A,最里面的一层主循环(消息框B的)退出,那么消息框B的MessageBox函数返回值怎么得出来?关闭的不是消息框B,但退出的却是消息框B的主循环,纠结中,看来需要参考别的GUI实现方式了。

2013-2-3

决定了,MessageBox必须根据显示顺序依次关闭,最先显示出来的MessageBox最后关闭,显示后,不能对其它显示出来的MessageBox进行操作,实现类似于模态对话框的功能。

模态部件始终显示在普通部件的前面,一旦该部件处于显示状态,那么,它所在的容器部件里的其它子部件就不能响应操作。

部件和图层的显示顺序处理需要调试一段时间。

2013-2-4

部件属性添加了modal,用于指定该部件是否为模态部件,相关模态部件处理代码,需要进一步完善。

部件队列中的显示顺序是对的,可图层队列中的显示顺序是错的,而且,前置部件显示后,图层队列貌似没改动,如下图所示:

原来问题出在widget的z-index值的设定上,可到这查看代码,由于在设定完前置部件的z_index值后忘记进行--z_index,导致下一个部件的z_index值也和它一样,从而使图层显示顺序出问题。

MessageBox需要支持自动尺寸调整。

添加RESIZE部件事件,在部件尺寸变动后,该部件将会触发RESIZE事件,如果有与之关联的回调函数,则会调用。

关联消息框中的label部件的RESIZE事件,回调函数里,就根据label部件的尺寸,计算出合适的尺寸。

消息框已经完成了一半左右,以下是效果图:

这里是新增的消息框源代码,头文件在这里

2013-2-5

窗口默认居中显示,align = ALIGN_MIDDLE_CENTER,一旦用鼠标点击它进行拖动,窗口则解除居中显示,align = ALIGN_NONE。

调整了一下MessageBox的代码,解决些细节问题,MessageBox现已基本完成,效果如下图所示:

MessageBox的测试程序的源代码在这里

2013-2-6

修改了一下部件代码中的函数命名。

在CSDN上看了一篇帖子,是说编辑器的,文中描述的eclipse的功能不错,我现在用的geany,有些不足,但也勉强能用,就是多文件切换有点麻烦,查看数据类型定义,跳转获取后,不知道怎么跳转回来。计划在跨平台后,在windows上用eclipse试试。

2013-2-7

添加了fontlibrary.c模块,有待继续完善。该模块主要用于缓冲各种字族、风格和尺寸的字体位图,其它模块若要获取字体位图,只需要调用该模块里的函数即可,这样方便集中管理字体位图,减少内存开销,不必为每个字的字体位图开辟新内存空间以保存数据。

补全了fontlibrary.c模块的代码,剩下的就是投入实际应用了,公开的函数就那么几个,其余的都是static的函数,结构体也不需要放到头文件里。

2013-2-8

学习机上编译LCUI,make install没问题,但make test_messagebox时出现问题:

/usr/bin/ld: ../src/.libs/libLCUI.so: invalid string offset 273637584 >= 12740 for section '.dynstr'

在电脑上交叉编译,也在make test_messagebox时出现问题:

./src/.libs/libLCUI.so: undefined reference to `rpl_malloc'
collect2: ld returned 1 exit status
make: *** [test_messagebox] 错误 1

电脑上configure的结果中有这么一条:

checking for GNU libc compatible malloc... yes

而在电脑上交叉编译时的configure的结果是这样的:

checking for GNU libc compatible malloc... no

网上搜索的结果,有人说是malloc被替换成了rpl_malloc 的原因。

把configure.ac中的AC_FUNC_MALLOC这一项去掉后,重新configure再编译一次,问题没了。

整理了一下代码,在整理过程中,发现有些地方只有添加,没有删除,在LCUI退出时,有些资源并没释放。

2013-2-9

解决了文本框的光标显示问题,修改了文本框的边框样式

话说,焦点是啥时候给文本框的?文本框的样式是焦点状态的样式,但输入字符,文本框没响应,非要我点击文本框让它得到焦点,才能输入。

原来是在Show的时候就让它得到了焦点,还是取消好了,不自动为部件设置焦点。话说,这个焦点,是当前容器下只能有一个,还是全局只有一个?

文本框获得了焦点,可文本框的容器部件的焦点,已经转移至另一部件,这就导致文本框处于焦点状态,但实际的数据输入都传送给另一个焦点部件了。

2013-2-10

一直在纠结数据结构,也就是该用什么样的结构体好,最后还是决定先设计好API,再考虑数据结构。

在搜索FreeType2中译文档时,发现了一篇文章:http://blog.csdn.net/junglefly/article/details/5340192,正好能解决LCUI的宋体汉字位图异常的问题。修改后的效果如下图所示:

但不知为何12px这字体不是点阵的?字体轮廓模糊。

字体处理模块的源代码已经修改,主要修改字体数据库的数据结构,font_database用于记录已经打开的字体文件信息,fontbitmap_database用于记录各种字体位图。修改了部分函数的参数列表,新增相关处理函数。还存在冗余代码,等调试完后再删除。

LCUI_Sys.default_font可以移除了,现在觉得,一个模块里的代码,还是不要过于依赖其它模块里的变量。

本来以为这次修改会存在致命BUG,需要进行调试,结果,在编译完后运行helloworld,居然没出现异常,字体能够正常显示,挺让人兴奋的。

移除了冗余代码,LCUI_Font结构体和相关函数已经移除。

看了Convert_FTGlyph函数,发现里面的局部变量的static的,难道之前的那个字体位图异常的问题就是它导致的?多个线程获取字体位图,调用了这个函数,而这个函数里的局部变量是静态的,导致一个变量同时被多个线程使用,这样就会有线程安全问题。该函数的局部变量已经取消static定义

测试在无字体文件的情况下运行程序,结果在意料之内,程序异常终止。

OK,问题已经解决,初始化FontLIB时,会添加内置字体的信息至库中,在font_id不大于0时,使用内置的字体位图。

内置的图形资源没必要在每次载入时开辟内存空间保存副本,直接引用就行了,这样的话,LCUI_Graph结构体里需要添加一个变量,用于标识该图形数据是否只读,只读的话,Graph_Free函数就不会释放内置图形资源。

2013-2-11

解决滚动条的数据计算错误,该错误会导致文本框的滚动条不能正常滚动文本图层。由于没有正确的获取父部件容器尺寸,导致进行除法运算时进行了除0运算,从而使得出来的结果异常。

本次字体处理模块的更新,文本图层的绘制效率稍有提升,通过那个文本框测试程序就能感觉得到。接下来就是优化文本图层处理。

在移动文本框里的光标时,文本图层是滚动了,但文本框的滚动条却没滚动;改了一下滚动条的测试程序,开个线程,循环移动滚动条,测试正常,既然不是滚动条的问题,那就是LCUI_Widget.c里的代码有问题。

经过一番调试,问题出在Record_WidgetUpdate函数里,把valid变量置为TRUE就可以了,估计是 “位置移动” 覆盖了 “位置更新”,但valid没有设置为TRUE,导致处理该操作时,把“位置移动”当成“位置更新”来处理。

2013-2-13

在移动光标时,会刷新整个文本框区域,需要进行优化。

在修改代码的过程中,顺便调整了部分函数的命名。

运行文本框的测试程序,打开LCUI_Widget.c文件,载入速度很慢,但没载入完就暂停载入了,用top命令查看,CPU使用率在90%以上,既然已经暂停载入,怎么还占这么高的CPU使用率?

估计是由于TextLayer的默认最大字符数限制为5000,导致文本框无法载入过多字符,而字符块队列中还有待追加的字符需要处理,使得CPU使用率占用过高。

修改了TextLayer的最大字符数上限,运行测试程序,用top命令看这个测试程序占用的内存,结果发现总已使内存一直在增长,估计是fontlibrary.c模块有BUG,字体位图没有正常记录进去。

在fontlibary.c里加一段代码,用于打印当前总记录数,运行文本框测试程序,载入纯英文的文本文件,结果,总记录数超过1000,英文也就26个字母,理论上也就100左右的记录。

fontlibary.c的BUG已经修复,由于在添加记录时忘记保存字符编码了,导致在获取缓存区中的字体位图时,找不到与目标字符编码对应的字体位图,结果,每次获取字体位图都添加新的字体位图。

2013-2-15

textlayer.c里的部分源代码已分离至textstyle.c

2013-2-16

经过一番纠结,决定舍弃读写锁,只要互斥锁。

之前那个Makefile的问题,configure得到的变量的值,到了子Makefile中用不了该变量,变量名被当成一个字符串。现在知道原因了,是由于没有调用AC_SUBST的缘故。

用了AC_SUBST后,autoreconf时出错:

configure.ac:185: `LCUI_VIDEO_DRIVER_SOURCES' includes configure substitution `@LCUI_VIDEO_DRIVER_SOURCES@'
configure.ac:185: and is referred to from `liboutput_la_SOURCES';
configure.ac:185: configure substitutions are not allowed in _SOURCES variables
autoreconf: automake failed with exit status: 1

不用AC_SUBST(LCUI_VIDEO_DRIVER_SOURCES)的话,可以通过,但configure后的Makefile,make时没有把源文件包含进来进行编译,明显LCUI_VIDEO_DRIVER_SOURCES是空的。

后来打开Makefile文件,搜索LCUI_VIDEO_DRIVER_SOURCES,有一行的是对的:

liboutput_la_SOURCES = $(LCUI_VIDEO_DRIVER_SOURCES) graph_display.c

在浏览其它地方时,发现了这一行内容:

am_liboutput_la_OBJECTS = graph_display.lo

怎么就一个graph_display.lo?是不是因为$(LCUI_VIDEO_DRIVER_SOURCES)问题导致不能获取$(LCUI_VIDEO_DRIVER_SOURCES)中的文件名并得到.lo后缀的文件名?

LCUI_VIDEO_DRIVER_SOURCES更名为LCUI_VIDEO_DRIVER, src/output/目录下的Makefile.am中相应行内容修改为:

liboutput_la_SOURCES = $(LCUI_VIDEO_DRIVER).c graph_display.c

重新autoreconf,正常通过了。

看来,若要跨平台,使用的数据类型也要做改变,比如线程,linux下的pthread,线程ID是pthread_t类型,互斥锁是pthread_mutex_t类型,而在windows下,都是HANDLE类型。

config.h也要随其它头文件一同安装,在调用其它模块的函数时,例如线程,根据config.h里的宏定义,决定使用何种数据类型。

修改了LCUI的线程模块,LCUI_Thread.c转移至src/thread/目录下。函数的命名做了修改,移除了LCUI_System结构体中的thread_tree成员。

2013-2-17

怎么将自己的项目转换成Windows里的VS2010的项目?

参考了FreeType的VS2010工程配置,设置了自己的项目配置。

测试生成项目时出现警告:

warning C4819: 该文件包含不能在当前代码页(936)中表示的字符。请将该文件保存为 Unicode 格式以防止数据丢失
warning C4001: 使用了非标准扩展“single line comment”

第一个警告,将源文件保存为带BOM的UTF-8编码后,就没了,但我觉得没必要,用C-Free5编译带BOM的UTF-8编码的源文件,编译器会报错,说有3个未知字符。
第二个警告,据说是 // 的问题,ASNI标准中,只能用/**/去注释文本,不能用//。
在项目属性里设置一下,禁止显示这两个警告。

无法正常生成,需要把平台相关的函数封装起来,例如:线程。

2013-2-18

封装了一下Windows平台的线程函数,这是测试程序的源代码:https://gist.github.com/lc-soft/4975334 ,可直接复制出来进行编译并运行,C-Free5上测试通过,主要代码从第713行开始,前面几百行的代码是从现有的代码中复制过来的,主要实现队列处理。

整理了一下LCUI的线程模块代码,更改了函数命名,部分使用了线程模块的相关代码也进行了修改。

2013-2-19

新增delay.c,主要封装延时函数。

修改了keyboard.c模块内的代码,添加LCUIKeyboard_HitKey和LCUIKeyboard_FreeKey函数,前者用于添加指定键值的按键按下事件,后者用于添加指定键值的按键释放事件。这样,在windows平台下,LCUI只需要接收windows的按键消息,并调用这两个函数即可。顺便添加了部分按键的键值的宏定义。

mouse.c模块不需要做多大修改,和keyboard.c一样,只需要接收windows的鼠标消息并转为LCUI的鼠标事件即可。

graph_display.c、framebuffer.c和dummy.c做了修改,主要改的是函数名,添加win32.c,用于在windows平台下实现图形输出。

点击这里可以查看本次修改后的代码。

2013-2-20

VS2010上编译,出现问题,用了简单的代码测试,还是有问题,如下图所示。

以为是VS2010的安装问题,于是卸载了它,尝试下载安装VS2012。

VS2012安装需要C盘4.6GB的可用空间,卸载了些没用的软件,删除了些没用的文件,还是不够,最终决定禁用“睡眠”功能,又腾出了1.5GB的可用空间。安装很慢。

在VS2012下又做了次测试,还是有问题,但不是之前VS2010上出现的问题,具体如下图所示。

注释掉#include 这行后,可以编译。

最后怀疑windows.h头文件里的代码是不是用了语言扩展,把“禁用语言扩展”改为“否”就可以了。

2013-2-21

在windows上编译jpeg库,参考了这篇文章:http://www.cppblog.com/stonexin/articles/jpeglib.html

warning LNK4042: 对象被多次指定;已忽略多余的指定

原来是src/draw/in-core/目录下的源文件名与src/widget/目录下的部分源文件重名的问题,VS2012编译时,这些同名的源文件,虽然在不同目录下,但编译后的文件都放在同一文件夹下,导致出现上述警告。

已经对src/draw/in-core/目录下的源文件名加了img_前缀。

error C2485: “__restrict”: 无法识别的扩展特性
需要将png头文件中使用的__restrict通过宏定义改为restrict,才能在VS2012下编译通过。

2013-2-22

JPEG库有问题,有些jpg图片读不了,png图倒是正常。

项目源文件内的换行符要改为windows的CR/LF,不然VS2012报错指示的行数,和实际行数不一样。

经过一番折腾,终于在windows上实现图形输出了,helloworld运行效果如下图所示:

文本的样式标签解析有问题,导致彩色文本处理异常,上图是去掉了helloworld里的文本标签后的效果。

像素数据的格式是BGRA,和linux系统上的32位显示器的帧缓冲(framebuffer)一样。

还差按键、鼠标的响应了,明天再继续撸。

2013-2-23

每次调用windProc函数,都会更新鼠标坐标,坐标变了,就要添加无效区域以及消息,导致消息过多,windows标题栏的消息就会延迟响应。

解决方法:暂停一段时间再更新鼠标,用定时器,每隔20ms,设置标志变量为FALSE,鼠标输入处理函数就会判断这个标志变量,若为FALSE,就更新鼠标指针的位置,否则,就不更新。

用了ShowCursor函数隐藏windows的鼠标游标。

2013-2-24

只生成了动态库,没有生成静态导入库,后来得知,是因为没在头文件内的每个函数声明前加上__declspec(dllexport)。又参考了libpng头文件,据说老版本的VC++或者BorlandC编译器,使用的是 __export,新版本的是使用__declspec(dllexport)

花了近一个小时,才把所有头文件中声明的函数修改完成。

编译helloworld来测试动态库时,居然报错:

error LNK2001: 无法解析的外部符号 _Load_Graph_Icon_LCUI_18x18

该函数在img_icon.c定义里,头文件中的函数也加上了__declspec(dllexport),为何生成的库里没有它?

知道问题原因了,除了要在头文件里每个函数声明前加LCUI_EXPORT,源文件里也要这样做。

动态库的体积比静态库小太多了,主程序只有8KB。。。

Visual Studio 2012还不错,鼠标移动到函数名上,就会有该函数的原型以及函数注释,移动到数据类型名上,也会有该类型的注释,FreeType项目的注释蛮多的,在VS2012上显示的效果也可以,看来也应该考虑完善一下LCUI头文件中的注释了,但不会在这次版本更新中完善。

2013-2-25

为文本框添加了占位符(placeholder)功能,可设置一段文本作为占位符,在文本框为空时会显示它。

鼠标游标的绘制,还是要和部件更新及绘制操作 同步好些,至少鼠标拖动窗口时不会有画面不同步的问题,把鼠标游标的位置更新放在部件更新前。

LCUI的App管理代码需要考虑移除,之前是考虑到处理多个LCUI程序,但直到现在还是在单进程上处理界面显示,也没创建多个线程跑多个LCUI_App实例(实例是啥?我也不知道,感觉在这里用这个词适合些)。
移除的话,那么部件数据、部件图形、部件事件以及屏幕更新,这些就能在单线程上按顺序执行了。

需要解决问题:有时为Label部件设置文本后,会使文字异常。

需要为label、button、window等设置文本的函数添加宽字符版本,宽字符版函数名里加上W,ASCII版的加上A,UTF-8版的则保持原样,例如:
Label_WText()、Label_AText()、Label_Text()。

把源文件改为带BOM的UTF-8编码的话,VisualStudio编译时就不会给警告,部分包含中文的常量字符串也不会给个错误说常量字符串中包含换行符。
但是,编译test_textbox.c后运行,汉字是乱码的,源文件是不带BOM的UTF-8编码,改成带BOM的后就会使汉字乱码,这是什么情况?

2013-2-27

charset.c和textbox.c的代码做了修改。

修改label部件代码,设置label部件的文本后,会等待LCUI在更新部件数据时更新文本位图。之前是在主线程设置文本后直接更新文本位图,这会与LCUI线程冲突,导致获取的字体位图异常。

expressjs主页设计的不错,尤其是API参考页:http://expressjs.com/api.html,可以借鉴一下它的网页设计,以应用到我的主页上。

2013-3-2

主要修改了各个头文件及源文件开头处的版权声明。

2013-3-3

无BOM的UTF-8,VC的编译器会默认当成GBK的,这样就造成LCUI的文字显示乱码。

改了一下宽字符版本的函数的命名风格,Label_WText()改为Label_TextW(),字母W放在后面去了。

2013-3-6

在windows下无法打开png图片,记得之前是可以打开的,哪里出了问题?libpng的测试程序是运行正常的,更新libpng库后,再编译LCUI,测试还是有问题,排除 libpng库有问题 的可能。

windows下的按键输入处理,在这个版本中就不完善了,感觉需要花些时间弄,目前还没什么好的思路。

windows下生成静态库、动态库实在是太慢了,每次测试程序都要等20+秒,linux下用gcc重新编译整个项目,外加链接成动态库,等待的时间都没这么长。主要面向的平台还是linux算了,windows仅供演示普通程序之用。

2013-3-7

部件显示顺序出了问题,虽然是按顺序调用Widget_Show函数对部件进行show操作,但在处理时,是按照部件队列中的部件排列顺序处理的,排列靠前的部件会优先进行show操作。

解决方法:修改LCUI_Widget结构体中的更新队列,将该队列改为用于记录子部件的更新记录,LCUI_System结构体中再添加个队列,用于记录根部件的更新记录。

照片查看器的源代码已经修改完成,部分小BUG已经解决,测试正常,没添加新功能。其它测试程序有待修改,正考虑是否需要写个教程,主要讲如何用LCUI实现照片查看器。

2013-3-8

部件内边距的测试程序有问题,窗口客户区设置内边距后,没变化,后来才知道,每次窗口更新,都会重置内边距,好吧,在测试程序里加个区域至客户区,把其它部件加入至这个区域,就能看到为这个区域设置的内边距的效果了。

2013-3-9

同一个图像,被作为多个按钮的背景图,在销毁按钮时,由于该图像已经被释放过,再次释放会导致段错误。修改一下:设置的背景图不会被LCUI自动释放,需要开发者手动释放,有多少次Load_Image,就有多少次Graph_Free。

添加了LCUIApp_AtQuit函数,和atexit函数的功能基本一样。

static定位类型的部件位置处理有问题,有待修改。

已修改完成,除了在父部件尺寸改变时更新STATIC定位类型的子部件的位置外,子部件在Show时也会进行更新。

运行测试程序时,发现LCUI退出时并没有撤销程序创建的线程。

原来是在撤销一个线程时,删除了它的结点,第i个结点已经向前移动一位,在读取第i个结点时就读不到,解决方法就是改为一直读第0个结点,并撤销该结点记录的线程。

定时器线程改用_LCUIThread_Create函数创建。

测试进度条时,发现有个线程在LCUI退出时并没有撤销,稍微分析了一下,问题出在LCUI的系统线程上,由于系统线程不在线程树中记录,导致在创建线程时将该线程ID添加至新的结点里。

解决方法:在创建线程时,判断当前线程是否为LCUI系统线程,是的话,就用加入至系统线程的结点里。

整理了一下测试程序的源代码。

git搞得好蛋疼,想将github服务器上的代码库同步到本地,而本地有个未添加的commit,不准同步,若提交commit,那就不好同步了,搞得我直接删除代码库,再重新clone下来,但耗时太长。

而在linux下,clone下来的LCUI目录内的文件不能修改,不能从压缩包内直接拖文件覆盖进来,用命令行是可以,但麻烦。直接chmod 777更改目录内所有文件的权限,那又会多出一个未提交的commit,涉及到大部分文件。

2013-3-10

更新了项目主页上的图库中展示的效果图。

0.13.0版本已经发布。