LVGL实现一个简易画图板
因为工作需要用LVGL实现了一个简易的画图板
LVGL版本:8.2
主要功能有画图,选择画笔颜色,设置画笔宽度,画图板清空
代码如下:
#ifndef __LV_OBJ_SKETCHPAD_H__
#define __LV_OBJ_SKETCHPAD_H__
#include "lvgl/lvgl.h"
#ifdef __cplusplus
extern "C" {
#endif
#define SKETCHPAD_DEFAULT_WIDTH (800)
#define SKETCHPAD_DEFAULT_HEIGHT (480)
typedef enum {
LV_SKETCHPAD_TOOLBAR_OPT_ALL = 0,
LV_SKETCHPAD_TOOLBAR_OPT_COOLWHEEL, // 色轮
LV_SKETCHPAD_TOOLBAR_OPT_WIDTH, // 画笔宽度调节
LV_SKETCHPAD_TOOLBAR_OPT_CLEAR, // 清空画布
LV_SKETCHPAD_TOOLBAR_OPT_LAST
}lv_100ask_sketchpad_toolbar_e;
/*Data of canvas*/
typedef struct {
lv_img_t img;
lv_img_dsc_t dsc;
lv_draw_line_dsc_t line_rect_dsc;
} lv_obj_sketchpad_t;
/***********************
* GLOBAL VARIABLES
***********************/
/**********************
* GLOBAL PROTOTYPES
**********************/
lv_obj_t* lv_obj_sketchpad_create(lv_obj_t* parent);
void lv_gui_sketchpad_display();
#ifdef __cplusplus
} /*extern "C"*/
#endif
#endif // __LV_GUI_SKETCHPAD_H__
#include "lv_obj_sketchpad.h"
/*********************
* DEFINES
*********************/
#define THIS_FILE "lv_obj_sketchpad.c"
#define MY_CLASS &lv_obj_sketchpad_class
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
static void lv_obj_sketchpad_constructor(const lv_obj_class_t* class_p, lv_obj_t* obj);
static void lv_obj_sketchpad_destructor(const lv_obj_class_t* class_p, lv_obj_t* obj);
static void lv_sketchpad_toolbar_constructor(const lv_obj_class_t* class_p, lv_obj_t* obj);
static void lv_sketchpad_toolbar_destructor(const lv_obj_class_t* class_p, lv_obj_t* obj);
static void lv_obj_sketchpad_event(const lv_obj_class_t* class_p, lv_event_t* e);
static void lv_sketchpad_toolbar_event(const lv_obj_class_t* class_p, lv_event_t* e);
static void sketchpad_toolbar_event_cb(lv_event_t* e);
static void toolbar_set_event_cb(lv_event_t* e);
/**********************
* STATIC VARIABLES
**********************/
const lv_obj_class_t lv_obj_sketchpad_class = {
.constructor_cb = lv_obj_sketchpad_constructor,
.destructor_cb = lv_obj_sketchpad_destructor,
.event_cb = lv_obj_sketchpad_event,
.width_def = LV_PCT(100), // 默认宽度
.height_def = LV_PCT(100), // 默认高度
.instance_size = sizeof(lv_obj_sketchpad_t),
.base_class = &lv_canvas_class
};
const lv_obj_class_t lv_sketchpad_toolbar_class = {
.constructor_cb = lv_sketchpad_toolbar_constructor,
.destructor_cb = lv_sketchpad_toolbar_destructor,
.event_cb = lv_sketchpad_toolbar_event,
.width_def = LV_SIZE_CONTENT,
.height_def = LV_SIZE_CONTENT,
.base_class = &lv_obj_class
};
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
lv_obj_t* lv_obj_sketchpad_create(lv_obj_t* parent)
{
LV_LOG_INFO("begin");
lv_obj_t* obj = lv_obj_class_create_obj(MY_CLASS, parent);
lv_obj_class_init_obj(obj);
return obj;
}
/*=====================
* Other functions
*====================*/
/**********************
* STATIC FUNCTIONS
**********************/
static void lv_obj_sketchpad_constructor(const lv_obj_class_t* class_p, lv_obj_t* obj)
{
LV_UNUSED(class_p);
LV_TRACE_OBJ_CREATE("begin");
if (obj == NULL)
return;
lv_obj_sketchpad_t* sketchpad = (lv_obj_sketchpad_t *)obj;
sketchpad->dsc.header.always_zero = 0;
sketchpad->dsc.header.cf = LV_IMG_CF_TRUE_COLOR;
sketchpad->dsc.header.h = 0;
sketchpad->dsc.header.w = 0;
sketchpad->dsc.data_size = 0;
sketchpad->dsc.data = NULL;
lv_draw_line_dsc_init(&sketchpad->line_rect_dsc);
sketchpad->line_rect_dsc.width = 2;
sketchpad->line_rect_dsc.round_start = true;
sketchpad->line_rect_dsc.round_end = true;
sketchpad->line_rect_dsc.color = lv_color_make(0xFF, 0x0, 0x00);
sketchpad->line_rect_dsc.opa = LV_OPA_COVER;
lv_img_set_src(obj, &sketchpad->dsc);
lv_obj_add_flag(obj, LV_OBJ_FLAG_CLICKABLE); // 添加点击属性
/*toolbar 基于sketchpad创建toolbar*/
lv_obj_t* toolbar = lv_obj_class_create_obj(&lv_sketchpad_toolbar_class, obj);
lv_obj_class_init_obj(toolbar);
LV_TRACE_OBJ_CREATE("finished");
}
static void lv_obj_sketchpad_destructor(const lv_obj_class_t* class_p, lv_obj_t* obj)
{
LV_UNUSED(class_p);
LV_TRACE_OBJ_CREATE("begin");
if (obj == NULL)
return;
lv_canvas_t* canvas = (lv_canvas_t*)obj;
lv_img_cache_invalidate_src(&canvas->dsc);
LV_TRACE_OBJ_CREATE("finished");
}
static void lv_obj_sketchpad_event(const lv_obj_class_t* class_p, lv_event_t* e)
{
LV_UNUSED(class_p);
/*Call the ancestor's event handler*/
lv_res_t res = lv_obj_event_base(MY_CLASS, e);
if (res != LV_RES_OK)
return;
lv_event_code_t code = lv_event_get_code(e);
lv_obj_t* obj = lv_event_get_target(e);
lv_obj_sketchpad_t* sketchpad = (lv_obj_sketchpad_t*)obj;
static lv_coord_t last_x = 0, last_y = -32768;
if (code == LV_EVENT_PRESSING)
{
lv_indev_t* indev = lv_indev_get_act();
if (indev == NULL) return;
lv_point_t point;
lv_indev_get_point(indev, &point);
lv_point_t points[2] = { 0 };
/*Release or first use*/
if ((last_x == -32768) || (last_y == -32768))
{
last_x = point.x;
last_y = point.y;
}
else
{
points[0].x = last_x;
points[0].y = last_y;
points[1].x = point.x;
points[1].y = point.y;
last_x = point.x;
last_y = point.y;
lv_canvas_draw_line(obj, points, 2, &sketchpad->line_rect_dsc);
}
}
/*Loosen the brush*/
else if (code == LV_EVENT_RELEASED)
{
last_x = -32768;
last_y = -32768;
}
}
/*toolbar*/
static void lv_sketchpad_toolbar_constructor(const lv_obj_class_t* class_p, lv_obj_t* obj)
{
LV_UNUSED(class_p);
LV_TRACE_OBJ_CREATE("begin");
lv_obj_add_flag(obj, LV_OBJ_FLAG_CLICKABLE); // 添加可点击属性
lv_obj_clear_flag(obj, LV_OBJ_FLAG_SCROLLABLE); // 移除可滚动属性
// 设置流式布局
lv_obj_set_flex_grow(obj, 1);
lv_obj_set_flex_flow(obj, LV_FLEX_FLOW_ROW);
lv_obj_set_size(obj, 60, 20);
lv_obj_align(obj, LV_ALIGN_TOP_MID, 0, 0);
// 颜色选择
static lv_coord_t sketchpad_toolbar_colorwheel = LV_SKETCHPAD_TOOLBAR_OPT_COOLWHEEL;
lv_obj_t* color_edit = lv_label_create(obj);
lv_label_set_text(color_edit, LV_SYMBOL_EDIT);
lv_obj_add_flag(color_edit, LV_OBJ_FLAG_CLICKABLE);
lv_obj_set_size(color_edit, 20, 20);
lv_obj_add_event_cb(color_edit, sketchpad_toolbar_event_cb, LV_EVENT_ALL, (void*)&sketchpad_toolbar_colorwheel);
// 画笔宽度
static lv_coord_t sketchpad_toolbar_width = LV_SKETCHPAD_TOOLBAR_OPT_WIDTH;
lv_obj_t* pen_size = lv_label_create(obj);
lv_label_set_text(pen_size, LV_SYMBOL_EJECT);
lv_obj_add_flag(pen_size, LV_OBJ_FLAG_CLICKABLE);
lv_obj_set_size(pen_size, 20, 20);
lv_obj_add_event_cb(pen_size, sketchpad_toolbar_event_cb, LV_EVENT_ALL, (void*)&sketchpad_toolbar_width);
// 清空按钮
static lv_coord_t sketchpad_toolbar_clear = LV_SKETCHPAD_TOOLBAR_OPT_CLEAR;
lv_obj_t* clear_obj = lv_label_create(obj);
lv_label_set_text(clear_obj, LV_SYMBOL_TRASH);
lv_obj_add_flag(clear_obj, LV_OBJ_FLAG_CLICKABLE);
lv_obj_set_size(clear_obj, 20, 20);
lv_obj_add_event_cb(clear_obj, sketchpad_toolbar_event_cb, LV_EVENT_CLICKED, (void*)&sketchpad_toolbar_clear);
LV_TRACE_OBJ_CREATE("finished");
}
static void lv_sketchpad_toolbar_destructor(const lv_obj_class_t* class_p, lv_obj_t* obj)
{
}
static void lv_sketchpad_toolbar_event(const lv_obj_class_t* class_p, lv_event_t* e)
{
LV_UNUSED(class_p);
/*Call the ancestor's event handler*/
lv_res_t res = lv_obj_event_base(MY_CLASS, e);
if (res != LV_RES_OK)
return;
lv_event_code_t code = lv_event_get_code(e);
lv_obj_t* obj = lv_event_get_target(e);
if (code == LV_EVENT_PRESSING)
{
lv_indev_t* indev = lv_indev_get_act();
if (indev == NULL)
return;
lv_point_t vect;
lv_indev_get_vect(indev, &vect);
lv_coord_t x = lv_obj_get_x(obj) + vect.x;
lv_coord_t y = lv_obj_get_y(obj) + vect.y;
lv_obj_set_pos(obj, x, y);
}
}
static void sketchpad_toolbar_event_cb(lv_event_t* e)
{
lv_coord_t* toolbar_opt = (lv_coord_t *)lv_event_get_user_data(e);
lv_event_code_t code = lv_event_get_code(e);
lv_obj_t* obj = lv_event_get_target(e);
lv_obj_t* toolbar = lv_obj_get_parent(obj);
lv_obj_t* sketchpad = lv_obj_get_parent(toolbar);
lv_obj_sketchpad_t* sketchpad_obj = (lv_obj_sketchpad_t*)sketchpad;
if (code == LV_EVENT_CLICKED)
{
if ((*toolbar_opt) == LV_SKETCHPAD_TOOLBAR_OPT_COOLWHEEL)
{
static lv_coord_t sketchpad_toolbar_cw = LV_SKETCHPAD_TOOLBAR_OPT_COOLWHEEL;
lv_obj_t* colorwheel = lv_colorwheel_create(sketchpad, true);
lv_obj_align_to(colorwheel, obj, LV_ALIGN_OUT_BOTTOM_MID, 0, 0);
lv_obj_add_event_cb(colorwheel, toolbar_set_event_cb, LV_EVENT_RELEASED, &sketchpad_toolbar_cw);
}
else if ((*toolbar_opt) == LV_SKETCHPAD_TOOLBAR_OPT_WIDTH)
{
static lv_coord_t sketchpad_toolbar_width = LV_SKETCHPAD_TOOLBAR_OPT_WIDTH;
lv_obj_t* slider = lv_slider_create(sketchpad);
lv_slider_set_value(slider, (int32_t)(sketchpad_obj->line_rect_dsc.width), LV_ANIM_OFF);
lv_obj_align_to(slider, obj, LV_ALIGN_OUT_BOTTOM_MID, 0, 0);
lv_obj_add_event_cb(slider, toolbar_set_event_cb, LV_EVENT_ALL, &sketchpad_toolbar_width);
}
else if ((*toolbar_opt) == LV_SKETCHPAD_TOOLBAR_OPT_CLEAR)
{
//lv_canvas_fill_bg(sketchpad, lv_palette_lighten(LV_PALETTE_GREY, 3), LV_OPA_COVER);
lv_canvas_fill_bg(sketchpad, lv_color_make(0xFF, 0xFF, 0xFF), LV_OPA_COVER);
}
}
}
static void toolbar_set_event_cb(lv_event_t* e)
{
lv_coord_t* toolbar_opt = (lv_coord_t *)lv_event_get_user_data(e);
lv_event_code_t code = lv_event_get_code(e);
lv_obj_t* obj = lv_event_get_target(e);
lv_obj_sketchpad_t* sketchpad_obj = (lv_obj_sketchpad_t*)lv_obj_get_parent(obj);
if (code == LV_EVENT_RELEASED)
{
if ((*toolbar_opt) == LV_SKETCHPAD_TOOLBAR_OPT_COOLWHEEL)
{
sketchpad_obj->line_rect_dsc.color = lv_colorwheel_get_rgb(obj);
lv_obj_del(obj);
}
else if (*(toolbar_opt) == LV_SKETCHPAD_TOOLBAR_OPT_WIDTH)
{
lv_obj_del(obj);
}
}
else if (code == LV_EVENT_VALUE_CHANGED)
{
if ((*toolbar_opt) == LV_SKETCHPAD_TOOLBAR_OPT_WIDTH)
{
sketchpad_obj->line_rect_dsc.width = (lv_coord_t)lv_slider_get_value(obj);
}
}
}
void lv_gui_sketchpad_display()
{
static lv_color_t color_buf[LV_CANVAS_BUF_SIZE_TRUE_COLOR(SKETCHPAD_DEFAULT_WIDTH, SKETCHPAD_DEFAULT_HEIGHT)] = { 0 };
lv_obj_t* sketchpad = lv_obj_sketchpad_create(lv_scr_act());
if (sketchpad != NULL)
{
lv_canvas_set_buffer(sketchpad, color_buf, SKETCHPAD_DEFAULT_WIDTH, SKETCHPAD_DEFAULT_HEIGHT, LV_IMG_CF_TRUE_COLOR);
//lv_obj_set_size(sketchpad, SKETCHPAD_DEFAULT_WIDTH, SKETCHPAD_DEFAULT_HEIGHT);
lv_obj_center(sketchpad);
//lv_canvas_fill_bg(sketchpad, lv_palette_lighten(LV_PALETTE_GREY, 3), LV_OPA_COVER);
lv_canvas_fill_bg(sketchpad, lv_color_make(0xFF,0xFF,0xFF), LV_OPA_COVER);
}
}
运行效果:
参考文档:
lv_100ask_sketchpad