LCUI 1.0.0 Alpha 开发日志

2013年11月25日  ·  44856 字  ·  阅读

2017-04-17

准备发布 1.0 alpha 版本。

2017-04-12

需要将 LCUI 编译成 Windows 运行时组件(Windows Runtime Component),第三方库和头文件需要改为存放至 vendor 目录,build 目录下的 VS2012 重命名为 windows。

2017-03-30

现在剩下的还有缩放功能,需要添加 dp 和 sp 单位支持,具体可以参考 Android 的做法,弄完后再添加几个函数接口,用于设置全局缩放比例。

CSS 中有4值概念:定义值、计算值、使用值、实际值,而在 LCUI 中使用值和实际值是混在一起的,例如部件的宽度 widget->width,在 100% 缩放比例下取出来的是 100px,而在 150% 缩放比例下取出来的却是 150px,需要考虑处理这个问题,毕竟有的时候需要手动写代码控制部件布局。

看上去这个功能牵扯到的地方比较多,工作量会比较大,那就不放在这个版本里完全实现了。接下来再修修几个内存泄漏问题、调整一些细节、再添加个英文版的 LCUI 主页就能发布 1.0 alpha 版了。

2017-02-28

换成 switch-case 后发现问题出在 libjpeg 的错误处理上,有的 jpg 图片文件会读取失败,报错信息为:

Improper call to JPEG library in state 203

在初始化图片读取器后还需要调用 setjmp() 设置跳转点。

2017-02-27

又出现了新问题,在以函数指针的形式调用 LCUI_ReadJEPG() 时会出现异常:

Run-Time Check Failure #0 - The value of ESP was not properly saved across a function call.  This is usually a result of calling a function declared with one calling convention with a function pointer declared with a different calling convention.

看来需要改用 switch-case 的形式来判断调用哪种函数。

2107-02-26

整理了图片读取功能,基本上算是重写了这块代码,现在 png、jpeg 和 bmp 读取器支持从自定义的数据流中读取图片数据。png 和 jpeg 的函数库是用 setjmp() 和 longjmp() 做异常处理的,setjmp() 会保存当前运行环境,等 longjmp() 被调用后就会恢复运行环境,但需要注意的是 setjmp() 所在的函数必须在 longjmp() 被调用时还在运行,否则会出现帧不存在的异常,因为在跳回到 setjmp() 处时它所在的运行环境已经被销毁了,毕竟在其它语言中也不允许将 try 和 catch 拆分到在两个独立函数里。

2017-02-12

surface 和 widget 之间的属性同步是双向的,这很容易出现循环同步的问题,例如:用鼠标拖动调整窗口尺寸时,surfcace 收到消息并调整尺寸,然后同步至 widget,widget 调整尺寸后又同步至 surface,surface 调整窗口后触发了消息,就这样一直循环。简单的办法,surface 的位置和尺寸只能由应用程序主动调用指定函数来调整,不受 widget 影响。像 widget 的 min-width、min-height、max-width、max-height 这四个属性需要单向同步至 surface。

2017-02-05

UWP 版的 LCFinder 有时界面会卡住,用调试器暂停运行后发现程序一直阻塞在 m_deviceResources->Present() 里的 m_swapChain->Present1(1, 0, &parameters);,代码注释里是说这个函数会让应用程序在下一个 VSync 前进入休眠,怎么突然就休眠这么久?查看 UI 线程时发现在调用 LCUIMutex_Lock() 锁住部件互斥锁时也被阻塞了,看上去是线程安全问题。

LCUI 的界面更新和渲染是在单独的线程上进行的,这样做反而增加了复杂度,各种部件操作还要加互斥锁,影响性能,像浏览器、Win32应用、UWP应用等都是把 UI 渲染和事件处理放在主线程上跑的,先处理各种任务,后渲染 UI,完全不用考虑线程安全问题。

2017-02-01

部件的坐标、宽高、内间距、外间距等属性值改用浮点类型。边框和阴影由于不影响部件的布局,对误差没有要求,差几个像素也没什么问题,所以不做修改。

以后向 Git 仓库推送的提交记录尽量用英文描述,反正也就那么几个简单的单词,用中文的话除了国人外就没多少人能看懂了。对于连翻译工具都懒得用的人,即使用全中文的提交信息也不见得对他们有多大作用。

2016-12-20

添加了圆角边框绘制功能,修改自以前的代码,删除了 RGB 像素格式判断,默认只当成 RGBA 像素格式处理,懒得再考虑其它格式。实际绘制还有些差异,四个角的圆角不对称,用 helloworld 例子程序来测试是没有问题的,但在 LC-Finder 中测试时,滚动视图内容时会出现崩溃问题。

2016-12-15

需要为部件添加一个 attributes 成员变量,用来保存自定义属性,这样方便部件与其它部件交互,例如:开关(switch)部件不自带文本,如果想将一个 textview 与它绑定,在开关切换状态时自动显示“开”或“关”,可以为这个 textview 添加 data-bind 属性,值为 switch,这样 switch 在状态切换时,获取附近 data-bind 属性值为 switch 的 textview 部件,并设置它显示的文本。

2016-11-25

需要调整驱动接口,目前是采用 LCUI_InitXXXX(driver) 这样的函数原型,而且是写死在 LCUI 的初始化函数代码中的,不能在应用程序的代码中注册和使用新的驱动。LCUI_Init() 函数默认是初始化全部功能的,需要添加个只初始化基本功能的函数,像图形输出、鼠标、键盘这类驱动可以在应用程序的代码中单独调用。

最近写了些测试用例,有些测试用例用的功能比较多,都是直接调用 LCUI_Init() 进行初始化的,为了确保后面的测试用例能够工作正常,需要添加一个函数,在测试代码执行完后能够销毁 LCUI 相关数据。

2016-10-24

调整了 LC-Finder 的缩略图列表布局方式,由于取消了布局锁定,部件布局的更新变频繁了,只要有新部件添加都会刷新布局。在部件数量过多的情况下,布局耗时会很长,而当前的超时处理方式是直接终止本轮部件任务处理,导致其它部件的任务被推迟处理。为解决这个问题,可考虑为布局操作加入缓存功能,缓存上一次布局的进度,这样就能将布局任务分多次执行,腾出时间去处理其它部件的任务。

2016-10-16

测试 LC-Finder 的英文版本,发现纯英文的文本里空格有些宽,整段英文比较散,不太美观,已将空格改成 a 的一半宽度,之前是直接取字母 a 的宽度。不知道其他 GUI 系统中是怎么处理空格宽度的,比如等宽和非等宽字体的空格宽度都是怎么算的?

2016-10-04

在解决了几个内存泄漏问题后再次测试,内存占用已经降到 400 MB 左右,但依然存在内存泄漏问题。

2016-10-01

之前在 LC-Finder 中测试显示 30000 多张图片,结果占用了 800MB 内存,粗略计算的话,每张图片由三个部件呈现,那么,(800 - 64) * 1024 / (30000 * 3) = 8.37 KB,平均每个部件占用 8.37 KB 的内存,有这么多?明显内存泄露了。据说 linux 下有个 valgrind 工具可以用来检测内存泄漏,用了一下,感觉还可以,检测出了几处问题,主要有:可能会产生内存访问越界的代码、未初始化就使用的结构体成员变量、某处申请的内存未被完全释放。

2016-09-28

一直有换图标的想法,最近在 Dribble 看到了 Electron 的图标设计,感觉还不错,于是就参考这个风格准备做一个新图标,圆形改成六边形,六种不同颜色改成六种不同深度的绿色,中间改成 LC。最后的成品如下,看上去为各个色块间的加上渐变过渡效果让边界线模糊掉,感觉会更好些。

2016-09-15

有些纠结,当部件为禁用状态后,是应该只禁止响应鼠标事件,还是禁止响应所有事件(包括自定义事件)?这个禁止处理是该放在 Widget_TriggerEvent() 里面,还是放在外面?放在放外面的话,虽然 LCUI 不主动调用已禁用的部件的事件处理器,但用户可手动触发事件。

在浏览器中,disabled 属性貌似只对按钮和输入框有效,普通元素即使将 disabled 属性设置为 true,也依然能够响应事件。感觉还是不主动禁止响应事件为好,把决定权交给部件的事件处理器,如果某部件需要针对禁用状态做处理,只需要判断 disabled 属性是否为 true。

2016-08-13

其实也不用队列化部件任务,以当前的处理方式也能够实现部件任务的超时中断,设置个全局变量作为循环条件,再设置个定时器每隔20毫秒重置循环条件,这样当定时器超时时如果当前帧还没处理完所有部件任务,就让任务循环终止,等到下一帧再继续。

添加了样式表缓存,经测试在有大量相同样式的部件的情况下,样式计算速度有明显提升,界面没有出现卡顿好几秒的现象。

为选择器添加了个 hash 属性,用于记录这个选择器的哈希值,哈希值是根据选择器的各个结点名称(字符串)来计算的。在为部件匹配继承过来的样式表时,会先获取它的选择器,凭该选择器的 hash 属性值在样式表缓存中获取对应的样式表,如果没有则在样式库中匹配样式表,再存入样式表缓存中。有了缓存后,在有大量样式相同的子部件的情况下,就不用为每个部件重新匹配样式表了。

2016-08-11

CSS 样式库改用新的数据存储结构后,样式计算的耗时比之前要多,当部件数量超过 5000 个时,计算这些部件的样式要花费好几秒,在这期间界面会进入未响应状态,为解决这个问题,可以分批次处理部件任务,每一帧仅处理有限数量的部件,当部件任务处理耗时超过一帧的最大停留时间(通常是 10ms)时,直接退出本次任务处理,等下一帧再继续。为方便实现这个功能,感觉还是需要把部件任务处理改为队列的形式。之前有改用过队列,但那时出现了些奇怪的问题,所以又改回来了。

2016-07-25

之前的 CSS 样式库采用的是这种数据存储结构: 只做了一级分组,因为当初设计时觉得经过第一级分组后,每组分配的样式记录数量不会有多少,查找样式时只需要遍历该组下的样式记录并判断选择器是否匹配就行,然而按这种数据结构来检测的话,必须遍历所有样式记录,感觉这样做性能太低,因此,为了方便判断子部件是否会受到父部件状态的影响,需要修改 CSS 样式库现有的数据存储结构,以下是大致结构图: 改用这种数据结构后,检测时就可以跳过第 0 区块,直接从第 1 区块的样式记录中开始遍历查找与父部件匹配的选择器,只要有匹配的样式表记录,说明子部件需要更新样式。第一阶段只需要判断在父部件更新样式类和状态后子有没有新样式,不用再考虑哪些子部件应用了这些样式,因为通常父部件容易变化的状态是 :hover 和 :active,而大多数情况下,除了按钮性质的部件,都不会为这些状态添加样式,更何况是那种有很多子级部件的列表性质部件。

这次修改可以顺便加上“空间”(暂定名称)属性,用于标识样式表来源于何处,以后可能会加入样式表卸载功能,到时候只需要指定“空间”,就能卸载属于这个“空间”内的所有样式表。

2016-07-19

在移动、改变尺寸、显示/隐藏部件时,产生的无效区域改为直接推送至根级部件,在逐级推送过程中,判断当前无效区域是否在部件的可见区域内,一旦判断为不在可见区域内则取消推送该无效区域。这样做可以减少多余的无效区域的遍历和合并操作。对于拥有上万子部件的部件,实际可见区域最大也就是整个屏幕,如果为处于可见区域外的几万子部件处理无效区域合并操作的话,性能开销是非常大的。

2016-07-17

快速排序对于无序的列表是很快,但对于基本有序的列表却非常慢。貌似也没必要用快排,因为在 LCUI 中通常不会需要重新排列所有部件,所以,部件排序这块貌似也不需要优化。

父部件一旦样式类、状态发生改变,其子级所有部件都会重新计算样式,这个操作非常耗时,测试时才 5000 多个部件就已经让界面有卡顿感了,得想办法优化才行,问题是在父级部件发生变化后,如何高效的计算出哪些子部件样式会受到影响?

2016-07-15

部件排序算法改为快速排序,如果待排序的部件数量很少,感觉可以考虑改用插入排序,由于需要考虑到大量部件的情况,可以把插入排序替换成二分法插入排序。

2016-07-14

x11 的事件循环貌似收不到其它线程发过来的事件,之前显示窗口、修改窗口坐标和尺寸等操作也是这样,必须放在主线程上跑才有效,这方面还是 windows 好啊,其它线程调用 PostThreadMessage() 函数就可以发送消息到指定消息队列里。

现在暂时将 x11 的事件等待时长设置为 10 毫秒,避免 LCUI 的任务处理被长时间阻塞。

2016-07-08

开始弄 linux 支持,linux 下可有两种图形输出方式:帧缓存(FrameBuffer)和X11,先弄 X11 支持。X11 除了 API 文档外,其它示例代码都不好找,至少没有 Windows 的文档好找,毕竟做 X11 开发的人很少,一般都用现成的图形界面库。

在 linux 下用的 IDE 是 geany,感觉不好用,代码提示功能不行,各种函数定义的跳转功能也不好使,除了标准库的函数以及当前项目内已打开的源文件内的函数外,第三方库头文件定义的数据结构、宏、函数等都无法自动补全。看样子需要试试 eclipse 或 code::blocks。

貌似 X11 也和 windows 一样,消息循环是与窗口绑定在一起的,不创建窗口而单纯运行消息循环的话也收不到自己发的消息,X11 的 XSendEvent() 函数需要指定目标窗口,测试时将根窗口传进去后没有任何效果,返回值正常,但在事件循环里取不到事件。自己手动创建一个窗口后再将它作为目标窗口来发送事件,结果能收到事件。这个问题的解决方法有两种:

  • 创建隐藏窗口,专门用于接收各种消息,windows 下的支持就是用这种方法。
  • 在进入主循环时,先运行自己的主循环,处理 LCUI 内部的一些任务,等窗口创建后再选择一个窗口作为主窗口来运行事件循环。这种方法在单窗口模式下 LCUI 的图形输出窗口就是主窗口,但如果以后要弄无缝模式的话,如何在多个窗口中确定主窗口?这个问题现在可以不用考虑。

2016-06-29

CSS 解析器还不支持解析 .a.b.c 这样的交集选择器,以后再更新。

当父容器尺寸和子部件尺寸一样时,子部件的阴影会被裁剪掉,以后可以考虑添加 overflow 属性,以支持其它的内容溢出处理方式,但方式也只有 visible 和 hidden 这两种,因为滚动条不属于内部功能,需要滚动条的话得自己手动创建,所以没有 scroll、scroll-x、scroll-y 这几种处理方式。

考虑 LC-Finder 的多语言支持,需要添加一种部件,可自动根据标识符获取对应语种的字符串,看上去这种部件只需要在 textview 部件的基础上加几个函数就能实现,但不能直接修改 textview 部件代码,对于这种情况,需要部件支持“继承”功能,这样只需新建个部件类型,继承自 textview,然后自己再扩充一些方法就能行了。基类部件和子类部件的都可以有自己的数据,可以提供个函数,用于获取指定类的数据。

2016-06-19

记得以前已经为 TextBox 部件加了占位符、密码模式、滚动条等功能,然而现在修改的版本没有这些,难道这不是最新的版本?TextEdit 部件的单行文本编辑功能已经完成,接下来是多行文本编辑。

在 Windows 系统中可以通过响应 WM_CHAR 消息来获取当前输入的字符,包括输入法输入的中文字符。但要实现让输入法的候选词列表框定位在 TextEdit 部件处的话,还需要深入了解才行,要么也可以像某些游戏那样,自己响应输入法的消息,自绘合适的输入法界面。

2016-06-17

TextEdit 和 TextView 有些 CSS 属性是共用的,例如:color、line-height、font-szie、font-family 等属性,如果在 TextEdit 里再重新写代码处理这些属性解析的话又感觉有些多余,要么把这些 CSS 属性列入预置属性里,但感觉还是有些多余,因为其它类型的部件并不需要用到这些属性。现在的样式表是用一个数组来存储的,可以用下标直接访问,但样式表占用的空间都是固定的,不能按部件中的有效属性数量来自动调整大小。等到样式表比较大的时候就需要考虑减少内存占用了,可能会改用红黑树、字典来存储。

其实也不用在 TextEdit 里重新写 CSS 属性解析代码,TextView 已经注册过这些 CSS 属性的解析器,而在 TextEdit 中只需要获取这些属性的标识号,然后凭借标识号访问这些已经解析好的属性值即可。

需要加个 focusable 属性,用于指示部件是否能够获得焦点。

2016-06-14

开始弄文本编辑框部件,名称由之前的 TextBox 改为 TextEdit,代码懒得新写了,直接在原有代码的基础上修改。文本编辑框需要获得焦点才能输入,需要添加 focus 和 blur 事件,还得处理输入法的支持。

2016-06-06

LC-Finder 的界面刷新率有些低,得考虑改用支持硬件加速的 Direct2D 来实现图形处理,但现有的图形处理功能都是用自己写的代码实现的,用 Direct2D 最多就用到图形填充这个功能,而矩形填充、线条绘制、Alpha 混合、图像缩放、图像旋转等功能都用不到,有些浪费。除非对 Direct2D 的 API 做一层封装,并且可在“缺省”和 Direct2D 这两种图形处理引擎中切换。

CSS解析功能中需要加入 @media 查询功能以方便实现响应式布局。

2016-06-01

底层的触屏支持已经完成了,开始弄部件的触屏事件支持,到时候可以写个多点触控的测试程序。

windows 既然有 SetCapture() 函数,那么 LCUI 中也需要有类似的函数,之前为实现部件拖拽功能还要绑定系统级的鼠标事件,要是有这个函数就只需要绑定部件级的事件了。考虑到多点触控支持,除了捕获鼠标,还得添加一个用于捕获触屏事件的函数,并且支持单独捕获指定 ID 的触控点的事件。

2016-05-31

在窗口外捕获鼠标消息可以用 SetCapture() 函数实现。

2016-05-30

开始弄触屏支持,顺便调整事件数据结构,之前的设计中所有事件的数据都混在一个结构体中,成员变量利用率不高,有的成员变量的值在某些事件中是无效的,会有误导性,而且扩展的事件数量多的话,会使整个结构变得臃肿,因此,改用 union 联合体来容纳各个事件数据。

触屏拖动功能已经完成,但还存在问题,一旦手指移动到窗口外后松手,拖动并不会结束,也就是说窗口无法收到窗口外触发的 TOUCHUP 和 MOUSEUP 消息。

在触屏拖动开始后,需要屏蔽当前滚动层的事件响应功能,以避免拖动结束后触发鼠标点击事件。

2016-05-23

部件在追加根部件里时需要立刻计算出坐标和尺寸,比如 LCFinder 的缩略图列表,当前的效果是一开始缩略图都挤在一起,很窄,等到能获取到实际容器宽度时才会恢复正常宽度,而在加载缩略图项的时候会看到有缩略图项在左上角闪烁。要改善效果,需要在排列缩略图前能直接获取到实际容器宽度,并且在缩略图项添加到容器里时能直接计算出它的坐标。

还有一种方法:加个 ready 事件,当部件在完成一次更新后触发 ready 事件,而在触发事件前部件是不可见的。

2016-05-15

为部件计算出的样式表需要缓存起来,这样其它拥有相同样式类的兄弟部件就能够快速的得到样式表,毕竟为每个部件重新计算一次样式表太浪费时间。

2016-05-14

为实现部件的淡入淡出效果,花些时间完善了部件的 opacity 属性支持和绘制功能,但测试结果惨不忍睹,刷新速度太低,设置的定时器是每 20 毫秒更改一次部件的透明度,也就是一秒内最多有50次变化,而实际效果只有几次变化。

交集选择器的样式解析貌似有问题,匹配不到预设的样式,这个以后再解决。

总感觉互斥锁和条件变量用起来有些问题,打算改用其它线程间通信手段。

2016-05-03

假设有选择器 textview#txt-test.text.text-muted:hover:focus,那么应该拆分成以下选择器来匹配样式表:

textview
textview#txt-test
textview#txt-test.text
textview#txt-test.text:hover
textview#txt-test.text:hover:focus
textview#txt-test.text:focus
textview#txt-test.text-muted
textview#txt-test.text-muted:hover
textview#txt-test.text-muted:hover:focus
textview#txt-test.text-muted:focus
textview#txt-test.text.text-muted:hover
textview#txt-test.text.text-muted:hover:focus
textview#txt-test:hover
textview#txt-test:hover:focus
textview#txt-test:focus
textview.text
textview.text:hover
textview.text:hover:focus
textview.text:focus
textview.text-muted
textview.text-muted:hover
textview.text-muted:focus
textview.text.text-muted
textview.text.text-muted:hover
textview.text.text-muted:focus
textview.text.text-muted:hover:focus
textview:hover
textview:hover:focus
textview:focus
#txt-test
#txt-test.text
#txt-test.text:hover
#txt-test.text:hover:focus
#txt-test.text:focus
#txt-test:hover
#txt-test:hover:focus
#txt-test:focus
.text:hover
.text:hover:focus
.text:focus
:hover
:hover:focus
:focus

像.text .text-muted :hover :focus 这类选择器需要排序,因为 .text.text-muted.text-muted.text 是一样的。

2016-05-02

CSS 样式匹配还要考虑到交集选择器,例如:textview.text:hover,当前的做法是直接把这些选择器都拆开来分别记录/匹配样式,这会导致匹配到本不属于当前选择器的样式表。

2016-04-29

添加了 vertical-align 属性,对话框可以用它来实现垂直居中显示。

2016-04-26

准备弄对话框,对话框内容有最大宽度限制,并且内容框能够居中,还有按钮组的位置也要能控制居中或靠右,看来得加上 max-width、min-width、max-height、min-height、float等样式属性的支持。

2016-04-25

LCUI 的 window 窗口已经支持拖动调整尺寸,测试最大化 LCFinder 的窗口后,滚动缩略图列表时的画面刷新率很低,有明显卡顿。

2016-04-16

主循环和图形显示控制功能已经修改完毕,misc 目录更名为 util,补充了几个用于实现 linux 支持的源文件,但里面都是没有实际代码的空函数,以后有时间再补充代码,尤其是 x11 的支持代码,毕竟虚拟机里不折腾的话就无法使用 framebuffer,只能依靠 x11 的窗口来显示 LCUI 的图形输出。还顺便修改了 automake 配置文件,把x11的依赖检测功能加了进去。

2016-04-11

准备修改主循环和图形显示的实现代码,文件目录结构也需要调整。

2016-04-05

改了后又出现了新问题,阴影和边框没有绘制出来,还有绘制时的图形残留问题真碍眼,需要解决。

2016-04-04

改了一段时间的绘制相关的代码,尤其是阴影绘制,要考虑到有无alpha通道、以及覆盖还是混合模式,真麻烦,后来发现自己之前有说过可用一个临时缓存区来绘制这些内容,绘制时无需关心底层图形内容以及混合模式,我居然差点忘记这个了,撤销代码修改后感觉轻松多了。

2016-04-03

开始弄部件的无位图缓存模式,之前的绘制流程都只考虑到有部件位图的情况,绘制的内容大都是直接覆盖(比如背景色填充、阴影绘制),切换到无位图缓存模式后效果就是下面这样:

2016-04-01

看来主循环的实现代码得弄多份,linux、windows各一份,而 linux 系统上又得支持字符控制台和X11模式,字符模式就是纯粹自己的事件循环,而x11模式多了x11的事件。之前本想让主循环的实现代码只保持一份的,单独建个线程等待系统消息,然后转发给 LCUI 的主循环去执行,然而在初步尝试后发现 windows 中的 MsgWaitForMultipleObjects() 函数貌似只能等待当前线程的消息,这方法行不通,作罢。

2016-03-07

用宏定义事件ID至少能在头文件中看都有哪些事件可用,而用字符串标识事件的话就没地方看了,这个得改,事件标识以ID为主,字符串为辅。

2016-02-15

event.c 的代码写得不咋地,需要改改。

2016-02-14

LCFinder 的各个视图的更新需要用事件来驱动,每当数据变化时触发相关事件,绑定该数据的视图就会收到通知,然后自己做处理,这样就不用在其他会修改数据的视图代码中手动补充调用代码,减少模块间的代码耦合度。

界面更新时还有残留图形内容,部分区域没被刷新。

2016-02-09

SHBrowseForFolder() 和 GetOpenFileName() 这类用于弹出对话框的函数放在非 windows消息循环的线程上调用会出现鼠标光标不显示的问题,看来要么把LCUI的主循环和windows消息循环合并在一起,要么找其它解决方法。

2016-02-07

找 windows 的API用法还是去msdn好些,网上那些博客、百科词条提供的资料不太靠谱,有的写了一大堆文字,就是不说明要什么头文件、依赖什么库,贴的代码要么就是纯文本、没缩进,看得不顺眼。

2016-01-26

遇到数据库操作问题,文件记录的唯一性是靠目录ID和文件路径决定的,那如何保证不重复插入数据?看了相关文章,貌似可以在文件信息表中加个字段保存来文件绝对路径,并设置UNIQUE约束,然后用 insert or ignore into 语句插入数据。

2016-01-20

虽然CSS样式数据是按照优先级存储的,但在计算部件样式时却是按固定的顺序合并样式表,并未按照实际优先级来合并。从打印的调试信息看来,本应作用于父部件的样式表居然也算进来了,还得花时间改。 VS2015中,显示的当前源文件的函数列表也不完整,漏掉了好几个函数。

2016-01-18

用测试程序测试发现CSS解析功能貌似没问题,部件在更改属性时也有递归为子级部件添加样式刷新任务的,还得花时间继续弄。 VS2015的代码自动格式化变得不太好用了,明明勾选了“键入 } 时自动设置块格式”,却没有任何效果,之前用VS2013可没这问题。

2016-01-17

原来是文本绘制时的坐标计算有问题,搞得我还花了这么长时间去验证图形重绘流程的代码。

2016-01-15

css 的type选择器不起作用,改用class选择器后对应的部件才应用到样式,优先级处理也有问题。可以考虑为CSS解析模块写个测试用例,用来验证处理结果。

2016-01-14

之前说的文字问题估计是文本尺寸计算错误导致的,一旦宽度少算了几个 px 会使最后一个字被自动换行到下一行。阴影效果有点问题,实际绘制出来的部件区域时大时小。

2016-01-13

之前没有做透明度补偿,RGB值在绘制文字时乘以透明度后就很暗了,需要再除以透明度来抵消透明掉的RGB值。用整型变量来计算RGB值总会有误差,白色文字会绘制成灰暗色文字,现在已经改用浮点数运算,测试效果正常。感觉用浮点数运算会增加耗时,以后看能不能再优化下。

2016-01-12

使用白色作为文字颜色时绘制出来的文字会很暗。测试时发现能看到文字一个个的显示出来,按理来说这点文字能一瞬间全部显示出来才对。部件的click事件触发次数超过一次后会有内存访问异常。

2016-01-08

看上去用标准文件读写接口和 dict 数据结构就够了,没必要用 redis。建个文件,然后把当前源文件夹下的所有文件路径写进这个文件里,用到时直接读取每个文件路径,载入到 dict 结构里。但首先得自己动手实现一个 dict 数据结构,参考资料有很多,比如直接看 redis 的 dict 实现代码。

目前比较担心 sqlite 的效率问题,例如要为某个文件夹下的所有文件添加相同的标签,如何避免重复添加?如果源文件夹下的文件列表缓存被删掉的话,那在同步文件列表时如何避免重复记录?也就是 update or insert 问题,网上与这个相关的内容蛮多的,到时候再看看。

2016-01-07

可以考虑用 redis 数据库,把源文件夹内的所有文件路径都保存到 redis 数据库中,以 dict 数据结构保存,当需要同步文件夹内的文件列表时将数据库中的数据载入到内存,之后遍历文件夹内的所有文件,并判断该文件路径是否存在于 dict 中(假设它叫A),不存在就说明是新增的文件,至于文件的删除判断,可以在遍历前再建一个新的 dict(假设它叫B),当文件存在时,把该文件信息从 A 移动到 B 中,遍历完所有文件后,A 中剩下的文件就是已经被删除的文件。

redis 的数据库文件有两个存放位置可选:1)放在源文件夹里,可以随着源文件夹一起迁移。2)放在程序所在位置的特定文件夹里,如果程序所在的文件夹被删掉的话,数据就都丢掉了。

至于内存占用的话,假设源文件夹内有50000个文件,平均每个文件名长度为128个字符,那么 50000 * 128b = 6400000b = 6.103MB,这只是纯数据,就算把 redis 数据结构本身占用的内存算进来,最多也不超过10MB,当然这只是估测,具体情况等实际用时才知道。

2016-01-06

准备弄个资源管理类的工具,和windows10的“照片”应用类似,不同之处是可以为文件添加标签,方便搜索,数据库是用sqlite3,有个问题比较纠结:如果把文件信息都记录到数据库里,那如何快速同步文件夹内的文件信息并计算出文件夹内都增加/删除了哪些文件?git 有文件追踪功能,能知道仓库中的文件变动,不知道它是怎么实现这个功能的,如果每次检测变更状态都是遍历所有文件和文件夹的话看上去有点粗暴,一旦有很多文件时应该会处理很久。

2016-01-01

从XML文档里载入的界面元素在程序里没法直接操作,嘛,还是先实现简单的ID选择器吧,看上去够用了,如果元素需要在程序里调用就加上ID属性。

但问题是该怎样索引ID?每个部件都记录子孙所有部件的ID?还是所有部件的ID都记录在一个地方?第一种方法感觉浪费空间,尤其是在最佳/移除子部件时操作繁琐,还是选第二种方案吧。

红黑树的函数接口不好用,需要改成链表那样的接口。

需要字典(dict)数据结构,一直手动建红黑树然后再自定义对比函数感觉好麻烦。

2015-12-30

结构体的定义有两种方式:

typedef struct ObjectRec_ ObjectRec, *Object;
typedef struct _Object Object, *ObjectPtr;

第一种方式在 FreeType 的代码中见过,而第二种是在 libxml,看上去都可以,有点纠结用哪一种。

2015-12-27

目前的混合算法会使颜色随着混合次数增多而变暗,估计是计算时的误差问题。

折腾了一段时间,终于搞定RGBA图层的混合算法了,算法如下:

outRGB = dstRGB * dstA * (1.0 - srcA) + srcRGB * srcA;
outA = srcA + (1.0 - srcA) * dstA;

之前拿错误的算法测试了好多次,绘制出来的文本透明效果异常,有的区域直接变成了纯黑色的,直到最后顿时领悟,混合其实就是两者的RGB值乘以不透明度然后相加,1.0 - srcA 得出 dstRGB 的混合比例,然后乘以自身不透明度 dstA 得出 dstRGB 的实际混合比例,outA 的计算方法也是如此。

2015-12-05

从文件载入新的CSS样式后,现有部件的样式不会自动刷新,以后还得把这个自动刷新功能加上,但问题是该怎样高效的搜索到相关部件?要是部件搜索功能做出来的话,那就能像 jquery 一样用选择器选定匹配的部件了。

想写个程序,但界面设计有些纠结,不知道该把程序界面设计成啥样,得找点参考才行,PC端好像没多少界面酷炫的软件,貌似可以去应用商店里的找点通用应用看看。听说 zune 的界面不错。

以后还得在 CSS 解析功能加入 media 支持,样式需要针对屏幕尺寸来自适应。

2015-11-30

之前说的做法是让图片缓存根据部件进行引用计数,要是部件在多个已设置 background-image 属性的样式类间切换的话,那每次都要从文件中载入图片,效率看上去有点低,这个以后再考虑改进吧。

2015-11-29

background-image 属性值直接存图像数据的话,处理样式表合并的时候不管是直接复制指针值还是复制整个图像数据都感觉有些问题,复制图像数据内存开销大,复制指针值又不好释放图像数据的内存。在更改 background-image 属性值后,之前的图像数据又该怎么处理?之前是想让应用层的代码自己处理图像数据的分配与释放,LCUI层的代码只管用,但现在样式表的是由LCUI处理的,看上去有些冲突。

看上去让 background-image 属性值存储成字符串是可行的,字符串复制操作的内存开销不大,可以在更新样式的时候再载入图像数据,但从文件载入图像数据会增加UI线程耗时,应该弄成异步的,等载入完图像后再应用背景图像。

有个新方法,让 background-image 属性支持两种类型值:图像数据 和 图像文件路径,当为图像数据时,由应用层代码处理该图形数据的释放,当为图像文件路径时,由LCUI管理图像数据,图像数据可以放到缓存里,然后根据路径建立索引,考虑到会有多个部件引用同一图像,可以加个引用计数器,当引用计数为0时释放该图像数据的内存。

2015-11-22

链表的代码需要整改一下,之前写的代码感觉还是有些奇葩。Linux 的链表是数据与链表结构分离的,它的做法是让数据包含结点,而不是常规的结点包含数据。这样做是可以,数据和结点只要有其中一个都可以访问到另一个,在删除数据的时候省去了遍历链表找结点的步骤,但这种做法需要再定义个结构来将结点和数据包含起来,而我想要“纯粹”点的数据,还是选择了常规的做法。要根据数据获取对应的结点也是可以做到的,在为数据分配内存时可以多分配一点内存给结点,像这样:


data = (Data*)malloc( sizeof(Data) + sizeof(Node) );
node = (Node*)(((char*)data) + sizeof(Data));
node->data = data;

数据块后面就是结点,结点地址 = 数据地址 + 数据块大小。在释放链表的时候只需要释放数据空间,因为结点和数据是共用一块内存空间的,要是单独释放数据和结点的话,会出现重复释放的问题。

2015-11-15

把平台及工具换成 VS2015 后编译,居然报错:

libxml2.lib(xmlregexp.obj) : error LNK2001: 无法解析的外部符号 __imp__printf
main.obj : error LNK2001: 无法解析的外部符号 __imp__printf
keyboard.obj : error LNK2001: 无法解析的外部符号 __imp____iob_func
main.obj : error LNK2001: 无法解析的外部符号 __imp__sprintf
dirent.obj : error LNK2001: 无法解析的外部符号 __imp___vswprintf_c_l
parse.obj : error LNK2001: 无法解析的外部符号 __imp__sscanf
libxml2.lib(xmlmemory.obj) : error LNK2001: 无法解析的外部符号 __imp__sscanf
libxml2.lib(xmlschemastypes.obj) : error LNK2001: 无法解析的外部符号 __imp__sscanf
libjpeg.lib(jerror.obj) : error LNK2001: 无法解析的外部符号 _fprintf
libjpeg.lib(jerror.obj) : error LNK2001: 无法解析的外部符号 _sprintf
libjpeg.lib(jmemmgr.obj) : error LNK2001: 无法解析的外部符号 _sscanf
MSVCRTD.lib(vsnprintf.obj) : error LNK2001: 无法解析的外部符号 __imp__vsnprintf
MSVCRTD.lib(vsnprintf.obj) : error LNK2001: 无法解析的外部符号 __imp___vsnprintf

标准库的函数都未定义?看上去需要重新编译依赖库试试,或者把依赖库都编译成dll动态库。以后得添加个配置,不将依赖库编译进来,以动态链接的形式调用。

2015-11-10

XML 文档结构也得好好设计一下,试着写了XML文档,以侧边栏菜单为例,刚开始是写成这样的:

<?xml version="1.0" encoding="UTF-8" ?>
<LCUI>
  <window>
    <sidebar>
      <sidebar-item icon="XXX">Home 测试</sidebar-item>
    </sidebar>
  </window>
</LCUI>

写着写着感觉有一些问题,sidebar 和 sidebar-item 部件只是简化一些操作,并没什么特殊功能,不太适合作为XML文档的元素类型使用,而且以部件类型名称作为元素名称也有些问题,首先,XML元素名称是必须的,没法在XML文档中使用无类型的部件,而实际上创建部件时部件类型并不一定要指定;其次,元素类型名称的长度一旦多起来会影响XML文档的美观,如果元素类型名称中还包含减号或下划线,那看起来更加怪异。

如果只是简单实现侧边栏菜单的布局及样式,看上去只需要设置元素的 class 属性即可实现效果,但这样做的话,界面效果会太依赖CSS,XML就写得像HTML一样。

嘛,重新调整了一下:

<?xml version="1.0" encoding="UTF-8" ?>
<lcui-app>
<resource type="text/css" src="resource/main.css"/>
<resource type="text/css" src="resource/font-awesome.css"/>
<resource type="application/font-ttf" src="resource/fontawesome-webfont.ttf"/>
<ui>
  <widget type="window">
    <widget class="sidebar">
        <widget id="item-home" class="sidebar-item">
          <widget type="textview" class="fa fa-home"></widget>
          <widget type="textview" class="text">Home</widget>
        </widget>
        <widget id="item-widgets" class="sidebar-item">
          <widget type="textview" class="fa fa-th"></widget>
          <widget type="textview" class="text">Widgets</widget>
        </widget>
        <widget id="item-settings" class="sidebar-item">
          <widget type="textview" class="fa fa-cogs"></widget>
          <widget type="textview" class="text">Settings</widget>
        </widget>
    </widget>
  </widget>
</ui>
</lcui-app>

字体文件和CSS样式文件可以用<resource>元素载入,type属性指定资源类型,src属性指定资源路径。GUI部件用<widget>元素创建,type属性就是部件的类型。XML元素的解析可以按模块划分,例如解析到<resource>元素时可以调用资源模块,而解析到<widget>元素时可以调用部件模块。也就是根据模块名称和调用方法建立一个映射表,然后在解析XML文档时根据元素名称调用相应的模块。

<ui>元素是一个容纳所有部件的容器,和HTML中的<body>类似,只能存在一个,XML解析完后返回的LCUI_Widget对象就是这个容器。这个容器仅仅是用来装部件的,需要加个函数用来展开容器,把里面的部件转移到目标容器中,然后删除这个容器。

CSS样式表中得加入 content 属性支持,这样字体图标的字符码就可以写到各个图标样式类 content 属性里,以后设置图标字体时只需要记住加什么样式类即可,不用再手动写具体的字符码了。

2015-11-09

之前部件在创建后默认添加至根部件里,而且是不可见的,一旦部件数量多的话,手动写代码去显示它们感觉很麻烦,需要改掉这个设定,部件创建后不属于任何部件,且默认为可见状态。

2015-11-04

XML解析出来的界面元素该怎样存储?指针数组?链表?还是弄一个根部件来存? 指针数组和链表看起来不好操作,得到后需要自己手动释放内存,而且也不方便从中选择特定的部件来操作,比如为按钮绑定点击事件什么的。还是返回一个根部件吧,以后会再考虑添加一个函数,用于根据ID来获取部件。

XML解析功能用不了多少代码,也就是遍历结点,创建部件,主要代码已经添加,等后面再实际测试一下。

2015-11-03

在 windows 下想用libxml2有些麻烦,官方给的已编译的库文件用不了,链接时报错,错误提示是说函数未定义,除去网络库接口,还有些是zlib库的,例如:gzopen()、gzread()、gzwrite(),明明zlib静态库是已经包含进来的,后面懒得折腾就自己下载源码编译了,libxml2依赖libiconv,而libiconv源码包里的文档建议用cygwin环境编译,懒得弄,直接修改libxml2的头文件配置宏,把libiconv禁用掉,顺便把 nanohttp 和 nanoftp 也禁用掉了,因为这两个模块需要再添加依赖项 ws2_32.lib 才能用,反正用不到。重新编译libxml2后可以使用。

2015-10-28

找了“混合模式”相关的资料,混合模式有:正常、溶解、正片叠底、叠加、排除、差值等,我比较想知道PhotoShop中合并图层时使用的是什么算法,相关文章里给出的公式都没考虑到透明度。

手写HTML有些麻烦,以后考虑用 markdown 语法写文档,然后转换成 HTML页面,方便管理。

目前对这网站的页面效果还不太满意,以后再花时间改改。

2015-10-26

参考了网上的 “CSS 优先级机制” 相关文章,之前说的匹配度其实就是文章中的“权值”,可以在选择器创建的时候顺便计算出权值,这样按优先级排序也就方便些。

2015-10-24

之前的样式表的匹配优先级只由添加时间的先后来决定,现在再追加一个判定条件:样式表的选择器(即:作用对象)。优先级的判定规则:选择器匹配度高的优先,若匹配度相同,则添加时间较新的优先。举个例子:有 A(选择器:button .text)、B(选择器:.text)、C(选择器:button:hover .text)三个样式表,先后添加A、B、C,那么,实际匹配优先级应是:C、A、B,

2015-10-13

文字透明度降低是因为混合算法的问题,混合文本图层混合时,文本图层的整体透明度都被部件的全透明图层拉低了。这个以后再解决。

2015-10-06

添加了 font-family、font-size、font-style 的解析支持,之前整的字体模块有些问题,做了些调整,弄完后测试发现绘制出来的文字变细了,而且透明度低了,还好 master 分支上是字体正常时的版本,可以对比两个分支的代码,看是哪里的问题。

添加了 color、line-heihgt、text-align 的解析支持,测试时好像有些问题,以后再继续整整。

2015-09-24

接触到了 flask,总之它的设计让我有种莫名的兴奋,说到设计,感觉现在 LCUI 的设计还不够有逼格,但目前也想不出什么好玩的设计。

字体的颜色、大小、风格等样式需要支持继承,容器部件设置了字体相关样式后,该容器的子级部件都会应用这些样式。嘛,现阶段可不用实现继承。

2015-09-20

CSS解析器需要支持扩展,能添加新的属性和对应的属性值解析器,单纯的添加倒是好做,但问题是动态添加的属性不能在样式表中直接访问,因为这个属性在表中的位置不一定是固定的,只能在注册属性后才能知道,那么,需要建个映射表保存属性的位置。样式表的长度是动态变化的,需要在表末尾设个NULL,确保遍历范围不越界。

样式表是有了,但扩展的属性是否有用还得看部件自己该怎么应用,需要为部件类记录加个样式表更新的回调函数,在基础的样式更新完后,如果该部件类有登记处理函数,则调用这个函数去处理扩展部分的样式。

2015-09-10

部件需要初始的样式数据,不然在切换CSS样式类后,由于当前应用的样式表与之前的不一样,会有一些残留的样式没被重置。

现在弄的侧边栏里需要用到图标,而图标是用特定字体文件里的,需要让 css 处理模块支持 font-family 属性,这样就能够方便的在各种字体间切换。

有的 UI 库有专门的布局元素来控制UI控件的布局,比如用BoxLayout、StackLayout、GridLayout之类的,在CSS中是用 position、display 属性控制元素布局的,如果让 LCUI 的部件布局和CSS中一样用 position、display 属性的话,那得先好好了解一下 css 的布局原理、处理流程。

2015-08-08

用代码写界面好麻烦,需要弄个配置文件,然后再写个转换工具,把配置文件转换成C代码,随着主程序一起编译。

2015-07-24

pthread_cond_timedwait() 的返回值是EINVAL,看来是参数的问题。后来发现是超时时限的计算方法有问题,tv_nsec 取值要小于 1000000000。之前一直在纠结 pthread_cond_timedwait() 的用法,超时后没有得到信号怎么办?要不要手动解开/锁上互斥锁?看了相关文档后,其实只要认定在调用 pthread_cond_timedwait() 前后都是锁上互斥锁的状态就行了。

2015-07-04

样式表的更新方式效率不高,各种遍历,没做优化,需要找一种能够快速确定需要更新样式的子级部件,减少无用的遍历次数,毕竟父级样式不一定会影响到所有子级部件,但现在还是先暂且用着吧。总感觉设计上有些问题,思路不够清晰,让人有种不安和迷茫,代码写着写着就没多少兴趣继续写了。

2015-07-02

之前在弄样式库纠结了一段时间,主要是读写操作,刚开始想的方法很复杂,整了个很杂很深的树,用树的结点记录样式块,到后面纠结问题时才发现根本问题就是如何搜索符合要求的样式块,其实数据结构只需要保存样式块+作用范围,查找时直接判断这两个即可。

加个规则:在部件创建后以及变更的容器、类名、状态时,会更新一次样式表,且会重新计算一次样式。但这样又有些问题,如果某些效果是靠写代码直接修改部件的坐标、尺寸、透明度等样式实现的话,一旦更新样式表,样式就会被覆盖掉,要是再为部件加一个自定义样式表的话,设置样式的代码又很难看,写起来也更麻烦,好蛋疼的样子。

有时命名会遇到问题,名字长不好看,短也不好看,合适的词不好找,即使用中文也无法简单的描述出具体含义。

2015-06-17

打算折腾部件事件处理,先从重写按钮部件开始,写的时候按以往的方式写一堆代码设置各种属性又觉得有些别扭,现在的需求是要像HTML网页+CSS样式那样,可以将样式块弄成样式类,向元素追加类名后可以覆盖原有样式,而移除指定样式类名后元素样式会还原。目前的部件样式是写成结构体形式,用起来有些麻烦,尤其样式块覆盖功能,实现起来会很麻烦,于是乎,打算写成以数组的形式存储所有样式属性值,这样用一个for循环遍历数组覆盖相应属性值就能搞定了,为了能够方便访问属性值,再定义一个枚举,把一堆样式属性名称填进去,用枚举值作为数组下标即可访问对应属性值,比如设置背景色可以这样:widget->style[key_background_color] = 0xffffffff; 嘛,加key_前缀是为了避免与普通变量产生冲突。

既然要做这个,那么可以顺便把部件样式库功能搞定,以后只需要接入CSS解析功能就能直接用.css文件设置部件样式,省的再去写一堆代码。

2015-06-13

用了一下午的时间,最后提交代码时发现居然只修改了这么点代码,我靠,好像大部分时间都在调试去了。

2015-05-23

还是先做事件吧,看到按键事件,想起以后还要解决按键输入问题,什么大小写啊,输入法啊,组合键啊,之类的,真够蛋疼的。

遇到一个奇怪的问题,有时创建的windows窗口虽然显示出来了,但没法操作,鼠标点击不到这个窗口,在创建窗口的线程那里加个延时,可以解决问题。经过一段时间的测试,发现问题出在SetWindowLong()上,之前是为了全屏和窗口模式之间的切换而调用它来改变 windows 窗口样式的,先暂且注释掉。

2015-05-16

区域刷新有些问题,估计哪里算错了。

Graph_WirtePNG() 函数居然存在内存泄露,自己 malloc() 的内存在写入完毕后都 free() 掉了,难道png自己内部也申请了一些内存资源,要调用相关函数手动释放?

查看了 libpng 的 example.c 示例代码,在写入完数据后,还要调用 png_destroy_write_struct() 释放相关资源,问题已经解决。感觉各种图片格式的文件读接口写需要整整。

在 windows 平台上可以直接转发窗口消息至绑定的部件,之前还想收集起来再处理,其实在一般情况下都用不到全局的鼠标坐标和键盘事件的,也就只是 LCUI 内部在派发部件事件时需要用到而已,感觉需要整一下,LCUI 在 linux 下是默认打开并监听鼠标、键盘设备事件的,产生事件后再由相关函数响应再派发给相关部件,这里有的代码可以抽离出来,因为不是必需的。

2015-05-12

解决了区域刷新、阴影绘制上存在的一些问题,接下来有点想弄模糊效果,但看模糊算法,一个像素点的值取决于周围像素点的值,那么,在局部绘制时像素读取范围得需要在原有区域上再向外扩张相应大小,一层模糊图层倒还可以,但底下有多层模糊图层怎么办?一直扩张直到屏幕边界?假如有5层叠加的透明模糊图层,模糊距离都为20px,要局部重绘100x50的区域,那么就会这样:120x70 -> 140x90 -> 160x110 -> 180x130 -> 200x150,最终要重绘的区域尺寸是200x150,而且这样在扩张过程中还可能会与其它本来不重叠的区域重叠了,然后又继续扩张,呃,在绘制一个区域前还得先计算上层图层实际需要读取的区域范围。

2015-04-18

开始做部件绘制功能,正纠结一个问题:一个部件有多个图层,例如:背景色、背景图、文字,那怎么将这些分多次绘制的图层合并成一个图层?单纯的根据透明度来合并看起来会有问题,因为各个图层会受各自的透明度影响,导致混合后的图层实际绘制出的效果不同于分次逐个绘制。例如:全透明背景色+不透明背景图,如果是单纯的混合话,最终得到的是全透明的图,而实际效果是不透明背景图覆盖在全透明色区域上。得需要找到一个合适的算法。

2015-04-12

试用了VS2013,之前在编辑器中输入分号时当前行代码会自动格式化,本想关闭这个功能,结果发现VS2013可以设置代码格式,还可以设置在什么情况下自动设置格式,这个功能感觉还不错。话说,要是一个团队都使用这种配置,那么就能很方便的让所有开发人员都保持统一的代码风格了,省去了看代码规范文档的步骤,当然了,前提是都使用VS2013进行开发。

2015-03-23

windows 的窗口给人的感觉是开销很大,LCUI 中新建的 部件默认是处于顶级的,在无缝模式下,这些顶级部件都会被绑定在各自的windows窗体中,但有个问题比较纠结:是该在部件新建时创建个windows窗体与之绑定,还是加点规则,以其它方式来实现?前者感觉会效率低、有多余的操作,并不是所有部件在创建后都被当成顶级部件用。而后者又会增加代码量,目前的想法是:加个规则,新部件在创建出来后,默认不属于任何容器,必须手动将之添加至根部件这个容器中才能看到它,和JavaScript的jQuery用法类似,新建出来的元素必须添加至<body>标签中才能看到该元素。

2015-03-15

准备做 widget 与 surface 的事件绑定,感觉这种事件绑定不能和部件级事件混在一起,因为在解除部件事件绑定时可能会一起被解除掉,需要独立开来,那么可以用系统级的事件绑定。

2015-02-17

整理一下思路。widget 的脏矩形最终是存储在 surface 中,因为部件自己的图形内容变化会影响到整个 surface,处理完部件的绘制后还得更新 surface 中的内容。如何确定 widget 是否有被映射、并且能找到对应的 surface ?在处理脏矩形时,如何确定 widget 的脏矩形该推送至哪个surface?还需要考虑是否有必要实现以下需求:

  1. 同一个 widget 可以被直接映射到多个 surface 上。
  2. 同一个 widget 可以间接的被映射到多个 surface 上,如:子级 widget 映射至 A,父级 widget 映射至 B,A和B中都有子级部件的内容。

这两个需求感觉不是很重要,一对一的映射应该够用了,毕竟surface主要是封装一些系统GUI的相关接口,为LCUI与系统GUI提供一个中间兼容层,提高LCUI的界面与系统GUI融合度,况且,映射到surface上的主要是顶级部件。既然这样的话,可以建立一个映射表,方便查找surface和widget,这个映射表由GUI线程维护,而 surface 模块只提供位置移动、尺寸调整、绘制、事件绑定等功能。

需要加一个函数,用于合并部件及其子级部件中的脏矩形记录,GUI线程可调用这个函数获取脏矩形记录,然后在 surface 上重绘。之前的做法,除了处理部件的脏矩形,还得调用另一个模块的接口把脏矩形提交到屏幕脏矩形记录中。感觉模块之间不应该有太多的接口调用,应该让GUI线程作为中间层,承当widget与surface之间的通信工作。

2015-02-03

windows窗口的创建和消息循环要在同一个线程上,而消息循环不能放在主线程上,因为LCUI的主循环也在主线程上,没法做到同时阻塞等待两个事件源,目前有两种解决方案:

  • 将主循环和windows的消息循环合并,主循环有任务时就添加消息,让GetMessage()解除阻塞以立刻处理LCUI的任务;没任务时则可以处理windows消息。但感觉这样做会降低代码的独立性和复用率,要是在linux环境上做支持的话,是不是又得整一套解决方案?
  • 为每个Surface开一个线程,用于创建windows窗口和运行消息循环,但由于是异步的,在其它线程创建Surface时这个Surface并不会立刻得到windows窗口句柄,需要等Surface的对应线程处理完windows窗口的创建任务才行,在这之前,对Surface设置尺寸、位置等操作都是无效的,可考虑在Surface中加个任务缓存记录,缓存待处理的任务,等获得windows窗口句柄后再处理掉。

为每个Surface创建线程是不是有点奢侈?想只用一个线程处理所有Surface的windows窗口,但创建Surface时没法通知这个Surface线程去创建窗口并获取句柄,因为Surface线程要跑消息循环,而要发消息通知这个线程的话,又需要知道窗口句柄,这又回到上述的问题了。

有个PostThreadMessage()函数,至少Surface的处理线程是在创建时就能得到的,可以试试。

2015-01-28

在命名函数时不知道该用哪种词:render、paint、draw,看上去有层级关系,由基础到高级,即render包含多个paint,而paint又包含多个draw。

要想在测试中看到效果,得修改现有的显示处理代码,老代码懒得整了,反正要改,那就趁现在把surface与部件的映射功能弄好,代替原来那种显示模式,但需要花一些时间整理思路,弄清功能需求。

在windows下,一个surfae对应一个windows窗口,到时候实现LCUI的无缝模式时,就把根部件下的各个子部件映射到对应的surfae,由surface的控制代码将部件图形绘制到对应的windows窗口内。

2015-01-24

部件的位图缓存只缓存自身的位图就够了,没必要与子级无缓存的部件共享,因为这样做会让处理变得更复杂。在所有子部件都没有位图缓存情况下,虽然可以省去遍历子部件的操作,但是,如果有带位图缓存的子部件存在,那怎么处理?

Widget_BeginPaint()与Widget_EndPaint()需要适应用这两个情况:1)更新部件的独立位图缓存。2)重绘屏幕内容时,绘制无位图缓存的部件。前者用的是部件本身的位图缓存,后者用的是屏幕绘制器提供的临时位图缓存。

绘制流程:

  • 获取当前的脏矩形,引用脏矩形区域内的位图缓存。
  • 按照显示顺序,从底到顶,递归遍历子级部件。
  • 若当前级部件的不透明度低于100%,或脏矩形区域中包含边框的圆角部分,则为当前级部件准备一份与当前脏矩形相同尺寸的位图缓存,用于缓存部件内容的位图,也方便实现圆角边框、透明等效果,比如圆角边框,圆角外的内容是需要裁剪掉的,而裁剪操作需要在独立的位图缓存中进行。若部件没有位图缓存,则再准备一份与当前脏矩形相同尺寸的位图缓存,以记录部件自身的位图。
  • 对于不满足上述条件的,则直接使用上级部件的内容位图缓存,不用为实现那些效果而准备位图缓存。
  • 当前部件绘制完后,递归进子级部件,让子级部件将位图绘制到当前准备的内容位图缓存中,若当前没有独立的内容位图缓存,则引用上级部件的,若都没有,则引用初始的脏矩形位图缓存。
  • 绘制完子部件后,根据圆角边框的参数,对内容位图中圆角以外的区域填充透明像素,然后与部件自身的位图进行混合,根据部件当前透明度,将混合后的位图以相应透明度混合到上级部件提供的位图缓存中。

主要是需要判断出哪些条件下需要位图缓存、需要多少个、分别用于什么地方,判断出的结果会影响到子级部件的绘制处理方式。

2015-01-18

脏矩形是相对于相对于内容区域还是整个部件区域?相对于内容框的话,那怎么重绘内容框外的区域?那加个参数吧,指定是内容框、边框盒还是整个部件占用的区域。

2015-01-17

需先完成部件的绘制功能,能看到具体效果才好做,在这里确定一下绘制规则:

  • 在每帧画面绘制前,先重绘各个可见部件中记录的脏矩形,以更新部件的位图缓存,然后将脏矩形转移至根记录,用于重绘根容器——“屏幕”。转移时需判断当前部件是否被上层部件完全遮挡,若完全遮挡,则不转移。
  • 对于没有位图缓存的部件,若它的父级部件有单独缓存,则由父级部件托管,共享父级部件的位图缓存,向该部件添加脏矩形实质上是添加至父级部件。
  • 部件绘制采用递归方式进行,在绘制完自己的脏矩形后,会递归绘制没有位图缓存的子级部件。一般情况下,部件嵌套不会很深,因此暂不用考虑函数递归调用所产生的栈溢出问题。
  • 绘制根容器的脏矩形时,获取与该脏矩形重叠的部件,过滤掉被遮挡的部件,然后从底至上开始绘制每个部件。具体绘制方法是:先引用帧缓冲对应的区域,然后根据根部件的背景样式,为该区域填充初始背景,在后续的部件绘制中,就直接往这个区域填充位图。

目前是逐个绘制脏矩形的,应该够了,开多线程同时绘制多个脏矩形貌似效果不大,或许应用并行技术的效果会更好点。

2015-01-11

部件的base属性可用于记录已经过计算的各种属性值,这样可以减少计算量,在计算各种百分比单位的属性值时,只需要根据父部件中base里记录的值进行计算。

2015-01-10

之前设定是调用相关函数时直接更新部件相关属性,但现在有些问题,假设要改变部件尺寸,按这种做法,需备份当前部件尺寸,作为任务的附带参数,供执行“改变尺寸”任务时计算脏矩形;由于同种任务在同一帧下只能缓存一个,当在一帧下多次改变尺寸时,任务的附带参数会覆盖上一个,这会导致脏矩形计算错误,不覆盖的话,那用户自定义的任务怎么办?自定义任务的附带参数的处理方式不是由LCUI决定的,其参数可能是动态分配的,要是直接覆盖,那会造成内存泄露,那么,是否要再记录个“任务参数合并”函数?当存在任务合并问题时,调用预设的回调函数去解决。

2015-01-03

graphlayer.c 需要移除,硬性抽象出的模块有些别扭,表面上,抽象出了图层概念,让部件基于图层,图层呈现部件的视觉效果;实际上,图层和部件这两个模块有诸多重叠的地方,例如:内边距、坐标、尺寸、堆叠顺序、父子关系等,核心功能也就是图层叠加,部件模块中有的数据还要在图层模块中同步,这样做反而增加了维护成本和复杂度,又由于要尽量遵从高内聚低耦合原则,模块间的交互会有些限制,这会对一些功能的实现带来不便,既然这样,还不如直接将部件作为基础绘制单元。

2015-01-02

部件结构体中,style 用于记录部件当前的样式,而 base 中记录一些已经过计算的数据。style 主要供内部使用,一般在应用层用不到,也没必要强制干涉内部功能的运作,就算有需求也可以调用相关函数接口,因此,不在 widget.h 中提供具体定义,而 base 中的数据在应用层可能会用到,列如自定义部件位置、尺寸及布局,或实现自定义动画效果,但以后随着相关功能支持的完善,这个接口可能会变得不常用了,现阶段还是留着,保留一定的扩展性。

2014-12-24

审美观在变化,现在觉得那种拟物风格的界面并不太好看,如果是以前的我,估计会截然不同吧,毕竟以前没见过多少让人觉得惊艳、舒适的图形界面。某些界面(包括图标),其配色、布局和设计风格让人觉得有点粗糙、暗淡、邋遢、陈旧。某种风格的界面看久了就会觉得有些老旧。同样是扁平风格,有的设计会让人感到简洁、大方、舒适,而有的设计却让人觉得简陋、粗糙,像是未完全扁平化的半成品。

看某网站页面的文字是宋体,有种违和感,不太适合其扁平化风格,于是想改一下样式看看效果,结果发现其中有指定微软雅黑,但拼写错了。

网页样式

2014-12-21

任务处理功能完成了大概,不知道接下来具体该做什么了,仔细想想的话又觉得要干的事很多,想太多又容易烦躁,没心情搞。总之,先让整个LCUI能够完整的成功生成吧,然后运行进行测试,看情况慢慢修改/补充功能,完善细节。

部件的背景是否透明,由背景色的透明度决定,不用单独整个transparent变量来表示。

GUI的绘制功能需要调整,Widget的数据结构、接口以及相关规则还没设计完成,又要纠结一段时间了。

2014-12-18

之前是集中处理部件任务的,所有待处理的部件都记录在一个地方,虽然可以快速、直接的访问部件并处理任务,但处理顺序不确定。由于要实现上面的需求,需要能够以父级到子级的顺序进行处理,有什么方法可以快速直接、又能以父到子的顺序访问部件?

让每个部件记录各自的任务列表,处理时从根部件开始向子级部件遍历,一个一个处理,以前用的就是这种方法,但感觉不够快捷,就算部件没有任务也要遍历一次所有部件,如果部件数量多、嵌套层次深怎么办?貌似一般GUI不会这么复杂,况且遍历这点东西又不会消耗多少时间。好吧,为部件加个标记,用于指示它的子级部件中是否存在待处理的部件。

2014-12-17

由于需要让内边距、外边距、尺寸、位置支持百分比单位,在思考这些属性值的计算方法时有些纠结:当部件尺寸为auto时,需要根据子部件占用的空间来计算合适的尺寸,但子部件的各项属性也有可能是百分比单位,这种双向依赖关系处理得有些蛋疼,要实现得话,假设有个子部件得宽度为100px,左右外边距分别为20%,那计算出来的合适尺寸应该是 100px ÷ (100%-(20%+20%)) = 166.67px,如果有多个子部件呢?如果外边距之和大于100%呢?怎么计算?用谷歌浏览器做了测试,结果有些怪异,反复设置子元素内边距时(如:padding: 100%; 和 padding: 100% 0;),每次计算出的父元素尺寸和子元素内边距与之前几次的都不一样,看样子感觉像是在计算时先用父元素的尺寸计算子元素的内边距,然后根据子元素的尺寸及内边距,计算父元素的尺寸,结果每设置一次内边距,子元素的内边距和父元素的尺寸就变大一次,呵呵,懒得纠结这东西,定个规则:当父部件的尺寸为auto时,若子部件的内边距、外边距或坐标使用的是百分比单位,则计算出的值为0。

LCUI 的部件的默认是浮动显示的,相对于父部件进行定位,效果和HTML元素的 position: absolute; 样式类似,这种情况下,外边距作用不大,以后需要添加其它的显示方式,比如块(block)、内联块(inline-block),这两种模式的部件不能设定坐标,在部件尺寸、内边距、外边距发生变化时,LCUI 会重新定位当前容器中所有使用该显示模式的部件,这样可以省去手工设置坐标的麻烦,制作表格、日历等东西也比较方便。

这设计有点接近HTML,用设计网页的思想写GUI程序,这是要做成网页浏览器的节奏啊。

部件的停靠(dock)属性可以移除了,因为可以用它方式实现相同的效果。之前是参考微软的可视化GUI设计器中的控件属性而添加的,该属性决定控件停靠位置,例如:停靠在顶部、左侧,或是填充整个容器。

2014-12-14

在部件尺寸改变时,应该调整那些使用百分比作为位置、尺寸、外边距的单位的子部件,始终会有个部件会使用确定的像素值(如:根部件,一般情况下与屏幕尺寸相同),在有确定像素值的部件尺寸和外边距改变的时候,若父级部件尺寸是自动的,则重新计算父部件尺寸。

2014-12-08

今天撸了点代码,思路稍微清晰了点,对于那些会影响屏幕内容的属性,在修改后需要添加相应的无效区域(脏矩形),部件任务主要就是干这个,之前我居然把“重绘”也列入至部件任务中了。

“部件任务”这个东西,是为了缓冲频繁的部件属性变化,减少不必要的CPU使用率,因为有的属性变化,会产生脏矩形记录,而在添加脏矩形记录时,会对现有矩形进行合并、分割等操作,比较耗时,也占CPU使用率。之前的做法,部件任务中会有对应属性的备份,例如:移动任务,该任务中包含新坐标,处理任务时会根据当前坐标和新坐标,计算需刷新的区域,这存在一个问题,在提交移动任务后,部件的当前坐标并没有立刻变更,从表面代码上看,按一般逻辑,大都会认为坐标会更改为新坐标,为了让别人少点纠结,还是改改为好。

2014-11-17

之前了解了一下泰文中的喷射符,有些人回复中的尾巴会有这种字符,显示效果就是会有很长的东西从这个字符向外射。各种国家的文字有不同的写法,还好我在中国,LCUI 的文字支持方面,目前暂时只需要像堆方块一样把这些文字位图堆起来就行,以后如果要做其它国家的文字支持,可就不会像堆方块这么简单了,还得研究、折腾一番。

做部件的任务功能时有些纠结,这种任务在GUI线程上跑,每次帧更新都会处理一次,每一帧中每种任务最多只存在一个,新任务会覆盖旧任务,而任务类别主要有:移动、改变尺寸、绘制、显示/隐藏这几种,这些动作都会影响屏幕内容,但不确定以后会不会有新的类型,起初是像其它功能的做法一样,整一个记录,注册任务类型和处理函数,但问题来了:这个记录是针对全局的,还是每类部件的,还是每个部件的?如果是针对每个部件,这样增加部件的内存占用真的有必要吗?(虽然很小,但有点强迫症);针对全局的话,那得排除任务类型ID冲突的问题,仅仅是ID倒好办,动态分配ID,但这样的话就不能用宏代替ID号了,总不可能定义一堆全局变量存ID吧?判断任务类型时连switch-case都不能用了,一堆if-else多难看?这是任务类型ID,ID难记,用宏,宏名如果长了又难写,怎么办?用字符串,只需记住任务类型名,但是,又要解决名字冲突问题,得限制作用域,要把冲突范围缩减至同类部件吗?看上去貌似可以,那么就把扩展任务的处理函数存进部件类库中吧,GUI线程在处理任务时,如果任务不是预置的类型,就在库中找对应的处理函数,把任务扔给它处理。

其实这些任务还有优先级问题,对于有依赖关系的几个任务,例如:改变尺寸与重绘,应该优先处理“改变尺寸”这一任务,然后再处理重绘。

2014-10-30

感觉需要考虑一下 surface ,毕竟部件可以映射到它上面,而现在正在实现部件的各个功能模块,到最后才考虑的话,回头改也麻烦。

2014-10-29

部件的事件响应函数的定义格式已经确定:void callback(LCUI_Widget w, LCUI_WidgetEvent *e, void *arg),在调用Widget_BindEvent()绑定事件时可以传个额外数据,可在该函数中利用 e->data 访问,而调用Post()或Send()函数执行事件处理器时也可以传个额外数据,可利用 arg 访问。可能有人会想,怎么不弄成两个或者四个参数的呢?要么把这两个数据都弄进 e 里面,要么都弄成单独参数,为什么要一个放里面一个放外面?这个接口设计问题以后再考虑吧。

2014-10-28

GUI线程负责在每一帧画面更新完后将部件事件转为任务,而主循环线程负责执行这些事件任务,事件任务就是把参数传给事件回调函数并执行,完成事件响应。

2014-10-27

部件的初始定位类型(position)是NONE,表示不由LCUI控制部件位置,位置可动态修改,但考虑到要实现部件的静态(static)定位模式,即部件的添加顺序就是部件的排列顺序,除了容器部件大小改变外,位置基本是固定不变的,为了不影响到部件定位,部件需要另外用个列表来记录子部件,按z-index值从大到小排序,这个是显示时的前后顺序。

2014-10-26

为缩短函数长度,用了宏定义代替函数前缀名,想尽量短些,一个字符,够短,于是就想到了美元符’$’。

2014-10-24

写了一些关于新游戏的文档,有兴趣的可以看看:https://github.com/LC-Team/PunchAndKick/wiki,文档写在项目wiki里,不定期更新。文档包括了游戏功能需求、一些功能的基本实现方法、游戏玩法及规则设计。之前是想弄3D的,但感觉成本较高,玩家们为游戏添加扩展的技术门槛高,就决定弄2D的,毕竟对这个游戏有兴趣、有想法而且是搞3D建模的玩家是少数。用2D呢,要为游戏添加些装扮、装备、道具、地图、装饰等元素,简单点,可以直接拿其它2D游戏的贴图,然后用编辑器进行简单的设置;高级点,自己用PS之类的工具画,再写点脚本实现一些高级功能和效果。

新游戏的开发工作计划在完成新版本的LCUI后进行,可能会在LCUI桌面完成后,或者与LCUI桌面项目共同进行。

回到LCUI:单缓冲模式是需要实现的,毕竟应用界面中widget通常是静态的,不会频繁变化(例如:移动、改变尺寸、改变透明度),一些基本效果在单缓冲下也能实现,而高级效果(缩放、旋转等变换效果)用双缓冲模式方便些,毕竟要让widget的绘制操作尽量独立,只管画,不用关心widget是否有变换效果。widget在单缓冲模式下进行局部重绘会有临时位图缓冲,主要是为了方便实现透明效果处理,或许还会实现透明玻璃磨砂效果。

考虑到在高像素密度的屏幕上的显示效果,例如:苹果的Retina屏幕和智能手机的屏幕,为了提高清晰度,需要调整部件的缩放功能,对于有矢量图的文字,就不能当普通位图进行缩放了,比如当前字体大小是14px,那么当widget的缩放比例为150%时,在绘制应该将当前字体大小乘以150%,得出实际字体大小(21px),最后绘制该大小的字体位图。除了缩放,内置类型的widget也需要进行相应调整,毕竟在以后也是需要考虑支持手机平台的。

在进程模式中,LCUI自带的窗口管理器需要记录LCUI应用程序的运行状态和退出类型,以后如果要写任务管理器的话会用到程序的运行状态。退出类型主要分为正常退出、异常中断、强制终止,在LCUI应用程序异常退出时,会触发相应事件,一般只有“桌面”会绑定该事件,“桌面”的处理方法和windows差不多,显示个“应用程序已经停止工作”窗口给用户,到时候如果写了个LCUI的IDE,并且有较稳定的调试功能,可以在窗口中加个“调试”按钮,直接调用IDE进行调试。

如果LCUI应用程序的GUI线程阻塞过久,窗口管理器会在一段时间后或在用户对未响应的界面进行操作时,会触发一个事件,该事件也是被“桌面”绑定的,处理结果就是弹出”程序未响应”的对话框,并让程序的所有顶级widget白化(依旧和windows的做法差不多)。LCUI应用的GUI是否未响应,可以用类似于看门狗的方法实现,由于LCUI应用的进程是与窗口管理器保持通信的,可以让GUI线程每隔一段时间向窗口管理器发信号,告知自己的GUI处于响应状态,当窗口管理器长时间未收到LCUI应用的进程发的消息,则判定该应用为”未响应”状态。

看样子在LCUI的进程运行模式完成后,需要写个桌面,桌面的设计有些纠结,照搬windows的设计太没意思,需要一个有特色的设计,呃,做个程序员除了编码还要干UI设计师的活。既然有了自己的桌面,可以自己整个操作系统,linux内核+必要运行库+桌面,但貌似要写个系统安装程序,不然系统怎么安装到主机/虚拟机上?到时候可以学点新东西,而且可以干的事也多了,比如:写些替代品,告别linux桌面上那些用不爽的GUI程序,还要支持Xwindows、Wayland后端。

之前是用互斥锁来锁定widget的,这会消耗点时间,一两个部件可能没多大影响,但需要考虑在数量达到上千甚至更多的情况,感觉可以用一个变量代替,主要用来表示两种状态:占用和可用。

结构体的名字还是还是和typedef定义的名字好些。

通常是LCUI_Widget用的多,几乎不会用到LCUI_Widget,那么就在LCUI_Widget的typedef里加个星号’‘,这样在定义部件操作函数和定义LCUI_Widget指针时可以少打星号’*‘。

2014-10-19

入手了Lumia 830,发现Windows Phone 8.1的音乐播放器基本一样,歌词不能用本地同名歌词文件,播放音乐实际上是让系统自己播放,而浏览歌曲列表时的界面,我试用的几个播放器都一模一样,像是用系统提供的同一接口实现的界面。听说WP的应用只能访问自己目录下的文件,不能访问其它位置的文件,这么一说,像音乐、视频、照片等资源,WP应用要获取它们,就得用系统的接口,音乐播放器就是个例子,WP系统对文件访问做了限制,那么文件管理器的功能也就那么个样了,除非是微软自己开发的文件管理器,用隐藏的API实现受限功能。试用过“文件”这一应用,居然不能复制文件夹,难道WP系统没提供操作文件夹的API?

2014-10-02

感觉没必要把Widget结构定义写在公开头文件中,widget指针大多用于Widget相关函数调用,很少需要访问内部成员,而访问内部成员最多的是Widget的内部相关代码。可以分两个头文件,一个用于普通开发,用void代替LCUI_Widget;一个用于widget开发,提供完整的widget的结构体定义。

用void感觉有些不妥,还是加上属性和方法集吧,这样可以写形如widget->func(widget)的格式的代码,只要widget变量名够短,就能比直接调用Widget_函数的代码短。但是,widget方法集需要写在widget结构体的头部,虽然可以让它不写在头部,计算方法集的首地址需要考虑内存对齐,麻烦。

2014-09-16

目前有两个阻止事件冒泡的方法:1)靠事件处理函数的返回值;2)靠事件中的cancel_bubble是否为真。但都存在一个问题,由于一个事件支持绑定多个处理函数,如果它们有的要取消事件冒泡,有的要继续事件冒泡,怎么办?还是决定使用后面一个方法,这样省的写返回值。

2014-08-03

现在需要完成的功能有:布局处理、样式设置、样式更新、任务处理、事件处理。

任务处理是以前的部件消息,只是改了一下名字。部件有两个任务表,一个是当前正处理的,一个是待处理的,UI线程每次处理部件任务前都会切换任务表,这样就省的用互斥锁。任务表用红黑树存储,每个部件任务都需要注册,任务ID号则是树结点的Key值。每种任务只能存在一个,多个相同任务会被最后一个任务覆盖。

2014-07-23

需要调整LCUI_Widget的数据结构和函数接口。

有点想换命名风格,数据类型名都是用大写,函数也是,而变量却是小写+下划线。

之前是用align设置GUI部件的对齐位置,想改成用float(浮动),比如:值为 top left 则表示 浮动在左上方。但 float 与保留关键字 float 相同,那改成position吧,表示定位方式,那么 top left 就表示定位在左上方。

GUI部件的布局功能需要修改。

既然部件的坐标、尺寸支持用百分比表示,那就需要额外的变量来存储经过计算后的具体像素坐标、尺寸,其它同类型样式属性也一样,这些变量不写在Widget公共结构体中,主要供内部使用。

2014-07-13

感觉以前整的主循环代码有的没什么用,主要就是跑循环,如果要在主循环中实现阻塞调用,异步响应界面上的用户操作反馈的结果,就需要再嵌套个主循环。但如果不是在主线程上,就不能用这种方法,目前想到的方法是使其它线程(包括主线程)上的主循环暂停掉,等当前主循环退出后解除暂停。

2014-07-12

头文件及源文件需要进行整理了,本次整理的目的是减少头文件的依赖性,调整部分函数接口及其代码。

2014-07-05

现在的代码还处于设计阶段,最多只是验证修改的代码能否编译通过,需要改的地方有点多,各个功能模块有一定的依赖性,只好等到全都修改完再进行测试并体验实际效果了。

看下面这几张动画(动画出自 ui.cn,点击图片即可访问源页面):

有想用LCUI实现这些动画的想法,可以应用于以后写的应用程序或游戏中。第一个比较容易,一堆气泡聚集起来,之后消失,显示一个logo;第二个是用气泡组成文字气泡聚集过程中部分气泡会膨胀/缩小,聚集成文字后会有“弹性”的位置变化。第三个是火焰效果,感觉会有相关曲线公式来计算这些气泡的运动轨迹。其实也就是几个气泡的移动、膨胀、缩小、淡入、淡出,主要问题是需要如何控制这些气泡的运动轨迹以及缩放。到时候再说吧,至少要等到LCUI的修改工作都完成之后,但按现在这效率,不知要等到何年何月…

2014-06-29

LCUI_Widget结构体中的部分数据需要隐藏,没必要公开所有结构体成员,实在要操作某个成员数据,那就再提供相关函数接口。现有的LCUI_Widget可以改成LCUI_WidgetFull,即LCUI_Widget的完全版,把一些基本成员变量都放到前排,至于都是些什么变量,估计会是一堆只读的变量,而可写变量,直接修改的话一般也要调用相关函数以应用变更,还是调用与该成员变量相关的操作函数好些,省了几行代码。后排就是一些需要隐藏的成员变量/数据,不在头文件中公开声明,仅供内部使用。那么,现在的LCUI_Widget就是用来存放前排数据的,通过LCUI_Widget指针能显式访问的也就么些成员变量,而LCUI内部要完全操作Widget的数据,可以将LCUI_Widget指针转换成LCUI_WidgetFull*,这样就可以显式访问全部数据了。这个改动任务,以后有空再进行。

2014-06-22

利用C++的特性,可以直接重写基类的事件响应函数,对象在初始化时调用LCUI的C接口将函数与事件进行绑定,这样就省的再额外写代码来绑定事件了。但有问题,对象的成员函数与事件绑定函数接受的函数指针类型不一致。毕竟只是个C++封装库,感觉用C++重写LCUI更好些,毕竟从C++到C,会受到一些限制。

main.c 程序管理功能可以移除了,这个功能交给窗口管理器去实现。

线程记录管理功能也可以移除,之前记录已创建的线程主要有两个用途:

  1. 区分资源,主要是考虑到以后要在单进程上开多线程跑多个LCUI实例。
  2. 用于在LCUI释放资源前解除其它线程对资源的占用,避免出现非法内存访问。第一个不用考虑了,第二个功能其实没必要在LCUI中实现,应该由LCUI应用程序自己去实现。那么现在的thread.c的代码也只是封装各个平台的线程操作函数。

一时心血来潮,买了个《仙剑5:前传》的激活码,现在有点后悔了,要看剧情的话可以找网上的游戏视频,干嘛非要玩游戏。

2014-06-14

事件绑定时的各种事件还是改用字符串标识好了,用整形数值作为事件标示符真麻烦,还要为这个数值弄个宏定义。可采用红黑树保存这些数据,为红黑树添加支持回调函数,用于进行自定义判定,函数调用对效率的影响不会太大,因为这种结构,判断次数不会太多,就算树的最后一层有2^32个结点,总结点数约为64G,最多也就33次判断。

用了Ubuntu Gnome 14.10,之前用800P屏幕看时感觉界面不怎么样,不紧凑,屏幕空间占用大,但现在用1080P屏幕看后,效果还可以。才注意到窗口标题栏与任务栏合并了,还可以,能减少各个程序的窗口占用的屏幕空间。

2014-06-01

窗口在部件显示时才创建,如果部件处于显示状态时改变了所在容器,也需要处理部件的映射窗口,就像Chrome浏览器可以将标签拖出来成为一个新的Chrome浏览器窗口那样。

在单窗口模式下,要做的也就是把收到的消息当成全局消息进行处理,但多窗口模式中,这消息处理就成了问题,收到的消息是只作用于顶级部件内区域的局部消息,主要是纠结鼠标事件的处理,比如:mousedrag、mouseover、mouseout消息,鼠标会有在窗口区域外的情况,在窗口外面就收不到消息了,消息不连续,如果改成响应桌面的全局鼠标消息,又感觉干了多余的事,系统已经分发了一次消息,却还要收集消息并重新分发。

源文件中的函数定义前可以不用加__declspec(dllimport),只要保证在编译器在编译时能够知道函数需要导出就行。

暂时不用纠结消息问题,等把部件的窗口映射功能完成了后再纠结。

2014-05-24

之前提到的“GUI模式”可以叫“无缝模式”,VitrualBox的无缝模式想到的,可以让windows系统中的窗口脱离虚拟机屏幕,和直接在本地系统上跑GUI程序一样。部件映射的媒介就叫 Surface。

2014-05-10

看了w3school上的box-shadow的说明,发现弄错了,之前说的阴影尺寸实际是指阴影模糊尺寸。

部件的阴影绘制功能算是基本完成了,没怎么考虑效率,一般不会遇到需要频繁重绘阴影的情况。接下来就整GUI模式,在windows上总得像个GUI,LCUI的GUI部件显示需要脱离那个作为容器的windows窗口。

想写个2048,要完全模拟实现网页版本的2048的画面效果,需要为LCUI的部件添加渐变/过渡效果的支持,主要是用于实现方块移动、膨胀的动画效果。在网页中,实现该功能的CSS3属性叫transition,功能接口的参数可参考它的。

到时候还需要整个程序来对LCUI进行测试,什么样的程序?目前选择的是照片查看器,重新写个,参考其它相关软件,再根据自己的需求去实现它,能用的部件都用上,顺便更新各个部件的代码,毕竟有的代码是时候需要更新了。

2014-05-08

上图是Chrome绘制的阴影,阴影大小为50px,修改了阴影的X轴坐标,可以看出,上下边的阴影渐变不是从矩形边缘开始的,有一半渐变被矩形遮挡,一半渐变显示在外面。这个,需要调整一下阴影渐变绘制的起始坐标。

2014-05-07

算是完成了圆形扩散渐变的效果了,采用的是绘制线条的方法,计算出圆的各个点,从圆心向圆的边界绘制渐变线,但线条不是平滑的,有锯齿,组成圆形后,有些像素点并未被线条覆盖,圆形填充不完整。

2014-05-05

在阴影的尺寸从大变成小后,会有多余的刷新区域,原因是阴影参数在调整大小前已经更新,计算内部区域坐标时时根据新阴影参数计算的,无法得到阴影尺寸改变前的坐标。算了,一般不会遇到部件阴影频繁变动、且尺寸变化很大的情况。

2014-05-01

阴影的渐变算法已经搞定,采用的是物理中的直线匀减速运动的公式:s = vt-at^2/2,可以把阴影的大小当成时间t,把初始透明度当成路程s,透明度减少速度为v,而加速度为a,这样就实现了阴影渐变速度的曲线变化。渐变速度v可根据当前阴影大小来计算,而初始透明度需要低于256,设置为128即可,不然效果和直线渐变一样,这是为了腾出足够的距离来渐变。

剩下的就是四个角上的阴影绘制了,还要添加阴影绘制消息,在阴影参数发生变化、部件尺寸改变的时候重绘阴影。

2014-04-30

对比以下两张图中的阴影,同样是20px的大小,左边的阴影是直线渐变的,而右边的阴影看上去是曲线渐变的,要绘制出右边的阴影,需要一个曲线方程。

2014-04-24

由于工作的需要,最近在折腾html、css、javascript,javascript的基本语法和C一样,可以像写C代码一样写javascript,没多大难度,主要是学习一些对象和函数的用法。由于不熟悉细节上的规则,有时会碰到一些蛋疼的问题。等有空时自己再整整项目主页。

在看腾讯webQQ的网页源代码时发现了一段注释,好奇就访问了注释中给出的链接,了解到了腾讯的Web前端框架–JX,页面上的动画效果蛮不错的,有想用LCUI实现类似动画效果的想法,但最多只能实现个2D版本的,以后折腾游戏时可以往游戏里加些动画效果。

2014-04-18

可考虑添加部件的旋转支持,部件可倾斜、翻转显示,动态改变角度可实现部件的旋转效果。

可考虑添加缩放比例支持,这样可以提升GUI在高分辨率、触屏的环境下的体验。

2014-04-16

像素数据的存储格式到底该用哪个?ARGB、RGBA、BGRA?Linux的帧缓冲、windows的BITMAP中都是BGRA,而png、jpeg库读到的像素数据格式是RGBA的,纠结。

关于函数的参数顺序也有点纠结,例如某函数用于获取rect区域的graph,那么该函数的参数顺序是(rect,graph)好些,还是(graph,rect)好些?

改成一个一个的在windows窗体里重绘脏矩形的方式后,虽然内存占用少了,但效率很低,也就是拷贝像素数据、BitBlt至窗口这几个步骤,而一帧更新的脏矩形又不多,实际显示效果居然有卡顿。之前听说过GDI的效率低,实际体验过后才发现真的有点低。最终还是改回来了,每绘制完一帧后再把帧缓冲里的数据拷贝至windows窗体内。

2014-04-14

C++类库的源文件就懒得建目录分类了,都放在一个目录里,通过文件名的前缀来分类,例如Label部件的源文件,文件名为:GUIWidget.Label.cpp,所有GUI部件的源文件及头文件的前缀都是GUIWidget.。

Server进程不能占用太多的内存资源,不用记录所有部件,只需记录各个Client进程的顶级部件,并为这些部件准备单独的位图缓存,而隶属于顶级部件的所有子部件,则由各个Client保留并进行管理,Client进程主要负责重绘无效区域,并把区域范围及重绘后的位图发送至Server进程,让Server进程更新顶级部件的位图并绘制到屏幕上。

以下是LCUI进程通信模型示例图:

话说,这个和Wayland的工作流程有些相似,有点像在重复造轮子,以后要用于linux平台的话,可考虑添加Wayland支持。

那么,顶级部件的模糊透明化效果就由Server进程(窗口管理器)实现了,这么一说,顶级部件内的子部件就不能实现模糊透明化效果了,之前用windows 7时,也没见过窗口内的子窗口有Aero效果。就算要实现,效率应该很低,又没有硬件加速。

2014-04-13

怎么应付多种色彩模式的图像处理?有RGB、ARGB两种模式,目前的做法是针对RGB=>RGB、ARGB=>RGB、ARGB=>ARGB、RGB=>ARGB分别进行处理,感觉好麻烦,代码量多,以后要支持其它色彩模式的话更麻烦。

经过纠结,决定弄成统一的色彩模式,只考虑同种色彩模式的图像处理,不同色彩模式的图像处理,需要转换成相同的色彩模式进行处理。将ARGB设为默认的色彩模式,以后要添加其它色彩模式支持时,只需添加相应的转换函数、处理函数即可。可以为LCUI加个功能,用于设置全局色彩模式,主要影响到GUI部件的位图图像、LCUI输出的图像,以及内存占用。

如果支持多种色彩模式的话,那各种图像处理函数不是都要准备针对各种色彩模式的版本?如果是临时转换成支持的色彩模式再进行处理的话,又会降低效率。

2014-04-12

局部重绘功能都有了,那么可以添加单缓冲模式,单缓冲模式的部件,在GUI线程重绘屏幕区域时会调用部件的OnPaint()函数进行局部重绘。需要修改屏幕绘制方法。

如果想减少脏矩形重绘时的临时位图缓存占用的内存空间,可以添加一个功能,用于限制最大脏矩形,超过这一限制的矩形将被分割成若干个小矩形。

其实在windows平台下可以不用弄个帧缓冲,在进行屏幕重绘时把生成的图像数据填进一个临时的BITMAP里,然后将这个BITMAP填充至客户区内。之前的全屏模式可以调整分辨率,当帧缓冲小于屏幕尺寸时会对输出的图像进行拉伸处理,这个功能感觉没什么用,移除掉的话还方便绘制些。

之前说过,LCUI的图形输出有三种模式:窗口模式、全屏模式和GUI模式,在全屏和窗口模式中,LCUI的“屏幕”是一个系统窗口,映射的是根部件的内容。话说,可以把这个功能当成“部件的窗口映射”,或者是“多屏输出”,在原有的“单屏输出”功能的基础上做些修改,以支持“多屏输出”功能。处于GUI模式的时候就创建与顶级部件相同数量的系统窗口,把这些系统窗口当成“屏幕”,“屏幕”中的内容是根据各自映射的部件绘制出来的,就这样。

上面说的是映射功能,由于是多窗口,有些消息不能像原来那样统一共同处理了,比如按键和鼠标的响应,需要负责消息分发功能。还需要实现系统窗口与顶级部件的位置、尺寸、透明度等的同步。

现在先考虑一下多个LCUI应用程序的图形显示问题,在GUI模式下不用考虑这个,因为操作系统现有的GUI系统已经解决了这个问题。首先是多进程通信问题,可以用socket进行通信,但不知道效率如何,Xwindow是这样实现的,那么效率应该不会很低。需要一个Server进程,相当于窗口管理器,负责向其它LCUI应用程序的进程派发事件/消息,在这里就把LCUI应用程序进程当成Client进程,Server进程记录各个Client进程的部件,所有Client进程的部件都由这个Server进程负责绘制并呈现在屏幕上。

Server进程只负责少量的图形绘制工作,部件的无效区域由所属进程来绘制,绘制完后将无效区域、重绘后的图像数据以及相关数据发送至Server进程,让Server进程更新。

说到这里,感觉部件的窗口映射功能和多进程GUI显示功能有重叠的地方,如果能够找到共同点的话,就可以不用写多余的代码了。

仔细想了一下,这两个的共同点是都负责了窗口管理器的工作,以及事件/消息的分发工作,不同点是进行进程间的异步通信的是与否。

2014-04-11

LCUI_Graph的结构改了,图形处理相关的功能也要进行修改。

2014-04-10

如果要实现部件模糊透明,那么,有些区域要独立出去,例如边框,不应该把边框也算进去进行模糊透明。怎么判定哪些地方需要进行透明模糊处理?部件有个全局透明度,这个透明度不应该参与透明模糊处理,那么只能从部件图层的Alpha透明通道下手了。

还有阴影,如果是用上述第一种方法实现阴影,那么在实现模糊透明效果时,需把阴影排除在外。

在为部件添加无效区域时,应该根据部件的上层部件遮挡情况,调整实际需要绘制的区域,但是,遮挡的部件移开后,被裁剪掉的无效区域还是需要重绘的。这样做的话,感觉双缓存没存在感,越来越像单缓冲了,直接在重绘屏幕区域时调用部件函数进行局部重绘算了。

想到了一个模糊效果的实现方法:添加一个函数,用于获取部件指定区域背后的图像内容。对于启用了模糊透明效果的部件,每当部件底层内容有变化,都会向该部件添加无效区域。在Widget_BeignPaint()函数加些处理,若部件启用了背景模糊透明,则会获取无效区域的背景内容,根据实际部件内容,进行混合,然后再模糊处理。这种方法,是让部件在重绘时,把背后的图像内容映射至自己的图层内,感觉有点“假”,像是用障眼法。我个人认为“真”的方法应该是在绘制屏幕无效区域时实现,但这很依赖绘制器(渲染器?),话说,Windows系统有没有这样的函数?到时候实现LCUI的GUI模式时,如果能在WinXP、Win8上实现透明磨砂效果就好了,但我估计就算实现了,效果也很糟糕,尤其是在频繁移动windows窗体时会露馅,窗体背景可能会不同步。

在绘制器中实现模糊透明效果倒是有点头绪,但绘制时需要牵涉到部件属性,根据部件中记录的实体区域、边框参数(因为要考虑圆角边框),照这样修改的话,底层的图层绘制要访问上层的部件属性,感觉会增加代码耦合度,原本的基本绘制对象是图层,一层一层叠加图层即可,而现在的基本绘制对象是部件,那之前从原有部件代码中抽离图层机制的工作不是白干了?

想实现一些动态效果,例如窗口显示时的淡入然后展开的动画效果,需要添加一个渐变处理系统,渐变是什么?就是渐渐变化、慢慢变化。能够渐变的有:透明度、尺寸、位置,显示和隐藏其实也就是透明度的变化。

需要调整像素数据的存储方式,RGBA颜色改用32位的int型变量保存。

矩形角上的阴影有点难度,参考了PhotoShop的投影效果,阴影是从角顶点呈圆形向外扩散,又是圆,之前的圆角绘制功能都实现得马马虎虎,又要折腾这蛋疼的圆形绘制方法。

应该去掉Graph_Lock()和Graph_Unlock()函数,一般也就部件在用Graph,有多个线程操作同一部件的Graph的情况,但部件已经有个互斥锁,所以不用在这个上面还加个互斥锁。

2014-04-09

感觉需要一个日志系统,直接用printf打印调试信息不行,因为有的BUG会在有printf这样的耗时长的函数调用时消失。现在调试函数库是用abort()的方法,BUG出现时查看相关变量是什么值,然后加些代码判断相关变量的值,当等于该值时,就调用abort()异常中断程序,以进行调试。

准备修改Window部件,添加新的风格样式,样式可以继承。

想为部件添加阴影功能,现在正纠结,有3种方法:

  1. 将阴影要绘制在部件图层内。
  2. 在部件周围用8个附属部件呈现阴影。
  3. 用一个大部件呈现阴影,并作为当前部件的容器。 第一种,需要加些代码,以确保正确判断部件实际尺寸、坐标。第二种方法感觉有些不好,一个部件要实现阴影,需要额外的8个部件,还要加代码实现部件的“吸附”功能。第三种,部件的阴影靠另一个部件来实现,也感觉有些不好。话说,之前在VS2012未响应的时候拖动过窗口,发现它的边框阴影不是与主窗口一起的,主窗口移动后,那个阴影还停留在原处。

目前只要想办法实现box-shadow,只需根据矩形边缘进行绘制。

2014-03-30

既然部件的绘制是由是否存在无效矩形而决定的,那么就不需要有PAINT消息了。

有些函数是给内部的其它功能调用的,上层代码不需要调用,那么就不用声明在公共头文件中,可以弄个私有头文件。既然不提供给上层代码用,那么函数声明前就不用加个LCUI_API来导出符号了。这个等以后再弄。

2014-03-25

添加了Widget_BeginPaint()和Widget_EndPaint()函数,主要在GUI部件的OnPaint()函数中绘图前后调用。调用Widget_BeginPaint()函数处理绘制前的一些任务,然后根据该函数给的无效区域,在部件位图的相应区域中进行重绘,当然,如果部件不支持局部重绘,那么可以自己重绘整个部件,在绘制完后,调用Widget_ValidateArea()函数设置整个部件区域有效即可。

有些纠结绘图函数的命名,Paint和Draw都有“绘制”的意思,用哪个?以前是用Draw。

开始修改脏矩形(无效区域)的处理功能。

2014-03-23

需要为部件图形绘制函数添加局部绘制的版本,像画线、颜色填充、图像填充之类的简单功能的函数倒是好弄,但复杂点的就不好弄了,例如:缩放,一个部件的背景图是缩放填充整个部件的,如果要实现部件局部重绘,那么需要支持局部缩放功能,并且,局部缩放后的图像能够与完整缩放的一致。

现在需要重新制定部件刷新规则:当部件存在脏矩形时,会调用部件的绘制函数进行局部重绘,绘制完后,转移至根脏矩形记录,以让LCUI将部件位图更新到屏幕上。

2014-03-20

\n \r 这样的字符还是需要从文本中分离出去,方便多行文本的编辑处理。

应该根据无效区域来绘制该区域内的文字,而不是由每个字携带的标志变量来决定是否重绘该字。这个也是为了支持以后的局部重绘。

2014-03-18

文本框几乎需要重写,在写绘制函数时想到了一个问题:即使只更改一小段文本,也需要重绘整个文本框,这有些不妥,都重绘了,那GUI部件还要单独的位图缓存干嘛?还不如在刷新屏幕区域时,提供一个通用的位图缓存,让各个GUI部件的绘制到这个缓存里,然后绘制到帧缓冲中,但这种绘制频繁的方法会很耗CPU使用率。之前让GUI部件有单独的位图缓存是为了在处理GUI部件的移动、显示、隐藏时不用重绘GUI部件,只需利用已缓存的位图绘制到帧缓冲。

感觉GUI绘制方法需要修改,在绘制部件时,绘制函数应该根据部件中的无效区域,重绘位图缓存中相应区域的位图。

当GUI部件中的无效区域的数量和总面积超过一定值后,应直接重绘整个GUI部件,理由和上面说的一样。

2014-03-14

关于脏矩形的处理,应该加个最小大小限制,几个小矩形重叠,不需要进行分割,直接合并就好了,脏矩形过多、尺寸越小,耗时也会越多,举个例子:刷新1个1000x1000的矩形区域与刷新100个10x10的矩形区域,那个更快?一般情况下,是前者更快,因为每次刷新矩形区域时还有个额外的开销,比如初始化相关数据、计算有效刷新区域,等等。话说,这段话感觉在哪里写过,这篇日志上居然没有记录。

2014-03-13

绘制文字时,有一个水平线,字体位图中的top属性指的是位图顶端到该水平线的距离,该属性值为负数时,说明字体位图绘制在水平线下方,例如逗号、下划线之类的符号。经过几次测试,该水平线大约在最大高度的4/5的位置,例如:一行文本最大高度为44像素,那么该水平线大约在35像素处,绘制字体位图时,Y轴坐标就按这个算。

关于文本行的最大高度的计算方法,之前的做法是直接在字体像素大小上+2,绘制出来的文字会有剃头剃尾的现象,做了个测试:字体大小为40像素,获取字符b和g的字形信息,字母b和g的top属性值分别为32、23,位图高度都为33,可以把字母b的上边界和字母g的下边界之间的距离当成最大高度,32与23之间相差10,那么最大高度为:33+10=43,再凑个1得44,比率就是10/11,这么算,12像素的字体,容器的高度至少要13像素。

经过本次修改后,文字剃头剃尾的现象应该会有所缓解。

LCUI_Queue用的比较泛滥,获取元素要调用Queue_Get()函数,效率低,就算设置为链表存储方式,也要从头到尾遍历结点,像消息记录、事件记录、脏矩形记录,读写都很频繁,用LCUI_Queue会降低效率,需要改用效率稍微高点的数据结构+操作函数。之前新写了个链表(misc/linkedlist.c),可以改用这个来实现,看看效率有没有提升。

关于LCUI的效率的衡量标准,可以用之前写的2D格斗游戏来测量,游戏玩家在30个左右可以保持流畅,玩家数量一多就会卡爆,那么,姑且将300个玩家数量作为标准,只要LCUI能让游戏在玩家数为300个时画面依然流畅,那么就说明效率还行,以后可以考虑挑战1000个玩家数量,当然,游戏也需要进行优化才行。

准备修改文本框。

像Label_Text()这样的函数名还是改掉好些,改成Label_SetText(),其它类似函数也应该改成这样,貌似是因为之前看过javascript的代码,例如obj.text = ‘abc’,也想弄成这样的,但C不可以这样,就弄成了XXX_Text(obj, ‘abc’)这样的形式。最近有为LCUI弄个C++类库的想法,说到C++,想到了“重载”这个词,貌似可以在C++中实现上述的效果,那么,C++版的设置label控件文本的代码就可以这样:label.text = “abc”;而获取label控件文本的代码则可以这样:char str[256];str = label.text; 直接重载=号,想起来有点小兴奋,具体有待实践。

经过测试,str = label.text这样的代码在C++中不能实现 ,对象不能在运算符的右边,那么只能用label.text >> str;这样的代码了,但是,会有溢出问题,目标字符串容量未知,运算符重载不能接受多个参数,还是通过调用函数来实现为好。C++标准头文件中有string类,如果字符串导出对象是string类的,那么在>>运算符重载时,先计算出字符数量,然后把字符串写进string对象里就可以了,这样应该不会有溢出问题。

为LCUI写C++类库也够折腾的,有点代码量,以后可以偶尔折腾一下。

2014-03-12

关于字体的字族、粗体、斜体等样式,以后再考虑,目前只记录字体字族、大小。

改进了TexLayer,修复部分BUG。

换行处理还有点BUG。

2014-02-28

之前看OpenGL的教程,用的代码可以直接创建windows窗口,那么在linux桌面环境下,应该也能够创建窗口。如果要单独获取OpenGL渲染的图像,该怎么办?之前听说过windows什么窗口什么控件是采用DirectX渲染的,看上去是将DirectX当渲染引擎用。之前用的是glut工具包,那么,各个平台上创建窗口就是由glut的代码实现的,glut负责把OpenGL渲染出来的图像绘制到窗口里,这个,具体有待深入研究,或许通过查看glut的源代码,能了解一些有用的东西。

2014-02-27

看了一下“敏捷开发”的百科词条,这个开发方法是把一个大项目分为多个相互较为独立子项目进行开发。感觉就是“把软件项目分为多个功能模块”的升级版,话说,VisualStudio新版中增加的各种功能和特性,不就是为了适应大项目的敏捷开发吗?

2014-02-23

需要修改文本样式处理功能,样式数据也要和字体位图缓存那样,分类分组存放,方便快速获取。文本样式标签只作用于当前设置的文本,文本框有个文本分块处理功能,主要用于应付内容多的文本,如果该文本包含了很多样式标签,并且有很多嵌套的样式标签,那么,需要有个缓存,用于记录当前样式数据,这样在处理每个文本块时,都能应用之前记录的样式,当所有文本块处理完后,清除缓存。

2014-02-19

之前是考虑到文本转纯文本,想保留原始文本内容,所以加了个文本缓存,编辑文本内容要同步两个文本缓存内容,很麻烦。以后如果要根据TextLayer中的文本样式转换成带样式标签的纯文本,那就再加个函数去解析文本。

为每个文字分配单独的内存空间来存储样式数据有些不划算,需要加个样式数据库。

貌似没必要单独记录行尾的换行符,排版时遇到换行符就断行,需要改改。

添加文本时不用考虑换行的问题,直接插入至目标文本行,只需标记当前行需要重新排版即可,到更新的时候再统一进行排版。

当字体的字族、大小改变时,若启用了自动换行功能,需要重新排版。

为了减少编译耗时,需要减少各个头文件间的依赖程度,以及各个数据结构间的依赖程度,这个以后再考虑。

终于换笔记本了,有足够的硬盘空间和内存空间,不再像以前那样在受限的环境下折腾。

2014-02-07

之前为GUI部件加的static定位类型,可以用于桌面图标排列,以后需要的时候再改改。

开个线程循环往TextBox中追加字符,处理效率很慢,追加一个字符都要等几百毫秒才显示出来。

需要从GUI线程中分离出屏幕重绘代码,放到单独的线程上跑。这样改的话,GUI线程就主要用于处理各个GUI部件的消息、更新GUI部件位图,不会受到屏幕重绘的耗时影响而使部件数据更新延迟。这样的话,脏矩形需要两个记录,一个是当前占用的,一个是可用的,每次进行屏幕重绘时,切换记录。

2014-01-29

看了GitHub的更新日志,组织功能有改进,在2013年的4月份,增加支持在线浏览STL格式的3D模型文件:https://github.com/blog/1465-stl-file-viewing,在9月份添加了3D模型对比功能:https://github.com/blog/1633-3d-file-diffs。GitHub的更新蛮快的,越来越强大了。

2014-01-21

可为LCUI添加显示刷新区域的功能,这功能不是什么新鲜玩意,也就是在刷新无效区域后绘制线条边框标记该区域。

需要修改图层模块,添加支持单缓冲模式,需要考虑支持RGB888以外的其它色彩模式,可以考虑再加入调色板、关键色透明功能。

对于单缓冲模式的图层,由于没有独立的内存空间储存像素数据,只能在刷新无效区域时绘制到帧缓冲里了,而双缓冲模式的图层则直接把它的位图绘制到帧缓冲里。考虑到效率问题,要求在每次进行屏幕重绘时,每个GUI部件最多被绘制一次。

双缓冲模式适合需要经过复杂处理才能生成的位图,或不容易局部生成的位图,例如图像、矢量图等。GUI部件用双缓冲模式的好处是,只管绘制部件位图就行,绘制时不用考虑自己和父部件的透明度,GUI部件的透明效果由渲染器(Renderer)处理实现,以后如果要实现GUI部件的透明磨砂效果的话,也比较方便。

windows的Areo效果主要应用在窗体上,那么,LCUI中则可以选择让window这个GUI部件拥有透明磨砂效果,目前的想法是设置混合方式,默认的混合方式是直接Alpha混合,每种混合方式都有相应的混合处理函数,供渲染器调用。

感觉需要弄个游戏开发日志,以后游戏开发相关的内容就不在LCUI开发日志里记录了。

打算写个游戏需求/策划/设计文档,把自己的想法以及游戏该有的特性、功能、效果等内容都写上,图文并茂。

2013-12-03

源码包打包不完整,漏了几个文件,需要修改Makefile.am。

由于工作原因,此项目现已暂停。

2013-11-27

感觉用wordpress来记录开发日志好一些,但是,需要折腾各种主题、样式,而且,升级wordpress版本的话,之前弄的东西就可能需要重新弄一次。为了避免每个版本的开发日志内容太长,可以考虑将开发日志按月份分割成若干篇日志。

考虑到游戏在以后能够有较好的视觉效果,可以考虑把游戏弄成3D版的,游戏画面嘛,弄成卡通风格;如果可以的话,看能不能开发出针对这个游戏的3D游戏引擎,当然,涉及到的知识肯定很多,反正总会有闲余时间,没事折腾一下也可以;还可以考虑学习3D模型制作,自己动手为游戏设计各种模型。

2013-11-26

经过一番折腾,问题已经解决,添加了AppTasks_Delete函数,用于移除指定任务。添加一个任务互斥锁,用于阻塞主循环的任务处理,避免在销毁定时器后到销毁相关数据时,程序还在执行任务。

2013-11-25

在退出游戏对战时,会先销毁定时器,然后销毁相关数据,但定时器在销毁后,程序任务队列中还有未执行的定时器任务,如果在销毁定时器及相关数据后,该定时器任务执行的话,会因访问了已被释放的内存空间而导致程序异常崩溃。这个需要解决。

文章版权归作者所有,未经许可不得转载。

问题反馈

对此文章有疑问?你可以点击 这里 反馈

目录


问题反馈