新国标电池轻量级GUI开源

最近在准备新国标的移动电源,发现mcu ram 4kb rom 64kb,难以运行像是lvgl绘制方便的图形系统,于是想写一份出来

这个gui系统共有两层:1层是中间层负责和底层驱动打交道 2层是应用层负责图形创建和渲染还有对象的内存管理。

开源地址:

因为gitee账号给封了,得等一会儿

1.中间层

lcd_draw.h

cpp 复制代码
/******************************************************************************
 * @file        display.h
 * @brief       LCD显示驱动头文件 - 提供基本图形绘制、文本显示、图片显示等功能
 * @author      古焕发
 * @version     V1.0
 * @date        2026-01-30
 * @copyright   Copyright (c) 2026
 * 
 * @description 该头文件定义了LCD显示屏的完整驱动接口,包括基本图形绘制、文本显示、
 *              图片显示等功能。采用模块化设计,支持多种图形元素和显示效果。
 * 
 * @note        修改日志:
 *              - 2026-01-30 V1.0 古焕发 创建文件,定义完整的LCD显示接口
 ******************************************************************************/

#ifndef LCD_DRAW_H
#define LCD_DRAW_H

#include "main.h"

/*---------------------- 颜色常量定义 ----------------------*/

/** 基础颜色定义 (RGB565格式) */
#define WHITE             0xFFFF  /**< 白色 */
#define BLACK             0x0000  /**< 黑色 */
#define BLUE              0x001F  /**< 蓝色 */
#define BRED              0xF81F  /**< 蓝红色 */
#define GRED              0xFFE0  /**< 绿红色 */
#define GBLUE             0x07FF  /**< 绿蓝色 */
#define RED               0xF800  /**< 红色 */


/*---------------------- 基本图形绘制函数 ----------------------*/

/**
 * @brief       在指定矩形区域填充颜色
 * @param[in]  xsta, ysta: 区域起始坐标(左上角)
 * @param[in]  xend, yend: 区域结束坐标(右下角)
 * @param[in]  color: 填充颜色值
 * @retval      无
 */
void LCD_Fill(uint16_t xsta, uint16_t ysta, uint16_t xend, uint16_t yend, uint16_t color);

/**
 * @brief       在指定位置绘制单个像素点
 * @param[in]  x, y: 点的坐标
 * @param[in]  color: 点的颜色值
 * @retval      无
 */
void LCD_DrawPoint(uint16_t x, uint16_t y, uint16_t color);

/**
 * @brief       在两点之间绘制直线
 * @param[in]  x1, y1: 起点坐标
 * @param[in]  x2, y2: 终点坐标
 * @param[in]  color: 线条颜色值
 * @retval      无
 */
void LCD_DrawLine(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color);

/**
 * @brief       绘制水平直线
 * @param[in]  x0, y0: 起点坐标
 * @param[in]  len: 直线长度(像素)
 * @param[in]  color: 线条颜色值
 * @retval      无
 */
void LCD_DrawHLine(uint16_t x0, uint16_t y0, uint16_t len, uint16_t color);

/**
 * @brief       绘制垂直直线
 * @param[in]  x0, y0: 起点坐标
 * @param[in]  len: 直线长度(像素)
 * @param[in]  color: 线条颜色值
 * @retval      无
 */
void LCD_DrawVLine(uint16_t x0, uint16_t y0, uint16_t len, uint16_t color);

/*---------------------- 矩形绘制函数 ----------------------*/

/**
 * @brief       绘制矩形边框
 * @param[in]  x1, y1: 矩形左上角坐标
 * @param[in]  x2, y2: 矩形右下角坐标
 * @param[in]  color: 边框颜色值
 * @retval      无
 */
void LCD_DrawRectangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color);

/**
 * @brief       绘制圆角矩形边框
 * @param[in]  x1, y1: 矩形左上角坐标
 * @param[in]  x2, y2: 矩形右下角坐标
 * @param[in]  r: 圆角半径
 * @param[in]  color: 边框颜色值
 * @retval      无
 */
void LCD_DrawRoundedRect(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, 
                         uint8_t r, uint16_t color);

/**
 * @brief       绘制带粗细的圆角矩形边框
 * @param[in]  x1, y1: 矩形左上角坐标
 * @param[in]  x2, y2: 矩形右下角坐标
 * @param[in]  r: 圆角半径
 * @param[in]  thickness: 边框粗细
 * @param[in]  color: 边框颜色值
 * @retval      无
 */
void LCD_DrawRoundedRect_Thick(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, 
                              uint8_t r, uint8_t thickness, uint16_t color);

/**
 * @brief       绘制填充式圆角矩形
 * @param[in]  x, y: 矩形左上角坐标
 * @param[in]  w: 矩形宽度
 * @param[in]  h: 矩形高度
 * @param[in]  r: 圆角半径
 * @param[in]  color: 填充颜色值
 * @retval      无
 */
void LCD_Draw_Filled_Rounded_Rect(uint16_t x, uint16_t y, uint16_t w, uint16_t h, 
                                 uint16_t r, uint16_t color);

/*---------------------- 圆形和圆弧绘制函数 ----------------------*/

/**
 * @brief       绘制圆形边框
 * @param[in]  x0, y0: 圆心坐标
 * @param[in]  r: 圆半径
 * @param[in]  color: 边框颜色值
 * @retval      无
 */
void LCD_Draw_Circle(uint16_t x0, uint16_t y0, uint8_t r, uint16_t color);

/**
 * @brief       绘制填充圆形
 * @param[in]  x0, y0: 圆心坐标
 * @param[in]  r: 圆半径
 * @param[in]  color: 填充颜色值
 * @retval      无
 */
void LCD_Draw_FillCircle(uint16_t x0, uint16_t y0, uint8_t r, uint16_t color);

/**
 * @brief       绘制圆弧(优化版本)
 * @param[in]  x0, y0: 圆心坐标
 * @param[in]  r: 圆弧半径
 * @param[in]  start_angle: 起始角度(0-359度)
 * @param[in]  end_angle: 结束角度(0-359度)
 * @param[in]  color: 圆弧颜色值
 * @retval      无
 */
void LCD_DrawArc_Optimized(uint16_t x0, uint16_t y0, uint8_t r, 
                           uint16_t start_angle, uint16_t end_angle, uint16_t color);

/**
 * @brief       绘制圆弧(极坐标方法)
 * @param[in]  x0, y0: 圆心坐标
 * @param[in]  r: 圆弧半径
 * @param[in]  start_angle: 起始角度(0-359度)
 * @param[in]  end_angle: 结束角度(0-359度)
 * @param[in]  thickness: 圆弧粗细
 * @param[in]  color: 圆弧颜色值
 * @retval      无
 */
void LCD_DrawArc_Polar(uint16_t x0, uint16_t y0, uint8_t r, 
                       uint16_t start_angle, uint16_t end_angle, 
                       uint8_t thickness, uint16_t color);

/*---------------------- 文本显示函数 ----------------------*/

/**
 * @brief       显示汉字字符串
 * @param[in]  x, y: 显示起始坐标
 * @param[in]  s: 要显示的汉字字符串
 * @param[in]  fc: 文字颜色值
 * @param[in]  bc: 文字背景颜色值
 * @param[in]  sizey: 字体大小(12/16/24/32)
 * @param[in]  mode: 显示模式(0-非叠加, 1-叠加)
 * @retval      无
 */
void LCD_ShowChinese(uint16_t x, uint16_t y, uint8_t *s, uint16_t fc, 
                     uint16_t bc, uint8_t sizey, uint8_t mode);

/**
 * @brief       显示单个12x12汉字
 * @param[in]  x, y: 显示坐标
 * @param[in]  s: 要显示的汉字
 * @param[in]  fc: 文字颜色值
 * @param[in]  bc: 文字背景颜色值
 * @param[in]  sizey: 字体大小
 * @param[in]  mode: 显示模式(0-非叠加, 1-叠加)
 * @retval      无
 */
void LCD_ShowChinese12x12(uint16_t x, uint16_t y, uint8_t *s, uint16_t fc, 
                          uint16_t bc, uint8_t sizey, uint8_t mode);

/**
 * @brief       显示单个16x16汉字
 * @param[in]  参数同上
 * @retval      无
 */
void LCD_ShowChinese16x16(uint16_t x, uint16_t y, uint8_t *s, uint16_t fc, 
                          uint16_t bc, uint8_t sizey, uint8_t mode);

/**
 * @brief       显示单个24x24汉字
 * @param[in]  参数同上
 * @retval      无
 */
void LCD_ShowChinese24x24(uint16_t x, uint16_t y, uint8_t *s, uint16_t fc, 
                          uint16_t bc, uint8_t sizey, uint8_t mode);

/**
 * @brief       显示单个32x32汉字
 * @param[in]  参数同上
 * @retval      无
 */
void LCD_ShowChinese32x32(uint16_t x, uint16_t y, uint8_t *s, uint16_t fc, 
                         uint16_t bc, uint8_t sizey, uint8_t mode);

/**
 * @brief       显示单个ASCII字符
 * @param[in]  x, y: 显示坐标
 * @param[in]  num: 要显示的字符
 * @param[in]  fc: 文字颜色值
 * @param[in]  bc: 文字背景颜色值
 * @param[in]  sizey: 字体大小
 * @param[in]  mode: 显示模式(0-非叠加, 1-叠加)
 * @retval      无
 */
void LCD_ShowChar(uint16_t x, uint16_t y, uint8_t num, uint16_t fc, 
                  uint16_t bc, uint8_t sizey, uint8_t mode);

/**
 * @brief       显示字符串(ASCII)
 * @param[in]  x, y: 显示起始坐标
 * @param[in]  p: 要显示的字符串
 * @param[in]  fc: 文字颜色值
 * @param[in]  bc: 文字背景颜色值
 * @param[in]  sizey: 字体大小
 * @param[in]  mode: 显示模式(0-非叠加, 1-叠加)
 * @retval      无
 */
void LCD_ShowString(uint16_t x, uint16_t y, const uint8_t *p, uint16_t fc, 
                    uint16_t bc, uint8_t sizey, uint8_t mode);

/**
 * @brief       显示中英文混合文本
 * @param[in]  x, y: 显示起始坐标
 * @param[in]  str: 要显示的字符串(支持中英文混合)
 * @param[in]  fc: 文字颜色值
 * @param[in]  bc: 文字背景颜色值
 * @param[in]  sizey: 字体大小
 * @param[in]  mode: 显示模式(0-非叠加, 1-叠加)
 * @retval      无
 */
void LCD_ShowText(uint16_t x, uint16_t y, const uint8_t *str, uint16_t fc, 
                  uint16_t bc, uint8_t sizey, uint8_t mode);

/**
 * @brief       自动换行显示文本
 * @param[in]  x, y: 显示起始坐标
 * @param[in]  width: 显示区域宽度
 * @param[in]  str: 要显示的字符串
 * @param[in]  fc: 文字颜色值
 * @param[in]  bc: 文字背景颜色值
 * @param[in]  sizey: 字体大小
 * @param[in]  mode: 显示模式(0-非叠加, 1-叠加)
 * @param[in]  line_spacing: 行间距
 * @return      uint16_t: 实际显示的行数
 */
uint16_t LCD_ShowTextAutoWrap(uint16_t x, uint16_t y, uint16_t width, 
                              const uint8_t *str, uint16_t fc, uint16_t bc, 
                              uint8_t sizey, uint8_t mode, uint8_t line_spacing);

/*---------------------- 数学计算函数 ----------------------*/

/**
 * @brief       计算幂运算
 * @param[in]  m: 底数
 * @param[in]  n: 指数
 * @return      uint32_t: 计算结果
 */
uint32_t mypow(uint8_t m, uint8_t n);

/*---------------------- 数字显示函数 ----------------------*/

/**
 * @brief       显示整数变量
 * @param[in]  x, y: 显示坐标
 * @param[in]  num: 要显示的整数值
 * @param[in]  len: 显示位数
 * @param[in]  fc: 文字颜色值
 * @param[in]  bc: 文字背景颜色值
 * @param[in]  sizey: 字体大小
 * @retval      无
 */
void LCD_ShowIntNum(uint16_t x, uint16_t y, uint16_t num, uint8_t len, 
                    uint16_t fc, uint16_t bc, uint8_t sizey);

/**
 * @brief       显示浮点数变量(两位小数)
 * @param[in]  x, y: 显示坐标
 * @param[in]  num: 要显示的浮点数值
 * @param[in]  len: 显示位数
 * @param[in]  fc: 文字颜色值
 * @param[in]  bc: 文字背景颜色值
 * @param[in]  sizey: 字体大小
 * @retval      无
 */
void LCD_ShowFloatNum1(uint16_t x, uint16_t y, float num, uint8_t len, 
                       uint16_t fc, uint16_t bc, uint8_t sizey);

/*---------------------- 图片显示函数 ----------------------*/

/**
 * @brief       显示图片
 * @param[in]  x, y: 图片左上角坐标
 * @param[in]  length: 图片长度(像素)
 * @param[in]  width: 图片宽度(像素)
 * @param[in]  pic: 图片数据数组
 * @retval      无
 */
void LCD_ShowPicture(uint16_t x, uint16_t y, uint16_t length, uint16_t width, 
                     const uint8_t pic[]);

/**
 * @brief       以图片中心为基准显示图片
 * @param[in]  center_x, center_y: 图片中心坐标
 * @param[in]  length: 图片宽度(像素)
 * @param[in]  width: 图片高度(像素)
 * @param[in]  pic: 图片数据数组
 * @retval      无
 */
void LCD_ShowCentrePicture(uint16_t center_x, uint16_t center_y, 
                          uint16_t length, uint16_t width, const uint8_t pic[]);

#endif /* DISPLAY_H */

lcd_draw.c

cpp 复制代码
/******************************************************************************
 * @file        lcd_front.c
 * @brief       LCD图形绘制前端实现 - 提供基本图形、圆角矩形、圆弧等绘制功能
 * @author      古焕发
 * @version     V1.0
 * @date        2026-01-30
 * @copyright   Copyright (c) 2026
 * 
 * @description 该文件实现了LCD显示屏的各种图形绘制功能,包括基本图形、圆角矩形、
 *              圆弧等,采用查表法优化三角函数计算,提高绘制效率。
 *              所有代码内容保持原样,仅添加注释和格式优化。
 * 
 * @note        修改日志:
 *              - 2026-01-30 V1.0 古焕发 创建文件,实现完整的图形绘制功能
 ******************************************************************************/

#include "main.h"
#include "math.h"
#include "string.h"
#include "lcd_draw.h"
#include "st7789.h"
#include "lcd_front.h"
#include "bsp_htim.h"

/*---------------------- 三角函数查表数据 ----------------------*/

/**
 * @brief 余弦值查表(0-89度,放大1000倍)
 * @note  用于快速计算圆弧绘制,避免浮点运算
 */
static const uint16_t cos_tab[90] = {
    2, 15, 32, 49, 67, 84, 102, 119, 136, 153, 
    171, 188, 205, 222, 239, 256, 273, 289, 306, 323,
    339, 355, 372, 388, 404, 420, 436, 451, 467, 482, 
    497, 512, 527, 542, 556, 571, 585, 599, 613, 627, 
    640, 653, 667, 679, 692, 705, 717, 729, 741, 752, 
    764, 775, 786, 796, 807, 817, 827, 837, 846, 855, 
    864, 873, 881, 889, 897, 905, 912, 919, 926, 932, 
    938, 944, 950, 955, 960, 965, 969, 973, 977, 981, 
    984, 987, 989, 992, 994, 995, 997, 998, 999, 999,
};	

/**
 * @brief 正弦值查表(0-89度,放大1000倍)
 * @note  与余弦表配合使用,用于快速三角函数计算
 */
static const uint16_t sin_tab[90] = {
    999, 999, 999, 998, 997, 996, 994, 992, 990, 988, 
    985, 982, 978, 974, 970, 966, 961, 957, 951, 946, 
    940, 934, 928, 921, 914, 907, 899, 892, 884, 875, 
    867, 858, 849, 840, 830, 820, 810, 800, 789, 778, 
    767, 756, 744, 733, 721, 709, 696, 684, 671, 658, 
    644, 631, 617, 604, 590, 575, 561, 547, 532, 517, 
    502, 487, 472, 456, 441, 425, 409, 393, 377, 361, 
    344, 328, 311, 295, 278, 261, 244, 227, 210, 193, 
    176, 159, 142, 124, 107, 90, 72, 55, 38, 20
};

/*---------------------- 辅助计算函数 ----------------------*/

/**
 * @brief       计算角度近似值(0-90度)
 * @param[in]  x: X坐标分量
 * @param[in]  y: Y坐标分量
 * @return      int16_t: 计算的角度值(0-90度)
 * @note        使用简化公式 angle ≈ 90 * y / (x + y) 进行快速估算
 */
static int16_t calc_angle(int16_t x, int16_t y)
{
    /** 边界条件处理 */
    if (x == 0) return 90;
    if (y == 0) return 0;
    
    /** 使用简化公式进行角度估算 */
    int32_t angle = (90 * y) / (x + y);
    return (int16_t)angle;
}

/*---------------------- 基本图形绘制函数 ----------------------*/

/**
 * @brief       在指定矩形区域填充颜色
 * @param[in]  xsta, ysta: 区域起始坐标(左上角)
 * @param[in]  xend, yend: 区域结束坐标(右下角)
 * @param[in]  color: 填充颜色值
 * @retval      无
 * @note        使用双重循环逐个像素填充,适合小区域填充操作
 */
void LCD_Fill(uint16_t xsta, uint16_t ysta, uint16_t xend, uint16_t yend, uint16_t color)
{          
    uint16_t i, j; 
    
    /** 设置显示窗口范围 */
    ST7789_Set_Window(xsta, ysta, xend - 1, yend - 1);
    
    /** 双重循环填充每个像素 */
    for (i = ysta; i < yend; i++) {													   	 	
        for (j = xsta; j < xend; j++) {
            ST7789_Write_Gram(color);
        }
    } 					  	    
}

/**
 * @brief       在指定位置绘制单个像素点
 * @param[in]  x, y: 点的坐标位置
 * @param[in]  color: 点的颜色值
 * @retval      无
 * @note        直接调用底层ST7789驱动函数进行点绘制
 */
void LCD_DrawPoint(uint16_t x, uint16_t y, uint16_t color)
{
    ST7789_Draw_Point(x, y, color);
} 

/**
 * @brief       使用Bresenham算法绘制直线
 * @param[in]  x0, y0: 直线起点坐标
 * @param[in]  x1, y1: 直线终点坐标
 * @param[in]  color: 直线颜色值
 * @retval      无
 * @note        采用整数运算的Bresenham算法,避免浮点运算提高效率
 */
void LCD_DrawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint16_t color)
{
    int16_t dx, dy, sx, sy, err, e2;
    
    /** 计算坐标差值和方向 */
    dx = (x1 > x0) ? (x1 - x0) : (x0 - x1);
    dy = (y1 > y0) ? (y1 - y0) : (y0 - y1);
    
    sx = (x0 < x1) ? 1 : -1;
    sy = (y0 < y1) ? 1 : -1;
    
    err = dx - dy;
    
    /** Bresenham算法主循环 */
    while (1) {
        lptim_delay_ms(1);
        LCD_DrawPoint(x0, y0, color);
        
        /** 检查是否到达终点 */
        if (x0 == x1 && y0 == y1) break;
        
        e2 = 2 * err;
        
        /** 误差项调整和坐标更新 */
        if (e2 > -dy) {
            err -= dy;
            x0 += sx;
        }
        
        if (e2 < dx) {
            err += dx;
            y0 += sy;
        }
    }
}

/**
 * @brief       绘制水平直线
 * @param[in]  x0, y0: 起点坐标
 * @param[in]  len: 直线长度(像素)
 * @param[in]  color: 直线颜色值
 * @retval      无
 * @note        优化水平线绘制,直接使用水平线函数提高效率
 */
void LCD_DrawHLine(uint16_t x0, uint16_t y0, uint16_t len, uint16_t color)
{
    for (uint16_t i = 0; i < len; i++) {
        LCD_DrawPoint(x0 + i, y0, color);
    }
}

/**
 * @brief       绘制垂直直线
 * @param[in]  x0, y0: 起点坐标
 * @param[in]  len: 直线长度(像素)
 * @param[in]  color: 直线颜色值
 * @retval      无
 * @note        调用通用直线绘制函数实现垂直线
 */
void LCD_DrawVLine(uint16_t x0, uint16_t y0, uint16_t len, uint16_t color)
{
    LCD_DrawLine(x0, y0, x0, y0 + len, color);
}

/**
 * @brief       绘制矩形边框
 * @param[in]  x1, y1: 矩形左上角坐标
 * @param[in]  x2, y2: 矩形右下角坐标
 * @param[in]  color: 边框颜色值
 * @retval      无
 * @note        通过绘制四条直线组成矩形边框
 */
void LCD_DrawRectangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color)
{
    LCD_DrawLine(x1, y1, x2, y1, color);
    LCD_DrawLine(x1, y1, x1, y2, color);
    LCD_DrawLine(x1, y2, x2, y2, color);
    LCD_DrawLine(x2, y1, x2, y2, color);
}

/*---------------------- 圆角矩形绘制函数 ----------------------*/

/**
 * @brief       绘制圆角矩形边框(优化版本)
 * @param[in]  x1, y1: 矩形左上角坐标
 * @param[in]  x2, y2: 矩形右下角坐标
 * @param[in]  r: 圆角半径(像素)
 * @param[in]  color: 边框颜色值
 * @retval      无
 * @note        组合圆弧和直线段,实现平滑的圆角矩形效果
 */
void LCD_DrawRoundedRect(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, 
                         uint8_t r, uint16_t color)
{
    /** 参数有效性检查 */
    if (x1 > x2 || y1 > y2) {
        return;
    }
    
    uint16_t width = x2 - x1;
    uint16_t height = y2 - y1;
    
    /** 调整圆角半径避免过大 */
    if (r > width / 2) r = width / 2;
    if (r > height / 2) r = height / 2;
    
    /** 小半径回退到普通矩形绘制 */
    if (r <= 1) {
        LCD_DrawRectangle(x1, y1, x2, y2, color);
        return;
    }
    
    /** 绘制四个圆角(使用圆弧函数) */
    LCD_DrawArc_Optimized(x1 + r, y1 + r, r, 270, 360, color);
    LCD_DrawArc_Optimized(x2 - r, y1 + r, r, 0, 90, color);
    LCD_DrawArc_Optimized(x1 + r, y2 - r, r, 180, 270, color);
    LCD_DrawArc_Optimized(x2 - r, y2 - r, r, 90, 180, color);
    
    /** 绘制直线边部分 */
    if (width > 2 * r) {
        LCD_DrawHLine(x1 + r, y1, width - 2 * r, color);
        LCD_DrawHLine(x1 + r, y2, width - 2 * r, color);
    }
    
    if (height > 2 * r) {
        LCD_DrawVLine(x1, y1 + r, height - 2 * r, color);
        LCD_DrawVLine(x2, y1 + r, height - 2 * r, color);
    }
}

/**
 * @brief       绘制带粗细的圆角矩形边框
 * @param[in]  x1, y1: 矩形左上角坐标
 * @param[in]  x2, y2: 矩形右下角坐标
 * @param[in]  r: 圆角半径(像素)
 * @param[in]  thickness: 边框粗细(像素)
 * @param[in]  color: 边框颜色值
 * @retval      无
 * @note        通过绘制多个同心圆角矩形实现边框粗细效果
 */
void LCD_DrawRoundedRect_Thick(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, 
                              uint8_t r, uint8_t thickness, uint16_t color)
{
    /** 参数有效性检查 */
    if (x1 > x2 || y1 > y2 || thickness == 0) {
        return;
    }
    
    uint16_t width = x2 - x1;
    uint16_t height = y2 - y1;
    
    /** 调整圆角半径 */
    if (r > width / 2) r = width / 2;
    if (r > height / 2) r = height / 2;
    
    /** 小半径回退到普通矩形绘制 */
    if (r <= 1) {
        LCD_DrawRectangle(x1, y1, x2, y2, color);
        if (thickness > 1 && width > 2 && height > 2) {
            LCD_DrawRectangle(x1 + 1, y1 + 1, x2 - 1, y2 - 1, color);
        }
        return;
    }
    
    /** 绘制多个同心圆角矩形实现边框效果 */
    for (uint8_t t = 0; t < thickness; t++) {
        uint8_t current_r = r;
        uint16_t offset = t;
        
        /** 计算当前矩形坐标和尺寸 */
        uint16_t cur_x1 = x1 + offset;
        uint16_t cur_y1 = y1 + offset;
        uint16_t cur_x2 = x2 - offset;
        uint16_t cur_y2 = y2 - offset;
        
        uint16_t cur_width = cur_x2 - cur_x1;
        uint16_t cur_height = cur_y2 - cur_y1;
        
        /** 调整当前圆角半径 */
        if (current_r > cur_width / 2) current_r = cur_width / 2;
        if (current_r > cur_height / 2) current_r = cur_height / 2;
        
        /** 根据半径选择绘制方式 */
        if (current_r <= 1) {
            LCD_DrawRectangle(cur_x1, cur_y1, cur_x2, cur_y2, color);
        } else {
            LCD_DrawRoundedRect(cur_x1, cur_y1, cur_x2, cur_y2, current_r, color);
        }
    }
}

/**
 * @brief       绘制填充圆角矩形
 * @param[in]  x, y: 矩形左上角坐标
 * @param[in]  w, h: 矩形宽度和高度
 * @param[in]  r: 圆角半径(像素)
 * @param[in]  color: 填充颜色值
 * @retval      无
 * @note        通过组合填充圆形和矩形区域实现圆角填充效果
 */
void LCD_Draw_Filled_Rounded_Rect(uint16_t x, uint16_t y, uint16_t w, uint16_t h, 
                                  uint16_t r, uint16_t color)
{
    /** 参数检查 */
    if (w - (r * 2) < 0 || h - (r * 2) < 0) {
        return;
    }
    
    x += 1;
    
    /** 绘制四个圆角填充区域 */
    LCD_Draw_FillCircle(x + r, y + r, r, color);
    LCD_Draw_FillCircle(x + w - r, y + r, r - 2, color);
    LCD_Draw_FillCircle(x + r, y + h - r, r - 1, color);
    LCD_Draw_FillCircle(x + w - r, y + h - r, r - 2, color);
    
    /** 填充矩形主体区域 */
    ST7789_Clear_Window(x + r, y - 1, x + w - r, y + h, color);
    ST7789_Clear_Window(x - 1, y + r, x + r, y + h - r, color);
    ST7789_Clear_Window(x + w - r, y + r, x + w - 1, y + h - r, color);
}

/*---------------------- 圆弧绘制函数 ----------------------*/

/**
 * @brief       使用极坐标方法绘制带粗细的圆弧
 * @param[in]  x0, y0: 圆心坐标
 * @param[in]  r: 圆弧半径(像素)
 * @param[in]  start_angle: 起始角度(0-359度)
 * @param[in]  end_angle: 结束角度(0-359度)
 * @param[in]  thickness: 圆弧粗细(像素)
 * @param[in]  color: 圆弧颜色值
 * @retval      无
 * @note        使用极坐标公式计算每个点位置,支持任意角度和粗细
 */
void LCD_DrawArc_Polar(uint16_t x0, uint16_t y0, uint8_t r, 
                       uint16_t start_angle, uint16_t end_angle, 
                       uint8_t thickness, uint16_t color)
{
    /** 参数有效性检查 */
    if (r == 0 || thickness == 0) return;
    
    /** 角度规范化处理 */
    start_angle = start_angle % 360;
    end_angle = end_angle % 360;
    
    if (start_angle > end_angle) {
        end_angle += 360;
    }
    
    /** 计算内外半径 */
    float inner_r = (float)r;
    float outer_r = (float)(r + thickness - 1);
    
    /** 极坐标绘制主循环 */
    for (uint16_t angle = start_angle; angle <= end_angle; angle++) {
        /** 角度转弧度 */
        float rad = (float)angle * 3.14159265f / 180.0f;
        
        /** 计算三角函数值 */
        float cos_a = cosf(rad);
        float sin_a = sinf(rad);
        
        /** 径向绘制从内到外的点 */
        for (float current_r = inner_r; current_r <= outer_r; current_r += 0.5f) {
            int16_t x = x0 + (int16_t)(current_r * cos_a);
            int16_t y = y0 - (int16_t)(current_r * sin_a);
            
            /** 坐标有效性检查 */
            if (x >= 0 && y >= 0) {
                LCD_DrawPoint(x, y, color);
            }
        }
    }
}

/******************************************************************************
      函数说明:画圆弧(优化版本,使用角度查找表)
      入口数据:x0,y0   圆心坐标
                r       半径
                start_angle 起始角度(度,0-359)
                end_angle   结束角度(度,0-359)
                color   圆弧的颜色
      返回值:  无
******************************************************************************/
void LCD_DrawArc_Optimized(uint16_t x0, uint16_t y0, uint8_t r, 
                           uint16_t start_angle, uint16_t end_angle, uint16_t color)
{
    int a, b;
    static uint8_t angle_table[361];  // 角度查找表,0-360度
    
    // 参数检查
    if (r == 0) return;
    
    // 规范化角度
    start_angle = start_angle % 360;
    end_angle = end_angle % 360;
    
    // 初始化角度查找表
    memset(angle_table, 0, sizeof(angle_table));
    
    // 标记需要绘制的角度
    if (start_angle <= end_angle) {
        for (uint16_t angle = start_angle; angle <= end_angle; angle++) {
            angle_table[angle] = 1;
        }
    } else {
        // 跨越360度的情况
        for (uint16_t angle = start_angle; angle < 360; angle++) {
            angle_table[angle] = 1;
        }
        for (uint16_t angle = 0; angle <= end_angle; angle++) {
            angle_table[angle] = 1;
        }
    }
    
    a = 0;
    b = r;
    
    // 使用与Draw_Circle相同的算法
    while (a <= b) {
        // 计算8个点的角度
        int16_t angles[8];
        
        // 计算角度(近似计算)
        angles[0] = calc_angle(a, b);      // 第1象限
        angles[1] = calc_angle(b, a);      // 第2象限
        angles[2] = 180 - angles[1];       // 第3象限
        angles[3] = 180 - angles[0];       // 第4象限
        angles[4] = 180 + angles[0];       // 第5象限
        angles[5] = 180 + angles[1];       // 第6象限
        angles[6] = 360 - angles[1];       // 第7象限
        angles[7] = 360 - angles[0];       // 第8象限
        
        // 检查并绘制每个点
        if (angle_table[angles[0]]) LCD_DrawPoint(x0 + a, y0 - b, color);
        if (angle_table[angles[1]]) LCD_DrawPoint(x0 + b, y0 - a, color);
        if (angle_table[angles[2]]) LCD_DrawPoint(x0 + b, y0 + a, color);
        if (angle_table[angles[3]]) LCD_DrawPoint(x0 + a, y0 + b, color);
        if (angle_table[angles[4]]) LCD_DrawPoint(x0 - a, y0 + b, color);
        if (angle_table[angles[5]]) LCD_DrawPoint(x0 - b, y0 + a, color);
        if (angle_table[angles[6]]) LCD_DrawPoint(x0 - b, y0 - a, color);
        if (angle_table[angles[7]]) LCD_DrawPoint(x0 - a, y0 - b, color);
        
        a++;
        if ((a * a + b * b) > (r * r)) {
            b--;
        }
    }
}

/******************************************************************************
      函数说明:画圆
      入口数据:x0,y0   圆心坐标
                r       半径
                color   圆的颜色
      返回值:  无
******************************************************************************/
void LCD_Draw_Circle(uint16_t x,uint16_t y,uint8_t r,uint16_t color)
{
	uint32_t rx = 0;
    uint32_t ry = 0;
    uint32_t last_rx = 0;
    uint32_t last_ry = 0;
    LCD_DrawPoint(x, y, color);          /* 圆心 */
	for (uint16_t angle = 0; angle < 90; angle++)
	{
		rx = r * cos_tab[angle] / 1000 + x;
		ry = r * sin_tab[angle] / 1000 + y;
		
		if (last_rx != rx || last_ry != ry)
		{
			LCD_DrawLine(rx, y - (ry - y), rx, ry, color);
			LCD_DrawLine(x - (rx - x), y - (ry - y), x - (rx - x), ry, color);
			last_rx = rx;
			last_ry = ry;
		}
	}
}

/******************************************************************************
      函数说明:画圆角填充圆形
      入口数据:x0,y0   圆心坐标
                r       半径
                color   矩形的颜色
      返回值:  无
******************************************************************************/
void LCD_Draw_FillCircle(uint16_t x0, uint16_t y0, uint8_t r, uint16_t color)
{
    int16_t x = 0;
    int16_t y = r;
    int16_t d = 3 - 2 * r;
    
    while (x <= y) {
        // 关键:内部循环确保每个垂直段都被填充
        for (int16_t i = x; i <= y; i++) {
            // 绘制8个对称位置
            // 使用水平线提高效率
            LCD_DrawPoint(x0 + x, y0 + i, color);
            LCD_DrawPoint(x0 - x, y0 + i, color);
            
            if (i != 0) {
                LCD_DrawPoint(x0 - i, y0 + x, color);
                LCD_DrawPoint(x0 - i, y0 - x, color);
                LCD_DrawPoint(x0 - x, y0 - i, color);
                LCD_DrawPoint(x0 + x, y0 - i, color);
                LCD_DrawPoint(x0 + i, y0 - x, color);
                LCD_DrawPoint(x0 + i, y0 + x, color);
            }
        }
        
        if (d < 0) {
            d = d + 4 * x + 6;
        } else {
            d = d + 4 * (x - y) + 10;
            y--;
        }
        x++;
    }
}
/******************************************************************************
      函数说明:显示汉字串
      入口数据:x,y显示坐标
                *s 要显示的汉字串
                fc 字的颜色
                bc 字的背景色
                sizey 字号 可选 16 24 32
                mode:  0非叠加模式  1叠加模式
      返回值:  无
******************************************************************************/
void LCD_ShowChinese(uint16_t x,uint16_t y,uint8_t *s,uint16_t fc,uint16_t bc,uint8_t sizey,uint8_t mode)
{
	while(*s!=0)
	{
		if(sizey==12) LCD_ShowChinese12x12(x,y,s,fc,bc,sizey,mode);
		else if(sizey==16) LCD_ShowChinese16x16(x,y,s,fc,bc,sizey,mode);
		else if(sizey==24) LCD_ShowChinese24x24(x,y,s,fc,bc,sizey,mode);
		else if(sizey==32) LCD_ShowChinese32x32(x,y,s,fc,bc,sizey,mode);
		else return;
		s+=2;
		x+=sizey;
	}
}

/******************************************************************************
      函数说明:显示单个12x12汉字
      入口数据:x,y显示坐标
                *s 要显示的汉字
                fc 字的颜色
                bc 字的背景色
                sizey 字号
                mode:  0非叠加模式  1叠加模式
      返回值:  无
******************************************************************************/
void LCD_ShowChinese12x12(uint16_t x,uint16_t y,uint8_t *s,uint16_t fc,uint16_t bc,uint8_t sizey,uint8_t mode)
{
	uint8_t i,j,m=0;
	uint16_t k;
	uint16_t HZnum;//汉字数目
	uint16_t TypefaceNum;//一个字符所占字节大小
	uint16_t x0=x;
	TypefaceNum=(sizey/8+((sizey%8)?1:0))*sizey;
	                         
	HZnum=sizeof(tfont12)/sizeof(typFNT_GB12);	//统计汉字数目
	for(k=0;k<HZnum;k++) 
	{
		if((tfont12[k].Index[0]==*(s))&&(tfont12[k].Index[1]==*(s+1)))
		{ 	
			ST7789_Set_Window(x,y,x+sizey-1,y+sizey-1);
			for(i=0;i<TypefaceNum;i++)
			{
				for(j=0;j<8;j++)
				{	
					if(!mode)//非叠加方式
					{
						if(tfont12[k].Msk[i]&(0x01<<j))ST7789_Write_Gram(fc);
						else ST7789_Write_Gram(bc);
						m++;
						if(m%sizey==0)
						{
							m=0;
							break;
						}
					}
					else//叠加方式
					{
						if(tfont12[k].Msk[i]&(0x01<<j))	LCD_DrawPoint(x,y,fc);//画一个点
						x++;
						if((x-x0)==sizey)
						{
							x=x0;
							y++;
							break;
						}
					}
				}
			}
		}				  	
		continue;  //查找到对应点阵字库立即退出,防止多个汉字重复取模带来影响
	}
} 

/******************************************************************************
      函数说明:显示单个16x16汉字
      入口数据:x,y显示坐标
                *s 要显示的汉字
                fc 字的颜色
                bc 字的背景色
                sizey 字号
                mode:  0非叠加模式  1叠加模式
      返回值:  无
******************************************************************************/
void LCD_ShowChinese16x16(uint16_t x,uint16_t y,uint8_t *s,uint16_t fc,uint16_t bc,uint8_t sizey,uint8_t mode)
{
	uint8_t i,j,m=0;
	uint16_t k;
	uint16_t HZnum;//汉字数目
	uint16_t TypefaceNum;//一个字符所占字节大小
	uint16_t x0=x;
	TypefaceNum=(sizey/8+((sizey%8)?1:0))*sizey;
	HZnum=sizeof(tfont16)/sizeof(typFNT_GB16);	//统计汉字数目
	
	for(k=0;k<HZnum;k++) 
	{
		if ((tfont16[k].Index[0]==*(s))&&(tfont16[k].Index[1]==*(s+1)))
		{ 	
			ST7789_Set_Window(x,y,x+sizey-1,y+sizey-1);
			for(i=0;i<TypefaceNum;i++)
			{
				for(j=0;j<8;j++)
				{	
					if(!mode)//非叠加方式
					{
						if(tfont16[k].Msk[i]&(0x01<<j))ST7789_Write_Gram(fc);
						else ST7789_Write_Gram(bc);
						m++;
						if(m%sizey==0)
						{
							m=0;
							break;
						}
					}
					else//叠加方式
					{
						if(tfont16[k].Msk[i]&(0x01<<j))	LCD_DrawPoint(x,y,fc);//画一个点
						x++;
						if((x-x0)==sizey)
						{
							x=x0;
							y++;
							break;
						}
					}
				}
			}
		}				  	
		continue;  //查找到对应点阵字库立即退出,防止多个汉字重复取模带来影响
	}
} 


/******************************************************************************
      函数说明:显示单个24x24汉字
      入口数据:x,y显示坐标
                *s 要显示的汉字
                fc 字的颜色
                bc 字的背景色
                sizey 字号
                mode:  0非叠加模式  1叠加模式
      返回值:  无
******************************************************************************/
void LCD_ShowChinese24x24(uint16_t x,uint16_t y,uint8_t *s,uint16_t fc,uint16_t bc,uint8_t sizey,uint8_t mode)
{
	uint8_t i,j,m=0;
	uint16_t k;
	uint16_t HZnum;//汉字数目
	uint16_t TypefaceNum;//一个字符所占字节大小
	uint16_t x0=x;
	TypefaceNum=(sizey/8+((sizey%8)?1:0))*sizey;
	HZnum=sizeof(tfont24)/sizeof(typFNT_GB24);	//统计汉字数目
	for(k=0;k<HZnum;k++) 
	{
		if ((tfont24[k].Index[0]==*(s))&&(tfont24[k].Index[1]==*(s+1)))
		{ 	
			ST7789_Set_Window(x,y,x+sizey-1,y+sizey-1);
			for(i=0; i <TypefaceNum; i++)
			{
				for(j=0;j<8;j++)
				{	
					if(!mode)//非叠加方式
					{
						if(tfont24[k].Msk[i]&(0x01<<j))ST7789_Write_Gram(fc);
						else ST7789_Write_Gram(bc);
						m++;
						if(m%sizey==0)
						{
							m=0;
							break;
						}
					}
					else//叠加方式
					{
						if(tfont24[k].Msk[i]&(0x01<<j))	LCD_DrawPoint(x,y,fc);//画一个点
						x++;
						if((x-x0)==sizey)
						{
							x=x0;
							y++;
							break;
						}
					}
				}
			}
		}				  	
		continue;  //查找到对应点阵字库立即退出,防止多个汉字重复取模带来影响
	}
} 

/******************************************************************************
      函数说明:显示单个32x32汉字
      入口数据:x,y显示坐标
                *s 要显示的汉字
                fc 字的颜色
                bc 字的背景色
                sizey 字号
                mode:  0非叠加模式  1叠加模式
      返回值:  无
******************************************************************************/
void LCD_ShowChinese32x32(uint16_t x,uint16_t y,uint8_t *s,uint16_t fc,uint16_t bc,uint8_t sizey,uint8_t mode)
{
	uint8_t i,j,m=0;
	uint16_t k;
	uint16_t HZnum;//汉字数目
	uint16_t TypefaceNum;//一个字符所占字节大小
	uint16_t x0=x;
	TypefaceNum=(sizey/8+((sizey%8)?1:0))*sizey;
	HZnum=sizeof(tfont32)/sizeof(typFNT_GB32);	//统计汉字数目
	for(k=0;k<HZnum;k++) 
	{
		if ((tfont32[k].Index[0]==*(s))&&(tfont32[k].Index[1]==*(s+1)))
		{ 	
			ST7789_Set_Window(x,y,x+sizey-1,y+sizey-1);
			for(i=0;i<TypefaceNum;i++)
			{
				for(j=0;j<8;j++)
				{	
					if(!mode)//非叠加方式
					{
						if(tfont32[k].Msk[i]&(0x01<<j))ST7789_Write_Gram(fc);
						else ST7789_Write_Gram(bc);
						m++;
						if(m%sizey==0)
						{
							m=0;
							break;
						}
					}
					else//叠加方式
					{
						if(tfont32[k].Msk[i]&(0x01<<j))	LCD_DrawPoint(x,y,fc);//画一个点
						x++;
						if((x-x0)==sizey)
						{
							x=x0;
							y++;
							break;
						}
					}
				}
			}
		}				  	
		continue;  //查找到对应点阵字库立即退出,防止多个汉字重复取模带来影响
	}
}


/******************************************************************************
      函数说明:显示单个字符
      入口数据:x,y显示坐标
                num 要显示的字符
                fc 字的颜色
                bc 字的背景色
                sizey 字号
                mode:  0非叠加模式  1叠加模式
      返回值:  无
******************************************************************************/
void LCD_ShowChar(uint16_t x,uint16_t y,uint8_t num,uint16_t fc,uint16_t bc,uint8_t sizey,uint8_t mode)
{
	uint8_t temp,sizex,t,m=0;
	uint16_t i,TypefaceNum;//一个字符所占字节大小
	uint16_t x0=x;
	sizex=sizey/2;
	TypefaceNum=(sizex/8+((sizex%8)?1:0))*sizey;
	num=num-' ';    //得到偏移后的值
	ST7789_Set_Window(x,y,x+sizex-1,y+sizey-1);  //设置光标位置 
	for(i=0;i<TypefaceNum;i++)
	{ 
		if(sizey==12)temp=ascii_1206[num][i];		     //调用6x12字体
		else if(sizey==16)temp=ascii_1608[num][i];		 //调用8x16字体
		else if(sizey==24)temp=ascii_2412[num][i];		 //调用12x24字体
		else if(sizey==32)temp=ascii_3216[num][i];		 //调用16x32字体
		else return;
		for(t=0;t<8;t++)
		{
			if(!mode)//非叠加模式
			{
				if(temp&(0x01<<t))ST7789_Write_Gram(fc);
				else ST7789_Write_Gram(bc);
				m++;
				if(m%sizex==0)
				{
					m=0;
					break;
				}
			}
			else//叠加模式
			{
				if(temp&(0x01<<t))LCD_DrawPoint(x,y,fc);//画一个点
				x++;
				if((x-x0)==sizex)
				{
					x=x0;
					y++;
					break;
				}
			}
		}
	}   	 	  
}
/******************************************************************************
      函数说明:显示字符串
      入口数据:x,y显示坐标
                *p 要显示的字符串
                fc 字的颜色
                bc 字的背景色
                sizey 字号
                mode:  0非叠加模式  1叠加模式
      返回值:  无
******************************************************************************/
void LCD_ShowString(uint16_t x,uint16_t y,const uint8_t *p,uint16_t fc,uint16_t bc,uint8_t sizey,uint8_t mode)
{         
	while(*p!='\0')
	{       
		LCD_ShowChar(x,y,*p,fc,bc,sizey,mode);
		x+=sizey/2;
		p++;
	}  
}
/******************************************************************************
      函数说明:显示数字
      入口数据:m底数,n指数
      返回值:  无
******************************************************************************/
uint32_t mypow(uint8_t m,uint8_t n)
{
	uint32_t result=1;	 
	while(n--)result*=m;
	return result;
}
/******************************************************************************
      函数说明:显示整数变量
      入口数据:x,y显示坐标
                num 要显示整数变量
                len 要显示的位数
                fc 字的颜色
                bc 字的背景色
                sizey 字号
      返回值:  无
******************************************************************************/
void LCD_ShowIntNum(uint16_t x,uint16_t y,uint16_t num,uint8_t len,uint16_t fc,uint16_t bc,uint8_t sizey)
{         	
	uint8_t t,temp;
	uint8_t enshow=0;
	uint8_t sizex=sizey/2;
	for(t=0;t<len;t++)
	{
		temp=(num/mypow(10,len-t-1))%10;
		if(enshow==0&&t<(len-1))
		{
			if(temp==0)
			{
				LCD_ShowChar(x+t*sizex,y,' ',fc,bc,sizey,0);
				continue;
			}else enshow=1; 
		 	 
		}
	 	LCD_ShowChar(x+t*sizex,y,temp+48,fc,bc,sizey,0);
	}
} 
/******************************************************************************
      函数说明:显示两位小数变量
      入口数据:x,y显示坐标
                num 要显示小数变量
                len 要显示的位数
                fc 字的颜色
                bc 字的背景色
                sizey 字号
      返回值:  无
******************************************************************************/
void LCD_ShowFloatNum1(uint16_t x,uint16_t y,float num,uint8_t len,uint16_t fc,uint16_t bc,uint8_t sizey)
{         	
	uint8_t t,temp,sizex;
	uint16_t num1;
	sizex=sizey/2;
	num1=num*100;
	for(t=0;t<len;t++)
	{
		temp=(num1/mypow(10,len-t-1))%10;
		if(t==(len-2))
		{
			LCD_ShowChar(x+(len-2)*sizex,y,'.',fc,bc,sizey,0);
			t++;
			len+=1;
		}
	 	LCD_ShowChar(x+t*sizex,y,temp+48,fc,bc,sizey,0);
	}
}


/******************************************************************************
      函数说明:显示图片
      入口数据:x,y起点坐标
                length 图片长度
                width  图片宽度
                pic[]  图片数组    
      返回值:  无
******************************************************************************/
void LCD_ShowPicture(uint16_t x,uint16_t y,uint16_t length,uint16_t width,const uint8_t pic[])
{
	uint16_t i,j;
	uint32_t k=0;
	ST7789_Set_Window(x,y,x+length-1,y+width-1);
	for(i=0;i<length;i++)
	{
		for(j=0;j<width;j++)
		{					 	
			uint16_t data = (pic[k*2+1] << 8) | pic[k*2];
			ST7789_Write_Gram(data);
			k++;
		}
	}
}

/**
 * @brief 以图片中心为基准绘制图片
 * @param center_x: 图片中心X坐标
 * @param center_y: 图片中心Y坐标
 * @param length: 图片宽度
 * @param width: 图片高度
 * @param pic: 图片数据数组
 * 
 * 注意:函数将图片中心放在指定的(center_x, center_y)位置
 */
void LCD_ShowCentrePicture(uint16_t center_x, uint16_t center_y, 
                     uint16_t length, uint16_t width, 
                     const uint8_t pic[])
{
    // 1. 计算左上角起点坐标
    uint16_t start_x = center_x - (length / 2);
    uint16_t start_y = center_y - (width / 2);
    
    // 2. 设置显示窗口
    ST7789_Set_Window(start_x, start_y, 
                     start_x + length - 1, 
                     start_y + width - 1);
    
    // 3. 写入图片数据
    uint16_t i, j;
    uint32_t k = 0;
    
    for(i = 0; i < length; i++) {
        for(j = 0; j < width; j++) {
            uint16_t data = (pic[k*2+1] << 8) | pic[k*2];
            ST7789_Write_Gram(data);
            k++;
        }
    }
}

/******************************************************************************
      函数说明:显示中英文字符串(通用函数)
      入口数据:x,y显示坐标
                *str 要显示的字符串(支持中英文混合)
                fc 字的颜色
                bc 字的背景色
                sizey 字号
                mode: 0非叠加模式 1叠加模式
      返回值:  无
******************************************************************************/
void LCD_ShowText(uint16_t x, uint16_t y, const uint8_t *str, uint16_t fc, uint16_t bc, uint8_t sizey, uint8_t mode)
{
    uint16_t cursor_x = x;
    uint16_t cursor_y = y;
    
    while (*str != '\0')
    {
        // 判断是否为中文字符(GB2312编码,首字节0xA1~0xF7,次字节0xA1~0xFE)
        if ((*str >= 0xA1) && (*str <= 0xF7))
        {
            // 检查是否有下一个字符
            if (*(str + 1) != '\0' && (*(str + 1) >= 0xA1) && (*(str + 1) <= 0xFE))
            {
                // 显示单个汉字
                if (sizey == 12)
                    LCD_ShowChinese12x12(cursor_x, cursor_y, (uint8_t *)str, fc, bc, sizey, mode);
                else if (sizey == 16)
                    LCD_ShowChinese16x16(cursor_x, cursor_y, (uint8_t *)str, fc, bc, sizey, mode);
                else if (sizey == 24)
                    LCD_ShowChinese24x24(cursor_x, cursor_y, (uint8_t *)str, fc, bc, sizey, mode);
                else if (sizey == 32)
                    LCD_ShowChinese32x32(cursor_x, cursor_y, (uint8_t *)str, fc, bc, sizey, mode);
                
                cursor_x += sizey;  // 中文字符宽度
                str += 2;           // 跳过两个字节
                continue;
            }
        }
        // 判断是否为ASCII字符
        else if (*str >= 0x20 && *str <= 0x7E)
        {
            // 显示单个ASCII字符
            LCD_ShowChar(cursor_x, cursor_y, *str, fc, bc, sizey, mode);
            cursor_x += sizey / 2;  // ASCII字符宽度是中文的一半
        }
        // 处理换行符
        else if (*str == '\n')
        {
            cursor_x = x;           // 回到行首
            cursor_y += sizey;      // 换行
        }
        // 处理回车符
        else if (*str == '\r')
        {
            cursor_x = x;           // 回到行首
        }
        // 处理制表符(4个空格)
        else if (*str == '\t')
        {
            cursor_x += (sizey / 2) * 4;  // 4个空格宽度
        }
        // 其他字符(如控制字符)跳过
        else
        {
            // 不显示的字符,跳过
        }
        
        str++;  // 移动到下一个字符
    }
}

/******************************************************************************
      函数说明:显示中英文字符串(带换行自动处理)
      入口数据:x,y显示坐标
                width 显示区域宽度
                *str 要显示的字符串
                fc 字的颜色
                bc 字的背景色
                sizey 字号
                mode: 0非叠加模式 1叠加模式
                line_spacing 行间距
      返回值:  实际显示的行数
******************************************************************************/
uint16_t LCD_ShowTextAutoWrap(uint16_t x, uint16_t y, uint16_t width, 
                               const uint8_t *str, uint16_t fc, uint16_t bc, 
                               uint8_t sizey, uint8_t mode, uint8_t line_spacing)
{
    uint16_t cursor_x = x;
    uint16_t cursor_y = y;
    uint16_t line_count = 1;
    uint16_t char_width = 0;
    const uint8_t *line_start = str;
    const uint8_t *word_start = str;
    uint8_t is_chinese = 0;
    
    while (*str != '\0')
    {
        // 判断字符类型
        if ((*str >= 0xA1) && (*str <= 0xF7))
        {
            // 中文字符
            if (*(str + 1) != '\0' && (*(str + 1) >= 0xA1) && (*(str + 1) <= 0xFE))
            {
                char_width = sizey;  // 中文字符宽度
                is_chinese = 1;
            }
        }
        else if (*str >= 0x20 && *str <= 0x7E)
        {
            // ASCII字符
            char_width = sizey / 2;
            is_chinese = 0;
        }
        else if (*str == '\n')
        {
            // 强制换行
            if (cursor_x != x)
            {
                // 显示当前行
                uint8_t line_len = str - line_start;
                uint8_t temp_str[256];
                if (line_len < 255)
                {
                    memcpy(temp_str, line_start, line_len);
                    temp_str[line_len] = '\0';
                    LCD_ShowText(x, cursor_y, temp_str, fc, bc, sizey, mode);
                }
            }
            
            cursor_x = x;
            cursor_y += sizey + line_spacing;
            line_start = str + 1;
            line_count++;
            char_width = 0;
        }
        else if (*str == ' ')
        {
            char_width = sizey / 2;  // 空格宽度
        }
        else
        {
            char_width = 0;
        }
        
        // 检查是否需要自动换行
        if (cursor_x - x + char_width > width && cursor_x > x)
        {
            // 找到行内最后一个空格或标点符号进行换行
            const uint8_t *wrap_pos = str;
            uint8_t found_break = 0;
            
            // 向前查找合适的断点
            while (wrap_pos > word_start)
            {
                 if (*wrap_pos == ' ' || *wrap_pos == ',' || *wrap_pos == '.' || 
                    *wrap_pos == ';' || *wrap_pos == '!' || *wrap_pos == '?' ||
                    *wrap_pos == ':')
                {
                    found_break = 1;
                    break;
                }
                wrap_pos--;
            }
            
            if (!found_break)
            {
                wrap_pos = str;  // 没有找到合适的断点,在当前字符前换行
            }
            
            // 显示当前行
            uint8_t line_len = wrap_pos - line_start;
            if (line_len > 0)
            {
                uint8_t temp_str[256];
                if (line_len < 255)
                {
                    memcpy(temp_str, line_start, line_len);
                    temp_str[line_len] = '\0';
                    LCD_ShowText(x, cursor_y, temp_str, fc, bc, sizey, mode);
                }
            }
            
            // 准备下一行
            cursor_x = x;
            cursor_y += sizey + line_spacing;
            line_start = wrap_pos;
            if (found_break) line_start++;  // 跳过断点字符
            
            // 重置当前位置
            str = line_start - 1;  // 减1,因为循环末尾会自增
            word_start = line_start;
            line_count++;
        }
        else
        {
            cursor_x += char_width;
            
            // 记录单词开始位置(用于英文断行)
            if (*str == ' ' || is_chinese)
            {
                word_start = str;
                if (*str == ' ') word_start++;
            }
        }
        
        str++;
    }
    
    // 显示最后一行
    if (line_start < str)
    {
        uint8_t last_line_len = str - line_start;
        if (last_line_len > 0)
        {
            uint8_t temp_str[256];
            if (last_line_len < 255)
            {
                memcpy(temp_str, line_start, last_line_len);
                temp_str[last_line_len] = '\0';
                LCD_ShowText(x, cursor_y, temp_str, fc, bc, sizey, mode);
            }
        }
    }
    
    return line_count;
}

2.GVGL层

内存管理

gui_mem.h
cpp 复制代码
/******************************************************************************
 * @file        gui_mem.h
 * @brief       GUI内存管理头文件 - 栈式内存池实现,1KB固定大小内存管理
 * @author      古焕发
 * @version     V1.0
 * @date        2026-01-30
 * @copyright   Copyright (c) 2026
 * 
 * @description 该头文件定义了嵌入式GUI系统的内存管理接口,采用栈式内存池设计,
 *              提供固定1KB内存空间的分配、释放、压缩和完整性检查功能。
 *              使用句柄代替指针,避免内存碎片,适合资源受限的嵌入式环境。
 * 
 * @note        修改日志:
 *              - 2026-01-30 V1.0 古焕发 创建文件,实现栈式内存池管理
 ******************************************************************************/

#ifndef GUI_MEM_H
#define GUI_MEM_H

#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>

/*---------------------- 内存池配置常量 ----------------------*/

/** 内存池总大小配置(1KB固定空间) */
#define TOTAL_POOL_SIZE      1024  /**< 内存池总容量:1024字节(1KB) */

/** 句柄和块管理配置 */
#define MAX_HANDLES          16    /**< 最大句柄数量:支持同时管理16个内存块 */

/** 内存对齐配置(4字节对齐优化访问效率) */
#define ALIGNMENT            4     /**< 内存对齐字节数 */
#define ALIGN_MASK           (ALIGNMENT - 1)  /**< 对齐掩码 */

/**
 * @brief       内存大小对齐宏
 * @param[in]  x: 需要对齐的内存大小
 * @return      对齐后的内存大小
 * @note        确保分配的内存块按4字节边界对齐,提高访问效率
 */
#define ALIGN_UP(x)         (((x) + ALIGN_MASK) & ~ALIGN_MASK)

/*---------------------- 枚举类型定义 ----------------------*/

/**
 * @brief 内存块状态枚举
 * @note  定义内存块的生命周期状态,支持延迟释放和碎片整理机制
 */
typedef enum {
    BLOCK_FREE = 0,     /**< 空闲状态:块未被使用,可分配 */
    BLOCK_USED,         /**< 已用状态:块已被分配,正在使用 */
    BLOCK_DANGLING,     /**< 悬挂状态:已释放但尚未压缩回收 */
} block_state_t;

/*---------------------- 数据结构定义 ----------------------*/

/**
 * @brief 内存块描述符结构
 * @note  记录每个内存块的元数据信息,用于管理和追踪内存使用情况
 */
typedef struct {
    uint16_t offset;    /**< 在内存池中的偏移地址(相对于pool[0]) */
    uint16_t size;      /**< 块实际大小(包括对齐填充) */
    uint8_t  state;     /**< 块当前状态(FREE/USED/DANGLING) */
    uint8_t  type;      /**< 对象类型标识(由调用者定义用途) */
} block_desc_t;

/**
 * @brief 栈式内存池主结构
 * @note  完整的内存池管理系统,包含存储空间、管理数据和状态信息
 */
typedef struct {
    uint8_t pool[TOTAL_POOL_SIZE];      /**< 1KB实际内存存储空间 */
    block_desc_t blocks[MAX_HANDLES];    /**< 块描述符表(管理元数据) */
    uint8_t handle_stack[MAX_HANDLES];   /**< 空闲句柄栈(LIFO管理) */
    int16_t stack_top;                  /**< 栈顶指针(-1表示栈空) */
    uint16_t alloc_ptr;                 /**< 当前分配指针(下一个空闲位置) */
    uint16_t watermark;                 /**< 高水位标记(历史最大使用量) */
    uint16_t compactions;               /**< 内存压缩次数统计 */
} stack_mempool_t;

/*---------------------- 类型定义和常量 ----------------------*/

/** 内存句柄类型(代替直接指针使用) */
typedef uint8_t mem_handle_t;

/** 无效句柄常量 */
#define INVALID_HANDLE     0xFF  /**< 无效句柄标识(分配失败返回值) */

/*---------------------- 全局变量声明 ----------------------*/

/** 全局内存池实例 */
extern stack_mempool_t mempool;

/*---------------------- 函数声明 ----------------------*/

/**
 * @defgroup mem_init 内存池初始化函数
 * @{
 */

/**
 * @brief       初始化栈式内存池系统
 * @return      bool: 成功返回true,失败返回false
 * @note        清零内存池,初始化空闲句柄栈,设置初始状态。
 *              必须在其他内存操作函数之前调用。
 */
bool stack_mempool_init(void);

/** @} */

/**
 * @defgroup mem_alloc 内存分配和释放函数
 * @{
 */

/**
 * @brief       从内存池分配指定大小的内存块
 * @param[in]  size: 请求的内存大小(字节)
 * @param[in]  type: 内存块类型标识(用户自定义)
 * @return      mem_handle_t: 成功返回有效句柄,失败返回INVALID_HANDLE
 * @note        自动处理内存对齐,空间不足时尝试压缩,支持延迟释放机制。
 *              返回句柄而非指针,避免内存碎片问题。
 */
mem_handle_t stack_mempool_alloc(uint16_t size, uint8_t type);

/**
 * @brief       释放指定句柄对应的内存块
 * @param[in]  handle: 要释放的内存块句柄
 * @return      bool: 成功返回true,失败返回false
 * @note        采用延迟释放策略,标记为悬挂状态,等待压缩时真正回收内存。
 *              立即回收句柄到空闲栈供后续分配使用。
 */
bool stack_mempool_free(mem_handle_t handle);

/**
 * @brief       执行内存压缩,解决内存碎片问题
 * @retval      无
 * @note        移动所有在用内存块到低地址,合并悬挂块,回收碎片空间。
 *              压缩操作会更新所有块的偏移量,确保数据完整性。
 */
void stack_mempool_compact(void);

/** @} */

/**
 * @defgroup mem_query 内存状态查询函数
 * @{
 */

/**
 * @brief       获取当前可用内存大小
 * @return      uint16_t: 可用内存字节数
 * @note        基于当前分配指针计算剩余连续空间。
 *              不包括悬挂块占用的空间(压缩后可回收)。
 */
uint16_t stack_mempool_available(void);

/**
 * @brief       根据句柄获取对应的内存数据指针
 * @param[in]  handle: 内存块句柄
 * @return      void*: 成功返回数据指针,失败返回NULL
 * @note        必须确保句柄有效且对应的内存块处于已用状态。
 *              返回的指针在内存压缩后可能失效,使用后应及时更新。
 */
void* stack_mempool_get_ptr(mem_handle_t handle);

/**
 * @brief       执行内存池完整性检查
 * @return      bool: 检查通过返回true,发现问题返回false
 * @note        验证分配指针、栈指针、块描述符等关键数据的合理性。
 *              用于调试和系统可靠性保障。
 */
bool stack_mempool_integrity_check(void);

/** @} */

/**
 * @defgroup mem_debug 调试和诊断函数
 * @{
 */

/**
 * @brief       内存池状态转储(调试用)
 * @retval      无
 * @note        详细显示内存池使用情况、块状态和内存布局信息。
 *              仅在调试版本中启用,生产环境建议关闭。
 */
void stack_mempool_dump(void);

/** @} */

#endif /* GUI_MEM_H */
gui_mem.c
cpp 复制代码
#include "gui_mem.h"
#include <string.h>
#include <stdio.h>

/******************************************************************************
 * @file        gui_mem.c
 * @brief       栈式内存池实现 - 1KB固定大小内存池,支持句柄管理和内存压缩
 * @author      古焕发
 * @version     V1.0
 * @date        2026-01-30
 * @copyright   Copyright (c) 2026
 * 
 * @description 该文件实现了一个高效的栈式内存池管理系统,采用固定1KB内存空间,
 *              支持句柄管理、内存压缩和完整性检查,适用于嵌入式GUI系统。
 *              所有代码内容保持原样,仅添加注释和格式优化。
 * 
 * @note        修改日志:
 *              - 2026-01-30 V1.0 古焕发 创建文件,实现栈式内存池管理
 ******************************************************************************/

#include "gui_mem.h"
#include <string.h>
#include <stdio.h>

/** 全局内存池实例 */
stack_mempool_t mempool = {0};

/**
 * @brief       初始化内存池系统
 * @return      bool: 初始化成功返回true
 * @note        清零内存池,初始化空闲句柄栈和块描述符,设置初始状态
 */
bool stack_mempool_init(void) {
    /** 清零整个内存池结构 */
    memset(&mempool, 0, sizeof(stack_mempool_t));
    
    /** 初始化空闲句柄栈(从高到低填充) */
    mempool.stack_top = MAX_HANDLES - 1;
    for (int i = 0; i < MAX_HANDLES; i++) {
        mempool.handle_stack[i] = i;
    }
    
    /** 初始化所有块描述符为空闲状态 */
    for (int i = 0; i < MAX_HANDLES; i++) {
        mempool.blocks[i].state = BLOCK_FREE;
        mempool.blocks[i].offset = 0;
        mempool.blocks[i].size = 0;
    }
    
    /** 初始化内存分配指针和统计信息 */
    mempool.alloc_ptr = 0;
    mempool.watermark = 0;
    mempool.compactions = 0;
    
    return true;
}

/**
 * @brief       从内存池分配指定大小的内存块
 * @param[in]  size: 请求的内存大小(字节)
 * @param[in]  type: 内存块类型标识
 * @return      mem_handle_t: 成功返回有效句柄,失败返回INVALID_HANDLE
 * @note        自动处理内存对齐,空间不足时尝试压缩,更新高水位标记
 */
mem_handle_t stack_mempool_alloc(uint16_t size, uint8_t type) {
    /** 参数检查:大小不能为0,且必须有空闲句柄 */
    if (size == 0 || mempool.stack_top < 0) {
        return INVALID_HANDLE;
    }
    
    /** 计算对齐后的实际需要大小 */
    uint16_t aligned_size = ALIGN_UP(size);
    if (aligned_size == 0) {
        aligned_size = ALIGNMENT;
    }
    
    /** 检查当前连续空间是否足够 */
    uint16_t needed_space = mempool.alloc_ptr + aligned_size;
    
    /** 空间不足时尝试内存压缩 */
    if (needed_space > TOTAL_POOL_SIZE) {
        stack_mempool_compact();
        needed_space = mempool.alloc_ptr + aligned_size;
        
        /** 压缩后仍然空间不足,返回错误 */
        if (needed_space > TOTAL_POOL_SIZE) {
            return INVALID_HANDLE;
        }
    }
    
    /** 从栈顶弹出空闲句柄 */
    mem_handle_t handle = mempool.handle_stack[mempool.stack_top--];
    
    /** 设置块描述符信息 */
    mempool.blocks[handle].offset = mempool.alloc_ptr;
    mempool.blocks[handle].size = aligned_size;
    mempool.blocks[handle].state = BLOCK_USED;
    mempool.blocks[handle].type = type;
    
    /** 更新内存分配指针 */
    mempool.alloc_ptr += aligned_size;
    
    /** 更新高水位标记(记录历史最大使用量) */
    if (mempool.alloc_ptr > mempool.watermark) {
        mempool.watermark = mempool.alloc_ptr;
    }
    
    return handle;
}

/**
 * @brief       释放指定句柄对应的内存块
 * @param[in]  handle: 要释放的内存块句柄
 * @return      bool: 成功返回true,失败返回false
 * @note        实际采用延迟释放策略,标记为悬挂状态,等待压缩时真正回收
 */
bool stack_mempool_free(mem_handle_t handle) {
    /** 句柄有效性检查 */
    if (handle >= MAX_HANDLES) {
        return false;
    }
    
    /** 获取块描述符并检查状态 */
    block_desc_t* block = &mempool.blocks[handle];
    if (block->state != BLOCK_USED) {
        return false;  /**< 不是已使用的块 */
    }
    
    /** 标记为悬挂状态(延迟释放) */
    block->state = BLOCK_DANGLING;
    
    /** 将句柄压回空闲栈,供后续分配使用 */
    if (mempool.stack_top < MAX_HANDLES - 1) {
        mempool.handle_stack[++mempool.stack_top] = handle;
    }
    
    return true;
}

/**
 * @brief       执行内存压缩,解决内存碎片问题
 * @retval      无
 * @note        移动所有在用内存块到低地址,回收悬挂块,更新分配指针
 */
void stack_mempool_compact(void) {
    uint16_t new_offset = 0;
    
    /** 创建临时数组记录需要移动的块信息 */
    struct {
        mem_handle_t handle;   /**< 块句柄 */
        uint16_t old_offset;   /**< 原始偏移量 */
    } move_list[MAX_HANDLES];
    
    int move_count = 0;
    
    /** 第一遍扫描:收集所有需要保留的已用块 */
    for (int i = 0; i < MAX_HANDLES; i++) {
        if (mempool.blocks[i].state == BLOCK_USED) {
            move_list[move_count].handle = i;
            move_list[move_count].old_offset = mempool.blocks[i].offset;
            move_count++;
        } else {
            /** 释放悬挂块,标记为空闲状态 */
            mempool.blocks[i].state = BLOCK_FREE;
        }
    }
    
    /** 如果没有需要移动的块,直接重置分配指针 */
    if (move_count == 0) {
        mempool.alloc_ptr = 0;
        mempool.compactions++;
        return;
    }
    
    /** 第二遍扫描:按顺序移动内存块到新位置 */
    for (int i = 0; i < move_count; i++) {
        block_desc_t* block = &mempool.blocks[move_list[i].handle];
        
        /** 检查是否需要实际移动(偏移量是否改变) */
        if (new_offset != move_list[i].old_offset) {
            /** 计算源地址和目标地址 */
            uint8_t* src = &mempool.pool[move_list[i].old_offset];
            uint8_t* dst = &mempool.pool[new_offset];
            
            /** 执行内存移动操作 */
            memmove(dst, src, block->size);
            
            /** 更新块的偏移量 */
            block->offset = new_offset;
        }
        
        /** 更新新偏移量指针 */
        new_offset += block->size;
    }
    
    /** 更新全局分配指针和压缩计数 */
    mempool.alloc_ptr = new_offset;
    mempool.compactions++;
    
    /** 可选:清零剩余内存区域(提高安全性) */
    if (mempool.alloc_ptr < TOTAL_POOL_SIZE) {
        memset(&mempool.pool[mempool.alloc_ptr], 0, 
               TOTAL_POOL_SIZE - mempool.alloc_ptr);
    }
}

/**
 * @brief       获取当前可用内存大小
 * @return      uint16_t: 可用内存字节数
 * @note        基于当前分配指针计算剩余空间
 */
uint16_t stack_mempool_available(void) {
    return TOTAL_POOL_SIZE - mempool.alloc_ptr;
}

/**
 * @brief       根据句柄获取对应的内存数据指针
 * @param[in]  handle: 内存块句柄
 * @return      void*: 成功返回数据指针,失败返回NULL
 * @note        必须确保句柄有效且对应的内存块处于已用状态
 */
void* stack_mempool_get_ptr(mem_handle_t handle) {
    /** 句柄有效性检查和状态验证 */
    if (handle >= MAX_HANDLES || mempool.blocks[handle].state != BLOCK_USED) {
        return NULL;
    }
    
    /** 返回内存池中对应偏移量的数据指针 */
    return &mempool.pool[mempool.blocks[handle].offset];
}

/**
 * @brief       执行内存池完整性检查
 * @return      bool: 检查通过返回true,发现问题返回false
 * @note        验证分配指针、栈指针、块描述符等关键数据的合理性
 */
bool stack_mempool_integrity_check(void) {
    /** 检查分配指针是否超出总容量 */
    if (mempool.alloc_ptr > TOTAL_POOL_SIZE) {
        return false;
    }
    
    /** 检查栈指针范围是否合理 */
    if (mempool.stack_top < -1 || mempool.stack_top >= MAX_HANDLES) {
        return false;
    }
    
    /** 检查高水位标记是否合理 */
    if (mempool.watermark > TOTAL_POOL_SIZE) {
        return false;
    }
    
    /** 检查所有块描述符的完整性 */
    uint16_t total_used = 0;
    uint16_t used_count = 0;
    
    for (int i = 0; i < MAX_HANDLES; i++) {
        block_desc_t* block = &mempool.blocks[i];
        
        if (block->state == BLOCK_USED) {
            /** 检查块偏移量是否有效 */
            if (block->offset >= TOTAL_POOL_SIZE) {
                return false;
            }
            
            /** 检查块大小是否会导致越界 */
            if (block->offset + block->size > TOTAL_POOL_SIZE) {
                return false;
            }
            
            total_used += block->size;
            used_count++;
        }
    }
    
    /** 验证分配指针是否与已用内存总量匹配 */
    uint16_t current_used = 0;
    for (int i = 0; i < MAX_HANDLES; i++) {
        if (mempool.blocks[i].state == BLOCK_USED) {
            current_used += mempool.blocks[i].size;
        }
    }
    
    if (current_used != mempool.alloc_ptr) {
        return false;
    }
    
    return true;
}

/**
 * @brief       内存池状态转储函数(已注释,需要时启用)
 * @retval      无
 * @note        详细显示内存池使用情况、块状态和内存布局信息
 */
/*
void stack_mempool_dump(void) {
    printf("\n=== 1KB栈式内存池状态 ===\n");
    printf("分配指针: %u bytes\n", mempool.alloc_ptr);
    printf("可用内存: %u bytes\n", stack_mempool_available());
    printf("高水位: %u bytes\n", mempool.watermark);
    printf("压缩次数: %u\n", mempool.compactions);
    printf("空闲句柄: %d\n", mempool.stack_top + 1);
    
    printf("\n块状态:\n");
    printf("ID  | 状态  | 偏移  | 大小  | 类型\n");
    printf("----|-------|-------|-------|-----\n");
    
    for (int i = 0; i < MAX_HANDLES; i++) {
        block_desc_t* block = &mempool.blocks[i];
        if (block->state != BLOCK_FREE) {
            const char* state_str = "";
            switch (block->state) {
                case BLOCK_USED: state_str = "已用"; break;
                case BLOCK_DANGLING: state_str = "悬挂"; break;
                case BLOCK_FREE: state_str = "空闲"; break;
            }
            printf("%2d  | %-6s| %-5u | %-5u | %-3u\n", 
                   i, state_str, block->offset, block->size, block->type);
        }
    }
    
    // 显示内存布局图形化表示
    printf("\n内存布局:\n");
    char layout[TOTAL_POOL_SIZE / 16 + 1] = {0};
    for (int i = 0; i < TOTAL_POOL_SIZE / 16; i++) {
        layout[i] = '.';
    }
    
    for (int i = 0; i < MAX_HANDLES; i++) {
        if (mempool.blocks[i].state == BLOCK_USED) {
            uint16_t start = mempool.blocks[i].offset / 16;
            uint16_t end = (mempool.blocks[i].offset + mempool.blocks[i].size - 1) / 16;
            for (uint16_t j = start; j <= end && j < sizeof(layout); j++) {
                layout[j] = 'X';
            }
        }
    }
    
    printf("内存使用: |%.*s|\n", TOTAL_POOL_SIZE / 16, layout);
    printf("         0");
    for (int i = 1; i < TOTAL_POOL_SIZE / 16; i++) {
        if (i % 8 == 0) printf("%d", i/8);
        else printf(" ");
    }
    printf("%d bytes\n", TOTAL_POOL_SIZE);
}
*/

对象管理器+渲染

gui_obj_mgr.h
cpp 复制代码
/******************************************************************************
 * @file        gui_obj_mgr.h
 * @brief       GUI对象管理系统头文件 - 提供图形对象创建、管理、渲染和事件处理功能
 * @author      古焕发
 * @version     V1.0
 * @date        2026-01-30
 * @copyright   Copyright (c) 2026
 * 
 * @description 该头文件定义了完整的GUI对象管理系统,采用分层对象模型设计,
 *              支持多种图形元素、相对定位、事件回调等高级特性。
 *              所有代码内容保持原样,仅添加注释和格式优化。
 * 
 * @note        修改日志:
 *              - 2026-01-30 V1.0 [您的姓名] 创建文件,定义完整的GUI对象管理系统
 ******************************************************************************/

#ifndef GUI_OBJ_MGR_H
#define GUI_OBJ_MGR_H

#include <stdint.h>
#include <stdbool.h>
#include "gui_mem.h"

/*---------------------- 颜色定义常量 ----------------------*/

/** 颜色类型定义 (RGB565格式) */
typedef uint16_t gui_color_t;

/** 特殊颜色标记 - 使用父对象背景色 */
#define USE_PARENT_BG          0xFEFE  /**< 使用父对象背景色的特殊标记 */

/** 基础颜色定义 (RGB565格式) */
#define GUI_COLOR_BLACK         0x0000  /**< 黑色 */
#define GUI_COLOR_WHITE         0xFFFF  /**< 白色 */
#define GUI_COLOR_RED           0xF800  /**< 红色 */
#define GUI_COLOR_GREEN         0x07E0  /**< 绿色 */
#define GUI_COLOR_BLUE          0x001F  /**< 蓝色 */
#define GUI_COLOR_YELLOW        0xFFE0  /**< 黄色 */
#define GUI_COLOR_CYAN          0x07FF  /**< 青色 */
#define GUI_COLOR_MAGENTA       0xF81F  /**< 洋红色 */
#define GUI_COLOR_GRAY          0x8410  /**< 灰色 */
#define GUI_COLOR_LIGHTGRAY     0xC618  /**< 浅灰色 */
#define GUI_COLOR_DARKGRAY      0x4208  /**< 深灰色 */

/** 暖色系扩展 */
#define GUI_COLOR_ORANGE         0xFD20  /**< 橙色 */
#define GUI_COLOR_BROWN          0xBC40  /**< 棕色 */
#define GUI_COLOR_BRRED          0xFC07  /**< 棕红色 */
#define GUI_COLOR_PINK           0xFE19  /**< 粉色 */
#define GUI_COLOR_CORAL          0xFBEA  /**< 珊瑚色 */
#define GUI_COLOR_GOLD           0xFEA0  /**< 金色 */
#define GUI_COLOR_MAROON         0x7800  /**< 栗色 */
#define GUI_COLOR_PURPLE         0x8010  /**< 紫色 */
#define GUI_COLOR_OLIVE          0x5340  /**< 橄榄绿 */

/** 冷色系扩展 */
#define GUI_COLOR_DARKBLUE       0x01CF  /**< 深蓝色 */
#define GUI_COLOR_LIGHTBLUE      0x7D7C  /**< 浅蓝色 */
#define GUI_COLOR_GRAYBLUE       0x5458  /**< 灰蓝色 */
#define GUI_COLOR_NAVY           0x000F  /**< 海军蓝 */
#define GUI_COLOR_TEAL           0x0410  /**< 青蓝色 */
#define GUI_COLOR_TURQUOISE      0x06FF  /**< 绿松石色 */
#define GUI_COLOR_DARKGREEN      0x0320  /**< 深绿色 */
#define GUI_COLOR_LIGHTGREEN     0x841F  /**< 浅绿色 */
#define GUI_COLOR_PALEGREEN      0x9FD3  /**< 淡绿色 */
#define GUI_COLOR_SEAGREEN       0x2C4A  /**< 海绿色 */
#define GUI_COLOR_AQUAMARINE     0x7FFA  /**< 海蓝宝石色 */
#define GUI_COLOR_EMERALDGREEN   0x07D0  /**< 宝石绿色 */
#define GUI_COLOR_SPRINGGREEN    0x07EF  /**< 春绿色 */
#define GUI_COLOR_MEDIUMSPRINGGREEN 0x06D3 /**< 中春绿色 */

/** 中性色与特殊色扩展 */
#define GUI_COLOR_SILVER         0xC618  /**< 银色 */
#define GUI_COLOR_VIOLET         0xEC1D  /**< 紫罗兰色 */
#define GUI_COLOR_INDIGO         0x4810  /**< 靛蓝色 */
#define GUI_COLOR_MINTCREAM      0xF7FE  /**< 薄荷奶油色 */
#define GUI_COLOR_MINTPASTEL     0x8FF0  /**< 柔和薄荷色 */
#define GUI_COLOR_PALETURQUOISE  0xAF7D  /**< 苍绿松石色 */
#define GUI_COLOR_DARKTURQUOISE  0x067A  /**< 深绿松石色 */
#define GUI_COLOR_MEDIUMTURQUOISE 0x4E0B /**< 中绿松石色 */

/** 专业UI色系扩展 */
#define GUI_COLOR_SLATEBLUE      0x6AD9  /**< 石板蓝色 */
#define GUI_COLOR_CADETBLUE      0x5CF4  /**< 军服蓝色 */
#define GUI_COLOR_POWDERBLUE     0xAEFC  /**< 粉末蓝色 */
#define GUI_COLOR_LGRAYBLUE      0xA651  /**< 浅灰蓝色(中间层颜色) */
#define GUI_COLOR_LBBLUE         0x2B12  /**< 浅棕蓝色(选择条反色) */

/*---------------------- 基本类型定义 ----------------------*/

/** 图形对象句柄类型 (基于内存管理器) */
typedef mem_handle_t gui_handle_t;

/** 无效句柄常量 */
#define GUI_INVALID_HANDLE      INVALID_HANDLE

/*---------------------- 枚举类型定义 ----------------------*/

/**
 * @brief 字体大小枚举
 * @note  支持12、16、24、32四种标准字号
 */
typedef enum {
    GUI_FONT_12 = 12,  /**< 12像素字体 */
    GUI_FONT_16 = 16,  /**< 16像素字体 */
    GUI_FONT_24 = 24,  /**< 24像素字体 */
    GUI_FONT_32 = 32   /**< 32像素字体 */
} gui_font_size_t;

/**
 * @brief 图形对象类型枚举
 * @note  定义系统中支持的各类图形对象类型
 */
typedef enum {
    GUI_OBJ_TYPE_WIDGET = 1,   /**< 基本控件类型 */
    GUI_OBJ_TYPE_LABEL,        /**< 标签对象 */
    GUI_OBJ_TYPE_LABEL_WRAP,   /**< 自动换行标签 */
    GUI_OBJ_TYPE_BUTTON,       /**< 按钮对象 */
    GUI_OBJ_TYPE_PANEL,        /**< 面板容器 */
    GUI_OBJ_TYPE_IMAGE,        /**< 图片对象 */
    GUI_OBJ_TYPE_WINDOW        /**< 窗口对象 */
} gui_obj_type_t;

/**
 * @brief 事件类型枚举
 * @note  定义GUI系统支持的用户交互事件类型
 */
typedef enum {
    GUI_EVENT_CLICK = 0,      /**< 点击事件 */
    GUI_EVENT_PRESS,          /**< 按下事件 */
    GUI_EVENT_RELEASE,        /**< 释放事件 */
    GUI_EVENT_LONG_PRESS,     /**< 长按事件 */
    GUI_EVENT_UPDATE          /**< 更新事件 */
} gui_event_t;

/**
 * @brief 对齐方式枚举
 * @note  定义对象在容器内的水平和对齐方式
 */
typedef enum {
    GUI_ALIGN_LEFT = 0,      /**< 左对齐 */
    GUI_ALIGN_CENTER,        /**< 居中对齐 */
    GUI_ALIGN_RIGHT,         /**< 右对齐 */
    GUI_ALIGN_TOP = 0,       /**< 顶部对齐 */
    GUI_ALIGN_MIDDLE,        /**< 垂直居中 */
    GUI_ALIGN_BOTTOM         /**< 底部对齐 */
} gui_align_t;

/**
 * @brief 定位模式枚举
 * @note  定义对象相对于父容器或屏幕的定位方式
 */
typedef enum {
    GUI_POS_MODE_ABSOLUTE = 0,  /**< 绝对定位(相对于屏幕) */
    GUI_POS_MODE_RELATIVE,      /**< 相对定位(相对于父对象) */
    GUI_POS_MODE_ANCHOR         /**< 锚点定位 */
} gui_pos_mode_t;

/**
 * @brief 锚点类型枚举
 * @note  定义对象在父容器内的锚点位置,用于精确定位
 */
typedef enum {
    GUI_ANCHOR_NONE = 0,        /**< 无锚点 */
    GUI_ANCHOR_TOP_LEFT,        /**< 左上角锚点 */
    GUI_ANCHOR_TOP_CENTER,      /**< 顶部居中锚点 */
    GUI_ANCHOR_TOP_RIGHT,       /**< 右上角锚点 */
    GUI_ANCHOR_CENTER_LEFT,     /**< 左侧居中锚点 */
    GUI_ANCHOR_CENTER,          /**< 中心锚点 */
    GUI_ANCHOR_CENTER_RIGHT,    /**< 右侧居中锚点 */
    GUI_ANCHOR_BOTTOM_LEFT,     /**< 左下角锚点 */
    GUI_ANCHOR_BOTTOM_CENTER,   /**< 底部居中锚点 */
    GUI_ANCHOR_BOTTOM_RIGHT     /**< 右下角锚点 */
} gui_anchor_t;

/**
 * @brief 面板形状类型枚举
 * @note  定义面板对象支持的各种形状样式
 */
typedef enum {
    GUI_PANEL_SHAPE_RECT = 0,   /**< 矩形面板 */
    GUI_PANEL_SHAPE_ROUNDED,    /**< 圆角矩形面板 */
    GUI_PANEL_SHAPE_CIRCLE,     /**< 圆形面板 */
    GUI_PANEL_SHAPE_ARC         /**< 圆弧形状面板 */
} gui_panel_shape_t;

/*---------------------- 数据结构定义 ----------------------*/

/**
 * @brief 数据块尾部结构(用于存储句柄信息)
 * @note  附加在数据块末尾,用于管理数据块的生命周期和内存管理
 */
typedef struct {
    mem_handle_t data_handle;   /**< 数据块句柄 */
} gui_data_footer_t;

/**
 * @brief 坐标点结构
 * @note  定义二维坐标系中的点坐标
 */
typedef struct {
    int16_t x;  /**< X坐标 */
    int16_t y;  /**< Y坐标 */
} gui_point_t;

/**
 * @brief 自动换行标签数据结构
 * @note  用于支持文本自动换行功能的标签对象
 */
typedef struct {
    gui_font_size_t font_size;  /**< 字体大小 */
    int16_t max_width;          /**< 最大宽度(0表示不限制) */
    int16_t max_lines;          /**< 最大行数 */
    int16_t char_width;         /**< 字符宽度 */
    int16_t char_height;        /**< 字符高度 */
    char* text;                 /**< 文本内容指针 */
} gui_label_wrap_data_t;

/**
 * @brief 面板扩展数据结构(紧密打包)
 * @note  使用#pragma pack确保结构体紧密排列,节省内存空间
 */
#pragma pack(push, 1)  // 确保紧密打包
typedef struct {
    gui_panel_shape_t shape;      /**< 面板形状类型 */
    uint8_t radius;               /**< 圆角半径/圆弧半径 */
    uint8_t thickness;            /**< 边框粗细 */
    uint16_t start_angle;         /**< 圆弧起始角度(0-359度) */
    uint16_t end_angle;           /**< 圆弧结束角度(0-359度) */
} gui_panel_data_t;
#pragma pack(pop)

/**
 * @brief 矩形区域结构
 * @note  定义矩形区域的坐标和尺寸信息
 */
typedef struct {
    int16_t x;       /**< 左上角X坐标 */
    int16_t y;       /**< 左上角Y坐标 */
    int16_t width;   /**< 矩形宽度 */
    int16_t height;  /**< 矩形高度 */
} gui_rect_t;

/**
 * @brief 相对定位信息结构
 * @note  存储对象相对于父对象的定位信息和锚点设置
 */
typedef struct {
    gui_handle_t parent;         /**< 父对象句柄 */
    int16_t rel_x;               /**< 相对于父对象的X坐标偏移 */
    int16_t rel_y;               /**< 相对于父对象的Y坐标偏移 */
    gui_pos_mode_t pos_mode;     /**< 定位模式 */
    gui_anchor_t anchor;         /**< 锚点类型 */
} gui_pos_info_t;

/*---------------------- 对象特定数据结构 ----------------------*/

/** 基本图形对象结构前置声明 */
typedef struct gui_obj_t gui_obj_t;

/**
 * @brief 事件回调函数类型定义
 * @param[in] handle: 触发事件的对象句柄
 * @param[in] event: 事件类型
 * @note  用于处理用户交互事件的回调函数接口
 */
typedef void (*gui_event_callback_t)(gui_handle_t handle, uint8_t event);

/**
 * @brief 标签对象数据结构
 * @note  存储标签对象的文本和字体信息
 */
typedef struct {
    char* text;                   /**< 文本内容指针 */
    gui_font_size_t font_size;    /**< 字体大小 */
} gui_label_data_t;

/**
 * @brief 按钮对象数据结构
 * @note  存储按钮对象的文本、字体和状态信息
 */
typedef struct {
    char* text;                   /**< 按钮文本 */
    gui_font_size_t font_size;    /**< 字体大小 */
    bool pressed;                 /**< 按钮按下状态 */
} gui_button_data_t;

/**
 * @brief 图片对象数据结构
 * @note  存储图片对象的数据指针和相关信息
 */
typedef struct {
    const uint8_t* image_data;    /**< 图片数据指针 */
} gui_image_data_t;

/*---------------------- 核心对象结构定义 ----------------------*/

/**
 * @brief 基本图形对象结构
 * @note  所有GUI对象的基类,包含对象的通用属性和方法
 *        采用4字节对齐优化内存访问效率
 */
struct gui_obj_t {
    /* 基本属性 */
    gui_obj_type_t type;          /**< 对象类型 */
    bool visible;                 /**< 可见性标志 */
    bool updated;                 /**< 更新标志 */
    
    /* 几何属性 */
    int16_t x;                    /**< X坐标(绝对或相对) */
    int16_t y;                    /**< Y坐标(绝对或相对) */
    int16_t width;                /**< 对象宽度 */
    int16_t height;               /**< 对象高度 */
    
    /* 外观属性 */
    gui_color_t color;            /**< 前景颜色 */
    gui_color_t bg_color;         /**< 背景颜色 */
    
    /* 事件回调 */
    gui_event_callback_t callback; /**< 事件回调函数指针 */
    void* data;                   /**< 对象特定数据指针 */
    
    /* 相对定位信息 */
    gui_handle_t parent;          /**< 父对象句柄 */
    int16_t rel_x;               /**< 相对于父对象的X坐标 */
    int16_t rel_y;               /**< 相对于父对象的Y坐标 */
    gui_pos_mode_t pos_mode;     /**< 定位模式 */
    gui_anchor_t anchor;         /**< 锚点类型 */
} __attribute__((aligned(4)));   /**< 4字节对齐,优化内存访问 */

/*---------------------- 系统初始化和诊断函数 ----------------------*/

/**
 * @brief       执行内存对齐诊断
 * @retval      无
 * @note        用于调试阶段检查内存对齐情况,确保数据结构正确对齐
 */
void diagnose_memory_alignment(void);

/**
 * @brief       执行完整内存测试
 * @retval      无
 * @note        测试所有内存相关功能,包括分配、释放、边界检查等完整性测试
 */
void test_memory_all(void);

/**
 * @brief       初始化GUI图形系统
 * @return      bool: 初始化成功返回true,失败返回false
 * @note        必须在调用其他GUI函数前执行,负责初始化内存管理和基本硬件
 */
bool gui_init(void);

/*---------------------- 基础绘制函数 ----------------------*/

/**
 * @brief       自动换行文本绘制函数
 * @param[in]  x, y: 文本起始坐标
 * @param[in]  width: 文本区域宽度
 * @param[in]  text: 要显示的文本字符串
 * @param[in]  color: 文本颜色
 * @param[in]  bg_color: 背景颜色
 * @param[in]  font_size: 字体大小
 * @param[in]  line_spacing: 行间距
 * @retval      无
 * @note        支持自动换行功能,适合显示长文本内容
 */
void gui_draw_text_auto(int16_t x, int16_t y, int16_t width, const char* text, 
                       gui_color_t color, gui_color_t bg_color, 
                       gui_font_size_t font_size, uint8_t line_spacing);

/*---------------------- 对象管理核心函数 ----------------------*/

/**
 * @brief       创建基本图形对象
 * @param[in]  type: 对象类型
 * @param[in]  x, y: 对象位置坐标
 * @param[in]  width, height: 对象尺寸
 * @return      gui_handle_t: 成功返回对象句柄,失败返回GUI_INVALID_HANDLE
 * @note        这是创建所有图形对象的基础函数,分配内存并初始化基本属性
 */
gui_handle_t gui_create_obj(gui_obj_type_t type, int16_t x, int16_t y, 
                             int16_t width, int16_t height);

/**
 * @brief       销毁图形对象并释放资源
 * @param[in]  handle: 要销毁的对象句柄
 * @return      bool: 成功返回true,失败返回false
 * @note        会递归销毁所有子对象,并释放相关内存资源
 */
bool gui_destroy_obj(gui_handle_t handle);

/**
 * @brief       设置对象位置
 * @param[in]  handle: 目标对象句柄
 * @param[in]  x, y: 新的位置坐标
 * @return      bool: 成功返回true,失败返回false
 * @note        设置对象的绝对或相对位置,触发界面更新
 */
bool gui_set_obj_pos(gui_handle_t handle, int16_t x, int16_t y);

/**
 * @brief       设置对象尺寸
 * @param[in]  handle: 目标对象句柄
 * @param[in]  width, height: 新的尺寸
 * @return      bool: 成功返回true,失败返回false
 * @note        调整对象宽度和高度,可能影响子对象布局
 */
bool gui_set_obj_size(gui_handle_t handle, int16_t width, int16_t height);

/**
 * @brief       设置对象可见性
 * @param[in]  handle: 目标对象句柄
 * @param[in]  visible: 可见性标志
 * @return      bool: 成功返回true,失败返回false
 * @note        控制对象显示或隐藏,隐藏对象不参与渲染但仍保留在内存中
 */
bool gui_set_obj_visible(gui_handle_t handle, bool visible);

/**
 * @brief       设置对象事件回调函数
 * @param[in]  handle: 目标对象句柄
 * @param[in]  callback: 回调函数指针
 * @return      bool: 成功返回true,失败返回false
 * @note        注册用户交互事件的处理函数,如点击、触摸等事件
 */
bool gui_set_obj_callback(gui_handle_t handle, gui_event_callback_t callback);

/**
 * @brief       根据句柄获取对象指针
 * @param[in]  handle: 对象句柄
 * @return      gui_obj_t*: 成功返回对象指针,失败返回NULL
 * @note        返回的指针在对象销毁后无效,使用时需确保对象生命周期
 */
gui_obj_t* gui_get_obj(gui_handle_t handle);

/*---------------------- 特定对象创建函数 ----------------------*/

// 基本对象创建函数
gui_handle_t gui_create_label(int16_t x, int16_t y, const char* text, 
                             gui_font_size_t font_size, gui_color_t color, 
                             gui_color_t bg_color);
                             
gui_handle_t gui_create_button(int16_t x, int16_t y, int16_t width, int16_t height, 
                              const char* text, gui_font_size_t font_size);
                              
gui_handle_t gui_create_panel(int16_t x, int16_t y, int16_t width, int16_t height, 
                             gui_color_t color, gui_color_t border_color);
                             
gui_handle_t gui_create_image(int16_t x, int16_t y, int16_t width, int16_t height, 
                            const uint8_t* image_data);

// 扩展面板创建函数
gui_handle_t gui_create_panel_ex(int16_t x, int16_t y, int16_t width, int16_t height, 
                               gui_color_t color, gui_color_t border_color, 
                               gui_panel_shape_t shape, uint8_t radius, uint8_t thickness, 
                               uint16_t start_angle, uint16_t end_angle);
                               
gui_handle_t gui_create_rounded_panel(int16_t x, int16_t y, int16_t width, int16_t height, 
                                    gui_color_t color, gui_color_t border_color, 
                                    uint8_t radius, uint8_t thickness);
                                    
gui_handle_t gui_create_circle_panel(int16_t x, int16_t y, int16_t diameter, 
                                   gui_color_t color, gui_color_t border_color, 
                                   uint8_t thickness);
                                   
gui_handle_t gui_create_arc_panel(int16_t x, int16_t y, uint8_t radius, 
                                 gui_color_t color, gui_color_t border_color, 
                                 uint8_t thickness, uint16_t start_angle, uint16_t end_angle);

/*---------------------- 相对定位对象创建函数 ----------------------*/

gui_handle_t gui_create_panel_relative(gui_handle_t parent, int16_t rel_x, int16_t rel_y,
                                      int16_t width, int16_t height,
                                      gui_color_t color, gui_color_t border_color);
                                      
gui_handle_t gui_create_panel_anchor(gui_handle_t parent, gui_anchor_t anchor,
                                    int16_t offset_x, int16_t offset_y,
                                    int16_t width, int16_t height,
                                    gui_color_t color, gui_color_t border_color);
                                    
gui_handle_t gui_create_label_relative(gui_handle_t parent, int16_t rel_x, int16_t rel_y, 
                                      const char* text, gui_font_size_t font_size, 
                                      gui_color_t color, gui_color_t bg_color);
                                      
gui_handle_t gui_create_label_anchor(gui_handle_t parent, gui_anchor_t anchor, 
                                   int16_t offset_x, int16_t offset_y, 
                                   const char* text, gui_font_size_t font_size, 
                                   gui_color_t color, gui_color_t bg_color);
                                   
gui_handle_t gui_create_button_relative(gui_handle_t parent, int16_t rel_x, int16_t rel_y, 
                                       int16_t width, int16_t height, 
                                       const char* text, gui_font_size_t font_size);

/*---------------------- 对象属性设置函数 ----------------------*/

bool gui_set_text(gui_handle_t handle, const char* text);
bool gui_set_color(gui_handle_t handle, gui_color_t color);
bool gui_set_bg_color(gui_handle_t handle, gui_color_t bg_color);
bool gui_set_font_size(gui_handle_t handle, gui_font_size_t font_size);
bool gui_set_image(gui_handle_t handle, const uint8_t* image_data);
bool gui_set_panel_shape(gui_handle_t handle, gui_panel_shape_t shape, 
                        uint8_t radius, uint8_t thickness);
bool gui_set_panel_arc_angle(gui_handle_t handle, uint16_t start_angle, 
                           uint16_t end_angle);
bool gui_set_panel_radius(gui_handle_t handle, uint8_t radius);

/*---------------------- 相对定位相关函数 ----------------------*/

bool gui_set_parent(gui_handle_t child, gui_handle_t parent);
bool gui_set_relative_position(gui_handle_t child, int16_t rel_x, int16_t rel_y);
bool gui_set_anchor(gui_handle_t child, gui_anchor_t anchor, 
                   int16_t offset_x, int16_t offset_y);
bool gui_update_relative_position(gui_handle_t parent);

/*---------------------- 渲染和事件处理函数 ----------------------*/

void gui_render_obj(gui_handle_t handle);
void gui_render_all(void);
void gui_handle_touch(int16_t x, int16_t y, uint8_t event);
void gui_update(void);

/*---------------------- 内存管理函数 ----------------------*/

uint16_t gui_get_memory_used(void);
uint16_t gui_get_memory_available(void);
bool gui_memory_check(void);

#endif /* GUI_OBJ_MGR_H */
gui_obj_mgr.c
cpp 复制代码
#include "gui_obj_mgr.h"
#include "lcd_draw.h"
#include "bsp_all.h"
#include <string.h>
#include <stdio.h>

/******************************************************************************
 * @file        gui_obj_mgr.c
 * @brief       GUI对象管理系统实现文件 - 提供图形对象创建、管理、渲染和事件处理功能
 * @author      古焕发
 * @version     V1.0
 * @date        2026-01-30
 * @copyright   Copyright (c) 2026
 * 
 * @description 该文件实现了GUI对象管理系统的核心功能,包括图形对象的创建、销毁、
 *              管理、渲染和事件处理等。采用分层对象模型设计,支持多种图形元素、
 *              相对定位、事件回调等高级特性。
 * 
 * @note        修改日志:
 *              - 2026-01-30 V1.0 古焕发 创建文件,实现完整的GUI对象管理系统
 ******************************************************************************/

/*---------------------- 内部辅助函数 ----------------------*/

/******************************************************************************
      函数说明:获取数据块的句柄
      入口数据:type     对象类型
                data_ptr 数据指针
      返回值:  数据句柄
******************************************************************************/
static mem_handle_t get_data_handle_from_footer(gui_obj_type_t type, void* data_ptr) {
    if (!data_ptr) return INVALID_HANDLE;
    
    gui_data_footer_t* footer = NULL;
    
    switch (type) {
        case GUI_OBJ_TYPE_LABEL: {
            gui_label_data_t* label_data = (gui_label_data_t*)data_ptr;
            if (!label_data->text) return INVALID_HANDLE;
            int text_len = strlen(label_data->text) + 1;
            footer = (gui_data_footer_t*)((uint8_t*)label_data + 
                                          sizeof(gui_label_data_t) + text_len);
            break;
        }
        case GUI_OBJ_TYPE_BUTTON: {
            gui_button_data_t* button_data = (gui_button_data_t*)data_ptr;
            if (!button_data->text) return INVALID_HANDLE;
            int text_len = strlen(button_data->text) + 1;
            footer = (gui_data_footer_t*)((uint8_t*)button_data + 
                                          sizeof(gui_button_data_t) + text_len);
            break;
        }
        case GUI_OBJ_TYPE_IMAGE: {
            footer = (gui_data_footer_t*)((uint8_t*)data_ptr + sizeof(gui_image_data_t));
            break;
        }
		

        default:
            return INVALID_HANDLE;
    }
    
    return footer ? footer->data_handle : INVALID_HANDLE;
}

/******************************************************************************
      函数说明:渲染圆角矩形面板(修复版本)
      入口数据:obj      对象指针
                panel_data 面板数据
      返回值:  无
******************************************************************************/
static void render_rounded_panel_fixed(gui_obj_t* obj, gui_panel_data_t* panel_data) {
    if (!panel_data) return;
    
    uint8_t radius = panel_data->radius;
    uint8_t border_thickness = panel_data->thickness;
    uint16_t width = obj->width;
    uint16_t height = obj->height;
    
    // 限制半径大小
    if (radius > width / 2) radius = width / 2;
    if (radius > height / 2) radius = height / 2;
    
     if (radius <= 1) {
        // 半径太小,绘制普通矩形
        if (obj->bg_color != obj->color) {
            LCD_DrawRectangle(obj->x, obj->y, 
                            obj->x + width - 1, 
                            obj->y + height - 1, 
                            obj->bg_color);
            LCD_Fill(obj->x + 1, obj->y + 1, 
                   obj->x + width - 2, 
                   obj->y + height - 2, 
                   obj->color);
        } else {
            LCD_Fill(obj->x, obj->y, 
                   obj->x + width - 1, 
                   obj->y + height - 1, 
                   obj->color);
        }
    } else {
        // 绘制圆角矩形
        
        // 1. 先绘制填充的圆角矩形(主体)
        LCD_Draw_Filled_Rounded_Rect(obj->x, obj->y, 
                               width, height, radius, obj->color);
        
        // 2. 绘制边框
        if (border_thickness > 0) {
            if (border_thickness == 1) {
                // 薄边框
                LCD_DrawRoundedRect(obj->x, obj->y, 
                                  obj->x + width - 1, 
                                  obj->y + height - 1, 
                                  radius, obj->bg_color);
            } else {
                // 厚边框,使用LCD_DrawRoundedRect_Thick函数
                LCD_DrawRoundedRect_Thick(obj->x, obj->y, 
                                        obj->x + width - 1, 
                                        obj->y + height - 1, 
                                        radius, 4, obj->bg_color);
            }
        }
    }
}

/*---------------------- 系统初始化和诊断函数 ----------------------*/

/******************************************************************************
      函数说明:初始化图形系统
      入口数据:无
      返回值:  true-成功 false-失败
******************************************************************************/
bool gui_init(void) {
    // 初始化内存池
    if (!stack_mempool_init()) {
        return false;
    }
    
    return true;
}

/******************************************************************************
      函数说明:检查面板数据内存
      入口数据:panel_data 面板数据指针
      返回值:  无
******************************************************************************/
static void check_panel_memory(gui_panel_data_t* panel_data) {
    if (!panel_data) {
        TFTP_DEBUG("MEM: NULL");
        return;
    }
    
    // 直接查看内存字节
    uint8_t* bytes = (uint8_t*)panel_data;
    
    // 打印前8个字节
    TFTP_DEBUG("MEM: [0]=%d [1]=%d [2]=%d [3]=%d [4]=%d [5]=%d [6]=%d [7]=%d",
              bytes[0], bytes[1], bytes[2], bytes[3], 
              bytes[4], bytes[5], bytes[6], bytes[7]);
    
    // 解释这些字节
    TFTP_DEBUG("DECODE: shape=%d, radius=%d, thickness=%d", 
              bytes[0], bytes[1], bytes[2]);
}

void diagnose_memory_alignment(void) {
    TFTP_DEBUG("=== Memory Alignment Diagnosis ===");
    
    // 1. 检查结构体大小和对齐
    TFTP_DEBUG("1. Structure Info:");
    TFTP_DEBUG("   sizeof(gui_panel_data_t) = %d", sizeof(gui_panel_data_t));
    
    gui_panel_data_t dummy;
    TFTP_DEBUG("   address of dummy: %p", &dummy);
    TFTP_DEBUG("   alignment of dummy: %d", (uintptr_t)&dummy % 4);
    
    // 2. 直接从内存池分配和读取
    TFTP_DEBUG("\n2. Direct Memory Pool Test:");
    
    uint16_t size = sizeof(gui_panel_data_t);
    mem_handle_t handle = stack_mempool_alloc(size, 0);
    
    if (handle != INVALID_HANDLE) {
        void* ptr = stack_mempool_get_ptr(handle);
        TFTP_DEBUG("   Allocated handle: %d", handle);
        TFTP_DEBUG("   Pointer: %p", ptr);
        TFTP_DEBUG("   Pointer alignment: %d", (uintptr_t)ptr % 4);
        
        // 写入数据
        gui_panel_data_t* data = (gui_panel_data_t*)ptr;
        data->shape = GUI_PANEL_SHAPE_ROUNDED;
        data->radius = 10;
        data->thickness = 5;
        
        // 读取数据
        TFTP_DEBUG("   Written: shape=%d, radius=%d, thickness=%d", 
                  data->shape, data->radius, data->thickness);
        
        // 通过字节读取
        uint8_t* bytes = (uint8_t*)ptr;
        TFTP_DEBUG("   Bytes: [0]=%d, [1]=%d, [2]=%d", 
                  bytes[0], bytes[1], bytes[2]);
    }
    
    TFTP_DEBUG("\n3. Creating panel through GUI...");
    
    // 3. 通过GUI系统创建
    gui_handle_t panel = gui_create_rounded_panel(50, 50, 100, 60, 
                                                 MAGENTA, GRED, 10, 5);
    
    if (panel != GUI_INVALID_HANDLE) {
        gui_obj_t* obj = gui_get_obj(panel);
        if (obj && obj->data) {
            TFTP_DEBUG("   Object data pointer: %p", obj->data);
            TFTP_DEBUG("   Pointer alignment: %d", (uintptr_t)obj->data % 4);
            
            // 直接读取内存
            uint8_t* bytes = (uint8_t*)obj->data;
            TFTP_DEBUG("   Memory bytes: [0]=%d, [1]=%d, [2]=%d", 
                      bytes[0], bytes[1], bytes[2]);
        }
    }
    
    TFTP_DEBUG("=== Diagnosis Complete ===");
}

void test_memory_all(void){
     // 遍历内存池中的所有块
    for (int i = 0; i < MAX_HANDLES; i++) {
        if (mempool.blocks[i].state == BLOCK_USED) {
            uint8_t type = mempool.blocks[i].type;
            if (type >= GUI_OBJ_TYPE_WIDGET && type <= GUI_OBJ_TYPE_WINDOW) {
                 gui_obj_t* obj  = (gui_obj_t*)stack_mempool_get_ptr(i);
                 TFTP_DEBUG("Address of panel_data: %p", obj->data);
                 check_panel_memory(obj->data);
            }
        }
    }
}

/*---------------------- 对象管理核心函数 ----------------------*/

/******************************************************************************
      函数说明:创建基本对象
      入口数据:type     对象类型
                x,y      坐标
                width,height 宽高
      返回值:  对象句柄
******************************************************************************/
gui_handle_t gui_create_obj(gui_obj_type_t type, int16_t x, int16_t y, 
                           int16_t width, int16_t height) {
    // 分配对象内存
    gui_handle_t handle = stack_mempool_alloc(sizeof(gui_obj_t), (uint8_t)type);
    if (handle == GUI_INVALID_HANDLE) {
        return GUI_INVALID_HANDLE;
    }
    
    // 获取对象指针
    gui_obj_t* obj = (gui_obj_t*)stack_mempool_get_ptr(handle);
    if (!obj) {
        return GUI_INVALID_HANDLE;
    }
    
    // 初始化对象
    obj->type = type;
    obj->visible = true;
    obj->updated = true;
    obj->x = x;
    obj->y = y;
    obj->width = width;
    obj->height = height;
    obj->color = GUI_COLOR_BLACK;
    obj->bg_color = GUI_COLOR_WHITE;
    obj->callback = NULL;
    obj->data = NULL;
    
    // 初始化相对定位字段
    obj->parent = GUI_INVALID_HANDLE;
    obj->rel_x = 0;
    obj->rel_y = 0;
    obj->pos_mode = GUI_POS_MODE_ABSOLUTE;
    obj->anchor = GUI_ANCHOR_NONE;
    
    return handle;
}

/******************************************************************************
      函数说明:销毁对象
      入口数据:handle   对象句柄
      返回值:  true-成功 false-失败
******************************************************************************/
bool gui_destroy_obj(gui_handle_t handle) {
    if (handle == GUI_INVALID_HANDLE) {
        return false;
    }
    
    // 获取对象
    gui_obj_t* obj = gui_get_obj(handle);
    if (!obj) {
        return false;
    }
    
    // 释放对象特定数据
    if (obj->data) {
        // 获取数据块的句柄
        mem_handle_t data_handle = get_data_handle_from_footer(obj->type, obj->data);
        if (data_handle != INVALID_HANDLE) {
            stack_mempool_free(data_handle);
        }
        
        obj->data = NULL;
    }
    
    // 释放对象本身
    return stack_mempool_free(handle);
}

/******************************************************************************
      函数说明:创建相对定位的矩形面板
      入口数据:parent   父对象句柄
                rel_x,rel_y 相对坐标
                width,height 宽高
                color    填充颜色
                border_color 边框颜色
      返回值:  对象句柄
******************************************************************************/
gui_handle_t gui_create_panel_relative(gui_handle_t parent, int16_t rel_x, int16_t rel_y,
                                       int16_t width, int16_t height,
                                       gui_color_t color, gui_color_t border_color) {
    // 获取父对象
    gui_obj_t* parent_obj = gui_get_obj(parent);
    if (!parent_obj) {
        return GUI_INVALID_HANDLE;
    }
    
    // 计算绝对坐标
    int16_t abs_x = parent_obj->x + rel_x;
    int16_t abs_y = parent_obj->y + rel_y;
    
    // 边界检查,确保面板不超出父对象范围
    if (abs_x < parent_obj->x) abs_x = parent_obj->x;
    if (abs_y < parent_obj->y) abs_y = parent_obj->y;
    if (abs_x + width > parent_obj->x + parent_obj->width) {
        width = parent_obj->x + parent_obj->width - abs_x;
    }
    if (abs_y + height > parent_obj->y + parent_obj->height) {
        height = parent_obj->y + parent_obj->height - abs_y;
    }
    
    // 确保宽高不为负
    if (width <= 0) width = 1;
    if (height <= 0) height = 1;
    
    // 创建面板
    gui_handle_t handle = gui_create_panel(abs_x, abs_y, width, height, color, border_color);
    if (handle == GUI_INVALID_HANDLE) {
        return GUI_INVALID_HANDLE;
    }
    
    // 设置相对定位信息
    gui_obj_t* obj = gui_get_obj(handle);
    if (obj) {
        obj->parent = parent;
        obj->rel_x = rel_x;
        obj->rel_y = rel_y;
        obj->pos_mode = GUI_POS_MODE_RELATIVE;
    }
    
    return handle;
}

/******************************************************************************
      函数说明:创建锚点定位的矩形面板
      入口数据:parent   父对象句柄
                anchor   锚点类型
                offset_x,offset_y 偏移量
                width,height 宽高
                color    填充颜色
                border_color 边框颜色
      返回值:  对象句柄
******************************************************************************/
gui_handle_t gui_create_panel_anchor(gui_handle_t parent, gui_anchor_t anchor,
                                     int16_t offset_x, int16_t offset_y,
                                     int16_t width, int16_t height,
                                     gui_color_t color, gui_color_t border_color) {
    // 获取父对象
    gui_obj_t* parent_obj = gui_get_obj(parent);
    if (!parent_obj) {
        return GUI_INVALID_HANDLE;
    }
    
    // 根据锚点计算位置
    int16_t abs_x = 0, abs_y = 0;
    
    switch(anchor) {
        case GUI_ANCHOR_TOP_LEFT:
            abs_x = parent_obj->x + offset_x;
            abs_y = parent_obj->y + offset_y;
            break;
        case GUI_ANCHOR_TOP_CENTER:
            abs_x = parent_obj->x + (parent_obj->width - width) / 2 + offset_x;
            abs_y = parent_obj->y + offset_y;
            break;
        case GUI_ANCHOR_TOP_RIGHT:
            abs_x = parent_obj->x + parent_obj->width - width - offset_x;
            abs_y = parent_obj->y + offset_y;
            break;
        case GUI_ANCHOR_CENTER_LEFT:
            abs_x = parent_obj->x + offset_x;
            abs_y = parent_obj->y + (parent_obj->height - height) / 2 + offset_y;
            break;
        case GUI_ANCHOR_CENTER:
            abs_x = parent_obj->x + (parent_obj->width - width) / 2 + offset_x;
            abs_y = parent_obj->y + (parent_obj->height - height) / 2 + offset_y;
            break;
        case GUI_ANCHOR_CENTER_RIGHT:
            abs_x = parent_obj->x + parent_obj->width - width - offset_x;
            abs_y = parent_obj->y + (parent_obj->height - height) / 2 + offset_y;
            break;
        case GUI_ANCHOR_BOTTOM_LEFT:
            abs_x = parent_obj->x + offset_x;
            abs_y = parent_obj->y + parent_obj->height - height - offset_y;
            break;
        case GUI_ANCHOR_BOTTOM_CENTER:
            abs_x = parent_obj->x + (parent_obj->width - width) / 2 + offset_x;
            abs_y = parent_obj->y + parent_obj->height - height - offset_y;
            break;
        case GUI_ANCHOR_BOTTOM_RIGHT:
            abs_x = parent_obj->x + parent_obj->width - width - offset_x;
            abs_y = parent_obj->y + parent_obj->height - height - offset_y;
            break;
        default:
            abs_x = parent_obj->x + offset_x;
            abs_y = parent_obj->y + offset_y;
    }
    
    // 边界检查
    if (abs_x < parent_obj->x) abs_x = parent_obj->x;
    if (abs_y < parent_obj->y) abs_y = parent_obj->y;
    if (abs_x + width > parent_obj->x + parent_obj->width) {
        width = parent_obj->x + parent_obj->width - abs_x;
    }
    if (abs_y + height > parent_obj->y + parent_obj->height) {
        height = parent_obj->y + parent_obj->height - abs_y;
    }
    
    // 确保宽高不为负
    if (width <= 0) width = 1;
    if (height <= 0) height = 1;
    
    // 创建面板
    gui_handle_t handle = gui_create_panel(abs_x, abs_y, width, height, color, border_color);
    if (handle == GUI_INVALID_HANDLE) {
        return GUI_INVALID_HANDLE;
    }
    
    // 设置锚点定位信息
    gui_obj_t* obj = gui_get_obj(handle);
    if (obj) {
        obj->parent = parent;
        obj->anchor = anchor;
        obj->rel_x = offset_x;
        obj->rel_y = offset_y;
        obj->pos_mode = GUI_POS_MODE_ANCHOR;
    }
    
    return handle;
}

/******************************************************************************
 * 函数说明:创建一个支持自动换行的文本标签控件
 * 入口数据:x, y         标签的起始坐标
 *           max_width    单行最大宽度(像素),超过此宽度将自动换行
 *           max_lines    最大显示行数
 *           text         要显示的文本字符串
 *           font_size    字体大小
 *           color        文本颜色
 *           bg_color     背景颜色(若为透明,可指定为GUI_TRANSPARENT)
 * 返回值:  成功创建返回标签对象的句柄,失败返回GUI_NULL
 ******************************************************************************/
gui_handle_t gui_create_label_wrap(int16_t x, int16_t y, int16_t max_width, int16_t max_lines,
                                   const char* text, gui_font_size_t font_size, 
                                   gui_color_t color, gui_color_t bg_color) {
    // 计算字符宽度
    int16_t char_width, char_height;
    switch(font_size) {
        case GUI_FONT_12: char_width = 6; char_height = 12; break;
        case GUI_FONT_16: char_width = 8; char_height = 16; break;
        case GUI_FONT_24: char_width = 12; char_height = 24; break;
        case GUI_FONT_32: char_width = 16; char_height = 32; break;
        default: char_width = 8; char_height = 16;
    }
    
    int text_len = strlen(text);
    int16_t text_width, text_height;
    
    if (max_width > 0) {
        // 需要换行
        int chars_per_line = max_width / char_width;
        int total_lines = (text_len + chars_per_line - 1) / chars_per_line;
        
        // 如果指定了最大行数,则限制行数
        int actual_lines = (max_lines > 0 && total_lines > max_lines) ? max_lines : total_lines;
        
        text_width = max_width;
        text_height = actual_lines * char_height;
    } else {
        // 不换行
        text_width = char_width * text_len;
        text_height = char_height;
        max_lines = 0; // 表示无限制
    }
    
    gui_handle_t handle = gui_create_obj(GUI_OBJ_TYPE_LABEL_WRAP, x, y, text_width, text_height);
    if (handle == GUI_INVALID_HANDLE) {
        return GUI_INVALID_HANDLE;
    }
    
    // 获取对象
    gui_obj_t* obj = gui_get_obj(handle);
    if (!obj) {
        gui_destroy_obj(handle);
        return GUI_INVALID_HANDLE;
    }
    
    // 设置颜色
    obj->color = color;
    obj->bg_color = bg_color;
    
    // 分配标签数据
    uint16_t data_size = sizeof(gui_label_wrap_data_t) + text_len + 1 + sizeof(gui_data_footer_t);
    mem_handle_t data_handle = stack_mempool_alloc(data_size, (uint8_t)GUI_OBJ_TYPE_LABEL_WRAP);
    if (data_handle == GUI_INVALID_HANDLE) {
        gui_destroy_obj(handle);
        return GUI_INVALID_HANDLE;
    }
    
    // 设置标签数据
    gui_label_wrap_data_t* label_data = (gui_label_wrap_data_t*)stack_mempool_get_ptr(data_handle);
    if (!label_data) {
        stack_mempool_free(data_handle);
        gui_destroy_obj(handle);
        return GUI_INVALID_HANDLE;
    }
    
    label_data->font_size = font_size;
    label_data->max_width = max_width;
    label_data->max_lines = max_lines; // 0表示无限制
    label_data->char_width = char_width;
    label_data->char_height = char_height;
    label_data->text = (char*)(label_data + 1);
    strcpy(label_data->text, text);
    
    // 存储数据句柄在数据块末尾
    gui_data_footer_t* footer = (gui_data_footer_t*)((uint8_t*)label_data + sizeof(gui_label_wrap_data_t) + text_len + 1);
    footer->data_handle = data_handle;
    
    // 设置对象数据
    obj->data = label_data;
    
    return handle;
}


/******************************************************************************
      函数说明:创建相对定位的标签
      入口数据:parent   父对象句柄
                rel_x,rel_y 相对坐标
                text     文本内容
                font_size 字体大小
                color    字体颜色
                bg_color 背景颜色
      返回值:  对象句柄
******************************************************************************/
gui_handle_t gui_create_label_relative(gui_handle_t parent, int16_t rel_x, int16_t rel_y,
                                       const char* text, gui_font_size_t font_size,
                                       gui_color_t color, gui_color_t bg_color) {
    // 获取父对象
    gui_obj_t* parent_obj = gui_get_obj(parent);
    if (!parent_obj) {
        return GUI_INVALID_HANDLE;
    }
    
    // 计算文本尺寸
    int16_t char_width, char_height;
    switch(font_size) {
        case GUI_FONT_12: char_width = 6; char_height = 12; break;
        case GUI_FONT_16: char_width = 8; char_height = 16; break;
        case GUI_FONT_24: char_width = 12; char_height = 24; break;
        case GUI_FONT_32: char_width = 16; char_height = 32; break;
        default: char_width = 8; char_height = 16;
    }
    
    int text_len = strlen(text);
    int16_t text_width = char_width * text_len;
    int16_t text_height = char_height;
    
    // 计算绝对坐标
    int16_t abs_x = parent_obj->x + rel_x;
    int16_t abs_y = parent_obj->y + rel_y;
    
    // 创建标签
    gui_handle_t handle = gui_create_label(abs_x, abs_y, text, font_size, color, bg_color);
    if (handle == GUI_INVALID_HANDLE) {
        return GUI_INVALID_HANDLE;
    }
    
    // 设置相对定位信息
    gui_obj_t* obj = gui_get_obj(handle);
    if (obj) {
        obj->parent = parent;
        obj->rel_x = rel_x;
        obj->rel_y = rel_y;
        obj->pos_mode = GUI_POS_MODE_RELATIVE;
    }
    
    return handle;
}

/******************************************************************************
      函数说明:创建锚点定位的标签(增强版,可选择使用父对象背景色)
      入口数据:parent   父对象句柄
                anchor   锚点类型
                offset_x,offset_y 偏移量
                text     文本内容
                font_size 字体大小
                color    字体颜色
                bg_color 背景颜色(如果为USE_PARENT_BG则使用父对象背景色)
      返回值:  对象句柄
******************************************************************************/
gui_handle_t gui_create_label_anchor(gui_handle_t parent, gui_anchor_t anchor,
                                     int16_t offset_x, int16_t offset_y,
                                     const char* text, gui_font_size_t font_size,
                                     gui_color_t color, gui_color_t bg_color) {
    // 获取父对象
    gui_obj_t* parent_obj = gui_get_obj(parent);
    if (!parent_obj) {
        return GUI_INVALID_HANDLE;
    }
    
    // 如果bg_color为特殊值USE_PARENT_BG,则使用父对象的背景色
    gui_color_t final_bg_color = bg_color;
    if (bg_color == USE_PARENT_BG) {
        final_bg_color = parent_obj->bg_color;
    }
    
    // 计算字符尺寸
    int16_t char_width, char_height;
    switch(font_size) {
        case GUI_FONT_12: char_width = 6; char_height = 12; break;
        case GUI_FONT_16: char_width = 8; char_height = 16; break;
        case GUI_FONT_24: char_width = 12; char_height = 24; break;
        case GUI_FONT_32: char_width = 16; char_height = 32; break;
        default: char_width = 8; char_height = 16;
    }
    
    int text_len = strlen(text);
    int16_t max_width = parent_obj->width;
    bool need_wrap = false;
    int16_t actual_width = 0;
    int16_t text_height = char_height;
    int16_t max_lines = 0;
    
    // 分析文本内容,处理换行符
    int line_count = 1;
    int current_line_chars = 0;
    int max_line_chars = 0;
    
    // 第一遍扫描:统计实际行数和最大行宽
    for (int i = 0; i < text_len; i++) {
        if (text[i] == '\n') {
            line_count++;
            if (current_line_chars > max_line_chars) {
                max_line_chars = current_line_chars;
            }
            current_line_chars = 0;
        } else {
            current_line_chars++;
        }
    }
    // 处理最后一行
    if (current_line_chars > max_line_chars) {
        max_line_chars = current_line_chars;
    }
    
    // 计算单行文本宽度
    int16_t single_line_width = char_width * max_line_chars;
    
    // 检查是否需要自动换行
    if (single_line_width > max_width) {
        need_wrap = true;
        actual_width = max_width;
        int chars_per_line = max_width / char_width;
        
        // 第二遍扫描:考虑自动换行后的实际行数
        line_count = 0;
        current_line_chars = 0;
        
        for (int i = 0; i < text_len; i++) {
            if (text[i] == '\n') {
                line_count++;
                current_line_chars = 0;
            } else {
                current_line_chars++;
                if (current_line_chars >= chars_per_line) {
                    line_count++;
                    current_line_chars = 0;
                }
            }
        }
        if (current_line_chars > 0) line_count++;
        
        // 限制最大行数
        int max_possible_lines = parent_obj->height / char_height;
        if (max_possible_lines <= 0) max_possible_lines = 999;
        
        max_lines = (line_count > max_possible_lines) ? max_possible_lines : line_count;
        text_height = max_lines * char_height;
    } else {
        // 不需要自动换行
        actual_width = single_line_width;
        text_height = line_count * char_height;
        
        // 检查高度是否超出父对象
        if (text_height > parent_obj->height && parent_obj->height > 0) {
            int max_possible_lines = parent_obj->height / char_height;
            if (max_possible_lines <= 0) max_possible_lines = 1;
            max_lines = (line_count > max_possible_lines) ? max_possible_lines : line_count;
            text_height = max_lines * char_height;
        }
    }
    
    // 根据锚点计算位置
    int16_t abs_x = 0, abs_y = 0;
    
    switch(anchor) {
        case GUI_ANCHOR_TOP_LEFT:
            abs_x = parent_obj->x + offset_x;
            abs_y = parent_obj->y + offset_y;
            break;
        case GUI_ANCHOR_TOP_CENTER:
            abs_x = parent_obj->x + (parent_obj->width - actual_width) / 2 + offset_x;
            abs_y = parent_obj->y + offset_y;
            break;
        case GUI_ANCHOR_TOP_RIGHT:
            abs_x = parent_obj->x + parent_obj->width - actual_width - offset_x;
            abs_y = parent_obj->y + offset_y;
            break;
        case GUI_ANCHOR_CENTER_LEFT:
            abs_x = parent_obj->x + offset_x;
            abs_y = parent_obj->y + (parent_obj->height - text_height) / 2 + offset_y;
            break;
        case GUI_ANCHOR_CENTER:
            abs_x = parent_obj->x + (parent_obj->width - actual_width) / 2 + offset_x;
            abs_y = parent_obj->y + (parent_obj->height - text_height) / 2 + offset_y;
            break;
        case GUI_ANCHOR_CENTER_RIGHT:
            abs_x = parent_obj->x + parent_obj->width - actual_width - offset_x;
            abs_y = parent_obj->y + (parent_obj->height - text_height) / 2 + offset_y;
            break;
        case GUI_ANCHOR_BOTTOM_LEFT:
            abs_x = parent_obj->x + offset_x;
            abs_y = parent_obj->y + parent_obj->height - text_height - offset_y;
            break;
        case GUI_ANCHOR_BOTTOM_CENTER:
            abs_x = parent_obj->x + (parent_obj->width - actual_width) / 2 + offset_x;
            abs_y = parent_obj->y + parent_obj->height - text_height - offset_y;
            break;
        case GUI_ANCHOR_BOTTOM_RIGHT:
            abs_x = parent_obj->x + parent_obj->width - actual_width - offset_x;
            abs_y = parent_obj->y + parent_obj->height - text_height - offset_y;
            break;
        default:
            abs_x = parent_obj->x + offset_x;
            abs_y = parent_obj->y + offset_y;
    }
    
    // 边界检查
    if (abs_y < parent_obj->y) abs_y = parent_obj->y;
    if (abs_y + text_height > parent_obj->y + parent_obj->height) {
        text_height = parent_obj->y + parent_obj->height - abs_y;
        if (text_height < 0) text_height = 0;
    }
    if (abs_x < parent_obj->x) abs_x = parent_obj->x;
    if (abs_x + actual_width > parent_obj->x + parent_obj->width) {
        actual_width = parent_obj->x + parent_obj->width - abs_x;
        if (actual_width < 0) actual_width = 0;
    }
    
    // 创建标签
    gui_handle_t handle;
    if (need_wrap && max_lines > 0) {
        handle = gui_create_label_wrap(abs_x, abs_y, max_width, max_lines,
                                     text, font_size, color, final_bg_color);
    } else {
        handle = gui_create_label_wrap(abs_x, abs_y, 
                                      need_wrap ? max_width : 0,
                                      0, text, font_size, color, final_bg_color);
    }
    
    if (handle == GUI_INVALID_HANDLE) {
        return GUI_INVALID_HANDLE;
    }
    
    // 设置标签属性
    gui_obj_t* obj = gui_get_obj(handle);
    if (obj) {
        obj->width = actual_width;
        obj->height = text_height;
        obj->parent = parent;
        obj->anchor = anchor;
        obj->rel_x = offset_x;
        obj->rel_y = offset_y;
        obj->pos_mode = GUI_POS_MODE_ANCHOR;
    }
    
    return handle;
}
/******************************************************************************
      函数说明:创建相对定位的按钮
      入口数据:parent   父对象句柄
                rel_x,rel_y 相对坐标
                width,height 宽高
                text     文本内容
                font_size 字体大小
      返回值:  对象句柄
******************************************************************************/
gui_handle_t gui_create_button_relative(gui_handle_t parent, int16_t rel_x, int16_t rel_y,
                                        int16_t width, int16_t height,
                                        const char* text, gui_font_size_t font_size) {
    // 获取父对象
    gui_obj_t* parent_obj = gui_get_obj(parent);
    if (!parent_obj) {
        return GUI_INVALID_HANDLE;
    }
    
    // 计算绝对坐标
    int16_t abs_x = parent_obj->x + rel_x;
    int16_t abs_y = parent_obj->y + rel_y;
    
    // 创建按钮
    gui_handle_t handle = gui_create_button(abs_x, abs_y, width, height, text, font_size);
    if (handle == GUI_INVALID_HANDLE) {
        return GUI_INVALID_HANDLE;
    }
    
    // 设置相对定位信息
    gui_obj_t* obj = gui_get_obj(handle);
    if (obj) {
        obj->parent = parent;
        obj->rel_x = rel_x;
        obj->rel_y = rel_y;
        obj->pos_mode = GUI_POS_MODE_RELATIVE;
    }
    
    return handle;
}

/******************************************************************************
      函数说明:获取对象
      入口数据:handle   对象句柄
      返回值:  对象指针
******************************************************************************/
gui_obj_t* gui_get_obj(gui_handle_t handle) {
    if (handle == GUI_INVALID_HANDLE) {
        return NULL;
    }
    return (gui_obj_t*)stack_mempool_get_ptr(handle);
}

/******************************************************************************
      函数说明:设置父对象
      入口数据:child    子对象句柄
                parent   父对象句柄
      返回值:  true-成功 false-失败
******************************************************************************/
bool gui_set_parent(gui_handle_t child, gui_handle_t parent) {
    if (child == GUI_INVALID_HANDLE) {
        return false;
    }
    
    gui_obj_t* obj = gui_get_obj(child);
    if (!obj) {
        return false;
    }
    
    if (parent != GUI_INVALID_HANDLE) {
        gui_obj_t* parent_obj = gui_get_obj(parent);
        if (!parent_obj) {
            return false;
        }
        
        // 计算相对坐标
        obj->rel_x = obj->x - parent_obj->x;
        obj->rel_y = obj->y - parent_obj->y;
    } else {
        obj->rel_x = 0;
        obj->rel_y = 0;
    }
    
    obj->parent = parent;
    return true;
}

/******************************************************************************
      函数说明:设置相对位置
      入口数据:child    子对象句柄
                rel_x,rel_y 相对坐标
      返回值:  true-成功 false-失败
******************************************************************************/
bool gui_set_relative_position(gui_handle_t child, int16_t rel_x, int16_t rel_y) {
    gui_obj_t* obj = gui_get_obj(child);
    if (!obj || obj->parent == GUI_INVALID_HANDLE) {
        return false;
    }
    
    gui_obj_t* parent = gui_get_obj(obj->parent);
    if (!parent) {
        return false;
    }
    
    obj->rel_x = rel_x;
    obj->rel_y = rel_y;
    obj->pos_mode = GUI_POS_MODE_RELATIVE;
    
    // 更新绝对位置
    int16_t new_x = parent->x + rel_x;
    int16_t new_y = parent->y + rel_y;
    
    return gui_set_obj_pos(child, new_x, new_y);
}

/******************************************************************************
      函数说明:设置锚点
      入口数据:child    子对象句柄
                anchor   锚点类型
                offset_x,offset_y 偏移量
      返回值:  true-成功 false-失败
******************************************************************************/
bool gui_set_anchor(gui_handle_t child, gui_anchor_t anchor, int16_t offset_x, int16_t offset_y) {
    gui_obj_t* obj = gui_get_obj(child);
    if (!obj || obj->parent == GUI_INVALID_HANDLE) {
        return false;
    }
    
    gui_obj_t* parent = gui_get_obj(obj->parent);
    if (!parent) {
        return false;
    }
    
    obj->anchor = anchor;
    obj->rel_x = offset_x;
    obj->rel_y = offset_y;
    obj->pos_mode = GUI_POS_MODE_ANCHOR;
    
    // 根据锚点计算新位置
    int16_t new_x = 0, new_y = 0;
    
    switch(anchor) {
        case GUI_ANCHOR_TOP_LEFT:
            new_x = parent->x + offset_x;
            new_y = parent->y + offset_y;
            break;
        case GUI_ANCHOR_TOP_CENTER:
            new_x = parent->x + (parent->width - obj->width) / 2 + offset_x;
            new_y = parent->y + offset_y;
            break;
        case GUI_ANCHOR_TOP_RIGHT:
            new_x = parent->x + parent->width - obj->width - offset_x;
            new_y = parent->y + offset_y;
            break;
        case GUI_ANCHOR_CENTER_LEFT:
            new_x = parent->x + offset_x;
            new_y = parent->y + (parent->height - obj->height) / 2 + offset_y;
            break;
        case GUI_ANCHOR_CENTER:
            new_x = parent->x + (parent->width - obj->width) / 2 + offset_x;
            new_y = parent->y + (parent->height - obj->height) / 2 + offset_y;
            break;
        case GUI_ANCHOR_CENTER_RIGHT:
            new_x = parent->x + parent->width - obj->width - offset_x;
            new_y = parent->y + (parent->height - obj->height) / 2 + offset_y;
            break;
        case GUI_ANCHOR_BOTTOM_LEFT:
            new_x = parent->x + offset_x;
            new_y = parent->y + parent->height - obj->height - offset_y;
            break;
        case GUI_ANCHOR_BOTTOM_CENTER:
            new_x = parent->x + (parent->width - obj->width) / 2 + offset_x;
            new_y = parent->y + parent->height - obj->height - offset_y;
            break;
        case GUI_ANCHOR_BOTTOM_RIGHT:
            new_x = parent->x + parent->width - obj->width - offset_x;
            new_y = parent->y + parent->height - obj->height - offset_y;
            break;
        default:
            return false;
    }
    
    return gui_set_obj_pos(child, new_x, new_y);
}

/******************************************************************************
      函数说明:更新相对位置(当父对象移动时调用)
      入口数据:parent_handle 父对象句柄
      返回值:  无
******************************************************************************/
static void update_relative_position(gui_handle_t parent_handle) {
    gui_obj_t* parent_obj = gui_get_obj(parent_handle);
    if (!parent_obj) return;
    
    // 遍历所有对象,找到以此对象为父对象的子对象
    for (mem_handle_t handle = 0; handle < MAX_HANDLES; handle++) {
        if (mempool.blocks[handle].state == BLOCK_USED) {
            gui_obj_t* child_obj = (gui_obj_t*)stack_mempool_get_ptr(handle);
            if (child_obj && child_obj->parent == parent_handle) {
                // 根据定位模式重新计算子对象位置
                if (child_obj->pos_mode == GUI_POS_MODE_RELATIVE) {
                    int16_t new_x = parent_obj->x + child_obj->rel_x;
                    int16_t new_y = parent_obj->y + child_obj->rel_y;
                    
                    if (child_obj->x != new_x || child_obj->y != new_y) {
                        // 清除原位置
                        if (child_obj->visible) {
                            LCD_Fill(child_obj->x, child_obj->y, 
                                    child_obj->x + child_obj->width, 
                                    child_obj->y + child_obj->height, 
                                    child_obj->bg_color);
                        }
                        
                        child_obj->x = new_x;
                        child_obj->y = new_y;
                        child_obj->updated = true;
                    }
                }
                else if (child_obj->pos_mode == GUI_POS_MODE_ANCHOR) {
                    // 重新计算锚点位置
                    int16_t new_x = 0, new_y = 0;
                    
                    switch(child_obj->anchor) {
                        case GUI_ANCHOR_TOP_LEFT:
                            new_x = parent_obj->x + child_obj->rel_x;
                            new_y = parent_obj->y + child_obj->rel_y;
                            break;
                        case GUI_ANCHOR_TOP_CENTER:
                            new_x = parent_obj->x + (parent_obj->width - child_obj->width) / 2 + child_obj->rel_x;
                            new_y = parent_obj->y + child_obj->rel_y;
                            break;
                        case GUI_ANCHOR_TOP_RIGHT:
                            new_x = parent_obj->x + parent_obj->width - child_obj->width - child_obj->rel_x;
                            new_y = parent_obj->y + child_obj->rel_y;
                            break;
                        case GUI_ANCHOR_CENTER_LEFT:
                            new_x = parent_obj->x + child_obj->rel_x;
                            new_y = parent_obj->y + (parent_obj->height - child_obj->height) / 2 + child_obj->rel_y;
                            break;
                        case GUI_ANCHOR_CENTER:
                            new_x = parent_obj->x + (parent_obj->width - child_obj->width) / 2 + child_obj->rel_x;
                            new_y = parent_obj->y + (parent_obj->height - child_obj->height) / 2 + child_obj->rel_y;
                            break;
                        case GUI_ANCHOR_CENTER_RIGHT:
                            new_x = parent_obj->x + parent_obj->width - child_obj->width - child_obj->rel_x;
                            new_y = parent_obj->y + (parent_obj->height - child_obj->height) / 2 + child_obj->rel_y;
                            break;
                        case GUI_ANCHOR_BOTTOM_LEFT:
                            new_x = parent_obj->x + child_obj->rel_x;
                            new_y = parent_obj->y + parent_obj->height - child_obj->height - child_obj->rel_y;
                            break;
                        case GUI_ANCHOR_BOTTOM_CENTER:
                            new_x = parent_obj->x + (parent_obj->width - child_obj->width) / 2 + child_obj->rel_x;
                            new_y = parent_obj->y + parent_obj->height - child_obj->height - child_obj->rel_y;
                            break;
                        case GUI_ANCHOR_BOTTOM_RIGHT:
                            new_x = parent_obj->x + parent_obj->width - child_obj->width - child_obj->rel_x;
                            new_y = parent_obj->y + parent_obj->height - child_obj->height - child_obj->rel_y;
                            break;
                        default:
                            continue;
                    }
                    
                    if (child_obj->x != new_x || child_obj->y != new_y) {
                        // 清除原位置
                        if (child_obj->visible) {
                            LCD_Fill(child_obj->x, child_obj->y, 
                                    child_obj->x + child_obj->width, 
                                    child_obj->y + child_obj->height, 
                                    child_obj->bg_color);
                        }
                        
                        child_obj->x = new_x;
                        child_obj->y = new_y;
                        child_obj->updated = true;
                    }
                }
            }
        }
    }
}

/******************************************************************************
      函数说明:更新父对象的所有子对象的相对位置
      入口数据:parent   父对象句柄
      返回值:  true-成功 false-失败
******************************************************************************/
bool gui_update_relative_position(gui_handle_t parent) {
    update_relative_position(parent);
    return true;
}

/******************************************************************************
      函数说明:设置对象位置
      入口数据:handle   对象句柄
                x,y      新坐标
      返回值:  true-成功 false-失败
******************************************************************************/
bool gui_set_obj_pos(gui_handle_t handle, int16_t x, int16_t y) {
    gui_obj_t* obj = gui_get_obj(handle);
    if (!obj) {
        return false;
    }
    
    if (obj->x != x || obj->y != y) {
        // 清除原位置
        if (obj->visible) {
            LCD_Fill(obj->x, obj->y, obj->x + obj->width, obj->y + obj->height, obj->bg_color);
        }
        
        obj->x = x;
        obj->y = y;
        obj->updated = true;
        
        // 更新所有子对象的相对位置
        update_relative_position(handle);
    }
    
    return true;
}
/******************************************************************************
      函数说明:设置对象大小
      入口数据:handle   对象句柄
                width,height 新宽高
      返回值:  true-成功 false-失败
******************************************************************************/
bool gui_set_obj_size(gui_handle_t handle, int16_t width, int16_t height) {
    gui_obj_t* obj = gui_get_obj(handle);
    if (!obj) {
        return false;
    }
    
    if (obj->width != width || obj->height != height) {
        // 清除原区域
        if (obj->visible) {
            LCD_Fill(obj->x, obj->y, obj->x + obj->width, obj->y + obj->height, obj->bg_color);
        }
        
        obj->width = width;
        obj->height = height;
        obj->updated = true;
    }
    
    return true;
}

/******************************************************************************
      函数说明:设置对象可见性
      入口数据:handle   对象句柄
                visible  是否可见
      返回值:  true-成功 false-失败
******************************************************************************/
bool gui_set_obj_visible(gui_handle_t handle, bool visible) {
    gui_obj_t* obj = gui_get_obj(handle);
    if (!obj) {
        return false;
    }
    
    if (obj->visible != visible) {
        obj->visible = visible;
        obj->updated = true;
    }
    
    return true;
}

/******************************************************************************
      函数说明:设置对象回调
      入口数据:handle   对象句柄
                callback 回调函数
      返回值:  true-成功 false-失败
******************************************************************************/
bool gui_set_obj_callback(gui_handle_t handle, gui_event_callback_t callback) {
    gui_obj_t* obj = gui_get_obj(handle);
    if (!obj) {
        return false;
    }
    
    obj->callback = callback;
    return true;
}

/******************************************************************************
      函数说明:创建扩展面板
      入口数据:x,y      坐标
                width,height 宽高
                color    填充颜色
                border_color 边框颜色
                shape    面板形状
                radius   半径
                thickness 边框粗细
                start_angle 起始角度
                end_angle   结束角度
      返回值:  对象句柄
******************************************************************************/


/*---------------------- 特定对象创建函数 ----------------------*/

gui_handle_t gui_create_panel_ex(int16_t x, int16_t y, int16_t width, int16_t height, 
                                gui_color_t color, gui_color_t border_color,
                                gui_panel_shape_t shape, uint8_t radius, 
                                uint8_t thickness, uint16_t start_angle, 
                                uint16_t end_angle) {
    // 创建基本对象
    gui_handle_t handle = gui_create_obj(GUI_OBJ_TYPE_PANEL, x, y, width, height);
    if (handle == GUI_INVALID_HANDLE) {
        return GUI_INVALID_HANDLE;
    }
    
    // 获取对象
    gui_obj_t* obj = gui_get_obj(handle);
    if (!obj) {
        gui_destroy_obj(handle);
        return GUI_INVALID_HANDLE;
    }
    
    // 设置颜色
    obj->color = color;
    obj->bg_color = border_color;
    
    // 分配面板数据
    uint16_t data_size = sizeof(gui_panel_data_t) + sizeof(gui_data_footer_t);
    mem_handle_t data_handle = stack_mempool_alloc(data_size, (uint8_t)GUI_OBJ_TYPE_PANEL);
    if (data_handle == GUI_INVALID_HANDLE) {
        gui_destroy_obj(handle);
        return GUI_INVALID_HANDLE;
    }
    
    // 设置面板数据
    gui_panel_data_t* panel_data = (gui_panel_data_t*)stack_mempool_get_ptr(data_handle);
    if (!panel_data) {
        stack_mempool_free(data_handle);
        gui_destroy_obj(handle);
        return GUI_INVALID_HANDLE;
    }
    
    // 初始化面板数据
    panel_data->shape = shape;
    panel_data->radius = radius;
    panel_data->thickness = thickness;
    panel_data->start_angle = start_angle;
    panel_data->end_angle = end_angle;
    
    // 存储数据句柄
    gui_data_footer_t* footer = (gui_data_footer_t*)((uint8_t*)panel_data + sizeof(gui_panel_data_t));
    footer->data_handle = data_handle;
	
    // 设置对象数据
    obj->data = panel_data;
    TFTP_DEBUG("Address of panel_data: %p", obj->data);
	check_panel_memory(obj->data);
	
    return handle;
}

/******************************************************************************
      函数说明:创建矩形面板
      入口数据:x,y      坐标
                width,height 宽高
                color    填充颜色
                border_color 边框颜色
      返回值:  对象句柄
******************************************************************************/
gui_handle_t gui_create_panel(int16_t x, int16_t y, int16_t width, int16_t height, 
                             gui_color_t color, gui_color_t border_color) {
    return gui_create_panel_ex(x, y, width, height, color, border_color, 
                              GUI_PANEL_SHAPE_RECT, 0, 1, 0, 0);
}

/******************************************************************************
      函数说明:创建圆角矩形面板
      入口数据:x,y      坐标
                width,height 宽高
                color    填充颜色
                border_color 边框颜色
                radius   圆角半径
                thickness 边框粗细
      返回值:  对象句柄
******************************************************************************/
gui_handle_t gui_create_rounded_panel(int16_t x, int16_t y, int16_t width, int16_t height, 
                                     gui_color_t color, gui_color_t border_color, 
                                     uint8_t radius, uint8_t thickness) {
    return gui_create_panel_ex(x, y, width, height, color, border_color, 
                              GUI_PANEL_SHAPE_ROUNDED, radius, thickness, 0, 0);
}

/******************************************************************************
      函数说明:创建圆形面板
      入口数据:x,y      坐标
                diameter 直径
                color    填充颜色
                border_color 边框颜色
                thickness 边框粗细
      返回值:  对象句柄
******************************************************************************/
gui_handle_t gui_create_circle_panel(int16_t x, int16_t y, int16_t diameter, 
                                    gui_color_t color, gui_color_t border_color, 
                                    uint8_t thickness) {
    return gui_create_panel_ex(x, y, diameter, diameter, color, border_color, 
                              GUI_PANEL_SHAPE_CIRCLE, diameter/2, thickness, 0, 0);
}

/******************************************************************************
      函数说明:创建圆弧面板
      入口数据:x,y      坐标
                radius   半径
                color    填充颜色
                border_color 边框颜色
                thickness 边框粗细
                start_angle 起始角度
                end_angle   结束角度
      返回值:  对象句柄
******************************************************************************/
gui_handle_t gui_create_arc_panel(int16_t x, int16_t y, uint8_t radius, 
                                 gui_color_t color, gui_color_t border_color, 
                                 uint8_t thickness, uint16_t start_angle, 
                                 uint16_t end_angle) {
    int16_t size = radius * 2 + thickness * 2;
    return gui_create_panel_ex(x - radius - thickness, y - radius - thickness, 
                              size, size, color, border_color, 
                              GUI_PANEL_SHAPE_ARC, radius, thickness, 
                              start_angle, end_angle);
}

/******************************************************************************
      函数说明:创建标签
      入口数据:x,y      坐标
                text     文本内容
                font_size 字体大小
                color    字体颜色
                bg_color 背景颜色
      返回值:  对象句柄
******************************************************************************/
gui_handle_t gui_create_label(int16_t x, int16_t y, const char* text, 
                             gui_font_size_t font_size, gui_color_t color, 
                             gui_color_t bg_color) {
     // 计算文本长度
    int text_len = strlen(text) + 1;  // 包括结束符
    
    // 根据字体大小计算字符宽度
    int16_t char_width, char_height, text_width;
    
    switch(font_size) {
        case GUI_FONT_12:
            char_width = 6;   // 12x6字体
            char_height = 12;
            break;
        case GUI_FONT_16:
            char_width = 8;   // 16x8字体
            char_height = 16;
            break;
        case GUI_FONT_24:
            char_width = 12;  // 24x12字体
            char_height = 24;
            break;
        case GUI_FONT_32:
            char_width = 16;  // 32x16字体
            char_height = 32;
            break;
        default:
            char_width = 8;
            char_height = 16;
    }
    
    // 文本宽度 = 字符数 * 字符宽度
    text_width = char_width * (text_len - 1);  // 减1因为text_len包含结束符
    
    gui_handle_t handle = gui_create_obj(GUI_OBJ_TYPE_LABEL, x, y, text_width, char_height);
    if (handle == GUI_INVALID_HANDLE) {
        return GUI_INVALID_HANDLE;
    }
    
    // 获取对象
    gui_obj_t* obj = gui_get_obj(handle);
    if (!obj) {
        gui_destroy_obj(handle);
        return GUI_INVALID_HANDLE;
    }
    
    // 设置颜色
    obj->color = color;
    obj->bg_color = bg_color;
    
    // 分配标签数据
    uint16_t data_size = sizeof(gui_label_data_t) + text_len + sizeof(gui_data_footer_t);
    mem_handle_t data_handle = stack_mempool_alloc(data_size, (uint8_t)GUI_OBJ_TYPE_LABEL);
    if (data_handle == GUI_INVALID_HANDLE) {
        gui_destroy_obj(handle);
        return GUI_INVALID_HANDLE;
    }
    
    // 设置标签数据
    gui_label_data_t* label_data = (gui_label_data_t*)stack_mempool_get_ptr(data_handle);
    if (!label_data) {
        stack_mempool_free(data_handle);
        gui_destroy_obj(handle);
        return GUI_INVALID_HANDLE;
    }
    
    label_data->font_size = font_size;
    label_data->text = (char*)(label_data + 1);
    strcpy(label_data->text, text);
    
    // 存储数据句柄在数据块末尾
    gui_data_footer_t* footer = (gui_data_footer_t*)((uint8_t*)label_data + sizeof(gui_label_data_t) + text_len);
    footer->data_handle = data_handle;
    
    // 设置对象数据
    obj->data = label_data;
    
    return handle;
}

/******************************************************************************
      函数说明:创建按钮
      入口数据:x,y      坐标
                width,height 宽高
                text     文本内容
                font_size 字体大小
      返回值:  对象句柄
******************************************************************************/
gui_handle_t gui_create_button(int16_t x, int16_t y, int16_t width, int16_t height, 
                              const char* text, gui_font_size_t font_size) {
    // 创建基本对象
    gui_handle_t handle = gui_create_obj(GUI_OBJ_TYPE_BUTTON, x, y, width, height);
    if (handle == GUI_INVALID_HANDLE) {
        return GUI_INVALID_HANDLE;
    }
    
    // 获取对象
    gui_obj_t* obj = gui_get_obj(handle);
    if (!obj) {
        gui_destroy_obj(handle);
        return GUI_INVALID_HANDLE;
    }
    
    // 设置按钮默认颜色
    obj->color = GUI_COLOR_WHITE;
    obj->bg_color = GUI_COLOR_BLUE;
    
    // 分配按钮数据
    int text_len = strlen(text) + 1;
    uint16_t data_size = sizeof(gui_button_data_t) + text_len + sizeof(gui_data_footer_t);
    mem_handle_t data_handle = stack_mempool_alloc(data_size, (uint8_t)GUI_OBJ_TYPE_BUTTON);
    if (data_handle == GUI_INVALID_HANDLE) {
        gui_destroy_obj(handle);
        return GUI_INVALID_HANDLE;
    }
    
    // 设置按钮数据
    gui_button_data_t* button_data = (gui_button_data_t*)stack_mempool_get_ptr(data_handle);
    if (!button_data) {
        stack_mempool_free(data_handle);
        gui_destroy_obj(handle);
        return GUI_INVALID_HANDLE;
    }
    
    button_data->font_size = font_size;
    button_data->pressed = false;
    button_data->text = (char*)(button_data + 1);
    strcpy(button_data->text, text);
    
    // 存储数据句柄
    gui_data_footer_t* footer = (gui_data_footer_t*)((uint8_t*)button_data + sizeof(gui_button_data_t) + text_len);
    footer->data_handle = data_handle;
    
    obj->data = button_data;
    
    return handle;
}
/******************************************************************************
      函数说明:创建图片
      入口数据:x,y      坐标
                width,height 宽高
                image_data 图片数据
      返回值:  对象句柄
******************************************************************************/


/*---------------------- 对象属性设置函数 ----------------------*/

gui_handle_t gui_create_image(int16_t x, int16_t y, int16_t width, int16_t height, 
                             const uint8_t* image_data) {
    // 创建基本对象
    gui_handle_t handle = gui_create_obj(GUI_OBJ_TYPE_IMAGE, x, y, width, height);
    if (handle == GUI_INVALID_HANDLE) {
        return GUI_INVALID_HANDLE;
    }
    
    // 获取对象
    gui_obj_t* obj = gui_get_obj(handle);
    if (!obj) {
        gui_destroy_obj(handle);
        return GUI_INVALID_HANDLE;
    }
    
    // 分配图片数据
    uint16_t data_size = sizeof(gui_image_data_t) + sizeof(gui_data_footer_t);
    mem_handle_t data_handle = stack_mempool_alloc(data_size, (uint8_t)GUI_OBJ_TYPE_IMAGE);
    if (data_handle == GUI_INVALID_HANDLE) {
        gui_destroy_obj(handle);
        return GUI_INVALID_HANDLE;
    }
    
    // 设置图片数据
    gui_image_data_t* image_data_struct = (gui_image_data_t*)stack_mempool_get_ptr(data_handle);
    if (!image_data_struct) {
        stack_mempool_free(data_handle);
        gui_destroy_obj(handle);
        return GUI_INVALID_HANDLE;
    }
    
    image_data_struct->image_data = image_data;
    
    // 存储数据句柄
    gui_data_footer_t* footer = (gui_data_footer_t*)((uint8_t*)image_data_struct + sizeof(gui_image_data_t));
    footer->data_handle = data_handle;
    
    obj->data = image_data_struct;
    
    return handle;
}

/******************************************************************************
      函数说明:设置文本
      入口数据:handle   对象句柄
                text     文本内容
      返回值:  true-成功 false-失败
******************************************************************************/
bool gui_set_text(gui_handle_t handle, const char* text) {
    gui_obj_t* obj = gui_get_obj(handle);
    if (!obj || !obj->data) {
        return false;
    }
    
    switch (obj->type) {
        case GUI_OBJ_TYPE_LABEL: {
            gui_label_data_t* label_data = (gui_label_data_t*)obj->data;
            int text_len = strlen(text) + 1;
            
            // 获取旧数据句柄
            mem_handle_t old_data_handle = get_data_handle_from_footer(obj->type, obj->data);
            if (old_data_handle == INVALID_HANDLE) {
                return false;
            }
            
            // 分配新数据
            uint16_t new_data_size = sizeof(gui_label_data_t) + text_len + sizeof(gui_data_footer_t);
            mem_handle_t new_data_handle = stack_mempool_alloc(new_data_size, (uint8_t)GUI_OBJ_TYPE_LABEL);
            if (new_data_handle == INVALID_HANDLE) {
                return false;
            }
            
            // 复制数据
            gui_label_data_t* new_label_data = (gui_label_data_t*)stack_mempool_get_ptr(new_data_handle);
            if (!new_label_data) {
                stack_mempool_free(new_data_handle);
                return false;
            }
            
            new_label_data->font_size = label_data->font_size;
            new_label_data->text = (char*)(new_label_data + 1);
            strcpy(new_label_data->text, text);
            
            // 存储新句柄
            gui_data_footer_t* footer = (gui_data_footer_t*)((uint8_t*)new_label_data + 
                                                             sizeof(gui_label_data_t) + text_len);
            footer->data_handle = new_data_handle;
            
            // 更新对象
            obj->data = new_label_data;
            
            // 释放旧数据
            stack_mempool_free(old_data_handle);
            
            // 更新对象大小
            int16_t char_width = label_data->font_size / 2;
            int16_t char_height = label_data->font_size;
            obj->width = char_width * (text_len - 1);
            obj->height = char_height;
            
            obj->updated = true;
            break;
        }
        case GUI_OBJ_TYPE_BUTTON: {
            gui_button_data_t* button_data = (gui_button_data_t*)obj->data;
            int text_len = strlen(text) + 1;
            
            // 获取旧数据句柄
            mem_handle_t old_data_handle = get_data_handle_from_footer(obj->type, obj->data);
            if (old_data_handle == INVALID_HANDLE) {
                return false;
            }
            
            // 分配新数据
            uint16_t new_data_size = sizeof(gui_button_data_t) + text_len + sizeof(gui_data_footer_t);
            mem_handle_t new_data_handle = stack_mempool_alloc(new_data_size, (uint8_t)GUI_OBJ_TYPE_BUTTON);
            if (new_data_handle == INVALID_HANDLE) {
                return false;
            }
            
            // 复制数据
            gui_button_data_t* new_button_data = (gui_button_data_t*)stack_mempool_get_ptr(new_data_handle);
            if (!new_button_data) {
                stack_mempool_free(new_data_handle);
                return false;
            }
            
            new_button_data->font_size = button_data->font_size;
            new_button_data->pressed = button_data->pressed;
            new_button_data->text = (char*)(new_button_data + 1);
            strcpy(new_button_data->text, text);
            
            // 存储新句柄
            gui_data_footer_t* footer = (gui_data_footer_t*)((uint8_t*)new_button_data + 
                                                             sizeof(gui_button_data_t) + text_len);
            footer->data_handle = new_data_handle;
            
            // 更新对象
            obj->data = new_button_data;
            
            // 释放旧数据
            stack_mempool_free(old_data_handle);
            
            obj->updated = true;
            break;
        }
        default:
            return false;
    }
    
    return true;
}

/******************************************************************************
      函数说明:设置颜色
      入口数据:handle   对象句柄
                color    颜色
      返回值:  true-成功 false-失败
******************************************************************************/
bool gui_set_color(gui_handle_t handle, gui_color_t color) {
    gui_obj_t* obj = gui_get_obj(handle);
    if (!obj) {
        return false;
    }
    
    if (obj->color != color) {
        obj->color = color;
        obj->updated = true;
    }
    
    return true;
}

/******************************************************************************
      函数说明:设置背景色
      入口数据:handle   对象句柄
                bg_color 背景颜色
      返回值:  true-成功 false-失败
******************************************************************************/
bool gui_set_bg_color(gui_handle_t handle, gui_color_t bg_color) {
    gui_obj_t* obj = gui_get_obj(handle);
    if (!obj) {
        return false;
    }
    
    if (obj->bg_color != bg_color) {
        obj->bg_color = bg_color;
        obj->updated = true;
    }
    
    return true;
}

/******************************************************************************
      函数说明:设置字体大小
      入口数据:handle   对象句柄
                font_size 字体大小
      返回值:  true-成功 false-失败
******************************************************************************/
bool gui_set_font_size(gui_handle_t handle, gui_font_size_t font_size) {
    gui_obj_t* obj = gui_get_obj(handle);
    if (!obj || !obj->data) {
        return false;
    }
    
    switch (obj->type) {
        case GUI_OBJ_TYPE_LABEL: {
            gui_label_data_t* label_data = (gui_label_data_t*)obj->data;
            if (label_data->font_size != font_size) {
                label_data->font_size = font_size;
                
                // 更新对象大小
                int16_t char_width = font_size / 2;
                int16_t char_height = font_size;
                int text_len = label_data->text ? strlen(label_data->text) : 0;
                obj->width = char_width * text_len;
                obj->height = char_height;
                
                obj->updated = true;
            }
            break;
        }
        case GUI_OBJ_TYPE_BUTTON: {
            gui_button_data_t* button_data = (gui_button_data_t*)obj->data;
            if (button_data->font_size != font_size) {
                button_data->font_size = font_size;
                obj->updated = true;
            }
            break;
        }
        default:
            return false;
    }
    
    return true;
}

/******************************************************************************
      函数说明:设置图片
      入口数据:handle   对象句柄
                image_data 图片数据
      返回值:  true-成功 false-失败
******************************************************************************/
bool gui_set_image(gui_handle_t handle, const uint8_t* image_data) {
    gui_obj_t* obj = gui_get_obj(handle);
    if (!obj || obj->type != GUI_OBJ_TYPE_IMAGE || !obj->data) {
        return false;
    }
    
    gui_image_data_t* image_data_struct = (gui_image_data_t*)obj->data;
    image_data_struct->image_data = image_data;
    obj->updated = true;
    
    return true;
}


/*---------------------- 渲染和事件处理函数 ----------------------*/

/******************************************************************************
      函数说明:渲染单个对象
      入口数据:handle   对象句柄
      返回值:  无
******************************************************************************/
void gui_render_obj(gui_handle_t handle) {
    gui_obj_t* obj = gui_get_obj(handle);
    if (!obj || !obj->visible) {
        return;
    }
    // 如果不需要更新,跳过
    if (!obj->updated) {
        return;
    }
    
    // 根据对象类型进行渲染
    switch (obj->type) {
        case GUI_OBJ_TYPE_PANEL: {
            if (!obj->data) {
                // 没有数据,默认绘制矩形
                LCD_DrawRectangle(obj->x, obj->y, 
                                obj->x + obj->width - 1, 
                                obj->y + obj->height - 1, 
                                obj->bg_color);
                LCD_Fill(obj->x + 1, obj->y + 1, 
                       obj->x + obj->width - 2, 
                       obj->y + obj->height - 2, 
                       obj->color);
                break;
            }
			
			 gui_panel_data_t* panel_data = (gui_panel_data_t*)obj->data;
			 
			 
               switch (panel_data->shape) {
                case GUI_PANEL_SHAPE_RECT: {
                    // 绘制矩形面板
                    if (obj->bg_color != obj->color) {
                        // 画边框
                        LCD_DrawRectangle(obj->x, obj->y, 
                                        obj->x + obj->width - 1, 
                                        obj->y + obj->height - 1, 
                                        obj->bg_color);
                        // 填充内部
                        LCD_Fill(obj->x + 1, obj->y + 1, 
                               obj->x + obj->width - 2, 
                               obj->y + obj->height - 2, 
                               obj->color);
                    } else {
                        // 无边框
                        LCD_Fill(obj->x, obj->y, 
                               obj->x + obj->width - 1, 
                               obj->y + obj->height - 1, 
                               obj->color);
                    }
                    break;
                }
                
                case GUI_PANEL_SHAPE_ROUNDED: {
					check_panel_memory(panel_data);
				// 打印结构体值
					TFTP_DEBUG("Address of panel_data: %p", obj->data);
					TFTP_DEBUG("STRUCT: shape=%d, radius=%d, thickness=%d", 
							  panel_data->shape, panel_data->radius, panel_data->thickness);
					
					render_rounded_panel_fixed(obj, panel_data);
                    break;
                }
                
                case GUI_PANEL_SHAPE_CIRCLE: {
                    uint8_t r = panel_data->radius;
                    uint8_t thickness = panel_data->thickness;
                    int16_t center_x = obj->x + obj->width / 2;
                    int16_t center_y = obj->y + obj->height / 2;
                    
                    if (r == 0) {
                        r = (obj->width < obj->height) ? 
                            obj->width / 2 : obj->height / 2;
                    }
                    
                    if (thickness <= 1) {
                        // 薄边框或无边框
                        if (obj->bg_color != obj->color) {
                            // 绘制边框圆
                            LCD_Draw_Circle(center_x, center_y, r, obj->bg_color);
                            // 填充内部圆
                            if (r > 1) {
                                LCD_Draw_FillCircle(center_x, center_y, r - 1, obj->color);
                            }
                        } else {
                            // 无边框
                            LCD_Draw_FillCircle(center_x, center_y, r, obj->color);
                        }
                    } else {
                        // 绘制带粗细的圆
                        for (uint8_t t = 0; t < thickness; t++) {
                            LCD_Draw_Circle(center_x, center_y, r + t, obj->bg_color);
                        }
                    }
                    break;
                }
                
                case GUI_PANEL_SHAPE_ARC: {
                    uint8_t r = panel_data->radius;
                    uint8_t thickness = panel_data->thickness;
                    uint16_t start_angle = panel_data->start_angle;
                    uint16_t end_angle = panel_data->end_angle;
                    int16_t center_x = obj->x + obj->width / 2;
                    int16_t center_y = obj->y + obj->height / 2;
                    
                    if (thickness <= 1) {
                        // 薄边框圆弧
                        LCD_DrawArc_Optimized(center_x, center_y, r, 
                                            start_angle, end_angle, obj->color);
                    } else {
                        // 厚边框圆弧
                        LCD_DrawArc_Polar(center_x, center_y, r, 
                                        start_angle, end_angle, thickness, obj->color);
                    }
                    break;
                }
                
                default:
                    // 默认绘制矩形
                    LCD_DrawRectangle(obj->x, obj->y, 
                                    obj->x + obj->width - 1, 
                                    obj->y + obj->height - 1, 
                                    obj->bg_color);
                    LCD_Fill(obj->x + 1, obj->y + 1, 
                           obj->x + obj->width - 2, 
                           obj->y + obj->height - 2, 
                           obj->color);
            }
            break;
        }
        
        case GUI_OBJ_TYPE_LABEL: {
            if (obj->data) {
                gui_label_data_t* label_data = (gui_label_data_t*)obj->data;
                // 填充背景
                LCD_Fill(obj->x, obj->y, obj->x + obj->width, obj->y + obj->height, obj->bg_color);
                // 绘制文本
                LCD_ShowText(obj->x, obj->y, (uint8_t*)label_data->text, obj->color, obj->bg_color, label_data->font_size, 0);
            }
            break;
        }
        
		case GUI_OBJ_TYPE_LABEL_WRAP: {
			if (obj->data) {
				gui_label_wrap_data_t* label_data = (gui_label_wrap_data_t*)obj->data;
				
				// 填充背景
				LCD_Fill(obj->x, obj->y, obj->x + obj->width, obj->y + obj->height, obj->bg_color);
				
				const char* text = label_data->text;
				int16_t x = obj->x;
				int16_t y = obj->y;
				int16_t char_width = label_data->char_width;
				int16_t char_height = label_data->char_height;
				int16_t max_width = label_data->max_width;
				
				if (max_width <= 0) {
					// 不换行的情况
					LCD_ShowText(x, y, (uint8_t*)text, obj->color, obj->bg_color, label_data->font_size, 0);
				} else {
					// 换行处理
					int chars_per_line = max_width / char_width;
					int text_len = strlen(text);
					int current_pos = 0;
					
					while (current_pos < text_len && y < obj->y + obj->height) {
						// 计算当前行的字符数
						int line_chars = text_len - current_pos;
						if (line_chars > chars_per_line) {
							line_chars = chars_per_line;
						}
						
						// 复制当前行
						char line[128]; // 假设最大行长度
						strncpy(line, text + current_pos, line_chars);
						line[line_chars] = '\0';
						
						// 绘制当前行
						LCD_ShowText(x, y, (uint8_t*)line, obj->color, obj->bg_color, label_data->font_size, 0);
						
						// 更新位置
						current_pos += line_chars;
						y += char_height;
					}
				}
			}
			break;
		}

		
        case GUI_OBJ_TYPE_BUTTON: {
            if (obj->data) {
                gui_button_data_t* button_data = (gui_button_data_t*)obj->data;
                
                // 绘制按钮
                if (button_data->pressed) {
                    // 按下状态
                    LCD_Fill(obj->x, obj->y, obj->x + obj->width, obj->y + obj->height, GUI_COLOR_DARKGRAY);
                    LCD_DrawRectangle(obj->x, obj->y, obj->x + obj->width - 1, obj->y + obj->height - 1, GUI_COLOR_BLACK);
                } else {
                    // 正常状态
                    LCD_Fill(obj->x, obj->y, obj->x + obj->width, obj->y + obj->height, obj->bg_color);
                    LCD_DrawRectangle(obj->x, obj->y, obj->x + obj->width - 1, obj->y + obj->height - 1, GUI_COLOR_BLACK);
                    
                    // 绘制阴影效果
                    LCD_DrawLine(obj->x, obj->y + obj->height - 1, 
                                 obj->x + obj->width - 1, obj->y + obj->height - 1, 
                                 GUI_COLOR_DARKGRAY);
                    LCD_DrawLine(obj->x + obj->width - 1, obj->y, 
                                 obj->x + obj->width - 1, obj->y + obj->height - 1, 
                                 GUI_COLOR_DARKGRAY);
                }
                
                // 绘制按钮文本
                int16_t text_x = obj->x + (obj->width - (button_data->font_size / 2) * strlen(button_data->text)) / 2;
                int16_t text_y = obj->y + (obj->height - button_data->font_size) / 2;
                LCD_ShowText(text_x, text_y, (uint8_t*)button_data->text, obj->color, obj->bg_color, button_data->font_size, 0);
            }
            break;
        }
        
        case GUI_OBJ_TYPE_IMAGE: {
            if (obj->data) {
                gui_image_data_t* image_data = (gui_image_data_t*)obj->data;
                if (image_data->image_data) {
                    LCD_ShowCentrePicture(obj->x, obj->y, obj->width, obj->height, image_data->image_data);
                }
            }
            break;
        }
        
        default:
            break;
    }
    
    obj->updated = false;
}


/**
 * @brief 渲染所有GUI对象(按层次顺序)
 * 
 * 渲染顺序:
 * 1. 先渲染所有根对象(无父对象的对象)
 * 2. 按层次顺序渲染子对象
 * 3. 渲染剩余未处理的对象(容错机制)
 */
void gui_render_all(void) {
    static gui_handle_t rendered_handles[MAX_HANDLES];
    static int rendered_count = 0;
    rendered_count = 0;
    
    // 第一阶段:渲染所有根对象(无父对象的对象)
    for (int i = 0; i < MAX_HANDLES; i++) {
        if (mempool.blocks[i].state == BLOCK_USED) {
            uint8_t type = mempool.blocks[i].type;
            if (type >= GUI_OBJ_TYPE_WIDGET && type <= GUI_OBJ_TYPE_WINDOW) {
                gui_obj_t* obj = (gui_obj_t*)stack_mempool_get_ptr(i);
                if (obj && obj->parent == GUI_INVALID_HANDLE) {
                    // 渲染根对象
                    gui_render_obj(i);
                    rendered_handles[rendered_count++] = i;
                }
            }
        }
    }
    
    // 第二阶段:按层次顺序渲染子对象
    bool found_child = true;
    while (found_child) {
        found_child = false;
        
        for (int i = 0; i < MAX_HANDLES; i++) {
            if (mempool.blocks[i].state == BLOCK_USED) {
                uint8_t type = mempool.blocks[i].type;
                if (type >= GUI_OBJ_TYPE_WIDGET && type <= GUI_OBJ_TYPE_WINDOW) {
                    // 检查是否已渲染
                    bool already_rendered = false;
                    for (int j = 0; j < rendered_count; j++) {
                        if (rendered_handles[j] == i) {
                            already_rendered = true;
                            break;
                        }
                    }
                    
                    if (!already_rendered) {
                        gui_obj_t* obj = (gui_obj_t*)stack_mempool_get_ptr(i);
                        if (obj) {
                            // 检查父对象是否已渲染
                            bool parent_rendered = false;
                            for (int j = 0; j < rendered_count; j++) {
                                if (rendered_handles[j] == obj->parent) {
                                    parent_rendered = true;
                                    break;
                                }
                            }
                            
                            if (parent_rendered) {
                                gui_render_obj(i);
                                rendered_handles[rendered_count++] = i;
                                found_child = true;
                            }
                        }
                    }
                }
            }
        }
    }
    
    // 第三阶段:渲染剩余未处理的对象(容错机制)
    for (int i = 0; i < MAX_HANDLES; i++) {
        if (mempool.blocks[i].state == BLOCK_USED) {
            uint8_t type = mempool.blocks[i].type;
            if (type >= GUI_OBJ_TYPE_WIDGET && type <= GUI_OBJ_TYPE_WINDOW) {
                // 检查是否已渲染
                bool already_rendered = false;
                for (int j = 0; j < rendered_count; j++) {
                    if (rendered_handles[j] == i) {
                        already_rendered = true;
                        break;
                    }
                }
                
                if (!already_rendered) {
                    gui_render_obj(i);
                    rendered_handles[rendered_count++] = i;
                }
            }
        }
    }
    
    // 记录渲染完成信息
    TFTP_DEBUG("Rendering completed: %d objects rendered", rendered_count);
    
    // 边界检查:验证子对象是否在父对象范围内
    for (int i = 0; i < rendered_count; i++) {
        gui_obj_t* obj = gui_get_obj(rendered_handles[i]);
        if (obj && obj->parent != GUI_INVALID_HANDLE) {
            gui_obj_t* parent = gui_get_obj(obj->parent);
            if (parent) {
                // 检查子对象是否超出父对象边界
                if (obj->x < parent->x || obj->x + obj->width > parent->x + parent->width ||
                    obj->y < parent->y || obj->y + obj->height > parent->y + parent->height) {
                    TFTP_DEBUG("WARNING: Child %d exceeds parent %d bounds", 
                              rendered_handles[i], obj->parent);
                }
            }
        }
    }
}

/**
 * @brief 处理触摸屏输入事件
 * 
 * 此函数遍历所有按钮对象,检测触摸点是否落在按钮区域内,并根据触摸事件类型
 * (按下/释放)更新按钮状态。当触摸释放事件发生在按钮区域内时,会触发按钮的
 * 点击回调函数。
 * 
 * @param x 触摸点的X坐标(屏幕坐标系)
 * @param y 触摸点的Y坐标(屏幕坐标系) 
 * @param event 触摸事件类型,应为以下值之一:
 *              - GUI_EVENT_PRESS: 触摸按下事件
 *              - GUI_EVENT_RELEASE: 触摸释放事件
 * 
 * @note 该函数会遍历所有已使用的按钮类型对象,检查触摸点是否在对象区域内。
 *       对于触摸按下事件,设置按钮的按下状态并标记需要更新显示。
 *       对于触摸释放事件,清除按钮的按下状态,并如果触摸点在按钮区域内释放,
 *       则触发GUI_EVENT_CLICK回调函数。
 * 
 * @see GUI_EVENT_PRESS, GUI_EVENT_RELEASE, GUI_EVENT_CLICK
 */
void gui_handle_touch(int16_t x, int16_t y, uint8_t event) {
    // 遍历所有按钮对象
    for (mem_handle_t handle = 0; handle < MAX_HANDLES; handle++) {
        if (mempool.blocks[handle].state == BLOCK_USED && 
            mempool.blocks[handle].type == GUI_OBJ_TYPE_BUTTON) {
            gui_obj_t* obj = gui_get_obj(handle);
            if (obj && obj->visible) {
                // 检查触摸点是否在按钮内
                if (x >= obj->x && x < obj->x + obj->width &&
                    y >= obj->y && y < obj->y + obj->height) {
                    
                    if (obj->data) {
                        gui_button_data_t* button_data = (gui_button_data_t*)obj->data;
                        
                        if (event == GUI_EVENT_PRESS) {
                            button_data->pressed = true;
                            obj->updated = true;
                        } 
                        else if (event == GUI_EVENT_RELEASE) {
                            button_data->pressed = false;
                            obj->updated = true;
                            
                            // 触发点击事件
                            if (obj->callback) {
                                obj->callback(handle, GUI_EVENT_CLICK);
                            }
                        }
                    }
                }
            }
        }
    }
}

/**
 * @brief 执行图形系统更新(渲染所有脏区)
 * @note 此函数会触发整个GUI系统的重绘流程,通常在主循环中调用
 */
void gui_update(void) {
    // 渲染所有需要更新的对象
    gui_render_all();
}

/**
 * @brief 获取GUI系统已使用的内存大小
 * @return uint16_t 已使用内存大小(字节)
 * @note 用于监控内存使用情况,防止内存泄漏
 */
uint16_t gui_get_memory_used(void) {
    return mempool.alloc_ptr;
}

/**
 * @brief 获取GUI系统当前可用内存大小
 * @return uint16_t 可用内存大小(字节)
 * @note 在创建新对象前可调用此函数检查内存是否充足
 */
uint16_t gui_get_memory_available(void) {
    return stack_mempool_available();
}

/**
 * @brief 执行内存池完整性检查
 * @return bool 检查通过返回true,发现错误返回false
 * @note 用于调试和验证内存管理系统的稳定性
 */
bool gui_memory_check(void) {
    return stack_mempool_integrity_check();
}
相关推荐
Juicedata6 小时前
JuiceFS 企业版 5.3 特性详解:单文件系统支持超 5,000 亿文件,首次引入 RDMA
大数据·人工智能·机器学习·性能优化·开源
熊猫钓鱼>_>6 小时前
【开源鸿蒙跨平台开发先锋训练营】Day 19: 开源鸿蒙React Native动效体系构建与混合开发复盘
react native·华为·开源·harmonyos·鸿蒙·openharmony
向哆哆6 小时前
构建健康档案管理快速入口:Flutter × OpenHarmony 跨端开发实战
flutter·开源·鸿蒙·openharmony·开源鸿蒙
FIT2CLOUD飞致云6 小时前
赛道第一!1Panel成功入选Gitee 2025年度开源项目
服务器·ai·开源·1panel
向哆哆7 小时前
构建智能健康档案管理与预约挂号系统:Flutter × OpenHarmony 跨端开发实践
flutter·开源·鸿蒙·openharmony·开源鸿蒙
向哆哆7 小时前
Flutter × OpenHarmony:打造校园勤工俭学个人中心界面实战
flutter·开源·鸿蒙·openharmony
开源能源管理系统7 小时前
开源筑基,智领零碳:MyEMS 赋能零碳工厂全周期转型新实践
大数据·开源·能源·能源管理系统·零碳工厂
CoderJia程序员甲8 小时前
GitHub 热榜项目 - 日榜(2026-01-30)
开源·大模型·llm·github·ai教程
熊猫钓鱼>_>8 小时前
【开源鸿蒙跨平台开发先锋训练营】鸿蒙应用开发 Day 10 - React Native for OpenHarmony 实战:多端响应式布局与高可用交互设计
华为·开源·交互·harmonyos·鸿蒙·rn·gridrow
昇腾CANN8 小时前
DeepSeek-V3.2-Exp高吞吐优化实践
开源·昇腾·cann