LVGL 库提交
This commit is contained in:
@@ -0,0 +1,189 @@
|
||||
/**
|
||||
* @file lv_tree.c
|
||||
* Tree.
|
||||
* The nodes are dynamically allocated by the 'lv_mem' module,
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_tree.h"
|
||||
#include "../stdlib/lv_mem.h"
|
||||
#include "../stdlib/lv_string.h"
|
||||
|
||||
#include "lv_assert.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
#define INIT_CHILDREN_CAP 4
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
const lv_tree_class_t lv_tree_node_class = {
|
||||
.base_class = NULL,
|
||||
.instance_size = sizeof(lv_tree_node_t),
|
||||
.constructor_cb = NULL,
|
||||
.destructor_cb = NULL,
|
||||
};
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
static void _lv_tree_node_construct(const lv_tree_class_t * class_p, lv_tree_node_t * node)
|
||||
{
|
||||
if(node->class_p->base_class) {
|
||||
const lv_tree_class_t * original_class_p = node->class_p;
|
||||
|
||||
node->class_p = node->class_p->base_class;
|
||||
|
||||
_lv_tree_node_construct(class_p, node);
|
||||
|
||||
node->class_p = original_class_p;
|
||||
}
|
||||
|
||||
if(node->class_p->constructor_cb) node->class_p->constructor_cb(class_p, node);
|
||||
}
|
||||
|
||||
static void _lv_tree_node_destruct(lv_tree_node_t * node)
|
||||
{
|
||||
if(node->class_p->destructor_cb) node->class_p->destructor_cb(node->class_p, node);
|
||||
|
||||
if(node->class_p->base_class) {
|
||||
node->class_p = node->class_p->base_class;
|
||||
|
||||
_lv_tree_node_destruct(node);
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t get_instance_size(const lv_tree_class_t * class_p)
|
||||
{
|
||||
const lv_tree_class_t * base = class_p;
|
||||
while(base && base->instance_size == 0)
|
||||
base = base->base_class;
|
||||
|
||||
LV_ASSERT_NULL(base);
|
||||
|
||||
return base->instance_size;
|
||||
}
|
||||
|
||||
static lv_tree_node_t * _lv_tree_class_create_node(const lv_tree_class_t * class_p, lv_tree_node_t * parent)
|
||||
{
|
||||
uint32_t s = get_instance_size(class_p);
|
||||
lv_tree_node_t * node = lv_malloc(s);
|
||||
if(node == NULL) return NULL;
|
||||
lv_memzero(node, s);
|
||||
node->class_p = class_p;
|
||||
node->parent = parent;
|
||||
node->child_cap = INIT_CHILDREN_CAP;
|
||||
node->children = lv_malloc(sizeof(lv_tree_node_t *) * node->child_cap);
|
||||
if(parent != NULL) {
|
||||
parent->child_cnt++;
|
||||
if(parent->child_cnt == parent->child_cap) {
|
||||
parent->child_cap <<= 1;
|
||||
parent->children = lv_realloc(parent->children, sizeof(lv_tree_node_t *) * parent->child_cap);
|
||||
}
|
||||
parent->children[parent->child_cnt - 1] = node;
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
lv_tree_node_t * lv_tree_node_create(const lv_tree_class_t * class_p, lv_tree_node_t * parent)
|
||||
{
|
||||
LV_ASSERT_NULL(class_p);
|
||||
lv_tree_node_t * node = _lv_tree_class_create_node(class_p, parent);
|
||||
LV_ASSERT_NULL(node);
|
||||
_lv_tree_node_construct(node->class_p, node);
|
||||
return node;
|
||||
}
|
||||
|
||||
static bool _lv_tree_node_destructor_cb(const lv_tree_node_t * n, void * user_data)
|
||||
{
|
||||
LV_UNUSED(user_data);
|
||||
if(n) {
|
||||
lv_tree_node_t * node = (lv_tree_node_t *)n;
|
||||
_lv_tree_node_destruct(node);
|
||||
lv_free(node->children);
|
||||
lv_free(node);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void lv_tree_node_delete(lv_tree_node_t * node)
|
||||
{
|
||||
if(node) {
|
||||
if(node->parent) {
|
||||
/* Remove from parent */
|
||||
lv_tree_node_t * parent = node->parent;
|
||||
for(uint32_t i = 0; i < parent->child_cnt; i++) {
|
||||
if(parent->children[i] == node) {
|
||||
parent->children[i] = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
lv_tree_walk(node, LV_TREE_WALK_POST_ORDER, _lv_tree_node_destructor_cb, NULL, NULL, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
bool lv_tree_walk(const lv_tree_node_t * node,
|
||||
lv_tree_walk_mode_t mode,
|
||||
lv_tree_traverse_cb_t cb,
|
||||
lv_tree_before_cb_t bcb,
|
||||
lv_tree_after_cb_t acb,
|
||||
void * user_data)
|
||||
{
|
||||
if(node && cb) {
|
||||
if(mode == LV_TREE_WALK_PRE_ORDER) {
|
||||
if(bcb && !bcb(node, user_data)) {
|
||||
return false;
|
||||
}
|
||||
if(!cb(node, user_data)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
for(uint32_t i = 0; i < node->child_cnt; i++) {
|
||||
if(!lv_tree_walk(node->children[i], mode, cb, bcb, acb, user_data)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if(mode == LV_TREE_WALK_PRE_ORDER) {
|
||||
if(acb) {
|
||||
acb(node, user_data);
|
||||
}
|
||||
}
|
||||
|
||||
if(mode == LV_TREE_WALK_POST_ORDER) {
|
||||
if(bcb && !bcb(node, user_data)) {
|
||||
return false;
|
||||
}
|
||||
if(!cb(node, user_data)) {
|
||||
return false;
|
||||
}
|
||||
if(acb) {
|
||||
acb(node, user_data);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user