Use designer 0831 PNG bitmaps for mode-select labels.
Replace on-device Chinese glyphs with MiSans icon+text row assets so the trial format matches the designer's export. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
ba31d91aef
commit
b996c8876e
45
UI/UI_Idle.c
45
UI/UI_Idle.c
|
|
@ -19,34 +19,18 @@ void RGB_Y_TO_G()
|
||||||
#define UI_MODE_SCREEN_WIDTH 240
|
#define UI_MODE_SCREEN_WIDTH 240
|
||||||
#define UI_MODE_SCREEN_HEIGHT 320
|
#define UI_MODE_SCREEN_HEIGHT 320
|
||||||
|
|
||||||
#define UI_MODE_BG_COLOR 0x1925
|
|
||||||
#define UI_MODE_LINE_COLOR DARKBLUE
|
|
||||||
#define UI_MODE_TEXT_COLOR 0xFFFF
|
|
||||||
/* PDF 标注 MiSans-Medium 21;字库无 21,用 28 与 40x30 图标比例接近标注稿 */
|
|
||||||
#define UI_MODE_FONT_SIZE 28
|
|
||||||
#define UI_MODE_ICON_W 40
|
|
||||||
#define UI_MODE_ICON_H 30
|
|
||||||
#define UI_MODE_ICON_TEXT_GAP 8
|
|
||||||
/* 汉字墨心略偏上;下移与图标光心平齐(过大易显得文字偏下) */
|
|
||||||
#define UI_MODE_TEXT_OPTICAL_DY 2
|
|
||||||
|
|
||||||
/* 模式选择页焦点:0=万能 1=普通 2=专业,默认选中万能(与规范一致) */
|
/* 模式选择页焦点:0=万能 1=普通 2=专业,默认选中万能(与规范一致) */
|
||||||
static uint8_t s_mode_select_focus = 0;
|
static uint8_t s_mode_select_focus = 0;
|
||||||
|
|
||||||
static void UI_DrawModeSelectButton(uint16_t y, const uint8_t *text,
|
/* 0831 美工试用图:图标+MiSans 文字整行位图 */
|
||||||
const uint8_t *icon, uint8_t focused)
|
static void UI_DrawModeSelectButton(uint16_t y, const uint8_t *row, uint8_t focused)
|
||||||
{
|
{
|
||||||
const uint16_t btn_w = 220;
|
const uint16_t btn_w = 220;
|
||||||
const uint16_t btn_h = 87;
|
const uint16_t btn_h = 87;
|
||||||
const uint16_t btn_r = 10;
|
const uint16_t btn_r = 10;
|
||||||
const uint16_t btn_x = (240 - btn_w) / 2;
|
const uint16_t btn_x = (240 - btn_w) / 2;
|
||||||
const uint16_t text_w = (uint16_t)(4 * UI_MODE_FONT_SIZE);
|
const uint16_t row_x = (uint16_t)(btn_x + (btn_w - UI_MODE0831_ROW_W) / 2);
|
||||||
const uint16_t group_w = (uint16_t)(UI_MODE_ICON_W + UI_MODE_ICON_TEXT_GAP + text_w);
|
const uint16_t row_y = (uint16_t)(y + (btn_h - UI_MODE0831_ROW_H) / 2);
|
||||||
const uint16_t group_x = (uint16_t)(btn_x + (btn_w - group_w) / 2);
|
|
||||||
const uint16_t mid_y = (uint16_t)(y + btn_h / 2);
|
|
||||||
const uint16_t icon_y = (uint16_t)(mid_y - UI_MODE_ICON_H / 2);
|
|
||||||
const uint16_t text_y = (uint16_t)(mid_y - UI_MODE_FONT_SIZE / 2 + UI_MODE_TEXT_OPTICAL_DY);
|
|
||||||
const uint16_t text_x = (uint16_t)(group_x + UI_MODE_ICON_W + UI_MODE_ICON_TEXT_GAP);
|
|
||||||
|
|
||||||
if (focused)
|
if (focused)
|
||||||
{
|
{
|
||||||
|
|
@ -58,17 +42,7 @@ static void UI_DrawModeSelectButton(uint16_t y, const uint8_t *text,
|
||||||
LCD_FillRoundRect(btn_x, y, btn_w, btn_h, btn_r, COLOR_NORMAL_BG);
|
LCD_FillRoundRect(btn_x, y, btn_w, btn_h, btn_r, COLOR_NORMAL_BG);
|
||||||
}
|
}
|
||||||
|
|
||||||
LCD_WR_PIC_Trans(group_x, icon_y, UI_MODE_ICON_W, UI_MODE_ICON_H, icon, BLACK);
|
LCD_WR_PIC_Trans(row_x, row_y, UI_MODE0831_ROW_W, UI_MODE0831_ROW_H, row, BLACK);
|
||||||
LCD_ShowChinese_AutoAlign(
|
|
||||||
text_x, (uint16_t)(text_x + text_w - 1),
|
|
||||||
text_y,
|
|
||||||
text,
|
|
||||||
LCD_ALIGN_LEFT,
|
|
||||||
UI_MODE_TEXT_COLOR,
|
|
||||||
BLACK,
|
|
||||||
1,
|
|
||||||
UI_MODE_FONT_SIZE
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void UI_DrawModeSelectScreen(void)
|
void UI_DrawModeSelectScreen(void)
|
||||||
|
|
@ -81,16 +55,13 @@ void UI_DrawModeSelectScreen(void)
|
||||||
label_top();
|
label_top();
|
||||||
|
|
||||||
UI_DrawModeSelectButton(40,
|
UI_DrawModeSelectButton(40,
|
||||||
(const uint8_t *)"\xCD\xF2\xC4\xDC\xC4\xA3\xCA\xBD",
|
gImage_Mode0831_Universal_Row_180_52,
|
||||||
gImage_FreeMode_Icon_40_30,
|
|
||||||
s_mode_select_focus == 0);
|
s_mode_select_focus == 0);
|
||||||
UI_DrawModeSelectButton(132,
|
UI_DrawModeSelectButton(132,
|
||||||
(const uint8_t *)"\xC6\xD5\xCD\xA8\xC4\xA3\xCA\xBD",
|
gImage_Mode0831_Normal_Row_180_52,
|
||||||
gImage_NormalMode_Icon_40_30,
|
|
||||||
s_mode_select_focus == 1);
|
s_mode_select_focus == 1);
|
||||||
UI_DrawModeSelectButton(224,
|
UI_DrawModeSelectButton(224,
|
||||||
(const uint8_t *)"\xD7\xA8\xD2\xB5\xC4\xA3\xCA\xBD",
|
gImage_Mode0831_Expert_Row_180_52,
|
||||||
gImage_ExpressMode_Icon_40_30,
|
|
||||||
s_mode_select_focus == 2);
|
s_mode_select_focus == 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,15 @@
|
||||||
|
#ifndef __DRV_ILI9341_LCD_IMAGE_MODESELECT0831_H
|
||||||
|
#define __DRV_ILI9341_LCD_IMAGE_MODESELECT0831_H
|
||||||
|
|
||||||
|
#include "stdint.h"
|
||||||
|
|
||||||
|
#define UI_MODE0831_ROW_W 180
|
||||||
|
#define UI_MODE0831_ROW_H 52
|
||||||
|
|
||||||
|
extern const unsigned char gImage_Mode0831_Universal_Row_180_52[];
|
||||||
|
|
||||||
|
extern const unsigned char gImage_Mode0831_Normal_Row_180_52[];
|
||||||
|
|
||||||
|
extern const unsigned char gImage_Mode0831_Expert_Row_180_52[];
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -2078,6 +2078,12 @@
|
||||||
<file>
|
<file>
|
||||||
<name>$PROJ_DIR$\..\..\device\LCD_ILI9341\Drv_ILI9341_Lcd_Image.c</name>
|
<name>$PROJ_DIR$\..\..\device\LCD_ILI9341\Drv_ILI9341_Lcd_Image.c</name>
|
||||||
</file>
|
</file>
|
||||||
|
<file>
|
||||||
|
<name>$PROJ_DIR$\..\..\device\LCD_ILI9341\Drv_ILI9341_Lcd_Image_ModeSelect0831.c</name>
|
||||||
|
</file>
|
||||||
|
<file>
|
||||||
|
<name>$PROJ_DIR$\..\..\device\LCD_ILI9341\Drv_ILI9341_Lcd_Image_ModeSelect0831.h</name>
|
||||||
|
</file>
|
||||||
<file>
|
<file>
|
||||||
<name>$PROJ_DIR$\..\..\device\LCD_ILI9341\Drv_ILI9341_Lcd_Image.h</name>
|
<name>$PROJ_DIR$\..\..\device\LCD_ILI9341\Drv_ILI9341_Lcd_Image.h</name>
|
||||||
</file>
|
</file>
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,7 @@
|
||||||
#include "Drv_ILI9341_Lcd_Init.h"
|
#include "Drv_ILI9341_Lcd_Init.h"
|
||||||
#include "Drv_ILI9341_Lcd_App.h"
|
#include "Drv_ILI9341_Lcd_App.h"
|
||||||
#include "Drv_ILI9341_Lcd_Image.h"
|
#include "Drv_ILI9341_Lcd_Image.h"
|
||||||
|
#include "Drv_ILI9341_Lcd_Image_ModeSelect0831.h"
|
||||||
#include "Drv_ILI9341_Lcd_Dump.h"
|
#include "Drv_ILI9341_Lcd_Dump.h"
|
||||||
#include "Drv_XPT2046_Touch.h"
|
#include "Drv_XPT2046_Touch.h"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,129 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Convert Doc/UI 0831 trial PNG slices to RGB565 C arrays for mode-select."""
|
||||||
|
from PIL import Image, ImageDraw
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
ROOT = Path(__file__).resolve().parents[1]
|
||||||
|
SRC = ROOT / "tools" / "assets_0831"
|
||||||
|
OUT_C = ROOT / "device" / "LCD_ILI9341" / "Drv_ILI9341_Lcd_Image_ModeSelect0831.c"
|
||||||
|
OUT_H = ROOT / "device" / "LCD_ILI9341" / "Drv_ILI9341_Lcd_Image_ModeSelect0831.h"
|
||||||
|
PREV = SRC / "preview_mode_select.png"
|
||||||
|
|
||||||
|
# Only emit composite rows (icon+MiSans text) to save Flash.
|
||||||
|
ROW_W, ROW_H = 180, 52
|
||||||
|
|
||||||
|
NAMES = [
|
||||||
|
("Universal", "mode_row_0.png"), # 万能
|
||||||
|
("Normal", "mode_row_1.png"), # 普通
|
||||||
|
("Expert", "mode_row_2.png"), # 专业
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def rgba_to_rgb565_bytes(im: Image.Image) -> bytes:
|
||||||
|
im = im.convert("RGBA")
|
||||||
|
px = im.load()
|
||||||
|
w, h = im.size
|
||||||
|
out = bytearray(w * h * 2)
|
||||||
|
i = 0
|
||||||
|
for y in range(h):
|
||||||
|
for x in range(w):
|
||||||
|
r, g, b, a = px[x, y]
|
||||||
|
if a < 40 or (r < 12 and g < 12 and b < 12):
|
||||||
|
out[i] = 0
|
||||||
|
out[i + 1] = 0
|
||||||
|
else:
|
||||||
|
r = (r * a) // 255
|
||||||
|
g = (g * a) // 255
|
||||||
|
b = (b * a) // 255
|
||||||
|
c = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3)
|
||||||
|
out[i] = (c >> 8) & 0xFF
|
||||||
|
out[i + 1] = c & 0xFF
|
||||||
|
i += 2
|
||||||
|
return bytes(out)
|
||||||
|
|
||||||
|
|
||||||
|
def fit_on_canvas(src_im: Image.Image, cw: int, ch: int) -> Image.Image:
|
||||||
|
im = src_im.convert("RGBA")
|
||||||
|
bbox = im.getbbox()
|
||||||
|
if bbox:
|
||||||
|
im = im.crop(bbox)
|
||||||
|
sw, sh = im.size
|
||||||
|
scale = min(cw / sw, ch / sh)
|
||||||
|
nw = max(1, int(round(sw * scale)))
|
||||||
|
nh = max(1, int(round(sh * scale)))
|
||||||
|
im = im.resize((nw, nh), Image.Resampling.LANCZOS)
|
||||||
|
canvas = Image.new("RGBA", (cw, ch), (0, 0, 0, 255))
|
||||||
|
ox = (cw - nw) // 2
|
||||||
|
oy = (ch - nh) // 2
|
||||||
|
canvas.paste(im, (ox, oy), im)
|
||||||
|
return canvas
|
||||||
|
|
||||||
|
|
||||||
|
def emit_array(name: str, data: bytes, w: int, h: int, lines: list) -> None:
|
||||||
|
lines.append(f"const unsigned char {name}[{len(data)}] = {{ /* {w}x{h} RGB565 BE */")
|
||||||
|
for i in range(0, len(data), 16):
|
||||||
|
chunk = data[i : i + 16]
|
||||||
|
hexes = ",".join(f"0x{b:02X}" for b in chunk)
|
||||||
|
lines.append(hexes + ",")
|
||||||
|
lines.append("};")
|
||||||
|
lines.append("")
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> None:
|
||||||
|
c_lines = [
|
||||||
|
'#include "Drv_ILI9341_Lcd_Image_ModeSelect0831.h"',
|
||||||
|
"",
|
||||||
|
"/* Auto-generated from Doc/UI 0831 trial PNG. Do not hand-edit. */",
|
||||||
|
"",
|
||||||
|
]
|
||||||
|
h_lines = [
|
||||||
|
"#ifndef __DRV_ILI9341_LCD_IMAGE_MODESELECT0831_H",
|
||||||
|
"#define __DRV_ILI9341_LCD_IMAGE_MODESELECT0831_H",
|
||||||
|
"",
|
||||||
|
'#include "stdint.h"',
|
||||||
|
"",
|
||||||
|
f"#define UI_MODE0831_ROW_W {ROW_W}",
|
||||||
|
f"#define UI_MODE0831_ROW_H {ROW_H}",
|
||||||
|
"",
|
||||||
|
]
|
||||||
|
|
||||||
|
screen = Image.new("RGBA", (240, 320), (0, 0, 0, 255))
|
||||||
|
d = ImageDraw.Draw(screen)
|
||||||
|
d.rectangle([0, 0, 239, 27], fill=(20, 28, 40, 255))
|
||||||
|
|
||||||
|
btn_ys = [40, 132, 224]
|
||||||
|
btn_w, btn_h, btn_r = 220, 87, 10
|
||||||
|
total = 0
|
||||||
|
|
||||||
|
for idx, (tag, row_n) in enumerate(NAMES):
|
||||||
|
row = fit_on_canvas(Image.open(SRC / row_n), ROW_W, ROW_H)
|
||||||
|
row.save(SRC / f"gen_{tag.lower()}_row.png")
|
||||||
|
|
||||||
|
rdata = rgba_to_rgb565_bytes(row)
|
||||||
|
total += len(rdata)
|
||||||
|
|
||||||
|
rname = f"gImage_Mode0831_{tag}_Row_{ROW_W}_{ROW_H}"
|
||||||
|
emit_array(rname, rdata, ROW_W, ROW_H, c_lines)
|
||||||
|
h_lines.append(f"extern const unsigned char {rname}[];")
|
||||||
|
h_lines.append("")
|
||||||
|
|
||||||
|
by = btn_ys[idx]
|
||||||
|
bx = (240 - btn_w) // 2
|
||||||
|
fill = (47, 54, 71, 255) if idx == 0 else (25, 32, 45, 255)
|
||||||
|
d.rounded_rectangle([bx, by, bx + btn_w - 1, by + btn_h - 1], radius=btn_r, fill=fill)
|
||||||
|
rx = bx + (btn_w - ROW_W) // 2
|
||||||
|
ry = by + (btn_h - ROW_H) // 2
|
||||||
|
screen.paste(row, (rx, ry), row)
|
||||||
|
|
||||||
|
h_lines += ["#endif", ""]
|
||||||
|
OUT_H.write_text("\n".join(h_lines), encoding="utf-8")
|
||||||
|
OUT_C.write_text("\n".join(c_lines), encoding="utf-8")
|
||||||
|
screen.convert("RGB").save(PREV)
|
||||||
|
print(f"wrote {OUT_C} ({OUT_C.stat().st_size} bytes)")
|
||||||
|
print(f"wrote {OUT_H}")
|
||||||
|
print(f"flash payload ~{total} bytes")
|
||||||
|
print(f"preview {PREV}")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
Loading…
Reference in New Issue