Files
DTU-HMI/src/Drv/pages/YC/view.c

366 lines
14 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include "Drv/pages/YC/view.h"
#include <stdio.h>
static const PageRenderPort *s_port = NULL;
/* -------------------------------------------------------------------------
* 宏定义:遥测页面布局常量
* ------------------------------------------------------------------------- */
#define YC_TOP_BAND_MAX_Y (24u) /* 顶栏最大 Y 坐标 */
#define YC_CONTENT_BASE_Y (24u) /* 内容区起始 Y 坐标 */
#define YC_NAME_X (6u) /* 名称显示 X 坐标 */
#define YC_VALUE_X (100u) /* 数值显示 X 坐标 */
#define YC_ROW_PAD_X0 (2u) /* 行内容左侧留白 */
#define YC_ROW_PAD_X1 (2u) /* 行内容右侧留白 */
#define YC_FOOTER_Y_FROM_BOTTOM (16u) /* 底栏距底部距离(与 PageRenderer_LcdShowInfoPage 一致)*/
#define YC_FOOTER_GAP_PX (2u) /* 内容区与底栏之间的留白间隙 */
/* -------------------------------------------------------------------------
* 函数名YCView_ShowInfoPage
* 功能:
* 显示当前页码和总页数信息到底栏。
*
* 参数:
* wPageNum - 当前页码(从 1 开始)
* wPageMax - 总页数
*
* 边界处理:
* - 本函数不做参数合法性校验,直接传递给渲染端口显示。
*
* 说明:
* - 该函数通过 s_port->show_info_page() 调用底层渲染接口显示页码信息。
* - 通常在内容区绘制完成后调用,用于告知用户当前浏览位置。
*
* 返回值:
* - 无
* ------------------------------------------------------------------------- */
static void YCView_ShowInfoPage(uint16_t wPageNum, uint16_t wPageMax)
{
s_port->show_info_page(wPageNum, wPageMax);
}
/* -------------------------------------------------------------------------
* 函数名YCView_ShowTopName
* 功能:
* 在页面顶栏居中显示顶部名称,并绘制装饰性箭头。
*
* 参数:
* name - 要显示的顶部名称字符串UTF-8 编码)
*
* 边界处理:
* - 本函数不对 name 做空指针校验,调用方需保证 name 有效。
* - 若名称过长导致居中计算偏移为负数,显示位置可能异常,由底层渲染处理。
*
* 说明:
* - 首先填充整个屏幕为背景色,实现清屏效果。
* - 通过 s_port->get_utf8_len() 和 s_port->get_ascii_width() 计算字符串显示宽度。
* - 使用居中公式 (screen_width - text_width) / 2 确定 X 坐标。
* - 在 Y=3 位置绘制名称,并在固定位置 (18, 2) 绘制箭头装饰draw_meitou
* - 顶栏高度为 0-23 像素,名称显示于第 3 行以确保视觉美观。
*
* 返回值:
* - 无
* ------------------------------------------------------------------------- */
static void YCView_ShowTopName(const uint8_t *name)
{
uint16_t wLen = s_port->get_utf8_len(name) * s_port->get_ascii_width();
s_port->fill_rect(0, 0, s_port->get_size_x() - 1, s_port->get_size_y() - 1, s_port->get_color_back());
/* 显示顶部名称,居中显示 */
s_port->show_str((s_port->get_size_x() - wLen) / 2, 3, name);
s_port->draw_meitou(18, 2);
}
/* -------------------------------------------------------------------------
* 函数名YCView_RowY
* 功能:
* 根据行号计算该行在屏幕上的实际 Y 坐标。
*
* 参数:
* row - 行号(从 0 开始)
*
* 边界处理:
* - 本函数不做行号范围校验,调用方应保证 row 有效。
*
* 说明:
* - 计算公式row_y = YC_CONTENT_BASE_Y + row × (字符高度 + 行间距)
* - YC_CONTENT_BASE_Y 为内容区起始 Y 坐标24 像素)。
* - 每行高度由 s_port->get_ascii_height() 和 s_port->get_row_space() 决定。
* - 该函数确保所有遥测数据显示在内容区内,从第 24 像素开始向下排列。
*
* 返回值:
* - 该行在屏幕上的 Y 坐标
* ------------------------------------------------------------------------- */
static uint16_t YCView_RowY(uint8_t row)
{
uint16_t lineH = s_port->get_ascii_height() + s_port->get_row_space();
return YC_CONTENT_BASE_Y + (uint16_t)row * lineH;
}
/* -------------------------------------------------------------------------
* 函数名YCView_DrawRowNameAndValue
* 功能:
* 在指定行绘制遥测项的名称和数值。
*
* 参数:
* name - 名称字符串指针
* value - 数值字符串指针
* row - 目标行号(从 0 开始)
* drawName - 是否显示名称的标志,非 0 表示显示0 表示不显示
*
* 边界处理:
* - 本函数不对 name/value 做空指针校验,调用方需保证字符串有效。
* - 若 drawName 为 0则跳过名称绘制仅显示数值。
*
* 说明:
* - 根据 drawName 标志决定是否在左侧区域YC_NAME_X显示名称。
* - 数值始终在右侧固定位置YC_VALUE_X显示。
* - Y 坐标通过 YCView_RowY(row) 计算,确保内容对齐到指定行。
* - 该函数是遥测数据显示的核心绘制单元,被 YCView_PaintContent() 调用。
*
* 返回值:
* - 无
* ------------------------------------------------------------------------- */
static void YCView_DrawRowNameAndValue(const uint8_t *name, const uint8_t *value, uint8_t row, uint8_t drawName)
{
if (drawName != 0u)
{
s_port->show_str(YC_NAME_X, YCView_RowY(row), name);
}
s_port->show_str(YC_VALUE_X, YCView_RowY(row), value);
}
/* -------------------------------------------------------------------------
* 函数名YCView_ClearContentArea
* 功能:
* 清空内容区域(不含顶栏和底栏),填充背景色并准备重绘。
*
* 参数:
* 无
*
* 边界处理:
* - 若内容区上边界 y0 大于等于下边界 y1或屏幕宽度为 0不执行填充操作。
* - 自动将下边界限制在屏幕有效范围内sy-1
*
* 说明:
* - 内容区范围:从 YC_CONTENT_BASE_Y-2 到 YC_FOOTER_Y_FROM_BOTTOM
* - 上边界预留 2 像素用于视觉缓冲,避免与顶栏过于接近。
* - 下边界通过 YC_FOOTER_Y_FROM_BOTTOM 计算,确保不覆盖底栏页码信息。
* - 清空后内容区处于待绘制状态,由调用方继续执行数据项绘制。
*
* 返回值:
* - 无
* ------------------------------------------------------------------------- */
static void YCView_ClearContentArea(void)
{
uint16_t sx = s_port->get_size_x();
uint16_t sy = s_port->get_size_y();
uint16_t y0 = YC_CONTENT_BASE_Y - 2u;
uint16_t y1 = sy - YC_FOOTER_Y_FROM_BOTTOM;
if ((y1 > y0) && (sx > 0u))
{
s_port->fill_rect(0, y0, sx - 1u, y1, s_port->get_color_back());
}
}
/* -------------------------------------------------------------------------
* 函数名YCView_ApplyCursorInvert
* 功能:
* 对当前光标所在行进行反显高亮处理。
*
* 参数:
* input - 视图输入结构体,包含页码、光标位置等信息
*
* 边界处理:
* - 若数据为空input->empty != 0或没有可显示的行数直接返回。
* - 若计算的反显区域越界,自动调整至有效范围内。
* - 若反显上边界大于等于下边界,不执行反显操作。
*
* 说明:
* - 光标行 Y 坐标通过 YCView_RowY(input->cursor_row) 计算。
* - 反显区域高度为单行高度lineH-1确保覆盖整个字符区域。
* - X 方向留白:左侧 YC_ROW_PAD_X0右侧 sx-1-YC_ROW_PAD_X1避免触及屏幕边缘。
* - 下边界受 YC_FOOTER_Y_FROM_BOTTOM 限制,防止覆盖底栏页码。
* - 该函数在绘制页码前调用,避免因页码绘制导致光标高亮消失。
*
* 返回值:
* - 无
* ------------------------------------------------------------------------- */
static void YCView_ApplyCursorInvert(const yc_view_input_t *input)
{
uint16_t sx = s_port->get_size_x();
uint16_t rows = input->rows_on_page;
uint16_t lineH = s_port->get_ascii_height() + s_port->get_row_space();
uint16_t y0;
uint16_t y1;
uint16_t yMax;
if ((input->empty != 0u) || (rows == 0u))
{
return;
}
y0 = YCView_RowY((uint8_t)input->cursor_row);
y1 = y0 + lineH - 1u;
yMax = s_port->get_size_y() - YC_FOOTER_Y_FROM_BOTTOM;
if (y1 > yMax)
{
y1 = yMax;
}
if (y1 < y0)
{
return;
}
s_port->invert(YC_ROW_PAD_X0, y0, sx - 1u - YC_ROW_PAD_X1, y1);
}
/* -------------------------------------------------------------------------
* 函数名YCView_PaintContent
* 功能:
* 绘制内容区,包括清空背景、显示遥测数据项、光标高亮和页码信息。
*
* 参数:
* input - 视图输入结构体,包含页面索引、行数据等信息
*
* 边界处理:
* - 若数据为空input->empty != 0显示"无遥测数据"提示并返回。
* - 跳过无效行input->row_valid[row] == 0
* - 循环次数受 input->rows_on_page 和 YC_VIEW_ROWS_MAX 双重限制。
*
* 说明:
* - 绘制流程:
* 1) 调用 YCView_ClearContentArea() 清空内容区背景
* 2) 若数据为空,显示提示信息并返回
* 3) 遍历有效行,逐行调用 YCView_DrawRowNameAndValue() 绘制名称和数值
* 4) 先反显光标行YCView_ApplyCursorInvert再绘制页码
* - 顺序重要:避免页码绘制覆盖光标高亮效果
* 5) 最后显示页码信息YCView_ShowInfoPage
* - 该函数是遥测页面内容绘制的核心入口,被 YCView_DrawFull() 和 YCView_DrawValues() 调用。
*
* 返回值:
* - 无
* ------------------------------------------------------------------------- */
static void YCView_PaintContent(const yc_view_input_t *input)
{
uint8_t row;
uint16_t rows;
YCView_ClearContentArea();
if (input->empty != 0u)
{
s_port->show_str(6u, YC_CONTENT_BASE_Y + 20u, (const uint8_t *)"无遥测数据");
return;
}
rows = input->rows_on_page;
for (row = 0; row < (uint8_t)rows && row < YC_VIEW_ROWS_MAX; row++)
{
if (input->row_valid[row] == 0u)
{
continue;
}
YCView_DrawRowNameAndValue(input->row_name[row], input->row_value[row], row, 1u);
}
/* 先反显光标,再绘页码,避免 invert 覆盖底栏「第 x 页」造成花屏 */
YCView_ApplyCursorInvert(input);
YCView_ShowInfoPage(input->page, input->page_max);
}
/* -------------------------------------------------------------------------
* 函数名YCView_DrawFull
* 功能:
* 完整绘制遥测页面,包括顶栏和内容区。
*
* 参数:
* view - 视图对象指针(当前未使用)
* input - 视图输入结构体,包含顶部名称和行数据等信息
*
* 边界处理:
* - 若 input 或 s_port 为 NULL直接返回。
* - 通过 (void)view 消除未使用参数警告。
*
* 说明:
* - 完整绘制流程先显示顶栏名称YCView_ShowTopName再绘制内容区YCView_PaintContent
* - 整屏擦除操作在 MenuPage_OnExit() 统一完成,此处无需重复清屏。
* - 该函数用于首次加载页面或需要完整重绘的场景。
*
* 返回值:
* - 无
* ------------------------------------------------------------------------- */
static void YCView_DrawFull(view_t *view, const yc_view_input_t *input)
{
(void)view;
if ((input == NULL) || (s_port == NULL))
{
return;
}
/* 整屏擦除在 MenuPage_OnExit 统一完成,此处直接绘制顶栏与内容 */
YCView_ShowTopName(input->top_name);
YCView_PaintContent(input);
}
/* -------------------------------------------------------------------------
* 函数名YCView_DrawValues
* 功能:
* 仅重绘内容区数值(不重绘顶栏),用于主循环中的数值刷新。
*
* 参数:
* view - 视图对象指针(当前未使用)
* input - 视图输入结构体,包含页面和行数据信息
*
* 边界处理:
* - 若 input 或 s_port 为 NULL直接返回。
* - 通过 (void)view 消除未使用参数警告。
*
* 说明:
* - 该函数是主循环节拍的核心调用点,用于周期性刷新遥测数值显示。
* - 仅重绘内容区YCView_PaintContent顶栏保持不变以减少绘制开销。
* - 在桩模式下,此函数会触发 YCView_FormatStubValue() 生成模拟数据并更新显示。
* - 相比 YCView_DrawFull(),此函数更高效,适合高频刷新场景。
*
* 返回值:
* - 无
* ------------------------------------------------------------------------- */
static void YCView_DrawValues(view_t *view, const yc_view_input_t *input)
{
(void)view;
if ((input == NULL) || (s_port == NULL))
{
return;
}
/* 主循环节拍:重绘内容区以更新桩数值(不重画面顶栏) */
YCView_PaintContent(input);
}
/* -------------------------------------------------------------------------
* 函数名View_Init
* 功能:
* 初始化遥测页面视图,绑定渲染端口和回调函数。
*
* 参数:
* view - 视图对象指针,待初始化的视图结构体
*
* 边界处理:
* - 本函数不对 view 做空指针校验,调用方需保证 view 有效。
*
* 说明:
* - 初始化流程:
* 1) 获取 LCD 渲染端口s_port = PageRenderer_Lcd()
* 2) 设置 show_top_name 为 NULL表示不使用自定义顶栏显示函数
* 3) 绑定 show_info_page 回调到 YCView_ShowInfoPage
* 4) 绑定 draw_full 回调到 YCView_DrawFull完整绘制入口
* 5) 绑定 draw_values 回调到 YCView_DrawValues数值刷新入口
* - 初始化后,视图对象即可被页面管理器使用。
*
* 返回值:
* - 无
* ------------------------------------------------------------------------- */
void View_Init(view_t *view)
{
s_port = PageRenderer_Lcd();
view->show_top_name = NULL;
view->show_info_page = YCView_ShowInfoPage;
view->draw_full = YCView_DrawFull;
view->draw_values = YCView_DrawValues;
}