Files
V2_micropython/display.py
jeremygan2021 0aa8f5f473 1
2026-03-03 23:07:17 +08:00

213 lines
7.6 KiB
Python
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.
import machine
import st7789py as st7789
from config import CURRENT_CONFIG
import font
class Display:
def __init__(self):
self.tft = None
self.width = 240
self.height = 240
self._init_display()
self.font = font.Font()
def _init_display(self):
print(">>> Initializing Display...")
try:
pins = CURRENT_CONFIG.pins
spi = machine.SPI(2, baudrate=40000000, polarity=1, phase=1,
sck=machine.Pin(pins['sck']), mosi=machine.Pin(pins['mosi']))
cs_pin = pins.get('cs')
cs = machine.Pin(cs_pin, machine.Pin.OUT) if cs_pin is not None else None
rst_pin = pins.get('rst')
dc_pin = pins.get('dc')
self.tft = st7789.ST7789(spi, self.width, self.height,
reset=machine.Pin(rst_pin, machine.Pin.OUT) if rst_pin else None,
dc=machine.Pin(dc_pin, machine.Pin.OUT) if dc_pin else None,
cs=cs,
backlight=None)
self.tft.init()
self.tft.fill(st7789.BLUE)
except Exception as e:
print(f"Display error: {e}")
self.tft = None
def fill(self, color):
if self.tft:
self.tft.fill(color)
def fill_rect(self, x, y, w, h, color):
if self.tft:
self.tft.fill_rect(x, y, w, h, color)
def set_ws(self, ws):
if self.font:
self.font.set_ws(ws)
def text(self, text, x, y, color, wait=True):
if self.tft:
self.font.text(self.tft, text, x, y, color, wait=wait)
def init_ui(self):
"""初始化 UI 背景"""
if self.tft:
self.tft.fill(st7789.BLACK)
self.tft.fill_rect(0, 0, 240, 30, st7789.WHITE)
def update_audio_bar(self, bar_height, last_bar_height):
"""更新音频可视化的柱状图"""
if not self.tft: return last_bar_height
# 确定当前颜色
color = st7789.GREEN
if bar_height > 50: color = st7789.YELLOW
if bar_height > 100: color = st7789.RED
# 确定上一次颜色
last_color = st7789.GREEN
if last_bar_height > 50: last_color = st7789.YELLOW
if last_bar_height > 100: last_color = st7789.RED
# 1. 如果变矮了,清除顶部多余部分
if bar_height < last_bar_height:
self.tft.fill_rect(100, 240 - last_bar_height, 40, last_bar_height - bar_height, st7789.BLACK)
# 2. 如果颜色变了,必须重绘整个条
if color != last_color:
self.tft.fill_rect(100, 240 - bar_height, 40, bar_height, color)
# 3. 如果颜色没变且变高了,只绘新增部分
elif bar_height > last_bar_height:
self.tft.fill_rect(100, 240 - bar_height, 40, bar_height - last_bar_height, color)
return bar_height
def show_image(self, x, y, width, height, rgb565_data):
"""在指定位置显示RGB565格式的图片数据"""
if not self.tft: return
try:
# 将字节数据转换为适合blit_buffer的格式
self.tft.blit_buffer(rgb565_data, x, y, width, height)
except Exception as e:
print(f"Show image error: {e}")
def show_image_chunk(self, x, y, width, height, data, offset):
"""流式显示图片数据块"""
if not self.tft: return
# ST7789 blit_buffer expects a complete buffer for the window
# But we can calculate which pixels this chunk corresponds to
# This is tricky because blit_buffer sets a window and then writes data.
# If we want to stream, we should probably set the window once and then write chunks.
# But st7789py library might not expose raw write easily without window set.
# Alternative: Calculate the sub-window for this chunk.
# Data is a linear sequence of pixels (2 bytes per pixel)
# We assume data length is even.
try:
# Simple approach: If offset is 0, we set the window for the whole image
# And then write data. But st7789py's blit_buffer does both.
# Let's look at st7789py implementation.
# fill_rect sets window then writes.
# blit_buffer sets window then writes.
# We can use a modified approach:
# If it's the first chunk, set window.
# Then write data.
# But we can't easily modify the library state from here.
# So we calculate the rect for this chunk.
# Total pixels
total_pixels = width * height
# Current pixel offset
pixel_offset = offset // 2
num_pixels = len(data) // 2
# This only works if chunks align with rows, or if we can write partial rows.
# ST7789 supports writing continuous memory.
# Let's try to determine the x, y, w, h for this chunk.
# This is complex if it wraps around lines.
# Easier approach for ESP32 memory constrained environment:
# We just need to use the raw write method of the display driver if available.
if offset == 0:
# Set window for the whole image
self.tft.set_window(x, y, x + width - 1, y + height - 1)
# Write raw data
self.tft.write(None, data)
except Exception as e:
print(f"Show chunk error: {e}")
def render_home_screen(self):
"""渲染首页"""
if not self.tft:
return
self.tft.fill(st7789.BLACK)
# 顶部标题栏
self.tft.fill_rect(0, 0, 240, 40, 0x2124) # Dark Grey
self.text("量迹AI贴纸生成", 45, 12, st7789.WHITE)
# 中间Logo区域简单绘制一个框
self.tft.fill_rect(80, 80, 80, 80, st7789.BLUE)
self.text("AI", 108, 110, st7789.WHITE)
# 底部提示
self.text("正在启动...", 80, 200, st7789.CYAN)
def render_wifi_connecting(self):
"""渲染WiFi连接中界面"""
if not self.tft:
return
self.tft.fill(st7789.BLACK)
self.text("WiFi连接中...", 60, 110, st7789.WHITE)
# 加载动画会在主循环中绘制
def render_wifi_status(self, success):
"""渲染WiFi连接结果"""
if not self.tft:
return
self.tft.fill(st7789.BLACK)
if success:
self.text("WiFi连接成功!", 60, 100, st7789.GREEN)
self.draw_check_icon(110, 130)
else:
self.text("WiFi连接失败", 60, 100, st7789.RED)
self.text("请重试", 95, 130, st7789.WHITE)
def draw_top_tip(self, text):
"""在右上角显示提示文字"""
if not self.tft:
return
# 清除区域 (假设背景是白色的,因为顶部栏通常是白色)
# x=170, w=70, h=30
self.tft.fill_rect(170, 0, 70, 30, st7789.WHITE)
if text:
# 使用红色显示提示,醒目
self.text(text, 170, 8, st7789.RED, wait=False)
def draw_check_icon(self, x, y):
"""绘制勾选图标"""
if not self.tft:
return
self.tft.line(x, y + 5, x + 3, y + 8, st7789.GREEN)
self.tft.line(x + 3, y + 8, x + 10, y, st7789.GREEN)