awtk-widget-chart-view-mvvm C版本适配笔记

一、前言

awtk-widget-chart-view 是 AWTK 提供的图表自定义控件,该控件包含:曲线图、柱状图和饼图。最近需要让该控件支持 AWTK-MVVM,但受限于原有的接口,实现起来有点麻烦,因此重构了 chart-view 控件序列点数据(先进先出队列 FIFO)的代码。

AWTK是 ZLG 开发的开源 GUI 引擎,官网地址:https://www.zlg.cn/index/pub/awtk.html
AWTK GitHub 仓库:http://github.com/zlgopen/awtk-mvvm

AWTK-MVVM是一套用C语言开发的,专门为嵌入式平台优化的MVVM框架。它实现了数据绑定、命令绑定和窗口导航等基本功能。
AWTK-MVVM GitHub 仓库:http://github.com/zlgopen/awtk-mvvm

二、序列点数据结构(FIFO)

在 chart-view 控件中,以折线图为例,折线数据储存在一个先进先出队列 FIFO(First in,First out )结构中,绘制控件时从该 FIFO 中读取数据,添加序列点时,将点数据推送到 FIFO 中,若队列已满,则删除最旧的序列点数据。

适配 MVVM 前 chart-view 控件中的 FIFO 结构代码如下:

FIFO 完整的实现代码请前往 GitHub 控件仓库下载: http://github.com/zlgopen/awtk-widget-store

/**
 * @class fifo_t
 * FIFO,先进先出队列,环形缓存。
 *
 * 用fifo\_init初始化时,用fifo\_deinit释放。如:
 *
 * ```c
 * fifo_t fifo;
 * fifo_init(&fifo, 10, 10, compare);
 * ...
 * fifo_deinit(&fifo);
 * ```
 *
 * 用fifo\_create创建时,用fifo\_destroy销毁。如:
 *
 * ```c
 * fifo_t* fifo = fifo_create(10, 10, compare);
 * ...
 * fifo_destroy(fifo);
 * ```
 *
 */
typedef struct _fifo_t {
   
  /**
   * @property {uint32_t} capacity
   * @annotation ["readable"]
   * FIFO的容量大小。
   */
  uint32_t capacity;
  /**
   * @property {uint32_t} size
   * @annotation ["readable"]
   * FIFO中元素的个数。
   */
  uint32_t size;
  /**
   * @property {uint32_t} cursor
   * @annotation ["readable"]
   * FIFO中最后一个元素的索引。
   */
  uint32_t cursor;
  /**
   * @property {uint32_t} unit_size
   * @annotation ["readable"]
   * FIFO中单个元素的大小。
   */
  uint32_t unit_size;
  /**
   * @property {uint8_t*} buffer
   * @annotation ["readable"]
   * FIFO中的数据缓存。
   */
  uint8_t* buffer;
  /**
   * @property {tk_destroy_t} destroy
   * @annotation ["readable"]
   * 元素销毁函数。
   */
  tk_destroy_t destroy;
  /**
   * @property {tk_compare_t} compare
   * @annotation ["readable"]
   * 元素过滤函数。
   */
  tk_compare_t compare;
} fifo_t;

三、重构FIFO

要让 chart-view 支持 AWTK-MVVM,其关键点就是在 MVVM 绑定数据时,能够替换该控件中的FIFO数据结构,而根据目前 FIFO 的结构是无法实现的,因此,这里定义一个继承 object_t 的抽象类 object_fifo_t ,并实现一个默认类 object_fifo_default_t。

object_t 是 AWTK 中的一个对象基类,其实现详见 AWTK 源码。

这样一来,使用 MVVM 时即可在 Model 层通过 object_fifo_default_t 实例化一个 object_fifo_t 对象,并将其替换到控件中达到数据和界面分离的目的。

3.1 object_fifo_t

抽象类 object_fifo_t 的接口如下:

#ifndef TK_OBJECT_FIFO_H
#define TK_OBJECT_FIFO_H

#include "tkc/object.h"
#include "object_fifo_data.h"
#include "object_fifo_event.h"

BEGIN_C_DECLS

struct _object_fifo_t;
typedef struct _object_fifo_t object_fifo_t;

typedef object_t* (*object_fifo_clone_t)(object_t* obj);
typedef object_t* (*object_fifo_part_clone_t)(object_t* obj, uint32_t index, uint32_t nr);
typedef void* (*object_fifo_at_t)(object_t* obj, uint32_t index);
typedef ret_t (*object_fifo_set_t)(object_t* obj, uint32_t index, const void* data, uint32_t nr);
typedef ret_t (*object_fifo_get_t)(object_t* obj, uint32_t index, uint32_t nr, uint8_t* buffer);
typedef int (*object_fifo_index_of_t)(object_t* obj, void* data);
typedef int (*object_fifo_compare_t)(object_t* obj, const void* a, const void* b);
typedef ret_t (*object_fifo_npush_t)(object_t* obj, const void* data, uint32_t nr);
typedef ret_t (*object_fifo_npop_t)(object_t* obj, uint32_t nr);
typedef ret_t (*object_fifo_clear_t)(object_t* obj);
typedef ret_t (*object_fifo_foreach_t)(object_t* obj, tk_visit_t visit, void* ctx);
typedef ret_t (*object_fifo_reset_t)(object_t* obj, uint32_t capacity, fifo_data_type_t type);

typedef struct _object_fifo_vtable_t {
   
  object_fifo_clone_t clone;
  object_fifo_part_clone_t part_clone;
  object_fifo_at_t at;
  object_fifo_set_t set;
  object_fifo_get_t get;
  object_fifo_index_of_t index_of;
  object_fifo_compare_t compare;
  object_fifo_npush_t npush;
  object_fifo_npop_t npop;
  object_fifo_clear_t clear;
  object_fifo_foreach_t foreach;
  object_fifo_reset_t reset;
} object_fifo_vtable_t;

/**
 * @class object_fifo_t
 * @parent object_t
 *
 * FIFO,先进先出队列,环形缓存。
 * 可以使用 object_fifo_default_t 实例化该类。
 *
 */
struct _object_fifo_t {
   
  object_t obj;
  /**
   * @property {fifo_data_type_t} type
   * @annotation ["readable"]
   * FIFO类型(决定FIFO中元素的单位大小)。
   */
  fifo_data_type_t type;
  /**
   * @property {object_fifo_vtable_t} vt
   * @annotation ["readable"]
   * 虚函数表。
   */
  const object_fifo_vtable_t* vt;

  /*private*/
  object_fifo_event_t e;
};

/**
 * @method object_fifo_clone
 * clone。
 *
 * @param {object_t*} obj object_fifo对象。
 *
 * @return {object_t*} 返回clone的obj对象。
 */
object_t* object_fifo_clone(object_t* obj);

/**
 * @method object_fifo_part_clone
 * clone部分。
 *
 * @param {object_t*} obj object_fifo对象。
 * @param {uint32_t*} index 被clone元素在FIFO中的位置。
 * @param {uint32_t*} nr 被clone元素的数量。
 *
 * @return {object_t*} 返回clone的对象。
 */
object_t* object_fifo_part_clone(object_t* obj, uint32_t index, uint32_t nr);

/**
 * @method object_fifo_at
 * 返回特定位置的元素。
 *
 * @param {object_t*} obj object_fifo对象。
 * @param {uint32_t} index 元素在FIFO中的位置。
 *
 * @return {void*} 如果找到,返回特定位置的元素,否则返回NULL。
 */
void* object_fifo_at(object_t* obj, uint32_t index);

/**
 * @method object_fifo_set
 * 设置特定位置开始的多个元素。
 *
 * @param {object_t*} obj object_fifo对象。
 * @param {uint32_t} index 元素在FIFO中的位置。
 * @param {const void*} data 元素数据。
 * @param {uint32_t} nr 元素数量。
 *
 * @return {ret_t} 返回RET_OK表示成功,否则表示失败。
 */
ret_t object_fifo_set(object_t* obj, uint32_t index, const void* data, uint32_t nr);

/**
 * @method object_fifo_set_reverse
 * 设置特定位置开始的多个元素(反向)。
 *
 * @param {object_t*} obj object_fifo对象。
 * @param {uint32_t} index 元素在FIFO中的位置。
 * @param {const void*} data 元素数据。
 * @param {uint32_t} nr 元素数量。
 *
 * @return {ret_t} 返回RET_OK表示成功,否则表示失败。
 */
ret_t object_fifo_set_reverse(object_t* obj, uint32_t index, const void* data, uint32_t nr);

/**
 * @method object_fifo_get
 * 返回特定位置开始的多个元素。
 *
 * @param {object_t*} obj object_fifo对象。
 * @param {uint32_t} index 元素在FIFO中的位置。
 * @param {uint32_t} nr 元素数量。
 * @param {uint8_t*} buffer 返回元素的缓存。
 *
 * @return {ret_t} 返回RET_OK表示成功,否则表示失败。
 */
ret_t object_fifo_get(object_t* obj, uint32_t index, uint32_t nr, uint8_t* buffer);

/**
 * @method object_fifo_prev
 * 返回上一个元素。
 *
 * @param {object_t*} obj object_fifo对象。
 * @param {void*} data 当前元素。
 *
 * @return {void*} 如果找到,返回上一个元素,否则返回NULL。
 */
void* object_fifo_prev(object_t* obj, void* data);

/**
 * @method object_fifo_next
 * 返回下一个元素。
 *
 * @param {object_t*} obj object_fifo对象。
 * @param {void*} data 当前元素。
 *
 * @return {void*} 如果找到,返回下一个元素,否则返回NULL。
 */
void* object_fifo_next(object_t* obj, void* data);

/**
 * @method object_fifo_tail
 * 返回最后一个元素。
 *
 * @param {object_t*} obj object_fifo对象。
 *
 * @return {void*} 成功返回最后一个元素,失败返回NULL。
 */
void* object_fifo_tail(object_t* obj);

/**
 * @method object_fifo_head
 * 返回第一个元素。
 *
 * @param {object_t*} obj object_fifo对象。
 *
 * @return {void*} 成功返回最后一个元素,失败返回NULL。
 */
void* object_fifo_head(object_t* obj);

/**
 * @method object_fifo_index_of
 * 返回元素的位置。
 *
 * @param {object_t*} obj object_fifo对象。
 * @param {void*} data 元素。
 *
 * @return {int} 如果找到,返回元素的位置,否则返回-1。
 */
int object_fifo_index_of(object_t* obj, void* data);

/**
 * @method object_fifo_compare
 * 比较两个元素。
 *
 * @param {object_t*} obj object_fifo对象。
 * @param {const void*} a 元素a。
 * @param {const void*} b 元素b。
 *
 * @return {int} 两元素相等返回0。
 */
int object_fifo_compare(object_t* obj, const void* a, const void* b);

/**
 * @method object_fifo_count
 * 返回满足条件元素的个数。
 *
 * @param {object_t*} obj object_fifo对象。
 * @param {void*} ctx 比较函数的上下文。
 *
 * @return {int32_t} 返回元素个数。
 */
int32_t object_fifo_count(object_t* obj, void* ctx);

/**
 * @method object_fifo_find
 * 查找第一个满足条件的元素。
 *
 * @param {object_t*} obj object_fifo对象。
 * @param {void*} ctx 比较函数的上下文。
 *
 * @return {void*} 如果找到,返回满足条件的对象,否则返回NULL。
 */
void* object_fifo_find(object_t* obj, void* ctx);

/**
 * @method object_fifo_find_index
 * 查找第一个满足条件的元素,并返回位置。
 *
 * @param {object_t*} obj object_fifo对象。
 * @param {void*} ctx 比较函数的上下文。
 *
 * @return {int} 如果找到,返回满足条件的对象的位置,否则返回-1。
 */
int object_fifo_find_index(object_t* obj, void* ctx);

/**
 * @method object_fifo_push
 * 在尾巴追加一个元素。
 *
 * @param {object_t*} obj object_fifo对象。
 * @param {const void*} data 待追加的元素。
 *
 * @return {ret_t} 返回RET_OK表示成功,否则表示失败。
 */
ret_t object_fifo_push(object_t* obj, const void* data);

/**
 * @method object_fifo_pop
 * 弹出第一个元素。
 *
 * @param {object_t*} obj object_fifo对象。
 *
 * @return {void*} 成功返回第一个元素,失败返回NULL。
 */
void* object_fifo_pop(object_t* obj);

/**
 * @method object_fifo_npush
 * 在尾巴追加多个元素。
 *
 * @param {object_t*} obj object_fifo对象。
 * @param {const void*} data 待追加的元素。
 * @param {uint32_t} nr 待追加的元素个数。
 *
 * @return {ret_t} 返回RET_OK表示成功,否则表示失败。
 */
ret_t object_fifo_npush(object_t* obj, const void* data, uint32_t nr);

/**
 * @method object_fifo_npop
 * 弹出开头多个元素。
 *
 * @param {object_t*} obj object_fifo对象。
 * @param {uint32_t} nr 待弹出的元素个数。
 *
 * @return {ret_t} 返回RET_OK表示成功,否则表示失败。
 */
ret_t object_fifo_npop(object_t* obj, uint32_t nr);

/**
 * @method object_fifo_clear
 * 清除全部元素。
 *
 * @param {object_t*} obj object_fifo对象。
 *
 * @return {ret_t} 返回RET_OK表示成功,否则表示失败。
 */
ret_t object_fifo_clear(object_t* obj);

/**
 * @method object_fifo_foreach
 * 遍历元素。
 *
 * @param {object_t*} obj object_fifo对象。
 * @param {tk_visit_t} visit 遍历函数。
 * @param {void*} ctx 遍历函数的上下文。
 *
 * @return {ret_t} 返回RET_OK表示成功,否则表示失败。
 */
ret_t object_fifo_foreach(object_t* obj, tk_visit_t visit, void* ctx);

/**
 * @method object_fifo_reset
 * 重置fifo。
 *
 * @param {object_t*} obj object_fifo对象。
 * @param {uint32_t} capacity 容量。
 * @param {fifo_data_type_t} type FIFO类型。
 *
 * @return {ret_t} 返回RET_OK表示成功,否则表示失败。
 */
ret_t object_fifo_reset(object_t* obj, uint32_t capacity, fifo_data_type_t type);

/*helper functions*/
ret_t object_fifo_set_raw(object_t* obj, uint32_t index, const void* data, uint32_t nr);

#define OBJECT_FIFO(obj) ((object_fifo_t*)(obj))

#define OBJECT_FIFO_PROP_TYPE "type"
#define OBJECT_FIFO_PROP_CAPACITY "capacity"
#define OBJECT_FIFO_PROP_SIZE "size"
#define OBJECT_FIFO_PROP_CURSOR "cursor"
#define OBJECT_FIFO_PROP_UNIT_SIZE "unit_size"
#define OBJECT_FIFO_PROP_BUFFER "buffer"

#define OBJECT_FIFO_GET_TYPE(obj) object_get_prop_uint32(obj, OBJECT_FIFO_PROP_TYPE, 0)
#define OBJECT_FIFO_GET_CAPACITY(obj) object_get_prop_uint32(obj, OBJECT_FIFO_PROP_CAPACITY, 0)
#define OBJECT_FIFO_GET_SIZE(obj) object_get_prop_uint32(obj, OBJECT_FIFO_PROP_SIZE, 0)
#define OBJECT_FIFO_GET_CURSOR(obj) object_get_prop_uint32(obj, OBJECT_FIFO_PROP_CURSOR, 0)
#define OBJECT_FIFO_GET_UNIT_SIZE(obj) object_get_prop_uint32(obj, OBJECT_FIFO_PROP_UNIT_SIZE, 0)
#define OBJECT_FIFO_GET_BUFFER(obj) (uint8_t*)object_get_prop_pointer(obj, OBJECT_FIFO_PROP_BUFFER)

END_C_DECLS

#endif /*TK_OBJECT_FIFO_H*/

3.2 object_fifo_default_t

子类 object_fifo_default_t 的接口如下:

#ifndef TK_OBJECT_FIFO_DEFAULT_H
#define TK_OBJECT_FIFO_DEFAULT_H

#include "object_fifo.h"

BEGIN_C_DECLS

struct _object_fifo_default_t;
typedef struct _object_fifo_default_t object_fifo_default_t;

/**
 * @class object_fifo_default_t
 * @parent object_fifo_t
 *
 * object_fifo的缺省实现。
 *
 */
struct _object_fifo_default_t {
   
  object_fifo_t obj_fifo;

  /**
   * @property {uint32_t} capacity
   * @annotation ["readable"]
   * FIFO的容量大小。
   */
  uint32_t capacity;
  /**
   * @property {uint32_t} size
   * @annotation ["readable"]
   * FIFO中元素的个数。
   */
  uint32_t size;
  /**
   * @property {uint32_t} cursor
   * @annotation ["readable"]
   * FIFO中最后一个元素的索引。
   */
  uint32_t cursor;
  /**
   * @property {uint32_t} unit_size
   * @annotation ["readable"]
   * FIFO中单个元素的大小。
   */
  uint32_t unit_size;
  /**
   * @property {uint8_t*} buffer
   * @annotation ["readable"]
   * FIFO中的数据缓存。
   */
  uint8_t* buffer;
};

/**
 * @method object_fifo_default_create
 * 创建object_fifo对象。
 *
 * @annotation ["constructor"]
 * @param {uint32_t} capacity FIFO的初始容量。
 * @param {fifo_data_type_t} type FIFO数据类型。
 *
 * @return {object_t} 返回object_fifo对象。
 */
object_t* object_fifo_default_create(uint32_t capacity, fifo_data_type_t type);

#define OBJECT_FIFO_DEFAULT(obj) ((object_fifo_default_t*)(obj))

END_C_DECLS

#endif /*TK_OBJECT_FIFO_DEFAULT_H*/

子类 object_fifo_default_t 的实现代码如下:

#include "tkc/mem.h"
#include "object_fifo_default.h"

#define FIFO_IS_VALID(fifo, index) ((index) >= 0 && (index) < fifo->size)
#define FIFO_TO_ABS_INDEX(fifo, index) \
  ((fifo->cursor - fifo->size + 1 + fifo->capacity + (index)) % fifo->capacity)
#define FIFO_ABS_ELM(fifo, index) ((void*)(fifo->buffer + fifo->unit_size * (index)))
#define FIFO_TO_INDEX(fifo, index) (((index)-fifo->cursor + fifo->size - 1) % fifo->capacity)

static int object_fifo_default_compare(object_t* obj, const void* a, const void* b) {
   
  object_fifo_default_t* fifo = OBJECT_FIFO_DEFAULT(obj);
  return_value_if_fail(fifo != NULL, RET_BAD_PARAMS);

  return memcmp(a, b, fifo->unit_size);
}

static ret_t object_fifo_default_set_internal(object_t* obj, uint32_t index, const void* data,
                                              uint32_t nr) {
   
  object_fifo_default_t* fifo = OBJECT_FIFO_DEFAULT(obj);
  uint8_t* start = (uint8_t*)(data);
  uint8_t* elm = (uint8_t*)FIFO_ABS_ELM(fifo, index);

  if (nr > fifo->capacity) {
   
    if (start != NULL) {
   
      start += (nr - fifo->capacity) * fifo->unit_size;
    
AWTK开发手册-AWTK开发实践指南-中文手册.pdf AWTK = Toolkit AnyWhere 随着手机、智能手表等便携式设备的普及,用户对 GUI 的要求越来越高,嵌入式系统对高性能、高可靠性、低功耗、美观炫酷的 GUI 的需求也越来越迫切,ZLG开源 GUI 引擎 AWTK 应运而生。AWTK 全称为 Toolkit AnyWhere,是 ZLG 倾心打造的一套基于 C 语言开发的 GUI 框架。旨在为用户提供一个功能强大、高效可靠、简单易用、可轻松做出炫酷效果的 GUI 引擎,并支持跨平台同步开发,一次编程,终生使用。 最终目标: 支持开发嵌入式软件。 支持开发Linux应用程序。 支持开发MacOS应用程序。 支持开发Windows应用程序。 支持开发Android应用程序。 支持开发iOS应用程序。 支持开发2D游戏。 其主要特色有: 小巧。在精简配置下,不依赖第三方软件包,仅需要32K RAM + 256K FLASH即可开发一些简单的图形应用程序。 高效。采用脏矩形裁剪算法,每次只绘制和更新变化的部分,极大提高运行效率和能源利用率。 稳定。通过良好的架构设计和编程风格、单元测试、动态(valgrind)检查和Code Review保证其运行的稳定性。 丰富的GUI组件。提供窗口、对话框和各种常用的组件(用户可以配置自己需要的组件,降低对运行环境的要求)。 支持多种字体格式。内置位图字体(并提供转换工具),也可以使用stb_truetype或freetype加载ttf字体。 支持多种图片格式。内置位图图片(并提供转换工具),也可以使用stb_image加载png/jpg等格式的图片。 紧凑的二进制界面描述格式。可以手工编辑的XML格式的界面描述文件,也可以使用Qt Designer设计界面,然后转换成紧凑的二进制界面描述格式,提高运行效率,减小内存开销。 支持主题并采用紧凑的二进制格式。开发时使用XML格式描述主题,然后转换成紧凑的二进制格式,提高运行效率,减小内存开销。 支持裸系统,无需OS和文件系统。字体、图片、主题和界面描述数据都编译到代码中,以常量数据的形式存放,运行时无需加载到内存。 内置nanovg实现高质量的矢量动画,并支持SVG矢量图。 支持窗口动画、控件动画、滑动动画和高清LCD等现代GUI常见特性。 支持国际化(Unicode、字符串翻译和输入法等)。 可移植。支持移植到各种RTOS和嵌入式Linux系统,并通过SDL在各种流行的PC/手机系统上运行。 脚本化。从API注释中提取API的描述信息,通过这些信息可以自动生成各种脚本的绑定代码。 支持硬件2D加速(目前支持STM32的DMA2D和NXP的PXP)和GPU加速(OpenGL/OpenGLES/DirectX/Metal),充分挖掘硬件潜能。 丰富的文档和示例代码。 采用LGPL协议开源发布,在商业软件中使用时无需付费。 目前核心功能已经完成,内部开始在实际项目中使用了,欢迎有兴趣的朋友评估和尝试,期待您的反馈。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值