新增加了 交流量 直流量 遥信量的查看 YC页面的基础编写

This commit is contained in:
2026-04-07 20:40:29 +08:00
parent d19ce588b3
commit 0f5368bb51
18 changed files with 9578 additions and 7977 deletions

View File

@@ -1,45 +1,365 @@
#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);
}
static void YCView_ShowTerminalInfo(void)
{
uint8_t *context[] = {
"终端类型 F30",
"终端型号 F30",
"软件版本 SV0.010",
"硬件版本 HW0.010",
"软件校验 4454",
"程序日期 2024.08.27"
};
s_port->show_str(32, 26, "馈线自动化终端");
for(uint8_t index = 0; index < 6; index++ )
{
s_port->show_str(6, 26 + (index + 1) * (s_port->get_ascii_height() + s_port->get_row_space()), context[index]);
}
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();
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 = YCView_ShowTopName;
view->show_top_name = NULL;
view->show_info_page = YCView_ShowInfoPage;
}
view->draw_full = YCView_DrawFull;
view->draw_values = YCView_DrawValues;
}